00001 /* 00002 FreeRTOS.org V4.6.0 - Copyright (C) 2003-2007 Richard Barry. 00003 00004 This file is part of the FreeRTOS.org distribution. 00005 00006 FreeRTOS.org is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 FreeRTOS.org is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with FreeRTOS.org; if not, write to the Free Software 00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 00020 A special exception to the GPL can be applied should you wish to distribute 00021 a combined work that includes FreeRTOS.org, without being obliged to provide 00022 the source code for any proprietary components. See the licensing section 00023 of http://www.FreeRTOS.org for full details of how and when the exception 00024 can be applied. 00025 00026 *************************************************************************** 00027 See http://www.FreeRTOS.org for documentation, latest information, license 00028 and contact details. Please ensure to read the configuration and relevant 00029 port sections of the online documentation. 00030 00031 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along 00032 with commercial development and support options. 00033 *************************************************************************** 00034 */ 00035 00036 /* 00037 * Interrupt driven driver for the EMAC peripheral. This driver is not 00038 * reentrant, re-entrancy is handled by a semaphore at the network interface 00039 * level. 00040 */ 00041 00042 00043 /* 00044 Changes from V3.2.2 00045 00046 + Corrected the byte order when writing the MAC address to the MAC. 00047 + Support added for MII interfaces. Previously only RMII was supported. 00048 00049 Changes from V3.2.3 00050 00051 + The MII interface is now the default. 00052 + Modified the initialisation sequence slightly to allow auto init more 00053 time to complete. 00054 00055 Changes from V4.0.1 00056 00057 + Made the function vClearEMACTxBuffer() more robust by moving the index 00058 manipulation into the if() statement. This allows the tx interrupt to 00059 execute even when there is no data to handle. 00060 00061 Changes from V4.0.4 00062 00063 + Corrected the Rx frame length mask when obtaining the length from the 00064 rx descriptor. 00065 */ 00066 00067 #include "config.h" // MakingThings. 00068 #ifdef MAKE_CTRL_NETWORK 00069 00070 /* Standard includes. */ 00071 #include <string.h> 00072 00073 /* Scheduler includes. */ 00074 #include "FreeRTOS.h" 00075 #include "semphr.h" 00076 #include "task.h" 00077 00078 /* Demo app includes. */ 00079 #include "SAM7_EMAC.h" 00080 00081 /* Hardware specific includes. */ 00082 #include "Emac.h" 00083 #include "mii.h" 00084 #include "AT91SAM7X256.h" 00085 00086 /* MAKINGTHING: ADDED */ 00087 00088 #include "Board.h" 00089 00090 /* USE_RMII_INTERFACE must be defined as 1 to use an RMII interface, or 0 00091 to use an MII interface. */ 00092 /* MAKINGTHINGS: Make Sure we're using RMII for Version 90 */ 00093 #if ( CONTROLLER_VERSION == 50 || CONTROLLER_VERSION == 100 || CONTROLLER_VERSION == 200 ) 00094 #define USE_RMII_INTERFACE 0 00095 #elif ( CONTROLLER_VERSION == 90 || CONTROLLER_VERSION == 95 ) 00096 #define USE_RMII_INTERFACE 1 00097 #endif 00098 00099 /* The buffer addresses written into the descriptors must be aligned so the 00100 last few bits are zero. These bits have special meaning for the EMAC 00101 peripheral and cannot be used as part of the address. */ 00102 #define emacADDRESS_MASK ( ( unsigned portLONG ) 0xFFFFFFFC ) 00103 00104 /* Bit used within the address stored in the descriptor to mark the last 00105 descriptor in the array. */ 00106 #define emacRX_WRAP_BIT ( ( unsigned portLONG ) 0x02 ) 00107 00108 /* Bit used within the Tx descriptor status to indicate whether the 00109 descriptor is under the control of the EMAC or the software. */ 00110 #define emacTX_BUF_USED ( ( unsigned portLONG ) 0x80000000 ) 00111 00112 /* A short delay is used to wait for a buffer to become available, should 00113 one not be immediately available when trying to transmit a frame. */ 00114 #define emacBUFFER_WAIT_DELAY ( 2 ) 00115 #define emacMAX_WAIT_CYCLES ( ( portBASE_TYPE ) ( configTICK_RATE_HZ / 40 ) ) 00116 00117 /* The time to block waiting for input. */ 00118 #define emacBLOCK_TIME_WAITING_FOR_INPUT ( ( portTickType ) 100 ) 00119 00120 /* Peripheral setup for the EMAC. */ 00121 00122 /* MAKINGTHINGS: ADDITION */ 00123 #if ( CONTROLLER_VERSION == 50 || CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 || CONTROLLER_VERSION == 200 ) 00124 #define emacPERIPHERAL_A_SETUP \ 00125 ( ( unsigned portLONG ) AT91C_PB2_ETX0 ) | \ 00126 ( ( unsigned portLONG ) AT91C_PB3_ETX1 ) | \ 00127 ( ( unsigned portLONG ) AT91C_PB10_ETX2 ) | \ 00128 ( ( unsigned portLONG ) AT91C_PB11_ETX3 ) | \ 00129 ( ( unsigned portLONG ) AT91C_PB12_ETXER ) | \ 00130 ( ( unsigned portLONG ) AT91C_PB1_ETXEN ) | \ 00131 ( ( unsigned portLONG ) AT91C_PB0_ETXCK_EREFCK ) | \ 00132 ( ( unsigned portLONG ) AT91C_PB16_ECOL ) | \ 00133 ( ( unsigned portLONG ) AT91C_PB5_ERX0 ) | \ 00134 ( ( unsigned portLONG ) AT91C_PB6_ERX1 ) | \ 00135 ( ( unsigned portLONG ) AT91C_PB13_ERX2 ) | \ 00136 ( ( unsigned portLONG ) AT91C_PB14_ERX3 ) | \ 00137 ( ( unsigned portLONG ) AT91C_PB15_ERXDV ) | \ 00138 ( ( unsigned portLONG ) AT91C_PB8_EMDC ) | \ 00139 ( ( unsigned portLONG ) AT91C_PB4_ECRS_ECRSDV ) | \ 00140 ( ( unsigned portLONG ) AT91C_PB9_EMDIO ) | \ 00141 ( ( unsigned portLONG ) AT91C_PB7_ERXER ) | \ 00142 ( ( unsigned portLONG ) AT91C_PB17_ERXCK ); 00143 #elif ( CONTROLLER_VERSION == 90 ) 00144 #define emacPERIPHERAL_A_SETUP \ 00145 ( ( unsigned portLONG ) AT91C_PB2_ETX0 ) | \ 00146 ( ( unsigned portLONG ) AT91C_PB6_ERX1 ) | \ 00147 ( ( unsigned portLONG ) AT91C_PB15_ERXDV ) | \ 00148 ( ( unsigned portLONG ) AT91C_PB3_ETX1 ) | \ 00149 ( ( unsigned portLONG ) AT91C_PB8_EMDC ) | \ 00150 ( ( unsigned portLONG ) AT91C_PB4_ECRS_ECRSDV ) | \ 00151 ( ( unsigned portLONG ) AT91C_PB5_ERX0 ) | \ 00152 ( ( unsigned portLONG ) AT91C_PB1_ETXEN ) | \ 00153 ( ( unsigned portLONG ) AT91C_PB0_ETXCK_EREFCK ) | \ 00154 ( ( unsigned portLONG ) AT91C_PB9_EMDIO ) | \ 00155 ( ( unsigned portLONG ) AT91C_PB7_ERXER ); 00156 #endif 00157 00158 /* Misc defines. */ 00159 #define emacINTERRUPT_LEVEL ( 5 ) 00160 #define emacNO_DELAY ( 0 ) 00161 #define emacTOTAL_FRAME_HEADER_SIZE ( 54 ) 00162 #define emacPHY_INIT_DELAY ( 5000 / portTICK_RATE_MS ) 00163 #define emacRESET_KEY ( ( unsigned portLONG ) 0xA5000000 ) 00164 #define emacRESET_LENGTH ( ( unsigned portLONG ) ( 0x01 << 8 ) ) 00165 00166 /* The Atmel header file only defines the TX frame length mask. */ 00167 #define emacRX_LENGTH_FRAME ( 0xfff ) 00168 00169 /*-----------------------------------------------------------*/ 00170 00171 /* Buffer written to by the EMAC DMA. Must be aligned as described by the 00172 comment above the emacADDRESS_MASK definition. */ 00173 static volatile portCHAR pcRxBuffer[ NB_RX_BUFFERS * ETH_RX_BUFFER_SIZE ] __attribute__ ((aligned (8))); 00174 00175 /* Buffer read by the EMAC DMA. Must be aligned as described by the comment 00176 above the emacADDRESS_MASK definition. */ 00177 static portCHAR pcTxBuffer[ NB_TX_BUFFERS * ETH_TX_BUFFER_SIZE ] __attribute__ ((aligned (8))); 00178 00179 /* Descriptors used to communicate between the program and the EMAC peripheral. 00180 These descriptors hold the locations and state of the Rx and Tx buffers. */ 00181 static volatile AT91S_TxTdDescriptor xTxDescriptors[ NB_TX_BUFFERS ]; 00182 static volatile AT91S_RxTdDescriptor xRxDescriptors[ NB_RX_BUFFERS ]; 00183 00184 /* The IP and Ethernet addresses are read from the header files. */ 00185 /* MakingThings: commented this out to accomodate being able to change the MAC address */ 00186 //const portCHAR cMACAddress[ 6 ] = { emacETHADDR0, emacETHADDR1, emacETHADDR2, emacETHADDR3, emacETHADDR4, emacETHADDR5 }; 00187 //const unsigned char ucIPAddress[ 4 ] = { emacIPADDR0, emacIPADDR1, emacIPADDR2, emacIPADDR3 }; 00188 00189 /*-----------------------------------------------------------*/ 00190 00191 /* See the header file for descriptions of public functions. */ 00192 00193 /* 00194 * Prototype for the EMAC interrupt function. 00195 */ 00196 void vEMACISR_Wrapper( void ) __attribute__ ((naked)); 00197 00198 /* 00199 * Initialise both the Tx and Rx descriptors used by the EMAC. 00200 */ 00201 static void prvSetupDescriptors(void); 00202 00203 /* 00204 * Write our MAC address into the EMAC. 00205 */ 00206 static void prvSetupMACAddress( void ); 00207 00208 /* 00209 * Configure the EMAC and AIC for EMAC interrupts. 00210 */ 00211 static void prvSetupEMACInterrupt( void ); 00212 00213 /* 00214 * Some initialisation functions taken from the Atmel EMAC sample code. 00215 */ 00216 static void vReadPHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG *pulValue ); 00217 static portBASE_TYPE xGetLinkSpeed( void ); 00218 static portBASE_TYPE prvProbePHY( void ); 00219 #if USE_RMII_INTERFACE != 1 00220 static void vWritePHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG ulValue); 00221 #endif 00222 00223 00224 /* The semaphore used by the EMAC ISR to wake the EMAC task. */ 00225 static xSemaphoreHandle xSemaphore = NULL; 00226 00227 /* Holds the index to the next buffer from which data will be read. */ 00228 static volatile unsigned portLONG ulNextRxBuffer = 0; 00229 00230 /*-----------------------------------------------------------*/ 00231 00232 /* See the header file for descriptions of public functions. */ 00233 portLONG lEMACSend( portCHAR *pcFrom, unsigned portLONG ulLength, portLONG lEndOfFrame ) 00234 { 00235 static unsigned portBASE_TYPE uxTxBufferIndex = 0; 00236 portBASE_TYPE xWaitCycles = 0; 00237 portLONG lReturn = pdPASS; 00238 portCHAR *pcBuffer; 00239 unsigned portLONG ulLastBuffer, ulDataBuffered = 0, ulDataRemainingToSend, ulLengthToSend; 00240 00241 /* If the length of data to be transmitted is greater than each individual 00242 transmit buffer then the data will be split into more than one buffer. 00243 Loop until the entire length has been buffered. */ 00244 while( ulDataBuffered < ulLength ) 00245 { 00246 /* Is a buffer available? */ 00247 while( !( xTxDescriptors[ uxTxBufferIndex ].U_Status.status & AT91C_TRANSMIT_OK ) ) 00248 { 00249 /* There is no room to write the Tx data to the Tx buffer. Wait a 00250 short while, then try again. */ 00251 xWaitCycles++; 00252 if( xWaitCycles > emacMAX_WAIT_CYCLES ) 00253 { 00254 /* Give up. */ 00255 lReturn = pdFAIL; 00256 break; 00257 } 00258 else 00259 { 00260 vTaskDelay( emacBUFFER_WAIT_DELAY ); 00261 } 00262 } 00263 00264 /* lReturn will only be pdPASS if a buffer is available. */ 00265 if( lReturn == pdPASS ) 00266 { 00267 portENTER_CRITICAL(); 00268 { 00269 /* Get the address of the buffer from the descriptor, then copy 00270 the data into the buffer. */ 00271 pcBuffer = ( portCHAR * ) xTxDescriptors[ uxTxBufferIndex ].addr; 00272 00273 /* How much can we write to the buffer? */ 00274 ulDataRemainingToSend = ulLength - ulDataBuffered; 00275 if( ulDataRemainingToSend <= ETH_TX_BUFFER_SIZE ) 00276 { 00277 /* We can write all the remaining bytes. */ 00278 ulLengthToSend = ulDataRemainingToSend; 00279 } 00280 else 00281 { 00282 /* We can not write more than ETH_TX_BUFFER_SIZE in one go. */ 00283 ulLengthToSend = ETH_TX_BUFFER_SIZE; 00284 } 00285 00286 /* Copy the data into the buffer. */ 00287 memcpy( ( void * ) pcBuffer, ( void * ) &( pcFrom[ ulDataBuffered ] ), ulLengthToSend ); 00288 ulDataBuffered += ulLengthToSend; 00289 00290 /* Is this the last data for the frame? */ 00291 if( lEndOfFrame && ( ulDataBuffered >= ulLength ) ) 00292 { 00293 /* No more data remains for this frame so we can start the 00294 transmission. */ 00295 ulLastBuffer = AT91C_LAST_BUFFER; 00296 } 00297 else 00298 { 00299 /* More data to come for this frame. */ 00300 ulLastBuffer = 0; 00301 } 00302 00303 /* Fill out the necessary in the descriptor to get the data sent, 00304 then move to the next descriptor, wrapping if necessary. */ 00305 if( uxTxBufferIndex >= ( NB_TX_BUFFERS - 1 ) ) 00306 { 00307 xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( ulLengthToSend & ( unsigned portLONG ) AT91C_LENGTH_FRAME ) 00308 | ulLastBuffer 00309 | AT91C_TRANSMIT_WRAP; 00310 uxTxBufferIndex = 0; 00311 } 00312 else 00313 { 00314 xTxDescriptors[ uxTxBufferIndex ].U_Status.status = ( ulLengthToSend & ( unsigned portLONG ) AT91C_LENGTH_FRAME ) 00315 | ulLastBuffer; 00316 uxTxBufferIndex++; 00317 } 00318 00319 /* If this is the last buffer to be sent for this frame we can 00320 start the transmission. */ 00321 if( ulLastBuffer ) 00322 { 00323 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART; 00324 } 00325 } 00326 portEXIT_CRITICAL(); 00327 } 00328 else 00329 { 00330 break; 00331 } 00332 } 00333 00334 return lReturn; 00335 } 00336 /*-----------------------------------------------------------*/ 00337 00338 /* See the header file for descriptions of public functions. */ 00339 unsigned portLONG ulEMACInputLength( void ) 00340 { 00341 register unsigned portLONG ulIndex, ulLength = 0; 00342 00343 /* Skip any fragments. We are looking for the first buffer that contains 00344 data and has the SOF (start of frame) bit set. */ 00345 while( ( xRxDescriptors[ ulNextRxBuffer ].addr & AT91C_OWNERSHIP_BIT ) && !( xRxDescriptors[ ulNextRxBuffer ].U_Status.status & AT91C_SOF ) ) 00346 { 00347 /* Ignoring this buffer. Mark it as free again. */ 00348 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT ); 00349 ulNextRxBuffer++; 00350 if( ulNextRxBuffer >= NB_RX_BUFFERS ) 00351 { 00352 ulNextRxBuffer = 0; 00353 } 00354 } 00355 00356 /* We are going to walk through the descriptors that make up this frame, 00357 but don't want to alter ulNextRxBuffer as this would prevent vEMACRead() 00358 from finding the data. Therefore use a copy of ulNextRxBuffer instead. */ 00359 ulIndex = ulNextRxBuffer; 00360 00361 /* Walk through the descriptors until we find the last buffer for this 00362 frame. The last buffer will give us the length of the entire frame. */ 00363 int count = 0; // MAKINGTHINGS - if the buffer is not found, this just spins forever 00364 while( ( xRxDescriptors[ ulIndex ].addr & AT91C_OWNERSHIP_BIT ) && !ulLength && count < NB_RX_BUFFERS) 00365 { 00366 ulLength = xRxDescriptors[ ulIndex ].U_Status.status & emacRX_LENGTH_FRAME; 00367 00368 /* Increment to the next buffer, wrapping if necessary. */ 00369 ulIndex++; 00370 count++; 00371 if( ulIndex >= NB_RX_BUFFERS ) 00372 { 00373 ulIndex = 0; 00374 } 00375 } 00376 00377 return ulLength; 00378 } 00379 /*-----------------------------------------------------------*/ 00380 00381 /* See the header file for descriptions of public functions. */ 00382 void vEMACRead( portCHAR *pcTo, unsigned portLONG ulSectionLength, unsigned portLONG ulTotalFrameLength ) 00383 { 00384 static unsigned portLONG ulSectionBytesReadSoFar = 0, ulBufferPosition = 0, ulFameBytesReadSoFar = 0; 00385 static portCHAR *pcSource; 00386 register unsigned portLONG ulBytesRemainingInBuffer, ulRemainingSectionBytes; 00387 00388 /* Read ulSectionLength bytes from the Rx buffers. This is not necessarily any 00389 correspondence between the length of our Rx buffers, and the length of the 00390 data we are returning or the length of the data being requested. Therefore, 00391 between calls we have to remember not only which buffer we are currently 00392 processing, but our position within that buffer. This would be greatly 00393 simplified if PBUF_POOL_BUFSIZE could be guaranteed to be greater than 00394 the size of each Rx buffer, and that memory fragmentation did not occur. 00395 00396 This function should only be called after a call to ulEMACInputLength(). 00397 This will ensure ulNextRxBuffer is set to the correct buffer. */ 00398 00399 00400 00401 /* vEMACRead is called with pcTo set to NULL to indicate that we are about 00402 to read a new frame. Any fragments remaining in the frame we were 00403 processing during the last call should be dropped. */ 00404 if( pcTo == NULL ) 00405 { 00406 /* How many bytes are indicated as being in this buffer? If none then 00407 the buffer is completely full and the frame is contained within more 00408 than one buffer. */ 00409 00410 /* Reset our state variables ready for the next read from this buffer. */ 00411 pcSource = ( portCHAR * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK ); 00412 ulFameBytesReadSoFar = ( unsigned portLONG ) 0; 00413 ulBufferPosition = ( unsigned portLONG ) 0; 00414 } 00415 else 00416 { 00417 /* Loop until we have obtained the required amount of data. */ 00418 ulSectionBytesReadSoFar = 0; 00419 while( ulSectionBytesReadSoFar < ulSectionLength ) 00420 { 00421 /* We may have already read some data from this buffer. How much 00422 data remains in the buffer? */ 00423 ulBytesRemainingInBuffer = ( ETH_RX_BUFFER_SIZE - ulBufferPosition ); 00424 00425 /* How many more bytes do we need to read before we have the 00426 required amount of data? */ 00427 ulRemainingSectionBytes = ulSectionLength - ulSectionBytesReadSoFar; 00428 00429 /* Do we want more data than remains in the buffer? */ 00430 if( ulRemainingSectionBytes > ulBytesRemainingInBuffer ) 00431 { 00432 /* We want more data than remains in the buffer so we can 00433 write the remains of the buffer to the destination, then move 00434 onto the next buffer to get the rest. */ 00435 memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulBytesRemainingInBuffer ); 00436 ulSectionBytesReadSoFar += ulBytesRemainingInBuffer; 00437 ulFameBytesReadSoFar += ulBytesRemainingInBuffer; 00438 00439 /* Mark the buffer as free again. */ 00440 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT ); 00441 00442 /* Move onto the next buffer. */ 00443 ulNextRxBuffer++; 00444 if( ulNextRxBuffer >= NB_RX_BUFFERS ) 00445 { 00446 ulNextRxBuffer = ( unsigned portLONG ) 0; 00447 } 00448 00449 /* Reset the variables for the new buffer. */ 00450 pcSource = ( portCHAR * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK ); 00451 ulBufferPosition = ( unsigned portLONG ) 0; 00452 } 00453 else 00454 { 00455 /* We have enough data in this buffer to send back. Read out 00456 enough data and remember how far we read up to. */ 00457 memcpy( &( pcTo[ ulSectionBytesReadSoFar ] ), &( pcSource[ ulBufferPosition ] ), ulRemainingSectionBytes ); 00458 00459 /* There may be more data in this buffer yet. Increment our 00460 position in this buffer past the data we have just read. */ 00461 ulBufferPosition += ulRemainingSectionBytes; 00462 ulSectionBytesReadSoFar += ulRemainingSectionBytes; 00463 ulFameBytesReadSoFar += ulRemainingSectionBytes; 00464 00465 /* Have we now finished with this buffer? */ 00466 if( ( ulBufferPosition >= ETH_RX_BUFFER_SIZE ) || ( ulFameBytesReadSoFar >= ulTotalFrameLength ) ) 00467 { 00468 /* Mark the buffer as free again. */ 00469 xRxDescriptors[ ulNextRxBuffer ].addr &= ~( AT91C_OWNERSHIP_BIT ); 00470 00471 /* Move onto the next buffer. */ 00472 ulNextRxBuffer++; 00473 if( ulNextRxBuffer >= NB_RX_BUFFERS ) 00474 { 00475 ulNextRxBuffer = 0; 00476 } 00477 00478 pcSource = ( portCHAR * )( xRxDescriptors[ ulNextRxBuffer ].addr & emacADDRESS_MASK ); 00479 ulBufferPosition = 0; 00480 } 00481 } 00482 } 00483 } 00484 } 00485 /*-----------------------------------------------------------*/ 00486 00487 /* See the header file for descriptions of public functions. */ 00488 xSemaphoreHandle xEMACInit( void ) 00489 { 00490 unsigned portLONG saved_RSTC_RMR; 00491 00492 /* Code supplied by Atmel -------------------------------*/ 00493 00494 /* Disable pull up on RXDV => PHY normal mode (not in test mode), 00495 PHY has internal pull down. */ 00496 AT91C_BASE_PIOB->PIO_PPUDR = 1 << 15; 00497 00498 #if USE_RMII_INTERFACE != 1 00499 /* PHY has internal pull down : set MII mode. */ 00500 AT91C_BASE_PIOB->PIO_PPUDR = 1 << 16; 00501 #endif 00502 00503 /* MAKINGTHINGS: ADDITION */ 00504 /* Clear PB18 <=> PHY power up. */ 00505 #if ( CONTROLLER_VERSION == 50 || CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 || CONTROLLER_VERSION == 200 ) 00506 AT91C_BASE_PIOB->PIO_PER = 1 << 18; 00507 AT91C_BASE_PIOB->PIO_OER = 1 << 18; 00508 AT91C_BASE_PIOB->PIO_CODR = 1 << 18; 00509 #endif 00510 #if ( CONTROLLER_VERSION == 90 ) 00511 /* PB13 <=> PHY powerdown - so clearing it is power up. */ 00512 AT91C_BASE_PIOB->PIO_PER = 1 << 13; 00513 AT91C_BASE_PIOB->PIO_OER = 1 << 13; 00514 AT91C_BASE_PIOB->PIO_CODR = 1 << 13; 00515 #endif 00516 00517 /* MAKINGTHINGS 00518 Critical section while commandeering the RSTC. */ 00519 portENTER_CRITICAL(); 00520 00521 /* We do not have to do anything special with the RSTC interrupt, since the following disables it in RSTC_RMR. */ 00522 00523 /* Save prior RTSC setup to restore afterward. */ 00524 saved_RSTC_RMR = AT91C_BASE_RSTC->RSTC_RMR; 00525 00526 /* Wait until it is safe to write to RSTC_RCR. */ 00527 while(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP) 00528 { 00529 portNOP(); 00530 } 00531 00532 /* After PHY power up, hardware reset. */ 00533 AT91C_BASE_RSTC->RSTC_RMR = emacRESET_KEY | emacRESET_LENGTH; 00534 AT91C_BASE_RSTC->RSTC_RCR = emacRESET_KEY | AT91C_RSTC_EXTRST; 00535 00536 /* Wait for hardware reset end and for NRST to not be asserted. */ 00537 while((AT91C_BASE_RSTC->RSTC_RSR & (AT91C_RSTC_SRCMP | AT91C_RSTC_NRSTL)) != (AT91C_RSTC_NRSTL)) 00538 { 00539 portNOP(); 00540 } 00541 00542 /* Restore prior RTSC setup. */ 00543 AT91C_BASE_RSTC->RSTC_RMR = (saved_RSTC_RMR & ~(0xff << 24)) | (0xa5 << 24); 00544 00545 portEXIT_CRITICAL(); 00546 /* end MAKINGTHINGS */ 00547 00548 /* Setup the pins. */ 00549 AT91C_BASE_PIOB->PIO_ASR = emacPERIPHERAL_A_SETUP; 00550 AT91C_BASE_PIOB->PIO_PDR = emacPERIPHERAL_A_SETUP; 00551 00552 /* Enable com between EMAC PHY. 00553 00554 Enable management port. */ 00555 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE; 00556 00557 /* MDC = MCK/32. */ 00558 AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10; 00559 00560 /* Wait for PHY auto init end (rather crude delay!). */ 00561 vTaskDelay( emacPHY_INIT_DELAY ); 00562 00563 /* PHY configuration. */ 00564 #if USE_RMII_INTERFACE != 1 00565 { 00566 unsigned portLONG ulControl; 00567 00568 /* PHY has internal pull down : disable MII isolate. */ 00569 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl ); 00570 vReadPHY( AT91C_PHY_ADDR, MII_BMCR, &ulControl ); 00571 ulControl &= ~BMCR_ISOLATE; 00572 vWritePHY( AT91C_PHY_ADDR, MII_BMCR, ulControl ); 00573 } 00574 #endif 00575 00576 /* Disable management port again. */ 00577 AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE; 00578 00579 #if USE_RMII_INTERFACE != 1 00580 /* Enable EMAC in MII mode, enable clock ERXCK and ETXCK. */ 00581 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN ; 00582 #else 00583 /* Enable EMAC in RMII mode, enable RMII clock (50MHz from oscillator 00584 on ERFCK). */ 00585 AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_RMII | AT91C_EMAC_CLKEN ; 00586 #endif 00587 00588 /* End of code supplied by Atmel ------------------------*/ 00589 00590 /* Setup the buffers and descriptors. */ 00591 prvSetupDescriptors(); 00592 00593 /* Load our MAC address into the EMAC. */ 00594 prvSetupMACAddress(); 00595 00596 /* Are we connected? */ 00597 if( prvProbePHY() ) 00598 { 00599 /* Enable the interrupt! */ 00600 portENTER_CRITICAL(); 00601 { 00602 prvSetupEMACInterrupt(); 00603 vPassEMACSemaphore( xSemaphore ); 00604 } 00605 portEXIT_CRITICAL(); 00606 } 00607 00608 return xSemaphore; 00609 } 00610 /*-----------------------------------------------------------*/ 00611 00612 /* See the header file for descriptions of public functions. */ 00613 void vClearEMACTxBuffer( void ) 00614 { 00615 static unsigned portBASE_TYPE uxNextBufferToClear = 0; 00616 00617 /* Called on Tx interrupt events to reset the AT91C_TRANSMIT_OK bit in each 00618 Tx buffer within the frame just transmitted. This marks all the buffers 00619 as available again. 00620 00621 The first buffer in the frame should have the bit set automatically. */ 00622 if( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AT91C_TRANSMIT_OK ) 00623 { 00624 /* Loop through the other buffers in the frame. */ 00625 while( !( xTxDescriptors[ uxNextBufferToClear ].U_Status.status & AT91C_LAST_BUFFER ) ) 00626 { 00627 uxNextBufferToClear++; 00628 00629 if( uxNextBufferToClear >= NB_TX_BUFFERS ) 00630 { 00631 uxNextBufferToClear = 0; 00632 } 00633 00634 xTxDescriptors[ uxNextBufferToClear ].U_Status.status |= AT91C_TRANSMIT_OK; 00635 } 00636 00637 /* Start with the next buffer the next time a Tx interrupt is called. */ 00638 uxNextBufferToClear++; 00639 00640 /* Do we need to wrap back to the first buffer? */ 00641 if( uxNextBufferToClear >= NB_TX_BUFFERS ) 00642 { 00643 uxNextBufferToClear = 0; 00644 } 00645 } 00646 } 00647 /*-----------------------------------------------------------*/ 00648 00649 static void prvSetupDescriptors(void) 00650 { 00651 unsigned portBASE_TYPE xIndex; 00652 unsigned portLONG ulAddress; 00653 00654 /* Initialise xRxDescriptors descriptor. */ 00655 for( xIndex = 0; xIndex < NB_RX_BUFFERS; ++xIndex ) 00656 { 00657 /* Calculate the address of the nth buffer within the array. */ 00658 ulAddress = ( unsigned portLONG )( pcRxBuffer + ( xIndex * ETH_RX_BUFFER_SIZE ) ); 00659 00660 /* Write the buffer address into the descriptor. The DMA will place 00661 the data at this address when this descriptor is being used. Mask off 00662 the bottom bits of the address as these have special meaning. */ 00663 xRxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK; 00664 } 00665 00666 /* The last buffer has the wrap bit set so the EMAC knows to wrap back 00667 to the first buffer. */ 00668 xRxDescriptors[ NB_RX_BUFFERS - 1 ].addr |= emacRX_WRAP_BIT; 00669 00670 /* Initialise xTxDescriptors. */ 00671 for( xIndex = 0; xIndex < NB_TX_BUFFERS; ++xIndex ) 00672 { 00673 /* Calculate the address of the nth buffer within the array. */ 00674 ulAddress = ( unsigned portLONG )( pcTxBuffer + ( xIndex * ETH_TX_BUFFER_SIZE ) ); 00675 00676 /* Write the buffer address into the descriptor. The DMA will read 00677 data from here when the descriptor is being used. */ 00678 xTxDescriptors[ xIndex ].addr = ulAddress & emacADDRESS_MASK; 00679 xTxDescriptors[ xIndex ].U_Status.status = AT91C_TRANSMIT_OK; 00680 } 00681 00682 /* The last buffer has the wrap bit set so the EMAC knows to wrap back 00683 to the first buffer. */ 00684 xTxDescriptors[ NB_TX_BUFFERS - 1 ].U_Status.status = AT91C_TRANSMIT_WRAP | AT91C_TRANSMIT_OK; 00685 00686 /* Tell the EMAC where to find the descriptors. */ 00687 AT91C_BASE_EMAC->EMAC_RBQP = ( unsigned portLONG ) xRxDescriptors; 00688 AT91C_BASE_EMAC->EMAC_TBQP = ( unsigned portLONG ) xTxDescriptors; 00689 00690 /* Clear all the bits in the receive status register. */ 00691 AT91C_BASE_EMAC->EMAC_RSR = ( AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA ); 00692 00693 /* Enable the copy of data into the buffers, ignore broadcasts, 00694 and don't copy FCS. */ 00695 AT91C_BASE_EMAC->EMAC_NCFGR |= ( AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_DRFCS); 00696 00697 /* Enable Rx and Tx, plus the stats register. */ 00698 AT91C_BASE_EMAC->EMAC_NCR |= ( AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT ); 00699 } 00700 /*-----------------------------------------------------------*/ 00701 00702 static void prvSetupMACAddress( void ) 00703 { 00704 /* Must be written SA1L then SA1H. */ 00705 /* MakingThings: Switch variables to load from */ 00706 AT91C_BASE_EMAC->EMAC_SA1L = ( ( unsigned portLONG ) emacETHADDR3 << 24 ) | 00707 ( ( unsigned portLONG ) emacETHADDR2 << 16 ) | 00708 ( ( unsigned portLONG ) emacETHADDR1 << 8 ) | 00709 emacETHADDR0; 00710 00711 AT91C_BASE_EMAC->EMAC_SA1H = ( ( unsigned portLONG ) emacETHADDR5 << 8 ) | 00712 emacETHADDR4; 00713 } 00714 /*-----------------------------------------------------------*/ 00715 00716 static void prvSetupEMACInterrupt( void ) 00717 { 00718 /* Create the semaphore used to trigger the EMAC task. */ 00719 vSemaphoreCreateBinary( xSemaphore ); 00720 if( xSemaphore ) 00721 { 00722 /* We start by 'taking' the semaphore so the ISR can 'give' it when the 00723 first interrupt occurs. */ 00724 xSemaphoreTake( xSemaphore, emacNO_DELAY ); 00725 portENTER_CRITICAL(); 00726 { 00727 /* We want to interrupt on Rx and Tx events. */ 00728 AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP; 00729 00730 /* Enable the interrupts in the AIC. */ 00731 AT91F_AIC_ConfigureIt( AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISR_Wrapper ); 00732 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_EMAC; 00733 } 00734 portEXIT_CRITICAL(); 00735 } 00736 } 00737 00738 00739 00740 00741 00742 /* 00743 * The following functions are initialisation functions taken from the Atmel 00744 * EMAC sample code. 00745 */ 00746 00747 00748 static portBASE_TYPE prvProbePHY( void ) 00749 { 00750 unsigned portLONG ulPHYId1, ulPHYId2, ulStatus; 00751 portBASE_TYPE xReturn = pdPASS; 00752 00753 /* Code supplied by Atmel (reformatted) -----------------*/ 00754 00755 /* Enable management port */ 00756 AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE; 00757 AT91C_BASE_EMAC->EMAC_NCFGR |= ( 2 ) << 10; 00758 00759 /* Read the PHY ID. */ 00760 vReadPHY( AT91C_PHY_ADDR, MII_PHYSID1, &ulPHYId1 ); 00761 vReadPHY(AT91C_PHY_ADDR, MII_PHYSID2, &ulPHYId2 ); 00762 00763 /* AMD AM79C875: 00764 PHY_ID1 = 0x0022 00765 PHY_ID2 = 0x5541 00766 Bits 3:0 Revision Number Four bit manufacturer?s revision number. 00767 0001 stands for Rev. A, etc. 00768 */ 00769 if( ( ( ulPHYId1 << 16 ) | ( ulPHYId2 & 0xfff0 ) ) != MII_DM9161_ID ) 00770 { 00771 /* Did not expect this ID. */ 00772 xReturn = pdFAIL; 00773 } 00774 else 00775 { 00776 ulStatus = xGetLinkSpeed(); 00777 00778 if( ulStatus != pdPASS ) 00779 { 00780 xReturn = pdFAIL; 00781 } 00782 } 00783 00784 /* Disable management port */ 00785 AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE; 00786 00787 /* End of code supplied by Atmel ------------------------*/ 00788 00789 return xReturn; 00790 } 00791 /*-----------------------------------------------------------*/ 00792 00793 static void vReadPHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG *pulValue ) 00794 { 00795 /* Code supplied by Atmel (reformatted) ----------------------*/ 00796 00797 AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01<<30)) 00798 | (2 << 16) | (2 << 28) 00799 | ((ucPHYAddress & 0x1f) << 23) 00800 | (ucAddress << 18); 00801 00802 /* Wait until IDLE bit in Network Status register is cleared. */ 00803 while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) ) 00804 { 00805 portNOP(); 00806 } 00807 00808 *pulValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff ); 00809 00810 /* End of code supplied by Atmel ------------------------*/ 00811 } 00812 /*-----------------------------------------------------------*/ 00813 00814 #if USE_RMII_INTERFACE != 1 00815 static void vWritePHY( unsigned portCHAR ucPHYAddress, unsigned portCHAR ucAddress, unsigned portLONG ulValue ) 00816 { 00817 /* Code supplied by Atmel (reformatted) ----------------------*/ 00818 00819 AT91C_BASE_EMAC->EMAC_MAN = (( AT91C_EMAC_SOF & (0x01<<30)) 00820 | (2 << 16) | (1 << 28) 00821 | ((ucPHYAddress & 0x1f) << 23) 00822 | (ucAddress << 18)) 00823 | (ulValue & 0xffff); 00824 00825 /* Wait until IDLE bit in Network Status register is cleared */ 00826 while( !( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE ) ) 00827 { 00828 portNOP(); 00829 }; 00830 00831 /* End of code supplied by Atmel ------------------------*/ 00832 } 00833 #endif 00834 /*-----------------------------------------------------------*/ 00835 00836 static portBASE_TYPE xGetLinkSpeed( void ) 00837 { 00838 unsigned portLONG ulBMSR, ulBMCR, ulLPA, ulMACCfg, ulSpeed, ulDuplex; 00839 00840 /* Code supplied by Atmel (reformatted) -----------------*/ 00841 00842 /* Link status is latched, so read twice to get current value */ 00843 vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR); 00844 vReadPHY(AT91C_PHY_ADDR, MII_BMSR, &ulBMSR); 00845 00846 if( !( ulBMSR & BMSR_LSTATUS ) ) 00847 { 00848 /* No Link. */ 00849 return pdFAIL; 00850 } 00851 00852 vReadPHY(AT91C_PHY_ADDR, MII_BMCR, &ulBMCR); 00853 if (ulBMCR & BMCR_ANENABLE) 00854 { 00855 /* AutoNegotiation is enabled. */ 00856 if (!(ulBMSR & BMSR_ANEGCOMPLETE)) 00857 { 00858 /* Auto-negotitation in progress. */ 00859 return pdFAIL; 00860 } 00861 00862 vReadPHY(AT91C_PHY_ADDR, MII_LPA, &ulLPA); 00863 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_100HALF ) ) 00864 { 00865 ulSpeed = SPEED_100; 00866 } 00867 else 00868 { 00869 ulSpeed = SPEED_10; 00870 } 00871 00872 if( ( ulLPA & LPA_100FULL ) || ( ulLPA & LPA_10FULL ) ) 00873 { 00874 ulDuplex = DUPLEX_FULL; 00875 } 00876 else 00877 { 00878 ulDuplex = DUPLEX_HALF; 00879 } 00880 } 00881 else 00882 { 00883 ulSpeed = ( ulBMCR & BMCR_SPEED100 ) ? SPEED_100 : SPEED_10; 00884 ulDuplex = ( ulBMCR & BMCR_FULLDPLX ) ? DUPLEX_FULL : DUPLEX_HALF; 00885 } 00886 00887 /* Update the MAC */ 00888 ulMACCfg = AT91C_BASE_EMAC->EMAC_NCFGR & ~( AT91C_EMAC_SPD | AT91C_EMAC_FD ); 00889 if( ulSpeed == SPEED_100 ) 00890 { 00891 if( ulDuplex == DUPLEX_FULL ) 00892 { 00893 /* 100 Full Duplex */ 00894 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD | AT91C_EMAC_FD; 00895 } 00896 else 00897 { 00898 /* 100 Half Duplex */ 00899 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_SPD; 00900 } 00901 } 00902 else 00903 { 00904 if (ulDuplex == DUPLEX_FULL) 00905 { 00906 /* 10 Full Duplex */ 00907 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg | AT91C_EMAC_FD; 00908 } 00909 else 00910 { /* 10 Half Duplex */ 00911 AT91C_BASE_EMAC->EMAC_NCFGR = ulMACCfg; 00912 } 00913 } 00914 00915 /* End of code supplied by Atmel ------------------------*/ 00916 00917 return pdPASS; 00918 } 00919 /*-----------------------------------------------------------*/ 00920 00921 void vEMACWaitForInput( void ) 00922 { 00923 /* Just wait until we are signled from an ISR that data is available, or 00924 we simply time out. */ 00925 xSemaphoreTake( xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT ); 00926 } 00927 00928 #endif // MAKE_CTRL_NETWORK
The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.