#include <linux/string_choices.h>
#include <net/phy/realtek_phy.h>
-@@ -205,10 +207,26 @@
+@@ -205,10 +207,27 @@
#define RTL_8221B_VM_CG 0x001cc84a
#define RTL_8251B 0x001cc862
#define RTL_8261C 0x001cc890
+
+#define RTL826X_VEND1_PKG_MODEL 0x103
+#define RTL826X_VEND1_VERSION_ID 0x104
++#define RTL826X_VEND1_VERSION_ID_VARIANT GENMASK(2, 0)
+
+#define RTL826X_VND2_INER 0xA424
+#define RTL826X_VND2_INER_LINK_STATUS BIT(4)
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");
-@@ -1993,6 +2011,125 @@ static int rtl8251b_c45_match_phy_device
+@@ -1993,6 +2012,125 @@ static int rtl8251b_c45_match_phy_device
return rtlgen_is_c45_match(phydev, RTL_8251B, true);
}
static int rtlgen_resume(struct phy_device *phydev)
{
int ret = genphy_resume(phydev);
-@@ -2214,6 +2351,493 @@ static int rtlgen_sfp_config_aneg(struct
+@@ -2214,6 +2352,482 @@ static int rtlgen_sfp_config_aneg(struct
return 0;
}
++static int rtl826x_patch_db_init(struct phy_device *phydev)
++{
++ int ver;
++
++ ver = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL826X_VEND1_VERSION_ID);
++ if (ver < 0)
++ return ver;
++
++ if (ver & RTL826X_VEND1_VERSION_ID_VARIANT)
++ return rtl8261n_phy_patch_db_init(phydev);
++ else
++ return rtl8264b_phy_patch_db_init(phydev);
++}
++
+static int rtl826x_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct rtl826x_priv *priv;
++ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(struct rtl826x_priv), GFP_KERNEL);
+ if (!priv)
+ phy_disable_eee_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
+ phy_disable_eee_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
+
-+ if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON))
-+ return rtl822x_hwmon_init(phydev);
-+
-+ return 0;
-+}
-+
-+static int rtl8261n_probe(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = rtl826x_probe(phydev);
++ ret = rtl826x_patch_db_init(phydev);
+ if (ret < 0)
+ return ret;
+
-+ ret = rtl8261n_phy_patch_db_init(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int rtl8264b_probe(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = rtl826x_probe(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = rtl8264b_phy_patch_db_init(phydev);
-+ if (ret < 0)
-+ return ret;
++ if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON))
++ return rtl822x_hwmon_init(phydev);
+
+ return 0;
+}
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
-@@ -2520,6 +3144,108 @@ static struct phy_driver realtek_drvs[]
+@@ -2520,6 +3134,108 @@ static struct phy_driver realtek_drvs[]
.resume = genphy_resume,
.read_mmd = genphy_read_mmd_unsupported,
.write_mmd = genphy_write_mmd_unsupported,
+ }, {
+ .name = "RTL8251L 5Gbps PHY",
+ .config_init = rtl826x_config_init,
-+ .probe = rtl8261n_probe,
++ .probe = rtl826x_probe,
+ .get_features = rtl825xb_get_features,
+ .suspend = rtl826x_suspend,
+ .resume = rtlgen_c45_resume,
+ }, {
+ .name = "RTL8254B 5Gbps PHY",
+ .config_init = rtl826x_config_init,
-+ .probe = rtl8264b_probe,
++ .probe = rtl826x_probe,
+ .get_features = rtl825xb_get_features,
+ .suspend = rtl826x_suspend,
+ .resume = rtlgen_c45_resume,
+ }, {
+ .name = "RTL8261BE 10Gbps PHY",
+ .config_init = rtl826x_config_init,
-+ .probe = rtl8261n_probe,
++ .probe = rtl826x_probe,
+ .get_features = rtl826x_get_features,
+ .suspend = rtl826x_suspend,
+ .resume = rtlgen_c45_resume,
+ }, {
+ .name = "RTL8261N 10Gbps PHY",
+ .config_init = rtl826x_config_init,
-+ .probe = rtl8261n_probe,
++ .probe = rtl826x_probe,
+ .get_features = rtl826x_get_features,
+ .suspend = rtl826x_suspend,
+ .resume = rtlgen_c45_resume,
+ PHY_ID_MATCH_EXACT(RTL_8264),
+ .name = "RTL8264 10Gbps PHY",
+ .config_init = rtl826x_config_init,
-+ .probe = rtl8264b_probe,
++ .probe = rtl826x_probe,
+ .get_features = rtl826x_get_features,
+ .suspend = rtl826x_suspend,
+ .resume = rtlgen_c45_resume,
+ }, {
+ .name = "RTL8264B 10Gbps PHY",
+ .config_init = rtl826x_config_init,
-+ .probe = rtl8264b_probe,
++ .probe = rtl826x_probe,
+ .get_features = rtl826x_get_features,
+ .suspend = rtl826x_suspend,
+ .resume = rtlgen_c45_resume,