From 9c2796ece27a77a564e6f6a17d2f5e0cab036a78 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 16 Oct 2012 18:26:45 +0200 Subject: [PATCH] net: old_gem: Add old gem driver back to the repository The reason is to get more time for solving issue with new mainline gem driver. Signed-off-by: Michal Simek --- board/xilinx/zynq_common/board.c | 4 + drivers/net/Makefile | 2 + drivers/net/zynq_gem.h | 645 ++++++++++++++++++++ drivers/net/zynq_gem_bd.h | 696 ++++++++++++++++++++++ drivers/net/zynq_gem_bdring.c | 983 +++++++++++++++++++++++++++++++ drivers/net/zynq_gem_bdring.h | 195 ++++++ drivers/net/zynq_gem_control.c | 924 +++++++++++++++++++++++++++++ drivers/net/zynq_gem_g.c | 46 ++ drivers/net/zynq_gem_hw.h | 539 +++++++++++++++++ drivers/net/zynq_gem_old.c | 362 ++++++++++++ drivers/net/zynq_gem_sinit.c | 58 ++ drivers/net/zynq_gem_wrap.c | 759 ++++++++++++++++++++++++ include/netdev.h | 2 + 13 files changed, 5215 insertions(+) create mode 100644 drivers/net/zynq_gem.h create mode 100644 drivers/net/zynq_gem_bd.h create mode 100644 drivers/net/zynq_gem_bdring.c create mode 100644 drivers/net/zynq_gem_bdring.h create mode 100644 drivers/net/zynq_gem_control.c create mode 100644 drivers/net/zynq_gem_g.c create mode 100644 drivers/net/zynq_gem_hw.h create mode 100644 drivers/net/zynq_gem_old.c create mode 100644 drivers/net/zynq_gem_sinit.c create mode 100644 drivers/net/zynq_gem_wrap.c diff --git a/board/xilinx/zynq_common/board.c b/board/xilinx/zynq_common/board.c index 05aa106af3e..0d1a55e21c1 100644 --- a/board/xilinx/zynq_common/board.c +++ b/board/xilinx/zynq_common/board.c @@ -135,6 +135,10 @@ int board_eth_init(bd_t *bis) # endif #endif +#ifdef CONFIG_ZYNQ_GEM_OLD + ret |= zynq_gem_initialize_old(bis); +#endif + return ret; } #endif diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 48046bc806d..023473faf42 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -80,6 +80,8 @@ COBJS-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o COBJS-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o COBJS-$(CONFIG_ZYNQ_GEM) += zynq_gem.o +COBJS-$(CONFIG_ZYNQ_GEM_OLD) += zynq_gem_old.o zynq_gem_bdring.o zynq_gem_control.o \ + zynq_gem_g.o zynq_gem_sinit.o zynq_gem_wrap.o COBJS := $(sort $(COBJS-y)) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/zynq_gem.h b/drivers/net/zynq_gem.h new file mode 100644 index 00000000000..101db96dc84 --- /dev/null +++ b/drivers/net/zynq_gem.h @@ -0,0 +1,645 @@ +/* + * (C) Copyright 2012 Xilinx + * + * The Xilinx Embedded Processor Block Ethernet driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef XEMACPSS_H /* prevent circular inclusions */ +#define XEMACPSS_H /* by using protection macros */ + +/** + * For a full description of XEMACPSS features, please see the hardware spec. + * This driver supports the following features: + * - Memory mapped access to host interface registers + * - Statistics counter registers for RMON/MIB + * - API for interrupt driven frame transfers for hardware configured DMA + * - Virtual memory support + * - Unicast, broadcast, and multicast receive address filtering + * - Full and half duplex operation + * - Automatic PAD & FCS insertion and stripping + * - Flow control + * - Support up to four 48bit addresses + * - Address checking for four specific 48bit addresses + * - VLAN frame support + * - Pause frame support + * - Large frame support up to 1536 bytes + * - Checksum offload + * + * Driver Description: + * + * The device driver enables higher layer software (e.g., an application) to + * communicate to the XEmacPss. The driver handles transmission and reception + * of Ethernet frames, as well as configuration and control. No pre or post + * processing of frame data is performed. The driver does not validate the + * contents of an incoming frame in addition to what has already occurred in + * hardware. + * A single device driver can support multiple devices even when those devices + * have significantly different configurations. + * + * Initialization & Configuration: + * + * The XEmacPss_Config structure is used by the driver to configure itself. + * This configuration structure is typically created by the tool-chain based + * on hardware build properties. + * + * The driver instance can be initialized in + * + * - XEmacPss_CfgInitialize(InstancePtr, CfgPtr, EffectiveAddress): Uses a + * configuration structure provided by the caller. If running in a system + * with address translation, the provided virtual memory base address + * replaces the physical address present in the configuration structure. + * + * The device supports DMA only as current development plan. No FIFO mode is + * supported. The driver expects to start the DMA channels and expects that + * the user has set up the buffer descriptor lists. + * + * Interrupts and Asynchronous Callbacks: + * + * The driver has no dependencies on the interrupt controller. When an + * interrupt occurs, the handler will perform a small amount of + * housekeeping work, determine the source of the interrupt, and call the + * appropriate callback function. All callbacks are registered by the user + * level application. + * + * Virtual Memory: + * + * All virtual to physical memory mappings must occur prior to accessing the + * driver API. + * + * For DMA transactions, user buffers supplied to the driver must be in terms + * of their physical address. + * + * DMA: + * + * The DMA engine uses buffer descriptors (BDs) to describe Ethernet frames. + * These BDs are typically chained together into a list the hardware follows + * when transferring data in and out of the packet buffers. Each BD describes + * a memory region containing either a full or partial Ethernet packet. + * + * Interrupt coalescing is not suppoted from this built-in DMA engine. + * + * This API requires the user to understand how the DMA operates. The + * following paragraphs provide some explanation, but the user is encouraged + * to read documentation in zynq_gem_bdring.h as well as study example code + * that accompanies this driver. + * + * The API is designed to get BDs to and from the DMA engine in the most + * efficient means possible. The first step is to establish a memory region + * to contain all BDs for a specific channel. This is done with + * XEmacPss_BdRingCreate(). This function sets up a BD ring that hardware will + * follow as BDs are processed. The ring will consist of a user defined number + * of BDs which will all be partially initialized. For example on the transmit + * channel, the driver will initialize all BDs' so that they are configured + * for transmit. The more fields that can be permanently setup at + * initialization, then the fewer accesses will be needed to each BD while + * the DMA engine is in operation resulting in better throughput and CPU + * utilization. The best case initialization would require the user to set + * only a frame buffer address and length prior to submitting the BD to the + * engine. + * + * BDs move through the engine with the help of functions + * XEmacPss_BdRingAlloc(), XEmacPss_BdRingToHw(), XEmacPss_BdRingFromHw(), + * and XEmacPss_BdRingFree(). + * All these functions handle BDs that are in place. That is, there are no + * copies of BDs kept anywhere and any BD the user interacts with is an actual + * BD from the same ring hardware accesses. + * + * BDs in the ring go through a series of states as follows: + * 1. Idle. The driver controls BDs in this state. + * 2. The user has data to transfer. XEmacPss_BdRingAlloc() is called to + * reserve BD(s). Once allocated, the user may setup the BD(s) with + * frame buffer address, length, and other attributes. The user controls + * BDs in this state. + * 3. The user submits BDs to the DMA engine with XEmacPss_BdRingToHw. BDs + * in this state are either waiting to be processed by hardware, are in + * process, or have been processed. The DMA engine controls BDs in this + * state. + * 4. Processed BDs are retrieved with XEmacEpv_BdRingFromHw() by the + * user. Once retrieved, the user can examine each BD for the outcome of + * the DMA transfer. The user controls BDs in this state. After examining + * the BDs the user calls XEmacPss_BdRingFree() which places the BDs back + * into state 1. + * + * Each of the four BD accessor functions operate on a set of BDs. A set is + * defined as a segment of the BD ring consisting of one or more BDs. The user + * views the set as a pointer to the first BD along with the number of BDs for + * that set. The set can be navigated by using macros XEmacPss_BdNext(). The + * user must exercise extreme caution when changing BDs in a set as there is + * nothing to prevent doing a mBdNext past the end of the set and modifying a + * BD out of bounds. + * + * XEmacPss_BdRingAlloc() + XEmacPss_BdRingToHw(), as well as + * XEmacPss_BdRingFromHw() + XEmacPss_BdRingFree() are designed to be used in + * tandem. The same BD set retrieved with BdRingAlloc should be the same one + * provided to hardware with BdRingToHw. Same goes with BdRingFromHw and + * BdRIngFree. + * + * Alignment & Data Cache Restrictions: + * + * Due to the design of the hardware, all RX buffers, BDs need to be 4-byte + * aligned. Please reference zynq_gem_bd.h for cache related macros. + * + * DMA Tx: + * + * - If frame buffers exist in cached memory, then they must be flushed + * prior to committing them to hardware. + * + * DMA Rx: + * + * - If frame buffers exist in cached memory, then the cache must be + * invalidated for the memory region containing the frame prior to data + * access + * + * Both cache invalidate/flush are taken care of in driver code. + * + * Buffer Copying: + * + * The driver is designed for a zero-copy buffer scheme. That is, the driver + * will not copy buffers. This avoids potential throughput bottlenecks within + * the driver. If byte copying is required, then the transfer will take longer + * to complete. + * + * Checksum Offloading: + * + * The Embedded Processor Block Ethernet can be configured to perform IP, TCP + * and UDP checksum offloading in both receive and transmit directions. + * + * IP packets contain a 16-bit checksum field, which is the 16-bit 1s + * complement of the 1s complement sum of all 16-bit words in the header. + * TCP and UDP packets contain a 16-bit checksum field, which is the 16-bit + * 1s complement of the 1s complement sum of all 16-bit words in the header, + * the data and a conceptual pseudo header. + * + * To calculate these checksums in software requires each byte of the packet + * to be read. For TCP and UDP this can use a large amount of processing power. + * Offloading the checksum calculation to hardware can result in significant + * performance improvements. + * + * The transmit checksum offload is only available to use DMA in packet buffer + * mode. This is because the complete frame to be transmitted must be read + * into the packet buffer memory before the checksum can be calculated and + * written to the header at the beginning of the frame. + * + * For IP, TCP or UDP receive checksum offload to be useful, the operating + * system containing the protocol stack must be aware that this offload is + * available so that it can make use of the fact that the hardware has verified + * the checksum. + * + * When receive checksum offloading is enabled in the hardware, the IP header + * checksum is checked, where the packet meets the following criteria: + * + * 1. If present, the VLAN header must be four octets long and the CFI bit + * must not be set. + * 2. Encapsulation must be RFC 894 Ethernet Type Encoding or RFC 1042 SNAP + * encoding. + * 3. IP v4 packet. + * 4. IP header is of a valid length. + * 5. Good IP header checksum. + * 6. No IP fragmentation. + * 7. TCP or UDP packet. + * + * When an IP, TCP or UDP frame is received, the receive buffer descriptor + * gives an indication if the hardware was able to verify the checksums. + * There is also an indication if the frame had SNAP encapsulation. These + * indication bits will replace the type ID match indication bits when the + * receive checksum offload is enabled. + * + * If any of the checksums are verified incorrect by the hardware, the packet + * is discarded and the appropriate statistics counter incremented. + * + * PHY Interfaces: + * + * RGMII 1.3 is the only interface supported. + * + * Asserts: + * + * Asserts are used within all Xilinx drivers to enforce constraints on + * parameters. Asserts can be turned off on a system-wide basis by defining, + * at compile time, the NDEBUG identifier. By default, asserts are turned on + * and it is recommended that users leave asserts on during development. For + * deployment use -DNDEBUG compiler switch to remove assert code. + * + * @note + * + * Xilinx drivers are typically composed of two parts, one is the driver + * and the other is the adapter. The driver is independent of OS and processor + * and is intended to be highly portable. The adapter is OS-specific and + * facilitates communication between the driver and an OS. + * This driver is intended to be RTOS and processor independent. Any needs for + * dynamic memory management, threads or thread mutual exclusion, or cache + * control must be satisfied bythe layer above this driver. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files ********************************/ + +#include "xbasic_types.h" +#include "xstatus.h" +#include "zynq_gem_hw.h" +#include "zynq_gem_bd.h" +#include "zynq_gem_bdring.h" + +/************************** Constant Definitions ****************************/ + +/* + * Device information + */ +#define XEMACPSS_DEVICE_NAME "xemacps" +#define XEMACPSS_DEVICE_DESC "Xilinx PSS 10/100/1000 MAC" + +/** @name Configuration options + * + * Device configuration options. See the XEmacPss_SetOptions(), + * XEmacPss_ClearOptions() and XEmacPss_GetOptions() for information on how to + * use options. + * + * The default state of the options are noted and are what the device and + * driver will be set to after calling XEmacPss_Reset() or + * XEmacPss_Initialize(). + * + * @{ + */ + +#define XEMACPSS_PROMISC_OPTION 0x00000001 +/**< Accept all incoming packets. + * This option defaults to disabled (cleared) */ + +#define XEMACPSS_FRAME1536_OPTION 0x00000002 +/**< Frame larger than 1516 support for Tx & Rx. + * This option defaults to disabled (cleared) */ + +#define XEMACPSS_VLAN_OPTION 0x00000004 +/**< VLAN Rx & Tx frame support. + * This option defaults to disabled (cleared) */ + +#define XEMACPSS_FLOW_CONTROL_OPTION 0x00000010 +/**< Enable recognition of flow control frames on Rx + * This option defaults to enabled (set) */ + +#define XEMACPSS_FCS_STRIP_OPTION 0x00000020 +/**< Strip FCS and PAD from incoming frames. Note: PAD from VLAN frames is not + * stripped. + * This option defaults to enabled (set) */ + +#define XEMACPSS_FCS_INSERT_OPTION 0x00000040 +/**< Generate FCS field and add PAD automatically for outgoing frames. + * This option defaults to disabled (cleared) */ + +#define XEMACPSS_LENTYPE_ERR_OPTION 0x00000080 +/**< Enable Length/Type error checking for incoming frames. When this option is + * set, the MAC will filter frames that have a mismatched type/length field + * and if XEMACPSS_REPORT_RXERR_OPTION is set, the user is notified when these + * types of frames are encountered. When this option is cleared, the MAC will + * allow these types of frames to be received. + * + * This option defaults to disabled (cleared) */ + +#define XEMACPSS_TRANSMITTER_ENABLE_OPTION 0x00000100 +/**< Enable the transmitter. + * This option defaults to enabled (set) */ + +#define XEMACPSS_RECEIVER_ENABLE_OPTION 0x00000200 +/**< Enable the receiver + * This option defaults to enabled (set) */ + +#define XEMACPSS_BROADCAST_OPTION 0x00000400 +/**< Allow reception of the broadcast address + * This option defaults to enabled (set) */ + +#define XEMACPSS_MULTICAST_OPTION 0x00000800 +/**< Allows reception of multicast addresses programmed into hash + * This option defaults to disabled (clear) */ + +#define XEMACPSS_RX_CHKSUM_ENABLE_OPTION 0x00001000 +/**< Enable the RX checksum offload + * This option defaults to enabled (set) */ + +#define XEMACPSS_TX_CHKSUM_ENABLE_OPTION 0x00002000 +/**< Enable the TX checksum offload + * This option defaults to enabled (set) */ + + +#define XEMACPSS_DEFAULT_OPTIONS \ + (XEMACPSS_FLOW_CONTROL_OPTION | \ + XEMACPSS_FCS_INSERT_OPTION | \ + XEMACPSS_FCS_STRIP_OPTION | \ + XEMACPSS_BROADCAST_OPTION | \ + XEMACPSS_LENTYPE_ERR_OPTION | \ + XEMACPSS_TRANSMITTER_ENABLE_OPTION | \ + XEMACPSS_RECEIVER_ENABLE_OPTION | \ + XEMACPSS_RX_CHKSUM_ENABLE_OPTION | \ + XEMACPSS_TX_CHKSUM_ENABLE_OPTION) + +/**< Default options set when device is initialized or reset */ +/*@}*/ + +/** @name Callback identifiers + * + * These constants are used as parameters to XEmacPss_SetHandler() + * @{ + */ +#define XEMACPSS_HANDLER_DMASEND 1 +#define XEMACPSS_HANDLER_DMARECV 2 +#define XEMACPSS_HANDLER_ERROR 3 +/*@}*/ + +/* Constants to determine the configuration of the hardware device. They are + * used to allow the driver to verify it can operate with the hardware. + */ +#define XEMACPSS_MDIO_DIV_DFT MDC_DIV_32 /**< Default MDIO clock divisor */ + +/* The next few constants help upper layers determine the size of memory + * pools used for Ethernet buffers and descriptor lists. + */ +#define XEMACPSS_MAC_ADDR_SIZE 6 /* size of Ethernet header */ + +#define XEMACPSS_MTU 1500 /* max MTU size of Ethernet frame */ +#define XEMACPSS_HDR_SIZE 14 /* size of Ethernet header */ +#define XEMACPSS_HDR_VLAN_SIZE 18 /* size of Ethernet header with VLAN */ +#define XEMACPSS_TRL_SIZE 4 /* size of Ethernet trailer (FCS) */ +#define XEMACPSS_MAX_FRAME_SIZE (XEMACPSS_MTU + XEMACPSS_HDR_SIZE + \ + XEMACPSS_TRL_SIZE) +#define XEMACPSS_MAX_VLAN_FRAME_SIZE (XEMACPSS_MTU + XEMACPSS_HDR_SIZE + \ + XEMACPSS_HDR_VLAN_SIZE + XEMACPSS_TRL_SIZE) + + +/**************************** Type Definitions ******************************/ +/** @name Typedefs for callback functions + * + * These callbacks are invoked in interrupt context. + * @{ + */ +/** + * Callback invoked when frame(s) have been sent or received in interrupt + * driven DMA mode. To set the send callback, invoke XEmacPss_SetHandler(). + * + * @param CallBackRef is user data assigned when the callback was set. + * + * @note + * See zynq_gem_hw.h for bitmasks definitions and the device hardware spec for + * further information on their meaning. + * + */ +typedef void (*XEmacPss_Handler) (void *CallBackRef); + +/** + * Callback when an asynchronous error occurs. To set this callback, invoke + * XEmacPss_SetHandler() with XEMACPSS_HANDLER_ERROR in the HandlerType + * paramter. + * + * @param CallBackRef is user data assigned when the callback was set. + * @param Direction defines either receive or transmit error(s) has occurred. + * @param ErrorWord definition varies with Direction + * + */ +typedef void (*XEmacPss_ErrHandler) (void *CallBackRef, u8 Direction, + u32 ErrorWord); + +/*@}*/ + +/** + * This typedef contains configuration information for a device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress;/**< Physical base address of IPIF registers */ +} XEmacPss_Config; + + +/** + * The XEmacPss driver instance data. The user is required to allocate a + * structure of this type for every XEmacPss device in the system. A pointer + * to a structure of this type is then passed to the driver API functions. + */ +typedef struct XEmacPss { + XEmacPss_Config Config; /* Hardware configuration */ + u32 IsStarted; /* Device is currently started */ + u32 IsReady; /* Device is initialized and ready */ + u32 Options; /* Current options word */ + + XEmacPss_BdRing TxBdRing; /* Transmit BD ring */ + XEmacPss_BdRing RxBdRing; /* Receive BD ring */ + + XEmacPss_Handler SendHandler; + XEmacPss_Handler RecvHandler; + void *SendRef; + void *RecvRef; + + XEmacPss_ErrHandler ErrorHandler; + void *ErrorRef; + +} XEmacPss; + + +/***************** Macros (Inline Functions) Definitions ********************/ + +/****************************************************************************/ +/** +* Retrieve the Tx ring object. This object can be used in the various Ring +* API functions. +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return TxBdRing attribute +* +* @note +* C-style signature: +* XEmacPss_BdRing XEmacPss_GetTxRing(XEmacPss *InstancePtr) +* +*****************************************************************************/ +#define XEmacPss_GetTxRing(InstancePtr) ((InstancePtr)->TxBdRing) + +/****************************************************************************/ +/** +* Retrieve the Rx ring object. This object can be used in the various Ring +* API functions. +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return RxBdRing attribute +* +* @note +* C-style signature: +* XEmacPss_BdRing XEmacPss_GetRxRing(XEmacPss *InstancePtr) +* +*****************************************************************************/ +#define XEmacPss_GetRxRing(InstancePtr) ((InstancePtr)->RxBdRing) + +/****************************************************************************/ +/** +* +* Enable interrupts specified in Mask. The corresponding interrupt for +* each bit set to 1 in Mask, will be enabled. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Mask contains a bit mask of interrupts to enable. The mask can +* be formed using a set of bitwise or'd values. +* +* @note +* The state of the transmitter and receiver are not modified by this function. +* C-style signature +* void XEmacPss_IntEnable(XEmacPss *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XEmacPss_IntEnable(InstancePtr, Mask) \ + XEmacPss_WriteReg((InstancePtr)->Config.BaseAddress, \ + XEMACPSS_IER_OFFSET, \ + XEmacPss_ReadReg((InstancePtr)->Config.BaseAddress, \ + XEMACPSS_IER_OFFSET) | ((Mask) & XEMACPSS_IXR_ALL_MASK)); + +/****************************************************************************/ +/** +* +* Disable interrupts specified in Mask. The corresponding interrupt for +* each bit set to 1 in Mask, will be enabled. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Mask contains a bit mask of interrupts to disable. The mask can +* be formed using a set of bitwise or'd values. +* +* @note +* The state of the transmitter and receiver are not modified by this function. +* C-style signature +* void XEmacPss_IntDisable(XEmacPss *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XEmacPss_IntDisable(InstancePtr, Mask) \ + XEmacPss_WriteReg((InstancePtr)->Config.BaseAddress, \ + XEMACPSS_IER_OFFSET, \ + XEmacPss_ReadReg((InstancePtr)->Config.BaseAddress, \ + XEMACPSS_IER_OFFSET) & ~((Mask) & XEMACPSS_IXR_ALL_MASK)); + +/****************************************************************************/ +/** +* +* This macro triggers trasmit circuit to send data currently in TX buffer(s). +* +* @param InstancePtr is a pointer to the XEmacPss instance to be worked on. +* +* @return +* +* @note +* +* Signature: void XEmacPss_Transmit(XEmacPss *InstancePtr) +* +*****************************************************************************/ +#define XEmacPss_Transmit(InstancePtr) \ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, \ + XEMACPSS_NWCTRL_OFFSET, \ + (XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, \ + XEMACPSS_NWCTRL_OFFSET) | XEMACPSS_NWCTRL_STARTTX_MASK)) + +/****************************************************************************/ +/** +* +* This macro determines if the device is configured with checksum offloading +* on the receive channel +* +* @param InstancePtr is a pointer to the XEmacPss instance to be worked on. +* +* @return +* +* Boolean TRUE if the device is configured with checksum offloading, or +* FALSE otherwise. +* +* @note +* +* Signature: u32 XEmacPss_IsRxCsum(XEmacPss *InstancePtr) +* +*****************************************************************************/ +#define XEmacPss_IsRxCsum(InstancePtr) \ + ((XEmacPss_ReadReg((InstancePtr)->Config.BaseAddress, \ + XEMACPSS_NWCFG_OFFSET) & XEMACPSS_NWCFG_RXCHKSUMEN_MASK) \ + ? TRUE : FALSE) + +/****************************************************************************/ +/** +* +* This macro determines if the device is configured with checksum offloading +* on the transmit channel +* +* @param InstancePtr is a pointer to the XEmacPss instance to be worked on. +* +* @return +* +* Boolean TRUE if the device is configured with checksum offloading, or +* FALSE otherwise. +* +* @note +* +* Signature: u32 XEmacPss_IsTxCsum(XEmacPss *InstancePtr) +* +*****************************************************************************/ +#define XEmacPss_IsTxCsum(InstancePtr) \ + ((XEmacPss_ReadReg((InstancePtr)->Config.BaseAddress, \ + XEMACPSS_DMACR_OFFSET) & XEMACPSS_DMACR_TCPCKSUM_MASK) \ + ? TRUE : FALSE) + +/************************** Function Prototypes *****************************/ + +/* + * Initialization functions in zynq_gem.c + */ +int XEmacPss_CfgInitialize(XEmacPss *InstancePtr, XEmacPss_Config *CfgPtr, + u32 EffectiveAddress); +void XEmacPss_Start(XEmacPss *InstancePtr); +void XEmacPss_Stop(XEmacPss *InstancePtr); +void XEmacPss_Reset(XEmacPss *InstancePtr); + +/* + * Lookup configuration in zynq_gem_sinit.c + */ +XEmacPss_Config *XEmacPss_LookupConfig(u16 DeviceId); + +/* + * Interrupt-related functions in xemacps_intr.c + * DMA only and FIFO is not supported. This DMA does not support coalescing. + */ +int XEmacPss_SetHandler(XEmacPss *InstancePtr, u32 HandlerType, + void *FuncPtr, void *CallBackRef); +void XEmacPss_IntrHandler(void *InstancePtr); + +/* + * MAC configuration/control functions in zynq_gem_control.c + */ +int XEmacPss_SetOptions(XEmacPss *InstancePtr, u32 Options); +int XEmacPss_ClearOptions(XEmacPss *InstancePtr, u32 Options); +u32 XEmacPss_GetOptions(XEmacPss *InstancePtr); + +int XEmacPss_SetMacAddress(XEmacPss *InstancePtr, void *AddressPtr, u8 Index); +void XEmacPss_GetMacAddress(XEmacPss *InstancePtr, void *AddressPtr, u8 Index); + +int XEmacPss_SetHash(XEmacPss *InstancePtr, void *AddressPtr); +void XEmacPss_ClearHash(XEmacPss *InstancePtr); +void XEmacPss_GetHash(XEmacPss *InstancePtr, void *AddressPtr); + +void XEmacPss_PhySetMdioDivisor(XEmacPss *InstancePtr, + XEmacPss_MdcDiv Divisor); +void XEmacPss_SetOperatingSpeed(XEmacPss *InstancePtr, u16 Speed); +u16 XEmacPss_GetOperatingSpeed(XEmacPss *InstancePtr); +int XEmacPss_PhyRead(XEmacPss *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr); +int XEmacPss_PhyWrite(XEmacPss *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData); +int XEmacPss_SetTypeIdCheck(XEmacPss *InstancePtr, u32 Id_Check, u8 Index); + +int XEmacPss_SendPausePacket(XEmacPss *InstancePtr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/drivers/net/zynq_gem_bd.h b/drivers/net/zynq_gem_bd.h new file mode 100644 index 00000000000..c6e791d6aab --- /dev/null +++ b/drivers/net/zynq_gem_bd.h @@ -0,0 +1,696 @@ +/* + * (C) Copyright 2012 Xilinx + * + * This header provides operations to manage buffer descriptors in support + * of scatter-gather DMA. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef XEMACPSS_BD_H /* prevent circular inclusions */ +#define XEMACPSS_BD_H /* by using protection macros */ + +/* + * + * The API exported by this header defines abstracted macros that allow the + * user to read/write specific BD fields. + * + * Buffer Descriptors: + * + * A buffer descriptor (BD) defines a DMA transaction. The macros defined by + * this header file allow access to most fields within a BD to tailor a DMA + * transaction according to user and hardware requirements. See the hardware + * IP DMA spec for more information on BD fields and how they affect transfers. + * + * The XEmacPss_Bd structure defines a BD. The organization of this structure + * is driven mainly by the hardware for use in scatter-gather DMA transfers. + * + * Performance: + * + * Limiting I/O to BDs can improve overall performance of the DMA channel. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +//#include +//#include "xbasic_types.h" +#include +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/* Minimum BD alignment */ +#define XEMACPSS_DMABD_MINIMUM_ALIGNMENT 4 + +/** + * The XEmacPss_Bd is the type for buffer descriptors (BDs). + */ +#define XEMACPSS_BD_NUM_WORDS 2 +typedef u32 XEmacPss_Bd[XEMACPSS_BD_NUM_WORDS]; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** + * Zero out BD fields + * + * @param BdPtr is the BD pointer to operate on + * + * @return Nothing + * + * @note + * C-style signature: + * void XEmacPss_BdClear(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdClear(BdPtr) \ + memset((BdPtr), 0, sizeof(XEmacPss_Bd)) + +/****************************************************************************/ +/** +* +* Read the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to read +* @param Offset is the word offset to be read +* +* @return The 32-bit value of the field +* +* @note +* C-style signature: +* u32 XEmacPss_BdRead(u32 BaseAddress, u32 Offset) +* +*****************************************************************************/ +#define XEmacPss_BdRead(BaseAddress, Offset) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset))) + +/****************************************************************************/ +/** +* +* Write the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to write +* @param Offset is the word offset to be written +* @param Data is the 32-bit value to write to the field +* +* @return None. +* +* @note +* C-style signature: +* void XEmacPss_BdWrite(u32 BaseAddress, u32 Offset, u32 Data) +* +*****************************************************************************/ +#define XEmacPss_BdWrite(BaseAddress, Offset, Data) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset)) = (Data)) + +/*****************************************************************************/ +/** + * Set the BD's Address field (word 0). + * + * @param BdPtr is the BD pointer to operate on + * @param Addr is the value to write to BD's status field. + * + * @note : + * + * C-style signature: + * void XEmacPss_BdSetAddressTx(XEmacPss_Bd* BdPtr, u32 Addr) + * + *****************************************************************************/ +#define XEmacPss_BdSetAddressTx(BdPtr, Addr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_ADDR_OFFSET, (u32)(Addr))) + + +/*****************************************************************************/ +/** + * Set the BD's Address field (word 0). + * + * @param BdPtr is the BD pointer to operate on + * @param Data is the value to write to BD's status field. + * + * @note : Due to some bits are mixed within recevie BD's address field, + * read-modify-write is performed. + * + * C-style signature: + * void XEmacPss_BdSetAddressRx(XEmacPss_Bd* BdPtr, u32 Addr) + * + *****************************************************************************/ +#define XEmacPss_BdSetAddressRx(BdPtr, Addr) \ + XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_ADDR_OFFSET, \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_ADDR_OFFSET) & \ + ~XEMACPSS_RXBUF_ADD_MASK) | (u32)(Addr))) + + +/*****************************************************************************/ +/** + * Set the BD's Status field (word 1). + * + * @param BdPtr is the BD pointer to operate on + * @param Data is the value to write to BD's status field. + * + * @note + * C-style signature: + * void XEmacPss_BdSetStatus(XEmacPss_Bd* BdPtr, u32 Data) + * + *****************************************************************************/ +#define XEmacPss_BdSetStatus(BdPtr, Data) \ + XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) | Data) + + +/*****************************************************************************/ +/** + * Retrieve the BD's Packet DMA transfer status word (word 1). + * + * @param BdPtr is the BD pointer to operate on + * + * @return Status word + * + * @note + * C-style signature: + * u32 XEmacPss_BdGetStatus(XEmacPss_Bd* BdPtr) + * + * Due to the BD bit layout differences in transmit and receive. User's + * caution is required. + *****************************************************************************/ +#define XEmacPss_BdGetStatus(BdPtr) \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) + + +/*****************************************************************************/ +/** + * Get the address (bits 0..31) of the BD's buffer address (word 0) + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdGetBufAddr(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdGetBufAddr(BdPtr) \ + (XEmacPss_BdRead((BdPtr), XEMACPSS_BD_ADDR_OFFSET)) + + +/*****************************************************************************/ +/** + * Set transfer length in bytes for the given BD. The length must be set each + * time a BD is submitted to hardware. + * + * @param BdPtr is the BD pointer to operate on + * @param LenBytes is the number of bytes to transfer. + * + * @note + * C-style signature: + * void XEmacPss_BdSetLength(XEmacPss_Bd* BdPtr, u32 LenBytes) + * + *****************************************************************************/ +#define XEmacPss_BdSetLength(BdPtr, LenBytes) \ + XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + ~XEMACPSS_TXBUF_LEN_MASK) | (LenBytes))) + + +/*****************************************************************************/ +/** + * Retrieve the BD length field. + * + * For Tx channels, the returned value is the same as that written with + * XEmacPss_BdSetLength(). + * + * For Rx channels, the returned value is the size of the received packet. + * + * @param BdPtr is the BD pointer to operate on + * + * @return Length field processed by hardware or set by + * XEmacPss_BdSetLength(). + * + * @note + * C-style signature: + * u32 XEmacPss_BdGetLength(XEmacPss_Bd* BdPtr) + * XEAMCPSS_RXBUF_LEN_MASK is same as XEMACPSS_TXBUF_LEN_MASK. + * + *****************************************************************************/ +#define XEmacPss_BdGetLength(BdPtr) \ + (XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_LEN_MASK) + + +/*****************************************************************************/ +/** + * Test whether the given BD has been marked as the last BD of a packet. + * + * @param BdPtr is the BD pointer to operate on + * + * @return TRUE if BD represents the "Last" BD of a packet, FALSE otherwise + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsLast(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsLast(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_EOF_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Tell the DMA engine that the given transmit BD marks the end of the current + * packet to be processed. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPss_BdSetLast(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdSetLast(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) | \ + XEMACPSS_TXBUF_LAST_MASK)) + + +/*****************************************************************************/ +/** + * Tell the DMA engine that the current packet does not end with the given + * BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPss_BdClearLast(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdClearLast(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + ~XEMACPSS_TXBUF_LAST_MASK)) + + +/*****************************************************************************/ +/** + * Set this bit to mark the last descriptor in the receive buffer descriptor + * list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPss_BdSetRxWrap(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdSetRxWrap(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_ADDR_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_ADDR_OFFSET) | \ + XEMACPSS_RXBUF_WRAP_MASK)) + + +/*****************************************************************************/ +/** + * Determine the wrap bit of the receive BD which indicates end of the + * BD list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxWrap(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxWrap(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_ADDR_OFFSET) & \ + XEMACPSS_RXBUF_WRAP_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Sets this bit to mark the last descriptor in the transmit buffer + * descriptor list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPss_BdSetTxWrap(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdSetTxWrap(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) | \ + XEMACPSS_TXBUF_WRAP_MASK)) + + +/*****************************************************************************/ +/** + * Determine the wrap bit of the transmit BD which indicates end of the + * BD list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdGetTxWrap(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsTxWrap(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_TXBUF_WRAP_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/* + * Must clear this bit to enable the MAC to write data to the receive + * buffer. Hardware sets this bit once it has successfully written a frame to + * memory. Once set, software has to clear the bit before the buffer can be + * used again. This macro clear the new bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPss_BdClearRxNew(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdClearRxNew(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_ADDR_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_ADDR_OFFSET) & \ + ~XEMACPSS_RXBUF_NEW_MASK)) + + +/*****************************************************************************/ +/** + * Determine the new bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxNew(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxNew(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_ADDR_OFFSET) & \ + XEMACPSS_RXBUF_NEW_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Software sets this bit to disable the buffer to be read by the hardware. + * Hardware sets this bit for the first buffer of a frame once it has been + * successfully transmitted. This macro sets this bit of transmit BD to avoid + * confusion. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPss_BdSetTxUsed(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdSetTxUsed(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) | \ + XEMACPSS_TXBUF_USED_MASK)) + + +/*****************************************************************************/ +/** + * Software clears this bit to enable the buffer to be read by the hardware. + * Hardware sets this bit for the first buffer of a frame once it has been + * successfully transmitted. This macro clears this bit of transmit BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPss_BdClearTxUsed(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdClearTxUsed(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + ~XEMACPSS_TXBUF_USED_MASK)) + + +/*****************************************************************************/ +/** + * Determine the used bit of the transmit BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsTxUsed(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsTxUsed(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_TXBUF_USED_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if a frame fails to be transmitted due to too many retries. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsTxRetry(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsTxRetry(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_TXBUF_RETRY_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if a frame fails to be transmitted due to data can not be + * feteched in time or buffers are exhausted. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsTxUrun(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsTxUrun(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_TXBUF_URUN_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if a frame fails to be transmitted due to buffer is exhausted + * mid-frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsTxExh(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsTxExh(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_TXBUF_EXH_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Sets this bit, no CRC will be appended to the current frame. This control + * bit must be set for the first buffer in a frame and will be ignored for + * the subsequent buffers of a frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * This bit must be clear when using the transmit checksum generation offload, + * otherwise checksum generation and substitution will not occur. + * + * C-style signature: + * u32 XEmacPss_BdSetTxNoCRC(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdSetTxNoCRC(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) | \ + XEMACPSS_TXBUF_NOCRC_MASK)) + + +/*****************************************************************************/ +/** + * Clear this bit, CRC will be appended to the current frame. This control + * bit must be set for the first buffer in a frame and will be ignored for + * the subsequent buffers of a frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * This bit must be clear when using the transmit checksum generation offload, + * otherwise checksum generation and substitution will not occur. + * + * C-style signature: + * u32 XEmacPss_BdClearTxNoCRC(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdClearTxNoCRC(BdPtr) \ + (XEmacPss_BdWrite((BdPtr), XEMACPSS_BD_STAT_OFFSET, \ + XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + ~XEMACPSS_TXBUF_NOCRC_MASK)) + + +/*****************************************************************************/ +/** + * Determine the broadcast bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxBcast(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxBcast(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_BCAST_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the multicast hash bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxMultiHash(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxMultiHash(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_MULTIHASH_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the unicast hash bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxUniHash(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxUniHash(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_UNIHASH_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if the received frame is a VLAN Tagged frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxVlan(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxVlan(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_VLAN_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if the received frame has Type ID of 8100h and null VLAN + * identifier(Priority tag). + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxPri(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxPri(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_PRI_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if the received frame's Concatenation Format Indicator (CFI) of + * the frames VLANTCI field was set. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdIsRxCFI(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxCFI(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_CFI_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the End Of Frame (EOF) bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdGetRxEOF(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxEOF(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_EOF_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the Start Of Frame (SOF) bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPss_BdGetRxSOF(XEmacPss_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPss_BdIsRxSOF(BdPtr) \ + ((XEmacPss_BdRead((BdPtr), XEMACPSS_BD_STAT_OFFSET) & \ + XEMACPSS_RXBUF_SOF_MASK) ? TRUE : FALSE) + + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/drivers/net/zynq_gem_bdring.c b/drivers/net/zynq_gem_bdring.c new file mode 100644 index 00000000000..6e534fcabd2 --- /dev/null +++ b/drivers/net/zynq_gem_bdring.c @@ -0,0 +1,983 @@ +/* + * (C) Copyright 2012 Xilinx + * + * This file implements buffer descriptor ring related functions. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "xstatus.h" +//#include "xcache.h" +#include "zynq_gem_hw.h" +#include "zynq_gem_bd.h" +#include "zynq_gem_bdring.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/**************************************************************************** + * Define methods to flush and invalidate cache for BDs should they be + * located in cached memory. These macros may NOPs if the underlying + * XENV_BD_CACHE macros are not implemented or they do nothing. + * + * @note Assume cache line size is in word length. Please update accordingly + * for different system. + ****************************************************************************/ +//#define XENV_BD_CACHE_FLUSH +//#define XENV_BD_CACHE_INVALIDATE + +#ifdef XENV_BD_CACHE_FLUSH +# define XEMACPSS_CACHE_FLUSH(BdPtr) \ + XCache_FlushDCacheRange((unsigned)BdPtr, XEMACPSS_BD_NUM_WORDS * 4) +#else +# define XEMACPSS_CACHE_FLUSH(BdPtr) +#endif + +#ifdef XENV_BD_CACHE_INVALIDATE +# define XEMACPSS_CACHE_INVALIDATE(BdPtr) \ + XCache_InvalidateDCacheRange((unsigned)BdPtr, XEMACPSS_BD_NUM_WORDS * 4) +#else +# define XEMACPSS_CACHE_INVALIDATE(BdPtr) +#endif + +/**************************************************************************** + * Compute the virtual address of a descriptor from its physical address + * + * @param BdPtr is the physical address of the BD + * + * @returns Virtual address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XEMACPSS_PHYS_TO_VIRT(BdPtr) \ + ((u32)BdPtr + (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr)) + +/**************************************************************************** + * Compute the physical address of a descriptor from its virtual address + * + * @param BdPtr is the physical address of the BD + * + * @returns Physical address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XEMACPSS_VIRT_TO_PHYS(BdPtr) \ + ((u32)BdPtr - (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr)) + +/**************************************************************************** + * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around + * to the beginning of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is greater than + * the high address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XEMACPSS_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)BdPtr; \ + \ + Addr += ((RingPtr)->Separation * NumBd); \ + if ((Addr > (RingPtr)->HighBdAddr) || ((u32)BdPtr > Addr)) \ + { \ + Addr -= (RingPtr)->Length; \ + } \ + \ + BdPtr = (XEmacPss_Bd*)Addr; \ + } + +/**************************************************************************** + * Move the BdPtr argument backwards an arbitrary number of BDs wrapping + * around to the end of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is less than + * the base address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XEMACPSS_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)BdPtr; \ + \ + Addr -= ((RingPtr)->Separation * NumBd); \ + if ((Addr < (RingPtr)->BaseBdAddr) || ((u32)BdPtr < Addr)) \ + { \ + Addr += (RingPtr)->Length; \ + } \ + \ + BdPtr = (XEmacPss_Bd*)Addr; \ + } + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** + * Using a memory segment allocated by the caller, create and setup the BD list + * for the given DMA channel. + * + * @param RingPtr is the instance to be worked on. + * @param PhysAddr is the physical base address of user memory region. + * @param VirtAddr is the virtual base address of the user memory region. If + * address translation is not being utilized, then VirtAddr should be + * equivalent to PhysAddr. + * @param Alignment governs the byte alignment of individual BDs. This function + * will enforce a minimum alignment of 4 bytes with no maximum as long + * as it is specified as a power of 2. + * @param BdCount is the number of BDs to setup in the user memory region. It + * is assumed the region is large enough to contain the BDs. + * + * @return + * + * - XST_SUCCESS if initialization was successful + * - XST_NO_FEATURE if the provided instance is a non DMA type + * channel. + * - XST_INVALID_PARAM under any of the following conditions: + * 1) PhysAddr and/or VirtAddr are not aligned to the given Alignment + * parameter; + * 2) Alignment parameter does not meet minimum requirements or is not a + * power of 2 value; + * 3) BdCount is 0. + * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans + * over address 0x00000000 in virtual address space. + * + * @note + * Make sure to pass in the right alignment value. + *****************************************************************************/ +int XEmacPss_BdRingCreate(XEmacPss_BdRing * RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, unsigned BdCount) +{ + unsigned i; + u32 BdVirtAddr; + u32 BdPhyAddr; + + /* In case there is a failure prior to creating list, make sure the + * following attributes are 0 to prevent calls to other functions + * from doing anything. + */ + RingPtr->AllCnt = 0; + RingPtr->FreeCnt = 0; + RingPtr->HwCnt = 0; + RingPtr->PreCnt = 0; + RingPtr->PostCnt = 0; + + /* Make sure Alignment parameter meets minimum requirements */ + if (Alignment < XEMACPSS_DMABD_MINIMUM_ALIGNMENT) { + return (XST_INVALID_PARAM); + } + + /* Make sure Alignment is a power of 2 */ + if ((Alignment - 1) & Alignment) { + return (XST_INVALID_PARAM); + } + + /* Make sure PhysAddr and VirtAddr are on same Alignment */ + if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) { + return (XST_INVALID_PARAM); + } + + /* Is BdCount reasonable? */ + if (BdCount == 0) { + return (XST_INVALID_PARAM); + } + + /* Figure out how many bytes will be between the start of adjacent BDs */ + RingPtr->Separation = + (sizeof(XEmacPss_Bd) + (Alignment - 1)) & ~(Alignment - 1); + + /* Must make sure the ring doesn't span address 0x00000000. If it does, + * then the next/prev BD traversal macros will fail. + */ + if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Initial ring setup: + * - Clear the entire space + * - Setup each BD's BDA field with the physical address of the next BD + */ + memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount)); + + BdVirtAddr = VirtAddr; + BdPhyAddr = PhysAddr + RingPtr->Separation; + for (i = 1; i < BdCount; i++) { + XEMACPSS_CACHE_FLUSH(BdVirtAddr); + BdVirtAddr += RingPtr->Separation; + BdPhyAddr += RingPtr->Separation; + } + + /* Setup and initialize pointers and counters */ + RingPtr->RunState = XST_DMA_SG_IS_STOPPED; + RingPtr->BaseBdAddr = VirtAddr; + RingPtr->PhysBaseAddr = PhysAddr; + RingPtr->HighBdAddr = BdVirtAddr; + RingPtr->Length = + RingPtr->HighBdAddr - RingPtr->BaseBdAddr + RingPtr->Separation; + RingPtr->AllCnt = BdCount; + RingPtr->FreeCnt = BdCount; + RingPtr->FreeHead = (XEmacPss_Bd *) VirtAddr; + RingPtr->PreHead = (XEmacPss_Bd *) VirtAddr; + RingPtr->HwHead = (XEmacPss_Bd *) VirtAddr; + RingPtr->HwTail = (XEmacPss_Bd *) VirtAddr; + RingPtr->PostHead = (XEmacPss_Bd *) VirtAddr; + RingPtr->BdaRestart = (XEmacPss_Bd *) PhysAddr; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Clone the given BD into every BD in the list. + * every field of the source BD is replicated in every BD of the list. + * + * This function can be called only when all BDs are in the free group such as + * they are immediately after initialization with XEmacPss_BdRingCreate(). + * This prevents modification of BDs while they are in use by hardware or the + * user. + * + * @param RingPtr is the pointer of BD ring instance to be worked on. + * @param SrcBdPtr is the source BD template to be cloned into the list. This + * BD will be modified. + * + * @return + * - XST_SUCCESS if the list was modified. + * - XST_DMA_SG_NO_LIST if a list has not been created. + * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under + * hardware or user control. + * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped. + * + *****************************************************************************/ +int XEmacPss_BdRingClone(XEmacPss_BdRing * RingPtr, XEmacPss_Bd * SrcBdPtr, + u8 Direction) +{ + unsigned i; + u32 CurBd; + + /* Can't do this function if there isn't a ring */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't do this function with the channel running */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Can't do this function with some of the BDs in use */ + if (RingPtr->FreeCnt != RingPtr->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + if ((Direction != XEMACPSS_SEND) && (Direction != XEMACPSS_RECV)) { + return (XST_INVALID_PARAM); + } + + /* Starting from the top of the ring, save BD.Next, overwrite the entire + * BD with the template, then restore BD.Next + */ + for (i = 0, CurBd = (u32) RingPtr->BaseBdAddr; + i < RingPtr->AllCnt; i++, CurBd += RingPtr->Separation) { + memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPss_Bd)); + XEMACPSS_CACHE_FLUSH(CurBd); + } + + CurBd -= RingPtr->Separation; + + if (Direction == XEMACPSS_RECV) { + XEmacPss_BdSetRxWrap(CurBd); + } + else { + XEmacPss_BdSetTxWrap(CurBd); + } + + XEMACPSS_CACHE_FLUSH(CurBd); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Reserve locations in the BD list. The set of returned BDs may be modified + * in preparation for future DMA transaction(s). Once the BDs are ready to be + * submitted to hardware, the user must call XEmacPss_BdRingToHw() in the same + * order which they were allocated here. Example: + * + *
+ *        NumBd = 2;
+ *        Status = XEmacPss_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet);
+ *
+ *        if (Status != XST_SUCCESS)
+ *        {
+ *            // Not enough BDs available for the request
+ *        }
+ *
+ *        CurBd = MyBdSet;
+ *        for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be allocated and given to hardware in the correct sequence:
+ * 
+ *        // Legal
+ *        XEmacPss_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XEmacPss_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPss_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ *        XEmacPss_BdRingToHw(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XEmacPss_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPss_BdRingToHw(MyRingPtr, NumBd2, MySet2);
+ *        XEmacPss_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * Use the API defined in zynq_gem_bd.h to modify individual BDs. Traversal + * of the BD set can be done using XEmacPss_BdRingNext() and + * XEmacPss_BdRingPrev(). + * + * @param RingPtr is a pointer to the BD ring instance to be worked on. + * @param NumBd is the number of BDs to allocate + * @param BdSetPtr is an output parameter, it points to the first BD available + * for modification. + * + * @return + * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr + * parameter. + * - XST_FAILURE if there were not enough free BDs to satisfy the request. + * + * @note This function should not be preempted by another XEmacPss_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + * @note Do not modify more BDs than the number requested with the NumBd + * parameter. Doing so will lead to data corruption and system + * instability. + * + *****************************************************************************/ +int XEmacPss_BdRingAlloc(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd ** BdSetPtr) +{ + /* Enough free BDs available for the request? */ + if (RingPtr->FreeCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead forward */ + *BdSetPtr = RingPtr->FreeHead; + XEMACPSS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd); + RingPtr->FreeCnt -= NumBd; + RingPtr->PreCnt += NumBd; + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * Fully or partially undo an XEmacPss_BdRingAlloc() operation. Use this + * function if all the BDs allocated by XEmacPss_BdRingAlloc() could not be + * transferred to hardware with XEmacPss_BdRingToHw(). + * + * This function helps out in situations when an unrelated error occurs after + * BDs have been allocated but before they have been given to hardware. + * An example of this type of error would be an OS running out of resources. + * + * This function is not the same as XEmacPss_BdRingFree(). The Free function + * returns BDs to the free list after they have been processed by hardware, + * while UnAlloc returns them before being processed by hardware. + * + * There are two scenarios where this function can be used. Full UnAlloc or + * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned: + * + *
+ *    Status = XEmacPss_BdRingAlloc(MyRingPtr, 10, &BdPtr);
+ *        .
+ *        .
+ *    if (Error)
+ *    {
+ *        Status = XEmacPss_BdRingUnAlloc(MyRingPtr, 10, &BdPtr);
+ *    }
+ * 
+ * + * A partial UnAlloc means some of the BDs Alloc'd will be returned: + * + *
+ *    Status = XEmacPss_BdRingAlloc(MyRingPtr, 10, &BdPtr);
+ *    BdsLeft = 10;
+ *    CurBdPtr = BdPtr;
+ *
+ *    while (BdsLeft)
+ *    {
+ *       if (Error)
+ *       {
+ *          Status = XEmacPss_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr);
+ *       }
+ *
+ *       CurBdPtr = XEmacPss_BdRingNext(MyRingPtr, CurBdPtr);
+ *       BdsLeft--;
+ *    }
+ * 
+ * + * A partial UnAlloc must include the last BD in the list that was Alloc'd. + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs to allocate + * @param BdSetPtr is an output parameter, it points to the first BD available + * for modification. + * + * @return + * - XST_SUCCESS if the BDs were unallocated. + * - XST_FAILURE if NumBd parameter was greater that the number of BDs in + * the preprocessing state. + * + * @note This function should not be preempted by another XEmacPss_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPss_BdRingUnAlloc(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd * BdSetPtr) +{ + /* Enough BDs in the free state for the request? */ + if (RingPtr->PreCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead backward */ + XEMACPSS_RING_SEEKBACK(RingPtr, RingPtr->FreeHead, NumBd); + RingPtr->FreeCnt += NumBd; + RingPtr->PreCnt -= NumBd; + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Enqueue a set of BDs to hardware that were previously allocated by + * XEmacPss_BdRingAlloc(). Once this function returns, the argument BD set goes + * under hardware control. Any changes made to these BDs after this point will + * corrupt the BD list leading to data corruption and system instability. + * + * The set will be rejected if the last BD of the set does not mark the end of + * a packet (see XEmacPss_BdSetLast()). + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs in the set. + * @param BdSetPtr is the first BD of the set to commit to hardware. + * + * @return + * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware. + * - XST_FAILURE if the set of BDs was rejected because the last BD of the set + * did not have its "last" bit set. + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XEmacPss_BdRingAlloc(). + * + * @note This function should not be preempted by another XEmacPss_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPss_BdRingToHw(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd * BdSetPtr) +{ + XEmacPss_Bd *CurBdPtr; + unsigned i; + + /* if no bds to process, simply return. */ + if (0 == NumBd) + return (XST_SUCCESS); + + /* Make sure we are in sync with XEmacPss_BdRingAlloc() */ + if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + CurBdPtr = BdSetPtr; + for (i = 0; i < NumBd; i++) { + XEMACPSS_CACHE_FLUSH(CurBdPtr); + CurBdPtr = XEmacPss_BdRingNext(RingPtr, CurBdPtr); + } + + /* Adjust ring pointers & counters */ + XEMACPSS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); + RingPtr->PreCnt -= NumBd; + + RingPtr->HwTail = CurBdPtr; + RingPtr->HwCnt += NumBd; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Returns a set of BD(s) that have been processed by hardware. The returned + * BDs may be examined to determine the outcome of the DMA transaction(s). + * Once the BDs have been examined, the user must call XEmacPss_BdRingFree() + * in the same order which they were retrieved here. Example: + * + *
+ *        NumBd = XEmacPss_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet);
+ *
+ *        if (NumBd == 0)
+ *        {
+ *           // hardware has nothing ready for us yet
+ *        }
+ *
+ *        CurBd = MyBdSet;
+ *        for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be retrieved from hardware and freed in the correct sequence:
+ * 
+ *        // Legal
+ *        XEmacPss_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XEmacPss_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XEmacPss_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * If hardware has only partially completed a packet spanning multiple BDs, + * then none of the BDs for that packet will be included in the results. + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param BdLimit is the maximum number of BDs to return in the set. + * @param BdSetPtr is an output parameter, it points to the first BD available + * for examination. + * + * @return + * The number of BDs processed by hardware. A value of 0 indicates that no + * data is available. No more than BdLimit BDs will be returned. + * + * @note Treat BDs returned by this function as read-only. + * + * @note This function should not be preempted by another XEmacPss_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +unsigned XEmacPss_BdRingFromHwTx(XEmacPss_BdRing * RingPtr, unsigned BdLimit, + XEmacPss_Bd ** BdSetPtr) +{ + XEmacPss_Bd *CurBdPtr; + u32 BdStr = 0; + unsigned BdCount; + unsigned BdPartialCount; + + CurBdPtr = RingPtr->HwHead; + BdCount = 0; + BdPartialCount = 0; + + /* If no BDs in work group, then there's nothing to search */ + if (RingPtr->HwCnt == 0) { + *BdSetPtr = NULL; + return (0); + } + + /* Starting at HwHead, keep moving forward in the list until: + * - A BD is encountered with its new/used bit set which means + * hardware has not completed processing of that BD. + * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached. + * - The number of requested BDs has been processed + */ + while (BdCount < BdLimit) { + /* Read the status */ + XEMACPSS_CACHE_INVALIDATE(CurBdPtr); + BdStr = XEmacPss_BdRead(CurBdPtr, XEMACPSS_BD_STAT_OFFSET); + + BdCount++; + + /* hardware has processed this BD so check the "last" bit. If + * it is clear, then there are more BDs for the current packet. + * Keep a count of these partial packet BDs. + */ + if (BdStr & XEMACPSS_TXBUF_LAST_MASK) { + BdPartialCount = 0; + } + else { + BdPartialCount++; + } + + /* Reached the end of the work group */ + if (CurBdPtr == RingPtr->HwTail) { + break; + } + + /* Move on to next BD in work group */ + CurBdPtr = XEmacPss_BdRingNext(RingPtr, CurBdPtr); + } + + /* Subtract off any partial packet BDs found */ + BdCount -= BdPartialCount; + + /* If BdCount is non-zero then BDs were found to return. Set return + * parameters, update pointers and counters, return success + */ + if (BdCount > 0) { + *BdSetPtr = RingPtr->HwHead; + RingPtr->HwCnt -= BdCount; + RingPtr->PostCnt += BdCount; + XEMACPSS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); + return (BdCount); + } + else { + *BdSetPtr = NULL; + return (0); + } +} + + +/*****************************************************************************/ +/** + * Returns a set of BD(s) that have been processed by hardware. The returned + * BDs may be examined to determine the outcome of the DMA transaction(s). + * Once the BDs have been examined, the user must call XEmacPss_BdRingFree() + * in the same order which they were retrieved here. Example: + * + *
+ *        NumBd = XEmacPss_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet);
+ *
+ *        if (NumBd == 0)
+ *        {
+ *           // hardware has nothing ready for us yet
+ *        }
+ *
+ *        CurBd = MyBdSet;
+ *        for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be retrieved from hardware and freed in the correct sequence:
+ * 
+ *        // Legal
+ *        XEmacPss_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XEmacPss_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XEmacPss_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPss_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *        XEmacPss_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * If hardware has only partially completed a packet spanning multiple BDs, + * then none of the BDs for that packet will be included in the results. + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param BdLimit is the maximum number of BDs to return in the set. + * @param BdSetPtr is an output parameter, it points to the first BD available + * for examination. + * + * @return + * The number of BDs processed by hardware. A value of 0 indicates that no + * data is available. No more than BdLimit BDs will be returned. + * + * @note Treat BDs returned by this function as read-only. + * + * @note This function should not be preempted by another XEmacPss_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +unsigned XEmacPss_BdRingFromHwRx(XEmacPss_BdRing * RingPtr, unsigned BdLimit, + XEmacPss_Bd ** BdSetPtr) +{ + XEmacPss_Bd *CurBdPtr; + u32 BdStr = 0; + unsigned BdCount; + unsigned BdPartialCount; + + CurBdPtr = RingPtr->HwHead; + BdCount = 0; + BdPartialCount = 0; + + /* If no BDs in work group, then there's nothing to search */ + if (RingPtr->HwCnt == 0) { + *BdSetPtr = NULL; + return (0); + } + + /* Starting at HwHead, keep moving forward in the list until: + * - A BD is encountered with its new/used bit set which means + * hardware has completed processing of that BD. + * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached. + * - The number of requested BDs has been processed + */ + while (BdCount < BdLimit) { + /* Read the status */ + XEMACPSS_CACHE_INVALIDATE(CurBdPtr); + BdStr = XEmacPss_BdRead(CurBdPtr, XEMACPSS_BD_STAT_OFFSET); + + if (!(XEmacPss_BdIsRxNew(CurBdPtr))) { + break; + } + + BdCount++; + + /* hardware has processed this BD so check the "last" bit. If + * it is clear, then there are more BDs for the current packet. + * Keep a count of these partial packet BDs. + */ + if (BdStr & XEMACPSS_RXBUF_EOF_MASK) { + BdPartialCount = 0; + } + else { + BdPartialCount++; + } + + /* Reached the end of the work group */ + if (CurBdPtr == RingPtr->HwTail) { + break; + } + + /* Move on to next BD in work group */ + CurBdPtr = XEmacPss_BdRingNext(RingPtr, CurBdPtr); + } + + /* Subtract off any partial packet BDs found */ + BdCount -= BdPartialCount; + + /* If BdCount is non-zero then BDs were found to return. Set return + * parameters, update pointers and counters, return success + */ + if (BdCount > 0) { + *BdSetPtr = RingPtr->HwHead; + RingPtr->HwCnt -= BdCount; + RingPtr->PostCnt += BdCount; + XEMACPSS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); + return (BdCount); + } + else { + *BdSetPtr = NULL; + return (0); + } +} + + +/*****************************************************************************/ +/** + * Frees a set of BDs that had been previously retrieved with + * XEmacPss_BdRingFromHw(). + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs to free. + * @param BdSetPtr is the head of a list of BDs returned by + * XEmacPss_BdRingFromHw(). + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XEmacPss_BdRingFromHw(). + * + * @note This function should not be preempted by another XEmacPss_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPss_BdRingFree(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd * BdSetPtr) +{ + /* if no bds to process, simply return. */ + if (0 == NumBd) + return (XST_SUCCESS); + + /* Make sure we are in sync with XEmacPss_BdRingFromHw() */ + if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Update pointers and counters */ + RingPtr->FreeCnt += NumBd; + RingPtr->PostCnt -= NumBd; + XEMACPSS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Check the internal data structures of the BD ring for the provided channel. + * The following checks are made: + * + * - Is the BD ring linked correctly in physical address space. + * - Do the internal pointers point to BDs in the ring. + * - Do the internal counters add up. + * + * The channel should be stopped prior to calling this function. + * + * @param RingPtr is a pointer to the instance to be worked on. + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_DMA_SG_NO_LIST if the list has not been created. + * - XST_IS_STARTED if the channel is not stopped. + * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data + * structures. If this value is returned, the channel should be reset to + * avoid data corruption or system instability. + * + * @note This function should not be preempted by another XEmacPss_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPss_BdRingCheck(XEmacPss_BdRing * RingPtr, u8 Direction) +{ + u32 AddrV, AddrP; + unsigned i; + + if ((Direction != XEMACPSS_SEND) && (Direction != XEMACPSS_RECV)) { + return (XST_INVALID_PARAM); + } + + /* Is the list created */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't check if channel is running */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_IS_STARTED); + } + + /* RunState doesn't make sense */ + else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal pointers point to correct memory space */ + AddrV = (u32) RingPtr->FreeHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PreHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwTail; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PostHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal counters add up */ + if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt + + RingPtr->PostCnt) != RingPtr->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify BDs are linked correctly */ + AddrV = RingPtr->BaseBdAddr; + AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation; + + for (i = 1; i < RingPtr->AllCnt; i++) { + /* Check BDA for this BD. It should point to next physical addr */ + if (XEmacPss_BdRead(AddrV, XEMACPSS_BD_ADDR_OFFSET) != AddrP) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Move on to next BD */ + AddrV += RingPtr->Separation; + AddrP += RingPtr->Separation; + } + + /* Last BD should have wrap bit set */ + if (XEMACPSS_SEND == Direction) { + if (!XEmacPss_BdIsTxWrap(AddrV)) { + return (XST_DMA_SG_LIST_ERROR); + } + } + else { /* XEMACPSS_RECV */ + if (!XEmacPss_BdIsRxWrap(AddrV)) { + return (XST_DMA_SG_LIST_ERROR); + } + } + + /* No problems found */ + return (XST_SUCCESS); +} diff --git a/drivers/net/zynq_gem_bdring.h b/drivers/net/zynq_gem_bdring.h new file mode 100644 index 00000000000..72d52002eef --- /dev/null +++ b/drivers/net/zynq_gem_bdring.h @@ -0,0 +1,195 @@ +/* + * (C) Copyright 2012 Xilinx + * + * The Xiline EmacPss Buffer Descriptor ring driver. This is part of EmacPss + * DMA functionalities. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef XEMACPSS_BDRING_H /* prevent curcular inclusions */ +#define XEMACPSS_BDRING_H /* by using protection macros */ + +/**************************** Type Definitions *******************************/ + +/** This is an internal structure used to maintain the DMA list */ +typedef struct { + u32 PhysBaseAddr;/**< Physical address of 1st BD in list */ + u32 BaseBdAddr; /**< Virtual address of 1st BD in list */ + u32 HighBdAddr; /**< Virtual address of last BD in the list */ + u32 Length; /**< Total size of ring in bytes */ + u32 RunState; /**< Flag to indicate DMA is started */ + u32 Separation; /**< Number of bytes between the starting address + of adjacent BDs */ + XEmacPss_Bd *RxBD_start; /**< First BD in the Rx queue*/ + int RxBD_current; /**< Index to the current BD*/ + int RxBD_end; /**< Index to the last BD*/ + int Rx_first_buf; /**< Index to the first BD*/ + XEmacPss_Bd *FreeHead; + /**< First BD in the free group */ + XEmacPss_Bd *PreHead;/**< First BD in the pre-work group */ + XEmacPss_Bd *HwHead; /**< First BD in the work group */ + XEmacPss_Bd *HwTail; /**< Last BD in the work group */ + XEmacPss_Bd *PostHead; + /**< First BD in the post-work group */ + XEmacPss_Bd *BdaRestart; + /**< BDA to load when channel is started */ + unsigned HwCnt; /**< Number of BDs in work group */ + unsigned PreCnt; /**< Number of BDs in pre-work group */ + unsigned FreeCnt; /**< Number of allocatable BDs in the free group */ + unsigned PostCnt; /**< Number of BDs in post-work group */ + unsigned AllCnt; /**< Total Number of BDs for channel */ +} XEmacPss_BdRing; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many BDs will fit +* in a BD list within the given memory constraints. +* +* The results of this macro can be provided to XEmacPss_BdRingCreate(). +* +* @param Alignment specifies what byte alignment the BDs must fall on and +* must be a power of 2 to get an accurate calculation (32, 64, 128,...) +* @param Bytes is the number of bytes to be used to store BDs. +* +* @return Number of BDs that can fit in the given memory area +* +* @note +* C-style signature: +* u32 XEmacPss_BdRingCntCalc(u32 Alignment, u32 Bytes) +* +******************************************************************************/ +#define XEmacPss_BdRingCntCalc(Alignment, Bytes) \ + (u32)((Bytes) / ((sizeof(XEmacPss_Bd) + ((Alignment)-1)) & \ + ~((Alignment)-1))) + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many bytes of memory +* is required to contain a given number of BDs at a given alignment. +* +* @param Alignment specifies what byte alignment the BDs must fall on. This +* parameter must be a power of 2 to get an accurate calculation (32, 64, +* 128,...) +* @param NumBd is the number of BDs to calculate memory size requirements for +* +* @return The number of bytes of memory required to create a BD list with the +* given memory constraints. +* +* @note +* C-style signature: +* u32 XEmacPss_BdRingMemCalc(u32 Alignment, u32 NumBd) +* +******************************************************************************/ +#define XEmacPss_BdRingMemCalc(Alignment, NumBd) \ + (u32)((sizeof(XEmacPss_Bd) + ((Alignment)-1)) & \ + ~((Alignment)-1)) * (NumBd) + +/****************************************************************************/ +/** +* Return the total number of BDs allocated by this channel with +* XEmacPss_BdRingCreate(). +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return The total number of BDs allocated for this channel. +* +* @note +* C-style signature: +* u32 XEmacPss_BdRingGetCnt(XEmacPss_BdRing* RingPtr) +* +*****************************************************************************/ +#define XEmacPss_BdRingGetCnt(RingPtr) ((RingPtr)->AllCnt) + +/****************************************************************************/ +/** +* Return the number of BDs allocatable with XEmacPss_BdRingAlloc() for pre- +* processing. +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return The number of BDs currently allocatable. +* +* @note +* C-style signature: +* u32 XEmacPss_BdRingGetFreeCnt(XEmacPss_BdRing* RingPtr) +* +*****************************************************************************/ +#define XEmacPss_BdRingGetFreeCnt(RingPtr) ((RingPtr)->FreeCnt) + +/****************************************************************************/ +/** +* Return the next BD from BdPtr in a list. +* +* @param InstancePtr is the DMA channel to operate on. +* @param BdPtr is the BD to operate on. +* +* @return The next BD in the list relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XEmacPss_Bd *XEmacPss_BdRingNext(XEmacPss_BdRing* RingPtr, +* XEmacPss_Bd *BdPtr) +* +*****************************************************************************/ +#define XEmacPss_BdRingNext(RingPtr, BdPtr) \ + (((u32)(BdPtr) >= (RingPtr)->HighBdAddr) ? \ + (XEmacPss_Bd*)(RingPtr)->BaseBdAddr : \ + (XEmacPss_Bd*)((u32)(BdPtr) + (RingPtr)->Separation)) + +/****************************************************************************/ +/** +* Return the previous BD from BdPtr in the list. +* +* @param InstancePtr is the DMA channel to operate on. +* @param BdPtr is the BD to operate on +* +* @return The previous BD in the list relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XEmacPss_Bd *XEmacPss_BdRingPrev(XEmacPss_BdRing* RingPtr, +* XEmacPss_Bd *BdPtr) +* +*****************************************************************************/ +#define XEmacPss_BdRingPrev(RingPtr, BdPtr) \ + (((u32)(BdPtr) <= (RingPtr)->BaseBdAddr) ? \ + (XEmacPss_Bd*)(RingPtr)->HighBdAddr : \ + (XEmacPss_Bd*)((u32)(BdPtr) - (RingPtr)->Separation)) + +/************************** Function Prototypes ******************************/ + +/* + * Scatter gather DMA related functions in zynq_gem_bdring.c + */ +int XEmacPss_BdRingCreate(XEmacPss_BdRing * RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, unsigned BdCount); +int XEmacPss_BdRingClone(XEmacPss_BdRing * RingPtr, XEmacPss_Bd * SrcBdPtr, + u8 Direction); +int XEmacPss_BdRingAlloc(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd ** BdSetPtr); +int XEmacPss_BdRingUnAlloc(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd * BdSetPtr); +int XEmacPss_BdRingToHw(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd * BdSetPtr); +int XEmacPss_BdRingFree(XEmacPss_BdRing * RingPtr, unsigned NumBd, + XEmacPss_Bd * BdSetPtr); +unsigned XEmacPss_BdRingFromHwTx(XEmacPss_BdRing * RingPtr, unsigned BdLimit, + XEmacPss_Bd ** BdSetPtr); +unsigned XEmacPss_BdRingFromHwRx(XEmacPss_BdRing * RingPtr, unsigned BdLimit, + XEmacPss_Bd ** BdSetPtr); +int XEmacPss_BdRingCheck(XEmacPss_BdRing * RingPtr, u8 Direction); + + +#endif /* end of protection macros */ diff --git a/drivers/net/zynq_gem_control.c b/drivers/net/zynq_gem_control.c new file mode 100644 index 00000000000..d7612ad7956 --- /dev/null +++ b/drivers/net/zynq_gem_control.c @@ -0,0 +1,924 @@ +/* + * (C) Copyright 2012 Xilinx + * + * Functions in this file implement general purpose command and control related + * functionality. See zynq_gem.h for a detailed description of the driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/***************************** Include Files *********************************/ + +#include "zynq_gem.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** + * Set the MAC address for this driver/device. The address is a 48-bit value. + * The device must be stopped before calling this function. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is a pointer to a 6-byte MAC address. + * @param Index is a index to which MAC (1-4) address. + * + * @return + * - XST_SUCCESS if the MAC address was set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + *****************************************************************************/ +int XEmacPss_SetMacAddress(XEmacPss *InstancePtr, void *AddressPtr, u8 Index) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(AddressPtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_NONVOID((Index <= XEMACPSS_MAX_MAC_ADDR) && (Index > 0)); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ + Index--; + + /* Set the MAC bits [31:0] in BOT */ + MacAddr = Aptr[0]; + MacAddr |= Aptr[1] << 8; + MacAddr |= Aptr[2] << 16; + MacAddr |= Aptr[3] << 24; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + (XEMACPSS_LADDR1L_OFFSET + Index * 8), MacAddr); + + /* There are reserved bits in TOP so don't affect them */ + MacAddr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + (XEMACPSS_LADDR1H_OFFSET + (Index * 8))); + + MacAddr &= ~XEMACPSS_LADDR_MACH_MASK; + + /* Set MAC bits [47:32] in TOP */ + MacAddr |= Aptr[4]; + MacAddr |= Aptr[5] << 8; + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + (XEMACPSS_LADDR1H_OFFSET + (Index * 8)), MacAddr); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Get the MAC address for this driver/device. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is an output parameter, and is a pointer to a buffer into + * which the current MAC address will be copied. + * @param Index is a index to which MAC (1-4) address. + * + *****************************************************************************/ +void XEmacPss_GetMacAddress(XEmacPss *InstancePtr, void *AddressPtr, u8 Index) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(AddressPtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_VOID((Index <= XEMACPSS_MAX_MAC_ADDR) && (Index > 0)); + + /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ + Index--; + + MacAddr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + (XEMACPSS_LADDR1L_OFFSET + (Index * 8))); + Aptr[0] = (u8) MacAddr; + Aptr[1] = (u8) (MacAddr >> 8); + Aptr[2] = (u8) (MacAddr >> 16); + Aptr[3] = (u8) (MacAddr >> 24); + + /* Read MAC bits [47:32] in TOP */ + MacAddr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + (XEMACPSS_LADDR1H_OFFSET + (Index * 8))); + Aptr[4] = (u8) MacAddr; + Aptr[5] = (u8) (MacAddr >> 8); +} + + +/*****************************************************************************/ +/** + * Set 48-bit MAC addresses in hash table. + * The device must be stopped before calling this function. + * + * The hash address register is 64 bits long and takes up two locations in + * the memory map. The least significant bits are stored in hash register + * bottom and the most significant bits in hash register top. + * + * The unicast hash enable and the multicast hash enable bits in the network + * configuration register enable the reception of hash matched frames. The + * destination address is reduced to a 6 bit index into the 64 bit hash + * register using the following hash function. The hash function is an XOR + * of every sixth bit of the destination address. + * + *
+ * hash_index[05] = da[05]^da[11]^da[17]^da[23]^da[29]^da[35]^da[41]^da[47]
+ * hash_index[04] = da[04]^da[10]^da[16]^da[22]^da[28]^da[34]^da[40]^da[46]
+ * hash_index[03] = da[03]^da[09]^da[15]^da[21]^da[27]^da[33]^da[39]^da[45]
+ * hash_index[02] = da[02]^da[08]^da[14]^da[20]^da[26]^da[32]^da[38]^da[44]
+ * hash_index[01] = da[01]^da[07]^da[13]^da[19]^da[25]^da[31]^da[37]^da[43]
+ * hash_index[00] = da[00]^da[06]^da[12]^da[18]^da[24]^da[30]^da[36]^da[42]
+ * 
+ * + * da[0] represents the least significant bit of the first byte received, + * that is, the multicast/unicast indicator, and da[47] represents the most + * significant bit of the last byte received. + * + * If the hash index points to a bit that is set in the hash register then + * the frame will be matched according to whether the frame is multicast + * or unicast. + * + * A multicast match will be signaled if the multicast hash enable bit is + * set, da[0] is logic 1 and the hash index points to a bit set in the hash + * register. + * + * A unicast match will be signaled if the unicast hash enable bit is set, + * da[0] is logic 0 and the hash index points to a bit set in the hash + * register. + * + * To receive all multicast frames, the hash register should be set with + * all ones and the multicast hash enable bit should be set in the network + * configuration register. + * + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is a pointer to a 6-byte MAC address. + * + * @return + * - XST_SUCCESS if the HASH MAC address was set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * - XST_INVALID_PARAM if the HASH MAC address passed in does not meet + * requirement after calculation + * + * @note + * Having Aptr be unsigned type prevents the following operations from sign + * extending. + *****************************************************************************/ +int XEmacPss_SetHash(XEmacPss *InstancePtr, void *AddressPtr) +{ + u32 HashAddr; + u8 *Aptr = (u8 *) AddressPtr; + u8 Temp1, Temp2, Temp3, Temp4, Temp5, Temp6, Temp7, Temp8; + int Result; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(AddressPtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + Temp1 = Aptr[0] & 0x3F; + Temp2 = ((Aptr[0] >> 6) & 0x3) | ((Aptr[1] & 0xF) << 2); + Temp3 = ((Aptr[1] >> 4) & 0xF) | ((Aptr[2] & 0x3) << 4); + Temp4 = ((Aptr[2] >> 2) & 0x3F); + Temp5 = Aptr[3] & 0x3F; + Temp6 = ((Aptr[3] >> 6) & 0x3) | ((Aptr[4] & 0xF) << 2); + Temp7 = ((Aptr[4] >> 4) & 0xF) | ((Aptr[5] & 0x3) << 4); + Temp8 = ((Aptr[5] >> 2) & 0x3F); + + Result = Temp1 ^ Temp2 ^ Temp3 ^ Temp4 ^ Temp5 ^ Temp6 ^ Temp7 ^ Temp8; + + if (Result >= XEMACPSS_MAX_HASH_BITS) { + return (XST_INVALID_PARAM); + } + + if (Result < 32) { + HashAddr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHL_OFFSET); + HashAddr |= (1 << Result); + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHL_OFFSET, HashAddr); + } else { + HashAddr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHH_OFFSET); + HashAddr |= (1 << (Result - 32)); + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHH_OFFSET, HashAddr); + } + + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * Clear the Hash registers for the mac address pointed by AddressPtr. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + *****************************************************************************/ +void XEmacPss_ClearHash(XEmacPss *InstancePtr) +{ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHL_OFFSET, 0x0); + + /* write bits [63:32] in TOP */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHH_OFFSET, 0x0); +} + + +/*****************************************************************************/ +/** + * Get the Hash address for this driver/device. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is an output parameter, and is a pointer to a buffer into + * which the current HASH MAC address will be copied. + * + *****************************************************************************/ +void XEmacPss_GetHash(XEmacPss *InstancePtr, void *AddressPtr) +{ + u32 *Aptr = (u32 *) AddressPtr; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(AddressPtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + Aptr[0] = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHL_OFFSET); + + /* Read Hash bits [63:32] in TOP */ + Aptr[1] = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_HASHH_OFFSET); +} + + +/*****************************************************************************/ +/** + * Set the Type ID match for this driver/device. The register is a 32-bit + * value. The device must be stopped before calling this function. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Id_Check. + * @param Index is a index to which Type ID (1-4). + * + * @return + * - XST_SUCCESS if the MAC address was set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + *****************************************************************************/ +int XEmacPss_SetTypeIdCheck(XEmacPss *InstancePtr, u32 Id_Check, u8 Index) +{ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_NONVOID((Index <= XEMACPSS_MAX_TYPE_ID) && (Index > 0)); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ + Index--; + + /* Set the ID bits in MATCHx register */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + (XEMACPSS_MATCH1_OFFSET + (Index * 4)), Id_Check); + + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * Set options for the driver/device. The driver should be stopped with + * XEmacPss_Stop() before changing options. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Options are the options to set. Multiple options can be set by OR'ing + * XTE_*_OPTIONS constants together. Options not specified are not + * affected. + * + * @return + * - XST_SUCCESS if the options were set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + * @note + * See zynq_gem.h for a description of the available options. + * + *****************************************************************************/ +int XEmacPss_SetOptions(XEmacPss *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic register contents */ + u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */ + u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Many of these options will change the NET_CONFIG registers. + * To reduce the amount of IO to the device, group these options here + * and change them all at once. + */ + + /* Grab current register contents */ + RegNetCfg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET); + RegNewNetCfg = RegNetCfg; + + /* + * It is configured to max 1536. + */ + if (Options & XEMACPSS_FRAME1536_OPTION) { + RegNewNetCfg |= (XEMACPSS_NWCFG_1536RXEN_MASK); + } + + /* Turn on VLAN packet only, only VLAN tagged will be accepted */ + if (Options & XEMACPSS_VLAN_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_NVLANDISC_MASK; + } + + /* Turn on FCS stripping on receive packets */ + if (Options & XEMACPSS_FCS_STRIP_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_FCSREM_MASK; + } + + /* Turn on length/type field checking on receive packets */ + if (Options & XEMACPSS_LENTYPE_ERR_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_LENGTHERRDSCRD_MASK; + } + + /* Turn on flow control */ + if (Options & XEMACPSS_FLOW_CONTROL_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_PAUSEEN_MASK; + } + + /* Turn on promiscuous frame filtering (all frames are received) */ + if (Options & XEMACPSS_PROMISC_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_COPYALLEN_MASK; + } + + /* Allow broadcast address reception */ + if (Options & XEMACPSS_BROADCAST_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_BCASTDI_MASK; + } + + /* Allow multicast address filtering */ + if (Options & XEMACPSS_MULTICAST_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_MCASTHASHEN_MASK; + } + + /* enable RX checksum offload */ + if (Options & XEMACPSS_RX_CHKSUM_ENABLE_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_RXCHKSUMEN_MASK; + } + + /* Officially change the NET_CONFIG registers if it needs to be + * modified. + */ + if (RegNetCfg != RegNewNetCfg) { + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, RegNewNetCfg); + } + + /* Enable TX checksum offload */ + if (Options & XEMACPSS_TX_CHKSUM_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_DMACR_OFFSET); + Reg |= XEMACPSS_DMACR_TCPCKSUM_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_DMACR_OFFSET, Reg); + } + + /* Enable transmitter */ + if (Options & XEMACPSS_TRANSMITTER_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + Reg |= XEMACPSS_NWCTRL_TXEN_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, Reg); + } + + /* Enable receiver */ + if (Options & XEMACPSS_RECEIVER_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + Reg |= XEMACPSS_NWCTRL_RXEN_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, Reg); + } + + /* The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. Reflecting + * the option in InstancePtr->Options is good enough for now. + */ + + /* Set options word to its new value */ + InstancePtr->Options |= Options; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Clear options for the driver/device + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Options are the options to clear. Multiple options can be cleared by + * OR'ing XEMACPSS_*_OPTIONS constants together. Options not specified + * are not affected. + * + * @return + * - XST_SUCCESS if the options were set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + * @note + * See zynq_gem.h for a description of the available options. + * + *****************************************************************************/ +int XEmacPss_ClearOptions(XEmacPss *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic */ + u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */ + u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */ + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Many of these options will change the NET_CONFIG registers. + * To reduce the amount of IO to the device, group these options here + * and change them all at once. + */ + + /* Grab current register contents */ + RegNetCfg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET); + RegNewNetCfg = RegNetCfg; + + /* There is only RX configuration!? + * It is configured in two different length, upto 1536 and 10240 bytes + */ + if (Options & XEMACPSS_FRAME1536_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_1536RXEN_MASK; + } + + /* Turn off VLAN packet only */ + if (Options & XEMACPSS_VLAN_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_NVLANDISC_MASK; + } + + /* Turn off FCS stripping on receive packets */ + if (Options & XEMACPSS_FCS_STRIP_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_FCSREM_MASK; + } + + /* Turn off length/type field checking on receive packets */ + if (Options & XEMACPSS_LENTYPE_ERR_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_LENGTHERRDSCRD_MASK; + } + + /* Turn off flow control */ + if (Options & XEMACPSS_FLOW_CONTROL_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_PAUSEEN_MASK; + } + + /* Turn off promiscuous frame filtering (all frames are received) */ + if (Options & XEMACPSS_PROMISC_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_COPYALLEN_MASK; + } + + /* Disallow broadcast address filtering => broadcast reception */ + if (Options & XEMACPSS_BROADCAST_OPTION) { + RegNewNetCfg |= XEMACPSS_NWCFG_BCASTDI_MASK; + } + + /* Disallow multicast address filtering */ + if (Options & XEMACPSS_MULTICAST_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_MCASTHASHEN_MASK; + } + + /* Disable RX checksum offload */ + if (Options & XEMACPSS_RX_CHKSUM_ENABLE_OPTION) { + RegNewNetCfg &= ~XEMACPSS_NWCFG_RXCHKSUMEN_MASK; + } + + /* Officially change the NET_CONFIG registers if it needs to be + * modified. + */ + if (RegNetCfg != RegNewNetCfg) { + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, RegNewNetCfg); + } + + /* Disable TX checksum offload */ + if (Options & XEMACPSS_TX_CHKSUM_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_DMACR_OFFSET); + Reg &= ~XEMACPSS_DMACR_TCPCKSUM_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_DMACR_OFFSET, Reg); + } + + /* Disable transmitter */ + if (Options & XEMACPSS_TRANSMITTER_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + Reg &= ~XEMACPSS_NWCTRL_TXEN_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, Reg); + } + + /* Disable receiver */ + if (Options & XEMACPSS_RECEIVER_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + Reg &= ~XEMACPSS_NWCTRL_RXEN_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, Reg); + } + + /* The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. Reflecting + * option in InstancePtr->Options is good enough for now. + */ + + /* Set options word to its new value */ + InstancePtr->Options &= ~Options; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Get current option settings + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return + * A bitmask of XTE_*_OPTION constants. Any bit set to 1 is to be interpreted + * as a set opion. + * + * @note + * See zynq_gem.h for a description of the available options. + * + *****************************************************************************/ +u32 XEmacPss_GetOptions(XEmacPss *InstancePtr) +{ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + return (InstancePtr->Options); +} + + +/*****************************************************************************/ +/** + * Send a pause packet + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return + * - XST_SUCCESS if pause frame transmission was initiated + * - XST_DEVICE_IS_STOPPED if the device has not been started. + * + *****************************************************************************/ +int XEmacPss_SendPausePacket(XEmacPss *InstancePtr) +{ + u32 Reg; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* Make sure device is ready for this operation */ + if (InstancePtr->IsStarted != XCOMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STOPPED); + } + + /* Send flow control frame */ + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + Reg |= XEMACPSS_NWCTRL_PAUSETX_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, Reg); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * XEmacPss_GetOperatingSpeed gets the current operating link speed. This may + * be the value set by XEmacPss_SetOperatingSpeed() or a hardware default. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XEmacPss_GetOperatingSpeed returns the link speed in units of + * megabits per second. + * + * @note + * + *****************************************************************************/ +u16 XEmacPss_GetOperatingSpeed(XEmacPss *InstancePtr) +{ + u32 Reg; + + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET); + + if (Reg & XEMACPSS_NWCFG_1000_MASK) { + return (1000); + } else { + if (Reg & XEMACPSS_NWCFG_100_MASK) { + return (100); + } else { + return (10); + } + } +} + + +/*****************************************************************************/ +/** + * XEmacPss_SetOperatingSpeed sets the current operating link speed. For any + * traffic to be passed, this speed must match the current MII/GMII/SGMII/RGMII + * link speed. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param Speed is the speed to set in units of Mbps. Valid values are 10, 100, + * or 1000. XEmacPss_SetOperatingSpeed ignores invalid values. + * + * @note + * + *****************************************************************************/ +void XEmacPss_SetOperatingSpeed(XEmacPss *InstancePtr, u16 Speed) +{ + u32 Reg; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_VOID((Speed == 10) || (Speed == 100) || (Speed == 1000)); + + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET); + Reg &= ~(XEMACPSS_NWCFG_1000_MASK | XEMACPSS_NWCFG_100_MASK); + + switch (Speed) { + case 10: + break; + + case 100: + Reg |= XEMACPSS_NWCFG_100_MASK; + break; + + case 1000: + Reg |= XEMACPSS_NWCFG_1000_MASK; + break; + + default: + return; + } + + /* Set register and return */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, Reg); +} + + +/*****************************************************************************/ +/** + * Set the MDIO clock divisor. + * + * Calculating the divisor: + * + *
+ *              f[HOSTCLK]
+ *   f[MDC] = -----------------
+ *            (1 + Divisor) * 2
+ * 
+ * + * where f[HOSTCLK] is the bus clock frequency in MHz, and f[MDC] is the + * MDIO clock frequency in MHz to the PHY. Typically, f[MDC] should not + * exceed 2.5 MHz. Some PHYs can tolerate faster speeds which means faster + * access. Here is the table to show values to generate MDC, + * + *
+ * 000 : divide pclk by   8 (pclk up to  20 MHz)
+ * 001 : divide pclk by  16 (pclk up to  40 MHz)
+ * 010 : divide pclk by  32 (pclk up to  80 MHz)
+ * 011 : divide pclk by  48 (pclk up to 120 MHz)
+ * 100 : divide pclk by  64 (pclk up to 160 MHz)
+ * 101 : divide pclk by  96 (pclk up to 240 MHz)
+ * 110 : divide pclk by 128 (pclk up to 320 MHz)
+ * 111 : divide pclk by 224 (pclk up to 540 MHz)
+ * 
+ * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Divisor is the divisor to set. Range is 0b000 to 0b111. + * + *****************************************************************************/ +void XEmacPss_SetMdioDivisor(XEmacPss *InstancePtr, XEmacPss_MdcDiv Divisor) +{ + u32 Reg; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY) + XASSERT_VOID(Divisor <= 0x7); /* only last three bits are valid */ + + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET); + /* clear these three bits, could be done with mask */ + Reg &= ~XEMACPSS_NWCFG_MDCCLKDIV_MASK; + + Reg |= (Divisor << XEMACPSS_NWCFG_MDC_SHIFT_MASK); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, Reg); + +} + + +/*****************************************************************************/ +/** +* Read the current value of the PHY register indicated by the PhyAddress and +* the RegisterNum parameters. The MAC provides the driver with the ability to +* talk to a PHY that adheres to the Media Independent Interface (MII) as +* defined in the IEEE 802.3 standard. +* +* Prior to PHY access with this function, the user should have setup the MDIO +* clock with XEmacPss_SetMdioDivisor(). +* +* @param InstancePtr is a pointer to the XEmacPss instance to be worked on. +* @param PhyAddress is the address of the PHY to be read (supports multiple +* PHYs) +* @param RegisterNum is the register number, 0-31, of the specific PHY register +* to read +* @param PhyDataPtr is an output parameter, and points to a 16-bit buffer into +* which the current value of the register will be copied. +* +* @return +* +* - XST_SUCCESS if the PHY was read from successfully +* - XST_EMAC_MII_BUSY if there is another PHY operation in progress +* +* @note +* +* This function is not thread-safe. The user must provide mutually exclusive +* access to this function if there are to be multiple threads that can call it. +* +* There is the possibility that this function will not return if the hardware +* is broken (i.e., it never sets the status bit indicating that the read is +* done). If this is of concern to the user, the user should provide a mechanism +* suitable to their needs for recovery. +* +* For the duration of this function, all host interface reads and writes are +* blocked to the current XEmacPss instance. +* +******************************************************************************/ +int XEmacPss_PhyRead(XEmacPss *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr) +{ + u32 Mgtcr; + volatile u32 Ipisr; + + XASSERT_NONVOID(InstancePtr != NULL); + + /* Make sure no other PHY operation is currently in progress */ + if (!(XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWSR_OFFSET) & + XEMACPSS_NWSR_MDIOIDLE_MASK)) { + return (XST_EMAC_MII_BUSY); + } + + /* Construct Mgtcr mask for the operation */ + Mgtcr = XEMACPSS_PHYMNTNC_OP_MASK | XEMACPSS_PHYMNTNC_OP_R_MASK | + (PhyAddress << XEMACPSS_PHYMNTNC_PHYAD_SHIFT_MASK) | + (RegisterNum << XEMACPSS_PHYMNTNC_PHREG_SHIFT_MASK); + + /* Write Mgtcr and wait for completion */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_PHYMNTNC_OFFSET, Mgtcr); + + do { + Ipisr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWSR_OFFSET); + } while ((Ipisr & XEMACPSS_NWSR_MDIOIDLE_MASK) == 0); + + /* Read data */ + *PhyDataPtr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_PHYMNTNC_OFFSET); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* Write data to the specified PHY register. The Ethernet driver does not +* require the device to be stopped before writing to the PHY. Although it is +* probably a good idea to stop the device, it is the responsibility of the +* application to deem this necessary. The MAC provides the driver with the +* ability to talk to a PHY that adheres to the Media Independent Interface +* (MII) as defined in the IEEE 802.3 standard. +* +* Prior to PHY access with this function, the user should have setup the MDIO +* clock with XEmacPss_SetMdioDivisor(). +* +* @param InstancePtr is a pointer to the XEmacPss instance to be worked on. +* @param PhyAddress is the address of the PHY to be written (supports multiple +* PHYs) +* @param RegisterNum is the register number, 0-31, of the specific PHY register +* to write +* @param PhyData is the 16-bit value that will be written to the register +* +* @return +* +* - XST_SUCCESS if the PHY was written to successfully. Since there is no error +* status from the MAC on a write, the user should read the PHY to verify the +* write was successful. +* - XST_EMAC_MII_BUSY if there is another PHY operation in progress +* +* @note +* +* This function is not thread-safe. The user must provide mutually exclusive +* access to this function if there are to be multiple threads that can call it. +* +* There is the possibility that this function will not return if the hardware +* is broken (i.e., it never sets the status bit indicating that the write is +* done). If this is of concern to the user, the user should provide a mechanism +* suitable to their needs for recovery. +* +* For the duration of this function, all host interface reads and writes are +* blocked to the current XEmacPss instance. +* +******************************************************************************/ +int XEmacPss_PhyWrite(XEmacPss *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData) +{ + u32 Mgtcr; + volatile u32 Ipisr; + + XASSERT_NONVOID(InstancePtr != NULL); + + /* Make sure no other PHY operation is currently in progress */ + if (!(XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWSR_OFFSET) & + XEMACPSS_NWSR_MDIOIDLE_MASK)) { + return (XST_EMAC_MII_BUSY); + } + + /* Construct Mgtcr mask for the operation */ + Mgtcr = XEMACPSS_PHYMNTNC_OP_MASK | XEMACPSS_PHYMNTNC_OP_W_MASK | + (PhyAddress << XEMACPSS_PHYMNTNC_PHYAD_SHIFT_MASK) | + (RegisterNum << XEMACPSS_PHYMNTNC_PHREG_SHIFT_MASK) | PhyData; + + /* Write Mgtcr and wait for completion */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_PHYMNTNC_OFFSET, Mgtcr); + + do { + Ipisr = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWSR_OFFSET); + } while ((Ipisr & XEMACPSS_NWSR_MDIOIDLE_MASK) == 0); + + return (XST_SUCCESS); +} diff --git a/drivers/net/zynq_gem_g.c b/drivers/net/zynq_gem_g.c new file mode 100644 index 00000000000..04399169577 --- /dev/null +++ b/drivers/net/zynq_gem_g.c @@ -0,0 +1,46 @@ +/* + * (C) Copyright 2012 Xilinx + * + * This file contains a configuration table that specifies the configuration of + * ethernet devices in the system. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/***************************** Include Files *********************************/ + +#include "zynq_gem.h" + +/************************** Constant Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Prototypes ******************************/ + +/* + * The configuration table for emacps device + */ + +XEmacPss_Config XEmacPss_ConfigTable[XPAR_XEMACPSS_NUM_INSTANCES] = { + { + XPAR_XEMACPSS_0_DEVICE_ID, /* Device ID */ + XPAR_XEMACPSS_0_BASEADDR /* Device base address */ + }, + { + XPAR_XEMACPSS_1_DEVICE_ID, /* Device ID */ + XPAR_XEMACPSS_1_BASEADDR /* Device base address */ + } +}; diff --git a/drivers/net/zynq_gem_hw.h b/drivers/net/zynq_gem_hw.h new file mode 100644 index 00000000000..5a3b4959bdb --- /dev/null +++ b/drivers/net/zynq_gem_hw.h @@ -0,0 +1,539 @@ +/* + * (C) Copyright 2012 Xilinx + * + * This header file contains identifiers and low-level driver functions (or + * macros) that can be used to access the PSS Ethernet MAC (XEmacPss) device. + * High-level driver functions are defined in zynq_gem.h. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef XEMACPSS_HW_H /* prevent circular inclusions */ +#define XEMACPSS_HW_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +//#include "xbasic_types.h" +//#include "xio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************** Constant Definitions *****************************/ + +#define XEMACPSS_MAX_MAC_ADDR 4 /**< Maxmum number of mac address + supported */ +#define XEMACPSS_MAX_TYPE_ID 4 /**< Maxmum number of type id supported */ +#define XEMACPSS_BD_ALIGNMENT 4 /**< Minimum buffer descriptor alignment + on the local bus */ +#define XEMACPSS_RX_BUF_ALIGNMENT 4 /**< Minimum buffer alignment when using + options that impose alignment + restrictions on the buffer data on + the local bus */ + +/** @name Direction identifiers + * + * These are used by several functions and callbacks that need + * to specify whether an operation specifies a send or receive channel. + * @{ + */ +#define XEMACPSS_SEND 1 /**< send direction */ +#define XEMACPSS_RECV 2 /**< receive direction */ +/*@}*/ + +/** @name MDC clock division + * currently supporting 8, 16, 32, 48, 64, 96, 128, 224. + * @{ + */ +typedef enum { XMDC_DIV_8 = 0, XMDC_DIV_16, XMDC_DIV_32, XMDC_DIV_48, + XMDC_DIV_64, XMDC_DIV_96, XMDC_DIV_128, XMDC_DIV_224 +} XEmacPss_MdcDiv; + +/*@}*/ + +#define XEMACPSS_RX_BUF_SIZE 1536 /**< Specify the receive buffer size in + bytes, 64, 128, ... 10240 */ +#define XEMACPSS_RX_BUF_UNIT 64 /**< Number of receive buffer bytes as a + unit, this is HW setup */ + +#define XEMACPSS_MAX_RXBD 128 /**< Size of RX buffer descriptor queues */ +#define XEMACPSS_MAX_TXBD 128 /**< Size of TX buffer descriptor queues */ + +#define XEMACPSS_MAX_HASH_BITS 64 /**< Maximum value for hash bits. 2**6 */ + +/* Register offset definitions. Unless otherwise noted, register access is + * 32 bit. Names are self explained here. + */ + +#define XEMACPSS_NWCTRL_OFFSET 0x00000000 /**< Network Control reg */ +#define XEMACPSS_NWCFG_OFFSET 0x00000004 /**< Network Config reg */ +#define XEMACPSS_NWSR_OFFSET 0x00000008 /**< Network Status reg */ + +#define XEMACPSS_DMACR_OFFSET 0x00000010 /**< DMA Control reg */ +#define XEMACPSS_TXSR_OFFSET 0x00000014 /**< TX Status reg */ +#define XEMACPSS_RXQBASE_OFFSET 0x00000018 /**< RX Q Base address reg */ +#define XEMACPSS_TXQBASE_OFFSET 0x0000001C /**< TX Q Base address reg */ +#define XEMACPSS_RXSR_OFFSET 0x00000020 /**< RX Status reg */ + +#define XEMACPSS_ISR_OFFSET 0x00000024 /**< Interrupt Status reg */ +#define XEMACPSS_IER_OFFSET 0x00000028 /**< Interrupt Enable reg */ +#define XEMACPSS_IDR_OFFSET 0x0000002C /**< Interrupt Disable reg */ +#define XEMACPSS_IMR_OFFSET 0x00000030 /**< Interrupt Mask reg */ + +#define XEMACPSS_PHYMNTNC_OFFSET 0x00000034 /**< Phy Maintaince reg */ +#define XEMACPSS_RXPAUSE_OFFSET 0x00000038 /**< RX Pause Time reg */ +#define XEMACPSS_TXPAUSE_OFFSET 0x0000003C /**< TX Pause Time reg */ + +#define XEMACPSS_HASHL_OFFSET 0x00000080 /**< Hash Low address reg */ +#define XEMACPSS_HASHH_OFFSET 0x00000084 /**< Hash High address reg */ + +#define XEMACPSS_LADDR1L_OFFSET 0x00000088 /**< Specific1 addr low reg */ +#define XEMACPSS_LADDR1H_OFFSET 0x0000008C /**< Specific1 addr high reg */ +#define XEMACPSS_LADDR2L_OFFSET 0x00000090 /**< Specific2 addr low reg */ +#define XEMACPSS_LADDR2H_OFFSET 0x00000094 /**< Specific2 addr high reg */ +#define XEMACPSS_LADDR3L_OFFSET 0x00000098 /**< Specific3 addr low reg */ +#define XEMACPSS_LADDR3H_OFFSET 0x0000009C /**< Specific3 addr high reg */ +#define XEMACPSS_LADDR4L_OFFSET 0x000000A0 /**< Specific4 addr low reg */ +#define XEMACPSS_LADDR4H_OFFSET 0x000000A4 /**< Specific4 addr high reg */ + +#define XEMACPSS_MATCH1_OFFSET 0x000000A8 /**< Type ID1 Match reg */ +#define XEMACPSS_MATCH2_OFFSET 0x000000AC /**< Type ID2 Match reg */ +#define XEMACPSS_MATCH3_OFFSET 0x000000B0 /**< Type ID3 Match reg */ +#define XEMACPSS_MATCH4_OFFSET 0x000000B4 /**< Type ID4 Match reg */ + +#define XEMACPSS_STRETCH_OFFSET 0x000000BC /**< IPG Stretch reg */ + +#define XEMACPSS_OCTTXL_OFFSET 0x00000100 /**< Octects transmitted Low + reg */ +#define XEMACPSS_OCTTXH_OFFSET 0x00000104 /**< Octects transmitted High + reg */ + +#define XEMACPSS_TXCNT_OFFSET 0x00000108 /**< Error-free Frmaes + transmitted counter */ +#define XEMACPSS_TXBCCNT_OFFSET 0x0000010C /**< Error-free Broadcast + Frames counter*/ +#define XEMACPSS_TXMCCNT_OFFSET 0x00000110 /**< Error-free Multicast + Frame counter */ +#define XEMACPSS_TXPAUSECNT_OFFSET 0x00000114 /**< Pause Frames Transmitted + Counter */ +#define XEMACPSS_TX64CNT_OFFSET 0x00000118 /**< Error-free 64 byte Frames + Transmitted counter */ +#define XEMACPSS_TX65CNT_OFFSET 0x0000011C /**< Error-free 65-127 byte + Frames Transmitted + counter */ +#define XEMACPSS_TX128CNT_OFFSET 0x00000120 /**< Error-free 128-255 byte + Frames Transmitted + counter*/ +#define XEMACPSS_TX256CNT_OFFSET 0x00000124 /**< Error-free 256-511 byte + Frames transmitted + counter */ +#define XEMACPSS_TX512CNT_OFFSET 0x00000128 /**< Error-free 512-1023 byte + Frames transmitted + counter */ +#define XEMACPSS_TX1024CNT_OFFSET 0x0000012C /**< Error-free 1024-1518 byte + Frames transmitted + counter */ +#define XEMACPSS_TX1519CNT_OFFSET 0x00000130 /**< Error-free larger than + 1519 byte Frames + transmitted counter */ +#define XEMACPSS_TXURUNCNT_OFFSET 0x00000134 /**< TX under run error + counter */ + +#define XEMACPSS_SNGLCOLLCNT_OFFSET 0x00000138 /**< Single Collision Frame + Counter */ +#define XEMACPSS_MULTICOLLCNT_OFFSET 0x0000013C /**< Multiple Collision Frame + Counter */ +#define XEMACPSS_EXCESSCOLLCNT_OFFSET 0x00000140 /**< Excessive Collision Frame + Counter */ +#define XEMACPSS_LATECOLLCNT_OFFSET 0x00000144 /**< Late Collision Frame + Counter */ +#define XEMACPSS_TXDEFERCNT_OFFSET 0x00000148 /**< Deferred Transmission + Frame Counter */ +#define XEMACPSS_TXCSENSECNT_OFFSET 0x0000014C /**< Transmit Carrier Sense + Error Counter */ + +#define XEMACPSS_OCTRXL_OFFSET 0x00000150 /**< Octects Received register + Low */ +#define XEMACPSS_OCTRXH_OFFSET 0x00000154 /**< Octects Received register + High */ + +#define XEMACPSS_RXCNT_OFFSET 0x00000158 /**< Error-free Frames + Received Counter */ +#define XEMACPSS_RXBROADCNT_OFFSET 0x0000015C /**< Error-free Broadcast + Frames Received Counter */ +#define XEMACPSS_RXMULTICNT_OFFSET 0x00000160 /**< Error-free Multicast + Frames Received Counter */ +#define XEMACPSS_RXPAUSECNT_OFFSET 0x00000164 /**< Pause Frames + Received Counter */ +#define XEMACPSS_RX64CNT_OFFSET 0x00000168 /**< Error-free 64 byte Frames + Received Counter */ +#define XEMACPSS_RX65CNT_OFFSET 0x0000016C /**< Error-free 65-127 byte + Frames Received Counter */ +#define XEMACPSS_RX128CNT_OFFSET 0x00000170 /**< Error-free 128-255 byte + Frames Received Counter */ +#define XEMACPSS_RX256CNT_OFFSET 0x00000174 /**< Error-free 256-512 byte + Frames Received Counter */ +#define XEMACPSS_RX512CNT_OFFSET 0x00000178 /**< Error-free 512-1023 byte + Frames Received Counter */ +#define XEMACPSS_RX1024CNT_OFFSET 0x0000017C /**< Error-free 1024-1518 byte + Frames Received Counter */ +#define XEMACPSS_RX1519CNT_OFFSET 0x00000180 /**< Error-free 1519-max byte + Frames Received Counter */ +#define XEMACPSS_RXUNDRCNT_OFFSET 0x00000184 /**< Undersize Frames Received + Counter */ +#define XEMACPSS_RXOVRCNT_OFFSET 0x00000188 /**< Oversize Frames Received + Counter */ +#define XEMACPSS_RXJABCNT_OFFSET 0x0000018C /**< Jabbers Received + Counter */ +#define XEMACPSS_RXFCSCNT_OFFSET 0x00000190 /**< Frame Check Sequence + Error Counter */ +#define XEMACPSS_RXLENGTHCNT_OFFSET 0x00000194 /**< Length Field Error + Counter */ +#define XEMACPSS_RXSYMBCNT_OFFSET 0x00000198 /**< Symbol Error Counter */ +#define XEMACPSS_RXALIGNCNT_OFFSET 0x0000019C /**< Alignment Error Counter */ +#define XEMACPSS_RXRESERRCNT_OFFSET 0x000001A0 /**< Receive Resource Error + Counter */ +#define XEMACPSS_RXORCNT_OFFSET 0x000001A4 /**< Receive Overrun Counter */ +#define XEMACPSS_RXIPCCNT_OFFSET 0x000001A8 /**< IP header Checksum Error + Counter */ +#define XEMACPSS_RXTCPCCNT_OFFSET 0x000001AC /**< TCP Checksum Error + Counter */ +#define XEMACPSS_RXUDPCCNT_OFFSET 0x000001B0 /**< UDP Checksum Error + Counter */ +#define XEMACPSS_LAST_OFFSET 0x000001B4 /**< Last statistic counter + offset, for clearing */ + +#define XEMACPSS_1588_SEC_OFFSET 0x000001D0 /**< 1588 second counter */ +#define XEMACPSS_1588_NANOSEC_OFFSET 0x000001D4 /**< 1588 nanosecond counter */ +#define XEMACPSS_1588_ADJ_OFFSET 0x000001D8 /**< 1588 nanosecond + adjustment counter */ +#define XEMACPSS_1588_INC_OFFSET 0x000001DC /**< 1588 nanosecond + increment counter */ +#define XEMACPSS_PTP_TXSEC_OFFSET 0x000001E0 /**< 1588 PTP transmit second + counter */ +#define XEMACPSS_PTP_TXNANOSEC_OFFSET 0x000001E4 /**< 1588 PTP transmit + nanosecond counter */ +#define XEMACPSS_PTP_RXSEC_OFFSET 0x000001E8 /**< 1588 PTP receive second + counter */ +#define XEMACPSS_PTP_RXNANOSEC_OFFSET 0x000001EC /**< 1588 PTP receive + nanosecond counter */ +#define XEMACPSS_PTPP_TXSEC_OFFSET 0x000001F0 /**< 1588 PTP peer transmit + second counter */ +#define XEMACPSS_PTPP_TXNANOSEC_OFFSET 0x000001F4 /**< 1588 PTP peer transmit + nanosecond counter */ +#define XEMACPSS_PTPP_RXSEC_OFFSET 0x000001F8 /**< 1588 PTP peer receive + second counter */ +#define XEMACPSS_PTPP_RXNANOSEC_OFFSET 0x000001FC /**< 1588 PTP peer receive + nanosecond counter */ + +/* Define some bit positions for registers. */ + +/** @name network control register bit definitions + * @{ + */ +#define XEMACPSS_NWCTRL_ZEROPAUSETX_MASK 0x00000800 /**< Transmit zero quantum + pause frame */ +#define XEMACPSS_NWCTRL_PAUSETX_MASK 0x00000800 /**< Transmit pause frame */ +#define XEMACPSS_NWCTRL_HALTTX_MASK 0x00000400 /**< Halt transmission + after current frame */ +#define XEMACPSS_NWCTRL_STARTTX_MASK 0x00000200 /**< Start tx (tx_go) */ + +#define XEMACPSS_NWCTRL_STATWEN_MASK 0x00000080 /**< Enable writing to + stat counters */ +#define XEMACPSS_NWCTRL_STATINC_MASK 0x00000040 /**< Increment statistic + registers */ +#define XEMACPSS_NWCTRL_STATCLR_MASK 0x00000020 /**< Clear statistic + registers */ +#define XEMACPSS_NWCTRL_MDEN_MASK 0x00000010 /**< Enable MDIO port */ +#define XEMACPSS_NWCTRL_TXEN_MASK 0x00000008 /**< Enable transmit */ +#define XEMACPSS_NWCTRL_RXEN_MASK 0x00000004 /**< Enable receive */ +#define XEMACPSS_NWCTRL_LOOPEN_MASK 0x00000002 /**< local loopback */ +/*@}*/ + +/** @name network configuration register bit definitions + * @{ + */ +#define XEMACPSS_NWCFG_BADPREAMBEN_MASK 0x20000000 /**< disable rejection of + non-standard preamble */ +#define XEMACPSS_NWCFG_IPDSTRETCH_MASK 0x10000000 /**< enable transmit IPG */ +#define XEMACPSS_NWCFG_FCSIGNORE_MASK 0x04000000 /**< disable rejection of + FCS error */ +#define XEMACPSS_NWCFG_HDRXEN_MASK 0x02000000 /**< RX half duplex */ +#define XEMACPSS_NWCFG_RXCHKSUMEN_MASK 0x01000000 /**< enable RX checksum + offload */ +#define XEMACPSS_NWCFG_PAUSECOPYDI_MASK 0x00800000 /**< Do not copy pause + Frames to memory */ +#define XEMACPSS_NWCFG_MDC_SHIFT_MASK 18 /**< shift bits for MDC */ +#define XEMACPSS_NWCFG_MDCCLKDIV_MASK 0x001C0000 /**< MDC Mask PCLK divisor */ +#define XEMACPSS_NWCFG_FCSREM_MASK 0x00020000 /**< Discard FCS from + received frames */ +#define XEMACPSS_NWCFG_LENGTHERRDSCRD_MASK 0x00010000 +/**< RX length error discard */ +#define XEMACPSS_NWCFG_RXOFFS_MASK 0x0000C000 /**< RX buffer offset */ +#define XEMACPSS_NWCFG_PAUSEEN_MASK 0x00002000 /**< Enable pause RX */ +#define XEMACPSS_NWCFG_RETRYTESTEN_MASK 0x00001000 /**< Retry test */ +#define XEMACPSS_NWCFG_EXTADDRMATCHEN_MASK 0x00000200 +/**< External address match enable */ +#define XEMACPSS_NWCFG_1000_MASK 0x00000400 /**< 1000 Mbps */ +#define XEMACPSS_NWCFG_1536RXEN_MASK 0x00000100 /**< Enable 1536 byte + frames reception */ +#define XEMACPSS_NWCFG_UCASTHASHEN_MASK 0x00000080 /**< Receive unicast hash + frames */ +#define XEMACPSS_NWCFG_MCASTHASHEN_MASK 0x00000040 /**< Receive multicast hash + frames */ +#define XEMACPSS_NWCFG_BCASTDI_MASK 0x00000020 /**< Do not receive + broadcast frames */ +#define XEMACPSS_NWCFG_COPYALLEN_MASK 0x00000010 /**< Copy all frames */ +#define XEMACPSS_NWCFG_JUMBO_MASK 0x00000008 /**< Jumbo frames */ +#define XEMACPSS_NWCFG_NVLANDISC_MASK 0x00000004 /**< Receive only VLAN + frames */ +#define XEMACPSS_NWCFG_FDEN_MASK 0x00000002 /**< full duplex */ +#define XEMACPSS_NWCFG_100_MASK 0x00000001 /**< 100 Mbps */ +/*@}*/ + +/** @name network status register bit definitaions + * @{ + */ +#define XEMACPSS_NWSR_MDIOIDLE_MASK 0x00000004 /**< PHY management idle */ +#define XEMACPSS_NWSR_MDIO_MASK 0x00000002 /**< Status of mdio_in */ +/*@}*/ + + +/** @name MAC address register word 1 mask + * @{ + */ +#define XEMACPSS_LADDR_MACH_MASK 0x0000FFFF /**< Address bits[47:32] + bit[31:0] are in BOTTOM */ +/*@}*/ + + +/** @name DMA control register bit definitions + * @{ + */ +#define XEMACPSS_DMACR_RXBUF_MASK 0x00FF0000 /**< Mask bit for RX buffer + size */ +#define XEMACPSS_DMACR_RXBUF_SHIFT 16 /**< Shift bit for RX buffer + size */ +#define XEMACPSS_DMACR_TCPCKSUM_MASK 0x00000800 /**< enable/disable TX + checksum offload */ +#define XEMACPSS_DMACR_TXSIZE_MASK 0x00000400 /**< TX buffer memory size */ +#define XEMACPSS_DMACR_RXSIZE_MASK 0x00000300 /**< RX buffer memory size */ +#define XEMACPSS_DMACR_ENDIAN_MASK 0x00000080 /**< endian configuration */ +#define XEMACPSS_DMACR_BLENGTH_MASK 0x0000001F /**< buffer burst length */ +/*@}*/ + +/** @name transmit status register bit definitions + * @{ + */ +#define XEMACPSS_TXSR_HRESPNOK_MASK 0x00000100 /**< Transmit hresp not OK */ +#define XEMACPSS_TXSR_URUN_MASK 0x00000040 /**< Transmit underrun */ +#define XEMACPSS_TXSR_TXCOMPL_MASK 0x00000020 /**< Transmit completed OK */ +#define XEMACPSS_TXSR_BUFEXH_MASK 0x00000010 /**< Transmit buffs exhausted + mid frame */ +#define XEMACPSS_TXSR_TXGO_MASK 0x00000008 /**< Status of go flag */ +#define XEMACPSS_TXSR_RXOVR_MASK 0x00000004 /**< Retry limit exceeded */ +#define XEMACPSS_TXSR_FRAMERX_MASK 0x00000002 /**< Collision tx frame */ +#define XEMACPSS_TXSR_USEDREAD_MASK 0x00000001 /**< TX buffer used bit set */ + +#define XEMACPSS_TXSR_ERROR_MASK (XEMACPSS_TXSR_HRESPNOK_MASK | \ + XEMACPSS_TXSR_URUN_MASK | \ + XEMACPSS_TXSR_BUFEXH_MASK | \ + XEMACPSS_TXSR_RXOVR_MASK | \ + XEMACPSS_TXSR_FRAMERX_MASK | \ + XEMACPSS_TXSR_USEDREAD_MASK) +/*@}*/ + +/** @name receive status register bit definitions + * @{ + */ +#define XEMACPSS_RXSR_HRESPNOK_MASK 0x00000008 /**< Receive hresp not OK */ +#define XEMACPSS_RXSR_RXOVR_MASK 0x00000004 /**< Receive overrun */ +#define XEMACPSS_RXSR_FRAMERX_MASK 0x00000002 /**< Frame received OK */ +#define XEMACPSS_RXSR_BUFFNA_MASK 0x00000001 /**< RX buffer used bit set */ + +#define XEMACPSS_RXSR_ERROR_MASK (XEMACPSS_RXSR_HRESPNOK_MASK | \ + XEMACPSS_RXSR_RXOVR_MASK | \ + XEMACPSS_RXSR_BUFFNA_MASK) +/*@}*/ + +/** @name interrupts bit definitions + * Bits definitions are same in XEMACPSS_ISR_OFFSET, + * XEMACPSS_IER_OFFSET, XEMACPSS_IDR_OFFSET, and XEMACPSS_IMR_OFFSET + * @{ + */ +#define XEMACPSS_IXR_PTPPSTX_MASK 0x02000000 /**< PTP Psync transmitted */ +#define XEMACPSS_IXR_PTPPDRTX_MASK 0x01000000 /**< PTP Pdelay_req + transmitted */ +#define XEMACPSS_IXR_PTPSTX_MASK 0x00800000 /**< PTP Sync transmitted */ +#define XEMACPSS_IXR_PTPDRTX_MASK 0x00400000 /**< PTP Delay_req transmitted + */ +#define XEMACPSS_IXR_PTPPSRX_MASK 0x00200000 /**< PTP Psync received */ +#define XEMACPSS_IXR_PTPPDRRX_MASK 0x00100000 /**< PTP Pdelay_req received */ +#define XEMACPSS_IXR_PTPSRX_MASK 0x00080000 /**< PTP Sync received */ +#define XEMACPSS_IXR_PTPDRRX_MASK 0x00040000 /**< PTP Delay_req received */ +#define XEMACPSS_IXR_PAUSETX_MASK 0x00004000 /**< Pause frame transmitted */ +#define XEMACPSS_IXR_PAUSEZERO_MASK 0x00002000 /**< Pause time has reached + zero */ +#define XEMACPSS_IXR_PAUSENZERO_MASK 0x00001000 /**< Pause frame received */ +#define XEMACPSS_IXR_HRESPNOK_MASK 0x00000800 /**< hresp not ok */ +#define XEMACPSS_IXR_RXOVR_MASK 0x00000400 /**< Receive overrun occurred */ +#define XEMACPSS_IXR_TXCOMPL_MASK 0x00000080 /**< Frame transmitted ok */ +#define XEMACPSS_IXR_TXEXH_MASK 0x00000040 /**< Transmit err occurred or + no buffers*/ +#define XEMACPSS_IXR_RETRY_MASK 0x00000020 /**< Retry limit exceeded */ +#define XEMACPSS_IXR_URUN_MASK 0x00000010 /**< Transmit underrun */ +#define XEMACPSS_IXR_TXUSED_MASK 0x00000008 /**< Tx buffer used bit read */ +#define XEMACPSS_IXR_RXUSED_MASK 0x00000004 /**< Rx buffer used bit read */ +#define XEMACPSS_IXR_FRAMERX_MASK 0x00000002 /**< Frame received ok */ +#define XEMACPSS_IXR_MGMNT_MASK 0x00000001 /**< PHY management complete */ +#define XEMACPSS_IXR_ALL_MASK 0x00007FFF /**< Everything! */ + +#define XEMACPSS_IXR_TX_ERR_MASK (XEMACPSS_IXR_TXEXH_MASK | \ + XEMACPSS_IXR_RETRY_MASK | \ + XEMACPSS_IXR_URUN_MASK | \ + XEMACPSS_IXR_TXUSED_MASK) + + +#define XEMACPSS_IXR_RX_ERR_MASK (XEMACPSS_IXR_HRESPNOK_MASK | \ + XEMACPSS_IXR_RXUSED_MASK | \ + XEMACPSS_IXR_RXOVR_MASK) + +/*@}*/ + +/** @name PHY Maintenance bit definitions + * @{ + */ +#define XEMACPSS_PHYMNTNC_OP_MASK 0x40020000 /**< operation mask bits */ +#define XEMACPSS_PHYMNTNC_OP_R_MASK 0x20000000 /**< read operation */ +#define XEMACPSS_PHYMNTNC_OP_W_MASK 0x10000000 /**< write operation */ +#define XEMACPSS_PHYMNTNC_ADDR_MASK 0x0F800000 /**< Address bits */ +#define XEMACPSS_PHYMNTNC_REG_MASK 0x007C0000 /**< register bits */ +#define XEMACPSS_PHYMNTNC_DATA_MASK 0x00000FFF /**< data bits */ +#define XEMACPSS_PHYMNTNC_PHYAD_SHIFT_MASK 23 /**< Shift bits for PHYAD */ +#define XEMACPSS_PHYMNTNC_PHREG_SHIFT_MASK 18 /**< Shift bits for PHREG */ +/*@}*/ + +/* Transmit buffer descriptor status words offset + * @{ + */ +#define XEMACPSS_BD_ADDR_OFFSET 0x00000000 /**< word 0/addr of BDs */ +#define XEMACPSS_BD_STAT_OFFSET 0x00000004 /**< word 1/status of BDs */ +/*@}*/ + +/* Transmit buffer descriptor status words bit positions. + * Transmit buffer descriptor consists of two 32-bit registers, + * the first - word0 contains a 32-bit address pointing to the location of + * the transmit data. + * The following register - word1, consists of various information to control + * the XEmacPss transmit process. After transmit, this is updated with status + * information, whether the frame was transmitted OK or why it had failed. + * @{ + */ +#define XEMACPSS_TXBUF_USED_MASK 0x80000000 /**< Used bit. */ +#define XEMACPSS_TXBUF_WRAP_MASK 0x40000000 /**< Wrap bit, last descriptor */ +#define XEMACPSS_TXBUF_RETRY_MASK 0x20000000 /**< Retry limit exceeded */ +#define XEMACPSS_TXBUF_URUN_MASK 0x10000000 /**< Transmit underrun occurred */ +#define XEMACPSS_TXBUF_EXH_MASK 0x08000000 /**< Buffers exhausted */ +#define XEMACPSS_TXBUF_TCP_MASK 0x04000000 /**< Late collision. */ +#define XEMACPSS_TXBUF_NOCRC_MASK 0x00010000 /**< No CRC */ +#define XEMACPSS_TXBUF_LAST_MASK 0x00008000 /**< Last buffer */ +#define XEMACPSS_TXBUF_LEN_MASK 0x00003FFF /**< Mask for length field */ +/*@}*/ + +/* Receive buffer descriptor status words bit positions. + * Receive buffer descriptor consists of two 32-bit registers, + * the first - word0 contains a 32-bit word aligned address pointing to the + * address of the buffer. The lower two bits make up the wrap bit indicating + * the last descriptor and the ownership bit to indicate it has been used by + * the XEmacPss. + * The following register - word1, contains status information regarding why + * the frame was received (the filter match condition) as well as other + * useful info. + * @{ + */ +#define XEMACPSS_RXBUF_BCAST_MASK 0x80000000 /**< Broadcast frame */ +#define XEMACPSS_RXBUF_MULTIHASH_MASK 0x40000000 /**< Multicast hashed frame */ +#define XEMACPSS_RXBUF_UNIHASH_MASK 0x20000000 /**< Unicast hashed frame */ +#define XEMACPSS_RXBUF_EXH_MASK 0x08000000 /**< buffer exhausted */ +#define XEMACPSS_RXBUF_AMATCH_MASK 0x06000000 /**< Specific address + matched */ +#define XEMACPSS_RXBUF_IDFOUND_MASK 0x01000000 /**< Type ID matched */ +#define XEMACPSS_RXBUF_IDMATCH_MASK 0x00C00000 /**< ID matched mask */ +#define XEMACPSS_RXBUF_VLAN_MASK 0x00200000 /**< VLAN tagged */ +#define XEMACPSS_RXBUF_PRI_MASK 0x00100000 /**< Priority tagged */ +#define XEMACPSS_RXBUF_VPRI_MASK 0x000E0000 /**< Vlan priority */ +#define XEMACPSS_RXBUF_CFI_MASK 0x00010000 /**< CFI frame */ +#define XEMACPSS_RXBUF_EOF_MASK 0x00008000 /**< End of frame. */ +#define XEMACPSS_RXBUF_SOF_MASK 0x00004000 /**< Start of frame. */ +#define XEMACPSS_RXBUF_LEN_MASK 0x00003FFF /**< Mask for length field */ + +#define XEMACPSS_RXBUF_WRAP_MASK 0x00000002 /**< Wrap bit, last BD */ +#define XEMACPSS_RXBUF_NEW_MASK 0x00000001 /**< Used bit.. */ +#define XEMACPSS_RXBUF_ADD_MASK 0xFFFFFFFC /**< Mask for address */ +/*@}*/ + +/* + * Define appropriate I/O access method to mempry mapped I/O or other + * intarfce if necessary. + */ +/* Defined in zynq_gem_control.c*/ +void XIo_Out32(u32 OutAddress, u32 Value); +u32 XIo_In32(u32 InAddress); + +#define XEmacPss_In32 XIo_In32 +#define XEmacPss_Out32 XIo_Out32 + + +/****************************************************************************/ +/** +* +* Read the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be read +* +* @return The 32-bit value of the register +* +* @note +* C-style signature: +* u32 XEmacPss_ReadReg(u32 BaseAddress, u32 RegOffset) +* +*****************************************************************************/ +#define XEmacPss_ReadReg(BaseAddress, RegOffset) \ + XEmacPss_In32((BaseAddress) + (RegOffset)) + + +/****************************************************************************/ +/** +* +* Write the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be written +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note +* C-style signature: +* void XEmacPss_WriteReg(u32 BaseAddress, u32 RegOffset, +* u32 Data) +* +*****************************************************************************/ +#define XEmacPss_WriteReg(BaseAddress, RegOffset, Data) \ + XEmacPss_Out32((BaseAddress) + (RegOffset), (Data)) + +#ifdef __cplusplus + } +#endif + +#endif /* end of protection macro */ diff --git a/drivers/net/zynq_gem_old.c b/drivers/net/zynq_gem_old.c new file mode 100644 index 00000000000..50ceb91f17f --- /dev/null +++ b/drivers/net/zynq_gem_old.c @@ -0,0 +1,362 @@ +/* + * (C) Copyright 2012 Xilinx + * + * The XEmacPss driver. Functions in this file are the minimum required + * functions for this driver. + * See zynq_gem.h for a detailed description of the driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/***************************** Include Files *********************************/ + +#include "zynq_gem.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +void XEmacPss_StubHandler(void); /* Default handler routine */ + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* Initialize a specific XEmacPss instance/driver. The initialization entails: +* - Initialize fields of the XEmacPss instance structure +* - Reset hardware and apply default options +* - Configure the DMA channels +* +* The PHY is setup independently from the device. Use the MII or whatever other +* interface may be present for setup. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param CfgPtr is the device configuration structure containing required +* hardware build data. +* @param EffectiveAddress is the base address of the device. If address +* translation is not utilized, this parameter can be passed in using +* CfgPtr->Config.BaseAddress to specify the physical base address. +* +* @return +* - XST_SUCCESS if initialization was successful +* +******************************************************************************/ +int XEmacPss_CfgInitialize(XEmacPss *InstancePtr, XEmacPss_Config * CfgPtr, + u32 EffectiveAddress) +{ + /* Verify arguments */ + XASSERT_NONVOID(InstancePtr != NULL); + XASSERT_NONVOID(CfgPtr != NULL); + + /* Set device base address and ID */ + InstancePtr->Config.DeviceId = CfgPtr->DeviceId; + InstancePtr->Config.BaseAddress = EffectiveAddress; + + /* Set callbacks to an initial stub routine */ + InstancePtr->SendHandler = (XEmacPss_Handler) XEmacPss_StubHandler; + InstancePtr->RecvHandler = (XEmacPss_Handler) XEmacPss_StubHandler; + InstancePtr->ErrorHandler = (XEmacPss_ErrHandler) XEmacPss_StubHandler; + + /* Reset the hardware and set default options */ + InstancePtr->IsReady = XCOMPONENT_IS_READY; + XEmacPss_Reset(InstancePtr); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* Start the Ethernet controller as follows: +* - Enable transmitter if XTE_TRANSMIT_ENABLE_OPTION is set +* - Enable receiver if XTE_RECEIVER_ENABLE_OPTION is set +* - Start the SG DMA send and receive channels and enable the device +* interrupt +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return N/A +* +* @note +* Hardware is configured with scatter-gather DMA, the driver expects to start +* the scatter-gather channels and expects that the user has previously set up +* the buffer descriptor lists. +* +* This function makes use of internal resources that are shared between the +* Start, Stop, and Set/ClearOptions functions. So if one task might be setting +* device options while another is trying to start the device, the user is +* required to provide protection of this shared data (typically using a +* semaphore). +* +* This function must not be preempted by an interrupt that may service the +* device. +* +******************************************************************************/ +void XEmacPss_Start(XEmacPss *InstancePtr) +{ + u32 Reg; + + /* Assert bad arguments and conditions */ + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + XASSERT_VOID(InstancePtr->RxBdRing.BaseBdAddr != 0); + XASSERT_VOID(InstancePtr->TxBdRing.BaseBdAddr != 0); + + /* If already started, then there is nothing to do */ + if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED) { + return; + } + + /* Start DMA */ + /* When starting the DMA channels, both transmit and receive sides + * need an initialized BD list. + */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_RXQBASE_OFFSET, + InstancePtr->RxBdRing.BaseBdAddr); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_TXQBASE_OFFSET, + InstancePtr->TxBdRing.BaseBdAddr); + + /* clear any existed int status */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, XEMACPSS_ISR_OFFSET, + XEMACPSS_IXR_ALL_MASK); + + /* Enable transmitter if not already enabled */ + if (InstancePtr->Options & XEMACPSS_TRANSMITTER_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + if (!(Reg & XEMACPSS_NWCTRL_TXEN_MASK)) { + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, + Reg | XEMACPSS_NWCTRL_TXEN_MASK); + } + } + + /* Enable receiver if not already enabled */ + if (InstancePtr->Options & XEMACPSS_RECEIVER_ENABLE_OPTION) { + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + if (!(Reg & XEMACPSS_NWCTRL_RXEN_MASK)) { + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, + Reg | XEMACPSS_NWCTRL_RXEN_MASK); + } + } + +#if 0 + /* Enable TX and RX interrupts */ + XEmacPss_IntEnable(InstancePtr, (XEMACPSS_IXR_TX_ERR_MASK | + XEMACPSS_IXR_RX_ERR_MASK | XEMACPSS_IXR_FRAMERX_MASK | + XEMACPSS_IXR_TXCOMPL_MASK)); +#endif + /* Mark as started */ + InstancePtr->IsStarted = XCOMPONENT_IS_STARTED; + + return; +} + + +/*****************************************************************************/ +/** +* Gracefully stop the Ethernet MAC as follows: +* - Disable all interrupts from this device +* - Stop DMA channels +* - Disable the tansmitter and receiver +* +* Device options currently in effect are not changed. +* +* This function will disable all interrupts. Default interrupts settings that +* had been enabled will be restored when XEmacPss_Start() is called. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @note +* This function makes use of internal resources that are shared between the +* Start, Stop, SetOptions, and ClearOptions functions. So if one task might be +* setting device options while another is trying to start the device, the user +* is required to provide protection of this shared data (typically using a +* semaphore). +* +* Stopping the DMA channels causes this function to block until the DMA +* operation is complete. +* +******************************************************************************/ +void XEmacPss_Stop(XEmacPss *InstancePtr) +{ + u32 Reg; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* Disable all interrupts */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, XEMACPSS_IDR_OFFSET, + XEMACPSS_IXR_ALL_MASK); + + /* Disable the receiver & transmitter */ + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + Reg &= ~XEMACPSS_NWCTRL_RXEN_MASK; + Reg &= ~XEMACPSS_NWCTRL_TXEN_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, Reg); + + /* Mark as stopped */ + InstancePtr->IsStarted = 0; +} + + +/*****************************************************************************/ +/** +* Perform a graceful reset of the Ethernet MAC. Resets the DMA channels, the +* transmitter, and the receiver. +* +* Steps to reset +* - Stops transmit and receive channels +* - Stops DMA +* - Configure transmit and receive buffer size to default +* - Clear transmit and receive status register and counters +* - Clear all interrupt sources +* - Clear phy (if there is any previously detected) address +* - Clear MAC addresses (1-4) as well as Type IDs and hash value +* +* All options are placed in their default state. Any frames in the +* descriptor lists will remain in the lists. The side effect of doing +* this is that after a reset and following a restart of the device, frames +* were in the list before the reset may be transmitted or received. +* +* The upper layer software is responsible for re-configuring (if necessary) +* and restarting the MAC after the reset. Note also that driver statistics +* are not cleared on reset. It is up to the upper layer software to clear the +* statistics if needed. +* +* When a reset is required, the driver notifies the upper layer software of +* this need through the ErrorHandler callback and specific status codes. +* The upper layer software is responsible for calling this Reset function +* and then re-configuring the device. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +******************************************************************************/ +void XEmacPss_Reset(XEmacPss *InstancePtr) +{ + u32 Reg; + u8 i; + char EmacPss_zero_MAC[6] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + XASSERT_VOID(InstancePtr != NULL); + XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); + + /* Stop the device and reset hardware */ + XEmacPss_Stop(InstancePtr); + InstancePtr->Options = XEMACPSS_DEFAULT_OPTIONS; + + /* Setup hardware with default values */ + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, + (XEMACPSS_NWCTRL_STATCLR_MASK | + XEMACPSS_NWCTRL_MDEN_MASK) & + ~XEMACPSS_NWCTRL_LOOPEN_MASK); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, + XEMACPSS_NWCFG_100_MASK | + XEMACPSS_NWCFG_FDEN_MASK | + XEMACPSS_NWCFG_UCASTHASHEN_MASK); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_DMACR_OFFSET, + ((((XEMACPSS_RX_BUF_SIZE / XEMACPSS_RX_BUF_UNIT) + + ((XEMACPSS_RX_BUF_SIZE % + XEMACPSS_RX_BUF_UNIT) ? 1 : 0)) << + XEMACPSS_DMACR_RXBUF_SHIFT) & + XEMACPSS_DMACR_RXBUF_MASK) | + XEMACPSS_DMACR_RXSIZE_MASK | + XEMACPSS_DMACR_TXSIZE_MASK); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_TXSR_OFFSET, 0x0); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_RXQBASE_OFFSET, 0x0); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_TXQBASE_OFFSET, 0x0); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_RXSR_OFFSET, 0x0); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, XEMACPSS_IDR_OFFSET, + XEMACPSS_IXR_ALL_MASK); + + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_ISR_OFFSET); + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, XEMACPSS_ISR_OFFSET, + Reg); + + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_PHYMNTNC_OFFSET, 0x0); + + XEmacPss_ClearHash(InstancePtr); + + for (i = 1; i < 5; i++) { + XEmacPss_SetMacAddress(InstancePtr, EmacPss_zero_MAC, i); + XEmacPss_SetTypeIdCheck(InstancePtr, 0x0, i); + } + + /* clear all counters */ + for (i = 0; i < (XEMACPSS_LAST_OFFSET - XEMACPSS_OCTTXL_OFFSET) / 4; + i++) { + XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_OCTTXL_OFFSET + i * 4); + } + + /* Disable the receiver */ + Reg = XEmacPss_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + Reg &= ~XEMACPSS_NWCTRL_RXEN_MASK; + XEmacPss_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, Reg); + + /* Sync default options with hardware but leave receiver and + * transmitter disabled. They get enabled with XEmacPss_Start() if + * XEMACPSS_TRANSMITTER_ENABLE_OPTION and + * XEMACPSS_RECEIVER_ENABLE_OPTION are set. + */ + XEmacPss_SetOptions(InstancePtr, InstancePtr->Options & + ~(XEMACPSS_TRANSMITTER_ENABLE_OPTION | + XEMACPSS_RECEIVER_ENABLE_OPTION)); + + XEmacPss_ClearOptions(InstancePtr, ~InstancePtr->Options); +} + + +/******************************************************************************/ +/** + * This is a stub for the asynchronous callbacks. The stub is here in case the + * upper layer forgot to set the handler(s). On initialization, all handlers are + * set to this callback. It is considered an error for this handler to be + * invoked. + * + ******************************************************************************/ +void XEmacPss_StubHandler(void) +{ + XASSERT_VOID_ALWAYS(); +} diff --git a/drivers/net/zynq_gem_sinit.c b/drivers/net/zynq_gem_sinit.c new file mode 100644 index 00000000000..9f1157a9c7d --- /dev/null +++ b/drivers/net/zynq_gem_sinit.c @@ -0,0 +1,58 @@ +/* + * (C) Copyright 2012 Xilinx + * + * This file contains lookup method by device ID when success, it returns + * pointer to config table to be used to initialize the device. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/***************************** Include Files *********************************/ + +#include "zynq_gem.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* Lookup the device configuration based on the unique device ID. The table +* contains the configuration info for each device in the system. +* +* @param DeviceId is the unique device ID of the device being looked up. +* +* @return +* A pointer to the configuration table entry corresponding to the given +* device ID, or NULL if no match is found. +* +******************************************************************************/ +XEmacPss_Config *XEmacPss_LookupConfig(u16 DeviceId) +{ + extern XEmacPss_Config XEmacPss_ConfigTable[]; + XEmacPss_Config *CfgPtr = NULL; + int i; + + for (i = 0; i < XPAR_XEMACPSS_NUM_INSTANCES; i++) { + if (XEmacPss_ConfigTable[i].DeviceId == DeviceId) { + CfgPtr = &XEmacPss_ConfigTable[i]; + break; + } + } + + return (CfgPtr); +} diff --git a/drivers/net/zynq_gem_wrap.c b/drivers/net/zynq_gem_wrap.c new file mode 100644 index 00000000000..9547d921047 --- /dev/null +++ b/drivers/net/zynq_gem_wrap.c @@ -0,0 +1,759 @@ +/* + * (C) Copyright 2012 Xilinx + * + * The XEmacPss Wrapper driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "zynq_gem.h" + +/************************ Forward function declaration **********************/ + +static int Xgmac_process_rx(XEmacPss *EmacPssInstancePtr); +static int Xgmac_init_rxq(XEmacPss *EmacPssInstancePtr, + void *bd_start, int num_elem); +static int Xgmac_make_rxbuff_mem(XEmacPss *EmacPssInstancePtr, + void *rx_buf_start, u32 rx_buffsize); +static int Xgmac_next_rx_buf(XEmacPss *EmacPssInstancePtr); +static int Xgmac_phy_mgmt_idle(XEmacPss *EmacPssInstancePtr); +static void Xgmac_set_eth_advertise(XEmacPss *EmacPssInstancePtr, + int link_speed); + +/*************************** Constant Definitions ***************************/ + +#define EMACPSS_DEVICE_ID 0 +#define RXBD_CNT 8 /* Number of RxBDs to use */ +#define TXBD_CNT 8 /* Number of TxBDs to use */ + +#define phy_spinwait(e) do { while (!Xgmac_phy_mgmt_idle(e)); } while (0) + +#define dmb() __asm__ __volatile__ ("dmb" : : : "memory") + +/*************************** Variable Definitions ***************************/ + +/* + * Aligned memory segments to be used for buffer descriptors + */ +//#define BRAM_BUFFERS +#ifdef BRAM_BUFFERS +static XEmacPss_Bd RxBdSpace[RXBD_CNT] __attribute__ ((section (".bram_buffers"))); +static XEmacPss_Bd TxBdSpace[TXBD_CNT] __attribute__ ((section (".bram_buffers"))); +static char RxBuffers[RXBD_CNT * XEMACPSS_RX_BUF_SIZE] __attribute__ ((section (".bram_buffers"))); +static uchar data_buffer[XEMACPSS_RX_BUF_SIZE] __attribute__ ((section (".bram_buffers"))); +#else +static XEmacPss_Bd RxBdSpace[RXBD_CNT]; +static XEmacPss_Bd TxBdSpace[TXBD_CNT]; +static char RxBuffers[RXBD_CNT * XEMACPSS_RX_BUF_SIZE]; +static uchar data_buffer[XEMACPSS_RX_BUF_SIZE]; +#endif + +static struct { + u8 initialized; +} ethstate = {0}; + +XEmacPss EmacPssInstance; + +/*****************************************************************************/ +/* +* Following are the supporting functions to read and write GEM PHY registers. +*/ +static int Xgmac_phy_mgmt_idle(XEmacPss * EmacPssInstancePtr) +{ + return ((XEmacPss_ReadReg + (EmacPssInstancePtr->Config.BaseAddress, XEMACPSS_NWSR_OFFSET) + & XEMACPSS_NWSR_MDIOIDLE_MASK) == XEMACPSS_NWSR_MDIOIDLE_MASK); +} + +#if defined(CONFIG_CMD_MII) && !defined(CONFIG_BITBANGMII) +static int Xgmac_mii_read(const char *devname, unsigned char addr, + unsigned char reg, unsigned short *value) +{ + phy_spinwait(&EmacPssInstance); + XEmacPss_PhyRead(&EmacPssInstance, addr, reg, value); + phy_spinwait(&EmacPssInstance); + return 0; +} + +static int Xgmac_mii_write(const char *devname, unsigned char addr, + unsigned char reg, unsigned short value) +{ + phy_spinwait(&EmacPssInstance); + XEmacPss_PhyWrite(&EmacPssInstance, addr, reg, value); + phy_spinwait(&EmacPssInstance); + return 0; +} +#endif + +static u32 phy_rd(XEmacPss * e, u32 a) +{ + u16 PhyData; + + phy_spinwait(e); + XEmacPss_PhyRead(e, CONFIG_XGMAC_PHY_ADDR, a, &PhyData); + phy_spinwait(e); + return PhyData; +} + +static void phy_wr(XEmacPss * e, u32 a, u32 v) +{ + phy_spinwait(e); + XEmacPss_PhyWrite(e, CONFIG_XGMAC_PHY_ADDR, a, v); + phy_spinwait(e); +} + +static void phy_rst(XEmacPss * e) +{ + int tmp; + + puts("Resetting PHY...\n"); + tmp = phy_rd(e, 0); + tmp |= 0x8000; + phy_wr(e, 0, tmp); + + while (phy_rd(e, 0) & 0x8000) { + udelay(10000); + tmp++; + if (tmp > 1000) { /* stalled if reset unfinished after 10 seconds */ + puts("***Error: Reset stalled...\n"); + return; + } + } + puts("\nPHY reset complete.\n"); +} + +static void Out32(u32 OutAddress, u32 Value) +{ + *(volatile u32 *) OutAddress = Value; + dmb(); +} + +/*****************************************************************************/ + +int Xgmac_one_time_init(void) +{ + int tmp; + int Status; + XEmacPss_Config *Config; + XEmacPss *EmacPssInstancePtr = &EmacPssInstance; + XEmacPss_Bd BdTemplate; + + Config = XEmacPss_LookupConfig(EMACPSS_DEVICE_ID); + + Status = + XEmacPss_CfgInitialize(EmacPssInstancePtr, Config, + Config->BaseAddress); + if (Status != 0) { + puts("Error in initialize"); + return 0; + } + + /* + * Setup RxBD space. + */ + + if (Xgmac_init_rxq(EmacPssInstancePtr, &RxBdSpace, RXBD_CNT)) { + puts("Xgmac_init_rxq failed!\n"); + return -1; + } + + /* + * Create the RxBD ring + */ + tmp = + Xgmac_make_rxbuff_mem(EmacPssInstancePtr, &RxBuffers, + sizeof(RxBuffers)); + if (tmp == 0 || tmp == -1) { + printf("Xgmac_make_rxbuff_mem failed! (%i)\n", tmp); + return -1; + } + + /* + * Setup TxBD space. + */ + + XEmacPss_BdClear(&BdTemplate); + XEmacPss_BdSetStatus(&BdTemplate, XEMACPSS_TXBUF_USED_MASK); + + /* + * Create the TxBD ring + */ + Status = + XEmacPss_BdRingCreate(&(XEmacPss_GetTxRing(EmacPssInstancePtr)), + (u32) & TxBdSpace, (u32) & TxBdSpace, + XEMACPSS_BD_ALIGNMENT, TXBD_CNT); + if (Status != 0) { + puts("Error setting up TxBD space, BdRingCreate"); + return -1; + } + + Status = XEmacPss_BdRingClone(&(XEmacPss_GetTxRing(EmacPssInstancePtr)), + &BdTemplate, XEMACPSS_SEND); + if (Status != 0) { + puts("Error setting up TxBD space, BdRingClone"); + return -1; + } + + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_TXQBASE_OFFSET, + EmacPssInstancePtr->TxBdRing.BaseBdAddr); + + /*************************** MAC Setup ***************************/ + tmp = (3 << 18); /* MDC clock division (48 for up to 120MHz) */ + tmp |= (1 << 17); /* set for FCS removal */ + tmp |= (1 << 10); /* enable gigabit */ + tmp |= (1 << 4); /* copy all frames */ + tmp |= (1 << 1); /* enable full duplex */ + + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, tmp); + + /* MDIO enable */ + tmp = + XEmacPss_ReadReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + tmp |= XEMACPSS_NWCTRL_MDEN_MASK; + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, tmp); + + return 0; +} + +int Xgmac_init(struct eth_device *dev, bd_t * bis) +{ + int tmp; + int link_speed; + XEmacPss *EmacPssInstancePtr = &EmacPssInstance; + + if (ethstate.initialized) + return 1; + + /* + * Setup the ethernet. + */ + printf("Trying to set up GEM link...\n"); + + /* Configure DMA */ + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_DMACR_OFFSET, 0x00180704); + + /* Disable all the MAC Interrupts */ + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_IDR_OFFSET, 0xFFFFFFFF); + + /* Rx and Tx enable */ + tmp = + XEmacPss_ReadReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET); + tmp |= XEMACPSS_NWCTRL_RXEN_MASK | XEMACPSS_NWCTRL_TXEN_MASK; + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCTRL_OFFSET, tmp); + + /*************************** PHY Setup ***************************/ + + phy_wr(EmacPssInstancePtr, 22, 0); /* page 0 */ + + tmp = phy_rd(EmacPssInstancePtr, 2); + printf("Phy ID: %04X", tmp); + tmp = phy_rd(EmacPssInstancePtr, 3); + printf("%04X\n", tmp); + + /* Auto-negotiation advertisement register */ + tmp = phy_rd(EmacPssInstancePtr, 4); + tmp |= (1 << 11); /* asymmetric pause */ + tmp |= (1 << 10); /* MAC pause implemented */ + phy_wr(EmacPssInstancePtr, 4, tmp); + +#ifdef CONFIG_EP107 + /* Extended PHY specific control register */ + tmp = phy_rd(EmacPssInstancePtr, 20); + tmp |= (7 << 9); /* max number of gigabit attempts */ + tmp |= (1 << 8); /* enable downshift */ + tmp |= (1 << 7); /* RGMII receive timing internally delayed */ + tmp |= (1 << 1); /* RGMII transmit clock internally delayed */ + phy_wr(EmacPssInstancePtr, 20, tmp); +#else + /* Copper specific control register 1 */ + tmp = phy_rd(EmacPssInstancePtr, 16); + tmp |= (7 << 12); /* max number of gigabit attempts */ + tmp |= (1 << 11); /* enable downshift */ + phy_wr(EmacPssInstancePtr, 16, tmp); + + /* Control register - MAC */ + phy_wr(EmacPssInstancePtr, 22, 2); /* page 2 */ + tmp = phy_rd(EmacPssInstancePtr, 21); + tmp |= (1 << 5); /* RGMII receive timing transition when data stable */ + tmp |= (1 << 4); /* RGMII transmit clock internally delayed */ + phy_wr(EmacPssInstancePtr, 21, tmp); + phy_wr(EmacPssInstancePtr, 22, 0); /* page 0 */ +#endif + + /* Control register */ + tmp = phy_rd(EmacPssInstancePtr, 0); + tmp |= (1 << 12); /* auto-negotiation enable */ + tmp |= (1 << 8); /* enable full duplex */ + phy_wr(EmacPssInstancePtr, 0, tmp); + + /***** Try to establish a link at the highest speed possible *****/ +#ifdef CONFIG_EP107 + /* CR-659040: + * Advertise link speed as 100Mbps for ep107 targets + */ + Xgmac_set_eth_advertise(EmacPssInstancePtr, 100); +#else + /* CR-659040 */ + /* Could be 1000 if an unknown bug is fixed */ + Xgmac_set_eth_advertise(EmacPssInstancePtr, 1000); +#endif + phy_rst(EmacPssInstancePtr); + + /* Attempt auto-negotiation */ + puts("Waiting for PHY to complete auto-negotiation...\n"); + tmp = 0; /* delay counter */ + while (!(phy_rd(EmacPssInstancePtr, 1) & (1 << 5))) { + udelay(10000); + tmp++; + if (tmp > 1000) { /* stalled if no link after 10 seconds */ + puts("***Error: Auto-negotiation stalled...\n"); + return -1; + } + } + + /* Check if the link is up */ + tmp = phy_rd(EmacPssInstancePtr, 17); + if ( ((tmp >> 10) & 1) ) { + /* Check for an auto-negotiation error */ + tmp = phy_rd(EmacPssInstancePtr, 19); + if ( (tmp >> 15) & 1 ) { + puts("***Error: Auto-negotiation error is present.\n"); + return -1; + } + } else { + puts("***Error: Link is not up.\n"); + return -1; + } + + /********************** Determine link speed **********************/ + tmp = phy_rd(EmacPssInstancePtr, 17); + if ( ((tmp >> 14) & 3) == 2) /* 1000Mbps */ + link_speed = 1000; + else if ( ((tmp >> 14) & 3) == 1) /* 100Mbps */ + link_speed = 100; + else /* 10Mbps */ + link_speed = 10; + + /*************************** MAC Setup ***************************/ + tmp = XEmacPss_ReadReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET); + if (link_speed == 10) + tmp &= ~(0x1); /* enable 10Mbps */ + else + tmp |= 0x1; /* enable 100Mbps */ + if (link_speed == 1000) + tmp |= 0x400; /* enable 1000Mbps */ + else + tmp &= ~(0x400); /* disable gigabit */ + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, tmp); + + /************************* GEM0_CLK Setup *************************/ + /* SLCR unlock */ + Out32(0xF8000008, 0xDF0D); + + /* Configure GEM0_RCLK_CTRL */ + Out32(0xF8000138, ((0 << 4) | (1 << 0))); + + /* Set divisors for appropriate frequency in GEM0_CLK_CTRL */ +#ifdef CONFIG_EP107 + if (link_speed == 1000) /* 125MHz */ + Out32(0xF8000140, ((1 << 20) | (48 << 8) | (1 << 4) | (1 << 0))); + else if (link_speed == 100) /* 25 MHz */ + Out32(0xF8000140, ((1 << 20) | (48 << 8) | (0 << 4) | (1 << 0))); + else /* 2.5 MHz */ + Out32(0xF8000140, ((1 << 20) | (48 << 8) | (3 << 4) | (1 << 0))); +#else + if (link_speed == 1000) /* 125MHz */ + Out32(0xF8000140, ((1 << 20) | (8 << 8) | (0 << 4) | (1 << 0))); + else if (link_speed == 100) /* 25 MHz */ + Out32(0xF8000140, ((1 << 20) | (40 << 8) | (0 << 4) | (1 << 0))); + else /* 2.5 MHz */ + Out32(0xF8000140, ((10 << 20) | (40 << 8) | (0 << 4) | (1 << 0))); +#endif + + /* SLCR lock */ + Out32(0xF8000004, 0x767B); + + printf("Link is now at %dMbps!\n", link_speed); + + ethstate.initialized = 1; + return 0; +} + +void Xgmac_halt(struct eth_device *dev) +{ + return; +} + +int Xgmac_send(struct eth_device *dev, void *packet, int length) +{ + volatile int Status; + XEmacPss_Bd *BdPtr; + XEmacPss *EmacPssInstancePtr = &EmacPssInstance; + + if (!ethstate.initialized) { + puts("Error GMAC not initialized"); + return 0; + } + + Status = + XEmacPss_BdRingAlloc(&(XEmacPss_GetTxRing(&EmacPssInstance)), 1, + &BdPtr); + if (Status != 0) { + puts("Error allocating TxBD"); + return 0; + } + + /* + * Setup TxBD + */ + XEmacPss_BdSetAddressTx(BdPtr, (u32)packet); + XEmacPss_BdSetLength(BdPtr, length); + XEmacPss_BdClearTxUsed(BdPtr); + XEmacPss_BdSetLast(BdPtr); + + /* + * Enqueue to HW + */ + Status = + XEmacPss_BdRingToHw(&(XEmacPss_GetTxRing(&EmacPssInstance)), 1, + BdPtr); + if (Status != 0) { + puts("Error committing TxBD to HW"); + return 0; + } + + /* Start transmit */ + XEmacPss_Transmit(EmacPssInstancePtr); + + /* Read the status register to know if the packet has been Transmitted. */ + Status = + XEmacPss_ReadReg(EmacPssInstance.Config.BaseAddress, + XEMACPSS_TXSR_OFFSET); + if (Status & + (XEMACPSS_TXSR_HRESPNOK_MASK | XEMACPSS_TXSR_URUN_MASK | + XEMACPSS_TXSR_BUFEXH_MASK)) { + printf("Something has gone wrong here!? Status is 0x%x.\n", + Status); + } + + if (Status & XEMACPSS_TXSR_TXCOMPL_MASK) { + +// printf("tx packet sent\n"); + + /* + * Now that the frame has been sent, post process our TxBDs. + */ + if (XEmacPss_BdRingFromHwTx + (&(XEmacPss_GetTxRing(&EmacPssInstance)), 1, &BdPtr) == 0) { + puts("TxBDs were not ready for post processing"); + return 0; + } + + /* + * Free the TxBD. + */ + Status = + XEmacPss_BdRingFree(&(XEmacPss_GetTxRing(&EmacPssInstance)), + 1, BdPtr); + if (Status != 0) { + puts("Error freeing up TxBDs"); + return 0; + } + } + /* Clear Tx status register before leaving . */ + XEmacPss_WriteReg(EmacPssInstance.Config.BaseAddress, + XEMACPSS_TXSR_OFFSET, Status); + return 1; + +} + +int Xgmac_rx(struct eth_device *dev) +{ + u32 status, retval; + XEmacPss *EmacPssInstancePtr = &EmacPssInstance; + + status = + XEmacPss_ReadReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_RXSR_OFFSET); + if (status & XEMACPSS_RXSR_FRAMERX_MASK) { + +// printf("rx packet received\n"); + + do { + retval = Xgmac_process_rx(EmacPssInstancePtr); + } while (retval == 0) ; + } + + /* Clear interrupt status. + */ + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_RXSR_OFFSET, status); + + return 1; +} + +static int Xgmac_write_hwaddr(struct eth_device *dev) +{ + /* Initialize the first MAC filter with our address */ + XEmacPss_SetMacAddress((XEmacPss *)dev->priv, dev->enetaddr, 1); + + return 0; +} + +int zynq_gem_initialize(bd_t *bis) +{ + struct eth_device *dev; + dev = malloc(sizeof(*dev)); + if (dev == NULL) + return 1; + + memset(dev, 0, sizeof(*dev)); + sprintf(dev->name, "zynq_gem"); + + if (Xgmac_one_time_init() < 0) { + printf("zynq_gem init failed!"); + return -1; + } + dev->iobase = EmacPssInstance.Config.BaseAddress; + dev->priv = &EmacPssInstance; + dev->init = Xgmac_init; + dev->halt = Xgmac_halt; + dev->send = Xgmac_send; + dev->recv = Xgmac_rx; + dev->write_hwaddr = Xgmac_write_hwaddr; + + eth_register(dev); + +#if defined(CONFIG_CMD_MII) && !defined(CONFIG_BITBANGMII) + miiphy_register(dev->name, Xgmac_mii_read, Xgmac_mii_write); +#endif + return 0; +} + +/*============================================================================= + * + * Xgmac_process_rx- process the next incoming packet + * + * return's 0 if OK, -1 on error + */ +int Xgmac_process_rx(XEmacPss * EmacPssInstancePtr) +{ + uchar *buffer = data_buffer; + u32 rx_status, hwbuf; + int frame_len; + u32 *bd_addr; + + bd_addr = (u32 *) & EmacPssInstancePtr->RxBdRing. + RxBD_start[EmacPssInstancePtr->RxBdRing.RxBD_current]; + + rx_status = XEmacPss_BdRead((bd_addr), XEMACPSS_BD_ADDR_OFFSET); + if (! (rx_status & XEMACPSS_RXBUF_NEW_MASK)) { + return (-1); + } + + rx_status = XEmacPss_BdIsRxSOF(bd_addr); + if (!rx_status) { + printf("GEM: SOF not set for last buffer received!\n"); + return (-1); + } + rx_status = XEmacPss_BdIsRxEOF(bd_addr); + if (!rx_status) { + printf("GEM: EOF not set for last buffer received!\n"); + return (-1); + } + + frame_len = XEmacPss_BdGetLength(bd_addr); + if (frame_len == 0) { + printf("GEM: Hardware reported 0 length frame!\n"); + return (-1); + } + + hwbuf = (u32) (*bd_addr & XEMACPSS_RXBUF_ADD_MASK); + if (hwbuf == (u32) NULL) { + printf("GEM: Error swapping out buffer!\n"); + return (-1); + } + memcpy(buffer, (void *)hwbuf, frame_len); + Xgmac_next_rx_buf(EmacPssInstancePtr); + NetReceive(buffer, frame_len); + + return (0); +} + +int Xgmac_init_rxq(XEmacPss * EmacPssInstancePtr, void *bd_start, int num_elem) +{ + XEmacPss_BdRing *r; + int loop = 0; + + if ((num_elem <= 0) || (num_elem > RXBD_CNT)) { + return (-1); + } + + for (; loop < 2 * (num_elem);) { + *(((u32 *) bd_start) + loop) = 0x00000000; + *(((u32 *) bd_start) + loop + 1) = 0xF0000000; + loop += 2; + } + + r = & EmacPssInstancePtr->RxBdRing; + r->RxBD_start = (XEmacPss_Bd *) bd_start; + r->Length = num_elem; + r->RxBD_current = 0; + r->RxBD_end = 0; + r->Rx_first_buf = 0; + + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_RXQBASE_OFFSET, (u32) bd_start); + + return 0; +} + +int Xgmac_make_rxbuff_mem(XEmacPss * EmacPssInstancePtr, void *rx_buf_start, + u32 rx_buffsize) +{ + XEmacPss_BdRing *r; + int num_bufs; + int assigned_bufs; + int i; + u32 *bd_addr; + + if ((EmacPssInstancePtr == NULL) || (rx_buf_start == NULL)) { + return (-1); + } + + r = & EmacPssInstancePtr->RxBdRing; + + assigned_bufs = 0; + + if ((num_bufs = rx_buffsize / XEMACPSS_RX_BUF_SIZE) == 0) { + return 0; + } + for (i = 0; i < num_bufs; i++) { + if (r->RxBD_end < r->Length) { + memset((char *)(rx_buf_start + + (i * XEMACPSS_RX_BUF_SIZE)), 0, XEMACPSS_RX_BUF_SIZE); + + bd_addr = (u32 *) & r->RxBD_start[r->RxBD_end]; + + XEmacPss_BdSetAddressRx(bd_addr, + (u32) (((char *) + rx_buf_start) + (i * XEMACPSS_RX_BUF_SIZE))); + + r->RxBD_end++; + assigned_bufs++; + } else { + return assigned_bufs; + } + } + bd_addr = (u32 *) & r->RxBD_start[r->RxBD_end - 1]; + XEmacPss_BdSetRxWrap(bd_addr); + + return assigned_bufs; +} + +int Xgmac_next_rx_buf(XEmacPss * EmacPssInstancePtr) +{ + XEmacPss_BdRing *r; + u32 prev_stat = 0; + u32 *bd_addr = NULL; + + if (EmacPssInstancePtr == NULL) { + printf + ("\ngem_clr_rx_buf with EmacPssInstancePtr as !!NULL!! \n"); + return -1; + } + + r = & EmacPssInstancePtr->RxBdRing; + + bd_addr = (u32 *) & r->RxBD_start[r->RxBD_current]; + prev_stat = XEmacPss_BdIsRxSOF(bd_addr); + if (prev_stat) { + r->Rx_first_buf = r->RxBD_current; + } else { + XEmacPss_BdClearRxNew(bd_addr); + XIo_Out32((u32) (bd_addr + 1), 0xF0000000); + } + + if (XEmacPss_BdIsRxEOF(bd_addr)) { + bd_addr = (u32 *) & r->RxBD_start[r->Rx_first_buf]; + XEmacPss_BdClearRxNew(bd_addr); + XIo_Out32((u32) (bd_addr + 1), 0xF0000000); + } + + if ((++r->RxBD_current) > r->Length - 1) { + r->RxBD_current = 0; + } + + return 0; +} + +void Xgmac_set_eth_advertise(XEmacPss *EmacPssInstancePtr, int link_speed) +{ + int tmp; + + /* MAC setup */ + tmp = XEmacPss_ReadReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET); + if (link_speed == 10) + tmp &= ~(1 << 0); /* enable 10Mbps */ + else if (link_speed == 100) + tmp |= (1 << 0); /* enable 100Mbps */ + XEmacPss_WriteReg(EmacPssInstancePtr->Config.BaseAddress, + XEMACPSS_NWCFG_OFFSET, tmp); + + phy_wr(EmacPssInstancePtr, 22, 0); /* page 0 */ + + /* Auto-negotiation advertisement register */ + tmp = phy_rd(EmacPssInstancePtr, 4); + if (link_speed >= 100) { + tmp |= (1 << 8); /* advertise 100Mbps F */ + tmp |= (1 << 7); /* advertise 100Mbps H */ + } else { + tmp &= ~(1 << 8); /* advertise 100Mbps F */ + tmp &= ~(1 << 7); /* advertise 100Mbps H */ + } + if (link_speed >= 10) { + tmp |= (1 << 6); /* advertise 10Mbps F */ + tmp |= (1 << 5); /* advertise 10Mbps H */ + } else { + tmp &= ~(1 << 6); /* advertise 10Mbps F */ + tmp &= ~(1 << 5); /* advertise 10Mbps H */ + } + phy_wr(EmacPssInstancePtr, 4, tmp); + + /* 1000BASE-T control register */ + tmp = phy_rd(EmacPssInstancePtr, 9); + if (link_speed == 1000) { + tmp |= (1 << 9); /* advertise 1000Mbps F */ + tmp |= (1 << 8); /* advertise 1000Mbps H */ + } else { + tmp &= ~(1 << 9); /* advertise 1000Mbps F */ + tmp &= ~(1 << 8); /* advertise 1000Mbps H */ + } + phy_wr(EmacPssInstancePtr, 9, tmp); + +} + diff --git a/include/netdev.h b/include/netdev.h index 21ebb4eced6..86eed5c9408 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -105,6 +105,8 @@ int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr, int xilinx_ll_temac_initialize(bd_t *bis, unsigned long base_addr, int mode, unsigned long ctrl); int zynq_gem_initialize(bd_t *bis, int base_addr); +int zynq_gem_initialize_old(bd_t *bis); + /* * As long as the Xilinx xps_ll_temac ethernet driver has not its own interface * exported by a public hader file, we need a global definition at this point. -- 2.47.3