
Added initial support Xilinx Embedded Software. Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
967 lines
27 KiB
C
Executable file
967 lines
27 KiB
C
Executable file
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2004 - 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 xemaclite.c
|
|
*
|
|
* Functions in this file are the minimum required functions for the EmacLite
|
|
* driver. See xemaclite.h for a detailed description of the driver.
|
|
*
|
|
* <pre>
|
|
* MODIFICATION HISTORY:
|
|
*
|
|
* Ver Who Date Changes
|
|
* ----- ---- -------- --------------------------------------------------------
|
|
* 1.01a ecm 01/31/04 First release
|
|
* 1.11a mta 03/21/07 Updated to new coding style
|
|
* 1.11a ecm 05/18/07 Updated the TxBufferAvailable routine to look at both
|
|
* the active and busy bits
|
|
* 1.13a sv 02/1/08 Updated the TxBufferAvailable routine to return
|
|
* busy status properly
|
|
* 2.00a ktn 02/16/09 Added support for MDIO
|
|
* 2.01a ktn 07/20/09 Modified XEmacLite_Send function to use Ping buffers
|
|
* Interrupt enable bit since this alone is used to enable
|
|
* the interrupts for both Ping and Pong Buffers.
|
|
* 3.00a ktn 10/22/09 Updated driver to use the HAL APIs/macros.
|
|
* The macros have been renamed to remove _m from the name.
|
|
* 3.01a ktn 07/08/10 The macro XEmacLite_GetReceiveDataLength is changed to
|
|
* a static function.
|
|
* Updated the XEmacLite_GetReceiveDataLength and
|
|
* XEmacLite_Recv functions to support little endian
|
|
* MicroBlaze.
|
|
* 3.02a sdm 07/22/11 Removed redundant code in XEmacLite_Recv functions for
|
|
* CR617290
|
|
* 3.04a srt 04/13/13 Removed warnings (CR 705000).
|
|
*
|
|
* </pre>
|
|
******************************************************************************/
|
|
|
|
/***************************** Include Files *********************************/
|
|
|
|
#include "xil_io.h"
|
|
#include "xenv.h"
|
|
#include "xemaclite.h"
|
|
#include "xemaclite_i.h"
|
|
|
|
/************************** Constant Definitions *****************************/
|
|
|
|
/**************************** Type Definitions *******************************/
|
|
|
|
/***************** Macros (Inline Functions) Definitions *********************/
|
|
|
|
|
|
/************************** Function Prototypes ******************************/
|
|
|
|
static u16 XEmacLite_GetReceiveDataLength(u32 BaseAddress);
|
|
|
|
/************************** Variable Definitions *****************************/
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* Initialize a specific XEmacLite instance/driver. The initialization entails:
|
|
* - Initialize fields of the XEmacLite instance structure.
|
|
*
|
|
* The driver defaults to polled mode operation.
|
|
*
|
|
* @param InstancePtr is a pointer to the XEmacLite instance.
|
|
* @param EmacLiteConfigPtr points to the XEmacLite device configuration
|
|
* structure.
|
|
* @param EffectiveAddr is the device base address in the virtual memory
|
|
* address space. If the address translation is not used then the
|
|
* physical address is passed.
|
|
* Unexpected errors may occur if the address mapping is changed
|
|
* after this function is invoked.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if initialization was successful.
|
|
*
|
|
* @note The initialization of the PHY device is not done in this
|
|
* function. The user needs to use XEmacLite_PhyRead and
|
|
* XEmacLite_PhyWrite functions to access the PHY device.
|
|
*
|
|
******************************************************************************/
|
|
int XEmacLite_CfgInitialize(XEmacLite *InstancePtr,
|
|
XEmacLite_Config *EmacLiteConfigPtr,
|
|
u32 EffectiveAddr)
|
|
{
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
Xil_AssertNonvoid(EmacLiteConfigPtr != NULL);
|
|
|
|
/*
|
|
* Zero the provided instance memory.
|
|
*/
|
|
memset(InstancePtr, 0, sizeof(XEmacLite));
|
|
|
|
/*
|
|
* Set some default values for instance data, don't indicate the device
|
|
* is ready to use until everything has been initialized successfully.
|
|
*/
|
|
InstancePtr->EmacLiteConfig.BaseAddress = EffectiveAddr;
|
|
InstancePtr->EmacLiteConfig.DeviceId = EmacLiteConfigPtr->DeviceId;
|
|
InstancePtr->EmacLiteConfig.TxPingPong = EmacLiteConfigPtr->TxPingPong;
|
|
InstancePtr->EmacLiteConfig.RxPingPong = EmacLiteConfigPtr->RxPingPong;
|
|
InstancePtr->EmacLiteConfig.MdioInclude = EmacLiteConfigPtr->MdioInclude;
|
|
InstancePtr->EmacLiteConfig.Loopback = EmacLiteConfigPtr->Loopback;
|
|
|
|
InstancePtr->NextTxBufferToUse = 0x0;
|
|
InstancePtr->NextRxBufferToUse = 0x0;
|
|
InstancePtr->RecvHandler = (XEmacLite_Handler) StubHandler;
|
|
InstancePtr->SendHandler = (XEmacLite_Handler) StubHandler;
|
|
|
|
/*
|
|
* Clear the TX CSR's in case this is a restart.
|
|
*/
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_TSR_OFFSET, 0);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0);
|
|
|
|
/*
|
|
* Since there were no failures, indicate the device is ready to use.
|
|
*/
|
|
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* Send an Ethernet frame. The ByteCount is the total frame size, including
|
|
* header.
|
|
*
|
|
* @param InstancePtr is a pointer to the XEmacLite instance.
|
|
* @param FramePtr is a pointer to frame. For optimal performance, a
|
|
* 32-bit aligned buffer should be used but it is not required, the
|
|
* function will align the data if necessary.
|
|
* @param ByteCount is the size, in bytes, of the frame
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if data was transmitted.
|
|
* - XST_FAILURE if buffer(s) was (were) full and no valid data was
|
|
* transmitted.
|
|
*
|
|
* @note
|
|
*
|
|
* This function call is not blocking in nature, i.e. it will not wait until the
|
|
* frame is transmitted.
|
|
*
|
|
******************************************************************************/
|
|
int XEmacLite_Send(XEmacLite *InstancePtr, u8 *FramePtr, unsigned ByteCount)
|
|
{
|
|
u32 Register;
|
|
u32 BaseAddress;
|
|
u32 EmacBaseAddress;
|
|
u32 IntrEnableStatus;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
|
|
/*
|
|
* Determine the expected TX buffer address.
|
|
*/
|
|
BaseAddress = XEmacLite_NextTransmitAddr(InstancePtr);
|
|
EmacBaseAddress = InstancePtr->EmacLiteConfig.BaseAddress;
|
|
|
|
/*
|
|
* Check the Length if it is too large, truncate it.
|
|
* The maximum Tx packet size is
|
|
* Ethernet header (14 Bytes) + Maximum MTU (1500 bytes).
|
|
*/
|
|
if (ByteCount > XEL_MAX_TX_FRAME_SIZE) {
|
|
|
|
ByteCount = XEL_MAX_TX_FRAME_SIZE;
|
|
}
|
|
|
|
/*
|
|
* Determine if the expected buffer address is empty.
|
|
*/
|
|
Register = XEmacLite_GetTxStatus(BaseAddress);
|
|
|
|
/*
|
|
* If the expected buffer is available, fill it with the provided data
|
|
* Align if necessary.
|
|
*/
|
|
if ((Register & (XEL_TSR_XMIT_BUSY_MASK |
|
|
XEL_TSR_XMIT_ACTIVE_MASK)) == 0) {
|
|
|
|
/*
|
|
* Switch to next buffer if configured.
|
|
*/
|
|
if (InstancePtr->EmacLiteConfig.TxPingPong != 0) {
|
|
InstancePtr->NextTxBufferToUse ^= XEL_BUFFER_OFFSET;
|
|
}
|
|
|
|
/*
|
|
* Write the frame to the buffer.
|
|
*/
|
|
XEmacLite_AlignedWrite(FramePtr, (u32 *) BaseAddress,
|
|
ByteCount);
|
|
|
|
|
|
/*
|
|
* The frame is in the buffer, now send it.
|
|
*/
|
|
XEmacLite_WriteReg(BaseAddress, XEL_TPLR_OFFSET,
|
|
(ByteCount & (XEL_TPLR_LENGTH_MASK_HI |
|
|
XEL_TPLR_LENGTH_MASK_LO)));
|
|
|
|
/*
|
|
* Update the Tx Status Register to indicate that there is a
|
|
* frame to send.
|
|
* If the interrupt enable bit of Ping buffer(since this
|
|
* controls both the buffers) is enabled then set the
|
|
* XEL_TSR_XMIT_ACTIVE_MASK flag which is used by the interrupt
|
|
* handler to call the callback function provided by the user
|
|
* to indicate that the frame has been transmitted.
|
|
*/
|
|
Register = XEmacLite_GetTxStatus(BaseAddress);
|
|
Register |= XEL_TSR_XMIT_BUSY_MASK;
|
|
IntrEnableStatus = XEmacLite_GetTxStatus(EmacBaseAddress);
|
|
if ((IntrEnableStatus & XEL_TSR_XMIT_IE_MASK) != 0) {
|
|
Register |= XEL_TSR_XMIT_ACTIVE_MASK;
|
|
}
|
|
XEmacLite_SetTxStatus(BaseAddress, Register);
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* If the expected buffer was full, try the other buffer if configured.
|
|
*/
|
|
if (InstancePtr->EmacLiteConfig.TxPingPong != 0) {
|
|
|
|
BaseAddress ^= XEL_BUFFER_OFFSET;
|
|
|
|
/*
|
|
* Determine if the expected buffer address is empty.
|
|
*/
|
|
Register = XEmacLite_GetTxStatus(BaseAddress);
|
|
|
|
/*
|
|
* If the next buffer is available, fill it with the provided
|
|
* data.
|
|
*/
|
|
if ((Register & (XEL_TSR_XMIT_BUSY_MASK |
|
|
XEL_TSR_XMIT_ACTIVE_MASK)) == 0) {
|
|
|
|
/*
|
|
* Write the frame to the buffer.
|
|
*/
|
|
XEmacLite_AlignedWrite(FramePtr, (u32 *) BaseAddress,
|
|
ByteCount);
|
|
|
|
/*
|
|
* The frame is in the buffer, now send it.
|
|
*/
|
|
XEmacLite_WriteReg(BaseAddress, XEL_TPLR_OFFSET,
|
|
(ByteCount & (XEL_TPLR_LENGTH_MASK_HI |
|
|
XEL_TPLR_LENGTH_MASK_LO)));
|
|
|
|
/*
|
|
* Update the Tx Status Register to indicate that there
|
|
* is a frame to send.
|
|
* If the interrupt enable bit of Ping buffer(since this
|
|
* controls both the buffers) is enabled then set the
|
|
* XEL_TSR_XMIT_ACTIVE_MASK flag which is used by the
|
|
* interrupt handler to call the callback function
|
|
* provided by the user to indicate that the frame has
|
|
* been transmitted.
|
|
*/
|
|
Register = XEmacLite_GetTxStatus(BaseAddress);
|
|
Register |= XEL_TSR_XMIT_BUSY_MASK;
|
|
IntrEnableStatus =
|
|
XEmacLite_GetTxStatus(EmacBaseAddress);
|
|
if ((IntrEnableStatus & XEL_TSR_XMIT_IE_MASK) != 0) {
|
|
Register |= XEL_TSR_XMIT_ACTIVE_MASK;
|
|
}
|
|
XEmacLite_SetTxStatus(BaseAddress, Register);
|
|
|
|
/*
|
|
* Do not switch to next buffer, there is a sync problem
|
|
* and the expected buffer should not change.
|
|
*/
|
|
return XST_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Buffer(s) was(were) full, return failure to allow for polling usage.
|
|
*/
|
|
return XST_FAILURE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* Receive a frame. Intended to be called from the interrupt context or
|
|
* with a wrapper which waits for the receive frame to be available.
|
|
*
|
|
* @param InstancePtr is a pointer to the XEmacLite instance.
|
|
* @param FramePtr is a pointer to a buffer where the frame will
|
|
* be stored. The buffer must be at least XEL_MAX_FRAME_SIZE bytes.
|
|
* For optimal performance, a 32-bit aligned buffer should be used
|
|
* but it is not required, the function will align the data if
|
|
* necessary.
|
|
*
|
|
* @return
|
|
*
|
|
* The type/length field of the frame received. When the type/length field
|
|
* contains the type, XEL_MAX_FRAME_SIZE bytes will be copied out of the
|
|
* buffer and it is up to the higher layers to sort out the frame.
|
|
* Function returns 0 if there is no data waiting in the receive buffer or
|
|
* the pong buffer if configured.
|
|
*
|
|
* @note
|
|
*
|
|
* This function call is not blocking in nature, i.e. it will not wait until
|
|
* a frame arrives.
|
|
*
|
|
******************************************************************************/
|
|
u16 XEmacLite_Recv(XEmacLite *InstancePtr, u8 *FramePtr)
|
|
{
|
|
u16 LengthType;
|
|
u16 Length;
|
|
u32 Register;
|
|
u32 BaseAddress;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
|
|
/*
|
|
* Determine the expected buffer address.
|
|
*/
|
|
BaseAddress = XEmacLite_NextReceiveAddr(InstancePtr);
|
|
|
|
/*
|
|
* Verify which buffer has valid data.
|
|
*/
|
|
Register = XEmacLite_GetRxStatus(BaseAddress);
|
|
|
|
if ((Register & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
|
|
|
|
/*
|
|
* The driver is in sync, update the next expected buffer if
|
|
* configured.
|
|
*/
|
|
|
|
if (InstancePtr->EmacLiteConfig.RxPingPong != 0) {
|
|
InstancePtr->NextRxBufferToUse ^= XEL_BUFFER_OFFSET;
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
* The instance is out of sync, try other buffer if other
|
|
* buffer is configured, return 0 otherwise. If the instance is
|
|
* out of sync, do not update the 'NextRxBufferToUse' since it
|
|
* will correct on subsequent calls.
|
|
*/
|
|
if (InstancePtr->EmacLiteConfig.RxPingPong != 0) {
|
|
BaseAddress ^= XEL_BUFFER_OFFSET;
|
|
}
|
|
else {
|
|
return 0; /* No data was available */
|
|
}
|
|
|
|
/*
|
|
* Verify that buffer has valid data.
|
|
*/
|
|
Register = XEmacLite_GetRxStatus(BaseAddress);
|
|
if ((Register & XEL_RSR_RECV_DONE_MASK) !=
|
|
XEL_RSR_RECV_DONE_MASK) {
|
|
return 0; /* No data was available */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the length of the frame that arrived.
|
|
*/
|
|
LengthType = XEmacLite_GetReceiveDataLength(BaseAddress);
|
|
|
|
/*
|
|
* Check if length is valid.
|
|
*/
|
|
if (LengthType > XEL_MAX_FRAME_SIZE) {
|
|
|
|
|
|
if (LengthType == XEL_ETHER_PROTO_TYPE_IP) {
|
|
|
|
/*
|
|
* The packet is a an IP Packet.
|
|
*/
|
|
#ifdef __LITTLE_ENDIAN__
|
|
Length = (XEmacLite_ReadReg((BaseAddress),
|
|
XEL_HEADER_IP_LENGTH_OFFSET +
|
|
XEL_RXBUFF_OFFSET) &
|
|
(XEL_RPLR_LENGTH_MASK_HI |
|
|
XEL_RPLR_LENGTH_MASK_LO));
|
|
Length = (u16) (((Length & 0xFF00) >> 8) | ((Length & 0x00FF) << 8));
|
|
#else
|
|
Length = ((XEmacLite_ReadReg((BaseAddress),
|
|
XEL_HEADER_IP_LENGTH_OFFSET +
|
|
XEL_RXBUFF_OFFSET) >>
|
|
XEL_HEADER_SHIFT) &
|
|
(XEL_RPLR_LENGTH_MASK_HI |
|
|
XEL_RPLR_LENGTH_MASK_LO));
|
|
#endif
|
|
|
|
Length += XEL_HEADER_SIZE + XEL_FCS_SIZE;
|
|
|
|
} else if (LengthType == XEL_ETHER_PROTO_TYPE_ARP) {
|
|
|
|
/*
|
|
* The packet is an ARP Packet.
|
|
*/
|
|
Length = XEL_ARP_PACKET_SIZE + XEL_HEADER_SIZE +
|
|
XEL_FCS_SIZE;
|
|
|
|
} else {
|
|
/*
|
|
* Field contains type other than IP or ARP, use max
|
|
* frame size and let user parse it.
|
|
*/
|
|
Length = XEL_MAX_FRAME_SIZE;
|
|
|
|
}
|
|
} else {
|
|
|
|
/*
|
|
* Use the length in the frame, plus the header and trailer.
|
|
*/
|
|
Length = LengthType + XEL_HEADER_SIZE + XEL_FCS_SIZE;
|
|
}
|
|
|
|
/*
|
|
* Read from the EmacLite.
|
|
*/
|
|
XEmacLite_AlignedRead(((u32 *) (BaseAddress + XEL_RXBUFF_OFFSET)),
|
|
FramePtr, Length);
|
|
|
|
/*
|
|
* Acknowledge the frame.
|
|
*/
|
|
Register = XEmacLite_GetRxStatus(BaseAddress);
|
|
Register &= ~XEL_RSR_RECV_DONE_MASK;
|
|
XEmacLite_SetRxStatus(BaseAddress, Register);
|
|
|
|
return Length;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* Set the MAC address for this device. The address is a 48-bit value.
|
|
*
|
|
* @param InstancePtr is a pointer to the XEmacLite instance.
|
|
* @param AddressPtr is a pointer to a 6-byte MAC address.
|
|
* the format of the MAC address is major octet to minor octet
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note
|
|
*
|
|
* - TX must be idle and RX should be idle for deterministic results.
|
|
* It is recommended that this function should be called after the
|
|
* initialization and before transmission of any packets from the device.
|
|
* - Function will not return if hardware is absent or not functioning
|
|
* properly.
|
|
* - The MAC address can be programmed using any of the two transmit
|
|
* buffers (if configured).
|
|
*
|
|
******************************************************************************/
|
|
void XEmacLite_SetMacAddress(XEmacLite *InstancePtr, u8 *AddressPtr)
|
|
{
|
|
u32 BaseAddress;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
|
|
/*
|
|
* Determine the expected TX buffer address.
|
|
*/
|
|
BaseAddress = XEmacLite_NextTransmitAddr(InstancePtr);
|
|
|
|
/*
|
|
* Copy the MAC address to the Transmit buffer.
|
|
*/
|
|
XEmacLite_AlignedWrite(AddressPtr,
|
|
(u32 *) BaseAddress,
|
|
XEL_MAC_ADDR_SIZE);
|
|
|
|
/*
|
|
* Set the length.
|
|
*/
|
|
XEmacLite_WriteReg(BaseAddress,
|
|
XEL_TPLR_OFFSET,
|
|
XEL_MAC_ADDR_SIZE);
|
|
|
|
/*
|
|
* Update the MAC address in the EmacLite.
|
|
*/
|
|
XEmacLite_SetTxStatus(BaseAddress, XEL_TSR_PROG_MAC_ADDR);
|
|
|
|
|
|
/*
|
|
* Wait for EmacLite to finish with the MAC address update.
|
|
*/
|
|
while ((XEmacLite_GetTxStatus(BaseAddress) &
|
|
XEL_TSR_PROG_MAC_ADDR) != 0);
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
*
|
|
* This is a stub for the send and receive callbacks. The stub
|
|
* is here in case the upper layers forget to set the handlers.
|
|
*
|
|
* @param CallBackRef is a pointer to the upper layer callback reference.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
void StubHandler(void *CallBackRef)
|
|
{
|
|
(void)(CallBackRef);
|
|
Xil_AssertVoidAlways();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* Determine if there is a transmit buffer available.
|
|
*
|
|
* @param InstancePtr is the pointer to the instance of the driver to
|
|
* be worked on.
|
|
*
|
|
* @return
|
|
* - TRUE if there is a TX buffer available for data to be written
|
|
* - FALSE if Tx Buffer is not available.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
int XEmacLite_TxBufferAvailable(XEmacLite *InstancePtr)
|
|
{
|
|
|
|
u32 Register;
|
|
int TxPingBusy;
|
|
int TxPongBusy;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
|
|
/*
|
|
* Read the Tx Status and determine if the buffer is available.
|
|
*/
|
|
Register = XEmacLite_GetTxStatus(InstancePtr->EmacLiteConfig.
|
|
BaseAddress);
|
|
|
|
TxPingBusy = (Register & (XEL_TSR_XMIT_BUSY_MASK |
|
|
XEL_TSR_XMIT_ACTIVE_MASK));
|
|
|
|
|
|
/*
|
|
* Read the Tx Status of the second buffer register and determine if the
|
|
* buffer is available.
|
|
*/
|
|
if (InstancePtr->EmacLiteConfig.TxPingPong != 0) {
|
|
Register = XEmacLite_GetTxStatus(InstancePtr->EmacLiteConfig.
|
|
BaseAddress +
|
|
XEL_BUFFER_OFFSET);
|
|
|
|
TxPongBusy = (Register & (XEL_TSR_XMIT_BUSY_MASK |
|
|
XEL_TSR_XMIT_ACTIVE_MASK));
|
|
|
|
return (!(TxPingBusy && TxPongBusy));
|
|
}
|
|
|
|
return (!TxPingBusy);
|
|
|
|
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* Flush the Receive buffers. All data will be lost.
|
|
*
|
|
* @param InstancePtr is the pointer to the instance of the driver to
|
|
* be worked on.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
void XEmacLite_FlushReceive(XEmacLite *InstancePtr)
|
|
{
|
|
|
|
u32 Register;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
|
|
/*
|
|
* Read the current buffer register and determine if the buffer is
|
|
* available.
|
|
*/
|
|
Register = XEmacLite_GetRxStatus(InstancePtr->EmacLiteConfig.
|
|
BaseAddress);
|
|
|
|
/*
|
|
* Preserve the IE bit.
|
|
*/
|
|
Register &= XEL_RSR_RECV_IE_MASK;
|
|
|
|
/*
|
|
* Write out the value to flush the RX buffer.
|
|
*/
|
|
XEmacLite_SetRxStatus(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
Register);
|
|
|
|
/*
|
|
* If the pong buffer is available, flush it also.
|
|
*/
|
|
if (InstancePtr->EmacLiteConfig.RxPingPong != 0) {
|
|
/*
|
|
* Read the current buffer register and determine if the buffer
|
|
* is available.
|
|
*/
|
|
Register = XEmacLite_GetRxStatus(InstancePtr->EmacLiteConfig.
|
|
BaseAddress +
|
|
XEL_BUFFER_OFFSET);
|
|
|
|
/*
|
|
* Preserve the IE bit.
|
|
*/
|
|
Register &= XEL_RSR_RECV_IE_MASK;
|
|
|
|
/*
|
|
* Write out the value to flush the RX buffer.
|
|
*/
|
|
XEmacLite_SetRxStatus(InstancePtr->EmacLiteConfig.BaseAddress +
|
|
XEL_BUFFER_OFFSET, Register);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
*
|
|
* Read the specified PHY register.
|
|
*
|
|
* @param InstancePtr is the pointer to the instance of the driver.
|
|
* @param PhyAddress is the address of the PHY device. The valid range is
|
|
* is from 0 to 31.
|
|
* @param RegNum is the register number in the PHY device which
|
|
* is to be read. The valid range is is from 0 to 31.
|
|
* @param PhyDataPtr is a pointer to the data in which the data read
|
|
* from the PHY device is returned.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if the data is read from the PHY.
|
|
* - XST_DEVICE_BUSY if MDIO is busy.
|
|
*
|
|
* @note This function waits for the completion of MDIO data transfer.
|
|
*
|
|
*****************************************************************************/
|
|
int XEmacLite_PhyRead(XEmacLite *InstancePtr, u32 PhyAddress, u32 RegNum,
|
|
u16 *PhyDataPtr)
|
|
{
|
|
u32 PhyAddrReg;
|
|
u32 MdioCtrlReg;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
Xil_AssertNonvoid(InstancePtr->EmacLiteConfig.MdioInclude == TRUE);
|
|
Xil_AssertNonvoid(PhyAddress <= 31);
|
|
Xil_AssertNonvoid(RegNum <= 31);
|
|
Xil_AssertNonvoid(PhyDataPtr != NULL);
|
|
|
|
/*
|
|
* Verify MDIO master status.
|
|
*/
|
|
if (XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET) &
|
|
XEL_MDIOCNTR_STATUS_MASK) {
|
|
return XST_DEVICE_BUSY;
|
|
}
|
|
|
|
PhyAddrReg = ((((PhyAddress << XEL_MDIO_ADDRESS_SHIFT) &
|
|
XEL_MDIO_ADDRESS_MASK) | RegNum) | XEL_MDIO_OP_MASK);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOADDR_OFFSET, PhyAddrReg);
|
|
|
|
/*
|
|
* Enable MDIO and start the transfer.
|
|
*/
|
|
MdioCtrlReg =
|
|
XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET,
|
|
MdioCtrlReg |
|
|
XEL_MDIOCNTR_STATUS_MASK |
|
|
XEL_MDIOCNTR_ENABLE_MASK);
|
|
|
|
/*
|
|
* Wait till the completion of transfer.
|
|
*/
|
|
while ((XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET) &
|
|
XEL_MDIOCNTR_STATUS_MASK));
|
|
|
|
/*
|
|
* Read data from MDIO read data register.
|
|
*/
|
|
*PhyDataPtr = (u16)XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIORD_OFFSET);
|
|
|
|
/*
|
|
* Disable the MDIO.
|
|
*/
|
|
MdioCtrlReg =
|
|
XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET);
|
|
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET,
|
|
MdioCtrlReg & ~XEL_MDIOCNTR_ENABLE_MASK);
|
|
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
*
|
|
* Write the given data to the specified register in the PHY device.
|
|
*
|
|
* @param InstancePtr is the pointer to the instance of the driver.
|
|
* @param PhyAddress is the address of the PHY device. The valid range is
|
|
* is from 0 to 31.
|
|
* @param RegNum is the register number in the PHY device which
|
|
* is to be written. The valid range is is from 0 to 31.
|
|
* @param PhyData is the data to be written to the specified register in
|
|
* the PHY device.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if the data is written to the PHY.
|
|
* - XST_DEVICE_BUSY if MDIO is busy.
|
|
*
|
|
* @note This function waits for the completion of MDIO data transfer.
|
|
*
|
|
*******************************************************************************/
|
|
int XEmacLite_PhyWrite(XEmacLite *InstancePtr, u32 PhyAddress, u32 RegNum,
|
|
u16 PhyData)
|
|
{
|
|
u32 PhyAddrReg;
|
|
u32 MdioCtrlReg;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
Xil_AssertNonvoid(InstancePtr->EmacLiteConfig.MdioInclude == TRUE);
|
|
Xil_AssertNonvoid(PhyAddress <= 31);
|
|
Xil_AssertNonvoid(RegNum <= 31);
|
|
|
|
/*
|
|
* Verify MDIO master status.
|
|
*/
|
|
if (XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET) &
|
|
XEL_MDIOCNTR_STATUS_MASK) {
|
|
return XST_DEVICE_BUSY;
|
|
}
|
|
|
|
|
|
|
|
PhyAddrReg = ((((PhyAddress << XEL_MDIO_ADDRESS_SHIFT) &
|
|
XEL_MDIO_ADDRESS_MASK) | RegNum) & ~XEL_MDIO_OP_MASK);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOADDR_OFFSET, PhyAddrReg);
|
|
|
|
/*
|
|
* Write data to MDIO write data register.
|
|
*/
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOWR_OFFSET, (u32)PhyData);
|
|
|
|
/*
|
|
* Enable MDIO and start the transfer.
|
|
*/
|
|
MdioCtrlReg =
|
|
XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET,
|
|
MdioCtrlReg | XEL_MDIOCNTR_STATUS_MASK |
|
|
XEL_MDIOCNTR_ENABLE_MASK);
|
|
|
|
/*
|
|
* Wait till the completion of transfer.
|
|
*/
|
|
while ((XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET) & XEL_MDIOCNTR_STATUS_MASK));
|
|
|
|
|
|
/*
|
|
* Disable the MDIO.
|
|
*/
|
|
MdioCtrlReg =
|
|
XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_MDIOCNTR_OFFSET,
|
|
MdioCtrlReg & ~XEL_MDIOCNTR_ENABLE_MASK);
|
|
|
|
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* Enable Internal loop back functionality.
|
|
*
|
|
* @param InstancePtr is the pointer to the instance of the driver.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
void XEmacLite_EnableLoopBack(XEmacLite *InstancePtr)
|
|
{
|
|
u32 TsrReg;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
Xil_AssertVoid(InstancePtr->EmacLiteConfig.Loopback == TRUE);
|
|
|
|
TsrReg = XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_TSR_OFFSET);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_TSR_OFFSET, TsrReg | XEL_TSR_LOOPBACK_MASK);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* Disable Internal loop back functionality.
|
|
*
|
|
* @param InstancePtr is the pointer to the instance of the driver.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
void XEmacLite_DisableLoopBack(XEmacLite *InstancePtr)
|
|
{
|
|
u32 TsrReg;
|
|
|
|
/*
|
|
* Verify that each of the inputs are valid.
|
|
*/
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
Xil_AssertVoid(InstancePtr->EmacLiteConfig.Loopback == TRUE);
|
|
|
|
TsrReg = XEmacLite_ReadReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_TSR_OFFSET);
|
|
XEmacLite_WriteReg(InstancePtr->EmacLiteConfig.BaseAddress,
|
|
XEL_TSR_OFFSET, TsrReg & (~XEL_TSR_LOOPBACK_MASK));
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
*
|
|
* Return the length of the data in the Receive Buffer.
|
|
*
|
|
* @param BaseAddress contains the base address of the device.
|
|
*
|
|
* @return The type/length field of the frame received.
|
|
*
|
|
* @note None.
|
|
*
|
|
******************************************************************************/
|
|
static u16 XEmacLite_GetReceiveDataLength(u32 BaseAddress)
|
|
{
|
|
u16 Length;
|
|
|
|
#ifdef __LITTLE_ENDIAN__
|
|
Length = (XEmacLite_ReadReg((BaseAddress),
|
|
XEL_HEADER_OFFSET + XEL_RXBUFF_OFFSET) &
|
|
(XEL_RPLR_LENGTH_MASK_HI | XEL_RPLR_LENGTH_MASK_LO));
|
|
Length = (u16) (((Length & 0xFF00) >> 8) | ((Length & 0x00FF) << 8));
|
|
#else
|
|
Length = ((XEmacLite_ReadReg((BaseAddress),
|
|
XEL_HEADER_OFFSET + XEL_RXBUFF_OFFSET) >>
|
|
XEL_HEADER_SHIFT) &
|
|
(XEL_RPLR_LENGTH_MASK_HI | XEL_RPLR_LENGTH_MASK_LO));
|
|
#endif
|
|
|
|
return Length;
|
|
}
|
|
|