/**************************************************************************** * 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; EthMIIMReadStart(PHY_REG_SPECIAL_CTRL, PHY_ADDRESS); phyReg=EthMIIMReadResult()&(_SPECIALCTRL_XPOL_MASK); // mask off not used bits if(oFlagsÐ_OPEN_MDIX_AUTO) { // enable Auto-MDIX phyReg&=~_SPECIALCTRL_AMDIXCTRL_MASK; } else { // no Auto-MDIX phyReg|=_SPECIALCTRL_AMDIXCTRL_MASK; // disable Auto-MDIX if(oFlagsÐ_OPEN_MDIX_SWAP) { phyReg|=_SPECIALCTRL_CH_SELECT_MASK; // swap } else { phyReg&=~_SPECIALCTRL_CH_SELECT_MASK; // normal } } EthMIIMWriteStart(PHY_REG_SPECIAL_CTRL, PHY_ADDRESS, phyReg); return ETH_RES_OK; }
/**************************************************************************** * 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; EthMIIMReadStart(PHY_REG_PHY_CTRL, PHY_ADDRESS); phyReg=EthMIIMReadResult(); 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 } } EthMIIMWriteStart(PHY_REG_PHY_CTRL, PHY_ADDRESS, phyReg); return ETH_RES_OK; }
/**************************************************************************** * Function: EthPhyRestartNegotiation * * PreCondition: - EthPhyInit should have been called. * - The PHY should have been initialized with proper duplex/speed mode! * * Input: None * * Output: ETH_RES_OK for success, * ETH_RES_NEGOTIATION_UNABLE if the auto-negotiation is not supported. * * Side Effects: None * * Overview: This function restarts the PHY negotiation. * After this restart the link can be reconfigured. * The EthPhyGetNegotiationResults() can be used to see the outcoming result. * * Note: None *****************************************************************************/ eEthRes __attribute__((weak)) EthPhyRestartNegotiation(void) { eEthRes res; __BMSTATbits_t phyCpbl; phyCpbl.w=_PhyReadReg(PHY_REG_BMSTAT, _PhyAdd); if(phyCpbl.AN_ABLE) { // ok, we can perform auto negotiation EthMIIMWriteStart(PHY_REG_BMCON, _PhyAdd, _BMCON_AN_ENABLE_MASK|_BMCON_AN_RESTART_MASK); // restart negotiation and we'll have to wait res=ETH_RES_OK; } else { res=ETH_RES_NEGOTIATION_UNABLE; // no negotiation ability! } return res; }
/**************************************************************************** * Function: EthPhyConfigureMII * * PreCondition: - Communication to the PHY should have been established. * * Input: cFlags - the requested configuration 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; EthMIIMReadStart(PHY_REG_SPECIAL_MODE, PHY_ADDRESS); phyReg=EthMIIMReadResult()&(_SPECIALMODE_PHYAD_MASK|_SPECIALMODE_MODE_MASK); // not used bits should be 0 if(cFlagsÐ_PHY_CFG_RMII) { phyReg|=_SPECIALMODE_MIIMODE_MASK; } else { phyReg&=~_SPECIALMODE_MIIMODE_MASK; } EthMIIMWriteStart(PHY_REG_SPECIAL_MODE, PHY_ADDRESS, phyReg); // update the Special Modes reg 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; EthMIIMReadStart(PHY_REG_RMII_BYPASS, PHY_ADDRESS); phyReg=EthMIIMReadResult(); 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 } EthMIIMWriteStart(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=EthPhyGetHwConfigFlags(); 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 } oFlags|=(cFlagsÐ_PHY_CFG_RMII)?ETH_OPEN_RMII:ETH_OPEN_MII; _PhyInitIo(); // init IO pins EthMIIMConfig(GetSystemClock(), EthPhyMIIMClock()); // 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=_PhyReadReg(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(ETH_MAC_PAUSE_CPBL_MASK & ETH_MAC_PAUSE_TYPE_PAUSE) { anadReg|=_ANAD_PAUSE_MASK; } if(ETH_MAC_PAUSE_CPBL_MASK& ETH_MAC_PAUSE_TYPE_ASM_DIR) { anadReg|=_ANAD_ASM_DIR_MASK; } EthMIIMWriteStart(PHY_REG_ANAD, _PhyAdd, anadReg); // advertise our capabilities EthPhyRestartNegotiation(); // restart negotiation and we'll have to wait }