From nobody Thu Sep 24 12:53:02 2026 Received: from out28-197.mail.aliyun.com (out28-197.mail.aliyun.com [115.124.28.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 43EF643B3D8; Thu, 24 Sep 2026 07:51:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790236267; cv=none; b=ufKR40Sqvr9ioBalw73EBy6cHoih1tOTEMHiR15eiqANl5jXV4Twa2FRTrsw6+jUjl6EtKVgjseb0LKRMWiXtozQyhcXLTIKlt+xCVJk0HS2anss4L7d8Q3AXZCrKMwD5fqaCrJdlmZkE3H6o+lTsdcfD5nUXaLgevfyEiCaHwc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790236267; c=relaxed/simple; bh=QLjEfsr7PR7u6X/5MtL/X4oP6WsRpLPR1KfJyXZB7Bo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YYNDieqDS0yGUtjxg5gwmgmxZ4o8OwFOzq6eswGHAT9YB0P4scan2Qwz6j6yTgl9SuG/PdyTe6ZffWcwZi9YniFKmS/i0v5D2BdIGLOq7WD1pLiwfHvJFaeVLdOgEgCaJ/SWPu6bud/kc/L7HhHzwGmNt8TvVvsugL3I2gzCeq4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=motor-comm.com; spf=pass smtp.mailfrom=motor-comm.com; arc=none smtp.client-ip=115.124.28.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=motor-comm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=motor-comm.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07249854|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_regular_dialog|0.04611-0.00409288-0.949797;FP=16348516055955080369|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033037032089;MF=kyle.switch@motor-comm.com;NM=1;PH=DS;RN=19;RT=19;SR=0;TI=SMTPD_---.jM7IE1._1790236254; Received: from motor-comm.com(mailfrom:kyle.switch@motor-comm.com fp:SMTPD_---.jM7IE1._1790236254 cluster:ay29) by smtp.aliyun-inc.com; Thu, 24 Sep 2026 15:50:54 +0800 From: Kyle Switch To: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, Frank.Sae@motor-comm.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: ming.xu@motor-comm.com, xiaolin.xu@motor-comm.com, jianmin.wang@motor-comm.com, jie.han@motor-comm.com Subject: [PATCH net-next v21 1/3] dt-bindings: net: Document Motorcomm YT8824 PHY package Date: Thu, 24 Sep 2026 15:50:46 +0800 Message-Id: <20260924075048.4060414-2-kyle.switch@motor-comm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260924075048.4060414-1-kyle.switch@motor-comm.com> References: <20260924075048.4060414-1-kyle.switch@motor-comm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Motorcomm YT8824 Ethernet PHY is PHY package of 4 PHY-s. Signed-off-by: Kyle Switch --- .../bindings/net/motorcomm,yt8824.yaml | 69 +++++++++++++++++++ MAINTAINERS | 2 + 2 files changed, 71 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/motorcomm,yt8824.= yaml diff --git a/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml b/= Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml new file mode 100644 index 000000000000..fd62b309e7ff --- /dev/null +++ b/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/motorcomm,yt8824.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MotorComm YT8824 Ethernet PHY + +maintainers: + - Kyle Switch + +description: + Motorcomm YT8824 Ethernet PHY is a PHY package of 4 PHYs. + +$ref: ethernet-phy-package.yaml# + +properties: + compatible: + enum: + - motorcomm,yt8824-package + phy-mode: + $ref: /schemas/types.yaml#/definitions/string + enum: [ internal, 10g-qxgmii ] + reg: + description: + The absolute MDIO address of the YT8824 shared top extend + register block. + For internal mode, this is fixed at 9; + For external mode it is (base MDIO address of the four + member PHYs) + 4. + Note that this is NOT the base ID of the first member PHY. +required: + - compatible + - phy-mode + - reg + +unevaluatedProperties: false + +examples: + - | + mdio { + #address-cells =3D <1>; + #size-cells =3D <0>; + + ethernet-phy-package@9 { + #address-cells =3D <1>; + #size-cells =3D <0>; + compatible =3D "motorcomm,yt8824-package"; + reg =3D <9>; + + phy-mode =3D "internal"; + + ethernet-phy@4 { + reg =3D <4>; + }; + + ethernet-phy@5 { + reg =3D <5>; + }; + + ethernet-phy@6 { + reg =3D <6>; + }; + + ethernet-phy@7 { + reg =3D <7>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e3ce77c839b0..ed7af1bd9521 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18409,8 +18409,10 @@ F: drivers/net/ethernet/stmicro/stmmac/dwmac-motor= comm.c =20 MOTORCOMM PHY DRIVER M: Frank +M: Kyle Switch L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml F: Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml F: drivers/net/phy/motorcomm.c =20 --=20 2.25.1 From nobody Thu Sep 24 12:53:02 2026 Received: from out28-196.mail.aliyun.com (out28-196.mail.aliyun.com [115.124.28.196]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB26641F5CA; Thu, 24 Sep 2026 07:51:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.196 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790236266; cv=none; b=GIMaFxDFa/snGu00tuRrAWw7XR7lpB6wvk4V5hzpPA/PE+scj97Kok/WpNrj7HdMm1HMG8Y1dMnobDaYWoxJJUkiCi8XiH4YRZNfpQptG4Aj0MVlhqHRNzcq7UNLP9iQ9dwJ0DC2ZooTd+UD7Bbil2Isp7Uo0YV+SOc87xvJg1g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790236266; c=relaxed/simple; bh=JNmDqQEsqaS3LQl7YieCN8X6JrPQ2zp01edgGMu334g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SOzUYw86xAcAK+QvAHzHEXwizvdbCCtKsac0obvO516htrkBZevlug1qinJImWjSOx2ZOOybGNjiqGwb8Ww00Ew7uggYbK1Aeexa3tJ6cUAqcjexbpPsemyZb8UtqnTMtS7n54rWLNFPchVC1sxfVO6By6Xmut2WzqIeqyZuB8E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=motor-comm.com; spf=pass smtp.mailfrom=motor-comm.com; arc=none smtp.client-ip=115.124.28.196 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=motor-comm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=motor-comm.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.06741586|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.316453-0.0542113-0.629336;FP=13581216796948058038|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033037071049;MF=kyle.switch@motor-comm.com;NM=1;PH=DS;RN=19;RT=19;SR=0;TI=SMTPD_---.jM7IE2D_1790236255; Received: from motor-comm.com(mailfrom:kyle.switch@motor-comm.com fp:SMTPD_---.jM7IE2D_1790236255 cluster:ay29) by smtp.aliyun-inc.com; Thu, 24 Sep 2026 15:50:55 +0800 From: Kyle Switch To: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, Frank.Sae@motor-comm.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: ming.xu@motor-comm.com, xiaolin.xu@motor-comm.com, jianmin.wang@motor-comm.com, jie.han@motor-comm.com Subject: [PATCH net-next v21 2/3] net: phy: Add support for Template Control register for PMA Date: Thu, 24 Sep 2026 15:50:47 +0800 Message-Id: <20260924075048.4060414-3-kyle.switch@motor-comm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260924075048.4060414-1-kyle.switch@motor-comm.com> References: <20260924075048.4060414-1-kyle.switch@motor-comm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for the 10GBASE-T PMA Template Test Mode register field, which allows selecting one of eight test modes (Normal and TestMode1..TestMode7) used for PHY validation. Signed-off-by: Kyle Switch --- drivers/net/phy/phy-c45.c | 23 +++++++++++++++++++++++ include/linux/phy.h | 1 + include/uapi/linux/mdio.h | 12 ++++++++++++ 3 files changed, 36 insertions(+) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 870920311f9a..c5f5753f7194 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1408,6 +1408,29 @@ int genphy_c45_fast_retrain(struct phy_device *phyde= v, bool enable) } EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain); =20 +/** + * genphy_c45_template_testmode - configure template testmode registers + * @phydev: target phy_device struct + * @test_mode: testmode includes Normal to Test mode 7 + * + * Description: Set template testmode include Normal to Test mode 7 + * + * Return: 0 on success, or a negative error code on failure (e.g. register + * read/write error). + */ +int genphy_c45_template_testmode(struct phy_device *phydev, u16 test_mode) +{ + u16 ctrl; + + if (test_mode > MDIO_PMA_10GBT_TESTMODE_7) + return -EOPNOTSUPP; + + ctrl =3D FIELD_PREP(MDIO_PMA_10GBT_TESTMODE_MASK, test_mode); + return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TESTMODE, + MDIO_PMA_10GBT_TESTMODE_MASK, ctrl); +} +EXPORT_SYMBOL_GPL(genphy_c45_template_testmode); + /** * genphy_c45_plca_get_cfg - get PLCA configuration from standard registers * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index 7c5098a0dd6c..b9dee2655e6b 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -2357,6 +2357,7 @@ int genphy_c45_loopback(struct phy_device *phydev, bo= ol enable, int speed); int genphy_c45_pma_resume(struct phy_device *phydev); int genphy_c45_pma_suspend(struct phy_device *phydev); int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable); +int genphy_c45_template_testmode(struct phy_device *phydev, u16 test_mode); int genphy_c45_plca_get_cfg(struct phy_device *phydev, struct phy_plca_cfg *plca_cfg); int genphy_c45_plca_set_cfg(struct phy_device *phydev, diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index 06f4bc3c20c7..353ca13c64fc 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -63,6 +63,7 @@ /* Media-dependent registers. */ #define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */ #define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ +#define MDIO_PMA_10GBT_TESTMODE 132 /* Test mode control */ #define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A. * Lanes B-D are numbered 134-136. */ #define MDIO_PMA_10GBR_FSRT_CSR 147 /* 10GBASE-R fast retrain status and c= ontrol */ @@ -320,6 +321,17 @@ /* PMA 10GBASE-R Fast Retrain status and control register. */ #define MDIO_PMA_10GBR_FSRT_ENABLE 0x0001 /* Fast retrain enable */ =20 +/* PMA 10GBASE-T Template Test Mode Register*/ +#define MDIO_PMA_10GBT_TESTMODE_MASK GENMASK(15, 13) /* Template test mode= */ +#define MDIO_PMA_10GBT_TESTMODE_NORMAL 0x0 /* Template Normal */ +#define MDIO_PMA_10GBT_TESTMODE_1 0x1 /* Template TestMode1 */ +#define MDIO_PMA_10GBT_TESTMODE_2 0x2 /* Template TestMode2 */ +#define MDIO_PMA_10GBT_TESTMODE_3 0x3 /* Template TestMode3 */ +#define MDIO_PMA_10GBT_TESTMODE_4 0x4 /* Template TestMode4 */ +#define MDIO_PMA_10GBT_TESTMODE_5 0x5 /* Template TestMode5 */ +#define MDIO_PMA_10GBT_TESTMODE_6 0x6 /* Template TestMode6 */ +#define MDIO_PMA_10GBT_TESTMODE_7 0x7 /* Template TestMode7 */ + /* PCS 10GBASE-R/-T status register 1. */ #define MDIO_PCS_10GBRT_STAT1_BLKLK 0x0001 /* Block lock attained */ =20 --=20 2.25.1 From nobody Thu Sep 24 12:53:02 2026 Received: from out198-23.us.a.mail.aliyun.com (out198-23.us.a.mail.aliyun.com [47.90.198.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6EFDB43BDC8; Thu, 24 Sep 2026 07:51:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=47.90.198.23 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790236280; cv=none; b=UZ4sy1rKKdCbbzeIAWbQ4tWIJYuNvqteNug5KUvMZz5bcK0MOf/wJNw0oupXfzkRJTwP5J46RIzB+vc7MiKNIRVb8Xx1pefM1gasY25zDglzVxa6qUzAOBFGGRPgaacEsHOE81yZsuceftKlYn3esIgr3F0YyPSeO0WU3EnYjy4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790236280; c=relaxed/simple; bh=Ann3kQ3xBkxAvgOdbfG3PsDRuxxLtvH6C1t0efxi0TA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Sjn+L0npfBTzM3vM7AdW//oz1Um5Xa0zKFAcazbq7z6gmktIcM3bOg0l2Do8Gb86+U0OeJKoN77Qi2wfK1nYfVGIuiG5WTUbxAZt9D1qXYBY3BmSPaTCYjH8FZ+afbiwVtg0qimHk2wNv1YGfJ8sqw75SCRba+XlftVceDVB7AI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=motor-comm.com; spf=pass smtp.mailfrom=motor-comm.com; arc=none smtp.client-ip=47.90.198.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=motor-comm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=motor-comm.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.06712908|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.0108436-0.15722-0.831936;FP=16911401953898548466|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033037021217;MF=kyle.switch@motor-comm.com;NM=1;PH=DS;RN=19;RT=19;SR=0;TI=SMTPD_---.jM7IE3i_1790236255; Received: from motor-comm.com(mailfrom:kyle.switch@motor-comm.com fp:SMTPD_---.jM7IE3i_1790236255 cluster:ay29) by smtp.aliyun-inc.com; Thu, 24 Sep 2026 15:50:56 +0800 From: Kyle Switch To: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk, Frank.Sae@motor-comm.com, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: ming.xu@motor-comm.com, xiaolin.xu@motor-comm.com, jianmin.wang@motor-comm.com, jie.han@motor-comm.com Subject: [PATCH net-next v21 3/3] net: phy: Add driver for Motorcomm Quad 2.5GbE phy Date: Thu, 24 Sep 2026 15:50:48 +0800 Message-Id: <20260924075048.4060414-4-kyle.switch@motor-comm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260924075048.4060414-1-kyle.switch@motor-comm.com> References: <20260924075048.4060414-1-kyle.switch@motor-comm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Motorcomm YT8824 quad-port 2.5G PHY to the existing motorcomm driver, using the phy_package helpers for the shared top extended register space. Signed-off-by: Kyle Switch --- drivers/net/phy/Kconfig | 3 +- drivers/net/phy/motorcomm.c | 1585 ++++++++++++++++++++++++++++++++++- 2 files changed, 1585 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d3835597e379..996d75afed44 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -361,9 +361,10 @@ config MICROSEMI_PHY =20 config MOTORCOMM_PHY tristate "Motorcomm PHYs" + select PHY_PACKAGE help Enables support for Motorcomm network PHYs. - Currently supports YT85xx Gigabit Ethernet PHYs. + Currently supports YT85xx Gigabit Ethernet PHYs and YT8824 4 * 2.5G PHY. =20 config NATIONAL_PHY tristate "National Semiconductor PHYs" diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 90a4f86f2758..c89ffb00e55e 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1,24 +1,31 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Motorcomm 8511/8521/8522/8531/8531S/8821 PHY driver. + * Motorcomm 8511/8521/8522/8531/8531S/8821/8824 PHY driver. * * Author: Peter Geis * Author: Frank + * Author: Kyle */ =20 #include #include #include +#include #include +#include +#include #include #include =20 +#include "phylib.h" + #define PHY_ID_YT8511 0x0000010a #define PHY_ID_YT8521 0x0000011a #define PHY_ID_YT8522 0x4f51e928 #define PHY_ID_YT8531 0x4f51e91b #define PHY_ID_YT8531S 0x4f51e91a #define PHY_ID_YT8821 0x4f51ea19 +#define PHY_ID_YT8824 0x4f51e8b8 /* YT8521/YT8531S/YT8821 Register Overview * UTP Register space | FIBER Register space * ------------------------------------------------------------ @@ -30,6 +37,18 @@ * ------------------------------------------------------------ */ =20 +/* YT8824 Register Overview + * UTP Register space | SERDES Register space + * ------------------------------------------------------------ + * | UTP MII | SERDES MII | + * | UTP MMD | | + * | UTP Extended | SERDES Extended | + * | UTP Top Extended | SERDES Top Extended | + * ------------------------------------------------------------ + * | Common Top Extended | + * ------------------------------------------------------------ + */ + /* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */ =20 /* Specific Function Control Register */ @@ -381,6 +400,13 @@ #define YT8821_CHIP_MODE_AUTO_BX2500_SGMII 0 #define YT8821_CHIP_MODE_FORCE_BX2500 1 =20 +#define YT8824_RSSR_SPACE_MASK BIT(0) +#define YT8824_RSSR_SERDES_SPACE (0x1) +#define YT8824_RSSR_UTP_SPACE (0x0) +#define YT8824_SDS_CFG_MIN_PRE_MASK GENMASK(3, 0) +#define YT8824_SDS_EN_FILL_PRE BIT(13) +#define YT8824_SDS_TX_PRE_PADDING (0x7) + 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 @@ -399,6 +425,12 @@ struct yt8521_priv { u8 reg_page; }; =20 +struct yt8824_shared_priv { + phy_interface_t interface_mode; + /* shared_lock used to UTPs operation isolation during swap reg space */ + struct mutex shared_lock; +}; + /** * ytphy_read_ext() - read a PHY's extended register * @phydev: a pointer to a &struct phy_device @@ -437,6 +469,70 @@ static int ytphy_read_ext_with_lock(struct phy_device = *phydev, u16 regnum) return ret; } =20 +/** + * ytphy_read_top_ext() - read a PHY's top extended register for YT8824 + * @phydev: a pointer to a &struct phy_device + * @regnum: register number to read + * + * Returns: the value of regnum reg or negative error code + */ +static int ytphy_read_top_ext(struct phy_device *phydev, u16 regnum) +{ + int ret; + + lockdep_assert_held(&phydev->mdio.bus->mdio_lock); + ret =3D __phy_package_write(phydev, 0, YTPHY_PAGE_SELECT, regnum); + if (ret < 0) + return ret; + + return __phy_package_read(phydev, 0, YTPHY_PAGE_DATA); +} + +/** + * ytphy_write_top_ext() - write a PHY's top extended register for YT8824 + * @phydev: a pointer to a &struct phy_device + * @regnum: register number to write + * @val: register val to write + * + * Returns: 0 or negative error code + */ +static int ytphy_write_top_ext(struct phy_device *phydev, u16 regnum, + u16 val) +{ + int ret; + + lockdep_assert_held(&phydev->mdio.bus->mdio_lock); + ret =3D __phy_package_write(phydev, 0, YTPHY_PAGE_SELECT, regnum); + if (ret < 0) + return ret; + + return __phy_package_write(phydev, 0, YTPHY_PAGE_DATA, val); +} + +/** + * phy8824_page_write_with_lock() - write page for YT8824 + * @phydev: a pointer to a &struct phy_device + * @page: reg page(YT8824_RSSR_SERDES_SPACE/YT8824_RSSR_UTP_SPACE). + * + * Returns: 0 or negative error code + */ +static int phy8824_page_write_with_lock(struct phy_device *phydev, int pag= e) +{ + int ret; + + phy_lock_mdio_bus(phydev); + ret =3D ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG); + if (ret < 0) + goto err; + ret &=3D ~YT8824_RSSR_SPACE_MASK; + ret |=3D (page & YT8824_RSSR_SPACE_MASK); + ret =3D ytphy_write_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG, ret); + +err: + phy_unlock_mdio_bus(phydev); + return ret; +} + /** * ytphy_write_ext() - write a PHY's extended register * @phydev: a pointer to a &struct phy_device @@ -633,6 +729,1036 @@ static int ytphy_set_wol(struct phy_device *phydev, = struct ethtool_wolinfo *wol) return phy_restore_page(phydev, old_page, ret); } =20 +/** + * yt8824_read_page() - read PHY8824 reg page + * @phydev: a pointer to a &struct phy_device + * + * Returns: current reg space of yt8824 (YT8824_RSSR_SERDES_SPACE/ + * YT8824_RSSR_UTP_SPACE) or negative errno code + */ +static int yt8824_read_page(struct phy_device *phydev) +{ + int old_page; + + old_page =3D ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG); + if (old_page < 0) + return old_page; + + return old_page & YT8824_RSSR_SPACE_MASK; +}; + +/** + * yt8824_write_page() - write reg page + * @phydev: a pointer to a &struct phy_device + * @page: Reg page(YT8824_RSSR_SERDES_SPACE/YT8824_RSSR_UTP_SPACE) to writ= e. + * + * Returns: 0 or negative errno code + */ +static int yt8824_write_page(struct phy_device *phydev, int page) +{ + int old_page; + u16 data; + + old_page =3D ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG); + if (old_page < 0) + return old_page; + data =3D old_page & (~YT8824_RSSR_SPACE_MASK); + data |=3D page; + + return ytphy_write_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG, data); +}; + +/** + * yt8824_utp_set_template_test_mode() - config YT8824 UTP test mode. + * @phydev: a pointer to a &struct phy_device + * @test_mode: template test mode from normal, testmode1 to testmode7 + * + * Returns: 0 or negative errno code + */ +static int yt8824_utp_set_template_test_mode(struct phy_device *phydev, + u16 test_mode) +{ + int ret; + + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + return ret; + + return genphy_c45_template_testmode(phydev, test_mode); +} + +/** + * yt8824_sds_isolate_paged() - enable YT8824 serdes isolate. + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_sds_isolate_paged(struct phy_device *phydev) +{ + int old_page =3D YT8824_RSSR_UTP_SPACE; + int ret =3D 0; + + old_page =3D phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE); + if (old_page < 0) + goto err_restore_page; + + /* enable sds isolate */ + ret =3D __phy_modify(phydev, MII_BMCR, BMCR_ISOLATE, BMCR_ISOLATE); + +err_restore_page: + /* restore page, release the lock */ + return phy_restore_page(phydev, old_page, ret); +} + +/** + * yt8824_utp_softreset_paged() - config YT8824 UTP softreset. + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_utp_softreset_paged(struct phy_device *phydev) +{ + int ret =3D 0; + int val; + + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + return ret; + ret =3D phy_modify(phydev, MII_BMCR, BMCR_RESET, BMCR_RESET); + if (ret < 0) + return ret; + /* wait until softreset done. */ + return phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), + 50000, 600000, true); +} + +/** + * yt8824_sds_isolate_and_softreset_paged() - disable YT8824 serdes isolate + * and sds softreset. + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_sds_isolate_and_softreset_paged(struct phy_device *phyde= v) +{ + int old_page =3D YT8824_RSSR_UTP_SPACE; + int val =3D 0; + int ret =3D -1; + + old_page =3D phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE); + if (old_page < 0) + goto err_restore_page; + + /* sds softreset and disable isolate */ + ret =3D __phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ISOLATE, + BMCR_RESET & ~BMCR_ISOLATE); + if (ret < 0) + goto err_restore_page; + + /* poll while still holding the lock */ + ret =3D read_poll_timeout(__phy_read, val, + (val < 0) || !(val & BMCR_RESET), 50000, 600000, + true, phydev, MII_BMCR); + if (val < 0) + ret =3D val; + +err_restore_page: + /* restore page, release the lock */ + return phy_restore_page(phydev, old_page, ret); +} + +/** + * yt8824_restore_working_status() - called to do store working status + * @phydev: a pointer to a &struct phy_device + * @ret: operation's return code + * + * Returns: 0 or negative errno code + */ +static int yt8824_restore_working_status(struct phy_device *phydev, int re= t) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int r; + + /* configure normal test mode */ + r =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret >=3D 0 && r < 0) + ret =3D r; + if (priv->interface_mode !=3D PHY_INTERFACE_MODE_INTERNAL) { + /* sds soft reset and disable isolation */ + r =3D yt8824_sds_isolate_and_softreset_paged(phydev); + if (ret >=3D 0 && r < 0) + ret =3D r; + } + + return ret; +} + +/** + * yt8824_soft_reset() - called to do PHY software reset + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_soft_reset(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + + mutex_lock(&priv->shared_lock); + if (priv->interface_mode =3D=3D PHY_INTERFACE_MODE_INTERNAL) { + /* test mode 1 */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret < 0) + goto retry; + ret =3D yt8824_utp_softreset_paged(phydev); + if (ret < 0) + goto retry; + /* normal mode */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto retry; + } else { + /* test mode 1 */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret < 0) + goto retry; + + /* sds isolation */ + ret =3D yt8824_sds_isolate_paged(phydev); + if (ret < 0) + goto retry; + + /* utp soft reset */ + ret =3D yt8824_utp_softreset_paged(phydev); + if (ret < 0) + goto retry; + + /* normal mode */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto retry; + + /* sds soft reset and disable isolation */ + ret =3D yt8824_sds_isolate_and_softreset_paged(phydev); + if (ret < 0) + goto retry; + } + mutex_unlock(&priv->shared_lock); + return ret; +retry: + ret =3D yt8824_restore_working_status(phydev, ret); + mutex_unlock(&priv->shared_lock); + + return ret; +} + +/** + * yt8824_extern_config_utp_init_paged() - config external phy8824 utp init + * @phydev: target phy_device struct + * + * Returns: 0 or negative errno code + */ +static int yt8824_extern_config_utp_init_paged(struct phy_device *phydev) +{ + int ret =3D 0; + int val =3D 0; + int r; + + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + return ret; + /* power down */ + ret =3D phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN); + if (ret < 0) + goto err_restore; + + /* pll calibration */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x0001, 0x0003); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa20e, 0x0cba); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa20a, 0xc3f1); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa20c, 0x1620); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2b6, 0x0a00); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2b6, 0x0e00); + if (ret < 0) + goto err_restore; + + /* optimization utp */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x0001, 0x0003); + if (ret < 0) + goto err_restore; + + /* enable nibble */ + ret =3D ytphy_write_ext_with_lock(phydev, 0xa003, 0x0003); + if (ret < 0) + goto err_restore; + + /* idle err detect enable */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x03d0, 0x5210); + if (ret < 0) + goto err_restore; + + /* optimized 2.5G long cable performance */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x0372, 0x5038); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x037c, 0x6068); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0388, 0x00a0); + if (ret < 0) + goto err_restore; + + /* optimized fast retrain */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x0359, 0x2140); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x000c, 0xc1a0); + if (ret < 0) + goto err_restore; + + /* 2.5G template tone */ + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2fa, 0x0083); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x04e2, 0x0149); + if (ret < 0) + goto err_restore; + + /* optimized 2.5G template */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x047e, 0x3939); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x047f, 0x3939); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0480, 0x3939); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0481, 0x3939); + if (ret < 0) + goto err_restore; + + /* optimized 1000M cable length threshold */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x0336, 0xab0a); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0340, 0x301d); + if (ret < 0) + goto err_restore; + + /* 100M template amplitude */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x046e, 0x4545); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x046f, 0x4545); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0470, 0x4545); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0471, 0x4545); + if (ret < 0) + goto err_restore; + + /* optimized 100M cable length threshold */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x030b, 0xaa1d); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x071f, 0x0036); + if (ret < 0) + goto err_restore; + + /* 10M template amplitude */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x046b, 0x1818); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x046c, 0x1818); + if (ret < 0) + goto err_restore; + + /* optimized 10M cable length threshold */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x0466, 0x6c6c); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0467, 0x6c6c); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0468, 0x6c6c); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0469, 0x6c6c); + if (ret < 0) + goto err_restore; + + /* optimize utp 1000M performance */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x034a, 0xff03); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x00f8, 0xb3ff); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0059, 0x4040); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x032c, 0x5094); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x032d, 0xd094); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x032e, 0x5308); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x0322, 0x6440); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x04d3, 0x5220); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x04d2, 0x5220); + if (ret < 0) + goto err_restore; + + /* optimized EMC CS */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x00c8, 0xffff); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x00be, 0x6406); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x037a, 0x40ff); + if (ret < 0) + goto err_restore; + + /* optimized EMC RE */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x0482, 0xffff); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d5, 0x1f1f); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d6, 0x1f1f); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d7, 0x1f1f); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d8, 0x1f1f); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa218, 0x006e); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01d, 0xfff0); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01e, 0xfff0); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01d, 0xffff); + if (ret < 0) + goto err_restore; + + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01e, 0xffff); + if (ret < 0) + goto err_restore; + + ret =3D genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret < 0) + goto err_restore_normal; + /* reset */ + ret =3D phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE, + BMCR_RESET | BMCR_ANENABLE); + if (ret < 0) + goto err_restore_normal; + ret =3D phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), + 50000, 600000, true); + if (ret < 0) + goto err_restore_normal; + + ret =3D genphy_c45_template_testmode(phydev, + MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto err_restore_normal; + return 0; + +err_restore: + r =3D phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0); + if (ret >=3D 0 && r < 0) + ret =3D r; + return ret; + +err_restore_normal: + r =3D genphy_c45_template_testmode(phydev, + MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret >=3D 0 && r < 0) + ret =3D r; + r =3D phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0); + if (ret >=3D 0 && r < 0) + ret =3D r; + return ret; +} + +/** + * yt8824_extern_config_sds_init_paged() - config external phy8824 sds init + * @phydev: target phy_device struct + * + * + * Returns: 0 or negative errno code + */ +static int yt8824_extern_config_sds_init_paged(struct phy_device *phydev) +{ + int old_page =3D YT8824_RSSR_UTP_SPACE; + int val_1, val_2, val_3, tmp; + int ret =3D -1; + int val; + + old_page =3D phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE); + if (old_page < 0) + goto err_restore_page; + + /* read efuse */ + ret =3D ytphy_read_top_ext(phydev, 0xa13e); + if (ret < 0) + goto err_restore_page; + else + val_1 =3D ret; + + ret =3D ytphy_read_top_ext(phydev, 0xa13f); + if (ret < 0) + goto err_restore_page; + else + val_2 =3D ret; + + ret =3D ytphy_read_top_ext(phydev, 0xa140); + if (ret < 0) + goto err_restore_page; + else + val_3 =3D ret; + + /* Serdes optimization */ + ret =3D ytphy_write_ext(phydev, 0x04be, 0x000d); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x049f, 0x7ded); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x04a9, 0x009f); + if (ret < 0) + goto err_restore_page; + + /* analog CDR */ + ret =3D ytphy_write_ext(phydev, 0x0406, 0x0800); + if (ret < 0) + goto err_restore_page; + + /* optimized VCO */ + ret =3D ytphy_write_ext(phydev, 0x0438, 0x9024); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x0439, 0x00c0); + if (ret < 0) + goto err_restore_page; + + /* optimized PLL lock */ + ret =3D ytphy_read_ext(phydev, 0x0429); + if (ret < 0) + goto err_restore_page; + + ret &=3D ~(BIT(13) | BIT(12)); + tmp =3D (val_1 & (BIT(7) | BIT(6))) >> 6; + ret |=3D (tmp << 12); + ret =3D ytphy_write_ext(phydev, 0x0429, ret); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_read_ext(phydev, 0x0441); + if (ret < 0) + goto err_restore_page; + + ret &=3D ~(BIT(1) | BIT(0)); + tmp =3D (val_1 & (BIT(5) | BIT(4))) >> 4; + ret |=3D tmp; + ret =3D ytphy_write_ext(phydev, 0x0441, ret); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_read_ext(phydev, 0x042b); + if (ret < 0) + goto err_restore_page; + + ret &=3D ~(BIT(13) | BIT(12)); + tmp =3D (val_3 & (BIT(1) | BIT(0))); + ret |=3D (tmp << 12); + ret =3D ytphy_write_ext(phydev, 0x042b, ret); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x043a, 0x1006); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x042a, 0xf070); + if (ret < 0) + goto err_restore_page; + + /* cable length threshold */ + ret =3D ytphy_write_ext(phydev, 0x0491, 0x007f); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x0492, 0x7f7f); + if (ret < 0) + goto err_restore_page; + + /* Serdes training threshold */ + ret =3D ytphy_write_ext(phydev, 0x0454, 0x0f14); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x0497, 0x0a44); + if (ret < 0) + goto err_restore_page; + + /* digital eye diagram of SerDes */ + ret =3D ytphy_write_ext(phydev, 0x04cd, 0x0000); + if (ret < 0) + goto err_restore_page; + + /* Serdes LDO */ + ret =3D ytphy_read_ext(phydev, 0x04b5); + if (ret < 0) + goto err_restore_page; + + ret &=3D ~(BIT(6) | BIT(5) | BIT(4)); + tmp =3D (val_2 & (BIT(4) | BIT(3) | BIT(2))) >> 2; + ret |=3D (tmp << 4); + ret =3D ytphy_write_ext(phydev, 0x04b5, ret); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_read_ext(phydev, 0x04b4); + if (ret < 0) + goto err_restore_page; + + ret &=3D ~(BIT(10) | BIT(9) | BIT(8)); + tmp =3D (val_2 & (BIT(7) | BIT(6) | BIT(5))) >> 5; + ret |=3D (tmp << 8); + ret =3D ytphy_write_ext(phydev, 0x04b4, ret); + if (ret < 0) + goto err_restore_page; + + /* optimized Serdes RX */ + ret =3D ytphy_write_ext(phydev, 0x04af, 0x45e3); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x048a, 0x0fff); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x0408, 0x7c00); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x04d6, 0x007f); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x044f, 0xff08); + if (ret < 0) + goto err_restore_page; + + /* optimized Serdes TX */ + ret =3D ytphy_write_ext(phydev, 0x048e, 0x7d00); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x000d, 0x0606); + if (ret < 0) + goto err_restore_page; + + /* Serdes manual config */ + ret =3D ytphy_write_ext(phydev, 0x04b0, 0x0804); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x04b1, 0x7074); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x04af, 0x45e7); + if (ret < 0) + goto err_restore_page; + + /* restart calibration */ + ret =3D ytphy_write_ext(phydev, 0x0003, 0x5603); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x0492, 0x7fff); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x0492, 0x7f7f); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x2000, 0x0040); + if (ret < 0) + goto err_restore_page; + + ret =3D ytphy_write_ext(phydev, 0x2000, 0x0000); + if (ret < 0) + goto err_restore_page; + + /* TX preamble padded to 8; RX IPG always > 8 */ + ret =3D __phy_read(phydev, MII_RESV1); + if (ret < 0) + goto err_restore_page; + ret &=3D ~YT8824_SDS_CFG_MIN_PRE_MASK; + ret |=3D YT8824_SDS_TX_PRE_PADDING; + ret |=3D YT8824_SDS_EN_FILL_PRE; + ret =3D __phy_write(phydev, MII_RESV1, ret); + if (ret < 0) + goto err_restore_page; + /* reset serdes */ + ret =3D __phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE, + BMCR_RESET | BMCR_ANENABLE); + if (ret < 0) + goto err_restore_page; + /* poll while still holding the lock; __phy_read takes no lock */ + ret =3D read_poll_timeout(__phy_read, val, + (val < 0) || !(val & BMCR_RESET), 50000, 600000, + true, phydev, MII_BMCR); + if (val < 0) + ret =3D val; +err_restore_page: + /* restore page, release the lock */ + return phy_restore_page(phydev, old_page, ret); +} + +/** + * yt8824_internal_config_init_paged() - config internal phy8824 init + * @phydev: target phy_device struct + * + * + * Returns: 0 or negative errno code + */ +static int yt8824_internal_config_init_paged(struct phy_device *phydev) +{ + int ret =3D 0; + int val =3D 0; + int r =3D 0; + + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + return ret; + + ret =3D ytphy_write_ext_with_lock(phydev, 0x1, 0x3); + if (ret < 0) + return ret; + /* power down */ + ret =3D phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa20e, 0xcba); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa20a, 0xc3f1); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa20c, 0x1620); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2b6, 0xa00); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2b6, 0xe00); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa003, 0x3); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x3d0, 0x5210); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x372, 0x5038); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x37c, 0x6068); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x388, 0xa0); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x359, 0x2140); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2fa, 0x83); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x4e2, 0x149); + if (ret < 0) + goto err_restore; + /* 2.5G tempate */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x47e, 0x3939); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x47f, 0x3939); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x480, 0x3939); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x481, 0x3939); + if (ret < 0) + goto err_restore; + /* 1000 cable length threshold */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x336, 0xab0a); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x340, 0x301d); + if (ret < 0) + goto err_restore; + /* 1000 performance */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x34a, 0xff03); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xf8, 0xb3ff); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x32c, 0x5094); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x32d, 0xd094); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x32e, 0x5308); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x322, 0x6440); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x4d3, 0x5220); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x4d2, 0x5220); + if (ret < 0) + goto err_restore; + /* 100 tempate */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x46e, 0x4545); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x46f, 0x4545); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x470, 0x4545); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x471, 0x4545); + if (ret < 0) + goto err_restore; + /* 100 cable length threshold */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x30b, 0xaa1d); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x71f, 0x36); + if (ret < 0) + goto err_restore; + /* 10 tempate */ + ret =3D ytphy_write_ext_with_lock(phydev, 0x46b, 0x1818); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x46c, 0x1818); + if (ret < 0) + goto err_restore; + /* 10 tempate MAU*/ + ret =3D ytphy_write_ext_with_lock(phydev, 0x466, 0x6c6c); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x467, 0x6c6c); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x468, 0x6c6c); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x469, 0x6c6c); + if (ret < 0) + goto err_restore; + /* EMC CS, Inconsistent with external phy */ + ret =3D ytphy_write_ext_with_lock(phydev, 0xc8, 0xfff); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xbe, 0x6406); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0x37a, 0x40ff); + if (ret < 0) + goto err_restore; + /* EMC RE*/ + ret =3D ytphy_write_ext_with_lock(phydev, 0x482, 0xffff); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d5, 0x1f1f); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d6, 0x1f1f); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d7, 0x1f1f); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa2d8, 0x1f1f); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa218, 0x6e); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01d, 0xfff0); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01e, 0xfff0); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01d, 0xffff); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xa01e, 0xffff); + if (ret < 0) + goto err_restore; + ret =3D ytphy_write_ext_with_lock(phydev, 0xc, 0x41a1); + if (ret < 0) + goto err_restore; + ret =3D genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret) + goto err_restore_normal; + /* reset */ + ret =3D phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE, + BMCR_RESET | BMCR_ANENABLE); + if (ret < 0) + goto err_restore_normal; + ret =3D phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), + 50000, 600000, true); + if (ret < 0) + goto err_restore_normal; + + ret =3D genphy_c45_template_testmode(phydev, + MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto err_restore_normal; + + return 0; + +err_restore: + r =3D phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0); + if (ret >=3D 0 && r < 0) + ret =3D r; + return ret; + +err_restore_normal: + r =3D genphy_c45_template_testmode(phydev, + MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret >=3D 0 && r < 0) + ret =3D r; + r =3D phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0); + if (ret >=3D 0 && r < 0) + ret =3D r; + return ret; +} + +/** + * yt8824_config_init() - phy initializatioin + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_config_init(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + + mutex_lock(&priv->shared_lock); + if (priv->interface_mode =3D=3D PHY_INTERFACE_MODE_INTERNAL) { + ret =3D yt8824_internal_config_init_paged(phydev); + if (ret < 0) + goto err; + } else { + ret =3D yt8824_extern_config_sds_init_paged(phydev); + if (ret < 0) + goto err; + ret =3D yt8824_extern_config_utp_init_paged(phydev); + if (ret < 0) + goto err; + } + mutex_unlock(&priv->shared_lock); + ret =3D yt8824_soft_reset(phydev); + + phydev_dbg(phydev, "%s done, phy addr: %d\n", __func__, + phydev->mdio.addr); + return ret; +err: + mutex_unlock(&priv->shared_lock); + return ret; +} + static int yt8531_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { @@ -3104,6 +4230,444 @@ static int yt8821_resume(struct phy_device *phydev) return yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0); } =20 +/** + * yt8824_get_features - read mmd register to get 2.5G capability + * @phydev: target phy_device struct + * + * Returns: 0 or negative errno code + */ +static int yt8824_get_features(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + + mutex_lock(&priv->shared_lock); + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + goto err; + ret =3D yt8821_get_features(phydev); + +err: + mutex_unlock(&priv->shared_lock); + return ret; +} + +/** + * yt8824_aneg_done() - check negotiation state. + * @phydev: a pointer to a &struct phy_device + * + * Returns: auto-negotiation complete status or negative errno code + */ +static int yt8824_aneg_done(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int auto_neg; + int ret; + + mutex_lock(&priv->shared_lock); + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + goto err; + + ret =3D phy_read(phydev, MII_BMSR); + if (ret < 0) + goto err; + mutex_unlock(&priv->shared_lock); + auto_neg =3D !!(ret & BMSR_ANEGCOMPLETE); + + phydev_dbg(phydev, "%s, phy addr: %d, auto negotiation done: %d\n", + __func__, phydev->mdio.addr, auto_neg); + return auto_neg; +err: + mutex_unlock(&priv->shared_lock); + return ret; +} + +/** + * yt8824_read_status_paged() - determines the speed and duplex of one pa= ge + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_read_status_paged(struct phy_device *phydev) +{ + int ret; + int val; + + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + return ret; + + ret =3D genphy_read_status(phydev); + if (ret < 0) + return ret; + + if (phydev->autoneg =3D=3D AUTONEG_ENABLE && phydev->autoneg_complete) { + ret =3D genphy_c45_read_lpa(phydev); + if (ret < 0) + return ret; + } + + if (!phydev->link) { + phydev->speed =3D SPEED_UNKNOWN; + phydev->duplex =3D DUPLEX_UNKNOWN; + if (phydev->autoneg =3D=3D AUTONEG_ENABLE) + phy_resolve_aneg_pause(phydev); + return 0; + } + + ret =3D phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG); + if (ret < 0) + return ret; + + val =3D ret; + + yt8821_adjust_status(phydev, val); + + if (phydev->autoneg =3D=3D AUTONEG_ENABLE) + phy_resolve_aneg_pause(phydev); + + return 0; +} + +/** + * yt8824_read_status() - determines the negotiated speed and duplex + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_read_status(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + + mutex_lock(&priv->shared_lock); + ret =3D yt8824_read_status_paged(phydev); + mutex_unlock(&priv->shared_lock); + + return ret; +} + +/** + * yt8824_utp_power_on(): utp power on. + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_utp_power_on(struct phy_device *phydev) +{ + int ret =3D 0; + + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + return ret; + + return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0x0); +} + +/** + * yt8824_utp_power_down(): utp power down. + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_utp_power_down(struct phy_device *phydev) +{ + int ret; + + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + return ret; + + return phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN); +} + +/** + * yt8824_power_on() - set utp power on. + * @phydev: a pointer to a &struct phy_device + * + * NOTE: need WA like softreset + * + * Returns: 0 or negative errno code + */ +static int yt8824_power_on(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + int r; + + if (priv->interface_mode =3D=3D PHY_INTERFACE_MODE_INTERNAL) { + /* test mode 1 */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret < 0) + goto retry; + /* utp power on */ + ret =3D yt8824_utp_power_on(phydev); + if (ret < 0) + goto retry; + /* normal mode */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto retry; + } else { + /* test mode 1 */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret < 0) + goto retry; + + /* sds isolation */ + ret =3D yt8824_sds_isolate_paged(phydev); + if (ret < 0) + goto retry; + + /* utp power on */ + ret =3D yt8824_utp_power_on(phydev); + if (ret < 0) + goto retry; + + /* normal mode */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto retry; + + /* sds soft reset and disable isolation */ + ret =3D yt8824_sds_isolate_and_softreset_paged(phydev); + if (ret < 0) + goto retry; + } + return 0; + +retry: + /* + * If the PHY up operation succeeds but the subsequent operation + * fails, revert to the default state. + */ + r =3D yt8824_utp_power_down(phydev); + if (ret >=3D 0 && r < 0) + ret =3D r; + ret =3D yt8824_restore_working_status(phydev, ret); + return ret; +} + +/** + * yt8824_resume() - resume the hardware + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_resume(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + + mutex_lock(&priv->shared_lock); + ret =3D yt8824_power_on(phydev); + mutex_unlock(&priv->shared_lock); + + return ret; +} + +/** + * yt8824_power_down() - set utp power down. + * @phydev: a pointer to a &struct phy_device + * + * NOTE: need WA like softreset + * + * Returns: 0 or negative errno code + */ +static int yt8824_power_down(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + int r; + + if (priv->interface_mode =3D=3D PHY_INTERFACE_MODE_INTERNAL) { + /* test mode 1 */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret < 0) + goto retry; + /* utp power down */ + ret =3D yt8824_utp_power_down(phydev); + if (ret < 0) + goto retry; + /* normal mode */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto retry; + } else { + /* test mode 1 */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_1); + if (ret < 0) + goto retry; + + /* sds isolation */ + ret =3D yt8824_sds_isolate_paged(phydev); + if (ret < 0) + goto retry; + + /* utp power down */ + ret =3D yt8824_utp_power_down(phydev); + if (ret < 0) + goto retry; + + /* normal mode */ + ret =3D yt8824_utp_set_template_test_mode + (phydev, MDIO_PMA_10GBT_TESTMODE_NORMAL); + if (ret < 0) + goto retry; + + /* sds soft reset and disable isolation */ + ret =3D yt8824_sds_isolate_and_softreset_paged(phydev); + if (ret < 0) + goto retry; + } + return 0; + +retry: + /* + * If the PHY down operation succeeds but the subsequent operation + * fails, revert to the default state. + */ + r =3D yt8824_utp_power_on(phydev); + if (ret >=3D 0 && r < 0) + ret =3D r; + ret =3D yt8824_restore_working_status(phydev, ret); + return ret; +} + +/** + * yt8824_suspend() - suspend the hardware + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_suspend(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int ret; + + mutex_lock(&priv->shared_lock); + ret =3D yt8824_power_down(phydev); + mutex_unlock(&priv->shared_lock); + + return ret; +} + +/** + * yt8824_config_aneg() - config negotiation + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_config_aneg(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + int phy_ctrl =3D 0; + int ret; + + mutex_lock(&priv->shared_lock); + ret =3D phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE); + if (ret < 0) + goto err; + + /* + * Only advertise 2.5G when autoneg is enabled, or when 2.5G is + * explicitly forced. When a different speed is forced, clear + * ADV2_5G so a 2.5G-capable link partner cannot negotiate 2.5G. + * __genphy_config_aneg() only rewrites the + * clause 22 registers on the forced-speed path, so it will not + * clear this bit. + */ + if ((phydev->autoneg =3D=3D AUTONEG_ENABLE || + phydev->speed =3D=3D SPEED_2500) && + linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + phydev->advertising)) + phy_ctrl =3D MDIO_AN_10GBT_CTRL_ADV2_5G; + + ret =3D phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); + if (ret < 0) + goto err; + + ret =3D __genphy_config_aneg(phydev, ret); + +err: + mutex_unlock(&priv->shared_lock); + return ret; +} + +/** + * yt8824_phy_package_probe_once() - init phy package for phy8824. + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_phy_package_probe_once(struct phy_device *phydev) +{ + struct yt8824_shared_priv *priv =3D phy_package_get_priv(phydev); + struct device_node *np =3D phy_package_get_node(phydev); + int res; + + if (!priv || !np) { + phydev_err(phydev, "%s: missing shared priv or DT node\n", + __func__); + return -EINVAL; + } + /* Initialise shared lock for YT8824 */ + mutex_init(&priv->shared_lock); + res =3D of_get_phy_mode(np, &priv->interface_mode); + if (res < 0) { + phydev_err(phydev, "missing phy-mode in PHY package node.\n"); + return res; + } + + if (priv->interface_mode !=3D PHY_INTERFACE_MODE_INTERNAL && + priv->interface_mode !=3D PHY_INTERFACE_MODE_10G_QXGMII) { + phydev_err(phydev, "unsupported phy-mode %s\n", + phy_modes(priv->interface_mode)); + return -EINVAL; + } + + return 0; +} + +/** + * yt8824_probe() - phy8824 probe. + * @phydev: a pointer to a &struct phy_device + * + * Returns: 0 or negative errno code + */ +static int yt8824_probe(struct phy_device *phydev) +{ + struct device *dev =3D &phydev->mdio.dev; + struct yt8824_shared_priv *shared_priv; + int ret; + + ret =3D devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv)); + if (ret) + return ret; + + /* Ensure other PHY probes wait for shared mutex initialization. */ + phy_package_lock(phydev); + if (phy_package_probe_once(phydev)) { + ret =3D yt8824_phy_package_probe_once(phydev); + if (ret) { + phy_package_unlock(phydev); + return ret; + } + } + phy_package_unlock(phydev); + + return 0; +} + static struct phy_driver motorcomm_phy_drvs[] =3D { { PHY_ID_MATCH_EXACT(PHY_ID_YT8511), @@ -3190,13 +4754,29 @@ static struct phy_driver motorcomm_phy_drvs[] =3D { .suspend =3D yt8821_suspend, .resume =3D yt8821_resume, }, + { + PHY_ID_MATCH_EXACT(PHY_ID_YT8824), + .name =3D "YT8824 Quad Ports 2.5Gbps Ethernet", + .get_features =3D yt8824_get_features, + .read_page =3D yt8824_read_page, + .write_page =3D yt8824_write_page, + .probe =3D yt8824_probe, + .config_aneg =3D yt8824_config_aneg, + .aneg_done =3D yt8824_aneg_done, + .config_init =3D yt8824_config_init, + .read_status =3D yt8824_read_status, + .soft_reset =3D yt8824_soft_reset, + .suspend =3D yt8824_suspend, + .resume =3D yt8824_resume, + }, }; =20 module_phy_driver(motorcomm_phy_drvs); =20 -MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/8821 PHY driver"); +MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/8821/8824 PHY driver"); MODULE_AUTHOR("Peter Geis"); MODULE_AUTHOR("Frank"); +MODULE_AUTHOR("Kyle"); MODULE_LICENSE("GPL"); =20 static const struct mdio_device_id __maybe_unused motorcomm_tbl[] =3D { @@ -3206,6 +4786,7 @@ static const struct mdio_device_id __maybe_unused mot= orcomm_tbl[] =3D { { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8821) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8824) }, { /* sentinel */ } }; =20 --=20 2.25.1