#include "3C90x.h"
void
Apple3Com3C90x::physicalMgmtWriteWord( UInt32 word, UInt8 bits )
{
UInt16 reg;
for ( int shifts = 31; (shifts >= 0) && bits; shifts--, bits-- )
{
reg = kPhysicalMgmtDirWrite
| ( (word & (1 << shifts)) ? kPhysicalMgmtDataMask : 0 );
setPhysicalMgmt( reg );
IODelay( kMIIDelay );
reg |= kPhysicalMgmtClkMask;
setPhysicalMgmt( reg );
IODelay( kMIIDelay );
reg &= ~kPhysicalMgmtClkMask;
setPhysicalMgmt( reg );
IODelay( kMIIDelay );
}
}
UInt8 Apple3Com3C90x::physicalMgmtReadBit()
{
UInt16 reg;
reg = kPhysicalMgmtDirRead;
setPhysicalMgmt( reg );
IODelay( kMIIDelay );
reg = kPhysicalMgmtDirRead | kPhysicalMgmtClkMask;
setPhysicalMgmt( reg );
IODelay( kMIIDelay );
reg = kPhysicalMgmtDirRead;
setPhysicalMgmt( reg );
IODelay( kMIIDelay );
reg = getPhysicalMgmt();
return ( reg & kPhysicalMgmtDataMask ) ? 1 : 0;
}
bool
Apple3Com3C90x::miiReadWord( PHYAddress phyAddr,
PHYRegAddr phyReg,
PHYWord * phyData )
{
UInt32 miiFrame;
PHYWord value = 0;
bool ret = true;
physicalMgmtWriteWord( kMIIFramePreamble, kMIIFrameSize );
miiFrame = kMIIFrameStart
| kMIIFrameOpcodeRead
| SetBitField( MIIFrame, RegAddr, phyReg )
| SetBitField( MIIFrame, PhyAddr, phyAddr );
physicalMgmtWriteWord( miiFrame, 14 );
if ( physicalMgmtReadBit() ) ret = false;
for ( int i = 0; i < 16; i++ )
{
value = physicalMgmtReadBit() | (value << 1);
}
if ( phyData )
*phyData = value;
physicalMgmtReadBit();
return ret;
}
void
Apple3Com3C90x::miiWriteWord( PHYAddress phyAddr,
PHYRegAddr phyReg,
PHYWord phyData )
{
UInt32 miiFrame;
physicalMgmtWriteWord( kMIIFramePreamble, kMIIFrameSize );
miiFrame = kMIIFrameStart
| kMIIFrameOpcodeWrite
| kMIIFrameTAWrite
| SetBitField( MIIFrame, RegAddr, phyReg )
| SetBitField( MIIFrame, PhyAddr, phyAddr )
| SetBitField( MIIFrame, Data, phyData );
physicalMgmtWriteWord( miiFrame, kMIIFrameSize );
physicalMgmtReadBit();
}
bool Apple3Com3C90x::phyProbe( PHYAddress phy )
{
if ( phy > kPHYAddrMax ) return false;
return( miiReadWord( phy, kMIIRegisterStatus ) );
}
bool Apple3Com3C90x::phyReset( PHYAddress phy )
{
bool success = false;
PHYWord control;
LOG_PHY("%s::%s\n", getName(), __FUNCTION__);
if ( miiReadWord( phy, kMIIRegisterControl, &control ) == false )
return false;
miiWriteWord( phy, kMIIRegisterControl,
(control | kMIIControlResetMask) );
for ( SInt32 timeout = kPHYResetTimeout;
timeout > 0;
timeout -= kPHYResetDelay )
{
if ( miiReadWord( phy, kMIIRegisterControl, &control ) == false )
break;
if ( (control & kMIIControlResetMask) == 0 )
{
IOSleep(10);
success = true;
break;
}
IOSleep( kPHYResetDelay );
}
return success;
}
bool Apple3Com3C90x::phyWaitForValidLink( PHYAddress phy )
{
PHYWord status;
LOG_PHY("%s::%s\n", getName(), __FUNCTION__);
for ( SInt32 timeout = kPHYLinkTimeout;
timeout > 0;
timeout -= kPHYLinkDelay )
{
if ( miiReadWord( phy, kMIIRegisterStatus, &status ) == false )
return false;
if ( status & kMIIStatusLinkValidMask )
return true;
IOSleep( kPHYLinkDelay );
}
return false;
}
bool Apple3Com3C90x::phyWaitForNegotiation( PHYAddress phy )
{
PHYWord status;
LOG_PHY("%s::%s\n", getName(), __FUNCTION__);
for ( SInt32 timeout = kPHYLinkTimeout;
timeout > 0;
timeout -= kPHYLinkDelay )
{
if ( miiReadWord( phy, kMIIRegisterStatus, &status ) == false )
return false;
if ( status & kMIIStatusNegotiationCompleteMask )
return true;
IOSleep( kPHYLinkDelay );
}
return false;
}
UInt32 Apple3Com3C90x::phyGetSupportedLinks( PHYAddress phy )
{
PHYWord status;
UInt32 mask = 0;
if ( miiReadWord( phy, kMIIRegisterStatus, &status ) == true )
{
mask = GetBitField( MIIStatus, Links, status );
}
return mask;
}
MIILink Apple3Com3C90x::phyGetBestNegotiatedLink( PHYAddress phy,
MIILink phyLink,
MIILink reportedLink,
PHYWord * reportedStatus )
{
MIILink newLink = kMIILinkNone;
PHYWord status;
miiReadWord( phy, kMIIRegisterStatus, &status );
if ( reportedStatus )
{
if ( ( ( status ^ *reportedStatus ) &
( kMIIStatusNegotiationCompleteMask |
kMIIStatusLinkValidMask ) ) == 0 )
{
return reportedLink;
}
*reportedStatus = status; }
if ( phyLink & kMIILinkNway )
{
if (( status &
( kMIIStatusLinkValidMask | kMIIStatusNegotiationCompleteMask ))
== ( kMIIStatusLinkValidMask | kMIIStatusNegotiationCompleteMask ))
{
PHYWord local, remote;
if ( miiReadWord( phy, kMIIRegisterAdvertisement, &local ) &&
miiReadWord( phy, kMIIRegisterLinkPartner, &remote ) )
{
UInt32 commonLinks;
LOG_PHY("%s: local links: 0x%04x\n", getName(),
GetBitField( MIIAdvertisement, Links, local ));
LOG_PHY("%s: remote links: 0x%04x\n", getName(),
GetBitField( MIILinkPartner, Links, remote ));
commonLinks = GetBitField( MIIAdvertisement, Links, local ) &
GetBitField( MIILinkPartner, Links, remote );
if ( commonLinks & kMIILink100TX_FD )
newLink = kMIILink100TX_FD;
else if ( commonLinks & kMIILink100T4 )
newLink = kMIILink100T4;
else if ( commonLinks & kMIILink100TX )
newLink = kMIILink100TX;
else if ( commonLinks & kMIILink10BT_FD )
newLink = kMIILink10BT_FD;
else if ( commonLinks & kMIILink10BT )
newLink = kMIILink10BT;
}
}
}
else
{
if ( status & kMIIStatusLinkValidMask )
newLink = phyLink;
}
newLink |= ( phyLink & kMIILinkNway );
return newLink;
}
UInt32 Apple3Com3C90x::phyGetIdentifier( PHYAddress phy )
{
UInt32 id = kPHYIDInvalid;
UInt16 id_hi;
UInt16 id_lo;
if ( miiReadWord( phy, kMIIRegisterID0, &id_hi ) &&
miiReadWord( phy, kMIIRegisterID1, &id_lo ) )
{
id = ((id_hi << 16) & 0xffff0000) | id_lo;
}
LOG_PHY("%s: PHY ID = %08lx\n", getName(), id);
return id;
}
bool Apple3Com3C90x::phyForceMIILink( PHYAddress phy, MIILink link )
{
PHYWord reg;
UInt32 linkMask;
LOG_PHY("%s::%s(%lx)\n", getName(), __FUNCTION__, link);
if ( link & kMIILinkNway )
return false;
if ( ( link & kMIILinkMask ) == kMIILinkNone )
return false;
linkMask = phyGetSupportedLinks( phy );
if ( ( link & linkMask ) == 0 )
{
LOG_PHY("%s::%s PHY does not support link %lx\n",
getName(), __FUNCTION__, link);
return false;
}
if ( phyReset( phy ) == false )
{
LOG_PHY("%s::%s PHY reset error\n", getName(), __FUNCTION__);
return false;
}
if ( miiReadWord( phy, kMIIRegisterAdvertisement, ® ) )
{
reg &= ~( kMIIAdvertisementProtocolMask |
kMIIAdvertisementLinksMask |
kMIIAdvertisementPauseCapableMask );
reg |= SetBitField( MIIAdvertisement, Links, link );
reg |= SetBitField( MIIAdvertisement, Protocol, 0x01 );
if (_flowControlEnabled)
reg |= SetBitField( MIIAdvertisement, PauseCapable, 0x01 );
miiWriteWord( phy, kMIIRegisterAdvertisement, reg );
phyWaitForNegotiation( phy );
}
if ( miiReadWord( phy, kMIIRegisterControl, ® ) == false )
{
LOG_PHY("%s::%s CONTROL read error\n", getName(), __FUNCTION__);
return false;
}
reg &= ~( kMIIControlSpeedSelectionMask |
kMIIControlFullDuplexMask |
kMIIControlIsolateMask |
kMIIControlAutoNegotiationMask );
if ( link >= kMIILink100TX )
reg |= kMIIControlSpeedSelectionMask;
if ( link & ( kMIILink100TX_FD | kMIILink10BT_FD ) )
reg |= kMIIControlFullDuplexMask;
miiWriteWord( phy, kMIIRegisterControl, reg );
LOG_PHY("%s::%s CONTROL set to %04x\n", getName(), __FUNCTION__,
reg);
return true;
}
bool
Apple3Com3C90x::phyStartNegotiation( PHYAddress phy )
{
PHYWord reg;
UInt32 linkMask;
LOG_PHY("%s::%s\n", getName(), __FUNCTION__);
if ( phyReset( phy ) == false )
{
LOG_PHY("%s::%s PHY reset error\n", getName(), __FUNCTION__);
return false;
}
if ( miiReadWord( phy, kMIIRegisterStatus, ® ) == false )
{
LOG_PHY("%s::%s STATUS read error\n", getName(), __FUNCTION__);
return false;
}
if ( ( reg & kMIIStatusNegotiationAbilityMask ) == 0 )
{
LOG_PHY("%s::%s no Nway support\n", getName(), __FUNCTION__);
return false;
}
linkMask = phyGetSupportedLinks( phy );
if ( linkMask == 0 )
{
LOG_PHY("%s::%s zero link support\n", getName(), __FUNCTION__);
return false;
}
if ( miiReadWord( phy, kMIIRegisterAdvertisement, ® ) == false )
{
LOG_PHY("%s::%s: ANAR read error\n", getName(), __FUNCTION__);
return false;
}
reg &= ~( kMIIAdvertisementProtocolMask |
kMIIAdvertisementLinksMask |
kMIIAdvertisementPauseCapableMask );
reg |= SetBitField( MIIAdvertisement, Links, linkMask );
reg |= SetBitField( MIIAdvertisement, Protocol, 0x01 );
if (_flowControlEnabled)
reg |= SetBitField( MIIAdvertisement, PauseCapable, 0x01 );
miiWriteWord( phy, kMIIRegisterAdvertisement, reg );
if ( miiReadWord( phy, kMIIRegisterControl, ® ) == false )
{
LOG_PHY("%s::%s CONTROL read error\n", getName(), __FUNCTION__);
return false;
}
reg |= ( kMIIControlAutoNegotiationMask |
kMIIControlRestartNegotiationMask );
miiWriteWord( phy, kMIIRegisterControl, reg );
return true;
}