embeddedsw/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_util.c
Punnaiah Choudary Kalluri ae31a85612 emacps: Add support for Zynq Ultrascale Mp and misra c guidelines
Upgrade and make misra c compliant

Signed-off-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
2015-04-26 09:58:11 +05:30

620 lines
16 KiB
C
Executable file

/******************************************************************************
*
* 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.
*
* <pre>
* 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.
* </pre>
*
*****************************************************************************/
/***************************** 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:
* <pre>
* 0, 1, 2, ... 254, 255, 00, 00, 00, 01, 00, 02, ...
* </pre>
*
* @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
}