Add missing +TCP code.

This commit is contained in:
Richard Barry 2017-08-17 12:26:43 +00:00
parent 77e95538dc
commit e42a701e99
18 changed files with 11695 additions and 501 deletions

View file

@ -97,7 +97,9 @@ a constant. */
/* Time delay between repeated attempts to initialise the network hardware. */ /* Time delay between repeated attempts to initialise the network hardware. */
#ifndef ipINITIALISATION_RETRY_DELAY
#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) ) #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) )
#endif
/* Defines how often the ARP timer callback function is executed. The time is /* Defines how often the ARP timer callback function is executed. The time is
shorted in the Windows simulator as simulated time is not real time. */ shorted in the Windows simulator as simulated time is not real time. */
@ -1027,8 +1029,11 @@ BaseType_t xReturn = pdFALSE;
/* Added to prevent ARP flood to gateway. Ensure the /* Added to prevent ARP flood to gateway. Ensure the
gateway is on the same subnet as the IP address. */ gateway is on the same subnet as the IP address. */
if( xNetworkAddressing.ulGatewayAddress != 0ul )
{
configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) ); configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );
} }
}
#endif /* ipconfigUSE_DHCP == 1 */ #endif /* ipconfigUSE_DHCP == 1 */
/* The MAC address is stored in the start of the default packet /* The MAC address is stored in the start of the default packet

View file

@ -2893,11 +2893,26 @@ void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
creation, it could still be changed with setsockopt(). */ creation, it could still be changed with setsockopt(). */
if( xIsInputStream != pdFALSE ) if( xIsInputStream != pdFALSE )
{ {
/* Flow control for input streams works with a low- and a high-water mark.
1) If the RX-space becomes less than uxLittleSpace, the flag 'bLowWater' will
be set, and a TCP window update message will be sent to the peer.
2) The data will be read from the socket by recv() and when RX-space becomes
larger than or equal to than 'uxEnoughSpace', a new TCP window update
message will be sent to the peer, and 'bLowWater' will get cleared again.
By default:
uxLittleSpace == 1/5 x uxRxStreamSize
uxEnoughSpace == 4/5 x uxRxStreamSize
How-ever it is very inefficient to make 'uxLittleSpace' smaller than the actual MSS.
*/
uxLength = pxSocket->u.xTCP.uxRxStreamSize; uxLength = pxSocket->u.xTCP.uxRxStreamSize;
if( pxSocket->u.xTCP.uxLittleSpace == 0ul ) if( pxSocket->u.xTCP.uxLittleSpace == 0ul )
{ {
pxSocket->u.xTCP.uxLittleSpace = ( 1ul * pxSocket->u.xTCP.uxRxStreamSize ) / 5u; /*_RB_ Why divide by 5? Can this be changed to a #define? */ pxSocket->u.xTCP.uxLittleSpace = ( 1ul * pxSocket->u.xTCP.uxRxStreamSize ) / 5u; /*_RB_ Why divide by 5? Can this be changed to a #define? */
if( (pxSocket->u.xTCP.uxLittleSpace < pxSocket->u.xTCP.usCurMSS ) && ( pxSocket->u.xTCP.uxRxStreamSize >= 2 * pxSocket->u.xTCP.usCurMSS ) )
{
pxSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.usCurMSS;
}
} }
if( pxSocket->u.xTCP.uxEnoughSpace == 0ul ) if( pxSocket->u.xTCP.uxEnoughSpace == 0ul )

View file

@ -744,6 +744,8 @@ NetworkBufferDescriptor_t xTempBuffer;
xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket; xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket;
xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ); xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket );
/* A pseudo network buffer can not be released. */
xReleaseAfterSend = pdFALSE;
} }
#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) #if( ipconfigZERO_COPY_TX_DRIVER != 0 )

View file

@ -0,0 +1,664 @@
/*
* Handling of Ethernet PHY's
* PHY's communicate with an EMAC either through
* a Media-Independent Interface (MII), or a Reduced Media-Independent Interface (RMII).
* The EMAC can poll for PHY ports on 32 different addresses. Each of the PHY ports
* shall be treated independently.
*
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "phyHandling.h"
#include "eventLogging.h"
#define phyMIN_PHY_ADDRESS 0
#define phyMAX_PHY_ADDRESS 31
#if defined( PHY_LS_HIGH_CHECK_TIME_MS ) || defined( PHY_LS_LOW_CHECK_TIME_MS )
#warning please use the new defines with 'ipconfig' prefix
#endif
#ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
receiving packets. */
#define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000
#endif
#ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still low every second. */
#define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000
#endif
/* Naming and numbering of basic PHY registers. */
#define phyREG_00_BMCR 0x00u /* Basic Mode Control Register. */
#define phyREG_01_BMSR 0x01u /* Basic Mode Status Register. */
#define phyREG_02_PHYSID1 0x02u /* PHYS ID 1 */
#define phyREG_03_PHYSID2 0x03u /* PHYS ID 2 */
#define phyREG_04_ADVERTISE 0x04u /* Advertisement control reg */
/* Naming and numbering of extended PHY registers. */
#define PHYREG_10_PHYSTS 0x10u /* 16 PHY status register Offset */
#define phyREG_19_PHYCR 0x19u /* 25 RW PHY Control Register */
#define phyREG_1F_PHYSPCS 0x1Fu /* 31 RW PHY Special Control Status */
/* Bit fields for 'phyREG_00_BMCR', the 'Basic Mode Control Register'. */
#define phyBMCR_FULL_DUPLEX 0x0100u /* Full duplex. */
#define phyBMCR_AN_RESTART 0x0200u /* Auto negotiation restart. */
#define phyBMCR_AN_ENABLE 0x1000u /* Enable auto negotiation. */
#define phyBMCR_SPEED_100 0x2000u /* Select 100Mbps. */
#define phyBMCR_RESET 0x8000u /* Reset the PHY. */
/* Bit fields for 'phyREG_19_PHYCR', the 'PHY Control Register'. */
#define PHYCR_MDIX_EN 0x8000u /* Enable Auto MDIX. */
#define PHYCR_MDIX_FORCE 0x4000u /* Force MDIX crossed. */
#define phyBMSR_AN_COMPLETE 0x0020u /* Auto-Negotiation process completed */
#define phyBMSR_LINK_STATUS 0x0004u
#define phyPHYSTS_LINK_STATUS 0x0001u /* PHY Link mask */
#define phyPHYSTS_SPEED_STATUS 0x0002u /* PHY Speed mask */
#define phyPHYSTS_DUPLEX_STATUS 0x0004u /* PHY Duplex mask */
/* Bit fields for 'phyREG_1F_PHYSPCS
001 = 10BASE-T half-duplex
101 = 10BASE-T full-duplex
010 = 100BASE-TX half-duplex
110 = 100BASE-TX full-duplex
*/
#define phyPHYSPCS_SPEED_MASK 0x000Cu
#define phyPHYSPCS_SPEED_10 0x0004u
#define phyPHYSPCS_FULL_DUPLEX 0x0010u
/*
* Description of all capabilities that can be advertised to
* the peer (usually a switch or router).
*/
#define phyADVERTISE_CSMA 0x0001u /* Only selector supported. */
#define phyADVERTISE_10HALF 0x0020u /* Try for 10mbps half-duplex. */
#define phyADVERTISE_10FULL 0x0040u /* Try for 10mbps full-duplex. */
#define phyADVERTISE_100HALF 0x0080u /* Try for 100mbps half-duplex. */
#define phyADVERTISE_100FULL 0x0100u /* Try for 100mbps full-duplex. */
#define phyADVERTISE_ALL ( phyADVERTISE_10HALF | phyADVERTISE_10FULL | \
phyADVERTISE_100HALF | phyADVERTISE_100FULL )
/* Send a reset commando to a set of PHY-ports. */
static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask );
static BaseType_t xHas_1F_PHYSPCS( uint32_t ulPhyID )
{
BaseType_t xResult;
switch( ulPhyID )
{
case PHY_ID_LAN8720:
case PHY_ID_LAN8742A:
case PHY_ID_KSZ8041:
/*
case PHY_ID_KSZ8051: // same ID as 8041
case PHY_ID_KSZ8081: // same ID as 8041
*/
case PHY_ID_KSZ8863:
default:
/* Most PHY's have a 1F_PHYSPCS */
xResult = pdTRUE;
break;
case PHY_ID_DP83848I:
xResult = pdFALSE;
break;
}
return xResult;
}
/*-----------------------------------------------------------*/
static BaseType_t xHas_19_PHYCR( uint32_t ulPhyID )
{
BaseType_t xResult;
switch( ulPhyID )
{
case PHY_ID_LAN8742A:
case PHY_ID_DP83848I:
xResult = pdTRUE;
break;
default:
/* Most PHY's do not have a 19_PHYCR */
xResult = pdFALSE;
break;
}
return xResult;
}
/*-----------------------------------------------------------*/
/* Initialise the struct and assign a PHY-read and -write function. */
void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhyRead, xApplicationPhyWriteHook_t fnPhyWrite )
{
memset( ( void * )pxPhyObject, '\0', sizeof( *pxPhyObject ) );
pxPhyObject->fnPhyRead = fnPhyRead;
pxPhyObject->fnPhyWrite = fnPhyWrite;
}
/*-----------------------------------------------------------*/
/* Discover all PHY's connected by polling 32 indexes ( zero-based ) */
BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject )
{
BaseType_t xPhyAddress;
pxPhyObject->xPortCount = 0;
for( xPhyAddress = phyMIN_PHY_ADDRESS; xPhyAddress <= phyMAX_PHY_ADDRESS; xPhyAddress++ )
{
uint32_t ulLowerID;
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_03_PHYSID2, &ulLowerID );
/* A valid PHY id can not be all zeros or all ones. */
if( ( ulLowerID != ( uint16_t )~0u ) && ( ulLowerID != ( uint16_t )0u ) )
{
uint32_t ulUpperID;
uint32_t ulPhyID;
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_02_PHYSID1, &ulUpperID );
ulPhyID = ( ( ( uint32_t ) ulUpperID ) << 16 ) | ( ulLowerID & 0xFFF0 );
pxPhyObject->ucPhyIndexes[ pxPhyObject->xPortCount ] = xPhyAddress;
pxPhyObject->ulPhyIDs[ pxPhyObject->xPortCount ] = ulPhyID;
pxPhyObject->xPortCount++;
/* See if there is more storage space. */
if( pxPhyObject->xPortCount == ipconfigPHY_MAX_PORTS )
{
break;
}
}
}
if( pxPhyObject->xPortCount > 0 )
{
FreeRTOS_printf( ( "PHY ID %lX\n", pxPhyObject->ulPhyIDs[ 0 ] ) );
eventLogAdd( "PHY ID 0x%lX", pxPhyObject->ulPhyIDs[ 0 ] );
}
return pxPhyObject->xPortCount;
}
/*-----------------------------------------------------------*/
/* Send a reset commando to a set of PHY-ports. */
static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
{
uint32_t ulDoneMask, ulConfig;
TickType_t xRemainingTime;
TimeOut_t xTimer;
BaseType_t xPhyIndex;
/* A bit-mask ofPHY ports that are ready. */
ulDoneMask = 0ul;
/* Set the RESET bits high. */
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
/* Read Control register. */
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig | phyBMCR_RESET );
}
xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL );
vTaskSetTimeOutState( &xTimer );
/* The reset should last less than a second. */
for( ;; )
{
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
if( ( ulConfig & phyBMCR_RESET ) == 0 )
{
FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET %d ready\n", (int)xPhyIndex ) );
ulDoneMask |= ( 1ul << xPhyIndex );
}
}
if( ulDoneMask == ulPhyMask )
{
break;
}
if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
{
FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );
break;
}
}
/* Clear the reset bits. */
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig & ~phyBMCR_RESET );
}
vTaskDelay( pdMS_TO_TICKS( 50ul ) );
eventLogAdd( "PHY reset %d ports", (int)pxPhyObject->xPortCount );
return ulDoneMask;
}
/*-----------------------------------------------------------*/
BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties )
{
uint32_t ulConfig, ulAdvertise;
BaseType_t xPhyIndex;
if( pxPhyObject->xPortCount < 1 )
{
FreeRTOS_printf( ( "xPhyResetAll: No PHY's detected.\n" ) );
return -1;
}
/* The expected ID for the 'LAN8742A' is 0x0007c130. */
/* The expected ID for the 'LAN8720' is 0x0007c0f0. */
/* The expected ID for the 'DP83848I' is 0x20005C90. */
/* Set advertise register. */
if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) && ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) )
{
ulAdvertise = phyADVERTISE_CSMA | phyADVERTISE_ALL;
/* Reset auto-negotiation capability. */
}
else
{
ulAdvertise = phyADVERTISE_CSMA;
if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO )
{
if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
{
ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_100FULL;
}
else
{
ulAdvertise |= phyADVERTISE_10HALF | phyADVERTISE_100HALF;
}
}
else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO )
{
if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )
{
ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_10HALF;
}
else
{
ulAdvertise |= phyADVERTISE_100FULL | phyADVERTISE_100HALF;
}
}
else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 )
{
if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
{
ulAdvertise |= phyADVERTISE_100FULL;
}
else
{
ulAdvertise |= phyADVERTISE_100HALF;
}
}
else
{
if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
{
ulAdvertise |= phyADVERTISE_10FULL;
}
else
{
ulAdvertise |= phyADVERTISE_10HALF;
}
}
}
/* Send a reset commando to a set of PHY-ports. */
xPhyReset( pxPhyObject, xPhyGetMask( pxPhyObject ) );
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
/* Write advertise register. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, ulAdvertise );
/*
AN_EN AN1 AN0 Forced Mode
0 0 0 10BASE-T, Half-Duplex
0 0 1 10BASE-T, Full-Duplex
0 1 0 100BASE-TX, Half-Duplex
0 1 1 100BASE-TX, Full-Duplex
AN_EN AN1 AN0 Advertised Mode
1 0 0 10BASE-T, Half/Full-Duplex
1 0 1 100BASE-TX, Half/Full-Duplex
1 1 0 10BASE-T Half-Duplex
100BASE-TX, Half-Duplex
1 1 1 10BASE-T, Half/Full-Duplex
100BASE-TX, Half/Full-Duplex
*/
/* Read Control register. */
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig );
ulConfig &= ~( phyBMCR_SPEED_100 | phyBMCR_FULL_DUPLEX );
ulConfig |= phyBMCR_AN_ENABLE;
if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 )
{
ulConfig |= phyBMCR_SPEED_100;
}
else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 )
{
ulConfig &= ~phyBMCR_SPEED_100;
}
if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL )
{
ulConfig |= phyBMCR_FULL_DUPLEX;
}
else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_HALF )
{
ulConfig &= ~phyBMCR_FULL_DUPLEX;
}
if( xHas_19_PHYCR( ulPhyID ) )
{
uint32_t ulPhyControl;
/* Read PHY Control register. */
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_19_PHYCR, &ulPhyControl );
/* Clear bits which might get set: */
ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );
if( pxPhyProperties->ucMDI_X == PHY_MDIX_AUTO )
{
ulPhyControl |= PHYCR_MDIX_EN;
}
else if( pxPhyProperties->ucMDI_X == PHY_MDIX_CROSSED )
{
/* Force direct link = Use crossed RJ45 cable. */
ulPhyControl &= ~PHYCR_MDIX_FORCE;
}
else
{
/* Force crossed link = Use direct RJ45 cable. */
ulPhyControl |= PHYCR_MDIX_FORCE;
}
/* update PHY Control Register. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_19_PHYCR, ulPhyControl );
}
FreeRTOS_printf( ( "+TCP: advertise: %04lX config %04lX\n", ulAdvertise, ulConfig ) );
eventLogAdd( "adv: %04lX config %04lX", ulAdvertise, ulConfig );
}
/* Keep these values for later use. */
pxPhyObject->ulBCRValue = ulConfig;
pxPhyObject->ulACRValue = ulAdvertise;
return 0;
}
/*-----------------------------------------------------------*/
BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
{
BaseType_t xPhyIndex;
uint32_t ulValue, ulBitMask = ( uint32_t )1u;
ulValue = ( uint32_t )0u;
if( pxPhyObject->xPhyPreferences.ucDuplex == PHY_DUPLEX_FULL )
{
ulValue |= phyBMCR_FULL_DUPLEX;
}
if( pxPhyObject->xPhyPreferences.ucSpeed == PHY_SPEED_100 )
{
ulValue |= phyBMCR_SPEED_100;
}
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
if( ( ulPhyMask & ulBitMask ) != 0lu )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
/* Enable Auto-Negotiation. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulValue );
}
}
return 0;
}
/*-----------------------------------------------------------*/
BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask )
{
uint32_t xPhyIndex, ulDoneMask, ulBitMask;
uint32_t ulPHYLinkStatus, ulRegValue;
TickType_t xRemainingTime;
TimeOut_t xTimer;
if( ulPhyMask == ( uint32_t )0u )
{
return 0;
}
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ )
{
if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
/* Enable Auto-Negotiation. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, pxPhyObject->ulACRValue);
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue | phyBMCR_AN_RESTART );
}
}
eventLogAdd( "AN start" );
xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 3000UL );
vTaskSetTimeOutState( &xTimer );
ulDoneMask = 0;
/* Wait until the auto-negotiation will be completed */
for( ;; )
{
ulBitMask = ( uint32_t )1u;
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
if( ( ulPhyMask & ulBitMask ) != 0lu )
{
if( ( ulDoneMask & ulBitMask ) == 0lu )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );
if( ( ulRegValue & phyBMSR_AN_COMPLETE ) != 0 )
{
ulDoneMask |= ulBitMask;
}
}
}
}
if( ulPhyMask == ulDoneMask )
{
break;
}
if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
{
FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) );
eventLogAdd( "ANtimed out");
break;
}
}
eventLogAdd( "AN done %02lX / %02lX", ulDoneMask, ulPhyMask );
if( ulDoneMask != ( uint32_t)0u )
{
ulBitMask = ( uint32_t )1u;
pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask );
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];
if( ( ulDoneMask & ulBitMask ) == ( uint32_t )0u )
{
continue;
}
/* Clear the 'phyBMCR_AN_RESTART' bit. */
pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue );
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue);
if( ( ulRegValue & phyBMSR_LINK_STATUS ) != 0 )
{
ulPHYLinkStatus |= phyBMSR_LINK_STATUS;
pxPhyObject->ulLinkStatusMask |= ulBitMask;
}
else
{
ulPHYLinkStatus &= ~( phyBMSR_LINK_STATUS );
}
if( xHas_1F_PHYSPCS( ulPhyID ) )
{
/* 31 RW PHY Special Control Status */
uint32_t ulControlStatus;
pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus);
ulRegValue = 0;
if( ( ulControlStatus & phyPHYSPCS_FULL_DUPLEX ) != 0 )
{
ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
}
if( ( ulControlStatus & phyPHYSPCS_SPEED_MASK ) == phyPHYSPCS_SPEED_10 )
{
ulRegValue |= phyPHYSTS_SPEED_STATUS;
}
}
else
{
/* Read the result of the auto-negotiation. */
pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue);
}
FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n",
ulRegValue,
( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half",
( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100,
( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0) ? "high" : "low" ) );
eventLogAdd( "%s duplex %u mbit %s st",
( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half",
( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100,
( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0) ? "high" : "low" );
{
uint32_t regs[4];
int i,j;
int address = 0x10;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
pxPhyObject->fnPhyRead( xPhyAddress, address, regs + j );
address++;
}
eventLogAdd("%04lX %04lX %04lX %04lX",
regs[0], regs[1], regs[2], regs[3]);
}
}
if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t )0u )
{
pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL;
}
else
{
pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_HALF;
}
if( ( ulRegValue & phyPHYSTS_SPEED_STATUS ) != 0 )
{
pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_10;
}
else
{
pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100;
}
}
} /* if( ulDoneMask != ( uint32_t)0u ) */
return 0;
}
/*-----------------------------------------------------------*/
BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception )
{
uint32_t ulStatus, ulBitMask = 1u;
BaseType_t xPhyIndex;
BaseType_t xNeedCheck = pdFALSE;
if( xHadReception > 0 )
{
/* A packet was received. No need to check for the PHY status now,
but set a timer to check it later on. */
vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
}
else if( xTaskCheckForTimeOut( &( pxPhyObject->xLinkStatusTimer ), &( pxPhyObject->xLinkStatusRemaining ) ) != pdFALSE )
{
for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
{
BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
if( pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulStatus ) == 0 )
{
if( !!( pxPhyObject->ulLinkStatusMask & ulBitMask ) != !!( ulStatus & phyBMSR_LINK_STATUS ) )
{
if( ( ulStatus & phyBMSR_LINK_STATUS ) != 0 )
{
pxPhyObject->ulLinkStatusMask |= ulBitMask;
}
else
{
pxPhyObject->ulLinkStatusMask &= ~( ulBitMask );
}
FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) );
eventLogAdd( "PHY LS now %02lX", pxPhyObject->ulLinkStatusMask );
xNeedCheck = pdTRUE;
}
}
}
vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) );
if( ( pxPhyObject->ulLinkStatusMask & phyBMSR_LINK_STATUS ) != 0 )
{
pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS );
}
else
{
pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS );
}
}
return xNeedCheck;
}
/*-----------------------------------------------------------*/

View file

@ -78,23 +78,13 @@
#include "FreeRTOS_DNS.h" #include "FreeRTOS_DNS.h"
#include "NetworkBufferManagement.h" #include "NetworkBufferManagement.h"
#include "NetworkInterface.h" #include "NetworkInterface.h"
#include "phyHandling.h"
/* ST includes. */ /* ST includes. */
#ifdef STM32F7xx
#include "stm32f7xx_hal.h"
#else
#include "stm32f4xx_hal.h" #include "stm32f4xx_hal.h"
#ifndef BMSR_LINK_STATUS
#define BMSR_LINK_STATUS 0x0004UL
#endif
#ifndef PHY_LS_HIGH_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
receiving packets. */
#define PHY_LS_HIGH_CHECK_TIME_MS 15000
#endif
#ifndef PHY_LS_LOW_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still low every second. */
#define PHY_LS_LOW_CHECK_TIME_MS 1000
#endif #endif
/* Interrupt events to process. Currently only the Rx event is processed /* Interrupt events to process. Currently only the Rx event is processed
@ -110,75 +100,7 @@ expansion. */
ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \
ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T ) ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T )
/* Naming and numbering of PHY registers. */
#define PHY_REG_00_BMCR 0x00 /* Basic Mode Control Register. */
#define PHY_REG_01_BMSR 0x01 /* Basic Mode Status Register. */
#define PHY_REG_02_PHYSID1 0x02 /* PHYS ID 1 */
#define PHY_REG_03_PHYSID2 0x03 /* PHYS ID 2 */
#define PHY_REG_04_ADVERTISE 0x04 /* Advertisement control reg */
#define PHY_ID_LAN8720 0x0007c0f0
#define PHY_ID_DP83848I 0x20005C90
#ifndef USE_STM324xG_EVAL
#define USE_STM324xG_EVAL 1
#endif
#if( USE_STM324xG_EVAL == 0 )
#define EXPECTED_PHY_ID PHY_ID_LAN8720
#define PHY_REG_1F_PHYSPCS 0x1F /* 31 RW PHY Special Control Status */
/* Use 3 bits in register 31 */
#define PHYSPCS_SPEED_MASK 0x0C
#define PHYSPCS_SPEED_10 0x04
#define PHYSPCS_SPEED_100 0x08
#define PHYSPCS_FULL_DUPLEX 0x10
#else
#define EXPECTED_PHY_ID PHY_ID_DP83848I
#define PHY_REG_10_PHY_SR 0x10 /* PHY status register Offset */
#define PHY_REG_19_PHYCR 0x19 /* 25 RW PHY Control Register */
#endif
/* Some defines used internally here to indicate preferences about speed, MDIX
(wired direct or crossed), and duplex (half or full). */
#define PHY_SPEED_10 1
#define PHY_SPEED_100 2
#define PHY_SPEED_AUTO (PHY_SPEED_10|PHY_SPEED_100)
#define PHY_MDIX_DIRECT 1
#define PHY_MDIX_CROSSED 2
#define PHY_MDIX_AUTO (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT)
#define PHY_DUPLEX_HALF 1
#define PHY_DUPLEX_FULL 2
#define PHY_DUPLEX_AUTO (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF)
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
/*
* Description of all capabilities that can be advertised to
* the peer (usually a switch or router).
*/
#define ADVERTISE_CSMA 0x0001 /* Only selector supported. */
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex. */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex. */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex. */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex. */
#define ADVERTISE_ALL ( ADVERTISE_10HALF | ADVERTISE_10FULL | \
ADVERTISE_100HALF | ADVERTISE_100FULL)
/*
* Value for the 'PHY_REG_00_BMCR', the PHY's Basic Mode Control Register.
*/
#define BMCR_FULLDPLX 0x0100 /* Full duplex. */
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart. */
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation. */
#define BMCR_SPEED100 0x2000 /* Select 100Mbps. */
#define BMCR_RESET 0x8000 /* Reset the PHY. */
#define PHYCR_MDIX_EN 0x8000 /* Enable Auto MDIX. */
#define PHYCR_MDIX_FORCE 0x4000 /* Force MDIX crossed. */
#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */ #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */
@ -223,6 +145,18 @@ FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
#define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE ) #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
#endif #endif
/* Two choices must be made: RMII versus MII,
and the index of the PHY in use ( between 0 and 31 ). */
#ifndef ipconfigUSE_RMII
#ifdef STM32F7xx
#define ipconfigUSE_RMII 1
#else
#define ipconfigUSE_RMII 0
#endif /* STM32F7xx */
#endif /* ipconfigUSE_RMII */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -263,43 +197,30 @@ static void prvDMATxDescListInit( void );
*/ */
static void prvDMARxDescListInit( void ); static void prvDMARxDescListInit( void );
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
/* After packets have been sent, the network /* After packets have been sent, the network
buffers will be released. */ buffers will be released. */
static void vClearTXBuffers( void ); static void vClearTXBuffers( void );
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
typedef struct _PhyProperties_t
{
uint8_t speed;
uint8_t mdix;
uint8_t duplex;
uint8_t spare;
} PhyProperties_t;
/* Bit map of outstanding ETH interrupt events for processing. Currently only /* Bit map of outstanding ETH interrupt events for processing. Currently only
the Rx interrupt is handled, although code is included for other events to the Rx interrupt is handled, although code is included for other events to
enable future expansion. */ enable future expansion. */
static volatile uint32_t ulISREvents; static volatile uint32_t ulISREvents;
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
static uint32_t ulPHYLinkStatus = 0;
#if( ipconfigUSE_LLMNR == 1 ) #if( ipconfigUSE_LLMNR == 1 )
static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
#endif #endif
static EthernetPhy_t xPhyObject;
/* Ethernet handle. */ /* Ethernet handle. */
static ETH_HandleTypeDef xETH; static ETH_HandleTypeDef xETH;
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
/* xTXDescriptorSemaphore is a counting semaphore with /* xTXDescriptorSemaphore is a counting semaphore with
a maximum count of ETH_TXBUFNB, which is the number of a maximum count of ETH_TXBUFNB, which is the number of
DMA TX descriptors. */ DMA TX descriptors. */
static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/* /*
* Note: it is adviced to define both * Note: it is adviced to define both
@ -314,14 +235,29 @@ static ETH_HandleTypeDef xETH;
* TX buffers are allocated in a zero-copy driver. * TX buffers are allocated in a zero-copy driver.
*/ */
/* MAC buffers: ---------------------------------------------------------*/ /* MAC buffers: ---------------------------------------------------------*/
__ALIGN_BEGIN ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ] __ALIGN_END;/* Ethernet Rx MA Descriptor */
/* Put the DMA descriptors in '.first_data'.
This is important for STM32F7, which has an L1 data cache.
The first 64KB of the SRAM is not cached. */
/* Ethernet Rx MA Descriptor */
__attribute__ ((aligned (32)))
__attribute__ ((section(".first_data")))
ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ];
#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) #if( ipconfigZERO_COPY_RX_DRIVER == 0 )
__ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; /* Ethernet Receive Buffer */ /* Ethernet Receive Buffer */
__ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END;
#endif #endif
__ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ] __ALIGN_END;/* Ethernet Tx DMA Descriptor */ /* Ethernet Tx DMA Descriptor */
__attribute__ ((aligned (32)))
__attribute__ ((section(".first_data")))
ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ];
#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) #if( ipconfigZERO_COPY_TX_DRIVER == 0 )
__ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; /* Ethernet Transmit Buffer */ /* Ethernet Transmit Buffer */
__ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END;
#endif #endif
#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
@ -330,12 +266,6 @@ __ALIGN_BEGIN ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ] __ALIGN_END;/* Eth
static __IO ETH_DMADescTypeDef *DMATxDescToClear; static __IO ETH_DMADescTypeDef *DMATxDescToClear;
#endif #endif
/* Value to be written into the 'Basic mode Control Register'. */
static uint32_t ulBCRvalue;
/* Value to be written into the 'Advertisement Control Register'. */
static uint32_t ulACRValue;
/* ucMACAddress as it appears in main.c */ /* ucMACAddress as it appears in main.c */
extern const uint8_t ucMACAddress[ 6 ]; extern const uint8_t ucMACAddress[ 6 ];
@ -348,13 +278,13 @@ static TaskHandle_t xEMACTaskHandle = NULL;
const PhyProperties_t xPHYProperties = const PhyProperties_t xPHYProperties =
{ {
#if( ipconfigETHERNET_AN_ENABLE != 0 ) #if( ipconfigETHERNET_AN_ENABLE != 0 )
.speed = PHY_SPEED_AUTO, .ucSpeed = PHY_SPEED_AUTO,
.duplex = PHY_DUPLEX_AUTO, .ucDuplex = PHY_DUPLEX_AUTO,
#else #else
#if( ipconfigETHERNET_USE_100MB != 0 ) #if( ipconfigETHERNET_USE_100MB != 0 )
.speed = PHY_SPEED_100, .ucSpeed = PHY_SPEED_100,
#else #else
.speed = PHY_SPEED_10, .ucSpeed = PHY_SPEED_10,
#endif #endif
#if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 ) #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 )
@ -365,11 +295,11 @@ const PhyProperties_t xPHYProperties =
#endif #endif
#if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 ) #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 )
.mdix = PHY_MDIX_AUTO, .ucMDI_X = PHY_MDIX_AUTO,
#elif( ipconfigETHERNET_CROSSED_LINK != 0 ) #elif( ipconfigETHERNET_CROSSED_LINK != 0 )
.mdix = PHY_MDIX_CROSSED, .ucMDI_X = PHY_MDIX_CROSSED,
#else #else
.mdix = PHY_MDIX_DIRECT, .ucMDI_X = PHY_MDIX_DIRECT,
#endif #endif
}; };
@ -390,7 +320,6 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ) void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth )
{ {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
@ -407,17 +336,16 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
} }
} }
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
static void vClearTXBuffers() static void vClearTXBuffers()
{ {
__IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc; __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc;
size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
NetworkBufferDescriptor_t *pxNetworkBuffer; NetworkBufferDescriptor_t *pxNetworkBuffer;
uint8_t *ucPayLoad; uint8_t *ucPayLoad;
size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); #endif
/* This function is called after a TX-completion interrupt. /* This function is called after a TX-completion interrupt.
It will release each Network Buffer used in xNetworkInterfaceOutput(). It will release each Network Buffer used in xNetworkInterfaceOutput().
@ -429,7 +357,8 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
{ {
break; break;
} }
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr; ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr;
if( ucPayLoad != NULL ) if( ucPayLoad != NULL )
@ -441,6 +370,8 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
} }
DMATxDescToClear->Buffer1Addr = ( uint32_t )0u; DMATxDescToClear->Buffer1Addr = ( uint32_t )0u;
} }
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr ); DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr );
@ -449,7 +380,6 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGive( xTXDescriptorSemaphore ); xSemaphoreGive( xTXDescriptorSemaphore );
} }
} }
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void ) BaseType_t xNetworkInterfaceInitialise( void )
@ -458,16 +388,12 @@ HAL_StatusTypeDef hal_eth_init_status;
BaseType_t xResult; BaseType_t xResult;
if( xEMACTaskHandle == NULL ) if( xEMACTaskHandle == NULL )
{
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{ {
if( xTXDescriptorSemaphore == NULL ) if( xTXDescriptorSemaphore == NULL )
{ {
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB ); xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB );
configASSERT( xTXDescriptorSemaphore ); configASSERT( xTXDescriptorSemaphore );
} }
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/* Initialise ETH */ /* Initialise ETH */
@ -475,7 +401,8 @@ BaseType_t xResult;
xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
xETH.Init.Speed = ETH_SPEED_100M; xETH.Init.Speed = ETH_SPEED_100M;
xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
xETH.Init.PhyAddress = 1; /* Value of PhyAddress doesn't matter, will be probed for. */
xETH.Init.PhyAddress = 0;
xETH.Init.MACAddr = ( uint8_t *) ucMACAddress; xETH.Init.MACAddr = ( uint8_t *) ucMACAddress;
xETH.Init.RxMode = ETH_RXINTERRUPT_MODE; xETH.Init.RxMode = ETH_RXINTERRUPT_MODE;
@ -485,7 +412,16 @@ BaseType_t xResult;
by the peripheral. */ by the peripheral. */
xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
#if( ipconfigUSE_RMII != 0 )
{
xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
}
#else
{
xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII; xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII;
}
#endif /* ipconfigUSE_RMII */
hal_eth_init_status = HAL_ETH_Init( &xETH ); hal_eth_init_status = HAL_ETH_Init( &xETH );
/* Only for inspection by debugger. */ /* Only for inspection by debugger. */
@ -499,12 +435,8 @@ BaseType_t xResult;
memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) ); memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) );
memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) ); memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) );
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Initialize Tx Descriptors list: Chain Mode */ /* Initialize Tx Descriptors list: Chain Mode */
DMATxDescToClear = DMATxDscrTab; DMATxDescToClear = DMATxDscrTab;
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/* Initialise TX-descriptors. */ /* Initialise TX-descriptors. */
prvDMATxDescListInit(); prvDMATxDescListInit();
@ -529,7 +461,7 @@ BaseType_t xResult;
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle ); xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
} /* if( xEMACTaskHandle == NULL ) */ } /* if( xEMACTaskHandle == NULL ) */
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) if( xPhyObject.ulLinkStatusMask != 0 )
{ {
xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS; xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
xResult = pdPASS; xResult = pdPASS;
@ -538,7 +470,7 @@ BaseType_t xResult;
else else
{ {
/* For now pdFAIL will be returned. But prvEMACHandlerTask() is running /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
and it will keep on checking the PHY and set ulPHYLinkStatus when necessary. */ and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */
xResult = pdFAIL; xResult = pdFAIL;
FreeRTOS_printf( ( "Link Status still low\n" ) ) ; FreeRTOS_printf( ( "Link Status still low\n" ) ) ;
} }
@ -683,6 +615,12 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
{ {
ProtocolPacket_t *pxPacket; ProtocolPacket_t *pxPacket;
#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
{
configASSERT( bReleaseAfterSend != 0 );
}
#endif /* ipconfigZERO_COPY_RX_DRIVER */
/* If the peripheral must calculate the checksum, it wants /* If the peripheral must calculate the checksum, it wants
the protocol checksum to have a value of zero. */ the protocol checksum to have a value of zero. */
pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer ); pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer );
@ -697,28 +635,21 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
/* Open a do {} while ( 0 ) loop to be able to call break. */ /* Open a do {} while ( 0 ) loop to be able to call break. */
do do
{ {
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) if( xPhyObject.ulLinkStatusMask != 0 )
{ {
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
if( xTXDescriptorSemaphore == NULL )
{
break;
}
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
{ {
/* Time-out waiting for a free TX descriptor. */ /* Time-out waiting for a free TX descriptor. */
break; break;
} }
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/* This function does the actual transmission of the packet. The packet is /* This function does the actual transmission of the packet. The packet is
contained in 'pxDescriptor' that is passed to the function. */ contained in 'pxDescriptor' that is passed to the function. */
pxDmaTxDesc = xETH.TxDesc; pxDmaTxDesc = xETH.TxDesc;
/* Is this buffer available? */ /* Is this buffer available? */
if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 ) configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 );
{ {
/* Is this buffer available? */ /* Is this buffer available? */
/* Get bytes in current buffer. */ /* Get bytes in current buffer. */
@ -733,20 +664,20 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
{ {
/* Copy the bytes. */ /* Copy the bytes. */
memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize ); memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize );
pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL;
} }
#else #else
{ {
/* Move the buffer. */ /* Move the buffer. */
pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer; pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer;
/* Ask to set the IPv4 checksum.
Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
/* The Network Buffer has been passed to DMA, no need to release it. */ /* The Network Buffer has been passed to DMA, no need to release it. */
bReleaseAfterSend = pdFALSE_UNSIGNED; bReleaseAfterSend = pdFALSE_UNSIGNED;
} }
#endif /* ipconfigZERO_COPY_TX_DRIVER */ #endif /* ipconfigZERO_COPY_TX_DRIVER */
/* Ask to set the IPv4 checksum.
Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */
pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC;
/* Prepare transmit descriptors to give to DMA. */ /* Prepare transmit descriptors to give to DMA. */
/* Set LAST and FIRST segment */ /* Set LAST and FIRST segment */
@ -758,7 +689,8 @@ const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
/* Point to next descriptor */ /* Point to next descriptor */
xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr ); xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr );
/* Ensure completion of memory access */
__DSB();
/* Resume DMA transmission*/ /* Resume DMA transmission*/
xETH.Instance->DMATPDR = 0; xETH.Instance->DMATPDR = 0;
iptraceNETWORK_INTERFACE_TRANSMIT(); iptraceNETWORK_INTERFACE_TRANSMIT();
@ -977,6 +909,8 @@ uint8_t *pucBuffer;
pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE;
pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN; pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN;
/* Ensure completion of memory access */
__DSB();
/* When Rx Buffer unavailable flag is set clear it and resume /* When Rx Buffer unavailable flag is set clear it and resume
reception. */ reception. */
if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 ) if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 )
@ -993,305 +927,141 @@ uint8_t *pucBuffer;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue )
{
uint16_t usPrevAddress = xETH.Init.PhyAddress;
BaseType_t xResult;
HAL_StatusTypeDef xHALResult;
xETH.Init.PhyAddress = xAddress;
xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue );
xETH.Init.PhyAddress = usPrevAddress;
if( xHALResult == HAL_OK )
{
xResult = 0;
}
else
{
xResult = -1;
}
return xResult;
}
/*-----------------------------------------------------------*/
BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue )
{
uint16_t usPrevAddress = xETH.Init.PhyAddress;
BaseType_t xResult;
HAL_StatusTypeDef xHALResult;
xETH.Init.PhyAddress = xAddress;
xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue );
xETH.Init.PhyAddress = usPrevAddress;
if( xHALResult == HAL_OK )
{
xResult = 0;
}
else
{
xResult = -1;
}
return xResult;
}
/*-----------------------------------------------------------*/
void phy_test()
{
BaseType_t xPhyCount;
BaseType_t xPhyIndex;
vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );
xPhyCount = xPhyDiscover( &xPhyObject );
FreeRTOS_printf( ( "PHY count %ld\n", xPhyCount ) );
for( xPhyIndex = 0; xPhyIndex < xPhyCount; xPhyIndex++ )
{
FreeRTOS_printf( ( "PHY[%d] at address %d ( 0x%08X )\n",
xPhyIndex,
xPhyObject.ucPhyIndexes[ xPhyIndex ],
xPhyObject.ulPhyIDs[ xPhyIndex ] ) );
}
}
void vMACBProbePhy( void ) void vMACBProbePhy( void )
{ {
uint32_t ulConfig, ulAdvertise, ulLower, ulUpper, ulMACPhyID, ulValue; vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );
TimeOut_t xPhyTime; xPhyDiscover( &xPhyObject );
TickType_t xRemTime = 0; xPhyConfigure( &xPhyObject, &xPHYProperties );
#if( EXPECTED_PHY_ID == PHY_ID_DP83848I )
uint32_t ulPhyControl;
#endif
HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_03_PHYSID2, &ulLower);
HAL_ETH_ReadPHYRegister(&xETH, PHY_REG_02_PHYSID1, &ulUpper);
ulMACPhyID = ( ( ulUpper << 16 ) & 0xFFFF0000 ) | ( ulLower & 0xFFF0 );
/* The expected ID for the 'LAN8720' is 0x0007c0f0. */
/* The expected ID for the 'DP83848I' is 0x20005C90. */
FreeRTOS_printf( ( "PHY ID %lX (%s)\n", ulMACPhyID,
( ulMACPhyID == EXPECTED_PHY_ID ) ? "OK" : "Unknown" ) );
/* Remove compiler warning if FreeRTOS_printf() is not defined. */
( void ) ulMACPhyID;
/* Set advertise register. */
if( ( xPHYProperties.speed == PHY_SPEED_AUTO ) && ( xPHYProperties.duplex == PHY_DUPLEX_AUTO ) )
{
ulAdvertise = ADVERTISE_CSMA | ADVERTISE_ALL;
/* Reset auto-negotiation capability. */
}
else
{
ulAdvertise = ADVERTISE_CSMA;
if( xPHYProperties.speed == PHY_SPEED_AUTO )
{
if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
{
ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_100FULL;
}
else
{
ulAdvertise |= ADVERTISE_10HALF | ADVERTISE_100HALF;
}
}
else if( xPHYProperties.duplex == PHY_DUPLEX_AUTO )
{
if( xPHYProperties.speed == PHY_SPEED_10 )
{
ulAdvertise |= ADVERTISE_10FULL | ADVERTISE_10HALF;
}
else
{
ulAdvertise |= ADVERTISE_100FULL | ADVERTISE_100HALF;
}
}
else if( xPHYProperties.speed == PHY_SPEED_100 )
{
if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
{
ulAdvertise |= ADVERTISE_100FULL;
}
else
{
ulAdvertise |= ADVERTISE_100HALF;
}
}
else
{
if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
{
ulAdvertise |= ADVERTISE_10FULL;
}
else
{
ulAdvertise |= ADVERTISE_10HALF;
}
}
}
/* Read Control register. */
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig | BMCR_RESET );
xRemTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL );
vTaskSetTimeOutState( &xPhyTime );
for( ; ; )
{
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulValue );
if( ( ulValue & BMCR_RESET ) == 0 )
{
FreeRTOS_printf( ( "BMCR_RESET ready\n" ) );
break;
}
if( xTaskCheckForTimeOut( &xPhyTime, &xRemTime ) != pdFALSE )
{
FreeRTOS_printf( ( "BMCR_RESET timed out\n" ) );
break;
}
}
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulConfig & ~BMCR_RESET );
vTaskDelay( pdMS_TO_TICKS( 50ul ) );
/* Write advertise register. */
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulAdvertise );
/*
AN_EN AN1 AN0 Forced Mode
0 0 0 10BASE-T, Half-Duplex
0 0 1 10BASE-T, Full-Duplex
0 1 0 100BASE-TX, Half-Duplex
0 1 1 100BASE-TX, Full-Duplex
AN_EN AN1 AN0 Advertised Mode
1 0 0 10BASE-T, Half/Full-Duplex
1 0 1 100BASE-TX, Half/Full-Duplex
1 1 0 10BASE-T Half-Duplex
100BASE-TX, Half-Duplex
1 1 1 10BASE-T, Half/Full-Duplex
100BASE-TX, Half/Full-Duplex
*/
/* Read Control register. */
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_00_BMCR, &ulConfig );
ulConfig &= ~( BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX );
/* HT 12/9/14: always set AN-restart and AN-enable, even though the choices
are limited. */
ulConfig |= (BMCR_ANRESTART | BMCR_ANENABLE);
if( xPHYProperties.speed == PHY_SPEED_100 )
{
ulConfig |= BMCR_SPEED100;
}
else if( xPHYProperties.speed == PHY_SPEED_10 )
{
ulConfig &= ~BMCR_SPEED100;
}
if( xPHYProperties.duplex == PHY_DUPLEX_FULL )
{
ulConfig |= BMCR_FULLDPLX;
}
else if( xPHYProperties.duplex == PHY_DUPLEX_HALF )
{
ulConfig &= ~BMCR_FULLDPLX;
}
#if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
{
}
#elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
{
/* Read PHY Control register. */
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_19_PHYCR, &ulPhyControl );
/* Clear bits which might get set: */
ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE );
if( xPHYProperties.mdix == PHY_MDIX_AUTO )
{
ulPhyControl |= PHYCR_MDIX_EN;
}
else if( xPHYProperties.mdix == PHY_MDIX_CROSSED )
{
/* Force direct link = Use crossed RJ45 cable. */
ulPhyControl &= ~PHYCR_MDIX_FORCE;
}
else
{
/* Force crossed link = Use direct RJ45 cable. */
ulPhyControl |= PHYCR_MDIX_FORCE;
}
/* update PHY Control Register. */
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_19_PHYCR, ulPhyControl );
}
#endif
FreeRTOS_printf( ( "+TCP: advertise: %lX config %lX\n", ulAdvertise, ulConfig ) );
/* Now the two values to global values for later use. */
ulBCRvalue = ulConfig;
ulACRValue = ulAdvertise;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvEthernetUpdateConfig( BaseType_t xForce ) static void prvEthernetUpdateConfig( BaseType_t xForce )
{ {
__IO uint32_t ulTimeout = 0; FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n",
uint32_t ulRegValue = 0; xPhyObject.ulLinkStatusMask,
( int )xForce ) );
FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS %d Force %d\n", if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) )
( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ,
xForce ) );
if( ( xForce != pdFALSE ) || ( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) )
{ {
/* Restart the auto-negotiation. */ /* Restart the auto-negotiation. */
if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE ) if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE )
{ {
/* Enable Auto-Negotiation. */ xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) );
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue | BMCR_ANRESTART );
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_04_ADVERTISE, ulACRValue);
/* Wait until the auto-negotiation will be completed */
do
{
ulTimeout++;
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue );
} while( ( ( ulRegValue & PHY_AUTONEGO_COMPLETE) == 0 ) && ( ulTimeout < PHY_READ_TO ) );
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, ulBCRvalue & ~BMCR_ANRESTART );
if( ulTimeout < PHY_READ_TO )
{
/* Reset Timeout counter. */
ulTimeout = 0;
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &ulRegValue);
if( ( ulRegValue & BMSR_LINK_STATUS ) != 0 )
{
ulPHYLinkStatus |= BMSR_LINK_STATUS;
}
else
{
ulPHYLinkStatus &= ~( BMSR_LINK_STATUS );
}
#if( EXPECTED_PHY_ID == PHY_ID_LAN8720 )
{
/* 31 RW PHY Special Control Status */
uint32_t ulControlStatus;
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_1F_PHYSPCS, &ulControlStatus);
ulRegValue = 0;
if( ( ulControlStatus & PHYSPCS_FULL_DUPLEX ) != 0 )
{
ulRegValue |= PHY_DUPLEX_STATUS;
}
if( ( ulControlStatus & PHYSPCS_SPEED_MASK ) == PHYSPCS_SPEED_10 )
{
ulRegValue |= PHY_SPEED_STATUS;
}
}
#elif( EXPECTED_PHY_ID == PHY_ID_DP83848I )
{
/* Read the result of the auto-negotiation. */
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_10_PHY_SR, &ulRegValue);
}
#endif
FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n",
ulRegValue,
(ulRegValue & PHY_DUPLEX_STATUS) ? "full" : "half",
(ulRegValue & PHY_SPEED_STATUS) ? 10 : 100,
((ulPHYLinkStatus |= BMSR_LINK_STATUS) != 0) ? "high" : "low" ) );
/* Configure the MAC with the Duplex Mode fixed by the /* Configure the MAC with the Duplex Mode fixed by the
auto-negotiation process. */ auto-negotiation process. */
if( ( ulRegValue & PHY_DUPLEX_STATUS ) != ( uint32_t ) RESET ) if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL )
{ {
/* Set Ethernet duplex mode to Full-duplex following the
auto-negotiation. */
xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
} }
else else
{ {
/* Set Ethernet duplex mode to Half-duplex following the
auto-negotiation. */
xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX; xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX;
} }
/* Configure the MAC with the speed fixed by the /* Configure the MAC with the speed fixed by the
auto-negotiation process. */ auto-negotiation process. */
if( ( ulRegValue & PHY_SPEED_STATUS) != 0 ) if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 )
{ {
/* Set Ethernet speed to 10M following the
auto-negotiation. */
xETH.Init.Speed = ETH_SPEED_10M; xETH.Init.Speed = ETH_SPEED_10M;
} }
else else
{ {
/* Set Ethernet speed to 100M following the
auto-negotiation. */
xETH.Init.Speed = ETH_SPEED_100M; xETH.Init.Speed = ETH_SPEED_100M;
} }
} /* if( ulTimeout < PHY_READ_TO ) */
} }
else /* AutoNegotiation Disable */ else /* AutoNegotiation Disable */
{ {
uint16_t usValue;
/* Check parameters */ /* Check parameters */
assert_param( IS_ETH_SPEED( xETH.Init.Speed ) ); assert_param( IS_ETH_SPEED( xETH.Init.Speed ) );
assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) ); assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) );
/* Set MAC Speed and Duplex Mode to PHY */ if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX )
usValue = ( uint16_t ) ( xETH.Init.DuplexMode >> 3 ) | ( uint16_t ) ( xETH.Init.Speed >> 1 ); {
HAL_ETH_WritePHYRegister( &xETH, PHY_REG_00_BMCR, usValue ); xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF;
}
else
{
xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL;
}
if( xETH.Init.Speed == ETH_SPEED_10M )
{
xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10;
}
else
{
xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100;
}
xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO;
/* Use predefined (fixed) configuration. */
xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) );
} }
/* ETHERNET MAC Re-Configuration */ /* ETHERNET MAC Re-Configuration */
@ -1312,7 +1082,7 @@ BaseType_t xGetPhyLinkStatus( void )
{ {
BaseType_t xReturn; BaseType_t xReturn;
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) if( xPhyObject.ulLinkStatusMask != 0 )
{ {
xReturn = pdPASS; xReturn = pdPASS;
} }
@ -1325,27 +1095,45 @@ BaseType_t xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Uncomment this in case BufferAllocation_1.c is used. */
/*
#define niBUFFER_1_PACKET_SIZE 1536
static __attribute__ ((section(".first_data"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
uint8_t *ucRAMBuffer = ucNetworkPackets;
uint32_t ul;
for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
{
pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
*( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
}
}
*/
/*-----------------------------------------------------------*/
static void prvEMACHandlerTask( void *pvParameters ) static void prvEMACHandlerTask( void *pvParameters )
{ {
TimeOut_t xPhyTime;
TickType_t xPhyRemTime;
UBaseType_t uxLastMinBufferCount = 0; UBaseType_t uxLastMinBufferCount = 0;
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
UBaseType_t uxLastMinQueueSpace = 0; UBaseType_t uxLastMinQueueSpace = 0;
#endif #endif
UBaseType_t uxCurrentCount; UBaseType_t uxCurrentCount;
BaseType_t xResult = 0; BaseType_t xResult;
uint32_t xStatus;
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
/* Remove compiler warnings about unused parameters. */ /* Remove compiler warnings about unused parameters. */
( void ) pvParameters; ( void ) pvParameters;
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
for( ;; ) for( ;; )
{ {
xResult = 0;
uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
if( uxLastMinBufferCount != uxCurrentCount ) if( uxLastMinBufferCount != uxCurrentCount )
{ {
@ -1356,7 +1144,6 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
} }
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
if( xTXDescriptorSemaphore != NULL ) if( xTXDescriptorSemaphore != NULL )
{ {
static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1; static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1;
@ -1369,7 +1156,7 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
} }
} }
#endif
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
{ {
uxCurrentCount = uxGetMinimumIPQueueSpace(); uxCurrentCount = uxGetMinimumIPQueueSpace();
@ -1406,48 +1193,20 @@ const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
{ {
/* Code to release TX buffers if zero-copy is used. */ /* Code to release TX buffers if zero-copy is used. */
ulISREvents &= ~EMAC_IF_TX_EVENT; ulISREvents &= ~EMAC_IF_TX_EVENT;
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Check if DMA packets have been delivered. */ /* Check if DMA packets have been delivered. */
vClearTXBuffers(); vClearTXBuffers();
} }
#endif
}
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
{ {
/* Future extension: logging about errors that occurred. */ /* Future extension: logging about errors that occurred. */
ulISREvents &= ~EMAC_IF_ERR_EVENT; ulISREvents &= ~EMAC_IF_ERR_EVENT;
} }
if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
if( xResult > 0 )
{ {
/* A packet was received. No need to check for the PHY status now, /* Something has changed to a Link Status, need re-check. */
but set a timer to check it later on. */
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
xResult = 0;
}
else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
{
HAL_ETH_ReadPHYRegister( &xETH, PHY_REG_01_BMSR, &xStatus );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
{
ulPHYLinkStatus = xStatus;
FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
prvEthernetUpdateConfig( pdFALSE ); prvEthernetUpdateConfig( pdFALSE );
} }
vTaskSetTimeOutState( &xPhyTime );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
{
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
}
else
{
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
}
}
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -1456,3 +1215,4 @@ void ETH_IRQHandler( void )
{ {
HAL_ETH_IRQHandler( &xETH ); HAL_ETH_IRQHandler( &xETH );
} }

View file

@ -0,0 +1,119 @@
#warning Temoporary file and a dependent on the Zynq network interface.
/*
* uncached_memory.c
*
* This module will declare 1 MB of memory and switch off the caching for it.
*
* pucGetUncachedMemory( ulSize ) returns a trunc of this memory with a length
* rounded up to a multiple of 4 KB
*
* ucIsCachedMemory( pucBuffer ) returns non-zero if a given pointer is NOT
* within the range of the 1 MB non-cached memory.
*
*/
/*
* After "_end", 1 MB of uncached memory will be allocated for DMA transfers.
* Both the DMA descriptors as well as all EMAC TX-buffers will be allocated in
* uncached memory.
*/
#include "Zynq/x_emacpsif.h"
#include "Zynq/x_topology.h"
#include "xstatus.h"
#include "xparameters.h"
#include "xparameters_ps.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "FreeRTOS.h"
#include "uncached_memory.h"
#include "Demo_Logging.h"
#define UNCACHED_MEMORY_SIZE 0x100000ul
#define DDR_MEMORY_END (XPAR_PS7_DDR_0_S_AXI_HIGHADDR+1)
static void vInitialiseUncachedMemory( void );
static uint8_t *pucHeadOfMemory;
static uint32_t ulMemorySize;
static uint8_t *pucStartOfMemory = NULL;
uint8_t ucIsCachedMemory( const uint8_t *pucBuffer )
{
uint8_t ucReturn;
if( ( pucStartOfMemory != NULL ) &&
( pucBuffer >= pucStartOfMemory ) &&
( pucBuffer < ( pucStartOfMemory + UNCACHED_MEMORY_SIZE ) ) )
{
ucReturn = pdFALSE;
}
else
{
ucReturn = pdTRUE;
}
return ucReturn;
}
uint8_t *pucGetUncachedMemory( uint32_t ulSize )
{
uint8_t *pucReturn;
if( pucStartOfMemory == NULL )
{
vInitialiseUncachedMemory( );
}
if( ( pucStartOfMemory == NULL ) || ( ulSize > ulMemorySize ) )
{
pucReturn = NULL;
}
else
{
uint32_t ulSkipSize;
pucReturn = pucHeadOfMemory;
ulSkipSize = ( ulSize + 0x1000ul ) & ~0xffful;
pucHeadOfMemory += ulSkipSize;
ulMemorySize -= ulSkipSize;
}
return pucReturn;
}
extern u8 _end;
static void vInitialiseUncachedMemory( )
{
/* At the end of program's space... */
pucStartOfMemory = (uint8_t *) &_end;
/*
* Align the start address to 1 MB boundary.
*/
pucStartOfMemory = (uint8_t *)( ( ( uint32_t )pucStartOfMemory + UNCACHED_MEMORY_SIZE ) & ( ~( UNCACHED_MEMORY_SIZE - 1 ) ) );
if( ( ( u32 )pucStartOfMemory ) + UNCACHED_MEMORY_SIZE > DDR_MEMORY_END )
{
vLoggingPrintf("vInitialiseUncachedMemory: Can not allocate uncached memory\n" );
}
else
{
/*
* Some objects want to be stored in uncached memory. Hence the 1 MB
* address range that starts after "_end" is made uncached
* by setting appropriate attributes in the translation table.
*/
Xil_SetTlbAttributes( ( uint32_t )pucStartOfMemory, 0xc02 ); // addr, attr
/* For experiments in the SDIO driver, make the remaining uncached memory public */
pucHeadOfMemory = pucStartOfMemory;
ulMemorySize = UNCACHED_MEMORY_SIZE;
memset( pucStartOfMemory, '\0', UNCACHED_MEMORY_SIZE );
}
}

View file

@ -0,0 +1,23 @@
/*
* uncached_memory.h
*
* This module will declare 1 MB of memory and switch off the caching for it.
*
* pucGetUncachedMemory( ulSize ) returns a trunc of this memory with a length
* rounded up to a multiple of 4 KB
*
* ucIsCachedMemory( pucBuffer ) returns non-zero if a given pointer is NOT
* within the range of the 1 MB non-cached memory.
*
*/
#ifndef UNCACHEMEMORY_H
#define UNCACHEMEMORY_H
uint8_t *pucGetUncachedMemory( uint32_t ulSize );
uint8_t ucIsCachedMemory( const uint8_t *pucBuffer );
#endif /* UNCACHEMEMORY_H */

View file

@ -0,0 +1,118 @@
/*
* Handling of Ethernet PHY's
* PHY's communicate with an EMAC either through
* a Media-Independent Interface (MII), or a Reduced Media-Independent Interface (RMII).
* The EMAC can poll for PHY ports on 32 different addresses. Each of the PHY ports
* shall be treated independently.
*
*/
#ifndef PHYHANDLING_H
#define PHYHANDLING_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ipconfigPHY_MAX_PORTS
/* There can be at most 32 PHY ports, but in most cases there are 4 or less. */
#define ipconfigPHY_MAX_PORTS 4
#endif
/* A generic user-provided function that reads from the PHY-port at 'xAddress'( 0-based ). A 16-bit value shall be stored in
'*pusValue'. xRegister is the register number ( 0 .. 31 ). In fact all PHY registers are 16-bit.
Return non-zero in case the action failed. */
typedef BaseType_t ( *xApplicationPhyReadHook_t )( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue );
/* A generic user-provided function that writes 'usValue' to the
PHY-port at 'xAddress' ( 0-based ). xRegister is the register number ( 0 .. 31 ).
Return non-zero in case the action failed. */
typedef BaseType_t ( *xApplicationPhyWriteHook_t )( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue );
typedef struct xPhyProperties
{
uint8_t ucSpeed;
uint8_t ucMDI_X; /* MDI-X : Medium Dependent Interface - Crossover */
uint8_t ucDuplex;
uint8_t ucSpare;
} PhyProperties_t;
typedef struct xEthernetPhy
{
xApplicationPhyReadHook_t fnPhyRead;
xApplicationPhyWriteHook_t fnPhyWrite;
uint32_t ulPhyIDs[ ipconfigPHY_MAX_PORTS ];
uint8_t ucPhyIndexes[ ipconfigPHY_MAX_PORTS ];
TimeOut_t xLinkStatusTimer;
TickType_t xLinkStatusRemaining;
BaseType_t xPortCount;
uint32_t ulBCRValue;
uint32_t ulACRValue;
uint32_t ulLinkStatusMask;
PhyProperties_t xPhyPreferences;
PhyProperties_t xPhyProperties;
} EthernetPhy_t;
/* Some defines used internally here to indicate preferences about speed, MDIX
(wired direct or crossed), and duplex (half or full). */
/* Values for PhyProperties_t::ucSpeed : */
#define PHY_SPEED_10 1
#define PHY_SPEED_100 2
#define PHY_SPEED_AUTO 3
/* Values for PhyProperties_t::ucMDI_X : */
#define PHY_MDIX_DIRECT 1
#define PHY_MDIX_CROSSED 2
#define PHY_MDIX_AUTO 3
/* Values for PhyProperties_t::ucDuplex : */
#define PHY_DUPLEX_HALF 1
#define PHY_DUPLEX_FULL 2
#define PHY_DUPLEX_AUTO 3
/* ID's of supported PHY's : */
#define PHY_ID_LAN8742A 0x0007c130
#define PHY_ID_LAN8720 0x0007c0f0
#define PHY_ID_KSZ8041 0x000010A1
#define PHY_ID_KSZ8051 0x000010A1
#define PHY_ID_KSZ8081 0x000010A1
#define PHY_ID_KSZ8863 0x00221430
#define PHY_ID_DP83848I 0x20005C90
/* Initialise the struct and assign a PHY-read and -write function. */
void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhyRead, xApplicationPhyWriteHook_t fnPhyWrite );
/* Discover all PHY's connected by polling 32 indexes ( zero-based ) */
BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject );
/* Send a reset commando to the connected PHY ports and send configuration. */
BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties );
/* Give a commando to start auto negotiation on a set of PHY port's. */
BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask );
/* Do not use auto negotiation but use predefined values from 'pxPhyObject->xPhyPreferences'. */
BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask );
/* Check the current Link Status.
'xHadReception' : make this true if a packet has been received since the
last call to this function. */
BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception );
static __inline uint32_t xPhyGetMask( EthernetPhy_t *pxPhyObject )
{
return ( ( ( uint32_t ) 1u ) << pxPhyObject-> xPortCount ) - 1;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View file

@ -0,0 +1,610 @@
/**
*
* \file
*
* \brief KS8851SNL driver for SAM.
*
* Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "spi_master.h"
#include "ksz8851snl.h"
#include "ksz8851snl_reg.h"
#include "delay.h"
#include "pio.h"
#include "pio_handler.h"
#include "pdc.h"
#include "conf_eth.h"
/* Clock polarity. */
#define SPI_CLK_POLARITY 0
/* Clock phase. */
#define SPI_CLK_PHASE 1
/* SPI PDC register base. */
Pdc *g_p_spi_pdc = 0;
int lUDPLoggingPrintf( const char *pcFormatString, ... );
/* Temporary buffer for PDC reception. */
uint8_t tmpbuf[1536] __attribute__ ((aligned (16)));
union {
uint64_t ul[2];
uint8_t uc[16];
} cmdBuf, respBuf;
void dbg_add_line( const char *pcFormat, ... );
static void spi_clear_ovres( void );
/**
* \brief Read register content, set bitmask and write back to register.
*
* \param reg the register address to modify.
* \param bits_to_set bitmask to apply.
*/
void ksz8851_reg_setbits(uint16_t reg, uint16_t bits_to_set)
{
uint16_t temp;
temp = ksz8851_reg_read(reg);
temp |= bits_to_set;
ksz8851_reg_write(reg, temp);
}
/**
* \brief Read register content, clear bitmask and write back to register.
*
* \param reg the register address to modify.
* \param bits_to_set bitmask to apply.
*/
void ksz8851_reg_clrbits(uint16_t reg, uint16_t bits_to_clr)
{
uint16_t temp;
temp = ksz8851_reg_read(reg);
temp &= ~(uint32_t) bits_to_clr;
ksz8851_reg_write(reg, temp);
}
/**
* \brief Configure the INTN interrupt.
*/
void configure_intn(void (*p_handler) (uint32_t, uint32_t))
{
// gpio_configure_pin(KSZ8851SNL_INTN_GPIO, PIO_INPUT);
// pio_set_input(PIOA, PIO_PA11_IDX, PIO_PULLUP);
/* Configure PIO clock. */
pmc_enable_periph_clk(INTN_ID);
/* Adjust PIO debounce filter parameters, uses 10 Hz filter. */
pio_set_debounce_filter(INTN_PIO, INTN_PIN_MSK, 10);
/* Initialize PIO interrupt handlers, see PIO definition in board.h. */
pio_handler_set(INTN_PIO, INTN_ID, INTN_PIN_MSK,
INTN_ATTR, p_handler);
/* Enable NVIC interrupts. */
NVIC_SetPriority(INTN_IRQn, INT_PRIORITY_PIO);
NVIC_EnableIRQ((IRQn_Type)INTN_ID);
/* Enable PIO interrupts. */
pio_enable_interrupt(INTN_PIO, INTN_PIN_MSK);
}
/**
* \brief Read a register value.
*
* \param reg the register address to modify.
*
* \return the register value.
*/
uint16_t ksz8851_reg_read(uint16_t reg)
{
pdc_packet_t g_pdc_spi_tx_packet;
pdc_packet_t g_pdc_spi_rx_packet;
uint16_t cmd = 0;
uint16_t res = 0;
int iTryCount = 3;
while( iTryCount-- > 0 )
{
uint32_t ulStatus;
spi_clear_ovres();
/* Move register address to cmd bits 9-2, make 32-bit address. */
cmd = (reg << 2) & REG_ADDR_MASK;
/* Last 2 bits still under "don't care bits" handled with byte enable. */
/* Select byte enable for command. */
if (reg & 2) {
/* Odd word address writes bytes 2 and 3 */
cmd |= (0xc << 10);
} else {
/* Even word address write bytes 0 and 1 */
cmd |= (0x3 << 10);
}
/* Add command read code. */
cmd |= CMD_READ;
cmdBuf.uc[0] = cmd >> 8;
cmdBuf.uc[1] = cmd & 0xff;
cmdBuf.uc[2] = CONFIG_SPI_MASTER_DUMMY;
cmdBuf.uc[3] = CONFIG_SPI_MASTER_DUMMY;
/* Prepare PDC transfer. */
g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;
g_pdc_spi_tx_packet.ul_size = 4;
g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf;
g_pdc_spi_rx_packet.ul_size = 4;
pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL);
pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL);
gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);
spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul );
pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
for( ;; )
{
ulStatus = spi_read_status( KSZ8851SNL_SPI );
if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 )
{
break;
}
}
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
if( ( ulStatus & SPI_SR_OVRES ) == 0 )
{
break;
}
pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
lUDPLoggingPrintf( "ksz8851_reg_read: SPI_SR_OVRES\n" );
}
res = (tmpbuf[3] << 8) | tmpbuf[2];
return res;
}
/**
* \brief Write a register value.
*
* \param reg the register address to modify.
* \param wrdata the new register value.
*/
void ksz8851_reg_write(uint16_t reg, uint16_t wrdata)
{
pdc_packet_t g_pdc_spi_tx_packet;
pdc_packet_t g_pdc_spi_rx_packet;
uint16_t cmd = 0;
int iTryCount = 3;
while( iTryCount-- > 0 )
{
uint32_t ulStatus;
spi_clear_ovres();
/* Move register address to cmd bits 9-2, make 32-bit address. */
cmd = (reg << 2) & REG_ADDR_MASK;
/* Last 2 bits still under "don't care bits" handled with byte enable. */
/* Select byte enable for command. */
if (reg & 2) {
/* Odd word address writes bytes 2 and 3 */
cmd |= (0xc << 10);
} else {
/* Even word address write bytes 0 and 1 */
cmd |= (0x3 << 10);
}
/* Add command write code. */
cmd |= CMD_WRITE;
cmdBuf.uc[0] = cmd >> 8;
cmdBuf.uc[1] = cmd & 0xff;
cmdBuf.uc[2] = wrdata & 0xff;
cmdBuf.uc[3] = wrdata >> 8;
/* Prepare PDC transfer. */
g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;
g_pdc_spi_tx_packet.ul_size = 4;
g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf;
g_pdc_spi_rx_packet.ul_size = 4;
pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL);
pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL);
gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);
spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul );
pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
for( ;; )
{
ulStatus = spi_read_status( KSZ8851SNL_SPI );
if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 )
{
break;
}
}
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
if( ( ulStatus & SPI_SR_OVRES ) == 0 )
{
break;
}
pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
lUDPLoggingPrintf( "ksz8851_reg_write: SPI_SR_OVRES\n" );
}
}
static void spi_clear_ovres( void )
{
volatile uint32_t rc;
rc = KSZ8851SNL_SPI->SPI_RDR;
spi_read_status( KSZ8851SNL_SPI );
}
/**
* \brief Read internal fifo buffer.
*
* \param buf the buffer to store the data from the fifo buffer.
* \param len the amount of data to read.
*/
void ksz8851_fifo_read(uint8_t *buf, uint32_t len)
{
pdc_packet_t g_pdc_spi_tx_packet;
pdc_packet_t g_pdc_spi_rx_packet;
pdc_packet_t g_pdc_spi_tx_npacket;
pdc_packet_t g_pdc_spi_rx_npacket;
memset( cmdBuf.uc, '\0', sizeof cmdBuf );
cmdBuf.uc[0] = FIFO_READ;
spi_clear_ovres();
/* Prepare PDC transfer. */
g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;
g_pdc_spi_tx_packet.ul_size = 9;
g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc;
g_pdc_spi_rx_packet.ul_size = 9;
g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf;
g_pdc_spi_tx_npacket.ul_size = len;
g_pdc_spi_rx_npacket.ul_addr = (uint32_t) buf;
g_pdc_spi_rx_npacket.ul_size = len;
pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket);
pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket);
spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_RXBUFF | SPI_IER_OVRES);
pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
}
/**
* \brief Write internal fifo buffer.
*
* \param buf the buffer to send to the fifo buffer.
* \param ulActualLength the total amount of data to write.
* \param ulFIFOLength the size of the first pbuf to write from the pbuf chain.
*/
void ksz8851_fifo_write(uint8_t *buf, uint32_t ulActualLength, uint32_t ulFIFOLength)
{
static uint8_t frameID = 0;
pdc_packet_t g_pdc_spi_tx_packet;
pdc_packet_t g_pdc_spi_rx_packet;
pdc_packet_t g_pdc_spi_tx_npacket;
pdc_packet_t g_pdc_spi_rx_npacket;
/* Prepare control word and byte count. */
cmdBuf.uc[0] = FIFO_WRITE;
cmdBuf.uc[1] = frameID++ & 0x3f;
cmdBuf.uc[2] = 0;
cmdBuf.uc[3] = ulActualLength & 0xff;
cmdBuf.uc[4] = ulActualLength >> 8;
spi_clear_ovres();
/* Prepare PDC transfer. */
g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc;
g_pdc_spi_tx_packet.ul_size = 5;
g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc;
g_pdc_spi_rx_packet.ul_size = 5;
g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf;
g_pdc_spi_tx_npacket.ul_size = ulFIFOLength;
g_pdc_spi_rx_npacket.ul_addr = (uint32_t) tmpbuf;
g_pdc_spi_rx_npacket.ul_size = ulFIFOLength;
pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket);
#if( TX_USES_RECV == 1 )
pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket);
spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_ENDRX | SPI_IER_OVRES);
pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
#else
spi_enable_interrupt(KSZ8851SNL_SPI, SPI_SR_TXBUFE | SPI_IER_OVRES);
pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_TXTEN);
#endif
}
/**
* \brief Write dummy data to the internal fifo buffer.
*
* \param len the amount of dummy data to write.
*/
void ksz8851_fifo_dummy(uint32_t len)
{
pdc_packet_t g_pdc_spi_tx_packet;
pdc_packet_t g_pdc_spi_rx_packet;
/* Prepare PDC transfer. */
g_pdc_spi_tx_packet.ul_addr = (uint32_t) tmpbuf;
g_pdc_spi_tx_packet.ul_size = len;
g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf;
g_pdc_spi_rx_packet.ul_size = len;
pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL);
pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL);
pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
while (!(spi_read_status(KSZ8851SNL_SPI) & SPI_SR_ENDRX))
;
}
void ksz8851snl_set_registers(void)
{
/* Init step2-4: write QMU MAC address (low, middle then high). */
ksz8851_reg_write(REG_MAC_ADDR_0, (ETHERNET_CONF_ETHADDR4 << 8) | ETHERNET_CONF_ETHADDR5);
ksz8851_reg_write(REG_MAC_ADDR_2, (ETHERNET_CONF_ETHADDR2 << 8) | ETHERNET_CONF_ETHADDR3);
ksz8851_reg_write(REG_MAC_ADDR_4, (ETHERNET_CONF_ETHADDR0 << 8) | ETHERNET_CONF_ETHADDR1);
/* Init step5: enable QMU Transmit Frame Data Pointer Auto Increment. */
ksz8851_reg_write(REG_TX_ADDR_PTR, ADDR_PTR_AUTO_INC);
/* Init step6: configure QMU transmit control register. */
ksz8851_reg_write(REG_TX_CTRL,
TX_CTRL_ICMP_CHECKSUM |
TX_CTRL_UDP_CHECKSUM |
TX_CTRL_TCP_CHECKSUM |
TX_CTRL_IP_CHECKSUM |
TX_CTRL_FLOW_ENABLE |
TX_CTRL_PAD_ENABLE |
TX_CTRL_CRC_ENABLE
);
/* Init step7: enable QMU Receive Frame Data Pointer Auto Increment. */
ksz8851_reg_write(REG_RX_ADDR_PTR, ADDR_PTR_AUTO_INC);
/* Init step8: configure QMU Receive Frame Threshold for one frame. */
ksz8851_reg_write(REG_RX_FRAME_CNT_THRES, 1);
/* Init step9: configure QMU receive control register1. */
ksz8851_reg_write(REG_RX_CTRL1,
RX_CTRL_UDP_CHECKSUM |
RX_CTRL_TCP_CHECKSUM |
RX_CTRL_IP_CHECKSUM |
RX_CTRL_MAC_FILTER |
RX_CTRL_FLOW_ENABLE |
RX_CTRL_BROADCAST |
RX_CTRL_ALL_MULTICAST|
RX_CTRL_UNICAST);
// ksz8851_reg_write(REG_RX_CTRL1,
// RX_CTRL_UDP_CHECKSUM |
// RX_CTRL_TCP_CHECKSUM |
// RX_CTRL_IP_CHECKSUM |
// RX_CTRL_FLOW_ENABLE |
// RX_CTRL_PROMISCUOUS);
ksz8851_reg_write(REG_RX_CTRL2,
RX_CTRL_IPV6_UDP_NOCHECKSUM |
RX_CTRL_UDP_LITE_CHECKSUM |
RX_CTRL_ICMP_CHECKSUM |
RX_CTRL_BURST_LEN_FRAME);
//#define RXQ_TWOBYTE_OFFSET (0x0200) /* Enable adding 2-byte before frame header for IP aligned with DWORD */
#warning Remember to try the above option to get a 2-byte offset
/* Init step11: configure QMU receive queue: trigger INT and auto-dequeue frame. */
ksz8851_reg_write( REG_RXQ_CMD, RXQ_CMD_CNTL | RXQ_TWOBYTE_OFFSET );
/* Init step12: adjust SPI data output delay. */
ksz8851_reg_write(REG_BUS_CLOCK_CTRL, BUS_CLOCK_166 | BUS_CLOCK_DIVIDEDBY_1);
/* Init step13: restart auto-negotiation. */
ksz8851_reg_setbits(REG_PORT_CTRL, PORT_AUTO_NEG_RESTART);
/* Init step13.1: force link in half duplex if auto-negotiation failed. */
if ((ksz8851_reg_read(REG_PORT_CTRL) & PORT_AUTO_NEG_RESTART) != PORT_AUTO_NEG_RESTART)
{
ksz8851_reg_clrbits(REG_PORT_CTRL, PORT_FORCE_FULL_DUPLEX);
}
/* Init step14: clear interrupt status. */
ksz8851_reg_write(REG_INT_STATUS, 0xFFFF);
/* Init step15: set interrupt mask. */
ksz8851_reg_write(REG_INT_MASK, INT_RX);
/* Init step16: enable QMU Transmit. */
ksz8851_reg_setbits(REG_TX_CTRL, TX_CTRL_ENABLE);
/* Init step17: enable QMU Receive. */
ksz8851_reg_setbits(REG_RX_CTRL1, RX_CTRL_ENABLE);
}
/**
* \brief KSZ8851SNL initialization function.
*
* \return 0 on success, 1 on communication error.
*/
uint32_t ksz8851snl_init(void)
{
uint32_t count = 10;
uint16_t dev_id = 0;
uint8_t id_ok = 0;
/* Configure the SPI peripheral. */
spi_enable_clock(KSZ8851SNL_SPI);
spi_disable(KSZ8851SNL_SPI);
spi_reset(KSZ8851SNL_SPI);
spi_set_master_mode(KSZ8851SNL_SPI);
spi_disable_mode_fault_detect(KSZ8851SNL_SPI);
spi_set_peripheral_chip_select_value(KSZ8851SNL_SPI, ~(uint32_t)(1UL << KSZ8851SNL_CS_PIN));
spi_set_fixed_peripheral_select(KSZ8851SNL_SPI);
//spi_disable_peripheral_select_decode(KSZ8851SNL_SPI);
spi_set_clock_polarity(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_POLARITY);
spi_set_clock_phase(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_PHASE);
spi_set_bits_per_transfer(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN,
SPI_CSR_BITS_8_BIT);
spi_set_baudrate_div(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, (sysclk_get_cpu_hz() / KSZ8851SNL_CLOCK_SPEED));
// spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, CONFIG_SPI_MASTER_DELAY_BS,
// CONFIG_SPI_MASTER_DELAY_BCT);
spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, 0, 0);
spi_enable(KSZ8851SNL_SPI);
/* Get pointer to UART PDC register base. */
g_p_spi_pdc = spi_get_pdc_base(KSZ8851SNL_SPI);
pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN);
/* Control RSTN and CSN pin from the driver. */
gpio_configure_pin(KSZ8851SNL_CSN_GPIO, KSZ8851SNL_CSN_FLAGS);
gpio_set_pin_high(KSZ8851SNL_CSN_GPIO);
gpio_configure_pin(KSZ8851SNL_RSTN_GPIO, KSZ8851SNL_RSTN_FLAGS);
/* Reset the Micrel in a proper state. */
while( count-- )
{
/* Perform hardware reset with respect to the reset timing from the datasheet. */
gpio_set_pin_low(KSZ8851SNL_RSTN_GPIO);
vTaskDelay(2);
gpio_set_pin_high(KSZ8851SNL_RSTN_GPIO);
vTaskDelay(2);
/* Init step1: read chip ID. */
dev_id = ksz8851_reg_read(REG_CHIP_ID);
if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 )
{
id_ok = 1;
break;
}
}
if( id_ok != 0 )
{
ksz8851snl_set_registers();
}
return id_ok ? 1 : -1;
}
uint32_t ksz8851snl_reinit(void)
{
uint32_t count = 10;
uint16_t dev_id = 0;
uint8_t id_ok = 0;
/* Reset the Micrel in a proper state. */
while( count-- )
{
/* Perform hardware reset with respect to the reset timing from the datasheet. */
gpio_set_pin_low(KSZ8851SNL_RSTN_GPIO);
vTaskDelay(2);
gpio_set_pin_high(KSZ8851SNL_RSTN_GPIO);
vTaskDelay(2);
/* Init step1: read chip ID. */
dev_id = ksz8851_reg_read(REG_CHIP_ID);
if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 )
{
id_ok = 1;
break;
}
}
if( id_ok != 0 )
{
ksz8851snl_set_registers();
}
return id_ok ? 1 : -1;
}
uint32_t ksz8851snl_reset_rx( void )
{
uint16_t usValue;
usValue = ksz8851_reg_read(REG_RX_CTRL1);
usValue &= ~( ( uint16_t ) RX_CTRL_ENABLE | RX_CTRL_FLUSH_QUEUE );
ksz8851_reg_write( REG_RX_CTRL1, usValue ); vTaskDelay( 2 );
ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_FLUSH_QUEUE ); vTaskDelay( 1 );
ksz8851_reg_write( REG_RX_CTRL1, usValue ); vTaskDelay( 1 );
ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_ENABLE ); vTaskDelay( 1 );
return ( uint32_t )usValue;
}
uint32_t ksz8851snl_reset_tx( void )
{
uint16_t usValue;
usValue = ksz8851_reg_read( REG_TX_CTRL );
usValue &= ~( ( uint16_t ) TX_CTRL_ENABLE | TX_CTRL_FLUSH_QUEUE );
ksz8851_reg_write( REG_TX_CTRL, usValue ); vTaskDelay( 2 );
ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_FLUSH_QUEUE ); vTaskDelay( 1 );
ksz8851_reg_write( REG_TX_CTRL, usValue ); vTaskDelay( 1 );
ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_ENABLE ); vTaskDelay( 1 );
return ( uint32_t )usValue;
}

View file

@ -0,0 +1,67 @@
/**
*
* \file
*
* \brief KS8851SNL driver for SAM.
*
* Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef KSZ8851SNL_H_INCLUDED
#define KSZ8851SNL_H_INCLUDED
#include "gpio.h"
void configure_intn(void (*p_handler) (uint32_t, uint32_t));
void ksz8851_reg_setbits(uint16_t reg, uint16_t bits_to_set);
void ksz8851_reg_clrbits(uint16_t reg, uint16_t bits_to_clr);
void ksz8851_fifo_read(uint8_t *buf, uint32_t len);
void ksz8851_fifo_write(uint8_t *buf, uint32_t ulActualLength, uint32_t ulFIFOLength);
void ksz8851_fifo_dummy(uint32_t len);
void ksz8851_reg_write(uint16_t reg, uint16_t wrdata);
uint16_t ksz8851_reg_read(uint16_t reg);
uint32_t ksz8851snl_init(void);
uint32_t ksz8851snl_reinit(void);
uint32_t ksz8851snl_reset_rx( void );
uint32_t ksz8851snl_reset_tx( void );
#endif /* KSZ8851SNL_H_INCLUDED */

View file

@ -0,0 +1,473 @@
/**
*
* \file
*
* \brief KS8851SNL registers definitions.
*
* Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef KSZ8851SNL_REG_H_INCLUDED
#define KSZ8851SNL_REG_H_INCLUDED
#define REG_ADDR_MASK (0x3F0) /* Register address mask */
#define OPCODE_MASK (3 << 14)
#define CMD_READ (0 << 14)
#define CMD_WRITE (1 << 14)
#define FIFO_READ (0x80)
#define FIFO_WRITE (0xC0)
/*
* MAC Registers
* (Offset 0x00 - 0x25)
*/
#define REG_BUS_ERROR_STATUS (0x06) /* BESR */
#define BUS_ERROR_IBEC (0x8000)
#define BUS_ERROR_IBECV_MASK (0x7800) /* Default IPSec clock at 166Mhz */
#define REG_CHIP_CFG_STATUS (0x08) /* CCFG */
#define LITTLE_ENDIAN_BUS_MODE (0x0400) /* Bus in little endian mode */
#define EEPROM_PRESENCE (0x0200) /* External EEPROM is used */
#define SPI_BUS_MODE (0x0100) /* In SPI bus mode */
#define DATA_BUS_8BIT (0x0080) /* In 8-bit bus mode operation */
#define DATA_BUS_16BIT (0x0040) /* In 16-bit bus mode operation */
#define DATA_BUS_32BIT (0x0020) /* In 32-bit bus mode operation */
#define MULTIPLEX_MODE (0x0010) /* Data and address bus are shared */
#define CHIP_PACKAGE_128PIN (0x0008) /* 128-pin package */
#define CHIP_PACKAGE_80PIN (0x0004) /* 80-pin package */
#define CHIP_PACKAGE_48PIN (0x0002) /* 48-pin package */
#define CHIP_PACKAGE_32PIN (0x0001) /* 32-pin package for SPI host interface only */
#define REG_MAC_ADDR_0 (0x10) /* MARL */
#define REG_MAC_ADDR_1 (0x11) /* MARL */
#define REG_MAC_ADDR_2 (0x12) /* MARM */
#define REG_MAC_ADDR_3 (0x13) /* MARM */
#define REG_MAC_ADDR_4 (0x14) /* MARH */
#define REG_MAC_ADDR_5 (0x15) /* MARH */
#define REG_BUS_CLOCK_CTRL (0x20) /* OBCR */
#define BUS_CLOCK_166 (0x0004) /* 166 MHz on-chip bus clock (defaul is 125MHz) */
#define BUS_CLOCK_DIVIDEDBY_5 (0x0003) /* Bus clock devided by 5 */
#define BUS_CLOCK_DIVIDEDBY_3 (0x0002) /* Bus clock devided by 3 */
#define BUS_CLOCK_DIVIDEDBY_2 (0x0001) /* Bus clock devided by 2 */
#define BUS_CLOCK_DIVIDEDBY_1 (0x0000) /* Bus clock devided by 1 */
#define BUS_CLOCK_DIVIDED_MASK (0x0003) /* Bus clock devider mask */
#define BUS_SPEED_166_MHZ (0x0004) /* Set bus speed to 166 MHz */
#define BUS_SPEED_125_MHZ (0x0000) /* Set bus speed to 125 MHz */
#define BUS_SPEED_83_MHZ (0x0005) /* Set bus speed to 83 MHz (166/2)*/
#define BUS_SPEED_62_5_MHZ (0x0001) /* Set bus speed to 62.5 MHz (125/2) */
#define BUS_SPEED_53_3_MHZ (0x0006) /* Set bus speed to 53.3 MHz (166/3) */
#define BUS_SPEED_41_7_MHZ (0x0002) /* Set bus speed to 41.67 MHz (125/3) */
#define BUS_SPEED_33_2_MHZ (0x0007) /* Set bus speed to 33.2 MHz (166/5) */
#define BUS_SPEED_25_MHZ (0x0003) /* Set bus speed to 25 MHz (125/5) */
#define REG_EEPROM_CTRL (0x22) /* EEPCR */
#define EEPROM_ACCESS_ENABLE (0x0010) /* Enable software to access EEPROM through bit 3 to bit 0 */
#define EEPROM_DATA_IN (0x0008) /* Data receive from EEPROM (EEDI pin) */
#define EEPROM_DATA_OUT (0x0004) /* Data transmit to EEPROM (EEDO pin) */
#define EEPROM_SERIAL_CLOCK (0x0002) /* Serial clock (EESK pin) */
#define EEPROM_CHIP_SELECT (0x0001) /* EEPROM chip select (EECS pin) */
#define REG_MEM_BIST_INFO (0x24) /* MBIR */
#define TX_MEM_TEST_FINISHED (0x1000) /* TX memeory BIST test finish */
#define TX_MEM_TEST_FAILED (0x0800) /* TX memory BIST test fail */
#define TX_MEM_TEST_FAILED_COUNT (0x0700) /* TX memory BIST test fail count */
#define RX_MEM_TEST_FINISHED (0x0010) /* RX memory BIST test finish */
#define RX_MEM_TEST_FAILED (0x0008) /* RX memory BIST test fail */
#define RX_MEM_TEST_FAILED_COUNT (0x0003) /* RX memory BIST test fail count */
#define REG_RESET_CTRL (0x26) /* GRR */
#define QMU_SOFTWARE_RESET (0x0002) /* QMU soft reset (clear TxQ, RxQ) */
#define GLOBAL_SOFTWARE_RESET (0x0001) /* Global soft reset (PHY, MAC, QMU) */
/*
* Wake On Lan Control Registers
* (Offset 0x2A - 0x6B)
*/
#define REG_WOL_CTRL (0x2A) /* WFCR */
#define WOL_MAGIC_ENABLE (0x0080) /* Enable the magic packet pattern detection */
#define WOL_FRAME3_ENABLE (0x0008) /* Enable the wake up frame 3 pattern detection */
#define WOL_FRAME2_ENABLE (0x0004) /* Enable the wake up frame 2 pattern detection */
#define WOL_FRAME1_ENABLE (0x0002) /* Enable the wake up frame 1 pattern detection */
#define WOL_FRAME0_ENABLE (0x0001) /* Enable the wake up frame 0 pattern detection */
#define REG_WOL_FRAME0_CRC0 (0x30) /* WF0CRC0 */
#define REG_WOL_FRAME0_CRC1 (0x32) /* WF0CRC1 */
#define REG_WOL_FRAME0_BYTE_MASK0 (0x34) /* WF0BM0 */
#define REG_WOL_FRAME0_BYTE_MASK1 (0x36) /* WF0BM1 */
#define REG_WOL_FRAME0_BYTE_MASK2 (0x38) /* WF0BM2 */
#define REG_WOL_FRAME0_BYTE_MASK3 (0x3A) /* WF0BM3 */
#define REG_WOL_FRAME1_CRC0 (0x40) /* WF1CRC0 */
#define REG_WOL_FRAME1_CRC1 (0x42) /* WF1CRC1 */
#define REG_WOL_FRAME1_BYTE_MASK0 (0x44) /* WF1BM0 */
#define REG_WOL_FRAME1_BYTE_MASK1 (0x46) /* WF1BM1 */
#define REG_WOL_FRAME1_BYTE_MASK2 (0x48) /* WF1BM2 */
#define REG_WOL_FRAME1_BYTE_MASK3 (0x4A) /* WF1BM3 */
#define REG_WOL_FRAME2_CRC0 (0x50) /* WF2CRC0 */
#define REG_WOL_FRAME2_CRC1 (0x52) /* WF2CRC1 */
#define REG_WOL_FRAME2_BYTE_MASK0 (0x54) /* WF2BM0 */
#define REG_WOL_FRAME2_BYTE_MASK1 (0x56) /* WF2BM1 */
#define REG_WOL_FRAME2_BYTE_MASK2 (0x58) /* WF2BM2 */
#define REG_WOL_FRAME2_BYTE_MASK3 (0x5A) /* WF2BM3 */
#define REG_WOL_FRAME3_CRC0 (0x60) /* WF3CRC0 */
#define REG_WOL_FRAME3_CRC1 (0x62) /* WF3CRC1 */
#define REG_WOL_FRAME3_BYTE_MASK0 (0x64) /* WF3BM0 */
#define REG_WOL_FRAME3_BYTE_MASK1 (0x66) /* WF3BM1 */
#define REG_WOL_FRAME3_BYTE_MASK2 (0x68) /* WF3BM2 */
#define REG_WOL_FRAME3_BYTE_MASK3 (0x6A) /* WF3BM3 */
/*
* Transmit/Receive Control Registers
* (Offset 0x70 - 0x9F)
*/
/* Transmit Frame Header */
#define REG_QDR_DUMMY (0x00) /* Dummy address to access QMU RxQ, TxQ */
#define TX_CTRL_INTERRUPT_ON (0x8000) /* Transmit Interrupt on Completion */
#define REG_TX_CTRL (0x70) /* TXCR */
#define TX_CTRL_ICMP_CHECKSUM (0x0100) /* Enable ICMP frame checksum generation */
#define TX_CTRL_UDP_CHECKSUM (0x0080) /* Enable UDP frame checksum generation */
#define TX_CTRL_TCP_CHECKSUM (0x0040) /* Enable TCP frame checksum generation */
#define TX_CTRL_IP_CHECKSUM (0x0020) /* Enable IP frame checksum generation */
#define TX_CTRL_FLUSH_QUEUE (0x0010) /* Clear transmit queue, reset tx frame pointer */
#define TX_CTRL_FLOW_ENABLE (0x0008) /* Enable transmit flow control */
#define TX_CTRL_PAD_ENABLE (0x0004) /* Eanble adding a padding to a packet shorter than 64 bytes */
#define TX_CTRL_CRC_ENABLE (0x0002) /* Enable adding a CRC to the end of transmit frame */
#define TX_CTRL_ENABLE (0x0001) /* Enable tranmsit */
#define REG_TX_STATUS (0x72) /* TXSR */
#define TX_STAT_LATE_COL (0x2000) /* Tranmsit late collision occurs */
#define TX_STAT_MAX_COL (0x1000) /* Tranmsit maximum collision is reached */
#define TX_FRAME_ID_MASK (0x003F) /* Transmit frame ID mask */
#define TX_STAT_ERRORS ( TX_STAT_MAX_COL | TX_STAT_LATE_COL )
#define REG_RX_CTRL1 (0x74) /* RXCR1 */
#define RX_CTRL_FLUSH_QUEUE (0x8000) /* Clear receive queue, reset rx frame pointer */
#define RX_CTRL_UDP_CHECKSUM (0x4000) /* Enable UDP frame checksum verification */
#define RX_CTRL_TCP_CHECKSUM (0x2000) /* Enable TCP frame checksum verification */
#define RX_CTRL_IP_CHECKSUM (0x1000) /* Enable IP frame checksum verification */
#define RX_CTRL_MAC_FILTER (0x0800) /* Receive with address that pass MAC address filtering */
#define RX_CTRL_FLOW_ENABLE (0x0400) /* Enable receive flow control */
#define RX_CTRL_BAD_PACKET (0x0200) /* Eanble receive CRC error frames */
#define RX_CTRL_MULTICAST (0x0100) /* Receive multicast frames that pass the CRC hash filtering */
#define RX_CTRL_BROADCAST (0x0080) /* Receive all the broadcast frames */
#define RX_CTRL_ALL_MULTICAST (0x0040) /* Receive all the multicast frames (including broadcast frames) */
#define RX_CTRL_UNICAST (0x0020) /* Receive unicast frames that match the device MAC address */
#define RX_CTRL_PROMISCUOUS (0x0010) /* Receive all incoming frames, regardless of frame's DA */
#define RX_CTRL_STRIP_CRC (0x0008) /* Enable strip CRC on the received frames */
#define RX_CTRL_INVERSE_FILTER (0x0002) /* Receive with address check in inverse filtering mode */
#define RX_CTRL_ENABLE (0x0001) /* Enable receive */
/* Address filtering scheme mask */
#define RX_CTRL_FILTER_MASK ( RX_CTRL_INVERSE_FILTER | RX_CTRL_PROMISCUOUS | RX_CTRL_MULTICAST | RX_CTRL_MAC_FILTER )
#define REG_RX_CTRL2 (0x76) /* RXCR2 */
#define RX_CTRL_IPV6_UDP_NOCHECKSUM (0x0010) /* No checksum generation and verification if IPv6 UDP is fragment */
#define RX_CTRL_IPV6_UDP_CHECKSUM (0x0008) /* Receive pass IPv6 UDP frame with UDP checksum is zero */
#define RX_CTRL_UDP_LITE_CHECKSUM (0x0004) /* Enable UDP Lite frame checksum generation and verification */
#define RX_CTRL_ICMP_CHECKSUM (0x0002) /* Enable ICMP frame checksum verification */
#define RX_CTRL_BLOCK_MAC (0x0001) /* Receive drop frame if the SA is same as device MAC address */
#define RX_CTRL_BURST_LEN_MASK (0x00e0) /* SRDBL SPI Receive Data Burst Length */
#define RX_CTRL_BURST_LEN_4 (0x0000)
#define RX_CTRL_BURST_LEN_8 (0x0020)
#define RX_CTRL_BURST_LEN_16 (0x0040)
#define RX_CTRL_BURST_LEN_32 (0x0060)
#define RX_CTRL_BURST_LEN_FRAME (0x0080)
#define REG_TX_MEM_INFO (0x78) /* TXMIR */
#define TX_MEM_AVAILABLE_MASK (0x1FFF) /* The amount of memory available in TXQ */
#define REG_RX_FHR_STATUS (0x7C) /* RXFHSR */
#define RX_VALID (0x8000) /* Frame in the receive packet memory is valid */
#define RX_ICMP_ERROR (0x2000) /* ICMP checksum field doesn't match */
#define RX_IP_ERROR (0x1000) /* IP checksum field doesn't match */
#define RX_TCP_ERROR (0x0800) /* TCP checksum field doesn't match */
#define RX_UDP_ERROR (0x0400) /* UDP checksum field doesn't match */
#define RX_BROADCAST (0x0080) /* Received frame is a broadcast frame */
#define RX_MULTICAST (0x0040) /* Received frame is a multicast frame */
#define RX_UNICAST (0x0020) /* Received frame is a unicast frame */
#define RX_PHY_ERROR (0x0010) /* Received frame has runt error */
#define RX_FRAME_ETHER (0x0008) /* Received frame is an Ethernet-type frame */
#define RX_TOO_LONG (0x0004) /* Received frame length exceeds max size 0f 2048 bytes */
#define RX_RUNT_ERROR (0x0002) /* Received frame was demaged by a collision */
#define RX_BAD_CRC (0x0001) /* Received frame has a CRC error */
#define RX_ERRORS ( RX_BAD_CRC | RX_TOO_LONG | RX_RUNT_ERROR | RX_PHY_ERROR | \
RX_ICMP_ERROR | RX_IP_ERROR | RX_TCP_ERROR | RX_UDP_ERROR )
#define REG_RX_FHR_BYTE_CNT (0x7E) /* RXFHBCR */
#define RX_BYTE_CNT_MASK (0x0FFF) /* Received frame byte size mask */
#define REG_TXQ_CMD (0x80) /* TXQCR */
#define TXQ_AUTO_ENQUEUE (0x0004) /* Enable enqueue tx frames from tx buffer automatically */
#define TXQ_MEM_AVAILABLE_INT (0x0002) /* Enable generate interrupt when tx memory is available */
#define TXQ_ENQUEUE (0x0001) /* Enable enqueue tx frames one frame at a time */
#define REG_RXQ_CMD (0x82) /* RXQCR */
#define RXQ_STAT_TIME_INT (0x1000) /* RX interrupt is occured by timer duration */
#define RXQ_STAT_BYTE_CNT_INT (0x0800) /* RX interrupt is occured by byte count threshold */
#define RXQ_STAT_FRAME_CNT_INT (0x0400) /* RX interrupt is occured by frame count threshold */
#define RXQ_TWOBYTE_OFFSET (0x0200) /* Enable adding 2-byte before frame header for IP aligned with DWORD */
#define RXQ_TIME_INT (0x0080) /* Enable RX interrupt by timer duration */
#define RXQ_BYTE_CNT_INT (0x0040) /* Enable RX interrupt by byte count threshold */
#define RXQ_FRAME_CNT_INT (0x0020) /* Enable RX interrupt by frame count threshold */
#define RXQ_AUTO_DEQUEUE (0x0010) /* Enable release rx frames from rx buffer automatically */
#define RXQ_START (0x0008) /* Start QMU transfer operation */
#define RXQ_CMD_FREE_PACKET (0x0001) /* Manual dequeue (release the current frame from RxQ) */
#define RXQ_CMD_CNTL (RXQ_FRAME_CNT_INT|RXQ_AUTO_DEQUEUE)
#define REG_TX_ADDR_PTR (0x84) /* TXFDPR */
#define REG_RX_ADDR_PTR (0x86) /* RXFDPR */
#define ADDR_PTR_AUTO_INC (0x4000) /* Enable Frame data pointer increments automatically */
#define ADDR_PTR_MASK (0x03ff) /* Address pointer mask */
#define REG_RX_TIME_THRES (0x8C) /* RXDTTR */
#define RX_TIME_THRESHOLD_MASK (0xFFFF) /* Set receive timer duration threshold */
#define REG_RX_BYTE_CNT_THRES (0x8E) /* RXDBCTR */
#define RX_BYTE_THRESHOLD_MASK (0xFFFF) /* Set receive byte count threshold */
#define REG_INT_MASK (0x90) /* IER */
#define INT_PHY (0x8000) /* Enable link change interrupt */
#define INT_TX (0x4000) /* Enable transmit done interrupt */
#define INT_RX (0x2000) /* Enable receive interrupt */
#define INT_RX_OVERRUN (0x0800) /* Enable receive overrun interrupt */
#define INT_TX_STOPPED (0x0200) /* Enable transmit process stopped interrupt */
#define INT_RX_STOPPED (0x0100) /* Enable receive process stopped interrupt */
#define INT_TX_SPACE (0x0040) /* Enable transmit space available interrupt */
#define INT_RX_WOL_FRAME (0x0020) /* Enable WOL on receive wake-up frame detect interrupt */
#define INT_RX_WOL_MAGIC (0x0010) /* Enable WOL on receive magic packet detect interrupt */
#define INT_RX_WOL_LINKUP (0x0008) /* Enable WOL on link up detect interrupt */
#define INT_RX_WOL_ENERGY (0x0004) /* Enable WOL on energy detect interrupt */
#define INT_RX_SPI_ERROR (0x0002) /* Enable receive SPI bus error interrupt */
#define INT_RX_WOL_DELAY_ENERGY (0x0001) /* Enable WOL on delay energy detect interrupt */
#define INT_MASK ( INT_RX | INT_TX | INT_PHY )
#define REG_INT_STATUS (0x92) /* ISR */
#define REG_RX_FRAME_CNT_THRES (0x9C) /* RXFCTFC */
#define RX_FRAME_CNT_MASK (0xFF00) /* Received frame count mask */
#define RX_FRAME_THRESHOLD_MASK (0x00FF) /* Set receive frame count threshold mask */
#define REG_TX_TOTAL_FRAME_SIZE (0x9E) /* TXNTFSR */
#define TX_TOTAL_FRAME_SIZE_MASK (0xFFFF) /* Set next total tx frame size mask */
/*
* MAC Address Hash Table Control Registers
* (Offset 0xA0 - 0xA7)
*/
#define REG_MAC_HASH_0 (0xA0) /* MAHTR0 */
#define REG_MAC_HASH_1 (0xA1)
#define REG_MAC_HASH_2 (0xA2) /* MAHTR1 */
#define REG_MAC_HASH_3 (0xA3)
#define REG_MAC_HASH_4 (0xA4) /* MAHTR2 */
#define REG_MAC_HASH_5 (0xA5)
#define REG_MAC_HASH_6 (0xA6) /* MAHTR3 */
#define REG_MAC_HASH_7 (0xA7)
/*
* QMU Receive Queue Watermark Control Registers
* (Offset 0xB0 - 0xB5)
*/
#define REG_RX_LOW_WATERMARK (0xB0) /* FCLWR */
#define RX_LOW_WATERMARK_MASK (0x0FFF) /* Set QMU RxQ low watermark mask */
#define REG_RX_HIGH_WATERMARK (0xB2) /* FCHWR */
#define RX_HIGH_WATERMARK_MASK (0x0FFF) /* Set QMU RxQ high watermark mask */
#define REG_RX_OVERRUN_WATERMARK (0xB4) /* FCOWR */
#define RX_OVERRUN_WATERMARK_MASK (0x0FFF) /* Set QMU RxQ overrun watermark mask */
/*
* Global Control Registers
* (Offset 0xC0 - 0xD3)
*/
#define REG_CHIP_ID (0xC0) /* CIDER */
#define CHIP_ID_MASK (0xFFF0) /* Family ID and chip ID mask */
#define REVISION_MASK (0x000E) /* Chip revision mask */
#define CHIP_ID_SHIFT (4)
#define REVISION_SHIFT (1)
#define CHIP_ID_8851_16 (0x8870) /* KS8851-16/32MQL chip ID */
#define REG_LED_CTRL (0xC6) /* CGCR */
#define LED_CTRL_SEL1 (0x8000) /* Select LED3/LED2/LED1/LED0 indication */
#define LED_CTRL_SEL0 (0x0200) /* Select LED3/LED2/LED1/LED0 indication */
#define REG_IND_IACR (0xC8) /* IACR */
#define TABLE_READ (0x1000) /* Indirect read */
#define TABLE_MIB (0x0C00) /* Select MIB counter table */
#define TABLE_ENTRY_MASK (0x001F) /* Set table entry to access */
#define REG_IND_DATA_LOW (0xD0) /* IADLR */
#define REG_IND_DATA_HIGH (0xD2) /* IADHR */
/*
* Power Management Control Registers
* (Offset 0xD4 - 0xD7)
*/
#define REG_POWER_CNTL (0xD4) /* PMECR */
#define PME_DELAY_ENABLE (0x4000) /* Enable the PME output pin assertion delay */
#define PME_ACTIVE_HIGHT (0x1000) /* PME output pin is active high */
#define PME_FROM_WKFRAME (0x0800) /* PME asserted when wake-up frame is detected */
#define PME_FROM_MAGIC (0x0400) /* PME asserted when magic packet is detected */
#define PME_FROM_LINKUP (0x0200) /* PME asserted when link up is detected */
#define PME_FROM_ENERGY (0x0100) /* PME asserted when energy is detected */
#define PME_EVENT_MASK (0x0F00) /* PME asserted event mask */
#define WAKEUP_AUTO_ENABLE (0x0080) /* Enable auto wake-up in energy mode */
#define WAKEUP_NORMAL_AUTO_ENABLE (0x0040) /* Enable auto goto normal mode from energy detecion mode */
#define WAKEUP_FROM_WKFRAME (0x0020) /* Wake-up from wake-up frame event detected */
#define WAKEUP_FROM_MAGIC (0x0010) /* Wake-up from magic packet event detected */
#define WAKEUP_FROM_LINKUP (0x0008) /* Wake-up from link up event detected */
#define WAKEUP_FROM_ENERGY (0x0004) /* Wake-up from energy event detected */
#define WAKEUP_EVENT_MASK (0x003C) /* Wake-up event mask */
#define POWER_STATE_D1 (0x0003) /* Power saving mode */
#define POWER_STATE_D3 (0x0002) /* Power down mode */
#define POWER_STATE_D2 (0x0001) /* Power detection mode */
#define POWER_STATE_D0 (0x0000) /* Normal operation mode (default) */
#define POWER_STATE_MASK (0x0003) /* Power management mode mask */
#define REG_WAKEUP_TIME (0xD6) /* GSWUTR */
#define WAKEUP_TIME (0xFF00) /* Min time (sec) wake-uo after detected energy */
#define GOSLEEP_TIME (0x00FF) /* Min time (sec) before goto sleep when in energy mode */
/*
* PHY Control Registers
* (Offset 0xD8 - 0xF9)
*/
#define REG_PHY_RESET (0xD8) /* PHYRR */
#define PHY_RESET (0x0001) /* Reset PHY */
#define REG_PHY_CNTL (0xE4) /* P1MBCR */
#define PHY_SPEED_100MBIT (0x2000) /* Force PHY 100Mbps */
#define PHY_AUTO_NEG_ENABLE (0x1000) /* Enable PHY auto-negotiation */
#define PHY_POWER_DOWN (0x0800) /* Set PHY power-down */
#define PHY_AUTO_NEG_RESTART (0x0200) /* Restart PHY auto-negotiation */
#define PHY_FULL_DUPLEX (0x0100) /* Force PHY in full duplex mode */
#define PHY_HP_MDIX (0x0020) /* Set PHY in HP auto MDI-X mode */
#define PHY_FORCE_MDIX (0x0010) /* Force MDI-X */
#define PHY_AUTO_MDIX_DISABLE (0x0008) /* Disable auto MDI-X */
#define PHY_TRANSMIT_DISABLE (0x0002) /* Disable PHY transmit */
#define PHY_LED_DISABLE (0x0001) /* Disable PHY LED */
#define REG_PHY_STATUS (0xE6) /* P1MBSR */
#define PHY_100BT4_CAPABLE (0x8000) /* 100 BASE-T4 capable */
#define PHY_100BTX_FD_CAPABLE (0x4000) /* 100BASE-TX full duplex capable */
#define PHY_100BTX_CAPABLE (0x2000) /* 100BASE-TX half duplex capable */
#define PHY_10BT_FD_CAPABLE (0x1000) /* 10BASE-TX full duplex capable */
#define PHY_10BT_CAPABLE (0x0800) /* 10BASE-TX half duplex capable */
#define PHY_AUTO_NEG_ACKNOWLEDGE (0x0020) /* Auto-negotiation complete */
#define PHY_AUTO_NEG_CAPABLE (0x0008) /* Auto-negotiation capable */
#define PHY_LINK_UP (0x0004) /* PHY link is up */
#define PHY_EXTENDED_CAPABILITY (0x0001) /* PHY extended register capable */
#define REG_PHY_ID_LOW (0xE8) /* PHY1ILR */
#define REG_PHY_ID_HIGH (0xEA) /* PHY1IHR */
#define REG_PHY_AUTO_NEGOTIATION (0xEC) /* P1ANAR */
#define PHY_AUTO_NEG_SYM_PAUSE (0x0400) /* Advertise pause capability */
#define PHY_AUTO_NEG_100BTX_FD (0x0100) /* Advertise 100 full-duplex capability */
#define PHY_AUTO_NEG_100BTX (0x0080) /* Advertise 100 half-duplex capability */
#define PHY_AUTO_NEG_10BT_FD (0x0040) /* Advertise 10 full-duplex capability */
#define PHY_AUTO_NEG_10BT (0x0020) /* Advertise 10 half-duplex capability */
#define PHY_AUTO_NEG_SELECTOR (0x001F) /* Selector field mask */
#define PHY_AUTO_NEG_802_3 (0x0001) /* 802.3 */
#define REG_PHY_REMOTE_CAPABILITY (0xEE) /* P1ANLPR */
#define PHY_REMOTE_SYM_PAUSE (0x0400) /* Link partner pause capability */
#define PHY_REMOTE_100BTX_FD (0x0100) /* Link partner 100 full-duplex capability */
#define PHY_REMOTE_100BTX (0x0080) /* Link partner 100 half-duplex capability */
#define PHY_REMOTE_10BT_FD (0x0040) /* Link partner 10 full-duplex capability */
#define PHY_REMOTE_10BT (0x0020) /* Link partner 10 half-duplex capability */
#define REG_PORT_LINK_MD (0xF4) /* P1SCLMD */
#define PORT_CABLE_10M_SHORT (0x8000) /* Cable length is less than 10m short */
#define PORT_CABLE_STAT_FAILED (0x6000) /* Cable diagnostic test fail */
#define PORT_CABLE_STAT_SHORT (0x4000) /* Short condition detected in the cable */
#define PORT_CABLE_STAT_OPEN (0x2000) /* Open condition detected in the cable */
#define PORT_CABLE_STAT_NORMAL (0x0000) /* Normal condition */
#define PORT_CABLE_DIAG_RESULT (0x6000) /* Cable diagnostic test result mask */
#define PORT_START_CABLE_DIAG (0x1000) /* Enable cable diagnostic test */
#define PORT_FORCE_LINK (0x0800) /* Enable force link pass */
#define PORT_POWER_SAVING (0x0400) /* Disable power saving */
#define PORT_REMOTE_LOOPBACK (0x0200) /* Enable remote loopback at PHY */
#define PORT_CABLE_FAULT_COUNTER (0x01FF) /* Cable length distance to the fault */
#define REG_PORT_CTRL (0xF6) /* P1CR */
#define PORT_LED_OFF (0x8000) /* Turn off all the port LEDs (LED3/LED2/LED1/LED0) */
#define PORT_TX_DISABLE (0x4000) /* Disable port transmit */
#define PORT_AUTO_NEG_RESTART (0x2000) /* Restart auto-negotiation */
#define PORT_POWER_DOWN (0x0800) /* Set port power-down */
#define PORT_AUTO_MDIX_DISABLE (0x0400) /* Disable auto MDI-X */
#define PORT_FORCE_MDIX (0x0200) /* Force MDI-X */
#define PORT_AUTO_NEG_ENABLE (0x0080) /* Enable auto-negotiation */
#define PORT_FORCE_100_MBIT (0x0040) /* Force PHY 100Mbps */
#define PORT_FORCE_FULL_DUPLEX (0x0020) /* Force PHY in full duplex mode */
#define PORT_AUTO_NEG_SYM_PAUSE (0x0010) /* Advertise pause capability */
#define PORT_AUTO_NEG_100BTX_FD (0x0008) /* Advertise 100 full-duplex capability */
#define PORT_AUTO_NEG_100BTX (0x0004) /* Advertise 100 half-duplex capability */
#define PORT_AUTO_NEG_10BT_FD (0x0002) /* Advertise 10 full-duplex capability */
#define PORT_AUTO_NEG_10BT (0x0001) /* Advertise 10 half-duplex capability */
#define REG_PORT_STATUS (0xF8) /* P1SR */
#define PORT_HP_MDIX (0x8000) /* Set PHY in HP auto MDI-X mode */
#define PORT_REVERSED_POLARITY (0x2000) /* Polarity is reversed */
#define PORT_RX_FLOW_CTRL (0x1000) /* Reeive flow control feature is active */
#define PORT_TX_FLOW_CTRL (0x0800) /* Transmit flow control feature is active */
#define PORT_STAT_SPEED_100MBIT (0x0400) /* Link is 100Mbps */
#define PORT_STAT_FULL_DUPLEX (0x0200) /* Link is full duplex mode */
#define PORT_MDIX_STATUS (0x0080) /* Is MDI */
#define PORT_AUTO_NEG_COMPLETE (0x0040) /* Auto-negotiation complete */
#define PORT_STATUS_LINK_GOOD (0x0020) /* PHY link is up */
#define PORT_REMOTE_SYM_PAUSE (0x0010) /* Link partner pause capability */
#define PORT_REMOTE_100BTX_FD (0x0008) /* Link partner 100 full-duplex capability */
#define PORT_REMOTE_100BTX (0x0004) /* Link partner 100 half-duplex capability */
#define PORT_REMOTE_10BT_FD (0x0002) /* Link partner 10 full-duplex capability */
#define PORT_REMOTE_10BT (0x0001) /* Link partner 10 half-duplex capability */
#endif /* KSZ8851SNL_REG_H_INCLUDED */

View file

@ -72,7 +72,7 @@
#include "FreeRTOS_server_private.h" #include "FreeRTOS_server_private.h"
/* Remove the entire file if TCP is not being used. */ /* Remove the entire file if TCP is not being used. */
#if( ipconfigUSE_TCP == 1 ) #if( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) )
#if !defined( ARRAY_SIZE ) #if !defined( ARRAY_SIZE )
#define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )
@ -238,8 +238,11 @@ const char *pcType = "Unknown";
pcType = "closed"; pcType = "closed";
FreeRTOS_closesocket( xNexSocket ); FreeRTOS_closesocket( xNexSocket );
} }
{
FreeRTOS_printf( ( "TPC-server: new %s client\n", pcType ) ); struct freertos_sockaddr xRemoteAddress;
FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress );
FreeRTOS_printf( ( "TPC-server: new %s client %xip\n", pcType, (unsigned)FreeRTOS_ntohl( xRemoteAddress.sin_addr ) ) );
}
/* Remove compiler warnings in case FreeRTOS_printf() is not used. */ /* Remove compiler warnings in case FreeRTOS_printf() is not used. */
( void ) pcType; ( void ) pcType;
@ -379,4 +382,4 @@ BaseType_t xLength = strlen( pcDir );
#endif /* ipconfigSUPPORT_SIGNALS */ #endif /* ipconfigSUPPORT_SIGNALS */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#endif /* ipconfigUSE_TCP != 1 */ #endif /* ( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) */

View file

@ -72,6 +72,9 @@
#include "FreeRTOS_TCP_server.h" #include "FreeRTOS_TCP_server.h"
#include "FreeRTOS_server_private.h" #include "FreeRTOS_server_private.h"
/* Remove the whole file if HTTP is not supported. */
#if( ipconfigUSE_HTTP == 1 )
/* FreeRTOS+FAT includes. */ /* FreeRTOS+FAT includes. */
#include "ff_stdio.h" #include "ff_stdio.h"
@ -453,3 +456,5 @@ static const char *pcGetContentsType (const char *apFname)
return pcResult; return pcResult;
} }
#endif /* ipconfigUSE_HTTP */