Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 1999 - 2010 Intel Corporation.
0004  * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
0005  *
0006  * This code was derived from the Intel e1000e Linux driver.
0007  */
0008 
0009 #include "pch_gbe.h"
0010 #include "pch_gbe_phy.h"
0011 
0012 #define PHY_MAX_REG_ADDRESS   0x1F  /* 5 bit address bus (0-0x1F) */
0013 
0014 /* PHY 1000 MII Register/Bit Definitions */
0015 /* PHY Registers defined by IEEE */
0016 #define PHY_CONTROL           0x00  /* Control Register */
0017 #define PHY_STATUS            0x01  /* Status Regiser */
0018 #define PHY_ID1               0x02  /* Phy Id Register (word 1) */
0019 #define PHY_ID2               0x03  /* Phy Id Register (word 2) */
0020 #define PHY_AUTONEG_ADV       0x04  /* Autoneg Advertisement */
0021 #define PHY_LP_ABILITY        0x05  /* Link Partner Ability (Base Page) */
0022 #define PHY_AUTONEG_EXP       0x06  /* Autoneg Expansion Register */
0023 #define PHY_NEXT_PAGE_TX      0x07  /* Next Page TX */
0024 #define PHY_LP_NEXT_PAGE      0x08  /* Link Partner Next Page */
0025 #define PHY_1000T_CTRL        0x09  /* 1000Base-T Control Register */
0026 #define PHY_1000T_STATUS      0x0A  /* 1000Base-T Status Register */
0027 #define PHY_EXT_STATUS        0x0F  /* Extended Status Register */
0028 #define PHY_PHYSP_CONTROL     0x10  /* PHY Specific Control Register */
0029 #define PHY_EXT_PHYSP_CONTROL 0x14  /* Extended PHY Specific Control Register */
0030 #define PHY_LED_CONTROL       0x18  /* LED Control Register */
0031 #define PHY_EXT_PHYSP_STATUS  0x1B  /* Extended PHY Specific Status Register */
0032 
0033 /* PHY Control Register */
0034 #define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
0035 #define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
0036 #define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
0037 #define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
0038 #define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
0039 #define MII_CR_POWER_DOWN       0x0800  /* Power down */
0040 #define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
0041 #define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
0042 #define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
0043 #define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
0044 #define MII_CR_SPEED_1000       0x0040
0045 #define MII_CR_SPEED_100        0x2000
0046 #define MII_CR_SPEED_10         0x0000
0047 
0048 /* PHY Status Register */
0049 #define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
0050 #define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
0051 #define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
0052 #define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
0053 #define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
0054 #define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
0055 #define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
0056 #define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
0057 #define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
0058 #define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
0059 #define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
0060 #define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
0061 #define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
0062 #define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
0063 #define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
0064 
0065 /* AR8031 PHY Debug Registers */
0066 #define PHY_AR803X_ID           0x00001374
0067 #define PHY_AR8031_DBG_OFF      0x1D
0068 #define PHY_AR8031_DBG_DAT      0x1E
0069 #define PHY_AR8031_SERDES       0x05
0070 #define PHY_AR8031_HIBERNATE    0x0B
0071 #define PHY_AR8031_SERDES_TX_CLK_DLY   0x0100 /* TX clock delay of 2.0ns */
0072 #define PHY_AR8031_PS_HIB_EN           0x8000 /* Hibernate enable */
0073 
0074 /* Phy Id Register (word 2) */
0075 #define PHY_REVISION_MASK        0x000F
0076 
0077 /* PHY Specific Control Register */
0078 #define PHYSP_CTRL_ASSERT_CRS_TX  0x0800
0079 
0080 
0081 /* Default value of PHY register */
0082 #define PHY_CONTROL_DEFAULT         0x1140 /* Control Register */
0083 #define PHY_AUTONEG_ADV_DEFAULT     0x01e0 /* Autoneg Advertisement */
0084 #define PHY_NEXT_PAGE_TX_DEFAULT    0x2001 /* Next Page TX */
0085 #define PHY_1000T_CTRL_DEFAULT      0x0300 /* 1000Base-T Control Register */
0086 #define PHY_PHYSP_CONTROL_DEFAULT   0x01EE /* PHY Specific Control Register */
0087 
0088 /**
0089  * pch_gbe_phy_get_id - Retrieve the PHY ID and revision
0090  * @hw:        Pointer to the HW structure
0091  * Returns
0092  *  0:          Successful.
0093  *  Negative value:     Failed.
0094  */
0095 s32 pch_gbe_phy_get_id(struct pch_gbe_hw *hw)
0096 {
0097     struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
0098     struct pch_gbe_phy_info *phy = &hw->phy;
0099     s32 ret;
0100     u16 phy_id1;
0101     u16 phy_id2;
0102 
0103     ret = pch_gbe_phy_read_reg_miic(hw, PHY_ID1, &phy_id1);
0104     if (ret)
0105         return ret;
0106     ret = pch_gbe_phy_read_reg_miic(hw, PHY_ID2, &phy_id2);
0107     if (ret)
0108         return ret;
0109     /*
0110      * PHY_ID1: [bit15-0:ID(21-6)]
0111      * PHY_ID2: [bit15-10:ID(5-0)][bit9-4:Model][bit3-0:revision]
0112      */
0113     phy->id = (u32)phy_id1;
0114     phy->id = ((phy->id << 6) | ((phy_id2 & 0xFC00) >> 10));
0115     phy->revision = (u32) (phy_id2 & 0x000F);
0116     netdev_dbg(adapter->netdev,
0117            "phy->id : 0x%08x  phy->revision : 0x%08x\n",
0118            phy->id, phy->revision);
0119     return 0;
0120 }
0121 
0122 /**
0123  * pch_gbe_phy_read_reg_miic - Read MII control register
0124  * @hw:      Pointer to the HW structure
0125  * @offset:  Register offset to be read
0126  * @data:    Pointer to the read data
0127  * Returns
0128  *  0:      Successful.
0129  *  -EINVAL:    Invalid argument.
0130  */
0131 s32 pch_gbe_phy_read_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 *data)
0132 {
0133     struct pch_gbe_phy_info *phy = &hw->phy;
0134 
0135     if (offset > PHY_MAX_REG_ADDRESS) {
0136         struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
0137 
0138         netdev_err(adapter->netdev, "PHY Address %d is out of range\n",
0139                offset);
0140         return -EINVAL;
0141     }
0142     *data = pch_gbe_mac_ctrl_miim(hw, phy->addr, PCH_GBE_HAL_MIIM_READ,
0143                       offset, (u16)0);
0144     return 0;
0145 }
0146 
0147 /**
0148  * pch_gbe_phy_write_reg_miic - Write MII control register
0149  * @hw:      Pointer to the HW structure
0150  * @offset:  Register offset to be read
0151  * @data:    data to write to register at offset
0152  * Returns
0153  *  0:      Successful.
0154  *  -EINVAL:    Invalid argument.
0155  */
0156 s32 pch_gbe_phy_write_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 data)
0157 {
0158     struct pch_gbe_phy_info *phy = &hw->phy;
0159 
0160     if (offset > PHY_MAX_REG_ADDRESS) {
0161         struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
0162 
0163         netdev_err(adapter->netdev, "PHY Address %d is out of range\n",
0164                offset);
0165         return -EINVAL;
0166     }
0167     pch_gbe_mac_ctrl_miim(hw, phy->addr, PCH_GBE_HAL_MIIM_WRITE,
0168                  offset, data);
0169     return 0;
0170 }
0171 
0172 /**
0173  * pch_gbe_phy_sw_reset - PHY software reset
0174  * @hw:             Pointer to the HW structure
0175  */
0176 static void pch_gbe_phy_sw_reset(struct pch_gbe_hw *hw)
0177 {
0178     u16 phy_ctrl;
0179 
0180     pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &phy_ctrl);
0181     phy_ctrl |= MII_CR_RESET;
0182     pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, phy_ctrl);
0183     udelay(1);
0184 }
0185 
0186 /**
0187  * pch_gbe_phy_hw_reset - PHY hardware reset
0188  * @hw:    Pointer to the HW structure
0189  */
0190 void pch_gbe_phy_hw_reset(struct pch_gbe_hw *hw)
0191 {
0192     pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, PHY_CONTROL_DEFAULT);
0193     pch_gbe_phy_write_reg_miic(hw, PHY_AUTONEG_ADV,
0194                     PHY_AUTONEG_ADV_DEFAULT);
0195     pch_gbe_phy_write_reg_miic(hw, PHY_NEXT_PAGE_TX,
0196                     PHY_NEXT_PAGE_TX_DEFAULT);
0197     pch_gbe_phy_write_reg_miic(hw, PHY_1000T_CTRL, PHY_1000T_CTRL_DEFAULT);
0198     pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL,
0199                     PHY_PHYSP_CONTROL_DEFAULT);
0200 }
0201 
0202 /**
0203  * pch_gbe_phy_power_up - restore link in case the phy was powered down
0204  * @hw:    Pointer to the HW structure
0205  */
0206 void pch_gbe_phy_power_up(struct pch_gbe_hw *hw)
0207 {
0208     u16 mii_reg;
0209 
0210     mii_reg = 0;
0211     /* Just clear the power down bit to wake the phy back up */
0212     /* according to the manual, the phy will retain its
0213      * settings across a power-down/up cycle */
0214     pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &mii_reg);
0215     mii_reg &= ~MII_CR_POWER_DOWN;
0216     pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, mii_reg);
0217 }
0218 
0219 /**
0220  * pch_gbe_phy_power_down - Power down PHY
0221  * @hw:    Pointer to the HW structure
0222  */
0223 void pch_gbe_phy_power_down(struct pch_gbe_hw *hw)
0224 {
0225     u16 mii_reg;
0226 
0227     mii_reg = 0;
0228     /* Power down the PHY so no link is implied when interface is down *
0229      * The PHY cannot be powered down if any of the following is TRUE *
0230      * (a) WoL is enabled
0231      * (b) AMT is active
0232      */
0233     pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &mii_reg);
0234     mii_reg |= MII_CR_POWER_DOWN;
0235     pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, mii_reg);
0236     mdelay(1);
0237 }
0238 
0239 /**
0240  * pch_gbe_phy_set_rgmii - RGMII interface setting
0241  * @hw:             Pointer to the HW structure
0242  */
0243 void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
0244 {
0245     pch_gbe_phy_sw_reset(hw);
0246 }
0247 
0248 /**
0249  * pch_gbe_phy_tx_clk_delay - Setup TX clock delay via the PHY
0250  * @hw:             Pointer to the HW structure
0251  * Returns
0252  *  0:      Successful.
0253  *  -EINVAL:    Invalid argument.
0254  */
0255 static int pch_gbe_phy_tx_clk_delay(struct pch_gbe_hw *hw)
0256 {
0257     /* The RGMII interface requires a ~2ns TX clock delay. This is typically
0258      * done in layout with a longer trace or via PHY strapping, but can also
0259      * be done via PHY configuration registers.
0260      */
0261     struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
0262     u16 mii_reg;
0263     int ret = 0;
0264 
0265     switch (hw->phy.id) {
0266     case PHY_AR803X_ID:
0267         netdev_dbg(adapter->netdev,
0268                "Configuring AR803X PHY for 2ns TX clock delay\n");
0269         pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_OFF, &mii_reg);
0270         ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
0271                          PHY_AR8031_SERDES);
0272         if (ret)
0273             break;
0274 
0275         pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
0276         mii_reg |= PHY_AR8031_SERDES_TX_CLK_DLY;
0277         ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
0278                          mii_reg);
0279         break;
0280     default:
0281         netdev_err(adapter->netdev,
0282                "Unknown PHY (%x), could not set TX clock delay\n",
0283                hw->phy.id);
0284         return -EINVAL;
0285     }
0286 
0287     if (ret)
0288         netdev_err(adapter->netdev,
0289                "Could not configure tx clock delay for PHY\n");
0290     return ret;
0291 }
0292 
0293 /**
0294  * pch_gbe_phy_init_setting - PHY initial setting
0295  * @hw:             Pointer to the HW structure
0296  */
0297 void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
0298 {
0299     struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
0300     struct ethtool_cmd     cmd = { .cmd = ETHTOOL_GSET };
0301     int ret;
0302     u16 mii_reg;
0303 
0304     mii_ethtool_gset(&adapter->mii, &cmd);
0305 
0306     ethtool_cmd_speed_set(&cmd, hw->mac.link_speed);
0307     cmd.duplex = hw->mac.link_duplex;
0308     cmd.advertising = hw->phy.autoneg_advertised;
0309     cmd.autoneg = hw->mac.autoneg;
0310     pch_gbe_phy_write_reg_miic(hw, MII_BMCR, BMCR_RESET);
0311     ret = mii_ethtool_sset(&adapter->mii, &cmd);
0312     if (ret)
0313         netdev_err(adapter->netdev, "Error: mii_ethtool_sset\n");
0314 
0315     pch_gbe_phy_sw_reset(hw);
0316 
0317     pch_gbe_phy_read_reg_miic(hw, PHY_PHYSP_CONTROL, &mii_reg);
0318     mii_reg |= PHYSP_CTRL_ASSERT_CRS_TX;
0319     pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL, mii_reg);
0320 
0321     /* Setup a TX clock delay on certain platforms */
0322     if (adapter->pdata && adapter->pdata->phy_tx_clk_delay)
0323         pch_gbe_phy_tx_clk_delay(hw);
0324 }
0325 
0326 /**
0327  * pch_gbe_phy_disable_hibernate - Disable the PHY low power state
0328  * @hw:             Pointer to the HW structure
0329  * Returns
0330  *  0:      Successful.
0331  *  -EINVAL:    Invalid argument.
0332  */
0333 int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw)
0334 {
0335     struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
0336     u16 mii_reg;
0337     int ret = 0;
0338 
0339     switch (hw->phy.id) {
0340     case PHY_AR803X_ID:
0341         netdev_dbg(adapter->netdev,
0342                "Disabling hibernation for AR803X PHY\n");
0343         ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
0344                          PHY_AR8031_HIBERNATE);
0345         if (ret)
0346             break;
0347 
0348         pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
0349         mii_reg &= ~PHY_AR8031_PS_HIB_EN;
0350         ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
0351                          mii_reg);
0352         break;
0353     default:
0354         netdev_err(adapter->netdev,
0355                "Unknown PHY (%x), could not disable hibernation\n",
0356                hw->phy.id);
0357         return -EINVAL;
0358     }
0359 
0360     if (ret)
0361         netdev_err(adapter->netdev,
0362                "Could not disable PHY hibernation\n");
0363     return ret;
0364 }