Signed-off-by: Howard Wang <howard_w...@realsil.com.cn>
---
 drivers/net/r8169/meson.build    |   1 +
 drivers/net/r8169/r8169_ethdev.h |   3 +
 drivers/net/r8169/r8169_fiber.c  | 201 +++++++++++++++++++++++++++++++
 drivers/net/r8169/r8169_fiber.h  |  42 +++++++
 drivers/net/r8169/r8169_hw.c     |  93 +++++++++-----
 drivers/net/r8169/r8169_hw.h     |   2 +-
 drivers/net/r8169/r8169_phy.c    |  14 ++-
 7 files changed, 324 insertions(+), 32 deletions(-)
 create mode 100644 drivers/net/r8169/r8169_fiber.c
 create mode 100644 drivers/net/r8169/r8169_fiber.h

diff --git a/drivers/net/r8169/meson.build b/drivers/net/r8169/meson.build
index e139452416..ed644059f5 100644
--- a/drivers/net/r8169/meson.build
+++ b/drivers/net/r8169/meson.build
@@ -7,6 +7,7 @@ sources = files(
         'r8169_rxtx.c',
         'r8169_phy.c',
         'r8169_dash.c',
+        'r8169_fiber.c',
         'base/rtl8125a.c',
         'base/rtl8125a_mcu.c',
         'base/rtl8125b.c',
diff --git a/drivers/net/r8169/r8169_ethdev.h b/drivers/net/r8169/r8169_ethdev.h
index bc65ccf68a..84a233dfed 100644
--- a/drivers/net/r8169/r8169_ethdev.h
+++ b/drivers/net/r8169/r8169_ethdev.h
@@ -90,6 +90,9 @@ struct rtl_hw {
        u8 AllowAccessDashOcp;
        u8 HwPkgDet;
        u8 HwSuppSerDesPhyVer;
+
+       /* Fiber */
+       u32 HwFiberModeVer;
 };
 
 struct rtl_sw_stats {
diff --git a/drivers/net/r8169/r8169_fiber.c b/drivers/net/r8169/r8169_fiber.c
new file mode 100644
index 0000000000..9108fa6bba
--- /dev/null
+++ b/drivers/net/r8169/r8169_fiber.c
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Realtek Corporation. All rights reserved
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <rte_ether.h>
+#include <ethdev_driver.h>
+
+#include "r8169_fiber.h"
+
+static bool
+rtl8127_wait_8127_sds_cmd_done(struct rtl_hw *hw)
+{
+       u32 timeout = 0;
+       u32 waitcount = 100;
+
+       do {
+               if (RTL_R16(hw, R8127_SDS_8127_CMD) & R8127_SDS_8127_CMD_IN)
+                       rte_delay_us(1);
+               else
+                       return true;
+       } while (++timeout < waitcount);
+
+       return false;
+}
+
+static u16
+rtl8127_sds_phy_read_8127(struct rtl_hw *hw, u16 index, u16 page, u16 reg)
+{
+       RTL_W16(hw, R8127_SDS_8127_ADDR,
+               R8127_MAKE_SDS_8127_ADDR(index, page, reg));
+       RTL_W16(hw, R8127_SDS_8127_CMD, R8127_SDS_8127_CMD_IN);
+
+       if (rtl8127_wait_8127_sds_cmd_done(hw))
+               return RTL_R16(hw, R8127_SDS_8127_DATA_OUT);
+       else
+               return 0xffff;
+}
+
+static void
+rtl8127_sds_phy_write_8127(struct rtl_hw *hw, u16 index, u16 page, u16 reg,
+                          u16 val)
+{
+       RTL_W16(hw, R8127_SDS_8127_DATA_IN, val);
+       RTL_W16(hw, R8127_SDS_8127_ADDR,
+               R8127_MAKE_SDS_8127_ADDR(index, page, reg));
+       RTL_W16(hw, R8127_SDS_8127_CMD,
+               R8127_SDS_8127_CMD_IN | R8127_SDS_8127_WE_IN);
+
+       rtl8127_wait_8127_sds_cmd_done(hw);
+}
+
+static void
+rtl8127_clear_and_set_sds_phy_bit(struct rtl_hw *hw, u16 index, u16 page,
+                                 u16 addr, u16 clearmask, u16 setmask)
+{
+       u16 val;
+
+       val = rtl8127_sds_phy_read_8127(hw, index, page, addr);
+       val &= ~clearmask;
+       val |= setmask;
+       rtl8127_sds_phy_write_8127(hw, index, page, addr, val);
+}
+
+static void
+rtl8127_clear_sds_phy_bit(struct rtl_hw *hw, u16 index, u16 page,
+                         u16 addr, u16 mask)
+{
+       rtl8127_clear_and_set_sds_phy_bit(hw, index, page, addr, mask, 0);
+}
+
+static void
+rtl8127_set_sds_phy_bit(struct rtl_hw *hw, u16 index, u16 page, u16 addr,
+                       u16 mask)
+{
+       rtl8127_clear_and_set_sds_phy_bit(hw, index, page, addr, 0, mask);
+}
+
+static void
+rtl8127_sds_phy_reset_8127(struct rtl_hw *hw)
+{
+       RTL_W8(hw, 0x2350, RTL_R8(hw, 0x2350) & ~BIT_0);
+       rte_delay_us(1);
+
+       RTL_W16(hw, 0x233A, 0x801F);
+       RTL_W8(hw, 0x2350, RTL_R8(hw, 0x2350) | BIT_0);
+       rte_delay_us(10);
+}
+
+static void
+rtl8127_sds_phy_reset(struct rtl_hw *hw)
+{
+       switch (hw->HwFiberModeVer) {
+       case FIBER_MODE_RTL8127ATF:
+               rtl8127_sds_phy_reset_8127(hw);
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+rtl8127_set_sds_phy_caps_1g_8127(struct rtl_hw *hw)
+{
+       u16 val;
+
+       rtl8127_set_sds_phy_bit(hw, 0, 1, 31, BIT_3);
+       rtl8127_clear_and_set_sds_phy_bit(hw, 0, 2, 0, BIT_13 | BIT_12 | BIT_6,
+                                         BIT_12 | BIT_6);
+       RTL_W16(hw, 0x233A, 0x8004);
+
+       val = RTL_R16(hw, 0x233E);
+       val &= (BIT_13 | BIT_12 | BIT_1 | BIT_0);
+       val |= BIT_1;
+       RTL_W16(hw, 0x233E, val);
+
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC40A, 0x0);
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC466, 0x0);
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC808, 0x0);
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC80A, 0x0);
+       rtl_clear_and_set_eth_phy_ocp_bit(hw, 0xC804, 0x000F, 0x000C);
+}
+
+static void
+rtl8127_sds_phy_exit_1g_8127(struct rtl_hw *hw)
+{
+       rtl8127_clear_sds_phy_bit(hw, 0, 1, 31, BIT_3);
+       rtl8127_clear_and_set_sds_phy_bit(hw, 0, 2, 0, BIT_13 | BIT_12 | BIT_6,
+                                         BIT_6);
+
+       rtl8127_sds_phy_reset(hw);
+}
+
+static void
+rtl8127_set_sds_phy_caps_10g_8127(struct rtl_hw *hw)
+{
+       u16 val;
+
+       RTL_W16(hw, 0x233A, 0x801A);
+
+       val = RTL_R16(hw, 0x233E);
+       val &= (BIT_13 | BIT_12 | BIT_1 | BIT_0);
+       val |= BIT_12;
+       RTL_W16(hw, 0x233E, val);
+
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC40A, 0x0);
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC466, 0x3);
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC808, 0x0);
+       rtl_mdio_direct_write_phy_ocp(hw, 0xC80A, 0x0);
+       rtl_clear_and_set_eth_phy_ocp_bit(hw, 0xC804, 0x000F, 0x000C);
+}
+
+static void
+rtl8127_set_sds_phy_caps_8127(struct rtl_hw *hw)
+{
+       rtl8127_sds_phy_exit_1g_8127(hw);
+
+       switch (hw->speed) {
+       case SPEED_10000:
+               rtl8127_set_sds_phy_caps_10g_8127(hw);
+               break;
+       case SPEED_1000:
+               rtl8127_set_sds_phy_caps_1g_8127(hw);
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+rtl8127_set_sds_phy_caps(struct rtl_hw *hw)
+{
+       switch (hw->HwFiberModeVer) {
+       case FIBER_MODE_RTL8127ATF:
+               rtl8127_set_sds_phy_caps_8127(hw);
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+rtl8127_hw_sds_phy_config(struct rtl_hw *hw)
+{
+       rtl8127_set_sds_phy_caps(hw);
+}
+
+void
+rtl8127_hw_fiber_phy_config(struct rtl_hw *hw)
+{
+       switch (hw->HwFiberModeVer) {
+       case FIBER_MODE_RTL8127ATF:
+               rtl8127_hw_sds_phy_config(hw);
+               break;
+       default:
+               break;
+       }
+}
diff --git a/drivers/net/r8169/r8169_fiber.h b/drivers/net/r8169/r8169_fiber.h
new file mode 100644
index 0000000000..52bafc7e4c
--- /dev/null
+++ b/drivers/net/r8169/r8169_fiber.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Realtek Corporation. All rights reserved
+ */
+
+#ifndef R8169_FIBER_H
+#define R8169_FIBER_H
+
+#include <stdint.h>
+
+#include <bus_pci_driver.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_core.h>
+
+#include "r8169_compat.h"
+#include "r8169_ethdev.h"
+#include "r8169_phy.h"
+#include "r8169_hw.h"
+
+enum {
+       FIBER_MODE_NIC_ONLY = 0,
+       FIBER_MODE_RTL8127ATF,
+       FIBER_MODE_MAX
+};
+
+#define HW_FIBER_MODE_ENABLED(_M)   ((_M)->HwFiberModeVer > 0)
+
+/* sds address */
+#define R8127_SDS_8127_CMD      0x2348
+#define R8127_SDS_8127_ADDR     0x234A
+#define R8127_SDS_8127_DATA_IN  0x234C
+#define R8127_SDS_8127_DATA_OUT 0x234E
+
+#define R8127_MAKE_SDS_8127_ADDR(_index, _page, _reg) \
+       (((_index) << 11) | ((_page) << 5) | (_reg))
+
+/* sds command */
+#define R8127_SDS_8127_CMD_IN BIT_0
+#define R8127_SDS_8127_WE_IN  BIT_1
+
+void rtl8127_hw_fiber_phy_config(struct rtl_hw *hw);
+
+#endif /* R8169_FIBER_H */
diff --git a/drivers/net/r8169/r8169_hw.c b/drivers/net/r8169/r8169_hw.c
index c131353ef8..e25336ac19 100644
--- a/drivers/net/r8169/r8169_hw.c
+++ b/drivers/net/r8169/r8169_hw.c
@@ -12,6 +12,7 @@
 #include "r8169_hw.h"
 #include "r8169_logs.h"
 #include "r8169_dash.h"
+#include "r8169_fiber.h"
 
 static u32
 rtl_eri_read_with_oob_base_address(struct rtl_hw *hw, int addr, int len,
@@ -1439,18 +1440,28 @@ rtl_write_mac_mcu_ram_code(struct rtl_hw *hw, const u16 
*entry, u16 entry_cnt)
 }
 
 bool
-rtl_is_speed_mode_valid(u32 speed)
-{
-       switch (speed) {
-       case SPEED_10000:
-       case SPEED_5000:
-       case SPEED_2500:
-       case SPEED_1000:
-       case SPEED_100:
-       case SPEED_10:
-               return true;
-       default:
-               return false;
+rtl_is_speed_mode_valid(struct rtl_hw *hw, u32 speed)
+{
+       if (HW_FIBER_MODE_ENABLED(hw)) {
+               switch (speed) {
+               case SPEED_10000:
+               case SPEED_1000:
+                       return true;
+               default:
+                       return false;
+               }
+       } else {
+               switch (speed) {
+               case SPEED_10000:
+               case SPEED_5000:
+               case SPEED_2500:
+               case SPEED_1000:
+               case SPEED_100:
+               case SPEED_10:
+                       return true;
+               default:
+                       return false;
+               }
        }
 }
 
@@ -1482,9 +1493,9 @@ void
 rtl_set_link_option(struct rtl_hw *hw, u8 autoneg, u32 speed, u8 duplex,
                    enum rtl_fc_mode fc)
 {
-       u64 adv;
+       u64 adv = 0;
 
-       if (!rtl_is_speed_mode_valid(speed))
+       if (!rtl_is_speed_mode_valid(hw, speed))
                speed = hw->HwSuppMaxPhyLinkSpeed;
 
        if (!rtl_is_duplex_mode_valid(duplex))
@@ -1495,22 +1506,34 @@ rtl_set_link_option(struct rtl_hw *hw, u8 autoneg, u32 
speed, u8 duplex,
 
        speed = RTE_MIN(speed, hw->HwSuppMaxPhyLinkSpeed);
 
-       adv = 0;
-       switch (speed) {
-       case SPEED_10000:
-               adv |= ADVERTISE_10000_FULL;
-       /* Fall through */
-       case SPEED_5000:
-               adv |= ADVERTISE_5000_FULL;
-       /* Fall through */
-       case SPEED_2500:
-               adv |= ADVERTISE_2500_FULL;
-       /* Fall through */
-       default:
-               adv |= (ADVERTISE_10_HALF | ADVERTISE_10_FULL |
-                       ADVERTISE_100_HALF | ADVERTISE_100_FULL |
-                       ADVERTISE_1000_HALF | ADVERTISE_1000_FULL);
-               break;
+       if (HW_FIBER_MODE_ENABLED(hw)) {
+               switch (speed) {
+               case SPEED_10000:
+                       adv |= ADVERTISE_10000_FULL;
+               /* Fall through */
+               case SPEED_1000:
+                       adv |= ADVERTISE_1000_FULL;
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               switch (speed) {
+               case SPEED_10000:
+                       adv |= ADVERTISE_10000_FULL;
+               /* Fall through */
+               case SPEED_5000:
+                       adv |= ADVERTISE_5000_FULL;
+               /* Fall through */
+               case SPEED_2500:
+                       adv |= ADVERTISE_2500_FULL;
+               /* Fall through */
+               default:
+                       adv |= (ADVERTISE_10_HALF | ADVERTISE_10_FULL |
+                               ADVERTISE_100_HALF | ADVERTISE_100_FULL |
+                               ADVERTISE_1000_HALF | ADVERTISE_1000_FULL);
+                       break;
+               }
        }
 
        hw->autoneg = autoneg;
@@ -1962,6 +1985,16 @@ rtl_init_software_variable(struct rtl_hw *hw)
                break;
        }
 
+       switch (hw->mcfg) {
+       case CFG_METHOD_91:
+               tmp = (u8)rtl_mac_ocp_read(hw, 0xD006);
+               if (tmp == 0x07)
+                       hw->HwFiberModeVer = FIBER_MODE_RTL8127ATF;
+               break;
+       default:
+               break;
+       }
+
        rtl_set_link_option(hw, autoneg_mode, speed_mode, duplex_mode, 
rtl_fc_full);
 
        hw->mtu = RTL_DEFAULT_MTU;
diff --git a/drivers/net/r8169/r8169_hw.h b/drivers/net/r8169/r8169_hw.h
index 6f2d38ac81..558ffaac95 100644
--- a/drivers/net/r8169/r8169_hw.h
+++ b/drivers/net/r8169/r8169_hw.h
@@ -47,7 +47,7 @@ void rtl_write_mac_mcu_ram_code(struct rtl_hw *hw, const u16 
*entry,
 
 void rtl_hw_initialize(struct rtl_hw *hw);
 
-bool rtl_is_speed_mode_valid(u32 speed);
+bool rtl_is_speed_mode_valid(struct rtl_hw *hw, u32 speed);
 
 void rtl_get_mac_version(struct rtl_hw *hw, struct rte_pci_device *pci_dev);
 int rtl_get_mac_address(struct rtl_hw *hw, struct rte_ether_addr *ea);
diff --git a/drivers/net/r8169/r8169_phy.c b/drivers/net/r8169/r8169_phy.c
index cc06c7b55a..e547b44137 100644
--- a/drivers/net/r8169/r8169_phy.c
+++ b/drivers/net/r8169/r8169_phy.c
@@ -14,6 +14,7 @@
 #include "r8169_phy.h"
 #include "r8169_logs.h"
 #include "r8169_dash.h"
+#include "r8169_fiber.h"
 
 static u16
 rtl_map_phy_ocp_addr(u16 PageNum, u8 RegNum)
@@ -1327,6 +1328,9 @@ rtl_hw_phy_config(struct rtl_hw *hw)
        if (rtl_is_8125(hw))
                rtl_clear_eth_phy_ocp_bit(hw, 0xA5B4, BIT_15);
 
+       if (HW_FIBER_MODE_ENABLED(hw))
+               rtl8127_hw_fiber_phy_config(hw);
+
        rtl_mdio_write(hw, 0x1F, 0x0000);
 
        if (HW_HAS_WRITE_PHY_MCU_RAM_CODE(hw))
@@ -1424,12 +1428,15 @@ rtl_set_speed_xmii(struct rtl_hw *hw, u8 autoneg, u32 
speed, u8 duplex, u64 adv)
                break;
        }
 
-       if (!rtl_is_speed_mode_valid(speed)) {
+       if (!rtl_is_speed_mode_valid(hw, speed)) {
                speed = hw->HwSuppMaxPhyLinkSpeed;
                duplex = DUPLEX_FULL;
                adv |= hw->advertising;
        }
 
+       if (HW_FIBER_MODE_ENABLED(hw))
+               goto set_speed;
+
        giga_ctrl = rtl_mdio_read(hw, MII_CTRL1000);
        giga_ctrl &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
        if (rtl_is_8125(hw)) {
@@ -1482,11 +1489,16 @@ rtl_set_speed_xmii(struct rtl_hw *hw, u8 autoneg, u32 
speed, u8 duplex, u64 adv)
                else
                        goto out;
        }
+
+set_speed:
        hw->autoneg = autoneg;
        hw->speed = speed;
        hw->duplex = duplex;
        hw->advertising = adv;
 
+       if (HW_FIBER_MODE_ENABLED(hw))
+               rtl8127_hw_fiber_phy_config(hw);
+
        rc = 0;
 out:
        return rc;
-- 
2.34.1

Reply via email to