| #include <Copyright.h> |
| /******************************************************************************* |
| * gtVct.c |
| * |
| * DESCRIPTION: |
| * API for Marvell Virtual Cable Tester. |
| * |
| * DEPENDENCIES: |
| * None. |
| * |
| * FILE REVISION NUMBER: |
| * $Revision: 1 $ |
| *******************************************************************************/ |
| #include <msApi.h> |
| #include <gtVct.h> |
| #include <gtDrvConfig.h> |
| #include <gtDrvSwRegs.h> |
| #include <gtHwCntl.h> |
| #include <gtSem.h> |
| |
| |
| |
| /******************************************************************************* |
| * analizePhy100MVCTResult |
| * |
| * DESCRIPTION: |
| * This routine analize the virtual cable test result for 10/100M Phy |
| * |
| * INPUTS: |
| * regValue - test result |
| * |
| * OUTPUTS: |
| * cableStatus - analized test result. |
| * cableLen - cable length or the distance where problem occurs. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * None. |
| * |
| * GalTis: |
| * |
| *******************************************************************************/ |
| static |
| GT_STATUS analizePhy100MVCTResult |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U16 regValue, |
| OUT GT_TEST_STATUS *cableStatus, |
| OUT GT_CABLE_LEN *cableLen |
| ) |
| { |
| int len; |
| |
| GT_UNUSED_PARAM(dev); |
| |
| switch((regValue & 0x6000) >> 13) |
| { |
| case 0: |
| /* test passed. No problem found. */ |
| /* check if there is impedance mismatch */ |
| if ((regValue & 0xFF) == 0xFF) |
| { |
| *cableStatus = GT_NORMAL_CABLE; |
| cableLen->normCableLen = GT_UNKNOWN_LEN; |
| } |
| else |
| { |
| *cableStatus = GT_IMPEDANCE_MISMATCH; |
| len = (int)FORMULA_PHY100M(regValue & 0xFF); |
| if(len <= 0) |
| cableLen->errCableLen = 0; |
| else |
| cableLen->errCableLen = (GT_U8)len; |
| } |
| |
| break; |
| case 1: |
| /* test passed. Cable is short. */ |
| *cableStatus = GT_SHORT_CABLE; |
| len = (int)FORMULA_PHY100M(regValue & 0xFF); |
| if(len <= 0) |
| cableLen->errCableLen = 0; |
| else |
| cableLen->errCableLen = (GT_U8)len; |
| break; |
| case 2: |
| /* test passed. Cable is open. */ |
| *cableStatus = GT_OPEN_CABLE; |
| len = (int)FORMULA_PHY100M(regValue & 0xFF); |
| if(len <= 0) |
| cableLen->errCableLen = 0; |
| else |
| cableLen->errCableLen = (GT_U8)len; |
| break; |
| case 3: |
| default: |
| /* test failed. No result is valid. */ |
| *cableStatus = GT_TEST_FAIL; |
| break; |
| } |
| |
| return GT_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * getCableStatus_Phy100M |
| * |
| * DESCRIPTION: |
| * This routine perform the virtual cable test for the 10/100Mbps phy, |
| * and returns the the status per Rx/Tx pair. |
| * |
| * INPUTS: |
| * port - logical port number. |
| * |
| * OUTPUTS: |
| * cableStatus - the port copper cable status. |
| * cableLen - the port copper cable length. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * None. |
| * |
| * GalTis: |
| * |
| *******************************************************************************/ |
| static |
| GT_STATUS getCableStatus_Phy100M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort, |
| OUT GT_CABLE_STATUS *cableStatus |
| ) |
| { |
| GT_STATUS status; |
| GT_U16 reg26, reg27; |
| |
| DBG_INFO(("getCableStatus_100Phy Called.\n")); |
| |
| /* |
| * phy should be in 100 Full Duplex. |
| */ |
| if((status= hwWritePhyReg(dev,hwPort,0,QD_PHY_RESET | QD_PHY_SPEED | QD_PHY_DUPLEX)) != GT_OK) |
| { |
| return status; |
| } |
| |
| /* |
| * start Virtual Cable Tester |
| */ |
| if((status= hwWritePhyReg(dev,hwPort,26,0x8000)) != GT_OK) |
| { |
| return status; |
| } |
| |
| do |
| { |
| if((status= hwReadPhyReg(dev,hwPort,26,®26)) != GT_OK) |
| { |
| return status; |
| } |
| |
| } while(reg26 & 0x8000); |
| |
| /* |
| * read the test result for RX Pair |
| */ |
| if((status= hwReadPhyReg(dev,hwPort,26,®26)) != GT_OK) |
| { |
| return status; |
| } |
| |
| /* |
| * read the test result for TX Pair |
| */ |
| if((status= hwReadPhyReg(dev,hwPort,27,®27)) != GT_OK) |
| { |
| return status; |
| } |
| |
| cableStatus->phyType = PHY_100M; |
| |
| /* |
| * analyze the test result for RX Pair |
| */ |
| analizePhy100MVCTResult(dev, reg26, &cableStatus->cableStatus[MDI_RX_PAIR], |
| &cableStatus->cableLen[MDI_RX_PAIR]); |
| |
| /* |
| * analyze the test result for TX Pair |
| */ |
| analizePhy100MVCTResult(dev, reg27, &cableStatus->cableStatus[MDI_TX_PAIR], |
| &cableStatus->cableLen[MDI_TX_PAIR]); |
| |
| return status; |
| } |
| |
| static |
| GT_STATUS enable1stWorkAround_Phy100M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort |
| ) |
| { |
| GT_U16 value; |
| GT_STATUS status; |
| |
| /* enable 1st work-around */ |
| if ((status = hwWritePhyReg(dev, hwPort, 29, 3)) != GT_OK) |
| return status; |
| |
| value = 0x6440; |
| if ((status = hwWritePhyReg(dev, hwPort, 30, value)) != GT_OK) |
| return status; |
| |
| return GT_OK; |
| } |
| |
| static |
| GT_STATUS disable1stWorkAround_Phy100M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort |
| ) |
| { |
| GT_STATUS status; |
| |
| /* disable 1st work-around */ |
| if ((status = hwWritePhyReg(dev, hwPort, 29, 3)) != GT_OK) |
| return status; |
| |
| if ((status = hwWritePhyReg(dev, hwPort, 30, 0)) != GT_OK) |
| return status; |
| |
| return GT_OK; |
| } |
| |
| static |
| GT_STATUS workAround_Phy100M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort, |
| OUT GT_CABLE_STATUS *cableStatus |
| ) |
| { |
| GT_STATUS status = GT_OK; |
| |
| /* |
| * If Cable Status is OPEN and the length is less than 15m, |
| * then apply Work Around. |
| */ |
| |
| if((cableStatus->cableStatus[MDI_RX_PAIR] == GT_OPEN_CABLE) || |
| (cableStatus->cableStatus[MDI_TX_PAIR] == GT_OPEN_CABLE)) |
| { |
| /* must be disabled first and then enable again */ |
| disable1stWorkAround_Phy100M(dev,hwPort); |
| |
| enable1stWorkAround_Phy100M(dev,hwPort); |
| |
| if((status= hwWritePhyReg(dev,hwPort,29,0x000A)) != GT_OK) |
| { |
| return status; |
| } |
| if((status= hwWritePhyReg(dev,hwPort,30,0x0002)) != GT_OK) |
| { |
| return status; |
| } |
| |
| if((status = getCableStatus_Phy100M(dev,hwPort,cableStatus)) != GT_OK) |
| { |
| return status; |
| } |
| |
| if((status= hwWritePhyReg(dev,hwPort,29,0x000A)) != GT_OK) |
| { |
| return status; |
| } |
| if((status= hwWritePhyReg(dev,hwPort,30,0x0000)) != GT_OK) |
| { |
| return status; |
| } |
| } |
| |
| return status; |
| } |
| |
| |
| static |
| GT_STATUS enable1stWorkAround_Phy1000M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort |
| ) |
| { |
| GT_STATUS status; |
| |
| /* enable 1st work-around */ |
| if ((status = hwWritePhyReg(dev, hwPort, 29, 0x0018)) != GT_OK) |
| return status; |
| |
| if ((status = hwWritePhyReg(dev, hwPort, 30, 0x00c2)) != GT_OK) |
| return status; |
| |
| if ((status = hwWritePhyReg(dev, hwPort, 30, 0x00ca)) != GT_OK) |
| return status; |
| |
| if ((status = hwWritePhyReg(dev, hwPort, 30, 0x00c2)) != GT_OK) |
| return status; |
| |
| return GT_OK; |
| } |
| |
| static |
| GT_STATUS disable1stWorkAround_Phy1000M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort |
| ) |
| { |
| GT_STATUS status; |
| |
| /* disable 1st work-around */ |
| if ((status = hwWritePhyReg(dev, hwPort, 29, 0x0018)) != GT_OK) |
| return status; |
| |
| if ((status = hwWritePhyReg(dev, hwPort, 30, 0x0042)) != GT_OK) |
| return status; |
| |
| return GT_OK; |
| } |
| |
| /******************************************************************************* |
| * analizePhy1000MVCTResult |
| * |
| * DESCRIPTION: |
| * This routine analize the virtual cable test result for a Gigabit Phy |
| * |
| * INPUTS: |
| * reg17 - original value of register 17 |
| * regValue - test result |
| * |
| * OUTPUTS: |
| * cableStatus - analized test result. |
| * cableLen - cable length or the distance where problem occurs. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * None. |
| * |
| * GalTis: |
| * |
| *******************************************************************************/ |
| static |
| GT_STATUS analizePhy1000MVCTResult |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U16 reg17, |
| IN GT_U16 regValue, |
| OUT GT_TEST_STATUS *cableStatus, |
| OUT GT_CABLE_LEN *cableLen |
| ) |
| { |
| GT_U16 u16Data; |
| int len; |
| |
| GT_UNUSED_PARAM(dev); |
| |
| switch((regValue & 0x6000) >> 13) |
| { |
| case 0: |
| |
| /* Check Impedance Mismatch */ |
| if ((regValue & 0xFF) < 0xFF) |
| { |
| /* if the reflected amplitude is low it is good cable too. |
| for this registers values it is a good cable: |
| 0xE23, 0xE24, 0xE25, 0xE26, 0xE27 */ |
| if ((regValue < 0xE23) || (regValue > 0xE27)) |
| { |
| *cableStatus = GT_IMPEDANCE_MISMATCH; |
| len = (int)FORMULA_PHY1000M(regValue & 0xFF); |
| if(len <= 0) |
| cableLen->errCableLen = 0; |
| else |
| cableLen->errCableLen = (GT_U8)len; |
| break; |
| } |
| } |
| |
| /* test passed. No problem found. */ |
| *cableStatus = GT_NORMAL_CABLE; |
| |
| u16Data = reg17; |
| |
| /* To get Cable Length, Link should be on and Speed should be 100M or 1000M */ |
| if(!(u16Data & 0x0400)) |
| { |
| cableLen->normCableLen = GT_UNKNOWN_LEN; |
| break; |
| } |
| |
| if((u16Data & 0xC000) != 0x8000) |
| { |
| cableLen->normCableLen = GT_UNKNOWN_LEN; |
| break; |
| } |
| |
| /* |
| * read the test result for the selected MDI Pair |
| */ |
| |
| u16Data = ((u16Data >> 7) & 0x7); |
| |
| switch(u16Data) |
| { |
| case 0: |
| cableLen->normCableLen = GT_LESS_THAN_50M; |
| break; |
| case 1: |
| cableLen->normCableLen = GT_50M_80M; |
| break; |
| case 2: |
| cableLen->normCableLen = GT_80M_110M; |
| break; |
| case 3: |
| cableLen->normCableLen = GT_110M_140M; |
| break; |
| case 4: |
| cableLen->normCableLen = GT_MORE_THAN_140; |
| break; |
| default: |
| cableLen->normCableLen = GT_UNKNOWN_LEN; |
| break; |
| } |
| break; |
| case 1: |
| /* test passed. Cable is short. */ |
| *cableStatus = GT_SHORT_CABLE; |
| len = (int)FORMULA_PHY1000M(regValue & 0xFF); |
| if(len <= 0) |
| cableLen->errCableLen = 0; |
| else |
| cableLen->errCableLen = (GT_U8)len; |
| break; |
| case 2: |
| /* test passed. Cable is open. */ |
| *cableStatus = GT_OPEN_CABLE; |
| len = (int)FORMULA_PHY1000M(regValue & 0xFF); |
| if(len <= 0) |
| cableLen->errCableLen = 0; |
| else |
| cableLen->errCableLen = (GT_U8)len; |
| break; |
| case 3: |
| default: |
| /* test failed. No result is valid. */ |
| *cableStatus = GT_TEST_FAIL; |
| break; |
| } |
| |
| return GT_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * getCableStatus_Phy1000M |
| * |
| * DESCRIPTION: |
| * This routine perform the virtual cable test for the 10/100Mbps phy, |
| * and returns the the status per Rx/Tx pair. |
| * |
| * INPUTS: |
| * port - logical port number. |
| * reg17 - original value of reg17. |
| * |
| * OUTPUTS: |
| * cableStatus - the port copper cable status. |
| * cableLen - the port copper cable length. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * None. |
| * |
| * GalTis: |
| * |
| *******************************************************************************/ |
| static |
| GT_STATUS getCableStatus_Phy1000M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort, |
| IN GT_U16 reg17, |
| OUT GT_CABLE_STATUS *cableStatus |
| ) |
| { |
| GT_STATUS status; |
| GT_U16 reg28; |
| int i; |
| |
| DBG_INFO(("getCableStatus_Phy1000M Called.\n")); |
| |
| /* |
| * start Virtual Cable Tester |
| */ |
| if((status= hwWritePagedPhyReg(dev,hwPort,0,28,0,0x8000)) != GT_OK) |
| { |
| return status; |
| } |
| |
| do |
| { |
| if((status= hwReadPhyReg(dev,hwPort,28,®28)) != GT_OK) |
| { |
| return status; |
| } |
| |
| } while(reg28 & 0x8000); |
| |
| cableStatus->phyType = PHY_1000M; |
| |
| DBG_INFO(("Reg28 after test : %0#x.\n", reg28)); |
| |
| for (i=0; i<GT_MDI_PAIR_NUM; i++) |
| { |
| /* |
| * read the test result for the selected MDI Pair |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,(GT_U8)i,28,0,®28)) != GT_OK) |
| { |
| return status; |
| } |
| |
| /* |
| * analyze the test result for RX Pair |
| */ |
| if((status = analizePhy1000MVCTResult(dev, reg17, reg28, |
| &cableStatus->cableStatus[i], |
| &cableStatus->cableLen[i])) != GT_OK) |
| { |
| return status; |
| } |
| } |
| |
| return GT_OK; |
| } |
| |
| static |
| GT_STATUS workAround_Phy1000M |
| ( |
| GT_QD_DEV *dev, |
| GT_U8 hwPort |
| ) |
| { |
| GT_STATUS status; |
| |
| DBG_INFO(("workAround for Gigabit Phy Called.\n")); |
| |
| if((status = hwWritePhyReg(dev,hwPort,29,0x1e)) != GT_OK) |
| { |
| return status; |
| } |
| |
| if((status = hwWritePhyReg(dev,hwPort,30,0xcc00)) != GT_OK) |
| { |
| return status; |
| } |
| |
| if((status = hwWritePhyReg(dev,hwPort,30,0xc800)) != GT_OK) |
| { |
| return status; |
| } |
| if((status = hwWritePhyReg(dev,hwPort,30,0xc400)) != GT_OK) |
| { |
| return status; |
| } |
| if((status = hwWritePhyReg(dev,hwPort,30,0xc000)) != GT_OK) |
| { |
| return status; |
| } |
| if((status = hwWritePhyReg(dev,hwPort,30,0xc100)) != GT_OK) |
| { |
| return status; |
| } |
| |
| DBG_INFO(("workAround for Gigabit Phy completed.\n")); |
| return GT_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * getCableStatus_Phy1000MPage |
| * |
| * DESCRIPTION: |
| * This routine perform the virtual cable test for the 10/100Mbps phy with |
| * multiple page mode and returns the the status per MDIP/N. |
| * |
| * INPUTS: |
| * port - logical port number. |
| * |
| * OUTPUTS: |
| * cableStatus - the port copper cable status. |
| * cableLen - the port copper cable length. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * None. |
| * |
| * GalTis: |
| * |
| *******************************************************************************/ |
| static |
| GT_STATUS getCableStatus_Phy1000MPage |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort, |
| IN GT_PHY_INFO *phyInfo, |
| OUT GT_CABLE_STATUS *cableStatus |
| ) |
| { |
| GT_STATUS status; |
| GT_U16 u16Data; |
| GT_U16 reg17 = 0; |
| int i; |
| |
| DBG_INFO(("getCableStatus_Phy1000M Called.\n")); |
| |
| /* |
| * If Fiber is used, simply return with test fail. |
| */ |
| if(phyInfo->flag & GT_PHY_FIBER) |
| { |
| if((status= hwReadPagedPhyReg(dev,hwPort,1,17,phyInfo->anyPage,&u16Data)) != GT_OK) |
| { |
| return status; |
| } |
| |
| if(u16Data & 0x400) |
| { |
| for (i=0; i<GT_MDI_PAIR_NUM; i++) |
| { |
| cableStatus->cableStatus[i] = GT_TEST_FAIL; |
| } |
| return GT_OK; |
| } |
| } |
| |
| /* |
| * If Copper is used and Link is on, get DSP Distance and put it in the |
| * old reg17 format.(bit9:7 with DSP Distance) |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,0,17,phyInfo->anyPage,&u16Data)) != GT_OK) |
| { |
| return status; |
| } |
| |
| if(u16Data & 0x400) |
| { |
| reg17 = (u16Data & 0xC000) | 0x400; |
| |
| if((status= hwReadPagedPhyReg(dev,hwPort,5,26,phyInfo->anyPage,&u16Data)) != GT_OK) |
| { |
| return status; |
| } |
| reg17 |= ((u16Data & 0x7) << 7); |
| } |
| |
| /* |
| * start Virtual Cable Tester |
| */ |
| if((status= hwWritePagedPhyReg(dev,hwPort,5,16,phyInfo->anyPage,0x8000)) != GT_OK) |
| { |
| return status; |
| } |
| |
| do |
| { |
| if((status= hwReadPagedPhyReg(dev,hwPort,5,16,phyInfo->anyPage,&u16Data)) != GT_OK) |
| { |
| return status; |
| } |
| |
| } while(u16Data & 0x8000); |
| |
| cableStatus->phyType = PHY_1000M; |
| |
| DBG_INFO(("Page 5 of Reg16 after test : %0#x.\n", u16Data)); |
| |
| for (i=0; i<GT_MDI_PAIR_NUM; i++) |
| { |
| /* |
| * read the test result for the selected MDI Pair |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,5,(GT_U8)(16+i),phyInfo->anyPage,&u16Data)) != GT_OK) |
| { |
| return status; |
| } |
| |
| /* |
| * analyze the test result for RX Pair |
| */ |
| if((status = analizePhy1000MVCTResult(dev, reg17, u16Data, |
| &cableStatus->cableStatus[i], |
| &cableStatus->cableLen[i])) != GT_OK) |
| { |
| return status; |
| } |
| } |
| |
| return GT_OK; |
| } |
| |
| |
| |
| /******************************************************************************* |
| * gvctGetCableStatus |
| * |
| * DESCRIPTION: |
| * This routine perform the virtual cable test for the requested port, |
| * and returns the the status per MDI pair. |
| * |
| * INPUTS: |
| * port - logical port number. |
| * |
| * OUTPUTS: |
| * cableStatus - the port copper cable status. |
| * cableLen - the port copper cable length. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * Internal Gigabit Phys in 88E6165 family and 88E6351 family devices |
| * are not supported by this API. For those devices, gvctGetAdvCableDiag |
| * API can be used, instead. |
| * |
| *******************************************************************************/ |
| GT_STATUS gvctGetCableDiag |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_LPORT port, |
| OUT GT_CABLE_STATUS *cableStatus |
| ) |
| { |
| GT_STATUS status; |
| GT_U8 hwPort; |
| GT_U16 orgReg0, orgReg17; |
| GT_BOOL ppuEn; |
| GT_PHY_INFO phyInfo; |
| GT_BOOL autoOn; |
| GT_U16 pageReg; |
| |
| DBG_INFO(("gvctGetCableDiag Called.\n")); |
| 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 VCT */ |
| 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_VCT_CAPABLE)) |
| { |
| DBG_INFO(("Not Supported\n")); |
| gtSemGive(dev,dev->phyRegsSem); |
| return GT_NOT_SUPPORTED; |
| } |
| |
| /* Need to disable PPUEn for safe. */ |
| if(gsysGetPPUEn(dev,&ppuEn) != GT_OK) |
| { |
| ppuEn = GT_FALSE; |
| } |
| |
| if(ppuEn != GT_FALSE) |
| { |
| if((status= gsysSetPPUEn(dev,GT_FALSE)) != GT_OK) |
| { |
| DBG_INFO(("Not able to disable PPUEn.\n")); |
| gtSemGive(dev,dev->phyRegsSem); |
| return status; |
| } |
| gtDelay(250); |
| } |
| |
| if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK) |
| { |
| gtSemGive(dev,dev->phyRegsSem); |
| return GT_FAIL; |
| } |
| |
| /* |
| * save original register 17 value, which will be used later depending on |
| * test result. |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,0,17,phyInfo.anyPage,&orgReg17)) != GT_OK) |
| { |
| DBG_INFO(("Not able to reset the Phy.\n")); |
| goto cableDiagCleanup; |
| } |
| |
| /* |
| * save Config Register data |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,0,0,phyInfo.anyPage,&orgReg0)) != GT_OK) |
| { |
| DBG_INFO(("Not able to reset the Phy.\n")); |
| goto cableDiagCleanup; |
| } |
| |
| switch(phyInfo.vctType) |
| { |
| case GT_PHY_VCT_TYPE1: |
| enable1stWorkAround_Phy100M(dev,hwPort); |
| status = getCableStatus_Phy100M(dev,hwPort,cableStatus); |
| /* every fast ethernet phy requires this work-around */ |
| workAround_Phy100M(dev,hwPort,cableStatus); |
| disable1stWorkAround_Phy100M(dev,hwPort); |
| break; |
| case GT_PHY_VCT_TYPE2: |
| enable1stWorkAround_Phy1000M(dev,hwPort); |
| status = getCableStatus_Phy1000M(dev,hwPort,orgReg17,cableStatus); |
| disable1stWorkAround_Phy1000M(dev,hwPort); |
| break; |
| case GT_PHY_VCT_TYPE3: |
| enable1stWorkAround_Phy1000M(dev,hwPort); |
| workAround_Phy1000M(dev,hwPort); |
| status = getCableStatus_Phy1000M(dev,hwPort,orgReg17,cableStatus); |
| disable1stWorkAround_Phy1000M(dev,hwPort); |
| break; |
| case GT_PHY_VCT_TYPE4: |
| status = getCableStatus_Phy1000MPage(dev,hwPort,&phyInfo,cableStatus); |
| break; |
| default: |
| status = GT_FAIL; |
| break; |
| } |
| |
| if (!(phyInfo.flag & GT_PHY_GIGABIT)) |
| { |
| if((status = hwPhyReset(dev,hwPort,orgReg0)) != GT_OK) |
| { |
| gtSemGive(dev,dev->phyRegsSem); |
| return status; |
| } |
| } |
| else |
| { |
| /* |
| * restore Config Register Data |
| */ |
| if((status= hwWritePagedPhyReg(dev,hwPort,0,0,phyInfo.anyPage,orgReg0)) != GT_OK) |
| { |
| gtSemGive(dev,dev->phyRegsSem); |
| return status; |
| } |
| |
| /* soft reset */ |
| if((status = hwPhyReset(dev,hwPort,0xFF)) != GT_OK) |
| { |
| gtSemGive(dev,dev->phyRegsSem); |
| return status; |
| } |
| } |
| |
| cableDiagCleanup: |
| |
| if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK) |
| { |
| gtSemGive(dev,dev->phyRegsSem); |
| return GT_FAIL; |
| } |
| |
| if(ppuEn != GT_FALSE) |
| { |
| if(gsysSetPPUEn(dev,ppuEn) != GT_OK) |
| { |
| DBG_INFO(("Not able to enable PPUEn.\n")); |
| status = GT_FAIL; |
| } |
| } |
| |
| gtSemGive(dev,dev->phyRegsSem); |
| return status; |
| } |
| |
| |
| /******************************************************************************* |
| * getExStatus1000M |
| * |
| * DESCRIPTION: |
| * This routine retrieves Pair Skew, Pair Swap, and Pair Polarity |
| * for 1000M phy |
| * |
| * INPUTS: |
| * dev - device context. |
| * port - logical port number. |
| * |
| * OUTPUTS: |
| * extendedStatus - extended cable status. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * None. |
| * |
| *******************************************************************************/ |
| static GT_STATUS getExStatus1000M |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort, |
| OUT GT_1000BT_EXTENDED_STATUS *extendedStatus |
| ) |
| { |
| GT_STATUS status; |
| GT_U16 u16Data, i; |
| |
| /* |
| * get data from 28_5 register |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,5,28,0,&u16Data)) != GT_OK) |
| { |
| DBG_INFO(("Not able to read a Phy register.\n")); |
| return status; |
| } |
| |
| /* if bit 6 is not set, it's not valid. */ |
| if (!(u16Data & 0x0040)) |
| { |
| DBG_INFO(("Valid Bit is not set (%0#x).\n", u16Data)); |
| extendedStatus->isValid = GT_FALSE; |
| return GT_OK; |
| } |
| |
| extendedStatus->isValid = GT_TRUE; |
| |
| /* get Pair Polarity */ |
| for(i=0; i<GT_MDI_PAIR_NUM; i++) |
| { |
| switch((u16Data >> i) & 0x1) |
| { |
| case 0: |
| extendedStatus->pairPolarity[i] = GT_POSITIVE; |
| break; |
| default: |
| extendedStatus->pairPolarity[i] = GT_NEGATIVE; |
| break; |
| } |
| } |
| |
| /* get Pair Swap */ |
| for(i=0; i<GT_CHANNEL_PAIR_NUM; i++) |
| { |
| switch((u16Data >> (i+4)) & 0x1) |
| { |
| case 0: |
| extendedStatus->pairSwap[i] = GT_STRAIGHT_CABLE; |
| break; |
| default: |
| extendedStatus->pairSwap[i] = GT_CROSSOVER_CABLE; |
| break; |
| } |
| } |
| |
| /* |
| * get data from 28_4 register |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,4,28,0,&u16Data)) != GT_OK) |
| { |
| DBG_INFO(("Not able to read a Phy register.\n")); |
| return status; |
| } |
| |
| /* get Pair Skew */ |
| for(i=0; i<GT_MDI_PAIR_NUM; i++) |
| { |
| extendedStatus->pairSkew[i] = ((u16Data >> i*4) & 0xF) * 8; |
| } |
| |
| return GT_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * getExStatus1000MPage |
| * |
| * DESCRIPTION: |
| * This routine retrieves Pair Skew, Pair Swap, and Pair Polarity |
| * for 1000M phy with multiple page mode |
| * |
| * INPUTS: |
| * dev - device context. |
| * port - logical port number. |
| * |
| * OUTPUTS: |
| * extendedStatus - extended cable status. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * None. |
| * |
| *******************************************************************************/ |
| static GT_STATUS getExStatus1000MPage |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_U8 hwPort, |
| OUT GT_1000BT_EXTENDED_STATUS *extendedStatus |
| ) |
| { |
| GT_STATUS status; |
| GT_U16 u16Data, i; |
| |
| /* |
| * get data from 21_5 register for pair swap |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,5,21,0,&u16Data)) != GT_OK) |
| { |
| DBG_INFO(("Not able to read a paged Phy register.\n")); |
| return status; |
| } |
| |
| /* if bit 6 is not set, it's not valid. */ |
| if (!(u16Data & 0x0040)) |
| { |
| DBG_INFO(("Valid Bit is not set (%0#x).\n", u16Data)); |
| extendedStatus->isValid = GT_FALSE; |
| return GT_OK; |
| } |
| |
| extendedStatus->isValid = GT_TRUE; |
| |
| /* get Pair Polarity */ |
| for(i=0; i<GT_MDI_PAIR_NUM; i++) |
| { |
| switch((u16Data >> i) & 0x1) |
| { |
| case 0: |
| extendedStatus->pairPolarity[i] = GT_POSITIVE; |
| break; |
| default: |
| extendedStatus->pairPolarity[i] = GT_NEGATIVE; |
| break; |
| } |
| } |
| |
| /* get Pair Swap */ |
| for(i=0; i<GT_CHANNEL_PAIR_NUM; i++) |
| { |
| switch((u16Data >> (i+4)) & 0x1) |
| { |
| case 0: |
| extendedStatus->pairSwap[i] = GT_STRAIGHT_CABLE; |
| break; |
| default: |
| extendedStatus->pairSwap[i] = GT_CROSSOVER_CABLE; |
| break; |
| } |
| } |
| |
| /* |
| * get data from 20_5 register for pair skew |
| */ |
| if((status= hwReadPagedPhyReg(dev,hwPort,5,20,0,&u16Data)) != GT_OK) |
| { |
| DBG_INFO(("Not able to read a paged Phy register.\n")); |
| return status; |
| } |
| |
| /* get Pair Skew */ |
| for(i=0; i<GT_MDI_PAIR_NUM; i++) |
| { |
| extendedStatus->pairSkew[i] = ((u16Data >> i*4) & 0xF) * 8; |
| } |
| |
| return GT_OK; |
| } |
| |
| |
| /******************************************************************************* |
| * gvctGet1000BTExtendedStatus |
| * |
| * DESCRIPTION: |
| * This routine retrieves Pair Skew, Pair Swap, and Pair Polarity |
| * |
| * INPUTS: |
| * dev - device context. |
| * port - logical port number. |
| * |
| * OUTPUTS: |
| * extendedStatus - extended cable status. |
| * |
| * RETURNS: |
| * GT_OK - on success |
| * GT_FAIL - on error |
| * |
| * COMMENTS: |
| * Internal Gigabit Phys in 88E6165 family and 88E6351 family devices |
| * are not supported by this API. For those devices, gvctGetAdvExtendedStatus |
| * API can be used, instead. |
| * |
| *******************************************************************************/ |
| GT_STATUS gvctGet1000BTExtendedStatus |
| ( |
| IN GT_QD_DEV *dev, |
| IN GT_LPORT port, |
| OUT GT_1000BT_EXTENDED_STATUS *extendedStatus |
| ) |
| { |
| GT_STATUS status; |
| GT_U8 hwPort; |
| GT_BOOL ppuEn; |
| GT_PHY_INFO phyInfo; |
| GT_BOOL autoOn; |
| GT_U16 pageReg; |
| |
| DBG_INFO(("gvctGetCableDiag Called.\n")); |
| 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 VCT */ |
| 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_EX_CABLE_STATUS)) |
| { |
| DBG_INFO(("Not Supported\n")); |
| gtSemGive(dev,dev->phyRegsSem); |
| return GT_NOT_SUPPORTED; |
| } |
| |
| /* Need to disable PPUEn for safe. */ |
| if(gsysGetPPUEn(dev,&ppuEn) != GT_OK) |
| { |
| ppuEn = GT_FALSE; |
| } |
| |
| if(ppuEn != GT_FALSE) |
| { |
| if((status= gsysSetPPUEn(dev,GT_FALSE)) != GT_OK) |
| { |
| DBG_INFO(("Not able to disable PPUEn.\n")); |
| gtSemGive(dev,dev->phyRegsSem); |
| return status; |
| } |
| gtDelay(250); |
| } |
| |
| if(driverPagedAccessStart(dev,hwPort,phyInfo.pageType,&autoOn,&pageReg) != GT_OK) |
| { |
| gtSemGive(dev,dev->phyRegsSem); |
| return GT_FAIL; |
| } |
| |
| switch(phyInfo.vctType) |
| { |
| case GT_PHY_VCT_TYPE2: |
| status = getExStatus1000M(dev,hwPort,extendedStatus); |
| break; |
| case GT_PHY_VCT_TYPE4: |
| status = getExStatus1000MPage(dev,hwPort,extendedStatus); |
| break; |
| default: |
| DBG_INFO(("Device is not supporting Extended Cable Status.\n")); |
| status = GT_NOT_SUPPORTED; |
| } |
| |
| if(driverPagedAccessStop(dev,hwPort,phyInfo.pageType,autoOn,pageReg) != GT_OK) |
| { |
| gtSemGive(dev,dev->phyRegsSem); |
| return GT_FAIL; |
| } |
| |
| if(ppuEn != GT_FALSE) |
| { |
| if(gsysSetPPUEn(dev,ppuEn) != GT_OK) |
| { |
| DBG_INFO(("Not able to enable PPUEn.\n")); |
| status = GT_FAIL; |
| } |
| } |
| |
| gtSemGive(dev,dev->phyRegsSem); |
| return status; |
| } |
| |
| |