
This patch fixes the compiler warnings in the xemacps_ieee1588_example.c file. Signed-off-by: Venkata Naga Sai Krishna Kolapalli <venkatan@xilinx.com>
2386 lines
69 KiB
C
Executable file
2386 lines
69 KiB
C
Executable file
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2011 - 2014 Xilinx, Inc. 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.
|
|
*
|
|
* Use of the Software is limited solely to applications:
|
|
* (a) running on a Xilinx device, or
|
|
* (b) that interact with a Xilinx device through a bus or interconnect.
|
|
*
|
|
* 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
|
|
* XILINX CONSORTIUM 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.
|
|
*
|
|
* Except as contained in this notice, the name of the Xilinx shall not be used
|
|
* in advertising or otherwise to promote the sale, use or other dealings in
|
|
* this Software without prior written authorization from Xilinx.
|
|
*
|
|
******************************************************************************/
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* @file xemacps_ieee1588_example.c
|
|
*
|
|
* This is top level c file for the IEEE1588 (PTP) standalone example. It has the
|
|
* following functionalities. It uses SCUTimer to transmit PTP packets at
|
|
* regular intervals.
|
|
* - Contains the main routine for the PTP protocol example.
|
|
* - Initializes the SCUGIC, SCUTimer
|
|
* - Initializes the EmacPs hardware for packet transfer.
|
|
* - Initializes the buffer descriptors for the PTP packet transfer.
|
|
* - Initializes and handles the buffers that receive the PTP packets and whose
|
|
* address goes in the buffer descriptors.
|
|
* - Contains the interrupt handlers for Ethernet Tx and Ethernet Rx.
|
|
* - Contains the Timer interrupt handlers.
|
|
* - Implements the top level state machine for the PTP protocol.
|
|
* - Contains routines that initiate the PTP Tx.
|
|
* - Initializes the some fields in the PTP Tx packets. These fields are
|
|
* fixed and its entries do not change with time.
|
|
* - Contains various helper routines, e.g. routines for endian conversion.
|
|
*
|
|
* <pre>
|
|
* MODIFICATION HISTORY:
|
|
*
|
|
* Ver Who Date Changes
|
|
* ----- ---- -------- -----------------------------------------------
|
|
* 1.00a asa 09/16/11 First release based on the AVB driver.
|
|
* 1.01a asa 03/03/12 Support for Zynq is added. BD handling is changed.
|
|
* </pre>
|
|
*
|
|
******************************************************************************/
|
|
|
|
/***************************** Include Files *********************************/
|
|
|
|
#include "xil_types.h"
|
|
#include "xil_io.h"
|
|
#include "xil_assert.h"
|
|
#include "xparameters.h"
|
|
#include "stdio.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 "xscugic.h"
|
|
#include "xscutimer.h"
|
|
#include "xemacps.h" /* defines XEmacPs API */
|
|
#include "xemacps_ieee1588.h"
|
|
#include "xil_mmu.h"
|
|
/************************** Constant Definitions *****************************/
|
|
|
|
/*
|
|
* The following constants map to the XPAR parameters created in the
|
|
* xparameters_ps.h file. They are defined here such that a user can easily
|
|
* change all the needed parameters in one place.
|
|
*/
|
|
#define EMACPS_DEVICE_ID XPAR_XEMACPS_0_DEVICE_ID
|
|
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
|
|
#define TIMER_DEVICE_ID XPAR_SCUTIMER_DEVICE_ID
|
|
#define EMACPS_IRPT_INTR XPS_GEM0_INT_ID
|
|
#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR
|
|
|
|
#ifndef PEEP
|
|
#define RX_BD_START_ADDRESS 0x0FF00000
|
|
#define TX_BD_START_ADDRESS 0x0FF10000
|
|
#endif
|
|
|
|
#ifdef PEEP
|
|
/* Timer load value for timer expiry in every 500 mseconds. */
|
|
#define TIMER_LOAD_VALUE 0x2625A0
|
|
#else
|
|
/* Timer load value for timer expiry in every 500 milli seconds. */
|
|
#define TIMER_LOAD_VALUE XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 4
|
|
#endif
|
|
/**************************** Type Definitions *******************************/
|
|
|
|
/***************** Macros (Inline Functions) Definitions *********************/
|
|
|
|
#define RXBD_SPACE_BYTES \
|
|
XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, XEMACPS_IEEE1588_NO_OF_RX_DESCS)
|
|
|
|
#define TXBD_SPACE_BYTES \
|
|
XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, XEMACPS_IEEE1588_NO_OF_TX_DESCS)
|
|
|
|
/************************** Variable Definitions *****************************/
|
|
|
|
XEmacPs_Ieee1588 *GlobalInstancePntr;
|
|
|
|
XEmacPs Mac;
|
|
XEmacPs_Ieee1588 IEEE1588ProtoHandler;
|
|
static XScuGic IntcInstance; /* The instance of the SCUGic Driver */
|
|
static XScuTimer TimerInstance; /* The instance of the SCUTimer Driver */
|
|
|
|
/* Detected link speed goes here. */
|
|
int Link_Speed = 100;
|
|
/* Detected PHY address goes here. */
|
|
int PhyAddress;
|
|
#ifdef IEEE1588_MASTER
|
|
/* Set MAC address */
|
|
u8 UnicastMAC[] = {0x00, 0x0A, 0x35, 0x01, 0x02, 0x03};
|
|
#else
|
|
u8 UnicastMAC[] = {0x00, 0x0A, 0x35, 0x01, 0x02, 0x09};
|
|
#endif
|
|
/*
|
|
* Aligned memory segments to be used for Rx buffer descriptors
|
|
*/
|
|
u8 RxBuf[XEMACPS_IEEE1588_NO_OF_RX_DESCS][XEMACPS_PACKET_LEN + 2]
|
|
__attribute__ ((aligned(XEMACPS_RX_BUF_ALIGNMENT)));
|
|
|
|
#ifdef PEEP
|
|
u8 TxRingPntrBase[TXBD_SPACE_BYTES]
|
|
__attribute__ ((aligned(XEMACPS_BD_ALIGNMENT)));
|
|
u8 RxRingPntrBase[RXBD_SPACE_BYTES]
|
|
__attribute__ ((aligned(XEMACPS_BD_ALIGNMENT)));
|
|
#endif
|
|
#ifdef IEEE1588_MASTER
|
|
u8 SrcAddr[6] = {0x00,0x0A,0x35,0x01,0x02,0x03};
|
|
u8 DestnAddr[6] = {0x01,0x80,0xC2,0x00,0x00,0x0E};
|
|
#else
|
|
u8 SrcAddr[6] = {0x00,0x0A,0x35,0x01,0x02,0x09};
|
|
u8 DestnAddr[6] = {0x01,0x80,0xC2,0x00,0x00,0x0E};
|
|
#endif
|
|
volatile u8 PDelayRespSent;
|
|
volatile u8 SyncSent;
|
|
volatile u32 PTPSendPacket = 0;
|
|
|
|
/************************** Function Prototypes ******************************/
|
|
|
|
int XEmacPs_InitScuTimer(void);
|
|
void XEmacPs_PHYSetup (XEmacPs *EmacPsInstancePtr);
|
|
int XEmacPs_SetupIntrSystem(XScuGic *IntcInstancePtr,
|
|
XEmacPs *EmacPsInstancePtr, XScuTimer *TimerInstancePtr,
|
|
u16 EmacPsIntrId, u16 TimerIntrId);
|
|
void XEmacPs_RunIEEE1588Protocol(XEmacPs *EmacInstance);
|
|
void XEmacPs_InitializeEmacPsDma (XEmacPs_Ieee1588 *InstancePntr);
|
|
void XEmacPs_InitializeProtocolData(XEmacPs_Ieee1588 *InstancePntr);
|
|
void XEmacPs_HandleRecdPTPPacket(XEmacPs_Ieee1588 *InstancePtr);
|
|
void XEmacPs_PtpTxInterruptHandler (XEmacPs_Ieee1588 *InstancePtr);
|
|
void XEmacPs_SetDfltTxFrms(XEmacPs_Ieee1588 *InstancePtr);
|
|
u8 XEmacPs_GetMsgType (u8 *PacketBuf);
|
|
void XEmacPs_PtpTxDoFurtherProcessing (XEmacPs_Ieee1588 *InstancePtr,
|
|
u8 *PacketBuf);
|
|
void XEmacPs_TimerInterruptHandler(XEmacPs_Ieee1588 *InstancePtr);
|
|
void XEmacPs_PtpErrorInterruptHandler (XEmacPs_Ieee1588 *InstancePtr,
|
|
u8 Direction, u32 ErrorWord);
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This is the main function for the IEEE1588 (PTP) standalone example. It calls
|
|
* routines to initialize ScuTimer and EmacPs. It enables interrupts
|
|
* at the end of all initializations and calls XEmacPs_RunIEEE1588Protocol that
|
|
* runs the protocol state machine.
|
|
*
|
|
* @param None.
|
|
*
|
|
* @return - XST_SUCCESS to indicate success.
|
|
* - XST_FAILURE to indicate failure
|
|
*
|
|
* @note None.
|
|
*
|
|
****************************************************************************/
|
|
int main(void)
|
|
{
|
|
XEmacPs_Config *Cfg;
|
|
int Status = XST_SUCCESS;
|
|
XEmacPs *EmacPsInstancePtr = &Mac;
|
|
unsigned int NSIncrementVal;
|
|
|
|
#ifdef PEEP
|
|
/*
|
|
* Caches are disabled for this example as of now.
|
|
*/
|
|
Xil_ICacheDisable();
|
|
Xil_DCacheDisable();
|
|
#endif
|
|
xil_printf("Entering into main() \r\n");
|
|
|
|
#ifndef PEEP
|
|
Xil_DisableMMU();
|
|
Xil_SetTlbAttributes(0x0FF00000, 0xc02); // addr, attr
|
|
Xil_EnableMMU();
|
|
#endif
|
|
/* Initialize SCUTIMER */
|
|
|
|
if (XEmacPs_InitScuTimer() != XST_SUCCESS) while(1);
|
|
|
|
/*
|
|
* Get the configuration of EmacPs hardware.
|
|
*/
|
|
Cfg = XEmacPs_LookupConfig(EMACPS_DEVICE_ID);
|
|
|
|
/*
|
|
* Initialize EmacPs hardware.
|
|
*/
|
|
Status = XEmacPs_CfgInitialize(EmacPsInstancePtr, Cfg,
|
|
Cfg->BaseAddress);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Set the MAC address
|
|
*/
|
|
Status = XEmacPs_SetMacAddress(EmacPsInstancePtr,
|
|
(unsigned char*)UnicastMAC, 1);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
#ifndef PEEP
|
|
XEmacPs_SetMdioDivisor(EmacPsInstancePtr, MDC_DIV_224);
|
|
#endif
|
|
/*
|
|
* Detect and initialize the PHY
|
|
*/
|
|
XEmacPs_PHYSetup (EmacPsInstancePtr);
|
|
sleep(1);
|
|
|
|
/*
|
|
* Set the operating speed in EmacPs hardware.
|
|
*/
|
|
XEmacPs_SetOperatingSpeed(EmacPsInstancePtr, Link_Speed);
|
|
sleep(1);
|
|
|
|
/*
|
|
* Enable the promiscuous mode in EmacPs hardware.
|
|
*/
|
|
Status = XEmacPs_SetOptions(EmacPsInstancePtr, XEMACPS_PROMISC_OPTION);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
#ifdef PEEP
|
|
/*
|
|
* Set the 1588 Timer register for 50 MHz timer, i.e. 20 ns increment
|
|
* for every clock cycle.
|
|
*/
|
|
XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress,
|
|
XEMACPS_1588_INC_OFFSET,
|
|
XEMACPS_1588_INC_VAL);
|
|
#else
|
|
|
|
NSIncrementVal = XEmacPs_TsuCalcClk
|
|
(XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 6);
|
|
XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress,
|
|
XEMACPS_1588_INC_OFFSET,
|
|
NSIncrementVal);
|
|
#endif
|
|
|
|
/*
|
|
* Register Ethernet Rx, Tx and Error handlers with the EmacPs driver.
|
|
*/
|
|
Status = XEmacPs_SetHandler (EmacPsInstancePtr,
|
|
XEMACPS_HANDLER_DMARECV,
|
|
XEmacPs_PtpRxInterruptHandler,
|
|
&IEEE1588ProtoHandler);
|
|
Status |= XEmacPs_SetHandler (EmacPsInstancePtr,
|
|
XEMACPS_HANDLER_DMASEND,
|
|
XEmacPs_PtpTxInterruptHandler,
|
|
&IEEE1588ProtoHandler);
|
|
Status |= XEmacPs_SetHandler (EmacPsInstancePtr,
|
|
XEMACPS_HANDLER_ERROR,
|
|
XEmacPs_PtpErrorInterruptHandler,
|
|
&IEEE1588ProtoHandler);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Connect to the interrupt controller and enable interrupts in
|
|
* interrupt controller.
|
|
*/
|
|
Status = XEmacPs_SetupIntrSystem(&IntcInstance, EmacPsInstancePtr,
|
|
&TimerInstance, EMACPS_IRPT_INTR,
|
|
TIMER_IRPT_INTR);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Enable the timer interrupt in the timer module
|
|
*/
|
|
XScuTimer_EnableInterrupt(&TimerInstance);
|
|
|
|
/*
|
|
* Start the PTP standalone state machine.
|
|
*/
|
|
XEmacPs_RunIEEE1588Protocol(EmacPsInstancePtr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function initializes the SCUTimer.
|
|
*
|
|
* @param None.
|
|
*
|
|
* @return - XST_SUCCESS to indicate success.
|
|
* - XST_FAILURE to indicate failure
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
int XEmacPs_InitScuTimer(void)
|
|
{
|
|
int Status = XST_SUCCESS;
|
|
XScuTimer_Config *ConfigPtr;
|
|
|
|
/*
|
|
* Get the configuration of Timer hardware.
|
|
*/
|
|
ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
|
|
|
|
/*
|
|
* Initialize ScuTimer hardware.
|
|
*/
|
|
Status = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr,
|
|
ConfigPtr->BaseAddr);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
XScuTimer_EnableAutoReload(&TimerInstance);
|
|
|
|
/*
|
|
* Initialize ScuTimer with a count so that the interrupt
|
|
* comes every 500 msec.
|
|
*/
|
|
XScuTimer_LoadTimer(&TimerInstance, TIMER_LOAD_VALUE);
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
#ifndef PEEP
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* Calculate clock configuration register values for indicated input clock
|
|
*
|
|
* @param - Freq
|
|
*
|
|
* @return - XST_SUCCESS to indicate success.
|
|
* - XST_FAILURE to indicate failure
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
unsigned int XEmacPs_TsuCalcClk(u32 Freq)
|
|
{
|
|
u64 Period_ns = (NS_PER_SEC * FP_MULT)/Freq;
|
|
unsigned Retval;
|
|
|
|
Period_ns = (NS_PER_SEC * FP_MULT)/Freq;
|
|
Retval = Period_ns / FP_MULT;
|
|
return Retval;
|
|
}
|
|
#endif
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function sets up interrupts. It registers interrupt handlers and then
|
|
* enables them..
|
|
*
|
|
* @param IntcInstancePtr is a pointer to the instance of the SCUGic..
|
|
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs.
|
|
* @param TimerInstancePtr is a pointer to the instance of the SCUTimer.
|
|
* @param EmacPsIntrId is the Interrupt ID for EmacPs and the value
|
|
* used is taken from xparameters_ps.h.
|
|
* @param TimerIntrId is the Interrupt ID for SCUTimer and the value
|
|
* used is taken from xparameters_ps.h.
|
|
*
|
|
* @return - XST_SUCCESS to indicate success.
|
|
* - XST_FAILURE to indicate failure
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
int XEmacPs_SetupIntrSystem(XScuGic *IntcInstancePtr,
|
|
XEmacPs *EmacPsInstancePtr, XScuTimer *TimerInstancePtr,
|
|
u16 EmacPsIntrId, u16 TimerIntrId)
|
|
{
|
|
int Status = XST_SUCCESS;
|
|
XScuGic_Config *GicConfig;
|
|
|
|
Xil_ExceptionInit();
|
|
|
|
/*
|
|
* Initialize the interrupt controller driver so that it is ready to
|
|
* use.
|
|
*/
|
|
GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
|
|
if (NULL == GicConfig) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
Status = XScuGic_CfgInitialize(&IntcInstance, GicConfig,
|
|
GicConfig->CpuBaseAddress);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
/*
|
|
* Connect the interrupt controller interrupt handler to the hardware
|
|
* interrupt handling logic in the processor.
|
|
*/
|
|
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
|
|
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
|
|
IntcInstancePtr);
|
|
|
|
/*
|
|
* Connect the EmacPs device driver handler that will be called when an
|
|
* interrupt for the device occurs. The device driver handler performs
|
|
* the specific interrupt processing for the device.
|
|
*/
|
|
Status = XScuGic_Connect(IntcInstancePtr, EmacPsIntrId,
|
|
(Xil_InterruptHandler) XEmacPs_IntrHandler,
|
|
(void *) EmacPsInstancePtr);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Connect the handler for timer interrupt that will be called when the
|
|
* timer.expires.
|
|
*/
|
|
Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId,
|
|
(Xil_ExceptionHandler)XEmacPs_TimerInterruptHandler,
|
|
(void *)&IEEE1588ProtoHandler);
|
|
if (Status != XST_SUCCESS) {
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Enable interrupts from the hardware
|
|
*/
|
|
XScuGic_Enable(IntcInstancePtr, EmacPsIntrId);
|
|
XScuGic_Enable(IntcInstancePtr, TimerIntrId);
|
|
|
|
/*
|
|
* Enable interrupts in the processor
|
|
*/
|
|
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function finds out if a PHY is connected or not and if connected what
|
|
* is the PHY address of the connected PHY.
|
|
*
|
|
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs.
|
|
*
|
|
* @return - Detected PHY address if successful.
|
|
* - 0 if no PHY is connected.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
unsigned long XEmacPs_DetectPHY(XEmacPs *EmacPsInstancePtr)
|
|
{
|
|
u16 PhyReg;
|
|
int PhyAddr;
|
|
|
|
for (PhyAddr = 31; PhyAddr >= 0; PhyAddr--) {
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, PHY_DETECT_REG,
|
|
&PhyReg);
|
|
|
|
if ((PhyReg != 0xFFFF) && ((PhyReg & PHY_DETECT_MASK) ==
|
|
PHY_DETECT_MASK)) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: Detected PHY address is %d \r\n",
|
|
__func__, PhyAddr);
|
|
#endif
|
|
return (u32) PhyAddr;
|
|
}
|
|
}
|
|
return 0; /* default to zero */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function configures the PHY with proper speed settings and set up the
|
|
* PHY to be used subsequently.
|
|
*
|
|
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_PHYSetup (XEmacPs *EmacPsInstancePtr)
|
|
{
|
|
#ifdef PEEP
|
|
int Status;
|
|
int Index=0;
|
|
u16 PhyReg0;
|
|
u16 PhyReg20;
|
|
|
|
/*
|
|
* Detect the connected PHY and get the PHY address.
|
|
*/
|
|
PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr);
|
|
Status = XEmacPs_PhyRead(&Mac, PhyAddress, 20, &PhyReg20);
|
|
PhyReg20 |= 0x0080;
|
|
Status |= XEmacPs_PhyWrite(&Mac, PhyAddress, 20, PhyReg20);
|
|
|
|
/*
|
|
* Set the PHY speed as 100 Mbps and reset the PHY.
|
|
*/
|
|
Status |= XEmacPs_PhyRead(&Mac, PhyAddress, 0, &PhyReg0);
|
|
PhyReg0 = PHY_R0_100;
|
|
Status |= XEmacPs_PhyWrite(&Mac, PhyAddress, 0, PhyReg0);
|
|
Status |= XEmacPs_PhyWrite(&Mac, PhyAddress, 0, (PhyReg0 |
|
|
PHY_R0_RESET));
|
|
|
|
if (Status != XST_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Delay for the PHY reset to get over.
|
|
*/
|
|
while (Index < 0x10000) Index++;
|
|
#else
|
|
#ifdef PHY_AUTONEGOTIATION
|
|
u16 Temp;
|
|
u16 Partner_capabilities;
|
|
#else
|
|
u16 PhyReg0 = 0;
|
|
#endif
|
|
u16 Control = 0;
|
|
u16 Status;
|
|
u32 SlcrTxClkCntrl;
|
|
|
|
#ifdef PHY_AUTONEGOTIATION
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: Start PHY autonegotiation \r\n",__func__);
|
|
#endif
|
|
/*
|
|
* Detect the connected PHY and get the PHY address.
|
|
*/
|
|
PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr);
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr,PhyAddress, 22, 2);
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 21, &Control);
|
|
Control |= 0x30;
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 21, Control);
|
|
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0);
|
|
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_AUTONEGO_ADVERTISE_REG, &Control);
|
|
Control |= 0xd80;
|
|
Control |= 0x60;
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_AUTONEGO_ADVERTISE_REG, Control);
|
|
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_1000_ADVERTISE_REG_OFFSET, &Control);
|
|
Control |= ADVERTISE_1000;
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_1000_ADVERTISE_REG_OFFSET, Control);
|
|
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0);
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 16, &Control);
|
|
Control |= (7 << 12); /* max number of gigabit attempts */
|
|
Control |= (1 << 11); /* enable downshift */
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 16, Control);
|
|
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_CONTROL_REG_OFFSET, &Control);
|
|
Control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
|
|
Control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_CONTROL_REG_OFFSET, Control);
|
|
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_CONTROL_REG_OFFSET, &Control);
|
|
Control |= IEEE_CTRL_RESET_MASK;
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_CONTROL_REG_OFFSET, Control);
|
|
|
|
while (1) {
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_CONTROL_REG_OFFSET, &Control);
|
|
if (Control & IEEE_CTRL_RESET_MASK)
|
|
continue;
|
|
else
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: Waiting for PHY to complete autonegotiation.\r\n",
|
|
__func__);
|
|
#endif
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_STATUS_REG_OFFSET, &Status);
|
|
while ( !(Status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
|
|
sleep(1);
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 19, &Temp);
|
|
if (Temp & 0x8000) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: Auto negotiation error \r\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_STATUS_REG_OFFSET,
|
|
&Status);
|
|
}
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: Autonegotiation complete \r\n", __func__);
|
|
#endif
|
|
|
|
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
|
|
IEEE_SPECIFIC_STATUS_REG,
|
|
&Partner_capabilities);
|
|
if ( ((Partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */ {
|
|
Link_Speed = 1000;
|
|
xil_printf("Partner_capabilities are %x\r\n",
|
|
Partner_capabilities);
|
|
/* GEM1 1G clock configuration*/
|
|
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) =
|
|
SLCR_UNLOCK_KEY_VALUE;
|
|
SlcrTxClkCntrl =
|
|
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
|
|
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
|
SlcrTxClkCntrl |=
|
|
(XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20);
|
|
SlcrTxClkCntrl
|
|
|= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8);
|
|
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) =
|
|
SlcrTxClkCntrl;
|
|
*(volatile unsigned int *)(SLCR_LOCK_ADDR) =
|
|
SLCR_LOCK_KEY_VALUE;
|
|
sleep(1);
|
|
}
|
|
else if ( ((Partner_capabilities >> 14) & 3) == 1)/* 100Mbps */ {
|
|
Link_Speed = 100;
|
|
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) =
|
|
SLCR_UNLOCK_KEY_VALUE;
|
|
SlcrTxClkCntrl =
|
|
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
|
|
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
|
SlcrTxClkCntrl
|
|
|= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20);
|
|
SlcrTxClkCntrl
|
|
|= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8);
|
|
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) =
|
|
SlcrTxClkCntrl;
|
|
*(volatile unsigned int *)(SLCR_LOCK_ADDR) =
|
|
SLCR_LOCK_KEY_VALUE;
|
|
sleep(1);
|
|
}
|
|
else /* 10Mbps */ {
|
|
Link_Speed = 10;
|
|
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) =
|
|
SLCR_UNLOCK_KEY_VALUE;
|
|
SlcrTxClkCntrl =
|
|
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
|
|
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
|
SlcrTxClkCntrl |=
|
|
(XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1 << 20);
|
|
SlcrTxClkCntrl |=
|
|
(XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 << 8);
|
|
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) =
|
|
SlcrTxClkCntrl;
|
|
*(volatile unsigned int *)(SLCR_LOCK_ADDR) =
|
|
SLCR_LOCK_KEY_VALUE;
|
|
sleep(1);
|
|
}
|
|
xil_printf("In %s: Autonegotiated link speed is %d\r\n",
|
|
__func__, Link_Speed);
|
|
return;
|
|
#else
|
|
/*
|
|
* Detect the connected PHY and get the PHY address.
|
|
*/
|
|
PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr);
|
|
Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
|
|
PhyReg0 &= (~IEEE_CTRL_AUTONEGOTIATE_ENABLE);
|
|
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, PhyReg0);
|
|
|
|
Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
|
|
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0,
|
|
(PhyReg0 |PHY_R0_RESET));
|
|
sleep(1);
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr,PhyAddress, 22, 2);
|
|
Control |= PHY_REG21_100;
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 21, Control);
|
|
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0);
|
|
|
|
/*
|
|
* Set the PHY speed and reset the PHY.
|
|
*/
|
|
Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
|
|
PhyReg0 = PHY_REG0_100;
|
|
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, PhyReg0);
|
|
|
|
Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
|
|
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0,
|
|
(PhyReg0 |PHY_R0_RESET));
|
|
sleep(1);
|
|
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
|
|
SlcrTxClkCntrl = *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
|
|
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
|
SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20);
|
|
SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8);
|
|
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = SlcrTxClkCntrl;
|
|
*(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
|
|
sleep(1);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function implements the main state machine. After initializing the
|
|
* EmacPs DMA and initializing some protocol data structures it enters into a
|
|
* while(1) loop. Here it repeatedly checks if a new packet has been received
|
|
* or not. If received (the ISR marks the variable PtpNewPktRecd as true), then
|
|
* it calls XEmacPs_HandleRecdPTPPacket for further processing.
|
|
* Similarly if a packet needs to be sent out (as marked by the bits in
|
|
* variable PTPSendPacket, it sends it out.
|
|
*
|
|
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_RunIEEE1588Protocol(XEmacPs *EmacInstance)
|
|
{
|
|
XEmacPs_Stop(EmacInstance);
|
|
GlobalInstancePntr = &IEEE1588ProtoHandler;
|
|
GlobalInstancePntr->EmacPsInstance = EmacInstance;
|
|
|
|
/*
|
|
* Initialize the DMA and buffer descriptors
|
|
*/
|
|
XEmacPs_InitializeEmacPsDma (GlobalInstancePntr);
|
|
|
|
/*
|
|
* Initialize some of the protocol structure instances and Tx frames
|
|
* with default data.
|
|
*/
|
|
XEmacPs_InitializeProtocolData(GlobalInstancePntr);
|
|
|
|
|
|
while(1) {
|
|
/*
|
|
* If a new packet has been received, copy the packet into
|
|
* corresponding buffer and call XEmacPs_HandleRecdPTPPacket to
|
|
* do further processing.
|
|
*/
|
|
if (GlobalInstancePntr->PtpNewPktRecd == TRUE) {
|
|
GlobalInstancePntr->PtpNewPktRecd = FALSE;
|
|
XEmacPs_HandleRecdPTPPacket(GlobalInstancePntr);
|
|
}
|
|
|
|
/*
|
|
* If a packet needs to be sent
|
|
*/
|
|
if (PTPSendPacket != 0) {
|
|
/*
|
|
* If a PDelayResp needs to be sent, initiate a Tx.
|
|
* Set the corresponding bit in the variable
|
|
* PTPSendPacket to send a PDelayRespFollowUp packet
|
|
* once the PDelayResp is successfully sent out
|
|
* (Tx Done interrupt generated for PDelayResp.)
|
|
*/
|
|
|
|
if (PTPSendPacket & SEND_PDELAY_RESP) {
|
|
XEmacPs_PtpTxPacket(GlobalInstancePntr,
|
|
GlobalInstancePntr->PDelayRespFrmToTx,
|
|
XEMACPS_PDELAYRESPMSG_TOT_LEN);
|
|
PTPSendPacket = PTPSendPacket &
|
|
(~SEND_PDELAY_RESP);
|
|
PTPSendPacket |= SEND_PDELAY_RESP_FOLLOWUP;
|
|
}
|
|
|
|
/*
|
|
* If a PDelayRespFollowUp needs to be sent check if
|
|
* the previous PDelayResp is successfully sent out or
|
|
* not. If the PDelayResp is sent out successfully,
|
|
* the flag PDelayRespSent is marked as True in the
|
|
* Tx Done ISR.
|
|
*/
|
|
if (PTPSendPacket & SEND_PDELAY_RESP_FOLLOWUP) {
|
|
if (PDelayRespSent == TRUE) {
|
|
XEmacPs_SendPDelayRespFollowUp
|
|
(GlobalInstancePntr);
|
|
PTPSendPacket = PTPSendPacket &
|
|
(~SEND_PDELAY_RESP_FOLLOWUP);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If a PDelayReq needs to be sent initiate a Tx here.
|
|
*/
|
|
if (PTPSendPacket & SEND_PDELAY_REQ) {
|
|
XEmacPs_PtpTxPacket(GlobalInstancePntr,
|
|
GlobalInstancePntr->PDelayReqFrmToTx,
|
|
XEMACPS_PDELAYREQMSG_TOT_LEN);
|
|
PTPSendPacket = PTPSendPacket &
|
|
(~SEND_PDELAY_REQ);
|
|
}
|
|
|
|
/*
|
|
* If a SYNC packet needs to be sent initiate a Tx
|
|
* here. Set the bit corresponding to FOLLOWUP packet
|
|
* in the variable PTPSendPacket. This will initiate a
|
|
* Tx for FollowUp frame once the SYNC frame is
|
|
* successfully sent out and a Tx done interrupt is
|
|
* received.
|
|
*/
|
|
if (PTPSendPacket & SEND_SYNC) {
|
|
XEmacPs_PtpTxPacket (GlobalInstancePntr,
|
|
GlobalInstancePntr->SyncFrmToTx,
|
|
XEMACPS_SYNCMSG_TOT_LEN);
|
|
PTPSendPacket = PTPSendPacket & (~SEND_SYNC);
|
|
PTPSendPacket |= SEND_FOLLOW_UP;
|
|
}
|
|
|
|
/*
|
|
* If a FollowUp needs to be sent check if
|
|
* the previous SYNC is successfully sent out or
|
|
* not. If the SYNC is sent out successfully,
|
|
* the flag SyncSent is marked as True in the
|
|
* Tx Done ISR.
|
|
*/
|
|
if (PTPSendPacket & SEND_FOLLOW_UP) {
|
|
if (SyncSent == TRUE) {
|
|
XEmacPs_MasterSendFollowUp
|
|
(GlobalInstancePntr);
|
|
PTPSendPacket = PTPSendPacket &
|
|
(~SEND_FOLLOW_UP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function initializes the EmacPs DMA buffer descriptors. 16 BDs are used
|
|
* on the Tx path and 16 on the Rx path. On the Rx path a 2-dimensional array
|
|
* RxBuf[16][1540] is used. The last byte in each of the buffers is used to mark
|
|
* whether the RxBuf is already submitted or not. For example, if the location
|
|
* RxBuf[1][1539] is 1, then it means the RxBuf[1] is already submitted. During
|
|
* initialization, for 16 BDs, 16 RxBufs are submitted (RxBuf[0, RxBuf[1], ...
|
|
* RxBuf[15]]) and the corresponding entries RxBuf[0][1539], RxBuf[1][1539], ...
|
|
* RxBuf[15][1539] are marked as 1.
|
|
* On the Rx path, all 16 BDs are submitted to the hardware.
|
|
* Once that is done, the timer is started and so is the EmacPs.
|
|
*
|
|
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_InitializeEmacPsDma (XEmacPs_Ieee1588 *InstancePntr)
|
|
{
|
|
XEmacPs_BdRing *TxRingPtr;
|
|
XEmacPs_BdRing *RxRingPtr;
|
|
XEmacPs_Bd *RxBdPtr;
|
|
XEmacPs_Bd *CurrBdPtr;
|
|
int Status;
|
|
int Index;
|
|
XEmacPs_Bd BdTemplate;
|
|
|
|
Status = XST_SUCCESS;
|
|
|
|
TxRingPtr = &XEmacPs_GetTxRing(InstancePntr->EmacPsInstance);
|
|
RxRingPtr = &XEmacPs_GetRxRing(InstancePntr->EmacPsInstance);
|
|
|
|
/*
|
|
* BdTemplate is used for cloning. Hence it is cleared so that
|
|
* all 16 BDs can be cleared.
|
|
*/
|
|
XEmacPs_BdClear(&BdTemplate);
|
|
#ifdef PEEP
|
|
/*
|
|
* Create 16 BDs for Rx path.
|
|
*/
|
|
Status = XEmacPs_BdRingCreate (RxRingPtr,
|
|
(u32)&RxRingPntrBase,
|
|
(u32)&RxRingPntrBase,
|
|
XEMACPS_IEEE1588_BD_ALIGNMENT,
|
|
XEMACPS_IEEE1588_NO_OF_RX_DESCS);
|
|
#else
|
|
Status = XEmacPs_BdRingCreate (RxRingPtr,
|
|
(u32)RX_BD_START_ADDRESS,
|
|
(u32)RX_BD_START_ADDRESS,
|
|
XEMACPS_IEEE1588_BD_ALIGNMENT,
|
|
XEMACPS_IEEE1588_NO_OF_RX_DESCS);
|
|
#endif
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: BD Ring Creation failed for Rx path \r\n",
|
|
__func__);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Clone the 16 BDs with BdTemplate. This will clear all the 16 BDs.
|
|
*/
|
|
Status = XEmacPs_BdRingClone(RxRingPtr, &BdTemplate, XEMACPS_RECV);
|
|
if (Status != XST_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* BdTemplate is used for cloning on Tx path. Hence it is cleared so
|
|
* that all 16 BDs can be cleared.
|
|
*/
|
|
XEmacPs_BdClear(&BdTemplate);
|
|
/*
|
|
* Set the Used Bit.
|
|
*/
|
|
XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
|
|
|
|
/*
|
|
* Create 16 BDs for Tx path.
|
|
*/
|
|
#ifdef PEEP
|
|
Status = XEmacPs_BdRingCreate (TxRingPtr,
|
|
(u32)&TxRingPntrBase,
|
|
(u32)&TxRingPntrBase,
|
|
XEMACPS_IEEE1588_BD_ALIGNMENT,
|
|
XEMACPS_IEEE1588_NO_OF_TX_DESCS);
|
|
#else
|
|
Status = XEmacPs_BdRingCreate (TxRingPtr,
|
|
(u32)TX_BD_START_ADDRESS,
|
|
(u32)TX_BD_START_ADDRESS,
|
|
XEMACPS_IEEE1588_BD_ALIGNMENT,
|
|
XEMACPS_IEEE1588_NO_OF_TX_DESCS);
|
|
#endif
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: BD Ring Creation failed for Tx path \r\n",
|
|
__func__);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Clone the 16 BDs with BdTemplate. This will clear all the 16 BDs
|
|
* and set the Used bit in all of them.
|
|
*/
|
|
Status = XEmacPs_BdRingClone (TxRingPtr, &BdTemplate, XEMACPS_SEND);
|
|
if (Status != XST_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Allocate the 16 BDs on Rx path.
|
|
*/
|
|
Status = XEmacPs_BdRingAlloc (RxRingPtr,
|
|
XEMACPS_IEEE1588_NO_OF_RX_DESCS,
|
|
&RxBdPtr);
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: BD Ring allocation failed for Rx path \r\n",
|
|
__func__);
|
|
#endif
|
|
return;
|
|
}
|
|
/*
|
|
* Mark the RxBufs as used.
|
|
*/
|
|
CurrBdPtr = RxBdPtr;
|
|
for (Index = 0; Index < XEMACPS_IEEE1588_NO_OF_RX_DESCS; Index++) {
|
|
XEmacPs_BdSetAddressRx (CurrBdPtr, &(RxBuf[Index][0]));
|
|
XEmacPs_BdSetLast(CurrBdPtr);
|
|
RxBuf[Index][XEMACPS_PACKET_LEN - 2] = 1;
|
|
CurrBdPtr = XEmacPs_BdRingNext (RxRingPtr, CurrBdPtr);
|
|
}
|
|
/*
|
|
* Submit the BDs on the Rx path.
|
|
*/
|
|
Status = XEmacPs_BdRingToHw (RxRingPtr,
|
|
XEMACPS_IEEE1588_NO_OF_RX_DESCS,
|
|
RxBdPtr);
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: BD Ring submission failed for Rx path \r\n",
|
|
__func__);
|
|
#endif
|
|
return;
|
|
}
|
|
/*
|
|
* Start the timer and EmacPs.
|
|
*/
|
|
XEmacPs_Start(InstancePntr->EmacPsInstance);
|
|
XScuTimer_Start(&TimerInstance);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function does various initializations.
|
|
* - It initializes the Local Port Identity. Clock Identity is
|
|
* initialized with 000A35FFFE010203 and port number as 1.
|
|
* - It initializes some of the fields of Tx PTP buffers. These fields remain
|
|
* constant over time and hence are initialized at one place.
|
|
* - It initializes signalling frame data. Since signalling frames are
|
|
* not implemented, the entries in the structure SignallingFrameData are
|
|
* hard coded.
|
|
* - The entries in the structure instance PtpCounters are initialized to 0.
|
|
* - The variable PtpIsRunning is made as 1 so that PTP packets Tx can be
|
|
* initiated in the Timer ISR.
|
|
* - The PTP node is made as Master to start with.
|
|
* - The Peer Ieee1588v2 capability is made as 0 which means the peer is not
|
|
* Ieee1588v2 capable.
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_InitializeProtocolData(XEmacPs_Ieee1588 *InstancePntr)
|
|
{
|
|
/*
|
|
* Populate the local port identity.
|
|
*/
|
|
#ifdef IEEE1588_MASTER
|
|
InstancePntr->PortIdLocal.ClockIdentity[0] = 0x00;
|
|
InstancePntr->PortIdLocal.ClockIdentity[1] = 0x0A;
|
|
InstancePntr->PortIdLocal.ClockIdentity[2] = 0x35;
|
|
InstancePntr->PortIdLocal.ClockIdentity[3] = 0xFF;
|
|
InstancePntr->PortIdLocal.ClockIdentity[4] = 0xFE;
|
|
InstancePntr->PortIdLocal.ClockIdentity[5] = 0x01;
|
|
InstancePntr->PortIdLocal.ClockIdentity[6] = 0x02;
|
|
InstancePntr->PortIdLocal.ClockIdentity[7] = 0x03;
|
|
InstancePntr->PortIdLocal.PortNumber = 0x0001;
|
|
#else
|
|
InstancePntr->PortIdLocal.ClockIdentity[0] = 0x00;
|
|
InstancePntr->PortIdLocal.ClockIdentity[1] = 0x0A;
|
|
InstancePntr->PortIdLocal.ClockIdentity[2] = 0x35;
|
|
InstancePntr->PortIdLocal.ClockIdentity[3] = 0xFF;
|
|
InstancePntr->PortIdLocal.ClockIdentity[4] = 0xFE;
|
|
InstancePntr->PortIdLocal.ClockIdentity[5] = 0x01;
|
|
InstancePntr->PortIdLocal.ClockIdentity[6] = 0x02;
|
|
InstancePntr->PortIdLocal.ClockIdentity[7] = 0x09;
|
|
InstancePntr->PortIdLocal.PortNumber = 0x0001;
|
|
#endif
|
|
/*
|
|
* Initialze some fields in the Tx Ptp buffers.
|
|
*/
|
|
XEmacPs_SetDfltTxFrms(InstancePntr);
|
|
|
|
/*
|
|
* The PTP node is made Master..
|
|
*/
|
|
XEmacPs_BecomeRtcMaster(InstancePntr,0);
|
|
|
|
/*
|
|
* The Peer node not Ieee1588v2 capable to start with...
|
|
*/
|
|
XEmacPs_ChangePeerIeee1588v2Capability(InstancePntr, 0);
|
|
|
|
InstancePntr->PtpIsRunning = 0;
|
|
InstancePntr->PtpRecords.LinkDelay = 0;
|
|
|
|
InstancePntr->SignallingFrameData.SyncIntervalDuration = 2;
|
|
InstancePntr->SignallingFrameData.LinkDelayIntervalDuration = 8;
|
|
InstancePntr->SignallingFrameData.AnnounceIntervalDuration = 10;
|
|
|
|
InstancePntr->LatestMDSyncReceive.SyncIntervalDuration = 2;
|
|
|
|
/*
|
|
* Initialize other driver variables in the device's data structure
|
|
*/
|
|
InstancePntr->PtpCounters.CounterSyncInterval = 0;
|
|
InstancePntr->PtpCounters.CounterLinkDelayInterval = 0;
|
|
InstancePntr->PtpCounters.CounterAnnounceInterval = 0;
|
|
InstancePntr->PtpCounters.CounterSyncEvents = 0;
|
|
InstancePntr->StateMachineData.LostResponses = 0;
|
|
InstancePntr->StateMachineData.RcvdPDelayResp = 0;
|
|
InstancePntr->StateMachineData.RcvdPDelayRespFollowUp = 0;
|
|
|
|
XEmacPs_DecodeTxAnnounceFrame (InstancePntr,
|
|
InstancePntr->AnnounceFrmToTx);
|
|
/*
|
|
* The PTP packets can now be transmitted out.
|
|
*/
|
|
InstancePntr->PtpIsRunning = 1;
|
|
XEmacPs_ChangePeerIeee1588v2Capability (InstancePntr, 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is used when PTP node is initialized once again.
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note This function needs to be revisited as it is partially
|
|
* developed as of now..
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_ResetIeee1588Protocol (XEmacPs_Ieee1588 *InstancePtr)
|
|
{
|
|
/* Assert bad arguments and conditions */
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
Xil_AssertVoid(InstancePtr->EmacPsInstance->IsReady
|
|
== XIL_COMPONENT_IS_READY);
|
|
|
|
XEmacPs_InitializeProtocolData (InstancePtr);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is the timer ISR that is invoked every 500 mseconds. The Tx of
|
|
* PTP packets are initiated from here at appropriate intervals. When the PTP
|
|
* node is Master, the Tx of SYNC frame is triggered from here. Similarly
|
|
* Announce frame and PDelayReq frame Tx are triggered from here.
|
|
* When the PTP node is Slave, the PDelayReq frame Tx is triggered from here.
|
|
*
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note The intervals at which SYNC, ANNOUNCE and PDelayReq are
|
|
* triggered are hard coded to 1 sec, 5 seconds and 4 seconds
|
|
* respectively. When signalling frames are implemented
|
|
* the hardcoded values can be replaced with proper signalling
|
|
* frame values.
|
|
*
|
|
******************************************************************************/
|
|
|
|
void XEmacPs_TimerInterruptHandler(XEmacPs_Ieee1588 *InstancePtr)
|
|
{
|
|
XScuTimer *TimerInstancePntr = &TimerInstance;
|
|
/*
|
|
* Clear the Timer interrupt.
|
|
*/
|
|
XScuTimer_ClearInterruptStatus(TimerInstancePntr);
|
|
/*
|
|
* If PTP functions are marked as not running, then take no
|
|
* further action
|
|
*/
|
|
if (InstancePtr->PtpIsRunning == 1) {
|
|
|
|
/*
|
|
* If the Link Partner is not Ieee1588 capable, then take no
|
|
* further action
|
|
*/
|
|
if (InstancePtr->PeerIeee1588v2Capable == 1) {
|
|
/*
|
|
* If a Master, then initiate Sync Frames and
|
|
* Announce frames at the correct intervals
|
|
*/
|
|
if (InstancePtr->CurrentBmc.IAmTheRtcMaster == 1) {
|
|
|
|
/*
|
|
* Master will initiate a Sync Frame when the
|
|
* SyncIntervalDuration (1 second) expires
|
|
* (SyncIntervalDuration is used to count/time
|
|
* the duration)
|
|
*/
|
|
if ((InstancePtr->SignallingFrameData.
|
|
SyncIntervalDuration !=
|
|
XEMACPS_PKT_TYPE_DISABLED) &&
|
|
(InstancePtr->PtpCounters.
|
|
CounterSyncInterval >=
|
|
(InstancePtr->SignallingFrameData.
|
|
SyncIntervalDuration - 1))) {
|
|
XEmacPs_MasterSendSync(InstancePtr);
|
|
InstancePtr->
|
|
PtpCounters.CounterSyncInterval = 0;
|
|
|
|
} else {
|
|
InstancePtr->PtpCounters.
|
|
CounterSyncInterval
|
|
= InstancePtr->
|
|
PtpCounters.CounterSyncInterval
|
|
+ 1;
|
|
}
|
|
|
|
/*
|
|
* Master will initiate an Announce Frame when
|
|
* the AnnounceIntervalDuration (5 secs)
|
|
* expires (CounterAnnounceInterval is used to
|
|
* count/time the duration)
|
|
*/
|
|
if ((InstancePtr->SignallingFrameData.
|
|
AnnounceIntervalDuration
|
|
!= XEMACPS_PKT_TYPE_DISABLED) &&
|
|
(InstancePtr->
|
|
PtpCounters.CounterAnnounceInterval >=
|
|
(InstancePtr->SignallingFrameData.
|
|
AnnounceIntervalDuration - 1))) {
|
|
|
|
XEmacPs_MasterSendAnnounce(InstancePtr);
|
|
InstancePtr->
|
|
PtpCounters.CounterAnnounceInterval
|
|
= 0;
|
|
|
|
} else {
|
|
InstancePtr->
|
|
PtpCounters.CounterAnnounceInterval
|
|
= InstancePtr->PtpCounters.
|
|
CounterAnnounceInterval + 1;
|
|
}
|
|
|
|
/*
|
|
* If a Slave, monitor Announce/Sync Packet reception
|
|
* from the Master
|
|
*/
|
|
} else {
|
|
|
|
/*
|
|
* Timeout for Announce Packet reception:
|
|
* XEMACPS_ANNOUNCE_RECEIPT_TIMEOUT. The
|
|
* AnnounceIntervalDuration is stored with the
|
|
* GrandMaster BMCA data as it is captured
|
|
* from the last Announce frame that was
|
|
* received.
|
|
*/
|
|
if (InstancePtr->PtpCounters.
|
|
CounterAnnounceInterval >=
|
|
((InstancePtr->CurrentBmc.
|
|
AnnounceIntervalDuration - 1) *
|
|
XEMACPS_ANNOUNCE_RECEIPT_TIMEOUT) ) {
|
|
|
|
#ifdef DEBUG_LEVEL_TWO
|
|
xil_printf("XEMACPS_ANNOUNCE_RECEIPT_TIMEOUT: Becoming GM! CounterAnnounceInterval = %d\r\n",
|
|
InstancePtr->
|
|
PtpCounters.CounterAnnounceInterval);
|
|
#endif
|
|
InstancePtr->
|
|
PtpCounters.CounterAnnounceInterval
|
|
= 0;
|
|
|
|
#ifdef DEBUG_LEVEL_TWO
|
|
/*
|
|
* No Announce received from GM for timeout interval:
|
|
* we become the master */
|
|
xil_printf("\r\n*** Announce timeout : Call XEmacPs_BecomeRtcMaster() *** \r\n");
|
|
#endif
|
|
XEmacPs_BecomeRtcMaster(InstancePtr,0);
|
|
|
|
} else {
|
|
InstancePtr->
|
|
PtpCounters.CounterAnnounceInterval
|
|
= InstancePtr->
|
|
PtpCounters.CounterAnnounceInterval
|
|
+ 1;
|
|
}
|
|
|
|
/*
|
|
* Timeout for Sync Packet reception:
|
|
* XEMACPS_SYNC_RECEIPT_TIMEOUT *
|
|
* The SyncIntervalDuration is stored with the
|
|
* Received Sync data as it is captured from
|
|
* the last Sync frame that was received.
|
|
*/
|
|
if( InstancePtr->PtpCounters.
|
|
CounterSyncInterval >=
|
|
((InstancePtr->LatestMDSyncReceive.
|
|
SyncIntervalDuration - 1) *
|
|
XEMACPS_SYNC_RECEIPT_TIMEOUT) ) {
|
|
#ifdef DEBUG_LEVEL_TWO
|
|
xil_printf("\r\nXEMACPS_SYNC_RECEIPT_TIMEOUT: Becoming GM! CounterSyncInterval = %d\r\n",
|
|
InstancePtr->PtpCounters.
|
|
CounterSyncInterval);
|
|
xil_printf("\r\nXEMACPS_SYNC_RECEIPT_TIMEOUT: SyncIntervalDuration = %d\r\n",
|
|
InstancePtr->SignallingFrameData.
|
|
SyncIntervalDuration);
|
|
#endif
|
|
InstancePtr->
|
|
PtpCounters.CounterSyncInterval = 0;
|
|
/*
|
|
* No Syncs received from GM for timeout interval: we become
|
|
* the master
|
|
*/
|
|
#ifdef DEBUG_LEVEL_TWO
|
|
xil_printf("\r\n*** Sync Timeout : Call XEmacPs_BecomeRtcMaster() *** \r\n");
|
|
#endif
|
|
XEmacPs_BecomeRtcMaster(InstancePtr,0);
|
|
|
|
} else {
|
|
InstancePtr->
|
|
PtpCounters.CounterSyncInterval
|
|
= InstancePtr->
|
|
PtpCounters.CounterSyncInterval + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Both Master and Slave will initiate a link delay
|
|
* measurement when the LinkDelayIntervalDuration (4 secs)
|
|
* expires (LinkDelayIntervalDuration is used to
|
|
* count/time the duration)
|
|
*/
|
|
if ((InstancePtr->SignallingFrameData.LinkDelayIntervalDuration
|
|
!= XEMACPS_PKT_TYPE_DISABLED) &&
|
|
(InstancePtr->PtpCounters.CounterLinkDelayInterval >=
|
|
(InstancePtr->
|
|
SignallingFrameData.LinkDelayIntervalDuration - 1))) {
|
|
/*
|
|
* Check to see if we've received PDelayResp and
|
|
* PDelayRespFollowUp messages since the last
|
|
* PDelayReq was sent
|
|
*/
|
|
if( InstancePtr->StateMachineData.RcvdPDelayResp &&
|
|
InstancePtr->StateMachineData.RcvdPDelayRespFollowUp ){
|
|
|
|
InstancePtr->StateMachineData.LostResponses
|
|
= 0;
|
|
} else {
|
|
InstancePtr->StateMachineData.LostResponses++;
|
|
}
|
|
|
|
if( InstancePtr->StateMachineData.LostResponses >=
|
|
XEMACPS_ALLOWED_LOST_RESPONSES ) {
|
|
/*
|
|
* The peer is no longer Ieee1588v2 Capable
|
|
*/
|
|
XEmacPs_ChangePeerIeee1588v2Capability
|
|
(InstancePtr, 0);
|
|
|
|
#ifdef DEBUG_LEVEL_TWO
|
|
xil_printf("\r\n** XEmacPs_PtpTimerInterruptHandler(): The peer is no longer ASCapable **");
|
|
xil_printf("\r\n** XEmacPs_PtpTimerInterruptHandler(): StateMachineData.LostResponses >= %d **",
|
|
XEMACPS_ALLOWED_LOST_RESPONSES);
|
|
#endif
|
|
/* avoid potential overflow */
|
|
InstancePtr->StateMachineData.LostResponses =
|
|
XEMACPS_ALLOWED_LOST_RESPONSES;
|
|
}
|
|
|
|
XEmacPs_SendPDelayReq(InstancePtr);
|
|
|
|
InstancePtr->StateMachineData.RcvdPDelayResp = 0;
|
|
InstancePtr->StateMachineData.RcvdPDelayRespFollowUp
|
|
= 0;
|
|
InstancePtr->PtpCounters.CounterLinkDelayInterval
|
|
= 0;
|
|
|
|
} else {
|
|
InstancePtr->PtpCounters.CounterLinkDelayInterval
|
|
= InstancePtr->PtpCounters.CounterLinkDelayInterval
|
|
+ 1;
|
|
}
|
|
|
|
} /* end of 'if (InstancePtr->PtpIsRunning == 1)' */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is the EmacPs Rx interrupt callback invoked from the EmacPs
|
|
* driver. Here we set the flag PtpNewPktRecd to true. This flag is checked for
|
|
* in the function XEmacPs_RunIEEE1588Protocol for further processing of
|
|
* packets.
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_PtpRxInterruptHandler(XEmacPs_Ieee1588 *InstancePtr)
|
|
{
|
|
InstancePtr->PtpNewPktRecd = TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is processes the received packets. This is invoked from
|
|
* XEmacPs_RunIEEE1588Protocol. It copies the received packet from the RxBuf
|
|
* to the corresponding buffer in XEmacPs_Ieee1588 structure instance.It then
|
|
* identifies the type of PTP packet received and calls the corresponding
|
|
* handlers to do further processing.
|
|
* It then frees the corresponding BD, does a allocation of the freed BD and
|
|
* populates the BD with appropriate buffer address (RxBuf).
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_HandleRecdPTPPacket(XEmacPs_Ieee1588 *InstancePtr)
|
|
{
|
|
u8 MessageType = 0;
|
|
XEmacPs_Bd *BdPtr;
|
|
XEmacPs_Bd *CurBdPtr;
|
|
unsigned int NumBds;
|
|
unsigned int FreeBds;
|
|
int i;
|
|
int j;
|
|
int k;
|
|
u8 *BufAddr;
|
|
int BufLen;
|
|
int Status;
|
|
XEmacPs_BdRing *TxRingPtr;
|
|
XEmacPs_BdRing *RxRingPtr;
|
|
|
|
/*
|
|
* Get the ring pointers from EmacPs instance
|
|
*/
|
|
TxRingPtr = &XEmacPs_GetTxRing(InstancePtr->EmacPsInstance);
|
|
RxRingPtr = &XEmacPs_GetRxRing(InstancePtr->EmacPsInstance);
|
|
|
|
/*
|
|
* If PTP functions are marked as not running, then take no further
|
|
* action.
|
|
*/
|
|
if (InstancePtr->PtpIsRunning == 1) {
|
|
|
|
/*
|
|
* Extract all available BDs from EmacPs.
|
|
*/
|
|
NumBds = XEmacPs_BdRingFromHwRx( RxRingPtr,
|
|
XEMACPS_IEEE1588_NO_OF_RX_DESCS, &BdPtr);
|
|
if (NumBds == 0)
|
|
return;
|
|
for (i = 0, CurBdPtr=BdPtr; i < NumBds; i++) {
|
|
/*
|
|
* Get the buffer address in which the PTP packet is
|
|
* stored from the BD.
|
|
*/
|
|
BufAddr = (void*)(INTPTR)(XEmacPs_BdGetBufAddr(CurBdPtr) &
|
|
~(XEMACPS_RXBUF_WRAP_MASK | XEMACPS_RXBUF_NEW_MASK));
|
|
BufLen = XEmacPs_BdGetLength(CurBdPtr);
|
|
#ifndef PEEP
|
|
Xil_DCacheInvalidateRange((u32)BufAddr, 132);
|
|
#endif
|
|
/*
|
|
* If the received packet is not PTP, then there is
|
|
* some error. The example is used to demonstrate the
|
|
* PTP protocol and hence any other packet is not
|
|
* acceptable. Print the wrond packet to get some
|
|
* idea regarding what it contains.
|
|
*/
|
|
if (XEmacPs_IsRxFramePTP((u8*)BufAddr) == FALSE) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("A WRONG Packet Received \r\n");
|
|
for (k = 0; k <= 100; k=k+10) {
|
|
xil_printf("%x %x %x %x %x %x %x %x %x %x\r\n",
|
|
BufAddr[k],
|
|
BufAddr[k+1],
|
|
BufAddr[k+2],
|
|
BufAddr[k+3],
|
|
BufAddr[k+4],
|
|
BufAddr[k+5],
|
|
BufAddr[k+6],
|
|
BufAddr[k+7],
|
|
BufAddr[k+8],
|
|
BufAddr[k+9]);
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
/*
|
|
* Extract the PTP message type
|
|
*/
|
|
MessageType = XEmacPs_GetMsgType (BufAddr);
|
|
switch (MessageType) {
|
|
case XEMACPS_PTP_TYPE_SYNC:
|
|
/*
|
|
* Copy to relevant buffer and call the
|
|
* corresponding handler.
|
|
*/
|
|
memcpy(InstancePtr->LastRecdSyncFrm,
|
|
BufAddr, BufLen);
|
|
XEmacPs_DecodeRxSync(InstancePtr,
|
|
InstancePtr->LastRecdSyncFrm);
|
|
break;
|
|
|
|
case XEMACPS_PTP_TYPE_FOLLOW_UP:
|
|
/*
|
|
* Copy to relevant buffer and call the
|
|
* corresponding handler.
|
|
*/
|
|
memcpy(
|
|
InstancePtr->LastRecdFollowUpFrm,
|
|
BufAddr, BufLen);
|
|
XEmacPs_DecodeRxFollowUp(InstancePtr,
|
|
InstancePtr->LastRecdFollowUpFrm);
|
|
break;
|
|
|
|
case XEMACPS_PTP_TYPE_PDELAYREQ:
|
|
/*
|
|
* Copy to relevant buffer and call the
|
|
* corresponding handler.
|
|
*/
|
|
memcpy(
|
|
InstancePtr->LastRecdPDelayReqFrm,
|
|
BufAddr, BufLen);
|
|
XEmacPs_SendPDelayResp(InstancePtr);
|
|
break;
|
|
|
|
case XEMACPS_PTP_TYPE_PDELAYRESP:
|
|
/*
|
|
* Copy to relevant buffer and call the
|
|
* corresponding handler.
|
|
*/
|
|
memcpy(
|
|
InstancePtr->LastRecdPDelayRespFrm,
|
|
BufAddr, BufLen);
|
|
XEmacPs_DecodeRxPDelayResp(InstancePtr,
|
|
InstancePtr->LastRecdPDelayRespFrm);
|
|
|
|
break;
|
|
|
|
case XEMACPS_PTP_TYPE_PDELAYRESP_FOLLOW_UP:
|
|
/*
|
|
* Copy to relevant buffer and call the
|
|
* corresponding handler.
|
|
*/
|
|
memcpy(
|
|
InstancePtr->
|
|
LastRecdPDelayRespFollowUpFrm, BufAddr,
|
|
BufLen);
|
|
XEmacPs_DecodeRxPDelayRespFollowUp
|
|
(InstancePtr,
|
|
InstancePtr->
|
|
LastRecdPDelayRespFollowUpFrm);
|
|
break;
|
|
|
|
case XEMACPS_PTP_TYPE_ANNOUNCE:
|
|
/*
|
|
* Copy to relevant buffer and call the
|
|
* corresponding handler.
|
|
*/
|
|
memcpy(
|
|
InstancePtr->LastRecdAnnounceFrm,
|
|
BufAddr, BufLen);
|
|
XEmacPs_DecodeRxAnnounceFrame
|
|
(InstancePtr,
|
|
InstancePtr->LastRecdAnnounceFrm);
|
|
break;
|
|
|
|
case XEMACPS_PTP_TYPE_SIGNALING:
|
|
/*
|
|
* Copy to relevant buffer and call the
|
|
* corresponding handler.
|
|
*/
|
|
memcpy(
|
|
InstancePtr->LastRecdSignallingFrm,
|
|
BufAddr, BufLen);
|
|
XEmacPs_DecodeRxSignaling
|
|
(InstancePtr,
|
|
InstancePtr->LastRecdSignallingFrm);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Clear the used bit in the buffer so that it can
|
|
* be reused.
|
|
*/
|
|
BufAddr[XEMACPS_PACKET_LEN - 2] = 0;
|
|
CurBdPtr = XEmacPs_BdRingNext( RxRingPtr, CurBdPtr);
|
|
}
|
|
|
|
/*
|
|
* Time to free the BDs
|
|
*/
|
|
XEmacPs_BdRingFree(RxRingPtr, NumBds, BdPtr);
|
|
/*
|
|
* Time to reallocate the BDs
|
|
*/
|
|
FreeBds = XEmacPs_BdRingGetFreeCnt (RxRingPtr);
|
|
Status = XEmacPs_BdRingAlloc (RxRingPtr, FreeBds,
|
|
&BdPtr);
|
|
if (Status != XST_SUCCESS) {
|
|
return;
|
|
}
|
|
CurBdPtr = BdPtr;
|
|
for (i = 0; i < FreeBds; i++) {
|
|
for (j = 0; j < XEMACPS_IEEE1588_NO_OF_RX_DESCS; j++) {
|
|
if ((RxBuf[j][XEMACPS_PACKET_LEN - 2]) == 0) {
|
|
XEmacPs_BdSetAddressRx
|
|
(CurBdPtr, &(RxBuf[j][0]));
|
|
/*
|
|
* Set the used bit in the Buffer
|
|
*/
|
|
RxBuf[j][XEMACPS_PACKET_LEN - 2] = 1;
|
|
/*
|
|
* Clear the used bit so that it
|
|
* can be reused.
|
|
*/
|
|
XEmacPs_BdClearRxNew (CurBdPtr);
|
|
break;
|
|
}
|
|
}
|
|
CurBdPtr = XEmacPs_BdRingNext (RxRingPtr, CurBdPtr);
|
|
}
|
|
/*
|
|
* Submit the BDs to the hardware
|
|
*/
|
|
Status = XEmacPs_BdRingToHw (RxRingPtr, FreeBds, BdPtr);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is the Tx Done interrupt callback invoked from the EmacPs
|
|
* driver.
|
|
* For some PTP packets, upon getting a Tx done interrupt some actions need
|
|
* to be taked. For example, when SYNC frame is successfully sent and Tx Done
|
|
* interrupt is received, the time stamp for the SYNC frame needs to be stored.
|
|
* For all such processing the function XEmacPs_PtpTxDoFurtherProcessing is
|
|
* invoked from here.
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_PtpTxInterruptHandler (XEmacPs_Ieee1588 *InstancePtr)
|
|
{
|
|
unsigned int NumBds;
|
|
unsigned int NumBdsToProcess;
|
|
XEmacPs_Bd *BdPtr, *CurBdPtr;
|
|
void *BufAddr;
|
|
int BufLen;
|
|
int Status;
|
|
XEmacPs_BdRing *TxRingPtr;
|
|
unsigned int *Temp;
|
|
|
|
TxRingPtr = &XEmacPs_GetTxRing(InstancePtr->EmacPsInstance);
|
|
|
|
NumBds = XEmacPs_BdRingFromHwTx( TxRingPtr,
|
|
XEMACPS_IEEE1588_NO_OF_TX_DESCS, &BdPtr);
|
|
if (NumBds == 0) {
|
|
return;
|
|
}
|
|
NumBdsToProcess = NumBds;
|
|
CurBdPtr=BdPtr;
|
|
while (NumBdsToProcess > 0) {
|
|
BufAddr = (void*)(INTPTR)(XEmacPs_BdGetBufAddr(CurBdPtr));
|
|
BufLen = XEmacPs_BdGetLength(CurBdPtr);
|
|
|
|
XEmacPs_PtpTxDoFurtherProcessing (InstancePtr, (u8 *)BufAddr);
|
|
Temp = (unsigned int *)CurBdPtr;
|
|
Temp++;
|
|
*Temp &= XEMACPS_TXBUF_WRAP_MASK;
|
|
*Temp |= XEMACPS_TXBUF_USED_MASK;
|
|
|
|
CurBdPtr = XEmacPs_BdRingNext(TxRingPtr, CurBdPtr);
|
|
NumBdsToProcess--;
|
|
dmb();
|
|
dsb();
|
|
}
|
|
Status = XEmacPs_BdRingFree( TxRingPtr, NumBds, BdPtr);
|
|
if (Status != XST_SUCCESS) {
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is the Error interrupt callback invoked from the EmacPs driver.
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
* @param Direction can be Rx or Tx
|
|
* @param ErrorWord gives further information about the exact error type.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note This function needs to be revisited. Probably upon an error
|
|
* we need to reset the EmacPs hardware and reinitialize the BDs.
|
|
* However further study is needed. Whether for all errors we
|
|
* need to reset or some errors can be ignored.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_PtpErrorInterruptHandler (XEmacPs_Ieee1588 *InstancePtr,
|
|
u8 Direction, u32 ErrorWord)
|
|
{
|
|
XEmacPs_Config *Cfg;
|
|
int Status = XST_SUCCESS;
|
|
unsigned int NSIncrementVal;
|
|
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In %s: EMAC Error Interrupt, Direction is %d and ErrorWord is %x \r\n",
|
|
__func__, Direction, ErrorWord);
|
|
#endif
|
|
XScuTimer_Stop(&TimerInstance);
|
|
XEmacPs_Stop(InstancePtr->EmacPsInstance);
|
|
Xil_ExceptionDisable();
|
|
PDelayRespSent = 0;
|
|
SyncSent = 0;
|
|
PTPSendPacket = 0;
|
|
memset(RxBuf, 0, sizeof(RxBuf));
|
|
Link_Speed = 100;
|
|
/* Initialize SCUTIMER */
|
|
if (XEmacPs_InitScuTimer() != XST_SUCCESS) while(1);
|
|
/*
|
|
* Get the configuration of EmacPs hardware.
|
|
*/
|
|
Cfg = XEmacPs_LookupConfig(EMACPS_DEVICE_ID);
|
|
|
|
/*
|
|
* Initialize EmacPs hardware.
|
|
*/
|
|
Status = XEmacPs_CfgInitialize(InstancePtr->EmacPsInstance, Cfg, Cfg->BaseAddress);
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In function %s: XEmacPs_CfgInitialize failure \r\n",__func__);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Set the MAC address
|
|
*/
|
|
Status = XEmacPs_SetMacAddress(InstancePtr->EmacPsInstance,
|
|
(unsigned char*)UnicastMAC, 1);
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In function %s: XEmacPs_SetMacAddress failure \r\n",__func__);
|
|
#endif
|
|
}
|
|
#ifndef PEEP
|
|
XEmacPs_SetMdioDivisor(InstancePtr->EmacPsInstance, MDC_DIV_224);
|
|
#endif
|
|
/*
|
|
* Detect and initialize the PHY
|
|
*/
|
|
XEmacPs_PHYSetup (InstancePtr->EmacPsInstance);
|
|
sleep(1);
|
|
|
|
/*
|
|
* Set the operating speed in EmacPs hardware.
|
|
*/
|
|
XEmacPs_SetOperatingSpeed(InstancePtr->EmacPsInstance, Link_Speed);
|
|
sleep(1);
|
|
|
|
/*
|
|
* Enable the promiscuous mode in EmacPs hardware.
|
|
*/
|
|
Status = XEmacPs_SetOptions(InstancePtr->EmacPsInstance, XEMACPS_PROMISC_OPTION);
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In function %s: XEmacPs_SetOptions failure \r\n",__func__);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#ifdef PEEP
|
|
/*
|
|
* Set the 1588 Timer register for 50 MHz timer, i.e. 20 ns increment
|
|
* for every clock cycle.
|
|
*/
|
|
XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress,
|
|
XEMACPS_1588_INC_OFFSET,
|
|
XEMACPS_1588_INC_VAL);
|
|
#else
|
|
|
|
NSIncrementVal = XEmacPs_TsuCalcClk(XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 6);
|
|
XEmacPs_WriteReg(InstancePtr->EmacPsInstance->Config.BaseAddress,
|
|
XEMACPS_1588_INC_OFFSET,
|
|
NSIncrementVal);
|
|
#endif
|
|
|
|
/*
|
|
* Register Ethernet Rx, Tx and Error handlers with the EmacPs driver.
|
|
*/
|
|
Status = XEmacPs_SetHandler (InstancePtr->EmacPsInstance,
|
|
XEMACPS_HANDLER_DMARECV,
|
|
XEmacPs_PtpRxInterruptHandler,
|
|
&IEEE1588ProtoHandler);
|
|
Status |= XEmacPs_SetHandler (InstancePtr->EmacPsInstance,
|
|
XEMACPS_HANDLER_DMASEND,
|
|
XEmacPs_PtpTxInterruptHandler,
|
|
&IEEE1588ProtoHandler);
|
|
Status |= XEmacPs_SetHandler (InstancePtr->EmacPsInstance,
|
|
XEMACPS_HANDLER_ERROR,
|
|
XEmacPs_PtpErrorInterruptHandler,
|
|
&IEEE1588ProtoHandler);
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In function %s: XEmacPs_SetHandler failure \r\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
/*
|
|
* Connect to the interrupt controller and enable interrupts in
|
|
* interrupt controller.
|
|
*/
|
|
Status = XEmacPs_SetupIntrSystem(&IntcInstance,
|
|
InstancePtr->EmacPsInstance,
|
|
&TimerInstance, EMACPS_IRPT_INTR,
|
|
TIMER_IRPT_INTR);
|
|
if (Status != XST_SUCCESS) {
|
|
#ifdef DEBUG_XEMACPS_LEVEL1
|
|
xil_printf("In function %s: XEmacPs_SetupIntrSystem failure \r\n",
|
|
__func__);
|
|
#endif
|
|
}
|
|
Xil_ExceptionEnable();
|
|
/*
|
|
* Enable the timer interrupt in the timer module
|
|
*/
|
|
XScuTimer_EnableInterrupt(&TimerInstance);
|
|
/*
|
|
* Start the PTP standalone state machine.
|
|
*/
|
|
XEmacPs_RunIEEE1588Protocol(InstancePtr->EmacPsInstance);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is initiates a PTP Tx. This is called from various places.
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
* @param PacketBuf is the buffer that contains the packet to be Txed
|
|
* @param PacketLen is the length of the packet to be Txed.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
int XEmacPs_PtpTxPacket(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf,
|
|
int PacketLen)
|
|
{
|
|
int Status;
|
|
XEmacPs_Bd *BdPtr;
|
|
XEmacPs_BdRing *TxRingPtr;
|
|
Xil_ExceptionDisable();
|
|
|
|
while((XEmacPs_ReadReg(InstancePtr->EmacPsInstance->Config.BaseAddress,
|
|
XEMACPS_TXSR_OFFSET)) & 0x08);
|
|
|
|
TxRingPtr = &(XEmacPs_GetTxRing(InstancePtr->EmacPsInstance));
|
|
Status = XEmacPs_BdRingAlloc(TxRingPtr, 1, &BdPtr);
|
|
if (Status != XST_SUCCESS) {
|
|
Xil_ExceptionEnable();
|
|
return XST_FAILURE;
|
|
}
|
|
/*
|
|
* Fill the BD entries for the Tx1!!1`
|
|
*/
|
|
#ifndef PEEP
|
|
Xil_DCacheFlushRange((u32)PacketBuf, 128);
|
|
#endif
|
|
|
|
XEmacPs_BdSetAddressTx (BdPtr, PacketBuf);
|
|
XEmacPs_BdSetLength(BdPtr, PacketLen);
|
|
XEmacPs_BdClearTxUsed(BdPtr);
|
|
XEmacPs_BdSetLast(BdPtr);
|
|
dmb();
|
|
dsb();
|
|
|
|
Status = XEmacPs_BdRingToHw(TxRingPtr, 1, BdPtr);
|
|
if (Status != XST_SUCCESS) {
|
|
Xil_ExceptionEnable();
|
|
return XST_FAILURE;
|
|
}
|
|
dmb();
|
|
dsb();
|
|
/*
|
|
* Start the Tx
|
|
*/
|
|
XEmacPs_Transmit(InstancePtr->EmacPsInstance);
|
|
Xil_ExceptionEnable();
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function extracts length/type information from the Ethernet packet.
|
|
*
|
|
* @param PacketBuf contains the Ethernet packet.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
u32 XEmacPs_IsRxFramePTP (u8 *PacketBuf)
|
|
{
|
|
if ((Xil_Ntohs (*(u16 *) (PacketBuf + 12))) ==
|
|
XEMACPS_PTP_ETHERTYPE)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function extracts PTP messgae type information from the PTP packet.
|
|
*
|
|
* @param PacketBuf contains the Ethernet packet.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
u8 XEmacPs_GetMsgType (u8 *PacketBuf)
|
|
{
|
|
return PacketBuf[XEMACPS_MSGTYP_OFFSET] & XEMACPS_MSGTYP_MASK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is used to populate the PTP Tx buffers. Some of the entries
|
|
* in a PTP Tx packet do not change with time and are constants over time for
|
|
* this PTP standalone example. Those entries are populated here.
|
|
*
|
|
* @param InstancePntr is a pointer to the instance of the
|
|
* XEmacPs_Ieee1588.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void XEmacPs_SetDfltTxFrms(XEmacPs_Ieee1588 *InstancePtr)
|
|
{
|
|
u8 TemplateFrm[50];
|
|
u16 *TempPntr;
|
|
XEmacPs_PortIdentity TempIdentity;
|
|
u32 GmClkQuality = 0xF8FE4100;
|
|
u32 *TempLongPntr;
|
|
u8 OrgId[3] = {0x00, 0x80, 0xC2};
|
|
u8 OrgSubType[3] = {0x00, 0x00, 0x01};
|
|
|
|
/*
|
|
* Zero out the template frame. Template frame is used to clone all
|
|
* the Tx buffers.
|
|
*/
|
|
memset (&TemplateFrm[0],0,sizeof(TemplateFrm));
|
|
memset (InstancePtr->SyncFrmToTx,0,sizeof(InstancePtr->SyncFrmToTx));
|
|
memset (InstancePtr->FollowUpFrmToTx,0,
|
|
sizeof(InstancePtr->FollowUpFrmToTx));
|
|
memset (InstancePtr->PDelayReqFrmToTx,0,
|
|
sizeof(InstancePtr->PDelayReqFrmToTx));
|
|
memset (InstancePtr->PDelayRespFrmToTx,0,
|
|
sizeof(InstancePtr->PDelayRespFrmToTx));
|
|
memset (InstancePtr->PDelayRespFollowUpFrmToTx, 0,
|
|
sizeof(InstancePtr->PDelayRespFollowUpFrmToTx));
|
|
memset (InstancePtr->SignallingFrmToTx, 0,
|
|
sizeof(InstancePtr->SignallingFrmToTx));
|
|
memset (InstancePtr->AnnounceFrmToTx, 0,
|
|
sizeof(InstancePtr->AnnounceFrmToTx));
|
|
|
|
/*
|
|
* Populate the template frame with source and destination MAC.
|
|
*/
|
|
memcpy(&TemplateFrm[0],DestnAddr,6);
|
|
memcpy(&TemplateFrm[6],SrcAddr,6);
|
|
|
|
/*
|
|
* Populate the template frame with source and destination MAC.
|
|
*/
|
|
TempPntr = (u16 *)(&(TemplateFrm[12]));
|
|
*TempPntr = Xil_Htons (XEMACPS_PTP_ETHERTYPE);
|
|
|
|
/*
|
|
* Populate the template frame with PTP version
|
|
*/
|
|
TemplateFrm[XEMACPS_VERSPTP_OFFSET] = XEMACPS_PTP_VERSION_PTP;
|
|
#ifdef IEEE1588_MASTER
|
|
/*
|
|
* Populate the template frame with Port identity
|
|
*/
|
|
TempIdentity.ClockIdentity[0] = 0x00;
|
|
TempIdentity.ClockIdentity[1] = 0x0A;
|
|
TempIdentity.ClockIdentity[2] = 0x35;
|
|
TempIdentity.ClockIdentity[3] = 0xFF;
|
|
TempIdentity.ClockIdentity[4] = 0xFE;
|
|
TempIdentity.ClockIdentity[5] = 0x01;
|
|
TempIdentity.ClockIdentity[6] = 0x02;
|
|
TempIdentity.ClockIdentity[7] = 0x03;
|
|
TempIdentity.PortNumber = Xil_Htons (0x0001);
|
|
#else
|
|
/*
|
|
* Populate the template frame with Port identity
|
|
*/
|
|
TempIdentity.ClockIdentity[0] = 0x00;
|
|
TempIdentity.ClockIdentity[1] = 0x0A;
|
|
TempIdentity.ClockIdentity[2] = 0x35;
|
|
TempIdentity.ClockIdentity[3] = 0xFF;
|
|
TempIdentity.ClockIdentity[4] = 0xFE;
|
|
TempIdentity.ClockIdentity[5] = 0x01;
|
|
TempIdentity.ClockIdentity[6] = 0x02;
|
|
TempIdentity.ClockIdentity[7] = 0x09;
|
|
TempIdentity.PortNumber = Xil_Htons (0x0001);
|
|
#endif
|
|
memcpy(&(TemplateFrm[XEMACPS_PORTIDENTITY_OFFSET]),
|
|
(u8 *)&TempIdentity,10);
|
|
|
|
/*
|
|
* Clone all Tx buffers with template frame
|
|
*/
|
|
memcpy (InstancePtr->SyncFrmToTx,TemplateFrm,50);
|
|
memcpy (InstancePtr->FollowUpFrmToTx,TemplateFrm,50);
|
|
memcpy (InstancePtr->PDelayReqFrmToTx,TemplateFrm,50);
|
|
memcpy (InstancePtr->PDelayRespFrmToTx,TemplateFrm,50);
|
|
memcpy (InstancePtr->PDelayRespFollowUpFrmToTx,TemplateFrm,50);
|
|
memcpy (InstancePtr->SignallingFrmToTx,TemplateFrm,50);
|
|
memcpy (InstancePtr->AnnounceFrmToTx,TemplateFrm,50);
|
|
|
|
/*
|
|
* Now initialize the individual frames
|
|
*/
|
|
/*
|
|
* Announce Frame
|
|
*/
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_MSGTYP_OFFSET] =
|
|
XEMACPS_ANNOUNCEFRM_MSG_TYPE;
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
AnnounceFrmToTx[XEMACPS_MSGLENGTH_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_ANNOUNCEFRM_LENGTH);
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
AnnounceFrmToTx[XEMACPS_FLAGS_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_ANNOUNCEFRM_FLAGS_VAL);
|
|
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05;
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_LOGMSG_INTERVAL_OFFSET] = 10;
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_CURRUTCOFFSET_OFFSET] = 0;
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_CURRUTCOFFSET_OFFSET + 1] = 0;
|
|
|
|
#ifdef IEEE1588_MASTER
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_GMPRI_ONE_OFFSET] = 0x01;
|
|
#else
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_GMPRI_ONE_OFFSET] = 0xFE;
|
|
#endif
|
|
TempLongPntr = (u32 *)&(InstancePtr->
|
|
AnnounceFrmToTx[XEMACPS_GM_CLK_QUALITY_OFFSET]);
|
|
*TempLongPntr = Xil_Htonl (GmClkQuality);
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_GMPRI_TWO_OFFSET] = 0xF8;
|
|
memcpy((u8 *)(&InstancePtr->
|
|
AnnounceFrmToTx[XEMACPS_GM_IDENTITY_OFFSET]),
|
|
(u8 *)TempIdentity.ClockIdentity, 8);
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_STEPS_REMOVED_OFFSET] = 0;
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_STEPS_REMOVED_OFFSET + 1] = 0;
|
|
|
|
InstancePtr->AnnounceFrmToTx[XEMACPS_TIMESOURCE_OFFSET] = 0x90;
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
AnnounceFrmToTx[XEMACPS_TLVTYPE_OFFSET]);
|
|
*TempPntr = Xil_Htons (0x0008);
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
AnnounceFrmToTx[XEMACPS_LENGTHFIELD_OFFSET]);
|
|
*TempPntr = Xil_Htons (0x0008);
|
|
|
|
memcpy((u8 *)(&InstancePtr->AnnounceFrmToTx[XEMACPS_PATHSEQ_OFFSET]),
|
|
(u8 *)TempIdentity.ClockIdentity, 8);
|
|
|
|
/*
|
|
* Sync Frame
|
|
*/
|
|
InstancePtr->SyncFrmToTx[XEMACPS_MSGTYP_OFFSET] =
|
|
XEMACPS_SYNCFRM_MSG_TYPE;
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
SyncFrmToTx[XEMACPS_MSGLENGTH_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_SYNCFRM_LENGTH);
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->SyncFrmToTx[XEMACPS_FLAGS_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_SYNCFRM_FLAGS_VAL);
|
|
|
|
/*
|
|
* Follow-up Frame
|
|
*/
|
|
InstancePtr->FollowUpFrmToTx[XEMACPS_MSGTYP_OFFSET] =
|
|
XEMACPS_FOLLOWUPFRM_MSG_TYPE;
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
FollowUpFrmToTx[XEMACPS_MSGLENGTH_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_FOLLOWUPFRM_LENGTH);
|
|
InstancePtr->FollowUpFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05;
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->FollowUpFrmToTx[58]);
|
|
*TempPntr = Xil_Htons (0x0003);
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->FollowUpFrmToTx[60]);
|
|
*TempPntr = Xil_Htons (28);
|
|
|
|
memcpy ((u8 *)&(InstancePtr->FollowUpFrmToTx[62]), OrgId, 3);
|
|
memcpy ((u8 *)&(InstancePtr->FollowUpFrmToTx[65]), OrgSubType, 3);
|
|
|
|
/*
|
|
* PDelay Req Frame
|
|
*/
|
|
InstancePtr->PDelayReqFrmToTx[XEMACPS_MSGTYP_OFFSET] =
|
|
XEMACPS_PDELAYREQFRM_MSG_TYPE;
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
PDelayReqFrmToTx[XEMACPS_MSGLENGTH_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_PDELAYREQFRM_LENGTH);
|
|
InstancePtr->PDelayReqFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05;
|
|
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
PDelayReqFrmToTx[XEMACPS_FLAGS_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_PDELAYREQFRM_FLAGS_VAL);
|
|
|
|
/*
|
|
* PDelay Resp Frame
|
|
*/
|
|
InstancePtr->PDelayRespFrmToTx[XEMACPS_MSGTYP_OFFSET] =
|
|
XEMACPS_PDELAYRESPFRM_MSG_TYPE;
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
PDelayRespFrmToTx[XEMACPS_MSGLENGTH_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_PDELAYRESPFRM_LENGTH);
|
|
InstancePtr->PDelayRespFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05;
|
|
InstancePtr->PDelayRespFrmToTx[XEMACPS_LOGMSG_INTERVAL_OFFSET] = 0x7F;
|
|
|
|
/*
|
|
* PDelay Response Follow Up Frame
|
|
*/
|
|
InstancePtr->PDelayRespFollowUpFrmToTx[XEMACPS_MSGTYP_OFFSET] =
|
|
XEMACPS_PDELAYRESPFOLLOWUPFRM_MSG_TYPE;
|
|
TempPntr = (u16 *)&(InstancePtr->
|
|
PDelayRespFollowUpFrmToTx[XEMACPS_MSGLENGTH_OFFSET]);
|
|
*TempPntr = Xil_Htons (XEMACPS_PDELAYRESPFOLLOWUP_LENGTH);
|
|
InstancePtr->PDelayRespFollowUpFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05;
|
|
InstancePtr->PDelayRespFollowUpFrmToTx[XEMACPS_LOGMSG_INTERVAL_OFFSET]
|
|
= 0x7F;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* A function to compare two PortIdentity values.
|
|
*
|
|
* @param Identity1 is the first sourcePortIdentity to be compared
|
|
* @param Identity2 is the second sourcePortIdentity to be compared
|
|
*
|
|
* @return - 1 if the two values are equal
|
|
* - 0 if not equal
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
u32 XEmacPs_ComparePortIdentity(XEmacPs_PortIdentity Identity1,
|
|
XEmacPs_PortIdentity Identity2)
|
|
{
|
|
|
|
int Result = memcmp (&(Identity1.ClockIdentity[0]),
|
|
&(Identity2.ClockIdentity[0]),
|
|
8);
|
|
if (Result != 0) {
|
|
return 0;
|
|
}
|
|
|
|
if( Identity1.PortNumber != Identity2.PortNumber ) {
|
|
return 0;
|
|
}
|
|
|
|
/* values are equal */
|
|
return 1;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* A function to compare two ClockIdentity values.
|
|
*
|
|
* @param Identity1 is the first ClockIdentity to be compared
|
|
* @param Identity2 is the second ClockIdentity to be compared
|
|
*
|
|
* @return - 1 if the two values are equal
|
|
* - 0 if not equal
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
u32 XEmacPs_CompareClockIdentity(
|
|
XEmacPs_ClockIdentity Identity1,
|
|
XEmacPs_ClockIdentity Identity2)
|
|
{
|
|
int Result = memcmp (&(Identity1.ClockIdentity[0]),
|
|
&(Identity2.ClockIdentity[0]),
|
|
8);
|
|
if (Result != 0) {
|
|
return 0;
|
|
}
|
|
/* values are equal */
|
|
return 1;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* A function to extract portIdentity information from a received PTP frame.
|
|
* This can be any portIdentity field (header portIdentity,
|
|
* requestingPortIdentity etc...)
|
|
*
|
|
* @param PacketBuf contains the PTP buffer from which the portIdentity
|
|
* is to be extracted.
|
|
* @param portID is the address of type XEmacPs_PortIdentity is which
|
|
* the extracted port identity is put.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
void XEmacPs_GetPortIdentity(u8 *PacketBuf, XEmacPs_PortIdentity *portID)
|
|
{
|
|
XEmacPs_PortIdentity TempIdentity;
|
|
u8 *ReadFromAddr = PacketBuf + XEMACPS_PORTIDENTITY_OFFSET;
|
|
|
|
memcpy ((u8 *)&(TempIdentity.ClockIdentity[0]), ReadFromAddr, 8);
|
|
TempIdentity.PortNumber = Xil_Ntohs (*(u16 *)(ReadFromAddr + 8));
|
|
|
|
memcpy ((u8 *)portID, (u8 *)&TempIdentity,
|
|
sizeof(XEmacPs_PortIdentity));
|
|
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* A function to extract SequenceId information from a received PTP frame.
|
|
*
|
|
* @param PacketBuf contains the PTP buffer from which the portIdentity
|
|
* is to be extracted.
|
|
*
|
|
* @return The extracted sequence ID.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
u16 XEmacPs_GetSequenceId(u8 *PacketBuf)
|
|
{
|
|
u8 *ReadFromAddr = PacketBuf + XEMACPS_SEQID_OFFSET;
|
|
u16 SequenceId;
|
|
|
|
SequenceId = Xil_Htons (*((u16 *)ReadFromAddr));
|
|
return SequenceId;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* A function to increment sequence ID in a PTP frames. It first extracts the
|
|
* sequence ID and then increments and puts it back in the PTP frame.
|
|
*
|
|
* @param PacketBuf contains the PTP buffer from which the portIdentity
|
|
* is to be extracted.
|
|
*
|
|
* @return The incremented sequence ID.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
u16 XEmacPs_IncSequenceId(u8 *PacketBuf)
|
|
{
|
|
u8 *ReadFromAddr = PacketBuf + XEMACPS_SEQID_OFFSET;
|
|
u8 *WriteToAddr = PacketBuf + XEMACPS_SEQID_OFFSET;
|
|
u16 SequenceId = 0;
|
|
|
|
SequenceId = Xil_Ntohs (*((u16 *)ReadFromAddr));
|
|
SequenceId = SequenceId + 1;
|
|
|
|
*((u16 *)WriteToAddr) = Xil_Htons (SequenceId);
|
|
|
|
return SequenceId;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* A function to do endian conversion for long long int type. This is for little
|
|
* to big endian conversion.
|
|
*
|
|
* @param Parameter whose endian conversion is needed
|
|
*
|
|
* @return The endian converted value.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
u32 XEmacPs_htonll (unsigned long long int n)
|
|
{
|
|
union {
|
|
unsigned long lv[2];
|
|
unsigned long long int llv;
|
|
} u;
|
|
u.lv[0] = Xil_Htonl(n >> 32);
|
|
u.lv[1] = Xil_Htonl(n & 0xFFFFFFFFULL);
|
|
return u.llv;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* A function to do endian conversion for long long int type. This is for big
|
|
* to little endian conversion.
|
|
*
|
|
* @param Parameter whose endian conversion is needed
|
|
*
|
|
* @return The endian converted value.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
u32 XEmacPs_ntohll (long long int n)
|
|
{
|
|
return XEmacPs_htonll (n);
|
|
}
|
|
|
|
|