/* $Id: xemacps_control.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ /****************************************************************************** * * Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * * @file xemacps_control.c * * Functions in this file implement general purpose command and control related * functionality. See xemacps.h for a detailed description of the driver. * *
* MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ------------------------------------------------------- * 1.00a wsy 01/10/10 First release * 1.02a asa 11/05/12 Added a new API for deleting an entry from the HASH * register. Added a new API for setting the BURST length * in DMACR register. * 2.1 srt 07/15/14 Add support for Zynq Ultrascale Mp architecture. ******************************************************************************/ /***************************** Include Files *********************************/ #include "xemacps.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 * *****************************************************************************/ LONG XEmacPs_SetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index) { u32 MacAddr; u8 *Aptr = (u8 *)(void *)AddressPtr; u8 IndexLoc = Index; LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(Aptr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((IndexLoc <= (u8)XEMACPS_MAX_MAC_ADDR) && (IndexLoc > 0x00U)); /* Be sure device has been stopped */ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) { Status = (LONG)(XST_DEVICE_IS_STARTED); } else{ /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ IndexLoc--; /* Set the MAC bits [31:0] in BOT */ MacAddr = *(Aptr); MacAddr |= ((u32)(*(Aptr+1)) << 8U); MacAddr |= ((u32)(*(Aptr+2)) << 16U); MacAddr |= ((u32)(*(Aptr+3)) << 24U); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, ((u32)XEMACPS_LADDR1L_OFFSET + ((u32)IndexLoc * (u32)8)), MacAddr); /* There are reserved bits in TOP so don't affect them */ MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, ((u32)XEMACPS_LADDR1H_OFFSET + ((u32)IndexLoc * (u32)8))); MacAddr &= (u32)(~XEMACPS_LADDR_MACH_MASK); /* Set MAC bits [47:32] in TOP */ MacAddr |= (u32)(*(Aptr+4)); MacAddr |= (u32)(*(Aptr+5)) << 8U; XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, ((u32)XEMACPS_LADDR1H_OFFSET + ((u32)IndexLoc * (u32)8)), MacAddr); Status = (LONG)(XST_SUCCESS); } return Status; } /*****************************************************************************/ /** * 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 XEmacPs_GetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index) { u32 MacAddr; u8 *Aptr = (u8 *)(void *)AddressPtr; u8 IndexLoc = Index; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(Aptr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertVoid((IndexLoc <= (u8)XEMACPS_MAX_MAC_ADDR) && (IndexLoc > 0x00U)); /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ IndexLoc--; MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, ((u32)XEMACPS_LADDR1L_OFFSET + ((u32)IndexLoc * (u32)8))); *Aptr = (u8) MacAddr; *(Aptr+1) = (u8) (MacAddr >> 8U); *(Aptr+2) = (u8) (MacAddr >> 16U); *(Aptr+3) = (u8) (MacAddr >> 24U); /* Read MAC bits [47:32] in TOP */ MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, ((u32)XEMACPS_LADDR1H_OFFSET + ((u32)IndexLoc * (u32)8))); *(Aptr+4) = (u8) MacAddr; *(Aptr+5) = (u8) (MacAddr >> 8U); } /*****************************************************************************/ /** * 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. *****************************************************************************/ LONG XEmacPs_SetHash(XEmacPs *InstancePtr, void *AddressPtr) { u32 HashAddr; u8 *Aptr = (u8 *)(void *)AddressPtr; u8 Temp1, Temp2, Temp3, Temp4, Temp5, Temp6, Temp7, Temp8; u32 Result; LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(AddressPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); /* Be sure device has been stopped */ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) { Status = (LONG)(XST_DEVICE_IS_STARTED); } else { Temp1 = (*(Aptr+0)) & 0x3FU; Temp2 = ((*(Aptr+0) >> 6U) & 0x03U) | ((*(Aptr+1) & 0x0FU) << 2U); Temp3 = ((*(Aptr+1) >> 4U) & 0x0FU) | ((*(Aptr+2) & 0x3U) << 4U); Temp4 = ((*(Aptr+2) >> 2U) & 0x3FU); Temp5 = (*(Aptr+3)) & 0x3FU; Temp6 = ((*(Aptr+3) >> 6U) & 0x03U) | ((*(Aptr+4) & 0x0FU) << 2U); Temp7 = ((*(Aptr+4) >> 4U) & 0x0FU) | ((*(Aptr+5) & 0x03U) << 4U); Temp8 = ((*(Aptr+5) >> 2U) & 0x3FU); Result = (u32)((u32)Temp1 ^ (u32)Temp2 ^ (u32)Temp3 ^ (u32)Temp4 ^ (u32)Temp5 ^ (u32)Temp6 ^ (u32)Temp7 ^ (u32)Temp8); if (Result >= (u32)XEMACPS_MAX_HASH_BITS) { Status = (LONG)(XST_INVALID_PARAM); } else { if (Result < (u32)32) { HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHL_OFFSET); HashAddr |= (u32)(0x00000001U << Result); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHL_OFFSET, HashAddr); } else { HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHH_OFFSET); HashAddr |= (u32)(0x00000001U << (u32)(Result - (u32)32)); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHH_OFFSET, HashAddr); } Status = (LONG)(XST_SUCCESS); } } return Status; } /*****************************************************************************/ /** * Delete 48-bit MAC addresses in hash table. * 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. * * @return * - XST_SUCCESS if the HASH MAC address was deleted 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. *****************************************************************************/ LONG XEmacPs_DeleteHash(XEmacPs *InstancePtr, void *AddressPtr) { u32 HashAddr; u8 *Aptr = (u8 *)(void *)AddressPtr; u8 Temp1, Temp2, Temp3, Temp4, Temp5, Temp6, Temp7, Temp8; u32 Result; LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(Aptr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); /* Be sure device has been stopped */ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) { Status = (LONG)(XST_DEVICE_IS_STARTED); } else { Temp1 = (*(Aptr+0)) & 0x3FU; Temp2 = ((*(Aptr+0) >> 6U) & 0x03U) | ((*(Aptr+1) & 0x0FU) << 2U); Temp3 = ((*(Aptr+1) >> 4U) & 0x0FU) | ((*(Aptr+2) & 0x03U) << 4U); Temp4 = ((*(Aptr+2) >> 2U) & 0x3FU); Temp5 = (*(Aptr+3)) & 0x3FU; Temp6 = ((*(Aptr+3) >> 6U) & 0x03U) | ((*(Aptr+4) & 0x0FU) << 2U); Temp7 = ((*(Aptr+4) >> 4U) & 0x0FU) | ((*(Aptr+5) & 0x03U) << 4U); Temp8 = ((*(Aptr+5) >> 2U) & 0x3FU); Result = (u32)((u32)Temp1 ^ (u32)Temp2 ^ (u32)Temp3 ^ (u32)Temp4 ^ (u32)Temp5 ^ (u32)Temp6 ^ (u32)Temp7 ^ (u32)Temp8); if (Result >= (u32)(XEMACPS_MAX_HASH_BITS)) { Status = (LONG)(XST_INVALID_PARAM); } else { if (Result < (u32)32) { HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHL_OFFSET); HashAddr &= (u32)(~(0x00000001U << Result)); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHL_OFFSET, HashAddr); } else { HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHH_OFFSET); HashAddr &= (u32)(~(0x00000001U << (u32)(Result - (u32)32))); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHH_OFFSET, HashAddr); } Status = (LONG)(XST_SUCCESS); } } return Status; } /*****************************************************************************/ /** * Clear the Hash registers for the mac address pointed by AddressPtr. * * @param InstancePtr is a pointer to the instance to be worked on. * *****************************************************************************/ void XEmacPs_ClearHash(XEmacPs *InstancePtr) { Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHL_OFFSET, 0x0U); /* write bits [63:32] in TOP */ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHH_OFFSET, 0x0U); } /*****************************************************************************/ /** * 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 XEmacPs_GetHash(XEmacPs *InstancePtr, void *AddressPtr) { u32 *Aptr = (u32 *)(void *)AddressPtr; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(AddressPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); *(Aptr+0) = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_HASHL_OFFSET); /* Read Hash bits [63:32] in TOP */ *(Aptr+1) = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_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 is type ID to be configured. * @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 * *****************************************************************************/ LONG XEmacPs_SetTypeIdCheck(XEmacPs *InstancePtr, u32 Id_Check, u8 Index) { u8 IndexLoc = Index; LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertNonvoid((IndexLoc <= (u8)XEMACPS_MAX_TYPE_ID) && (IndexLoc > 0x00U)); /* Be sure device has been stopped */ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) { Status = (LONG)(XST_DEVICE_IS_STARTED); } else { /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ IndexLoc--; /* Set the ID bits in MATCHx register */ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, ((u32)XEMACPS_MATCH1_OFFSET + ((u32)IndexLoc * (u32)4)), Id_Check); Status = (LONG)(XST_SUCCESS); } return Status; } /*****************************************************************************/ /** * Set options for the driver/device. The driver should be stopped with * XEmacPs_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 xemacps.h for a description of the available options. * *****************************************************************************/ LONG XEmacPs_SetOptions(XEmacPs *InstancePtr, u32 Options) { u32 Reg; /* Generic register contents */ u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */ u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */ LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); /* Be sure device has been stopped */ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) { Status = (LONG)(XST_DEVICE_IS_STARTED); } else { /* 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 = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET); RegNewNetCfg = RegNetCfg; /* * It is configured to max 1536. */ if ((Options & XEMACPS_FRAME1536_OPTION) != 0x00000000U) { RegNewNetCfg |= (XEMACPS_NWCFG_1536RXEN_MASK); } /* Turn on VLAN packet only, only VLAN tagged will be accepted */ if ((Options & XEMACPS_VLAN_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_NVLANDISC_MASK; } /* Turn on FCS stripping on receive packets */ if ((Options & XEMACPS_FCS_STRIP_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_FCSREM_MASK; } /* Turn on length/type field checking on receive packets */ if ((Options & XEMACPS_LENTYPE_ERR_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_LENERRDSCRD_MASK; } /* Turn on flow control */ if ((Options & XEMACPS_FLOW_CONTROL_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_PAUSEEN_MASK; } /* Turn on promiscuous frame filtering (all frames are received) */ if ((Options & XEMACPS_PROMISC_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_COPYALLEN_MASK; } /* Allow broadcast address reception */ if ((Options & XEMACPS_BROADCAST_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_BCASTDI_MASK); } /* Allow multicast address filtering */ if ((Options & XEMACPS_MULTICAST_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_MCASTHASHEN_MASK; } /* enable RX checksum offload */ if ((Options & XEMACPS_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_RXCHKSUMEN_MASK; } /* Officially change the NET_CONFIG registers if it needs to be * modified. */ if (RegNetCfg != RegNewNetCfg) { XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET, RegNewNetCfg); } /* Enable TX checksum offload */ if ((Options & XEMACPS_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET); Reg |= XEMACPS_DMACR_TCPCKSUM_MASK; XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET, Reg); } /* Enable transmitter */ if ((Options & XEMACPS_TRANSMITTER_ENABLE_OPTION) != 0x00000000U) { Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET); Reg |= XEMACPS_NWCTRL_TXEN_MASK; XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, Reg); } /* Enable receiver */ if ((Options & XEMACPS_RECEIVER_ENABLE_OPTION) != 0x00000000U) { Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET); Reg |= XEMACPS_NWCTRL_RXEN_MASK; XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_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; Status = (LONG)(XST_SUCCESS); } return Status; } /*****************************************************************************/ /** * 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 XEMACPS_*_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 xemacps.h for a description of the available options. * *****************************************************************************/ LONG XEmacPs_ClearOptions(XEmacPs *InstancePtr, u32 Options) { u32 Reg; /* Generic */ u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */ u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */ LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); /* Be sure device has been stopped */ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) { Status = (LONG)(XST_DEVICE_IS_STARTED); } else { /* 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 = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET); RegNewNetCfg = RegNetCfg; /* There is only RX configuration!? * It is configured in two different length, upto 1536 and 10240 bytes */ if ((Options & XEMACPS_FRAME1536_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_1536RXEN_MASK); } /* Turn off VLAN packet only */ if ((Options & XEMACPS_VLAN_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_NVLANDISC_MASK); } /* Turn off FCS stripping on receive packets */ if ((Options & XEMACPS_FCS_STRIP_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_FCSREM_MASK); } /* Turn off length/type field checking on receive packets */ if ((Options & XEMACPS_LENTYPE_ERR_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_LENERRDSCRD_MASK); } /* Turn off flow control */ if ((Options & XEMACPS_FLOW_CONTROL_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_PAUSEEN_MASK); } /* Turn off promiscuous frame filtering (all frames are received) */ if ((Options & XEMACPS_PROMISC_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_COPYALLEN_MASK); } /* Disallow broadcast address filtering => broadcast reception */ if ((Options & XEMACPS_BROADCAST_OPTION) != 0x00000000U) { RegNewNetCfg |= XEMACPS_NWCFG_BCASTDI_MASK; } /* Disallow multicast address filtering */ if ((Options & XEMACPS_MULTICAST_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_MCASTHASHEN_MASK); } /* Disable RX checksum offload */ if ((Options & XEMACPS_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_RXCHKSUMEN_MASK); } /* Officially change the NET_CONFIG registers if it needs to be * modified. */ if (RegNetCfg != RegNewNetCfg) { XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET, RegNewNetCfg); } /* Disable TX checksum offload */ if ((Options & XEMACPS_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U) { Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET); Reg &= (u32)(~XEMACPS_DMACR_TCPCKSUM_MASK); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET, Reg); } /* Disable transmitter */ if ((Options & XEMACPS_TRANSMITTER_ENABLE_OPTION) != 0x00000000U) { Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET); Reg &= (u32)(~XEMACPS_NWCTRL_TXEN_MASK); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, Reg); } /* Disable receiver */ if ((Options & XEMACPS_RECEIVER_ENABLE_OPTION) != 0x00000000U) { Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET); Reg &= (u32)(~XEMACPS_NWCTRL_RXEN_MASK); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_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; Status = (LONG)(XST_SUCCESS); } return Status; } /*****************************************************************************/ /** * 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 xemacps.h for a description of the available options. * *****************************************************************************/ u32 XEmacPs_GetOptions(XEmacPs *InstancePtr) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_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. * *****************************************************************************/ LONG XEmacPs_SendPausePacket(XEmacPs *InstancePtr) { u32 Reg; LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); /* Make sure device is ready for this operation */ if (InstancePtr->IsStarted != (u32)XIL_COMPONENT_IS_STARTED) { Status = (LONG)(XST_DEVICE_IS_STOPPED); } else { /* Send flow control frame */ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET); Reg |= XEMACPS_NWCTRL_PAUSETX_MASK; XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, Reg); Status = (LONG)(XST_SUCCESS); } return Status; } /*****************************************************************************/ /** * XEmacPs_GetOperatingSpeed gets the current operating link speed. This may * be the value set by XEmacPs_SetOperatingSpeed() or a hardware default. * * @param InstancePtr references the TEMAC channel on which to operate. * * @return XEmacPs_GetOperatingSpeed returns the link speed in units of * megabits per second. * * @note * *****************************************************************************/ u16 XEmacPs_GetOperatingSpeed(XEmacPs *InstancePtr) { u32 Reg; u16 Status; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET); if ((Reg & XEMACPS_NWCFG_1000_MASK) != 0x00000000U) { Status = (u16)(1000); } else { if ((Reg & XEMACPS_NWCFG_100_MASK) != 0x00000000U) { Status = (u16)(100); } else { Status = (u16)(10); } } return Status; } /*****************************************************************************/ /** * XEmacPs_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. XEmacPs_SetOperatingSpeed ignores invalid values. * * @note * *****************************************************************************/ void XEmacPs_SetOperatingSpeed(XEmacPs *InstancePtr, u16 Speed) { u32 Reg; u16 Status; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertVoid((Speed == (u16)10) || (Speed == (u16)100) || (Speed == (u16)1000)); Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET); Reg &= (u32)(~(XEMACPS_NWCFG_1000_MASK | XEMACPS_NWCFG_100_MASK)); switch (Speed) { case (u16)10: Status = 0U; break; case (u16)100: Status = 0U; Reg |= XEMACPS_NWCFG_100_MASK; break; case (u16)1000: Status = 0U; Reg |= XEMACPS_NWCFG_1000_MASK; break; default: Status = 1U; break; } if(Status == (u16)1){ return; } /* Set register and return */ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_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 XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr, XEmacPs_MdcDiv Divisor) { u32 Reg; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertVoid(Divisor <= (XEmacPs_MdcDiv)0x7); /* only last three bits are valid */ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET); /* clear these three bits, could be done with mask */ Reg &= (u32)(~XEMACPS_NWCFG_MDCCLKDIV_MASK); Reg |= ((u32)Divisor << XEMACPS_NWCFG_MDC_SHIFT_MASK); XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_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 XEmacPs_SetMdioDivisor(). * * @param InstancePtr is a pointer to the XEmacPs 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 XEmacPs instance. * ******************************************************************************/ LONG XEmacPs_PhyRead(XEmacPs *InstancePtr, u32 PhyAddress, u32 RegisterNum, u16 *PhyDataPtr) { u32 Mgtcr; volatile u32 Ipisr; u32 IpReadTemp; LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); /* Make sure no other PHY operation is currently in progress */ if ((!(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWSR_OFFSET) & XEMACPS_NWSR_MDIOIDLE_MASK))==TRUE) { Status = (LONG)(XST_EMAC_MII_BUSY); } else { /* Construct Mgtcr mask for the operation */ Mgtcr = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_R_MASK | (PhyAddress << XEMACPS_PHYMNTNC_PHAD_SHFT_MSK) | (RegisterNum << XEMACPS_PHYMNTNC_PREG_SHFT_MSK); /* Write Mgtcr and wait for completion */ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_PHYMNTNC_OFFSET, Mgtcr); do { Ipisr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWSR_OFFSET); IpReadTemp = Ipisr; } while ((IpReadTemp & XEMACPS_NWSR_MDIOIDLE_MASK) == 0x00000000U); /* Read data */ *PhyDataPtr = (u16)XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_PHYMNTNC_OFFSET); Status = (LONG)(XST_SUCCESS); } return Status; } /*****************************************************************************/ /** * 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 XEmacPs_SetMdioDivisor(). * * @param InstancePtr is a pointer to the XEmacPs 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 XEmacPs instance. * ******************************************************************************/ LONG XEmacPs_PhyWrite(XEmacPs *InstancePtr, u32 PhyAddress, u32 RegisterNum, u16 PhyData) { u32 Mgtcr; volatile u32 Ipisr; u32 IpWriteTemp; LONG Status; Xil_AssertNonvoid(InstancePtr != NULL); /* Make sure no other PHY operation is currently in progress */ if ((!(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWSR_OFFSET) & XEMACPS_NWSR_MDIOIDLE_MASK))==TRUE) { Status = (LONG)(XST_EMAC_MII_BUSY); } else { /* Construct Mgtcr mask for the operation */ Mgtcr = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_W_MASK | (PhyAddress << XEMACPS_PHYMNTNC_PHAD_SHFT_MSK) | (RegisterNum << XEMACPS_PHYMNTNC_PREG_SHFT_MSK) | (u32)PhyData; /* Write Mgtcr and wait for completion */ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_PHYMNTNC_OFFSET, Mgtcr); do { Ipisr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWSR_OFFSET); IpWriteTemp = Ipisr; } while ((IpWriteTemp & XEMACPS_NWSR_MDIOIDLE_MASK) == 0x00000000U); Status = (LONG)(XST_SUCCESS); } return Status; } /*****************************************************************************/ /** * API to update the Burst length in the DMACR register. * * @param InstancePtr is a pointer to the XEmacPs instance to be worked on. * @param BLength is the length in bytes for the dma burst. * * @return None * ******************************************************************************/ void XEmacPs_DMABLengthUpdate(XEmacPs *InstancePtr, s32 BLength) { u32 Reg; u32 RegUpdateVal; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid((BLength == XEMACPS_SINGLE_BURST) || (BLength == XEMACPS_4BYTE_BURST) || (BLength == XEMACPS_8BYTE_BURST) || (BLength == XEMACPS_16BYTE_BURST)); switch (BLength) { case XEMACPS_SINGLE_BURST: RegUpdateVal = XEMACPS_DMACR_SINGLE_AHB_BURST; break; case XEMACPS_4BYTE_BURST: RegUpdateVal = XEMACPS_DMACR_INCR4_AHB_BURST; break; case XEMACPS_8BYTE_BURST: RegUpdateVal = XEMACPS_DMACR_INCR8_AHB_BURST; break; case XEMACPS_16BYTE_BURST: RegUpdateVal = XEMACPS_DMACR_INCR16_AHB_BURST; break; default: RegUpdateVal = 0x00000000U; break; } Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET); Reg &= (u32)(~XEMACPS_DMACR_BLENGTH_MASK); Reg |= RegUpdateVal; XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET, Reg); }