📄 csl_mdio.c
字号:
/*****************************************************************************\
* Copyright (C) 1999-2003 Texas Instruments Incorporated.
* All Rights Reserved
*------------------------------------------------------------------------------
* FILENAME...... csl_mdio.c
* DATE CREATED.. 02/08/2002
* LAST MODIFIED. 05/09/2003
*------------------------------------------------------------------------------
* NOTE:
* When used in an multitasking environment, no MDIO function may be
* called while another MDIO function is operating on the same device
* handle in another thread. It is the responsibility of the application
* to assure adherence to this restriction.
*
* ALSO NOTE:
* When using the CSL EMAC module, the EMAC module will make use of this
* MDIO module. It is not necessary for the application to call any MDIO
* functions directly when the CSL EMAC module is in use.
*
\******************************************************************************/
/* Include the MDIO file from CSL */
#include <csl_mdiohal.h>
#include <csl_mdio.h>
#if (MDIO_SUPPORT)
/*
* Standard defines/assumptions for MDIO interface
*/
#define VBUSCLK 150 /* VBUS Clock Rate in MHz (1-255) */
/*-----------------------------------------------------------------------*\
* PHY Control Registers
*
* Used by MDIO to configure a MII compliant PHY
\*-----------------------------------------------------------------------*/
#define PHYREG_CONTROL 0
#define PHYREG_CONTROL_RESET (1<<15)
#define PHYREG_CONTROL_LOOPBACK (1<<14)
#define PHYREG_CONTROL_SPEED100 (1<<13)
#define PHYREG_CONTROL_AUTONEGEN (1<<12)
#define PHYREG_CONTROL_POWERDOWN (1<<11)
#define PHYREG_CONTROL_ISOLATE (1<<10)
#define PHYREG_CONTROL_AUTORESTART (1<<9)
#define PHYREG_CONTROL_DUPLEXFULL (1<<8)
#define PHYREG_STATUS 1
#define PHYREG_STATUS_FD100 (1<<14)
#define PHYREG_STATUS_HD100 (1<<13)
#define PHYREG_STATUS_FD10 (1<<12)
#define PHYREG_STATUS_HD10 (1<<11)
#define PHYREG_STATUS_NOPREAMBLE (1<<6)
#define PHYREG_STATUS_AUTOCOMPLETE (1<<5)
#define PHYREG_STATUS_REMOTEFAULT (1<<4)
#define PHYREG_STATUS_AUTOCAPABLE (1<<3)
#define PHYREG_STATUS_LINKSTATUS (1<<2)
#define PHYREG_STATUS_JABBER (1<<1)
#define PHYREG_STATUS_EXTENDED (1<<0)
#define PHYREG_ID1 2
#define PHYREG_ID2 3
#define PHYREG_ADVERTISE 4
#define PHYREG_ADVERTISE_NEXTPAGE (1<<15)
#define PHYREG_ADVERTISE_ACK (1<<14)
#define PHYREG_ADVERTISE_FAULT (1<<13)
#define PHYREG_ADVERTISE_PAUSE (1<<10)
#define PHYREG_ADVERTISE_FD100 (1<<8)
#define PHYREG_ADVERTISE_HD100 (1<<7)
#define PHYREG_ADVERTISE_FD10 (1<<6)
#define PHYREG_ADVERTISE_HD10 (1<<5)
#define PHYREG_ADVERTISE_MSGMASK (0x1F)
#define PHYREG_ADVERTISE_MSG (1)
#define PHYREG_PARTNER 5
#define PHYREG_PARTNER_NEXTPAGE (1<<15)
#define PHYREG_PARTNER_ACK (1<<14)
#define PHYREG_PARTNER_FAULT (1<<13)
#define PHYREG_PARTNER_PAUSE (1<<10)
#define PHYREG_PARTNER_FD100 (1<<8)
#define PHYREG_PARTNER_HD100 (1<<7)
#define PHYREG_PARTNER_FD10 (1<<6)
#define PHYREG_PARTNER_HD10 (1<<5)
#define PHYREG_PARTNER_MSGMASK (0x1F)
/*-----------------------------------------------------------------------*\
* PHY Control Register Macros
*
* These MACROS provide an easy way to read/write PHY registers
\*-----------------------------------------------------------------------*/
#define PHYREG_read(regadr, phyadr) \
MDIO_RSET( USERACCESS0, \
MDIO_FMK(USERACCESS0,GO,1u) | \
MDIO_FMK(USERACCESS0,REGADR,regadr) | \
MDIO_FMK(USERACCESS0,PHYADR,phyadr) )
#define PHYREG_write(regadr, phyadr, data) \
MDIO_RSET( USERACCESS0, \
MDIO_FMK(USERACCESS0,GO,1u) | \
MDIO_FMK(USERACCESS0,WRITE,1u) | \
MDIO_FMK(USERACCESS0,REGADR,regadr) | \
MDIO_FMK(USERACCESS0,PHYADR,phyadr) | \
MDIO_FMK(USERACCESS0,DATA, data) )
#define PHYREG_wait() \
while( MDIO_FGET(USERACCESS0,GO) )
#define PHYREG_waitResults( results ) { \
while( MDIO_FGET(USERACCESS0,GO) ); \
results = MDIO_FGET(USERACCESS0,DATA); }
#define PHYREG_waitResultsAck( results, ack ) { \
while( MDIO_FGET(USERACCESS0,GO) ); \
results = MDIO_FGET(USERACCESS0,DATA); \
ack = MDIO_FGET(USERACCESS0,ACK); }
/*-----------------------------------------------------------------------*\
* PHY State Machine
*
* When using auto-negotiation, the software must keep the MAC in
* sync with the PHY (for duplex). This module will also attempt to
* "auto-select" the PHY from a potential list of 32 based on which is
* first to get a link.
*
* On detection of a good link, the link speed and duplex settings will be
* used to update the EMAC configuration (done external to this module).
\*-----------------------------------------------------------------------*/
/* States in the PHY State Machine */
#define PHYSTATE_MDIOINIT 0
#define PHYSTATE_NWAYSTART 1
#define PHYSTATE_NWAYWAIT 2
#define PHYSTATE_LINKWAIT 3
#define PHYSTATE_LINKED 4
/*
// Tick counts for timeout of each state
// Note that NWAYSTART falls through to NWAYWAIT which falls through
// to LINKWAIT. The timeout is not reset progressing from one state
// to the next, so the system has 5 seconds total to find a link.
*/
static uint PhyStateTimeout[] = { 2, /* PHYSTATE_MDIOINIT - min-delay */
41, /* PHYSTATE_NWAYSTART - 4 seconds */
41, /* PHYSTATE_NWAYWAIT - 4 seconds */
51, /* PHYSTATE_LINKWAIT - 5 seconds */
0 };/* PHYSTATE_LINKED - no timeout*/
typedef struct _MDIO_Device {
uint ModeFlags; /* User specified configuration flgs */
uint phyAddr; /* Current (or next) PHY addr (0-31) */
uint phyState; /* PHY State */
uint phyStateTicks; /* Ticks elapsed in this PHY state */
uint PendingStatus; /* Pending Link Status */
uint LinkStatus; /* Link State EMI_STATUS_LINKSTATUS */
} MDIO_Device;
static void mdioInitStateMachine();
static MDIO_Device localDev;
/*-----------------------------------------------------------------------*\
* mdioInitStateMachine()
*
* Internal function to initialize the state machine. It is referred to
* often in the code as it is called in case of a PHY error
\*-----------------------------------------------------------------------*/
static void mdioInitStateMachine()
{
/* Setup the state machine defaults */
localDev.phyAddr = 0; /* The next PHY to try */
localDev.phyState = PHYSTATE_MDIOINIT; /* PHY State */
localDev.phyStateTicks = 0; /* Ticks elapsed */
localDev.LinkStatus = MDIO_LINKSTATUS_NOLINK;
}
/*-----------------------------------------------------------------------*\
* MDIO_open()
*
* Opens the MDIO peripheral and start searching for a PHY device.
*
* It is assumed that the MDIO module is reset prior to calling this
* function.
\*-----------------------------------------------------------------------*/
Handle MDIO_open( uint mdioModeFlags )
{
/* Get the mode flags from the user - clear our reserved flag */
localDev.ModeFlags = mdioModeFlags & ~MDIO_MODEFLG_NWAYACTIVE;
/* Setup the MDIO state machine */
mdioInitStateMachine();
/* Enable MDIO and setup divider */
MDIO_RSET( CONTROL, MDIO_FMKS(CONTROL,ENABLE,YES) |
MDIO_FMK(CONTROL,CLKDIV,VBUSCLK) );
/* We're done for now - all the rest is done via MDIO_event() */
return( &localDev );
}
/*-----------------------------------------------------------------------*\
* MDIO_close()
*
* Close the MDIO peripheral and disable further operation.
\*-----------------------------------------------------------------------*/
void MDIO_close( Handle hMDIO )
{
Uint32 ltmp1;
uint i;
(void)hMDIO;
/*
// We really don't care what state anything is in at this point,
// but to be safe, we'll isolate all the PHY devices.
*/
ltmp1 = MDIO_RGET( ALIVE );
for( i=0; ltmp1; i++,ltmp1>>=1 )
{
if( ltmp1 & 1 )
{
PHYREG_write( PHYREG_CONTROL, i, PHYREG_CONTROL_ISOLATE |
PHYREG_CONTROL_POWERDOWN );
PHYREG_wait();
}
}
}
/*-----------------------------------------------------------------------*\
* MDIO_getStatus()
*
* Called to get the status of the MDIO/PHY
\*-----------------------------------------------------------------------*/
void MDIO_getStatus( Handle hMDIO, uint *pPhy, uint *pLinkStatus )
{
MDIO_Device *pd = (MDIO_Device *)hMDIO;
if( pPhy )
*pPhy = pd->phyAddr;
if( pLinkStatus )
*pLinkStatus = pd->LinkStatus;
}
/*-----------------------------------------------------------------------*\
* MDIO_timerTick()
*
* Called to signify that approx 100mS have elapsed
*
* Returns an MDIO event code (see MDIO Events in CSL_MDIO.H).
\*-----------------------------------------------------------------------*/
uint MDIO_timerTick( Handle hMDIO )
{
MDIO_Device *pd = (MDIO_Device *)hMDIO;
Uint16 tmp1,tmp2,ack;
Uint32 ltmp1;
uint RetVal = MDIO_EVENT_NOCHANGE;
/*
// If we are linked, we just check to see if we lost link. Otherwise;
// we keep treking through our state machine.
*/
if( pd->phyState == PHYSTATE_LINKED )
{
/*
// Here we check for a "link-change" status indication or a link
// down indication.
*/
ltmp1 = MDIO_RGET( LINKINTRAW ) & 1;
MDIO_RSET( LINKINTRAW, ltmp1 );
if( ltmp1 || !(MDIO_RGET(LINK)&(1<<pd->phyAddr)) )
{
/*
// There has been a change in link (or it is down)
// If we do not auto-neg, then we just wait for a new link
// Otherwise, we enter NWAYSTART or NWAYWAIT
*/
pd->LinkStatus = MDIO_LINKSTATUS_NOLINK;
RetVal = MDIO_EVENT_LINKDOWN;
pd->phyStateTicks = 0; /* Reset timeout */
/* If not NWAY, just wait for link */
if( !(pd->ModeFlags & MDIO_MODEFLG_NWAYACTIVE) )
pd->phyState = PHYSTATE_LINKWAIT;
else
{
/* Handle NWAY condition */
/* First see if link is really down */
PHYREG_read( PHYREG_STATUS, pd->phyAddr );
PHYREG_wait();
PHYREG_read( PHYREG_STATUS, pd->phyAddr );
PHYREG_waitResultsAck( tmp1, ack );
if( !ack )
{
/* No PHY response, maybe it was unplugged */
mdioInitStateMachine();
}
else if( !(tmp1 & PHYREG_STATUS_LINKSTATUS) )
{
/* No Link - restart NWAY */
pd->phyState = PHYSTATE_NWAYSTART;
PHYREG_write( PHYREG_CONTROL, pd->phyAddr,
PHYREG_CONTROL_AUTONEGEN |
PHYREG_CONTROL_AUTORESTART );
PHYREG_wait();
}
else
{
/* We have a Link - re-read NWAY params */
pd->phyState = PHYSTATE_NWAYWAIT;
}
}
}
}
/*
// If running in a non-linked state, execute the next
// state of the state machine.
*/
if( pd->phyState != PHYSTATE_LINKED )
{
/* Bump the time counter */
pd->phyStateTicks++;
/* Process differently based on state */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -