Signed-off-by: Howard Wang <howard_w...@realsil.com.cn>
---
 drivers/net/r8169/r8169_ethdev.h |   1 +
 drivers/net/r8169/r8169_phy.c    | 219 +++++++++++++++++++++++++++++++
 drivers/net/r8169/r8169_phy.h    |  18 +++
 3 files changed, 238 insertions(+)

diff --git a/drivers/net/r8169/r8169_ethdev.h b/drivers/net/r8169/r8169_ethdev.h
index 20dbf06c9b..9656a26eb0 100644
--- a/drivers/net/r8169/r8169_ethdev.h
+++ b/drivers/net/r8169/r8169_ethdev.h
@@ -18,6 +18,7 @@ struct rtl_hw {
        u8  *mmio_addr;
        u32 mcfg;
        u8  HwSuppIntMitiVer;
+       u16 cur_page;
 
        /* Enable Tx No Close */
        u8 EnableTxNoClose;
diff --git a/drivers/net/r8169/r8169_phy.c b/drivers/net/r8169/r8169_phy.c
index f0a880eeca..cfec426ee1 100644
--- a/drivers/net/r8169/r8169_phy.c
+++ b/drivers/net/r8169/r8169_phy.c
@@ -39,3 +39,222 @@ rtl_set_mac_ocp_bit(struct rtl_hw *hw, u16 addr, u16 mask)
        rtl_clear_set_mac_ocp_bit(hw, addr, 0, mask);
 }
 
+static u16
+rtl_map_phy_ocp_addr(u16 PageNum, u8 RegNum)
+{
+       u8 ocp_reg_num = 0;
+       u16 ocp_page_num = 0;
+       u16 ocp_phy_address = 0;
+
+       if (PageNum == 0) {
+               ocp_page_num = OCP_STD_PHY_BASE_PAGE + (RegNum / 8);
+               ocp_reg_num = 0x10 + (RegNum % 8);
+       } else {
+               ocp_page_num = PageNum;
+               ocp_reg_num = RegNum;
+       }
+
+       ocp_page_num <<= 4;
+
+       if (ocp_reg_num < 16)
+               ocp_phy_address = 0;
+       else {
+               ocp_reg_num -= 16;
+               ocp_reg_num <<= 1;
+
+               ocp_phy_address = ocp_page_num + ocp_reg_num;
+       }
+
+       return ocp_phy_address;
+}
+
+static u32
+rtl_mdio_real_read_phy_ocp(struct rtl_hw *hw, u32 RegAddr)
+{
+       u32 data32;
+       int i, value = 0;
+
+       data32 = RegAddr / 2;
+       data32 <<= OCPR_Addr_Reg_shift;
+
+       RTL_W32(hw, PHYOCP, data32);
+       for (i = 0; i < 100; i++) {
+               udelay(1);
+
+               if (RTL_R32(hw, PHYOCP) & OCPR_Flag)
+                       break;
+       }
+       value = RTL_R32(hw, PHYOCP) & OCPDR_Data_Mask;
+
+       return value;
+}
+
+u32
+rtl_mdio_direct_read_phy_ocp(struct rtl_hw *hw, u32 RegAddr)
+{
+       return rtl_mdio_real_read_phy_ocp(hw, RegAddr);
+}
+
+static u32
+rtl_mdio_read_phy_ocp(struct rtl_hw *hw, u16 PageNum, u32 RegAddr)
+{
+       u16 ocp_addr;
+
+       ocp_addr = rtl_map_phy_ocp_addr(PageNum, RegAddr);
+
+       return rtl_mdio_direct_read_phy_ocp(hw, ocp_addr);
+}
+
+static u32
+rtl_mdio_real_read(struct rtl_hw *hw, u32 RegAddr)
+{
+       return rtl_mdio_read_phy_ocp(hw, hw->cur_page, RegAddr);
+}
+
+static void
+rtl_mdio_real_write_phy_ocp(struct rtl_hw *hw, u32 RegAddr, u32 value)
+{
+       u32 data32;
+       int i;
+
+       data32 = RegAddr / 2;
+       data32 <<= OCPR_Addr_Reg_shift;
+       data32 |= OCPR_Write | value;
+
+       RTL_W32(hw, PHYOCP, data32);
+       for (i = 0; i < 100; i++) {
+               udelay(1);
+
+               if (!(RTL_R32(hw, PHYOCP) & OCPR_Flag))
+                       break;
+       }
+}
+
+void
+rtl_mdio_direct_write_phy_ocp(struct rtl_hw *hw, u32 RegAddr, u32 value)
+{
+       rtl_mdio_real_write_phy_ocp(hw, RegAddr, value);
+}
+
+static void
+rtl_mdio_write_phy_ocp(struct rtl_hw *hw, u16 PageNum, u32 RegAddr, u32 value)
+{
+       u16 ocp_addr;
+
+       ocp_addr = rtl_map_phy_ocp_addr(PageNum, RegAddr);
+
+       rtl_mdio_direct_write_phy_ocp(hw, ocp_addr, value);
+}
+
+static void
+rtl_mdio_real_write(struct rtl_hw *hw, u32 RegAddr, u32 value)
+{
+       if (RegAddr == 0x1F)
+               hw->cur_page = value;
+       rtl_mdio_write_phy_ocp(hw, hw->cur_page, RegAddr, value);
+}
+
+u32
+rtl_mdio_read(struct rtl_hw *hw, u32 RegAddr)
+{
+       return rtl_mdio_real_read(hw, RegAddr);
+}
+
+void
+rtl_mdio_write(struct rtl_hw *hw, u32 RegAddr, u32 value)
+{
+       rtl_mdio_real_write(hw, RegAddr, value);
+}
+
+void
+rtl_clear_and_set_eth_phy_ocp_bit(struct rtl_hw *hw, u16 addr, u16 clearmask,
+                                  u16 setmask)
+{
+       u16 phy_reg_value;
+
+       phy_reg_value = rtl_mdio_direct_read_phy_ocp(hw, addr);
+       phy_reg_value &= ~clearmask;
+       phy_reg_value |= setmask;
+       rtl_mdio_direct_write_phy_ocp(hw, addr, phy_reg_value);
+}
+
+void
+rtl_clear_eth_phy_ocp_bit(struct rtl_hw *hw, u16 addr, u16 mask)
+{
+       rtl_clear_and_set_eth_phy_ocp_bit(hw, addr, mask, 0);
+}
+
+void
+rtl_set_eth_phy_ocp_bit(struct rtl_hw *hw, u16 addr, u16 mask)
+{
+       rtl_clear_and_set_eth_phy_ocp_bit(hw, addr, 0, mask);
+}
+
+void
+rtl_ephy_write(struct rtl_hw *hw, int addr, int value)
+{
+       int i;
+
+       RTL_W32(hw, EPHYAR, EPHYAR_Write |
+               (addr & EPHYAR_Reg_Mask_v2) << EPHYAR_Reg_shift |
+               (value & EPHYAR_Data_Mask));
+
+       for (i = 0; i < 10; i++) {
+               udelay(100);
+
+               /* Check if the NIC has completed EPHY write */
+               if (!(RTL_R32(hw, EPHYAR) & EPHYAR_Flag))
+                       break;
+       }
+
+       udelay(20);
+}
+
+static u16
+rtl_ephy_read(struct rtl_hw *hw, int addr)
+{
+       int i;
+       u16 value = 0xffff;
+
+       RTL_W32(hw, EPHYAR, EPHYAR_Read | (addr & EPHYAR_Reg_Mask_v2) <<
+               EPHYAR_Reg_shift);
+
+       for (i = 0; i < 10; i++) {
+               udelay(100);
+
+               /* Check if the NIC has completed EPHY read */
+               if (RTL_R32(hw, EPHYAR) & EPHYAR_Flag) {
+                       value = (u16)(RTL_R32(hw, EPHYAR) & EPHYAR_Data_Mask);
+                       break;
+               }
+       }
+
+       udelay(20);
+
+       return value;
+}
+
+void
+rtl_clear_and_set_pcie_phy_bit(struct rtl_hw *hw, u8 addr, u16 clearmask,
+                               u16 setmask)
+{
+       u16 ephy_value;
+
+       ephy_value = rtl_ephy_read(hw, addr);
+       ephy_value &= ~clearmask;
+       ephy_value |= setmask;
+       rtl_ephy_write(hw, addr, ephy_value);
+}
+
+void
+rtl_clear_pcie_phy_bit(struct rtl_hw *hw, u8 addr, u16 mask)
+{
+       rtl_clear_and_set_pcie_phy_bit(hw, addr, mask, 0);
+}
+
+void
+rtl_set_pcie_phy_bit(struct rtl_hw *hw, u8 addr, u16 mask)
+{
+       rtl_clear_and_set_pcie_phy_bit(hw, addr, 0, mask);
+}
+
diff --git a/drivers/net/r8169/r8169_phy.h b/drivers/net/r8169/r8169_phy.h
index f31eb163d8..da5a6575d4 100644
--- a/drivers/net/r8169/r8169_phy.h
+++ b/drivers/net/r8169/r8169_phy.h
@@ -17,5 +17,23 @@
 void rtl_clear_mac_ocp_bit(struct rtl_hw *hw, u16 addr, u16 mask);
 void rtl_set_mac_ocp_bit(struct rtl_hw *hw, u16 addr, u16 mask);
 
+u32 rtl_mdio_direct_read_phy_ocp(struct rtl_hw *hw, u32 RegAddr);
+void rtl_mdio_direct_write_phy_ocp(struct rtl_hw *hw, u32 RegAddr, u32 value);
+
+u32 rtl_mdio_read(struct rtl_hw *hw, u32 RegAddr);
+void rtl_mdio_write(struct rtl_hw *hw, u32 RegAddr, u32 value);
+
+void rtl_clear_and_set_eth_phy_ocp_bit(struct rtl_hw *hw, u16 addr,
+                                       u16 clearmask, u16 setmask);
+void rtl_clear_eth_phy_ocp_bit(struct rtl_hw *hw, u16 addr, u16 mask);
+void rtl_set_eth_phy_ocp_bit(struct rtl_hw *hw, u16 addr, u16 mask);
+
+void rtl_ephy_write(struct rtl_hw *hw, int addr, int value);
+
+void rtl_clear_and_set_pcie_phy_bit(struct rtl_hw *hw, u8 addr, u16 clearmask,
+                                    u16 setmask);
+void rtl_clear_pcie_phy_bit(struct rtl_hw *hw, u8 addr, u16 mask);
+void rtl_set_pcie_phy_bit(struct rtl_hw *hw, u8 addr, u16 mask);
+
 #endif
 
-- 
2.34.1

Reply via email to