2 FreeRTOS.org V4.8.0 - Copyright (C) 2003-2008 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 ***************************************************************************
\r
29 * SAVE TIME AND MONEY! Why not get us to quote to get FreeRTOS.org *
\r
30 * running on your hardware - or even write all or part of your application*
\r
31 * for you? See http://www.OpenRTOS.com for details. *
\r
33 ***************************************************************************
\r
34 ***************************************************************************
\r
36 Please ensure to read the configuration and relevant port sections of the
\r
37 online documentation.
\r
39 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
42 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
45 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
46 licensing and training services.
\r
49 /* Standard includes. */
\r
52 /* Scheduler includes. */
\r
53 #include "FreeRTOS.h"
\r
57 /* Demo application includes. */
\r
58 #include "SAM7_EMAC.h"
\r
63 /* Hardware specific includes. */
\r
66 #include "AT91SAM7X256.h"
\r
69 /* USE_RMII_INTERFACE must be defined as 1 to use an RMII interface, or 0
\r
70 to use an MII interface. */
\r
71 #define USE_RMII_INTERFACE 0
\r
73 /* The buffer addresses written into the descriptors must be aligned so the
\r
74 last few bits are zero. These bits have special meaning for the EMAC
\r
75 peripheral and cannot be used as part of the address. */
\r
76 #define emacADDRESS_MASK ( ( unsigned portLONG ) 0xFFFFFFFC )
\r
78 /* Bit used within the address stored in the descriptor to mark the last
\r
79 descriptor in the array. */
\r
80 #define emacRX_WRAP_BIT ( ( unsigned portLONG ) 0x02 )
\r
82 /* Bit used within the Tx descriptor status to indicate whether the
\r
83 descriptor is under the control of the EMAC or the software. */
\r
84 #define emacTX_BUF_USED ( ( unsigned portLONG ) 0x80000000 )
\r
86 /* A short delay is used to wait for a buffer to become available, should
\r
87 one not be immediately available when trying to transmit a frame. */
\r
88 #define emacBUFFER_WAIT_DELAY ( 2 )
\r
89 #define emacMAX_WAIT_CYCLES ( configTICK_RATE_HZ / 40 )
\r
92 #define emacINTERRUPT_LEVEL ( 5 )
\r
93 #define emacNO_DELAY ( 0 )
\r
94 #define emacTOTAL_FRAME_HEADER_SIZE ( 54 )
\r
95 #define emacPHY_INIT_DELAY ( 5000 / portTICK_RATE_MS )
\r
96 #define emacRESET_KEY ( ( unsigned portLONG ) 0xA5000000 )
\r
97 #define emacRESET_LENGTH ( ( unsigned portLONG ) ( 0x01 << 8 ) )
\r
99 /* The Atmel header file only defines the TX frame length mask. */
\r
100 #define emacRX_LENGTH_FRAME ( 0xfff )
\r
102 /* Peripheral setup for the EMAC. */
\r
103 #define emacPERIPHERAL_A_SETUP ( ( unsigned portLONG ) AT91C_PB2_ETX0 ) | \
\r
104 ( ( unsigned portLONG ) AT91C_PB12_ETXER ) | \
\r
105 ( ( unsigned portLONG ) AT91C_PB16_ECOL ) | \
\r
106 ( ( unsigned portLONG ) AT91C_PB11_ETX3 ) | \
\r
107 ( ( unsigned portLONG ) AT91C_PB6_ERX1 ) | \
\r
108 ( ( unsigned portLONG ) AT91C_PB15_ERXDV ) | \
\r
109 ( ( unsigned portLONG ) AT91C_PB13_ERX2 ) | \
\r
110 ( ( unsigned portLONG ) AT91C_PB3_ETX1 ) | \
\r
111 ( ( unsigned portLONG ) AT91C_PB8_EMDC ) | \
\r
112 ( ( unsigned portLONG ) AT91C_PB5_ERX0 ) | \
\r
113 ( ( unsigned portLONG ) AT91C_PB14_ERX3 ) | \
\r
114 ( ( unsigned portLONG ) AT91C_PB4_ECRS_ECRSDV ) | \
\r
115 ( ( unsigned portLONG ) AT91C_PB1_ETXEN ) | \
\r
116 ( ( unsigned portLONG ) AT91C_PB10_ETX2 ) | \
\r
117 ( ( unsigned portLONG ) AT91C_PB0_ETXCK_EREFCK ) | \
\r
118 ( ( unsigned portLONG ) AT91C_PB9_EMDIO ) | \
\r
119 ( ( unsigned portLONG ) AT91C_PB7_ERXER ) | \
\r
120 ( ( unsigned portLONG ) AT91C_PB17_ERXCK );
\r
122 /*-----------------------------------------------------------*/
\r
125 * Prototype for the EMAC interrupt function - called by the asm wrapper.
\r
127 extern void vEMACISR_Wrapper( void ) __attribute__((naked));
\r
130 * Initialise both the Tx and Rx descriptors used by the EMAC.
\r
132 static void prvSetupDescriptors(void);
\r
135 * Write our MAC address into the EMAC. The MAC address is set as one of the
\r
138 static void prvSetupMACAddress( void );
\r
141 * Configure the EMAC and AIC for EMAC interrupts.
\r
143 static void prvSetupEMACInterrupt( void );
\r
146 * Some initialisation functions taken from the Atmel EMAC sample code.
\r
148 static void vReadPHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG *pulValue );
\r
149 #if USE_RMII_INTERFACE != 1
\r
150 static void vWritePHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG ulValue);
\r
152 static portBASE_TYPE xGetLinkSpeed( void );
\r
153 static portBASE_TYPE prvProbePHY( void );
\r
155 /*-----------------------------------------------------------*/
\r
157 /* Buffer written to by the EMAC DMA. Must be aligned as described by the
\r
158 comment above the emacADDRESS_MASK definition. */
\r
159 #pragma data_alignment=8
\r
160 static volatile portCHAR pcRxBuffer[ NB_RX_BUFFERS * ETH_RX_BUFFER_SIZE ];
\r
162 /* Buffer read by the EMAC DMA. Must be aligned as described by he comment
\r
163 above the emacADDRESS_MASK definition. */
\r
164 #pragma data_alignment=8
\r
165 static portCHAR pcTxBuffer[ NB_TX_BUFFERS * ETH_TX_BUFFER_SIZE ];
\r
167 /* Descriptors used to communicate between the program and the EMAC peripheral.
\r
168 These descriptors hold the locations and state of the Rx and Tx buffers. */
\r
169 static volatile AT91S_TxTdDescriptor xTxDescriptors[ NB_TX_BUFFERS ];
\r
170 static volatile AT91S_RxTdDescriptor xRxDescriptors[ NB_RX_BUFFERS ];
\r
172 /* The IP and Ethernet addresses are read from the uIP setup. */
\r
173 const portCHAR cMACAddress[ 6 ] = { uipMAC_ADDR0, uipMAC_ADDR1, uipMAC_ADDR2, uipMAC_ADDR3, uipMAC_ADDR4, uipMAC_ADDR5 };
\r
174 const unsigned char ucIPAddress[ 4 ] = { uipIP_ADDR0, uipIP_ADDR1, uipIP_ADDR2, uipIP_ADDR3 };
\r
176 /* The semaphore used by the EMAC ISR to wake the EMAC task. */
\r
177 static xSemaphoreHandle xSemaphore = NULL;
\r
179 /*-----------------------------------------------------------*/
\r
181 xSemaphoreHandle xEMACInit( void )
\r
183 /* Code supplied by Atmel -------------------------------*/
\r
185 /* Disable pull up on RXDV => PHY normal mode (not in test mode),
\r
186 PHY has internal pull down. */
\r
187 AT91C_BASE_PIOB->PIO_PPUDR = 1 << 15;
\r
189 #if USE_RMII_INTERFACE != 1
\r
190 /* PHY has internal pull down : set MII mode. */
\r
191 AT91C_BASE_PIOB->PIO_PPUDR = 1 << 16;
\r
194 /* Clear PB18 <=> PHY powerdown. */
\r
195 AT91C_BASE_PIOB->PIO_PER = 1 << 18;
\r
196 AT91C_BASE_PIOB->PIO_OER = 1 << 18;
\r
197 AT91C_BASE_PIOB->PIO_CODR = 1 << 18;
\r
199 /* After PHY power up, hardware reset. */
\r
200 AT91C_BASE_RSTC->RSTC_RMR = emacRESET_KEY | emacRESET_LENGTH;
\r
201 AT91C_BASE_RSTC->RSTC_RCR = emacRESET_KEY | AT91C_RSTC_EXTRST;
\r
203 /* Wait for hardware reset end. */
\r
204 while( !( AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL ) )
\r
206 __asm volatile ( "NOP" );
\r
208 __asm volatile ( "NOP" );
\r
210 /* Setup the pins. */
\r
211 AT91C_BASE_PIOB->PIO_ASR = emacPERIPHERAL_A_SETUP;
\r
212 AT91C_BASE_PIOB->PIO_PDR = emacPERIPHERAL_A_SETUP;
\r
214 /* Enable com between EMAC PHY.
\r
216 Enable management port. */
\r
217 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
\r
219 /* MDC = MCK/32. */
\r
220 AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
\r
222 /* Wait for PHY auto init end (rather crude delay!). */
\r
223 vTaskDelay( emacPHY_INIT_DELAY );
\r
225 /* PHY configuration. */
\r
226 #if USE_RMII_INTERFACE != 1
\r
228 unsigned portLONG ulControl;
\r
230 /* PHY has internal pull down : disable MII isolate. */
\r
231 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
\r
232 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl );
\r
233 ulControl &= ~BMCR_ISOLATE;
\r
234 vWritePHY( AT91C_PHY_ADDR, MII_BMCR, ulControl );
\r
238 /* Disable management port again. */
\r
239 AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
\r
241 #if USE_RMII_INTERFACE != 1
\r
242 /* Enable EMAC in MII mode, enable clock ERXCK and ETXCK. */
\r
243 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN ;
\r
245 /* Enable EMAC in RMII mode, enable RMII clock (50MHz from oscillator
\r
247 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_RMII | AT91C_EMAC_CLKEN ;
\r
250 /* End of code supplied by Atmel ------------------------*/
\r
252 /* Setup the buffers and descriptors. */
\r
253 prvSetupDescriptors();
\r
255 /* Load our MAC address into the EMAC. */
\r
256 prvSetupMACAddress();
\r
258 /* Are we connected? */
\r
259 if( prvProbePHY() )
\r
261 /* Enable the interrupt! */
\r
262 portENTER_CRITICAL();
\r
264 prvSetupEMACInterrupt();
\r
265 vPassEMACSemaphore( xSemaphore );
\r
267 portEXIT_CRITICAL();
\r
272 /*-----------------------------------------------------------*/
\r
274 portLONG lEMACSend( void )
\r
276 static unsigned portBASE_TYPE uxTxBufferIndex = 0;
\r
277 portBASE_TYPE xWaitCycles = 0;
\r
278 portLONG lReturn = pdPASS;
\r
279 portCHAR *pcBuffer;
\r
281 /* Is a buffer available? */
\r
282 while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AT91C_TRANSMIT_OK ) )
\r
284 /* There is no room to write the Tx data to the Tx buffer. Wait a
\r
285 short while, then try again. */
\r
287 if( xWaitCycles > emacMAX_WAIT_CYCLES )
\r
295 vTaskDelay( emacBUFFER_WAIT_DELAY );
\r
299 /* lReturn will only be pdPASS if a buffer is available. */
\r
300 if( lReturn == pdPASS )
\r
302 /* Copy the headers into the Tx buffer. These will be in the uIP buffer. */
\r
303 pcBuffer = ( portCHAR * ) xTxDescriptors[ uxTxBufferIndex ].addr;
\r
304 memcpy( ( void * ) pcBuffer, ( void * ) uip_buf, emacTOTAL_FRAME_HEADER_SIZE );
\r
306 /* If there is room, also copy in the application data if any. */
\r
307 if( ( uip_len > emacTOTAL_FRAME_HEADER_SIZE ) && ( uip_len <= ( ETH_TX_BUFFER_SIZE - emacTOTAL_FRAME_HEADER_SIZE ) ) )
\r
309 memcpy( ( void * ) &( pcBuffer[ emacTOTAL_FRAME_HEADER_SIZE ] ), ( void * ) uip_appdata, ( uip_len - emacTOTAL_FRAME_HEADER_SIZE ) );
\r
313 portENTER_CRITICAL();
\r
315 if( uxTxBufferIndex >= ( NB_TX_BUFFERS - 1 ) )
\r
317 /* Fill out the necessary in the descriptor to get the data sent. */
\r
318 xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( uip_len & ( unsigned portLONG ) AT91C_LENGTH_FRAME )
\r
319 | AT91C_LAST_BUFFER
\r
320 | AT91C_TRANSMIT_WRAP;
\r
321 uxTxBufferIndex = 0;
\r
325 /* Fill out the necessary in the descriptor to get the data sent. */
\r
326 xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( uip_len & ( unsigned portLONG ) AT91C_LENGTH_FRAME )
\r
327 | AT91C_LAST_BUFFER;
\r
331 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
\r
333 portEXIT_CRITICAL();
\r
338 /*-----------------------------------------------------------*/
\r
340 unsigned portLONG ulEMACPoll( void )
\r
342 static unsigned portBASE_TYPE ulNextRxBuffer = 0;
\r
343 unsigned portLONG ulSectionLength = 0, ulLengthSoFar = 0, ulEOF = pdFALSE;
\r
344 portCHAR *pcSource;
\r
346 /* Skip any fragments. */
\r
347 while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_SOF ) )
\r
349 /* Mark the buffer as free again. */
\r
350 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
\r
352 if( ulNextRxBuffer >= NB_RX_BUFFERS )
\r
354 ulNextRxBuffer = 0;
\r
358 /* Is there a packet ready? */
\r
360 while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !ulSectionLength )
\r
362 pcSource = ( portCHAR * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK );
\r
363 ulSectionLength = xRxDescriptors[ ulNextRxBuffer ].U_Status.status & emacRX_LENGTH_FRAME;
\r
365 if( ulSectionLength == 0 )
\r
367 /* The frame is longer than the buffer pointed to by this
\r
368 descriptor so copy the entire buffer to uIP - then move onto
\r
369 the next descriptor to get the rest of the frame. */
\r
370 if( ( ulLengthSoFar + ETH_RX_BUFFER_SIZE ) <= UIP_BUFSIZE )
\r
372 memcpy( &( uip_buf[ ulLengthSoFar ] ), pcSource, ETH_RX_BUFFER_SIZE );
\r
373 ulLengthSoFar += ETH_RX_BUFFER_SIZE;
\r
378 /* This is the last section of the frame. Copy the section to
\r
380 if( ulSectionLength < UIP_BUFSIZE )
\r
382 /* The section length holds the length of the entire frame.
\r
383 ulLengthSoFar holds the length of the frame sections already
\r
384 copied to uIP, so the length of the final section is
\r
385 ulSectionLength - ulLengthSoFar; */
\r
386 if( ulSectionLength > ulLengthSoFar )
\r
388 memcpy( &( uip_buf[ ulLengthSoFar ] ), pcSource, ( ulSectionLength - ulLengthSoFar ) );
\r
392 /* Is this the last buffer for the frame? If not why? */
\r
393 ulEOF = xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_EOF;
\r
396 /* Mark the buffer as free again. */
\r
397 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT );
\r
399 /* Increment to the next buffer, wrapping if necessary. */
\r
401 if( ulNextRxBuffer >= NB_RX_BUFFERS )
\r
403 ulNextRxBuffer = 0;
\r
407 /* If we obtained data but for some reason did not find the end of the
\r
408 frame then discard the data as it must contain an error. */
\r
411 ulSectionLength = 0;
\r
414 return ulSectionLength;
\r
416 /*-----------------------------------------------------------*/
\r
418 static void prvSetupDescriptors(void)
\r
420 unsigned portBASE_TYPE xIndex;
\r
421 unsigned portLONG ulAddress;
\r
423 /* Initialise xRxDescriptors descriptor. */
\r
424 for( xIndex = 0; xIndex < NB_RX_BUFFERS; ++xIndex )
\r
426 /* Calculate the address of the nth buffer within the array. */
\r
427 ulAddress = ( unsigned portLONG )( pcRxBuffer + ( xIndex * ETH_RX_BUFFER_SIZE ) );
\r
429 /* Write the buffer address into the descriptor. The DMA will place
\r
430 the data at this address when this descriptor is being used. Mask off
\r
431 the bottom bits of the address as these have special meaning. */
\r
432 xRxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
\r
435 /* The last buffer has the wrap bit set so the EMAC knows to wrap back
\r
436 to the first buffer. */
\r
437 xRxDescriptors[ NB_RX_BUFFERS - 1 ].addr |= emacRX_WRAP_BIT;
\r
439 /* Initialise xTxDescriptors. */
\r
440 for( xIndex = 0; xIndex < NB_TX_BUFFERS; ++xIndex )
\r
442 /* Calculate the address of the nth buffer within the array. */
\r
443 ulAddress = ( unsigned portLONG )( pcTxBuffer + ( xIndex * ETH_TX_BUFFER_SIZE ) );
\r
445 /* Write the buffer address into the descriptor. The DMA will read
\r
446 data from here when the descriptor is being used. */
\r
447 xTxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK;
\r
448 xTxDescriptors[ xIndex ].U_Status.status = AT91C_TRANSMIT_OK;
\r
451 /* The last buffer has the wrap bit set so the EMAC knows to wrap back
\r
452 to the first buffer. */
\r
453 xTxDescriptors[ NB_TX_BUFFERS - 1 ].U_Status.status = AT91C_TRANSMIT_WRAP | AT91C_TRANSMIT_OK;
\r
455 /* Tell the EMAC where to find the descriptors. */
\r
456 AT91C_BASE_EMAC->EMAC_RBQP = ( unsigned portLONG ) xRxDescriptors;
\r
457 AT91C_BASE_EMAC->EMAC_TBQP = ( unsigned portLONG ) xTxDescriptors;
\r
459 /* Clear all the bits in the receive status register. */
\r
460 AT91C_BASE_EMAC->EMAC_RSR = ( AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA );
\r
462 /* Enable the copy of data into the buffers, ignore broadcasts,
\r
463 and don't copy FCS. */
\r
464 AT91C_BASE_EMAC->EMAC_NCFGR |= ( AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS);
\r
466 /* Enable Rx and Tx, plus the stats register. */
\r
467 AT91C_BASE_EMAC->EMAC_NCR |= ( AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT );
\r
469 /*-----------------------------------------------------------*/
\r
471 static void prvSetupMACAddress( void )
\r
473 /* Must be written SA1L then SA1H. */
\r
474 AT91C_BASE_EMAC->EMAC_SA1L = ( ( unsigned portLONG ) cMACAddress[ 3 ] << 24 ) |
\r
475 ( ( unsigned portLONG ) cMACAddress[ 2 ] << 16 ) |
\r
476 ( ( unsigned portLONG ) cMACAddress[ 1 ] << 8 ) |
\r
479 AT91C_BASE_EMAC->EMAC_SA1H = ( ( unsigned portLONG ) cMACAddress[ 5 ] << 8 ) |
\r
482 /*-----------------------------------------------------------*/
\r
484 static void prvSetupEMACInterrupt( void )
\r
486 /* Create the semaphore used to trigger the EMAC task. */
\r
487 vSemaphoreCreateBinary( xSemaphore );
\r
490 /* We start by 'taking' the semaphore so the ISR can 'give' it when the
\r
491 first interrupt occurs. */
\r
492 xSemaphoreTake( xSemaphore, emacNO_DELAY );
\r
493 portENTER_CRITICAL();
\r
495 /* We want to interrupt on Rx events. */
\r
496 AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP;
\r
498 /* Enable the interrupts in the AIC. */
\r
499 AT91F_AIC_ConfigureIt( AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISR_Wrapper );
\r
500 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_EMAC;
\r
502 portEXIT_CRITICAL();
\r
505 /*-----------------------------------------------------------*/
\r
511 * The following functions are initialisation functions taken from the Atmel
\r
512 * EMAC sample code.
\r
515 static portBASE_TYPE prvProbePHY( void )
\r
517 unsigned portLONG ulPHYId1, ulPHYId2, ulStatus;
\r
518 portBASE_TYPE xReturn = pdPASS;
\r
520 /* Code supplied by Atmel (reformatted) -----------------*/
\r
522 /* Enable management port */
\r
523 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
\r
524 AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10;
\r
526 /* Read the PHY ID. */
\r
527 vReadPHY( AT91C_PHY_ADDR, MII_PHYSID1, &ulPHYId1 );
\r
528 vReadPHY( AT91C_PHY_ADDR, MII_PHYSID2, &ulPHYId2 );
\r
533 Bits 3:0 Revision Number Four bit manufacturer
\92s revision number.
\r
534 0001 stands for Rev. A, etc.
\r
536 if( ( ( ulPHYId1 << 16 ) | ( ulPHYId2 & 0xfff0 ) ) != MII_DM9161_ID )
\r
538 /* Did not expect this ID. */
\r
543 ulStatus = xGetLinkSpeed();
\r
545 if( ulStatus != pdPASS )
\r
551 /* Disable management port */
\r
552 AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
\r
554 /* End of code supplied by Atmel ------------------------*/
\r
558 /*-----------------------------------------------------------*/
\r
560 static void vReadPHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG *pulValue )
\r
562 /* Code supplied by Atmel (reformatted) ----------------------*/
\r
564 AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01<<30))
\r
565 | (2 << 16) | (2 << 28)
\r
566 | ((ucPHYAddress & 0x1f) << 23)
\r
567 | (ucAddress << 18);
\r
569 /* Wait until IDLE bit in Network Status register is cleared. */
\r
570 while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
\r
575 *pulValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff );
\r
577 /* End of code supplied by Atmel ------------------------*/
\r
579 /*-----------------------------------------------------------*/
\r
581 #if USE_RMII_INTERFACE != 1
\r
582 static void vWritePHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG ulValue )
\r
584 /* Code supplied by Atmel (reformatted) ----------------------*/
\r
586 AT91C_BASE_EMAC->EMAC_MAN = (( AT91C_EMAC_SOF & (0x01<<30))
\r
587 | (2 << 16) | (1 << 28)
\r
588 | ((ucPHYAddress & 0x1f) << 23)
\r
589 | (ucAddress << 18))
\r
590 | (ulValue & 0xffff);
\r
592 /* Wait until IDLE bit in Network Status register is cleared */
\r
593 while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) )
\r
598 /* End of code supplied by Atmel ------------------------*/
\r
601 /*-----------------------------------------------------------*/
\r
603 static portBASE_TYPE xGetLinkSpeed( void )
\r
605 unsigned portLONG ulBMSR, ulBMCR, ulLPA, ulMACCfg, ulSpeed, ulDuplex;
\r
607 /* Code supplied by Atmel (reformatted) -----------------*/
\r
609 /* Link status is latched, so read twice to get current value */
\r
610 vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
\r
611 vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR);
\r
613 if( !( ulBMSR & BMSR_LSTATUS ) )
\r
619 vReadPHY(AT91C_PHY_ADDR, MII_BMCR, &ulBMCR);
\r
620 if (ulBMCR & BMCR_ANENABLE)
\r
622 /* AutoNegotiation is enabled. */
\r
623 if (!(ulBMSR & BMSR_ANEGCOMPLETE))
\r
625 /* Auto-negotiation in progress. */
\r
629 vReadPHY(AT91C_PHY_ADDR, MII_LPA, &ulLPA);
\r
630 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_100HALF ) )
\r
632 ulSpeed = SPEED_100;
\r
636 ulSpeed = SPEED_10;
\r
639 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_10FULL ) )
\r
641 ulDuplex = DUPLEX_FULL;
\r
645 ulDuplex = DUPLEX_HALF;
\r
650 ulSpeed = ( ulBMCR & BMCR_SPEED100 ) ? SPEED_100 : SPEED_10;
\r
651 ulDuplex = ( ulBMCR & BMCR_FULLDPLX ) ? DUPLEX_FULL : DUPLEX_HALF;
\r
654 /* Update the MAC */
\r
655 ulMACCfg = AT91C_BASE_EMAC->EMAC_NCFGR & ~( AT91C_EMAC_SPD | AT91C_EMAC_FD );
\r
656 if( ulSpeed == SPEED_100 )
\r
658 if( ulDuplex == DUPLEX_FULL )
\r
660 /* 100 Full Duplex */
\r
661 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;
\r
665 /* 100 Half Duplex */
\r
666 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD;
\r
671 if (ulDuplex == DUPLEX_FULL)
\r
673 /* 10 Full Duplex */
\r
674 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_FD;
\r
678 /* 10 Half Duplex */
\r
679 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg;
\r
683 /* End of code supplied by Atmel ------------------------*/
\r