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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [lwIP_AVR32_UC3/] [DRIVERS/] [MACB/] [macb.c] - Blame information for rev 592

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

Line No. Rev Author Line
1 583 jeremybenn
/*This file has been prepared for Doxygen automatic documentation generation.*/
2
/*! \file *********************************************************************
3
 *
4
 * \brief MACB driver for EVK1100 board.
5
 *
6
 * This file defines a useful set of functions for the MACB interface on
7
 * AVR32 devices.
8
 *
9
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
10
 * - Supported devices:  All AVR32 devices with a MACB module can be used.
11
 * - AppNote:
12
 *
13
 * \author               Atmel Corporation: http://www.atmel.com \n
14
 *                       Support and FAQ: http://support.atmel.no/
15
 *
16
 *****************************************************************************/
17
 
18
/* Copyright (c) 2007, Atmel Corporation All rights reserved.
19
 *
20
 * Redistribution and use in source and binary forms, with or without
21
 * modification, are permitted provided that the following conditions are met:
22
 *
23
 * 1. Redistributions of source code must retain the above copyright notice,
24
 * this list of conditions and the following disclaimer.
25
 *
26
 * 2. Redistributions in binary form must reproduce the above copyright notice,
27
 * this list of conditions and the following disclaimer in the documentation
28
 * and/or other materials provided with the distribution.
29
 *
30
 * 3. The name of ATMEL may not be used to endorse or promote products derived
31
 * from this software without specific prior written permission.
32
 *
33
 * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
34
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
35
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
36
 * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
37
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
42
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
 */
44
 
45
 
46
#include <stdio.h>
47
#include <string.h>
48
#include <avr32/io.h>
49
 
50
 
51
#ifdef FREERTOS_USED
52
  #include "FreeRTOS.h" 
53
  #include "task.h"
54
  #include "semphr.h"
55
#endif
56
#include "macb.h"
57
#include "gpio.h"
58
#include "conf_eth.h"
59
#include "intc.h"
60
 
61
 
62
/* Size of each receive buffer - DO NOT CHANGE. */
63
#define RX_BUFFER_SIZE    128
64
 
65
 
66
/* The buffer addresses written into the descriptors must be aligned so the
67
last few bits are zero.  These bits have special meaning for the MACB
68
peripheral and cannot be used as part of the address. */
69
#define ADDRESS_MASK      ( ( unsigned long ) 0xFFFFFFFC )
70
 
71
/* Bit used within the address stored in the descriptor to mark the last
72
descriptor in the array. */
73
#define RX_WRAP_BIT       ( ( unsigned long ) 0x02 )
74
 
75
/* A short delay is used to wait for a buffer to become available, should
76
one not be immediately available when trying to transmit a frame. */
77
#define BUFFER_WAIT_DELAY   ( 2 )
78
 
79
#ifndef FREERTOS_USED
80
#define portENTER_CRITICAL           Disable_global_interrupt 
81
#define portEXIT_CRITICAL            Enable_global_interrupt
82
#define portENTER_SWITCHING_ISR()  
83
#define portEXIT_SWITCHING_ISR()  
84
#endif 
85
 
86
 
87
/* Buffer written to by the MACB DMA.  Must be aligned as described by the
88
comment above the ADDRESS_MASK definition. */
89
#if __GNUC__
90
static volatile char pcRxBuffer[ ETHERNET_CONF_NB_RX_BUFFERS * RX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
91
#elif __ICCAVR32__
92
#pragma data_alignment=8
93
static volatile char pcRxBuffer[ ETHERNET_CONF_NB_RX_BUFFERS * RX_BUFFER_SIZE ];
94
#endif
95
 
96
 
97
/* Buffer read by the MACB DMA.  Must be aligned as described by the comment
98
above the ADDRESS_MASK definition. */
99
#if __GNUC__
100
static volatile char pcTxBuffer[ ETHERNET_CONF_NB_TX_BUFFERS * ETHERNET_CONF_TX_BUFFER_SIZE ] __attribute__ ((aligned (8)));
101
#elif __ICCAVR32__
102
#pragma data_alignment=8
103
static volatile char pcTxBuffer[ ETHERNET_CONF_NB_TX_BUFFERS * ETHERNET_CONF_TX_BUFFER_SIZE ];
104
#endif
105
 
106
/* Descriptors used to communicate between the program and the MACB peripheral.
107
These descriptors hold the locations and state of the Rx and Tx buffers. */
108
static volatile AVR32_TxTdDescriptor xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS ];
109
static volatile AVR32_RxTdDescriptor xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS ];
110
 
111
/* The IP and Ethernet addresses are read from the header files. */
112
char cMACAddress[ 6 ] = { ETHERNET_CONF_ETHADDR0,ETHERNET_CONF_ETHADDR1,ETHERNET_CONF_ETHADDR2,ETHERNET_CONF_ETHADDR3,ETHERNET_CONF_ETHADDR4,ETHERNET_CONF_ETHADDR5 };
113
 
114
/*-----------------------------------------------------------*/
115
 
116
/* See the header file for descriptions of public functions. */
117
 
118
/*
119
 * Prototype for the MACB interrupt function - called by the asm wrapper.
120
 */
121
#ifdef FREERTOS_USED
122
#if __GNUC__
123
__attribute__((naked))
124
#elif __ICCAVR32__
125
#pragma shadow_registers = full   // Naked.
126
#endif
127
#else
128
#if __GNUC__
129
__attribute__((__interrupt__))
130
#elif __ICCAVR32__
131
__interrupt
132
#endif
133
#endif
134
void vMACB_ISR( void );
135
static long prvMACB_ISR_NonNakedBehaviour( void );
136
 
137
 
138
#if ETHERNET_CONF_USE_PHY_IT
139
#ifdef FREERTOS_USED
140
#if __GNUC__
141
__attribute__((naked))
142
#elif __ICCAVR32__
143
#pragma shadow_registers = full   // Naked.
144
#endif
145
#else
146
#if __GNUC__
147
__attribute__((__interrupt__))
148
#elif __ICCAVR32__
149
__interrupt
150
#endif
151
#endif
152
void vPHY_ISR( void );
153
static long prvPHY_ISR_NonNakedBehaviour( void );
154
#endif
155
 
156
 
157
/*
158
 * Initialise both the Tx and Rx descriptors used by the MACB.
159
 */
160
static void prvSetupDescriptors(volatile avr32_macb_t * macb);
161
 
162
/*
163
 * Write our MAC address into the MACB.
164
 */
165
static void prvSetupMACAddress( volatile avr32_macb_t * macb );
166
 
167
/*
168
 * Configure the MACB for interrupts.
169
 */
170
static void prvSetupMACBInterrupt( volatile avr32_macb_t * macb );
171
 
172
/*
173
 * Some initialisation functions.
174
 */
175
static Bool prvProbePHY( volatile avr32_macb_t * macb );
176
static unsigned long ulReadMDIO(volatile avr32_macb_t * macb, unsigned short usAddress);
177
static void vWriteMDIO(volatile avr32_macb_t * macb, unsigned short usAddress, unsigned short usValue);
178
 
179
 
180
#ifdef FREERTOS_USED
181
/* The semaphore used by the MACB ISR to wake the MACB task. */
182
static xSemaphoreHandle xSemaphore = NULL;
183
#else
184
static volatile Bool DataToRead = FALSE;
185
#endif
186
 
187
/* Holds the index to the next buffer from which data will be read. */
188
volatile unsigned long ulNextRxBuffer = 0;
189
 
190
 
191
long lMACBSend(volatile avr32_macb_t * macb, char *pcFrom, unsigned long ulLength, long lEndOfFrame )
192
{
193
static unsigned long uxTxBufferIndex = 0;
194
char *pcBuffer;
195
unsigned long ulLastBuffer, ulDataBuffered = 0, ulDataRemainingToSend, ulLengthToSend;
196
 
197
 
198
  /* If the length of data to be transmitted is greater than each individual
199
  transmit buffer then the data will be split into more than one buffer.
200
  Loop until the entire length has been buffered. */
201
  while( ulDataBuffered < ulLength )
202
  {
203
    // Is a buffer available ?
204
    while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AVR32_TRANSMIT_OK ) )
205
    {
206
      // There is no room to write the Tx data to the Tx buffer.  
207
      // Wait a short while, then try again.
208
#ifdef FREERTOS_USED
209
      vTaskDelay( BUFFER_WAIT_DELAY );
210
#else
211
      __asm__ __volatile__ ("nop");
212
#endif
213
    }
214
 
215
    portENTER_CRITICAL();
216
    {
217
      // Get the address of the buffer from the descriptor, 
218
      // then copy the data into the buffer.
219
      pcBuffer = ( char * ) xTxDescriptors[ uxTxBufferIndex ].addr;
220
 
221
      // How much can we write to the buffer ?
222
      ulDataRemainingToSend = ulLength - ulDataBuffered;
223
      if( ulDataRemainingToSend <= ETHERNET_CONF_TX_BUFFER_SIZE )
224
      {
225
        // We can write all the remaining bytes.
226
        ulLengthToSend = ulDataRemainingToSend;
227
      }
228
      else
229
      {
230
        // We can't write more than ETH_TX_BUFFER_SIZE in one go.
231
        ulLengthToSend = ETHERNET_CONF_TX_BUFFER_SIZE;
232
      }
233
      // Copy the data into the buffer.
234
      memcpy( ( void * ) pcBuffer, ( void * ) &( pcFrom[ ulDataBuffered ] ), ulLengthToSend );
235
      ulDataBuffered += ulLengthToSend;
236
      // Is this the last data for the frame ? 
237
      if( lEndOfFrame && ( ulDataBuffered >= ulLength ) )
238
      {
239
        // No more data remains for this frame so we can start the transmission.
240
        ulLastBuffer = AVR32_LAST_BUFFER;
241
      }
242
      else
243
      {
244
        // More data to come for this frame.
245
        ulLastBuffer = 0;
246
      }
247
      // Fill out the necessary in the descriptor to get the data sent,
248
      // then move to the next descriptor, wrapping if necessary.
249
      if( uxTxBufferIndex >= ( ETHERNET_CONF_NB_TX_BUFFERS - 1 ) )
250
      {
251
        xTxDescriptors[ uxTxBufferIndex ].U_Status.status =   ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME )
252
                                    | ulLastBuffer
253
                                    | AVR32_TRANSMIT_WRAP;
254
        uxTxBufferIndex = 0;
255
      }
256
      else
257
      {
258
        xTxDescriptors[ uxTxBufferIndex ].U_Status.status =   ( ulLengthToSend & ( unsigned long ) AVR32_LENGTH_FRAME )
259
                                    | ulLastBuffer;
260
        uxTxBufferIndex++;
261
      }
262
      /* If this is the last buffer to be sent for this frame we can
263
         start the transmission. */
264
      if( ulLastBuffer )
265
      {
266
        macb->ncr |=  AVR32_MACB_TSTART_MASK;
267
      }
268
    }
269
    portEXIT_CRITICAL();
270
  }
271
 
272
  return PASS;
273
}
274
 
275
 
276
unsigned long ulMACBInputLength( void )
277
{
278
register unsigned long ulIndex , ulLength = 0;
279
unsigned int uiTemp;
280
 
281
  // Skip any fragments.  We are looking for the first buffer that contains
282
  // data and has the SOF (start of frame) bit set.
283
  while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AVR32_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AVR32_SOF ) )
284
  {
285
    // Ignoring this buffer.  Mark it as free again.
286
    uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;
287
    xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );
288
    ulNextRxBuffer++;
289
    if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )
290
    {
291
      ulNextRxBuffer = 0;
292
    }
293
  }
294
 
295
  // We are going to walk through the descriptors that make up this frame,
296
  // but don't want to alter ulNextRxBuffer as this would prevent vMACBRead()
297
  // from finding the data.  Therefore use a copy of ulNextRxBuffer instead. 
298
  ulIndex = ulNextRxBuffer;
299
 
300
  // Walk through the descriptors until we find the last buffer for this frame.
301
  // The last buffer will give us the length of the entire frame.
302
  while( ( xRxDescriptors[ ulIndex ].addr & AVR32_OWNERSHIP_BIT ) && !ulLength )
303
  {
304
    ulLength = xRxDescriptors[ ulIndex ].U_Status.status & AVR32_LENGTH_FRAME;
305
    // Increment to the next buffer, wrapping if necessary.
306
    ulIndex++;
307
    if( ulIndex >= ETHERNET_CONF_NB_RX_BUFFERS )
308
    {
309
      ulIndex = 0;
310
    }
311
  }
312
  return ulLength;
313
}
314
/*-----------------------------------------------------------*/
315
 
316
void vMACBRead( char *pcTo, unsigned long ulSectionLength, unsigned long ulTotalFrameLength )
317
{
318
static unsigned long ulSectionBytesReadSoFar = 0, ulBufferPosition = 0, ulFameBytesReadSoFar = 0;
319
static char *pcSource;
320
register unsigned long ulBytesRemainingInBuffer, ulRemainingSectionBytes;
321
unsigned int uiTemp;
322
 
323
  // Read ulSectionLength bytes from the Rx buffers. 
324
  // This is not necessarily any correspondence between the length of our Rx buffers, 
325
  // and the length of the data we are returning or the length of the data being requested.
326
  // Therefore, between calls  we have to remember not only which buffer we are currently
327
  // processing, but our position within that buffer.  
328
  // This would be greatly simplified if PBUF_POOL_BUFSIZE could be guaranteed to be greater 
329
  // than the size of each Rx buffer, and that memory fragmentation did not occur.
330
 
331
  // This function should only be called after a call to ulMACBInputLength().
332
  // This will ensure ulNextRxBuffer is set to the correct buffer. */
333
 
334
  // vMACBRead is called with pcTo set to NULL to indicate that we are about
335
  // to read a new frame.  Any fragments remaining in the frame we were
336
  // processing during the last call should be dropped.
337
  if( pcTo == NULL )
338
  {
339
    // How many bytes are indicated as being in this buffer?  
340
    // If none then the buffer is completely full and the frame is contained within more
341
    // than one buffer.
342
    // Reset our state variables ready for the next read from this buffer.
343
    pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );
344
    ulFameBytesReadSoFar = ( unsigned long ) 0;
345
    ulBufferPosition = ( unsigned long ) 0;
346
  }
347
  else
348
  {
349
    // Loop until we have obtained the required amount of data.
350
    ulSectionBytesReadSoFar = 0;
351
    while( ulSectionBytesReadSoFar < ulSectionLength )
352
    {
353
      // We may have already read some data from this buffer.
354
      // How much data remains in the buffer?
355
      ulBytesRemainingInBuffer = ( RX_BUFFER_SIZE - ulBufferPosition );
356
 
357
      // How many more bytes do we need to read before we have the
358
      // required amount of data?
359
      ulRemainingSectionBytes = ulSectionLength - ulSectionBytesReadSoFar;
360
 
361
      // Do we want more data than remains in the buffer? 
362
      if( ulRemainingSectionBytes > ulBytesRemainingInBuffer )
363
      {
364
        // We want more data than remains in the buffer so we can
365
        // write the remains of the buffer to the destination, then move
366
        // onto the next buffer to get the rest.
367
        memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulBytesRemainingInBuffer );
368
        ulSectionBytesReadSoFar += ulBytesRemainingInBuffer;
369
        ulFameBytesReadSoFar += ulBytesRemainingInBuffer;
370
 
371
        // Mark the buffer as free again.
372
        uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;
373
        xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );
374
        // Move onto the next buffer.
375
        ulNextRxBuffer++;
376
 
377
        if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )
378
        {
379
          ulNextRxBuffer = ( unsigned long ) 0;
380
        }
381
 
382
        // Reset the variables for the new buffer.
383
        pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );
384
        ulBufferPosition = ( unsigned long ) 0;
385
      }
386
      else
387
      {
388
        // We have enough data in this buffer to send back.
389
        // Read out enough data and remember how far we read up to.
390
        memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulRemainingSectionBytes );
391
 
392
        // There may be more data in this buffer yet.
393
        // Increment our position in this buffer past the data we have just read.
394
        ulBufferPosition += ulRemainingSectionBytes;
395
        ulSectionBytesReadSoFar += ulRemainingSectionBytes;
396
        ulFameBytesReadSoFar += ulRemainingSectionBytes;
397
 
398
        // Have we now finished with this buffer?
399
        if( ( ulBufferPosition >= RX_BUFFER_SIZE ) || ( ulFameBytesReadSoFar >= ulTotalFrameLength ) )
400
        {
401
          // Mark the buffer as free again.
402
          uiTemp = xRxDescriptors[ ulNextRxBuffer ].addr;
403
          xRxDescriptors[ ulNextRxBuffer ].addr = uiTemp & ~( AVR32_OWNERSHIP_BIT );
404
          // Move onto the next buffer.
405
          ulNextRxBuffer++;
406
 
407
          if( ulNextRxBuffer >= ETHERNET_CONF_NB_RX_BUFFERS )
408
          {
409
            ulNextRxBuffer = 0;
410
          }
411
 
412
          pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & ADDRESS_MASK );
413
          ulBufferPosition = 0;
414
        }
415
      }
416
    }
417
  }
418
}
419
/*-----------------------------------------------------------*/
420
void vMACBSetMACAddress(const char * MACAddress)
421
{
422
  memcpy(cMACAddress, MACAddress, sizeof(cMACAddress));
423
}
424
 
425
Bool xMACBInit( volatile avr32_macb_t * macb )
426
{
427
volatile unsigned long status;
428
 
429
  // set up registers
430
  macb->ncr = 0;
431
  macb->tsr = ~0UL;
432
  macb->rsr = ~0UL;
433
  macb->idr = ~0UL;
434
  status = macb->isr;
435
 
436
 
437
#if ETHERNET_CONF_USE_RMII_INTERFACE
438
  // RMII used, set 0 to the USRIO Register
439
  macb->usrio &= ~AVR32_MACB_RMII_MASK;
440
#else
441
  // RMII not used, set 1 to the USRIO Register
442
  macb->usrio |= AVR32_MACB_RMII_MASK;
443
#endif
444
 
445
  // Load our MAC address into the MACB. 
446
  prvSetupMACAddress(macb);
447
 
448
  // Setup the buffers and descriptors.
449
  prvSetupDescriptors(macb);
450
 
451
#if ETHERNET_CONF_SYSTEM_CLOCK <= 20000000
452
  macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV8 << AVR32_MACB_NCFGR_CLK_OFFSET);
453
#elif ETHERNET_CONF_SYSTEM_CLOCK <= 40000000
454
  macb->ncfgr |= (AVR32_MACB_NCFGR_CLK_DIV16 << AVR32_MACB_NCFGR_CLK_OFFSET);
455
#elif ETHERNET_CONF_SYSTEM_CLOCK <= 80000000
456
  macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV32 << AVR32_MACB_NCFGR_CLK_OFFSET;
457
#elif ETHERNET_CONF_SYSTEM_CLOCK <= 160000000
458
  macb->ncfgr |= AVR32_MACB_NCFGR_CLK_DIV64 << AVR32_MACB_NCFGR_CLK_OFFSET;
459
#else
460
# error System clock too fast
461
#endif
462
 
463
  // Are we connected?
464
  if( prvProbePHY(macb) == TRUE )
465
  {
466
    // Enable the interrupt!
467
    portENTER_CRITICAL();
468
    {
469
      prvSetupMACBInterrupt(macb);
470
    }
471
    portEXIT_CRITICAL();
472
    // Enable Rx and Tx, plus the stats register.
473
    macb->ncr = AVR32_MACB_NCR_TE_MASK | AVR32_MACB_NCR_RE_MASK;
474
    return (TRUE);
475
  }
476
  return (FALSE);
477
}
478
 
479
void vDisableMACBOperations(volatile avr32_macb_t * macb)
480
{
481
#if ETHERNET_CONF_USE_PHY_IT
482
volatile avr32_gpio_t *gpio = &AVR32_GPIO;
483
volatile avr32_gpio_port_t *gpio_port = &gpio->port[MACB_INTERRUPT_PIN/32];
484
 
485
  gpio_port->ierc =  1 << (MACB_INTERRUPT_PIN%32);
486
#endif
487
 
488
  // write the MACB control register : disable Tx & Rx
489
  macb->ncr &= ~((1 << AVR32_MACB_RE_OFFSET) | (1 << AVR32_MACB_TE_OFFSET));
490
  // We no more want to interrupt on Rx and Tx events.
491
  macb->idr = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK;
492
}
493
 
494
 
495
void vClearMACBTxBuffer( void )
496
{
497
static unsigned long uxNextBufferToClear = 0;
498
 
499
  // Called on Tx interrupt events to set the AVR32_TRANSMIT_OK bit in each
500
  // Tx buffer within the frame just transmitted.  This marks all the buffers
501
  // as available again.
502
 
503
  // The first buffer in the frame should have the bit set automatically. */
504
  if( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_TRANSMIT_OK )
505
  {
506
    // Loop through the other buffers in the frame.
507
    while( !( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AVR32_LAST_BUFFER ) )
508
    {
509
      uxNextBufferToClear++;
510
 
511
      if( uxNextBufferToClear >= ETHERNET_CONF_NB_TX_BUFFERS )
512
      {
513
        uxNextBufferToClear = 0;
514
      }
515
 
516
      xTxDescriptors[ uxNextBufferToClear ].U_Status.status |= AVR32_TRANSMIT_OK;
517
    }
518
 
519
    // Start with the next buffer the next time a Tx interrupt is called.
520
    uxNextBufferToClear++;
521
 
522
    // Do we need to wrap back to the first buffer? 
523
    if( uxNextBufferToClear >= ETHERNET_CONF_NB_TX_BUFFERS )
524
    {
525
      uxNextBufferToClear = 0;
526
    }
527
  }
528
}
529
 
530
static void prvSetupDescriptors(volatile avr32_macb_t * macb)
531
{
532
unsigned long xIndex;
533
unsigned long ulAddress;
534
 
535
  // Initialise xRxDescriptors descriptor.
536
  for( xIndex = 0; xIndex < ETHERNET_CONF_NB_RX_BUFFERS; ++xIndex )
537
  {
538
    // Calculate the address of the nth buffer within the array.
539
    ulAddress = ( unsigned long )( pcRxBuffer + ( xIndex * RX_BUFFER_SIZE ) );
540
 
541
    // Write the buffer address into the descriptor.  
542
    // The DMA will place the data at this address when this descriptor is being used.
543
    // Mask off the bottom bits of the address as these have special meaning.
544
    xRxDescriptors[ xIndex ].addr = ulAddress & ADDRESS_MASK;
545
  }
546
 
547
  // The last buffer has the wrap bit set so the MACB knows to wrap back
548
  // to the first buffer.
549
  xRxDescriptors[ ETHERNET_CONF_NB_RX_BUFFERS - 1 ].addr |= RX_WRAP_BIT;
550
 
551
  // Initialise xTxDescriptors.
552
  for( xIndex = 0; xIndex < ETHERNET_CONF_NB_TX_BUFFERS; ++xIndex )
553
  {
554
    // Calculate the address of the nth buffer within the array.
555
    ulAddress = ( unsigned long )( pcTxBuffer + ( xIndex * ETHERNET_CONF_TX_BUFFER_SIZE ) );
556
 
557
    // Write the buffer address into the descriptor.  
558
    // The DMA will read data from here when the descriptor is being used.
559
    xTxDescriptors[ xIndex ].addr = ulAddress & ADDRESS_MASK;
560
    xTxDescriptors[ xIndex ].U_Status.status = AVR32_TRANSMIT_OK;
561
  }
562
 
563
  // The last buffer has the wrap bit set so the MACB knows to wrap back
564
  // to the first buffer.
565
  xTxDescriptors[ ETHERNET_CONF_NB_TX_BUFFERS - 1 ].U_Status.status = AVR32_TRANSMIT_WRAP | AVR32_TRANSMIT_OK;
566
 
567
  // Tell the MACB where to find the descriptors.
568
  macb->rbqp =   ( unsigned long )xRxDescriptors;
569
  macb->tbqp =   ( unsigned long )xTxDescriptors;
570
 
571
  // Enable the copy of data into the buffers, ignore broadcasts,
572
  // and don't copy FCS.
573
  macb->ncfgr |= (AVR32_MACB_CAF_MASK |  AVR32_MACB_NBC_MASK | AVR32_MACB_NCFGR_DRFCS_MASK);
574
 
575
}
576
 
577
static void prvSetupMACAddress( volatile avr32_macb_t * macb )
578
{
579
  // Must be written SA1L then SA1H.
580
  macb->sa1b =  ( ( unsigned long ) cMACAddress[ 3 ] << 24 ) |
581
                ( ( unsigned long ) cMACAddress[ 2 ] << 16 ) |
582
                ( ( unsigned long ) cMACAddress[ 1 ] << 8  ) |
583
                                    cMACAddress[ 0 ];
584
 
585
  macb->sa1t =  ( ( unsigned long ) cMACAddress[ 5 ] << 8 ) |
586
                                    cMACAddress[ 4 ];
587
}
588
 
589
static void prvSetupMACBInterrupt( volatile avr32_macb_t * macb )
590
{
591
#ifdef FREERTOS_USED
592
  // Create the semaphore used to trigger the MACB task. 
593
  if (xSemaphore == NULL)
594
  {
595
    vSemaphoreCreateBinary( xSemaphore );
596
  }
597
#else 
598
  // Create the flag used to trigger the MACB polling task. 
599
  DataToRead = FALSE;
600
#endif
601
 
602
 
603
#ifdef FREERTOS_USED
604
  if( xSemaphore != NULL)
605
  {
606
    // We start by 'taking' the semaphore so the ISR can 'give' it when the
607
    // first interrupt occurs.
608
    xSemaphoreTake( xSemaphore, 0 );
609
#endif
610
    // Setup the interrupt for MACB.
611
    // Register the interrupt handler to the interrupt controller at interrupt level 2
612
    INTC_register_interrupt((__int_handler)&vMACB_ISR, AVR32_MACB_IRQ, INT2);
613
 
614
#if ETHERNET_CONF_USE_PHY_IT
615
    /* GPIO enable interrupt upon rising edge */
616
    gpio_enable_pin_interrupt(MACB_INTERRUPT_PIN, GPIO_FALLING_EDGE);
617
    // Setup the interrupt for PHY.
618
    // Register the interrupt handler to the interrupt controller at interrupt level 2
619
    INTC_register_interrupt((__int_handler)&vPHY_ISR, (AVR32_GPIO_IRQ_0 + (MACB_INTERRUPT_PIN/8)), INT2);
620
    /* enable interrupts on INT pin */
621
    vWriteMDIO( macb, PHY_MICR , ( MICR_INTEN | MICR_INTOE ));
622
    /* enable "link change" interrupt for Phy */
623
    vWriteMDIO( macb, PHY_MISR , MISR_LINK_INT_EN );
624
#endif
625
 
626
    // We want to interrupt on Rx and Tx events
627
    macb->ier = AVR32_MACB_IER_RCOMP_MASK | AVR32_MACB_IER_TCOMP_MASK;
628
#ifdef FREERTOS_USED
629
  }
630
#endif
631
}
632
 
633
/*! Read a register on MDIO bus (access to the PHY)
634
 *         This function is looping until PHY gets ready
635
 *
636
 * \param macb         Input. instance of the MACB to use
637
 * \param usAddress    Input. register to set.
638
 *
639
 * \return unsigned long data that has been read
640
 */
641
static unsigned long ulReadMDIO(volatile avr32_macb_t * macb, unsigned short usAddress)
642
{
643
unsigned long value, status;
644
 
645
  // initiate transaction : enable management port
646
  macb->ncr |= AVR32_MACB_NCR_MPE_MASK;
647
  // Write the PHY configuration frame to the MAN register
648
  macb->man = (AVR32_MACB_SOF_MASK & (0x01<<AVR32_MACB_SOF_OFFSET))  // SOF
649
            | (2 << AVR32_MACB_CODE_OFFSET)                          // Code
650
            | (2 << AVR32_MACB_RW_OFFSET)                            // Read operation
651
            | ((ETHERNET_CONF_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET)  // Phy Add
652
            | (usAddress << AVR32_MACB_REGA_OFFSET);                 // Reg Add
653
  // wait for PHY to be ready
654
  do {
655
    status = macb->nsr;
656
  } while (!(status & AVR32_MACB_NSR_IDLE_MASK));
657
  // read the register value in maintenance register
658
  value = macb->man & 0x0000ffff;
659
  // disable management port
660
  macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK;
661
  // return the read value
662
  return (value);
663
}
664
 
665
/*! Write a given value to a register on MDIO bus (access to the PHY)
666
 *         This function is looping until PHY gets ready
667
 *
668
 * \param *macb        Input. instance of the MACB to use
669
 * \param usAddress    Input. register to set.
670
 * \param usValue      Input. value to write.
671
 *
672
 */
673
static void vWriteMDIO(volatile avr32_macb_t * macb, unsigned short usAddress, unsigned short usValue)
674
{
675
unsigned long status;
676
 
677
  // initiate transaction : enable management port
678
  macb->ncr |= AVR32_MACB_NCR_MPE_MASK;
679
  // Write the PHY configuration frame to the MAN register
680
  macb->man = (( AVR32_MACB_SOF_MASK & (0x01<<AVR32_MACB_SOF_OFFSET)) // SOF
681
             | (2 << AVR32_MACB_CODE_OFFSET)                          // Code
682
             | (1 << AVR32_MACB_RW_OFFSET)                            // Write operation
683
             | ((ETHERNET_CONF_PHY_ADDR & 0x1f) << AVR32_MACB_PHYA_OFFSET)  // Phy Add
684
             | (usAddress << AVR32_MACB_REGA_OFFSET))                 // Reg Add
685
             | (usValue & 0xffff);                                    // Data
686
  // wait for PHY to be ready
687
  do {
688
    status = macb->nsr;
689
  } while (!(status & AVR32_MACB_NSR_IDLE_MASK));
690
  // disable management port
691
  macb->ncr &= ~AVR32_MACB_NCR_MPE_MASK;
692
}
693
 
694
static Bool prvProbePHY( volatile avr32_macb_t * macb )
695
{
696
volatile unsigned long mii_status, phy_ctrl;
697
volatile unsigned long config;
698
unsigned long upper, lower, mode, advertise, lpa;
699
volatile unsigned long physID;
700
 
701
  // Read Phy Identifier register 1 & 2
702
  lower = ulReadMDIO(macb, PHY_PHYSID2);
703
  upper = ulReadMDIO(macb, PHY_PHYSID1);
704
  // get Phy ID, ignore Revision
705
  physID = ((upper << 16) & 0xFFFF0000) | (lower & 0xFFF0);
706
  // check if it match config
707
  if (physID == ETHERNET_CONF_PHY_ID)
708
  {
709
    // read RBR
710
    mode = ulReadMDIO(macb, PHY_RBR);
711
    // set RMII mode if not done
712
    if ((mode & RBR_RMII) != RBR_RMII)
713
    {
714
      // force RMII flag if strap options are wrong
715
      mode |= RBR_RMII;
716
      vWriteMDIO(macb, PHY_RBR, mode);
717
    }
718
 
719
    // set advertise register
720
#if ETHERNET_CONF_AN_ENABLE == 1
721
    advertise = ADVERTISE_CSMA | ADVERTISE_ALL;
722
#else
723
    advertise = ADVERTISE_CSMA;
724
    #if ETHERNET_CONF_USE_100MB
725
      #if ETHERNET_CONF_USE_FULL_DUPLEX
726
        advertise |= ADVERTISE_100FULL;
727
      #else
728
        advertise |= ADVERTISE_100HALF;
729
      #endif
730
    #else
731
      #if ETHERNET_CONF_USE_FULL_DUPLEX
732
        advertise |= ADVERTISE_10FULL;
733
      #else
734
        advertise |= ADVERTISE_10HALF;
735
      #endif
736
    #endif
737
#endif
738
    // write advertise register
739
    vWriteMDIO(macb, PHY_ADVERTISE, advertise);
740
    // read Control register
741
    config = ulReadMDIO(macb, PHY_BMCR);
742
    // read Phy Control register
743
    phy_ctrl = ulReadMDIO(macb, PHY_PHYCR);
744
#if ETHERNET_CONF_AN_ENABLE
745
  #if ETHERNET_CONF_AUTO_CROSS_ENABLE
746
    // enable Auto MDIX
747
    phy_ctrl |= PHYCR_MDIX_EN;
748
  #else
749
    // disable Auto MDIX
750
    phy_ctrl &= ~PHYCR_MDIX_EN;
751
    #if ETHERNET_CONF_CROSSED_LINK
752
      // force direct link = Use crossed RJ45 cable
753
      phy_ctrl &= ~PHYCR_MDIX_FORCE;
754
    #else
755
      // force crossed link = Use direct RJ45 cable
756
      phy_ctrl |= PHYCR_MDIX_FORCE;
757
    #endif
758
  #endif
759
  // reset auto-negociation capability
760
  config |= (BMCR_ANRESTART | BMCR_ANENABLE);
761
#else
762
  // disable Auto MDIX
763
  phy_ctrl &= ~PHYCR_MDIX_EN;
764
  #if ETHERNET_CONF_CROSSED_LINK
765
    // force direct link = Use crossed RJ45 cable
766
    phy_ctrl &= ~PHYCR_MDIX_FORCE;
767
  #else
768
    // force crossed link = Use direct RJ45 cable
769
    phy_ctrl |= PHYCR_MDIX_FORCE;
770
  #endif
771
  // clear AN bit
772
  config &= ~BMCR_ANENABLE;
773
 
774
  #if ETHERNET_CONF_USE_100MB
775
    config |= BMCR_SPEED100;
776
  #else
777
    config &= ~BMCR_SPEED100;
778
  #endif
779
  #if ETHERNET_CONF_USE_FULL_DUPLEX
780
    config |= BMCR_FULLDPLX;
781
  #else
782
    config &= ~BMCR_FULLDPLX;
783
  #endif
784
#endif
785
    // update Phy ctrl register
786
    vWriteMDIO(macb, PHY_PHYCR, phy_ctrl);
787
 
788
    // update ctrl register
789
    vWriteMDIO(macb, PHY_BMCR, config);
790
 
791
    // loop while link status isn't OK
792
    do {
793
      mii_status = ulReadMDIO(macb, PHY_BMSR);
794
    } while (!(mii_status & BMSR_LSTATUS));
795
 
796
    // read the LPA configuration of the PHY
797
    lpa = ulReadMDIO(macb, PHY_LPA);
798
 
799
    // read the MACB config register
800
    config = AVR32_MACB.ncfgr;
801
 
802
    // if 100MB needed
803
    if ((lpa & advertise) & (LPA_100HALF | LPA_100FULL))
804
    {
805
      config |= AVR32_MACB_SPD_MASK;
806
    }
807
    else
808
    {
809
      config &= ~(AVR32_MACB_SPD_MASK);
810
    }
811
 
812
    // if FULL DUPLEX needed
813
    if ((lpa & advertise) & (LPA_10FULL | LPA_100FULL))
814
    {
815
      config |= AVR32_MACB_FD_MASK;
816
    }
817
    else
818
    {
819
      config &= ~(AVR32_MACB_FD_MASK);
820
    }
821
 
822
    // write the MACB config register
823
    macb->ncfgr = config;
824
 
825
    return TRUE;
826
  }
827
  return FALSE;
828
}
829
 
830
 
831
void vMACBWaitForInput( unsigned long ulTimeOut )
832
{
833
#ifdef FREERTOS_USED
834
  // Just wait until we are signled from an ISR that data is available, or
835
  // we simply time out.
836
  xSemaphoreTake( xSemaphore, ulTimeOut );
837
#else
838
unsigned long i;
839
  gpio_clr_gpio_pin(LED0_GPIO);
840
  i = ulTimeOut * 1000;
841
  // wait for an interrupt to occurs
842
  do
843
  {
844
    if ( DataToRead == TRUE )
845
    {
846
      // IT occurs, reset interrupt flag
847
      portENTER_CRITICAL();
848
      DataToRead = FALSE;
849
      portEXIT_CRITICAL();
850
      break;
851
    }
852
    i--;
853
  }
854
  while(i != 0);
855
  gpio_set_gpio_pin(LED0_GPIO);
856
#endif
857
}
858
 
859
 
860
/*
861
 * The MACB ISR.  Handles both Tx and Rx complete interrupts.
862
 */
863
#ifdef FREERTOS_USED
864
#if __GNUC__
865
__attribute__((naked))
866
#elif __ICCAVR32__
867
#pragma shadow_registers = full   // Naked.
868
#endif
869
#else
870
#if __GNUC__
871
__attribute__((__interrupt__))
872
#elif __ICCAVR32__
873
__interrupt
874
#endif
875
#endif
876
void vMACB_ISR( void )
877
{
878
  // This ISR can cause a context switch, so the first statement must be a
879
  // call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
880
  // variable declarations. 
881
  portENTER_SWITCHING_ISR();
882
 
883
  // the return value is used by FreeRTOS to change the context if needed after rete instruction
884
  // in standalone use, this value should be ignored 
885
  prvMACB_ISR_NonNakedBehaviour();
886
 
887
  // Exit the ISR.  If a task was woken by either a character being received
888
  // or transmitted then a context switch will occur.
889
  portEXIT_SWITCHING_ISR();
890
}
891
/*-----------------------------------------------------------*/
892
 
893
#if __GNUC__
894
__attribute__((__noinline__))
895
#elif __ICCAVR32__
896
#pragma optimize = no_inline
897
#endif
898
static long prvMACB_ISR_NonNakedBehaviour( void )
899
{
900
 
901
  // Variable definitions can be made now.
902
  volatile unsigned long ulIntStatus, ulEventStatus;
903
  long xHigherPriorityTaskWoken = FALSE;
904
 
905
  // Find the cause of the interrupt.
906
  ulIntStatus = AVR32_MACB.isr;
907
  ulEventStatus = AVR32_MACB.rsr;
908
 
909
  if( ( ulIntStatus & AVR32_MACB_IDR_RCOMP_MASK ) || ( ulEventStatus & AVR32_MACB_REC_MASK ) )
910
  {
911
    // A frame has been received, signal the IP task so it can process
912
    // the Rx descriptors.
913
    portENTER_CRITICAL();
914
#ifdef FREERTOS_USED
915
    xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
916
#else
917
    DataToRead = TRUE;
918
#endif      
919
    portEXIT_CRITICAL();
920
    AVR32_MACB.rsr =  AVR32_MACB_REC_MASK;
921
    AVR32_MACB.rsr;
922
  }
923
 
924
  if( ulIntStatus & AVR32_MACB_TCOMP_MASK )
925
  {
926
    // A frame has been transmitted.  Mark all the buffers used by the
927
    // frame just transmitted as free again.
928
    vClearMACBTxBuffer();
929
    AVR32_MACB.tsr =  AVR32_MACB_TSR_COMP_MASK;
930
    AVR32_MACB.tsr;
931
  }
932
 
933
  return ( xHigherPriorityTaskWoken );
934
}
935
 
936
 
937
 
938
#if ETHERNET_CONF_USE_PHY_IT
939
/*
940
 * The PHY ISR.  Handles Phy interrupts.
941
 */
942
#ifdef FREERTOS_USED
943
#if __GNUC__
944
__attribute__((naked))
945
#elif __ICCAVR32__
946
#pragma shadow_registers = full   // Naked.
947
#endif
948
#else
949
#if __GNUC__
950
__attribute__((__interrupt__))
951
#elif __ICCAVR32__
952
__interrupt
953
#endif
954
#endif
955
void vPHY_ISR( void )
956
{
957
  // This ISR can cause a context switch, so the first statement must be a
958
  // call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
959
  // variable declarations. 
960
  portENTER_SWITCHING_ISR();
961
 
962
  // the return value is used by FreeRTOS to change the context if needed after rete instruction
963
  // in standalone use, this value should be ignored 
964
  prvPHY_ISR_NonNakedBehaviour();
965
 
966
  // Exit the ISR.  If a task was woken by either a character being received
967
  // or transmitted then a context switch will occur.
968
  portEXIT_SWITCHING_ISR();
969
}
970
/*-----------------------------------------------------------*/
971
 
972
#if __GNUC__
973
__attribute__((__noinline__))
974
#elif __ICCAVR32__
975
#pragma optimize = no_inline
976
#endif
977
static long prvPHY_ISR_NonNakedBehaviour( void )
978
{
979
 
980
  // Variable definitions can be made now.
981
  volatile unsigned long ulIntStatus, ulEventStatus;
982
  long xSwitchRequired = FALSE;
983
  volatile avr32_gpio_t *gpio = &AVR32_GPIO;
984
  volatile avr32_gpio_port_t *gpio_port = &gpio->port[MACB_INTERRUPT_PIN/32];
985
 
986
  // read Phy Interrupt register Status
987
  ulIntStatus = ulReadMDIO(&AVR32_MACB, PHY_MISR);
988
 
989
  // read Phy status register
990
  ulEventStatus = ulReadMDIO(&AVR32_MACB, PHY_BMSR);
991
  // dummy read
992
  ulEventStatus = ulReadMDIO(&AVR32_MACB, PHY_BMSR);
993
 
994
   // clear interrupt flag on GPIO
995
  gpio_port->ifrc =  1 << (MACB_INTERRUPT_PIN%32);
996
 
997
  return ( xSwitchRequired );
998
}
999
#endif

powered by: WebSVN 2.1.0

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