Initial version
This commit is contained in:
@ -0,0 +1,432 @@
|
||||
/*
|
||||
FreeRTOS+TCP V2.0.11
|
||||
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
http://aws.amazon.com/freertos
|
||||
http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "FreeRTOS_ARP.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
/* Xilinx library files. */
|
||||
#include <xemacps.h>
|
||||
#include "Zynq/x_topology.h"
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
#include "Zynq/x_emacpsif_hw.h"
|
||||
|
||||
/* Provided memory configured as uncached. */
|
||||
#include "uncached_memory.h"
|
||||
|
||||
#ifndef niEMAC_HANDLER_TASK_PRIORITY
|
||||
#define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1
|
||||
#endif
|
||||
|
||||
#define niBMSR_LINK_STATUS 0x0004UL
|
||||
#define niBMSR_AN_COMPLETE 0x0020u /* Auto-Negotiation process completed */
|
||||
|
||||
#ifndef PHY_LS_HIGH_CHECK_TIME_MS
|
||||
/* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
|
||||
receiving packets. */
|
||||
#define PHY_LS_HIGH_CHECK_TIME_MS 15000
|
||||
#endif
|
||||
|
||||
#ifndef PHY_LS_LOW_CHECK_TIME_MS
|
||||
/* Check if the LinkSStatus in the PHY is still low every second. */
|
||||
#define PHY_LS_LOW_CHECK_TIME_MS 1000
|
||||
#endif
|
||||
|
||||
/* The size of each buffer when BufferAllocation_1 is used:
|
||||
http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */
|
||||
#define niBUFFER_1_PACKET_SIZE 1536
|
||||
|
||||
/* Naming and numbering of PHY registers. */
|
||||
#define PHY_REG_01_BMSR 0x01 /* Basic mode status register */
|
||||
|
||||
#ifndef iptraceEMAC_TASK_STARTING
|
||||
#define iptraceEMAC_TASK_STARTING() do { } while( 0 )
|
||||
#endif
|
||||
|
||||
/* Default the size of the stack used by the EMAC deferred handler task to twice
|
||||
the size of the stack used by the idle task - but allow this to be overridden in
|
||||
FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
|
||||
#ifndef configEMAC_TASK_STACK_SIZE
|
||||
#define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE )
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Look for the link to be up every few milliseconds until either xMaxTime time
|
||||
* has passed or a link is found.
|
||||
*/
|
||||
static BaseType_t prvGMACWaitLS( TickType_t xMaxTime );
|
||||
|
||||
/*
|
||||
* A deferred interrupt handler for all MAC/DMA interrupt sources.
|
||||
*/
|
||||
static void prvEMACHandlerTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* EMAC data/descriptions. */
|
||||
static xemacpsif_s xEMACpsif;
|
||||
struct xtopology_t xXTopology =
|
||||
{
|
||||
.emac_baseaddr = XPAR_PS7_ETHERNET_0_BASEADDR,
|
||||
.emac_type = xemac_type_emacps,
|
||||
.intc_baseaddr = 0x0,
|
||||
.intc_emac_intr = 0x0,
|
||||
.scugic_baseaddr = XPAR_PS7_SCUGIC_0_BASEADDR,
|
||||
.scugic_emac_intr = 0x36,
|
||||
};
|
||||
|
||||
XEmacPs_Config mac_config =
|
||||
{
|
||||
.DeviceId = XPAR_PS7_ETHERNET_0_DEVICE_ID, /**< Unique ID of device */
|
||||
.BaseAddress = XPAR_PS7_ETHERNET_0_BASEADDR /**< Physical base address of IPIF registers */
|
||||
};
|
||||
|
||||
extern int phy_detected;
|
||||
|
||||
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
|
||||
static uint32_t ulPHYLinkStatus = 0;
|
||||
|
||||
#if( ipconfigUSE_LLMNR == 1 )
|
||||
static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
|
||||
#endif
|
||||
|
||||
/* ucMACAddress as it appears in main.c */
|
||||
extern const uint8_t ucMACAddress[ 6 ];
|
||||
|
||||
/* Holds the handle of the task used as a deferred interrupt processor. The
|
||||
handle is used so direct notifications can be sent to the task for all EMAC/DMA
|
||||
related interrupts. */
|
||||
TaskHandle_t xEMACTaskHandle = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceInitialise( void )
|
||||
{
|
||||
uint32_t ulLinkSpeed, ulDMAReg;
|
||||
BaseType_t xStatus, xLinkStatus;
|
||||
XEmacPs *pxEMAC_PS;
|
||||
const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pdMS_TO_TICKS( 1000UL );
|
||||
|
||||
/* Guard against the init function being called more than once. */
|
||||
if( xEMACTaskHandle == NULL )
|
||||
{
|
||||
pxEMAC_PS = &( xEMACpsif.emacps );
|
||||
memset( &xEMACpsif, '\0', sizeof( xEMACpsif ) );
|
||||
|
||||
xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &mac_config, mac_config.BaseAddress);
|
||||
if( xStatus != XST_SUCCESS )
|
||||
{
|
||||
FreeRTOS_printf( ( "xEMACInit: EmacPs Configuration Failed....\n" ) );
|
||||
}
|
||||
|
||||
/* Initialize the mac and set the MAC address. */
|
||||
XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) ucMACAddress, 1 );
|
||||
|
||||
#if( ipconfigUSE_LLMNR == 1 )
|
||||
{
|
||||
/* Also add LLMNR multicast MAC address. */
|
||||
XEmacPs_SetMacAddress( pxEMAC_PS, ( void * )xLLMNR_MACAddress, 2 );
|
||||
}
|
||||
#endif /* ipconfigUSE_LLMNR == 1 */
|
||||
|
||||
XEmacPs_SetMdioDivisor( pxEMAC_PS, MDC_DIV_224 );
|
||||
ulLinkSpeed = Phy_Setup( pxEMAC_PS );
|
||||
XEmacPs_SetOperatingSpeed( pxEMAC_PS, ulLinkSpeed);
|
||||
|
||||
/* Setting the operating speed of the MAC needs a delay. */
|
||||
vTaskDelay( pdMS_TO_TICKS( 25UL ) );
|
||||
|
||||
ulDMAReg = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET);
|
||||
|
||||
/* DISC_WHEN_NO_AHB: when set, the GEM DMA will automatically discard receive
|
||||
packets from the receiver packet buffer memory when no AHB resource is available. */
|
||||
XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
|
||||
ulDMAReg | XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK);
|
||||
|
||||
setup_isr( &xEMACpsif );
|
||||
init_dma( &xEMACpsif );
|
||||
start_emacps( &xEMACpsif );
|
||||
|
||||
prvGMACWaitLS( xWaitLinkDelay );
|
||||
|
||||
/* The deferred interrupt handler task is created at the highest
|
||||
possible priority to ensure the interrupt handler can return directly
|
||||
to it. The task's handle is stored in xEMACTaskHandle so interrupts can
|
||||
notify the task when there is something to process. */
|
||||
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Initialisation was already performed, just wait for the link. */
|
||||
prvGMACWaitLS( xWaitRelinkDelay );
|
||||
}
|
||||
|
||||
/* Only return pdTRUE when the Link Status of the PHY is high, otherwise the
|
||||
DHCP process and all other communication will fail. */
|
||||
xLinkStatus = xGetPhyLinkStatus();
|
||||
|
||||
return ( xLinkStatus != pdFALSE );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, BaseType_t bReleaseAfterSend )
|
||||
{
|
||||
if( xCheckLoopback( pxBuffer, bReleaseAfterSend ) != 0 )
|
||||
{
|
||||
/* The packet has been sent back to the IP-task.
|
||||
The IP-task will further handle it.
|
||||
Do not release the descriptor. */
|
||||
return pdTRUE;
|
||||
}
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
|
||||
{
|
||||
ProtocolPacket_t *pxPacket;
|
||||
|
||||
/* If the peripheral must calculate the checksum, it wants
|
||||
the protocol checksum to have a value of zero. */
|
||||
pxPacket = ( ProtocolPacket_t * ) ( pxBuffer->pucEthernetBuffer );
|
||||
if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP )
|
||||
{
|
||||
IPHeader_t *pxIPHeader = &( pxPacket->xUDPPacket.xIPHeader );
|
||||
|
||||
pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u;
|
||||
pxIPHeader->usHeaderChecksum = 0u;
|
||||
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
|
||||
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
|
||||
|
||||
usGenerateProtocolChecksum( (uint8_t*)&( pxPacket->xUDPPacket ), pxBuffer->xDataLength, pdTRUE );
|
||||
}
|
||||
}
|
||||
#endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
iptraceNETWORK_INTERFACE_TRANSMIT();
|
||||
emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend );
|
||||
}
|
||||
else if( bReleaseAfterSend != pdFALSE )
|
||||
{
|
||||
/* No link. */
|
||||
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
||||
}
|
||||
|
||||
return pdTRUE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static inline unsigned long ulReadMDIO( unsigned ulRegister )
|
||||
{
|
||||
uint16_t usValue;
|
||||
|
||||
XEmacPs_PhyRead( &( xEMACpsif.emacps ), phy_detected, ulRegister, &usValue );
|
||||
return usValue;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t prvGMACWaitLS( TickType_t xMaxTime )
|
||||
{
|
||||
TickType_t xStartTime, xEndTime;
|
||||
const TickType_t xShortDelay = pdMS_TO_TICKS( 20UL );
|
||||
BaseType_t xReturn;
|
||||
|
||||
xStartTime = xTaskGetTickCount();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
xEndTime = xTaskGetTickCount();
|
||||
|
||||
if( xEndTime - xStartTime > xMaxTime )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
break;
|
||||
}
|
||||
ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
|
||||
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay( xShortDelay );
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
|
||||
{
|
||||
static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );
|
||||
uint8_t *ucRAMBuffer = ucNetworkPackets;
|
||||
uint32_t ul;
|
||||
|
||||
for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
|
||||
{
|
||||
pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;
|
||||
*( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );
|
||||
ucRAMBuffer += niBUFFER_1_PACKET_SIZE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xGetPhyLinkStatus( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) == 0 )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEMACHandlerTask( void *pvParameters )
|
||||
{
|
||||
TimeOut_t xPhyTime;
|
||||
TickType_t xPhyRemTime;
|
||||
UBaseType_t uxCurrentCount;
|
||||
BaseType_t xResult = 0;
|
||||
uint32_t xStatus;
|
||||
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
|
||||
UBaseType_t uxLastMinBufferCount = 0;
|
||||
UBaseType_t uxCurrentBufferCount = 0;
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* A possibility to set some additional task properties like calling
|
||||
portTASK_USES_FLOATING_POINT() */
|
||||
iptraceEMAC_TASK_STARTING();
|
||||
|
||||
vTaskSetTimeOutState( &xPhyTime );
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers();
|
||||
if( uxLastMinBufferCount != uxCurrentBufferCount )
|
||||
{
|
||||
/* The logging produced below may be helpful
|
||||
while tuning +TCP: see how many buffers are in use. */
|
||||
uxLastMinBufferCount = uxCurrentBufferCount;
|
||||
FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
|
||||
uxGetNumberOfFreeNetworkBuffers(), uxCurrentBufferCount ) );
|
||||
}
|
||||
|
||||
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
|
||||
{
|
||||
static UBaseType_t uxLastMinQueueSpace = 0;
|
||||
|
||||
uxCurrentCount = uxGetMinimumIPQueueSpace();
|
||||
if( uxLastMinQueueSpace != uxCurrentCount )
|
||||
{
|
||||
/* The logging produced below may be helpful
|
||||
while tuning +TCP: see how many buffers are in use. */
|
||||
uxLastMinQueueSpace = uxCurrentCount;
|
||||
FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
|
||||
}
|
||||
}
|
||||
#endif /* ipconfigCHECK_IP_QUEUE_SPACE */
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_ALL_EVENT ) == 0 )
|
||||
{
|
||||
/* No events to process now, wait for the next. */
|
||||
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
|
||||
}
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_RX_EVENT ) != 0 )
|
||||
{
|
||||
xEMACpsif.isr_events &= ~EMAC_IF_RX_EVENT;
|
||||
xResult = emacps_check_rx( &xEMACpsif );
|
||||
}
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_TX_EVENT ) != 0 )
|
||||
{
|
||||
xEMACpsif.isr_events &= ~EMAC_IF_TX_EVENT;
|
||||
emacps_check_tx( &xEMACpsif );
|
||||
}
|
||||
|
||||
if( ( xEMACpsif.isr_events & EMAC_IF_ERR_EVENT ) != 0 )
|
||||
{
|
||||
xEMACpsif.isr_events &= ~EMAC_IF_ERR_EVENT;
|
||||
emacps_check_errors( &xEMACpsif );
|
||||
}
|
||||
if( xResult > 0 )
|
||||
{
|
||||
/* A packet was received. No need to check for the PHY status now,
|
||||
but set a timer to check it later on. */
|
||||
vTaskSetTimeOutState( &xPhyTime );
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
|
||||
xResult = 0;
|
||||
/* Indicate that the Link Status is high, so that
|
||||
xNetworkInterfaceOutput() can send packets. */
|
||||
ulPHYLinkStatus |= niBMSR_LINK_STATUS;
|
||||
}
|
||||
else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
|
||||
{
|
||||
xStatus = ulReadMDIO( PHY_REG_01_BMSR );
|
||||
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != ( xStatus & niBMSR_LINK_STATUS ) )
|
||||
{
|
||||
ulPHYLinkStatus = xStatus;
|
||||
FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) );
|
||||
}
|
||||
|
||||
vTaskSetTimeOutState( &xPhyTime );
|
||||
if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 )
|
||||
{
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
|
||||
}
|
||||
else
|
||||
{
|
||||
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
@ -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,132 @@
|
||||
/*
|
||||
* uncached_memory.c
|
||||
*
|
||||
* This module will declare 1 MB of memory and switch off the caching for it.
|
||||
*
|
||||
* pucGetUncachedMemory( ulSize ) returns a trunc of this memory with a length
|
||||
* rounded up to a multiple of 4 KB
|
||||
*
|
||||
* ucIsCachedMemory( pucBuffer ) returns non-zero if a given pointer is NOT
|
||||
* within the range of the 1 MB non-cached memory.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* After "_end", 1 MB of uncached memory will be allocated for DMA transfers.
|
||||
* Both the DMA descriptors as well as all EMAC TX-buffers will be allocated in
|
||||
* uncached memory.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
#include "Zynq/x_topology.h"
|
||||
#include "xstatus.h"
|
||||
|
||||
#include "xparameters.h"
|
||||
#include "xparameters_ps.h"
|
||||
#include "xil_exception.h"
|
||||
#include "xil_mmu.h"
|
||||
|
||||
#include "uncached_memory.h"
|
||||
|
||||
#define UNCACHED_MEMORY_SIZE 0x100000ul
|
||||
|
||||
#define DDR_MEMORY_END (XPAR_PS7_DDR_0_S_AXI_HIGHADDR+1)
|
||||
|
||||
static void vInitialiseUncachedMemory( void );
|
||||
|
||||
static uint8_t *pucHeadOfMemory;
|
||||
static uint32_t ulMemorySize;
|
||||
static uint8_t *pucStartOfMemory = NULL;
|
||||
|
||||
uint8_t ucIsCachedMemory( const uint8_t *pucBuffer )
|
||||
{
|
||||
uint8_t ucReturn;
|
||||
|
||||
if( ( pucStartOfMemory != NULL ) &&
|
||||
( pucBuffer >= pucStartOfMemory ) &&
|
||||
( pucBuffer < ( pucStartOfMemory + UNCACHED_MEMORY_SIZE ) ) )
|
||||
{
|
||||
ucReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ucReturn = pdTRUE;
|
||||
}
|
||||
|
||||
return ucReturn;
|
||||
}
|
||||
|
||||
uint8_t *pucGetUncachedMemory( uint32_t ulSize )
|
||||
{
|
||||
uint8_t *pucReturn;
|
||||
|
||||
if( pucStartOfMemory == NULL )
|
||||
{
|
||||
vInitialiseUncachedMemory( );
|
||||
}
|
||||
if( ( pucStartOfMemory == NULL ) || ( ulSize > ulMemorySize ) )
|
||||
{
|
||||
pucReturn = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t ulSkipSize;
|
||||
|
||||
pucReturn = pucHeadOfMemory;
|
||||
ulSkipSize = ( ulSize + 0x1000ul ) & ~0xffful;
|
||||
pucHeadOfMemory += ulSkipSize;
|
||||
ulMemorySize -= ulSkipSize;
|
||||
}
|
||||
|
||||
return pucReturn;
|
||||
}
|
||||
|
||||
extern u8 _end;
|
||||
|
||||
static void vInitialiseUncachedMemory( )
|
||||
{
|
||||
/* At the end of program's space... */
|
||||
pucStartOfMemory = (uint8_t *) &_end;
|
||||
/*
|
||||
* Align the start address to 1 MB boundary.
|
||||
*/
|
||||
pucStartOfMemory = (uint8_t *)( ( ( uint32_t )pucStartOfMemory + UNCACHED_MEMORY_SIZE ) & ( ~( UNCACHED_MEMORY_SIZE - 1 ) ) );
|
||||
|
||||
if( ( ( u32 )pucStartOfMemory ) + UNCACHED_MEMORY_SIZE > DDR_MEMORY_END )
|
||||
{
|
||||
// vLoggingPrintf("vInitialiseUncachedMemory: Can not allocate uncached memory\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Some objects want to be stored in uncached memory. Hence the 1 MB
|
||||
* address range that starts after "_end" is made uncached
|
||||
* by setting appropriate attributes in the translation table.
|
||||
*/
|
||||
/* FIXME claudio rossi. Modified to prevent data abort exception (misaligned access)
|
||||
* when application is compiled with -O1 or more optimization flag.
|
||||
*/
|
||||
/* Xil_SetTlbAttributes( ( uint32_t )pucStartOfMemory, 0xc02 ); // addr, attr */
|
||||
Xil_SetTlbAttributes( ( uint32_t )pucStartOfMemory, 0x1c02 ); // addr, attr
|
||||
|
||||
/* For experiments in the SDIO driver, make the remaining uncached memory public */
|
||||
pucHeadOfMemory = pucStartOfMemory;
|
||||
ulMemorySize = UNCACHED_MEMORY_SIZE;
|
||||
memset( pucStartOfMemory, '\0', UNCACHED_MEMORY_SIZE );
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* uncached_memory.h
|
||||
*
|
||||
* This module will declare 1 MB of memory and switch off the caching for it.
|
||||
*
|
||||
* pucGetUncachedMemory( ulSize ) returns a trunc of this memory with a length
|
||||
* rounded up to a multiple of 4 KB
|
||||
*
|
||||
* ucIsCachedMemory( pucBuffer ) returns non-zero if a given pointer is NOT
|
||||
* within the range of the 1 MB non-cached memory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UNCACHEMEMORY_H
|
||||
|
||||
#define UNCACHEMEMORY_H
|
||||
|
||||
uint8_t *pucGetUncachedMemory( uint32_t ulSize );
|
||||
|
||||
uint8_t ucIsCachedMemory( const uint8_t *pucBuffer );
|
||||
|
||||
#endif /* UNCACHEMEMORY_H */
|
||||
|
@ -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,663 @@
|
||||
/*
|
||||
FreeRTOS+TCP V2.0.11
|
||||
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
http://aws.amazon.com/freertos
|
||||
http://www.FreeRTOS.org
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
#include "Zynq/x_topology.h"
|
||||
#include "xstatus.h"
|
||||
|
||||
#include "xparameters.h"
|
||||
#include "xparameters_ps.h"
|
||||
#include "xil_exception.h"
|
||||
#include "xil_mmu.h"
|
||||
|
||||
#include "uncached_memory.h"
|
||||
|
||||
/* Two defines used to set or clear the EMAC interrupt */
|
||||
#define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
|
||||
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
|
||||
|
||||
|
||||
|
||||
#if( ipconfigPACKET_FILLER_SIZE != 2 )
|
||||
#error Please define ipconfigPACKET_FILLER_SIZE as the value '2'
|
||||
#endif
|
||||
#define TX_OFFSET ipconfigPACKET_FILLER_SIZE
|
||||
|
||||
/* Defined in NetworkInterface.c */
|
||||
extern TaskHandle_t xEMACTaskHandle;
|
||||
|
||||
/*
|
||||
pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.
|
||||
The actual TX buffers are located in uncached RAM.
|
||||
*/
|
||||
static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };
|
||||
|
||||
/*
|
||||
pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.
|
||||
Once a message has been received by the EMAC, the descriptor can be passed
|
||||
immediately to the IP-task.
|
||||
*/
|
||||
static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };
|
||||
|
||||
/*
|
||||
The FreeRTOS+TCP port is using a fixed 'topology', which is declared in
|
||||
./portable/NetworkInterface/Zynq/NetworkInterface.c
|
||||
*/
|
||||
extern struct xtopology_t xXTopology;
|
||||
|
||||
static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
|
||||
|
||||
/*
|
||||
The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".
|
||||
In stead 'struct xemacpsif_s' has a "head" and a "tail" index.
|
||||
"head" is the next index to be written, used.
|
||||
"tail" is the next index to be read, freed.
|
||||
*/
|
||||
|
||||
int is_tx_space_available( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
size_t uxCount;
|
||||
|
||||
if( xTXDescriptorSemaphore != NULL )
|
||||
{
|
||||
uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
|
||||
}
|
||||
else
|
||||
{
|
||||
uxCount = ( UBaseType_t ) 0u;
|
||||
}
|
||||
|
||||
return uxCount;
|
||||
}
|
||||
|
||||
void emacps_check_tx( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
int tail = xemacpsif->txTail;
|
||||
int head = xemacpsif->txHead;
|
||||
size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );
|
||||
|
||||
/* uxCount is the number of TX descriptors that are in use by the DMA. */
|
||||
/* When done, "TXBUF_USED" will be set. */
|
||||
|
||||
while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )
|
||||
{
|
||||
if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
#warning ipconfigZERO_COPY_TX_DRIVER is defined
|
||||
{
|
||||
void *pvBuffer = pxDMA_tx_buffers[ tail ];
|
||||
NetworkBufferDescriptor_t *pxBuffer;
|
||||
|
||||
if( pvBuffer != NULL )
|
||||
{
|
||||
pxDMA_tx_buffers[ tail ] = NULL;
|
||||
pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );
|
||||
if( pxBuffer != NULL )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Clear all but the "used" and "wrap" bits. */
|
||||
if( tail < ipconfigNIC_N_TX_DESC - 1 )
|
||||
{
|
||||
xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
|
||||
}
|
||||
uxCount--;
|
||||
/* Tell the counting semaphore that one more TX descriptor is available. */
|
||||
xSemaphoreGive( xTXDescriptorSemaphore );
|
||||
if( ++tail == ipconfigNIC_N_TX_DESC )
|
||||
{
|
||||
tail = 0;
|
||||
}
|
||||
xemacpsif->txTail = tail;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void emacps_send_handler(void *arg)
|
||||
{
|
||||
xemacpsif_s *xemacpsif;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
|
||||
/* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in
|
||||
"isr_events". The task in NetworkInterface will wake-up and do the necessary work.
|
||||
*/
|
||||
xemacpsif->isr_events |= EMAC_IF_TX_EVENT;
|
||||
xemacpsif->txBusy = pdFALSE;
|
||||
|
||||
if( xEMACTaskHandle != NULL )
|
||||
{
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
static BaseType_t xValidLength( BaseType_t xLength )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )
|
||||
{
|
||||
int head = xemacpsif->txHead;
|
||||
//int tail = xemacpsif->txTail;
|
||||
int iHasSent = 0;
|
||||
uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;
|
||||
TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );
|
||||
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
{
|
||||
/* This driver wants to own all network buffers which are to be transmitted. */
|
||||
configASSERT( iReleaseAfterSend != pdFALSE );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open a do {} while ( 0 ) loop to be able to call break. */
|
||||
do
|
||||
{
|
||||
uint32_t ulFlags = 0;
|
||||
|
||||
if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( xTXDescriptorSemaphore == NULL )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
|
||||
{
|
||||
FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );
|
||||
break;
|
||||
}
|
||||
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
/* Pass the pointer (and its ownership) directly to DMA. */
|
||||
pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;
|
||||
if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
|
||||
}
|
||||
/* Buffer has been transferred, do not release it. */
|
||||
iReleaseAfterSend = pdFALSE;
|
||||
#else
|
||||
if( pxDMA_tx_buffers[ head ] == NULL )
|
||||
{
|
||||
FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );
|
||||
break;
|
||||
}
|
||||
/* Copy the message to unbuffered space in RAM. */
|
||||
memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );
|
||||
#endif
|
||||
/* Packets will be sent one-by-one, so for each packet
|
||||
the TXBUF_LAST bit will be set. */
|
||||
ulFlags |= XEMACPS_TXBUF_LAST_MASK;
|
||||
ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );
|
||||
if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )
|
||||
{
|
||||
ulFlags |= XEMACPS_TXBUF_WRAP_MASK;
|
||||
}
|
||||
|
||||
/* Copy the address of the buffer and set the flags. */
|
||||
xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];
|
||||
xemacpsif->txSegments[ head ].flags = ulFlags;
|
||||
|
||||
iHasSent = pdTRUE;
|
||||
if( ++head == ipconfigNIC_N_TX_DESC )
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
/* Update the TX-head index. These variable are declared volatile so they will be
|
||||
accessed as little as possible. */
|
||||
xemacpsif->txHead = head;
|
||||
} while( pdFALSE );
|
||||
|
||||
if( iReleaseAfterSend != pdFALSE )
|
||||
{
|
||||
vReleaseNetworkBufferAndDescriptor( pxBuffer );
|
||||
pxBuffer = NULL;
|
||||
}
|
||||
|
||||
/* Data Synchronization Barrier */
|
||||
dsb();
|
||||
|
||||
if( iHasSent != pdFALSE )
|
||||
{
|
||||
/* Make STARTTX high */
|
||||
uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);
|
||||
/* Start transmit */
|
||||
xemacpsif->txBusy = pdTRUE;
|
||||
XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );
|
||||
}
|
||||
dsb();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void emacps_recv_handler(void *arg)
|
||||
{
|
||||
xemacpsif_s *xemacpsif;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
xemacpsif->isr_events |= EMAC_IF_RX_EVENT;
|
||||
|
||||
if( xEMACTaskHandle != NULL )
|
||||
{
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
static void passEthMessages( NetworkBufferDescriptor_t *ethMsg )
|
||||
{
|
||||
IPStackEvent_t xRxEvent;
|
||||
|
||||
xRxEvent.eEventType = eNetworkRxEvent;
|
||||
xRxEvent.pvData = ( void * ) ethMsg;
|
||||
|
||||
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )
|
||||
{
|
||||
/* The buffer could not be sent to the stack so must be released again.
|
||||
This is a deferred handler taskr, not a real interrupt, so it is ok to
|
||||
use the task level function here. */
|
||||
do
|
||||
{
|
||||
NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;
|
||||
vReleaseNetworkBufferAndDescriptor( ethMsg );
|
||||
ethMsg = xNext;
|
||||
} while( ethMsg != NULL );
|
||||
|
||||
iptraceETHERNET_RX_EVENT_LOST();
|
||||
FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );
|
||||
}
|
||||
}
|
||||
|
||||
TickType_t ack_reception_delay = 10;
|
||||
|
||||
int emacps_check_rx( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;
|
||||
int rx_bytes;
|
||||
volatile int msgCount = 0;
|
||||
int head = xemacpsif->rxHead;
|
||||
BaseType_t bHasDataPacket = pdFALSE;
|
||||
NetworkBufferDescriptor_t *ethMsg = NULL;
|
||||
NetworkBufferDescriptor_t *ethLast = NULL;
|
||||
|
||||
/* There seems to be an issue (SI# 692601), see comments below. */
|
||||
resetrx_on_no_rxdata(xemacpsif);
|
||||
|
||||
{
|
||||
static int maxcount = 0;
|
||||
int count = 0;
|
||||
for( ;; )
|
||||
{
|
||||
if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
|
||||
( pxDMA_rx_buffers[ head ] == NULL ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
if( ++head == ipconfigNIC_N_RX_DESC )
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
if( head == xemacpsif->rxHead )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (maxcount < count) {
|
||||
maxcount = count;
|
||||
FreeRTOS_printf( ( "emacps_check_rx: %d packets\n", maxcount ) );
|
||||
}
|
||||
head = xemacpsif->rxHead;
|
||||
}
|
||||
|
||||
/* This FreeRTOS+TCP driver shall be compiled with the option
|
||||
"ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a
|
||||
chain of RX messages within one message to the IP-task. */
|
||||
for( ;; )
|
||||
{
|
||||
if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||
|
||||
( pxDMA_rx_buffers[ head ] == NULL ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
|
||||
if( pxNewBuffer == NULL )
|
||||
{
|
||||
/* A packet has been received, but there is no replacement for this Network Buffer.
|
||||
The packet will be dropped, and it Network Buffer will stay in place. */
|
||||
FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );
|
||||
pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];
|
||||
|
||||
/* Just avoiding to use or refer to the same buffer again */
|
||||
pxDMA_rx_buffers[ head ] = pxNewBuffer;
|
||||
|
||||
/*
|
||||
* Adjust the buffer size to the actual number of bytes received.
|
||||
*/
|
||||
rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;
|
||||
|
||||
pxBuffer->xDataLength = rx_bytes;
|
||||
if( rx_bytes > 60 )
|
||||
{
|
||||
bHasDataPacket = 1;
|
||||
}
|
||||
if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );
|
||||
}
|
||||
|
||||
/* store it in the receive queue, where it'll be processed by a
|
||||
different handler. */
|
||||
iptraceNETWORK_INTERFACE_RECEIVE();
|
||||
pxBuffer->pxNextBuffer = NULL;
|
||||
|
||||
if( ethMsg == NULL )
|
||||
{
|
||||
// Becomes the first message
|
||||
ethMsg = pxBuffer;
|
||||
}
|
||||
else if( ethLast != NULL )
|
||||
{
|
||||
// Add to the tail
|
||||
ethLast->pxNextBuffer = pxBuffer;
|
||||
}
|
||||
|
||||
ethLast = pxBuffer;
|
||||
msgCount++;
|
||||
}
|
||||
{
|
||||
if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
|
||||
}
|
||||
{
|
||||
uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
|
||||
if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )
|
||||
{
|
||||
addr |= XEMACPS_RXBUF_WRAP_MASK;
|
||||
}
|
||||
/* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */
|
||||
xemacpsif->rxSegments[ head ].flags = 0;
|
||||
xemacpsif->rxSegments[ head ].address = addr;
|
||||
if (xemacpsif->rxSegments[ head ].address) {
|
||||
// Just to read it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( ++head == ipconfigNIC_N_RX_DESC )
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
xemacpsif->rxHead = head;
|
||||
}
|
||||
|
||||
if( ethMsg != NULL )
|
||||
{
|
||||
if( bHasDataPacket == pdFALSE )
|
||||
{
|
||||
// vTaskDelay( ack_reception_delay );
|
||||
}
|
||||
passEthMessages( ethMsg );
|
||||
}
|
||||
|
||||
return msgCount;
|
||||
}
|
||||
|
||||
void clean_dma_txdescs(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
int index;
|
||||
unsigned char *ucTxBuffer;
|
||||
|
||||
/* Clear all TX descriptors and assign uncached memory to each descriptor.
|
||||
"tx_space" points to the first available TX buffer. */
|
||||
ucTxBuffer = xemacpsif->tx_space;
|
||||
|
||||
for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )
|
||||
{
|
||||
xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;
|
||||
xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;
|
||||
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
|
||||
pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;
|
||||
#else
|
||||
pxDMA_tx_buffers[ index ] = ( unsigned char * )( ucTxBuffer + TX_OFFSET );
|
||||
#endif
|
||||
ucTxBuffer += xemacpsif->uTxUnitSize;
|
||||
}
|
||||
xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =
|
||||
XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;
|
||||
}
|
||||
|
||||
XStatus init_dma(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
NetworkBufferDescriptor_t *pxBuffer;
|
||||
|
||||
int iIndex;
|
||||
UBaseType_t xRxSize;
|
||||
UBaseType_t xTxSize;
|
||||
struct xtopology_t *xtopologyp = &xXTopology;
|
||||
|
||||
xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );
|
||||
|
||||
xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );
|
||||
|
||||
/* Also round-up to 4KB */
|
||||
xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;
|
||||
/*
|
||||
* We allocate 65536 bytes for RX BDs which can accommodate a
|
||||
* maximum of 8192 BDs which is much more than any application
|
||||
* will ever need.
|
||||
*/
|
||||
xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) );
|
||||
xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );
|
||||
xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );
|
||||
|
||||
/* These variables will be used in XEmacPs_Start (see src/xemacps.c). */
|
||||
xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;
|
||||
xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;
|
||||
|
||||
if( xTXDescriptorSemaphore == NULL )
|
||||
{
|
||||
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );
|
||||
configASSERT( xTXDescriptorSemaphore );
|
||||
}
|
||||
/*
|
||||
* Allocate RX descriptors, 1 RxBD at a time.
|
||||
*/
|
||||
for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )
|
||||
{
|
||||
pxBuffer = pxDMA_rx_buffers[ iIndex ];
|
||||
if( pxBuffer == NULL )
|
||||
{
|
||||
pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );
|
||||
if( pxBuffer == NULL )
|
||||
{
|
||||
FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
xemacpsif->rxSegments[ iIndex ].flags = 0;
|
||||
xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;
|
||||
|
||||
pxDMA_rx_buffers[ iIndex ] = pxBuffer;
|
||||
/* Make sure this memory is not in cache for now. */
|
||||
if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )
|
||||
{
|
||||
Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,
|
||||
(unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );
|
||||
}
|
||||
}
|
||||
|
||||
xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;
|
||||
|
||||
memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );
|
||||
|
||||
clean_dma_txdescs( xemacpsif );
|
||||
|
||||
{
|
||||
uint32_t value;
|
||||
value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );
|
||||
|
||||
// 1xxxx: Attempt to use INCR16 AHB bursts
|
||||
value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;
|
||||
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )
|
||||
value |= XEMACPS_DMACR_TCPCKSUM_MASK;
|
||||
#else
|
||||
#warning Are you sure the EMAC should not calculate outgoing checksums?
|
||||
value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;
|
||||
#endif
|
||||
XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );
|
||||
}
|
||||
{
|
||||
uint32_t value;
|
||||
value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );
|
||||
|
||||
/* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).
|
||||
Now tell the EMAC that received messages should be stored at "address + 2". */
|
||||
value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;
|
||||
|
||||
#if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )
|
||||
value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
|
||||
#else
|
||||
#warning Are you sure the EMAC should not calculate incoming checksums?
|
||||
value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;
|
||||
#endif
|
||||
XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect the device driver handler that will be called when an
|
||||
* interrupt for the device occurs, the handler defined above performs
|
||||
* the specific interrupt processing for the device.
|
||||
*/
|
||||
XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
|
||||
(Xil_ExceptionHandler)XEmacPs_IntrHandler,
|
||||
(void *)&xemacpsif->emacps);
|
||||
/*
|
||||
* Enable the interrupt for emacps.
|
||||
*/
|
||||
EmacEnableIntr( );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* resetrx_on_no_rxdata():
|
||||
*
|
||||
* It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
|
||||
* called by the user.
|
||||
* The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
|
||||
* Under heavy Rx traffic because of the HW bug there are times when the Rx path
|
||||
* becomes unresponsive. The workaround for it is to check for the Rx path for
|
||||
* traffic (by reading the stats registers regularly). If the stats register
|
||||
* does not increment for sometime (proving no Rx traffic), the function resets
|
||||
* the Rx data path.
|
||||
*
|
||||
*/
|
||||
|
||||
void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
unsigned long regctrl;
|
||||
unsigned long tempcntr;
|
||||
|
||||
tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );
|
||||
if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )
|
||||
{
|
||||
FreeRTOS_printf( ( "resetrx_on_no_rxdata: RESET~\n" ) );
|
||||
regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET);
|
||||
regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET, regctrl);
|
||||
regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
|
||||
regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
|
||||
}
|
||||
xemacpsif->last_rx_frms_cntr = tempcntr;
|
||||
}
|
||||
|
||||
void EmacDisableIntr(void)
|
||||
{
|
||||
XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
|
||||
}
|
||||
|
||||
void EmacEnableIntr(void)
|
||||
{
|
||||
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);
|
||||
}
|
||||
|
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Xilinx, Inc.
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
|
||||
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
|
||||
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
|
||||
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
|
||||
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
|
||||
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
|
||||
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
|
||||
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
#include "NetworkInterface.h"
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
|
||||
extern TaskHandle_t xEMACTaskHandle;
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
|
||||
void setup_isr( xemacpsif_s *xemacpsif )
|
||||
{
|
||||
/*
|
||||
* Setup callbacks
|
||||
*/
|
||||
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
|
||||
(void *) emacps_send_handler,
|
||||
(void *) xemacpsif);
|
||||
|
||||
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
|
||||
(void *) emacps_recv_handler,
|
||||
(void *) xemacpsif);
|
||||
|
||||
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
|
||||
(void *) emacps_error_handler,
|
||||
(void *) xemacpsif);
|
||||
}
|
||||
|
||||
void start_emacps (xemacpsif_s *xemacps)
|
||||
{
|
||||
/* start the temac */
|
||||
XEmacPs_Start(&xemacps->emacps);
|
||||
}
|
||||
|
||||
extern struct xtopology_t xXTopology;
|
||||
|
||||
volatile int error_msg_count = 0;
|
||||
volatile const char *last_err_msg = "";
|
||||
|
||||
struct xERROR_MSG {
|
||||
void *arg;
|
||||
u8 Direction;
|
||||
u32 ErrorWord;
|
||||
};
|
||||
|
||||
static struct xERROR_MSG xErrorList[ 8 ];
|
||||
static BaseType_t xErrorHead, xErrorTail;
|
||||
|
||||
void emacps_error_handler(void *arg, u8 Direction, u32 ErrorWord)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xemacpsif_s *xemacpsif;
|
||||
BaseType_t xNextHead = xErrorHead;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
|
||||
if( ( Direction != XEMACPS_SEND ) || (ErrorWord != XEMACPS_TXSR_USEDREAD_MASK ) )
|
||||
{
|
||||
if( ++xNextHead == ( sizeof( xErrorList ) / sizeof( xErrorList[ 0 ] ) ) )
|
||||
xNextHead = 0;
|
||||
if( xNextHead != xErrorTail )
|
||||
{
|
||||
|
||||
xErrorList[ xErrorHead ].arg = arg;
|
||||
xErrorList[ xErrorHead ].Direction = Direction;
|
||||
xErrorList[ xErrorHead ].ErrorWord = ErrorWord;
|
||||
|
||||
xErrorHead = xNextHead;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
xemacpsif->isr_events |= EMAC_IF_ERR_EVENT;
|
||||
}
|
||||
|
||||
if( xEMACTaskHandle != NULL )
|
||||
{
|
||||
vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord);
|
||||
|
||||
int emacps_check_errors( xemacpsif_s *xemacps )
|
||||
{
|
||||
int xResult;
|
||||
|
||||
( void ) xemacps;
|
||||
|
||||
if( xErrorHead == xErrorTail )
|
||||
{
|
||||
xResult = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xResult = 1;
|
||||
emacps_handle_error(
|
||||
xErrorList[ xErrorTail ].arg,
|
||||
xErrorList[ xErrorTail ].Direction,
|
||||
xErrorList[ xErrorTail ].ErrorWord );
|
||||
}
|
||||
|
||||
return xResult;
|
||||
}
|
||||
|
||||
static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord)
|
||||
{
|
||||
xemacpsif_s *xemacpsif;
|
||||
struct xtopology_t *xtopologyp;
|
||||
XEmacPs *xemacps;
|
||||
|
||||
xemacpsif = (xemacpsif_s *)(arg);
|
||||
|
||||
xtopologyp = &xXTopology;
|
||||
|
||||
xemacps = &xemacpsif->emacps;
|
||||
|
||||
/* Do not appear to be used. */
|
||||
( void ) xemacps;
|
||||
( void ) xtopologyp;
|
||||
|
||||
last_err_msg = NULL;
|
||||
|
||||
if( ErrorWord != 0 )
|
||||
{
|
||||
switch (Direction) {
|
||||
case XEMACPS_RECV:
|
||||
if( ( ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Receive DMA error";
|
||||
xNetworkInterfaceInitialise( );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_RXSR_RXOVR_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Receive over run";
|
||||
emacps_recv_handler(arg);
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_RXSR_BUFFNA_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Receive buffer not available";
|
||||
emacps_recv_handler(arg);
|
||||
}
|
||||
break;
|
||||
case XEMACPS_SEND:
|
||||
if( ( ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit DMA error";
|
||||
xNetworkInterfaceInitialise( );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_URUN_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit under run";
|
||||
HandleTxErrors( xemacpsif );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_BUFEXH_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit buffer exhausted";
|
||||
HandleTxErrors( xemacpsif );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_RXOVR_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit retry excessed limits";
|
||||
HandleTxErrors( xemacpsif );
|
||||
}
|
||||
if( ( ErrorWord & XEMACPS_TXSR_FRAMERX_MASK ) != 0 )
|
||||
{
|
||||
last_err_msg = "Transmit collision";
|
||||
emacps_check_tx( xemacpsif );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Break on this statement and inspect error_msg if you like
|
||||
if( last_err_msg != NULL )
|
||||
{
|
||||
error_msg_count++;
|
||||
FreeRTOS_printf( ( "emacps_handle_error: %s\n", last_err_msg ) );
|
||||
}
|
||||
}
|
||||
|
||||
extern XEmacPs_Config mac_config;
|
||||
|
||||
void HandleTxErrors(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
u32 netctrlreg;
|
||||
|
||||
//taskENTER_CRITICAL()
|
||||
{
|
||||
netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET);
|
||||
netctrlreg = netctrlreg & (~XEMACPS_NWCTRL_TXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET, netctrlreg);
|
||||
|
||||
clean_dma_txdescs( xemacpsif );
|
||||
netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET);
|
||||
netctrlreg = netctrlreg | (XEMACPS_NWCTRL_TXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET, netctrlreg);
|
||||
}
|
||||
//taskEXIT_CRITICAL( );
|
||||
}
|
@ -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,581 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008, Advanced Micro Devices, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Advanced Micro Devices, Inc. nor the names
|
||||
* of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some portions copyright (c) 2010-2013 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Xilinx, Inc.
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
|
||||
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
|
||||
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
|
||||
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
|
||||
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
|
||||
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
|
||||
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
|
||||
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* FreeRTOS+TCP includes. */
|
||||
#include "FreeRTOS_IP.h"
|
||||
#include "FreeRTOS_Sockets.h"
|
||||
#include "FreeRTOS_IP_Private.h"
|
||||
#include "NetworkBufferManagement.h"
|
||||
|
||||
#include "Zynq/x_emacpsif.h"
|
||||
#include "xparameters_ps.h"
|
||||
#include "xparameters.h"
|
||||
|
||||
|
||||
int phy_detected = 0;
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
|
||||
/* Advertisement control register. */
|
||||
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
|
||||
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
|
||||
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
|
||||
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
|
||||
|
||||
#define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \
|
||||
ADVERTISE_10HALF | ADVERTISE_100HALF)
|
||||
#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF)
|
||||
#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF)
|
||||
|
||||
#define ADVERTISE_1000 0x0300
|
||||
|
||||
|
||||
//#define PHY_REG_00_BMCR 0x00 // Basic mode control register
|
||||
//#define PHY_REG_01_BMSR 0x01 // Basic mode status register
|
||||
//#define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1
|
||||
//#define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2
|
||||
//#define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg
|
||||
|
||||
#define IEEE_CONTROL_REG_OFFSET 0
|
||||
#define IEEE_STATUS_REG_OFFSET 1
|
||||
#define IEEE_PHYSID1_OFFSET 2
|
||||
#define IEEE_PHYSID2_OFFSET 3
|
||||
#define IEEE_AUTONEGO_ADVERTISE_REG 4
|
||||
#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5
|
||||
#define IEEE_1000_ADVERTISE_REG_OFFSET 9
|
||||
#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10
|
||||
#define IEEE_COPPER_SPECIFIC_CONTROL_REG 16
|
||||
#define IEEE_SPECIFIC_STATUS_REG 17
|
||||
#define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19
|
||||
#define IEEE_CONTROL_REG_MAC 21
|
||||
#define IEEE_PAGE_ADDRESS_REGISTER 22
|
||||
|
||||
|
||||
#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040
|
||||
#define IEEE_CTRL_LINKSPEED_MASK 0x0040
|
||||
#define IEEE_CTRL_LINKSPEED_1000M 0x0040
|
||||
#define IEEE_CTRL_LINKSPEED_100M 0x2000
|
||||
#define IEEE_CTRL_LINKSPEED_10M 0x0000
|
||||
#define IEEE_CTRL_RESET_MASK 0x8000
|
||||
#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#define IEEE_CTRL_RESET 0x9140
|
||||
#define IEEE_CTRL_ISOLATE_DISABLE 0xFBFF
|
||||
#endif
|
||||
#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008
|
||||
#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020
|
||||
#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200
|
||||
#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100
|
||||
#define IEEE_AN1_ABILITY_MASK 0x1FE0
|
||||
#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00
|
||||
#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380
|
||||
#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060
|
||||
#define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030
|
||||
|
||||
#define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800
|
||||
#define IEEE_PAUSE_MASK 0x0400
|
||||
#define IEEE_AUTONEG_ERROR_MASK 0x8000
|
||||
|
||||
#define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140
|
||||
#define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100
|
||||
#define XEMACPS_GMII2RGMII_SPEED10_FD 0x100
|
||||
#define XEMACPS_GMII2RGMII_REG_NUM 0x10
|
||||
|
||||
/* Frequency setting */
|
||||
#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4)
|
||||
#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
|
||||
#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
|
||||
#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
|
||||
#ifdef PEEP
|
||||
#define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031
|
||||
#define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001
|
||||
#define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011
|
||||
#endif
|
||||
#define SLCR_LOCK_KEY_VALUE 0x767B
|
||||
#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
|
||||
#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
|
||||
#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
|
||||
|
||||
#define EMAC0_BASE_ADDRESS 0xE000B000
|
||||
#define EMAC1_BASE_ADDRESS 0xE000C000
|
||||
|
||||
static int detect_phy(XEmacPs *xemacpsp)
|
||||
{
|
||||
u16 id_lower, id_upper;
|
||||
u32 phy_addr, id;
|
||||
|
||||
for (phy_addr = 0; phy_addr < 32; phy_addr++) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID1_OFFSET, &id_lower);
|
||||
|
||||
if ((id_lower != ( u16 )0xFFFFu) && (id_lower != ( u16 )0x0u)) {
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID2_OFFSET, &id_upper);
|
||||
id = ( ( ( uint32_t ) id_upper ) << 16 ) | ( id_lower & 0xFFF0 );
|
||||
FreeRTOS_printf( ("XEmacPs detect_phy: %04lX at address %d.\n", id, phy_addr ) );
|
||||
phy_detected = phy_addr;
|
||||
return phy_addr;
|
||||
}
|
||||
}
|
||||
|
||||
FreeRTOS_printf( ("XEmacPs detect_phy: No PHY detected. Assuming a PHY at address 0\n" ) );
|
||||
|
||||
/* default to zero */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PEEP
|
||||
unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
|
||||
{
|
||||
|
||||
u16 control;
|
||||
u16 status;
|
||||
u16 partner_capabilities;
|
||||
u16 partner_capabilities_1000;
|
||||
u16 phylinkspeed;
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
ADVERTISE_1000);
|
||||
/* Advertise PHY speed of 100 and 10 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_100_AND_10);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
|
||||
&control);
|
||||
control |= (IEEE_CTRL_AUTONEGOTIATE_ENABLE |
|
||||
IEEE_STAT_AUTONEGOTIATE_RESTART);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
/* Read PHY control and status registers is successful. */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
|
||||
|
||||
if ((control & IEEE_CTRL_AUTONEGOTIATE_ENABLE) && (status &
|
||||
IEEE_STAT_AUTONEGOTIATE_CAPABLE)) {
|
||||
|
||||
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
|
||||
&status);
|
||||
}
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET,
|
||||
&partner_capabilities);
|
||||
|
||||
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_3_REG_OFFSET,
|
||||
&partner_capabilities_1000);
|
||||
if (partner_capabilities_1000 & IEEE_AN3_ABILITY_MASK_1GBPS)
|
||||
return 1000;
|
||||
}
|
||||
|
||||
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_100MBPS)
|
||||
return 100;
|
||||
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS)
|
||||
return 10;
|
||||
|
||||
xil_printf("%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\n",
|
||||
__FUNCTION__);
|
||||
return 10;
|
||||
|
||||
} else {
|
||||
|
||||
/* Update TEMAC speed accordingly */
|
||||
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
|
||||
/* Get commanded link speed */
|
||||
phylinkspeed = control & IEEE_CTRL_1GBPS_LINKSPEED_MASK;
|
||||
|
||||
switch (phylinkspeed) {
|
||||
case (IEEE_CTRL_LINKSPEED_1000M):
|
||||
return 1000;
|
||||
case (IEEE_CTRL_LINKSPEED_100M):
|
||||
return 100;
|
||||
case (IEEE_CTRL_LINKSPEED_10M):
|
||||
return 10;
|
||||
default:
|
||||
xil_printf("%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\n",
|
||||
__FUNCTION__, phylinkspeed);
|
||||
return 10;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
return (control & IEEE_CTRL_LINKSPEED_MASK) ? 100 : 10;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else /* Zynq */
|
||||
unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
|
||||
{
|
||||
u16 temp;
|
||||
u16 control;
|
||||
u16 status;
|
||||
u16 partner_capabilities;
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
u32 phy_addr = XPAR_PCSPMA_SGMII_PHYADDR;
|
||||
#else
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
#endif
|
||||
xil_printf("Start PHY autonegotiation \n");
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
|
||||
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
control |= IEEE_PAUSE_MASK;
|
||||
control |= ADVERTISE_100;
|
||||
control |= ADVERTISE_10;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
&control);
|
||||
control |= ADVERTISE_1000;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
&control);
|
||||
control |= (7 << 12); /* max number of gigabit attempts */
|
||||
control |= (1 << 11); /* enable downshift */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
control);
|
||||
#endif
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
|
||||
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
control &= IEEE_CTRL_ISOLATE_DISABLE;
|
||||
#endif
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_RESET_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
while (1) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
if (control & IEEE_CTRL_RESET_MASK)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
xil_printf("Waiting for PHY to complete autonegotiation.\n");
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
|
||||
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
|
||||
sleep(1);
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2,
|
||||
&temp);
|
||||
if (temp & IEEE_AUTONEG_ERROR_MASK) {
|
||||
xil_printf("Auto negotiation error \n");
|
||||
}
|
||||
#endif
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
|
||||
&status);
|
||||
}
|
||||
|
||||
xil_printf("autonegotiation complete \n");
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &partner_capabilities);
|
||||
#endif
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1
|
||||
xil_printf("Waiting for Link to be up; Polling for SGMII core Reg \n");
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp);
|
||||
while(!(temp & 0x8000)) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp);
|
||||
}
|
||||
if((temp & 0x0C00) == 0x0800) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
return 1000;
|
||||
}
|
||||
else if((temp & 0x0C00) == 0x0400) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
return 100;
|
||||
}
|
||||
else if((temp & 0x0C00) == 0x0000) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
return 10;
|
||||
} else {
|
||||
xil_printf("get_IEEE_phy_speed(): Invalid speed bit value, Deafulting to Speed = 10 Mbps\n");
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, 0, 0x0100);
|
||||
return 10;
|
||||
}
|
||||
#else
|
||||
if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */
|
||||
return 1000;
|
||||
else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */
|
||||
return 100;
|
||||
else /* 10Mbps */
|
||||
return 10;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned configure_IEEE_phy_speed(XEmacPs *xemacpsp, unsigned speed)
|
||||
{
|
||||
u16 control;
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
|
||||
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
control |= IEEE_PAUSE_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control &= ~IEEE_CTRL_LINKSPEED_1000M;
|
||||
control &= ~IEEE_CTRL_LINKSPEED_100M;
|
||||
control &= ~IEEE_CTRL_LINKSPEED_10M;
|
||||
|
||||
if (speed == 1000) {
|
||||
control |= IEEE_CTRL_LINKSPEED_1000M;
|
||||
}
|
||||
|
||||
else if (speed == 100) {
|
||||
control |= IEEE_CTRL_LINKSPEED_100M;
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, 0);
|
||||
/* Dont advertise PHY speed of 10 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_100);
|
||||
}
|
||||
|
||||
else if (speed == 10) {
|
||||
control |= IEEE_CTRL_LINKSPEED_10M;
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
0);
|
||||
/* Dont advertise PHY speed of 100 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_10);
|
||||
}
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
|
||||
control | IEEE_CTRL_RESET_MASK);
|
||||
{
|
||||
volatile int wait;
|
||||
for (wait=0; wait < 100000; wait++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetUpSLCRDivisors(int mac_baseaddr, int speed)
|
||||
{
|
||||
volatile u32 slcrBaseAddress;
|
||||
#ifndef PEEP
|
||||
u32 SlcrDiv0;
|
||||
u32 SlcrDiv1=0;
|
||||
u32 SlcrTxClkCntrl;
|
||||
#endif
|
||||
|
||||
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
|
||||
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR;
|
||||
} else {
|
||||
slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR;
|
||||
}
|
||||
#ifdef PEEP
|
||||
if (speed == 1000) {
|
||||
*(volatile unsigned int *)(slcrBaseAddress) =
|
||||
SLCR_GEM_1G_CLK_CTRL_VALUE;
|
||||
} else if (speed == 100) {
|
||||
*(volatile unsigned int *)(slcrBaseAddress) =
|
||||
SLCR_GEM_100M_CLK_CTRL_VALUE;
|
||||
} else {
|
||||
*(volatile unsigned int *)(slcrBaseAddress) =
|
||||
SLCR_GEM_10M_CLK_CTRL_VALUE;
|
||||
}
|
||||
#else
|
||||
if (speed == 1000) {
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else if (speed == 100) {
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SlcrTxClkCntrl = *(volatile unsigned int *)(slcrBaseAddress);
|
||||
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
||||
SlcrTxClkCntrl |= (SlcrDiv1 << 20);
|
||||
SlcrTxClkCntrl |= (SlcrDiv0 << 8);
|
||||
*(volatile unsigned int *)(slcrBaseAddress) = SlcrTxClkCntrl;
|
||||
#endif
|
||||
*(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
unsigned link_speed;
|
||||
unsigned Phy_Setup (XEmacPs *xemacpsp)
|
||||
{
|
||||
unsigned long conv_present = 0;
|
||||
unsigned long convspeeddupsetting = 0;
|
||||
unsigned long convphyaddr = 0;
|
||||
|
||||
#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR
|
||||
convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR;
|
||||
conv_present = 1;
|
||||
#else
|
||||
#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR
|
||||
convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR;
|
||||
conv_present = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ipconfigNIC_LINKSPEED_AUTODETECT
|
||||
link_speed = get_IEEE_phy_speed(xemacpsp);
|
||||
if (link_speed == 1000) {
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
|
||||
} else if (link_speed == 100) {
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
|
||||
} else {
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
|
||||
}
|
||||
#elif defined(ipconfigNIC_LINKSPEED1000)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
|
||||
link_speed = 1000;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
|
||||
sleep(1);
|
||||
#elif defined(ipconfigNIC_LINKSPEED100)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
|
||||
link_speed = 100;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
|
||||
sleep(1);
|
||||
#elif defined(ipconfigNIC_LINKSPEED10)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
|
||||
link_speed = 10;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
|
||||
sleep(1);
|
||||
#endif
|
||||
if (conv_present) {
|
||||
XEmacPs_PhyWrite(xemacpsp, convphyaddr,
|
||||
XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
|
||||
}
|
||||
|
||||
xil_printf("link speed: %d\n", link_speed);
|
||||
return link_speed;
|
||||
}
|
||||
|
@ -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
|
Reference in New Issue
Block a user