+++ /dev/null
-Date: Tue, 12 Dec 2023 06:41:43 +0100
-Subject: [PATCH 01/20] net: phy: c45: add genphy_c45_pma_read_ext_abilities()
- function
-
-Move part of the genphy_c45_pma_read_abilities() code to a separate
-function.
-
-Some PHYs do not implement PMA/PMD status 2 register (Register 1.8) but
-do implement PMA/PMD extended ability register (Register 1.11). To make
-use of it, we need to be able to access this part of code separately.
-
-(cherry picked from commit 0c476157085fe2ad13b9bec70ea672e86647fa1a)
----
- drivers/net/phy/phy-c45.c | 129 ++++++++++++++++++++++----------------
- include/linux/phy.h | 1 +
- 2 files changed, 75 insertions(+), 55 deletions(-)
-
---- a/drivers/net/phy/phy-c45.c
-+++ b/drivers/net/phy/phy-c45.c
-@@ -920,6 +920,79 @@ int genphy_c45_pma_baset1_read_abilities
- EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_abilities);
-
- /**
-+ * genphy_c45_pma_read_ext_abilities - read supported link modes from PMA
-+ * @phydev: target phy_device struct
-+ *
-+ * Read the supported link modes from the PMA/PMD extended ability register
-+ * (Register 1.11).
-+ */
-+int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev)
-+{
-+ int val;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
-+ if (val < 0)
-+ return val;
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_10GBLRM);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_10GBT);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_10GBKX4);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_10GBKR);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_1000BT);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_1000BKX);
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_100BTX);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_100BTX);
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_10BT);
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_EXTABLE_10BT);
-+
-+ if (val & MDIO_PMA_EXTABLE_NBT) {
-+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
-+ MDIO_PMA_NG_EXTABLE);
-+ if (val < 0)
-+ return val;
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_NG_EXTABLE_2_5GBT);
-+
-+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-+ phydev->supported,
-+ val & MDIO_PMA_NG_EXTABLE_5GBT);
-+ }
-+
-+ if (val & MDIO_PMA_EXTABLE_BT1) {
-+ val = genphy_c45_pma_baset1_read_abilities(phydev);
-+ if (val < 0)
-+ return val;
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(genphy_c45_pma_read_ext_abilities);
-+
-+/**
- * genphy_c45_pma_read_abilities - read supported link modes from PMA
- * @phydev: target phy_device struct
- *
-@@ -962,63 +1035,9 @@ int genphy_c45_pma_read_abilities(struct
- val & MDIO_PMA_STAT2_10GBER);
-
- if (val & MDIO_PMA_STAT2_EXTABLE) {
-- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
-+ val = genphy_c45_pma_read_ext_abilities(phydev);
- if (val < 0)
- return val;
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_10GBLRM);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_10GBT);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_10GBKX4);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_10GBKR);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_1000BT);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_1000BKX);
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_100BTX);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_100BTX);
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_10BT);
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
-- phydev->supported,
-- val & MDIO_PMA_EXTABLE_10BT);
--
-- if (val & MDIO_PMA_EXTABLE_NBT) {
-- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
-- MDIO_PMA_NG_EXTABLE);
-- if (val < 0)
-- return val;
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_NG_EXTABLE_2_5GBT);
--
-- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
-- phydev->supported,
-- val & MDIO_PMA_NG_EXTABLE_5GBT);
-- }
--
-- if (val & MDIO_PMA_EXTABLE_BT1) {
-- val = genphy_c45_pma_baset1_read_abilities(phydev);
-- if (val < 0)
-- return val;
-- }
- }
-
- /* This is optional functionality. If not supported, we may get an error
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -1931,6 +1931,7 @@ int genphy_c45_an_config_aneg(struct phy
- int genphy_c45_an_disable_aneg(struct phy_device *phydev);
- int genphy_c45_read_mdix(struct phy_device *phydev);
- int genphy_c45_pma_read_abilities(struct phy_device *phydev);
-+int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev);
- int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev);
- int genphy_c45_read_eee_abilities(struct phy_device *phydev);
- int genphy_c45_pma_baset1_read_master_slave(struct phy_device *phydev);
+++ /dev/null
-Date: Sun, 1 Sep 2024 01:35:26 -0700
-Subject: [PATCH 03/20] net: phy: Add driver for Motorcomm yt8821 2.5G ethernet
- phy
-
-Add a driver for the motorcomm yt8821 2.5G ethernet phy. Verified the
-driver on BPI-R3(with MediaTek MT7986(Filogic 830) SoC) development board,
-which is developed by Guangdong Bipai Technology Co., Ltd..
-
-yt8821 2.5G ethernet phy works in AUTO_BX2500_SGMII or FORCE_BX2500
-interface, supports 2.5G/1000M/100M/10M speeds, and wol(magic package).
-
-
-(cherry picked from commit b671105b88c3bb9acc1fb61a3ee2ca0ece60cb8d)
----
- drivers/net/phy/motorcomm.c | 671 +++++++++++++++++++++++++++++++++++-
- 1 file changed, 667 insertions(+), 4 deletions(-)
-
---- a/drivers/net/phy/motorcomm.c
-+++ b/drivers/net/phy/motorcomm.c
-@@ -1,6 +1,6 @@
- // SPDX-License-Identifier: GPL-2.0+
- /*
-- * Motorcomm 8511/8521/8531/8531S PHY driver.
-+ * Motorcomm 8511/8521/8531/8531S/8821 PHY driver.
- *
-@@ -17,8 +17,8 @@
- #define PHY_ID_YT8521 0x0000011a
- #define PHY_ID_YT8531 0x4f51e91b
- #define PHY_ID_YT8531S 0x4f51e91a
--
--/* YT8521/YT8531S Register Overview
-+#define PHY_ID_YT8821 0x4f51ea19
-+/* YT8521/YT8531S/YT8821 Register Overview
- * UTP Register space | FIBER Register space
- * ------------------------------------------------------------
- * | UTP MII | FIBER MII |
-@@ -51,6 +51,8 @@
- #define YTPHY_SSR_SPEED_10M ((0x0 << 14))
- #define YTPHY_SSR_SPEED_100M ((0x1 << 14))
- #define YTPHY_SSR_SPEED_1000M ((0x2 << 14))
-+#define YTPHY_SSR_SPEED_10G ((0x3 << 14))
-+#define YTPHY_SSR_SPEED_2500M ((0x0 << 14) | BIT(9))
- #define YTPHY_SSR_DUPLEX_OFFSET 13
- #define YTPHY_SSR_DUPLEX BIT(13)
- #define YTPHY_SSR_PAGE_RECEIVED BIT(12)
-@@ -269,12 +271,89 @@
- #define YT8531_SCR_CLK_SRC_REF_25M 4
- #define YT8531_SCR_CLK_SRC_SSC_25M 5
-
-+#define YT8821_SDS_EXT_CSR_CTRL_REG 0x23
-+#define YT8821_SDS_EXT_CSR_VCO_LDO_EN BIT(15)
-+#define YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN BIT(8)
-+
-+#define YT8821_UTP_EXT_PI_CTRL_REG 0x56
-+#define YT8821_UTP_EXT_PI_RST_N_FIFO BIT(5)
-+#define YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE BIT(4)
-+#define YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE BIT(3)
-+#define YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE BIT(2)
-+#define YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE BIT(1)
-+#define YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE BIT(0)
-+
-+#define YT8821_UTP_EXT_VCT_CFG6_CTRL_REG 0x97
-+#define YT8821_UTP_EXT_FECHO_AMP_TH_HUGE GENMASK(15, 8)
-+
-+#define YT8821_UTP_EXT_ECHO_CTRL_REG 0x336
-+#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000 GENMASK(14, 8)
-+
-+#define YT8821_UTP_EXT_GAIN_CTRL_REG 0x340
-+#define YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000 GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_RPDN_CTRL_REG 0x34E
-+#define YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 BIT(15)
-+#define YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500 BIT(7)
-+#define YT8821_UTP_EXT_RPDN_IPR_SHT_2500 GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG 0x36A
-+#define YT8821_UTP_EXT_TH_20DB_2500 GENMASK(15, 0)
-+
-+#define YT8821_UTP_EXT_TRACE_CTRL_REG 0x372
-+#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500 GENMASK(14, 8)
-+#define YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500 GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG 0x374
-+#define YT8821_UTP_EXT_ALPHA_SHT_2500 GENMASK(14, 8)
-+#define YT8821_UTP_EXT_IPR_LNG_2500 GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_PLL_CTRL_REG 0x450
-+#define YT8821_UTP_EXT_PLL_SPARE_CFG GENMASK(7, 0)
-+
-+#define YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG 0x466
-+#define YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG GENMASK(14, 8)
-+#define YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG 0x467
-+#define YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG GENMASK(14, 8)
-+#define YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG 0x468
-+#define YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG GENMASK(14, 8)
-+#define YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG 0x469
-+#define YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG GENMASK(14, 8)
-+#define YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG GENMASK(6, 0)
-+
-+#define YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG 0x4B3
-+#define YT8821_UTP_EXT_MU_COARSE_FR_F_FFE GENMASK(14, 12)
-+#define YT8821_UTP_EXT_MU_COARSE_FR_F_FBE GENMASK(10, 8)
-+
-+#define YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG 0x4B5
-+#define YT8821_UTP_EXT_MU_FINE_FR_F_FFE GENMASK(14, 12)
-+#define YT8821_UTP_EXT_MU_FINE_FR_F_FBE GENMASK(10, 8)
-+
-+#define YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG 0x4D2
-+#define YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER GENMASK(7, 4)
-+#define YT8821_UTP_EXT_VGA_LPF1_CAP_2500 GENMASK(3, 0)
-+
-+#define YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG 0x4D3
-+#define YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER GENMASK(7, 4)
-+#define YT8821_UTP_EXT_VGA_LPF2_CAP_2500 GENMASK(3, 0)
-+
-+#define YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG 0x660
-+#define YT8821_UTP_EXT_NFR_TX_ABILITY BIT(3)
- /* Extended Register end */
-
- #define YTPHY_DTS_OUTPUT_CLK_DIS 0
- #define YTPHY_DTS_OUTPUT_CLK_25M 25000000
- #define YTPHY_DTS_OUTPUT_CLK_125M 125000000
-
-+#define YT8821_CHIP_MODE_AUTO_BX2500_SGMII 0
-+#define YT8821_CHIP_MODE_FORCE_BX2500 1
-+
- struct yt8521_priv {
- /* combo_advertising is used for case of YT8521 in combo mode,
- * this means that yt8521 may work in utp or fiber mode which depends
-@@ -2250,6 +2329,572 @@ static int yt8521_get_features(struct ph
- return ret;
- }
-
-+/**
-+ * yt8821_get_features - read mmd register to get 2.5G capability
-+ * @phydev: target phy_device struct
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_get_features(struct phy_device *phydev)
-+{
-+ int ret;
-+
-+ ret = genphy_c45_pma_read_ext_abilities(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ return genphy_read_abilities(phydev);
-+}
-+
-+/**
-+ * yt8821_get_rate_matching - read register to get phy chip mode
-+ * @phydev: target phy_device struct
-+ * @iface: PHY data interface type
-+ *
-+ * Returns: rate matching type or negative errno code
-+ */
-+static int yt8821_get_rate_matching(struct phy_device *phydev,
-+ phy_interface_t iface)
-+{
-+ int val;
-+
-+ val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
-+ if (val < 0)
-+ return val;
-+
-+ if (FIELD_GET(YT8521_CCR_MODE_SEL_MASK, val) ==
-+ YT8821_CHIP_MODE_FORCE_BX2500)
-+ return RATE_MATCH_PAUSE;
-+
-+ return RATE_MATCH_NONE;
-+}
-+
-+/**
-+ * yt8821_aneg_done() - determines the auto negotiation result
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0(no link)or 1(utp link) or negative errno code
-+ */
-+static int yt8821_aneg_done(struct phy_device *phydev)
-+{
-+ return yt8521_aneg_done_paged(phydev, YT8521_RSSR_UTP_SPACE);
-+}
-+
-+/**
-+ * yt8821_serdes_init() - serdes init
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_serdes_init(struct phy_device *phydev)
-+{
-+ int old_page;
-+ int ret = 0;
-+ u16 mask;
-+ u16 set;
-+
-+ old_page = phy_select_page(phydev, YT8521_RSSR_FIBER_SPACE);
-+ if (old_page < 0) {
-+ phydev_err(phydev, "Failed to select page: %d\n",
-+ old_page);
-+ goto err_restore_page;
-+ }
-+
-+ ret = __phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_SDS_EXT_CSR_VCO_LDO_EN |
-+ YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN;
-+ set = YT8821_SDS_EXT_CSR_VCO_LDO_EN;
-+ ret = ytphy_modify_ext(phydev, YT8821_SDS_EXT_CSR_CTRL_REG, mask,
-+ set);
-+
-+err_restore_page:
-+ return phy_restore_page(phydev, old_page, ret);
-+}
-+
-+/**
-+ * yt8821_utp_init() - utp init
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_utp_init(struct phy_device *phydev)
-+{
-+ int old_page;
-+ int ret = 0;
-+ u16 mask;
-+ u16 save;
-+ u16 set;
-+
-+ old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
-+ if (old_page < 0) {
-+ phydev_err(phydev, "Failed to select page: %d\n",
-+ old_page);
-+ goto err_restore_page;
-+ }
-+
-+ mask = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 |
-+ YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500 |
-+ YT8821_UTP_EXT_RPDN_IPR_SHT_2500;
-+ set = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 |
-+ YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500;
-+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_RPDN_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER |
-+ YT8821_UTP_EXT_VGA_LPF1_CAP_2500;
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG,
-+ mask, 0);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER |
-+ YT8821_UTP_EXT_VGA_LPF2_CAP_2500;
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG,
-+ mask, 0);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500 |
-+ YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500;
-+ set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500, 0x5a) |
-+ FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500, 0x3c);
-+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_TRACE_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_IPR_LNG_2500;
-+ set = FIELD_PREP(YT8821_UTP_EXT_IPR_LNG_2500, 0x6c);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000;
-+ set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000, 0x2a);
-+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_ECHO_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000;
-+ set = FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000, 0x22);
-+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_GAIN_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_TH_20DB_2500;
-+ set = FIELD_PREP(YT8821_UTP_EXT_TH_20DB_2500, 0x8000);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_MU_COARSE_FR_F_FFE |
-+ YT8821_UTP_EXT_MU_COARSE_FR_F_FBE;
-+ set = FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FFE, 0x7) |
-+ FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FBE, 0x7);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_MU_FINE_FR_F_FFE |
-+ YT8821_UTP_EXT_MU_FINE_FR_F_FBE;
-+ set = FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FFE, 0x2) |
-+ FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FBE, 0x2);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ /* save YT8821_UTP_EXT_PI_CTRL_REG's val for use later */
-+ ret = ytphy_read_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ save = ret;
-+
-+ mask = YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE |
-+ YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE |
-+ YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE |
-+ YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE |
-+ YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE;
-+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG,
-+ mask, 0);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ /* restore YT8821_UTP_EXT_PI_CTRL_REG's val */
-+ ret = ytphy_write_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG, save);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_FECHO_AMP_TH_HUGE;
-+ set = FIELD_PREP(YT8821_UTP_EXT_FECHO_AMP_TH_HUGE, 0x38);
-+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_VCT_CFG6_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_NFR_TX_ABILITY;
-+ set = YT8821_UTP_EXT_NFR_TX_ABILITY;
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_PLL_SPARE_CFG;
-+ set = FIELD_PREP(YT8821_UTP_EXT_PLL_SPARE_CFG, 0xe9);
-+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PLL_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG |
-+ YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG;
-+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG, 0x64) |
-+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG, 0x64);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG |
-+ YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG;
-+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG, 0x64) |
-+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG, 0x64);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG |
-+ YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG;
-+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG, 0x64) |
-+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG, 0x64);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG,
-+ mask, set);
-+ if (ret < 0)
-+ goto err_restore_page;
-+
-+ mask = YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG |
-+ YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG;
-+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG, 0x64) |
-+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG, 0x64);
-+ ret = ytphy_modify_ext(phydev,
-+ YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG,
-+ mask, set);
-+
-+err_restore_page:
-+ return phy_restore_page(phydev, old_page, ret);
-+}
-+
-+/**
-+ * yt8821_auto_sleep_config() - phy auto sleep config
-+ * @phydev: a pointer to a &struct phy_device
-+ * @enable: true enable auto sleep, false disable auto sleep
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_auto_sleep_config(struct phy_device *phydev,
-+ bool enable)
-+{
-+ int old_page;
-+ int ret = 0;
-+
-+ old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
-+ if (old_page < 0) {
-+ phydev_err(phydev, "Failed to select page: %d\n",
-+ old_page);
-+ goto err_restore_page;
-+ }
-+
-+ ret = ytphy_modify_ext(phydev,
-+ YT8521_EXTREG_SLEEP_CONTROL1_REG,
-+ YT8521_ESC1R_SLEEP_SW,
-+ enable ? 1 : 0);
-+
-+err_restore_page:
-+ return phy_restore_page(phydev, old_page, ret);
-+}
-+
-+/**
-+ * yt8821_soft_reset() - soft reset utp and serdes
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_soft_reset(struct phy_device *phydev)
-+{
-+ return ytphy_modify_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG,
-+ YT8521_CCR_SW_RST, 0);
-+}
-+
-+/**
-+ * yt8821_config_init() - phy initializatioin
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_config_init(struct phy_device *phydev)
-+{
-+ u8 mode = YT8821_CHIP_MODE_AUTO_BX2500_SGMII;
-+ int ret;
-+ u16 set;
-+
-+ if (phydev->interface == PHY_INTERFACE_MODE_2500BASEX)
-+ mode = YT8821_CHIP_MODE_FORCE_BX2500;
-+
-+ set = FIELD_PREP(YT8521_CCR_MODE_SEL_MASK, mode);
-+ ret = ytphy_modify_ext_with_lock(phydev,
-+ YT8521_CHIP_CONFIG_REG,
-+ YT8521_CCR_MODE_SEL_MASK,
-+ set);
-+ if (ret < 0)
-+ return ret;
-+
-+ __set_bit(PHY_INTERFACE_MODE_2500BASEX,
-+ phydev->possible_interfaces);
-+
-+ if (mode == YT8821_CHIP_MODE_AUTO_BX2500_SGMII) {
-+ __set_bit(PHY_INTERFACE_MODE_SGMII,
-+ phydev->possible_interfaces);
-+
-+ phydev->rate_matching = RATE_MATCH_NONE;
-+ } else if (mode == YT8821_CHIP_MODE_FORCE_BX2500) {
-+ phydev->rate_matching = RATE_MATCH_PAUSE;
-+ }
-+
-+ ret = yt8821_serdes_init(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = yt8821_utp_init(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* disable auto sleep */
-+ ret = yt8821_auto_sleep_config(phydev, false);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* soft reset */
-+ return yt8821_soft_reset(phydev);
-+}
-+
-+/**
-+ * yt8821_adjust_status() - update speed and duplex to phydev
-+ * @phydev: a pointer to a &struct phy_device
-+ * @val: read from YTPHY_SPECIFIC_STATUS_REG
-+ */
-+static void yt8821_adjust_status(struct phy_device *phydev, int val)
-+{
-+ int speed, duplex;
-+ int speed_mode;
-+
-+ duplex = FIELD_GET(YTPHY_SSR_DUPLEX, val);
-+ speed_mode = val & YTPHY_SSR_SPEED_MASK;
-+ switch (speed_mode) {
-+ case YTPHY_SSR_SPEED_10M:
-+ speed = SPEED_10;
-+ break;
-+ case YTPHY_SSR_SPEED_100M:
-+ speed = SPEED_100;
-+ break;
-+ case YTPHY_SSR_SPEED_1000M:
-+ speed = SPEED_1000;
-+ break;
-+ case YTPHY_SSR_SPEED_2500M:
-+ speed = SPEED_2500;
-+ break;
-+ default:
-+ speed = SPEED_UNKNOWN;
-+ break;
-+ }
-+
-+ phydev->speed = speed;
-+ phydev->duplex = duplex;
-+}
-+
-+/**
-+ * yt8821_update_interface() - update interface per current speed
-+ * @phydev: a pointer to a &struct phy_device
-+ */
-+static void yt8821_update_interface(struct phy_device *phydev)
-+{
-+ if (!phydev->link)
-+ return;
-+
-+ switch (phydev->speed) {
-+ case SPEED_2500:
-+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-+ break;
-+ case SPEED_1000:
-+ case SPEED_100:
-+ case SPEED_10:
-+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
-+ break;
-+ default:
-+ phydev_warn(phydev, "phy speed err :%d\n", phydev->speed);
-+ break;
-+ }
-+}
-+
-+/**
-+ * yt8821_read_status() - determines the negotiated speed and duplex
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_read_status(struct phy_device *phydev)
-+{
-+ int link;
-+ int ret;
-+ int val;
-+
-+ ret = ytphy_write_ext_with_lock(phydev,
-+ YT8521_REG_SPACE_SELECT_REG,
-+ YT8521_RSSR_UTP_SPACE);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = genphy_read_status(phydev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (phydev->autoneg_complete) {
-+ ret = genphy_c45_read_lpa(phydev);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ ret = phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
-+ if (ret < 0)
-+ return ret;
-+
-+ val = ret;
-+
-+ link = val & YTPHY_SSR_LINK;
-+ if (link)
-+ yt8821_adjust_status(phydev, val);
-+
-+ if (link) {
-+ if (phydev->link == 0)
-+ phydev_dbg(phydev,
-+ "%s, phy addr: %d, link up\n",
-+ __func__, phydev->mdio.addr);
-+ phydev->link = 1;
-+ } else {
-+ if (phydev->link == 1)
-+ phydev_dbg(phydev,
-+ "%s, phy addr: %d, link down\n",
-+ __func__, phydev->mdio.addr);
-+ phydev->link = 0;
-+ }
-+
-+ val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
-+ if (val < 0)
-+ return val;
-+
-+ if (FIELD_GET(YT8521_CCR_MODE_SEL_MASK, val) ==
-+ YT8821_CHIP_MODE_AUTO_BX2500_SGMII)
-+ yt8821_update_interface(phydev);
-+
-+ return 0;
-+}
-+
-+/**
-+ * yt8821_modify_utp_fiber_bmcr - bits modify a PHY's BMCR register
-+ * @phydev: the phy_device struct
-+ * @mask: bit mask of bits to clear
-+ * @set: bit mask of bits to set
-+ *
-+ * NOTE: Convenience function which allows a PHY's BMCR register to be
-+ * modified as new register value = (old register value & ~mask) | set.
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_modify_utp_fiber_bmcr(struct phy_device *phydev,
-+ u16 mask, u16 set)
-+{
-+ int ret;
-+
-+ ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_UTP_SPACE,
-+ mask, set);
-+ if (ret < 0)
-+ return ret;
-+
-+ return yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_FIBER_SPACE,
-+ mask, set);
-+}
-+
-+/**
-+ * yt8821_suspend() - suspend the hardware
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_suspend(struct phy_device *phydev)
-+{
-+ int wol_config;
-+
-+ wol_config = ytphy_read_ext_with_lock(phydev,
-+ YTPHY_WOL_CONFIG_REG);
-+ if (wol_config < 0)
-+ return wol_config;
-+
-+ /* if wol enable, do nothing */
-+ if (wol_config & YTPHY_WCR_ENABLE)
-+ return 0;
-+
-+ return yt8821_modify_utp_fiber_bmcr(phydev, 0, BMCR_PDOWN);
-+}
-+
-+/**
-+ * yt8821_resume() - resume the hardware
-+ * @phydev: a pointer to a &struct phy_device
-+ *
-+ * Returns: 0 or negative errno code
-+ */
-+static int yt8821_resume(struct phy_device *phydev)
-+{
-+ int wol_config;
-+ int ret;
-+
-+ /* disable auto sleep */
-+ ret = yt8821_auto_sleep_config(phydev, false);
-+ if (ret < 0)
-+ return ret;
-+
-+ wol_config = ytphy_read_ext_with_lock(phydev,
-+ YTPHY_WOL_CONFIG_REG);
-+ if (wol_config < 0)
-+ return wol_config;
-+
-+ /* if wol enable, do nothing */
-+ if (wol_config & YTPHY_WCR_ENABLE)
-+ return 0;
-+
-+ return yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
-+}
-+
- static struct phy_driver motorcomm_phy_drvs[] = {
- {
- PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
-@@ -2305,11 +2950,28 @@ static struct phy_driver motorcomm_phy_d
- .suspend = yt8521_suspend,
- .resume = yt8521_resume,
- },
-+ {
-+ PHY_ID_MATCH_EXACT(PHY_ID_YT8821),
-+ .name = "YT8821 2.5Gbps PHY",
-+ .get_features = yt8821_get_features,
-+ .read_page = yt8521_read_page,
-+ .write_page = yt8521_write_page,
-+ .get_wol = ytphy_get_wol,
-+ .set_wol = ytphy_set_wol,
-+ .config_aneg = genphy_config_aneg,
-+ .aneg_done = yt8821_aneg_done,
-+ .config_init = yt8821_config_init,
-+ .get_rate_matching = yt8821_get_rate_matching,
-+ .read_status = yt8821_read_status,
-+ .soft_reset = yt8821_soft_reset,
-+ .suspend = yt8821_suspend,
-+ .resume = yt8821_resume,
-+ },
- };
-
- module_phy_driver(motorcomm_phy_drvs);
-
--MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver");
-+MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/8821 PHY driver");
- MODULE_AUTHOR("Peter Geis");
- MODULE_AUTHOR("Frank");
- MODULE_LICENSE("GPL");
-@@ -2319,6 +2981,7 @@ static const struct mdio_device_id __may
- { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
- { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },
- { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
-+ { PHY_ID_MATCH_EXACT(PHY_ID_YT8821) },
- { /* sentinel */ }
- };
-