/**************************************************************************** * Function: EthPhyConfigureMdix * * PreCondition: - Communication to the PHY should have been established. * * Input: oFlags - the requested open flags: ETH_OPEN_MDIX_AUTO, ETH_OPEN_MDIX_NORM/ETH_OPEN_MDIX_SWAP * * Output: ETH_RES_OK - success, * an error code otherwise * * * Side Effects: None * * Overview: This function configures the MDIX mode for the PHY. * * Note: None *****************************************************************************/ eEthRes EthPhyConfigureMdix(eEthOpenFlags oFlags) { unsigned short phyReg; phyReg=EthMIIMReadReg(PHY_REG_PHY_CTRL, PHY_ADDRESS); if(oFlagsÐ_OPEN_MDIX_AUTO) { // enable Auto-MDIX phyReg|=_PHYCTRL_MDIX_EN_MASK; } else { // no Auto-MDIX phyReg&=~(_PHYCTRL_MDIX_EN_MASK); // disable Auto-MDIX if(oFlagsÐ_OPEN_MDIX_SWAP) { phyReg|=_PHYCTRL_FORCE_MDIX_MASK; // swap } else { phyReg&=~(_PHYCTRL_FORCE_MDIX_MASK); // normal } } EthMIIMWriteReg(PHY_REG_PHY_CTRL, PHY_ADDRESS, phyReg); return ETH_RES_OK; }
/**************************************************************************** * Function: EthPhyConfigureMII * * PreCondition: - Communication to the PHY should have been established. * * Input: cFlags - the requested open flags: ETH_PHY_CFG_RMII/ETH_PHY_CFG_MII * * Output: ETH_RES_OK - success, * an error code otherwise * * * Side Effects: None * * Overview: This function configures the PHY in one of MII/RMII operation modes. * * Note: None *****************************************************************************/ eEthRes EthPhyConfigureMII(eEthPhyCfgFlags cFlags) { unsigned short phyReg; phyReg=EthMIIMReadReg(PHY_REG_RMII_BYPASS, PHY_ADDRESS); if(cFlagsÐ_PHY_CFG_RMII) { phyReg|=_RMIIBYPASS_RMII_MODE_MASK; phyReg&=~_RMIIBYPASS_RMII_REV1_0_MASK; // use RMII 1.2 } else { phyReg&=~(_RMIIBYPASS_RMII_MODE_MASK); // MII } EthMIIMWriteReg(PHY_REG_RMII_BYPASS, PHY_ADDRESS, phyReg); // update the RMII and Bypass Register return ETH_RES_OK; }
/**************************************************************************** * Function: EthPhyInit * * PreCondition: - EthInit should have been called. * * Input: oFlags - the requested open flags * cFlags - PHY MII/RMII configuration flags * pResFlags - address to store the initialization result * * Output: ETH_RES_OK for success, * an error code otherwise * * * Side Effects: None * * Overview: This function initializes the PHY communication. * It tries to detect the external PHY, to read the capabilties and find a match * with the requested features. * Then it programs the PHY accordingly. * * Note: None *****************************************************************************/ eEthRes __attribute__((weak)) EthPhyInit(eEthOpenFlags oFlags, eEthPhyCfgFlags cFlags, eEthOpenFlags* pResFlags) { unsigned short ctrlReg; eEthPhyCfgFlags hwFlags, swFlags; unsigned short phyCpbl, openReqs, matchCpbl; eEthRes res; // the way the hw is configured hwFlags=(DEVCFG3bits.FMIIEN!=0)?ETH_PHY_CFG_MII:ETH_PHY_CFG_RMII; hwFlags|=(DEVCFG3bits.FETHIO!=0)?ETH_PHY_CFG_DEFAULT:ETH_PHY_CFG_ALTERNATE; if(cFlagsÐ_PHY_CFG_AUTO) { cFlags=hwFlags; } else { // some minimal check against the way the hw is configured swFlags=cFlags&(ETH_PHY_CFG_RMII|ETH_PHY_CFG_ALTERNATE); if((swFlags ^ hwFlags)!=0) { // hw-sw configuration mismatch MII/RMII, ALT/DEF config return ETH_RES_CFG_ERR; } } _PhyAdd=EthPhyMIIMAddress(); // get the PHY address if(oFlags&(ETH_OPEN_PHY_LOOPBACK|ETH_OPEN_MAC_LOOPBACK)) { oFlags&=~ETH_OPEN_AUTO; // no negotiation in loopback mode! } if(!(oFlagsÐ_OPEN_AUTO)) { oFlags&=~ETH_OPEN_MDIX_AUTO; // Auto-MDIX has to be in auto negotiation only } _PhyInitIo(); // init IO pins EthMIIMInit(GetSystemClock(), EthPhyMIIMClock(), oFlags, (cFlagsÐ_PHY_CFG_RMII)!=0); // try to detect the PHY and reset it if(!_PhyDetectReset()) { // failed to detect the PHY return ETH_RES_DTCT_ERR; } // provide some defaults if(!(oFlags&(ETH_OPEN_FDUPLEX|ETH_OPEN_HDUPLEX))) { oFlags|=ETH_OPEN_HDUPLEX; } if(!(oFlags&(ETH_OPEN_100|ETH_OPEN_10))) { oFlags|=ETH_OPEN_10; } if(oFlagsÐ_OPEN_AUTO) { // advertise auto negotiation openReqs=_BMSTAT_AN_ABLE_MASK; if(oFlagsÐ_OPEN_100) { if(oFlagsÐ_OPEN_FDUPLEX) { openReqs|=_BMSTAT_BASE100TX_FDX_MASK; } if(oFlagsÐ_OPEN_HDUPLEX) { openReqs|=_BMSTAT_BASE100TX_HDX_MASK; } } if(oFlagsÐ_OPEN_10) { if(oFlagsÐ_OPEN_FDUPLEX) { openReqs|=_BMSTAT_BASE10T_FDX_MASK; } if(oFlagsÐ_OPEN_HDUPLEX) { openReqs|=_BMSTAT_BASE10T_HDX_MASK; } } } else { // no auto negotiation if(oFlagsÐ_OPEN_100) { openReqs=(oFlagsÐ_OPEN_FDUPLEX)?_BMSTAT_BASE100TX_FDX_MASK:_BMSTAT_BASE100TX_HDX_MASK; } else { openReqs=(oFlagsÐ_OPEN_FDUPLEX)?_BMSTAT_BASE10T_FDX_MASK:_BMSTAT_BASE10T_HDX_MASK; } } // try to match the oFlags with the PHY capabilities phyCpbl=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); matchCpbl=(openReqs&(MAC_COMM_CPBL_MASK|_BMSTAT_AN_ABLE_MASK))&phyCpbl; // common features if(!(matchCpbl&MAC_COMM_CPBL_MASK)) { // no match? return ETH_RES_CPBL_ERR; } // we're ok, we can configure the PHY res=EthPhyConfigureMII(cFlags); if(res!=ETH_RES_OK) { return res; } res=EthPhyConfigureMdix(oFlags); if(res!=ETH_RES_OK) { return res; } if(matchCpbl&_BMSTAT_AN_ABLE_MASK) { // ok, we can perform auto negotiation unsigned short anadReg; anadReg=(((matchCpbl>>_BMSTAT_NEGOTIATION_POS)<<_ANAD_NEGOTIATION_POS)&_ANAD_NEGOTIATION_MASK)|PROT_802_3; if(MAC_PAUSE_CPBL_MASK&MAC_PAUSE_TYPE_PAUSE) { anadReg|=_ANAD_PAUSE_MASK; } if(MAC_PAUSE_CPBL_MASK&MAC_PAUSE_TYPE_ASM_DIR) { anadReg|=_ANAD_ASM_DIR_MASK; } EthMIIMWriteReg(PHY_REG_ANAD, _PhyAdd, anadReg); // advertise our capabilities EthPhyRestartNegotiation(); // restart negotiation and we'll have to wait }