📄 xtemac_control.c
字号:
/*****************************************************************************//** * Get the current operating link speed. This may be the value set by * XTemac_SetOperatingSpeed() or a HW default. * * @param InstancePtr is a pointer to the instance to be worked on. * * @return Link speed in units of megabits per second * ******************************************************************************/u16 XTemac_GetOperatingSpeed(XTemac *InstancePtr){ XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); switch(XTemac_mGetHostReg(XTE_EMCFG_OFFSET) & XTE_EMCFG_LINKSPD_MASK) { case XTE_EMCFG_LINKSPD_1000: return(1000); case XTE_EMCFG_LINKSPD_100: return(100); case XTE_EMCFG_LINKSPD_10: return(10); default: return(0); }}/*****************************************************************************//** * Set 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 is a pointer to the instance to be worked on. * @param Speed is the speed to set in units of Mbps. Valid values are 10, 100, * or 1000. Invalid values result in no change to the device. * ******************************************************************************/void XTemac_SetOperatingSpeed(XTemac *InstancePtr, u16 Speed){ u32 EcfgReg; XASSERT_VOID(InstancePtr != NULL); XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); XASSERT_VOID((Speed == 10) || (Speed == 100) || (Speed == 1000)); /* Get the current contents of the EMAC config register and zero out * speed bits */ EcfgReg = XTemac_mGetHostReg(XTE_EMCFG_OFFSET) & ~XTE_EMCFG_LINKSPD_MASK; switch(Speed) { case 10: break; case 100: EcfgReg |= XTE_EMCFG_LINKSPD_100; break; case 1000: EcfgReg |= XTE_EMCFG_LINKSPD_1000; break; default: return; } /* Set register and return */ XTemac_mSetHostReg(XTE_EMCFG_OFFSET, EcfgReg);}/*****************************************************************************//** * Get the current state of the link when media interface is of the SGMII type * * @param InstancePtr is a pointer to the instance to be worked on. * @param SpeedPtr is a return value set to either 0, 10, 100, or 1000. Units * are in Mbits/sec. * * @return * - XST_SUCCESS if the SGMII status was read and return values set. * - XST_NO_FEATURE if the device is not using SGMII. * ******************************************************************************/XStatus XTemac_GetSgmiiStatus(XTemac *InstancePtr, u16 *SpeedPtr){ int PhyType; u32 EgmicReg; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* Make sure PHY is SGMII */ PhyType = XTemac_mGetPhysicalInterface(InstancePtr); if (PhyType != XTE_PHY_TYPE_SGMII) { return(XST_NO_FEATURE); } /* Get the current contents of RGMII/SGMII config register */ EgmicReg = XTemac_mGetHostReg(XTE_GMIC_OFFSET); /* Extract speed */ switch (EgmicReg & XTE_GMIC_RGLINKSPD_MASK) { case XTE_GMIC_RGLINKSPD_10: *SpeedPtr = 10; break; case XTE_GMIC_RGLINKSPD_100: *SpeedPtr = 100; break; case XTE_GMIC_RGLINKSPD_1000: *SpeedPtr = 1000; break; default: *SpeedPtr = 0; } return(XST_SUCCESS);}/*****************************************************************************//** * Get the current state of the link when media interface is of the RGMII type * * @param InstancePtr is a pointer to the instance to be worked on. * @param SpeedPtr is a return value set to either 0, 10, 100, or 1000. Units * are in Mbits/sec. * @param IsFullDuplexPtr is a return value set to TRUE if the RGMII link * is operating in full duplex, or FALSE if operating in half duplex. * XTE_RGMII_LINK_UP. * @param IsLinkUpPtr is a return value set to TRUE if the RGMII link is up, * or FALSE if the link is down. * * @return * - XST_SUCCESS if the RGMII status was read and return values set. * - XST_NO_FEATURE if the device is not using RGMII. * ******************************************************************************/XStatus XTemac_GetRgmiiStatus(XTemac *InstancePtr, u16 *SpeedPtr, u32 *IsFullDuplexPtr, u32 *IsLinkUpPtr){ int PhyType; u32 EgmicReg; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* Make sure PHY is RGMII */ PhyType = XTemac_mGetPhysicalInterface(InstancePtr); if ((PhyType != XTE_PHY_TYPE_RGMII_1_3) && (PhyType != XTE_PHY_TYPE_RGMII_2_0)) { return(XST_NO_FEATURE); } /* Get the current contents of RGMII/SGMII config register */ EgmicReg = XTemac_mGetHostReg(XTE_GMIC_OFFSET); /* Extract speed */ switch (EgmicReg & XTE_GMIC_RGLINKSPD_MASK) { case XTE_GMIC_RGLINKSPD_10: *SpeedPtr = 10; break; case XTE_GMIC_RGLINKSPD_100: *SpeedPtr = 100; break; case XTE_GMIC_RGLINKSPD_1000: *SpeedPtr = 1000; break; default: *SpeedPtr = 0; } /* Extract duplex and link status */ if (EgmicReg & XTE_GMIC_RGHALFDUPLEX_MASK) { *IsFullDuplexPtr = FALSE; } else { *IsFullDuplexPtr = TRUE; } if (EgmicReg & XTE_GMIC_RGSTATUS_MASK) { *IsLinkUpPtr = TRUE; } else { *IsLinkUpPtr = FALSE; } return(XST_SUCCESS);}/*****************************************************************************//** * Set the MDIO clock divisor. This function must be called once after each * reset prior to accessing MII PHY registers. * * Calculating the divisor: * * From the Virtex-4 Embedded Tri-Mode Ethernet MAC User's Guide, the * following equation governs the MDIO clock to the PHY: * * <pre> * f[HOSTCLK] * f[MDC] = ----------------- * (1 + Divisor) * 2 * </pre> * * 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. * * @param InstancePtr is a pointer to the instance to be worked on. * @param Divisor is the divisor to set. Range is 0 to XTE_MC_CLK_DVD_MAX. * ******************************************************************************/void XTemac_PhySetMdioDivisor(XTemac *InstancePtr, u8 Divisor){ XASSERT_VOID(InstancePtr != NULL); XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY) XASSERT_VOID(Divisor <= XTE_MC_CLK_DVD_MAX); XTemac_mSetHostReg(XTE_MC_OFFSET, (u32)Divisor | XTE_MC_MDIO_MASK);}/*****************************************************************************//*** 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 XTemac_PhySetMdioDivisor().** @param InstancePtr is a pointer to the XTemac 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_NO_FEATURE if the device is not configured with MII support* - 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.* <br><br>* 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.* <br><br>* For the duration of this function, all host interface reads and writes are* blocked to the current Temac instance and also the 2nd instance if it exists* in the system. This is a HW limitation. See xtemac.h for a list of functions* that will be blocked until this operation completes.*******************************************************************************/XStatus XTemac_PhyRead(XTemac *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 (XTemac_mGetIpifReg(XTE_IPISR_OFFSET) & XTE_IPXR_MII_PEND_MASK) { return(XST_EMAC_MII_BUSY); } /* Construct Mgtcr mask for the operation */ Mgtcr = RegisterNum & XTE_MGTCR_REGAD_MASK; Mgtcr |= ((PhyAddress << XTE_MGTCR_PHYAD_SHIFT_MASK) & XTE_MGTCR_PHYAD_MASK); Mgtcr |= XTE_MGTCR_RWN_MASK; /* Write Mgtcr and wait for completion */ XTemac_mSetIpifReg(XTE_MGTCR_OFFSET, Mgtcr); do { Ipisr = XTemac_mGetIpifReg(XTE_IPISR_OFFSET); } while (!(Ipisr & XTE_IPXR_MII_DONE_MASK)); /* Read data */ *PhyDataPtr = XTemac_mGetIpifReg(XTE_MGTDR_OFFSET); /* Clear MII status bits */ XTemac_mSetIpifReg(XTE_IPISR_OFFSET, Ipisr & (XTE_IPXR_MII_DONE_MASK | XTE_IPXR_MII_PEND_MASK)); 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 XTemac_PhySetMdioDivisor().** @param InstancePtr is a pointer to the XTemac 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_NO_FEATURE if the device is not configured with MII support* - 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.* <br><br>* 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.* <br><br>* For the duration of this function, all host interface reads and writes are* blocked to the current Temac instance and also the 2nd instance if it exists* in the system. This is a HW limitation. See xtemac.h for a list of functions* that will be blocked until this operation completes.*******************************************************************************/XStatus XTemac_PhyWrite(XTemac *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 (XTemac_mGetIpifReg(XTE_IPISR_OFFSET) & XTE_IPXR_MII_PEND_MASK) { return(XST_EMAC_MII_BUSY); } /* Construct Mgtcr mask for the operation */ Mgtcr = RegisterNum & XTE_MGTCR_REGAD_MASK; Mgtcr |= ((PhyAddress << XTE_MGTCR_PHYAD_SHIFT_MASK) & XTE_MGTCR_PHYAD_MASK); /* Write Mgtdr and Mgtcr and wait for completion */ XTemac_mSetIpifReg(XTE_MGTDR_OFFSET, (u32)PhyData); XTemac_mSetIpifReg(XTE_MGTCR_OFFSET, Mgtcr); do { Ipisr = XTemac_mGetIpifReg(XTE_IPISR_OFFSET); } while (!(Ipisr & XTE_IPXR_MII_DONE_MASK)); /* Clear MII status bits */ XTemac_mSetIpifReg(XTE_IPISR_OFFSET, Ipisr & (XTE_IPXR_MII_DONE_MASK | XTE_IPXR_MII_PEND_MASK)); return(XST_SUCCESS);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -