/****************************************************************************
 * 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&ETH_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&ETH_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&ETH_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;	

}
Ejemplo n.º 3
0
/****************************************************************************
 * 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&ETH_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&ETH_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&ETH_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&ETH_OPEN_AUTO)
	{	// advertise auto negotiation
		openReqs=_BMSTAT_AN_ABLE_MASK;

		if(oFlags&ETH_OPEN_100)
		{
			if(oFlags&ETH_OPEN_FDUPLEX)
			{
				openReqs|=_BMSTAT_BASE100TX_FDX_MASK;
			}
			if(oFlags&ETH_OPEN_HDUPLEX)
			{
				openReqs|=_BMSTAT_BASE100TX_HDX_MASK;
			}
		}
			
		if(oFlags&ETH_OPEN_10)
		{
			if(oFlags&ETH_OPEN_FDUPLEX)
			{
				openReqs|=_BMSTAT_BASE10T_FDX_MASK;
			}
			if(oFlags&ETH_OPEN_HDUPLEX)
			{
				openReqs|=_BMSTAT_BASE10T_HDX_MASK;
			}
		}		
	}
	else
	{	// no auto negotiation
		if(oFlags&ETH_OPEN_100)
		{
			openReqs=(oFlags&ETH_OPEN_FDUPLEX)?_BMSTAT_BASE100TX_FDX_MASK:_BMSTAT_BASE100TX_HDX_MASK;
		}
		else
		{
			openReqs=(oFlags&ETH_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
	}