You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
658 lines
17 KiB
658 lines
17 KiB
3 weeks ago
|
/* vxbYt8521Phy.c - driver for yt8521 10/100/1000 ethernet PHY chips */
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
|
||
|
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <vxWorks.h>
|
||
|
#include <vxBusLib.h>
|
||
|
#include <logLib.h>
|
||
|
|
||
|
#include <hwif/vxbus/vxBus.h>
|
||
|
#include <hwif/util/hwMemLib.h>
|
||
|
|
||
|
#include <hwif/util/vxbParamSys.h>
|
||
|
#include <../src/hwif/h/mii/miiBus.h>
|
||
|
#include <vxbYt8521Phy.h>
|
||
|
|
||
|
/* defines */
|
||
|
|
||
|
#undef YT8521PHY_DEBUG
|
||
|
#ifdef YT8521PHY_DEBUG
|
||
|
#define YT8521PHY_LOGMSG(fmt,p1,p2,p3,p4,p5,p6) logMsg(fmt,p1,p2,p3,p4,p5,p6)
|
||
|
#else
|
||
|
#define YT8521PHY_LOGMSG(fmt,p1,p2,p3,p4,p5,p6)
|
||
|
#endif
|
||
|
|
||
|
/* externs */
|
||
|
|
||
|
IMPORT BOOL autoNegForce;
|
||
|
|
||
|
/* locals */
|
||
|
LOCAL STATUS ytPhyExtRead(VXB_DEVICE_ID ,UINT32 , UINT16*);
|
||
|
LOCAL STATUS ytPhyExtWrite(VXB_DEVICE_ID ,UINT32 ,UINT16);
|
||
|
LOCAL STATUS ytPhyConfigInit(VXB_DEVICE_ID pDev);
|
||
|
LOCAL void ytPhyInit (VXB_DEVICE_ID);
|
||
|
LOCAL STATUS ytPhyModeSet (VXB_DEVICE_ID, UINT32);
|
||
|
LOCAL STATUS ytPhyModeGet (VXB_DEVICE_ID, UINT32 *, UINT32 *);
|
||
|
|
||
|
LOCAL void ytPhyDevInstInit(VXB_DEVICE_ID pDev);
|
||
|
LOCAL void ytPhyDevInstInit2(VXB_DEVICE_ID pDev);
|
||
|
LOCAL void ytPhyDevInstConnect(VXB_DEVICE_ID pDev);
|
||
|
LOCAL BOOL ytPhyProbe(VXB_DEVICE_ID pDev);
|
||
|
LOCAL STATUS ytPhyInstUnlink (VXB_DEVICE_ID, void *);
|
||
|
|
||
|
LOCAL device_method_t ytPhyMethods[] =
|
||
|
{
|
||
|
DEVMETHOD(miiModeGet, ytPhyModeGet),
|
||
|
DEVMETHOD(miiModeSet, ytPhyModeSet),
|
||
|
DEVMETHOD(vxbDrvUnlink, ytPhyInstUnlink),
|
||
|
{ 0, 0 }
|
||
|
};
|
||
|
|
||
|
LOCAL struct drvBusFuncs ytPhyFuncs =
|
||
|
{
|
||
|
ytPhyDevInstInit, /* devInstanceInit */
|
||
|
ytPhyDevInstInit2, /* devInstanceInit2 */
|
||
|
ytPhyDevInstConnect /* devInstanceConnect */
|
||
|
};
|
||
|
|
||
|
LOCAL VXB_PARAMETERS ytPhyParamDefaults[] =
|
||
|
{
|
||
|
{"fcmode", VXB_PARAM_INT32, {(void *)MII_FCADV_NONE}},
|
||
|
{NULL, VXB_PARAM_END_OF_LIST, {NULL}}
|
||
|
};
|
||
|
|
||
|
struct vxbDevRegInfo ytPhyDevRegistration =
|
||
|
{
|
||
|
NULL, /* pNext */
|
||
|
VXB_DEVID_DEVICE, /* devID */
|
||
|
VXB_BUSID_MII, /* busID = MII Bus */
|
||
|
VXB_VER_5_0_0, /* busVer */
|
||
|
"yt8521Phy", /* drvName */
|
||
|
&ytPhyFuncs, /* pDrvBusFuncs */
|
||
|
ytPhyMethods, /* pMethods */
|
||
|
ytPhyProbe, /* devProbe */
|
||
|
ytPhyParamDefaults /* parameter defaults */
|
||
|
};
|
||
|
|
||
|
void ytPhyRegister(void)
|
||
|
{
|
||
|
vxbDevRegister (&ytPhyDevRegistration);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
LOCAL void ytPhyDevInstInit
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
vxbNextUnitGet (pDev);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
LOCAL void ytPhyDevInstConnect
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************
|
||
|
*
|
||
|
* ytPhyInstUnlink - VxBus unlink handler
|
||
|
*
|
||
|
* This function implements the VxBus unlink method for this driver.
|
||
|
* We delete each media type that was originally added to the MII bus
|
||
|
* instance by this device and take ourselves off the miiMonitor task
|
||
|
* list.
|
||
|
*
|
||
|
* RETURNS: OK if shutdown succeeds, else ERROR
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL STATUS ytPhyInstUnlink
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
void * unused
|
||
|
)
|
||
|
{
|
||
|
VXB_DEVICE_ID pBus;
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
UINT16 miiSts;
|
||
|
|
||
|
pDrvCtrl = (MII_DRV_CTRL *)pDev->pDrvCtrl;
|
||
|
|
||
|
if (pDrvCtrl->miiInitialized == FALSE)
|
||
|
return (ERROR);
|
||
|
|
||
|
/* Only our parent bus can delete us. */
|
||
|
if (pDrvCtrl->miiLeaving == FALSE)
|
||
|
return (ERROR);
|
||
|
|
||
|
/* Remove ourselves from the miiMonitor task list. */
|
||
|
|
||
|
miiBusListDel (pDev);
|
||
|
|
||
|
/* Remove media list entries. */
|
||
|
|
||
|
if ((pBus = vxbDevParent (pDev)) == NULL)
|
||
|
return (ERROR);
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_STAT_REG, &miiSts);
|
||
|
|
||
|
if (miiSts & MII_SR_EXT_STS)
|
||
|
{
|
||
|
miiBusMediaDel (pBus, IFM_ETHER|IFM_1000_T);
|
||
|
miiBusMediaDel (pBus, IFM_ETHER|IFM_1000_T|IFM_FDX);
|
||
|
}
|
||
|
|
||
|
if (miiSts & MII_SR_TX_HALF_DPX)
|
||
|
miiBusMediaDel (pBus, IFM_ETHER|IFM_100_TX);
|
||
|
if (miiSts & MII_SR_TX_FULL_DPX)
|
||
|
miiBusMediaDel (pBus, IFM_ETHER|IFM_100_TX|IFM_FDX);
|
||
|
if (miiSts & MII_SR_10T_HALF_DPX)
|
||
|
miiBusMediaDel (pBus, IFM_ETHER|IFM_10_T);
|
||
|
if (miiSts & MII_SR_10T_FULL_DPX)
|
||
|
miiBusMediaDel (pBus, IFM_ETHER|IFM_10_T|IFM_FDX);
|
||
|
if (miiSts & MII_SR_AUTO_SEL)
|
||
|
miiBusMediaDel (pBus, IFM_ETHER|IFM_AUTO);
|
||
|
|
||
|
pDrvCtrl->miiInitialized = FALSE;
|
||
|
|
||
|
free (pDrvCtrl);
|
||
|
|
||
|
return (OK);
|
||
|
}
|
||
|
|
||
|
/*********************************************************************
|
||
|
*
|
||
|
* ytPhyDevInstInit2 - vxBus instInit2 handler
|
||
|
*
|
||
|
* This routine does the final driver setup. The PHY registers
|
||
|
* its media types with its parent bus and adds itself to the MII
|
||
|
* monitoring list.
|
||
|
*
|
||
|
* RETURNS: N/A
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL void ytPhyDevInstInit2
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
VXB_DEVICE_ID pBus;
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
VXB_INST_PARAM_VALUE val;
|
||
|
UINT16 miiSts;
|
||
|
|
||
|
YT8521PHY_LOGMSG("ytPhyDevInstInit2(): entry for pDev: 0x%x\n",
|
||
|
(int)pDev, 0,0,0,0,0);
|
||
|
|
||
|
pDrvCtrl = (MII_DRV_CTRL *)pDev->pDrvCtrl;
|
||
|
|
||
|
if (pDrvCtrl->miiInitialized == TRUE)
|
||
|
{
|
||
|
YT8521PHY_LOGMSG("ytPhyDevInstInit2(): already initialized\n",
|
||
|
0,0,0,0,0,0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pDrvCtrl->miiInitialized = TRUE;
|
||
|
|
||
|
/*
|
||
|
* Tell miiBus about the media we support.
|
||
|
*/
|
||
|
|
||
|
if ((pBus = vxbDevParent (pDev)) == NULL)
|
||
|
return;
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_STAT_REG, &miiSts);
|
||
|
|
||
|
if (miiSts & MII_SR_EXT_STS)
|
||
|
{
|
||
|
miiBusMediaAdd (pBus, IFM_ETHER|IFM_1000_T);
|
||
|
miiBusMediaAdd (pBus, IFM_ETHER|IFM_1000_T|IFM_FDX);
|
||
|
}
|
||
|
|
||
|
if (miiSts & MII_SR_TX_HALF_DPX)
|
||
|
miiBusMediaAdd (pBus, IFM_ETHER|IFM_100_TX);
|
||
|
if (miiSts & MII_SR_TX_FULL_DPX)
|
||
|
miiBusMediaAdd (pBus, IFM_ETHER|IFM_100_TX|IFM_FDX);
|
||
|
if (miiSts & MII_SR_10T_HALF_DPX)
|
||
|
miiBusMediaAdd (pBus, IFM_ETHER|IFM_10_T);
|
||
|
if (miiSts & MII_SR_10T_FULL_DPX)
|
||
|
miiBusMediaAdd (pBus, IFM_ETHER|IFM_10_T|IFM_FDX);
|
||
|
if (miiSts & MII_SR_AUTO_SEL)
|
||
|
miiBusMediaAdd (pBus, IFM_ETHER|IFM_AUTO);
|
||
|
|
||
|
miiBusMediaDefaultSet (pBus, IFM_ETHER|IFM_AUTO);
|
||
|
|
||
|
/*
|
||
|
* Initialize the PHY. This may perform DSP code
|
||
|
* tweaking as needed.
|
||
|
*/
|
||
|
|
||
|
ytPhyInit (pDev);
|
||
|
|
||
|
/* Add to the monitor list. */
|
||
|
|
||
|
miiBusListAdd (pDev);
|
||
|
|
||
|
/*
|
||
|
* paramDesc {
|
||
|
* The fcmode parameter specifies how we advertise
|
||
|
* the device flow control ability. The selection can be
|
||
|
* MII_FCADV_NONE, MII_FCADV_PAUSE, MII_FCADV_ASM,
|
||
|
* MII_FCADV_PAUSE_ASM. }
|
||
|
*/
|
||
|
|
||
|
if (vxbInstParamByNameGet (pDev, "fcmode", VXB_PARAM_INT32, &val) == OK)
|
||
|
{
|
||
|
pDrvCtrl->fcmode = (UINT16) (val.int32Val);
|
||
|
}
|
||
|
else
|
||
|
pDrvCtrl->fcmode = (UINT16) MII_FCADV_NONE;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************
|
||
|
*
|
||
|
* ytPhyProbe - vxBus yt8521Phy probe handler
|
||
|
*
|
||
|
* This routine always returns TRUE.
|
||
|
*
|
||
|
* RETURNS: TRUE always.
|
||
|
*
|
||
|
* ERRNO: N/A
|
||
|
*/
|
||
|
|
||
|
LOCAL BOOL ytPhyProbe
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
UINT16 miiId1;
|
||
|
UINT16 miiId2;
|
||
|
|
||
|
pDrvCtrl = pDev->pDrvCtrl;
|
||
|
miiId1 = pDrvCtrl->miiId1;
|
||
|
miiId2 = pDrvCtrl->miiId2;
|
||
|
|
||
|
if ((miiId1 == 0x0000)&&(miiId2==0x011a))
|
||
|
return (TRUE);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
LOCAL void ytPhyInit
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
UINT16 miiSts;
|
||
|
UINT16 miiCtl;
|
||
|
UINT16 miiVal;
|
||
|
int i;
|
||
|
|
||
|
pDrvCtrl = (MII_DRV_CTRL *)pDev->pDrvCtrl;
|
||
|
|
||
|
ytPhyConfigInit(pDev);
|
||
|
|
||
|
/* Get status register so we can look for extended capabilities. */
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_STAT_REG, &miiSts);
|
||
|
|
||
|
miiVal = MII_CR_POWER_DOWN;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, miiVal);
|
||
|
|
||
|
miiVal = 0;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, miiVal);
|
||
|
|
||
|
/* Set reset bit and then wait for it to clear. */
|
||
|
|
||
|
miiVal = MII_CR_RESET;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, miiVal);
|
||
|
|
||
|
for (i = 0; i < 1000; i++)
|
||
|
{
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, &miiCtl);
|
||
|
if (!(miiCtl & MII_CR_RESET))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i == 1000)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If the extended capabilities bit is set, this is a gigE
|
||
|
* PHY, so make sure we advertise gigE modes.
|
||
|
*/
|
||
|
|
||
|
if (miiSts & MII_SR_EXT_STS)
|
||
|
{
|
||
|
/* Enable advertisement of gigE modes. */
|
||
|
miiVal = MII_MASSLA_CTRL_1000T_FD|MII_MASSLA_CTRL_1000T_HD;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_MASSLA_CTRL_REG, miiVal);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Some PHYs come out of reset with their isolate bit set. Make
|
||
|
* sure we don't write that bit back when setting the control
|
||
|
* register.
|
||
|
*/
|
||
|
|
||
|
miiCtl = MII_CR_AUTO_EN|MII_CR_RESTART;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, miiCtl);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
LOCAL STATUS ytPhyModeSet
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
UINT32 mode
|
||
|
)
|
||
|
{
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
UINT16 miiVal;
|
||
|
UINT16 miiAnar = 0;
|
||
|
UINT16 gmiiAnar = 0;
|
||
|
UINT16 miiCtl = 0;
|
||
|
UINT16 miiSts;
|
||
|
BOOL autoneg = TRUE;
|
||
|
|
||
|
pDrvCtrl = (MII_DRV_CTRL *)pDev->pDrvCtrl;
|
||
|
|
||
|
/* Get status register so we can look for extended capabilities. */
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_STAT_REG, &miiSts);
|
||
|
|
||
|
switch(IFM_SUBTYPE(mode)) {
|
||
|
case IFM_AUTO:
|
||
|
|
||
|
/* Set autoneg advertisement to advertise all modes. */
|
||
|
|
||
|
miiAnar = MII_ANAR_10TX_HD|MII_ANAR_10TX_FD|
|
||
|
MII_ANAR_100TX_HD|MII_ANAR_100TX_FD;
|
||
|
if (miiSts & MII_SR_EXT_STS)
|
||
|
gmiiAnar = MII_MASSLA_CTRL_1000T_FD|MII_MASSLA_CTRL_1000T_HD;
|
||
|
miiCtl = MII_CR_AUTO_EN|MII_CR_RESTART;
|
||
|
break;
|
||
|
case IFM_1000_T:
|
||
|
|
||
|
/* Auto-negotiation is mandatory per IEEE in 1000BASE-T. */
|
||
|
|
||
|
if (!(miiSts & MII_SR_EXT_STS))
|
||
|
return(ERROR);
|
||
|
if ((mode & IFM_GMASK) == IFM_FDX)
|
||
|
gmiiAnar = MII_MASSLA_CTRL_1000T_FD;
|
||
|
else
|
||
|
gmiiAnar = MII_MASSLA_CTRL_1000T_HD;
|
||
|
miiCtl = MII_CR_AUTO_EN|MII_CR_RESTART;
|
||
|
break;
|
||
|
case IFM_100_TX:
|
||
|
if (autoNegForce)
|
||
|
{
|
||
|
miiCtl = MII_CR_100|MII_CR_AUTO_EN|MII_CR_RESTART;
|
||
|
if ((mode & IFM_GMASK) == IFM_FDX)
|
||
|
{
|
||
|
miiAnar = MII_ANAR_100TX_FD;
|
||
|
miiCtl |= MII_CR_FDX;
|
||
|
}
|
||
|
else
|
||
|
miiAnar = MII_ANAR_100TX_HD;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
autoneg = FALSE;
|
||
|
|
||
|
/*
|
||
|
* Intel's PHY requires restarting auto-negotiation
|
||
|
* or software reset in order for speed/duplex changes
|
||
|
* to take effect. Use restarting auto-neg here.
|
||
|
*/
|
||
|
|
||
|
miiCtl = MII_CR_100|MII_CR_RESTART;
|
||
|
if ((mode & IFM_GMASK) == IFM_FDX)
|
||
|
miiCtl |= MII_CR_FDX;
|
||
|
}
|
||
|
break;
|
||
|
case IFM_10_T:
|
||
|
if (autoNegForce)
|
||
|
{
|
||
|
miiCtl = MII_CR_AUTO_EN|MII_CR_RESTART;
|
||
|
if ((mode & IFM_GMASK) == IFM_FDX)
|
||
|
{
|
||
|
miiAnar = MII_ANAR_10TX_FD;
|
||
|
miiCtl |= MII_CR_FDX;
|
||
|
}
|
||
|
else
|
||
|
miiAnar = MII_ANAR_10TX_HD;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
autoneg = FALSE;
|
||
|
miiCtl = MII_CR_RESTART;
|
||
|
if ((mode & IFM_GMASK) == IFM_FDX)
|
||
|
miiCtl |= MII_CR_FDX;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return (ERROR);
|
||
|
}
|
||
|
|
||
|
ytPhyInit (pDev);
|
||
|
|
||
|
/* set flow control advertise ability */
|
||
|
|
||
|
miiAnar |= (pDrvCtrl->fcmode) << MII_ANAR_PAUSE_SHIFT;
|
||
|
|
||
|
if (autoneg)
|
||
|
{
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_AN_ADS_REG, &miiVal);
|
||
|
miiVal &= ~(MII_ANAR_10TX_HD|MII_ANAR_10TX_FD|
|
||
|
MII_ANAR_100TX_HD|MII_ANAR_100TX_FD);
|
||
|
miiVal |= miiAnar;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_AN_ADS_REG, miiVal);
|
||
|
|
||
|
if (miiSts & MII_SR_EXT_STS)
|
||
|
{
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_MASSLA_CTRL_REG, &miiVal);
|
||
|
miiVal &= ~(MII_MASSLA_CTRL_1000T_HD|MII_MASSLA_CTRL_1000T_FD);
|
||
|
miiVal |= gmiiAnar;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_MASSLA_CTRL_REG, miiVal);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, &miiVal);
|
||
|
miiVal &= ~(MII_CR_FDX|MII_CR_100|MII_CR_1000|MII_CR_AUTO_EN|MII_CR_RESTART);
|
||
|
miiVal |= miiCtl;
|
||
|
miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, miiVal);
|
||
|
|
||
|
return(OK);
|
||
|
}
|
||
|
|
||
|
LOCAL STATUS ytPhyModeGet
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
UINT32 * mode,
|
||
|
UINT32 * status
|
||
|
)
|
||
|
{
|
||
|
UINT16 miiSts;
|
||
|
UINT16 miiCtl;
|
||
|
UINT16 miiAnar;
|
||
|
UINT16 miiLpar;
|
||
|
UINT16 gmiiAnar = 0;
|
||
|
UINT16 gmiiLpar = 0;
|
||
|
UINT16 anlpar;
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
|
||
|
pDrvCtrl = (MII_DRV_CTRL *)pDev->pDrvCtrl;
|
||
|
|
||
|
*mode = IFM_ETHER;
|
||
|
*status = IFM_AVALID;
|
||
|
|
||
|
YT8521PHY_LOGMSG("ytPhyModeGet(): entry\n", 0,0,0,0,0,0);
|
||
|
|
||
|
/* read MII status register once to unlatch link status bit */
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_STAT_REG, &miiSts);
|
||
|
|
||
|
/* read again to know its current value */
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_STAT_REG, &miiSts);
|
||
|
|
||
|
/* no link bit means no carrier. */
|
||
|
if (!(miiSts & MII_SR_LINK_STATUS) || (miiSts == 0xFFFF))
|
||
|
{
|
||
|
*mode |= IFM_NONE;
|
||
|
YT8521PHY_LOGMSG("ytPhyModeGet(): pDev: 0x%x no carrier\n",
|
||
|
(int)pDev,0,0,0,0,0);
|
||
|
return (OK);
|
||
|
}
|
||
|
|
||
|
*status |= IFM_ACTIVE;
|
||
|
|
||
|
/*
|
||
|
* read the control, ability advertisement and link
|
||
|
* partner advertisement registers.
|
||
|
*/
|
||
|
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_CTRL_REG, &miiCtl);
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_AN_ADS_REG, &miiAnar);
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_AN_PRTN_REG, &miiLpar);
|
||
|
|
||
|
if (miiSts & MII_SR_EXT_STS)
|
||
|
{
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_MASSLA_CTRL_REG, &gmiiAnar);
|
||
|
miiBusRead (pDev, pDrvCtrl->miiPhyAddr, MII_MASSLA_STAT_REG, &gmiiLpar);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If autoneg is on, figure out the link settings from the
|
||
|
* advertisement and partner ability registers. If autoneg is
|
||
|
* off, use the settings in the control register.
|
||
|
*/
|
||
|
|
||
|
if (miiCtl & MII_CR_AUTO_EN)
|
||
|
{
|
||
|
anlpar = miiAnar & miiLpar;
|
||
|
if ((gmiiAnar & MII_MASSLA_CTRL_1000T_FD) && \
|
||
|
(gmiiLpar & MII_MASSLA_STAT_LP1000T_FD))
|
||
|
*mode |= IFM_1000_T|IFM_FDX;
|
||
|
else if ((gmiiAnar & MII_MASSLA_CTRL_1000T_HD) && \
|
||
|
(gmiiLpar & MII_MASSLA_STAT_LP1000T_HD))
|
||
|
*mode |= IFM_1000_T|IFM_HDX;
|
||
|
else if (anlpar & MII_ANAR_100TX_FD)
|
||
|
*mode |= IFM_100_TX|IFM_FDX;
|
||
|
else if (anlpar & MII_ANAR_100TX_HD)
|
||
|
*mode |= IFM_100_TX|IFM_HDX;
|
||
|
else if (anlpar & MII_ANAR_10TX_FD)
|
||
|
*mode |= IFM_10_T|IFM_FDX;
|
||
|
else if (anlpar & MII_ANAR_10TX_HD)
|
||
|
*mode |= IFM_10_T|IFM_HDX;
|
||
|
else
|
||
|
*mode |= IFM_NONE;
|
||
|
|
||
|
YT8521PHY_LOGMSG("ytPhyModeGet(): pDev: 0x%x auto-neg ON,"
|
||
|
" mode: 0x%x\n", (int)pDev,(int)*mode,0,0,0,0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (miiCtl & MII_CR_FDX)
|
||
|
*mode |= IFM_FDX;
|
||
|
else
|
||
|
*mode |= IFM_HDX;
|
||
|
if ((miiCtl & (MII_CR_100 | MII_CR_1000)) == (MII_CR_100 | MII_CR_1000))
|
||
|
*mode |= IFM_1000_T;
|
||
|
else if (miiCtl & MII_CR_100)
|
||
|
*mode |= IFM_100_TX;
|
||
|
else
|
||
|
*mode |= IFM_10_T;
|
||
|
|
||
|
YT8521PHY_LOGMSG("ytPhyModeGet(): pDev: 0x%x auto-neg off,"
|
||
|
" mode: 0x%x\n",(int)pDev,(int)*mode,0,0,0,0);
|
||
|
}
|
||
|
|
||
|
return (OK);
|
||
|
}
|
||
|
|
||
|
LOCAL STATUS ytPhyConfigInit
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev
|
||
|
)
|
||
|
{
|
||
|
STATUS ret;
|
||
|
UINT16 miiVal;
|
||
|
/* disable auto sleep */
|
||
|
ret = ytPhyExtRead(pDev,YT8521_EXTREG_SLEEP_CONTROL1,&miiVal);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
miiVal &= ~(1 << YT8521_EN_SLEEP_SW_BIT);
|
||
|
ret = ytPhyExtWrite(pDev,YT8521_EXTREG_SLEEP_CONTROL1,miiVal);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
/* enable RXC clock when no wire plug */
|
||
|
ret = ytPhyExtWrite(pDev,YT8521_EXTREG_SMI_SDS_PHY,0);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
|
||
|
ret = ytPhyExtRead(pDev,YT8521_EXTREG_C,&miiVal);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
miiVal &= ~(1 << 12);
|
||
|
ret = ytPhyExtWrite(pDev,YT8521_EXTREG_C,miiVal);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
LOCAL STATUS ytPhyExtRead
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
UINT32 reg,
|
||
|
UINT16* val
|
||
|
)
|
||
|
{
|
||
|
STATUS ret;
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
pDrvCtrl = (MII_DRV_CTRL *)pDev->pDrvCtrl;
|
||
|
ret = miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, REG_DEBUG_ADDR_OFFSET, reg);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
ret = miiBusRead (pDev, pDrvCtrl->miiPhyAddr, REG_DEBUG_DATA, val);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
LOCAL STATUS ytPhyExtWrite
|
||
|
(
|
||
|
VXB_DEVICE_ID pDev,
|
||
|
UINT32 reg,
|
||
|
UINT16 val
|
||
|
)
|
||
|
{
|
||
|
STATUS ret;
|
||
|
MII_DRV_CTRL * pDrvCtrl;
|
||
|
pDrvCtrl = (MII_DRV_CTRL *)pDev->pDrvCtrl;
|
||
|
ret = miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, REG_DEBUG_ADDR_OFFSET, reg);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
ret = miiBusWrite (pDev, pDrvCtrl->miiPhyAddr, REG_DEBUG_DATA, val);
|
||
|
return (ret);
|
||
|
}
|
||
|
|