/* * Copyright (C) 2013 Realtek Semiconductor Corp. * All Rights Reserved. * * Unless you and Realtek execute a separate written software license * agreement governing use of this software, this software is licensed * to you under the terms of the GNU General Public License version 2, * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt * * $Revision: 76306 $ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ * * Purpose : RTL8367C switch high-level API for RTL8367C * Feature : PHY related functions * */ #include #if defined(MDC_MDIO_OPERATION) /* Function Name: * rtl8367c_setAsicPHYOCPReg * Description: * Set PHY OCP registers * Input: * phyNo - Physical port number (0~7) * ocpAddr - OCP address * ocpData - Writing data * Output: * None * Return: * RT_ERR_OK - Success * RT_ERR_SMI - SMI access error * RT_ERR_PHY_REG_ID - invalid PHY address * RT_ERR_PHY_ID - invalid PHY no * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy * Note: * None */ ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ) { ret_t retVal; rtk_uint32 regAddr; rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; /* OCP prefix */ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) return retVal; /*prepare access address*/ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; if((retVal = rtl8367c_setAsicReg(regAddr, ocpData)) != RT_ERR_OK) return retVal; return RT_ERR_OK; } /* Function Name: * rtl8367c_getAsicPHYOCPReg * Description: * Get PHY OCP registers * Input: * phyNo - Physical port number (0~7) * ocpAddr - PHY address * pRegData - read data * Output: * None * Return: * RT_ERR_OK - Success * RT_ERR_SMI - SMI access error * RT_ERR_PHY_REG_ID - invalid PHY address * RT_ERR_PHY_ID - invalid PHY no * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy * Note: * None */ ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ) { ret_t retVal; rtk_uint32 regAddr; rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; /* OCP prefix */ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) return retVal; /*prepare access address*/ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; if((retVal = rtl8367c_getAsicReg(regAddr, pRegData)) != RT_ERR_OK) return retVal; return RT_ERR_OK; } #else /* Function Name: * rtl8367c_setAsicPHYOCPReg * Description: * Set PHY OCP registers * Input: * phyNo - Physical port number (0~7) * ocpAddr - OCP address * ocpData - Writing data * Output: * None * Return: * RT_ERR_OK - Success * RT_ERR_SMI - SMI access error * RT_ERR_PHY_REG_ID - invalid PHY address * RT_ERR_PHY_ID - invalid PHY no * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy * Note: * None */ ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ) { ret_t retVal; rtk_uint32 regData; rtk_uint32 busyFlag, checkCounter; rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; /*Check internal phy access busy or not*/ /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); if(retVal != RT_ERR_OK) return retVal; if(busyFlag) return RT_ERR_BUSYWAIT_TIMEOUT; /* OCP prefix */ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) return retVal; /*prepare access data*/ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_WRITE_DATA, ocpData); if(retVal != RT_ERR_OK) return retVal; /*prepare access address*/ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData); if(retVal != RT_ERR_OK) return retVal; /*Set WRITE Command*/ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK | RTL8367C_RW_MASK); checkCounter = 100; while(checkCounter) { retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); if((retVal != RT_ERR_OK) || busyFlag) { checkCounter --; if(0 == checkCounter) return RT_ERR_BUSYWAIT_TIMEOUT; } else { checkCounter = 0; } } return retVal; } /* Function Name: * rtl8367c_getAsicPHYOCPReg * Description: * Get PHY OCP registers * Input: * phyNo - Physical port number (0~7) * ocpAddr - PHY address * pRegData - read data * Output: * None * Return: * RT_ERR_OK - Success * RT_ERR_SMI - SMI access error * RT_ERR_PHY_REG_ID - invalid PHY address * RT_ERR_PHY_ID - invalid PHY no * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy * Note: * None */ ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ) { ret_t retVal; rtk_uint32 regData; rtk_uint32 busyFlag,checkCounter; rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; /*Check internal phy access busy or not*/ /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); if(retVal != RT_ERR_OK) return retVal; if(busyFlag) return RT_ERR_BUSYWAIT_TIMEOUT; /* OCP prefix */ ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) return retVal; /*prepare access address*/ ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData); if(retVal != RT_ERR_OK) return retVal; /*Set READ Command*/ retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK ); if(retVal != RT_ERR_OK) return retVal; checkCounter = 100; while(checkCounter) { retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); if((retVal != RT_ERR_OK) || busyFlag) { checkCounter --; if(0 == checkCounter) return RT_ERR_FAILED; } else { checkCounter = 0; } } /*get PHY register*/ retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_READ_DATA, ®Data); if(retVal != RT_ERR_OK) return retVal; *pRegData = regData; return RT_ERR_OK; } #endif /* Function Name: * rtl8367c_setAsicPHYReg * Description: * Set PHY registers * Input: * phyNo - Physical port number (0~7) * phyAddr - PHY address (0~31) * phyData - Writing data * Output: * None * Return: * RT_ERR_OK - Success * RT_ERR_SMI - SMI access error * RT_ERR_PHY_REG_ID - invalid PHY address * RT_ERR_PHY_ID - invalid PHY no * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy * Note: * None */ ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 phyData ) { rtk_uint32 ocp_addr; if(phyAddr > RTL8367C_PHY_REGNOMAX) return RT_ERR_PHY_REG_ID; ocp_addr = 0xa400 + phyAddr*2; return rtl8367c_setAsicPHYOCPReg(phyNo, ocp_addr, phyData); } /* Function Name: * rtl8367c_getAsicPHYReg * Description: * Get PHY registers * Input: * phyNo - Physical port number (0~7) * phyAddr - PHY address (0~31) * pRegData - Writing data * Output: * None * Return: * RT_ERR_OK - Success * RT_ERR_SMI - SMI access error * RT_ERR_PHY_REG_ID - invalid PHY address * RT_ERR_PHY_ID - invalid PHY no * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy * Note: * None */ ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 *pRegData ) { rtk_uint32 ocp_addr; if(phyAddr > RTL8367C_PHY_REGNOMAX) return RT_ERR_PHY_REG_ID; ocp_addr = 0xa400 + phyAddr*2; return rtl8367c_getAsicPHYOCPReg(phyNo, ocp_addr, pRegData); } /* Function Name: * rtl8367c_setAsicSdsReg * Description: * Set Serdes registers * Input: * sdsId - sdsid (0~1) * sdsReg - reg address (0~31) * sdsPage - Writing data * Output: * None * Return: * RT_ERR_OK - Success * Note: * None */ ret_t rtl8367c_setAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 value) { rtk_uint32 retVal; if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value)) != RT_ERR_OK) return retVal; if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK) return retVal; if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0|sdsId)) != RT_ERR_OK) return retVal; return RT_ERR_OK; } /* Function Name: * rtl8367c_getAiscSdsReg * Description: * Get Serdes registers * Input: * sdsId - sdsid (0~1) * sdsReg - reg address (0~31) * sdsPage - Writing data * Output: * None * Return: * RT_ERR_OK - Success * Note: * None */ ret_t rtl8367c_getAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 *value) { rtk_uint32 retVal, busy; if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK) return retVal; if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080|sdsId)) != RT_ERR_OK) return retVal; while(1) { if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_CMD, &busy))!=RT_ERR_OK) return retVal; if ((busy & 0x100) == 0) break; } if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value))!=RT_ERR_OK) return retVal; return RT_ERR_OK; }