2 FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\r
9 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
10 the terms of the GNU General Public License (version 2) as published by the
\r
11 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
13 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
71 * Basic interrupt driven driver for the EMAC peripheral. This driver is not
\r
72 * reentrant as with uIP the buffers are only ever accessed from a single task.
\r
74 * The simple buffer management used within uIP allows the EMAC driver to also
\r
75 * be simplistic. The driver contained within the lwIP demo is more
\r
83 + Corrected the byte order when writing the MAC address to the MAC.
\r
84 + Support added for MII interfaces. Previously only RMII was supported.
\r
88 + The MII interface is now the default.
\r
89 + Modified the initialisation sequence slightly to allow auto init more
\r
94 + Also read the EMAC_RSR register in the EMAC ISR as a work around the
\r
95 the EMAC bug that can reset the RX bit in EMAC_ISR register before the
\r
100 + Corrected the Rx frame length mask when obtaining the length from the
\r
105 /* Standard includes. */
\r
106 #include <string.h>
\r
108 /* Scheduler includes. */
\r
109 #include "FreeRTOS.h"
\r
110 #include "semphr.h"
\r
113 /* uIP includes. */
\r
116 /* Hardware specific includes. */
\r
121 /* USE_RMII_INTERFACE must be defined as 1 to use an RMII interface, or 0
\r
122 to use an MII interface. */
\r
123 #define USE_RMII_INTERFACE 0
\r
125 /* The buffer addresses written into the descriptors must be aligned so the
\r
126 last few bits are zero. These bits have special meaning for the EMAC
\r
127 peripheral and cannot be used as part of the address. */
\r
128 #define emacADDRESS_MASK ( ( unsigned long ) 0xFFFFFFFC )
\r
130 /* Bit used within the address stored in the descriptor to mark the last
\r
131 descriptor in the array. */
\r
132 #define emacRX_WRAP_BIT ( ( unsigned long ) 0x02 )
\r
134 /* Bit used within the Tx descriptor status to indicate whether the
\r
135 descriptor is under the control of the EMAC or the software. */
\r
136 #define emacTX_BUF_USED ( ( unsigned long ) 0x80000000 )
\r
138 /* A short delay is used to wait for a buffer to become available, should
\r
139 one not be immediately available when trying to transmit a frame. */
\r
140 #define emacBUFFER_WAIT_DELAY ( 2 )
\r
141 #define emacMAX_WAIT_CYCLES ( configTICK_RATE_HZ / 40 )
\r
143 /* Misc defines. */
\r
144 #define emacINTERRUPT_LEVEL ( 5 )
\r
145 #define emacNO_DELAY ( 0 )
\r
146 #define emacTOTAL_FRAME_HEADER_SIZE ( 54 )
\r
147 #define emacPHY_INIT_DELAY ( 5000 / portTICK_PERIOD_MS )
\r
148 #define emacRESET_KEY ( ( unsigned long ) 0xA5000000 )
\r
149 #define emacRESET_LENGTH ( ( unsigned long ) ( 0x01 << 8 ) )
\r
151 /* The Atmel header file only defines the TX frame length mask. */
\r
152 #define emacRX_LENGTH_FRAME ( 0xfff )
\r
154 /*-----------------------------------------------------------*/
\r
157 * Prototype for the EMAC interrupt asm wrapper.
\r
159 extern void vEMACISREntry( void );
\r
162 * Prototype for the EMAC interrupt function - called by the asm wrapper.
\r
164 __arm void vEMACISR( void );
\r
167 * Initialise both the Tx and Rx descriptors used by the EMAC.
\r
169 static void prvSetupDescriptors(void);
\r
172 * Write our MAC address into the EMAC. The MAC address is set as one of the
\r
175 static void prvSetupMACAddress( void );
\r
178 * Configure the EMAC and AIC for EMAC interrupts.
\r
180 static void prvSetupEMACInterrupt( void );
\r
183 * Some initialisation functions taken from the Atmel EMAC sample code.
\r
185 static void vReadPHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long *pulValue );
\r
186 #if USE_RMII_INTERFACE != 1
\r
187 static void vWritePHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long ulValue);
\r
189 static portBASE_TYPE xGetLinkSpeed( void );
\r
190 static portBASE_TYPE prvProbePHY( void );
\r
192 /*-----------------------------------------------------------*/
\r
194 /* Buffer written to by the EMAC DMA. Must be aligned as described by the
\r
195 comment above the emacADDRESS_MASK definition. */
\r
196 #pragma data_alignment=8
\r
197 static volatile char pcRxBuffer[ NB_RX_BUFFERS * ETH_RX_BUFFER_SIZE ];
\r
199 /* Buffer read by the EMAC DMA. Must be aligned as described by he comment
\r
200 above the emacADDRESS_MASK definition. */
\r
201 #pragma data_alignment=8
\r
202 static char pcTxBuffer[ NB_TX_BUFFERS * ETH_TX_BUFFER_SIZE ];
\r
204 /* Descriptors used to communicate between the program and the EMAC peripheral.
\r
205 These descriptors hold the locations and state of the Rx and Tx buffers. */
\r
206 static volatile AT91S_TxTdDescriptor xTxDescriptors[ NB_TX_BUFFERS ];
\r
207 static volatile AT91S_RxTdDescriptor xRxDescriptors[ NB_RX_BUFFERS ];
\r
209 /* The IP and Ethernet addresses are read from the uIP setup. */
\r
210 const char cMACAddress[ 6 ] = { UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5 };
\r
211 const unsigned char ucIPAddress[ 4 ] = { UIP_IPADDR0, UIP_IPADDR1, UIP_IPADDR2, UIP_IPADDR3 };
\r
213 /* The semaphore used by the EMAC ISR to wake the EMAC task. */
\r
214 static SemaphoreHandle_t xSemaphore = NULL;
\r
216 /*-----------------------------------------------------------*/
\r
218 SemaphoreHandle_t xEMACInit( void )
\r
220 /* Code supplied by Atmel (modified) --------------------*/
\r
222 /* disable pull up on RXDV => PHY normal mode (not in test mode),
\r
223 PHY has internal pull down. */
\r
224 AT91C_BASE_PIOB->PIO_PPUDR = 1 << 15;
\r
226 #if USE_RMII_INTERFACE != 1
\r
227 /* PHY has internal pull down : set MII mode. */
\r
228 AT91C_BASE_PIOB->PIO_PPUDR= 1 << 16;
\r
231 /* clear PB18 <=> PHY powerdown. */
\r
232 AT91F_PIO_CfgOutput( AT91C_BASE_PIOB, 1 << 18 ) ;
\r
233 AT91F_PIO_ClearOutput( AT91C_BASE_PIOB, 1 << 18) ;
\r
235 /* After PHY power up, hardware reset. */
\r
236 AT91C_BASE_RSTC->RSTC_RMR = emacRESET_KEY | emacRESET_LENGTH;
\r
237 AT91C_BASE_RSTC->RSTC_RCR = emacRESET_KEY | AT91C_RSTC_EXTRST;
\r
239 /* Wait for hardware reset end. */
\r
240 while( !( AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL ) )
\r
246 /* EMAC IO init for EMAC-PHY com. Remove EF100 config. */
\r
247 AT91F_EMAC_CfgPIO();
\r
249 /* Enable com between EMAC PHY.
\r
251 Enable management port. */
\r
252 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
\r
254 /* MDC = MCK/32. */
\r
255 AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
\r
257 /* Wait for PHY auto init end (rather crude delay!). */
\r
258 vTaskDelay( emacPHY_INIT_DELAY );
\r
260 /* PHY configuration. */
\r
261 #if USE_RMII_INTERFACE != 1
\r
263 unsigned long ulControl;
\r
265 /* PHY has internal pull down : disable MII isolate. */
\r
266 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
\r
267 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
\r
268 ulControl &= ~BMCR_ISOLATE;
\r
269 vWritePHY( AT91C_PHY_ADDR, MII_BMCR, ulControl );
\r
273 /* Disable management port again. */
\r
274 AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
\r
276 #if USE_RMII_INTERFACE != 1
\r
277 /* Enable EMAC in MII mode, enable clock ERXCK and ETXCK. */
\r
278 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN ;
\r
280 /* Enable EMAC in RMII mode, enable RMII clock (50MHz from oscillator
\r
282 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_RMII | AT91C_EMAC_CLKEN ;
\r
285 /* End of code supplied by Atmel ------------------------*/
\r
287 /* Setup the buffers and descriptors. */
\r
288 prvSetupDescriptors();
\r
290 /* Load our MAC address into the EMAC. */
\r
291 prvSetupMACAddress();
\r
293 /* Try to connect. */
\r
294 if( prvProbePHY() )
\r
296 /* Enable the interrupt! */
\r
297 prvSetupEMACInterrupt();
\r
302 /*-----------------------------------------------------------*/
\r
304 long lEMACSend( void )
\r
306 static unsigned portBASE_TYPE uxTxBufferIndex = 0;
\r
307 portBASE_TYPE xWaitCycles = 0;
\r
308 long lReturn = pdPASS;
\r
311 /* Is a buffer available? */
\r
312 while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AT91C_TRANSMIT_OK ) )
\r
314 /* There is no room to write the Tx data to the Tx buffer. Wait a
\r
315 short while, then try again. */
\r
317 if( xWaitCycles > emacMAX_WAIT_CYCLES )
\r
325 vTaskDelay( emacBUFFER_WAIT_DELAY );
\r
329 /* lReturn will only be pdPASS if a buffer is available. */
\r
330 if( lReturn == pdPASS )
\r
332 /* Copy the headers into the Tx buffer. These will be in the uIP buffer. */
\r
333 pcBuffer = ( char * ) xTxDescriptors[ uxTxBufferIndex ].addr;
\r
334 memcpy( ( void * ) pcBuffer, ( void * ) uip_buf, emacTOTAL_FRAME_HEADER_SIZE );
\r
335 if( uip_len > emacTOTAL_FRAME_HEADER_SIZE )
\r
337 memcpy( ( void * ) &( pcBuffer[ emacTOTAL_FRAME_HEADER_SIZE ] ), ( void * ) uip_appdata, ( uip_len - emacTOTAL_FRAME_HEADER_SIZE ) );
\r
341 portENTER_CRITICAL();
\r
343 if( uxTxBufferIndex >= ( NB_TX_BUFFERS - 1 ) )
\r
345 /* Fill out the necessary in the descriptor to get the data sent. */
\r
346 xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( uip_len & ( unsigned long ) AT91C_LENGTH_FRAME )
\r
347 | AT91C_LAST_BUFFER
\r
348 | AT91C_TRANSMIT_WRAP;
\r
349 uxTxBufferIndex = 0;
\r
353 /* Fill out the necessary in the descriptor to get the data sent. */
\r
354 xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( uip_len & ( unsigned long ) AT91C_LENGTH_FRAME )
\r
355 | AT91C_LAST_BUFFER;
\r
359 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
\r
361 portEXIT_CRITICAL();
\r
366 /*-----------------------------------------------------------*/
\r
368 unsigned long ulEMACPoll( void )
\r
370 static unsigned portBASE_TYPE ulNextRxBuffer = 0;
\r
371 unsigned long ulSectionLength = 0, ulLengthSoFar = 0, ulEOF = pdFALSE;
\r
374 /* Skip any fragments. */
\r
375 while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_SOF ) )
\r
377 /* Mark the buffer as free again. */
\r
378 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
\r
380 if( ulNextRxBuffer >= NB_RX_BUFFERS )
\r
382 ulNextRxBuffer = 0;
\r
386 /* Is there a packet ready? */
\r
388 while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !ulSectionLength )
\r
390 pcSource = ( char * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
\r
391 ulSectionLength = xRxDescriptors[ ulNextRxBuffer ].U_Status.status & emacRX_LENGTH_FRAME;
\r
393 if( ulSectionLength == 0 )
\r
395 /* The frame is longer than the buffer pointed to by this
\r
396 descriptor so copy the entire buffer to uIP - then move onto
\r
397 the next descriptor to get the rest of the frame. */
\r
398 if( ( ulLengthSoFar + ETH_RX_BUFFER_SIZE ) <= UIP_BUFSIZE )
\r
400 memcpy( &( uip_buf[ ulLengthSoFar ] ), pcSource, ETH_RX_BUFFER_SIZE );
\r
401 ulLengthSoFar += ETH_RX_BUFFER_SIZE;
\r
406 /* This is the last section of the frame. Copy the section to
\r
408 if( ulSectionLength < UIP_BUFSIZE )
\r
410 /* The section length holds the length of the entire frame.
\r
411 ulLengthSoFar holds the length of the frame sections already
\r
412 copied to uIP, so the length of the final section is
\r
413 ulSectionLength - ulLengthSoFar; */
\r
414 if( ulSectionLength > ulLengthSoFar )
\r
416 memcpy( &( uip_buf[ ulLengthSoFar ] ), pcSource, ( ulSectionLength - ulLengthSoFar ) );
\r
420 /* Is this the last buffer for the frame? If not why? */
\r
421 ulEOF = xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_EOF;
\r
424 /* Mark the buffer as free again. */
\r
425 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
\r
427 /* Increment to the next buffer, wrapping if necessary. */
\r
429 if( ulNextRxBuffer >= NB_RX_BUFFERS )
\r
431 ulNextRxBuffer = 0;
\r
435 /* If we obtained data but for some reason did not find the end of the
\r
436 frame then discard the data as it must contain an error. */
\r
439 ulSectionLength = 0;
\r
442 return ulSectionLength;
\r
444 /*-----------------------------------------------------------*/
\r
446 static void prvSetupDescriptors(void)
\r
448 unsigned portBASE_TYPE xIndex;
\r
449 unsigned long ulAddress;
\r
451 /* Initialise xRxDescriptors descriptor. */
\r
452 for( xIndex = 0; xIndex < NB_RX_BUFFERS; ++xIndex )
\r
454 /* Calculate the address of the nth buffer within the array. */
\r
455 ulAddress = ( unsigned long )( pcRxBuffer + ( xIndex * ETH_RX_BUFFER_SIZE ) );
\r
457 /* Write the buffer address into the descriptor. The DMA will place
\r
458 the data at this address when this descriptor is being used. Mask off
\r
459 the bottom bits of the address as these have special meaning. */
\r
460 xRxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
\r
463 /* The last buffer has the wrap bit set so the EMAC knows to wrap back
\r
464 to the first buffer. */
\r
465 xRxDescriptors[ NB_RX_BUFFERS - 1 ].addr |= emacRX_WRAP_BIT;
\r
467 /* Initialise xTxDescriptors. */
\r
468 for( xIndex = 0; xIndex < NB_TX_BUFFERS; ++xIndex )
\r
470 /* Calculate the address of the nth buffer within the array. */
\r
471 ulAddress = ( unsigned long )( pcTxBuffer + ( xIndex * ETH_TX_BUFFER_SIZE ) );
\r
473 /* Write the buffer address into the descriptor. The DMA will read
\r
474 data from here when the descriptor is being used. */
\r
475 xTxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
\r
476 xTxDescriptors[ xIndex ].U_Status.status = AT91C_TRANSMIT_OK;
\r
479 /* The last buffer has the wrap bit set so the EMAC knows to wrap back
\r
480 to the first buffer. */
\r
481 xTxDescriptors[ NB_TX_BUFFERS - 1 ].U_Status.status = AT91C_TRANSMIT_WRAP | AT91C_TRANSMIT_OK;
\r
483 /* Tell the EMAC where to find the descriptors. */
\r
484 AT91C_BASE_EMAC->EMAC_RBQP = ( unsigned long ) xRxDescriptors;
\r
485 AT91C_BASE_EMAC->EMAC_TBQP = ( unsigned long ) xTxDescriptors;
\r
487 /* Clear all the bits in the receive status register. */
\r
488 AT91C_BASE_EMAC->EMAC_RSR = ( AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA );
\r
490 /* Enable the copy of data into the buffers, ignore broadcasts,
\r
491 and don't copy FCS. */
\r
492 AT91C_BASE_EMAC->EMAC_NCFGR |= ( AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS);
\r
494 /* Enable Rx and Tx, plus the stats register. */
\r
495 AT91C_BASE_EMAC->EMAC_NCR |= ( AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT );
\r
497 /*-----------------------------------------------------------*/
\r
499 static void prvSetupMACAddress( void )
\r
501 /* Must be written SA1L then SA1H. */
\r
502 AT91C_BASE_EMAC->EMAC_SA1L = ( ( unsigned long ) cMACAddress[ 3 ] << 24 ) |
\r
503 ( ( unsigned long ) cMACAddress[ 2 ] << 16 ) |
\r
504 ( ( unsigned long ) cMACAddress[ 1 ] << 8 ) |
\r
507 AT91C_BASE_EMAC->EMAC_SA1H = ( ( unsigned long ) cMACAddress[ 5 ] << 8 ) |
\r
510 /*-----------------------------------------------------------*/
\r
512 static void prvSetupEMACInterrupt( void )
\r
514 /* Create the semaphore used to trigger the EMAC task. */
\r
515 vSemaphoreCreateBinary( xSemaphore );
\r
518 /* We start by 'taking' the semaphore so the ISR can 'give' it when the
\r
519 first interrupt occurs. */
\r
520 xSemaphoreTake( xSemaphore, emacNO_DELAY );
\r
521 portENTER_CRITICAL();
\r
523 /* We want to interrupt on Rx events. */
\r
524 AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP;
\r
526 /* Enable the interrupts in the AIC. */
\r
527 AT91F_AIC_ConfigureIt( AT91C_BASE_AIC, AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISREntry );
\r
528 AT91F_AIC_EnableIt( AT91C_BASE_AIC, AT91C_ID_EMAC );
\r
530 portEXIT_CRITICAL();
\r
533 /*-----------------------------------------------------------*/
\r
535 __arm void vEMACISR( void )
\r
537 volatile unsigned long ulIntStatus, ulRxStatus;
\r
538 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
540 ulIntStatus = AT91C_BASE_EMAC->EMAC_ISR;
\r
541 ulRxStatus = AT91C_BASE_EMAC->EMAC_RSR;
\r
543 if( ( ulIntStatus & AT91C_EMAC_RCOMP ) || ( ulRxStatus & AT91C_EMAC_REC ) )
\r
545 /* A frame has been received, signal the uIP task so it can process
\r
546 the Rx descriptors. */
\r
547 xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
\r
548 AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_REC;
\r
551 /* If a task was woken by either a character being received or a character
\r
552 being transmitted then we may need to switch to another task. */
\r
553 portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
\r
555 /* Clear the interrupt. */
\r
556 AT91C_BASE_AIC->AIC_EOICR = 0;
\r
558 /*-----------------------------------------------------------*/
\r
563 * The following functions are initialisation functions taken from the Atmel
\r
564 * EMAC sample code.
\r
567 static portBASE_TYPE prvProbePHY( void )
\r
569 unsigned long ulPHYId1, ulPHYId2, ulStatus;
\r
570 portBASE_TYPE xReturn = pdPASS;
\r
572 /* Code supplied by Atmel (reformatted) -----------------*/
\r
574 /* Enable management port */
\r
575 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
\r
576 AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
\r
578 /* Read the PHY ID. */
\r
579 vReadPHY( AT91C_PHY_ADDR, MII_PHYSID1, &ulPHYId1 );
\r
580 vReadPHY( AT91C_PHY_ADDR, MII_PHYSID2, &ulPHYId2 );
\r
585 Bits 3:0 Revision Number Four bit manufacturer
\92s revision number.
\r
586 0001 stands for Rev. A, etc.
\r
588 if( ( ( ulPHYId1 << 16 ) | ( ulPHYId2 & 0xfff0 ) ) != MII_DM9161_ID )
\r
590 /* Did not expect this ID. */
\r
595 ulStatus = xGetLinkSpeed();
\r
597 if( ulStatus != pdPASS )
\r
603 /* Disable management port */
\r
604 AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
\r
606 /* End of code supplied by Atmel ------------------------*/
\r
610 /*-----------------------------------------------------------*/
\r
612 static void vReadPHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long *pulValue )
\r
614 /* Code supplied by Atmel (reformatted) ----------------------*/
\r
616 AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01<<30))
\r
617 | (2 << 16) | (2 << 28)
\r
618 | ((ucPHYAddress & 0x1f) << 23)
\r
619 | (ucAddress << 18);
\r
621 /* Wait until IDLE bit in Network Status register is cleared. */
\r
622 while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
\r
627 *pulValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff );
\r
629 /* End of code supplied by Atmel ------------------------*/
\r
631 /*-----------------------------------------------------------*/
\r
633 #if USE_RMII_INTERFACE != 1
\r
634 static void vWritePHY( unsigned char ucPHYAddress, unsigned char ucAddress, unsigned long ulValue )
\r
636 /* Code supplied by Atmel (reformatted) ----------------------*/
\r
638 AT91C_BASE_EMAC->EMAC_MAN = (( AT91C_EMAC_SOF & (0x01<<30))
\r
639 | (2 << 16) | (1 << 28)
\r
640 | ((ucPHYAddress & 0x1f) << 23)
\r
641 | (ucAddress << 18))
\r
642 | (ulValue & 0xffff);
\r
644 /* Wait until IDLE bit in Network Status register is cleared */
\r
645 while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
\r
650 /* End of code supplied by Atmel ------------------------*/
\r
653 /*-----------------------------------------------------------*/
\r
655 static portBASE_TYPE xGetLinkSpeed( void )
\r
657 unsigned long ulBMSR, ulBMCR, ulLPA, ulMACCfg, ulSpeed, ulDuplex;
\r
659 /* Code supplied by Atmel (reformatted) -----------------*/
\r
661 /* Link status is latched, so read twice to get current value */
\r
662 vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
\r
663 vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
\r
665 if( !( ulBMSR & BMSR_LSTATUS ) )
\r
671 vReadPHY(AT91C_PHY_ADDR, MII_BMCR, &ulBMCR);
\r
672 if (ulBMCR & BMCR_ANENABLE)
\r
674 /* AutoNegotiation is enabled. */
\r
675 if (!(ulBMSR & BMSR_ANEGCOMPLETE))
\r
677 /* Auto-negotiation in progress. */
\r
681 vReadPHY(AT91C_PHY_ADDR, MII_LPA, &ulLPA);
\r
682 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_100HALF ) )
\r
684 ulSpeed = SPEED_100;
\r
688 ulSpeed = SPEED_10;
\r
691 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_10FULL ) )
\r
693 ulDuplex = DUPLEX_FULL;
\r
697 ulDuplex = DUPLEX_HALF;
\r
702 ulSpeed = ( ulBMCR & BMCR_SPEED100 ) ? SPEED_100 : SPEED_10;
\r
703 ulDuplex = ( ulBMCR & BMCR_FULLDPLX ) ? DUPLEX_FULL : DUPLEX_HALF;
\r
706 /* Update the MAC */
\r
707 ulMACCfg = AT91C_BASE_EMAC->EMAC_NCFGR & ~( AT91C_EMAC_SPD | AT91C_EMAC_FD );
\r
708 if( ulSpeed == SPEED_100 )
\r
710 if( ulDuplex == DUPLEX_FULL )
\r
712 /* 100 Full Duplex */
\r
713 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;
\r
717 /* 100 Half Duplex */
\r
718 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD;
\r
723 if (ulDuplex == DUPLEX_FULL)
\r
725 /* 10 Full Duplex */
\r
726 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_FD;
\r
730 /* 10 Half Duplex */
\r
731 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg;
\r
735 /* End of code supplied by Atmel ------------------------*/
\r