⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mplphy.c

📁 NATIONAL公司DP83816芯片Linux下驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
   if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
   {
      // Apply fix for ATAN switch link-up issue
      atanPatchUp(pMplCtx);
   }
#endif //MPL_EXTERNAL_PHY

   // Cancel any PHY link timer
   OaiCancelTimer(pMplCtx->phyTimer);

   EXIT(MplPhyGetLinkStatus);
   return MPL_LINK_STATUS_DOWN;
}

//*****************************************************************************
//   MplPhyGetLinkSpeed
//      Returns current link speed. 
//      NOTE: SHOULD be called only after determing that the link is UP - 
//            i.e MplPhyGetLinkStatus has returned MPL_LINK_STATUS_UP
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      MPL_LINK_SPEED_TENMBPS 
//         The current link speed is 10Mbps
//      MPL_LINK_SPEED_HUNDREDMBPS
//         The current link speed is 100Mbps
//
//*****************************************************************************
MPL_LINK_SPEED 
   MplPhyGetLinkSpeed(
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 regVal;

   ENTER(MplPhyGetLinkSpeed);

#ifndef MPL_EXTERNAL_PHY
   {
      // Read the PhySts register to get the current link speed
      regVal = MPL_READ32(pMplCtx, PHYSTS);

      // Check the link state
      if (regVal & SPEED_10_STS)
      {
PRINT(("Phy Link SPEED 10Mbps\n"));
         EXIT(MplPhyGetLinkSpeed);
         return MPL_LINK_SPEED_TENMBPS;
      }
      else
      {
PRINT(("Phy Link SPEED 100Mbps\n"));
         EXIT(MplPhyGetLinkSpeed);
         return MPL_LINK_SPEED_HUNDREDMBPS;
      }
   }
#else
   // Use internal PHY registers to return current link SPEED
   // EXTERNAL_PHY_HOOK  Modify this to suit your specific device needs
   {
      pMplCtx = pMplCtx; regVal = regVal; //To supress warnings
      return DEFINE_CURRENT_SPEED; //One of MPL_LINK_SPEED_XXX
   }
#endif // MPL_EXTERNAL_PHY

}

//*****************************************************************************
//   MplPhyGetLinkDuplex
//      Returns current link duplex mode. 
//      NOTE: SHOULD be called only after determing that the link is UP - 
//            i.e MplPhyGetLinkStatus has returned MPL_LINK_STATUS_UP
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      MPL_LINK_DUPLEX_HALF
//         The current duplex mode is half
//      MPL_LINK_DUPLEX_FULL
//         The current duplex mode is full
//
//*****************************************************************************
MPL_LINK_DUPLEX
   MplPhyGetLinkDuplex(
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 regVal;

   ENTER(MplPhyGetLinkDuplex);

#ifndef MPL_EXTERNAL_PHY
   {
      // Read the PhySts register to get the current link mode
      regVal = MPL_READ32(pMplCtx, PHYSTS);

      // Check the link state
      if (regVal & DUPLEX_FULL_STS)
      {
PRINT(("Phy Link Duplex FULL \n"));
         EXIT(MplPhyGetLinkDuplex);
         return MPL_LINK_DUPLEX_FULL;
      }
      else
      {
PRINT(("Phy Link Duplex HALF \n"));
         EXIT(MplPhyGetLinkDuplex);
         return MPL_LINK_DUPLEX_HALF;
      }
   }
#else
   // Use internal PHY regs to return current DUPLEX mode
   // EXTERNAL_PHY_HOOK  Modify this to suit your specific device needs
   {
      pMplCtx = pMplCtx; regVal = regVal; //To supress warnings
      return DEFINE_CURRENT_DUPLEX; //One of MPL_LINK_DUPLEX_XXX
   }
#endif // MPL_EXTERNAL_PHY

}

//*****************************************************************************
//   MplPhyAutoNegDone
//      Returns if Auto Neg process is completed. 
//      NOTE: SHOULD be called only after determing that the link is UP - 
//            i.e MplPhyGetLinkStatus has returned MPL_LINK_STATUS_UP
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      NS_TRUE
//         The link was setup following a Auto-Neg process
//      NS_FALSE
//         The link was setup in forced mode
//
//*****************************************************************************
NS_BOOLEAN
   MplPhyAutoNegDone(
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 regVal;

   ENTER(MplPhyAutoNegDone);

   // Read the PhySts register to get the current mode
   regVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMSR);

   // Check the link state
   if (regVal & AUTONEG_COMP)
   {
PRINT(("Phy Link Auto DONE \n"));
      EXIT(MplPhyAutoNegDone);
      return NS_TRUE;
   }
   else
   {
PRINT(("Phy Link Auto NOT DONE \n"));
      EXIT(MplPhyAutoNegDone);
      return NS_FALSE;
   }
}

//*****************************************************************************
//   MplPhyLinkSetupComplete
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      NS_TRUE
//         The link was sucessfully setup
//      NS_FALSE
//         The link is not up (Assert - should not happen)
//      
//
//*****************************************************************************
NS_BOOLEAN
   MplPhyLinkSetupComplete(
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 anar, anlPar;

   ENTER(MplPhyLinkSetupComplete);

   // Make sure we have a valid link before proceeding
   if (MplPhyGetLinkStatus(pMplHandle) != MPL_LINK_STATUS_UP)
   {
      // FM: Assert - We should never come here!!
      EXIT(MplPhyLinkSetupComplete);
      return NS_FALSE;
   }

   // Get the Duplex Status
   if (MplPhyGetLinkDuplex(pMplCtx) == MPL_LINK_DUPLEX_FULL)
   {
      // We are in Full duplex mode
      pMplCtx->linkCfg.duplex = MPL_LINK_DUPLEX_FULL;

      // Set Pause - Only in AutoNeg'ed Full Duplex mode
      if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
      {
         // Read our adv values and that of our partner
         anar   = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR);
         anlPar = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANLPAR);

         /*
          * Look at the PAUSE and ASM_DIR bits between us and link partner
          *  to determine the pause setting. 
          * The following table, taken out of the IEEE 802.3ab/D6.0 spec
          * describes final PAUSE resolution
          * NOTE:  DC = Don't Care
          *
          *   LOCAL DEVICE  |   LINK PARTNER
          * PAUSE | ASM_DIR | PAUSE | ASM_DIR | PAUSE Resolution
          *-------|---------|-------|---------|--------------------
          *   0   |    0    |  DC   |   DC    | MPL_LINK_PAUSE_NONE
          *   0   |    1    |   0   |   DC    | MPL_LINK_PAUSE_NONE
          *   0   |    1    |   1   |    0    | MPL_LINK_PAUSE_NONE
          *   0   |    1    |   1   |    1    | MPL_LINK_PAUSE_TRANSMIT
          *   1   |    0    |   0   |   DC    | MPL_LINK_PAUSE_NONE
          *   1   |   DC    |   1   |   DC    | MPL_LINK_PAUSE_SYMMETRICAL
          *   1   |    1    |   0   |    0    | MPL_LINK_PAUSE_NONE
          *   1   |    1    |   0   |    1    | MPL_LINK_PAUSE_RECEIVE
          *
          */

         // Test for SYMMETRICAL pause mode
         if ((anar & ADV_PAUSE)  &&  (anlPar & ADV_PAUSE))
         {
           if (pMplCtx->linkCfg.pauseType == MPL_LINK_PAUSE_SYMMETRICAL)
           {
              pMplCtx->pauseType = MPL_LINK_PAUSE_SYMMETRICAL;
           }
           else
           {
              // Since we had earlier advertised Sym pause for rx-only mode too
              pMplCtx->pauseType = MPL_LINK_PAUSE_RECEIVE;
           }
         }
         else if (!(anar & ADV_PAUSE)  &&  (anar & ADV_ASM_DIR) &&
                    (anlPar & ADV_PAUSE) && (anlPar & ADV_ASM_DIR))
              {
                 // TRANSMIT only pause mode
                 pMplCtx->pauseType = MPL_LINK_PAUSE_TRANSMIT;
              }
              else if ((anar & ADV_PAUSE)  &&  (anar & ADV_ASM_DIR) &&
                         !(anlPar & ADV_PAUSE) && (anlPar & ADV_ASM_DIR))
                   {
                      // RECEIVE only pause mode
                      pMplCtx->pauseType = MPL_LINK_PAUSE_RECEIVE;
                   }
                   // At this point the IEEE spec says no pause generation
                   //  However unless the NSM has specifically asked for 
                   //  No-Pause or only Tx-Pause, we can enable Rx-Pause safely
                   //  since we are only receiveing pause requests and
                   //  not generating our own pause requests 
                   else if ((pMplCtx->linkCfg.pauseType == 
                                    MPL_LINK_PAUSE_TRANSMIT) ||
                            (pMplCtx->linkCfg.pauseType == MPL_LINK_PAUSE_NONE))
                        {
                           pMplCtx->pauseType = MPL_LINK_PAUSE_NONE;
                        }
                        else
                        {
                           pMplCtx->pauseType = MPL_LINK_PAUSE_RECEIVE;
                        }
      }
   }
   else
   {
      // We are in half duplex mode
      pMplCtx->linkCfg.duplex = MPL_LINK_DUPLEX_HALF;

      // Disable Pause
      pMplCtx->pauseType = MPL_LINK_PAUSE_NONE;
   }

   // Get the Speed Status
   if (MplPhyGetLinkSpeed(pMplCtx) == MPL_LINK_SPEED_HUNDREDMBPS)
   {
      // We are in 100Mbps
      pMplCtx->linkCfg.speed = MPL_LINK_SPEED_HUNDREDMBPS;
   }
   else
   {
      // We are in 10Mbps
      pMplCtx->linkCfg.speed = MPL_LINK_SPEED_TENMBPS;
   }

   // Postlink Patch Works - Only for Internal PHYs
#ifndef MPL_EXTERNAL_PHY
   {
      if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
      {
        // Since we are linked up remove ATAN patch and go to
        //  full attenuation level
        atanPatchDown(pMplCtx);
      }

      // Start timer to watch coeff 100msec from now - Short Cable patch
      if ((pMplCtx->linkCfg.speed == MPL_LINK_SPEED_HUNDREDMBPS) &&
           (((pMplCtx->srr & 0xFF00) == 0x0300) ||
            ((pMplCtx->srr & 0xFF00) == 0x0400) ||
            (pMplCtx->srr == 0x0504)))
      {
         OaiStartTimer(pMplCtx->phyTimer, 100);
      }
   }
#endif // MPL_EXTERNAL_PHY

   EXIT(MplPhyLinkSetupComplete);
   return NS_TRUE;
}

//*****************************************************************************
//   MplPhyRequiresPatch
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      NS_TRUE
//         The PHY requires patches to be applied
//      NS_FALSE
//         No Patch work required
//
//*****************************************************************************
NS_BOOLEAN
   MplPhyRequiresPatch(
      IN NS_VOID   *pMplHandle
      )
{
   NS_BOOLEAN retVal = NS_TRUE;

   ENTER(MplPhyRequiresPatch);

#ifndef MPL_EXTERNAL_PHY
   {
      MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;

      switch (pMplCtx->phySiliconRev)
      {
         case MP_PHY_REV    :  retVal = NS_TRUE; break;
         case ASPEN_PHY_REV    :  retVal = NS_FALSE; break; //FM: TBD
      } 
   }
#endif // MPL_EXTERNAL_PHY
   
   EXIT(MplPhyRequiresPatch);
   return retVal;
}

//*****************************************************************************
//   MplPhyGetDeviceAddr
//      Return the Phy device address
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//     Phy device addr
//
//*****************************************************************************
NS_UINT
   MplPhyGetDeviceAddr (
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;

   ENTER(MplPhyGetDeviceAddr);
   EXIT(MplPhyGetDeviceAddr);
   return pMplCtx->phyDeviceAddr;
}

//*****************************************************************************
//   MplPhyMdioRead
//      Read Phy register
//
//   Parameters
//      pMplHandle
//         MPL device handle
//      phyDevAddr
//         Device addr of the Phy
//      regIndex
//         Register to read (in terms of MII offset e.g. BMCR = 0x0, BMSR = 0x1)
//
//   Return Value
//     Reg data
//
//*****************************************************************************
NS_UINT32
   MplPhyMdioRead(
      IN NS_VOID   *pMplHandle,
      IN NS_UINT    phyDevAddr,
      IN NS_UINT    regIndex
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 regData = 0x0;

   // If we are using the internal PHY then go thru the simple register
   //  API to access the PHY registers, if not do bit-banging on MDIO

#ifndef MPL_EXTERNAL_PHY
   {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -