Initial version
This commit is contained in:
+649
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
* FreeRTOS+TCP V2.0.11
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://aws.amazon.com/freertos
|
||||
* http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
|
||||
/* 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 "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
/* Some files from the Atmel Software Framework */
|
||||
/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
|
||||
#include "instance/gmac.h"
|
||||
#include <sysclk.h>
|
||||
#include <ethernet_phy.h>
|
||||
|
||||
#ifndef BMSR_LINK_STATUS
|
||||
#define BMSR_LINK_STATUS 0x0004 //!< Link status
|
||||
#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
|
||||
|
||||
/* Interrupt events to process. Currently only the Rx event is processed
|
||||
although code for other events is included to allow for possible future
|
||||
expansion. */
|
||||
#define EMAC_IF_RX_EVENT 1UL
|
||||
#define EMAC_IF_TX_EVENT 2UL
|
||||
#define EMAC_IF_ERR_EVENT 4UL
|
||||
#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
|
||||
|
||||
#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
|
||||
|
||||
#define HZ_PER_MHZ ( 1000000UL )
|
||||
|
||||
#ifndef EMAC_MAX_BLOCK_TIME_MS
|
||||
#define EMAC_MAX_BLOCK_TIME_MS 100ul
|
||||
#endif
|
||||
|
||||
#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
|
||||
#error Please define GMAC_USES_TX_CALLBACK as 1
|
||||
#endif
|
||||
|
||||
#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
|
||||
#warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible
|
||||
#endif
|
||||
|
||||
/* Default the size of the stack used by the EMAC deferred handler task to 4x
|
||||
the size of the stack used by the idle task - but allow this to be overridden in
|
||||
FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
|
||||
#ifndef configEMAC_TASK_STACK_SIZE
|
||||
#define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Wait a fixed time for the link status to indicate the network is up.
|
||||
*/
|
||||
static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
|
||||
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
|
||||
void vGMACGenerateChecksum( uint8_t *apBuffer );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Called from the ASF GMAC driver.
|
||||
*/
|
||||
static void prvRxCallback( uint32_t ulStatus );
|
||||
static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
|
||||
|
||||
/*
|
||||
* A deferred interrupt handler task that processes GMAC interrupts.
|
||||
*/
|
||||
static void prvEMACHandlerTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Initialise the ASF GMAC driver.
|
||||
*/
|
||||
static BaseType_t prvGMACInit( void );
|
||||
|
||||
/*
|
||||
* Try to obtain an Rx packet from the hardware.
|
||||
*/
|
||||
static uint32_t prvEMACRxPoll( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Bit map of outstanding ETH interrupt events for processing. Currently only
|
||||
the Rx interrupt is handled, although code is included for other events to
|
||||
enable future expansion. */
|
||||
static volatile uint32_t ulISREvents;
|
||||
|
||||
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
|
||||
static uint32_t ulPHYLinkStatus = 0;
|
||||
static volatile BaseType_t xGMACSwitchRequired;
|
||||
|
||||
/* ethernet_phy_addr: the address of the PHY in use.
|
||||
Atmel was a bit ambiguous about it so the address will be stored
|
||||
in this variable, see ethernet_phy.c */
|
||||
extern int ethernet_phy_addr;
|
||||
|
||||
/* LLMNR multicast address. */
|
||||
static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
|
||||
|
||||
/* The GMAC object as defined by the ASF drivers. */
|
||||
static gmac_device_t gs_gmac_dev;
|
||||
|
||||
/* MAC address to use. */
|
||||
extern const uint8_t ucMACAddress[ 6 ];
|
||||
|
||||
/* Holds the handle of the task used as a deferred interrupt processor. The
|
||||
handle is used so direct notifications can be sent to the task for all EMAC/DMA
|
||||
related interrupts. */
|
||||
TaskHandle_t xEMACTaskHandle = NULL;
|
||||
|
||||
static QueueHandle_t xTxBufferQueue;
|
||||
int tx_release_count[ 4 ];
|
||||
|
||||
/* xTXDescriptorSemaphore is a counting semaphore with
|
||||
a maximum count of GMAC_TX_BUFFERS, which is the number of
|
||||
DMA TX descriptors. */
|
||||
static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* GMAC interrupt handler.
|
||||
*/
|
||||
void GMAC_Handler(void)
|
||||
{
|
||||
xGMACSwitchRequired = pdFALSE;
|
||||
|
||||
/* gmac_handler() may call prvRxCallback() which may change
|
||||
the value of xGMACSwitchRequired. */
|
||||
gmac_handler( &gs_gmac_dev );
|
||||
|
||||
if( xGMACSwitchRequired != pdFALSE )
|
||||
{
|
||||
portEND_SWITCHING_ISR( xGMACSwitchRequired );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRxCallback( uint32_t ulStatus )
|
||||
{
|
||||
if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
|
||||
{
|
||||
/* let the prvEMACHandlerTask know that there was an RX event. */
|
||||
ulISREvents |= EMAC_IF_RX_EVENT;
|
||||
/* Only an RX interrupt can wakeup prvEMACHandlerTask. */
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
|
||||
{
|
||||
if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
|
||||
{
|
||||
/* let the prvEMACHandlerTask know that there was an RX event. */
|
||||
ulISREvents |= EMAC_IF_TX_EVENT;
|
||||
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
|
||||
xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
|
||||
tx_release_count[ 2 ]++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceInitialise( void )
|
||||
{
|
||||
const TickType_t x5_Seconds = 5000UL;
|
||||
|
||||
if( xEMACTaskHandle == NULL )
|
||||
{
|
||||
prvGMACInit();
|
||||
|
||||
/* Wait at most 5 seconds for a Link Status in the PHY. */
|
||||
xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
|
||||
|
||||
/* The handler task is created at the highest possible priority to
|
||||
ensure the interrupt handler can return directly to it. */
|
||||
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
|
||||
configASSERT( xEMACTaskHandle );
|
||||
}
|
||||
|
||||
if( xTxBufferQueue == NULL )
|
||||
{
|
||||
xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
|
||||
configASSERT( xTxBufferQueue );
|
||||
}
|
||||
|
||||
if( xTXDescriptorSemaphore == NULL )
|
||||
{
|
||||
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
|
||||
configASSERT( xTXDescriptorSemaphore );
|
||||
}
|
||||
/* When returning non-zero, the stack will become active and
|
||||
start DHCP (in configured) */
|
||||
return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xGetPhyLinkStatus( void )
|
||||
{
|
||||
BaseType_t xResult;
|
||||
|
||||
/* This function returns true if the Link Status in the PHY is high. */
|
||||
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
xResult = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xResult = pdFALSE;
|
||||
}
|
||||
|
||||
return xResult;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
|
||||
{
|
||||
/* Do not wait too long for a free TX DMA buffer. */
|
||||
const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
|
||||
|
||||
do {
|
||||
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
|
||||
{
|
||||
/* Do not attempt to send packets as long as the Link Status is low. */
|
||||
break;
|
||||
}
|
||||
if( xTXDescriptorSemaphore == NULL )
|
||||
{
|
||||
/* Semaphore has not been created yet? */
|
||||
break;
|
||||
}
|
||||
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
|
||||
{
|
||||
/* Time-out waiting for a free TX descriptor. */
|
||||
tx_release_count[ 3 ]++;
|
||||
break;
|
||||
}
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
/* Confirm that the pxDescriptor may be kept by the driver. */
|
||||
configASSERT( bReleaseAfterSend != pdFALSE );
|
||||
}
|
||||
#endif /* ipconfigZERO_COPY_TX_DRIVER */
|
||||
|
||||
gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
|
||||
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
/* Confirm that the pxDescriptor may be kept by the driver. */
|
||||
bReleaseAfterSend = pdFALSE;
|
||||
}
|
||||
#endif /* ipconfigZERO_COPY_TX_DRIVER */
|
||||
/* Not interested in a call-back after TX. */
|
||||
iptraceNETWORK_INTERFACE_TRANSMIT();
|
||||
} while( 0 );
|
||||
|
||||
if( bReleaseAfterSend != pdFALSE )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxDescriptor );
|
||||
}
|
||||
return pdTRUE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t prvGMACInit( void )
|
||||
{
|
||||
uint32_t ncfgr;
|
||||
|
||||
gmac_options_t gmac_option;
|
||||
|
||||
memset( &gmac_option, '\0', sizeof( gmac_option ) );
|
||||
gmac_option.uc_copy_all_frame = 0;
|
||||
gmac_option.uc_no_boardcast = 0;
|
||||
memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
|
||||
|
||||
gs_gmac_dev.p_hw = GMAC;
|
||||
gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
|
||||
|
||||
NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
|
||||
NVIC_EnableIRQ( GMAC_IRQn );
|
||||
|
||||
/* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
|
||||
ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
|
||||
|
||||
ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
|
||||
ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
|
||||
|
||||
/* The GMAC driver will call a hook prvRxCallback(), which
|
||||
in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
|
||||
gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
|
||||
gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
|
||||
|
||||
ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
|
||||
|
||||
GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
|
||||
{
|
||||
uint32_t ulValue, ulReturn;
|
||||
int rc;
|
||||
|
||||
gmac_enable_management( GMAC, 1 );
|
||||
rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
|
||||
gmac_enable_management( GMAC, 0 );
|
||||
if( rc == GMAC_OK )
|
||||
{
|
||||
ulReturn = ulValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulReturn = 0UL;
|
||||
}
|
||||
|
||||
return ulReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
|
||||
{
|
||||
TickType_t xStartTime = xTaskGetTickCount();
|
||||
TickType_t xEndTime;
|
||||
BaseType_t xReturn;
|
||||
const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
xEndTime = xTaskGetTickCount();
|
||||
|
||||
if( ( xEndTime - xStartTime ) > xMaxTime )
|
||||
{
|
||||
/* Wated more than xMaxTime, return. */
|
||||
xReturn = pdFALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the link status again. */
|
||||
ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
|
||||
|
||||
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
/* Link is up - return. */
|
||||
xReturn = pdTRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Link is down - wait in the Blocked state for a short while (to allow
|
||||
other tasks to execute) before checking again. */
|
||||
vTaskDelay( xShortTime );
|
||||
}
|
||||
|
||||
FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
|
||||
xReturn,
|
||||
ethernet_phy_addr,
|
||||
sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
|
||||
|
||||
void vGMACGenerateChecksum( uint8_t *apBuffer )
|
||||
{
|
||||
ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
|
||||
|
||||
if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
|
||||
{
|
||||
IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
|
||||
|
||||
/* Calculate the IP header checksum. */
|
||||
pxIPHeader->usHeaderChecksum = 0x00;
|
||||
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
|
||||
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
|
||||
|
||||
/* Calculate the TCP checksum for an outgoing packet. */
|
||||
usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
|
||||
}
|
||||
}
|
||||
|
||||
//#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static uint32_t prvEMACRxPoll( void )
|
||||
{
|
||||
unsigned char *pucUseBuffer;
|
||||
uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
|
||||
static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
|
||||
const UBaseType_t xMinDescriptorsToLeave = 2UL;
|
||||
const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
|
||||
static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* If pxNextNetworkBufferDescriptor was not left pointing at a valid
|
||||
descriptor then allocate one now. */
|
||||
if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
|
||||
{
|
||||
pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
|
||||
}
|
||||
|
||||
if( pxNextNetworkBufferDescriptor != NULL )
|
||||
{
|
||||
/* Point pucUseBuffer to the buffer pointed to by the descriptor. */
|
||||
pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
|
||||
messages will be flushed and ignored. */
|
||||
pucUseBuffer = NULL;
|
||||
}
|
||||
|
||||
/* Read the next packet from the hardware into pucUseBuffer. */
|
||||
ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
|
||||
|
||||
if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
|
||||
{
|
||||
/* No data from the hardware. */
|
||||
break;
|
||||
}
|
||||
|
||||
if( pxNextNetworkBufferDescriptor == NULL )
|
||||
{
|
||||
/* Data was read from the hardware, but no descriptor was available
|
||||
for it, so it will be dropped. */
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
continue;
|
||||
}
|
||||
|
||||
iptraceNETWORK_INTERFACE_RECEIVE();
|
||||
pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
|
||||
xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
|
||||
|
||||
/* Send the descriptor to the IP task for processing. */
|
||||
if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
|
||||
{
|
||||
/* The buffer could not be sent to the stack so must be released
|
||||
again. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
|
||||
}
|
||||
|
||||
/* Now the buffer has either been passed to the IP-task,
|
||||
or it has been released in the code above. */
|
||||
pxNextNetworkBufferDescriptor = NULL;
|
||||
ulReturnValue++;
|
||||
}
|
||||
|
||||
return ulReturnValue;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCheckBuffersAndQueue( void )
|
||||
{
|
||||
static UBaseType_t uxLastMinBufferCount = 0;
|
||||
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
|
||||
static UBaseType_t uxLastMinQueueSpace;
|
||||
#endif
|
||||
static UBaseType_t uxCurrentCount;
|
||||
|
||||
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
|
||||
{
|
||||
uxCurrentCount = uxGetMinimumIPQueueSpace();
|
||||
if( uxLastMinQueueSpace != uxCurrentCount )
|
||||
{
|
||||
/* The logging produced below may be helpful
|
||||
while tuning +TCP: see how many buffers are in use. */
|
||||
uxLastMinQueueSpace = uxCurrentCount;
|
||||
FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
|
||||
}
|
||||
}
|
||||
#endif /* ipconfigCHECK_IP_QUEUE_SPACE */
|
||||
uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
|
||||
if( uxLastMinBufferCount != uxCurrentCount )
|
||||
{
|
||||
/* The logging produced below may be helpful
|
||||
while tuning +TCP: see how many buffers are in use. */
|
||||
uxLastMinBufferCount = uxCurrentCount;
|
||||
FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
|
||||
uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void prvEMACHandlerTask( void *pvParameters )
|
||||
{
|
||||
TimeOut_t xPhyTime;
|
||||
TickType_t xPhyRemTime;
|
||||
UBaseType_t uxCount;
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
NetworkBufferDescriptor_t *pxBuffer;
|
||||
#endif
|
||||
uint8_t *pucBuffer;
|
||||
BaseType_t xResult = 0;
|
||||
uint32_t xStatus;
|
||||
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
configASSERT( xEMACTaskHandle );
|
||||
|
||||
vTaskSetTimeOutState( &xPhyTime );
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
vCheckBuffersAndQueue();
|
||||
|
||||
if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
|
||||
{
|
||||
/* No events to process now, wait for the next. */
|
||||
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
|
||||
}
|
||||
|
||||
if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
|
||||
{
|
||||
ulISREvents &= ~EMAC_IF_RX_EVENT;
|
||||
|
||||
/* Wait for the EMAC interrupt to indicate that another packet has been
|
||||
received. */
|
||||
xResult = prvEMACRxPoll();
|
||||
}
|
||||
|
||||
if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
|
||||
{
|
||||
/* Future extension: code to release TX buffers if zero-copy is used. */
|
||||
ulISREvents &= ~EMAC_IF_TX_EVENT;
|
||||
while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
|
||||
{
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
|
||||
if( pxBuffer != NULL )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
||||
tx_release_count[ 0 ]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_release_count[ 1 ]++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
tx_release_count[ 0 ]++;
|
||||
}
|
||||
#endif
|
||||
uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
|
||||
if( uxCount < GMAC_TX_BUFFERS )
|
||||
{
|
||||
/* Tell the counting semaphore that one more TX descriptor is available. */
|
||||
xSemaphoreGive( xTXDescriptorSemaphore );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
|
||||
{
|
||||
/* Future extension: logging about errors that occurred. */
|
||||
ulISREvents &= ~EMAC_IF_ERR_EVENT;
|
||||
}
|
||||
|
||||
if( xResult > 0 )
|
||||
{
|
||||
/* A packet was received. No need to check for the PHY status now,
|
||||
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 )
|
||||
{
|
||||
/* Check the link status again. */
|
||||
xStatus = ulReadMDIO( PHY_REG_01_BMSR );
|
||||
|
||||
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
|
||||
{
|
||||
ulPHYLinkStatus = xStatus;
|
||||
FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
+746
@@ -0,0 +1,746 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Copyright (c) 2012 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SAM4E_GMAC_COMPONENT_
|
||||
#define _SAM4E_GMAC_COMPONENT_
|
||||
|
||||
/* ============================================================================= */
|
||||
/** SOFTWARE API DEFINITION FOR Gigabit Ethernet MAC */
|
||||
/* ============================================================================= */
|
||||
/** \addtogroup SAM4E_GMAC Gigabit Ethernet MAC */
|
||||
/*@{*/
|
||||
|
||||
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
|
||||
/** \brief GmacSa hardware registers */
|
||||
typedef struct {
|
||||
RwReg GMAC_SAB; /**< \brief (GmacSa Offset: 0x0) Specific Address 1 Bottom [31:0] Register */
|
||||
RwReg GMAC_SAT; /**< \brief (GmacSa Offset: 0x4) Specific Address 1 Top [47:32] Register */
|
||||
} GmacSa;
|
||||
/** \brief Gmac hardware registers */
|
||||
#define GMACSA_NUMBER 4
|
||||
typedef struct {
|
||||
RwReg GMAC_NCR; /**< \brief (Gmac Offset: 0x000) Network Control Register */
|
||||
RwReg GMAC_NCFGR; /**< \brief (Gmac Offset: 0x004) Network Configuration Register */
|
||||
RoReg GMAC_NSR; /**< \brief (Gmac Offset: 0x008) Network Status Register */
|
||||
RwReg GMAC_UR; /**< \brief (Gmac Offset: 0x00C) User Register */
|
||||
RwReg GMAC_DCFGR; /**< \brief (Gmac Offset: 0x010) DMA Configuration Register */
|
||||
RwReg GMAC_TSR; /**< \brief (Gmac Offset: 0x014) Transmit Status Register */
|
||||
RwReg GMAC_RBQB; /**< \brief (Gmac Offset: 0x018) Receive Buffer Queue Base Address */
|
||||
RwReg GMAC_TBQB; /**< \brief (Gmac Offset: 0x01C) Transmit Buffer Queue Base Address */
|
||||
RwReg GMAC_RSR; /**< \brief (Gmac Offset: 0x020) Receive Status Register */
|
||||
RoReg GMAC_ISR; /**< \brief (Gmac Offset: 0x024) Interrupt Status Register */
|
||||
WoReg GMAC_IER; /**< \brief (Gmac Offset: 0x028) Interrupt Enable Register */
|
||||
WoReg GMAC_IDR; /**< \brief (Gmac Offset: 0x02C) Interrupt Disable Register */
|
||||
RoReg GMAC_IMR; /**< \brief (Gmac Offset: 0x030) Interrupt Mask Register */
|
||||
RwReg GMAC_MAN; /**< \brief (Gmac Offset: 0x034) PHY Maintenance Register */
|
||||
RoReg GMAC_RPQ; /**< \brief (Gmac Offset: 0x038) Received Pause Quantum Register */
|
||||
RwReg GMAC_TPQ; /**< \brief (Gmac Offset: 0x03C) Transmit Pause Quantum Register */
|
||||
RwReg GMAC_TPSF; /**< \brief (Gmac Offset: 0x040) TX Partial Store and Forward Register */
|
||||
RwReg GMAC_RPSF; /**< \brief (Gmac Offset: 0x044) RX Partial Store and Forward Register */
|
||||
RoReg Reserved1[14];
|
||||
RwReg GMAC_HRB; /**< \brief (Gmac Offset: 0x080) Hash Register Bottom [31:0] */
|
||||
RwReg GMAC_HRT; /**< \brief (Gmac Offset: 0x084) Hash Register Top [63:32] */
|
||||
GmacSa GMAC_SA[GMACSA_NUMBER]; /**< \brief (Gmac Offset: 0x088) 1 .. 4 */
|
||||
RwReg GMAC_TIDM[4]; /**< \brief (Gmac Offset: 0x0A8) Type ID Match 1 Register */
|
||||
RwReg GMAC_WOL; /**< \brief (Gmac Offset: 0x0B8) Wake on LAN Register */
|
||||
RwReg GMAC_IPGS; /**< \brief (Gmac Offset: 0x0BC) IPG Stretch Register */
|
||||
RwReg GMAC_SVLAN; /**< \brief (Gmac Offset: 0x0C0) Stacked VLAN Register */
|
||||
RwReg GMAC_TPFCP; /**< \brief (Gmac Offset: 0x0C4) Transmit PFC Pause Register */
|
||||
RwReg GMAC_SAMB1; /**< \brief (Gmac Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register */
|
||||
RwReg GMAC_SAMT1; /**< \brief (Gmac Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register */
|
||||
RoReg Reserved2[12];
|
||||
RoReg GMAC_OTLO; /**< \brief (Gmac Offset: 0x100) Octets Transmitted [31:0] Register */
|
||||
RoReg GMAC_OTHI; /**< \brief (Gmac Offset: 0x104) Octets Transmitted [47:32] Register */
|
||||
RoReg GMAC_FT; /**< \brief (Gmac Offset: 0x108) Frames Transmitted Register */
|
||||
RoReg GMAC_BCFT; /**< \brief (Gmac Offset: 0x10C) Broadcast Frames Transmitted Register */
|
||||
RoReg GMAC_MFT; /**< \brief (Gmac Offset: 0x110) Multicast Frames Transmitted Register */
|
||||
RoReg GMAC_PFT; /**< \brief (Gmac Offset: 0x114) Pause Frames Transmitted Register */
|
||||
RoReg GMAC_BFT64; /**< \brief (Gmac Offset: 0x118) 64 Byte Frames Transmitted Register */
|
||||
RoReg GMAC_TBFT127; /**< \brief (Gmac Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register */
|
||||
RoReg GMAC_TBFT255; /**< \brief (Gmac Offset: 0x120) 128 to 255 Byte Frames Transmitted Register */
|
||||
RoReg GMAC_TBFT511; /**< \brief (Gmac Offset: 0x124) 256 to 511 Byte Frames Transmitted Register */
|
||||
RoReg GMAC_TBFT1023; /**< \brief (Gmac Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register */
|
||||
RoReg GMAC_TBFT1518; /**< \brief (Gmac Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register */
|
||||
RoReg GMAC_GTBFT1518; /**< \brief (Gmac Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register */
|
||||
RoReg GMAC_TUR; /**< \brief (Gmac Offset: 0x134) Transmit Under Runs Register */
|
||||
RoReg GMAC_SCF; /**< \brief (Gmac Offset: 0x138) Single Collision Frames Register */
|
||||
RoReg GMAC_MCF; /**< \brief (Gmac Offset: 0x13C) Multiple Collision Frames Register */
|
||||
RoReg GMAC_EC; /**< \brief (Gmac Offset: 0x140) Excessive Collisions Register */
|
||||
RoReg GMAC_LC; /**< \brief (Gmac Offset: 0x144) Late Collisions Register */
|
||||
RoReg GMAC_DTF; /**< \brief (Gmac Offset: 0x148) Deferred Transmission Frames Register */
|
||||
RoReg GMAC_CSE; /**< \brief (Gmac Offset: 0x14C) Carrier Sense Errors Register */
|
||||
RoReg GMAC_ORLO; /**< \brief (Gmac Offset: 0x150) Octets Received [31:0] Received */
|
||||
RoReg GMAC_ORHI; /**< \brief (Gmac Offset: 0x154) Octets Received [47:32] Received */
|
||||
RoReg GMAC_FR; /**< \brief (Gmac Offset: 0x158) Frames Received Register */
|
||||
RoReg GMAC_BCFR; /**< \brief (Gmac Offset: 0x15C) Broadcast Frames Received Register */
|
||||
RoReg GMAC_MFR; /**< \brief (Gmac Offset: 0x160) Multicast Frames Received Register */
|
||||
RoReg GMAC_PFR; /**< \brief (Gmac Offset: 0x164) Pause Frames Received Register */
|
||||
RoReg GMAC_BFR64; /**< \brief (Gmac Offset: 0x168) 64 Byte Frames Received Register */
|
||||
RoReg GMAC_TBFR127; /**< \brief (Gmac Offset: 0x16C) 65 to 127 Byte Frames Received Register */
|
||||
RoReg GMAC_TBFR255; /**< \brief (Gmac Offset: 0x170) 128 to 255 Byte Frames Received Register */
|
||||
RoReg GMAC_TBFR511; /**< \brief (Gmac Offset: 0x174) 256 to 511Byte Frames Received Register */
|
||||
RoReg GMAC_TBFR1023; /**< \brief (Gmac Offset: 0x178) 512 to 1023 Byte Frames Received Register */
|
||||
RoReg GMAC_TBFR1518; /**< \brief (Gmac Offset: 0x17C) 1024 to 1518 Byte Frames Received Register */
|
||||
RoReg GMAC_TMXBFR; /**< \brief (Gmac Offset: 0x180) 1519 to Maximum Byte Frames Received Register */
|
||||
RoReg GMAC_UFR; /**< \brief (Gmac Offset: 0x184) Undersize Frames Received Register */
|
||||
RoReg GMAC_OFR; /**< \brief (Gmac Offset: 0x188) Oversize Frames Received Register */
|
||||
RoReg GMAC_JR; /**< \brief (Gmac Offset: 0x18C) Jabbers Received Register */
|
||||
RoReg GMAC_FCSE; /**< \brief (Gmac Offset: 0x190) Frame Check Sequence Errors Register */
|
||||
RoReg GMAC_LFFE; /**< \brief (Gmac Offset: 0x194) Length Field Frame Errors Register */
|
||||
RoReg GMAC_RSE; /**< \brief (Gmac Offset: 0x198) Receive Symbol Errors Register */
|
||||
RoReg GMAC_AE; /**< \brief (Gmac Offset: 0x19C) Alignment Errors Register */
|
||||
RoReg GMAC_RRE; /**< \brief (Gmac Offset: 0x1A0) Receive Resource Errors Register */
|
||||
RoReg GMAC_ROE; /**< \brief (Gmac Offset: 0x1A4) Receive Overrun Register */
|
||||
RoReg GMAC_IHCE; /**< \brief (Gmac Offset: 0x1A8) IP Header Checksum Errors Register */
|
||||
RoReg GMAC_TCE; /**< \brief (Gmac Offset: 0x1AC) TCP Checksum Errors Register */
|
||||
RoReg GMAC_UCE; /**< \brief (Gmac Offset: 0x1B0) UDP Checksum Errors Register */
|
||||
RoReg Reserved3[5];
|
||||
RwReg GMAC_TSSS; /**< \brief (Gmac Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register */
|
||||
RwReg GMAC_TSSN; /**< \brief (Gmac Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register */
|
||||
RwReg GMAC_TS; /**< \brief (Gmac Offset: 0x1D0) 1588 Timer Seconds Register */
|
||||
RwReg GMAC_TN; /**< \brief (Gmac Offset: 0x1D4) 1588 Timer Nanoseconds Register */
|
||||
WoReg GMAC_TA; /**< \brief (Gmac Offset: 0x1D8) 1588 Timer Adjust Register */
|
||||
RwReg GMAC_TI; /**< \brief (Gmac Offset: 0x1DC) 1588 Timer Increment Register */
|
||||
RoReg GMAC_EFTS; /**< \brief (Gmac Offset: 0x1E0) PTP Event Frame Transmitted Seconds */
|
||||
RoReg GMAC_EFTN; /**< \brief (Gmac Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds */
|
||||
RoReg GMAC_EFRS; /**< \brief (Gmac Offset: 0x1E8) PTP Event Frame Received Seconds */
|
||||
RoReg GMAC_EFRN; /**< \brief (Gmac Offset: 0x1EC) PTP Event Frame Received Nanoseconds */
|
||||
RoReg GMAC_PEFTS; /**< \brief (Gmac Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds */
|
||||
RoReg GMAC_PEFTN; /**< \brief (Gmac Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds */
|
||||
RoReg GMAC_PEFRS; /**< \brief (Gmac Offset: 0x1F8) PTP Peer Event Frame Received Seconds */
|
||||
RoReg GMAC_PEFRN; /**< \brief (Gmac Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds */
|
||||
RoReg Reserved4[128];
|
||||
RoReg GMAC_ISRPQ[7]; /**< \brief (Gmac Offset: 0x400) Interrupt Status Register Priority Queue */
|
||||
RoReg Reserved5[9];
|
||||
RwReg GMAC_TBQBAPQ[7]; /**< \brief (Gmac Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue */
|
||||
RoReg Reserved6[9];
|
||||
RwReg GMAC_RBQBAPQ[7]; /**< \brief (Gmac Offset: 0x480) Receive Buffer Queue Base Address Priority Queue */
|
||||
RoReg Reserved7[1];
|
||||
RwReg GMAC_RBSRPQ[7]; /**< \brief (Gmac Offset: 0x4A0) Receive Buffer Size Register Priority Queue */
|
||||
RoReg Reserved8[17];
|
||||
RwReg GMAC_ST1RPQ[16]; /**< \brief (Gmac Offset: 0x500) Screening Type1 Register Priority Queue */
|
||||
RwReg GMAC_ST2RPQ[16]; /**< \brief (Gmac Offset: 0x540) Screening Type2 Register Priority Queue */
|
||||
RoReg Reserved9[32];
|
||||
WoReg GMAC_IERPQ[7]; /**< \brief (Gmac Offset: 0x600) Interrupt Enable Register Priority Queue */
|
||||
RoReg Reserved10[1];
|
||||
WoReg GMAC_IDRPQ[7]; /**< \brief (Gmac Offset: 0x620) Interrupt Disable Register Priority Queue */
|
||||
RoReg Reserved11[1];
|
||||
RwReg GMAC_IMRPQ[7]; /**< \brief (Gmac Offset: 0x640) Interrupt Mask Register Priority Queue */
|
||||
} Gmac;
|
||||
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
|
||||
/* -------- GMAC_NCR : (GMAC Offset: 0x000) Network Control Register -------- */
|
||||
#define GMAC_NCR_LB (0x1u << 0) /**< \brief (GMAC_NCR) Loop Back */
|
||||
#define GMAC_NCR_LBL (0x1u << 1) /**< \brief (GMAC_NCR) Loop Back Local */
|
||||
#define GMAC_NCR_RXEN (0x1u << 2) /**< \brief (GMAC_NCR) Receive Enable */
|
||||
#define GMAC_NCR_TXEN (0x1u << 3) /**< \brief (GMAC_NCR) Transmit Enable */
|
||||
#define GMAC_NCR_MPE (0x1u << 4) /**< \brief (GMAC_NCR) Management Port Enable */
|
||||
#define GMAC_NCR_CLRSTAT (0x1u << 5) /**< \brief (GMAC_NCR) Clear Statistics Registers */
|
||||
#define GMAC_NCR_INCSTAT (0x1u << 6) /**< \brief (GMAC_NCR) Increment Statistics Registers */
|
||||
#define GMAC_NCR_WESTAT (0x1u << 7) /**< \brief (GMAC_NCR) Write Enable for Statistics Registers */
|
||||
#define GMAC_NCR_BP (0x1u << 8) /**< \brief (GMAC_NCR) Back pressure */
|
||||
#define GMAC_NCR_TSTART (0x1u << 9) /**< \brief (GMAC_NCR) Start Transmission */
|
||||
#define GMAC_NCR_THALT (0x1u << 10) /**< \brief (GMAC_NCR) Transmit Halt */
|
||||
#define GMAC_NCR_TXPF (0x1u << 11) /**< \brief (GMAC_NCR) Transmit Pause Frame */
|
||||
#define GMAC_NCR_TXZQPF (0x1u << 12) /**< \brief (GMAC_NCR) Transmit Zero Quantum Pause Frame */
|
||||
#define GMAC_NCR_RDS (0x1u << 14) /**< \brief (GMAC_NCR) Read Snapshot */
|
||||
#define GMAC_NCR_SRTSM (0x1u << 15) /**< \brief (GMAC_NCR) Store Receive Time Stamp to Memory */
|
||||
#define GMAC_NCR_ENPBPR (0x1u << 16) /**< \brief (GMAC_NCR) Enable PFC Priority-based Pause Reception */
|
||||
#define GMAC_NCR_TXPBPF (0x1u << 17) /**< \brief (GMAC_NCR) Transmit PFC Priority-based Pause Frame */
|
||||
#define GMAC_NCR_FNP (0x1u << 18) /**< \brief (GMAC_NCR) Flush Next Packet */
|
||||
/* -------- GMAC_NCFGR : (GMAC Offset: 0x004) Network Configuration Register -------- */
|
||||
#define GMAC_NCFGR_SPD (0x1u << 0) /**< \brief (GMAC_NCFGR) Speed */
|
||||
#define GMAC_NCFGR_FD (0x1u << 1) /**< \brief (GMAC_NCFGR) Full Duplex */
|
||||
#define GMAC_NCFGR_DNVLAN (0x1u << 2) /**< \brief (GMAC_NCFGR) Discard Non-VLAN FRAMES */
|
||||
#define GMAC_NCFGR_JFRAME (0x1u << 3) /**< \brief (GMAC_NCFGR) Jumbo Frame Size */
|
||||
#define GMAC_NCFGR_CAF (0x1u << 4) /**< \brief (GMAC_NCFGR) Copy All Frames */
|
||||
#define GMAC_NCFGR_NBC (0x1u << 5) /**< \brief (GMAC_NCFGR) No Broadcast */
|
||||
#define GMAC_NCFGR_MTIHEN (0x1u << 6) /**< \brief (GMAC_NCFGR) Multicast Hash Enable */
|
||||
#define GMAC_NCFGR_UNIHEN (0x1u << 7) /**< \brief (GMAC_NCFGR) Unicast Hash Enable */
|
||||
#define GMAC_NCFGR_MAXFS (0x1u << 8) /**< \brief (GMAC_NCFGR) 1536 Maximum Frame Size */
|
||||
#define GMAC_NCFGR_GBE (0x1u << 10) /**< \brief (GMAC_NCFGR) Gigabit Mode Enable */
|
||||
#define GMAC_NCFGR_PIS (0x1u << 11) /**< \brief (GMAC_NCFGR) Physical Interface Select */
|
||||
#define GMAC_NCFGR_RTY (0x1u << 12) /**< \brief (GMAC_NCFGR) Retry Test */
|
||||
#define GMAC_NCFGR_PEN (0x1u << 13) /**< \brief (GMAC_NCFGR) Pause Enable */
|
||||
#define GMAC_NCFGR_RXBUFO_Pos 14
|
||||
#define GMAC_NCFGR_RXBUFO_Msk (0x3u << GMAC_NCFGR_RXBUFO_Pos) /**< \brief (GMAC_NCFGR) Receive Buffer Offset */
|
||||
#define GMAC_NCFGR_RXBUFO(value) ((GMAC_NCFGR_RXBUFO_Msk & ((value) << GMAC_NCFGR_RXBUFO_Pos)))
|
||||
#define GMAC_NCFGR_LFERD (0x1u << 16) /**< \brief (GMAC_NCFGR) Length Field Error Frame Discard */
|
||||
#define GMAC_NCFGR_RFCS (0x1u << 17) /**< \brief (GMAC_NCFGR) Remove FCS */
|
||||
#define GMAC_NCFGR_CLK_Pos 18
|
||||
#define GMAC_NCFGR_CLK_Msk (0x7u << GMAC_NCFGR_CLK_Pos) /**< \brief (GMAC_NCFGR) MDC CLock Division */
|
||||
#define GMAC_NCFGR_CLK_MCK_8 (0x0u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 8 (MCK up to 20 MHz) */
|
||||
#define GMAC_NCFGR_CLK_MCK_16 (0x1u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 16 (MCK up to 40 MHz) */
|
||||
#define GMAC_NCFGR_CLK_MCK_32 (0x2u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 32 (MCK up to 80 MHz) */
|
||||
#define GMAC_NCFGR_CLK_MCK_48 (0x3u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 48 (MCK up to 120MHz) */
|
||||
#define GMAC_NCFGR_CLK_MCK_64 (0x4u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 64 (MCK up to 160 MHz) */
|
||||
#define GMAC_NCFGR_CLK_MCK_96 (0x5u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 96 (MCK up to 240 MHz) */
|
||||
#define GMAC_NCFGR_CLK_MCK_128 (0x6u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 128 (MCK up to 320 MHz) */
|
||||
#define GMAC_NCFGR_CLK_MCK_224 (0x7u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 224 (MCK up to 540 MHz) */
|
||||
#define GMAC_NCFGR_DBW_Pos 21
|
||||
#define GMAC_NCFGR_DBW_Msk (0x3u << GMAC_NCFGR_DBW_Pos) /**< \brief (GMAC_NCFGR) Data Bus Width */
|
||||
#define GMAC_NCFGR_DBW_DBW32 (0x0u << 21) /**< \brief (GMAC_NCFGR) 32-bit data bus width */
|
||||
#define GMAC_NCFGR_DBW_DBW64 (0x1u << 21) /**< \brief (GMAC_NCFGR) 64-bit data bus width */
|
||||
#define GMAC_NCFGR_DCPF (0x1u << 23) /**< \brief (GMAC_NCFGR) Disable Copy of Pause Frames */
|
||||
#define GMAC_NCFGR_RXCOEN (0x1u << 24) /**< \brief (GMAC_NCFGR) Receive Checksum Offload Enable */
|
||||
#define GMAC_NCFGR_EFRHD (0x1u << 25) /**< \brief (GMAC_NCFGR) Enable Frames Received in Half Duplex */
|
||||
#define GMAC_NCFGR_IRXFCS (0x1u << 26) /**< \brief (GMAC_NCFGR) Ignore RX FCS */
|
||||
#define GMAC_NCFGR_IPGSEN (0x1u << 28) /**< \brief (GMAC_NCFGR) IP Stretch Enable */
|
||||
#define GMAC_NCFGR_RXBP (0x1u << 29) /**< \brief (GMAC_NCFGR) Receive Bad Preamble */
|
||||
#define GMAC_NCFGR_IRXER (0x1u << 30) /**< \brief (GMAC_NCFGR) Ignore IPG rx_er */
|
||||
/* -------- GMAC_NSR : (GMAC Offset: 0x008) Network Status Register -------- */
|
||||
#define GMAC_NSR_MDIO (0x1u << 1) /**< \brief (GMAC_NSR) MDIO Input Status */
|
||||
#define GMAC_NSR_IDLE (0x1u << 2) /**< \brief (GMAC_NSR) PHY Management Logic Idle */
|
||||
/* -------- GMAC_UR : (GMAC Offset: 0x00C) User Register -------- */
|
||||
#define GMAC_UR_RGMII (0x1u << 0) /**< \brief (GMAC_UR) RGMII Mode */
|
||||
#define GMAC_UR_HDFC (0x1u << 6) /**< \brief (GMAC_UR) Half Duplex Flow Control */
|
||||
#define GMAC_UR_BPDG (0x1u << 7) /**< \brief (GMAC_UR) BPDG Bypass Deglitchers */
|
||||
/* -------- GMAC_DCFGR : (GMAC Offset: 0x010) DMA Configuration Register -------- */
|
||||
#define GMAC_DCFGR_FBLDO_Pos 0
|
||||
#define GMAC_DCFGR_FBLDO_Msk (0x1fu << GMAC_DCFGR_FBLDO_Pos) /**< \brief (GMAC_DCFGR) Fixed Burst Length for DMA Data Operations: */
|
||||
#define GMAC_DCFGR_FBLDO_SINGLE (0x1u << 0) /**< \brief (GMAC_DCFGR) 00001: Always use SINGLE AHB bursts */
|
||||
#define GMAC_DCFGR_FBLDO_INCR4 (0x4u << 0) /**< \brief (GMAC_DCFGR) 001xx: Attempt to use INCR4 AHB bursts (Default) */
|
||||
#define GMAC_DCFGR_FBLDO_INCR8 (0x8u << 0) /**< \brief (GMAC_DCFGR) 01xxx: Attempt to use INCR8 AHB bursts */
|
||||
#define GMAC_DCFGR_FBLDO_INCR16 (0x10u << 0) /**< \brief (GMAC_DCFGR) 1xxxx: Attempt to use INCR16 AHB bursts */
|
||||
#define GMAC_DCFGR_ESMA (0x1u << 6) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Management Descriptor Accesses */
|
||||
#define GMAC_DCFGR_ESPA (0x1u << 7) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Packet Data Accesses */
|
||||
#define GMAC_DCFGR_RXBMS_Pos 8
|
||||
#define GMAC_DCFGR_RXBMS_Msk (0x3u << GMAC_DCFGR_RXBMS_Pos) /**< \brief (GMAC_DCFGR) Receiver Packet Buffer Memory Size Select */
|
||||
#define GMAC_DCFGR_RXBMS_EIGHTH (0x0u << 8) /**< \brief (GMAC_DCFGR) 1 Kbyte Memory Size */
|
||||
#define GMAC_DCFGR_RXBMS_QUARTER (0x1u << 8) /**< \brief (GMAC_DCFGR) 2 Kbytes Memory Size */
|
||||
#define GMAC_DCFGR_RXBMS_HALF (0x2u << 8) /**< \brief (GMAC_DCFGR) 4 Kbytes Memory Size */
|
||||
#define GMAC_DCFGR_RXBMS_FULL (0x3u << 8) /**< \brief (GMAC_DCFGR) 8 Kbytes Memory Size */
|
||||
#define GMAC_DCFGR_TXPBMS (0x1u << 10) /**< \brief (GMAC_DCFGR) Transmitter Packet Buffer Memory Size Select */
|
||||
#define GMAC_DCFGR_TXCOEN (0x1u << 11) /**< \brief (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable */
|
||||
#define GMAC_DCFGR_DRBS_Pos 16
|
||||
#define GMAC_DCFGR_DRBS_Msk (0xffu << GMAC_DCFGR_DRBS_Pos) /**< \brief (GMAC_DCFGR) DMA Receive Buffer Size */
|
||||
#define GMAC_DCFGR_DRBS(value) ((GMAC_DCFGR_DRBS_Msk & ((value) << GMAC_DCFGR_DRBS_Pos)))
|
||||
#define GMAC_DCFGR_DDRP (0x1u << 24) /**< \brief (GMAC_DCFGR) DMA Discard Receive Packets */
|
||||
/* -------- GMAC_TSR : (GMAC Offset: 0x014) Transmit Status Register -------- */
|
||||
#define GMAC_TSR_UBR (0x1u << 0) /**< \brief (GMAC_TSR) Used Bit Read */
|
||||
#define GMAC_TSR_COL (0x1u << 1) /**< \brief (GMAC_TSR) Collision Occurred */
|
||||
#define GMAC_TSR_RLE (0x1u << 2) /**< \brief (GMAC_TSR) Retry Limit Exceeded */
|
||||
#define GMAC_TSR_TXGO (0x1u << 3) /**< \brief (GMAC_TSR) Transmit Go */
|
||||
#define GMAC_TSR_TFC (0x1u << 4) /**< \brief (GMAC_TSR) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_TSR_TXCOMP (0x1u << 5) /**< \brief (GMAC_TSR) Transmit Complete */
|
||||
#define GMAC_TSR_UND (0x1u << 6) /**< \brief (GMAC_TSR) Transmit Under Run */
|
||||
#define GMAC_TSR_LCO (0x1u << 7) /**< \brief (GMAC_TSR) Late Collision Occurred */
|
||||
#define GMAC_TSR_HRESP (0x1u << 8) /**< \brief (GMAC_TSR) HRESP Not OK */
|
||||
/* -------- GMAC_RBQB : (GMAC Offset: 0x018) Receive Buffer Queue Base Address -------- */
|
||||
#define GMAC_RBQB_ADDR_Pos 2
|
||||
#define GMAC_RBQB_ADDR_Msk (0x3fffffffu << GMAC_RBQB_ADDR_Pos) /**< \brief (GMAC_RBQB) Receive buffer queue base address */
|
||||
#define GMAC_RBQB_ADDR(value) ((GMAC_RBQB_ADDR_Msk & ((value) << GMAC_RBQB_ADDR_Pos)))
|
||||
/* -------- GMAC_TBQB : (GMAC Offset: 0x01C) Transmit Buffer Queue Base Address -------- */
|
||||
#define GMAC_TBQB_ADDR_Pos 2
|
||||
#define GMAC_TBQB_ADDR_Msk (0x3fffffffu << GMAC_TBQB_ADDR_Pos) /**< \brief (GMAC_TBQB) Transmit Buffer Queue Base Address */
|
||||
#define GMAC_TBQB_ADDR(value) ((GMAC_TBQB_ADDR_Msk & ((value) << GMAC_TBQB_ADDR_Pos)))
|
||||
/* -------- GMAC_RSR : (GMAC Offset: 0x020) Receive Status Register -------- */
|
||||
#define GMAC_RSR_BNA (0x1u << 0) /**< \brief (GMAC_RSR) Buffer Not Available */
|
||||
#define GMAC_RSR_REC (0x1u << 1) /**< \brief (GMAC_RSR) Frame Received */
|
||||
#define GMAC_RSR_RXOVR (0x1u << 2) /**< \brief (GMAC_RSR) Receive Overrun */
|
||||
#define GMAC_RSR_HNO (0x1u << 3) /**< \brief (GMAC_RSR) HRESP Not OK */
|
||||
/* -------- GMAC_ISR : (GMAC Offset: 0x024) Interrupt Status Register -------- */
|
||||
#define GMAC_ISR_MFS (0x1u << 0) /**< \brief (GMAC_ISR) Management Frame Sent */
|
||||
#define GMAC_ISR_RCOMP (0x1u << 1) /**< \brief (GMAC_ISR) Receive Complete */
|
||||
#define GMAC_ISR_RXUBR (0x1u << 2) /**< \brief (GMAC_ISR) RX Used Bit Read */
|
||||
#define GMAC_ISR_TXUBR (0x1u << 3) /**< \brief (GMAC_ISR) TX Used Bit Read */
|
||||
#define GMAC_ISR_TUR (0x1u << 4) /**< \brief (GMAC_ISR) Transmit Under Run */
|
||||
#define GMAC_ISR_RLEX (0x1u << 5) /**< \brief (GMAC_ISR) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_ISR_TFC (0x1u << 6) /**< \brief (GMAC_ISR) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_ISR_TCOMP (0x1u << 7) /**< \brief (GMAC_ISR) Transmit Complete */
|
||||
#define GMAC_ISR_ROVR (0x1u << 10) /**< \brief (GMAC_ISR) Receive Overrun */
|
||||
#define GMAC_ISR_HRESP (0x1u << 11) /**< \brief (GMAC_ISR) HRESP Not OK */
|
||||
#define GMAC_ISR_PFNZ (0x1u << 12) /**< \brief (GMAC_ISR) Pause Frame with Non-zero Pause Quantum Received */
|
||||
#define GMAC_ISR_PTZ (0x1u << 13) /**< \brief (GMAC_ISR) Pause Time Zero */
|
||||
#define GMAC_ISR_PFTR (0x1u << 14) /**< \brief (GMAC_ISR) Pause Frame Transmitted */
|
||||
#define GMAC_ISR_EXINT (0x1u << 15) /**< \brief (GMAC_ISR) External Interrupt */
|
||||
#define GMAC_ISR_DRQFR (0x1u << 18) /**< \brief (GMAC_ISR) PTP Delay Request Frame Received */
|
||||
#define GMAC_ISR_SFR (0x1u << 19) /**< \brief (GMAC_ISR) PTP Sync Frame Received */
|
||||
#define GMAC_ISR_DRQFT (0x1u << 20) /**< \brief (GMAC_ISR) PTP Delay Request Frame Transmitted */
|
||||
#define GMAC_ISR_SFT (0x1u << 21) /**< \brief (GMAC_ISR) PTP Sync Frame Transmitted */
|
||||
#define GMAC_ISR_PDRQFR (0x1u << 22) /**< \brief (GMAC_ISR) PDelay Request Frame Received */
|
||||
#define GMAC_ISR_PDRSFR (0x1u << 23) /**< \brief (GMAC_ISR) PDelay Response Frame Received */
|
||||
#define GMAC_ISR_PDRQFT (0x1u << 24) /**< \brief (GMAC_ISR) PDelay Request Frame Transmitted */
|
||||
#define GMAC_ISR_PDRSFT (0x1u << 25) /**< \brief (GMAC_ISR) PDelay Response Frame Transmitted */
|
||||
#define GMAC_ISR_SRI (0x1u << 26) /**< \brief (GMAC_ISR) TSU Seconds Register Increment */
|
||||
#define GMAC_ISR_WOL (0x1u << 28) /**< \brief (GMAC_ISR) Wake On LAN */
|
||||
/* -------- GMAC_IER : (GMAC Offset: 0x028) Interrupt Enable Register -------- */
|
||||
#define GMAC_IER_MFS (0x1u << 0) /**< \brief (GMAC_IER) Management Frame Sent */
|
||||
#define GMAC_IER_RCOMP (0x1u << 1) /**< \brief (GMAC_IER) Receive Complete */
|
||||
#define GMAC_IER_RXUBR (0x1u << 2) /**< \brief (GMAC_IER) RX Used Bit Read */
|
||||
#define GMAC_IER_TXUBR (0x1u << 3) /**< \brief (GMAC_IER) TX Used Bit Read */
|
||||
#define GMAC_IER_TUR (0x1u << 4) /**< \brief (GMAC_IER) Transmit Under Run */
|
||||
#define GMAC_IER_RLEX (0x1u << 5) /**< \brief (GMAC_IER) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_IER_TFC (0x1u << 6) /**< \brief (GMAC_IER) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_IER_TCOMP (0x1u << 7) /**< \brief (GMAC_IER) Transmit Complete */
|
||||
#define GMAC_IER_ROVR (0x1u << 10) /**< \brief (GMAC_IER) Receive Overrun */
|
||||
#define GMAC_IER_HRESP (0x1u << 11) /**< \brief (GMAC_IER) HRESP Not OK */
|
||||
#define GMAC_IER_PFNZ (0x1u << 12) /**< \brief (GMAC_IER) Pause Frame with Non-zero Pause Quantum Received */
|
||||
#define GMAC_IER_PTZ (0x1u << 13) /**< \brief (GMAC_IER) Pause Time Zero */
|
||||
#define GMAC_IER_PFTR (0x1u << 14) /**< \brief (GMAC_IER) Pause Frame Transmitted */
|
||||
#define GMAC_IER_EXINT (0x1u << 15) /**< \brief (GMAC_IER) External Interrupt */
|
||||
#define GMAC_IER_DRQFR (0x1u << 18) /**< \brief (GMAC_IER) PTP Delay Request Frame Received */
|
||||
#define GMAC_IER_SFR (0x1u << 19) /**< \brief (GMAC_IER) PTP Sync Frame Received */
|
||||
#define GMAC_IER_DRQFT (0x1u << 20) /**< \brief (GMAC_IER) PTP Delay Request Frame Transmitted */
|
||||
#define GMAC_IER_SFT (0x1u << 21) /**< \brief (GMAC_IER) PTP Sync Frame Transmitted */
|
||||
#define GMAC_IER_PDRQFR (0x1u << 22) /**< \brief (GMAC_IER) PDelay Request Frame Received */
|
||||
#define GMAC_IER_PDRSFR (0x1u << 23) /**< \brief (GMAC_IER) PDelay Response Frame Received */
|
||||
#define GMAC_IER_PDRQFT (0x1u << 24) /**< \brief (GMAC_IER) PDelay Request Frame Transmitted */
|
||||
#define GMAC_IER_PDRSFT (0x1u << 25) /**< \brief (GMAC_IER) PDelay Response Frame Transmitted */
|
||||
#define GMAC_IER_SRI (0x1u << 26) /**< \brief (GMAC_IER) TSU Seconds Register Increment */
|
||||
#define GMAC_IER_WOL (0x1u << 28) /**< \brief (GMAC_IER) Wake On LAN */
|
||||
/* -------- GMAC_IDR : (GMAC Offset: 0x02C) Interrupt Disable Register -------- */
|
||||
#define GMAC_IDR_MFS (0x1u << 0) /**< \brief (GMAC_IDR) Management Frame Sent */
|
||||
#define GMAC_IDR_RCOMP (0x1u << 1) /**< \brief (GMAC_IDR) Receive Complete */
|
||||
#define GMAC_IDR_RXUBR (0x1u << 2) /**< \brief (GMAC_IDR) RX Used Bit Read */
|
||||
#define GMAC_IDR_TXUBR (0x1u << 3) /**< \brief (GMAC_IDR) TX Used Bit Read */
|
||||
#define GMAC_IDR_TUR (0x1u << 4) /**< \brief (GMAC_IDR) Transmit Under Run */
|
||||
#define GMAC_IDR_RLEX (0x1u << 5) /**< \brief (GMAC_IDR) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_IDR_TFC (0x1u << 6) /**< \brief (GMAC_IDR) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_IDR_TCOMP (0x1u << 7) /**< \brief (GMAC_IDR) Transmit Complete */
|
||||
#define GMAC_IDR_ROVR (0x1u << 10) /**< \brief (GMAC_IDR) Receive Overrun */
|
||||
#define GMAC_IDR_HRESP (0x1u << 11) /**< \brief (GMAC_IDR) HRESP Not OK */
|
||||
#define GMAC_IDR_PFNZ (0x1u << 12) /**< \brief (GMAC_IDR) Pause Frame with Non-zero Pause Quantum Received */
|
||||
#define GMAC_IDR_PTZ (0x1u << 13) /**< \brief (GMAC_IDR) Pause Time Zero */
|
||||
#define GMAC_IDR_PFTR (0x1u << 14) /**< \brief (GMAC_IDR) Pause Frame Transmitted */
|
||||
#define GMAC_IDR_EXINT (0x1u << 15) /**< \brief (GMAC_IDR) External Interrupt */
|
||||
#define GMAC_IDR_DRQFR (0x1u << 18) /**< \brief (GMAC_IDR) PTP Delay Request Frame Received */
|
||||
#define GMAC_IDR_SFR (0x1u << 19) /**< \brief (GMAC_IDR) PTP Sync Frame Received */
|
||||
#define GMAC_IDR_DRQFT (0x1u << 20) /**< \brief (GMAC_IDR) PTP Delay Request Frame Transmitted */
|
||||
#define GMAC_IDR_SFT (0x1u << 21) /**< \brief (GMAC_IDR) PTP Sync Frame Transmitted */
|
||||
#define GMAC_IDR_PDRQFR (0x1u << 22) /**< \brief (GMAC_IDR) PDelay Request Frame Received */
|
||||
#define GMAC_IDR_PDRSFR (0x1u << 23) /**< \brief (GMAC_IDR) PDelay Response Frame Received */
|
||||
#define GMAC_IDR_PDRQFT (0x1u << 24) /**< \brief (GMAC_IDR) PDelay Request Frame Transmitted */
|
||||
#define GMAC_IDR_PDRSFT (0x1u << 25) /**< \brief (GMAC_IDR) PDelay Response Frame Transmitted */
|
||||
#define GMAC_IDR_SRI (0x1u << 26) /**< \brief (GMAC_IDR) TSU Seconds Register Increment */
|
||||
#define GMAC_IDR_WOL (0x1u << 28) /**< \brief (GMAC_IDR) Wake On LAN */
|
||||
/* -------- GMAC_IMR : (GMAC Offset: 0x030) Interrupt Mask Register -------- */
|
||||
#define GMAC_IMR_MFS (0x1u << 0) /**< \brief (GMAC_IMR) Management Frame Sent */
|
||||
#define GMAC_IMR_RCOMP (0x1u << 1) /**< \brief (GMAC_IMR) Receive Complete */
|
||||
#define GMAC_IMR_RXUBR (0x1u << 2) /**< \brief (GMAC_IMR) RX Used Bit Read */
|
||||
#define GMAC_IMR_TXUBR (0x1u << 3) /**< \brief (GMAC_IMR) TX Used Bit Read */
|
||||
#define GMAC_IMR_TUR (0x1u << 4) /**< \brief (GMAC_IMR) Transmit Under Run */
|
||||
#define GMAC_IMR_RLEX (0x1u << 5) /**< \brief (GMAC_IMR) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_IMR_TFC (0x1u << 6) /**< \brief (GMAC_IMR) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_IMR_TCOMP (0x1u << 7) /**< \brief (GMAC_IMR) Transmit Complete */
|
||||
#define GMAC_IMR_ROVR (0x1u << 10) /**< \brief (GMAC_IMR) Receive Overrun */
|
||||
#define GMAC_IMR_HRESP (0x1u << 11) /**< \brief (GMAC_IMR) HRESP Not OK */
|
||||
#define GMAC_IMR_PFNZ (0x1u << 12) /**< \brief (GMAC_IMR) Pause Frame with Non-zero Pause Quantum Received */
|
||||
#define GMAC_IMR_PTZ (0x1u << 13) /**< \brief (GMAC_IMR) Pause Time Zero */
|
||||
#define GMAC_IMR_PFTR (0x1u << 14) /**< \brief (GMAC_IMR) Pause Frame Transmitted */
|
||||
#define GMAC_IMR_EXINT (0x1u << 15) /**< \brief (GMAC_IMR) External Interrupt */
|
||||
#define GMAC_IMR_DRQFR (0x1u << 18) /**< \brief (GMAC_IMR) PTP Delay Request Frame Received */
|
||||
#define GMAC_IMR_SFR (0x1u << 19) /**< \brief (GMAC_IMR) PTP Sync Frame Received */
|
||||
#define GMAC_IMR_DRQFT (0x1u << 20) /**< \brief (GMAC_IMR) PTP Delay Request Frame Transmitted */
|
||||
#define GMAC_IMR_SFT (0x1u << 21) /**< \brief (GMAC_IMR) PTP Sync Frame Transmitted */
|
||||
#define GMAC_IMR_PDRQFR (0x1u << 22) /**< \brief (GMAC_IMR) PDelay Request Frame Received */
|
||||
#define GMAC_IMR_PDRSFR (0x1u << 23) /**< \brief (GMAC_IMR) PDelay Response Frame Received */
|
||||
#define GMAC_IMR_PDRQFT (0x1u << 24) /**< \brief (GMAC_IMR) PDelay Request Frame Transmitted */
|
||||
#define GMAC_IMR_PDRSFT (0x1u << 25) /**< \brief (GMAC_IMR) PDelay Response Frame Transmitted */
|
||||
/* -------- GMAC_MAN : (GMAC Offset: 0x034) PHY Maintenance Register -------- */
|
||||
#define GMAC_MAN_DATA_Pos 0
|
||||
#define GMAC_MAN_DATA_Msk (0xffffu << GMAC_MAN_DATA_Pos) /**< \brief (GMAC_MAN) PHY Data */
|
||||
#define GMAC_MAN_DATA(value) ((GMAC_MAN_DATA_Msk & ((value) << GMAC_MAN_DATA_Pos)))
|
||||
#define GMAC_MAN_WTN_Pos 16
|
||||
#define GMAC_MAN_WTN_Msk (0x3u << GMAC_MAN_WTN_Pos) /**< \brief (GMAC_MAN) Write Ten */
|
||||
#define GMAC_MAN_WTN(value) ((GMAC_MAN_WTN_Msk & ((value) << GMAC_MAN_WTN_Pos)))
|
||||
#define GMAC_MAN_REGA_Pos 18
|
||||
#define GMAC_MAN_REGA_Msk (0x1fu << GMAC_MAN_REGA_Pos) /**< \brief (GMAC_MAN) Register Address */
|
||||
#define GMAC_MAN_REGA(value) ((GMAC_MAN_REGA_Msk & ((value) << GMAC_MAN_REGA_Pos)))
|
||||
#define GMAC_MAN_PHYA_Pos 23
|
||||
#define GMAC_MAN_PHYA_Msk (0x1fu << GMAC_MAN_PHYA_Pos) /**< \brief (GMAC_MAN) PHY Address */
|
||||
#define GMAC_MAN_PHYA(value) ((GMAC_MAN_PHYA_Msk & ((value) << GMAC_MAN_PHYA_Pos)))
|
||||
#define GMAC_MAN_OP_Pos 28
|
||||
#define GMAC_MAN_OP_Msk (0x3u << GMAC_MAN_OP_Pos) /**< \brief (GMAC_MAN) Operation */
|
||||
#define GMAC_MAN_OP(value) ((GMAC_MAN_OP_Msk & ((value) << GMAC_MAN_OP_Pos)))
|
||||
#define GMAC_MAN_CLTTO (0x1u << 30) /**< \brief (GMAC_MAN) Clause 22 Operation */
|
||||
#define GMAC_MAN_WZO (0x1u << 31) /**< \brief (GMAC_MAN) Write ZERO */
|
||||
/* -------- GMAC_RPQ : (GMAC Offset: 0x038) Received Pause Quantum Register -------- */
|
||||
#define GMAC_RPQ_RPQ_Pos 0
|
||||
#define GMAC_RPQ_RPQ_Msk (0xffffu << GMAC_RPQ_RPQ_Pos) /**< \brief (GMAC_RPQ) Received Pause Quantum */
|
||||
/* -------- GMAC_TPQ : (GMAC Offset: 0x03C) Transmit Pause Quantum Register -------- */
|
||||
#define GMAC_TPQ_TPQ_Pos 0
|
||||
#define GMAC_TPQ_TPQ_Msk (0xffffu << GMAC_TPQ_TPQ_Pos) /**< \brief (GMAC_TPQ) Transmit Pause Quantum */
|
||||
#define GMAC_TPQ_TPQ(value) ((GMAC_TPQ_TPQ_Msk & ((value) << GMAC_TPQ_TPQ_Pos)))
|
||||
/* -------- GMAC_TPSF : (GMAC Offset: 0x040) TX Partial Store and Forward Register -------- */
|
||||
#define GMAC_TPSF_TPB1ADR_Pos 0
|
||||
#define GMAC_TPSF_TPB1ADR_Msk (0xfffu << GMAC_TPSF_TPB1ADR_Pos) /**< \brief (GMAC_TPSF) tx_pbuf_addr-1:0 */
|
||||
#define GMAC_TPSF_TPB1ADR(value) ((GMAC_TPSF_TPB1ADR_Msk & ((value) << GMAC_TPSF_TPB1ADR_Pos)))
|
||||
#define GMAC_TPSF_ENTXP (0x1u << 31) /**< \brief (GMAC_TPSF) Enable TX Partial Store and Forward Operation */
|
||||
/* -------- GMAC_RPSF : (GMAC Offset: 0x044) RX Partial Store and Forward Register -------- */
|
||||
#define GMAC_RPSF_RPB1ADR_Pos 0
|
||||
#define GMAC_RPSF_RPB1ADR_Msk (0xfffu << GMAC_RPSF_RPB1ADR_Pos) /**< \brief (GMAC_RPSF) rx_pbuf_addr-1:0 */
|
||||
#define GMAC_RPSF_RPB1ADR(value) ((GMAC_RPSF_RPB1ADR_Msk & ((value) << GMAC_RPSF_RPB1ADR_Pos)))
|
||||
#define GMAC_RPSF_ENRXP (0x1u << 31) /**< \brief (GMAC_RPSF) Enable RX Partial Store and Forward Operation */
|
||||
/* -------- GMAC_HRB : (GMAC Offset: 0x080) Hash Register Bottom [31:0] -------- */
|
||||
#define GMAC_HRB_ADDR_Pos 0
|
||||
#define GMAC_HRB_ADDR_Msk (0xffffffffu << GMAC_HRB_ADDR_Pos) /**< \brief (GMAC_HRB) Hash Address */
|
||||
#define GMAC_HRB_ADDR(value) ((GMAC_HRB_ADDR_Msk & ((value) << GMAC_HRB_ADDR_Pos)))
|
||||
/* -------- GMAC_HRT : (GMAC Offset: 0x084) Hash Register Top [63:32] -------- */
|
||||
#define GMAC_HRT_ADDR_Pos 0
|
||||
#define GMAC_HRT_ADDR_Msk (0xffffffffu << GMAC_HRT_ADDR_Pos) /**< \brief (GMAC_HRT) Hash Address */
|
||||
#define GMAC_HRT_ADDR(value) ((GMAC_HRT_ADDR_Msk & ((value) << GMAC_HRT_ADDR_Pos)))
|
||||
/* -------- GMAC_SAB1 : (GMAC Offset: 0x088) Specific Address 1 Bottom [31:0] Register -------- */
|
||||
#define GMAC_SAB1_ADDR_Pos 0
|
||||
#define GMAC_SAB1_ADDR_Msk (0xffffffffu << GMAC_SAB1_ADDR_Pos) /**< \brief (GMAC_SAB1) Specific Address 1 */
|
||||
#define GMAC_SAB1_ADDR(value) ((GMAC_SAB1_ADDR_Msk & ((value) << GMAC_SAB1_ADDR_Pos)))
|
||||
/* -------- GMAC_SAT1 : (GMAC Offset: 0x08C) Specific Address 1 Top [47:32] Register -------- */
|
||||
#define GMAC_SAT1_ADDR_Pos 0
|
||||
#define GMAC_SAT1_ADDR_Msk (0xffffu << GMAC_SAT1_ADDR_Pos) /**< \brief (GMAC_SAT1) Specific Address 1 */
|
||||
#define GMAC_SAT1_ADDR(value) ((GMAC_SAT1_ADDR_Msk & ((value) << GMAC_SAT1_ADDR_Pos)))
|
||||
/* -------- GMAC_SAB2 : (GMAC Offset: 0x090) Specific Address 2 Bottom [31:0] Register -------- */
|
||||
#define GMAC_SAB2_ADDR_Pos 0
|
||||
#define GMAC_SAB2_ADDR_Msk (0xffffffffu << GMAC_SAB2_ADDR_Pos) /**< \brief (GMAC_SAB2) Specific Address 2 */
|
||||
#define GMAC_SAB2_ADDR(value) ((GMAC_SAB2_ADDR_Msk & ((value) << GMAC_SAB2_ADDR_Pos)))
|
||||
/* -------- GMAC_SAT2 : (GMAC Offset: 0x094) Specific Address 2 Top [47:32] Register -------- */
|
||||
#define GMAC_SAT2_ADDR_Pos 0
|
||||
#define GMAC_SAT2_ADDR_Msk (0xffffu << GMAC_SAT2_ADDR_Pos) /**< \brief (GMAC_SAT2) Specific Address 2 */
|
||||
#define GMAC_SAT2_ADDR(value) ((GMAC_SAT2_ADDR_Msk & ((value) << GMAC_SAT2_ADDR_Pos)))
|
||||
/* -------- GMAC_SAB3 : (GMAC Offset: 0x098) Specific Address 3 Bottom [31:0] Register -------- */
|
||||
#define GMAC_SAB3_ADDR_Pos 0
|
||||
#define GMAC_SAB3_ADDR_Msk (0xffffffffu << GMAC_SAB3_ADDR_Pos) /**< \brief (GMAC_SAB3) Specific Address 3 */
|
||||
#define GMAC_SAB3_ADDR(value) ((GMAC_SAB3_ADDR_Msk & ((value) << GMAC_SAB3_ADDR_Pos)))
|
||||
/* -------- GMAC_SAT3 : (GMAC Offset: 0x09C) Specific Address 3 Top [47:32] Register -------- */
|
||||
#define GMAC_SAT3_ADDR_Pos 0
|
||||
#define GMAC_SAT3_ADDR_Msk (0xffffu << GMAC_SAT3_ADDR_Pos) /**< \brief (GMAC_SAT3) Specific Address 3 */
|
||||
#define GMAC_SAT3_ADDR(value) ((GMAC_SAT3_ADDR_Msk & ((value) << GMAC_SAT3_ADDR_Pos)))
|
||||
/* -------- GMAC_SAB4 : (GMAC Offset: 0x0A0) Specific Address 4 Bottom [31:0] Register -------- */
|
||||
#define GMAC_SAB4_ADDR_Pos 0
|
||||
#define GMAC_SAB4_ADDR_Msk (0xffffffffu << GMAC_SAB4_ADDR_Pos) /**< \brief (GMAC_SAB4) Specific Address 4 */
|
||||
#define GMAC_SAB4_ADDR(value) ((GMAC_SAB4_ADDR_Msk & ((value) << GMAC_SAB4_ADDR_Pos)))
|
||||
/* -------- GMAC_SAT4 : (GMAC Offset: 0x0A4) Specific Address 4 Top [47:32] Register -------- */
|
||||
#define GMAC_SAT4_ADDR_Pos 0
|
||||
#define GMAC_SAT4_ADDR_Msk (0xffffu << GMAC_SAT4_ADDR_Pos) /**< \brief (GMAC_SAT4) Specific Address 4 */
|
||||
#define GMAC_SAT4_ADDR(value) ((GMAC_SAT4_ADDR_Msk & ((value) << GMAC_SAT4_ADDR_Pos)))
|
||||
/* -------- GMAC_TIDM[4] : (GMAC Offset: 0x0A8) Type ID Match 1 Register -------- */
|
||||
#define GMAC_TIDM_TID_Pos 0
|
||||
#define GMAC_TIDM_TID_Msk (0xffffu << GMAC_TIDM_TID_Pos) /**< \brief (GMAC_TIDM[4]) Type ID Match 1 */
|
||||
#define GMAC_TIDM_TID(value) ((GMAC_TIDM_TID_Msk & ((value) << GMAC_TIDM_TID_Pos)))
|
||||
/* -------- GMAC_WOL : (GMAC Offset: 0x0B8) Wake on LAN Register -------- */
|
||||
#define GMAC_WOL_IP_Pos 0
|
||||
#define GMAC_WOL_IP_Msk (0xffffu << GMAC_WOL_IP_Pos) /**< \brief (GMAC_WOL) ARP Request IP Address */
|
||||
#define GMAC_WOL_IP(value) ((GMAC_WOL_IP_Msk & ((value) << GMAC_WOL_IP_Pos)))
|
||||
#define GMAC_WOL_MAG (0x1u << 16) /**< \brief (GMAC_WOL) Magic Packet Event Enable */
|
||||
#define GMAC_WOL_ARP (0x1u << 17) /**< \brief (GMAC_WOL) ARP Request IP Address */
|
||||
#define GMAC_WOL_SA1 (0x1u << 18) /**< \brief (GMAC_WOL) Specific Address Register 1 Event Enable */
|
||||
#define GMAC_WOL_MTI (0x1u << 19) /**< \brief (GMAC_WOL) Multicast Hash Event Enable */
|
||||
/* -------- GMAC_IPGS : (GMAC Offset: 0x0BC) IPG Stretch Register -------- */
|
||||
#define GMAC_IPGS_FL_Pos 0
|
||||
#define GMAC_IPGS_FL_Msk (0xffffu << GMAC_IPGS_FL_Pos) /**< \brief (GMAC_IPGS) Frame Length */
|
||||
#define GMAC_IPGS_FL(value) ((GMAC_IPGS_FL_Msk & ((value) << GMAC_IPGS_FL_Pos)))
|
||||
/* -------- GMAC_SVLAN : (GMAC Offset: 0x0C0) Stacked VLAN Register -------- */
|
||||
#define GMAC_SVLAN_VLAN_TYPE_Pos 0
|
||||
#define GMAC_SVLAN_VLAN_TYPE_Msk (0xffffu << GMAC_SVLAN_VLAN_TYPE_Pos) /**< \brief (GMAC_SVLAN) User Defined VLAN_TYPE Field */
|
||||
#define GMAC_SVLAN_VLAN_TYPE(value) ((GMAC_SVLAN_VLAN_TYPE_Msk & ((value) << GMAC_SVLAN_VLAN_TYPE_Pos)))
|
||||
#define GMAC_SVLAN_ESVLAN (0x1u << 31) /**< \brief (GMAC_SVLAN) Enable Stacked VLAN Processing Mode */
|
||||
/* -------- GMAC_TPFCP : (GMAC Offset: 0x0C4) Transmit PFC Pause Register -------- */
|
||||
#define GMAC_TPFCP_PEV_Pos 0
|
||||
#define GMAC_TPFCP_PEV_Msk (0xffu << GMAC_TPFCP_PEV_Pos) /**< \brief (GMAC_TPFCP) Priority Enable Vector */
|
||||
#define GMAC_TPFCP_PEV(value) ((GMAC_TPFCP_PEV_Msk & ((value) << GMAC_TPFCP_PEV_Pos)))
|
||||
#define GMAC_TPFCP_PQ_Pos 8
|
||||
#define GMAC_TPFCP_PQ_Msk (0xffu << GMAC_TPFCP_PQ_Pos) /**< \brief (GMAC_TPFCP) Pause Quantum */
|
||||
#define GMAC_TPFCP_PQ(value) ((GMAC_TPFCP_PQ_Msk & ((value) << GMAC_TPFCP_PQ_Pos)))
|
||||
/* -------- GMAC_SAMB1 : (GMAC Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register -------- */
|
||||
#define GMAC_SAMB1_ADDR_Pos 0
|
||||
#define GMAC_SAMB1_ADDR_Msk (0xffffffffu << GMAC_SAMB1_ADDR_Pos) /**< \brief (GMAC_SAMB1) Specific Address 1 Mask */
|
||||
#define GMAC_SAMB1_ADDR(value) ((GMAC_SAMB1_ADDR_Msk & ((value) << GMAC_SAMB1_ADDR_Pos)))
|
||||
/* -------- GMAC_SAMT1 : (GMAC Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register -------- */
|
||||
#define GMAC_SAMT1_ADDR_Pos 0
|
||||
#define GMAC_SAMT1_ADDR_Msk (0xffffu << GMAC_SAMT1_ADDR_Pos) /**< \brief (GMAC_SAMT1) Specific Address 1 Mask */
|
||||
#define GMAC_SAMT1_ADDR(value) ((GMAC_SAMT1_ADDR_Msk & ((value) << GMAC_SAMT1_ADDR_Pos)))
|
||||
/* -------- GMAC_OTLO : (GMAC Offset: 0x100) Octets Transmitted [31:0] Register -------- */
|
||||
#define GMAC_OTLO_TXO_Pos 0
|
||||
#define GMAC_OTLO_TXO_Msk (0xffffffffu << GMAC_OTLO_TXO_Pos) /**< \brief (GMAC_OTLO) Transmitted Octets */
|
||||
/* -------- GMAC_OTHI : (GMAC Offset: 0x104) Octets Transmitted [47:32] Register -------- */
|
||||
#define GMAC_OTHI_TXO_Pos 0
|
||||
#define GMAC_OTHI_TXO_Msk (0xffffu << GMAC_OTHI_TXO_Pos) /**< \brief (GMAC_OTHI) Transmitted Octets */
|
||||
/* -------- GMAC_FT : (GMAC Offset: 0x108) Frames Transmitted Register -------- */
|
||||
#define GMAC_FT_FTX_Pos 0
|
||||
#define GMAC_FT_FTX_Msk (0xffffffffu << GMAC_FT_FTX_Pos) /**< \brief (GMAC_FT) Frames Transmitted without Error */
|
||||
/* -------- GMAC_BCFT : (GMAC Offset: 0x10C) Broadcast Frames Transmitted Register -------- */
|
||||
#define GMAC_BCFT_BFTX_Pos 0
|
||||
#define GMAC_BCFT_BFTX_Msk (0xffffffffu << GMAC_BCFT_BFTX_Pos) /**< \brief (GMAC_BCFT) Broadcast Frames Transmitted without Error */
|
||||
/* -------- GMAC_MFT : (GMAC Offset: 0x110) Multicast Frames Transmitted Register -------- */
|
||||
#define GMAC_MFT_MFTX_Pos 0
|
||||
#define GMAC_MFT_MFTX_Msk (0xffffffffu << GMAC_MFT_MFTX_Pos) /**< \brief (GMAC_MFT) Multicast Frames Transmitted without Error */
|
||||
/* -------- GMAC_PFT : (GMAC Offset: 0x114) Pause Frames Transmitted Register -------- */
|
||||
#define GMAC_PFT_PFTX_Pos 0
|
||||
#define GMAC_PFT_PFTX_Msk (0xffffu << GMAC_PFT_PFTX_Pos) /**< \brief (GMAC_PFT) Pause Frames Transmitted Register */
|
||||
/* -------- GMAC_BFT64 : (GMAC Offset: 0x118) 64 Byte Frames Transmitted Register -------- */
|
||||
#define GMAC_BFT64_NFTX_Pos 0
|
||||
#define GMAC_BFT64_NFTX_Msk (0xffffffffu << GMAC_BFT64_NFTX_Pos) /**< \brief (GMAC_BFT64) 64 Byte Frames Transmitted without Error */
|
||||
/* -------- GMAC_TBFT127 : (GMAC Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register -------- */
|
||||
#define GMAC_TBFT127_NFTX_Pos 0
|
||||
#define GMAC_TBFT127_NFTX_Msk (0xffffffffu << GMAC_TBFT127_NFTX_Pos) /**< \brief (GMAC_TBFT127) 65 to 127 Byte Frames Transmitted without Error */
|
||||
/* -------- GMAC_TBFT255 : (GMAC Offset: 0x120) 128 to 255 Byte Frames Transmitted Register -------- */
|
||||
#define GMAC_TBFT255_NFTX_Pos 0
|
||||
#define GMAC_TBFT255_NFTX_Msk (0xffffffffu << GMAC_TBFT255_NFTX_Pos) /**< \brief (GMAC_TBFT255) 128 to 255 Byte Frames Transmitted without Error */
|
||||
/* -------- GMAC_TBFT511 : (GMAC Offset: 0x124) 256 to 511 Byte Frames Transmitted Register -------- */
|
||||
#define GMAC_TBFT511_NFTX_Pos 0
|
||||
#define GMAC_TBFT511_NFTX_Msk (0xffffffffu << GMAC_TBFT511_NFTX_Pos) /**< \brief (GMAC_TBFT511) 256 to 511 Byte Frames Transmitted without Error */
|
||||
/* -------- GMAC_TBFT1023 : (GMAC Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register -------- */
|
||||
#define GMAC_TBFT1023_NFTX_Pos 0
|
||||
#define GMAC_TBFT1023_NFTX_Msk (0xffffffffu << GMAC_TBFT1023_NFTX_Pos) /**< \brief (GMAC_TBFT1023) 512 to 1023 Byte Frames Transmitted without Error */
|
||||
/* -------- GMAC_TBFT1518 : (GMAC Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register -------- */
|
||||
#define GMAC_TBFT1518_NFTX_Pos 0
|
||||
#define GMAC_TBFT1518_NFTX_Msk (0xffffffffu << GMAC_TBFT1518_NFTX_Pos) /**< \brief (GMAC_TBFT1518) 1024 to 1518 Byte Frames Transmitted without Error */
|
||||
/* -------- GMAC_GTBFT1518 : (GMAC Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register -------- */
|
||||
#define GMAC_GTBFT1518_NFTX_Pos 0
|
||||
#define GMAC_GTBFT1518_NFTX_Msk (0xffffffffu << GMAC_GTBFT1518_NFTX_Pos) /**< \brief (GMAC_GTBFT1518) Greater than 1518 Byte Frames Transmitted without Error */
|
||||
/* -------- GMAC_TUR : (GMAC Offset: 0x134) Transmit Under Runs Register -------- */
|
||||
#define GMAC_TUR_TXUNR_Pos 0
|
||||
#define GMAC_TUR_TXUNR_Msk (0x3ffu << GMAC_TUR_TXUNR_Pos) /**< \brief (GMAC_TUR) Transmit Under Runs */
|
||||
/* -------- GMAC_SCF : (GMAC Offset: 0x138) Single Collision Frames Register -------- */
|
||||
#define GMAC_SCF_SCOL_Pos 0
|
||||
#define GMAC_SCF_SCOL_Msk (0x3ffffu << GMAC_SCF_SCOL_Pos) /**< \brief (GMAC_SCF) Single Collision */
|
||||
/* -------- GMAC_MCF : (GMAC Offset: 0x13C) Multiple Collision Frames Register -------- */
|
||||
#define GMAC_MCF_MCOL_Pos 0
|
||||
#define GMAC_MCF_MCOL_Msk (0x3ffffu << GMAC_MCF_MCOL_Pos) /**< \brief (GMAC_MCF) Multiple Collision */
|
||||
/* -------- GMAC_EC : (GMAC Offset: 0x140) Excessive Collisions Register -------- */
|
||||
#define GMAC_EC_XCOL_Pos 0
|
||||
#define GMAC_EC_XCOL_Msk (0x3ffu << GMAC_EC_XCOL_Pos) /**< \brief (GMAC_EC) Excessive Collisions */
|
||||
/* -------- GMAC_LC : (GMAC Offset: 0x144) Late Collisions Register -------- */
|
||||
#define GMAC_LC_LCOL_Pos 0
|
||||
#define GMAC_LC_LCOL_Msk (0x3ffu << GMAC_LC_LCOL_Pos) /**< \brief (GMAC_LC) Late Collisions */
|
||||
/* -------- GMAC_DTF : (GMAC Offset: 0x148) Deferred Transmission Frames Register -------- */
|
||||
#define GMAC_DTF_DEFT_Pos 0
|
||||
#define GMAC_DTF_DEFT_Msk (0x3ffffu << GMAC_DTF_DEFT_Pos) /**< \brief (GMAC_DTF) Deferred Transmission */
|
||||
/* -------- GMAC_CSE : (GMAC Offset: 0x14C) Carrier Sense Errors Register -------- */
|
||||
#define GMAC_CSE_CSR_Pos 0
|
||||
#define GMAC_CSE_CSR_Msk (0x3ffu << GMAC_CSE_CSR_Pos) /**< \brief (GMAC_CSE) Carrier Sense Error */
|
||||
/* -------- GMAC_ORLO : (GMAC Offset: 0x150) Octets Received [31:0] Received -------- */
|
||||
#define GMAC_ORLO_RXO_Pos 0
|
||||
#define GMAC_ORLO_RXO_Msk (0xffffffffu << GMAC_ORLO_RXO_Pos) /**< \brief (GMAC_ORLO) Received Octets */
|
||||
/* -------- GMAC_ORHI : (GMAC Offset: 0x154) Octets Received [47:32] Received -------- */
|
||||
#define GMAC_ORHI_RXO_Pos 0
|
||||
#define GMAC_ORHI_RXO_Msk (0xffffu << GMAC_ORHI_RXO_Pos) /**< \brief (GMAC_ORHI) Received Octets */
|
||||
/* -------- GMAC_FR : (GMAC Offset: 0x158) Frames Received Register -------- */
|
||||
#define GMAC_FR_FRX_Pos 0
|
||||
#define GMAC_FR_FRX_Msk (0xffffffffu << GMAC_FR_FRX_Pos) /**< \brief (GMAC_FR) Frames Received without Error */
|
||||
/* -------- GMAC_BCFR : (GMAC Offset: 0x15C) Broadcast Frames Received Register -------- */
|
||||
#define GMAC_BCFR_BFRX_Pos 0
|
||||
#define GMAC_BCFR_BFRX_Msk (0xffffffffu << GMAC_BCFR_BFRX_Pos) /**< \brief (GMAC_BCFR) Broadcast Frames Received without Error */
|
||||
/* -------- GMAC_MFR : (GMAC Offset: 0x160) Multicast Frames Received Register -------- */
|
||||
#define GMAC_MFR_MFRX_Pos 0
|
||||
#define GMAC_MFR_MFRX_Msk (0xffffffffu << GMAC_MFR_MFRX_Pos) /**< \brief (GMAC_MFR) Multicast Frames Received without Error */
|
||||
/* -------- GMAC_PFR : (GMAC Offset: 0x164) Pause Frames Received Register -------- */
|
||||
#define GMAC_PFR_PFRX_Pos 0
|
||||
#define GMAC_PFR_PFRX_Msk (0xffffu << GMAC_PFR_PFRX_Pos) /**< \brief (GMAC_PFR) Pause Frames Received Register */
|
||||
/* -------- GMAC_BFR64 : (GMAC Offset: 0x168) 64 Byte Frames Received Register -------- */
|
||||
#define GMAC_BFR64_NFRX_Pos 0
|
||||
#define GMAC_BFR64_NFRX_Msk (0xffffffffu << GMAC_BFR64_NFRX_Pos) /**< \brief (GMAC_BFR64) 64 Byte Frames Received without Error */
|
||||
/* -------- GMAC_TBFR127 : (GMAC Offset: 0x16C) 65 to 127 Byte Frames Received Register -------- */
|
||||
#define GMAC_TBFR127_NFRX_Pos 0
|
||||
#define GMAC_TBFR127_NFRX_Msk (0xffffffffu << GMAC_TBFR127_NFRX_Pos) /**< \brief (GMAC_TBFR127) 65 to 127 Byte Frames Received without Error */
|
||||
/* -------- GMAC_TBFR255 : (GMAC Offset: 0x170) 128 to 255 Byte Frames Received Register -------- */
|
||||
#define GMAC_TBFR255_NFRX_Pos 0
|
||||
#define GMAC_TBFR255_NFRX_Msk (0xffffffffu << GMAC_TBFR255_NFRX_Pos) /**< \brief (GMAC_TBFR255) 128 to 255 Byte Frames Received without Error */
|
||||
/* -------- GMAC_TBFR511 : (GMAC Offset: 0x174) 256 to 511Byte Frames Received Register -------- */
|
||||
#define GMAC_TBFR511_NFRX_Pos 0
|
||||
#define GMAC_TBFR511_NFRX_Msk (0xffffffffu << GMAC_TBFR511_NFRX_Pos) /**< \brief (GMAC_TBFR511) 256 to 511 Byte Frames Received without Error */
|
||||
/* -------- GMAC_TBFR1023 : (GMAC Offset: 0x178) 512 to 1023 Byte Frames Received Register -------- */
|
||||
#define GMAC_TBFR1023_NFRX_Pos 0
|
||||
#define GMAC_TBFR1023_NFRX_Msk (0xffffffffu << GMAC_TBFR1023_NFRX_Pos) /**< \brief (GMAC_TBFR1023) 512 to 1023 Byte Frames Received without Error */
|
||||
/* -------- GMAC_TBFR1518 : (GMAC Offset: 0x17C) 1024 to 1518 Byte Frames Received Register -------- */
|
||||
#define GMAC_TBFR1518_NFRX_Pos 0
|
||||
#define GMAC_TBFR1518_NFRX_Msk (0xffffffffu << GMAC_TBFR1518_NFRX_Pos) /**< \brief (GMAC_TBFR1518) 1024 to 1518 Byte Frames Received without Error */
|
||||
/* -------- GMAC_TMXBFR : (GMAC Offset: 0x180) 1519 to Maximum Byte Frames Received Register -------- */
|
||||
#define GMAC_TMXBFR_NFRX_Pos 0
|
||||
#define GMAC_TMXBFR_NFRX_Msk (0xffffffffu << GMAC_TMXBFR_NFRX_Pos) /**< \brief (GMAC_TMXBFR) 1519 to Maximum Byte Frames Received without Error */
|
||||
/* -------- GMAC_UFR : (GMAC Offset: 0x184) Undersize Frames Received Register -------- */
|
||||
#define GMAC_UFR_UFRX_Pos 0
|
||||
#define GMAC_UFR_UFRX_Msk (0x3ffu << GMAC_UFR_UFRX_Pos) /**< \brief (GMAC_UFR) Undersize Frames Received */
|
||||
/* -------- GMAC_OFR : (GMAC Offset: 0x188) Oversize Frames Received Register -------- */
|
||||
#define GMAC_OFR_OFRX_Pos 0
|
||||
#define GMAC_OFR_OFRX_Msk (0x3ffu << GMAC_OFR_OFRX_Pos) /**< \brief (GMAC_OFR) Oversized Frames Received */
|
||||
/* -------- GMAC_JR : (GMAC Offset: 0x18C) Jabbers Received Register -------- */
|
||||
#define GMAC_JR_JRX_Pos 0
|
||||
#define GMAC_JR_JRX_Msk (0x3ffu << GMAC_JR_JRX_Pos) /**< \brief (GMAC_JR) Jabbers Received */
|
||||
/* -------- GMAC_FCSE : (GMAC Offset: 0x190) Frame Check Sequence Errors Register -------- */
|
||||
#define GMAC_FCSE_FCKR_Pos 0
|
||||
#define GMAC_FCSE_FCKR_Msk (0x3ffu << GMAC_FCSE_FCKR_Pos) /**< \brief (GMAC_FCSE) Frame Check Sequence Errors */
|
||||
/* -------- GMAC_LFFE : (GMAC Offset: 0x194) Length Field Frame Errors Register -------- */
|
||||
#define GMAC_LFFE_LFER_Pos 0
|
||||
#define GMAC_LFFE_LFER_Msk (0x3ffu << GMAC_LFFE_LFER_Pos) /**< \brief (GMAC_LFFE) Length Field Frame Errors */
|
||||
/* -------- GMAC_RSE : (GMAC Offset: 0x198) Receive Symbol Errors Register -------- */
|
||||
#define GMAC_RSE_RXSE_Pos 0
|
||||
#define GMAC_RSE_RXSE_Msk (0x3ffu << GMAC_RSE_RXSE_Pos) /**< \brief (GMAC_RSE) Receive Symbol Errors */
|
||||
/* -------- GMAC_AE : (GMAC Offset: 0x19C) Alignment Errors Register -------- */
|
||||
#define GMAC_AE_AER_Pos 0
|
||||
#define GMAC_AE_AER_Msk (0x3ffu << GMAC_AE_AER_Pos) /**< \brief (GMAC_AE) Alignment Errors */
|
||||
/* -------- GMAC_RRE : (GMAC Offset: 0x1A0) Receive Resource Errors Register -------- */
|
||||
#define GMAC_RRE_RXRER_Pos 0
|
||||
#define GMAC_RRE_RXRER_Msk (0x3ffffu << GMAC_RRE_RXRER_Pos) /**< \brief (GMAC_RRE) Receive Resource Errors */
|
||||
/* -------- GMAC_ROE : (GMAC Offset: 0x1A4) Receive Overrun Register -------- */
|
||||
#define GMAC_ROE_RXOVR_Pos 0
|
||||
#define GMAC_ROE_RXOVR_Msk (0x3ffu << GMAC_ROE_RXOVR_Pos) /**< \brief (GMAC_ROE) Receive Overruns */
|
||||
/* -------- GMAC_IHCE : (GMAC Offset: 0x1A8) IP Header Checksum Errors Register -------- */
|
||||
#define GMAC_IHCE_HCKER_Pos 0
|
||||
#define GMAC_IHCE_HCKER_Msk (0xffu << GMAC_IHCE_HCKER_Pos) /**< \brief (GMAC_IHCE) IP Header Checksum Errors */
|
||||
/* -------- GMAC_TCE : (GMAC Offset: 0x1AC) TCP Checksum Errors Register -------- */
|
||||
#define GMAC_TCE_TCKER_Pos 0
|
||||
#define GMAC_TCE_TCKER_Msk (0xffu << GMAC_TCE_TCKER_Pos) /**< \brief (GMAC_TCE) TCP Checksum Errors */
|
||||
/* -------- GMAC_UCE : (GMAC Offset: 0x1B0) UDP Checksum Errors Register -------- */
|
||||
#define GMAC_UCE_UCKER_Pos 0
|
||||
#define GMAC_UCE_UCKER_Msk (0xffu << GMAC_UCE_UCKER_Pos) /**< \brief (GMAC_UCE) UDP Checksum Errors */
|
||||
/* -------- GMAC_TSSS : (GMAC Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register -------- */
|
||||
#define GMAC_TSSS_VTS_Pos 0
|
||||
#define GMAC_TSSS_VTS_Msk (0xffffffffu << GMAC_TSSS_VTS_Pos) /**< \brief (GMAC_TSSS) Value of Timer Seconds Register Capture */
|
||||
#define GMAC_TSSS_VTS(value) ((GMAC_TSSS_VTS_Msk & ((value) << GMAC_TSSS_VTS_Pos)))
|
||||
/* -------- GMAC_TSSN : (GMAC Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register -------- */
|
||||
#define GMAC_TSSN_VTN_Pos 0
|
||||
#define GMAC_TSSN_VTN_Msk (0x3fffffffu << GMAC_TSSN_VTN_Pos) /**< \brief (GMAC_TSSN) Value Timer Nanoseconds Register Capture */
|
||||
#define GMAC_TSSN_VTN(value) ((GMAC_TSSN_VTN_Msk & ((value) << GMAC_TSSN_VTN_Pos)))
|
||||
/* -------- GMAC_TS : (GMAC Offset: 0x1D0) 1588 Timer Seconds Register -------- */
|
||||
#define GMAC_TS_TCS_Pos 0
|
||||
#define GMAC_TS_TCS_Msk (0xffffffffu << GMAC_TS_TCS_Pos) /**< \brief (GMAC_TS) Timer Count in Seconds */
|
||||
#define GMAC_TS_TCS(value) ((GMAC_TS_TCS_Msk & ((value) << GMAC_TS_TCS_Pos)))
|
||||
/* -------- GMAC_TN : (GMAC Offset: 0x1D4) 1588 Timer Nanoseconds Register -------- */
|
||||
#define GMAC_TN_TNS_Pos 0
|
||||
#define GMAC_TN_TNS_Msk (0x3fffffffu << GMAC_TN_TNS_Pos) /**< \brief (GMAC_TN) Timer Count in Nanoseconds */
|
||||
#define GMAC_TN_TNS(value) ((GMAC_TN_TNS_Msk & ((value) << GMAC_TN_TNS_Pos)))
|
||||
/* -------- GMAC_TA : (GMAC Offset: 0x1D8) 1588 Timer Adjust Register -------- */
|
||||
#define GMAC_TA_ITDT_Pos 0
|
||||
#define GMAC_TA_ITDT_Msk (0x3fffffffu << GMAC_TA_ITDT_Pos) /**< \brief (GMAC_TA) Increment/Decrement */
|
||||
#define GMAC_TA_ITDT(value) ((GMAC_TA_ITDT_Msk & ((value) << GMAC_TA_ITDT_Pos)))
|
||||
#define GMAC_TA_ADJ (0x1u << 31) /**< \brief (GMAC_TA) Adjust 1588 Timer */
|
||||
/* -------- GMAC_TI : (GMAC Offset: 0x1DC) 1588 Timer Increment Register -------- */
|
||||
#define GMAC_TI_CNS_Pos 0
|
||||
#define GMAC_TI_CNS_Msk (0xffu << GMAC_TI_CNS_Pos) /**< \brief (GMAC_TI) Count Nanoseconds */
|
||||
#define GMAC_TI_CNS(value) ((GMAC_TI_CNS_Msk & ((value) << GMAC_TI_CNS_Pos)))
|
||||
#define GMAC_TI_ACNS_Pos 8
|
||||
#define GMAC_TI_ACNS_Msk (0xffu << GMAC_TI_ACNS_Pos) /**< \brief (GMAC_TI) Alternative Count Nanoseconds */
|
||||
#define GMAC_TI_ACNS(value) ((GMAC_TI_ACNS_Msk & ((value) << GMAC_TI_ACNS_Pos)))
|
||||
#define GMAC_TI_NIT_Pos 16
|
||||
#define GMAC_TI_NIT_Msk (0xffu << GMAC_TI_NIT_Pos) /**< \brief (GMAC_TI) Number of Increments */
|
||||
#define GMAC_TI_NIT(value) ((GMAC_TI_NIT_Msk & ((value) << GMAC_TI_NIT_Pos)))
|
||||
/* -------- GMAC_EFTS : (GMAC Offset: 0x1E0) PTP Event Frame Transmitted Seconds -------- */
|
||||
#define GMAC_EFTS_RUD_Pos 0
|
||||
#define GMAC_EFTS_RUD_Msk (0xffffffffu << GMAC_EFTS_RUD_Pos) /**< \brief (GMAC_EFTS) Register Update */
|
||||
/* -------- GMAC_EFTN : (GMAC Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds -------- */
|
||||
#define GMAC_EFTN_RUD_Pos 0
|
||||
#define GMAC_EFTN_RUD_Msk (0x3fffffffu << GMAC_EFTN_RUD_Pos) /**< \brief (GMAC_EFTN) Register Update */
|
||||
/* -------- GMAC_EFRS : (GMAC Offset: 0x1E8) PTP Event Frame Received Seconds -------- */
|
||||
#define GMAC_EFRS_RUD_Pos 0
|
||||
#define GMAC_EFRS_RUD_Msk (0xffffffffu << GMAC_EFRS_RUD_Pos) /**< \brief (GMAC_EFRS) Register Update */
|
||||
/* -------- GMAC_EFRN : (GMAC Offset: 0x1EC) PTP Event Frame Received Nanoseconds -------- */
|
||||
#define GMAC_EFRN_RUD_Pos 0
|
||||
#define GMAC_EFRN_RUD_Msk (0x3fffffffu << GMAC_EFRN_RUD_Pos) /**< \brief (GMAC_EFRN) Register Update */
|
||||
/* -------- GMAC_PEFTS : (GMAC Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds -------- */
|
||||
#define GMAC_PEFTS_RUD_Pos 0
|
||||
#define GMAC_PEFTS_RUD_Msk (0xffffffffu << GMAC_PEFTS_RUD_Pos) /**< \brief (GMAC_PEFTS) Register Update */
|
||||
/* -------- GMAC_PEFTN : (GMAC Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds -------- */
|
||||
#define GMAC_PEFTN_RUD_Pos 0
|
||||
#define GMAC_PEFTN_RUD_Msk (0x3fffffffu << GMAC_PEFTN_RUD_Pos) /**< \brief (GMAC_PEFTN) Register Update */
|
||||
/* -------- GMAC_PEFRS : (GMAC Offset: 0x1F8) PTP Peer Event Frame Received Seconds -------- */
|
||||
#define GMAC_PEFRS_RUD_Pos 0
|
||||
#define GMAC_PEFRS_RUD_Msk (0xffffffffu << GMAC_PEFRS_RUD_Pos) /**< \brief (GMAC_PEFRS) Register Update */
|
||||
/* -------- GMAC_PEFRN : (GMAC Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds -------- */
|
||||
#define GMAC_PEFRN_RUD_Pos 0
|
||||
#define GMAC_PEFRN_RUD_Msk (0x3fffffffu << GMAC_PEFRN_RUD_Pos) /**< \brief (GMAC_PEFRN) Register Update */
|
||||
/* -------- GMAC_ISRPQ[7] : (GMAC Offset: 0x400) Interrupt Status Register Priority Queue -------- */
|
||||
#define GMAC_ISRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_ISRPQ[7]) Receive Complete */
|
||||
#define GMAC_ISRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_ISRPQ[7]) RX Used Bit Read */
|
||||
#define GMAC_ISRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_ISRPQ[7]) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_ISRPQ_TFC (0x1u << 6) /**< \brief (GMAC_ISRPQ[7]) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_ISRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_ISRPQ[7]) Transmit Complete */
|
||||
#define GMAC_ISRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_ISRPQ[7]) Receive Overrun */
|
||||
#define GMAC_ISRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_ISRPQ[7]) HRESP Not OK */
|
||||
/* -------- GMAC_TBQBAPQ[7] : (GMAC Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue -------- */
|
||||
#define GMAC_TBQBAPQ_TXBQBA_Pos 2
|
||||
#define GMAC_TBQBAPQ_TXBQBA_Msk (0x3fu << GMAC_TBQBAPQ_TXBQBA_Pos) /**< \brief (GMAC_TBQBAPQ[7]) Transmit Buffer Queue Base Address */
|
||||
#define GMAC_TBQBAPQ_TXBQBA(value) ((GMAC_TBQBAPQ_TXBQBA_Msk & ((value) << GMAC_TBQBAPQ_TXBQBA_Pos)))
|
||||
/* -------- GMAC_RBQBAPQ[7] : (GMAC Offset: 0x480) Receive Buffer Queue Base Address Priority Queue -------- */
|
||||
#define GMAC_RBQBAPQ_RXBQBA_Pos 2
|
||||
#define GMAC_RBQBAPQ_RXBQBA_Msk (0x3fu << GMAC_RBQBAPQ_RXBQBA_Pos) /**< \brief (GMAC_RBQBAPQ[7]) Receive Buffer Queue Base Address */
|
||||
#define GMAC_RBQBAPQ_RXBQBA(value) ((GMAC_RBQBAPQ_RXBQBA_Msk & ((value) << GMAC_RBQBAPQ_RXBQBA_Pos)))
|
||||
/* -------- GMAC_RBSRPQ[7] : (GMAC Offset: 0x4A0) Receive Buffer Size Register Priority Queue -------- */
|
||||
#define GMAC_RBSRPQ_RBS_Pos 0
|
||||
#define GMAC_RBSRPQ_RBS_Msk (0xffffu << GMAC_RBSRPQ_RBS_Pos) /**< \brief (GMAC_RBSRPQ[7]) Receive Buffer Size */
|
||||
#define GMAC_RBSRPQ_RBS(value) ((GMAC_RBSRPQ_RBS_Msk & ((value) << GMAC_RBSRPQ_RBS_Pos)))
|
||||
/* -------- GMAC_ST1RPQ[16] : (GMAC Offset: 0x500) Screening Type1 Register Priority Queue -------- */
|
||||
#define GMAC_ST1RPQ_QNB_Pos 0
|
||||
#define GMAC_ST1RPQ_QNB_Msk (0xfu << GMAC_ST1RPQ_QNB_Pos) /**< \brief (GMAC_ST1RPQ[16]) Que Number (0->7) */
|
||||
#define GMAC_ST1RPQ_QNB(value) ((GMAC_ST1RPQ_QNB_Msk & ((value) << GMAC_ST1RPQ_QNB_Pos)))
|
||||
#define GMAC_ST1RPQ_DSTCM_Pos 4
|
||||
#define GMAC_ST1RPQ_DSTCM_Msk (0xffu << GMAC_ST1RPQ_DSTCM_Pos) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match */
|
||||
#define GMAC_ST1RPQ_DSTCM(value) ((GMAC_ST1RPQ_DSTCM_Msk & ((value) << GMAC_ST1RPQ_DSTCM_Pos)))
|
||||
#define GMAC_ST1RPQ_UDPM_Pos 12
|
||||
#define GMAC_ST1RPQ_UDPM_Msk (0xffffu << GMAC_ST1RPQ_UDPM_Pos) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match */
|
||||
#define GMAC_ST1RPQ_UDPM(value) ((GMAC_ST1RPQ_UDPM_Msk & ((value) << GMAC_ST1RPQ_UDPM_Pos)))
|
||||
#define GMAC_ST1RPQ_DSTCE (0x1u << 28) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match Enable */
|
||||
#define GMAC_ST1RPQ_UDPE (0x1u << 29) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match Enable */
|
||||
/* -------- GMAC_ST2RPQ[16] : (GMAC Offset: 0x540) Screening Type2 Register Priority Queue -------- */
|
||||
#define GMAC_ST2RPQ_QNB_Pos 0
|
||||
#define GMAC_ST2RPQ_QNB_Msk (0xfu << GMAC_ST2RPQ_QNB_Pos) /**< \brief (GMAC_ST2RPQ[16]) Que Number (0->7) */
|
||||
#define GMAC_ST2RPQ_QNB(value) ((GMAC_ST2RPQ_QNB_Msk & ((value) << GMAC_ST2RPQ_QNB_Pos)))
|
||||
#define GMAC_ST2RPQ_VLANP_Pos 4
|
||||
#define GMAC_ST2RPQ_VLANP_Msk (0xfu << GMAC_ST2RPQ_VLANP_Pos) /**< \brief (GMAC_ST2RPQ[16]) VLAN Priority */
|
||||
#define GMAC_ST2RPQ_VLANP(value) ((GMAC_ST2RPQ_VLANP_Msk & ((value) << GMAC_ST2RPQ_VLANP_Pos)))
|
||||
#define GMAC_ST2RPQ_VLANE (0x1u << 8) /**< \brief (GMAC_ST2RPQ[16]) VLAN Enable */
|
||||
/* -------- GMAC_IERPQ[7] : (GMAC Offset: 0x600) Interrupt Enable Register Priority Queue -------- */
|
||||
#define GMAC_IERPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IERPQ[7]) Receive Complete */
|
||||
#define GMAC_IERPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IERPQ[7]) RX Used Bit Read */
|
||||
#define GMAC_IERPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IERPQ[7]) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_IERPQ_TFC (0x1u << 6) /**< \brief (GMAC_IERPQ[7]) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_IERPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IERPQ[7]) Transmit Complete */
|
||||
#define GMAC_IERPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IERPQ[7]) Receive Overrun */
|
||||
#define GMAC_IERPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IERPQ[7]) HRESP Not OK */
|
||||
/* -------- GMAC_IDRPQ[7] : (GMAC Offset: 0x620) Interrupt Disable Register Priority Queue -------- */
|
||||
#define GMAC_IDRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IDRPQ[7]) Receive Complete */
|
||||
#define GMAC_IDRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IDRPQ[7]) RX Used Bit Read */
|
||||
#define GMAC_IDRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IDRPQ[7]) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_IDRPQ_TFC (0x1u << 6) /**< \brief (GMAC_IDRPQ[7]) Transmit Frame Corruption due to AHB error */
|
||||
#define GMAC_IDRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IDRPQ[7]) Transmit Complete */
|
||||
#define GMAC_IDRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IDRPQ[7]) Receive Overrun */
|
||||
#define GMAC_IDRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IDRPQ[7]) HRESP Not OK */
|
||||
/* -------- GMAC_IMRPQ[7] : (GMAC Offset: 0x640) Interrupt Mask Register Priority Queue -------- */
|
||||
#define GMAC_IMRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IMRPQ[7]) Receive Complete */
|
||||
#define GMAC_IMRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IMRPQ[7]) RX Used Bit Read */
|
||||
#define GMAC_IMRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IMRPQ[7]) Retry Limit Exceeded or Late Collision */
|
||||
#define GMAC_IMRPQ_AHB (0x1u << 6) /**< \brief (GMAC_IMRPQ[7]) AHB Error */
|
||||
#define GMAC_IMRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IMRPQ[7]) Transmit Complete */
|
||||
#define GMAC_IMRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IMRPQ[7]) Receive Overrun */
|
||||
#define GMAC_IMRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IMRPQ[7]) HRESP Not OK */
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
#endif /* _SAM4E_GMAC_COMPONENT_ */
|
||||
+454
@@ -0,0 +1,454 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief API driver for KSZ8051MNL PHY component.
|
||||
*
|
||||
* Copyright (c) 2013 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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "FreeRTOSIPConfig.h"
|
||||
|
||||
#include "ethernet_phy.h"
|
||||
#include "instance/gmac.h"
|
||||
|
||||
/// @cond 0
|
||||
/**INDENT-OFF**/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**INDENT-ON**/
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* \defgroup ksz8051mnl_ethernet_phy_group PHY component (KSZ8051MNL)
|
||||
*
|
||||
* Driver for the ksz8051mnl component. This driver provides access to the main
|
||||
* features of the PHY.
|
||||
*
|
||||
* \section dependencies Dependencies
|
||||
* This driver depends on the following modules:
|
||||
* - \ref gmac_group Ethernet Media Access Controller (GMAC) module.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
SPhyProps phyProps;
|
||||
|
||||
/* Max PHY number */
|
||||
#define ETH_PHY_MAX_ADDR 31
|
||||
|
||||
/* Ethernet PHY operation max retry count */
|
||||
#define ETH_PHY_RETRY_MAX 1000000
|
||||
|
||||
/* Ethernet PHY operation timeout */
|
||||
#define ETH_PHY_TIMEOUT 10
|
||||
|
||||
/**
|
||||
* \brief Find a valid PHY Address ( from addrStart to 31 ).
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
* \param uc_start_addr Start address of the PHY to be searched.
|
||||
*
|
||||
* \return 0xFF when no valid PHY address is found.
|
||||
*/
|
||||
int ethernet_phy_addr = 0;
|
||||
static uint8_t ethernet_phy_find_valid(Gmac *p_gmac, uint8_t uc_phy_addr,
|
||||
uint8_t uc_start_addr)
|
||||
{
|
||||
uint32_t ul_value = 0;
|
||||
uint8_t uc_cnt;
|
||||
uint8_t uc_phy_address = uc_phy_addr;
|
||||
|
||||
gmac_enable_management(p_gmac, true);
|
||||
/*
|
||||
#define GMII_OUI_MSB 0x0022
|
||||
#define GMII_OUI_LSB 0x05
|
||||
|
||||
PHYID1 = 0x0022
|
||||
PHYID2 = 0x1550
|
||||
0001_0101_0101_0000 = 0x1550 <= mask should be 0xFFF0
|
||||
*/
|
||||
/* Check the current PHY address */
|
||||
gmac_phy_read(p_gmac, uc_phy_addr, GMII_PHYID1, &ul_value);
|
||||
|
||||
/* Find another one */
|
||||
if (ul_value != GMII_OUI_MSB) {
|
||||
ethernet_phy_addr = 0xFF;
|
||||
for (uc_cnt = uc_start_addr; uc_cnt <= ETH_PHY_MAX_ADDR; uc_cnt++) {
|
||||
uc_phy_address = (uc_phy_address + 1) & 0x1F;
|
||||
ul_value = 0;
|
||||
gmac_phy_read(p_gmac, uc_phy_address, GMII_PHYID1, &ul_value);
|
||||
if (ul_value == GMII_OUI_MSB) {
|
||||
ethernet_phy_addr = uc_phy_address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gmac_enable_management(p_gmac, false);
|
||||
|
||||
if (ethernet_phy_addr != 0xFF) {
|
||||
gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_value);
|
||||
}
|
||||
return ethernet_phy_addr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Perform a HW initialization to the PHY and set up clocks.
|
||||
*
|
||||
* This should be called only once to initialize the PHY pre-settings.
|
||||
* The PHY address is the reset status of CRS, RXD[3:0] (the emacPins' pullups).
|
||||
* The COL pin is used to select MII mode on reset (pulled up for Reduced MII).
|
||||
* The RXDV pin is used to select test mode on reset (pulled up for test mode).
|
||||
* The above pins should be predefined for corresponding settings in resetPins.
|
||||
* The GMAC peripheral pins are configured after the reset is done.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
* \param ul_mck GMAC MCK.
|
||||
*
|
||||
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t mck)
|
||||
{
|
||||
uint8_t uc_rc = GMAC_TIMEOUT;
|
||||
uint8_t uc_phy;
|
||||
|
||||
ethernet_phy_reset(GMAC,uc_phy_addr);
|
||||
|
||||
/* Configure GMAC runtime clock */
|
||||
uc_rc = gmac_set_mdc_clock(p_gmac, mck);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check PHY Address */
|
||||
uc_phy = ethernet_phy_find_valid(p_gmac, uc_phy_addr, 0);
|
||||
if (uc_phy == 0xFF) {
|
||||
return 0;
|
||||
}
|
||||
if (uc_phy != uc_phy_addr) {
|
||||
ethernet_phy_reset(p_gmac, uc_phy_addr);
|
||||
}
|
||||
phy_props.phy_chn = uc_phy;
|
||||
return uc_phy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get the Link & speed settings, and automatically set up the GMAC with the
|
||||
* settings.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
* \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.
|
||||
*
|
||||
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr,
|
||||
uint8_t uc_apply_setting_flag)
|
||||
{
|
||||
uint32_t ul_stat1;
|
||||
uint32_t ul_stat2;
|
||||
uint8_t uc_phy_address, uc_speed = true, uc_fd = true;
|
||||
uint8_t uc_rc = GMAC_TIMEOUT;
|
||||
|
||||
gmac_enable_management(p_gmac, true);
|
||||
|
||||
uc_phy_address = uc_phy_addr;
|
||||
|
||||
uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_stat1);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
/* Disable PHY management and start the GMAC transfer */
|
||||
gmac_enable_management(p_gmac, false);
|
||||
|
||||
return uc_rc;
|
||||
}
|
||||
if ((ul_stat1 & GMII_LINK_STATUS) == 0) {
|
||||
/* Disable PHY management and start the GMAC transfer */
|
||||
gmac_enable_management(p_gmac, false);
|
||||
|
||||
return GMAC_INVALID;
|
||||
}
|
||||
|
||||
if (uc_apply_setting_flag == 0) {
|
||||
/* Disable PHY management and start the GMAC transfer */
|
||||
gmac_enable_management(p_gmac, false);
|
||||
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
/* Read advertisement */
|
||||
uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_ANAR, &ul_stat2);
|
||||
phy_props.phy_stat1 = ul_stat1;
|
||||
phy_props.phy_stat2 = ul_stat2;
|
||||
if (uc_rc != GMAC_OK) {
|
||||
/* Disable PHY management and start the GMAC transfer */
|
||||
gmac_enable_management(p_gmac, false);
|
||||
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
if ((ul_stat1 & GMII_100BASE_TX_FD) && (ul_stat2 & GMII_100TX_FDX)) {
|
||||
/* Set GMAC for 100BaseTX and Full Duplex */
|
||||
uc_speed = true;
|
||||
uc_fd = true;
|
||||
} else
|
||||
if ((ul_stat1 & GMII_100BASE_T4_HD) && (ul_stat2 & GMII_100TX_HDX)) {
|
||||
/* Set MII for 100BaseTX and Half Duplex */
|
||||
uc_speed = true;
|
||||
uc_fd = false;
|
||||
} else
|
||||
if ((ul_stat1 & GMII_10BASE_T_FD) && (ul_stat2 & GMII_10_FDX)) {
|
||||
/* Set MII for 10BaseT and Full Duplex */
|
||||
uc_speed = false;
|
||||
uc_fd = true;
|
||||
} else
|
||||
if ((ul_stat1 & GMII_10BASE_T_HD) && (ul_stat2 & GMII_10_HDX)) {
|
||||
/* Set MII for 10BaseT and Half Duplex */
|
||||
uc_speed = false;
|
||||
uc_fd = false;
|
||||
}
|
||||
|
||||
gmac_set_speed(p_gmac, uc_speed);
|
||||
gmac_enable_full_duplex(p_gmac, uc_fd);
|
||||
|
||||
/* Start the GMAC transfers */
|
||||
gmac_enable_management(p_gmac, false);
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
PhyProps_t phy_props;
|
||||
|
||||
/**
|
||||
* \brief Issue an auto negotiation of the PHY.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
*
|
||||
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr)
|
||||
{
|
||||
uint32_t ul_retry_max = ETH_PHY_RETRY_MAX;
|
||||
uint32_t ul_value;
|
||||
uint32_t ul_phy_anar;
|
||||
uint32_t ul_retry_count = 0;
|
||||
uint8_t uc_speed = 0;
|
||||
uint8_t uc_fd=0;
|
||||
uint8_t uc_rc = GMAC_TIMEOUT;
|
||||
|
||||
gmac_enable_management(p_gmac, true);
|
||||
|
||||
/* Set up control register */
|
||||
uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -1;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
ul_value &= ~(uint32_t)GMII_AUTONEG; /* Remove auto-negotiation enable */
|
||||
ul_value &= ~(uint32_t)(GMII_LOOPBACK | GMII_POWER_DOWN);
|
||||
ul_value |= (uint32_t)GMII_ISOLATE; /* Electrically isolate PHY */
|
||||
uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -2;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the Auto_negotiation Advertisement Register.
|
||||
* MII advertising for Next page.
|
||||
* 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3.
|
||||
*/
|
||||
ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX |
|
||||
GMII_AN_IEEE_802_3;
|
||||
uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -3;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
/* Read & modify control register */
|
||||
uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -4;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE;
|
||||
uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -5;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
/* Restart auto negotiation */
|
||||
ul_value |= (uint32_t)GMII_RESTART_AUTONEG;
|
||||
ul_value &= ~(uint32_t)GMII_ISOLATE;
|
||||
uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -6;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
/* Check if auto negotiation is completed */
|
||||
while (1) {
|
||||
uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMSR, &ul_value);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -7;
|
||||
return uc_rc;
|
||||
}
|
||||
/* Done successfully */
|
||||
if (ul_value & GMII_AUTONEG_COMP) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Timeout check */
|
||||
if (ul_retry_max) {
|
||||
if (++ul_retry_count >= ul_retry_max) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -8;
|
||||
return GMAC_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the auto negotiate link partner base page */
|
||||
uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_PCR1, &phy_props.phy_params);
|
||||
if (uc_rc != GMAC_OK) {
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = -9;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
|
||||
/* Set up the GMAC link speed */
|
||||
if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_FDX) {
|
||||
/* Set MII for 100BaseTX and Full Duplex */
|
||||
uc_speed = true;
|
||||
uc_fd = true;
|
||||
} else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_FDX) {
|
||||
/* Set MII for 10BaseT and Full Duplex */
|
||||
uc_speed = false;
|
||||
uc_fd = true;
|
||||
} else if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_HDX) {
|
||||
/* Set MII for 100BaseTX and half Duplex */
|
||||
uc_speed = true;
|
||||
uc_fd = false;
|
||||
} else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_HDX) {
|
||||
/* Set MII for 10BaseT and half Duplex */
|
||||
uc_speed = false;
|
||||
uc_fd = false;
|
||||
}
|
||||
|
||||
gmac_set_speed(p_gmac, uc_speed);
|
||||
gmac_enable_full_duplex(p_gmac, uc_fd);
|
||||
|
||||
/* Select Media Independent Interface type */
|
||||
gmac_select_mii_mode(p_gmac, ETH_PHY_MODE);
|
||||
|
||||
gmac_enable_transmit(GMAC, true);
|
||||
gmac_enable_receive(GMAC, true);
|
||||
|
||||
gmac_enable_management(p_gmac, false);
|
||||
phy_props.phy_result = 1;
|
||||
return uc_rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Issue a SW reset to reset all registers of the PHY.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
*
|
||||
* \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr)
|
||||
{
|
||||
uint32_t ul_bmcr = GMII_RESET;
|
||||
uint8_t uc_phy_address = uc_phy_addr;
|
||||
uint32_t ul_timeout = ETH_PHY_TIMEOUT;
|
||||
uint8_t uc_rc = GMAC_TIMEOUT;
|
||||
|
||||
gmac_enable_management(p_gmac, true);
|
||||
|
||||
ul_bmcr = GMII_RESET;
|
||||
gmac_phy_write(p_gmac, uc_phy_address, GMII_BMCR, ul_bmcr);
|
||||
|
||||
do {
|
||||
gmac_phy_read(p_gmac, uc_phy_address, GMII_BMCR, &ul_bmcr);
|
||||
ul_timeout--;
|
||||
} while ((ul_bmcr & GMII_RESET) && ul_timeout);
|
||||
|
||||
gmac_enable_management(p_gmac, false);
|
||||
|
||||
if (!ul_timeout) {
|
||||
uc_rc = GMAC_OK;
|
||||
}
|
||||
|
||||
return (uc_rc);
|
||||
}
|
||||
|
||||
/// @cond 0
|
||||
/**INDENT-OFF**/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**INDENT-ON**/
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief KSZ8051MNL (Ethernet PHY) driver for SAM.
|
||||
*
|
||||
* Copyright (c) 2013 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ETHERNET_PHY_H_INCLUDED
|
||||
#define ETHERNET_PHY_H_INCLUDED
|
||||
|
||||
#include "compiler.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// IEEE defined Registers
|
||||
#define GMII_BMCR 0x00 // Basic Control
|
||||
#define GMII_BMSR 0x01 // Basic Status
|
||||
#define GMII_PHYID1 0x02 // PHY Idendifier 1
|
||||
#define GMII_PHYID2 0x03 // PHY Idendifier 2
|
||||
#define GMII_ANAR 0x04 // Auto_Negotiation Advertisement
|
||||
#define GMII_ANLPAR 0x05 // Auto_negotiation Link Partner Ability
|
||||
#define GMII_ANER 0x06 // Auto-negotiation Expansion
|
||||
#define GMII_ANNPR 0x07 // Auto-negotiation Next Page
|
||||
#define GMII_ANLPNPAR 0x08 // Link Partner Next Page Ability
|
||||
//#define GMII_1000BTCR 9 // 1000Base-T Control // Reserved
|
||||
//#define GMII_1000BTSR 10 // 1000Base-T Status // Reserved
|
||||
#define GMII_AFECR1 0x11 // AFE Control 1
|
||||
//#define GMII_ERDWR 12 // Extend Register - Data Write Register
|
||||
//#define GMII_ERDRR 13 // Extend Register - Data Read Register
|
||||
//14 reserved
|
||||
#define GMII_RXERCR 0x15 // RXER Counter
|
||||
|
||||
#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_REG_05_LPA 0x05 // Link partner ability reg
|
||||
#define PHY_REG_06_ANER 0x06 // 6 RW Auto-Negotiation Expansion Register
|
||||
#define PHY_REG_07_ANNPTR 0x07 // 7 RW Auto-Negotiation Next Page TX
|
||||
#define PHY_REG_08_RESERVED0 0x08 // 0x08..0x0Fh 8-15 RW RESERVED
|
||||
|
||||
#define PHY_REG_10_PHYSTS 0x10 // 16 RO PHY Status Register
|
||||
#define PHY_REG_11_MICR 0x11 // 17 RW MII Interrupt Control Register
|
||||
#define PHY_REG_12_MISR 0x12 // 18 RO MII Interrupt Status Register
|
||||
#define PHY_REG_13_RESERVED1 0x13 // 19 RW RESERVED
|
||||
#define PHY_REG_14_FCSCR 0x14 // 20 RO False Carrier Sense Counter Register
|
||||
#define PHY_REG_15_RECR 0x15 // 21 RO Receive Error Counter Register
|
||||
#define PHY_REG_16_PCSR 0x16 // 22 RW PCS Sub-Layer Configuration and Status Register
|
||||
#define PHY_REG_17_RBR 0x17 // 23 RW RMII and Bypass Register
|
||||
#define PHY_REG_18_LEDCR 0x18 // 24 RW LED Direct Control Register
|
||||
#define PHY_REG_19_PHYCR 0x19 // 25 RW PHY Control Register
|
||||
#define PHY_REG_1A_10BTSCR 0x1A // 26 RW 10Base-T Status/Control Register
|
||||
#define PHY_REG_1B_CDCTRL1 0x1B // 27 RW CD Test Control Register and BIST Extensions Register
|
||||
#define PHY_REG_1B_INT_CTRL 0x1B // 27 RW KSZ8041NL interrupt control
|
||||
#define PHY_REG_1C_RESERVED2 0x1C // 28 RW RESERVED
|
||||
#define PHY_REG_1D_EDCR 0x1D // 29 RW Energy Detect Control Register
|
||||
#define PHY_REG_1E_RESERVED3 0x1E //
|
||||
#define PHY_REG_1F_RESERVED4 0x1F // 30-31 RW RESERVED
|
||||
|
||||
#define PHY_REG_1E_PHYCR_1 0x1E //
|
||||
#define PHY_REG_1F_PHYCR_2 0x1F //
|
||||
|
||||
#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)
|
||||
|
||||
typedef struct _SPhyProps {
|
||||
unsigned char speed;
|
||||
unsigned char mdix;
|
||||
unsigned char duplex;
|
||||
unsigned char spare;
|
||||
} SPhyProps;
|
||||
|
||||
const char *phyPrintable (const SPhyProps *apProps);
|
||||
|
||||
extern SPhyProps phyProps;
|
||||
|
||||
#define GMII_OMSOR 0x16 // Operation Mode Strap Override
|
||||
#define GMII_OMSSR 0x17 // Operation Mode Strap Status
|
||||
#define GMII_ECR 0x18 // Expanded Control
|
||||
//#define GMII_DPPSR 19 // Digital PMA/PCS Status
|
||||
//20 reserved
|
||||
//#define GMII_RXERCR 21 // RXER Counter Register
|
||||
//22-26 reserved
|
||||
#define GMII_ICSR 0x1B // Interrupt Control/Status
|
||||
//#define GMII_DDC1R 28 // Digital Debug Control 1 Register
|
||||
#define GMII_LCSR 0x1D // LinkMD Control/Status
|
||||
|
||||
//29-30 reserved
|
||||
#define GMII_PCR1 0x1E // PHY Control 1
|
||||
#define GMII_PCR2 0x1F // PHY Control 2
|
||||
|
||||
/*
|
||||
//Extend Registers
|
||||
#define GMII_CCR 256 // Common Control Register
|
||||
#define GMII_SSR 257 // Strap Status Register
|
||||
#define GMII_OMSOR 258 // Operation Mode Strap Override Register
|
||||
#define GMII_OMSSR 259 // Operation Mode Strap Status Register
|
||||
#define GMII_RCCPSR 260 // RGMII Clock and Control Pad Skew Register
|
||||
#define GMII_RRDPSR 261 // RGMII RX Data Pad Skew Register
|
||||
#define GMII_ATR 263 // Analog Test Register
|
||||
*/
|
||||
|
||||
|
||||
// Bit definitions: GMII_BMCR 0x00 Basic Control
|
||||
#define GMII_RESET (1 << 15) // 1= Software Reset; 0=Normal Operation
|
||||
#define GMII_LOOPBACK (1 << 14) // 1=loopback Enabled; 0=Normal Operation
|
||||
#define GMII_SPEED_SELECT (1 << 13) // 1=100Mbps; 0=10Mbps
|
||||
#define GMII_AUTONEG (1 << 12) // Auto-negotiation Enable
|
||||
#define GMII_POWER_DOWN (1 << 11) // 1=Power down 0=Normal operation
|
||||
#define GMII_ISOLATE (1 << 10) // 1 = Isolates 0 = Normal operation
|
||||
#define GMII_RESTART_AUTONEG (1 << 9) // 1 = Restart auto-negotiation 0 = Normal operation
|
||||
#define GMII_DUPLEX_MODE (1 << 8) // 1 = Full duplex operation 0 = Normal operation
|
||||
#define GMII_COLLISION_TEST (1 << 7) // 1 = Enable COL test; 0 = Disable COL test
|
||||
//#define GMII_SPEED_SELECT_MSB (1 << 6) // Reserved
|
||||
// Reserved 6 to 0 // Read as 0, ignore on write
|
||||
|
||||
// Bit definitions: GMII_BMSR 0x01 Basic Status
|
||||
#define GMII_100BASE_T4 (1 << 15) // 100BASE-T4 Capable
|
||||
#define GMII_100BASE_TX_FD (1 << 14) // 100BASE-TX Full Duplex Capable
|
||||
#define GMII_100BASE_T4_HD (1 << 13) // 100BASE-TX Half Duplex Capable
|
||||
#define GMII_10BASE_T_FD (1 << 12) // 10BASE-T Full Duplex Capable
|
||||
#define GMII_10BASE_T_HD (1 << 11) // 10BASE-T Half Duplex Capable
|
||||
// Reserved 10 to79 // Read as 0, ignore on write
|
||||
//#define GMII_EXTEND_STATUS (1 << 8) // 1 = Extend Status Information In Reg 15
|
||||
// Reserved 7
|
||||
#define GMII_MF_PREAMB_SUPPR (1 << 6) // MII Frame Preamble Suppression
|
||||
#define GMII_AUTONEG_COMP (1 << 5) // Auto-negotiation Complete
|
||||
#define GMII_REMOTE_FAULT (1 << 4) // Remote Fault
|
||||
#define GMII_AUTONEG_ABILITY (1 << 3) // Auto Configuration Ability
|
||||
#define GMII_LINK_STATUS (1 << 2) // Link Status
|
||||
#define GMII_JABBER_DETECT (1 << 1) // Jabber Detect
|
||||
#define GMII_EXTEND_CAPAB (1 << 0) // Extended Capability
|
||||
|
||||
|
||||
// Bit definitions: GMII_PHYID1 0x02 PHY Idendifier 1
|
||||
// Bit definitions: GMII_PHYID2 0x03 PHY Idendifier 2
|
||||
#define GMII_LSB_MASK 0x3F
|
||||
#define GMII_OUI_MSB 0x0022
|
||||
#define GMII_OUI_LSB 0x05
|
||||
|
||||
|
||||
// Bit definitions: GMII_ANAR 0x04 Auto_Negotiation Advertisement
|
||||
// Bit definitions: GMII_ANLPAR 0x05 Auto_negotiation Link Partner Ability
|
||||
#define GMII_NP (1 << 15) // Next page Indication
|
||||
// Reserved 7
|
||||
#define GMII_RF (1 << 13) // Remote Fault
|
||||
// Reserved 12 // Write as 0, ignore on read
|
||||
#define GMII_PAUSE_MASK (3 << 11) // 0,0 = No Pause 1,0 = Asymmetric Pause(link partner)
|
||||
// 0,1 = Symmetric Pause 1,1 = Symmetric&Asymmetric Pause(local device)
|
||||
#define GMII_100T4 (1 << 9) // 100BASE-T4 Support
|
||||
#define GMII_100TX_FDX (1 << 8) // 100BASE-TX Full Duplex Support
|
||||
#define GMII_100TX_HDX (1 << 7) // 100BASE-TX Support
|
||||
#define GMII_10_FDX (1 << 6) // 10BASE-T Full Duplex Support
|
||||
#define GMII_10_HDX (1 << 5) // 10BASE-T Support
|
||||
// Selector 4 to 0 // Protocol Selection Bits
|
||||
#define GMII_AN_IEEE_802_3 0x0001 // [00001] = IEEE 802.3
|
||||
|
||||
|
||||
// Bit definitions: GMII_ANER 0x06 Auto-negotiation Expansion
|
||||
// Reserved 15 to 5 // Read as 0, ignore on write
|
||||
#define GMII_PDF (1 << 4) // Local Device Parallel Detection Fault
|
||||
#define GMII_LP_NP_ABLE (1 << 3) // Link Partner Next Page Able
|
||||
#define GMII_NP_ABLE (1 << 2) // Local Device Next Page Able
|
||||
#define GMII_PAGE_RX (1 << 1) // New Page Received
|
||||
#define GMII_LP_AN_ABLE (1 << 0) // Link Partner Auto-negotiation Able
|
||||
|
||||
/**
|
||||
* \brief Perform a HW initialization to the PHY and set up clocks.
|
||||
*
|
||||
* This should be called only once to initialize the PHY pre-settings.
|
||||
* The PHY address is the reset status of CRS, RXD[3:0] (the GmacPins' pullups).
|
||||
* The COL pin is used to select MII mode on reset (pulled up for Reduced MII).
|
||||
* The RXDV pin is used to select test mode on reset (pulled up for test mode).
|
||||
* The above pins should be predefined for corresponding settings in resetPins.
|
||||
* The GMAC peripheral pins are configured after the reset is done.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
* \param ul_mck GMAC MCK.
|
||||
*
|
||||
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t ul_mck);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get the Link & speed settings, and automatically set up the GMAC with the
|
||||
* settings.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
* \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.
|
||||
*
|
||||
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr,
|
||||
uint8_t uc_apply_setting_flag);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Issue an auto negotiation of the PHY.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
*
|
||||
* Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr);
|
||||
|
||||
/**
|
||||
* \brief Issue a SW reset to reset all registers of the PHY.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_addr PHY address.
|
||||
*
|
||||
* \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr);
|
||||
|
||||
typedef struct xPHY_PROPS {
|
||||
signed char phy_result;
|
||||
uint32_t phy_params;
|
||||
uint32_t phy_stat1;
|
||||
uint32_t phy_stat2;
|
||||
unsigned char phy_chn;
|
||||
} PhyProps_t;
|
||||
extern PhyProps_t phy_props;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef ETHERNET_PHY_H_INCLUDED */
|
||||
|
||||
+945
@@ -0,0 +1,945 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief GMAC (Ethernet MAC) driver for SAM.
|
||||
*
|
||||
* Copyright (c) 2013 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
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "FreeRTOSIPConfig.h"
|
||||
|
||||
#include "compiler.h"
|
||||
#include "instance/gmac.h"
|
||||
#include "ethernet_phy.h"
|
||||
|
||||
/// @cond 0
|
||||
/**INDENT-OFF**/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**INDENT-ON**/
|
||||
/// @endcond
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (int)( sizeof(x) / sizeof(x)[0] )
|
||||
#endif
|
||||
/**
|
||||
* \defgroup gmac_group Ethernet Media Access Controller
|
||||
*
|
||||
* See \ref gmac_quickstart.
|
||||
*
|
||||
* Driver for the GMAC (Ethernet Media Access Controller).
|
||||
* This file contains basic functions for the GMAC, with support for all modes, settings
|
||||
* and clock speeds.
|
||||
*
|
||||
* \section dependencies Dependencies
|
||||
* This driver does not depend on other modules.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** TX descriptor lists */
|
||||
COMPILER_ALIGNED(8)
|
||||
static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ];
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
/** TX callback lists */
|
||||
static gmac_dev_tx_cb_t gs_tx_callback[ GMAC_TX_BUFFERS ];
|
||||
#endif
|
||||
/** RX descriptors lists */
|
||||
COMPILER_ALIGNED(8)
|
||||
static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ];
|
||||
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER == 0 )
|
||||
/** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the
|
||||
* 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits
|
||||
* of the address shall be set to 0.
|
||||
*/
|
||||
COMPILER_ALIGNED(8)
|
||||
static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ];
|
||||
#endif /* ipconfigZERO_COPY_TX_DRIVER */
|
||||
|
||||
/** Receive Buffer */
|
||||
COMPILER_ALIGNED(8)
|
||||
static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ];
|
||||
|
||||
/**
|
||||
* GMAC device memory management struct.
|
||||
*/
|
||||
typedef struct gmac_dev_mem {
|
||||
/* Pointer to allocated buffer for RX. The address should be 8-byte aligned
|
||||
and the size should be GMAC_RX_UNITSIZE * wRxSize. */
|
||||
uint8_t *p_rx_buffer;
|
||||
/* Pointer to allocated RX descriptor list. */
|
||||
gmac_rx_descriptor_t *p_rx_dscr;
|
||||
/* RX size, in number of registered units (RX descriptors). */
|
||||
/* Increased size from 16- to 32-bits, because it's more efficient */
|
||||
uint32_t us_rx_size;
|
||||
/* Pointer to allocated buffer for TX. The address should be 8-byte aligned
|
||||
and the size should be GMAC_TX_UNITSIZE * wTxSize. */
|
||||
uint8_t *p_tx_buffer;
|
||||
/* Pointer to allocated TX descriptor list. */
|
||||
gmac_tx_descriptor_t *p_tx_dscr;
|
||||
/* TX size, in number of registered units (TX descriptors). */
|
||||
uint32_t us_tx_size;
|
||||
} gmac_dev_mem_t;
|
||||
|
||||
/** Return count in buffer */
|
||||
#define CIRC_CNT( head, tail, size ) ( ( ( head ) - ( tail ) ) % ( size ) )
|
||||
|
||||
/*
|
||||
* Return space available, from 0 to size-1.
|
||||
* Always leave one free char as a completely full buffer that has (head == tail),
|
||||
* which is the same as empty.
|
||||
*/
|
||||
#define CIRC_SPACE( head, tail, size ) CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) )
|
||||
|
||||
/** Circular buffer is empty ? */
|
||||
#define CIRC_EMPTY( head, tail ) ( head == tail )
|
||||
/** Clear circular buffer */
|
||||
#define CIRC_CLEAR( head, tail ) do { ( head ) = 0; ( tail ) = 0; } while( 0 )
|
||||
|
||||
/** Increment head or tail */
|
||||
static __inline void circ_inc32( int32_t *lHeadOrTail, uint32_t ulSize )
|
||||
{
|
||||
( *lHeadOrTail ) ++;
|
||||
if( ( *lHeadOrTail ) >= ( int32_t )ulSize )
|
||||
{
|
||||
( *lHeadOrTail ) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Wait PHY operation to be completed.
|
||||
*
|
||||
* \param p_gmac HW controller address.
|
||||
* \param ul_retry The retry times, 0 to wait forever until completeness.
|
||||
*
|
||||
* Return GMAC_OK if the operation is completed successfully.
|
||||
*/
|
||||
static uint8_t gmac_wait_phy(Gmac* p_gmac, const uint32_t ul_retry)
|
||||
{
|
||||
volatile uint32_t ul_retry_count = 0;
|
||||
const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul );
|
||||
|
||||
while (!gmac_is_phy_idle(p_gmac)) {
|
||||
if (ul_retry == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ul_retry_count++;
|
||||
|
||||
if (ul_retry_count >= ul_retry) {
|
||||
return GMAC_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Block the task to allow other tasks to execute while the PHY
|
||||
is not connected. */
|
||||
vTaskDelay( xPHYPollDelay );
|
||||
}
|
||||
return GMAC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable transfer, reset registers and descriptor lists.
|
||||
*
|
||||
* \param p_dev Pointer to GMAC driver instance.
|
||||
*
|
||||
*/
|
||||
static void gmac_reset_tx_mem(gmac_device_t* p_dev)
|
||||
{
|
||||
Gmac *p_hw = p_dev->p_hw;
|
||||
uint8_t *p_tx_buff = p_dev->p_tx_buffer;
|
||||
gmac_tx_descriptor_t *p_td = p_dev->p_tx_dscr;
|
||||
|
||||
uint32_t ul_index;
|
||||
uint32_t ul_address;
|
||||
|
||||
/* Disable TX */
|
||||
gmac_enable_transmit(p_hw, 0);
|
||||
|
||||
/* Set up the TX descriptors */
|
||||
CIRC_CLEAR(p_dev->l_tx_head, p_dev->l_tx_tail);
|
||||
for( ul_index = 0; ul_index < p_dev->ul_tx_list_size; ul_index++ )
|
||||
{
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
ul_address = (uint32_t) 0u;
|
||||
}
|
||||
#else
|
||||
{
|
||||
ul_address = (uint32_t) (&(p_tx_buff[ul_index * GMAC_TX_UNITSIZE]));
|
||||
}
|
||||
#endif /* ipconfigZERO_COPY_TX_DRIVER */
|
||||
p_td[ul_index].addr = ul_address;
|
||||
p_td[ul_index].status.val = GMAC_TXD_USED;
|
||||
}
|
||||
p_td[p_dev->ul_tx_list_size - 1].status.val =
|
||||
GMAC_TXD_USED | GMAC_TXD_WRAP;
|
||||
|
||||
/* Set transmit buffer queue */
|
||||
gmac_set_tx_queue(p_hw, (uint32_t) p_td);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable receiver, reset registers and descriptor list.
|
||||
*
|
||||
* \param p_drv Pointer to GMAC Driver instance.
|
||||
*/
|
||||
static void gmac_reset_rx_mem(gmac_device_t* p_dev)
|
||||
{
|
||||
Gmac *p_hw = p_dev->p_hw;
|
||||
uint8_t *p_rx_buff = p_dev->p_rx_buffer;
|
||||
gmac_rx_descriptor_t *pRd = p_dev->p_rx_dscr;
|
||||
|
||||
uint32_t ul_index;
|
||||
uint32_t ul_address;
|
||||
|
||||
/* Disable RX */
|
||||
gmac_enable_receive(p_hw, 0);
|
||||
|
||||
/* Set up the RX descriptors */
|
||||
p_dev->ul_rx_idx = 0;
|
||||
for( ul_index = 0; ul_index < p_dev->ul_rx_list_size; ul_index++ )
|
||||
{
|
||||
ul_address = (uint32_t) (&(p_rx_buff[ul_index * GMAC_RX_UNITSIZE]));
|
||||
pRd[ul_index].addr.val = ul_address & GMAC_RXD_ADDR_MASK;
|
||||
pRd[ul_index].status.val = 0;
|
||||
}
|
||||
pRd[p_dev->ul_rx_list_size - 1].addr.val |= GMAC_RXD_WRAP;
|
||||
|
||||
/* Set receive buffer queue */
|
||||
gmac_set_rx_queue(p_hw, (uint32_t) pRd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Initialize the allocated buffer lists for GMAC driver to transfer data.
|
||||
* Must be invoked after gmac_dev_init() but before RX/TX starts.
|
||||
*
|
||||
* \note If input address is not 8-byte aligned, the address is automatically
|
||||
* adjusted and the list size is reduced by one.
|
||||
*
|
||||
* \param p_gmac Pointer to GMAC instance.
|
||||
* \param p_gmac_dev Pointer to GMAC device instance.
|
||||
* \param p_dev_mm Pointer to the GMAC memory management control block.
|
||||
* \param p_tx_cb Pointer to allocated TX callback list.
|
||||
*
|
||||
* \return GMAC_OK or GMAC_PARAM.
|
||||
*/
|
||||
static uint8_t gmac_init_mem(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
|
||||
gmac_dev_mem_t* p_dev_mm
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
, gmac_dev_tx_cb_t* p_tx_cb
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (p_dev_mm->us_rx_size <= 1 || p_dev_mm->us_tx_size <= 1
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
|| p_tx_cb == NULL
|
||||
#endif
|
||||
) {
|
||||
return GMAC_PARAM;
|
||||
}
|
||||
|
||||
/* Assign RX buffers */
|
||||
if (((uint32_t) p_dev_mm->p_rx_buffer & 0x7)
|
||||
|| ((uint32_t) p_dev_mm->p_rx_dscr & 0x7)) {
|
||||
p_dev_mm->us_rx_size--;
|
||||
}
|
||||
p_gmac_dev->p_rx_buffer =
|
||||
(uint8_t *) ((uint32_t) p_dev_mm->p_rx_buffer & 0xFFFFFFF8);
|
||||
p_gmac_dev->p_rx_dscr =
|
||||
(gmac_rx_descriptor_t *) ((uint32_t) p_dev_mm->p_rx_dscr
|
||||
& 0xFFFFFFF8);
|
||||
p_gmac_dev->ul_rx_list_size = p_dev_mm->us_rx_size;
|
||||
|
||||
/* Assign TX buffers */
|
||||
if (((uint32_t) p_dev_mm->p_tx_buffer & 0x7)
|
||||
|| ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) {
|
||||
p_dev_mm->us_tx_size--;
|
||||
}
|
||||
p_gmac_dev->p_tx_buffer =
|
||||
(uint8_t *) ((uint32_t) p_dev_mm->p_tx_buffer & 0xFFFFFFF8);
|
||||
p_gmac_dev->p_tx_dscr =
|
||||
(gmac_tx_descriptor_t *) ((uint32_t) p_dev_mm->p_tx_dscr
|
||||
& 0xFFFFFFF8);
|
||||
p_gmac_dev->ul_tx_list_size = p_dev_mm->us_tx_size;
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
p_gmac_dev->func_tx_cb_list = p_tx_cb;
|
||||
#endif
|
||||
/* Reset TX & RX */
|
||||
gmac_reset_rx_mem(p_gmac_dev);
|
||||
gmac_reset_tx_mem(p_gmac_dev);
|
||||
|
||||
/* Enable Rx and Tx, plus the statistics register */
|
||||
gmac_enable_transmit(p_gmac, true);
|
||||
gmac_enable_receive(p_gmac, true);
|
||||
gmac_enable_statistics_write(p_gmac, true);
|
||||
|
||||
/* Set up the interrupts for transmission and errors */
|
||||
gmac_enable_interrupt(p_gmac,
|
||||
GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */
|
||||
GMAC_IER_TUR | /* Enable transmit underrun interrupt. */
|
||||
GMAC_IER_RLEX | /* Enable retry limit exceeded interrupt. */
|
||||
GMAC_IER_TFC | /* Enable transmit buffers exhausted in mid-frame interrupt. */
|
||||
GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */
|
||||
GMAC_IER_ROVR | /* Enable receive overrun interrupt. */
|
||||
GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */
|
||||
GMAC_IER_PFNZ | /* Enable pause frame received interrupt. */
|
||||
GMAC_IER_PTZ); /* Enable pause time zero interrupt. */
|
||||
|
||||
return GMAC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Read the PHY register.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_address PHY address.
|
||||
* \param uc_address Register address.
|
||||
* \param p_value Pointer to a 32-bit location to store read data.
|
||||
*
|
||||
* \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address,
|
||||
uint32_t* p_value)
|
||||
{
|
||||
gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 1, 0);
|
||||
|
||||
if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {
|
||||
return GMAC_TIMEOUT;
|
||||
}
|
||||
*p_value = gmac_get_phy_data(p_gmac);
|
||||
return GMAC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Write the PHY register.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param uc_phy_address PHY Address.
|
||||
* \param uc_address Register Address.
|
||||
* \param ul_value Data to write, actually 16-bit data.
|
||||
*
|
||||
* \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
|
||||
*/
|
||||
uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address,
|
||||
uint8_t uc_address, uint32_t ul_value)
|
||||
{
|
||||
gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 0, ul_value);
|
||||
|
||||
if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) {
|
||||
return GMAC_TIMEOUT;
|
||||
}
|
||||
return GMAC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize the GMAC driver.
|
||||
*
|
||||
* \param p_gmac Pointer to the GMAC instance.
|
||||
* \param p_gmac_dev Pointer to the GMAC device instance.
|
||||
* \param p_opt GMAC configure options.
|
||||
*/
|
||||
void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev,
|
||||
gmac_options_t* p_opt)
|
||||
{
|
||||
gmac_dev_mem_t gmac_dev_mm;
|
||||
|
||||
/* Disable TX & RX and more */
|
||||
gmac_network_control(p_gmac, 0);
|
||||
gmac_disable_interrupt(p_gmac, ~0u);
|
||||
|
||||
|
||||
gmac_clear_statistics(p_gmac);
|
||||
|
||||
/* Clear all status bits in the receive status register. */
|
||||
gmac_clear_rx_status(p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA);
|
||||
|
||||
/* Clear all status bits in the transmit status register */
|
||||
gmac_clear_tx_status(p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE
|
||||
| GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND);
|
||||
|
||||
/* Clear interrupts */
|
||||
gmac_get_interrupt_status(p_gmac);
|
||||
#if !defined(ETHERNET_CONF_DATA_OFFSET)
|
||||
/* Receive Buffer Offset
|
||||
* Indicates the number of bytes by which the received data
|
||||
* is offset from the start of the receive buffer
|
||||
* which can be handy for alignment reasons */
|
||||
/* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */
|
||||
#error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0
|
||||
#endif
|
||||
/* Enable the copy of data into the buffers
|
||||
ignore broadcasts, and not copy FCS. */
|
||||
|
||||
gmac_set_configure(p_gmac,
|
||||
( gmac_get_configure(p_gmac) & ~GMAC_NCFGR_RXBUFO_Msk ) |
|
||||
GMAC_NCFGR_RFCS | /* Remove FCS, frame check sequence (last 4 bytes) */
|
||||
GMAC_NCFGR_PEN | /* Pause Enable */
|
||||
GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) |
|
||||
GMAC_RXD_RXCOEN );
|
||||
|
||||
/*
|
||||
* GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable.
|
||||
* Note: tha SAM4E does have RX checksum offloading
|
||||
* but TX checksum offloading has NOT been implemented.
|
||||
* http://community.atmel.com/forum/sam4e-gmac-transmit-checksum-offload-enablesolved
|
||||
*/
|
||||
|
||||
gmac_set_dma(p_gmac,
|
||||
gmac_get_dma(p_gmac) | GMAC_DCFGR_TXCOEN );
|
||||
|
||||
gmac_enable_copy_all(p_gmac, p_opt->uc_copy_all_frame);
|
||||
gmac_disable_broadcast(p_gmac, p_opt->uc_no_boardcast);
|
||||
|
||||
/* Fill in GMAC device memory management */
|
||||
gmac_dev_mm.p_rx_buffer = gs_uc_rx_buffer;
|
||||
gmac_dev_mm.p_rx_dscr = gs_rx_desc;
|
||||
gmac_dev_mm.us_rx_size = GMAC_RX_BUFFERS;
|
||||
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
gmac_dev_mm.p_tx_buffer = NULL;
|
||||
}
|
||||
#else
|
||||
{
|
||||
gmac_dev_mm.p_tx_buffer = gs_uc_tx_buffer;
|
||||
}
|
||||
#endif
|
||||
gmac_dev_mm.p_tx_dscr = gs_tx_desc;
|
||||
gmac_dev_mm.us_tx_size = GMAC_TX_BUFFERS;
|
||||
|
||||
gmac_init_mem(p_gmac, p_gmac_dev, &gmac_dev_mm
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
, gs_tx_callback
|
||||
#endif
|
||||
);
|
||||
|
||||
gmac_set_address(p_gmac, 0, p_opt->uc_mac_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Frames can be read from the GMAC in multiple sections.
|
||||
*
|
||||
* Returns > 0 if a complete frame is available
|
||||
* It also it cleans up incomplete older frames
|
||||
*/
|
||||
|
||||
static uint32_t gmac_dev_poll(gmac_device_t* p_gmac_dev)
|
||||
{
|
||||
uint32_t ulReturn = 0;
|
||||
int32_t ulIndex = p_gmac_dev->ul_rx_idx;
|
||||
gmac_rx_descriptor_t *pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
|
||||
|
||||
/* Discard any incomplete frames */
|
||||
while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) &&
|
||||
(pxHead->status.val & GMAC_RXD_SOF) == 0) {
|
||||
pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
|
||||
circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);
|
||||
pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
|
||||
p_gmac_dev->ul_rx_idx = ulIndex;
|
||||
#if( GMAC_STATS != 0 )
|
||||
{
|
||||
gmacStats.incompCount++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) {
|
||||
if ((pxHead->status.val & GMAC_RXD_EOF) != 0) {
|
||||
/* Here a complete frame has been seen with SOF and EOF */
|
||||
ulReturn = pxHead->status.bm.len;
|
||||
break;
|
||||
}
|
||||
circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size);
|
||||
pxHead = &p_gmac_dev->p_rx_dscr[ulIndex];
|
||||
if ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) == 0) {
|
||||
/* CPU is not the owner (yet) */
|
||||
break;
|
||||
}
|
||||
if ((pxHead->status.val & GMAC_RXD_SOF) != 0) {
|
||||
/* Strange, we found a new Start Of Frame
|
||||
* discard previous segments */
|
||||
int32_t ulPrev = p_gmac_dev->ul_rx_idx;
|
||||
pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];
|
||||
do {
|
||||
pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
|
||||
circ_inc32 (&ulPrev, p_gmac_dev->ul_rx_list_size);
|
||||
pxHead = &p_gmac_dev->p_rx_dscr[ulPrev];
|
||||
#if( GMAC_STATS != 0 )
|
||||
{
|
||||
gmacStats.truncCount++;
|
||||
}
|
||||
#endif
|
||||
} while (ulPrev != ulIndex);
|
||||
p_gmac_dev->ul_rx_idx = ulIndex;
|
||||
}
|
||||
}
|
||||
return ulReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Frames can be read from the GMAC in multiple sections.
|
||||
* Read ul_frame_size bytes from the GMAC receive buffers to pcTo.
|
||||
* p_rcv_size is the size of the entire frame. Generally gmac_read
|
||||
* will be repeatedly called until the sum of all the ul_frame_size equals
|
||||
* the value of p_rcv_size.
|
||||
*
|
||||
* \param p_gmac_dev Pointer to the GMAC device instance.
|
||||
* \param p_frame Address of the frame buffer.
|
||||
* \param ul_frame_size Length of the frame.
|
||||
* \param p_rcv_size Received frame size.
|
||||
*
|
||||
* \return GMAC_OK if receiving frame successfully, otherwise failed.
|
||||
*/
|
||||
uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame,
|
||||
uint32_t ul_frame_size, uint32_t* p_rcv_size)
|
||||
{
|
||||
int32_t nextIdx; /* A copy of the Rx-index 'ul_rx_idx' */
|
||||
int32_t bytesLeft = gmac_dev_poll (p_gmac_dev);
|
||||
gmac_rx_descriptor_t *pxHead;
|
||||
|
||||
if (bytesLeft == 0 )
|
||||
{
|
||||
return GMAC_RX_NULL;
|
||||
}
|
||||
|
||||
/* gmac_dev_poll has confirmed that there is a complete frame at
|
||||
* the current position 'ul_rx_idx'
|
||||
*/
|
||||
nextIdx = p_gmac_dev->ul_rx_idx;
|
||||
|
||||
/* Read +2 bytes because buffers are aligned at -2 bytes */
|
||||
bytesLeft = min( bytesLeft + 2, ( int32_t )ul_frame_size );
|
||||
|
||||
/* The frame will be copied in 1 or 2 memcpy's */
|
||||
if( ( p_frame != NULL ) && ( bytesLeft != 0 ) )
|
||||
{
|
||||
const uint8_t *source;
|
||||
int32_t left;
|
||||
int32_t toCopy;
|
||||
|
||||
source = p_gmac_dev->p_rx_buffer + nextIdx * GMAC_RX_UNITSIZE;
|
||||
left = bytesLeft;
|
||||
toCopy = ( p_gmac_dev->ul_rx_list_size - nextIdx ) * GMAC_RX_UNITSIZE;
|
||||
if(toCopy > left )
|
||||
{
|
||||
toCopy = left;
|
||||
}
|
||||
memcpy (p_frame, source, toCopy);
|
||||
left -= toCopy;
|
||||
|
||||
if( left != 0ul )
|
||||
{
|
||||
memcpy (p_frame + toCopy, (void*)p_gmac_dev->p_rx_buffer, left);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
pxHead = &p_gmac_dev->p_rx_dscr[nextIdx];
|
||||
pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP);
|
||||
circ_inc32 (&nextIdx, p_gmac_dev->ul_rx_list_size);
|
||||
} while ((pxHead->status.val & GMAC_RXD_EOF) == 0);
|
||||
|
||||
p_gmac_dev->ul_rx_idx = nextIdx;
|
||||
|
||||
*p_rcv_size = bytesLeft;
|
||||
|
||||
return GMAC_OK;
|
||||
}
|
||||
|
||||
|
||||
extern void vGMACGenerateChecksum( uint8_t *apBuffer );
|
||||
|
||||
/**
|
||||
* \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the
|
||||
* GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready.
|
||||
* If lEndOfFrame is true then the data being copied is the end of the frame
|
||||
* and the frame can be transmitted.
|
||||
*
|
||||
* \param p_gmac_dev Pointer to the GMAC device instance.
|
||||
* \param p_buffer Pointer to the data buffer.
|
||||
* \param ul_size Length of the frame.
|
||||
* \param func_tx_cb Transmit callback function.
|
||||
*
|
||||
* \return Length sent.
|
||||
*/
|
||||
uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer,
|
||||
uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb)
|
||||
{
|
||||
|
||||
volatile gmac_tx_descriptor_t *p_tx_td;
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
volatile gmac_dev_tx_cb_t *p_func_tx_cb;
|
||||
#endif
|
||||
|
||||
Gmac *p_hw = p_gmac_dev->p_hw;
|
||||
|
||||
#if( GMAC_USES_TX_CALLBACK == 0 )
|
||||
( void )func_tx_cb;
|
||||
#endif
|
||||
|
||||
/* Check parameter */
|
||||
if (ul_size > GMAC_TX_UNITSIZE) {
|
||||
return GMAC_PARAM;
|
||||
}
|
||||
|
||||
/* Pointers to the current transmit descriptor */
|
||||
p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_head];
|
||||
|
||||
/* If no free TxTd, buffer can't be sent, schedule the wakeup callback */
|
||||
// if (CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
|
||||
// p_gmac_dev->ul_tx_list_size) == 0)
|
||||
{
|
||||
if ((p_tx_td->status.val & GMAC_TXD_USED) == 0)
|
||||
return GMAC_TX_BUSY;
|
||||
}
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
/* Pointers to the current Tx callback */
|
||||
p_func_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_head];
|
||||
#endif
|
||||
|
||||
/* Set up/copy data to transmission buffer */
|
||||
if (p_buffer && ul_size) {
|
||||
/* Driver manages the ring buffer */
|
||||
/* Calculating the checksum here is faster than calculating it from the GMAC buffer
|
||||
* because withing p_buffer, it is well aligned */
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
/* Zero-copy... */
|
||||
p_tx_td->addr = ( uint32_t ) p_buffer;
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* Or memcopy... */
|
||||
memcpy((void *)p_tx_td->addr, p_buffer, ul_size);
|
||||
}
|
||||
#endif /* ipconfigZERO_COPY_TX_DRIVER */
|
||||
vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr );
|
||||
}
|
||||
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
/* Tx callback */
|
||||
*p_func_tx_cb = func_tx_cb;
|
||||
#endif
|
||||
|
||||
/* Update transmit descriptor status */
|
||||
|
||||
/* The buffer size defined is the length of ethernet frame,
|
||||
so it's always the last buffer of the frame. */
|
||||
if( p_gmac_dev->l_tx_head == ( int32_t )( p_gmac_dev->ul_tx_list_size - 1 ) )
|
||||
{
|
||||
/* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked */
|
||||
p_tx_td->status.val =
|
||||
ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP;
|
||||
} else {
|
||||
p_tx_td->status.val =
|
||||
ul_size | GMAC_TXD_LAST;
|
||||
}
|
||||
|
||||
circ_inc32( &p_gmac_dev->l_tx_head, p_gmac_dev->ul_tx_list_size );
|
||||
|
||||
/* Now start to transmit if it is still not done */
|
||||
gmac_start_transmission(p_hw);
|
||||
|
||||
return GMAC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get current load of transmit.
|
||||
*
|
||||
* \param p_gmac_dev Pointer to the GMAC device instance.
|
||||
*
|
||||
* \return Current load of transmit.
|
||||
*/
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
/* Without defining GMAC_USES_TX_CALLBACK, l_tx_tail won't be updated */
|
||||
uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev)
|
||||
{
|
||||
uint16_t us_head = p_gmac_dev->l_tx_head;
|
||||
uint16_t us_tail = p_gmac_dev->l_tx_tail;
|
||||
return CIRC_CNT(us_head, us_tail, p_gmac_dev->ul_tx_list_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Register/Clear RX callback. Callback will be invoked after the next received
|
||||
* frame.
|
||||
*
|
||||
* When gmac_dev_read() returns GMAC_RX_NULL, the application task calls
|
||||
* gmac_dev_set_rx_callback() to register func_rx_cb() callback and enters suspend state.
|
||||
* The callback is in charge to resume the task once a new frame has been
|
||||
* received. The next time gmac_dev_read() is called, it will be successful.
|
||||
*
|
||||
* This function is usually invoked from the RX callback itself with NULL
|
||||
* callback, to unregister. Once the callback has resumed the application task,
|
||||
* there is no need to invoke the callback again.
|
||||
*
|
||||
* \param p_gmac_dev Pointer to the GMAC device instance.
|
||||
* \param func_tx_cb Receive callback function.
|
||||
*/
|
||||
void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev,
|
||||
gmac_dev_rx_cb_t func_rx_cb)
|
||||
{
|
||||
Gmac *p_hw = p_gmac_dev->p_hw;
|
||||
|
||||
if (func_rx_cb == NULL) {
|
||||
gmac_disable_interrupt(p_hw, GMAC_IDR_RCOMP);
|
||||
p_gmac_dev->func_rx_cb = NULL;
|
||||
} else {
|
||||
p_gmac_dev->func_rx_cb = func_rx_cb;
|
||||
gmac_enable_interrupt(p_hw, GMAC_IER_RCOMP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Register/Clear TX wakeup callback.
|
||||
*
|
||||
* When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application
|
||||
* task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and
|
||||
* enters suspend state. The callback is in charge to resume the task once
|
||||
* several transmit descriptors have been released. The next time gmac_dev_write() will be called,
|
||||
* it shall be successful.
|
||||
*
|
||||
* This function is usually invoked with NULL callback from the TX wakeup
|
||||
* callback itself, to unregister. Once the callback has resumed the
|
||||
* application task, there is no need to invoke the callback again.
|
||||
*
|
||||
* \param p_gmac_dev Pointer to GMAC device instance.
|
||||
* \param func_wakeup Pointer to wakeup callback function.
|
||||
* \param uc_threshold Number of free transmit descriptor before wakeup callback invoked.
|
||||
*
|
||||
* \return GMAC_OK, GMAC_PARAM on parameter error.
|
||||
*/
|
||||
#if( GMAC_USES_WAKEUP_CALLBACK )
|
||||
uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev,
|
||||
gmac_dev_wakeup_cb_t func_wakeup_cb, uint8_t uc_threshold)
|
||||
{
|
||||
if (func_wakeup_cb == NULL) {
|
||||
p_gmac_dev->func_wakeup_cb = NULL;
|
||||
} else {
|
||||
if (uc_threshold <= p_gmac_dev->ul_tx_list_size) {
|
||||
p_gmac_dev->func_wakeup_cb = func_wakeup_cb;
|
||||
p_gmac_dev->uc_wakeup_threshold = uc_threshold;
|
||||
} else {
|
||||
return GMAC_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
return GMAC_OK;
|
||||
}
|
||||
#endif /* GMAC_USES_WAKEUP_CALLBACK */
|
||||
|
||||
/**
|
||||
* \brief Reset TX & RX queue & statistics.
|
||||
*
|
||||
* \param p_gmac_dev Pointer to GMAC device instance.
|
||||
*/
|
||||
void gmac_dev_reset(gmac_device_t* p_gmac_dev)
|
||||
{
|
||||
Gmac *p_hw = p_gmac_dev->p_hw;
|
||||
|
||||
gmac_reset_rx_mem(p_gmac_dev);
|
||||
gmac_reset_tx_mem(p_gmac_dev);
|
||||
gmac_network_control(p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN
|
||||
| GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
|
||||
}
|
||||
|
||||
void gmac_dev_halt(Gmac* p_gmac);
|
||||
|
||||
void gmac_dev_halt(Gmac* p_gmac)
|
||||
{
|
||||
gmac_network_control(p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
|
||||
gmac_disable_interrupt(p_gmac, ~0u);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief GMAC Interrupt handler.
|
||||
*
|
||||
* \param p_gmac_dev Pointer to GMAC device instance.
|
||||
*/
|
||||
|
||||
#if( GMAC_STATS != 0 )
|
||||
extern int logPrintf( const char *pcFormat, ... );
|
||||
|
||||
void gmac_show_irq_counts ()
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < ARRAY_SIZE(intPairs); index++) {
|
||||
if (gmacStats.intStatus[intPairs[index].index]) {
|
||||
logPrintf("%s : %6u\n", intPairs[index].name, gmacStats.intStatus[intPairs[index].index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void gmac_handler(gmac_device_t* p_gmac_dev)
|
||||
{
|
||||
Gmac *p_hw = p_gmac_dev->p_hw;
|
||||
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
gmac_tx_descriptor_t *p_tx_td;
|
||||
gmac_dev_tx_cb_t *p_tx_cb = NULL;
|
||||
uint32_t ul_tx_status_flag;
|
||||
#endif
|
||||
#if( GMAC_STATS != 0 )
|
||||
int index;
|
||||
#endif
|
||||
|
||||
/* volatile */ uint32_t ul_isr;
|
||||
/* volatile */ uint32_t ul_rsr;
|
||||
/* volatile */ uint32_t ul_tsr;
|
||||
|
||||
ul_isr = gmac_get_interrupt_status(p_hw);
|
||||
ul_rsr = gmac_get_rx_status(p_hw);
|
||||
ul_tsr = gmac_get_tx_status(p_hw);
|
||||
|
||||
/* Why clear bits that are ignored anyway ? */
|
||||
/* ul_isr &= ~(gmac_get_interrupt_mask(p_hw) | 0xF8030300); */
|
||||
#if( GMAC_STATS != 0 )
|
||||
{
|
||||
for (index = 0; index < ARRAY_SIZE(intPairs); index++) {
|
||||
if (ul_isr & intPairs[index].mask)
|
||||
gmacStats.intStatus[intPairs[index].index]++;
|
||||
}
|
||||
}
|
||||
#endif /* GMAC_STATS != 0 */
|
||||
|
||||
/* RX packet */
|
||||
if ((ul_isr & GMAC_ISR_RCOMP) || (ul_rsr & (GMAC_RSR_REC|GMAC_RSR_RXOVR|GMAC_RSR_BNA))) {
|
||||
/* Clear status */
|
||||
gmac_clear_rx_status(p_hw, ul_rsr);
|
||||
|
||||
if (ul_isr & GMAC_ISR_RCOMP)
|
||||
ul_rsr |= GMAC_RSR_REC;
|
||||
/* Invoke callbacks which can be useful to wake op a task */
|
||||
if (p_gmac_dev->func_rx_cb) {
|
||||
p_gmac_dev->func_rx_cb(ul_rsr);
|
||||
}
|
||||
}
|
||||
|
||||
/* TX packet */
|
||||
if ((ul_isr & GMAC_ISR_TCOMP) || (ul_tsr & (GMAC_TSR_TXCOMP|GMAC_TSR_COL|GMAC_TSR_RLE|GMAC_TSR_UND))) {
|
||||
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
ul_tx_status_flag = GMAC_TSR_TXCOMP;
|
||||
#endif
|
||||
/* A frame transmitted */
|
||||
|
||||
/* Check RLE */
|
||||
if (ul_tsr & GMAC_TSR_RLE) {
|
||||
/* Status RLE & Number of discarded buffers */
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT(p_gmac_dev->l_tx_head,
|
||||
p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);
|
||||
p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];
|
||||
#endif
|
||||
gmac_reset_tx_mem(p_gmac_dev);
|
||||
gmac_enable_transmit(p_hw, 1);
|
||||
}
|
||||
/* Clear status */
|
||||
gmac_clear_tx_status(p_hw, ul_tsr);
|
||||
|
||||
#if( GMAC_USES_TX_CALLBACK != 0 )
|
||||
if (!CIRC_EMPTY(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail)) {
|
||||
/* Check the buffers */
|
||||
do {
|
||||
p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_tail];
|
||||
p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail];
|
||||
/* Any error? Exit if buffer has not been sent yet */
|
||||
if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Notify upper layer that a packet has been sent */
|
||||
if (*p_tx_cb) {
|
||||
(*p_tx_cb) (ul_tx_status_flag, (void*)p_tx_td->addr);
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
p_tx_td->addr = 0ul;
|
||||
}
|
||||
#endif /* ipconfigZERO_COPY_TX_DRIVER */
|
||||
}
|
||||
|
||||
circ_inc32(&p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size);
|
||||
} while (CIRC_CNT(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
|
||||
p_gmac_dev->ul_tx_list_size));
|
||||
}
|
||||
|
||||
if (ul_tsr & GMAC_TSR_RLE) {
|
||||
/* Notify upper layer RLE */
|
||||
if (*p_tx_cb) {
|
||||
(*p_tx_cb) (ul_tx_status_flag, NULL);
|
||||
}
|
||||
}
|
||||
#endif /* GMAC_USES_TX_CALLBACK */
|
||||
|
||||
#if( GMAC_USES_WAKEUP_CALLBACK )
|
||||
/* If a wakeup has been scheduled, notify upper layer that it can
|
||||
send other packets, and the sending will be successful. */
|
||||
if ((CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail,
|
||||
p_gmac_dev->ul_tx_list_size) >= p_gmac_dev->uc_wakeup_threshold)
|
||||
&& p_gmac_dev->func_wakeup_cb) {
|
||||
p_gmac_dev->func_wakeup_cb();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
/// @cond 0
|
||||
/**INDENT-OFF**/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**INDENT-ON**/
|
||||
/// @endcond
|
||||
+1346
File diff suppressed because it is too large
Load Diff
+1349
File diff suppressed because it is too large
Load Diff
+664
@@ -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;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
FreeRTOS+TCP V2.0.11
|
||||
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
http://aws.amazon.com/freertos
|
||||
http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Hardware abstraction. */
|
||||
#include "FreeRTOS_IO.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_UDP_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
/* Driver includes. */
|
||||
#include "lpc17xx_emac.h"
|
||||
#include "lpc17xx_pinsel.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
|
||||
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
|
||||
#else
|
||||
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
|
||||
#endif
|
||||
|
||||
/* When a packet is ready to be sent, if it cannot be sent immediately then the
|
||||
task performing the transmit will block for niTX_BUFFER_FREE_WAIT
|
||||
milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
|
||||
up. */
|
||||
#define niTX_BUFFER_FREE_WAIT ( pdMS_TO_TICKS( 2UL ) )
|
||||
#define niMAX_TX_ATTEMPTS ( 5 )
|
||||
|
||||
/* The length of the queue used to send interrupt status words from the
|
||||
interrupt handler to the deferred handler task. */
|
||||
#define niINTERRUPT_QUEUE_LENGTH ( 10 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* A deferred interrupt handler task that processes
|
||||
*/
|
||||
static void prvEMACHandlerTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue used to communicate Ethernet events with the IP task. */
|
||||
extern QueueHandle_t xNetworkEventQueue;
|
||||
|
||||
/* The semaphore used to wake the deferred interrupt handler task when an Rx
|
||||
interrupt is received. */
|
||||
static SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceInitialise( void )
|
||||
{
|
||||
EMAC_CFG_Type Emac_Config;
|
||||
PINSEL_CFG_Type xPinConfig;
|
||||
BaseType_t xStatus, xReturn;
|
||||
extern uint8_t ucMACAddress[ 6 ];
|
||||
|
||||
/* Enable Ethernet Pins */
|
||||
boardCONFIGURE_ENET_PINS( xPinConfig );
|
||||
|
||||
Emac_Config.Mode = EMAC_MODE_AUTO;
|
||||
Emac_Config.pbEMAC_Addr = ucMACAddress;
|
||||
xStatus = EMAC_Init( &Emac_Config );
|
||||
|
||||
LPC_EMAC->IntEnable &= ~( EMAC_INT_TX_DONE );
|
||||
|
||||
if( xStatus != ERROR )
|
||||
{
|
||||
vSemaphoreCreateBinary( xEMACRxEventSemaphore );
|
||||
configASSERT( xEMACRxEventSemaphore );
|
||||
|
||||
/* The handler task is created at the highest possible priority to
|
||||
ensure the interrupt handler can return directly to it. */
|
||||
xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
|
||||
|
||||
/* Enable the interrupt and set its priority to the minimum
|
||||
interrupt priority. */
|
||||
NVIC_SetPriority( ENET_IRQn, configMAC_INTERRUPT_PRIORITY );
|
||||
NVIC_EnableIRQ( ENET_IRQn );
|
||||
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
configASSERT( xStatus != ERROR );
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
|
||||
{
|
||||
BaseType_t xReturn = pdFAIL;
|
||||
int32_t x;
|
||||
extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength );
|
||||
extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer );
|
||||
|
||||
|
||||
/* Attempt to obtain access to a Tx buffer. */
|
||||
for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
|
||||
{
|
||||
if( EMAC_CheckTransmitIndex() == TRUE )
|
||||
{
|
||||
/* Will the data fit in the Tx buffer? */
|
||||
if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
|
||||
{
|
||||
/* Assign the buffer to the Tx descriptor that is now known to
|
||||
be free. */
|
||||
EMAC_SetNextPacketToSend( pxNetworkBuffer->pucBuffer );
|
||||
|
||||
/* The EMAC now owns the buffer. */
|
||||
pxNetworkBuffer->pucBuffer = NULL;
|
||||
|
||||
/* Initiate the Tx. */
|
||||
EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );
|
||||
iptraceNETWORK_INTERFACE_TRANSMIT();
|
||||
|
||||
/* The Tx has been initiated. */
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
vTaskDelay( niTX_BUFFER_FREE_WAIT );
|
||||
}
|
||||
}
|
||||
|
||||
/* Finished with the network buffer. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void ENET_IRQHandler( void )
|
||||
{
|
||||
uint32_t ulInterruptCause;
|
||||
|
||||
while( ( ulInterruptCause = LPC_EMAC->IntStatus ) != 0 )
|
||||
{
|
||||
/* Clear the interrupt. */
|
||||
LPC_EMAC->IntClear = ulInterruptCause;
|
||||
|
||||
/* Clear fatal error conditions. NOTE: The driver does not clear all
|
||||
errors, only those actually experienced. For future reference, range
|
||||
errors are not actually errors so can be ignored. */
|
||||
if( ( ulInterruptCause & EMAC_INT_TX_UNDERRUN ) != 0U )
|
||||
{
|
||||
LPC_EMAC->Command |= EMAC_CR_TX_RES;
|
||||
}
|
||||
|
||||
/* Unblock the deferred interrupt handler task if the event was an
|
||||
Rx. */
|
||||
if( ( ulInterruptCause & EMAC_INT_RX_DONE ) != 0UL )
|
||||
{
|
||||
xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* ulInterruptCause is used for convenience here. A context switch is
|
||||
wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
|
||||
compiler warning. */
|
||||
portEND_SWITCHING_ISR( ulInterruptCause );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEMACHandlerTask( void *pvParameters )
|
||||
{
|
||||
size_t xDataLength;
|
||||
const uint16_t usCRCLength = 4;
|
||||
NetworkBufferDescriptor_t *pxNetworkBuffer;
|
||||
IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
|
||||
|
||||
/* This is not included in the header file for some reason. */
|
||||
extern uint8_t *EMAC_NextPacketToRead( void );
|
||||
|
||||
( void ) pvParameters;
|
||||
configASSERT( xEMACRxEventSemaphore );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait for the EMAC interrupt to indicate that another packet has been
|
||||
received. The while() loop is only needed if INCLUDE_vTaskSuspend is
|
||||
set to 0 in FreeRTOSConfig.h. */
|
||||
while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );
|
||||
|
||||
/* At least one packet has been received. */
|
||||
while( EMAC_CheckReceiveIndex() != FALSE )
|
||||
{
|
||||
/* Obtain the length, minus the CRC. The CRC is four bytes
|
||||
but the length is already minus 1. */
|
||||
xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U );
|
||||
|
||||
if( xDataLength > 0U )
|
||||
{
|
||||
/* Obtain a network buffer to pass this data into the
|
||||
stack. No storage is required as the network buffer
|
||||
will point directly to the buffer that already holds
|
||||
the received data. */
|
||||
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 );
|
||||
|
||||
if( pxNetworkBuffer != NULL )
|
||||
{
|
||||
pxNetworkBuffer->pucBuffer = EMAC_NextPacketToRead();
|
||||
pxNetworkBuffer->xDataLength = xDataLength;
|
||||
xRxEvent.pvData = ( void * ) pxNetworkBuffer;
|
||||
|
||||
/* Data was received and stored. Send a message to the IP
|
||||
task to let it know. */
|
||||
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
}
|
||||
|
||||
iptraceNETWORK_INTERFACE_RECEIVE();
|
||||
}
|
||||
|
||||
/* Release the frame. */
|
||||
EMAC_UpdateRxConsumeIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
+1068
File diff suppressed because it is too large
Load Diff
+3
@@ -0,0 +1,3 @@
|
||||
NetworkInterface.c:
|
||||
Requires NXP's LPCOpen library and was developed on an LPC1830 and LPC1835 Xplorer
|
||||
boards from NGX.
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
Network drivers are provided as examples only, and do not form part of the
|
||||
FreeRTOS+TCP stack itself. They:
|
||||
|
||||
+ May be based on driver code provided by the chip vendors,
|
||||
+ May not have been tested in all possible configurations,
|
||||
+ Will not necessarily be optimised.
|
||||
+ May have a dependency on a particular PHY part number.
|
||||
+ May not necessarily comply with any particular coding standard.
|
||||
+ May have dependencies on chip company libraries.
|
||||
+ May include other hardware board dependencies.
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
FreeRTOS+TCP V2.0.11
|
||||
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
http://aws.amazon.com/freertos
|
||||
http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_UDP_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
/* Hardware includes. */
|
||||
#include "hwEthernet.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
|
||||
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
|
||||
#else
|
||||
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
|
||||
#endif
|
||||
|
||||
/* When a packet is ready to be sent, if it cannot be sent immediately then the
|
||||
task performing the transmit will block for niTX_BUFFER_FREE_WAIT
|
||||
milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
|
||||
up. */
|
||||
#define niTX_BUFFER_FREE_WAIT ( ( TickType_t ) 2UL / portTICK_PERIOD_MS )
|
||||
#define niMAX_TX_ATTEMPTS ( 5 )
|
||||
|
||||
/* The length of the queue used to send interrupt status words from the
|
||||
interrupt handler to the deferred handler task. */
|
||||
#define niINTERRUPT_QUEUE_LENGTH ( 10 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* A deferred interrupt handler task that processes
|
||||
*/
|
||||
extern void vEMACHandlerTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue used to communicate Ethernet events with the IP task. */
|
||||
extern QueueHandle_t xNetworkEventQueue;
|
||||
|
||||
/* The semaphore used to wake the deferred interrupt handler task when an Rx
|
||||
interrupt is received. */
|
||||
SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceInitialise( void )
|
||||
{
|
||||
BaseType_t xStatus, xReturn;
|
||||
extern uint8_t ucMACAddress[ 6 ];
|
||||
|
||||
/* Initialise the MAC. */
|
||||
vInitEmac();
|
||||
|
||||
while( lEMACWaitForLink() != pdPASS )
|
||||
{
|
||||
vTaskDelay( 20 );
|
||||
}
|
||||
|
||||
vSemaphoreCreateBinary( xEMACRxEventSemaphore );
|
||||
configASSERT( xEMACRxEventSemaphore );
|
||||
|
||||
/* The handler task is created at the highest possible priority to
|
||||
ensure the interrupt handler can return directly to it. */
|
||||
xTaskCreate( vEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
|
||||
xReturn = pdPASS;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
|
||||
{
|
||||
extern void vEMACCopyWrite( uint8_t * pucBuffer, uint16_t usLength );
|
||||
|
||||
vEMACCopyWrite( pxNetworkBuffer->pucBuffer, pxNetworkBuffer->xDataLength );
|
||||
|
||||
/* Finished with the network buffer. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
||||
|
||||
return pdTRUE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
+1193
File diff suppressed because it is too large
Load Diff
+1835
File diff suppressed because it is too large
Load Diff
+2214
File diff suppressed because it is too large
Load Diff
+1190
File diff suppressed because it is too large
Load Diff
+1833
File diff suppressed because it is too large
Load Diff
+6
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to
|
||||
* a single module that works for both parts: "stm32fxx_hal_eth"
|
||||
*/
|
||||
|
||||
#include "stm32fxx_hal_eth.h"
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
#define xBUFFER_CACHE_SIZE 10
|
||||
#define xMAX_FAULT_INJECTION_RATE 15
|
||||
#define xMIN_FAULT_INJECTION_RATE 3
|
||||
#define xNUM_FAULT_TYPES 1
|
||||
|
||||
static NetworkBufferDescriptor_t *xNetworkBufferCache[ xBUFFER_CACHE_SIZE ] = { 0 };
|
||||
|
||||
#define xFAULT_LOG_SIZE 2048
|
||||
uint32_t ulInjectedFault[ xFAULT_LOG_SIZE ];
|
||||
uint32_t ulFaultLogIndex = 0;
|
||||
|
||||
static BaseType_t prvCachePacket( NetworkBufferDescriptor_t *pxNetworkBufferIn )
|
||||
{
|
||||
BaseType_t x, xReturn = pdFALSE;
|
||||
|
||||
for( x = 0; x < xBUFFER_CACHE_SIZE; x++ )
|
||||
{
|
||||
if( xNetworkBufferCache[ x ] == NULL )
|
||||
{
|
||||
xNetworkBufferCache[ x ] = pxNetworkBufferIn;
|
||||
xReturn = pdTRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static NetworkBufferDescriptor_t *prvGetCachedPacket( void )
|
||||
{
|
||||
BaseType_t x;
|
||||
NetworkBufferDescriptor_t *pxReturn = NULL;
|
||||
|
||||
for( x = ( xBUFFER_CACHE_SIZE - 1 ); x >= 0; x-- )
|
||||
{
|
||||
if( xNetworkBufferCache[ x ] != NULL )
|
||||
{
|
||||
pxReturn = xNetworkBufferCache[ x ];
|
||||
xNetworkBufferCache[ x ] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static NetworkBufferDescriptor_t *prvDuplicatePacket( NetworkBufferDescriptor_t * pxOriginalPacket, const uint8_t *pucPacketData )
|
||||
{
|
||||
NetworkBufferDescriptor_t *pxReturn;
|
||||
|
||||
/* Obtain a new descriptor. */
|
||||
pxReturn = pxGetNetworkBufferWithDescriptor( pxOriginalPacket->xDataLength, 0 );
|
||||
|
||||
if( pxReturn != NULL )
|
||||
{
|
||||
/* Copy in the packet data. */
|
||||
pxReturn->xDataLength = pxOriginalPacket->xDataLength;
|
||||
memcpy( pxReturn->pucEthernetBuffer, pucPacketData, pxOriginalPacket->xDataLength );
|
||||
}
|
||||
|
||||
return pxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static NetworkBufferDescriptor_t *prvRxFaultInjection( NetworkBufferDescriptor_t *pxNetworkBufferIn, const uint8_t *pucPacketData )
|
||||
{
|
||||
static uint32_t ulCallCount = 0, ulNextFaultCallCount = 0;
|
||||
NetworkBufferDescriptor_t *pxReturn = pxNetworkBufferIn;
|
||||
IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
|
||||
uint32_t ulFault;
|
||||
|
||||
return pxNetworkBufferIn;
|
||||
|
||||
ulCallCount++;
|
||||
|
||||
if( ulCallCount > ulNextFaultCallCount )
|
||||
{
|
||||
ulNextFaultCallCount = ipconfigRAND32() % xMAX_FAULT_INJECTION_RATE;
|
||||
if( ulNextFaultCallCount < xMIN_FAULT_INJECTION_RATE )
|
||||
{
|
||||
ulNextFaultCallCount = xMIN_FAULT_INJECTION_RATE;
|
||||
}
|
||||
|
||||
ulCallCount = 0;
|
||||
|
||||
ulFault = ipconfigRAND32() % xNUM_FAULT_TYPES;
|
||||
|
||||
if( ulFaultLogIndex < xFAULT_LOG_SIZE )
|
||||
{
|
||||
ulInjectedFault[ ulFaultLogIndex ] = ulFault;
|
||||
ulFaultLogIndex++;
|
||||
}
|
||||
|
||||
switch( ulFault )
|
||||
{
|
||||
case 0:
|
||||
/* Just drop the packet. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
|
||||
pxReturn = NULL;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Store the packet in the cache for later. */
|
||||
if( prvCachePacket( pxNetworkBufferIn ) == pdTRUE )
|
||||
{
|
||||
/* The packet may get sent later, it is not being sent
|
||||
now. */
|
||||
pxReturn = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Send a cached packet. */
|
||||
pxReturn = prvGetCachedPacket();
|
||||
if( pxReturn != NULL )
|
||||
{
|
||||
/* A cached packet was obtained so drop the original
|
||||
packet. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Could not obtain a packet from the cache so just return
|
||||
the packet that was passed in. */
|
||||
pxReturn = pxNetworkBufferIn;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
|
||||
/* Send a duplicate of the packet right away. */
|
||||
pxReturn = prvDuplicatePacket( pxNetworkBufferIn, pucPacketData );
|
||||
|
||||
/* Send the original packet to the stack. */
|
||||
xRxEvent.pvData = ( void * ) pxNetworkBufferIn;
|
||||
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
|
||||
/* Send both a cached packet and the current packet. */
|
||||
xRxEvent.pvData = ( void * ) prvGetCachedPacket();
|
||||
if( xRxEvent.pvData != NULL )
|
||||
{
|
||||
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
/* Store the packet in the cache for later. */
|
||||
if( prvCachePacket( pxNetworkBufferIn ) == pdTRUE )
|
||||
{
|
||||
/* The packet may get sent later, it is not being sent
|
||||
now. */
|
||||
pxReturn = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
+636
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
FreeRTOS+TCP V2.0.11
|
||||
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
http://aws.amazon.com/freertos
|
||||
http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
/* WinPCap includes. */
|
||||
#define HAVE_REMOTE
|
||||
#include "pcap.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
/* Thread-safe circular buffers are being used to pass data to and from the PCAP
|
||||
access functions. */
|
||||
#include "Win32-Extensions.h"
|
||||
#include "FreeRTOS_Stream_Buffer.h"
|
||||
|
||||
/* Sizes of the thread safe circular buffers used to pass data to and from the
|
||||
WinPCAP Windows threads. */
|
||||
#define xSEND_BUFFER_SIZE 32768
|
||||
#define xRECV_BUFFER_SIZE 32768
|
||||
|
||||
/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
|
||||
driver will filter incoming packets and only pass the stack those packets it
|
||||
considers need processing. */
|
||||
#if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
|
||||
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
|
||||
#else
|
||||
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
|
||||
#endif
|
||||
|
||||
/* Used to insert test code only. */
|
||||
#define niDISRUPT_PACKETS 0
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Windows threads that are outside of the control of the FreeRTOS simulator are
|
||||
* used to interface with the WinPCAP libraries.
|
||||
*/
|
||||
DWORD WINAPI prvWinPcapRecvThread( void *pvParam );
|
||||
DWORD WINAPI prvWinPcapSendThread( void *pvParam );
|
||||
|
||||
/*
|
||||
* Print out a numbered list of network interfaces that are available on the
|
||||
* host computer.
|
||||
*/
|
||||
static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
|
||||
|
||||
/*
|
||||
* Open the network interface. The number of the interface to be opened is set
|
||||
* by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
|
||||
*/
|
||||
static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );
|
||||
static int prvOpenInterface( const char *pucName );
|
||||
|
||||
/*
|
||||
* Configure the capture filter to allow blocking reads, and to filter out
|
||||
* packets that are not of interest to this demo.
|
||||
*/
|
||||
static void prvConfigureCaptureBehaviour( void );
|
||||
|
||||
/*
|
||||
* A function that simulates Ethernet interrupts by periodically polling the
|
||||
* WinPCap interface for new data.
|
||||
*/
|
||||
static void prvInterruptSimulatorTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Create the buffers that are used to pass data between the FreeRTOS simulator
|
||||
* and the Win32 threads that manage WinPCAP.
|
||||
*/
|
||||
static void prvCreateThreadSafeBuffers( void );
|
||||
|
||||
/*
|
||||
* Utility function used to format print messages only.
|
||||
*/
|
||||
static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Required by the WinPCap library. */
|
||||
static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
|
||||
|
||||
/* An event used to wake up the Win32 thread that sends data through the WinPCAP
|
||||
library. */
|
||||
static void *pvSendEvent = NULL;
|
||||
|
||||
/* _HT_ made the PCAP interface number configurable through the program's
|
||||
parameters in order to test in different machines. */
|
||||
static BaseType_t xConfigNextworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE;
|
||||
|
||||
/* Handles to the Windows threads that handle the PCAP IO. */
|
||||
static HANDLE vWinPcapRecvThreadHandle = NULL;
|
||||
static HANDLE vWinPcapSendThreadHandle = NULL;;
|
||||
|
||||
/* The interface being used by WinPCap. */
|
||||
static pcap_t *pxOpenedInterfaceHandle = NULL;
|
||||
|
||||
/* Circular buffers used by the PCAP Win32 threads. */
|
||||
static StreamBuffer_t *xSendBuffer = NULL;
|
||||
static StreamBuffer_t *xRecvBuffer = NULL;
|
||||
|
||||
/* The MAC address initially set to the constants defined in FreeRTOSConfig.h. */
|
||||
extern uint8_t ucMACAddress[ 6 ];
|
||||
|
||||
/* Logs the number of WinPCAP send failures, for viewing in the debugger only. */
|
||||
static volatile uint32_t ulWinPCAPSendFailures = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceInitialise( void )
|
||||
{
|
||||
BaseType_t xReturn = pdFALSE;
|
||||
pcap_if_t *pxAllNetworkInterfaces;
|
||||
|
||||
/* Query the computer the simulation is being executed on to find the
|
||||
network interfaces it has installed. */
|
||||
pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
|
||||
|
||||
/* Open the network interface. The number of the interface to be opened is
|
||||
set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
|
||||
Calling this function will set the pxOpenedInterfaceHandle variable. If,
|
||||
after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
|
||||
the interface could not be opened. */
|
||||
if( pxAllNetworkInterfaces != NULL )
|
||||
{
|
||||
prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
|
||||
}
|
||||
|
||||
if( pxOpenedInterfaceHandle != NULL )
|
||||
{
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCreateThreadSafeBuffers( void )
|
||||
{
|
||||
/* The buffer used to pass data to be transmitted from a FreeRTOS task to
|
||||
the Win32 thread that sends via the WinPCAP library. */
|
||||
if( xSendBuffer == NULL)
|
||||
{
|
||||
xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 );
|
||||
configASSERT( xSendBuffer );
|
||||
memset( xSendBuffer, '\0', sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) );
|
||||
xSendBuffer->LENGTH = xSEND_BUFFER_SIZE + 1;
|
||||
}
|
||||
|
||||
/* The buffer used to pass received data from the Win32 thread that receives
|
||||
via the WinPCAP library to the FreeRTOS task. */
|
||||
if( xRecvBuffer == NULL)
|
||||
{
|
||||
xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 );
|
||||
configASSERT( xRecvBuffer );
|
||||
memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) );
|
||||
xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend )
|
||||
{
|
||||
size_t xSpace;
|
||||
|
||||
iptraceNETWORK_INTERFACE_TRANSMIT();
|
||||
configASSERT( xIsCallingFromIPTask() == pdTRUE );
|
||||
|
||||
/* Both the length of the data being sent and the actual data being sent
|
||||
are placed in the thread safe buffer used to pass data between the FreeRTOS
|
||||
tasks and the Win32 thread that sends data via the WinPCAP library. Drop
|
||||
the packet if there is insufficient space in the buffer to hold both. */
|
||||
xSpace = uxStreamBufferGetSpace( xSendBuffer );
|
||||
|
||||
if( ( pxNetworkBuffer->xDataLength <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
|
||||
( xSpace >= ( pxNetworkBuffer->xDataLength + sizeof( pxNetworkBuffer->xDataLength ) ) ) )
|
||||
{
|
||||
/* First write in the length of the data, then write in the data
|
||||
itself. */
|
||||
uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) &( pxNetworkBuffer->xDataLength ), sizeof( pxNetworkBuffer->xDataLength ) );
|
||||
uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeRTOS_debug_printf( ( "xNetworkInterfaceOutput: send buffers full to store %lu\n", pxNetworkBuffer->xDataLength ) );
|
||||
}
|
||||
|
||||
/* Kick the Tx task in either case in case it doesn't know the buffer is
|
||||
full. */
|
||||
SetEvent( pvSendEvent );
|
||||
|
||||
/* The buffer has been sent so can be released. */
|
||||
if( bReleaseAfterSend != pdFALSE )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
||||
}
|
||||
|
||||
return pdPASS;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
|
||||
{
|
||||
pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
|
||||
int32_t lInterfaceNumber = 1;
|
||||
char cBuffer[ 512 ];
|
||||
static BaseType_t xInvalidInterfaceDetected = pdFALSE;
|
||||
|
||||
if( xInvalidInterfaceDetected == pdFALSE )
|
||||
{
|
||||
if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
|
||||
{
|
||||
printf( "Could not obtain a list of network interfaces\n%s\n", cErrorBuffer );
|
||||
pxAllNetworkInterfaces = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "\r\n\r\nThe following network interfaces are available:\r\n\r\n" );
|
||||
}
|
||||
|
||||
if( pxAllNetworkInterfaces != NULL )
|
||||
{
|
||||
/* Print out the list of network interfaces. The first in the list
|
||||
is interface '1', not interface '0'. */
|
||||
for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
|
||||
{
|
||||
/* The descriptions of the devices can be full of spaces, clean them
|
||||
a little. printf() can only be used here because the network is not
|
||||
up yet - so no other network tasks will be running. */
|
||||
printf( "Interface %d - %s\n", lInterfaceNumber, prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->name ) );
|
||||
printf( " (%s)\n", prvRemoveSpaces(cBuffer, sizeof( cBuffer ), xInterface->description ? xInterface->description : "No description" ) );
|
||||
printf( "\n" );
|
||||
lInterfaceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
if( lInterfaceNumber == 1 )
|
||||
{
|
||||
/* The interface number was never incremented, so the above for() loop
|
||||
did not execute meaning no interfaces were found. */
|
||||
printf( " \nNo network interfaces were found.\n" );
|
||||
pxAllNetworkInterfaces = NULL;
|
||||
}
|
||||
|
||||
printf( "\r\nThe interface that will be opened is set by " );
|
||||
printf( "\"configNETWORK_INTERFACE_TO_USE\", which\r\nshould be defined in FreeRTOSConfig.h\r\n" );
|
||||
|
||||
if( ( xConfigNextworkInterfaceToUse < 0L ) || ( xConfigNextworkInterfaceToUse >= lInterfaceNumber ) )
|
||||
{
|
||||
printf( "\r\nERROR: configNETWORK_INTERFACE_TO_USE is set to %d, which is an invalid value.\r\n", xConfigNextworkInterfaceToUse );
|
||||
printf( "Please set configNETWORK_INTERFACE_TO_USE to one of the interface numbers listed above,\r\n" );
|
||||
printf( "then re-compile and re-start the application. Only Ethernet (as opposed to WiFi)\r\n" );
|
||||
printf( "interfaces are supported.\r\n\r\nHALTING\r\n\r\n\r\n" );
|
||||
xInvalidInterfaceDetected = pdTRUE;
|
||||
|
||||
if( pxAllNetworkInterfaces != NULL )
|
||||
{
|
||||
/* Free the device list, as no devices are going to be opened. */
|
||||
pcap_freealldevs( pxAllNetworkInterfaces );
|
||||
pxAllNetworkInterfaces = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Attempting to open interface number %d.\n", xConfigNextworkInterfaceToUse );
|
||||
}
|
||||
}
|
||||
|
||||
return pxAllNetworkInterfaces;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static int prvOpenInterface( const char *pucName )
|
||||
{
|
||||
static char pucInterfaceName[ 256 ];
|
||||
|
||||
if( pucName != NULL )
|
||||
{
|
||||
strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) );
|
||||
}
|
||||
|
||||
pxOpenedInterfaceHandle = pcap_open( pucInterfaceName, /* The name of the selected interface. */
|
||||
ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
|
||||
PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscuous mode as the MAC and
|
||||
IP address is going to be "simulated", and
|
||||
not be the real MAC and IP address. This allows
|
||||
traffic to the simulated IP address to be routed
|
||||
to uIP, and traffic to the real IP address to be
|
||||
routed to the Windows TCP/IP stack. */
|
||||
100,
|
||||
NULL, /* No authentication is required as this is
|
||||
not a remote capture session. */
|
||||
cErrorBuffer
|
||||
);
|
||||
|
||||
if ( pxOpenedInterfaceHandle == NULL )
|
||||
{
|
||||
printf( "\n%s is not supported by WinPcap and cannot be opened\n", pucInterfaceName );
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Configure the capture filter to allow blocking reads, and to filter
|
||||
out packets that are not of interest to this demo. */
|
||||
prvConfigureCaptureBehaviour();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
|
||||
{
|
||||
pcap_if_t *xInterface;
|
||||
int32_t x;
|
||||
|
||||
/* Walk the list of devices until the selected device is located. */
|
||||
xInterface = pxAllNetworkInterfaces;
|
||||
if (0 == xConfigNextworkInterfaceToUse) {
|
||||
while (NULL != xInterface) {
|
||||
xInterface = xInterface->next;
|
||||
if (0 == prvOpenInterface(xInterface->name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (x = 1L; x < xConfigNextworkInterfaceToUse; x++)
|
||||
{
|
||||
xInterface = xInterface->next;
|
||||
}
|
||||
/* Open the selected interface. */
|
||||
(void) prvOpenInterface(xInterface->name);
|
||||
}
|
||||
|
||||
/* The device list is no longer required. */
|
||||
pcap_freealldevs( pxAllNetworkInterfaces );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvConfigureCaptureBehaviour( void )
|
||||
{
|
||||
struct bpf_program xFilterCode;
|
||||
uint32_t ulNetMask;
|
||||
|
||||
/* Set up a filter so only the packets of interest are passed to the IP
|
||||
stack. cErrorBuffer is used for convenience to create the string. Don't
|
||||
confuse this with an error message. */
|
||||
sprintf( cErrorBuffer, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x",
|
||||
ucMACAddress[0], ucMACAddress[1], ucMACAddress[2], ucMACAddress[3], ucMACAddress[4], ucMACAddress[5] );
|
||||
|
||||
ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
|
||||
|
||||
if( pcap_compile( pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
|
||||
{
|
||||
printf( "\nThe packet filter string is invalid\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
|
||||
{
|
||||
printf( "\nAn error occurred setting the packet filter.\n" );
|
||||
}
|
||||
|
||||
pcap_freecode( &xFilterCode );
|
||||
}
|
||||
|
||||
/* Create the buffers used to pass packets between the FreeRTOS simulator
|
||||
and the Win32 threads that are handling WinPCAP. */
|
||||
prvCreateThreadSafeBuffers();
|
||||
|
||||
if( pvSendEvent == NULL )
|
||||
{
|
||||
/* Create event used to signal the Win32 WinPCAP Tx thread. */
|
||||
pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
|
||||
|
||||
/* Create the Win32 thread that handles WinPCAP Rx. */
|
||||
vWinPcapRecvThreadHandle = CreateThread(
|
||||
NULL, /* Pointer to thread security attributes. */
|
||||
0, /* Initial thread stack size, in bytes. */
|
||||
prvWinPcapRecvThread, /* Pointer to thread function. */
|
||||
NULL, /* Argument for new thread. */
|
||||
0, /* Creation flags. */
|
||||
NULL );
|
||||
|
||||
/* Use the cores that are not used by the FreeRTOS tasks. */
|
||||
SetThreadAffinityMask( vWinPcapRecvThreadHandle, ~0x01u );
|
||||
|
||||
/* Create the Win32 thread that handlers WinPCAP Tx. */
|
||||
vWinPcapSendThreadHandle = CreateThread(
|
||||
NULL, /* Pointer to thread security attributes. */
|
||||
0, /* initial thread stack size, in bytes. */
|
||||
prvWinPcapSendThread, /* Pointer to thread function. */
|
||||
NULL, /* Argument for new thread. */
|
||||
0, /* Creation flags. */
|
||||
NULL );
|
||||
|
||||
/* Use the cores that are not used by the FreeRTOS tasks. */
|
||||
SetThreadAffinityMask( vWinPcapSendThreadHandle, ~0x01u );
|
||||
|
||||
/* Create a task that simulates an interrupt in a real system. This will
|
||||
block waiting for packets, then send a message to the IP task when data
|
||||
is available. */
|
||||
xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* WinPCAP function. */
|
||||
void pcap_callback( u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data )
|
||||
{
|
||||
(void)user;
|
||||
|
||||
/* THIS IS CALLED FROM A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS
|
||||
OR TO PRINT OUT MESSAGES HERE. */
|
||||
|
||||
/* Pass data to the FreeRTOS simulator on a thread safe circular buffer. */
|
||||
if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
|
||||
( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) )
|
||||
{
|
||||
uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_header, sizeof( *pkt_header ) );
|
||||
uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_data, ( size_t ) pkt_header->caplen );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
DWORD WINAPI prvWinPcapRecvThread ( void *pvParam )
|
||||
{
|
||||
( void ) pvParam;
|
||||
|
||||
/* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
|
||||
OUT MESSAGES HERE. */
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
pcap_dispatch( pxOpenedInterfaceHandle, 1, pcap_callback, ( u_char * ) "mydata" );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
DWORD WINAPI prvWinPcapSendThread( void *pvParam )
|
||||
{
|
||||
size_t xLength;
|
||||
uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
|
||||
static char cErrorMessage[ 1024 ];
|
||||
const DWORD xMaxMSToWait = 1000;
|
||||
|
||||
/* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
|
||||
OUT MESSAGES HERE. */
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) pvParam;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait until notified of something to send. */
|
||||
WaitForSingleObject( pvSendEvent, xMaxMSToWait );
|
||||
|
||||
/* Is there more than the length value stored in the circular buffer
|
||||
used to pass data from the FreeRTOS simulator into this Win32 thread? */
|
||||
while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) )
|
||||
{
|
||||
uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE );
|
||||
uxStreamBufferGet( xSendBuffer, 0, ( uint8_t* ) ucBuffer, xLength, pdFALSE );
|
||||
if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 )
|
||||
{
|
||||
ulWinPCAPSendFailures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInterruptSimulatorTask( void *pvParameters )
|
||||
{
|
||||
struct pcap_pkthdr xHeader;
|
||||
static struct pcap_pkthdr *pxHeader;
|
||||
const uint8_t *pucPacketData;
|
||||
uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
|
||||
NetworkBufferDescriptor_t *pxNetworkBuffer;
|
||||
IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
|
||||
eFrameProcessingResult_t eResult;
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Does the circular buffer used to pass data from the Win32 thread that
|
||||
handles WinPCAP Rx into the FreeRTOS simulator contain another packet? */
|
||||
if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) )
|
||||
{
|
||||
/* Get the next packet. */
|
||||
uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)&xHeader, sizeof( xHeader ), pdFALSE );
|
||||
uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE );
|
||||
pucPacketData = ucRecvBuffer;
|
||||
pxHeader = &xHeader;
|
||||
|
||||
iptraceNETWORK_INTERFACE_RECEIVE();
|
||||
|
||||
/* Check for minimal size. */
|
||||
if( pxHeader->len >= sizeof( EthernetHeader_t ) )
|
||||
{
|
||||
eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
|
||||
}
|
||||
else
|
||||
{
|
||||
eResult = eReleaseBuffer;
|
||||
}
|
||||
|
||||
if( eResult == eProcessBuffer )
|
||||
{
|
||||
/* Will the data fit into the frame buffer? */
|
||||
if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
|
||||
{
|
||||
/* Obtain a buffer into which the data can be placed. This
|
||||
is only an interrupt simulator, not a real interrupt, so it
|
||||
is ok to call the task level function here, but note that
|
||||
some buffer implementations cannot be called from a real
|
||||
interrupt. */
|
||||
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 );
|
||||
|
||||
if( pxNetworkBuffer != NULL )
|
||||
{
|
||||
memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
|
||||
pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
|
||||
|
||||
#if( niDISRUPT_PACKETS == 1 )
|
||||
{
|
||||
pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData );
|
||||
}
|
||||
#endif /* niDISRUPT_PACKETS */
|
||||
|
||||
if( pxNetworkBuffer != NULL )
|
||||
{
|
||||
xRxEvent.pvData = ( void * ) pxNetworkBuffer;
|
||||
|
||||
/* Data was received and stored. Send a message to
|
||||
the IP task to let it know. */
|
||||
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
|
||||
{
|
||||
/* The buffer could not be sent to the stack so
|
||||
must be released again. This is only an
|
||||
interrupt simulator, not a real interrupt, so it
|
||||
is ok to use the task level function here, but
|
||||
note no all buffer implementations will allow
|
||||
this function to be executed from a real
|
||||
interrupt. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The packet was already released or stored inside
|
||||
vRxFaultInjection(). Don't release it here. */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Log that a packet was dropped because it would have
|
||||
overflowed the buffer, but there may be more buffers to
|
||||
process. */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is no real way of simulating an interrupt. Make sure
|
||||
other tasks can run. */
|
||||
vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage )
|
||||
{
|
||||
char *pcTarget = pcBuffer;
|
||||
|
||||
/* Utility function used to formap messages being printed only. */
|
||||
while( ( *pcMessage != 0 ) && ( pcTarget < ( pcBuffer + aBuflen - 1 ) ) )
|
||||
{
|
||||
*( pcTarget++ ) = *pcMessage;
|
||||
|
||||
if( isspace( *pcMessage ) != pdFALSE )
|
||||
{
|
||||
while( isspace( *pcMessage ) != pdFALSE )
|
||||
{
|
||||
pcMessage++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pcMessage++;
|
||||
}
|
||||
}
|
||||
|
||||
*pcTarget = '\0';
|
||||
|
||||
return pcBuffer;
|
||||
}
|
||||
|
||||
+432
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
FreeRTOS+TCP V2.0.11
|
||||
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
http://aws.amazon.com/freertos
|
||||
http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
/* 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 "FreeRTOS_IP_Private.h"
|
||||
#include "FreeRTOS_ARP.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
/* Xilinx library files. */
|
||||
#include <xemacps.h>
|
||||
#include "Zynq/x_topology.h"
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
#include "Zynq/x_emacpsif_hw.h"
|
||||
|
||||
/* Provided memory configured as uncached. */
|
||||
#include "uncached_memory.h"
|
||||
|
||||
#ifndef niEMAC_HANDLER_TASK_PRIORITY
|
||||
#define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
|
||||
#endif
|
||||
|
||||
#define niBMSR_LINK_STATUS 0x0004UL
|
||||
#define niBMSR_AN_COMPLETE 0x0020u /* Auto-Negotiation process completed */
|
||||
|
||||
#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
|
||||
|
||||
/* The size of each buffer when BufferAllocation_1 is used:
|
||||
http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */
|
||||
#define niBUFFER_1_PACKET_SIZE 1536
|
||||
|
||||
/* Naming and numbering of PHY registers. */
|
||||
#define PHY_REG_01_BMSR 0x01 /* Basic mode status register */
|
||||
|
||||
#ifndef iptraceEMAC_TASK_STARTING
|
||||
#define iptraceEMAC_TASK_STARTING() do { } while( 0 )
|
||||
#endif
|
||||
|
||||
/* Default the size of the stack used by the EMAC deferred handler task to twice
|
||||
the size of the stack used by the idle task - but allow this to be overridden in
|
||||
FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
|
||||
#ifndef configEMAC_TASK_STACK_SIZE
|
||||
#define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Look for the link to be up every few milliseconds until either xMaxTime time
|
||||
* has passed or a link is found.
|
||||
*/
|
||||
static BaseType_t prvGMACWaitLS( TickType_t xMaxTime );
|
||||
|
||||
/*
|
||||
* A deferred interrupt handler for all MAC/DMA interrupt sources.
|
||||
*/
|
||||
static void prvEMACHandlerTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* EMAC data/descriptions. */
|
||||
static xemacpsif_s xEMACpsif;
|
||||
struct xtopology_t xXTopology =
|
||||
{
|
||||
.emac_baseaddr = XPAR_PS7_ETHERNET_0_BASEADDR,
|
||||
.emac_type = xemac_type_emacps,
|
||||
.intc_baseaddr = 0x0,
|
||||
.intc_emac_intr = 0x0,
|
||||
.scugic_baseaddr = XPAR_PS7_SCUGIC_0_BASEADDR,
|
||||
.scugic_emac_intr = 0x36,
|
||||
};
|
||||
|
||||
XEmacPs_Config mac_config =
|
||||
{
|
||||
.DeviceId = XPAR_PS7_ETHERNET_0_DEVICE_ID, /**< Unique ID of device */
|
||||
.BaseAddress = XPAR_PS7_ETHERNET_0_BASEADDR /**< Physical base address of IPIF registers */
|
||||
};
|
||||
|
||||
extern int phy_detected;
|
||||
|
||||
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
|
||||
static uint32_t ulPHYLinkStatus = 0;
|
||||
|
||||
#if( ipconfigUSE_LLMNR == 1 )
|
||||
static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
|
||||
#endif
|
||||
|
||||
/* ucMACAddress as it appears in main.c */
|
||||
extern const uint8_t ucMACAddress[ 6 ];
|
||||
|
||||
/* Holds the handle of the task used as a deferred interrupt processor. The
|
||||
handle is used so direct notifications can be sent to the task for all EMAC/DMA
|
||||
related interrupts. */
|
||||
TaskHandle_t xEMACTaskHandle = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceInitialise( void )
|
||||
{
|
||||
uint32_t ulLinkSpeed, ulDMAReg;
|
||||
BaseType_t xStatus, xLinkStatus;
|
||||
XEmacPs *pxEMAC_PS;
|
||||
const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pdMS_TO_TICKS( 1000UL );
|
||||
|
||||
/* Guard against the init function being called more than once. */
|
||||
if( xEMACTaskHandle == NULL )
|
||||
{
|
||||
pxEMAC_PS = &( xEMACpsif.emacps );
|
||||
memset( &xEMACpsif, '\0', sizeof( xEMACpsif ) );
|
||||
|
||||
xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &mac_config, mac_config.BaseAddress);
|
||||
if( xStatus != XST_SUCCESS )
|
||||
{
|
||||
FreeRTOS_printf( ( "xEMACInit: EmacPs Configuration Failed....\n" ) );
|
||||
}
|
||||
|
||||
/* Initialize the mac and set the MAC address. */
|
||||
XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) ucMACAddress, 1 );
|
||||
|
||||
#if( ipconfigUSE_LLMNR == 1 )
|
||||
{
|
||||
/* Also add LLMNR multicast MAC address. */
|
||||
XEmacPs_SetMacAddress( pxEMAC_PS, ( void * )xLLMNR_MACAddress, 2 );
|
||||
}
|
||||
#endif /* ipconfigUSE_LLMNR == 1 */
|
||||
|
||||
XEmacPs_SetMdioDivisor( pxEMAC_PS, MDC_DIV_224 );
|
||||
ulLinkSpeed = Phy_Setup( pxEMAC_PS );
|
||||
XEmacPs_SetOperatingSpeed( pxEMAC_PS, ulLinkSpeed);
|
||||
|
||||
/* Setting the operating speed of the MAC needs a delay. */
|
||||
vTaskDelay( pdMS_TO_TICKS( 25UL ) );
|
||||
|
||||
ulDMAReg = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET);
|
||||
|
||||
/* DISC_WHEN_NO_AHB: when set, the GEM DMA will automatically discard receive
|
||||
packets from the receiver packet buffer memory when no AHB resource is available. */
|
||||
XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
|
||||
ulDMAReg | XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK);
|
||||
|
||||
setup_isr( &xEMACpsif );
|
||||
init_dma( &xEMACpsif );
|
||||
start_emacps( &xEMACpsif );
|
||||
|
||||
prvGMACWaitLS( xWaitLinkDelay );
|
||||
|
||||
/* The deferred interrupt handler task is created at the highest
|
||||
possible priority to ensure the interrupt handler can return directly
|
||||
to it. The task's handle is stored in xEMACTaskHandle so interrupts can
|
||||
notify the task when there is something to process. */
|
||||
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Initialisation was already performed, just wait for the link. */
|
||||
prvGMACWaitLS( xWaitRelinkDelay );
|
||||
}
|
||||
|
||||
/* Only return pdTRUE when the Link Status of the PHY is high, otherwise the
|
||||
DHCP process and all other communication will fail. */
|
||||
xLinkStatus = xGetPhyLinkStatus();
|
||||
|
||||
return ( xLinkStatus != pdFALSE );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, BaseType_t bReleaseAfterSend )
|
||||
{
|
||||
if( xCheckLoopback( pxBuffer, bReleaseAfterSend ) != 0 )
|
||||
{
|
||||
/* The packet has been sent back to the IP-task.
|
||||
The IP-task will further handle it.
|
||||
Do not release the descriptor. */
|
||||
return pdTRUE;
|
||||
}
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
|
||||
{
|
||||
ProtocolPacket_t *pxPacket;
|
||||
|
||||
/* If the peripheral must calculate the checksum, it wants
|
||||
the protocol checksum to have a value of zero. */
|
||||
pxPacket = ( ProtocolPacket_t * ) ( pxBuffer->pucEthernetBuffer );
|
||||
if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )
|
||||
{
|
||||
IPHeader_t *pxIPHeader = &( pxPacket->xUDPPacket.xIPHeader );
|
||||
|
||||
pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;
|
||||
pxIPHeader->usHeaderChecksum = 0u;
|
||||
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
|
||||
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
|
||||
|
||||
usGenerateProtocolChecksum( (uint8_t*)&( pxPacket->xUDPPacket ), pxBuffer->xDataLength, pdTRUE );
|
||||
}
|
||||
}
|
||||
#endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
iptraceNETWORK_INTERFACE_TRANSMIT();
|
||||
emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend );
|
||||
}
|
||||
else if( bReleaseAfterSend != pdFALSE )
|
||||
{
|
||||
/* No link. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
||||
}
|
||||
|
||||
return pdTRUE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static inline unsigned long ulReadMDIO( unsigned ulRegister )
|
||||
{
|
||||
uint16_t usValue;
|
||||
|
||||
XEmacPs_PhyRead( &( xEMACpsif.emacps ), phy_detected, ulRegister, &usValue );
|
||||
return usValue;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t prvGMACWaitLS( TickType_t xMaxTime )
|
||||
{
|
||||
TickType_t xStartTime, xEndTime;
|
||||
const TickType_t xShortDelay = pdMS_TO_TICKS( 20UL );
|
||||
BaseType_t xReturn;
|
||||
|
||||
xStartTime = xTaskGetTickCount();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
xEndTime = xTaskGetTickCount();
|
||||
|
||||
if( xEndTime - xStartTime > xMaxTime )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
break;
|
||||
}
|
||||
ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
|
||||
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay( xShortDelay );
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
|
||||
{
|
||||
static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
|
||||
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;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xGetPhyLinkStatus( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) == 0 )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEMACHandlerTask( void *pvParameters )
|
||||
{
|
||||
TimeOut_t xPhyTime;
|
||||
TickType_t xPhyRemTime;
|
||||
UBaseType_t uxCurrentCount;
|
||||
BaseType_t xResult = 0;
|
||||
uint32_t xStatus;
|
||||
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
|
||||
UBaseType_t uxLastMinBufferCount = 0;
|
||||
UBaseType_t uxCurrentBufferCount = 0;
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* A possibility to set some additional task properties like calling
|
||||
portTASK_USES_FLOATING_POINT() */
|
||||
iptraceEMAC_TASK_STARTING();
|
||||
|
||||
vTaskSetTimeOutState( &xPhyTime );
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers();
|
||||
if( uxLastMinBufferCount != uxCurrentBufferCount )
|
||||
{
|
||||
/* The logging produced below may be helpful
|
||||
while tuning +TCP: see how many buffers are in use. */
|
||||
uxLastMinBufferCount = uxCurrentBufferCount;
|
||||
FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
|
||||
uxGetNumberOfFreeNetworkBuffers(), uxCurrentBufferCount ) );
|
||||
}
|
||||
|
||||
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
|
||||
{
|
||||
static UBaseType_t uxLastMinQueueSpace = 0;
|
||||
|
||||
uxCurrentCount = uxGetMinimumIPQueueSpace();
|
||||
if( uxLastMinQueueSpace != uxCurrentCount )
|
||||
{
|
||||
/* The logging produced below may be helpful
|
||||
while tuning +TCP: see how many buffers are in use. */
|
||||
uxLastMinQueueSpace = uxCurrentCount;
|
||||
FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
|
||||
}
|
||||
}
|
||||
#endif /* ipconfigCHECK_IP_QUEUE_SPACE */
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_ALL_EVENT ) == 0 )
|
||||
{
|
||||
/* No events to process now, wait for the next. */
|
||||
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
|
||||
}
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_RX_EVENT ) != 0 )
|
||||
{
|
||||
xEMACpsif.isr_events &= ~EMAC_IF_RX_EVENT;
|
||||
xResult = emacps_check_rx( &xEMACpsif );
|
||||
}
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_TX_EVENT ) != 0 )
|
||||
{
|
||||
xEMACpsif.isr_events &= ~EMAC_IF_TX_EVENT;
|
||||
emacps_check_tx( &xEMACpsif );
|
||||
}
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_ERR_EVENT ) != 0 )
|
||||
{
|
||||
xEMACpsif.isr_events &= ~EMAC_IF_ERR_EVENT;
|
||||
emacps_check_errors( &xEMACpsif );
|
||||
}
|
||||
if( xResult > 0 )
|
||||
{
|
||||
/* A packet was received. No need to check for the PHY status now,
|
||||
but set a timer to check it later on. */
|
||||
vTaskSetTimeOutState( &xPhyTime );
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
|
||||
xResult = 0;
|
||||
/* Indicate that the Link Status is high, so that
|
||||
xNetworkInterfaceOutput() can send packets. */
|
||||
ulPHYLinkStatus |= niBMSR_LINK_STATUS;
|
||||
}
|
||||
else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
|
||||
{
|
||||
xStatus = ulReadMDIO( PHY_REG_01_BMSR );
|
||||
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != ( xStatus & niBMSR_LINK_STATUS ) )
|
||||
{
|
||||
ulPHYLinkStatus = xStatus;
|
||||
FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) );
|
||||
}
|
||||
|
||||
vTaskSetTimeOutState( &xPhyTime );
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
|
||||
}
|
||||
else
|
||||
{
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
NetworkInterface for Xilinx' Zynq
|
||||
|
||||
Please include the following source files:
|
||||
|
||||
$(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/NetworkInterface.c
|
||||
$(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
|
||||
$(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c
|
||||
$(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_hw.c
|
||||
|
||||
And include the following source files from the Xilinx library:
|
||||
|
||||
$(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps.c
|
||||
$(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_control.c
|
||||
$(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_g.c
|
||||
$(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_intr.c
|
||||
|
||||
E.g. ps7_cortexa9_0/libsrc/emacps_v2_0/src/xemacps_intr.c
|
||||
|
||||
The following source files are NOT used for the FreeRTOS+TCP interface:
|
||||
|
||||
$(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_bdring.c
|
||||
$(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_hw.c
|
||||
$(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_sinit.c
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
|
||||
#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 "uncached_memory.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.
|
||||
*/
|
||||
/* FIXME claudio rossi. Modified to prevent data abort exception (misaligned access)
|
||||
* when application is compiled with -O1 or more optimization flag.
|
||||
*/
|
||||
/* Xil_SetTlbAttributes( ( uint32_t )pucStartOfMemory, 0xc02 ); // addr, attr */
|
||||
Xil_SetTlbAttributes( ( uint32_t )pucStartOfMemory, 0x1c02 ); // 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 );
|
||||
}
|
||||
}
|
||||
+23
@@ -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 */
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Xilinx, Inc.
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
|
||||
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
|
||||
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
|
||||
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
|
||||
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
|
||||
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
|
||||
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
|
||||
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NETIF_XEMACPSIF_H__
|
||||
#define __NETIF_XEMACPSIF_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "xstatus.h"
|
||||
#include "sleep.h"
|
||||
#include "xparameters.h"
|
||||
#include "xparameters_ps.h" /* defines XPAR values */
|
||||
#include "xil_types.h"
|
||||
#include "xil_assert.h"
|
||||
#include "xil_io.h"
|
||||
#include "xil_exception.h"
|
||||
#include "xpseudo_asm.h"
|
||||
#include "xil_cache.h"
|
||||
#include "xil_printf.h"
|
||||
#include "xuartps.h"
|
||||
#include "xscugic.h"
|
||||
#include "xemacps.h" /* defines XEmacPs API */
|
||||
|
||||
//#include "netif/xpqueue.h"
|
||||
//#include "xlwipconfig.h"
|
||||
|
||||
void xemacpsif_setmac(uint32_t index, uint8_t *addr);
|
||||
uint8_t* xemacpsif_getmac(uint32_t index);
|
||||
//int xemacpsif_init(struct netif *netif);
|
||||
//int xemacpsif_input(struct netif *netif);
|
||||
#ifdef NOTNOW_BHILL
|
||||
unsigned get_IEEE_phy_speed(XLlTemac *xlltemacp);
|
||||
#endif
|
||||
|
||||
/* xaxiemacif_hw.c */
|
||||
void xemacps_error_handler(XEmacPs * Temac);
|
||||
|
||||
struct xBD_TYPE {
|
||||
uint32_t address;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Missing declaration in 'src/xemacps_hw.h' :
|
||||
* When set, the GEM DMA will automatically
|
||||
* discard receive packets from the receiver packet
|
||||
* buffer memory when no AHB resource is
|
||||
* available.
|
||||
* When low, then received packets will remain to be
|
||||
* stored in the SRAM based packet buffer until
|
||||
* AHB buffer resource next becomes available.
|
||||
*/
|
||||
#define XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK 0x01000000
|
||||
|
||||
#define EMAC_IF_RX_EVENT 1
|
||||
#define EMAC_IF_TX_EVENT 2
|
||||
#define EMAC_IF_ERR_EVENT 4
|
||||
#define EMAC_IF_ALL_EVENT 7
|
||||
|
||||
/* structure within each netif, encapsulating all information required for
|
||||
* using a particular temac instance
|
||||
*/
|
||||
typedef struct {
|
||||
XEmacPs emacps;
|
||||
|
||||
/* pointers to memory holding buffer descriptors (used only with SDMA) */
|
||||
struct xBD_TYPE *rxSegments;
|
||||
struct xBD_TYPE *txSegments;
|
||||
|
||||
unsigned char *tx_space;
|
||||
unsigned uTxUnitSize;
|
||||
|
||||
char *remain_mem;
|
||||
unsigned remain_siz;
|
||||
|
||||
volatile int rxHead, rxTail;
|
||||
volatile int txHead, txTail;
|
||||
|
||||
volatile int txBusy;
|
||||
|
||||
volatile uint32_t isr_events;
|
||||
|
||||
unsigned int last_rx_frms_cntr;
|
||||
|
||||
} xemacpsif_s;
|
||||
|
||||
//extern xemacpsif_s xemacpsif;
|
||||
|
||||
int is_tx_space_available(xemacpsif_s *emac);
|
||||
|
||||
/* xaxiemacif_dma.c */
|
||||
|
||||
struct xNETWORK_BUFFER;
|
||||
|
||||
int emacps_check_rx( xemacpsif_s *xemacpsif );
|
||||
void emacps_check_tx( xemacpsif_s *xemacpsif );
|
||||
int emacps_check_errors( xemacpsif_s *xemacps );
|
||||
void emacps_set_rx_buffers( xemacpsif_s *xemacpsif, u32 ulCount );
|
||||
|
||||
extern XStatus emacps_send_message(xemacpsif_s *xemacpsif, struct xNETWORK_BUFFER *pxBuffer, int iReleaseAfterSend );
|
||||
extern unsigned Phy_Setup( XEmacPs *xemacpsp );
|
||||
extern void setup_isr( xemacpsif_s *xemacpsif );
|
||||
extern XStatus init_dma( xemacpsif_s *xemacpsif );
|
||||
extern void start_emacps( xemacpsif_s *xemacpsif );
|
||||
|
||||
void EmacEnableIntr(void);
|
||||
void EmacDisableIntr(void);
|
||||
|
||||
XStatus init_axi_dma(xemacpsif_s *xemacpsif);
|
||||
void process_sent_bds( xemacpsif_s *xemacpsif );
|
||||
|
||||
void emacps_send_handler(void *arg);
|
||||
void emacps_recv_handler(void *arg);
|
||||
void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord);
|
||||
void HandleTxErrors(xemacpsif_s *xemacpsif);
|
||||
XEmacPs_Config *xemacps_lookup_config(unsigned mac_base);
|
||||
|
||||
void clean_dma_txdescs(xemacpsif_s *xemacpsif);
|
||||
void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NETIF_XAXIEMACIF_H__ */
|
||||
+663
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
FreeRTOS+TCP V2.0.11
|
||||
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
http://aws.amazon.com/freertos
|
||||
http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
#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 "uncached_memory.h"
|
||||
|
||||
/* Two defines used to set or clear the EMAC interrupt */
|
||||
#define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
|
||||
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
|
||||
|
||||
|
||||
|
||||
#if( ipconfigPACKET_FILLER_SIZE != 2 )
|
||||
#error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
|
||||
#endif
|
||||
#define TX_OFFSET ipconfigPACKET_FILLER_SIZE
|
||||
|
||||
/* Defined in NetworkInterface.c */
|
||||
extern TaskHandle_t xEMACTaskHandle;
|
||||
|
||||
/*
|
||||
pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
|
||||
The actual TX buffers are located in uncached RAM.
|
||||
*/
|
||||
static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
|
||||
|
||||
/*
|
||||
pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
|
||||
Once a message has been received by the EMAC, the descriptor can be passed
|
||||
immediately to the IP-task.
|
||||
*/
|
||||
static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
|
||||
|
||||
/*
|
||||
The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
|
||||
./portable/NetworkInterface/Zynq/NetworkInterface.c
|
||||
*/
|
||||
extern struct xtopology_t xXTopology;
|
||||
|
||||
static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
|
||||
|
||||
/*
|
||||
The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
|
||||
In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
|
||||
"head" is the next index to be written, used.
|
||||
"tail" is the next index to be read, freed.
|
||||
*/
|
||||
|
||||
int is_tx_space_available( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
size_t uxCount;
|
||||
|
||||
if( xTXDescriptorSemaphore != NULL )
|
||||
{
|
||||
uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
|
||||
}
|
||||
else
|
||||
{
|
||||
uxCount = ( UBaseType_t ) 0u;
|
||||
}
|
||||
|
||||
return uxCount;
|
||||
}
|
||||
|
||||
void emacps_check_tx( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
int tail = xemacpsif->txTail;
|
||||
int head = xemacpsif->txHead;
|
||||
size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
|
||||
|
||||
/* uxCount is the number of TX descriptors that are in use by the DMA. */
|
||||
/* When done, "TXBUF_USED" will be set. */
|
||||
|
||||
while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
|
||||
{
|
||||
if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
#warning ipconfigZERO_COPY_TX_DRIVER is defined
|
||||
{
|
||||
void *pvBuffer = pxDMA_tx_buffers[ tail ];
|
||||
NetworkBufferDescriptor_t *pxBuffer;
|
||||
|
||||
if( pvBuffer != NULL )
|
||||
{
|
||||
pxDMA_tx_buffers[ tail ] = NULL;
|
||||
pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
|
||||
if( pxBuffer != NULL )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Clear all but the "used" and "wrap" bits. */
|
||||
if( tail < ipconfigNIC_N_TX_DESC - 1 )
|
||||
{
|
||||
xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
|
||||
}
|
||||
uxCount--;
|
||||
/* Tell the counting semaphore that one more TX descriptor is available. */
|
||||
xSemaphoreGive( xTXDescriptorSemaphore );
|
||||
if( ++tail == ipconfigNIC_N_TX_DESC )
|
||||
{
|
||||
tail = 0;
|
||||
}
|
||||
xemacpsif->txTail = tail;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void emacps_send_handler(void *arg)
|
||||
{
|
||||
xemacpsif_s *xemacpsif;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
|
||||
/* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
|
||||
"isr_events". The task in NetworkInterface will wake-up and do the necessary work.
|
||||
*/
|
||||
xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
|
||||
xemacpsif->txBusy = pdFALSE;
|
||||
|
||||
if( xEMACTaskHandle != NULL )
|
||||
{
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
static BaseType_t xValidLength( BaseType_t xLength )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )
|
||||
{
|
||||
int head = xemacpsif->txHead;
|
||||
//int tail = xemacpsif->txTail;
|
||||
int iHasSent = 0;
|
||||
uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
|
||||
TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
|
||||
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
/* This driver wants to own all network buffers which are to be transmitted. */
|
||||
configASSERT( iReleaseAfterSend != pdFALSE );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open a do {} while ( 0 ) loop to be able to call break. */
|
||||
do
|
||||
{
|
||||
uint32_t ulFlags = 0;
|
||||
|
||||
if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( xTXDescriptorSemaphore == NULL )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
|
||||
{
|
||||
FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
|
||||
break;
|
||||
}
|
||||
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
/* Pass the pointer (and its ownership) directly to DMA. */
|
||||
pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
|
||||
if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
|
||||
}
|
||||
/* Buffer has been transferred, do not release it. */
|
||||
iReleaseAfterSend = pdFALSE;
|
||||
#else
|
||||
if( pxDMA_tx_buffers[ head ] == NULL )
|
||||
{
|
||||
FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );
|
||||
break;
|
||||
}
|
||||
/* Copy the message to unbuffered space in RAM. */
|
||||
memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
|
||||
#endif
|
||||
/* Packets will be sent one-by-one, so for each packet
|
||||
the TXBUF_LAST bit will be set. */
|
||||
ulFlags |= XEMACPS_TXBUF_LAST_MASK;
|
||||
ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
|
||||
if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
|
||||
{
|
||||
ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
|
||||
}
|
||||
|
||||
/* Copy the address of the buffer and set the flags. */
|
||||
xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
|
||||
xemacpsif->txSegments[ head ].flags = ulFlags;
|
||||
|
||||
iHasSent = pdTRUE;
|
||||
if( ++head == ipconfigNIC_N_TX_DESC )
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
/* Update the TX-head index. These variable are declared volatile so they will be
|
||||
accessed as little as possible. */
|
||||
xemacpsif->txHead = head;
|
||||
} while( pdFALSE );
|
||||
|
||||
if( iReleaseAfterSend != pdFALSE )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
||||
pxBuffer = NULL;
|
||||
}
|
||||
|
||||
/* Data Synchronization Barrier */
|
||||
dsb();
|
||||
|
||||
if( iHasSent != pdFALSE )
|
||||
{
|
||||
/* Make STARTTX high */
|
||||
uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
|
||||
/* Start transmit */
|
||||
xemacpsif->txBusy = pdTRUE;
|
||||
XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
|
||||
}
|
||||
dsb();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void emacps_recv_handler(void *arg)
|
||||
{
|
||||
xemacpsif_s *xemacpsif;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
|
||||
|
||||
if( xEMACTaskHandle != NULL )
|
||||
{
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
static void passEthMessages( NetworkBufferDescriptor_t *ethMsg )
|
||||
{
|
||||
IPStackEvent_t xRxEvent;
|
||||
|
||||
xRxEvent.eEventType = eNetworkRxEvent;
|
||||
xRxEvent.pvData = ( void * ) ethMsg;
|
||||
|
||||
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
|
||||
{
|
||||
/* The buffer could not be sent to the stack so must be released again.
|
||||
This is a deferred handler taskr, not a real interrupt, so it is ok to
|
||||
use the task level function here. */
|
||||
do
|
||||
{
|
||||
NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;
|
||||
vReleaseNetworkBufferAndDescriptor( ethMsg );
|
||||
ethMsg = xNext;
|
||||
} while( ethMsg != NULL );
|
||||
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );
|
||||
}
|
||||
}
|
||||
|
||||
TickType_t ack_reception_delay = 10;
|
||||
|
||||
int emacps_check_rx( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
|
||||
int rx_bytes;
|
||||
volatile int msgCount = 0;
|
||||
int head = xemacpsif->rxHead;
|
||||
BaseType_t bHasDataPacket = pdFALSE;
|
||||
NetworkBufferDescriptor_t *ethMsg = NULL;
|
||||
NetworkBufferDescriptor_t *ethLast = NULL;
|
||||
|
||||
/* There seems to be an issue (SI# 692601), see comments below. */
|
||||
resetrx_on_no_rxdata(xemacpsif);
|
||||
|
||||
{
|
||||
static int maxcount = 0;
|
||||
int count = 0;
|
||||
for( ;; )
|
||||
{
|
||||
if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
|
||||
( pxDMA_rx_buffers[ head ] == NULL ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
if( ++head == ipconfigNIC_N_RX_DESC )
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
if( head == xemacpsif->rxHead )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (maxcount < count) {
|
||||
maxcount = count;
|
||||
FreeRTOS_printf( ( "emacps_check_rx: %d packets\n", maxcount ) );
|
||||
}
|
||||
head = xemacpsif->rxHead;
|
||||
}
|
||||
|
||||
/* This FreeRTOS+TCP driver shall be compiled with the option
|
||||
"ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
|
||||
chain of RX messages within one message to the IP-task. */
|
||||
for( ;; )
|
||||
{
|
||||
if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
|
||||
( pxDMA_rx_buffers[ head ] == NULL ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
|
||||
if( pxNewBuffer == NULL )
|
||||
{
|
||||
/* A packet has been received, but there is no replacement for this Network Buffer.
|
||||
The packet will be dropped, and it Network Buffer will stay in place. */
|
||||
FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );
|
||||
pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
|
||||
|
||||
/* Just avoiding to use or refer to the same buffer again */
|
||||
pxDMA_rx_buffers[ head ] = pxNewBuffer;
|
||||
|
||||
/*
|
||||
* Adjust the buffer size to the actual number of bytes received.
|
||||
*/
|
||||
rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
|
||||
|
||||
pxBuffer->xDataLength = rx_bytes;
|
||||
if( rx_bytes > 60 )
|
||||
{
|
||||
bHasDataPacket = 1;
|
||||
}
|
||||
if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );
|
||||
}
|
||||
|
||||
/* store it in the receive queue, where it'll be processed by a
|
||||
different handler. */
|
||||
iptraceNETWORK_INTERFACE_RECEIVE();
|
||||
pxBuffer->pxNextBuffer = NULL;
|
||||
|
||||
if( ethMsg == NULL )
|
||||
{
|
||||
// Becomes the first message
|
||||
ethMsg = pxBuffer;
|
||||
}
|
||||
else if( ethLast != NULL )
|
||||
{
|
||||
// Add to the tail
|
||||
ethLast->pxNextBuffer = pxBuffer;
|
||||
}
|
||||
|
||||
ethLast = pxBuffer;
|
||||
msgCount++;
|
||||
}
|
||||
{
|
||||
if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
|
||||
}
|
||||
{
|
||||
uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
|
||||
if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
|
||||
{
|
||||
addr |= XEMACPS_RXBUF_WRAP_MASK;
|
||||
}
|
||||
/* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
|
||||
xemacpsif->rxSegments[ head ].flags = 0;
|
||||
xemacpsif->rxSegments[ head ].address = addr;
|
||||
if (xemacpsif->rxSegments[ head ].address) {
|
||||
// Just to read it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( ++head == ipconfigNIC_N_RX_DESC )
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
xemacpsif->rxHead = head;
|
||||
}
|
||||
|
||||
if( ethMsg != NULL )
|
||||
{
|
||||
if( bHasDataPacket == pdFALSE )
|
||||
{
|
||||
// vTaskDelay( ack_reception_delay );
|
||||
}
|
||||
passEthMessages( ethMsg );
|
||||
}
|
||||
|
||||
return msgCount;
|
||||
}
|
||||
|
||||
void clean_dma_txdescs(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
int index;
|
||||
unsigned char *ucTxBuffer;
|
||||
|
||||
/* Clear all TX descriptors and assign uncached memory to each descriptor.
|
||||
"tx_space" points to the first available TX buffer. */
|
||||
ucTxBuffer = xemacpsif->tx_space;
|
||||
|
||||
for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
|
||||
{
|
||||
xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
|
||||
xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;
|
||||
#else
|
||||
pxDMA_tx_buffers[ index ] = ( unsigned char * )( ucTxBuffer + TX_OFFSET );
|
||||
#endif
|
||||
ucTxBuffer += xemacpsif->uTxUnitSize;
|
||||
}
|
||||
xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
|
||||
XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
|
||||
}
|
||||
|
||||
XStatus init_dma(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
NetworkBufferDescriptor_t *pxBuffer;
|
||||
|
||||
int iIndex;
|
||||
UBaseType_t xRxSize;
|
||||
UBaseType_t xTxSize;
|
||||
struct xtopology_t *xtopologyp = &xXTopology;
|
||||
|
||||
xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
|
||||
|
||||
xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
|
||||
|
||||
/* Also round-up to 4KB */
|
||||
xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;
|
||||
/*
|
||||
* We allocate 65536 bytes for RX BDs which can accommodate a
|
||||
* maximum of 8192 BDs which is much more than any application
|
||||
* will ever need.
|
||||
*/
|
||||
xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) );
|
||||
xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );
|
||||
xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
|
||||
|
||||
/* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
|
||||
xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
|
||||
xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
|
||||
|
||||
if( xTXDescriptorSemaphore == NULL )
|
||||
{
|
||||
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
|
||||
configASSERT( xTXDescriptorSemaphore );
|
||||
}
|
||||
/*
|
||||
* Allocate RX descriptors, 1 RxBD at a time.
|
||||
*/
|
||||
for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
|
||||
{
|
||||
pxBuffer = pxDMA_rx_buffers[ iIndex ];
|
||||
if( pxBuffer == NULL )
|
||||
{
|
||||
pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
|
||||
if( pxBuffer == NULL )
|
||||
{
|
||||
FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
xemacpsif->rxSegments[ iIndex ].flags = 0;
|
||||
xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
|
||||
|
||||
pxDMA_rx_buffers[ iIndex ] = pxBuffer;
|
||||
/* Make sure this memory is not in cache for now. */
|
||||
if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
|
||||
(unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
|
||||
}
|
||||
}
|
||||
|
||||
xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
|
||||
|
||||
memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
|
||||
|
||||
clean_dma_txdescs( xemacpsif );
|
||||
|
||||
{
|
||||
uint32_t value;
|
||||
value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
|
||||
|
||||
// 1xxxx: Attempt to use INCR16 AHB bursts
|
||||
value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
|
||||
value |= XEMACPS_DMACR_TCPCKSUM_MASK;
|
||||
#else
|
||||
#warning Are you sure the EMAC should not calculate outgoing checksums?
|
||||
value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
|
||||
#endif
|
||||
XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
|
||||
}
|
||||
{
|
||||
uint32_t value;
|
||||
value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
|
||||
|
||||
/* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
|
||||
Now tell the EMAC that received messages should be stored at "address + 2". */
|
||||
value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
|
||||
|
||||
#if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
|
||||
value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
|
||||
#else
|
||||
#warning Are you sure the EMAC should not calculate incoming checksums?
|
||||
value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
|
||||
#endif
|
||||
XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect the device driver handler that will be called when an
|
||||
* interrupt for the device occurs, the handler defined above performs
|
||||
* the specific interrupt processing for the device.
|
||||
*/
|
||||
XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
|
||||
(Xil_ExceptionHandler)XEmacPs_IntrHandler,
|
||||
(void *)&xemacpsif->emacps);
|
||||
/*
|
||||
* Enable the interrupt for emacps.
|
||||
*/
|
||||
EmacEnableIntr( );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* resetrx_on_no_rxdata():
|
||||
*
|
||||
* It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
|
||||
* called by the user.
|
||||
* The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
|
||||
* Under heavy Rx traffic because of the HW bug there are times when the Rx path
|
||||
* becomes unresponsive. The workaround for it is to check for the Rx path for
|
||||
* traffic (by reading the stats registers regularly). If the stats register
|
||||
* does not increment for sometime (proving no Rx traffic), the function resets
|
||||
* the Rx data path.
|
||||
*
|
||||
*/
|
||||
|
||||
void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
unsigned long regctrl;
|
||||
unsigned long tempcntr;
|
||||
|
||||
tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
|
||||
if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
|
||||
{
|
||||
FreeRTOS_printf( ( "resetrx_on_no_rxdata: RESET~\n" ) );
|
||||
regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET);
|
||||
regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET, regctrl);
|
||||
regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
|
||||
regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
|
||||
}
|
||||
xemacpsif->last_rx_frms_cntr = tempcntr;
|
||||
}
|
||||
|
||||
void EmacDisableIntr(void)
|
||||
{
|
||||
XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
|
||||
}
|
||||
|
||||
void EmacEnableIntr(void)
|
||||
{
|
||||
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
|
||||
}
|
||||
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Xilinx, Inc.
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
|
||||
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
|
||||
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
|
||||
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
|
||||
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
|
||||
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
|
||||
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
|
||||
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
|
||||
extern TaskHandle_t xEMACTaskHandle;
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
|
||||
void setup_isr( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
/*
|
||||
* Setup callbacks
|
||||
*/
|
||||
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
|
||||
(void *) emacps_send_handler,
|
||||
(void *) xemacpsif);
|
||||
|
||||
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
|
||||
(void *) emacps_recv_handler,
|
||||
(void *) xemacpsif);
|
||||
|
||||
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
|
||||
(void *) emacps_error_handler,
|
||||
(void *) xemacpsif);
|
||||
}
|
||||
|
||||
void start_emacps (xemacpsif_s *xemacps)
|
||||
{
|
||||
/* start the temac */
|
||||
XEmacPs_Start(&xemacps->emacps);
|
||||
}
|
||||
|
||||
extern struct xtopology_t xXTopology;
|
||||
|
||||
volatile int error_msg_count = 0;
|
||||
volatile const char *last_err_msg = "";
|
||||
|
||||
struct xERROR_MSG {
|
||||
void *arg;
|
||||
u8 Direction;
|
||||
u32 ErrorWord;
|
||||
};
|
||||
|
||||
static struct xERROR_MSG xErrorList[ 8 ];
|
||||
static BaseType_t xErrorHead, xErrorTail;
|
||||
|
||||
void emacps_error_handler(void *arg, u8 Direction, u32 ErrorWord)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xemacpsif_s *xemacpsif;
|
||||
BaseType_t xNextHead = xErrorHead;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
|
||||
if( ( Direction != XEMACPS_SEND ) || (ErrorWord != XEMACPS_TXSR_USEDREAD_MASK ) )
|
||||
{
|
||||
if( ++xNextHead == ( sizeof( xErrorList ) / sizeof( xErrorList[ 0 ] ) ) )
|
||||
xNextHead = 0;
|
||||
if( xNextHead != xErrorTail )
|
||||
{
|
||||
|
||||
xErrorList[ xErrorHead ].arg = arg;
|
||||
xErrorList[ xErrorHead ].Direction = Direction;
|
||||
xErrorList[ xErrorHead ].ErrorWord = ErrorWord;
|
||||
|
||||
xErrorHead = xNextHead;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
xemacpsif->isr_events |= EMAC_IF_ERR_EVENT;
|
||||
}
|
||||
|
||||
if( xEMACTaskHandle != NULL )
|
||||
{
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord);
|
||||
|
||||
int emacps_check_errors( xemacpsif_s *xemacps )
|
||||
{
|
||||
int xResult;
|
||||
|
||||
( void ) xemacps;
|
||||
|
||||
if( xErrorHead == xErrorTail )
|
||||
{
|
||||
xResult = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xResult = 1;
|
||||
emacps_handle_error(
|
||||
xErrorList[ xErrorTail ].arg,
|
||||
xErrorList[ xErrorTail ].Direction,
|
||||
xErrorList[ xErrorTail ].ErrorWord );
|
||||
}
|
||||
|
||||
return xResult;
|
||||
}
|
||||
|
||||
static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord)
|
||||
{
|
||||
xemacpsif_s *xemacpsif;
|
||||
struct xtopology_t *xtopologyp;
|
||||
XEmacPs *xemacps;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
|
||||
xtopologyp = &xXTopology;
|
||||
|
||||
xemacps = &xemacpsif->emacps;
|
||||
|
||||
/* Do not appear to be used. */
|
||||
( void ) xemacps;
|
||||
( void ) xtopologyp;
|
||||
|
||||
last_err_msg = NULL;
|
||||
|
||||
if( ErrorWord != 0 )
|
||||
{
|
||||
switch (Direction) {
|
||||
case XEMACPS_RECV:
|
||||
if( ( ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Receive DMA error";
|
||||
xNetworkInterfaceInitialise( );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_RXSR_RXOVR_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Receive over run";
|
||||
emacps_recv_handler(arg);
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_RXSR_BUFFNA_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Receive buffer not available";
|
||||
emacps_recv_handler(arg);
|
||||
}
|
||||
break;
|
||||
case XEMACPS_SEND:
|
||||
if( ( ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit DMA error";
|
||||
xNetworkInterfaceInitialise( );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_URUN_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit under run";
|
||||
HandleTxErrors( xemacpsif );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_BUFEXH_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit buffer exhausted";
|
||||
HandleTxErrors( xemacpsif );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_RXOVR_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit retry excessed limits";
|
||||
HandleTxErrors( xemacpsif );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_FRAMERX_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit collision";
|
||||
emacps_check_tx( xemacpsif );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Break on this statement and inspect error_msg if you like
|
||||
if( last_err_msg != NULL )
|
||||
{
|
||||
error_msg_count++;
|
||||
FreeRTOS_printf( ( "emacps_handle_error: %s\n", last_err_msg ) );
|
||||
}
|
||||
}
|
||||
|
||||
extern XEmacPs_Config mac_config;
|
||||
|
||||
void HandleTxErrors(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
u32 netctrlreg;
|
||||
|
||||
//taskENTER_CRITICAL()
|
||||
{
|
||||
netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET);
|
||||
netctrlreg = netctrlreg & (~XEMACPS_NWCTRL_TXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET, netctrlreg);
|
||||
|
||||
clean_dma_txdescs( xemacpsif );
|
||||
netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET);
|
||||
netctrlreg = netctrlreg | (XEMACPS_NWCTRL_TXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET, netctrlreg);
|
||||
}
|
||||
//taskEXIT_CRITICAL( );
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Xilinx, Inc.
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
|
||||
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
|
||||
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
|
||||
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
|
||||
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
|
||||
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
|
||||
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
|
||||
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __XEMACPSIF_HW_H_
|
||||
#define __XEMACPSIF_HW_H_
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
//#include "lwip/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
XEmacPs_Config * lookup_config(unsigned mac_base);
|
||||
|
||||
//void init_emacps(xemacpsif_s *xemacpsif, struct netif *netif);
|
||||
|
||||
int emacps_check_errors( xemacpsif_s *xemacps );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+581
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008, Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the names
|
||||
* of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some portions copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Xilinx, Inc.
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
|
||||
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
|
||||
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
|
||||
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
|
||||
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
|
||||
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
|
||||
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
|
||||
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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 "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
#include "xparameters_ps.h"
|
||||
#include "xparameters.h"
|
||||
|
||||
|
||||
int phy_detected = 0;
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
|
||||
/* Advertisement control register. */
|
||||
#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_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \
|
||||
ADVERTISE_10HALF | ADVERTISE_100HALF)
|
||||
#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF)
|
||||
#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF)
|
||||
|
||||
#define ADVERTISE_1000 0x0300
|
||||
|
||||
|
||||
//#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 IEEE_CONTROL_REG_OFFSET 0
|
||||
#define IEEE_STATUS_REG_OFFSET 1
|
||||
#define IEEE_PHYSID1_OFFSET 2
|
||||
#define IEEE_PHYSID2_OFFSET 3
|
||||
#define IEEE_AUTONEGO_ADVERTISE_REG 4
|
||||
#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5
|
||||
#define IEEE_1000_ADVERTISE_REG_OFFSET 9
|
||||
#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10
|
||||
#define IEEE_COPPER_SPECIFIC_CONTROL_REG 16
|
||||
#define IEEE_SPECIFIC_STATUS_REG 17
|
||||
#define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19
|
||||
#define IEEE_CONTROL_REG_MAC 21
|
||||
#define IEEE_PAGE_ADDRESS_REGISTER 22
|
||||
|
||||
|
||||
#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040
|
||||
#define IEEE_CTRL_LINKSPEED_MASK 0x0040
|
||||
#define IEEE_CTRL_LINKSPEED_1000M 0x0040
|
||||
#define IEEE_CTRL_LINKSPEED_100M 0x2000
|
||||
#define IEEE_CTRL_LINKSPEED_10M 0x0000
|
||||
#define IEEE_CTRL_RESET_MASK 0x8000
|
||||
#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#define IEEE_CTRL_RESET 0x9140
|
||||
#define IEEE_CTRL_ISOLATE_DISABLE 0xFBFF
|
||||
#endif
|
||||
#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008
|
||||
#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020
|
||||
#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200
|
||||
#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100
|
||||
#define IEEE_AN1_ABILITY_MASK 0x1FE0
|
||||
#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00
|
||||
#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380
|
||||
#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060
|
||||
#define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030
|
||||
|
||||
#define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800
|
||||
#define IEEE_PAUSE_MASK 0x0400
|
||||
#define IEEE_AUTONEG_ERROR_MASK 0x8000
|
||||
|
||||
#define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140
|
||||
#define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100
|
||||
#define XEMACPS_GMII2RGMII_SPEED10_FD 0x100
|
||||
#define XEMACPS_GMII2RGMII_REG_NUM 0x10
|
||||
|
||||
/* Frequency setting */
|
||||
#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4)
|
||||
#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
|
||||
#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
|
||||
#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
|
||||
#ifdef PEEP
|
||||
#define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031
|
||||
#define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001
|
||||
#define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011
|
||||
#endif
|
||||
#define SLCR_LOCK_KEY_VALUE 0x767B
|
||||
#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
|
||||
#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
|
||||
#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
|
||||
|
||||
#define EMAC0_BASE_ADDRESS 0xE000B000
|
||||
#define EMAC1_BASE_ADDRESS 0xE000C000
|
||||
|
||||
static int detect_phy(XEmacPs *xemacpsp)
|
||||
{
|
||||
u16 id_lower, id_upper;
|
||||
u32 phy_addr, id;
|
||||
|
||||
for (phy_addr = 0; phy_addr < 32; phy_addr++) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID1_OFFSET, &id_lower);
|
||||
|
||||
if ((id_lower != ( u16 )0xFFFFu) && (id_lower != ( u16 )0x0u)) {
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID2_OFFSET, &id_upper);
|
||||
id = ( ( ( uint32_t ) id_upper ) << 16 ) | ( id_lower & 0xFFF0 );
|
||||
FreeRTOS_printf( ("XEmacPs detect_phy: %04lX at address %d.\n", id, phy_addr ) );
|
||||
phy_detected = phy_addr;
|
||||
return phy_addr;
|
||||
}
|
||||
}
|
||||
|
||||
FreeRTOS_printf( ("XEmacPs detect_phy: No PHY detected. Assuming a PHY at address 0\n" ) );
|
||||
|
||||
/* default to zero */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PEEP
|
||||
unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
|
||||
{
|
||||
|
||||
u16 control;
|
||||
u16 status;
|
||||
u16 partner_capabilities;
|
||||
u16 partner_capabilities_1000;
|
||||
u16 phylinkspeed;
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
ADVERTISE_1000);
|
||||
/* Advertise PHY speed of 100 and 10 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_100_AND_10);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
|
||||
&control);
|
||||
control |= (IEEE_CTRL_AUTONEGOTIATE_ENABLE |
|
||||
IEEE_STAT_AUTONEGOTIATE_RESTART);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
/* Read PHY control and status registers is successful. */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
|
||||
|
||||
if ((control & IEEE_CTRL_AUTONEGOTIATE_ENABLE) && (status &
|
||||
IEEE_STAT_AUTONEGOTIATE_CAPABLE)) {
|
||||
|
||||
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
|
||||
&status);
|
||||
}
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET,
|
||||
&partner_capabilities);
|
||||
|
||||
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_3_REG_OFFSET,
|
||||
&partner_capabilities_1000);
|
||||
if (partner_capabilities_1000 & IEEE_AN3_ABILITY_MASK_1GBPS)
|
||||
return 1000;
|
||||
}
|
||||
|
||||
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_100MBPS)
|
||||
return 100;
|
||||
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS)
|
||||
return 10;
|
||||
|
||||
xil_printf("%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\n",
|
||||
__FUNCTION__);
|
||||
return 10;
|
||||
|
||||
} else {
|
||||
|
||||
/* Update TEMAC speed accordingly */
|
||||
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
|
||||
/* Get commanded link speed */
|
||||
phylinkspeed = control & IEEE_CTRL_1GBPS_LINKSPEED_MASK;
|
||||
|
||||
switch (phylinkspeed) {
|
||||
case (IEEE_CTRL_LINKSPEED_1000M):
|
||||
return 1000;
|
||||
case (IEEE_CTRL_LINKSPEED_100M):
|
||||
return 100;
|
||||
case (IEEE_CTRL_LINKSPEED_10M):
|
||||
return 10;
|
||||
default:
|
||||
xil_printf("%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\n",
|
||||
__FUNCTION__, phylinkspeed);
|
||||
return 10;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
return (control & IEEE_CTRL_LINKSPEED_MASK) ? 100 : 10;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else /* Zynq */
|
||||
unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
|
||||
{
|
||||
u16 temp;
|
||||
u16 control;
|
||||
u16 status;
|
||||
u16 partner_capabilities;
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
u32 phy_addr = XPAR_PCSPMA_SGMII_PHYADDR;
|
||||
#else
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
#endif
|
||||
xil_printf("Start PHY autonegotiation \n");
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
|
||||
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
control |= IEEE_PAUSE_MASK;
|
||||
control |= ADVERTISE_100;
|
||||
control |= ADVERTISE_10;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
&control);
|
||||
control |= ADVERTISE_1000;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
&control);
|
||||
control |= (7 << 12); /* max number of gigabit attempts */
|
||||
control |= (1 << 11); /* enable downshift */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
control);
|
||||
#endif
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
|
||||
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
control &= IEEE_CTRL_ISOLATE_DISABLE;
|
||||
#endif
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_RESET_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
while (1) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
if (control & IEEE_CTRL_RESET_MASK)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
xil_printf("Waiting for PHY to complete autonegotiation.\n");
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
|
||||
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
|
||||
sleep(1);
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2,
|
||||
&temp);
|
||||
if (temp & IEEE_AUTONEG_ERROR_MASK) {
|
||||
xil_printf("Auto negotiation error \n");
|
||||
}
|
||||
#endif
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
|
||||
&status);
|
||||
}
|
||||
|
||||
xil_printf("autonegotiation complete \n");
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &partner_capabilities);
|
||||
#endif
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
xil_printf("Waiting for Link to be up; Polling for SGMII core Reg \n");
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp);
|
||||
while(!(temp & 0x8000)) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp);
|
||||
}
|
||||
if((temp & 0x0C00) == 0x0800) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
return 1000;
|
||||
}
|
||||
else if((temp & 0x0C00) == 0x0400) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
return 100;
|
||||
}
|
||||
else if((temp & 0x0C00) == 0x0000) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
return 10;
|
||||
} else {
|
||||
xil_printf("get_IEEE_phy_speed(): Invalid speed bit value, Deafulting to Speed = 10 Mbps\n");
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0, 0x0100);
|
||||
return 10;
|
||||
}
|
||||
#else
|
||||
if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */
|
||||
return 1000;
|
||||
else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */
|
||||
return 100;
|
||||
else /* 10Mbps */
|
||||
return 10;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned configure_IEEE_phy_speed(XEmacPs *xemacpsp, unsigned speed)
|
||||
{
|
||||
u16 control;
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
|
||||
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
control |= IEEE_PAUSE_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control &= ~IEEE_CTRL_LINKSPEED_1000M;
|
||||
control &= ~IEEE_CTRL_LINKSPEED_100M;
|
||||
control &= ~IEEE_CTRL_LINKSPEED_10M;
|
||||
|
||||
if (speed == 1000) {
|
||||
control |= IEEE_CTRL_LINKSPEED_1000M;
|
||||
}
|
||||
|
||||
else if (speed == 100) {
|
||||
control |= IEEE_CTRL_LINKSPEED_100M;
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, 0);
|
||||
/* Dont advertise PHY speed of 10 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_100);
|
||||
}
|
||||
|
||||
else if (speed == 10) {
|
||||
control |= IEEE_CTRL_LINKSPEED_10M;
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
0);
|
||||
/* Dont advertise PHY speed of 100 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_10);
|
||||
}
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
|
||||
control | IEEE_CTRL_RESET_MASK);
|
||||
{
|
||||
volatile int wait;
|
||||
for (wait=0; wait < 100000; wait++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetUpSLCRDivisors(int mac_baseaddr, int speed)
|
||||
{
|
||||
volatile u32 slcrBaseAddress;
|
||||
#ifndef PEEP
|
||||
u32 SlcrDiv0;
|
||||
u32 SlcrDiv1=0;
|
||||
u32 SlcrTxClkCntrl;
|
||||
#endif
|
||||
|
||||
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
|
||||
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR;
|
||||
} else {
|
||||
slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR;
|
||||
}
|
||||
#ifdef PEEP
|
||||
if (speed == 1000) {
|
||||
*(volatile unsigned int *)(slcrBaseAddress) =
|
||||
SLCR_GEM_1G_CLK_CTRL_VALUE;
|
||||
} else if (speed == 100) {
|
||||
*(volatile unsigned int *)(slcrBaseAddress) =
|
||||
SLCR_GEM_100M_CLK_CTRL_VALUE;
|
||||
} else {
|
||||
*(volatile unsigned int *)(slcrBaseAddress) =
|
||||
SLCR_GEM_10M_CLK_CTRL_VALUE;
|
||||
}
|
||||
#else
|
||||
if (speed == 1000) {
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else if (speed == 100) {
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SlcrTxClkCntrl = *(volatile unsigned int *)(slcrBaseAddress);
|
||||
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
||||
SlcrTxClkCntrl |= (SlcrDiv1 << 20);
|
||||
SlcrTxClkCntrl |= (SlcrDiv0 << 8);
|
||||
*(volatile unsigned int *)(slcrBaseAddress) = SlcrTxClkCntrl;
|
||||
#endif
|
||||
*(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
unsigned link_speed;
|
||||
unsigned Phy_Setup (XEmacPs *xemacpsp)
|
||||
{
|
||||
unsigned long conv_present = 0;
|
||||
unsigned long convspeeddupsetting = 0;
|
||||
unsigned long convphyaddr = 0;
|
||||
|
||||
#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR
|
||||
convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR;
|
||||
conv_present = 1;
|
||||
#else
|
||||
#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR
|
||||
convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR;
|
||||
conv_present = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ipconfigNIC_LINKSPEED_AUTODETECT
|
||||
link_speed = get_IEEE_phy_speed(xemacpsp);
|
||||
if (link_speed == 1000) {
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
|
||||
} else if (link_speed == 100) {
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
|
||||
} else {
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
|
||||
}
|
||||
#elif defined(ipconfigNIC_LINKSPEED1000)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
|
||||
link_speed = 1000;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
|
||||
sleep(1);
|
||||
#elif defined(ipconfigNIC_LINKSPEED100)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
|
||||
link_speed = 100;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
|
||||
sleep(1);
|
||||
#elif defined(ipconfigNIC_LINKSPEED10)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
|
||||
link_speed = 10;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
|
||||
sleep(1);
|
||||
#endif
|
||||
if (conv_present) {
|
||||
XEmacPs_PhyWrite(xemacpsp, convphyaddr,
|
||||
XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
|
||||
}
|
||||
|
||||
xil_printf("link speed: %d\n", link_speed);
|
||||
return link_speed;
|
||||
}
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2013 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Xilinx, Inc.
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
|
||||
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
|
||||
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
|
||||
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
|
||||
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
|
||||
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
|
||||
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
|
||||
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __XTOPOLOGY_H_
|
||||
#define __XTOPOLOGY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum xemac_types { xemac_type_unknown = -1, xemac_type_xps_emaclite, xemac_type_xps_ll_temac, xemac_type_axi_ethernet, xemac_type_emacps };
|
||||
|
||||
struct xtopology_t {
|
||||
unsigned emac_baseaddr;
|
||||
enum xemac_types emac_type;
|
||||
unsigned intc_baseaddr;
|
||||
unsigned intc_emac_intr; /* valid only for xemac_type_xps_emaclite */
|
||||
unsigned scugic_baseaddr; /* valid only for Zynq */
|
||||
unsigned scugic_emac_intr; /* valid only for GEM */
|
||||
};
|
||||
|
||||
extern int x_topology_n_emacs;
|
||||
extern struct xtopology_t x_topology[];
|
||||
|
||||
int x_topology_find_index(unsigned base);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+118
@@ -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
|
||||
+1272
File diff suppressed because it is too large
Load Diff
+610
@@ -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;
|
||||
}
|
||||
+67
@@ -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 */
|
||||
+473
@@ -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 */
|
||||
Reference in New Issue
Block a user