Initial version

This commit is contained in:
2019-06-28 23:08:36 +02:00
commit 4d8973e20b
2426 changed files with 948029 additions and 0 deletions

View File

@ -0,0 +1,423 @@
/*
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
*/
/******************************************************************************
*
* See the following web page for essential buffer allocation scheme usage and
* configuration details:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
*
******************************************************************************/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
/* For an Ethernet interrupt to be able to obtain a network buffer there must
be at least this number of buffers available. */
#define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 )
/* A list of free (available) NetworkBufferDescriptor_t structures. */
static List_t xFreeBuffersList;
/* Some statistics about the use of buffers. */
static UBaseType_t uxMinimumFreeNetworkBuffers = 0u;
/* Declares the pool of NetworkBufferDescriptor_t structures that are available
to the system. All the network buffers referenced from xFreeBuffersList exist
in this array. The array is not accessed directly except during initialisation,
when the xFreeBuffersList is filled (as all the buffers are free when the system
is booted). */
static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
/* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the
network buffers have constant size, large enough to hold the biggest Ethernet
packet. No resizing will be done. */
const BaseType_t xBufferAllocFixedSize = pdTRUE;
/* The semaphore used to obtain network buffers. */
static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
#if( ipconfigTCP_IP_SANITY != 0 )
static char cIsLow = pdFALSE;
UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
#else
static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc );
#endif /* ipconfigTCP_IP_SANITY */
static void prvShowWarnings( void );
/* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and
ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these
are not defined then default them to call the normal enter/exit critical
section macros. */
#if !defined( ipconfigBUFFER_ALLOC_LOCK )
#define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0)
#define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \
UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \
{
#define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
}
#define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL()
#define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL()
#endif /* ipconfigBUFFER_ALLOC_LOCK */
/*-----------------------------------------------------------*/
#if( ipconfigTCP_IP_SANITY != 0 )
/* HT: SANITY code will be removed as soon as the library is stable
* and and ready to become public
* Function below gives information about the use of buffers */
#define WARN_LOW ( 2 )
#define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 )
#endif /* ipconfigTCP_IP_SANITY */
/*-----------------------------------------------------------*/
#if( ipconfigTCP_IP_SANITY != 0 )
BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr )
{
return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) &&
( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 );
}
/*-----------------------------------------------------------*/
static void prvShowWarnings( void )
{
UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( );
if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) )
{
cIsLow = !cIsLow;
FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) );
}
}
/*-----------------------------------------------------------*/
UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc )
{
uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) );
if( ( offset >= sizeof( xNetworkBuffers ) ) ||
( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) )
return pdFALSE;
return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1;
}
/*-----------------------------------------------------------*/
#else
static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc)
{
( void ) pxDesc;
return ( UBaseType_t ) pdTRUE;
}
/*-----------------------------------------------------------*/
static void prvShowWarnings( void )
{
}
/*-----------------------------------------------------------*/
#endif /* ipconfigTCP_IP_SANITY */
BaseType_t xNetworkBuffersInitialise( void )
{
BaseType_t xReturn, x;
/* Only initialise the buffers and their associated kernel objects if they
have not been initialised before. */
if( xNetworkBufferSemaphore == NULL )
{
/* In case alternative locking is used, the mutexes can be initialised
here */
ipconfigBUFFER_ALLOC_INIT();
xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
configASSERT( xNetworkBufferSemaphore );
if( xNetworkBufferSemaphore != NULL )
{
vListInitialise( &xFreeBuffersList );
/* Initialise all the network buffers. The buffer storage comes
from the network interface, and different hardware has different
requirements. */
vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers );
for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
{
/* Initialise and set the owner of the buffer list items. */
vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) );
listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] );
/* Currently, all buffers are available for use. */
vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) );
}
uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
}
}
if( xNetworkBufferSemaphore == NULL )
{
xReturn = pdFAIL;
}
else
{
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
{
NetworkBufferDescriptor_t *pxReturn = NULL;
BaseType_t xInvalid = pdFALSE;
UBaseType_t uxCount;
/* The current implementation only has a single size memory block, so
the requested size parameter is not used (yet). */
( void ) xRequestedSizeBytes;
if( xNetworkBufferSemaphore != NULL )
{
/* If there is a semaphore available, there is a network buffer
available. */
if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
{
/* Protect the structure as they are accessed from tasks and
interrupts. */
ipconfigBUFFER_ALLOC_LOCK();
{
pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) &&
listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) )
{
uxListRemove( &( pxReturn->xBufferListItem ) );
}
else
{
xInvalid = pdTRUE;
}
}
ipconfigBUFFER_ALLOC_UNLOCK();
if( xInvalid == pdTRUE )
{
/* _RB_ Can printf() be called from an interrupt? (comment
above says this can be called from an interrupt too) */
/* _HT_ The function shall not be called from an ISR. Comment
was indeed misleading. Hopefully clear now?
So the printf()is OK here. */
FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n",
pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) );
pxReturn = NULL;
}
else
{
/* Reading UBaseType_t, no critical section needed. */
uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
/* For stats, latch the lowest number of network buffers since
booting. */
if( uxMinimumFreeNetworkBuffers > uxCount )
{
uxMinimumFreeNetworkBuffers = uxCount;
}
pxReturn->xDataLength = xRequestedSizeBytes;
#if( ipconfigTCP_IP_SANITY != 0 )
{
prvShowWarnings();
}
#endif /* ipconfigTCP_IP_SANITY */
#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
{
/* make sure the buffer is not linked */
pxReturn->pxNextBuffer = NULL;
}
#endif /* ipconfigUSE_LINKED_RX_MESSAGES */
if( xTCPWindowLoggingLevel > 3 )
{
FreeRTOS_debug_printf( ( "BUF_GET[%ld]: %p (%p)\n",
bIsValidNetworkDescriptor( pxReturn ),
pxReturn, pxReturn->pucEthernetBuffer ) );
}
}
iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
}
else
{
iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
}
}
return pxReturn;
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes )
{
NetworkBufferDescriptor_t *pxReturn = NULL;
/* The current implementation only has a single size memory block, so
the requested size parameter is not used (yet). */
( void ) xRequestedSizeBytes;
/* If there is a semaphore available then there is a buffer available, but,
as this is called from an interrupt, only take a buffer if there are at
least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents,
to a certain degree at least, a rapidly executing interrupt exhausting
buffer and in so doing preventing tasks from continuing. */
if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD )
{
if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS )
{
/* Protect the structure as it is accessed from tasks and interrupts. */
ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
{
pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
uxListRemove( &( pxReturn->xBufferListItem ) );
}
ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn );
}
}
if( pxReturn == NULL )
{
iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR();
}
return pxReturn;
}
/*-----------------------------------------------------------*/
BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Ensure the buffer is returned to the list of free buffers before the
counting semaphore is 'given' to say a buffer is available. */
ipconfigBUFFER_ALLOC_LOCK_FROM_ISR();
{
vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
}
ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR();
xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken );
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
return xHigherPriorityTaskWoken;
}
/*-----------------------------------------------------------*/
void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xListItemAlreadyInFreeList;
if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED )
{
FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) );
return ;
}
/* Ensure the buffer is returned to the list of free buffers before the
counting semaphore is 'given' to say a buffer is available. */
ipconfigBUFFER_ALLOC_LOCK();
{
{
xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
if( xListItemAlreadyInFreeList == pdFALSE )
{
vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
}
}
}
ipconfigBUFFER_ALLOC_UNLOCK();
if( xListItemAlreadyInFreeList )
{
FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n",
pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) );
}
if( xListItemAlreadyInFreeList == pdFALSE )
{
xSemaphoreGive( xNetworkBufferSemaphore );
prvShowWarnings();
if( xTCPWindowLoggingLevel > 3 )
FreeRTOS_debug_printf( ( "BUF_PUT[%ld]: %p (%p) (now %lu)\n",
bIsValidNetworkDescriptor( pxNetworkBuffer ),
pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer,
uxGetNumberOfFreeNetworkBuffers( ) ) );
}
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
}
/*-----------------------------------------------------------*/
UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
{
return uxMinimumFreeNetworkBuffers;
}
/*-----------------------------------------------------------*/
UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
{
return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
}
NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
{
/* In BufferAllocation_1.c all network buffer are allocated with a
maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the
network buffer. */
( void ) xNewSizeBytes;
return pxNetworkBuffer;
}
/*#endif */ /* ipconfigINCLUDE_TEST_CODE */

View File

@ -0,0 +1,390 @@
/*
* 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://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/******************************************************************************
*
* See the following web page for essential buffer allocation scheme usage and
* configuration details:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
*
******************************************************************************/
/* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR
THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used,
heap_4 can be used. */
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
/* The obtained network buffer must be large enough to hold a packet that might
replace the packet that was requested to be sent. */
#if ipconfigUSE_TCP == 1
#define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t )
#else
#define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t )
#endif /* ipconfigUSE_TCP == 1 */
/*_RB_ This is too complex not to have an explanation. */
#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
#define STATIC_ASSERT(e) \
;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );
#endif
/* A list of free (available) NetworkBufferDescriptor_t structures. */
static List_t xFreeBuffersList;
/* Some statistics about the use of buffers. */
static size_t uxMinimumFreeNetworkBuffers;
/* Declares the pool of NetworkBufferDescriptor_t structures that are available
to the system. All the network buffers referenced from xFreeBuffersList exist
in this array. The array is not accessed directly except during initialisation,
when the xFreeBuffersList is filled (as all the buffers are free when the system
is booted). */
static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
/* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the
network buffers have a variable size: resizing may be necessary */
const BaseType_t xBufferAllocFixedSize = pdFALSE;
/* The semaphore used to obtain network buffers. */
static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
/*-----------------------------------------------------------*/
BaseType_t xNetworkBuffersInitialise( void )
{
BaseType_t xReturn, x;
/* Only initialise the buffers and their associated kernel objects if they
have not been initialised before. */
if( xNetworkBufferSemaphore == NULL )
{
xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
configASSERT( xNetworkBufferSemaphore );
if( xNetworkBufferSemaphore != NULL )
{
#if ( configQUEUE_REGISTRY_SIZE > 0 )
{
vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );
}
#endif /* configQUEUE_REGISTRY_SIZE */
/* If the trace recorder code is included name the semaphore for viewing
in FreeRTOS+Trace. */
#if( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )
{
extern QueueHandle_t xNetworkEventQueue;
vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );
}
#endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */
vListInitialise( &xFreeBuffersList );
/* Initialise all the network buffers. No storage is allocated to
the buffers yet. */
for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
{
/* Initialise and set the owner of the buffer list items. */
xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL;
vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] );
/* Currently, all buffers are available for use. */
vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
}
uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
}
}
if( xNetworkBufferSemaphore == NULL )
{
xReturn = pdFAIL;
}
else
{
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes )
{
uint8_t *pucEthernetBuffer;
size_t xSize = *pxRequestedSizeBytes;
if( xSize < baMINIMAL_BUFFER_SIZE )
{
/* Buffers must be at least large enough to hold a TCP-packet with
headers, or an ARP packet, in case TCP is not included. */
xSize = baMINIMAL_BUFFER_SIZE;
}
/* Round up xSize to the nearest multiple of N bytes,
where N equals 'sizeof( size_t )'. */
if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u )
{
xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u;
}
*pxRequestedSizeBytes = xSize;
/* Allocate a buffer large enough to store the requested Ethernet frame size
and a pointer to a network buffer structure (hence the addition of
ipBUFFER_PADDING bytes). */
pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );
configASSERT( pucEthernetBuffer );
if( pucEthernetBuffer != NULL )
{
/* Enough space is left at the start of the buffer to place a pointer to
the network buffer structure that references this Ethernet buffer.
Return a pointer to the start of the Ethernet buffer itself. */
pucEthernetBuffer += ipBUFFER_PADDING;
}
return pucEthernetBuffer;
}
/*-----------------------------------------------------------*/
void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer )
{
/* There is space before the Ethernet buffer in which a pointer to the
network buffer that references this Ethernet buffer is stored. Remove the
space before freeing the buffer. */
if( pucEthernetBuffer != NULL )
{
pucEthernetBuffer -= ipBUFFER_PADDING;
vPortFree( ( void * ) pucEthernetBuffer );
}
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
{
NetworkBufferDescriptor_t *pxReturn = NULL;
size_t uxCount;
if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
{
/* ARP packets can replace application packets, so the storage must be
at least large enough to hold an ARP. */
xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;
}
/* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes
to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */
xRequestedSizeBytes += 2u;
if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u )
{
xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u;
}
/* If there is a semaphore available, there is a network buffer available. */
if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
{
/* Protect the structure as it is accessed from tasks and interrupts. */
taskENTER_CRITICAL();
{
pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
uxListRemove( &( pxReturn->xBufferListItem ) );
}
taskEXIT_CRITICAL();
/* Reading UBaseType_t, no critical section needed. */
uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
if( uxMinimumFreeNetworkBuffers > uxCount )
{
uxMinimumFreeNetworkBuffers = uxCount;
}
/* Allocate storage of exactly the requested size to the buffer. */
configASSERT( pxReturn->pucEthernetBuffer == NULL );
if( xRequestedSizeBytes > 0 )
{
/* Extra space is obtained so a pointer to the network buffer can
be stored at the beginning of the buffer. */
pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );
if( pxReturn->pucEthernetBuffer == NULL )
{
/* The attempt to allocate storage for the buffer payload failed,
so the network buffer structure cannot be used and must be
released. */
vReleaseNetworkBufferAndDescriptor( pxReturn );
pxReturn = NULL;
}
else
{
/* Store a pointer to the network buffer structure in the
buffer storage area, then move the buffer pointer on past the
stored pointer so the pointer value is not overwritten by the
application when the buffer is used. */
*( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
/* Store the actual size of the allocated buffer, which may be
greater than the original requested size. */
pxReturn->xDataLength = xRequestedSizeBytes;
#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
{
/* make sure the buffer is not linked */
pxReturn->pxNextBuffer = NULL;
}
#endif /* ipconfigUSE_LINKED_RX_MESSAGES */
}
}
else
{
/* A descriptor is being returned without an associated buffer being
allocated. */
}
}
if( pxReturn == NULL )
{
iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
}
else
{
iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
}
return pxReturn;
}
/*-----------------------------------------------------------*/
void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xListItemAlreadyInFreeList;
/* Ensure the buffer is returned to the list of free buffers before the
counting semaphore is 'given' to say a buffer is available. Release the
storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED
IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP
MEMORY. For example, heap_2 must not be used, heap_4 can be used. */
vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
pxNetworkBuffer->pucEthernetBuffer = NULL;
taskENTER_CRITICAL();
{
xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
if( xListItemAlreadyInFreeList == pdFALSE )
{
vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
}
}
taskEXIT_CRITICAL();
/*
* Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'.
* The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false.
*/
if( xListItemAlreadyInFreeList == pdFALSE )
{
if ( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE )
{
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
}
}
else
{
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
}
}
/*-----------------------------------------------------------*/
/*
* Returns the number of free network buffers
*/
UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
{
return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
}
/*-----------------------------------------------------------*/
UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
{
return uxMinimumFreeNetworkBuffers;
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes )
{
size_t xOriginalLength;
uint8_t *pucBuffer;
xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;
xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;
pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );
if( pucBuffer == NULL )
{
/* In case the allocation fails, return NULL. */
pxNetworkBuffer = NULL;
}
else
{
pxNetworkBuffer->xDataLength = xNewSizeBytes;
if( xNewSizeBytes > xOriginalLength )
{
xNewSizeBytes = xOriginalLength;
}
memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );
vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
pxNetworkBuffer->pucEthernetBuffer = pucBuffer;
}
return pxNetworkBuffer;
}

View File

@ -0,0 +1,46 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
__attribute__( (packed) );

View File

@ -0,0 +1,48 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
/* Nothing to do here. */

View File

@ -0,0 +1,47 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
;

View File

@ -0,0 +1,49 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
__packed

View File

@ -0,0 +1,48 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
;
#pragma pack( pop )

View File

@ -0,0 +1,47 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
#pragma pack( push, 1 )

View File

@ -0,0 +1,54 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
#ifdef _SH
#ifdef __RENESAS__
;
#pragma unpack
#endif
#endif

View File

@ -0,0 +1,53 @@
/*
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
*/
/*****************************************************************************
*
* See the following URL for an explanation of this file:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html
*
*****************************************************************************/
#ifdef _SH
#ifdef __RENESAS__
#pragma pack 1
#endif
#endif

View File

@ -0,0 +1,649 @@
/*
* FreeRTOS+TCP V2.0.11
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
/* Some files from the Atmel Software Framework */
/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */
#include "instance/gmac.h"
#include <sysclk.h>
#include <ethernet_phy.h>
#ifndef BMSR_LINK_STATUS
#define BMSR_LINK_STATUS 0x0004 //!< Link status
#endif
#ifndef PHY_LS_HIGH_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
receiving packets. */
#define PHY_LS_HIGH_CHECK_TIME_MS 15000
#endif
#ifndef PHY_LS_LOW_CHECK_TIME_MS
/* Check if the LinkSStatus in the PHY is still low every second. */
#define PHY_LS_LOW_CHECK_TIME_MS 1000
#endif
/* Interrupt events to process. Currently only the Rx event is processed
although code for other events is included to allow for possible future
expansion. */
#define EMAC_IF_RX_EVENT 1UL
#define EMAC_IF_TX_EVENT 2UL
#define EMAC_IF_ERR_EVENT 4UL
#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
#define HZ_PER_MHZ ( 1000000UL )
#ifndef EMAC_MAX_BLOCK_TIME_MS
#define EMAC_MAX_BLOCK_TIME_MS 100ul
#endif
#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 )
#error Please define GMAC_USES_TX_CALLBACK as 1
#endif
#if( ipconfigZERO_COPY_RX_DRIVER != 0 )
#warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible
#endif
/* Default the size of the stack used by the EMAC deferred handler task to 4x
the size of the stack used by the idle task - but allow this to be overridden in
FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
#ifndef configEMAC_TASK_STACK_SIZE
#define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
#endif
/*-----------------------------------------------------------*/
/*
* Wait a fixed time for the link status to indicate the network is up.
*/
static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
void vGMACGenerateChecksum( uint8_t *apBuffer );
#endif
/*
* Called from the ASF GMAC driver.
*/
static void prvRxCallback( uint32_t ulStatus );
static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer );
/*
* A deferred interrupt handler task that processes GMAC interrupts.
*/
static void prvEMACHandlerTask( void *pvParameters );
/*
* Initialise the ASF GMAC driver.
*/
static BaseType_t prvGMACInit( void );
/*
* Try to obtain an Rx packet from the hardware.
*/
static uint32_t prvEMACRxPoll( void );
/*-----------------------------------------------------------*/
/* Bit map of outstanding ETH interrupt events for processing. Currently only
the Rx interrupt is handled, although code is included for other events to
enable future expansion. */
static volatile uint32_t ulISREvents;
/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
static uint32_t ulPHYLinkStatus = 0;
static volatile BaseType_t xGMACSwitchRequired;
/* ethernet_phy_addr: the address of the PHY in use.
Atmel was a bit ambiguous about it so the address will be stored
in this variable, see ethernet_phy.c */
extern int ethernet_phy_addr;
/* LLMNR multicast address. */
static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
/* The GMAC object as defined by the ASF drivers. */
static gmac_device_t gs_gmac_dev;
/* MAC address to use. */
extern const uint8_t ucMACAddress[ 6 ];
/* Holds the handle of the task used as a deferred interrupt processor. The
handle is used so direct notifications can be sent to the task for all EMAC/DMA
related interrupts. */
TaskHandle_t xEMACTaskHandle = NULL;
static QueueHandle_t xTxBufferQueue;
int tx_release_count[ 4 ];
/* xTXDescriptorSemaphore is a counting semaphore with
a maximum count of GMAC_TX_BUFFERS, which is the number of
DMA TX descriptors. */
static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;
/*-----------------------------------------------------------*/
/*
* GMAC interrupt handler.
*/
void GMAC_Handler(void)
{
xGMACSwitchRequired = pdFALSE;
/* gmac_handler() may call prvRxCallback() which may change
the value of xGMACSwitchRequired. */
gmac_handler( &gs_gmac_dev );
if( xGMACSwitchRequired != pdFALSE )
{
portEND_SWITCHING_ISR( xGMACSwitchRequired );
}
}
/*-----------------------------------------------------------*/
static void prvRxCallback( uint32_t ulStatus )
{
if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) )
{
/* let the prvEMACHandlerTask know that there was an RX event. */
ulISREvents |= EMAC_IF_RX_EVENT;
/* Only an RX interrupt can wakeup prvEMACHandlerTask. */
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
}
}
/*-----------------------------------------------------------*/
static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer )
{
if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) )
{
/* let the prvEMACHandlerTask know that there was an RX event. */
ulISREvents |= EMAC_IF_TX_EVENT;
vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired );
xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired );
tx_release_count[ 2 ]++;
}
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
const TickType_t x5_Seconds = 5000UL;
if( xEMACTaskHandle == NULL )
{
prvGMACInit();
/* Wait at most 5 seconds for a Link Status in the PHY. */
xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
/* The handler task is created at the highest possible priority to
ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
configASSERT( xEMACTaskHandle );
}
if( xTxBufferQueue == NULL )
{
xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) );
configASSERT( xTxBufferQueue );
}
if( xTXDescriptorSemaphore == NULL )
{
xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS );
configASSERT( xTXDescriptorSemaphore );
}
/* When returning non-zero, the stack will become active and
start DHCP (in configured) */
return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
}
/*-----------------------------------------------------------*/
BaseType_t xGetPhyLinkStatus( void )
{
BaseType_t xResult;
/* This function returns true if the Link Status in the PHY is high. */
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
{
xResult = pdTRUE;
}
else
{
xResult = pdFALSE;
}
return xResult;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )
{
/* Do not wait too long for a free TX DMA buffer. */
const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u );
do {
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
{
/* Do not attempt to send packets as long as the Link Status is low. */
break;
}
if( xTXDescriptorSemaphore == NULL )
{
/* Semaphore has not been created yet? */
break;
}
if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )
{
/* Time-out waiting for a free TX descriptor. */
tx_release_count[ 3 ]++;
break;
}
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Confirm that the pxDescriptor may be kept by the driver. */
configASSERT( bReleaseAfterSend != pdFALSE );
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback );
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
/* Confirm that the pxDescriptor may be kept by the driver. */
bReleaseAfterSend = pdFALSE;
}
#endif /* ipconfigZERO_COPY_TX_DRIVER */
/* Not interested in a call-back after TX. */
iptraceNETWORK_INTERFACE_TRANSMIT();
} while( 0 );
if( bReleaseAfterSend != pdFALSE )
{
vReleaseNetworkBufferAndDescriptor( pxDescriptor );
}
return pdTRUE;
}
/*-----------------------------------------------------------*/
static BaseType_t prvGMACInit( void )
{
uint32_t ncfgr;
gmac_options_t gmac_option;
memset( &gmac_option, '\0', sizeof( gmac_option ) );
gmac_option.uc_copy_all_frame = 0;
gmac_option.uc_no_boardcast = 0;
memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) );
gs_gmac_dev.p_hw = GMAC;
gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option );
NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY );
NVIC_EnableIRQ( GMAC_IRQn );
/* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */
ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() );
ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr );
ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 );
/* The GMAC driver will call a hook prvRxCallback(), which
in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */
gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback );
gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address );
ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD;
GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr;
return 1;
}
/*-----------------------------------------------------------*/
static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress )
{
uint32_t ulValue, ulReturn;
int rc;
gmac_enable_management( GMAC, 1 );
rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue );
gmac_enable_management( GMAC, 0 );
if( rc == GMAC_OK )
{
ulReturn = ulValue;
}
else
{
ulReturn = 0UL;
}
return ulReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
{
TickType_t xStartTime = xTaskGetTickCount();
TickType_t xEndTime;
BaseType_t xReturn;
const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
for( ;; )
{
xEndTime = xTaskGetTickCount();
if( ( xEndTime - xStartTime ) > xMaxTime )
{
/* Wated more than xMaxTime, return. */
xReturn = pdFALSE;
break;
}
/* Check the link status again. */
ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
{
/* Link is up - return. */
xReturn = pdTRUE;
break;
}
/* Link is down - wait in the Blocked state for a short while (to allow
other tasks to execute) before checking again. */
vTaskDelay( xShortTime );
}
FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n",
xReturn,
ethernet_phy_addr,
sysclk_get_cpu_hz() / HZ_PER_MHZ ) );
return xReturn;
}
/*-----------------------------------------------------------*/
//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 )
void vGMACGenerateChecksum( uint8_t *apBuffer )
{
ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer;
if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
{
IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader );
/* Calculate the IP header checksum. */
pxIPHeader->usHeaderChecksum = 0x00;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
/* Calculate the TCP checksum for an outgoing packet. */
usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE );
}
}
//#endif
/*-----------------------------------------------------------*/
static uint32_t prvEMACRxPoll( void )
{
unsigned char *pucUseBuffer;
uint32_t ulReceiveCount, ulResult, ulReturnValue = 0;
static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
const UBaseType_t xMinDescriptorsToLeave = 2UL;
const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL );
static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
for( ;; )
{
/* If pxNextNetworkBufferDescriptor was not left pointing at a valid
descriptor then allocate one now. */
if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) )
{
pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime );
}
if( pxNextNetworkBufferDescriptor != NULL )
{
/* Point pucUseBuffer to the buffer pointed to by the descriptor. */
pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
}
else
{
/* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
messages will be flushed and ignored. */
pucUseBuffer = NULL;
}
/* Read the next packet from the hardware into pucUseBuffer. */
ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount );
if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) )
{
/* No data from the hardware. */
break;
}
if( pxNextNetworkBufferDescriptor == NULL )
{
/* Data was read from the hardware, but no descriptor was available
for it, so it will be dropped. */
iptraceETHERNET_RX_EVENT_LOST();
continue;
}
iptraceNETWORK_INTERFACE_RECEIVE();
pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount;
xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor;
/* Send the descriptor to the IP task for processing. */
if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE )
{
/* The buffer could not be sent to the stack so must be released
again. */
vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor );
iptraceETHERNET_RX_EVENT_LOST();
FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
}
/* Now the buffer has either been passed to the IP-task,
or it has been released in the code above. */
pxNextNetworkBufferDescriptor = NULL;
ulReturnValue++;
}
return ulReturnValue;
}
/*-----------------------------------------------------------*/
void vCheckBuffersAndQueue( void )
{
static UBaseType_t uxLastMinBufferCount = 0;
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
static UBaseType_t uxLastMinQueueSpace;
#endif
static UBaseType_t uxCurrentCount;
#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
{
uxCurrentCount = uxGetMinimumIPQueueSpace();
if( uxLastMinQueueSpace != uxCurrentCount )
{
/* The logging produced below may be helpful
while tuning +TCP: see how many buffers are in use. */
uxLastMinQueueSpace = uxCurrentCount;
FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
}
}
#endif /* ipconfigCHECK_IP_QUEUE_SPACE */
uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
if( uxLastMinBufferCount != uxCurrentCount )
{
/* The logging produced below may be helpful
while tuning +TCP: see how many buffers are in use. */
uxLastMinBufferCount = uxCurrentCount;
FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
}
}
static void prvEMACHandlerTask( void *pvParameters )
{
TimeOut_t xPhyTime;
TickType_t xPhyRemTime;
UBaseType_t uxCount;
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
NetworkBufferDescriptor_t *pxBuffer;
#endif
uint8_t *pucBuffer;
BaseType_t xResult = 0;
uint32_t xStatus;
const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
/* Remove compiler warnings about unused parameters. */
( void ) pvParameters;
configASSERT( xEMACTaskHandle );
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
for( ;; )
{
vCheckBuffersAndQueue();
if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
{
/* No events to process now, wait for the next. */
ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
}
if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
{
ulISREvents &= ~EMAC_IF_RX_EVENT;
/* Wait for the EMAC interrupt to indicate that another packet has been
received. */
xResult = prvEMACRxPoll();
}
if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
{
/* Future extension: code to release TX buffers if zero-copy is used. */
ulISREvents &= ~EMAC_IF_TX_EVENT;
while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE )
{
#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
{
pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer );
if( pxBuffer != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxBuffer );
tx_release_count[ 0 ]++;
}
else
{
tx_release_count[ 1 ]++;
}
}
#else
{
tx_release_count[ 0 ]++;
}
#endif
uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore );
if( uxCount < GMAC_TX_BUFFERS )
{
/* Tell the counting semaphore that one more TX descriptor is available. */
xSemaphoreGive( xTXDescriptorSemaphore );
}
}
}
if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
{
/* Future extension: logging about errors that occurred. */
ulISREvents &= ~EMAC_IF_ERR_EVENT;
}
if( xResult > 0 )
{
/* A packet was received. No need to check for the PHY status now,
but set a timer to check it later on. */
vTaskSetTimeOutState( &xPhyTime );
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
xResult = 0;
}
else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )
{
/* Check the link status again. */
xStatus = ulReadMDIO( PHY_REG_01_BMSR );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
{
ulPHYLinkStatus = xStatus;
FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
}
vTaskSetTimeOutState( &xPhyTime );
if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
{
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
}
else
{
xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
}
}
}
}
/*-----------------------------------------------------------*/

View File

@ -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_ */

View File

@ -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
/**
* \}
*/

View File

@ -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 */

View File

@ -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

View File

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

View File

@ -0,0 +1,267 @@
/*
FreeRTOS+TCP V2.0.11
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
http://aws.amazon.com/freertos
http://www.FreeRTOS.org
*/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* Hardware abstraction. */
#include "FreeRTOS_IO.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_Sockets.h"
#include "NetworkBufferManagement.h"
/* Driver includes. */
#include "lpc17xx_emac.h"
#include "lpc17xx_pinsel.h"
/* Demo includes. */
#include "NetworkInterface.h"
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#endif
/* When a packet is ready to be sent, if it cannot be sent immediately then the
task performing the transmit will block for niTX_BUFFER_FREE_WAIT
milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
up. */
#define niTX_BUFFER_FREE_WAIT ( pdMS_TO_TICKS( 2UL ) )
#define niMAX_TX_ATTEMPTS ( 5 )
/* The length of the queue used to send interrupt status words from the
interrupt handler to the deferred handler task. */
#define niINTERRUPT_QUEUE_LENGTH ( 10 )
/*-----------------------------------------------------------*/
/*
* A deferred interrupt handler task that processes
*/
static void prvEMACHandlerTask( void *pvParameters );
/*-----------------------------------------------------------*/
/* The queue used to communicate Ethernet events with the IP task. */
extern QueueHandle_t xNetworkEventQueue;
/* The semaphore used to wake the deferred interrupt handler task when an Rx
interrupt is received. */
static SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
EMAC_CFG_Type Emac_Config;
PINSEL_CFG_Type xPinConfig;
BaseType_t xStatus, xReturn;
extern uint8_t ucMACAddress[ 6 ];
/* Enable Ethernet Pins */
boardCONFIGURE_ENET_PINS( xPinConfig );
Emac_Config.Mode = EMAC_MODE_AUTO;
Emac_Config.pbEMAC_Addr = ucMACAddress;
xStatus = EMAC_Init( &Emac_Config );
LPC_EMAC->IntEnable &= ~( EMAC_INT_TX_DONE );
if( xStatus != ERROR )
{
vSemaphoreCreateBinary( xEMACRxEventSemaphore );
configASSERT( xEMACRxEventSemaphore );
/* The handler task is created at the highest possible priority to
ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
/* Enable the interrupt and set its priority to the minimum
interrupt priority. */
NVIC_SetPriority( ENET_IRQn, configMAC_INTERRUPT_PRIORITY );
NVIC_EnableIRQ( ENET_IRQn );
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
configASSERT( xStatus != ERROR );
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xReturn = pdFAIL;
int32_t x;
extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength );
extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer );
/* Attempt to obtain access to a Tx buffer. */
for( x = 0; x < niMAX_TX_ATTEMPTS; x++ )
{
if( EMAC_CheckTransmitIndex() == TRUE )
{
/* Will the data fit in the Tx buffer? */
if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
{
/* Assign the buffer to the Tx descriptor that is now known to
be free. */
EMAC_SetNextPacketToSend( pxNetworkBuffer->pucBuffer );
/* The EMAC now owns the buffer. */
pxNetworkBuffer->pucBuffer = NULL;
/* Initiate the Tx. */
EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength );
iptraceNETWORK_INTERFACE_TRANSMIT();
/* The Tx has been initiated. */
xReturn = pdPASS;
}
break;
}
else
{
vTaskDelay( niTX_BUFFER_FREE_WAIT );
}
}
/* Finished with the network buffer. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
return xReturn;
}
/*-----------------------------------------------------------*/
void ENET_IRQHandler( void )
{
uint32_t ulInterruptCause;
while( ( ulInterruptCause = LPC_EMAC->IntStatus ) != 0 )
{
/* Clear the interrupt. */
LPC_EMAC->IntClear = ulInterruptCause;
/* Clear fatal error conditions. NOTE: The driver does not clear all
errors, only those actually experienced. For future reference, range
errors are not actually errors so can be ignored. */
if( ( ulInterruptCause & EMAC_INT_TX_UNDERRUN ) != 0U )
{
LPC_EMAC->Command |= EMAC_CR_TX_RES;
}
/* Unblock the deferred interrupt handler task if the event was an
Rx. */
if( ( ulInterruptCause & EMAC_INT_RX_DONE ) != 0UL )
{
xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );
}
}
/* ulInterruptCause is used for convenience here. A context switch is
wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a
compiler warning. */
portEND_SWITCHING_ISR( ulInterruptCause );
}
/*-----------------------------------------------------------*/
static void prvEMACHandlerTask( void *pvParameters )
{
size_t xDataLength;
const uint16_t usCRCLength = 4;
NetworkBufferDescriptor_t *pxNetworkBuffer;
IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
/* This is not included in the header file for some reason. */
extern uint8_t *EMAC_NextPacketToRead( void );
( void ) pvParameters;
configASSERT( xEMACRxEventSemaphore );
for( ;; )
{
/* Wait for the EMAC interrupt to indicate that another packet has been
received. The while() loop is only needed if INCLUDE_vTaskSuspend is
set to 0 in FreeRTOSConfig.h. */
while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE );
/* At least one packet has been received. */
while( EMAC_CheckReceiveIndex() != FALSE )
{
/* Obtain the length, minus the CRC. The CRC is four bytes
but the length is already minus 1. */
xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U );
if( xDataLength > 0U )
{
/* Obtain a network buffer to pass this data into the
stack. No storage is required as the network buffer
will point directly to the buffer that already holds
the received data. */
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 );
if( pxNetworkBuffer != NULL )
{
pxNetworkBuffer->pucBuffer = EMAC_NextPacketToRead();
pxNetworkBuffer->xDataLength = xDataLength;
xRxEvent.pvData = ( void * ) pxNetworkBuffer;
/* Data was received and stored. Send a message to the IP
task to let it know. */
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
iptraceETHERNET_RX_EVENT_LOST();
}
}
else
{
iptraceETHERNET_RX_EVENT_LOST();
}
iptraceNETWORK_INTERFACE_RECEIVE();
}
/* Release the frame. */
EMAC_UpdateRxConsumeIndex();
}
}
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,3 @@
NetworkInterface.c:
Requires NXP's LPCOpen library and was developed on an LPC1830 and LPC1835 Xplorer
boards from NGX.

View File

@ -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.

View File

@ -0,0 +1,118 @@
/*
FreeRTOS+TCP V2.0.11
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
http://aws.amazon.com/freertos
http://www.FreeRTOS.org
*/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_Sockets.h"
#include "NetworkBufferManagement.h"
/* Hardware includes. */
#include "hwEthernet.h"
/* Demo includes. */
#include "NetworkInterface.h"
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#endif
/* When a packet is ready to be sent, if it cannot be sent immediately then the
task performing the transmit will block for niTX_BUFFER_FREE_WAIT
milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving
up. */
#define niTX_BUFFER_FREE_WAIT ( ( TickType_t ) 2UL / portTICK_PERIOD_MS )
#define niMAX_TX_ATTEMPTS ( 5 )
/* The length of the queue used to send interrupt status words from the
interrupt handler to the deferred handler task. */
#define niINTERRUPT_QUEUE_LENGTH ( 10 )
/*-----------------------------------------------------------*/
/*
* A deferred interrupt handler task that processes
*/
extern void vEMACHandlerTask( void *pvParameters );
/*-----------------------------------------------------------*/
/* The queue used to communicate Ethernet events with the IP task. */
extern QueueHandle_t xNetworkEventQueue;
/* The semaphore used to wake the deferred interrupt handler task when an Rx
interrupt is received. */
SemaphoreHandle_t xEMACRxEventSemaphore = NULL;
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
BaseType_t xStatus, xReturn;
extern uint8_t ucMACAddress[ 6 ];
/* Initialise the MAC. */
vInitEmac();
while( lEMACWaitForLink() != pdPASS )
{
vTaskDelay( 20 );
}
vSemaphoreCreateBinary( xEMACRxEventSemaphore );
configASSERT( xEMACRxEventSemaphore );
/* The handler task is created at the highest possible priority to
ensure the interrupt handler can return directly to it. */
xTaskCreate( vEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
xReturn = pdPASS;
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
extern void vEMACCopyWrite( uint8_t * pucBuffer, uint16_t usLength );
vEMACCopyWrite( pxNetworkBuffer->pucBuffer, pxNetworkBuffer->xDataLength );
/* Finished with the network buffer. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
return pdTRUE;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,6 @@
/*
* The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to
* a single module that works for both parts: "stm32fxx_hal_eth"
*/
#include "stm32fxx_hal_eth.h"

View File

@ -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;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,636 @@
/*
FreeRTOS+TCP V2.0.11
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
http://aws.amazon.com/freertos
http://www.FreeRTOS.org
*/
/* WinPCap includes. */
#define HAVE_REMOTE
#include "pcap.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
/* Thread-safe circular buffers are being used to pass data to and from the PCAP
access functions. */
#include "Win32-Extensions.h"
#include "FreeRTOS_Stream_Buffer.h"
/* Sizes of the thread safe circular buffers used to pass data to and from the
WinPCAP Windows threads. */
#define xSEND_BUFFER_SIZE 32768
#define xRECV_BUFFER_SIZE 32768
/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
driver will filter incoming packets and only pass the stack those packets it
considers need processing. */
#if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#endif
/* Used to insert test code only. */
#define niDISRUPT_PACKETS 0
/*-----------------------------------------------------------*/
/*
* Windows threads that are outside of the control of the FreeRTOS simulator are
* used to interface with the WinPCAP libraries.
*/
DWORD WINAPI prvWinPcapRecvThread( void *pvParam );
DWORD WINAPI prvWinPcapSendThread( void *pvParam );
/*
* Print out a numbered list of network interfaces that are available on the
* host computer.
*/
static pcap_if_t * prvPrintAvailableNetworkInterfaces( void );
/*
* Open the network interface. The number of the interface to be opened is set
* by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
*/
static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces );
static int prvOpenInterface( const char *pucName );
/*
* Configure the capture filter to allow blocking reads, and to filter out
* packets that are not of interest to this demo.
*/
static void prvConfigureCaptureBehaviour( void );
/*
* A function that simulates Ethernet interrupts by periodically polling the
* WinPCap interface for new data.
*/
static void prvInterruptSimulatorTask( void *pvParameters );
/*
* Create the buffers that are used to pass data between the FreeRTOS simulator
* and the Win32 threads that manage WinPCAP.
*/
static void prvCreateThreadSafeBuffers( void );
/*
* Utility function used to format print messages only.
*/
static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage );
/*-----------------------------------------------------------*/
/* Required by the WinPCap library. */
static char cErrorBuffer[ PCAP_ERRBUF_SIZE ];
/* An event used to wake up the Win32 thread that sends data through the WinPCAP
library. */
static void *pvSendEvent = NULL;
/* _HT_ made the PCAP interface number configurable through the program's
parameters in order to test in different machines. */
static BaseType_t xConfigNextworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE;
/* Handles to the Windows threads that handle the PCAP IO. */
static HANDLE vWinPcapRecvThreadHandle = NULL;
static HANDLE vWinPcapSendThreadHandle = NULL;;
/* The interface being used by WinPCap. */
static pcap_t *pxOpenedInterfaceHandle = NULL;
/* Circular buffers used by the PCAP Win32 threads. */
static StreamBuffer_t *xSendBuffer = NULL;
static StreamBuffer_t *xRecvBuffer = NULL;
/* The MAC address initially set to the constants defined in FreeRTOSConfig.h. */
extern uint8_t ucMACAddress[ 6 ];
/* Logs the number of WinPCAP send failures, for viewing in the debugger only. */
static volatile uint32_t ulWinPCAPSendFailures = 0;
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceInitialise( void )
{
BaseType_t xReturn = pdFALSE;
pcap_if_t *pxAllNetworkInterfaces;
/* Query the computer the simulation is being executed on to find the
network interfaces it has installed. */
pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces();
/* Open the network interface. The number of the interface to be opened is
set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h.
Calling this function will set the pxOpenedInterfaceHandle variable. If,
after calling this function, pxOpenedInterfaceHandle is equal to NULL, then
the interface could not be opened. */
if( pxAllNetworkInterfaces != NULL )
{
prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces );
}
if( pxOpenedInterfaceHandle != NULL )
{
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static void prvCreateThreadSafeBuffers( void )
{
/* The buffer used to pass data to be transmitted from a FreeRTOS task to
the Win32 thread that sends via the WinPCAP library. */
if( xSendBuffer == NULL)
{
xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 );
configASSERT( xSendBuffer );
memset( xSendBuffer, '\0', sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) );
xSendBuffer->LENGTH = xSEND_BUFFER_SIZE + 1;
}
/* The buffer used to pass received data from the Win32 thread that receives
via the WinPCAP library to the FreeRTOS task. */
if( xRecvBuffer == NULL)
{
xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 );
configASSERT( xRecvBuffer );
memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) );
xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1;
}
}
/*-----------------------------------------------------------*/
BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend )
{
size_t xSpace;
iptraceNETWORK_INTERFACE_TRANSMIT();
configASSERT( xIsCallingFromIPTask() == pdTRUE );
/* Both the length of the data being sent and the actual data being sent
are placed in the thread safe buffer used to pass data between the FreeRTOS
tasks and the Win32 thread that sends data via the WinPCAP library. Drop
the packet if there is insufficient space in the buffer to hold both. */
xSpace = uxStreamBufferGetSpace( xSendBuffer );
if( ( pxNetworkBuffer->xDataLength <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
( xSpace >= ( pxNetworkBuffer->xDataLength + sizeof( pxNetworkBuffer->xDataLength ) ) ) )
{
/* First write in the length of the data, then write in the data
itself. */
uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) &( pxNetworkBuffer->xDataLength ), sizeof( pxNetworkBuffer->xDataLength ) );
uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
}
else
{
FreeRTOS_debug_printf( ( "xNetworkInterfaceOutput: send buffers full to store %lu\n", pxNetworkBuffer->xDataLength ) );
}
/* Kick the Tx task in either case in case it doesn't know the buffer is
full. */
SetEvent( pvSendEvent );
/* The buffer has been sent so can be released. */
if( bReleaseAfterSend != pdFALSE )
{
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
return pdPASS;
}
/*-----------------------------------------------------------*/
static pcap_if_t * prvPrintAvailableNetworkInterfaces( void )
{
pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface;
int32_t lInterfaceNumber = 1;
char cBuffer[ 512 ];
static BaseType_t xInvalidInterfaceDetected = pdFALSE;
if( xInvalidInterfaceDetected == pdFALSE )
{
if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 )
{
printf( "Could not obtain a list of network interfaces\n%s\n", cErrorBuffer );
pxAllNetworkInterfaces = NULL;
}
else
{
printf( "\r\n\r\nThe following network interfaces are available:\r\n\r\n" );
}
if( pxAllNetworkInterfaces != NULL )
{
/* Print out the list of network interfaces. The first in the list
is interface '1', not interface '0'. */
for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next )
{
/* The descriptions of the devices can be full of spaces, clean them
a little. printf() can only be used here because the network is not
up yet - so no other network tasks will be running. */
printf( "Interface %d - %s\n", lInterfaceNumber, prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->name ) );
printf( " (%s)\n", prvRemoveSpaces(cBuffer, sizeof( cBuffer ), xInterface->description ? xInterface->description : "No description" ) );
printf( "\n" );
lInterfaceNumber++;
}
}
if( lInterfaceNumber == 1 )
{
/* The interface number was never incremented, so the above for() loop
did not execute meaning no interfaces were found. */
printf( " \nNo network interfaces were found.\n" );
pxAllNetworkInterfaces = NULL;
}
printf( "\r\nThe interface that will be opened is set by " );
printf( "\"configNETWORK_INTERFACE_TO_USE\", which\r\nshould be defined in FreeRTOSConfig.h\r\n" );
if( ( xConfigNextworkInterfaceToUse < 0L ) || ( xConfigNextworkInterfaceToUse >= lInterfaceNumber ) )
{
printf( "\r\nERROR: configNETWORK_INTERFACE_TO_USE is set to %d, which is an invalid value.\r\n", xConfigNextworkInterfaceToUse );
printf( "Please set configNETWORK_INTERFACE_TO_USE to one of the interface numbers listed above,\r\n" );
printf( "then re-compile and re-start the application. Only Ethernet (as opposed to WiFi)\r\n" );
printf( "interfaces are supported.\r\n\r\nHALTING\r\n\r\n\r\n" );
xInvalidInterfaceDetected = pdTRUE;
if( pxAllNetworkInterfaces != NULL )
{
/* Free the device list, as no devices are going to be opened. */
pcap_freealldevs( pxAllNetworkInterfaces );
pxAllNetworkInterfaces = NULL;
}
}
else
{
printf( "Attempting to open interface number %d.\n", xConfigNextworkInterfaceToUse );
}
}
return pxAllNetworkInterfaces;
}
/*-----------------------------------------------------------*/
static int prvOpenInterface( const char *pucName )
{
static char pucInterfaceName[ 256 ];
if( pucName != NULL )
{
strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) );
}
pxOpenedInterfaceHandle = pcap_open( pucInterfaceName, /* The name of the selected interface. */
ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */
PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscuous mode as the MAC and
IP address is going to be "simulated", and
not be the real MAC and IP address. This allows
traffic to the simulated IP address to be routed
to uIP, and traffic to the real IP address to be
routed to the Windows TCP/IP stack. */
100,
NULL, /* No authentication is required as this is
not a remote capture session. */
cErrorBuffer
);
if ( pxOpenedInterfaceHandle == NULL )
{
printf( "\n%s is not supported by WinPcap and cannot be opened\n", pucInterfaceName );
return 1;
}
else
{
/* Configure the capture filter to allow blocking reads, and to filter
out packets that are not of interest to this demo. */
prvConfigureCaptureBehaviour();
}
return 0;
}
/*-----------------------------------------------------------*/
static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces )
{
pcap_if_t *xInterface;
int32_t x;
/* Walk the list of devices until the selected device is located. */
xInterface = pxAllNetworkInterfaces;
if (0 == xConfigNextworkInterfaceToUse) {
while (NULL != xInterface) {
xInterface = xInterface->next;
if (0 == prvOpenInterface(xInterface->name)) {
break;
}
}
}
else {
for (x = 1L; x < xConfigNextworkInterfaceToUse; x++)
{
xInterface = xInterface->next;
}
/* Open the selected interface. */
(void) prvOpenInterface(xInterface->name);
}
/* The device list is no longer required. */
pcap_freealldevs( pxAllNetworkInterfaces );
}
/*-----------------------------------------------------------*/
static void prvConfigureCaptureBehaviour( void )
{
struct bpf_program xFilterCode;
uint32_t ulNetMask;
/* Set up a filter so only the packets of interest are passed to the IP
stack. cErrorBuffer is used for convenience to create the string. Don't
confuse this with an error message. */
sprintf( cErrorBuffer, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x",
ucMACAddress[0], ucMACAddress[1], ucMACAddress[2], ucMACAddress[3], ucMACAddress[4], ucMACAddress[5] );
ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0;
if( pcap_compile( pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 )
{
printf( "\nThe packet filter string is invalid\n" );
}
else
{
if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 )
{
printf( "\nAn error occurred setting the packet filter.\n" );
}
pcap_freecode( &xFilterCode );
}
/* Create the buffers used to pass packets between the FreeRTOS simulator
and the Win32 threads that are handling WinPCAP. */
prvCreateThreadSafeBuffers();
if( pvSendEvent == NULL )
{
/* Create event used to signal the Win32 WinPCAP Tx thread. */
pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL );
/* Create the Win32 thread that handles WinPCAP Rx. */
vWinPcapRecvThreadHandle = CreateThread(
NULL, /* Pointer to thread security attributes. */
0, /* Initial thread stack size, in bytes. */
prvWinPcapRecvThread, /* Pointer to thread function. */
NULL, /* Argument for new thread. */
0, /* Creation flags. */
NULL );
/* Use the cores that are not used by the FreeRTOS tasks. */
SetThreadAffinityMask( vWinPcapRecvThreadHandle, ~0x01u );
/* Create the Win32 thread that handlers WinPCAP Tx. */
vWinPcapSendThreadHandle = CreateThread(
NULL, /* Pointer to thread security attributes. */
0, /* initial thread stack size, in bytes. */
prvWinPcapSendThread, /* Pointer to thread function. */
NULL, /* Argument for new thread. */
0, /* Creation flags. */
NULL );
/* Use the cores that are not used by the FreeRTOS tasks. */
SetThreadAffinityMask( vWinPcapSendThreadHandle, ~0x01u );
/* Create a task that simulates an interrupt in a real system. This will
block waiting for packets, then send a message to the IP task when data
is available. */
xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL );
}
}
/*-----------------------------------------------------------*/
/* WinPCAP function. */
void pcap_callback( u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data )
{
(void)user;
/* THIS IS CALLED FROM A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS
OR TO PRINT OUT MESSAGES HERE. */
/* Pass data to the FreeRTOS simulator on a thread safe circular buffer. */
if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) &&
( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) )
{
uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_header, sizeof( *pkt_header ) );
uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_data, ( size_t ) pkt_header->caplen );
}
}
/*-----------------------------------------------------------*/
DWORD WINAPI prvWinPcapRecvThread ( void *pvParam )
{
( void ) pvParam;
/* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
OUT MESSAGES HERE. */
for( ;; )
{
pcap_dispatch( pxOpenedInterfaceHandle, 1, pcap_callback, ( u_char * ) "mydata" );
}
}
/*-----------------------------------------------------------*/
DWORD WINAPI prvWinPcapSendThread( void *pvParam )
{
size_t xLength;
uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
static char cErrorMessage[ 1024 ];
const DWORD xMaxMSToWait = 1000;
/* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT
OUT MESSAGES HERE. */
/* Remove compiler warnings about unused parameters. */
( void ) pvParam;
for( ;; )
{
/* Wait until notified of something to send. */
WaitForSingleObject( pvSendEvent, xMaxMSToWait );
/* Is there more than the length value stored in the circular buffer
used to pass data from the FreeRTOS simulator into this Win32 thread? */
while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) )
{
uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE );
uxStreamBufferGet( xSendBuffer, 0, ( uint8_t* ) ucBuffer, xLength, pdFALSE );
if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 )
{
ulWinPCAPSendFailures++;
}
}
}
}
/*-----------------------------------------------------------*/
static void prvInterruptSimulatorTask( void *pvParameters )
{
struct pcap_pkthdr xHeader;
static struct pcap_pkthdr *pxHeader;
const uint8_t *pucPacketData;
uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ];
NetworkBufferDescriptor_t *pxNetworkBuffer;
IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
eFrameProcessingResult_t eResult;
/* Remove compiler warnings about unused parameters. */
( void ) pvParameters;
for( ;; )
{
/* Does the circular buffer used to pass data from the Win32 thread that
handles WinPCAP Rx into the FreeRTOS simulator contain another packet? */
if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) )
{
/* Get the next packet. */
uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)&xHeader, sizeof( xHeader ), pdFALSE );
uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE );
pucPacketData = ucRecvBuffer;
pxHeader = &xHeader;
iptraceNETWORK_INTERFACE_RECEIVE();
/* Check for minimal size. */
if( pxHeader->len >= sizeof( EthernetHeader_t ) )
{
eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData );
}
else
{
eResult = eReleaseBuffer;
}
if( eResult == eProcessBuffer )
{
/* Will the data fit into the frame buffer? */
if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE )
{
/* Obtain a buffer into which the data can be placed. This
is only an interrupt simulator, not a real interrupt, so it
is ok to call the task level function here, but note that
some buffer implementations cannot be called from a real
interrupt. */
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 );
if( pxNetworkBuffer != NULL )
{
memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len );
pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len;
#if( niDISRUPT_PACKETS == 1 )
{
pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData );
}
#endif /* niDISRUPT_PACKETS */
if( pxNetworkBuffer != NULL )
{
xRxEvent.pvData = ( void * ) pxNetworkBuffer;
/* Data was received and stored. Send a message to
the IP task to let it know. */
if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL )
{
/* The buffer could not be sent to the stack so
must be released again. This is only an
interrupt simulator, not a real interrupt, so it
is ok to use the task level function here, but
note no all buffer implementations will allow
this function to be executed from a real
interrupt. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
iptraceETHERNET_RX_EVENT_LOST();
}
}
else
{
/* The packet was already released or stored inside
vRxFaultInjection(). Don't release it here. */
}
}
else
{
iptraceETHERNET_RX_EVENT_LOST();
}
}
else
{
/* Log that a packet was dropped because it would have
overflowed the buffer, but there may be more buffers to
process. */
}
}
}
else
{
/* There is no real way of simulating an interrupt. Make sure
other tasks can run. */
vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY );
}
}
}
/*-----------------------------------------------------------*/
static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage )
{
char *pcTarget = pcBuffer;
/* Utility function used to formap messages being printed only. */
while( ( *pcMessage != 0 ) && ( pcTarget < ( pcBuffer + aBuflen - 1 ) ) )
{
*( pcTarget++ ) = *pcMessage;
if( isspace( *pcMessage ) != pdFALSE )
{
while( isspace( *pcMessage ) != pdFALSE )
{
pcMessage++;
}
}
else
{
pcMessage++;
}
}
*pcTarget = '\0';
return pcBuffer;
}

View File

@ -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 );
}
}
}
}
/*-----------------------------------------------------------*/

View File

@ -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

View File

@ -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 );
}
}

View File

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

View File

@ -0,0 +1,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__ */

View File

@ -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);
}

View File

@ -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( );
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

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

View File

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

View File

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

View File

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