mirror of
https://github.com/FreeRTOS/FreeRTOS.git
synced 2025-06-26 03:08:27 +08:00
Added +TCP code to main repo.
This commit is contained in:
@ -0,0 +1,680 @@
|
||||
/*
|
||||
* FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
|
||||
* Authors include Hein Tibosch and Richard Barry
|
||||
*
|
||||
*******************************************************************************
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*** ***
|
||||
*** ***
|
||||
*** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
|
||||
*** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
|
||||
*** download): ***
|
||||
*** ***
|
||||
*** FreeRTOS+TCP is functional and has been used in commercial products ***
|
||||
*** for some time. Be aware however that we are still refining its ***
|
||||
*** design, the source code does not yet quite conform to the strict ***
|
||||
*** coding and style standards mandated by Real Time Engineers ltd., and ***
|
||||
*** the documentation and testing is not necessarily complete. ***
|
||||
*** ***
|
||||
*** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
|
||||
*** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
|
||||
*** the sole discretion of Real Time Engineers Ltd., be offered versions ***
|
||||
*** under a license other than that described below. ***
|
||||
*** ***
|
||||
*** ***
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*******************************************************************************
|
||||
*
|
||||
* FreeRTOS+TCP can be used under two different free open source licenses. The
|
||||
* license that applies is dependent on the processor on which FreeRTOS+TCP is
|
||||
* executed, as follows:
|
||||
*
|
||||
* If FreeRTOS+TCP is executed on one of the processors listed under the Special
|
||||
* License Arrangements heading of the FreeRTOS+TCP license information web
|
||||
* page, then it can be used under the terms of the FreeRTOS Open Source
|
||||
* License. If FreeRTOS+TCP is used on any other processor, then it can be used
|
||||
* under the terms of the GNU General Public License V2. Links to the relevant
|
||||
* licenses follow:
|
||||
*
|
||||
* The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
|
||||
* The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
|
||||
* The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
|
||||
*
|
||||
* FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
|
||||
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
|
||||
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
|
||||
* implied, expressed, or statutory.
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://www.FreeRTOS.org/plus
|
||||
* http://www.FreeRTOS.org/labs
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -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_ */
|
@ -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
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
@ -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 */
|
||||
|
@ -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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* FreeRTOS+TCP Labs Build 150406 (C) 2015 Real Time Engineers ltd.
|
||||
* Authors include Hein Tibosch and Richard Barry
|
||||
*
|
||||
*******************************************************************************
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*** ***
|
||||
*** ***
|
||||
*** FREERTOS+TCP IS STILL IN THE LAB: ***
|
||||
*** ***
|
||||
*** This product is functional and is already being used in commercial ***
|
||||
*** products. Be aware however that we are still refining its design, ***
|
||||
*** the source code does not yet fully conform to the strict coding and ***
|
||||
*** style standards mandated by Real Time Engineers ltd., and the ***
|
||||
*** documentation and testing is not necessarily complete. ***
|
||||
*** ***
|
||||
*** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
|
||||
*** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
|
||||
*** the sole discretion of Real Time Engineers Ltd., be offered versions ***
|
||||
*** under a license other than that described below. ***
|
||||
*** ***
|
||||
*** ***
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*******************************************************************************
|
||||
*
|
||||
* - Open source licensing -
|
||||
* While FreeRTOS+TCP is in the lab it is provided only under version two of the
|
||||
* GNU General Public License (GPL) (which is different to the standard FreeRTOS
|
||||
* license). FreeRTOS+TCP is free to download, use and distribute under the
|
||||
* terms of that license provided the copyright notice and this text are not
|
||||
* altered or removed from the source files. The GPL V2 text is available on
|
||||
* the gnu.org web site, and on the following
|
||||
* URL: http://www.FreeRTOS.org/gpl-2.0.txt. Active early adopters may, and
|
||||
* solely at the discretion of Real Time Engineers Ltd., be offered versions
|
||||
* under a license other then the GPL.
|
||||
*
|
||||
* FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
|
||||
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
|
||||
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
|
||||
* implied, expressed, or statutory.
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://www.FreeRTOS.org/plus
|
||||
* http://www.FreeRTOS.org/labs
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@
|
||||
NetworkInterface.c:
|
||||
Requires NXP's LPCOpen library and was developed on an LPC1830 and LPC1835 Xplorer
|
||||
boards from NGX.
|
@ -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.
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* FreeRTOS+TCP Labs Build 150406 (C) 2015 Real Time Engineers ltd.
|
||||
* Authors include Hein Tibosch and Richard Barry
|
||||
*
|
||||
*******************************************************************************
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*** ***
|
||||
*** ***
|
||||
*** FREERTOS+TCP IS STILL IN THE LAB: ***
|
||||
*** ***
|
||||
*** This product is functional and is already being used in commercial ***
|
||||
*** products. Be aware however that we are still refining its design, ***
|
||||
*** the source code does not yet fully conform to the strict coding and ***
|
||||
*** style standards mandated by Real Time Engineers ltd., and the ***
|
||||
*** documentation and testing is not necessarily complete. ***
|
||||
*** ***
|
||||
*** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
|
||||
*** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
|
||||
*** the sole discretion of Real Time Engineers Ltd., be offered versions ***
|
||||
*** under a license other than that described below. ***
|
||||
*** ***
|
||||
*** ***
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*******************************************************************************
|
||||
*
|
||||
* - Open source licensing -
|
||||
* While FreeRTOS+TCP is in the lab it is provided only under version two of the
|
||||
* GNU General Public License (GPL) (which is different to the standard FreeRTOS
|
||||
* license). FreeRTOS+TCP is free to download, use and distribute under the
|
||||
* terms of that license provided the copyright notice and this text are not
|
||||
* altered or removed from the source files. The GPL V2 text is available on
|
||||
* the gnu.org web site, and on the following
|
||||
* URL: http://www.FreeRTOS.org/gpl-2.0.txt. Active early adopters may, and
|
||||
* solely at the discretion of Real Time Engineers Ltd., be offered versions
|
||||
* under a license other then the GPL.
|
||||
*
|
||||
* FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
|
||||
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
|
||||
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
|
||||
* implied, expressed, or statutory.
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://www.FreeRTOS.org/plus
|
||||
* http://www.FreeRTOS.org/labs
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -0,0 +1,631 @@
|
||||
/*
|
||||
* FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
|
||||
* Authors include Hein Tibosch and Richard Barry
|
||||
*
|
||||
*******************************************************************************
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*** ***
|
||||
*** ***
|
||||
*** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
|
||||
*** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
|
||||
*** download): ***
|
||||
*** ***
|
||||
*** FreeRTOS+TCP is functional and has been used in commercial products ***
|
||||
*** for some time. Be aware however that we are still refining its ***
|
||||
*** design, the source code does not yet quite conform to the strict ***
|
||||
*** coding and style standards mandated by Real Time Engineers ltd., and ***
|
||||
*** the documentation and testing is not necessarily complete. ***
|
||||
*** ***
|
||||
*** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
|
||||
*** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
|
||||
*** the sole discretion of Real Time Engineers Ltd., be offered versions ***
|
||||
*** under a license other than that described below. ***
|
||||
*** ***
|
||||
*** ***
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*******************************************************************************
|
||||
*
|
||||
* FreeRTOS+TCP can be used under two different free open source licenses. The
|
||||
* license that applies is dependent on the processor on which FreeRTOS+TCP is
|
||||
* executed, as follows:
|
||||
*
|
||||
* If FreeRTOS+TCP is executed on one of the processors listed under the Special
|
||||
* License Arrangements heading of the FreeRTOS+TCP license information web
|
||||
* page, then it can be used under the terms of the FreeRTOS Open Source
|
||||
* License. If FreeRTOS+TCP is used on any other processor, then it can be used
|
||||
* under the terms of the GNU General Public License V2. Links to the relevant
|
||||
* licenses follow:
|
||||
*
|
||||
* The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
|
||||
* The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
|
||||
* The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
|
||||
*
|
||||
* FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
|
||||
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
|
||||
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
|
||||
* implied, expressed, or statutory.
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://www.FreeRTOS.org/plus
|
||||
* http://www.FreeRTOS.org/labs
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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 void 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 ];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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( "%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( "The interface that will be opened is set by\n" );
|
||||
printf( "\"configNETWORK_INTERFACE_TO_USE\" which should be defined in FreeRTOSConfig.h\n" );
|
||||
printf( "Attempting to open interface number %d.\n", xConfigNextworkInterfaceToUse );
|
||||
|
||||
if( ( xConfigNextworkInterfaceToUse < 1L ) || ( xConfigNextworkInterfaceToUse > lInterfaceNumber ) )
|
||||
{
|
||||
printf( "configNETWORK_INTERFACE_TO_USE is not in the valid range.\n" );
|
||||
|
||||
if( pxAllNetworkInterfaces != NULL )
|
||||
{
|
||||
/* Free the device list, as no devices are going to be opened. */
|
||||
pcap_freealldevs( pxAllNetworkInterfaces );
|
||||
pxAllNetworkInterfaces = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pxAllNetworkInterfaces;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void 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 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Configure the capture filter to allow blocking reads, and to filter
|
||||
out packets that are not of interest to this demo. */
|
||||
prvConfigureCaptureBehaviour();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
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;
|
||||
for( x = 0L; x < ( xConfigNextworkInterfaceToUse - 1L ); x++ )
|
||||
{
|
||||
xInterface = xInterface->next;
|
||||
}
|
||||
|
||||
/* Open the selected interface. */
|
||||
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" );
|
||||
}
|
||||
}
|
||||
|
||||
/* 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();
|
||||
|
||||
eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
|
||||
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;
|
||||
}
|
||||
|
@ -0,0 +1,430 @@
|
||||
/*
|
||||
* FreeRTOS+TCP Labs Build 200417 (C) 2016 Real Time Engineers ltd.
|
||||
* Authors include Hein Tibosch and Richard Barry
|
||||
*
|
||||
*******************************************************************************
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*** ***
|
||||
*** ***
|
||||
*** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
|
||||
*** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
|
||||
*** download): ***
|
||||
*** ***
|
||||
*** FreeRTOS+TCP is functional and has been used in commercial products ***
|
||||
*** for some time. Be aware however that we are still refining its ***
|
||||
*** design, the source code does not yet quite conform to the strict ***
|
||||
*** coding and style standards mandated by Real Time Engineers ltd., and ***
|
||||
*** the documentation and testing is not necessarily complete. ***
|
||||
*** ***
|
||||
*** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
|
||||
*** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
|
||||
*** the sole discretion of Real Time Engineers Ltd., be offered versions ***
|
||||
*** under a license other than that described below. ***
|
||||
*** ***
|
||||
*** ***
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*******************************************************************************
|
||||
*
|
||||
* FreeRTOS+TCP can be used under two different free open source licenses. The
|
||||
* license that applies is dependent on the processor on which FreeRTOS+TCP is
|
||||
* executed, as follows:
|
||||
*
|
||||
* If FreeRTOS+TCP is executed on one of the processors listed under the Special
|
||||
* License Arrangements heading of the FreeRTOS+TCP license information web
|
||||
* page, then it can be used under the terms of the FreeRTOS Open Source
|
||||
* License. If FreeRTOS+TCP is used on any other processor, then it can be used
|
||||
* under the terms of the GNU General Public License V2. Links to the relevant
|
||||
* licenses follow:
|
||||
*
|
||||
* The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
|
||||
* The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
|
||||
* The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
|
||||
*
|
||||
* FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
|
||||
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
|
||||
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
|
||||
* implied, expressed, or statutory.
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://www.FreeRTOS.org/plus
|
||||
* http://www.FreeRTOS.org/labs
|
||||
*
|
||||
*/
|
||||
|
||||
/* 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"
|
||||
|
||||
/* 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 BMSR_LINK_STATUS
|
||||
#define BMSR_LINK_STATUS 0x0004UL
|
||||
#endif
|
||||
|
||||
#ifndef PHY_LS_HIGH_CHECK_TIME_MS
|
||||
/* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
|
||||
receiving packets. */
|
||||
#define PHY_LS_HIGH_CHECK_TIME_MS 15000
|
||||
#endif
|
||||
|
||||
#ifndef PHY_LS_LOW_CHECK_TIME_MS
|
||||
/* Check if the LinkSStatus in the PHY is still low every second. */
|
||||
#define PHY_LS_LOW_CHECK_TIME_MS 1000
|
||||
#endif
|
||||
|
||||
/* 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, configMAX_PRIORITIES - 1, &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( ( ulPHYLinkStatus & BMSR_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 & BMSR_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 & BMSR_LINK_STATUS ) == 0 )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEMACHandlerTask( void *pvParameters )
|
||||
{
|
||||
TimeOut_t xPhyTime;
|
||||
TickType_t xPhyRemTime;
|
||||
UBaseType_t uxLastMinBufferCount = 0;
|
||||
UBaseType_t uxCurrentCount;
|
||||
BaseType_t xResult = 0;
|
||||
uint32_t xStatus;
|
||||
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
|
||||
|
||||
/* 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( ;; )
|
||||
{
|
||||
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 ) );
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -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
|
@ -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__ */
|
@ -0,0 +1,657 @@
|
||||
/*
|
||||
* FreeRTOS+TCP Labs Build 200417 (C) 2016 Real Time Engineers ltd.
|
||||
* Authors include Hein Tibosch and Richard Barry
|
||||
*
|
||||
*******************************************************************************
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*** ***
|
||||
*** ***
|
||||
*** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
|
||||
*** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
|
||||
*** download): ***
|
||||
*** ***
|
||||
*** FreeRTOS+TCP is functional and has been used in commercial products ***
|
||||
*** for some time. Be aware however that we are still refining its ***
|
||||
*** design, the source code does not yet quite conform to the strict ***
|
||||
*** coding and style standards mandated by Real Time Engineers ltd., and ***
|
||||
*** the documentation and testing is not necessarily complete. ***
|
||||
*** ***
|
||||
*** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
|
||||
*** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
|
||||
*** the sole discretion of Real Time Engineers Ltd., be offered versions ***
|
||||
*** under a license other than that described below. ***
|
||||
*** ***
|
||||
*** ***
|
||||
***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
|
||||
*******************************************************************************
|
||||
*
|
||||
* FreeRTOS+TCP can be used under two different free open source licenses. The
|
||||
* license that applies is dependent on the processor on which FreeRTOS+TCP is
|
||||
* executed, as follows:
|
||||
*
|
||||
* If FreeRTOS+TCP is executed on one of the processors listed under the Special
|
||||
* License Arrangements heading of the FreeRTOS+TCP license information web
|
||||
* page, then it can be used under the terms of the FreeRTOS Open Source
|
||||
* License. If FreeRTOS+TCP is used on any other processor, then it can be used
|
||||
* under the terms of the GNU General Public License V2. Links to the relevant
|
||||
* licenses follow:
|
||||
*
|
||||
* The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
|
||||
* The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
|
||||
* The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
|
||||
*
|
||||
* FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
|
||||
* use FreeRTOS+TCP unless you agree that you use the software 'as is'.
|
||||
* FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
|
||||
* implied, expressed, or statutory.
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://www.FreeRTOS.org/plus
|
||||
* http://www.FreeRTOS.org/labs
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
#include "Zynq/x_topology.h"
|
||||
#include "xstatus.h"
|
||||
|
||||
#include "xparameters.h"
|
||||
#include "xparameters_ps.h"
|
||||
#include "xil_exception.h"
|
||||
#include "xil_mmu.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "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 "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 NetworkBufferDescriptor_t *ethMsg = NULL;
|
||||
static NetworkBufferDescriptor_t *ethLast = NULL;
|
||||
|
||||
static void passEthMessages( void )
|
||||
{
|
||||
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" ) );
|
||||
}
|
||||
|
||||
ethMsg = ethLast = NULL;
|
||||
}
|
||||
|
||||
int emacps_check_rx( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
|
||||
int rx_bytes;
|
||||
volatile int msgCount = 0;
|
||||
int head = xemacpsif->rxHead;
|
||||
|
||||
/* There seems to be an issue (SI# 692601), see comments below. */
|
||||
resetrx_on_no_rxdata(xemacpsif);
|
||||
|
||||
/* 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( 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 ].address = addr;
|
||||
xemacpsif->rxSegments[ head ].flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( ++head == ipconfigNIC_N_RX_DESC )
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
xemacpsif->rxHead = head;
|
||||
}
|
||||
|
||||
if( ethMsg != NULL )
|
||||
{
|
||||
passEthMessages( );
|
||||
}
|
||||
|
||||
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 ] = ( void* )NULL;
|
||||
#else
|
||||
pxDMA_tx_buffers[ index ] = ( void* )( 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 ) )
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
///* FreeRTOS+TCP includes. */
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
extern TaskHandle_t xEMACTaskHandle;
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
|
||||
unsigned int link_speed = 100;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
BaseType_t xNetworkInterfaceInitialise( void );
|
||||
|
||||
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( );
|
||||
}
|
@ -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
|
@ -0,0 +1,585 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
//#include "lwipopts.h"
|
||||
#include "xparameters_ps.h"
|
||||
#include "xparameters.h"
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
///* FreeRTOS+TCP includes. */
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.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_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 PHY_DETECT_REG 1
|
||||
#define PHY_DETECT_MASK 0x1808
|
||||
|
||||
#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 phy_reg;
|
||||
u32 phy_addr;
|
||||
|
||||
for (phy_addr = 31; phy_addr > 0; phy_addr--) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,
|
||||
&phy_reg);
|
||||
|
||||
if ((phy_reg != 0xFFFF) &&
|
||||
((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
|
||||
/* Found a valid PHY address */
|
||||
FreeRTOS_printf( ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
|
||||
phy_addr));
|
||||
FreeRTOS_printf( ("XEmacPs detect_phy: PHY detected.\n" ) );
|
||||
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\r\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\r\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 \r\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.\r\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 \r\n");
|
||||
}
|
||||
#endif
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
|
||||
&status);
|
||||
}
|
||||
|
||||
xil_printf("autonegotiation complete \r\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 \r\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\r\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\r\n", link_speed);
|
||||
return link_speed;
|
||||
}
|
||||
|
@ -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
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user