blob: df24d814e4e4ababa63bc4c1a8ea92cee8395eb0 [file] [log] [blame]
#include <Copyright.h>
/********************************************************************************
* gtPhyCtrl.h
*
* DESCRIPTION:
* API definitions for PHY control facility.
*
* DEPENDENCIES:
* None.
*
* FILE REVISION NUMBER:
* $Revision: 10 $
*******************************************************************************/
#include <msApi.h>
#include <gtHwCntl.h>
#include <gtDrvConfig.h>
#include <gtDrvSwRegs.h>
#include <gtVct.h>
#include <gtSem.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/delay.h>
/*
* This routine set Auto-Negotiation Ad Register for Fast Ethernet Phy
*/
static
GT_STATUS feSetAutoMode
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_PHY_INFO *phyInfo,
IN GT_PHY_AUTO_MODE mode
)
{
GT_U16 u16Data;
GT_UNUSED_PARAM(phyInfo);
DBG_INFO(("feSetAutoMode Called.\n"));
if(hwReadPhyReg(dev,hwPort,QD_PHY_AUTONEGO_AD_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
/* Mask out all auto mode related bits. */
u16Data &= ~QD_PHY_MODE_AUTO_AUTO;
switch(mode)
{
case SPEED_AUTO_DUPLEX_AUTO:
u16Data |= QD_PHY_MODE_AUTO_AUTO;
break;
case SPEED_100_DUPLEX_AUTO:
u16Data |= QD_PHY_MODE_100_AUTO;
break;
case SPEED_10_DUPLEX_AUTO:
u16Data |= QD_PHY_MODE_10_AUTO;
break;
case SPEED_AUTO_DUPLEX_FULL:
u16Data |= QD_PHY_MODE_AUTO_FULL;
break;
case SPEED_AUTO_DUPLEX_HALF:
u16Data |= QD_PHY_MODE_AUTO_HALF;
break;
case SPEED_100_DUPLEX_FULL:
u16Data |= QD_PHY_100_FULL;
break;
case SPEED_100_DUPLEX_HALF:
u16Data |= QD_PHY_100_HALF;
break;
case SPEED_10_DUPLEX_FULL:
u16Data |= QD_PHY_10_FULL;
break;
case SPEED_10_DUPLEX_HALF:
u16Data |= QD_PHY_10_HALF;
break;
default:
DBG_INFO(("Unknown Auto Mode (%d)\n",mode));
return GT_BAD_PARAM;
}
/* Write to Phy AutoNegotiation Advertisement Register. */
if(hwWritePhyReg(dev,hwPort,QD_PHY_AUTONEGO_AD_REG,u16Data) != GT_OK)
{
DBG_INFO(("Not able to write Phy Reg(port:%d,offset:%d,data:%#x).\n",hwPort,QD_PHY_AUTONEGO_AD_REG,u16Data));
return GT_FAIL;
}
return GT_OK;
}
/*
* This routine get Auto-Negotiation Ad Register for Fast Ethernet Phy
*/
static
GT_STATUS feGetAutoMode
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_PHY_INFO *phyInfo,
OUT GT_PHY_AUTO_MODE *mode
)
{
GT_U16 u16Data;
GT_UNUSED_PARAM(phyInfo);
DBG_INFO(("feGetAutoMode Called.\n"));
if(hwReadPhyReg(dev,hwPort,QD_PHY_AUTONEGO_AD_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
/* Pick out all auto mode related bits. */
u16Data &= QD_PHY_MODE_AUTO_AUTO;
switch(u16Data)
{
case QD_PHY_MODE_10_HALF:
*mode = SPEED_10_DUPLEX_HALF;
break;
case QD_PHY_MODE_10_FULL:
*mode = SPEED_10_DUPLEX_FULL;
break;
case QD_PHY_MODE_100_HALF:
*mode = SPEED_100_DUPLEX_HALF;
break;
case QD_PHY_MODE_100_FULL:
*mode = SPEED_100_DUPLEX_FULL;
break;
case QD_PHY_MODE_AUTO_HALF:
*mode = SPEED_AUTO_DUPLEX_HALF;
break;
case QD_PHY_MODE_AUTO_FULL:
*mode = SPEED_AUTO_DUPLEX_FULL;
break;
case QD_PHY_MODE_10_AUTO:
*mode = SPEED_10_DUPLEX_AUTO;
break;
case QD_PHY_MODE_100_AUTO:
*mode = SPEED_100_DUPLEX_AUTO;
break;
case QD_PHY_MODE_AUTO_AUTO:
*mode = SPEED_AUTO_DUPLEX_AUTO;
break;
default:
DBG_INFO(("Unknown Auto Mode (%d)\n", u16Data));
*mode = SPEED_AUTO_DUPLEX_AUTO;
break;
}
return GT_OK;
}
/*
* This routine set Auto-Negotiation Ad Register for Copper
*/
static
GT_STATUS gigCopperSetAutoMode
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_PHY_INFO *phyInfo,
IN GT_PHY_AUTO_MODE mode
)
{
GT_U16 u16Data,u16Data1;
DBG_INFO(("gigCopperSetAutoMode Called.\n"));
if(hwReadPagedPhyReg(dev,hwPort,0,QD_PHY_AUTONEGO_AD_REG,phyInfo->anyPage,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
/* Mask out all auto mode related bits. */
u16Data &= ~QD_PHY_MODE_AUTO_AUTO;
if(hwReadPagedPhyReg(dev,hwPort,0,QD_PHY_AUTONEGO_1000AD_REG,phyInfo->anyPage,&u16Data1) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
/* Mask out all auto mode related bits. */
u16Data1 &= ~(QD_GIGPHY_1000T_FULL|QD_GIGPHY_1000T_HALF);
switch(mode)
{
case SPEED_AUTO_DUPLEX_AUTO:
u16Data |= QD_PHY_MODE_AUTO_AUTO;
case SPEED_1000_DUPLEX_AUTO:
u16Data1 |= QD_GIGPHY_1000T_FULL|QD_GIGPHY_1000T_HALF;
break;
case SPEED_AUTO_DUPLEX_FULL:
u16Data |= QD_PHY_MODE_AUTO_FULL;
u16Data1 |= QD_GIGPHY_1000T_FULL;
break;
case SPEED_1000_DUPLEX_FULL:
u16Data1 |= QD_GIGPHY_1000T_FULL;
break;
case SPEED_1000_DUPLEX_HALF:
u16Data1 |= QD_GIGPHY_1000T_HALF;
break;
case SPEED_AUTO_DUPLEX_HALF:
u16Data |= QD_PHY_MODE_AUTO_HALF;
u16Data1 |= QD_GIGPHY_1000T_HALF;
break;
case SPEED_100_DUPLEX_AUTO:
u16Data |= QD_PHY_MODE_100_AUTO;
break;
case SPEED_10_DUPLEX_AUTO:
u16Data |= QD_PHY_MODE_10_AUTO;
break;
case SPEED_100_DUPLEX_FULL:
u16Data |= QD_PHY_100_FULL;
break;
case SPEED_100_DUPLEX_HALF:
u16Data |= QD_PHY_100_HALF;
break;
case SPEED_10_DUPLEX_FULL:
u16Data |= QD_PHY_10_FULL;
break;
case SPEED_10_DUPLEX_HALF:
u16Data |= QD_PHY_10_HALF;
break;
default:
DBG_INFO(("Unknown Auto Mode (%d)\n",mode));
return GT_BAD_PARAM;
}
/* Write to Phy AutoNegotiation Advertisement Register. */
if(hwWritePagedPhyReg(dev,hwPort,0,QD_PHY_AUTONEGO_AD_REG,phyInfo->anyPage,u16Data) != GT_OK)
{
DBG_INFO(("Not able to write Phy Reg(port:%d,offset:%d,data:%#x).\n",hwPort,QD_PHY_AUTONEGO_AD_REG,u16Data));
return GT_FAIL;
}
/* Write to Phy AutoNegotiation 1000B Advertisement Register. */
if(hwWritePagedPhyReg(dev,hwPort,0,QD_PHY_AUTONEGO_1000AD_REG,phyInfo->anyPage,u16Data1) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
return GT_OK;
}
/*
* This routine get Auto-Negotiation Ad Register for Copper
*/
static
GT_STATUS gigCopperGetAutoMode
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_PHY_INFO *phyInfo,
IN GT_PHY_AUTO_MODE *mode
)
{
GT_U16 u16Data, u16Data1;
GT_U32 u32Data;
DBG_INFO(("gigCopperGetAutoMode Called.\n"));
if(hwReadPagedPhyReg(dev,hwPort,0,QD_PHY_AUTONEGO_AD_REG,phyInfo->anyPage,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
/* Pick out all auto mode related bits. */
u16Data &= QD_PHY_MODE_AUTO_AUTO;
if(hwReadPagedPhyReg(dev,hwPort,0,QD_PHY_AUTONEGO_1000AD_REG,phyInfo->anyPage,&u16Data1) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
/* Pick out all auto mode related bits. */
u16Data1 &= (QD_GIGPHY_1000T_FULL|QD_GIGPHY_1000T_HALF);
u32Data = (u16Data&0xffff)|((u16Data1&0xffff)<<16);
switch(u32Data)
{
case QD_PHY_MODE_10_HALF:
*mode = SPEED_10_DUPLEX_HALF;
break;
case QD_PHY_MODE_10_FULL:
*mode = SPEED_10_DUPLEX_FULL;
break;
case QD_PHY_MODE_100_HALF:
*mode = SPEED_100_DUPLEX_HALF;
break;
case QD_PHY_MODE_100_FULL:
*mode = SPEED_100_DUPLEX_FULL;
break;
case (QD_GIGPHY_1000T_HALF<<16):
*mode = SPEED_1000_DUPLEX_HALF;
break;
case (QD_GIGPHY_1000T_FULL<<16):
*mode = SPEED_1000_DUPLEX_FULL;
break;
case QD_PHY_MODE_AUTO_HALF|(QD_GIGPHY_1000T_HALF<<16):
*mode = SPEED_AUTO_DUPLEX_HALF;
break;
case QD_PHY_MODE_AUTO_FULL|(QD_GIGPHY_1000T_FULL<<16):
*mode = SPEED_AUTO_DUPLEX_FULL;
break;
case QD_PHY_MODE_10_AUTO:
*mode = SPEED_10_DUPLEX_AUTO;
break;
case QD_PHY_MODE_100_AUTO:
*mode = SPEED_100_DUPLEX_AUTO;
break;
case ((QD_GIGPHY_1000T_FULL|QD_GIGPHY_1000T_HALF)<<16):
*mode = SPEED_1000_DUPLEX_AUTO;
break;
case QD_PHY_MODE_AUTO_AUTO|((QD_GIGPHY_1000T_FULL|QD_GIGPHY_1000T_HALF)<<16):
*mode = SPEED_AUTO_DUPLEX_AUTO;
break;
default:
*mode = SPEED_AUTO_DUPLEX_AUTO;
DBG_INFO(("Unknown Auto Mode (%08x)\n", u32Data));
break;
}
return GT_OK;
}
/*
* This routine set Auto-Negotiation Ad Register for Fiber
*/
static
GT_STATUS gigFiberSetAutoMode
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_PHY_INFO *phyInfo,
IN GT_PHY_AUTO_MODE mode
)
{
GT_U16 u16Data;
DBG_INFO(("gigPhySetAutoMode Called.\n"));
if(hwReadPagedPhyReg(dev,hwPort,1,QD_PHY_AUTONEGO_AD_REG,phyInfo->anyPage,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
return GT_FAIL;
}
/* Mask out all auto mode related bits. */
u16Data &= ~(QD_GIGPHY_1000X_FULL|QD_GIGPHY_1000X_HALF);
switch(mode)
{
case SPEED_AUTO_DUPLEX_AUTO:
case SPEED_1000_DUPLEX_AUTO:
u16Data |= QD_GIGPHY_1000X_FULL|QD_GIGPHY_1000X_HALF;
break;
case SPEED_AUTO_DUPLEX_FULL:
case SPEED_1000_DUPLEX_FULL:
u16Data |= QD_GIGPHY_1000X_FULL;
break;
case SPEED_AUTO_DUPLEX_HALF:
case SPEED_1000_DUPLEX_HALF:
u16Data |= QD_GIGPHY_1000X_HALF;
break;
default:
DBG_INFO(("Unknown Auto Mode (%d)\n",mode));
return GT_BAD_PARAM;
}
/* Write to Phy AutoNegotiation Advertisement Register. */
if(hwWritePagedPhyReg(dev,hwPort,1,QD_PHY_AUTONEGO_AD_REG,phyInfo->anyPage,u16Data) != GT_OK)
{
DBG_INFO(("Not able to write Phy Reg(port:%d,offset:%d,data:%#x).\n",hwPort,QD_PHY_AUTONEGO_AD_REG,u16Data));
return GT_FAIL;
}
return GT_OK;
}
/*
* This routine sets Auto Mode and Reset the phy
*/
static
GT_STATUS phySetAutoMode
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_PHY_INFO *phyInfo,
IN GT_PHY_AUTO_MODE mode
)
{
GT_U16 u16Data;
GT_STATUS status;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("phySetAutoMode Called.\n"));
if (!(phyInfo->flag & GT_PHY_GIGABIT))
{
if((status=feSetAutoMode(dev,hwPort,phyInfo,mode)) != GT_OK)
{
return status;
}
if (hwReadPhyReg(dev, hwPort, QD_PHY_CONTROL_REG, &u16Data) != GT_OK)
return GT_FAIL;
u16Data = (u16Data & (QD_PHY_SPEED | QD_PHY_DUPLEX)) | QD_PHY_AUTONEGO;
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
/* soft reset */
return hwPhyReset(dev,hwPort,u16Data);
}
if(driverPagedAccessStart(dev,hwPort,phyInfo->pageType,&autoOn,&pageReg) != GT_OK)
{
return GT_FAIL;
}
/* Read to Phy Control Register. */
if(hwReadPagedPhyReg(dev, hwPort, 0, QD_PHY_CONTROL_REG, phyInfo->anyPage, &u16Data) != GT_OK)
return GT_FAIL;
if(phyInfo->flag & GT_PHY_COPPER)
{
if((status=gigCopperSetAutoMode(dev,hwPort,phyInfo,mode)) != GT_OK)
{
return status;
}
u16Data = (u16Data & (QD_PHY_SPEED_MSB | QD_PHY_SPEED | QD_PHY_DUPLEX)) | QD_PHY_AUTONEGO;
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
/* Write to Phy Control Register. */
if(hwWritePagedPhyReg(dev,hwPort,0,QD_PHY_CONTROL_REG,phyInfo->anyPage,u16Data) != GT_OK)
return GT_FAIL;
}
else if(phyInfo->flag & GT_PHY_FIBER)
{
if((status=gigFiberSetAutoMode(dev,hwPort,phyInfo,mode)) != GT_OK)
{
return status;
}
u16Data = (u16Data & (QD_PHY_SPEED_MSB | QD_PHY_SPEED | QD_PHY_DUPLEX)) | QD_PHY_AUTONEGO;
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
/* Write to Phy Control Register. */
if(hwWritePagedPhyReg(dev,hwPort,1,QD_PHY_CONTROL_REG,phyInfo->anyPage,u16Data) != GT_OK)
return GT_FAIL;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo->pageType,autoOn,pageReg) != GT_OK)
{
return GT_FAIL;
}
return hwPhyReset(dev,hwPort,0xFF);
}
/*
* This routine gets Auto Mode
*/
static
GT_STATUS phyGetAutoMode
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_PHY_INFO *phyInfo,
OUT GT_PHY_AUTO_MODE *mode
)
{
GT_STATUS status;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("phyGetAutoMode Called.\n"));
if (!(phyInfo->flag & GT_PHY_GIGABIT))
{
if((status=feGetAutoMode(dev,hwPort,phyInfo,mode)) != GT_OK)
{
return status;
}
return status;
}
if(driverPagedAccessStart(dev,hwPort,phyInfo->pageType,&autoOn,&pageReg) != GT_OK)
{
return GT_FAIL;
}
if(phyInfo->flag & GT_PHY_COPPER)
{
if((status=gigCopperGetAutoMode(dev,hwPort,phyInfo,mode)) != GT_OK)
{
return status;
}
}
else if(phyInfo->flag & GT_PHY_FIBER)
{
return GT_NOT_SUPPORTED;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo->pageType,autoOn,pageReg) != GT_OK)
{
return GT_FAIL;
}
return status;
}
/*******************************************************************************
* gprtPhyReset
*
* DESCRIPTION:
* This routine preforms PHY reset.
* After reset, phy will be in Autonegotiation mode.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* COMMENTS:
* data sheet register 0.15 - Reset
* data sheet register 0.13 - Speed
* data sheet register 0.12 - Autonegotiation
* data sheet register 0.8 - Duplex Mode
*******************************************************************************/
GT_STATUS gprtPhyReset
(
IN GT_QD_DEV *dev,
IN GT_LPORT port
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtPhyReset Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/* set Auto Negotiation AD Register */
retVal = phySetAutoMode(dev,hwPort,&phyInfo,SPEED_AUTO_DUPLEX_AUTO);
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
}
else
{
DBG_INFO(("OK.\n"));
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSetPortLoopback
*
* DESCRIPTION:
* Enable/Disable Internal Port Loopback.
* For 10/100 Fast Ethernet PHY, speed of Loopback is determined as follows:
* If Auto-Negotiation is enabled, this routine disables Auto-Negotiation and
* forces speed to be 10Mbps.
* If Auto-Negotiation is disabled, the forced speed is used.
* Disabling Loopback simply clears bit 14 of control register(0.14). Therefore,
* it is recommended to call gprtSetPortAutoMode for PHY configuration after
* Loopback test.
* For 10/100/1000 Gigagbit Ethernet PHY, speed of Loopback is determined as follows:
* If Auto-Negotiation is enabled and Link is active, the current speed is used.
* If Auto-Negotiation is disabled, the forced speed is used.
* All other cases, default MAC Interface speed is used. Please refer to the data
* sheet for the information of the default MAC Interface speed.
*
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* enable - If GT_TRUE, enable loopback mode
* If GT_FALSE, disable loopback mode
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.14 - Loop_back
*
*******************************************************************************/
GT_STATUS gprtSetPortLoopback
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL enable
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtSetPortLoopback Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/* Is this Fast Ethernet Phy? */
if (!(phyInfo.flag & GT_PHY_GIGABIT))
{
if(enable)
{
if(u16Data & QD_PHY_AUTONEGO)
{
/* Disable Auto-Neg*/
u16Data &= ~QD_PHY_AUTONEGO;
if((retVal=hwPhyReset(dev,hwPort,u16Data)) != GT_OK)
{
DBG_INFO(("Softreset failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
}
}
else
{
if(!(u16Data & QD_PHY_AUTONEGO))
{
/* Enable Auto-Neg*/
u16Data |= QD_PHY_RESET | QD_PHY_AUTONEGO;
if((retVal=hwPhyReset(dev,hwPort,u16Data)) != GT_OK)
{
DBG_INFO(("Softreset failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
}
}
}
BOOL_2_BIT(enable,u16Data);
/* Write to Phy Control Register. */
retVal = hwSetPhyRegField(dev,hwPort,QD_PHY_CONTROL_REG,14,1,u16Data);
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
}
else
{
DBG_INFO(("OK.\n"));
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPortLoopback
*
* DESCRIPTION:
* Get Internal Port Loopback state.
* For 10/100 Fast Ethernet PHY, speed of Loopback is determined as follows:
* If Auto-Negotiation is enabled, this routine disables Auto-Negotiation and
* forces speed to be 10Mbps.
* If Auto-Negotiation is disabled, the forced speed is used.
* Disabling Loopback simply clears bit 14 of control register(0.14). Therefore,
* it is recommended to call gprtSetPortAutoMode for PHY configuration after
* Loopback test.
* For 10/100/1000 Gigagbit Ethernet PHY, speed of Loopback is determined as follows:
* If Auto-Negotiation is enabled and Link is active, the current speed is used.
* If Auto-Negotiation is disabled, the forced speed is used.
* All other cases, default MAC Interface speed is used. Please refer to the data
* sheet for the information of the default MAC Interface speed.
*
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* enable - If GT_TRUE, loopback mode is enabled
* If GT_FALSE, loopback mode is disabled
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.14 - Loop_back
*
*******************************************************************************/
GT_STATUS gprtGetPortLoopback
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_BOOL *enable
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtGetPortLoopback Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/*get loopback state*/
retVal = hwGetPhyRegField(dev,hwPort,QD_PHY_CONTROL_REG,14,1,&u16Data);
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
}
else
{
DBG_INFO(("OK.\n"));
BIT_2_BOOL(u16Data, *enable);
}
return retVal;
}
/*******************************************************************************
* gprtSetPortLineLoopback
*
* DESCRIPTION:
* Enable/Disable Port Line Loopback.
*
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* enable - If GT_TRUE, enable loopback mode
* If GT_FALSE, disable loopback mode
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register FE:28.4, GE:21_2.14 - Loop_back
*
*******************************************************************************/
GT_STATUS gprtSetPortLineLoopback
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL enable
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
GT_U16 pageReg;
DBG_INFO(("gprtSetPortLineLoopback Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
BOOL_2_BIT(enable,u16Data);
/* GE Phy */
if ((phyInfo.flag & GT_PHY_GIGABIT))
{
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,0,&pageReg) != GT_OK)
{
return GT_FAIL;
}
/* Write to GE PHY MAC specific control register. */
retVal = hwSetPagedPhyRegField(dev,hwPort, 2, QD_PHY_GE_LINE_LOOPBACK_REG,14,1,phyInfo.anyPage, u16Data);
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,0,pageReg) != GT_OK)
{
return GT_FAIL;
}
}
else /* FE Phy */
{
/* Write to FE PHY specific control register. */
retVal = hwSetPhyRegField(dev,hwPort,QD_PHY_FE_LINE_LOOPBACK_REG,4,1,u16Data);
}
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
}
else
{
DBG_INFO(("OK.\n"));
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPortLineLoopback
*
* DESCRIPTION:
* Get Port Line Loopback status.
*
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* enable - If GT_TRUE, enable loopback mode
* If GT_FALSE, disable loopback mode* enable - If GT_TRUE, enable loopback mode
* If GT_FALSE, disable loopback mode
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register FE:28.4, GE:21_2.14 - Loop_back
*
*******************************************************************************/
GT_STATUS gprtGetPortLineLoopback
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_BOOL* enable
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
GT_U16 pageReg;
DBG_INFO(("gprtGetPortLineLoopback Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/* GE Phy */
if ((phyInfo.flag & GT_PHY_GIGABIT))
{
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,0,&pageReg) != GT_OK)
{
return GT_FAIL;
}
/* Read to GE PHY MAC specific control register. */
retVal = hwGetPagedPhyRegField(dev,hwPort, 2, QD_PHY_GE_LINE_LOOPBACK_REG,14,1,phyInfo.anyPage,&u16Data);
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,0,pageReg) != GT_OK)
{
return GT_FAIL;
}
}
else /* FE Phy */
{
/* Read to FE PHY specific control register. */
retVal = hwGetPhyRegField(dev,hwPort,QD_PHY_FE_LINE_LOOPBACK_REG,4,1,&u16Data);
}
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
}
else
{
DBG_INFO(("OK.\n"));
}
BIT_2_BOOL(u16Data, *enable);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSetPortSpeed
*
* DESCRIPTION:
* Sets speed for a specific logical port. This function will keep the duplex
* mode and loopback mode to the previous value, but disable others, such as
* Autonegotiation.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* speed - port speed.
* PHY_SPEED_10_MBPS for 10Mbps
* PHY_SPEED_100_MBPS for 100Mbps
* PHY_SPEED_1000_MBPS for 1000Mbps
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.13 - Speed Selection (LSB)
* data sheet register 0.6 - Speed Selection (MSB)
*
*******************************************************************************/
GT_STATUS gprtSetPortSpeed
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_PHY_SPEED speed
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
GT_STATUS retVal;
DBG_INFO(("gprtSetPortSpeed Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
switch(speed)
{
case PHY_SPEED_10_MBPS:
if ((phyInfo.flag & GT_PHY_GIGABIT) && !(phyInfo.flag & GT_PHY_COPPER))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
u16Data = u16Data & (QD_PHY_LOOPBACK | QD_PHY_DUPLEX);
break;
case PHY_SPEED_100_MBPS:
u16Data = (u16Data & (QD_PHY_LOOPBACK | QD_PHY_DUPLEX)) | QD_PHY_SPEED;
break;
case PHY_SPEED_1000_MBPS:
if (!(phyInfo.flag & GT_PHY_GIGABIT))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
u16Data = (u16Data & (QD_PHY_LOOPBACK | QD_PHY_DUPLEX)) | QD_PHY_SPEED_MSB;
break;
default:
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
retVal = hwPhyReset(dev,hwPort,u16Data);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPortSpeed
*
* DESCRIPTION:
* Gets speed for a specific logical port.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* speed - port speed.
* PHY_SPEED_10_MBPS for 10Mbps
* PHY_SPEED_100_MBPS for 100Mbps
* PHY_SPEED_1000_MBPS for 1000Mbps
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.13 - Speed Selection (LSB)
* data sheet register 0.6 - Speed Selection (MSB)
*
*******************************************************************************/
GT_STATUS gprtGetPortSpeed
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_PHY_SPEED *speed
)
{
GT_U8 hwPort; /* The physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtGetPortSpeed Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if ((phyInfo.flag & GT_PHY_GIGABIT) && !(phyInfo.flag & GT_PHY_COPPER))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
if ((phyInfo.flag & GT_PHY_GIGABIT) && (u16Data & QD_PHY_SPEED_MSB))
{
*speed = PHY_SPEED_1000_MBPS;
}
else
{
if (u16Data & QD_PHY_SPEED)
{
*speed = PHY_SPEED_100_MBPS;
}
else
{
*speed = PHY_SPEED_10_MBPS;
}
}
DBG_INFO(("Read phy(%d) register: regAddr 0x%x, data %#x, speed[%d] \r\n",
hwPort,QD_PHY_CONTROL_REG,u16Data, *speed));
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtPortAutoNegEnable
*
* DESCRIPTION:
* Enable/disable an Auto-Negotiation.
* This routine simply sets Auto Negotiation bit (bit 12) of Control
* Register and reset the phy.
* For Speed and Duplex selection, please use gprtSetPortAutoMode.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* state - GT_TRUE for enable Auto-Negotiation,
* GT_FALSE otherwise
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.12 - Auto-Negotiation Enable
* data sheet register 4.8, 4.7, 4.6, 4.5 - Auto-Negotiation Advertisement
*
*******************************************************************************/
GT_STATUS gprtPortAutoNegEnable
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL state
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_STATUS retVal;
DBG_INFO(("gprtPortAutoNegEnable Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if(!IS_CONFIGURABLE_PHY(dev,hwPort))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(state)
{
u16Data = (u16Data & (QD_PHY_SPEED_MSB | QD_PHY_SPEED | QD_PHY_DUPLEX)) | QD_PHY_AUTONEGO;
}
else
{
u16Data = u16Data & (QD_PHY_SPEED_MSB |QD_PHY_SPEED | QD_PHY_DUPLEX | QD_PHY_LOOPBACK);
}
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
retVal = hwPhyReset(dev,hwPort,u16Data);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPortAutoNegState
*
* DESCRIPTION:
* Read the auto negotiation state of specific logical port.
* This routine simply reads Auto Negotiation bit (bit 12) of Control
* Register.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* state - GT_TRUE for enable Auto-Negotiation,
* GT_FALSE otherwise
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.12 - Auto-Negotiation Enable
* data sheet register 4.8, 4.7, 4.6, 4.5 - Auto-Negotiation Advertisement
*
*******************************************************************************/
GT_STATUS gprtGetPortAutoNegState
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_BOOL *state
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_STATUS retVal;
DBG_INFO(("gprtGetPortAutoNegState Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if(!IS_CONFIGURABLE_PHY(dev,hwPort))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
/*read the auto negotiation state from bit 12 of PHY control register*/
if((retVal=hwGetPhyRegField(dev,hwPort,QD_PHY_CONTROL_REG,12,1,&u16Data)) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
BIT_2_BOOL(u16Data, *state);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtPortPowerDown
*
* DESCRIPTION:
* Enable/disable (power down) on specific logical port.
* Phy configuration remains unchanged after Power down.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* state - GT_TRUE: power down
* GT_FALSE: normal operation
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.11 - Power Down
*
*******************************************************************************/
GT_STATUS gprtPortPowerDown
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL state
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
DBG_INFO(("gprtPortPowerDown Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if(!IS_CONFIGURABLE_PHY(dev,hwPort))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
BOOL_2_BIT(state,u16Data);
if((retVal=hwSetPhyRegField(dev,hwPort,QD_PHY_CONTROL_REG,11,1,u16Data)) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtGetPortPowerDown
*
* DESCRIPTION:
* Read Port state (power down/normal operation) on specific logical port.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* state - GT_TRUE: power down
* GT_FALSE: normal operation
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.11 - Power Down
*
*******************************************************************************/
GT_STATUS gprtGetPortPowerDown
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_BOOL *state
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
DBG_INFO(("gprtGetPortPowerDown Called.\n"));
if(state == NULL)
{
DBG_INFO(("Input point state equals NULL which is illegal, return\n"));
return GT_BAD_PARAM;
}
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if(!IS_CONFIGURABLE_PHY(dev,hwPort))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if((retVal=hwGetPhyRegField(dev,hwPort,QD_PHY_CONTROL_REG,11,1,&u16Data)) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
BIT_2_BOOL(u16Data, *state);
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtPortRestartAutoNeg
*
* DESCRIPTION:
* Restart AutoNegotiation. If AutoNegotiation is not enabled, it'll enable
* it. Loopback and Power Down will be disabled by this routine.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.9 - Restart Auto-Negotiation
*
*******************************************************************************/
GT_STATUS gprtPortRestartAutoNeg
(
IN GT_QD_DEV *dev,
IN GT_LPORT port
)
{
GT_STATUS retVal;
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
DBG_INFO(("gprtPortRestartAutoNeg Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if(!IS_CONFIGURABLE_PHY(dev,hwPort))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
u16Data &= (QD_PHY_DUPLEX | QD_PHY_SPEED | QD_PHY_SPEED_MSB);
u16Data |= (QD_PHY_RESTART_AUTONEGO | QD_PHY_AUTONEGO);
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
/* Write to Phy Control Register. */
retVal = hwWritePhyReg(dev,hwPort,QD_PHY_CONTROL_REG,u16Data);
gtSemGive(dev,dev->phyRegsSem);
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
}
else
{
DBG_INFO(("OK.\n"));
}
return retVal;
}
/*******************************************************************************
* gprtSetPortDuplexMode
*
* DESCRIPTION:
* Sets duplex mode for a specific logical port. This function will keep
* the speed and loopback mode to the previous value, but disable others,
* such as Autonegotiation.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* dMode - dulpex mode
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.8 - Duplex Mode
*
*******************************************************************************/
GT_STATUS gprtSetPortDuplexMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL dMode
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_STATUS retVal;
DBG_INFO(("gprtSetPortDuplexMode Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if(!IS_CONFIGURABLE_PHY(dev,hwPort))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(dMode)
{
u16Data = (u16Data & (QD_PHY_LOOPBACK | QD_PHY_SPEED | QD_PHY_SPEED_MSB)) | QD_PHY_DUPLEX;
}
else
{
u16Data = u16Data & (QD_PHY_LOOPBACK | QD_PHY_SPEED | QD_PHY_SPEED_MSB);
}
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
/* Write to Phy Control Register. */
retVal = hwPhyReset(dev,hwPort,u16Data);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtPortGetDuplexMode
*
* DESCRIPTION:
* Gets duplex mode for a specific logical port.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* dMode - dulpex mode
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.8 - duplex mode
*
*******************************************************************************/
GT_STATUS gprtGetPortDuplexMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_BOOL* dMode
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
DBG_INFO(("gprtPortGetDuplexMode Called.\n"));
if(dMode == NULL)
{
DBG_INFO(("Input point state equals NULL which is illegal, return\n"));
return GT_BAD_PARAM;
}
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if(!IS_CONFIGURABLE_PHY(dev,hwPort))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if((retVal=hwGetPhyRegField(dev,hwPort,QD_PHY_CONTROL_REG,8,1,&u16Data)) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
BIT_2_BOOL(u16Data, *dMode);
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtSetPortSpeedDuplexMode
*
* DESCRIPTION:
* Sets speed and duplex mode for a specific logical port. This function
* will keep the loopback mode to the previous value, but disable others,
* such as Autonegotiation.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* speed - port speed.
* PHY_SPEED_10_MBPS for 10Mbps
* PHY_SPEED_100_MBPS for 100Mbps
* PHY_SPEED_1000_MBPS for 1000Mbps
* dMode - Duplex mode
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* data sheet register 0.13 - Speed Selection (LSB)
* data sheet register 0.6 - Speed Selection (MSB)
* data sheet register 0.8 - Duplex mode
*******************************************************************************/
GT_STATUS gprtSetPortSpeedDuplexMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_PHY_SPEED speed,
IN GT_BOOL dMode
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
GT_STATUS retVal;
DBG_INFO(("gprtSetPortSpeed Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/* Set Duplex mode */
if (dMode)
u16Data = u16Data | QD_PHY_DUPLEX;
else
u16Data = u16Data & (~QD_PHY_DUPLEX);
switch(speed)
{
case PHY_SPEED_10_MBPS:
if ((phyInfo.flag & GT_PHY_GIGABIT) && !(phyInfo.flag & GT_PHY_COPPER))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
u16Data = u16Data & (QD_PHY_LOOPBACK | QD_PHY_DUPLEX);
break;
case PHY_SPEED_100_MBPS:
u16Data = (u16Data & (QD_PHY_LOOPBACK | QD_PHY_DUPLEX)) | QD_PHY_SPEED;
break;
case PHY_SPEED_1000_MBPS:
if (!(phyInfo.flag & GT_PHY_GIGABIT))
{
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
u16Data = (u16Data & (QD_PHY_LOOPBACK | QD_PHY_DUPLEX)) | QD_PHY_SPEED_MSB;
break;
default:
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
retVal = hwPhyReset(dev,hwPort,u16Data);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSetPortAutoMode
*
* DESCRIPTION:
* This routine sets up the port with given Auto Mode.
* Supported mode is as follows:
* - Auto for both speed and duplex.
* - Auto for speed only and Full duplex.
* - Auto for speed only and Half duplex.
* - Auto for duplex only and speed 1000Mbps.
* - Auto for duplex only and speed 100Mbps.
* - Auto for duplex only and speed 10Mbps.
* - Speed 1000Mbps and Full duplex.
* - Speed 1000Mbps and Half duplex.
* - Speed 100Mbps and Full duplex.
* - Speed 100Mbps and Half duplex.
* - Speed 10Mbps and Full duplex.
* - Speed 10Mbps and Half duplex.
*
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* mode - Auto Mode to be written
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_NOT_SUPPORTED - on device without copper
*
* COMMENTS:
* data sheet register 4.8, 4.7, 4.6, and 4.5 Autonegotiation Advertisement
* data sheet register 4.6, 4.5 Autonegotiation Advertisement for 1000BX
* data sheet register 9.9, 9.8 Autonegotiation Advertisement for 1000BT
*******************************************************************************/
GT_STATUS gprtSetPortAutoMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_PHY_AUTO_MODE mode
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtSetPortAutoMode Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
retVal = GT_NOT_SUPPORTED;
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
retVal = phySetAutoMode(dev,hwPort,&phyInfo,mode);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPortAutoMode
*
* DESCRIPTION:
* This routine get Auto Mode of specific port.
* Supported mode is as follows:
* - Auto for both speed and duplex.
* - Auto for speed only and Full duplex.
* - Auto for speed only and Half duplex.
* - Auto for duplex only and speed 1000Mbps.
* - Auto for duplex only and speed 100Mbps.
* - Auto for duplex only and speed 10Mbps.
* - Speed 1000Mbps and Full duplex.
* - Speed 1000Mbps and Half duplex.
* - Speed 100Mbps and Full duplex.
* - Speed 100Mbps and Half duplex.
* - Speed 10Mbps and Full duplex.
* - Speed 10Mbps and Half duplex.
*
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* mode - Auto Mode to be written
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_NOT_SUPPORTED - on device without copper
*
* COMMENTS:
* data sheet register 4.8, 4.7, 4.6, and 4.5 Autonegotiation Advertisement
* data sheet register 4.6, 4.5 Autonegotiation Advertisement for 1000BX
* data sheet register 9.9, 9.8 Autonegotiation Advertisement for 1000BT
*******************************************************************************/
GT_STATUS gprtGetPortAutoMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_PHY_AUTO_MODE *mode
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtGetPortAutoMode Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
retVal = GT_NOT_SUPPORTED;
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
retVal = phyGetAutoMode(dev,hwPort,&phyInfo,mode);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSetPause
*
* DESCRIPTION:
* This routine will set the pause bit in Autonegotiation Advertisement
* Register. And restart the autonegotiation.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* state - GT_PHY_PAUSE_MODE enum value.
* GT_PHY_NO_PAUSE - disable pause
* GT_PHY_PAUSE - support pause
* GT_PHY_ASYMMETRIC_PAUSE - support asymmetric pause
* GT_PHY_BOTH_PAUSE - support both pause and asymmetric pause
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* COMMENTS:
* data sheet register 4.10 Autonegotiation Advertisement Register
*******************************************************************************/
GT_STATUS gprtSetPause
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_PHY_PAUSE_MODE state
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data,regStart;
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
DBG_INFO(("phySetPause Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
regStart = 10;
if(state & GT_PHY_ASYMMETRIC_PAUSE)
{
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (!(phyInfo.flag & GT_PHY_GIGABIT))
{
DBG_INFO(("Not Supported\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
if(!(phyInfo.flag & GT_PHY_COPPER))
{
regStart = 7;
}
}
u16Data = state;
/* Write to Phy AutoNegotiation Advertisement Register. */
if((retVal=hwSetPhyRegField(dev,hwPort,QD_PHY_AUTONEGO_AD_REG,(GT_U8)regStart,2,u16Data)) != GT_OK)
{
DBG_INFO(("Not able to write Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/* Restart auto negotiation. */
if(hwReadPhyReg(dev,hwPort,QD_PHY_CONTROL_REG,&u16Data) != GT_OK)
{
DBG_INFO(("Not able to read Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_CONTROL_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
u16Data |= (QD_PHY_RESTART_AUTONEGO);
DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, data %#x",
hwPort,QD_PHY_CONTROL_REG,u16Data));
/* Write to Phy Control Register. */
retVal = hwWritePhyReg(dev,hwPort,QD_PHY_CONTROL_REG,u16Data);
gtSemGive(dev,dev->phyRegsSem);
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
}
else
{
DBG_INFO(("OK.\n"));
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPause
*
* DESCRIPTION:
* This routine will get the pause bit in Autonegotiation Advertisement
* Register.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
*
* OUTPUTS:
* state - GT_PHY_PAUSE_MODE enum value.
* GT_PHY_NO_PAUSE - disable pause
* GT_PHY_PAUSE - support pause
* GT_PHY_ASYMMETRIC_PAUSE - support asymmetric pause
* GT_PHY_BOTH_PAUSE - support both pause and asymmetric pause
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* COMMENTS:
* data sheet register 4.10 Autonegotiation Advertisement Register
*******************************************************************************/
GT_STATUS gprtGetPause
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_PHY_PAUSE_MODE *state
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data,regStart;
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtGetPause Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
regStart = 10;
/* Read Phy AutoNegotiation Advertisement Register. */
if((retVal=hwGetPhyRegField(dev,hwPort,QD_PHY_AUTONEGO_AD_REG,(GT_U8)regStart,2,&u16Data)) != GT_OK)
{
DBG_INFO(("Not able to write Phy Reg(port:%d,offset:%d).\n",hwPort,QD_PHY_AUTONEGO_AD_REG));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
gtSemGive(dev,dev->phyRegsSem);
*state = u16Data;
return retVal;
}
static
GT_STATUS dteWorkAround_Phy100M
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort
)
{
GT_STATUS status = GT_OK;
GT_U32 threshold[] = {0x000B,0x0000,0x8780,0x0000,0x8F80,0x0000,
0x9780,0x0000,0x9F80,0x0000,0xA780,0x0000,
0xAF80,0x0000,0xB780,0x0000,0xBF80,0x0000,
0xC780,0x0000,0xCF80,0x0000,0xD780,0x0000,
0xDF80,0x0000,0xE780,0x0000,0xEF80,0x0000,
0xF780,0x0000,0xFF80,0x0000};
int i, thresholdSize;
/* force r125 clock */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x0003)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0x807f)) != GT_OK)
{
return status;
}
/* write thresholds */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x000B)) != GT_OK)
{
return status;
}
thresholdSize = sizeof(threshold)/sizeof(GT_U32);
for(i=0; i<thresholdSize; i++)
{
if((status= hwWritePhyReg(dev,hwPort,0x1E,(GT_U16)threshold[i])) != GT_OK)
{
return status;
}
}
/* setting adc Masking */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x0001)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0x4000)) != GT_OK)
{
return status;
}
/* setting noise level */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x0005)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0xA000)) != GT_OK)
{
return status;
}
/*
offseting cable length measurement by 6.72m(2*4*0.84m)
set 30_10.14:11 to 0x1001 for cable length measure.
*/
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x000a)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0x4840)) != GT_OK)
{
return status;
}
/* release force r125 clock */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x0003)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0x0000)) != GT_OK)
{
return status;
}
return status;
}
static
GT_STATUS dteWorkAround_Phy1000M
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort
)
{
GT_STATUS status = GT_OK;
GT_U32 threshold[] = {0x0000,0x8780,0x0000,0x8F80,0x0000,0x9780,
0x0000,0x9F80,0x0000,0xA780,0x0000,0xAF80,
0x0000,0xB780,0x0000,0xBF80,0x0000,0xC780,
0x0000,0xCF80,0x0000,0xD780,0x0000,0xDF80,
0x0000,0xE780,0x0000,0xEF80,0x0000,0xF780,
0x0000,0xFF80,0x0000};
int i, thresholdSize;
/* */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x001B)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0x43FF)) != GT_OK)
{
return status;
}
/* */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x001C)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0x9999)) != GT_OK)
{
return status;
}
/* */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x001F)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0xE00C)) != GT_OK)
{
return status;
}
/* */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x0018)) != GT_OK)
{
return status;
}
if((status= hwWritePhyReg(dev,hwPort,0x1E,0xFFA1)) != GT_OK)
{
return status;
}
/* write thresholds */
if((status= hwWritePhyReg(dev,hwPort,0x1D,0x0010)) != GT_OK)
{
return status;
}
thresholdSize = sizeof(threshold)/sizeof(GT_U32);
for(i=0; i<thresholdSize; i++)
{
if((status= hwWritePhyReg(dev,hwPort,0x1E,(GT_U16)threshold[i])) != GT_OK)
{
return status;
}
}
return status;
}
static
GT_STATUS feSetDTE
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_BOOL state
)
{
GT_U16 u16Data;
GT_STATUS retVal = GT_OK;
if((retVal = hwReadPhyReg(dev,hwPort,0x10,&u16Data)) != GT_OK)
{
return retVal;
}
u16Data = state?(u16Data|0x8000):(u16Data&(~0x8000));
if((retVal = hwWritePhyReg(dev,hwPort,0x10,u16Data)) != GT_OK)
{
return retVal;
}
/* soft reset */
if((retVal = hwPhyReset(dev,hwPort,0xFF)) != GT_OK)
{
return retVal;
}
return retVal;
}
static
GT_STATUS gigSetDTE
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_BOOL state
)
{
GT_U16 u16Data;
GT_STATUS retVal = GT_OK;
if((retVal = hwReadPhyReg(dev,hwPort,20,&u16Data)) != GT_OK)
{
return retVal;
}
u16Data = state?(u16Data|0x4):(u16Data&(~0x4));
if((retVal = hwWritePhyReg(dev,hwPort,20,u16Data)) != GT_OK)
{
return retVal;
}
/* soft reset */
if((retVal = hwPhyReset(dev,hwPort,0xFF)) != GT_OK)
{
return retVal;
}
return retVal;
}
static
GT_STATUS gigMPSetDTE
(
IN GT_QD_DEV *dev,
IN GT_U8 hwPort,
IN GT_BOOL state
)
{
GT_U16 u16Data;
GT_STATUS retVal = GT_OK;
if((retVal = hwReadPagedPhyReg(dev,hwPort,0,26,0,&u16Data)) != GT_OK)
{
return retVal;
}
u16Data = state?(u16Data|0x100):(u16Data&(~0x100));
if((retVal = hwWritePagedPhyReg(dev,hwPort,0,26,0,u16Data)) != GT_OK)
{
return retVal;
}
/* soft reset */
if((retVal = hwPhyReset(dev,hwPort,0xFF)) != GT_OK)
{
return retVal;
}
return retVal;
}
/*******************************************************************************
* gprtSetDTEDetect
*
* DESCRIPTION:
* This routine enables/disables DTE.
*
* INPUTS:
* port - The logical port number
* mode - either GT_TRUE(for enable) or GT_FALSE(for disable)
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtSetDTEDetect
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL state
)
{
GT_U8 hwPort; /* the physical port number */
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("phySetDTE Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
/* check if the port supports DTE */
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (!(phyInfo.flag & GT_PHY_DTE_CAPABLE))
{
DBG_INFO(("Not Supported\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
switch(phyInfo.dteType)
{
case GT_PHY_DTE_TYPE1:
/* FE Phy needs work-around */
if((retVal = feSetDTE(dev,hwPort,state)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if(state == GT_FALSE)
break;
if((retVal = dteWorkAround_Phy100M(dev,hwPort)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
break;
case GT_PHY_DTE_TYPE3:
/* Gigabit Phy with work-around required */
if((retVal = gigSetDTE(dev,hwPort,state)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if(state == GT_FALSE)
break;
if((retVal = dteWorkAround_Phy1000M(dev,hwPort)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
break;
case GT_PHY_DTE_TYPE2:
/* no workaround required */
if((retVal = gigSetDTE(dev,hwPort,state)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
break;
case GT_PHY_DTE_TYPE4:
/* no workaround required */
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if((retVal = gigMPSetDTE(dev,hwPort,state)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
break;
case GT_PHY_DTE_TYPE5:
/* FE Phy */
if((retVal = feSetDTE(dev,hwPort,state)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
break;
default:
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetDTEDetectStatus
*
* DESCRIPTION:
* This routine gets DTE status.
*
* INPUTS:
* port - The logical port number
*
* OUTPUTS:
* status - GT_TRUE, if link partner needs DTE power.
* GT_FALSE, otherwise.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtGetDTEDetectStatus
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_BOOL *state
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data,pageReg;
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
DBG_INFO(("gprtGetDTEStatus Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
/* check if the port supports DTE */
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (!(phyInfo.flag & GT_PHY_DTE_CAPABLE))
{
DBG_INFO(("Not Supported\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
switch(phyInfo.dteType)
{
case GT_PHY_DTE_TYPE1:
/* FE Phy needs work-around */
if((retVal = hwReadPhyReg(dev,hwPort,17,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
*state = (u16Data & 0x8000)?GT_TRUE:GT_FALSE;
break;
case GT_PHY_DTE_TYPE2:
case GT_PHY_DTE_TYPE3:
if((retVal = hwReadPhyReg(dev,hwPort,27,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
*state = (u16Data & 0x10)?GT_TRUE:GT_FALSE;
break;
case GT_PHY_DTE_TYPE4:
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if((retVal = hwReadPagedPhyReg(dev,hwPort,0,17,phyInfo.anyPage,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
*state = (u16Data & 0x4)?GT_TRUE:GT_FALSE;
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
break;
default:
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSetDTEDetectDropWait
*
* DESCRIPTION:
* Once the PHY no longer detects that the link partner filter, the PHY
* will wait a period of time before clearing the power over Ethernet
* detection status bit. The wait time is 5 seconds multiplied by the
* given value.
*
* INPUTS:
* port - The logical port number
* waitTime - 0 ~ 15 (unit of 4 sec.)
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtSetDTEDetectDropWait
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_U16 waitTime
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("gprtSetDTEDropWait Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
/* check if the port supports DTE */
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (!(phyInfo.flag & GT_PHY_DTE_CAPABLE))
{
DBG_INFO(("Not Supported\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
switch(phyInfo.dteType)
{
case GT_PHY_DTE_TYPE1:
if((retVal = hwReadPhyReg(dev,hwPort,22,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
u16Data = (u16Data & ~(0xF<<12)) | ((waitTime & 0xF) << 12);
if((retVal = hwWritePhyReg(dev,hwPort,22,u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
break;
case GT_PHY_DTE_TYPE2:
case GT_PHY_DTE_TYPE3:
if((retVal = hwReadPhyReg(dev,hwPort,27,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
u16Data = (u16Data & ~(0xF<<5)) | ((waitTime & 0xF) << 5);
if((retVal = hwWritePhyReg(dev,hwPort,27,u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
break;
case GT_PHY_DTE_TYPE4:
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if((retVal = hwReadPagedPhyReg(dev,hwPort,0,26,phyInfo.anyPage,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
u16Data = (u16Data & ~(0xF<<4)) | ((waitTime & 0xF) << 4);
if((retVal = hwWritePagedPhyReg(dev,hwPort,0,26,phyInfo.anyPage,u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
break;
default:
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetDTEDetectDropWait
*
* DESCRIPTION:
* Once the PHY no longer detects that the link partner filter, the PHY
* will wait a period of time before clearing the power over Ethernet
* detection status bit. The wait time is 5 seconds multiplied by the
* returned value.
*
* INPUTS:
* port - The logical port number
*
* OUTPUTS:
* waitTime - 0 ~ 15 (unit of 4 sec.)
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtGetDTEDetectDropWait
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_U16 *waitTime
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("gprtSetDTEDropWait Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (!(phyInfo.flag & GT_PHY_DTE_CAPABLE))
{
DBG_INFO(("Not Supported\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
switch(phyInfo.dteType)
{
case GT_PHY_DTE_TYPE1:
if((retVal = hwReadPhyReg(dev,hwPort,22,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
u16Data = (u16Data >> 12) & 0xF;
break;
case GT_PHY_DTE_TYPE2:
case GT_PHY_DTE_TYPE3:
if((retVal = hwReadPhyReg(dev,hwPort,27,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
u16Data = (u16Data >> 5) & 0xF;
break;
case GT_PHY_DTE_TYPE4:
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if((retVal = hwReadPagedPhyReg(dev,hwPort,0,26,phyInfo.anyPage,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
u16Data = (u16Data >> 4) & 0xF;
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
break;
default:
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
*waitTime = u16Data;
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSetEnergyDetect
*
* DESCRIPTION:
* Energy Detect power down mode enables or disables the PHY to wake up on
* its own by detecting activity on the CAT 5 cable.
*
* INPUTS:
* port - The logical port number
* mode - GT_EDETECT_MODE type
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_BAD_PARAM - if invalid parameter is given
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtSetEnergyDetect
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_EDETECT_MODE mode
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("gprtSetEnergyDetect Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (phyInfo.flag & GT_PHY_SERDES_CORE)
{
DBG_INFO(("Not Supported.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
else if (phyInfo.flag & GT_PHY_GIGABIT)
{
/* check if the mode is valid */
switch (mode)
{
case GT_EDETECT_OFF:
u16Data = 0;
break;
case GT_EDETECT_SENSE_PULSE:
u16Data = 3;
break;
case GT_EDETECT_SENSE:
u16Data = 2;
break;
default:
DBG_INFO(("Invalid paramerter.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if((retVal = hwSetPagedPhyRegField(dev,hwPort,0,0x10,8,2,phyInfo.anyPage,u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if((retVal = hwPhyReset(dev,hwPort,0xFF)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
}
else /* it's a Fast Ethernet device */
{
/* check if the mode is valid */
switch (mode)
{
case GT_EDETECT_OFF:
u16Data = 0;
break;
case GT_EDETECT_SENSE_PULSE:
u16Data = 1;
break;
case GT_EDETECT_SENSE:
default:
DBG_INFO(("Invalid paramerter.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_BAD_PARAM;
}
if((retVal = hwSetPhyRegField(dev,hwPort,0x10,14,1,u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetEnergyDetect
*
* DESCRIPTION:
* Energy Detect power down mode enables or disables the PHY to wake up on
* its own by detecting activity on the CAT 5 cable.
*
* INPUTS:
* port - The logical port number
*
* OUTPUTS:
* mode - GT_EDETECT_MODE type
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
* GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtGetEnergyDetect
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_EDETECT_MODE *mode
)
{
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_STATUS retVal = GT_OK;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("gprtGetEnergyDetect Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (phyInfo.flag & GT_PHY_SERDES_CORE)
{
DBG_INFO(("Not Supported.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
else if (phyInfo.flag & GT_PHY_GIGABIT)
{
/* read the mode */
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if((retVal = hwGetPagedPhyRegField(dev,hwPort,0,0x10,8,2,phyInfo.anyPage,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
switch (u16Data)
{
case 0:
case 1:
*mode = GT_EDETECT_OFF;
break;
case 2:
*mode = GT_EDETECT_SENSE;
break;
case 3:
*mode = GT_EDETECT_SENSE_PULSE;
break;
default:
DBG_INFO(("Unknown value (shouldn't happen).\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
}
else /* it's a Fast Ethernet device */
{
/* read the mode */
if((retVal = hwGetPhyRegField(dev,hwPort,0x10,14,1,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
switch (u16Data)
{
case 0:
*mode = GT_EDETECT_OFF;
break;
case 1:
*mode = GT_EDETECT_SENSE_PULSE;
break;
default:
DBG_INFO(("Unknown value (shouldn't happen).\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSet1000TMasterMode
*
* DESCRIPTION:
* This routine sets the ports 1000Base-T Master mode and restart the Auto
* negotiation.
*
* INPUTS:
* port - the logical port number.
* mode - GT_1000T_MASTER_SLAVE structure
* autoConfig - GT_TRUE for auto, GT_FALSE for manual setup.
* masterPrefer - GT_TRUE if Master configuration is preferred.
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
*
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gprtSet1000TMasterMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_1000T_MASTER_SLAVE *mode
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 data;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("gprtSet1000TMasterMode Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
if (!IS_IN_DEV_GROUP(dev,DEV_GIGABIT_SWITCH))
{
return GT_NOT_SUPPORTED;
}
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (!(phyInfo.flag & GT_PHY_GIGABIT) || !(phyInfo.flag & GT_PHY_COPPER))
{
DBG_INFO(("Not Supported\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(mode->autoConfig == GT_TRUE)
{
if(mode->masterPrefer == GT_TRUE)
{
data = 0x1;
}
else
{
data = 0x0;
}
}
else
{
if(mode->masterPrefer == GT_TRUE)
{
data = 0x6;
}
else
{
data = 0x4;
}
}
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/* Set the Master Mode. */
retVal = hwSetPagedPhyRegField(dev,hwPort,0,9,10,3,phyInfo.anyPage,data);
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
else
{
DBG_INFO(("OK.\n"));
}
/* Restart Auto Negotiation */
if((retVal=hwSetPhyRegField(dev,hwPort,QD_PHY_CONTROL_REG,9,1,1)) != GT_OK)
{
DBG_INFO(("Not able to write Phy Reg(port:%d,offset:%d,data:%#x).\n",hwPort,QD_PHY_CONTROL_REG,1));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGet1000TMasterMode
*
* DESCRIPTION:
* This routine retrieves 1000Base-T Master Mode
*
* INPUTS:
* port - the logical port number.
*
* OUTPUTS:
* mode - GT_1000T_MASTER_SLAVE structure
* autoConfig - GT_TRUE for auto, GT_FALSE for manual setup.
* masterPrefer - GT_TRUE if Master configuration is preferred.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
*
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gprtGet1000TMasterMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
OUT GT_1000T_MASTER_SLAVE *mode
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 data;
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("gprtGet1000TMasterMode Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
if (!IS_IN_DEV_GROUP(dev,DEV_GIGABIT_SWITCH))
{
return GT_NOT_SUPPORTED;
}
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (!(phyInfo.flag & GT_PHY_GIGABIT) || !(phyInfo.flag & GT_PHY_COPPER))
{
DBG_INFO(("Not Supported\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
/* Set the Master Mode. */
retVal = hwGetPagedPhyRegField(dev,hwPort,0,9,10,3,phyInfo.anyPage,&data);
if(retVal != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
else
{
DBG_INFO(("OK.\n"));
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(data & 0x4) /* Manual Mode */
{
mode->autoConfig = GT_FALSE;
if(data & 0x2)
{
mode->masterPrefer = GT_TRUE;
}
else
{
mode->masterPrefer = GT_FALSE;
}
}
else /* Auto Mode */
{
mode->autoConfig = GT_TRUE;
if(data & 0x1)
{
mode->masterPrefer = GT_TRUE;
}
else
{
mode->masterPrefer = GT_FALSE;
}
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPhyLinkStatus
*
* DESCRIPTION:
* This routine retrieves the Link status.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
*
* OUTPUTS:
* linkStatus - GT_FALSE if link is not established,
* GT_TRUE if link is established.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtGetPhyLinkStatus
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL *linkStatus
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 u16Data;
GT_PHY_INFO phyInfo;
DBG_INFO(("gprtGetPhyLinkStatus Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if((retVal=hwGetPhyRegField(dev,hwPort,17,10,1,&u16Data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
BIT_2_BOOL(u16Data,*linkStatus);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtSetPktGenEnable
*
* DESCRIPTION:
* This routine enables or disables Packet Generator.
* Link should be established first prior to enabling the packet generator,
* and generator will generate packets at the speed of the established link.
* When enables packet generator, the following information should be
* provided:
* Payload Type: either Random or 5AA55AA5
* Packet Length: either 64 or 1514 bytes
* Error Packet: either Error packet or normal packet
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* en - GT_TRUE to enable, GT_FALSE to disable
* pktInfo - packet information(GT_PG structure pointer), if en is GT_TRUE.
* ignored, if en is GT_FALSE
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gprtSetPktGenEnable
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_BOOL en,
IN GT_PG *pktInfo
)
{
GT_STATUS retVal; /* Functions return value. */
GT_U8 hwPort; /* the physical port number */
GT_U16 data;
GT_BOOL link;
GT_PHY_INFO phyInfo;
GT_U8 page,reg, offset, len;
GT_BOOL autoOn;
GT_U16 pageReg;
DBG_INFO(("gprtSetPktGenEnable Called.\n"));
/* translate LPORT to hardware port */
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(!(phyInfo.flag & GT_PHY_PKT_GENERATOR))
{
DBG_INFO(("Not Supported.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
switch (phyInfo.pktGenType)
{
case GT_PHY_PKTGEN_TYPE1: /* 30_18.5:2 */
page = 18;
reg = 30;
offset = 2;
break;
case GT_PHY_PKTGEN_TYPE2: /* 16_6.3:0 */
page = 6;
reg = 16;
offset = 0;
break;
case GT_PHY_PKTGEN_TYPE3: /* 25.3:0 */
page = 0;
reg = 25;
offset = 0;
break;
default:
DBG_INFO(("Unknown PKTGEN Type.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (en)
{
if((retVal = gprtGetPhyLinkStatus(dev,port,&link)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if (link == GT_FALSE)
{
DBG_INFO(("Link should be on to run Packet Generator.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
data = 0x8;
if (pktInfo->payload == GT_PG_PAYLOAD_5AA5)
data |= 0x4;
if (pktInfo->length == GT_PG_LENGTH_1514)
data |= 0x2;
if (pktInfo->tx == GT_PG_TX_ERROR)
data |= 0x1;
len = 4;
}
else
{
data = 0;
len = 1;
offset += 3;
}
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if((retVal=hwSetPagedPhyRegField(dev,hwPort,
page,reg,offset,len,phyInfo.anyPage,data)) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetSerdesMode
*
* DESCRIPTION:
* This routine reads Serdes Interface Mode.
*
* INPUTS:
* port - The physical SERDES device address
* (logical port number is also supported for backward comparibility)
*
* OUTPUTS:
* mode - Serdes Interface Mode
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* logical port number is supported only for the devices made production
* before 2009. (88E6131, 88E6122, 88E6108, 88E6161, and 88E6165)
*
*******************************************************************************/
GT_STATUS gprtGetSerdesMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_SERDES_MODE *mode
)
{
GT_U16 u16Data; /* The register's read data. */
GT_U8 hwPort; /* the physical port number */
DBG_INFO(("gprtGetSerdesMode Called.\n"));
if(!IS_IN_DEV_GROUP(dev,DEV_SERDES_CORE))
{
return GT_NOT_SUPPORTED;
}
/* check if input is logical port number */
hwPort = GT_LPORT_2_PORT(port);
GT_GET_SERDES_PORT(dev,&hwPort);
if(hwPort > dev->maxPhyNum)
{
/* check if input is physical serdes address */
if(dev->validSerdesVec & (1<<port))
{
hwPort = (GT_U8)port;
}
else
return GT_NOT_SUPPORTED;
}
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* Get Phy Register. */
if(hwGetPhyRegField(dev,hwPort,16,0,2,&u16Data) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
*mode = u16Data;
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtSetSerdesMode
*
* DESCRIPTION:
* This routine sets Serdes Interface Mode.
*
* INPUTS:
* port - The physical SERDES device address
* (logical port number is also supported for backward comparibility)
* mode - Serdes Interface Mode
*
* OUTPUTS:
* None.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* logical port number is supported only for the devices made production
* before 2009. (88E6131, 88E6122, 88E6108, 88E6161, and 88E6165)
*
*******************************************************************************/
GT_STATUS gprtSetSerdesMode
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_SERDES_MODE mode
)
{
GT_U16 u16Data; /* The register's read data. */
GT_U8 hwPort; /* the physical port number */
GT_STATUS retVal;
DBG_INFO(("gprtSetSerdesMode Called.\n"));
if(!IS_IN_DEV_GROUP(dev,DEV_SERDES_CORE))
{
return GT_NOT_SUPPORTED;
}
/* check if input is logical port number */
hwPort = GT_LPORT_2_PORT(port);
GT_GET_SERDES_PORT(dev,&hwPort);
if(hwPort > dev->maxPhyNum)
{
/* check if input is physical serdes address */
if(dev->validSerdesVec & (1<<port))
{
hwPort = (GT_U8)port;
}
else
return GT_NOT_SUPPORTED;
}
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
u16Data = mode;
/* Get Phy Register. */
if(hwSetPhyRegField(dev,hwPort,16,0,2,u16Data) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
retVal = hwPhyReset(dev,hwPort,0xFF);
gtSemGive(dev,dev->phyRegsSem);
return retVal;
}
/*******************************************************************************
* gprtGetPhyReg
*
* DESCRIPTION:
* This routine reads Phy Registers.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* regAddr - The register's address.
*
* OUTPUTS:
* data - The read register's data.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gprtGetPhyReg
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_U32 regAddr,
OUT GT_U16 *data
)
{
GT_U16 u16Data; /* The register's read data. */
GT_U8 hwPort; /* the physical port number */
DBG_INFO(("gprtGetPhyReg Called.\n"));
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* Get Phy Register. */
if(hwReadPhyReg(dev,hwPort,(GT_U8)regAddr,&u16Data) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
*data = u16Data;
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtSetPhyReg
*
* DESCRIPTION:
* This routine writes Phy Registers.
*
* INPUTS:
* port - The logical port number, unless SERDES device is accessed
* The physical address, if SERDES device is accessed
* regAddr - The register's address.
*
* OUTPUTS:
* data - The read register's data.
*
* RETURNS:
* GT_OK - on success
* GT_FAIL - on error
*
* COMMENTS:
* None.
*
* GalTis:
*
*******************************************************************************/
GT_STATUS gprtSetPhyReg
(
IN GT_QD_DEV *dev,
IN GT_LPORT port,
IN GT_U32 regAddr,
IN GT_U16 data
)
{
GT_U8 hwPort; /* the physical port number */
DBG_INFO(("gprtSetPhyReg Called.\n"));
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* Write to Phy Register */
if(hwWritePhyReg(dev,hwPort,(GT_U8)regAddr,data) != GT_OK)
{
DBG_INFO(("Failed.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtGetPagedPhyReg
*
* DESCRIPTION:
* This routine reads phy register of the given page
*
* INPUTS:
* port - logical port to be read
* regAddr - register offset to be read
* page - page number to be read
*
* OUTPUTS:
* data - value of the read register
*
* RETURNS:
* GT_OK - if read successed
* GT_FAIL - if read failed
*
* COMMENTS:
* None.
*
*******************************************************************************/
GT_STATUS gprtGetPagedPhyReg
(
IN GT_QD_DEV *dev,
IN GT_U32 port,
IN GT_U32 regAddr,
IN GT_U32 page,
OUT GT_U16* data
)
{
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
GT_U8 hwPort;
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(hwReadPagedPhyReg(dev,hwPort,(GT_U8)page,
(GT_U8)regAddr,0,data) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}
/*******************************************************************************
* gprtSetPagedPhyReg
*
* DESCRIPTION:
* This routine writes a value to phy register of the given page
*
* INPUTS:
* port - logical port to be read
* regAddr - register offset to be read
* page - page number to be read
* data - value of the read register
*
* OUTPUTS:
* None
*
* RETURNS:
* GT_OK - if read successed
* GT_FAIL - if read failed
*
* COMMENTS:
* None.
*
*******************************************************************************/
GT_STATUS gprtSetPagedPhyReg
(
IN GT_QD_DEV *dev,
IN GT_U32 port,
IN GT_U32 regAddr,
IN GT_U32 page,
IN GT_U16 data
)
{
GT_PHY_INFO phyInfo;
GT_BOOL autoOn;
GT_U16 pageReg;
GT_U8 hwPort;
hwPort = GT_LPORT_2_PHY(port);
gtSemTake(dev,dev->phyRegsSem,OS_WAIT_FOREVER);
/* check if the port is configurable */
if((phyInfo.phyId=GT_GET_PHY_ID(dev,hwPort)) == GT_INVALID_PHY)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_NOT_SUPPORTED;
}
if(driverFindPhyInformation(dev,hwPort,&phyInfo) != GT_OK)
{
DBG_INFO(("Unknown PHY device.\n"));
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(hwWritePagedPhyReg(dev,hwPort,(GT_U8)page,
(GT_U8)regAddr,0,data) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK)
{
gtSemGive(dev,dev->phyRegsSem);
return GT_FAIL;
}
gtSemGive(dev,dev->phyRegsSem);
return GT_OK;
}