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