📄 c6455_mdio.c
字号:
/*
* Copyright 2007 by Texas Instruments Incorporated.
* All rights reserved. Property of Texas Instruments Incorporated.
* Restricted rights to use, duplicate or disclose this code are
* granted through contract.
*
* @(#) TCP/IP_Network_Developers_Kit 1.92.00.22 01-10-2007 (ndk-b22)
*/
/*****************************************************************************\
* Copyright (C) 1999-2003 Texas Instruments Incorporated.
* All Rights Reserved
*------------------------------------------------------------------------------
* FILENAME...... c6455_mdio.c
* DATE CREATED.. 08/09/2005
* LAST MODIFIED.
*------------------------------------------------------------------------------
* 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.
*
\******************************************************************************/
/* Include the MDIO header file */
#include "c6455_mdio.h"
#include "usertype.h"
/*
* Standard defines/assumptions for MDIO interface
*/
#define VBUSCLK 165
/*-----------------------------------------------------------------------*\
* 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_SPEEDLSB (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_CONTROL_SPEEDMSB (1<<6)
#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_EXTSTATUS (1<<8)
#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_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)
#define PHYREG_1000CONTROL 9
#define PHYREG_ADVERTISE_FD1000 (1<<9)
#define PHYREG_1000STATUS 0xA
#define PHYREG_PARTNER_FD1000 (1<<11)
#define PHYREG_EXTSTATUS 0x0F
#define PHYREG_EXTSTATUS_FD1000 (1<<13)
#define PHYREG_SHADOW 0x18
#define PHYREG_SHADOW_EXTLOOPBACK 0x8400
#define PHYREG_SHADOW_RGMIIMODE 0xF080
#define PHYREG_SHADOW_INBAND 0xF1C7
#define PHYREG_ACCESS 0x1C
#define PHYREG_ACCESS_COPPER 0xFC00
/*-----------------------------------------------------------------------*\
* PHY Control Register Macros
*
* These MACROS provide an easy way to read/write PHY registers
\*-----------------------------------------------------------------------*/
#define PHYREG_read(regadr, phyadr) \
MDIO_REGS->USERACCESS0 = \
CSL_FMK(MDIO_USERACCESS0_GO,1u) | \
CSL_FMK(MDIO_USERACCESS0_REGADR,regadr) | \
CSL_FMK(MDIO_USERACCESS0_PHYADR,phyadr)
#define PHYREG_write(regadr, phyadr, data) \
MDIO_REGS->USERACCESS0 = \
CSL_FMK(MDIO_USERACCESS0_GO,1u) | \
CSL_FMK(MDIO_USERACCESS0_WRITE,1) | \
CSL_FMK(MDIO_USERACCESS0_REGADR,regadr) | \
CSL_FMK(MDIO_USERACCESS0_PHYADR,phyadr) | \
CSL_FMK(MDIO_USERACCESS0_DATA, data)
#define PHYREG_wait() \
while( CSL_FEXT(MDIO_REGS->USERACCESS0,MDIO_USERACCESS0_GO) )
#define PHYREG_waitResults( results ) { \
while( CSL_FEXT(MDIO_REGS->USERACCESS0,MDIO_USERACCESS0_GO) ); \
results = CSL_FEXT(MDIO_REGS->USERACCESS0,MDIO_USERACCESS0_DATA); }
#define PHYREG_waitResultsAck( results, ack ) { \
while( CSL_FEXT(MDIO_REGS->USERACCESS0,MDIO_USERACCESS0_GO) ); \
results = CSL_FEXT( MDIO_REGS->USERACCESS0,MDIO_USERACCESS0_DATA ); \
ack = CSL_FEXT( MDIO_REGS->USERACCESS0, MDIO_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_RESET 1
#define PHYSTATE_NWAYSTART 2
#define PHYSTATE_NWAYWAIT 3
#define PHYSTATE_LINKWAIT 4
#define PHYSTATE_LINKED 5
/*
// 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 */
6, /* PHYSTATE_RESET - 0.5 sec max */
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 flags */
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 PHYREG_STATUS_LINKSTATUS */
} MDIO_Device;
static void MDIO_initStateMachine( MDIO_Device *pd );
static uint MDIO_initContinue( MDIO_Device *pd );
Uint32 macsel = 0;
/*-----------------------------------------------------------------------*\
* MDIO_initStateMachine()
*
* 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 MDIO_initStateMachine( MDIO_Device *pd )
{
/* Setup the state machine defaults */
pd->phyAddr = 0; /* The next PHY to try */
pd->phyState = PHYSTATE_MDIOINIT; /* PHY State */
pd->phyStateTicks = 0; /* Ticks elapsed */
pd->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 )
{
/*
// Note: In a multi-instance environment, we'd have to allocate "localDev"
*/
static MDIO_Device localDev;
/* Find out what interface we are working with */
macsel = CSL_FEXT(DEV_REGS->DEVSTAT, DEV_DEVSTAT_MACSEL);
/* Get the mode flags from the user - clear our reserved flag */
localDev.ModeFlags = mdioModeFlags & ~MDIO_MODEFLG_NWAYACTIVE;
/* Setup the MDIO state machine */
MDIO_initStateMachine( &localDev );
/* Enable MDIO and setup divider */
MDIO_REGS->CONTROL = CSL_FMKT(MDIO_CONTROL_ENABLE,YES) |
CSL_FMK(MDIO_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_REGS->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 C6455_MDIO.H).
\*-----------------------------------------------------------------------*/
uint MDIO_timerTick( Handle hMDIO )
{
MDIO_Device *pd = (MDIO_Device *)hMDIO;
Uint16 tmp1,tmp2,tmp1gig = 0, tmp2gig = 0, ack;
Uint32 ltmp1 = 0;
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_REGS->LINKINTRAW & 1;
MDIO_REGS->LINKINTRAW = ltmp1;
if( ltmp1 || !(MDIO_REGS->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 */
MDIO_initStateMachine( pd );
}
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 */
switch( pd->phyState )
{
case PHYSTATE_RESET:
/* Don't try to read reset status for the first 100 to 200 ms */
if( pd->phyStateTicks < 2 )
break;
/* See if the PHY has come out of reset */
PHYREG_read( PHYREG_CONTROL, pd->phyAddr );
PHYREG_waitResultsAck( tmp1, ack );
if( ack && !(tmp1 & PHYREG_CONTROL_RESET) )
{
/* PHY is not reset. If the PHY init is going well, break out */
if( MDIO_initContinue( pd ) )
break;
/* Else, this PHY is toast. Manually trigger a timeout */
pd->phyStateTicks = PhyStateTimeout[pd->phyState];
}
/* Fall through to timeout check */
case PHYSTATE_MDIOINIT:
CheckTimeout:
/* Here we just check timeout and try to find a PHY */
if( pd->phyStateTicks >= PhyStateTimeout[pd->phyState] )
{
// Try the next PHY if anything but a MDIOINIT condition
if( pd->phyState != PHYSTATE_MDIOINIT )
if( ++pd->phyAddr == 32 )
pd->phyAddr = 0;
ltmp1 = MDIO_REGS->ALIVE;
for( tmp1=0; tmp1<32; tmp1++ )
{
if( ltmp1 & (1<<pd->phyAddr) )
{
if( MDIO_initPHY( pd, pd->phyAddr ) )
break;
}
if( ++pd->phyAddr == 32 )
pd->phyAddr = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -