/****************************************************************************** * * Copyright (C) 2010 - 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_example_util.c * * This file implements the utility functions for the XEmacPs example code. * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ------------------------------------------------------- * 1.00a wsy 01/10/10 First release * 1.00a asa 01/24/12 A new version of EmacPsUtilEnterLoopback is used for * Zynq boards. Now there are two versions of * EmacPsUtilEnterLoopback, one for PEEP and one for Zynq. * If the example is to be run on a PEEP board, define PEEP * in xemacps_example.h. * 1.01a asa 02/27/12 The sleep value after PHY loopback is setup is reduced * for Zynq. ** *****************************************************************************/ /***************************** Include Files ********************************/ #include "xemacps_example.h" #include "sleep.h" /************************** Variable Definitions ****************************/ XEmacPs EmacPsInstance; /* XEmacPs instance used throughout examples */ /* * Local MAC address */ char EmacPsMAC[] = { 0x00, 0x0a, 0x35, 0x01, 0x02, 0x03 }; /****************************************************************************/ /** * * Set the MAC addresses in the frame. * * @param FramePtr is the pointer to the frame. * @param DestAddr is the Destination MAC address. * * @return None. * * @note None. * *****************************************************************************/ void EmacPsUtilFrameHdrFormatMAC(EthernetFrame * FramePtr, char *DestAddr) { char *Frame = (char *) FramePtr; char *SourceAddress = EmacPsMAC; s32 Index; /* Destination address */ for (Index = 0; Index < XEMACPS_MAC_ADDR_SIZE; Index++) { *Frame++ = *DestAddr++; } /* Source address */ for (Index = 0; Index < XEMACPS_MAC_ADDR_SIZE; Index++) { *Frame++ = *SourceAddress++; } } /****************************************************************************/ /** * * Set the frame type for the specified frame. * * @param FramePtr is the pointer to the frame. * @param FrameType is the Type to set in frame. * * @return None. * * @note None. * *****************************************************************************/ void EmacPsUtilFrameHdrFormatType(EthernetFrame * FramePtr, u16 FrameType) { char *Frame = (char *) FramePtr; /* * Increment to type field */ Frame = Frame + 12; /* * Do endian swap from little to big-endian. */ FrameType = Xil_EndianSwap16(FrameType); /* * Set the type */ *(u16 *) Frame = FrameType; } /****************************************************************************/ /** * This function places a pattern in the payload section of a frame. The pattern * is a 8 bit incrementing series of numbers starting with 0. * Once the pattern reaches 256, then the pattern changes to a 16 bit * incrementing pattern: *
* 0, 1, 2, ... 254, 255, 00, 00, 00, 01, 00, 02, ... ** * @param FramePtr is a pointer to the frame to change. * @param PayloadSize is the number of bytes in the payload that will be set. * * @return None. * * @note None. * *****************************************************************************/ void EmacPsUtilFrameSetPayloadData(EthernetFrame * FramePtr, u32 PayloadSize) { u32 BytesLeft = PayloadSize; u8 *Frame; u16 Counter = 0; /* * Set the frame pointer to the start of the payload area */ Frame = (u8 *) FramePtr + XEMACPS_HDR_SIZE; /* * Insert 8 bit incrementing pattern */ while (BytesLeft && (Counter < 256)) { *Frame++ = (u8) Counter++; BytesLeft--; } /* * Switch to 16 bit incrementing pattern */ while (BytesLeft) { *Frame++ = (u8) (Counter >> 8); /* high */ BytesLeft--; if (!BytesLeft) break; *Frame++ = (u8) Counter++; /* low */ BytesLeft--; } } /****************************************************************************/ /** * This function verifies the frame data against a CheckFrame. * * Validation occurs by comparing the ActualFrame to the header of the * CheckFrame. If the headers match, then the payload of ActualFrame is * verified for the same pattern Util_FrameSetPayloadData() generates. * * @param CheckFrame is a pointer to a frame containing the 14 byte header * that should be present in the ActualFrame parameter. * @param ActualFrame is a pointer to a frame to validate. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. *****************************************************************************/ LONG EmacPsUtilFrameVerify(EthernetFrame * CheckFrame, EthernetFrame * ActualFrame) { char *CheckPtr = (char *) CheckFrame; char *ActualPtr = (char *) ActualFrame; u16 BytesLeft; u16 Counter; u32 Index; /* * Compare the headers */ for (Index = 0; Index < XEMACPS_HDR_SIZE; Index++) { if (CheckPtr[Index] != ActualPtr[Index]) { return XST_FAILURE; } } /* * Get the length of the payload */ BytesLeft = *(u16 *) &ActualPtr[12]; /* * Do endian swap from big back to little-endian. */ BytesLeft = Xil_EndianSwap16(BytesLeft); /* * Validate the payload */ Counter = 0; ActualPtr = &ActualPtr[14]; /* * Check 8 bit incrementing pattern */ while (BytesLeft && (Counter < 256)) { if (*ActualPtr++ != (char) Counter++) { return XST_FAILURE; } BytesLeft--; } /* * Check 16 bit incrementing pattern */ while (BytesLeft) { if (*ActualPtr++ != (char) (Counter >> 8)) { /* high */ return XST_FAILURE; } BytesLeft--; if (!BytesLeft) break; if (*ActualPtr++ != (char) Counter++) { /* low */ return XST_FAILURE; } BytesLeft--; } return XST_SUCCESS; } /****************************************************************************/ /** * This function sets all bytes of a frame to 0. * * @param FramePtr is a pointer to the frame itself. * * @return None. * * @note None. * *****************************************************************************/ void EmacPsUtilFrameMemClear(EthernetFrame * FramePtr) { u32 *Data32Ptr = (u32 *) FramePtr; u32 WordsLeft = sizeof(EthernetFrame) / sizeof(u32); /* frame should be an integral number of words */ while (WordsLeft--) { *Data32Ptr++ = 0xDEADBEEF; } } /****************************************************************************/ /** * * This function copys data from source to desitnation for n bytes. * * @param Destination is the targeted string to copy to. * @param Source is the source string to copy from. * @param n is number of bytes to be copied. * * @note This function is similiar to strncpy(), however strncpy will * stop either at null byte or n bytes is been copied. * This function will copy n bytes without checking the content. * *****************************************************************************/ void EmacPsUtilstrncpy(char *Destination, const char *Source, u32 n) { do { *Destination++ = *Source++; } while (--n != 0); } /****************************************************************************/ /** * * This function sets the emacps to loopback mode. * * @param EmacPsInstancePtr is the XEmacPs driver instance. * * @note None. * *****************************************************************************/ void EmacPsUtilEnterLocalLoopback(XEmacPs * EmacPsInstancePtr) { u32 reg; reg = XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET); XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, reg | XEMACPS_NWCTRL_LOOPEN_MASK); } /****************************************************************************/ /** * * This function detects the PHY address by looking for successful MII status * register contents. * * @param The XEMACPS driver instance * * @return The address of the PHY (defaults to 32 if none detected) * * @note None. * *****************************************************************************/ #define PHY_DETECT_REG1 2 #define PHY_DETECT_REG2 3 u32 XEmacPsDetectPHY(XEmacPs * EmacPsInstancePtr) { u32 PhyAddr; u32 Status; u16 PhyReg1; u16 PhyReg2; for (PhyAddr = 0; PhyAddr <= 31; PhyAddr++) { Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, PHY_DETECT_REG1, &PhyReg1); Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, PHY_DETECT_REG2, &PhyReg2); if ((Status == XST_SUCCESS) && (PhyReg1 > 0x0000) && (PhyReg1 < 0xffff) && (PhyReg2 > 0x0000) && (PhyReg2 < 0xffff)) { /* Found a valid PHY address */ return PhyAddr; } } return PhyAddr; /* default to 32(max of iteration) */ } /****************************************************************************/ /** * * This function sets the PHY to loopback mode. * * @param The XEMACPS driver instance * @param Speed is the loopback speed 10/100 Mbit. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. * *****************************************************************************/ #ifdef PEEP /* Define PEEP in xemacps_example.h if the example is run on PEEP*/ #define PHY_REG0_RESET 0x8000 #define PHY_REG0_LOOPBACK 0x4000 #define PHY_REG0_10 0x0100 #define PHY_REG0_100 0x2100 #define PHY_REG0_1000 0x0140 #define PHY_R20_DFT_SPD_MASK 0x0070 #define PHY_R20_DFT_SPD_10 0x0040 #define PHY_R20_DFT_SPD_100 0x0050 #define PHY_R20_DFT_SPD_1000 0x0060 LONG EmacPsUtilEnterLoopback(XEmacPs * EmacPsInstancePtr, u32 Speed) { LONG Status; u16 PhyReg0 = 0; u16 PhyReg20 = 0; u32 PhyAddr; /* Detect the PHY address */ PhyAddr = XEmacPsDetectPHY(EmacPsInstancePtr); if (PhyAddr >= 32) { EmacPsUtilErrorTrap("Error detect phy"); return XST_FAILURE; } Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 20, &PhyReg20); Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); PhyReg20 &= ~PHY_R20_DFT_SPD_MASK; switch (Speed) { case 10: PhyReg20 |= PHY_R20_DFT_SPD_10; break; case 100: PhyReg20 |= PHY_R20_DFT_SPD_100; break; case 1000: PhyReg20 |= PHY_R20_DFT_SPD_1000; break; default: EmacPsUtilErrorTrap("Error: speed not recognized "); return XST_FAILURE; } Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 20, PhyReg20); Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0 | PHY_REG0_RESET); /* setup speed and duplex */ switch (Speed) { case 10: PhyReg0 = PHY_REG0_10; break; case 100: PhyReg0 = PHY_REG0_100; break; case 1000: PhyReg0 = PHY_REG0_1000; break; default: EmacPsUtilErrorTrap("Error: speed not recognized "); return XST_FAILURE; } Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, (PhyReg0 | PHY_REG0_RESET)); /* FIXME: Sleep doesn't seem to work */ //sleep(1); Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error setup phy speed"); return XST_FAILURE; } /* enable loopback */ PhyReg0 |= PHY_REG0_LOOPBACK; Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error setup phy loopback"); return XST_FAILURE; } return XST_SUCCESS; } #else /*For Zynq board*/ #define PHY_REG0_RESET 0x8000 #define PHY_REG0_LOOPBACK 0x4000 #define PHY_REG0_10 0x0100 #define PHY_REG0_100 0x2100 #define PHY_REG0_1000 0x0140 #define PHY_REG21_10 0x0030 #define PHY_REG21_100 0x2030 #define PHY_REG21_1000 0x0070 LONG EmacPsUtilEnterLoopback(XEmacPs * EmacPsInstancePtr, u32 Speed) { LONG Status; u16 PhyReg0 = 0; u16 PhyReg21 = 0; u16 PhyReg22 = 0; u32 PhyAddr; u32 i =0; /* * Detect the PHY address */ PhyAddr = XEmacPsDetectPHY(EmacPsInstancePtr); if (PhyAddr >= 32) { EmacPsUtilErrorTrap("Error detect phy"); return XST_FAILURE; } /* * Setup speed and duplex */ switch (Speed) { case 10: PhyReg0 |= PHY_REG0_10; PhyReg21 |= PHY_REG21_10; break; case 100: PhyReg0 |= PHY_REG0_100; PhyReg21 |= PHY_REG21_100; break; case 1000: PhyReg0 |= PHY_REG0_1000; PhyReg21 |= PHY_REG21_1000; break; default: EmacPsUtilErrorTrap("Error: speed not recognized "); return XST_FAILURE; } Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); /* * Make sure new configuration is in effect */ Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error setup phy speed"); return XST_FAILURE; } /* * Switching to PAGE2 */ PhyReg22 = 0x2; Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22); /* * Adding Tx and Rx delay. Configuring loopback speed. */ Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 21, PhyReg21); /* * Make sure new configuration is in effect */ Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 21, &PhyReg21); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error setting Reg 21 in Page 2"); return XST_FAILURE; } /* * Switching to PAGE0 */ PhyReg22 = 0x0; Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22); /* * Issue a reset to phy */ Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); PhyReg0 |= PHY_REG0_RESET; Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error reset phy"); return XST_FAILURE; } /* * Enable loopback */ PhyReg0 |= PHY_REG0_LOOPBACK; Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); if (Status != XST_SUCCESS) { EmacPsUtilErrorTrap("Error setup phy loopback"); return XST_FAILURE; } /* * Delay loop */ for(i=0;i<0xfffff;i++); /* FIXME: Sleep doesn't seem to work */ //sleep(1); return XST_SUCCESS; } #endif /*PEEP*/ /****************************************************************************/ /** * * This function is called by example code when an error is detected. It * can be set as a breakpoint with a debugger or it can be used to print out * the given message if there is a UART or STDIO device. * * @param Message is the text explaining the error * * @return None * * @note None * *****************************************************************************/ void EmacPsUtilErrorTrap(const char *Message) { static u32 Count = 0; Count++; #ifdef STDOUT_BASEADDRESS xil_printf("%s\r\n", Message); #else (void) Message; #endif }