#include <Copyright.h>
/********************************************************************************
* gtHwCntl.c
*
* DESCRIPTION:
*       Functions declarations for Hw accessing quarterDeck phy, internal and
*       global registers.
*
* DEPENDENCIES:
*       None.
*
* FILE REVISION NUMBER:
*       $Revision: 5 $
*
*******************************************************************************/

#include <gtDrvSwRegs.h>
#include <gtHwCntl.h>
#include <gtMiiSmiIf.h>
#include <gtSem.h>


static GT_STATUS hwReadPPU(GT_QD_DEV *dev, GT_U16 *data);
static GT_STATUS hwWritePPU(GT_QD_DEV *dev, GT_U16 data);
static GT_STATUS coreReadPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
);
static GT_STATUS coreWritePhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
);
static GT_STATUS coreReadPagedPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U32     anyPage,
    OUT GT_U16   *data
);
static GT_STATUS coreWritePagedPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U32     anyPage,
    IN  GT_U16   data
);

GT_STATUS phyRegReadPPUEn (GT_QD_DEV* dev, unsigned int phyAddr , unsigned int regAddr,
                        GT_U16* value);
GT_STATUS phyRegWritePPUEn (GT_QD_DEV* dev, unsigned int phyAddr , unsigned int regAddr,
                       GT_U16 value);
#ifndef GT_RMGMT_ACCESS
static GT_STATUS phyReadGlobal2Reg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
);
static GT_STATUS phyWriteGlobal2Reg
(
    IN  GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
);
#endif


/*******************************************************************************
* portToSmiMapping
*
* DESCRIPTION:
*       This function mapps port to smi address
*
* INPUTS:
*        dev - device context
*       portNum - Port number to read the register for.
*        accessType - type of register (Phy, Port, or Global)
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       smiAddr    - smi address.
*
*******************************************************************************/
GT_U8 portToSmiMapping
(
    IN GT_QD_DEV *dev,
    IN GT_U8    portNum,
    IN GT_U32    accessType
)
{
    GT_U8 smiAddr;

    if(IS_IN_DEV_GROUP(dev,DEV_8PORT_SWITCH))
    {
        switch(accessType)
        {
            case PHY_ACCESS:
              if (dev->validPhyVec & (1<<portNum))
                smiAddr = PHY_REGS_START_ADDR_8PORT + portNum;
              else
			  {
                smiAddr = 0xFF;
                if(IS_IN_DEV_GROUP(dev,DEV_SERDES_CORE))
				{
                  if (dev->validSerdesVec & (1<<portNum))
                    smiAddr = PHY_REGS_START_ADDR_8PORT + portNum;
				}
			  }
              break;
            case PORT_ACCESS:
                    if (dev->validPortVec & (1<<portNum))
                        smiAddr = PORT_REGS_START_ADDR_8PORT + portNum;
                    else
                        smiAddr = 0xFF;
                    break;
            case GLOBAL_REG_ACCESS:
                    smiAddr = GLOBAL_REGS_START_ADDR_8PORT;
                    break;
            case GLOBAL3_REG_ACCESS:
                    smiAddr = GLOBAL_REGS_START_ADDR_8PORT + 2;
                    break;
            default:
                    smiAddr = GLOBAL_REGS_START_ADDR_8PORT + 1;
                    break;
        }
    }
    else
    {
        smiAddr = dev->baseRegAddr;
        switch(accessType)
        {
            case PHY_ACCESS:
              if (dev->validPhyVec & (1<<portNum))
                smiAddr += PHY_REGS_START_ADDR + portNum;
              else
			  {
                smiAddr = 0xFF;
                if(IS_IN_DEV_GROUP(dev,DEV_SERDES_CORE))
				{
                  if (dev->validSerdesVec & (1<<portNum))
                    smiAddr += PHY_REGS_START_ADDR + portNum;
				}
			  }
              break;
            case PORT_ACCESS:
                    if (dev->validPortVec & (1<<portNum))
                        smiAddr += PORT_REGS_START_ADDR + portNum;
                    else
                        smiAddr = 0xFF;
                    break;
            case GLOBAL_REG_ACCESS:
                    smiAddr += GLOBAL_REGS_START_ADDR;
                    break;
            default:
                    /*  88EC0XX uses PORT_REGS_START_ADDR -1 */
                    if(IS_IN_DEV_GROUP(dev,DEV_MELODY_SWITCH))
                      smiAddr += PORT_REGS_START_ADDR - 1;
                    else
                      smiAddr += GLOBAL_REGS_START_ADDR - 1;
                    break;
        }
    }
    return smiAddr;
}


/****************************************************************************/
/* Phy registers related functions.                                         */
/****************************************************************************/

/*******************************************************************************
* hwReadPhyReg
*
* DESCRIPTION:
*       This function reads a switch's port phy register.
*
* INPUTS:
*       portNum - Port number to read the register for.
*       regAddr - The register's address.
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwReadPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
)
{
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = coreReadPhyReg(dev, portNum, regAddr, data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwWritePhyReg
*
* DESCRIPTION:
*       This function writes to a switch's port phy register.
*
* INPUTS:
*       portNum - Port number to write the register for.
*       regAddr - The register's address.
*       data    - The data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwWritePhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = coreWritePhyReg(dev, portNum, regAddr, data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwGetPhyRegField
*
* DESCRIPTION:
*       This function reads a specified field from a switch's port phy register.
*
* INPUTS:
*       portNum     - Port number to read the register for.
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to read.
*
* OUTPUTS:
*       data        - The read register field.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwGetPhyRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    OUT GT_U16   *data
)
{
    GT_U16 mask;            /* Bits mask to be read */
    GT_U16 tmpData;
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = coreReadPhyReg(dev, portNum, regAddr, &tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    if (retVal != GT_OK)
        return retVal;

    CALC_MASK(fieldOffset,fieldLength,mask);

    tmpData = (tmpData & mask) >> fieldOffset;
    *data = tmpData;

    DBG_INFO(("Read from phy(%d) register: regAddr 0x%x, ",
              portNum,regAddr));
    DBG_INFO(("fOff %d, fLen %d, data 0x%x.\n",fieldOffset,fieldLength,*data));

    return retVal;
}


/*******************************************************************************
* hwSetPhyRegField
*
* DESCRIPTION:
*       This function writes to specified field in a switch's port phy register.
*
* INPUTS:
*       portNum     - Port number to write the register for.
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwSetPhyRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    IN  GT_U16   data
)
{
    GT_U16 mask;
    GT_U16 tmpData;
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = coreReadPhyReg(dev, portNum, regAddr, &tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= ((data << fieldOffset) & mask);

    DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, ",
              portNum,regAddr));
    DBG_INFO(("fieldOff %d, fieldLen %d, data 0x%x.\n",fieldOffset,
              fieldLength,data));

    retVal = coreWritePhyReg(dev, portNum, regAddr, tmpData);

    gtSemGive(dev,dev->multiAddrSem);
    return retVal;
}


/*******************************************************************************
* hwReadPagedPhyReg
*
* DESCRIPTION:
*       This function reads a switch's port phy register in page mode.
*
* INPUTS:
*       portNum - Port number to read the register for.
*       pageNum - Page number of the register to be read.
*       regAddr - The register's address.
*        anyPage - Any Page register vector
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwReadPagedPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U32     anyPage,
    OUT GT_U16   *data
)
{
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = coreReadPagedPhyReg(dev,portNum,pageNum,regAddr,anyPage,data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwWritePagedPhyReg
*
* DESCRIPTION:
*       This function writes to a switch's port phy register in page mode.
*
* INPUTS:
*       portNum - Port number to write the register for.
*       pageNum - Page number of the register to be written.
*       regAddr - The register's address.
*        anyPage - Any Page register vector
*       data    - The data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwWritePagedPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U32     anyPage,
    IN  GT_U16   data
)
{
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = coreWritePagedPhyReg(dev,portNum,pageNum,regAddr,anyPage,data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwGetPagedPhyRegField
*
* DESCRIPTION:
*       This function reads a specified field from a switch's port phy register
*        in page mode.
*
* INPUTS:
*       portNum     - Port number to read the register for.
*       pageNum     - Page number of the register to be read.
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to read.
*        anyPage     - Any Page register vector
*
* OUTPUTS:
*       data        - The read register field.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwGetPagedPhyRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    IN  GT_U32     anyPage,
    OUT GT_U16   *data
)
{
    GT_U16 mask;            /* Bits mask to be read */
    GT_U16 tmpData;
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = coreReadPagedPhyReg(dev,portNum,pageNum,regAddr,anyPage,&tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    if(retVal != GT_OK)
    {
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);

    tmpData = (tmpData & mask) >> fieldOffset;
    *data = tmpData;

    DBG_INFO(("Read from phy(%d) register: regAddr 0x%x, ",
              portNum,regAddr));
    DBG_INFO(("fOff %d, fLen %d, data 0x%x.\n",fieldOffset,fieldLength,*data));

    return GT_OK;
}


/*******************************************************************************
* hwSetPagedPhyRegField
*
* DESCRIPTION:
*       This function writes to specified field in a switch's port phy register
*        in page mode
*
* INPUTS:
*       portNum     - Port number to write the register for.
*       pageNum     - Page number of the register to be read.
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to write.
*        anyPage     - Any Page register vector
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwSetPagedPhyRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    IN  GT_U32     anyPage,
    IN  GT_U16   data
)
{
    GT_U16 mask;
    GT_U16 tmpData;
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    if((retVal=coreReadPagedPhyReg(dev,portNum,pageNum,regAddr,anyPage,&tmpData)) != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= ((data << fieldOffset) & mask);

    DBG_INFO(("Write to phy(%d) register: regAddr 0x%x, ",
              portNum,regAddr));
    DBG_INFO(("fieldOff %d, fieldLen %d, data 0x%x.\n",fieldOffset,
              fieldLength,data));
    retVal = coreWritePagedPhyReg(dev,portNum,pageNum,regAddr,anyPage,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;    
}


/*******************************************************************************
* hwPhyReset
*
* DESCRIPTION:
*       This function performs softreset and waits until reset completion.
*
* INPUTS:
*       portNum     - Port number to write the register for.
*       u16Data     - data should be written into Phy control register.
*                      if this value is 0xFF, normal operation occcurs (read, 
*                      update, and write back.)
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS hwPhyReset
(
    IN  GT_QD_DEV    *dev,
    IN  GT_U8        portNum,
    IN    GT_U16        u16Data
)
{
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U32 retryCount;
    GT_BOOL    pd = GT_FALSE;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    if((retVal=coreReadPhyReg(dev,portNum,0,&tmpData)) 
           != GT_OK)
    {
           DBG_INFO(("Reading Register failed\n"));
        gtSemGive(dev,dev->multiAddrSem);
           return retVal;
    }

    if (tmpData & 0x800)
    {
        pd = GT_TRUE;
    }

    if (u16Data != 0xFF)
    {
        tmpData = u16Data;
    }

    /* Set the desired bits to 0. */
    if (pd)
    {
        tmpData |= 0x800;
    }
    else
    {
        tmpData |= 0x8000;
    }

    if((retVal=coreWritePhyReg(dev,portNum,0,tmpData)) 
        != GT_OK)
    {
        DBG_INFO(("Writing to register failed\n"));
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    if (pd)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return GT_OK;
    }

    for (retryCount = 0x1000; retryCount > 0; retryCount--)
    {
        if((retVal=coreReadPhyReg(dev,portNum,0,&tmpData)) != GT_OK)
        {
            DBG_INFO(("Reading register failed\n"));
            gtSemGive(dev,dev->multiAddrSem);
            return retVal;
        }
        if ((tmpData & 0x8000) == 0)
            break;
    }

    gtSemGive(dev,dev->multiAddrSem);

    if (retryCount == 0)
    {
        DBG_INFO(("Reset bit is not cleared\n"));
        return GT_FAIL;
    }

    return GT_OK;
}

/****************************************************************************/
/* Per port registers related functions.                                    */
/****************************************************************************/

/*******************************************************************************
* hwReadPortReg
*
* DESCRIPTION:
*       This function reads a switch's port register.
*
* INPUTS:
*       portNum - Port number to read the register for.
*       regAddr - The register's address.
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwReadPortReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
)
{
    GT_U8       phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PORT_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal =  miiSmiIfReadRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    DBG_INFO(("Read from port(%d) register: phyAddr 0x%x, regAddr 0x%x, ",
              portNum,phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",*data));
    return retVal;
}


/*******************************************************************************
* hwWritePortReg
*
* DESCRIPTION:
*       This function writes to a switch's port register.
*
* INPUTS:
*       portNum - Port number to write the register for.
*       regAddr - The register's address.
*       data    - The data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwWritePortReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_U8   phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PORT_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    DBG_INFO(("Write to port(%d) register: phyAddr 0x%x, regAddr 0x%x, ",
              portNum,phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",data));

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwGetPortRegField
*
* DESCRIPTION:
*       This function reads a specified field from a switch's port register.
*
* INPUTS:
*       portNum     - Port number to read the register for.
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to read.
*
* OUTPUTS:
*       data        - The read register field.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwGetPortRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    OUT GT_U16   *data
)
{
    GT_U16 mask;            /* Bits mask to be read */
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PORT_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal =  miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    if (retVal != GT_OK)
        return retVal;
        
    CALC_MASK(fieldOffset,fieldLength,mask);

    tmpData = (tmpData & mask) >> fieldOffset;
    *data = tmpData;
    DBG_INFO(("Read from port(%d) register: regAddr 0x%x, ",
              portNum,regAddr));
    DBG_INFO(("fOff %d, fLen %d, data 0x%x.\n",fieldOffset,fieldLength,*data));

    return GT_OK;
}


/*******************************************************************************
* hwSetPortRegField
*
* DESCRIPTION:
*       This function writes to specified field in a switch's port register.
*
* INPUTS:
*       portNum     - Port number to write the register for.
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwSetPortRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    IN  GT_U16   data
)
{
    GT_U16 mask;
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PORT_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal =  miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= ((data << fieldOffset) & mask);
    DBG_INFO(("Write to port(%d) register: regAddr 0x%x, ",
              portNum,regAddr));
    DBG_INFO(("fieldOff %d, fieldLen %d, data 0x%x.\n",fieldOffset,
              fieldLength,data));

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwSetPortRegBits
*
* DESCRIPTION:
*       This function writes to specified bits in a switch's port register.
*
* INPUTS:
*       portNum     - Port number to write the register for.
*       regAddr     - The register's address.
*       mask         - The bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  When Data is 0x1002 and mask is 0xF00F, 0001b is written to bit[31:24]
*            and 0010b is written to bit[3:0]
*
*******************************************************************************/
GT_STATUS hwSetPortRegBits
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U16   mask,
    IN  GT_U16   data
)
{
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PORT_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal =  miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= (data & mask);
    DBG_INFO(("Write to port(%d) register: regAddr 0x%x, ",
              portNum,regAddr));
    DBG_INFO(("mask %d, data 0x%x.\n",mask,data));

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}



/****************************************************************************/
/* Global registers related functions.                                      */
/****************************************************************************/

/*******************************************************************************
* hwReadGlobalReg
*
* DESCRIPTION:
*       This function reads a switch's global register.
*
* INPUTS:
*       regAddr - The register's address.
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwReadGlobalReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
)
{
    GT_U8       phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    DBG_INFO(("read from global register: phyAddr 0x%x, regAddr 0x%x, ",
              phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",*data));
    return retVal;
}


/*******************************************************************************
* hwWriteGlobalReg
*
* DESCRIPTION:
*       This function writes to a switch's global register.
*
* INPUTS:
*       regAddr - The register's address.
*       data    - The data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwWriteGlobalReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_U8   phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);

    DBG_INFO(("Write to global register: phyAddr 0x%x, regAddr 0x%x, ",
              phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",data));

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwGetGlobalRegField
*
* DESCRIPTION:
*       This function reads a specified field from a switch's global register.
*
* INPUTS:
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to read.
*
* OUTPUTS:
*       data        - The read register field.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwGetGlobalRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    OUT GT_U16   *data
)
{
    GT_U16 mask;            /* Bits mask to be read */
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);

    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    if(retVal != GT_OK)
    {
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);
    tmpData = (tmpData & mask) >> fieldOffset;
    *data = tmpData;
    DBG_INFO(("Read from global register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("fOff %d, fLen %d, data 0x%x.\n",fieldOffset,fieldLength,*data));

    return GT_OK;
}


/*******************************************************************************
* hwSetGlobalRegField
*
* DESCRIPTION:
*       This function writes to specified field in a switch's global register.
*
* INPUTS:
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwSetGlobalRegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    IN  GT_U16   data
)
{
    GT_U16 mask;
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal =  miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= ((data << fieldOffset) & mask);

    DBG_INFO(("Write to global register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("fieldOff %d, fieldLen %d, data 0x%x.\n",fieldOffset,
              fieldLength,data));

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}

/*******************************************************************************
* hwReadGlobal2Reg
*
* DESCRIPTION:
*       This function reads a switch's global 2 register.
*
* INPUTS:
*       regAddr - The register's address.
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwReadGlobal2Reg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
)
{
    GT_U8       phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    DBG_INFO(("read from global 2 register: phyAddr 0x%x, regAddr 0x%x, ", phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",*data));
    return retVal;
}


/*******************************************************************************
* hwWriteGlobal2Reg
*
* DESCRIPTION:
*       This function writes to a switch's global 2 register.
*
* INPUTS:
*       regAddr - The register's address.
*       data    - The data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwWriteGlobal2Reg
(
    IN  GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_U8   phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    DBG_INFO(("Write to global 2 register: phyAddr 0x%x, regAddr 0x%x, ", phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",data));

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwGetGlobal2RegField
*
* DESCRIPTION:
*       This function reads a specified field from a switch's global 2 register.
*
* INPUTS:
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to read.
*
* OUTPUTS:
*       data        - The read register field.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwGetGlobal2RegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    OUT GT_U16   *data
)
{
    GT_U16 mask;            /* Bits mask to be read */
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    if(retVal != GT_OK)
        return retVal;

    CALC_MASK(fieldOffset,fieldLength,mask);
    tmpData = (tmpData & mask) >> fieldOffset;
    *data = tmpData;
    DBG_INFO(("Read from global 2 register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("fOff %d, fLen %d, data 0x%x.\n",fieldOffset,fieldLength,*data));

    return GT_OK;
}


/*******************************************************************************
* hwSetGlobal2RegField
*
* DESCRIPTION:
*       This function writes to specified field in a switch's global 2 register.
*
* INPUTS:
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwSetGlobal2RegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    IN  GT_U16   data
)
{
    GT_U16 mask;
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= ((data << fieldOffset) & mask);

    DBG_INFO(("Write to global 2 register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("fieldOff %d, fieldLen %d, data 0x%x.\n",fieldOffset,
              fieldLength,data));

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}

/*******************************************************************************
* hwSetGlobal2RegBits
*
* DESCRIPTION:
*       This function writes to specified bits in a switch's global 2 register.
*
* INPUTS:
*       regAddr     - The register's address.
*       mask         - The bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  When Data is 0x1002 and mask is 0xF00F, 0001b is written to bit[31:24]
*            and 0010b is written to bit[3:0]
*
*******************************************************************************/
GT_STATUS hwSetGlobal2RegBits
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U16   mask,
    IN  GT_U16   data
)
{
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= (data & mask);

    DBG_INFO(("Write to global 2 register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("mask %d, data 0x%x.\n",mask,data));

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwReadGlobal3Reg
*
* DESCRIPTION:
*       This function reads a switch's global 3 register.
*
* INPUTS:
*       regAddr - The register's address.
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwReadGlobal3Reg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
)
{
    GT_U8       phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL3_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    DBG_INFO(("read from global 3 register: phyAddr 0x%x, regAddr 0x%x, ", phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",*data));
    return retVal;
}


/*******************************************************************************
* hwWriteGlobal3Reg
*
* DESCRIPTION:
*       This function writes to a switch's global 3 register.
*
* INPUTS:
*       regAddr - The register's address.
*       data    - The data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwWriteGlobal3Reg
(
    IN  GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_U8   phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL3_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    DBG_INFO(("Write to global 3 register: phyAddr 0x%x, regAddr 0x%x, ", phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",data));

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*******************************************************************************
* hwGetGlobal3RegField
*
* DESCRIPTION:
*       This function reads a specified field from a switch's global 3 register.
*
* INPUTS:
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to read.
*
* OUTPUTS:
*       data        - The read register field.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwGetGlobal3RegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    OUT GT_U16   *data
)
{
    GT_U16 mask;            /* Bits mask to be read */
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL3_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    if(retVal != GT_OK)
        return retVal;

    CALC_MASK(fieldOffset,fieldLength,mask);
    tmpData = (tmpData & mask) >> fieldOffset;
    *data = tmpData;
    DBG_INFO(("Read from global 3 register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("fOff %d, fLen %d, data 0x%x.\n",fieldOffset,fieldLength,*data));

    return GT_OK;
}


/*******************************************************************************
* hwSetGlobal3RegField
*
* DESCRIPTION:
*       This function writes to specified field in a switch's global 3 register.
*
* INPUTS:
*       regAddr     - The register's address.
*       fieldOffset - The field start bit index. (0 - 15)
*       fieldLength - Number of bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  The sum of fieldOffset & fieldLength parameters must be smaller-
*           equal to 16.
*
*******************************************************************************/
GT_STATUS hwSetGlobal3RegField
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U8    fieldOffset,
    IN  GT_U8    fieldLength,
    IN  GT_U16   data
)
{
    GT_U16 mask;
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL3_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    CALC_MASK(fieldOffset,fieldLength,mask);

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= ((data << fieldOffset) & mask);

    DBG_INFO(("Write to global 3 register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("fieldOff %d, fieldLen %d, data 0x%x.\n",fieldOffset,
              fieldLength,data));

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}

/*******************************************************************************
* hwSetGlobal3RegBits
*
* DESCRIPTION:
*       This function writes to specified bits in a switch's global 3 register.
*
* INPUTS:
*       regAddr     - The register's address.
*       mask         - The bits to write.
*       data        - Data to be written.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       1.  When Data is 0x1002 and mask is 0xF00F, 0001b is written to bit[31:24]
*            and 0010b is written to bit[3:0]
*
*******************************************************************************/
GT_STATUS hwSetGlobal3RegBits
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U16   mask,
    IN  GT_U16   data
)
{
    GT_U16 tmpData;
    GT_STATUS   retVal;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL3_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,&tmpData);

    if(retVal != GT_OK)
    {
        gtSemGive(dev,dev->multiAddrSem);
        return retVal;
    }

    /* Set the desired bits to 0.                       */
    tmpData &= ~mask;
    /* Set the given data into the above reset bits.    */
    tmpData |= (data & mask);

    DBG_INFO(("Write to global 3 register: regAddr 0x%x, ",
              regAddr));
    DBG_INFO(("mask %d, data 0x%x.\n",mask,data));

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,tmpData);

    gtSemGive(dev,dev->multiAddrSem);

    return retVal;
}


/*********************************************************************************************/

/*******************************************************************************
* hwReadMiiReg
*
* DESCRIPTION:
*       This function reads a switch register.
*
* INPUTS:
*       phyAddr - Phy Address to read the register for.( 0 ~ 0x1F )
*       regAddr - The register's address.
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwReadMiiReg
(
    IN  GT_QD_DEV *dev,
    IN  GT_U8     phyAddr,
    IN  GT_U8     regAddr,
    OUT GT_U16    *data
)
{
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);

     gtSemGive(dev,dev->multiAddrSem);

    DBG_INFO(("Read from phy(0x%x) register: regAddr 0x%x, data 0x%x.\n",
              phyAddr,regAddr,*data));

    return retVal;
}


/*******************************************************************************
* hwWriteMiiReg
*
* DESCRIPTION:
*       This function writes a switch register.
*
* INPUTS:
*       phyAddr - Phy Address to read the register for.( 0 ~ 0x1F )
*       regAddr - The register's address.
*
* OUTPUTS:
*       data    - The read register's data.
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwWriteMiiReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    phyAddr,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_STATUS   retVal;

    gtSemTake(dev,dev->multiAddrSem,OS_WAIT_FOREVER);

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);

    gtSemGive(dev,dev->multiAddrSem);

    DBG_INFO(("Write to phy(0x%x) register: regAddr 0x%x, data 0x%x.\n",
              phyAddr,regAddr,data));

    return retVal;
}


/*******************************************************************************
* hwReadPPU
*
* DESCRIPTION:
*            This function reads PPU bit in Global Register
*
* INPUTS:
*            None.
*
* OUTPUTS:
*            data    - The read register's data.
*
* RETURNS:
*            GT_OK on success, or
*            GT_FAIL otherwise.
*
* COMMENTS:
*            This function can be used to access PHY register connected to Gigabit
*            Switch.
*            Semaphore should be acquired before this function get called.
*
*******************************************************************************/
static GT_STATUS hwReadPPU
(
    IN  GT_QD_DEV *dev,
    OUT GT_U16    *data
)
{
    GT_STATUS   retVal;
    GT_U16        tmpData;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    retVal =  miiSmiIfReadRegister(dev,phyAddr,4,&tmpData);

    if(retVal != GT_OK)
    {
        return retVal;
    }

    *data = (tmpData >> 14) & 0x1;

    DBG_INFO(("OK.\n"));
    return GT_OK;
}

/*******************************************************************************
* hwWritePPU
*
* DESCRIPTION:
*            This function writes PPU bit in Global Register
*
* INPUTS:
*            data - The value to write into PPU bit
*
* OUTPUTS:
*            None.
*
* RETURNS:
*            GT_OK on success, or
*            GT_FAIL otherwise.
*
* COMMENTS:
*            This function can be used to access PHY register connected to Gigabit
*            Switch.
*            Semaphore should be acquired before this function get called.
*
*******************************************************************************/
static GT_STATUS hwWritePPU
(
    IN  GT_QD_DEV *dev,
    IN  GT_U16    data
)
{
    GT_STATUS   retVal;
    GT_U16        tmpData;
    GT_U8       phyAddr;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    retVal =  miiSmiIfReadRegister(dev,phyAddr,4,&tmpData);

    if(retVal != GT_OK)
    {
        return retVal;
    }

    if (data)
        tmpData |= (0x1 << 14);
    else
        tmpData &= ~(0x1 << 14);

    retVal = miiSmiIfWriteRegister(dev,phyAddr,4,tmpData);

    if(retVal != GT_OK)
    {
        return retVal;
    }

    /* busy wait - till PPU is actually disabled */
    if (data == 0) /* disable PPU */
    {
        gtDelay(250);
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


static GT_STATUS coreReadPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
)
{
    GT_U8       phyAddr;
    GT_STATUS   retVal, retPPU = 0;
    GT_U16        orgPPU;
    GT_BOOL        usePPU = GT_FALSE;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PHY_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    orgPPU = 0;

    if(IS_IN_DEV_GROUP(dev, DEV_PPU_READ_ONLY))
    {
        if((IS_IN_DEV_GROUP(dev,DEV_PPU_SERDES_ACCESS_RES)) && (dev->validSerdesVec & (1<<phyAddr)))
        {
            if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
            {
                return retPPU;
            }

            if(orgPPU)
            {
                /* Disable PPU so that External Phy can be accessible */
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                    return retPPU;
                }
            }
        }
        else
        usePPU = GT_TRUE;
    }
    else if(IS_IN_DEV_GROUP(dev,DEV_EXTERNAL_PHY))
    {
        if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
        {
            return retPPU;
        }

        if(orgPPU)
        {
            if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS))
            {
                if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS_RES))
                {
                    if(dev->revision != 0)
                        usePPU = GT_TRUE;
                }
                else
                {
                     usePPU = GT_TRUE;
                }
            }

            /* Disable PPU so that External Phy can be accessible */
            if (!usePPU)
            {
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                    return retPPU;
                }
            }
        }
    }
    else if(IS_IN_DEV_GROUP(dev,DEV_PHY_ACCESS_NO_DIRECTLY))
    {
      usePPU = GT_TRUE;
    }

    if (usePPU)
    {
        retVal = phyRegReadPPUEn (dev,phyAddr,regAddr,data);
    }
    else
    {
        retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);
    }

    DBG_INFO(("Read from phy(%d) register: phyAddr 0x%x, regAddr 0x%x, ", portNum,phyAddr,regAddr));

    if(orgPPU && (!usePPU))
    {
      if((retPPU=hwWritePPU(dev, orgPPU)) != GT_OK)
      {
        return retPPU;
      }
    }

    return retVal;
}


static GT_STATUS coreWritePhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_U8           phyAddr;
    GT_STATUS   retVal, retPPU;
    GT_U16        orgPPU = 0;
    GT_BOOL        usePPU = GT_FALSE;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PHY_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    if(IS_IN_DEV_GROUP(dev,DEV_PPU_READ_ONLY))
    {
        if((IS_IN_DEV_GROUP(dev,DEV_PPU_SERDES_ACCESS_RES)) && (dev->validSerdesVec & (1<<phyAddr)))
        {
            if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
            {
                return retPPU;
            }

            if(orgPPU)
            {
                /* Disable PPU so that External Phy can be accessible */
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                        return retPPU;
                }
            }
        }
        else
          usePPU = GT_TRUE;
    }
    else if(IS_IN_DEV_GROUP(dev,DEV_EXTERNAL_PHY))
    {
        if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
        {
            return retPPU;
        }

        if(orgPPU)
        {
            if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS))
            {
                if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS_RES))
                {
                    if(dev->revision != 0)
                        usePPU = GT_TRUE;
                }
                else
                {
                     usePPU = GT_TRUE;
                }
            }

            /* Disable PPU so that External Phy can be accessible */
            if (!usePPU)
            {
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                    return retPPU;
                }
            }
        }
    }
    else if(IS_IN_DEV_GROUP(dev,DEV_PHY_ACCESS_NO_DIRECTLY))
    {
      usePPU = GT_TRUE;
    }

    DBG_INFO(("Write to phy(%d) register: phyAddr 0x%x, regAddr 0x%x, ",
                portNum,phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",data));

    if (usePPU)
    {
        retVal = phyRegWritePPUEn (dev,phyAddr,regAddr,data);
    }
    else
    {
        retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);
    }

        if(orgPPU && (!usePPU))
        {
            if((retPPU=hwWritePPU(dev, orgPPU)) != GT_OK)
            {
                return retPPU;
            }
        }

    return retVal;
}


static GT_STATUS coreReadPagedPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U32     anyPage,
    OUT GT_U16   *data
)
{
    GT_U8       phyAddr,pageAddr;
    GT_STATUS   retVal, retPPU;
    GT_U16        orgPPU, tmpData, orgPage;
    GT_BOOL        usePPU = GT_FALSE;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PHY_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    orgPPU = 0;

    if(IS_IN_DEV_GROUP(dev,DEV_PPU_READ_ONLY))
    {
        if((IS_IN_DEV_GROUP(dev,DEV_PPU_SERDES_ACCESS_RES)) && (dev->validSerdesVec & (1<<phyAddr)))
        {
            if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
            {
                return retPPU;
            }

            if(orgPPU)
            {
                /* Disable PPU so that External Phy can be accessible */
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                    return retPPU;
                }
            }
        }
        else
             usePPU = GT_TRUE;
    }
    else if(IS_IN_DEV_GROUP(dev,DEV_EXTERNAL_PHY))
    {
        if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
        {
            return retPPU;
        }

        if(orgPPU)
        {
            if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS))
            {
                if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS_RES))
                {
                    if(dev->revision != 0)
                        usePPU = GT_TRUE;
                }
                else
                {
                     usePPU = GT_TRUE;
                }
            }

            /* Disable PPU so that External Phy can be accessible */
            if (!usePPU)
            {
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                    return retPPU;
                }
            }
        }
    }

    if(anyPage & (1 << regAddr))
    {
        if (usePPU)
        {
            retVal = phyRegReadPPUEn (dev,phyAddr,regAddr,data);
        }
        else
        {
            retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);
        }
        DBG_INFO(("Read from phy(%d) register: smiAddr 0x%x, pageNum 0x%x, regAddr 0x%x\n",
                    portNum,phyAddr,pageNum,regAddr));
    }
    else
    {
        pageAddr = GT_GET_PAGE_ADDR(regAddr);

        if (usePPU)
        {
            retVal = phyRegReadPPUEn (dev,phyAddr,pageAddr,&orgPage);
        }
        else
        {
            retVal = miiSmiIfReadRegister(dev,phyAddr,pageAddr,&orgPage);
        }

        if (retVal != GT_OK)
        {
            DBG_INFO(("Reading page register failed\n"));
            return retVal;
        }

        if(pageAddr == 22)
            tmpData = orgPage & 0xFF00;
        else
            tmpData = orgPage & 0xFFC0;
        tmpData |= pageNum;

        if (usePPU)
        {
            if((retVal = phyRegWritePPUEn(dev,phyAddr,pageAddr,tmpData)) == GT_OK)
            {
                retVal = phyRegReadPPUEn (dev,phyAddr,regAddr,data);

                DBG_INFO(("Read from phy(%d) register: smiAddr 0x%x, pageNum 0x%x, regAddr 0x%x\n",
                            portNum,phyAddr,pageNum,regAddr));
            }
        }
        else
        {
            if((retVal = miiSmiIfWriteRegister(dev,phyAddr,pageAddr,tmpData)) == GT_OK)
            {
                retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);

                DBG_INFO(("Read from phy(%d) register: smiAddr 0x%x, pageNum 0x%x, regAddr 0x%x\n",
                            portNum,phyAddr,pageNum,regAddr));
            }
        }
    }

        if(orgPPU && (!usePPU))
        {
            if((retPPU=hwWritePPU(dev, orgPPU)) != GT_OK)
            {
                return retPPU;
            }
        }

    return retVal;

}


static GT_STATUS coreWritePagedPhyReg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    portNum,
    IN  GT_U8    pageNum,
    IN  GT_U8    regAddr,
    IN  GT_U32     anyPage,
    IN  GT_U16   data
)
{
    GT_U8           phyAddr,pageAddr;
    GT_STATUS   retVal, retPPU;
    GT_U16        orgPPU, tmpData, orgPage;
    GT_BOOL        usePPU = GT_FALSE;

    phyAddr = CALC_SMI_DEV_ADDR(dev, portNum, PHY_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    orgPPU = 0;

    if(IS_IN_DEV_GROUP(dev,DEV_PPU_READ_ONLY))
    {
        if((IS_IN_DEV_GROUP(dev,DEV_PPU_SERDES_ACCESS_RES)) && (dev->validSerdesVec & (1<<phyAddr)))
        {
            if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
            {
                return retPPU;
            }

            if(orgPPU)
            {
                /* Disable PPU so that External Phy can be accessible */
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                    return retPPU;
                }
            }
        }
        else
             usePPU = GT_TRUE;
    }
    else if(IS_IN_DEV_GROUP(dev,DEV_EXTERNAL_PHY))
    {
        if((retPPU=hwReadPPU(dev, &orgPPU)) != GT_OK)
        {
            return retPPU;
        }

        if(orgPPU)
        {
            if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS))
            {
                if(IS_IN_DEV_GROUP(dev,DEV_PPU_PHY_ACCESS_RES))
                {
                    if(dev->revision != 0)
                        usePPU = GT_TRUE;
                }
                else
                {
                     usePPU = GT_TRUE;
                }
            }

            /* Disable PPU so that External Phy can be accessible */
            if (!usePPU)
            {
                if((retPPU=hwWritePPU(dev, 0)) != GT_OK)
                {
                    return retPPU;
                }
            }
        }
    }

    DBG_INFO(("Write to phy(%d) register: smiAddr 0x%x, pageNum 0x%x, regAddr 0x%x\n",
                portNum,phyAddr,pageNum,regAddr));
    DBG_INFO(("data 0x%x.\n",data));

    if(anyPage & (1 << regAddr))
    {
        if (usePPU)
        {
            retVal = phyRegWritePPUEn (dev,phyAddr,regAddr,data);
        }
        else
        {
            retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);
        }
    }
    else
    {
        pageAddr = GT_GET_PAGE_ADDR(regAddr);

        if (usePPU)
        {
            retVal = phyRegReadPPUEn (dev,phyAddr,pageAddr,&orgPage);
        }
        else
        {
            retVal = miiSmiIfReadRegister(dev,phyAddr,pageAddr,&orgPage);
        }

        if (retVal != GT_OK)
        {
            DBG_INFO(("Reading page register failed\n"));
            return retVal;
        }

        if(pageAddr == 22)
            tmpData = orgPage & 0xFF00;
        else
            tmpData = orgPage & 0xFFC0;
        tmpData |= pageNum;

        if (usePPU)
        {
            if((retVal = phyRegWritePPUEn(dev,phyAddr,pageAddr,tmpData)) == GT_OK)
            {
                retVal = phyRegWritePPUEn(dev,phyAddr,regAddr,data);
            }
        }
        else
        {
            if((retVal = miiSmiIfWriteRegister(dev,phyAddr,pageAddr,tmpData)) == GT_OK)
            {
                retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);
            }
        }
    }

        if(orgPPU && (!usePPU))
        {
            if((retPPU=hwWritePPU(dev, orgPPU)) != GT_OK)
            {
                return retPPU;
            }
        }

    return retVal;
}


/*****************************************************************************
* phyRegReadPPUEn
*
* DESCRIPTION:
*       This function reads phy register data when PPU is enabled.
*
* INPUTS:
*       phyAddr     - The PHY address to be read.
*       regAddr     - The register address to read.
*       value       - The storage where register date to be saved.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_TRUE   - on success
*       GT_FALSE  - on error
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS phyRegReadPPUEn (GT_QD_DEV* dev, unsigned int phyAddr , unsigned int regAddr,
                        unsigned short* value)
#ifdef GT_RMGMT_ACCESS
{
  GT_U16 smiReg;
  GT_STATUS   retVal;

  HW_DEV_REG_ACCESS regAccess;

  DBG_INFO(("Read Phy register while PPU Enabled\n"));

  regAccess.entries = 4;

  regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
  regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
  regAccess.rw_reg_list[0].reg = QD_REG_SMI_PHY_CMD;
  regAccess.rw_reg_list[0].data = 15;
  smiReg =  QD_SMI_BUSY | (phyAddr << QD_SMI_DEV_ADDR_BIT) | (QD_SMI_READ << QD_SMI_OP_BIT) | (regAddr << QD_SMI_REG_ADDR_BIT) | (QD_SMI_CLAUSE22 << QD_SMI_MODE_BIT);

  regAccess.rw_reg_list[1].cmd = HW_REG_WRITE;
  regAccess.rw_reg_list[1].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
  regAccess.rw_reg_list[1].reg = QD_REG_SMI_PHY_CMD;
  regAccess.rw_reg_list[1].data = smiReg;

  regAccess.rw_reg_list[2].cmd = HW_REG_WAIT_TILL_0;
  regAccess.rw_reg_list[2].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
  regAccess.rw_reg_list[2].reg = QD_REG_SMI_PHY_CMD;
  regAccess.rw_reg_list[2].data = 15;

  regAccess.rw_reg_list[3].cmd = HW_REG_READ;
  regAccess.rw_reg_list[3].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
  regAccess.rw_reg_list[3].reg = QD_REG_SMI_PHY_DATA;
  regAccess.rw_reg_list[3].data = 0;
  retVal = hwAccessMultiRegs(dev, &regAccess);
  if(retVal != GT_OK)
  {
    return retVal;
  }
  *value = (unsigned short)regAccess.rw_reg_list[3].data;
    
  return GT_OK;
}
#else
{
    volatile unsigned int timeOut; /* in 100MS units */
    volatile int i;
    GT_U16 smiReg;

    DBG_INFO(("Read Phy register while PPU Enabled\n"));

    /* first check that it is not busy */
    if(phyReadGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, &smiReg) != GT_OK)
    {
        DBG_INFO(("Reading Phy register Failed\n"));
        return GT_FAIL;
    }
    timeOut = QD_SMI_ACCESS_LOOP; /* initialize the loop count */

    if(smiReg & QD_SMI_BUSY) 
    {
        for(i = 0 ; i < QD_SMI_TIMEOUT ; i++);
        do 
        {
            if(timeOut-- < 1 ) 
            {
                DBG_INFO(("Reading Phy register Timed Out\n"));
                return GT_FAIL;
            }
            if(phyReadGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, &smiReg) != GT_OK)
            {
                DBG_INFO(("Reading Phy register Failed\n"));
                return GT_FAIL;
            }
        } while (smiReg & QD_SMI_BUSY);
    }

    smiReg =  QD_SMI_BUSY | (phyAddr << QD_SMI_DEV_ADDR_BIT) | (QD_SMI_READ << QD_SMI_OP_BIT) | 
            (regAddr << QD_SMI_REG_ADDR_BIT) | (QD_SMI_CLAUSE22 << QD_SMI_MODE_BIT);

    if(phyWriteGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, smiReg) != GT_OK)
    {
        return GT_FAIL;
    }
    timeOut = QD_SMI_ACCESS_LOOP; /* initialize the loop count */
    if(phyReadGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, &smiReg) != GT_OK)
    {
        return GT_FAIL;
    }

    if(smiReg & QD_SMI_BUSY) 
    {
        for(i = 0 ; i < QD_SMI_TIMEOUT ; i++);
        do 
        {
            if(timeOut-- < 1 ) 
            {
                DBG_INFO(("Reading Phy register Timed Out\n"));
                return GT_FALSE;
            }
            if(phyReadGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, &smiReg) != GT_OK)
            {
                DBG_INFO(("Reading Phy register Failed\n"));
                return GT_FAIL;
            }
        } while (smiReg & QD_SMI_BUSY);
    }
    if(phyReadGlobal2Reg(dev,QD_REG_SMI_PHY_DATA, &smiReg) != GT_OK)
    {
        DBG_INFO(("Reading Phy register Failed\n"));
        return GT_FAIL;
    }
    *value = (unsigned short)smiReg;
    
    return GT_OK;
}
#endif

/*****************************************************************************
* phyRegWritePPUEn
*
* DESCRIPTION:
*       This function writes data to a phy register when PPU is enabled.
*
* INPUTS:
*       phyAddr     - The PHY address to be read.
*       regAddr     - The register address to read.
*       value       - The data to be written into the register.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_TRUE   - on success
*       GT_FALSE  - on error
*
* COMMENTS:
*       None.
*
*******************************************************************************/

GT_STATUS phyRegWritePPUEn (GT_QD_DEV* dev, unsigned int phyAddr , unsigned int regAddr,
                       unsigned short value)
#ifdef GT_RMGMT_ACCESS
{
  GT_U16 smiReg;
  GT_STATUS   retVal;

  HW_DEV_REG_ACCESS regAccess;

  DBG_INFO(("Write Phy register while PPU Enabled\n"));

  regAccess.entries = 3;

  regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
  regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
  regAccess.rw_reg_list[0].reg = QD_REG_SMI_PHY_CMD;
  regAccess.rw_reg_list[0].data = 15;

  regAccess.rw_reg_list[1].cmd = HW_REG_WRITE;
  regAccess.rw_reg_list[1].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
  regAccess.rw_reg_list[1].reg = QD_REG_SMI_PHY_DATA;
  regAccess.rw_reg_list[1].data = value;

  smiReg = QD_SMI_BUSY | (phyAddr << QD_SMI_DEV_ADDR_BIT) | (QD_SMI_WRITE << QD_SMI_OP_BIT) | (regAddr << QD_SMI_REG_ADDR_BIT) | (QD_SMI_CLAUSE22 << QD_SMI_MODE_BIT);

  regAccess.rw_reg_list[2].cmd = HW_REG_WRITE;
  regAccess.rw_reg_list[2].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
  regAccess.rw_reg_list[2].reg = QD_REG_SMI_PHY_CMD;
  regAccess.rw_reg_list[2].data = smiReg;

  retVal = hwAccessMultiRegs(dev, &regAccess);
  if(retVal != GT_OK)
  {
    return retVal;
  }
    
  return GT_OK;
}
#else
{
    volatile unsigned int timeOut; /* in 100MS units */
    volatile int i;
    GT_U16 smiReg;

    DBG_INFO(("Writing Phy register while PPU Enabled\n"));

    /* first check that it is not busy */
    if(phyReadGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, &smiReg) != GT_OK)
    {
        DBG_INFO(("Reading Phy register Failed\n"));
        return GT_FAIL;
    }
    timeOut = QD_SMI_ACCESS_LOOP; /* initialize the loop count */


    if(smiReg & QD_SMI_BUSY) 
    {
        for(i = 0 ; i < QD_SMI_TIMEOUT ; i++);
        do 
        {
            if(timeOut-- < 1 ) 
            {
                DBG_INFO(("Writing Phy register Timed Out\n"));
                return GT_FALSE;
            }
            if(phyReadGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, &smiReg) != GT_OK)
            {
                DBG_INFO(("Writing Phy register Failed\n"));
                return GT_FAIL;
            }
        } while (smiReg & QD_SMI_BUSY);
    }

    if(phyWriteGlobal2Reg(dev,QD_REG_SMI_PHY_DATA, value) != GT_OK)
    {
        DBG_INFO(("Writing Phy Data register Failed\n"));
        return GT_FAIL;
    }
    smiReg = QD_SMI_BUSY | (phyAddr << QD_SMI_DEV_ADDR_BIT) | (QD_SMI_WRITE << QD_SMI_OP_BIT) | 
            (regAddr << QD_SMI_REG_ADDR_BIT) | (QD_SMI_CLAUSE22 << QD_SMI_MODE_BIT);

    if(phyWriteGlobal2Reg(dev,QD_REG_SMI_PHY_CMD, smiReg) != GT_OK)
    {
        DBG_INFO(("Writing Phy Command register Failed\n"));
        return GT_FAIL;
    }

    return GT_OK;
}

static GT_STATUS phyReadGlobal2Reg
(
    IN GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    OUT GT_U16   *data
)
{
    GT_U8       phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    retVal = miiSmiIfReadRegister(dev,phyAddr,regAddr,data);

    DBG_INFO(("read from global 2 register: phyAddr 0x%x, regAddr 0x%x, ",
              phyAddr,regAddr));
    DBG_INFO(("data 0x%x.\n",*data));
    return retVal;
}


static GT_STATUS phyWriteGlobal2Reg
(
    IN  GT_QD_DEV *dev,
    IN  GT_U8    regAddr,
    IN  GT_U16   data
)
{
    GT_U8   phyAddr;
    GT_STATUS   retVal;

    phyAddr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
    if (phyAddr == 0xFF)
    {
        return GT_BAD_PARAM;
    }

    retVal = miiSmiIfWriteRegister(dev,phyAddr,regAddr,data);

    return retVal;
}
#endif

#ifdef GT_RMGMT_ACCESS
/*******************************************************************************
* hwAccessMultiRegs
*
* DESCRIPTION:
*       This function accesses switch's registers.
*
* INPUTS:
*   regList     - list of HW_DEV_RW_REG.
*     HW_DEV_RW_REG:
*     cmd - HW_REG_READ, HW_REG_WRITE, HW_REG_WAIT_TILL_0 or HW_REG_WAIT_TILL_1 
*     addr - SMI Address 
*     reg  - Register offset 
*     data - INPUT,OUTPUT:Value in the Register or Bit number
*     
* OUTPUTS:
*   regList
*
* RETURNS:
*       GT_OK on success, or
*       GT_FAIL otherwise.
*
* COMMENTS:
*       None.
*
*******************************************************************************/
GT_STATUS hwAccessMultiRegs
(
    IN GT_QD_DEV *dev,
    INOUT HW_DEV_REG_ACCESS *regList
)
{
  GT_STATUS   retVal;

  gtSemTake(dev,dev->hwAccessRegsSem,OS_WAIT_FOREVER);

  retVal = qdAccessRegs(dev, regList);

  gtSemGive(dev,dev->hwAccessRegsSem);

  return retVal;
}
#endif
