/******************************************************************************* * mvEthPhyRestartAN - Restart ethernet Phy Auto-Negotiation. * * DESCRIPTION: * This function resets a given ethernet Phy. * * INPUT: * phyAddr - Phy address. * timeout - in millisec; 0 - no timeout (don't wait) * * OUTPUT: * None. * * RETURN: MV_OK - Success * MV_TIMEOUT - Timeout * *******************************************************************************/ MV_STATUS mvEthPhyRestartAN(MV_U32 phyAddr, int timeout) { MV_U16 phyRegData; /* Reset the PHY */ if (mvEthPhyRegRead(phyAddr, ETH_PHY_CTRL_REG, &phyRegData) != MV_OK) return MV_FAIL; /* Set bit 12 to Enable autonegotiation of the PHY */ phyRegData |= ETH_PHY_CTRL_AN_ENABLE_MASK; /* Set bit 9 to Restart autonegotiation of the PHY */ phyRegData |= ETH_PHY_CTRL_AN_RESTART_MASK; mvEthPhyRegWrite(phyAddr, ETH_PHY_CTRL_REG, phyRegData); if (timeout == 0) return MV_OK; /* Wait untill Auotonegotiation completed */ while (timeout > 0) { mvOsSleep(100); timeout -= 100; if (mvEthPhyRegRead(phyAddr, ETH_PHY_STATUS_REG, &phyRegData) != MV_OK) return MV_FAIL; if (phyRegData & ETH_PHY_STATUS_AN_DONE_MASK) return MV_OK; } return MV_TIMEOUT; }
/******************************************************************************* * mvEthPhyReset - Reset ethernet Phy. * * DESCRIPTION: * This function resets a given ethernet Phy. * * INPUT: * phyAddr - Phy address. * timeout - in millisec * * OUTPUT: * None. * * RETURN: MV_OK - Success * MV_TIMEOUT - Timeout * *******************************************************************************/ MV_STATUS mvEthPhyReset(MV_U32 phyAddr, int timeout) { MV_U16 phyRegData; /* Reset the PHY */ if (mvEthPhyRegRead(phyAddr, ETH_PHY_CTRL_REG, &phyRegData) != MV_OK) return MV_FAIL; /* Set bit 15 to reset the PHY */ phyRegData |= ETH_PHY_CTRL_RESET_MASK; mvEthPhyRegWrite(phyAddr, ETH_PHY_CTRL_REG, phyRegData); /* Wait untill Reset completed */ while (timeout > 0) { mvOsSleep(100); timeout -= 100; if (mvEthPhyRegRead(phyAddr, ETH_PHY_CTRL_REG, &phyRegData) != MV_OK) return MV_FAIL; if ((phyRegData & ETH_PHY_CTRL_RESET_MASK) == 0) return MV_OK; } return MV_TIMEOUT; }
/****************************************************************************** * mvEthCompSataConfig * * DESCRIPTION: * Configure ethernet complex for sata port output. * * INPUT: * ethCompCfg - Ethernet complex configuration bitmap. * * OUTPUT: * None. * * RETURN: * MV_OK on success, * MV_ERROR otherwise. *******************************************************************************/ MV_STATUS mvEthCompSataConfig(MV_U32 ethCompCfg) { MV_U32 reg; MV_U32 tmp; MV_U16 serdesReg; if (!(ethCompCfg & ESC_OPT_SATA)) return MV_OK; /* 3.8.3. LP_SERDES_PHY initialization: * 3.8.3.1. Set LP_SERDES to reset: set Regunit Software Reset Control * register to Reset (0x1). */ MV_REG_BIT_SET(SOFT_RESET_CTRL_REG, SRC_LPSRDSSWRSTN_MASK); /* 3.8.3.2. De-assert LP_SERDES reset: set Regunit Software Reset * Control register to 0x0. */ MV_REG_BIT_RESET(SOFT_RESET_CTRL_REG, SRC_LPSRDSSWRSTN_MASK); reg = MV_REG_READ(MV_ETHCOMP_CTRL_REG(0)); /* 3.8.2.4. Connect LP_SERDES_PHY to required source: set Regunit * Ethernet_Complex_Control_0 register, field "LpphyMode" to "lpphyMode". */ tmp = 0x1; reg &= ~ETHCC_LPPHYMODE_MASK; reg |= (tmp << ETHCC_LPPHYMODE_OFFSET); reg |= ETHCC_LP_SERDES_DATA_SWAP_TX_MASK | ETHCC_LP_SERDES_DATA_SWAP_RX_MASK; MV_REG_WRITE(MV_ETHCOMP_CTRL_REG(0), reg); mvEthCompSetSerdesDefaults(); /* 3.8.3.3. Power up LP_SERDES: set Gunit Serdes Configuration * (SERDESCFG) register, fields "PU_TX", "PU_RX, "PU_PLL" (bits 1,2,3) * to Enable (0x1) */ reg = MV_REG_READ(MV_SATACOMP_SERDESCFG_REG); reg &= ~SERDES_CFG_PU_TX_MASK; reg &= ~SERDES_CFG_PU_RX_MASK; reg &= ~SERDES_CFG_PU_PLL_MASK; MV_REG_WRITE(MV_SATACOMP_SERDESCFG_REG, reg); /* 3.8.3.4. Configuring the LP_SERDES to Reference clock 25M, and * PHY_MODE to SERDES APB3 Reg 0x1. Access to LP_SERDES registers is * done by accessing Gunit0, base address * (0xE00 + (Serdes Reg Address << 2)) 0xE00 + 0x1<<2 = 0x4 + 0xE00 = 0xE04. * Configure to -0xF88. */ mvEthCompSerdesRegWrite(0x1, 0xF801); /* 3.8.3.5. Configyre LP_SERED data rate, by setting Gunit Serdes * Configuration (SERDESCFG) register, fields "PIN_PHY_GEN_TX" and * "PIN_PHY_GEN_RX" to 5Gbps (0xA). */ tmp = 0x1; reg = MV_REG_READ(MV_SATACOMP_SERDESCFG_REG); reg &= ~SERDES_CFG_PHY_GEN_RX_MASK; reg |= (tmp << SERDES_CFG_PHY_GEN_RX_OFFSET); reg &= ~SERDES_CFG_PHY_GEN_TX_MASK; reg |= (tmp << SERDES_CFG_PHY_GEN_TX_OFFSET); MV_REG_WRITE(MV_SATACOMP_SERDESCFG_REG, reg); /* Set PHY Gen Tx & Rx to 0xA, Same as in reg MV_ETHCOMP_SERDESCFG_REG ** Bit[9] - Dig_test_bus_en. */ mvEthCompSerdesRegWrite(0x26, 0x111); /* 3.8.3.6. Configuring the LP_SERDES to 10 bit interface, by setting * its internal register 0x23[11:10] to 0x1. Access to LP_SERDES * registers is done by accessing Gunit0, base address * (0xE00 + (Serdes Reg Address << 2)) = 0xE00 + 0x23<<2 = 0xE00 + 0x8c = 0xE8c. */ serdesReg = mvEthCompSerdesRegRead(0x23); serdesReg &= ~(0x3 << 10); if ((ethCompCfg & ESC_OPT_SATA) || (ethCompCfg & ESC_OPT_QSGMII)) serdesReg |= (0x1 << 10); mvEthCompSerdesRegWrite(0x23, serdesReg); /* 3.8.3.7. Wait for LP_SERDES pin "PLL_READY" to be 0x1. This pin is * reflected in Gunit Serdes Status (SERDESSTS) register, bit[2]. */ do { reg = MV_REG_READ(MV_SATACOMP_SERDESSTS_REG); } while ((reg & (1 << 2)) == 0); /* 3.8.3.8. Set PIN_RX_INIT to 1b1 for at least 16 TXDCLK cycles. Set * Gunit Serdes Configuration (SERDESCFG) register, field "PIN_RX_INIT" * to Enable (0x1). */ MV_REG_BIT_SET(MV_SATACOMP_SERDESCFG_REG, SERDES_CFG_RX_INIT_MASK); mvOsSleep(10); /* 3.8.3.9. Wait for LP_SERDES pin "PIN_RX_INIT_DONE" to be 0x1. This * pin is reflected in Gunit Serdes Status (SERDESSTS) register, bit[0]. */ do { reg = MV_REG_READ(MV_SATACOMP_SERDESSTS_REG); } while ((reg & 0x1) == 0); /* 3.8.3.10. Set PIN_RX_INIT back to 0x0. Set Gunit Serdes Configuration * (SERDESCFG) register; field "PIN_RX_INIT" to Enable (0x0). */ MV_REG_BIT_RESET(MV_SATACOMP_SERDESCFG_REG, SERDES_CFG_RX_INIT_MASK); return MV_OK; }
/****************************************************************************** * mvEthCompSerdesConfig * * DESCRIPTION: * Initialize serdes according to require PHY mode. * * INPUT: * ethCompCfg - Ethernet complex configuration bitmap. * * OUTPUT: * None. * * RETURN: * MV_OK on success, * MV_ERROR otherwise. *******************************************************************************/ static MV_STATUS mvEthCompSerdesConfig(MV_U32 ethCompCfg) { MV_U32 reg; MV_U32 tmp; MV_U16 serdesReg; reg = MV_REG_READ(MV_ETHCOMP_CTRL_REG(0)); /* 3.8.2.4. Connect LP_SERDES_PHY to required source: set Regunit * Ethernet_Complex_Control_0 register, field "LpphyMode" to "lpphyMode". */ if (ethCompCfg & (ESC_OPT_SGMII | ESC_OPT_SGMII_2_5)) tmp = 0x0; else if (ethCompCfg & ESC_OPT_QSGMII) tmp = 0x2; else if (ethCompCfg & ESC_OPT_SATA) tmp = 0x1; else tmp = 0x3; reg &= ~ETHCC_LPPHYMODE_MASK; reg |= (tmp << ETHCC_LPPHYMODE_OFFSET); MV_REG_WRITE(MV_ETHCOMP_CTRL_REG(0), reg); /* 3.8.2.5. Change signal detect indication polarity: set Regunit * QSGMII Control 1 register, field "QsgmiiInvSigdet" to 0x1. */ if (ethCompCfg & ESC_OPT_QSGMII) { reg = MV_REG_READ(MV_ETHCOMP_QSGMII_CONTROL_REG(1)); reg &= ~QSGCTRL_INV_SIG_DET_MASK; reg |= (0x1 << QSGCTRL_INV_SIG_DET_OFFSET); MV_REG_WRITE(MV_ETHCOMP_QSGMII_CONTROL_REG(1), reg); } /* 3.8.3. LP_SERDES_PHY initialization: * 3.8.3.1. Set LP_SERDES to reset: set Regunit Software Reset Control * register to Reset (0x1). */ MV_REG_BIT_SET(SOFT_RESET_CTRL_REG, SRC_LPSRDSSWRSTN_MASK); /* 3.8.3.2. De-assert LP_SERDES reset: set Regunit Software Reset * Control register to 0x0. */ MV_REG_BIT_RESET(SOFT_RESET_CTRL_REG, SRC_LPSRDSSWRSTN_MASK); mvEthCompSetSerdesDefaults(); if (ethCompCfg & ESC_OPT_QSGMII) { mvEthCompSerdesRegWrite(0x25, 0x0); mvEthCompSerdesRegWrite(0x24, mvEthCompSerdesRegRead(0x24) | 0x8000); mvEthCompSerdesRegWrite(0xD, 0x0BE0); mvEthCompSerdesRegWrite(0xE, 0x5055); } else if (ethCompCfg & ESC_OPT_SGMII_2_5) { mvEthCompSerdesRegWrite(0xD, 0x0BEF); mvEthCompSerdesRegWrite(0xE, 0x9055); } else if (ethCompCfg & ESC_OPT_SGMII) { mvEthCompSerdesRegWrite(0xD, 0x0430); mvEthCompSerdesRegWrite(0xE, 0x0080); } /* 3.8.3.3. Power up LP_SERDES: set Gunit Serdes Configuration * (SERDESCFG) register, fields "PU_TX", "PU_RX, "PU_PLL" (bits 1,2,3) * to Enable (0x1) */ reg = MV_REG_READ(MV_ETHCOMP_SERDESCFG_REG); reg &= ~SERDES_CFG_PU_TX_MASK; reg &= ~SERDES_CFG_PU_RX_MASK; reg &= ~SERDES_CFG_PU_PLL_MASK; MV_REG_WRITE(MV_ETHCOMP_SERDESCFG_REG, reg); /* 3.8.3.4. Configuring the LP_SERDES to Reference clock 25M, and * PHY_MODE to SERDES APB3 Reg 0x1. Access to LP_SERDES registers is * done by accessing Gunit0, base address * (0xE00 + (Serdes Reg Address << 2)) 0xE00 + 0x1<<2 = 0x4 + 0xE00 = 0xE04. * Configure to -0xF88. */ mvEthCompSerdesRegWrite(0x1, 0xF880); /* Was 0xF881 */ /* 3.8.3.5. Configyre LP_SERED data rate, by setting Gunit Serdes * Configuration (SERDESCFG) register, fields "PIN_PHY_GEN_TX" and * "PIN_PHY_GEN_RX" to 5Gbps (0xA). */ tmp = 0x4; if (ethCompCfg & ESC_OPT_QSGMII) tmp = 0xA; if (ethCompCfg & ESC_OPT_SATA) tmp = 0x1; reg = MV_REG_READ(MV_ETHCOMP_SERDESCFG_REG); reg &= ~SERDES_CFG_PHY_GEN_RX_MASK; reg |= (tmp << SERDES_CFG_PHY_GEN_RX_OFFSET); reg &= ~SERDES_CFG_PHY_GEN_TX_MASK; reg |= (tmp << SERDES_CFG_PHY_GEN_TX_OFFSET); MV_REG_WRITE(MV_ETHCOMP_SERDESCFG_REG, reg); /* Set PHY Gen Tx & Rx to 0xA, Same as in reg MV_ETHCOMP_SERDESCFG_REG ** Bit[9] - Dig_test_bus_en. */ if (ethCompCfg & ESC_OPT_QSGMII) mvEthCompSerdesRegWrite(0x26, 0x3AA); if (ethCompCfg & ESC_OPT_SGMII) mvEthCompSerdesRegWrite(0x26, 0x144); if (ethCompCfg & ESC_OPT_SGMII_2_5) mvEthCompSerdesRegWrite(0x26, 0x8166); if (ethCompCfg & ESC_OPT_SATA) mvEthCompSerdesRegWrite(0x26, 0x111); /* 3.8.3.6. Configuring the LP_SERDES to 10 bit interface, by setting * its internal register 0x23[11:10] to 0x1. Access to LP_SERDES * registers is done by accessing Gunit0, base address * (0xE00 + (Serdes Reg Address << 2)) = 0xE00 + 0x23<<2 = 0xE00 + 0x8c = 0xE8c. */ serdesReg = mvEthCompSerdesRegRead(0x23); serdesReg &= ~(0x3 << 10); if ((ethCompCfg & ESC_OPT_SATA) || (ethCompCfg & ESC_OPT_QSGMII)) serdesReg |= (0x1 << 10); /* serdesReg |= (0x1 << 10); */ /* serdesReg |= (0x1 << 12); */ /* serdesReg |= (0x1 << 13); // Analog loopback. */ mvEthCompSerdesRegWrite(0x23, serdesReg); #if 0 serdesReg = mvEthCompSerdesRegRead(0x51); serdesReg |= (0x1 << 9); mvEthCompSerdesRegWrite(0x51, serdesReg); #endif /* 3.8.3.7. Wait for LP_SERDES pin "PLL_READY" to be 0x1. This pin is * reflected in Gunit Serdes Status (SERDESSTS) register, bit[2]. */ do { reg = MV_REG_READ(MV_ETHCOMP_SERDESSTS_REG); } while ((reg & (1 << 2)) == 0); /* 3.8.3.8. Set PIN_RX_INIT to 1b1 for at least 16 TXDCLK cycles. Set * Gunit Serdes Configuration (SERDESCFG) register, field "PIN_RX_INIT" * to Enable (0x1). */ MV_REG_BIT_SET(MV_ETHCOMP_SERDESCFG_REG, SERDES_CFG_RX_INIT_MASK); mvOsSleep(10); /* 3.8.3.9. Wait for LP_SERDES pin "PIN_RX_INIT_DONE" to be 0x1. This * pin is reflected in Gunit Serdes Status (SERDESSTS) register, bit[0]. */ do { reg = MV_REG_READ(MV_ETHCOMP_SERDESSTS_REG); } while ((reg & 0x1) == 0); /* 3.8.3.10. Set PIN_RX_INIT back to 0x0. Set Gunit Serdes Configuration * (SERDESCFG) register; field "PIN_RX_INIT" to Enable (0x0). */ MV_REG_BIT_RESET(MV_ETHCOMP_SERDESCFG_REG, SERDES_CFG_RX_INIT_MASK); return MV_OK; }