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

📄 mplphy.c

📁 NATIONAL公司DP83816芯片Linux下驱动
💻 C
📖 第 1 页 / 共 3 页
字号:

//******************************************************************************
//
//  MPLPHY.C
//
//  Copyright (c) 2004 National Semiconductor Corporation.
//  All Rights Reserved
//
//  MPL Phy Interface Module.
//
//  This file contains the API implementations for
//     o Detection of PHY
//     o Configuring the PHY
//     o Reporting PHY status
//
//******************************************************************************

#include <mplinternal.h>

// Local helful debug macros
#undef ENTER
#undef EXIT
#undef ASSERT
#undef PRINT
#undef PRINTI
#undef PRINTS
#undef TBREAK

#define ENTER(fn) MPL_CENTER(DZONE_MPL_LINK, fn)
#define EXIT(fn) MPL_CEXIT(DZONE_MPL_LINK, fn)
#define ASSERT(le) MPL_CASSERT(DZONE_MPL_LINK, le)
#define PRINT(fmt) MPL_CTRACE(DZONE_MPL_LINK, fmt)
#define PRINTI(v) MPL_CTRACE(DZONE_MPL_LINK, (" "#v": %x \n",(NS_UINT)(v)))
#define PRINTS(v) MPL_CTRACE(DZONE_MPL_LINK, (" "#v": %s \n", v))
#define TBREAK(fmt) MPL_CTRACEBREAK(DZONE_MPL_LINK, fmt)

// Local functions
static NS_VOID mdioIdle(MPL_CONTEXT *pMplCtx);
static NS_VOID mdioSync(MPL_CONTEXT *pMplCtx);

#ifndef MPL_EXTERNAL_PHY
static NS_VOID phyAdjust(MPL_CONTEXT *pMplCtx);
static NS_VOID atanPatchUp(MPL_CONTEXT *pMplCtx);
static NS_VOID atanPatchDown(MPL_CONTEXT *pMplCtx);
#else
static NS_VOID mdioWriteReg(MPL_CONTEXT *pMplCtx, NS_UINT phyDevAddr, 
                             NS_UINT regIndex,NS_UINT16  regData);
static NS_UINT16 mdioReadReg(MPL_CONTEXT *pMplCtx, NS_UINT phyDevAddr,
                               NS_UINT regIndex);
#endif // MPL_EXTERNAL_PHY

//*****************************************************************************
//   MplPhyDetect
//      Detect the presence of a MacPhyter device on the system.
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      NS_STATUS_SUCCESS
//         A MacPhyter device was successfully probed
//      NS_STATUS_HARDWARE_FAILURE
//         Could not find a MacPhyter device
//
//*****************************************************************************
MPL_STATUS
   MplPhyDetect(
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 phyIdr1, phyIdr2;

   ENTER(MplPhyDetect);

   // Sync up the MII bus
   mdioSync(pMplCtx);

   // Scan for a matching OUI.
   for (pMplCtx->phyDeviceAddr = 31; pMplCtx->phyDeviceAddr != 0; 
                      pMplCtx->phyDeviceAddr--)
   {
      // Check bits 3 - 18 of the OUI
      phyIdr1 = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_PHYIDR1);

      switch (phyIdr1)
      {
         case MP_PHY_ID1 :  // NSC PHY Ids
                           phyIdr2 = MplPhyMdioRead(pMplCtx, 
                                        pMplCtx->phyDeviceAddr, MII_PHYIDR2);

                           switch (phyIdr2 & 0xfff0)
                           {
                              case MP_PHY_REV : 
                              case ASPEN_PHY_REV : 
                                 pMplCtx->phySiliconRev = phyIdr2 & 0xfff0; 
                                 EXIT(MplPhyDetect);
                                 return NS_STATUS_SUCCESS;
                             default : break;
                           }
                           break;

#ifdef MPL_EXTERNAL_PHY
        // Add a case here to match your PHY Ids
        // EXTERNAL_PHY_HOOK  Modify this to suit your specific device needs
        case DEFINE_PHY_ID :
                            break;
#endif
      }
   }


   EXIT(MplPhyDetect);
   return NS_STATUS_HARDWARE_FAILURE;
}

//*****************************************************************************
//   MplPhyReset
//      Reset the PHY device
//      
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      NS_STATUS_SUCCESS
//         A MacPhyter device was successfully probed
//      NS_STATUS_HARDWARE_FAILURE
//         Could not find a MacPhyter device
//
//*****************************************************************************
MPL_STATUS
   MplPhyReset(
      IN NS_VOID       *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT i;

   ENTER(MplPhyReset);

   // Hit the reset bit
   MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, PHY_RESET);

   // Wait (total 10 msec) for the PHY to come out of reset
   for (i = 0x0; i < 10; i ++)
   {
      OaiSleep(RESETINTERVAL_PHY);
      if ((MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR) & 
                              PHY_RESET) == 0x0)
      {
         // Reset done

#ifndef MPL_EXTERNAL_PHY
         // For NSC internal PHYs some more work remains to be done
         {
            NS_UINT32 regVal;

            // Apply Optimization patch
            phyAdjust(pMplCtx);

            // Enable Phy Interrupts, after clearing pending ones
            regVal = MPL_READ32(pMplCtx, MISR);
            MPL_WRITE32(pMplCtx, MISR, regVal & ~(MSK_LINK | MSK_ANC));
            MPL_WRITE32(pMplCtx, MICR, PHY_INT);
         }
#else
         // Set Interrupts and other init time operations
         // EXTERNAL_PHY_HOOK  Modify this to suit your specific device needs
         {
            DEFINE_PHY_INTERRUPTS;  
         }
#endif // MPL_EXTERNAL_PHY


         EXIT(MplPhyReset);
         return NS_STATUS_SUCCESS;
      }
   }

   EXIT(MplPhyReset);
   return NS_STATUS_HARDWARE_FAILURE;
}

//*****************************************************************************
//   MplPhyLinkSetup
//      Setup the link on the PHY with the requested settings
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      NS_STATUS_SUCCESS
//         The link was set on the PHY device
//      NS_STATUS_INVALID_PARAM
//         An invalid link configuration was detected
//      NS_STATUS_HARDWARE_FAILURE
//         Unexpected hardware error
//
//*****************************************************************************
MPL_STATUS
   MplPhyLinkSetup (
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 bmcrVal, anarVal, bmcrValTmp;

   ENTER(MplPhyLinkSetup);

   // Reset the PHY to apply patches before link being set
   if (MplPhyReset(pMplCtx) != NS_STATUS_SUCCESS)
   {
      return NS_STATUS_HARDWARE_FAILURE;
   }

   // Setup AutoNeg advertisements
   if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
   {
#ifndef MPL_EXTERNAL_PHY
      // Prelink Patch Works - Only for Internal PHYs
      {
         // Apply fix for ATAN switch link-up issue
         atanPatchUp(pMplCtx);
      }
#endif // MPL_EXTERNAL_PHY

      // Defaults
      bmcrVal = AUTONEG_ENABLE | AUTONEG_RESTART;
      anarVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR);
      anarVal &= ~(ADV_100BASET_FD | ADV_100BASET_HD | ADV_10BASET_FD
                    | ADV_10BASET_HD | ADV_PAUSE | ADV_ASM_DIR);

      // Using a fall though switch case statement since
      // in AUTONEG mode the modes must be backwards compatible
      // When the user selects Half Duplex then he is backwards
      // compatible only in Half duplex modes and does not enter
      // any Full Duplex modes, but when in Full Duplex mode he
      // can get into any backward compatible mode.
      switch (pMplCtx->linkCfg.speed)
      {
         default:
         case MPL_LINK_SPEED_HUNDREDMBPS:
                   if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
                   {
                      anarVal |= ADV_100BASET_FD;
                   }

                   // Half duplex and backward compatible 
                   anarVal |= ADV_100BASET_HD;

         case MPL_LINK_SPEED_TENMBPS:
                   if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
                   {
                      anarVal |= ADV_10BASET_FD;
                   }

                   // Half duplex and backward compatible 
                   anarVal |= ADV_10BASET_HD;
                   break;
      }

      // Setup advertisement of Flow control (Pause)
      switch (pMplCtx->linkCfg.pauseType)
      {
         case MPL_LINK_PAUSE_TRANSMIT:

                   // Transmit of pause requests only 
                   anarVal |= ADV_ASM_DIR;
                   break;

         case MPL_LINK_PAUSE_RECEIVE:

                   // The Auto-Neg spec does not specify a way to adv receive
                   //  only of pause requests. So we will adv both asym and
                   //  sym pause support - Later after link is setup we can
                   //  disable the transmission of pause requests 
                   anarVal |= ADV_ASM_DIR | ADV_PAUSE;
                   break;

         case MPL_LINK_PAUSE_SYMMETRICAL: // Tx and Rx

                   // Both Transmit and Reception of pause requests
                   anarVal |= ADV_ASM_DIR | ADV_PAUSE;
                   break;

         default:
                   // No pause advertisement
                   break;
      }

      // If we need to do/restart AutoNegtiation then we
      // first check if we are in forced mode, if we are in forced
      // mode then we clear bit 12 of the BMCR (AUTO_NEG_ENABLE) and
      // then reset the bit to 1 and then write to register to restart
      // Auto Negotiation if required.

      bmcrValTmp = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR);
      if (!(bmcrValTmp & AUTONEG_ENABLE))
      {
         // We clear the AUTONEGENABLE bit and then reset the bit
         // before we start a AutoNegotiate process.

         bmcrValTmp &= ~AUTONEG_ENABLE;
         MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, bmcrValTmp);

         bmcrValTmp |= AUTONEG_ENABLE;
         MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, bmcrValTmp);
      }

   }
   else
   {
      // Setup for Forced mode operation

      // Defaults
      bmcrVal = 0x0;
      anarVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR);
      anarVal &= ~(ADV_100BASET_FD | ADV_100BASET_HD | ADV_10BASET_FD |
                     ADV_10BASET_HD | ADV_PAUSE | ADV_ASM_DIR);

      // Set the speed on the card individually
      // based on the user selection and force selection
      switch (pMplCtx->linkCfg.speed)
      {
         default:
         case MPL_LINK_SPEED_HUNDREDMBPS:
                   if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
                   {
                      bmcrVal |= FORCE_MODE_FD;
                   }

                   bmcrVal |= FORCE_SPEED_100;
                   break;

         case MPL_LINK_SPEED_TENMBPS:
                   if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
                   {
                      bmcrVal |= FORCE_MODE_FD;
                   }

                   break;
      }
   }

   // Enable advertized values
   MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR, anarVal);

   // Write the new configuration
   MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, bmcrVal);

   EXIT(MplPhyLinkSetup);
   return NS_STATUS_SUCCESS;
}

//*****************************************************************************
//   MplPhyGetLinkStatus
//      Returns the status of the link
//
//   Parameters
//      pMplHandle
//         MPL device handle
//
//   Return Value
//      MPL_LINK_STATUS_NONE
//         An unexpected hardware error occurred while processing this request
//          and the link state was not retrieved.
//      MPL_LINK_STATUS_DOWN
//         The link is down.
//      MPL_LINK_STATUS_ACTIVE
//         The link is currently being configured or negotiated.
//      MPL_LINK_STATUS_UP
//         The link is up
//
//*****************************************************************************
MPL_LINK_STATUS
   MplPhyGetLinkStatus (
      IN NS_VOID   *pMplHandle
      )
{
   MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
   NS_UINT32 regVal;

   ENTER(MplPhyGetLinkStatus);

   // Read the PhySts register to get the current link state
   // MacPhy requires the read of BMSR twice to correctly note
   //  the link change event
   regVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMSR);
   regVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMSR);

   // Check the link state
   if (regVal & LINK_STATUS)
   {
      // Link Up
      // If we are in Auto-Neg mode, make sure that we are completely 
      //  ready
      if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
      {
         if (regVal & AUTONEG_COMP)
         {
            EXIT(MplPhyGetLinkStatus);
            return MPL_LINK_STATUS_UP;
         }

         // We are in the process of setting up link
         EXIT(MplPhyGetLinkStatus);
         return MPL_LINK_STATUS_ACTIVE;
      }

      EXIT(MplPhyGetLinkStatus);
      return MPL_LINK_STATUS_UP;
   }

   // All other cases no Link

   // This is a good time to apply linkup related patches
   //  (to link correctly with (potentially) a new partner)
#ifndef MPL_EXTERNAL_PHY

⌨️ 快捷键说明

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