| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/10/20 06:14 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch series introduces support for the Motorcomm YT8824 Quad 2.5Gbps Ethernet PHY in drivers/net/phy/motorcomm.c, along with a Device Tree binding and a Clause 45 PMA testmode helper in drivers/net/phy/phy-c45.c. The YT8824 driver represents physical ASIC Ethernet PHY hardware that strictly requires specific Device Tree structures (an ethernet-phy-package parent node with motorcomm,package-mode property checked in yt8824_probe via devm_of_phy_package_join). This hardware is not present or emulated in standard virtualized fuzzing environments (QEMU/GCE on amd64). The helper function genphy_c45_template_testmode() is only called by the YT8824 driver, and the minor change in ytphy_set_wol() is functionally identical to the existing code. Consequently, the modified executable code is structurally unreachable.",
"WorthFuzzing": false
} |
| 1/1 | 2026/10/20 06:14 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit e5aba756d67e6212999c9444868981aaf3cf7351\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Oct 20 06:14:18 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml b/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml\nnew file mode 100644\nindex 0000000000000..4c67f8afcf27a\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml\n@@ -0,0 +1,78 @@\n+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)\n+%YAML 1.2\n+---\n+$id: http://devicetree.org/schemas/net/motorcomm,yt8824.yaml#\n+$schema: http://devicetree.org/meta-schemas/core.yaml#\n+\n+title: MotorComm YT8824 Ethernet PHY\n+\n+maintainers:\n+ - Kyle Switch \u003ckyle.switch@motor-comm.com\u003e\n+\n+description:\n+ Motorcomm YT8824 Ethernet PHY is a PHY package of 4 PHYs.\n+\n+$ref: ethernet-phy-package.yaml#\n+\n+properties:\n+ compatible:\n+ enum:\n+ - motorcomm,yt8824-package\n+\n+ motorcomm,package-mode:\n+ description: |\n+ PHY package can be configured in 2 modes:\n+ - internal: YT8824 is embedded in the switch, using\n+ an internal interface to the MAC.\n+ - 10g-qxgmii: YT8824 is a standalone external PHY,\n+ connected via 10G QXGMII.\n+ $ref: /schemas/types.yaml#/definitions/string\n+ enum: [ internal, 10g-qxgmii ]\n+\n+ reg:\n+ description:\n+ The absolute MDIO address of the YT8824 shared top extend\n+ register block.\n+ For internal mode, this is fixed at 9;\n+ For external mode, it is the base MDIO address of the four\n+ member PHYs plus 4, where base is typically 0x0.\n+ Note that this is NOT the reg of the first member PHY.\n+\n+required:\n+ - compatible\n+ - motorcomm,package-mode\n+ - reg\n+\n+unevaluatedProperties: false\n+\n+examples:\n+ - |\n+ mdio {\n+ #address-cells = \u003c1\u003e;\n+ #size-cells = \u003c0\u003e;\n+\n+ ethernet-phy-package@9 {\n+ #address-cells = \u003c1\u003e;\n+ #size-cells = \u003c0\u003e;\n+ compatible = \"motorcomm,yt8824-package\";\n+ reg = \u003c9\u003e;\n+\n+ motorcomm,package-mode = \"internal\";\n+\n+ ethernet-phy@4 {\n+ reg = \u003c4\u003e;\n+ };\n+\n+ ethernet-phy@5 {\n+ reg = \u003c5\u003e;\n+ };\n+\n+ ethernet-phy@6 {\n+ reg = \u003c6\u003e;\n+ };\n+\n+ ethernet-phy@7 {\n+ reg = \u003c7\u003e;\n+ };\n+ };\n+ };\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 23e9194483d9b..ac8e12e7b8392 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -18424,8 +18424,10 @@ F:\tdrivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c\n \n MOTORCOMM PHY DRIVER\n M:\tFrank \u003cFrank.Sae@motor-comm.com\u003e\n+M:\tKyle Switch \u003ckyle.switch@motor-comm.com\u003e\n L:\tnetdev@vger.kernel.org\n S:\tMaintained\n+F:\tDocumentation/devicetree/bindings/net/motorcomm,yt8824.yaml\n F:\tDocumentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml\n F:\tdrivers/net/phy/motorcomm.c\n \ndiff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig\nindex 30e9d22c8d1a3..04593a770e433 100644\n--- a/drivers/net/phy/Kconfig\n+++ b/drivers/net/phy/Kconfig\n@@ -361,10 +361,12 @@ config MICROSEMI_PHY\n \n config MOTORCOMM_PHY\n \ttristate \"Motorcomm PHYs\"\n+\tselect PHY_PACKAGE\n \thelp\n \t Enables support for Motorcomm network PHYs.\n \t Currently supports YT85xx Gigabit Ethernet PHYs, YT861x PHYs\n-\t integrated in YT921x switches, and YT8821 2.5Gbps PHYs.\n+\t integrated in YT921x switches, YT8821 2.5Gbps PHYs and YT8824 4 * 2.5G\n+\t PHYs.\n \n config NATIONAL_PHY\n \ttristate \"National Semiconductor PHYs\"\ndiff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c\nindex 463e1ea3efc93..6628ebcca0819 100644\n--- a/drivers/net/phy/motorcomm.c\n+++ b/drivers/net/phy/motorcomm.c\n@@ -1,19 +1,25 @@\n // SPDX-License-Identifier: GPL-2.0+\n /*\n- * Motorcomm 8511/8521/8522/8531/8531S/861x/8821 PHY driver.\n+ * Motorcomm 8511/8521/8522/8531/8531S/861x/8821/8824 PHY driver.\n *\n * Author: Peter Geis \u003cpgwipeout@gmail.com\u003e\n * Author: Frank \u003cFrank.Sae@motor-comm.com\u003e\n+ * Author: Kyle \u003ckyle.switch@motor-comm.com\u003e\n */\n \n #include \u003clinux/clk.h\u003e\n #include \u003clinux/etherdevice.h\u003e\n #include \u003clinux/ethtool_netlink.h\u003e\n #include \u003clinux/kernel.h\u003e\n+#include \u003clinux/mdio.h\u003e\n #include \u003clinux/module.h\u003e\n+#include \u003clinux/of.h\u003e\n+#include \u003clinux/of_net.h\u003e\n #include \u003clinux/phy.h\u003e\n #include \u003clinux/property.h\u003e\n \n+#include \"phylib.h\"\n+\n #define PHY_ID_YT8511\t\t0x0000010a\n #define PHY_ID_YT8521\t\t0x0000011a\n #define PHY_ID_YT8522\t\t0x4f51e928\n@@ -22,6 +28,7 @@\n /* Live captured from YT921x switch internal MDIO bus */\n #define PHY_ID_INT861X\t\t0x01e04281\n #define PHY_ID_YT8821\t\t0x4f51ea19\n+#define PHY_ID_YT8824\t\t0x4f51e8b8\n /* YT8521/YT8531S/YT8821 Register Overview\n *\tUTP Register space\t|\tFIBER Register space\n * ------------------------------------------------------------\n@@ -33,6 +40,18 @@\n * ------------------------------------------------------------\n */\n \n+/* YT8824 Register Overview\n+ * UTP Register space\t| SERDES Register space\n+ * ------------------------------------------------------------\n+ * | UTP MII\t\t| SERDES MII\t\t|\n+ * | UTP MMD\t\t|\t\t\t|\n+ * | UTP Extended\t| SERDES Extended\t|\n+ * | UTP Top Extended\t| SERDES Top Extended\t|\n+ * ------------------------------------------------------------\n+ * | Common Top Extended\t\t\t|\n+ * ------------------------------------------------------------\n+ */\n+\n /* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */\n \n /* Specific Function Control Register */\n@@ -397,6 +416,226 @@\n #define YT8821_CHIP_MODE_AUTO_BX2500_SGMII\t0\n #define YT8821_CHIP_MODE_FORCE_BX2500\t\t1\n \n+#define YT8824_RSSR_SPACE_MASK\t\t\tBIT(0)\n+#define YT8824_RSSR_SERDES_SPACE\t\t(0x1)\n+#define YT8824_RSSR_UTP_SPACE\t\t\t(0x0)\n+#define YT8824_SDS_CFG_MIN_PRE_MASK\t\tGENMASK(3, 0)\n+#define YT8824_SDS_EN_FILL_PRE\t\t\tBIT(13)\n+#define YT8824_SDS_TX_PRE_PADDING\t\t(0x7)\n+\n+/* PHY8824 UTP init registers */\n+#define YT8824_WRITE_PROTECT_CAL_REG\t\t0x1\n+#define YT8824_WRITE_PROTECT\t\t\tBIT(0)\n+#define YT8824_PLL_VCO_ATEMP_REG\t\t0xa20e\n+#define YT8824_PLL_VCO_SEL_CURRENT\t\tGENMASK(7, 4)\n+#define YT8824_PLL_VCO_SEL_CURRENT_B\t\t0xb\n+#define YT8824_PLL_PFD_CTRL_REG\t\t\t0xa20a\n+#define YT8824_PLL_VCO_ICOSTANT\t\t\tGENMASK(9, 4)\n+#define YT8824_PLL_VCO_ATEMP_1_REG\t\t0xa20c\n+#define YT8824_PLL_VCO_IPTAT\t\t\tGENMASK(5, 0)\n+#define YT8824_PLL_DAC_0_REG\t\t\t0xa2b6\n+#define YT8824_PLL_DAC_RST\t\t\tBIT(10)\n+#define YT8824_IF_CTRL_REG\t\t\t0xa003\n+#define YT8824_U0_U1_ENABLE_ODD_PREAMBLE\tGENMASK(1, 0)\n+#define YT8824_IDLE_CTRL_REG\t\t\t0x3d0\n+#define YT8824_IDLE_DETECT\t\t\tBIT(9)\n+#define YT8824_TRACE_GAIN_THR_REG\t\t0x372\n+#define YT8824_TRACE_LNG_GAIN_THR_2500\t\tGENMASK(14, 8)\n+#define YT8824_TRACE_MED_GAIN_THR_2500\t\tGENMASK(6, 0)\n+#define YT8824_PRM_LONG_REG\t\t\t0x37C\n+#define YT8824_PRM_LARGE_SLAVE_2500\t\tGENMASK(10, 0)\n+#define YT8824_PRM_SMALL_REG\t\t\t0x388\n+#define YT8824_PRM_SMALL_LNG_2500\t\tGENMASK(10, 0)\n+#define YT8824_FAST_RETRAIN_REG\t\t\t0x359\n+#define YT8824_LINK_FAIL_SIG\t\t\tGENMASK(13, 8)\n+#define YT8824_EN_GATE_CTRL_REG\t\t\t0xc\n+#define YT8824_EN_GATE_GMII_CLK\t\t\tBIT(0)\n+#define YT8824_DAC_CFG_REG\t\t\t0xa2fa\n+#define YT8824_POWER_SAVE\t\t\tGENMASK(15, 0)\n+#define YT8824_DAC_BIAS_CFG_REG\t\t\t0x4e2\n+#define YT8824_DAC_BIAS_CFG_2500\t\tGENMASK(9, 5)\n+#define YT8824_DAC_IMID_CFG_REG\t\t\t0x47e\n+#define YT8824_DAC_IMID_CH2\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMID_CH3\t\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMID_CFG1_REG\t\t0x47f\n+#define YT8824_DAC_IMID_CH0\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMID_CH1\t\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMSB_CFG_REG\t\t\t0x480\n+#define YT8824_DAC_IMSB_CH2\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMSB_CH3\t\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMSB_CFG1_REG\t\t0x481\n+#define YT8824_DAC_IMSB_CH0\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMSB_CH1\t\t\tGENMASK(14, 8)\n+#define YT8824_TRACE_LNG_GAIN_REG\t\t0x336\n+#define YT8824_TRACE_LNG_GAIN_THR\t\tGENMASK(14, 8)\n+#define YT8824_TRACE_MED_GAIN_REG\t\t0x340\n+#define YT8824_TRACE_MED_GAIN_THR\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMID_CH2_CH3_CFG_ORG_REG\t0x46e\n+#define YT8824_DAC_IMID_CH3_ORG\t\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMID_CH2_ORG\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMID_CH0_CH1_CFG_ORG_REG\t0x46f\n+#define YT8824_DAC_IMID_CH1_ORG\t\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMID_CH0_ORG\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMSB_CH2_CH3_CFG_ORG_REG\t0x470\n+#define YT8824_DAC_IMSB_CH3_ORG\t\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMSB_CH2_ORG\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMSB_CH0_CH1_CFG_ORG_REG\t0x471\n+#define YT8824_DAC_IMSB_CH1_ORG\t\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMSB_CH0_ORG\t\t\tGENMASK(6, 0)\n+#define YT8824_TRACE_LNG_GAIN_100_REG\t\t0x030b\n+#define YT8824_TRACE_LNG_GAIN_THR_100\t\tGENMASK(14, 8)\n+#define YT8824_TRACE_MED_GAIN_THR_100\t\tGENMASK(6, 0)\n+#define YT8824_CABLE_VSHT_REG\t\t\t0x071f\n+#define YT8824_CABLE_VSHT_THR_S\t\t\tGENMASK(6, 0)\n+#define YT8824_DAC_LPFIL_CH2_CH3_ADJ_REG\t0x046b\n+#define YT8824_DAC_LPFIL_ADJ_CH3_10\t\tGENMASK(12, 8)\n+#define YT8824_DAC_LPFIL_ADJ_CH2_10\t\tGENMASK(4, 0)\n+#define YT8824_DAC_LPFIL_CH0_CH1_ADJ_REG\t0x046c\n+#define YT8824_DAC_LPFIL_ADJ_CH1_10\t\tGENMASK(12, 8)\n+#define YT8824_DAC_LPFIL_ADJ_CH0_10\t\tGENMASK(4, 0)\n+#define YT8824_DAC_IMID_CFG_CH2_CH3_10_ORG\t0x0466\n+#define YT8824_DAC_IMID_CFG_CH3_10_ORG\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMID_CFG_CH2_10_ORG\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMID_CFG_CH0_CH1_10_ORG\t0x0467\n+#define YT8824_DAC_IMID_CFG_CH1_10_ORG\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMID_CFG_CH0_10_ORG\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMSB_CFG_CH2_CH3_10_ORG\t0x0468\n+#define YT8824_DAC_IMSB_CFG_CH3_10_ORG\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMSB_CFG_CH2_10_ORG\t\tGENMASK(6, 0)\n+#define YT8824_DAC_IMSB_CFG_CH0_CH1_10_ORG\t0x0469\n+#define YT8824_DAC_IMSB_CFG_CH1_10_ORG\t\tGENMASK(14, 8)\n+#define YT8824_DAC_IMSB_CFG_CH0_10_ORG\t\tGENMASK(6, 0)\n+#define YT8824_FFE_REG\t\t\t\t0x034a\n+#define YT8824_WAIT_TO_1000\t\t\tGENMASK(15, 8)\n+#define YT8824_FFE_SUM_THRES\t\t\tGENMASK(2, 0)\n+#define YT8824_EN_GATE_REG\t\t\t0x00f8\n+#define YT8824_EN_GATE_PHYDBG\t\t\tBIT(10)\n+#define YT8824_EN_GATE_BT1000\t\t\tBIT(9)\n+#define YT8824_CNT_REG\t\t\t\t0x0059\n+#define YT8824_CNT_ERR_AUTO\t\t\tBIT(14)\n+#define YT8824_PRM_LARGE_MASTER_REG\t\t0x032c\n+#define YT8824_PRM_LARGE_MASTER_1000\t\tGENMASK(10, 0)\n+#define YT8824_PRM_LARGE_SLAVE_REG\t\t0x032d\n+#define YT8824_PRM_LARGE_SLAVE_1000\t\tGENMASK(10, 0)\n+#define YT8824_SIG_GONE_REG\t\t\t0x032e\n+#define YT8824_SIG_GONE_THR_1000\t\tGENMASK(7, 0)\n+#define YT8824_EC_NX_TRAIN_COARSE_REG\t\t0x0322\n+#define YT8824_EC_NX_TRAIN_COARSE_TO_1000\tGENMASK(7, 0)\n+#define YT8824_VGA_IN_LPF2_CAP_REG\t\t0x04d3\n+#define YT8824_VGA_IN_LPF2_CAP_OTHER\t\tGENMASK(7, 4)\n+#define YT8824_VGA_IN_LPF1_CAP_REG\t\t0x04d2\n+#define YT8824_VGA_IN_LPF1_CAP_OTHER\t\tGENMASK(7, 4)\n+#define YT8824_LDPC_LFER_FAIL_REG\t\t0x00c8\n+#define YT8824_LDPC_FAIL_THR\t\t\tGENMASK(15, 8)\n+#define YT8824_LFER_FAIL_THR\t\t\tGENMASK(7, 0)\n+#define YT8824_FR_REQ_REG\t\t\t0x00be\n+#define YT8824_FR_REQ_THR\t\t\tGENMASK(4, 0)\n+#define YT8824_GN_MU_COARSE_REG\t\t\t0x037a\n+#define YT8824_PRM_SMALL_SHT_2500\t\tGENMASK(10, 0)\n+#define YT8824_DAC_AMP_ADJ_REG\t\t\t0x0482\n+#define YT8824_DAC_AMP_ADJ_CH3_PBO0_2500\tGENMASK(15, 12)\n+#define YT8824_DAC_AMP_ADJ_CH2_PBO0_2500\tGENMASK(11, 8)\n+#define YT8824_DAC_AMP_ADJ_CH1_PBO0_2500\tGENMASK(7, 4)\n+#define YT8824_DAC_AMP_ADJ_CH0_PBO0_2500\tGENMASK(3, 0)\n+#define YT8824_P0_DAC_BIAS_CAS_CH3_CH2_REG\t0xa2d5\n+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH3\t\tGENMASK(12, 8)\n+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH2\t\tGENMASK(4, 0)\n+#define YT8824_P0_DAC_BIAS_CAS_CH1_CH0_REG\t0xa2d6\n+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH1\t\tGENMASK(12, 8)\n+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH0\t\tGENMASK(4, 0)\n+#define YT8824_P1_DAC_BIAS_CAS_CH3_CH2_REG\t0xa2d7\n+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH3\t\tGENMASK(12, 8)\n+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH2\t\tGENMASK(4, 0)\n+#define YT8824_P1_DAC_BIAS_CAS_CH1_CH0_REG\t0xa2d8\n+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH1\t\tGENMASK(12, 8)\n+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH0\t\tGENMASK(4, 0)\n+#define YT8824_P01_PLL_EN_REG\t\t\t0xa218\n+#define YT8824_CSR_EFUSE_BYPASS_ANALOG_SECOND_RESET\tBIT(6)\n+#define YT8824_CSR_EFUSE_BYPASS_PLL_TXRX_RESET\t\tBIT(5)\n+#define YT8824_U0_CSR_RESET_REG\t\t\t0xa01d\n+#define YT8824_U0_CSR_RESETB_TX_CH0\t\tBIT(3)\n+#define YT8824_U0_CSR_RESETB_TX_CH1\t\tBIT(2)\n+#define YT8824_U0_CSR_RESETB_TX_CH2\t\tBIT(1)\n+#define YT8824_U0_CSR_RESETB_TX_CH3\t\tBIT(0)\n+#define YT8824_U1_CSR_RESET_REG\t\t\t0xa01e\n+#define YT8824_U1_CSR_RESETB_TX_CH0\t\tBIT(3)\n+#define YT8824_U1_CSR_RESETB_TX_CH1\t\tBIT(2)\n+#define YT8824_U1_CSR_RESETB_TX_CH2\t\tBIT(1)\n+#define YT8824_U1_CSR_RESETB_TX_CH3\t\tBIT(0)\n+/* External PHY8824 serdes init registers */\n+#define YT8824_SERDES_PLL_CTRL1_REG\t\t0xa13e\n+#define YT8824_SERDES_PLL_CTRL2_REG\t\t0xa13f\n+#define YT8824_SERDES_PLL_CTRL3_REG\t\t0xa140\n+#define YT8824_WRITE_PROTECT_REG\t\t0x4be\n+#define YT8824_SERDES_REG_WR_PRT\t\tBIT(2)\n+#define YT8824_CSR_CTRL_REG\t\t\t0x49f\n+#define YT8824_CSR_PCS_GLB_RST_BYPASS\t\tBIT(10)\n+#define YT8824_CSR_SG_MODE_RST_BYPASS\t\tBIT(9)\n+#define YT8824_CSR_US_GLB_RESET_N\t\tBIT(7)\n+#define YT8824_CSR_PCS_BEF_TRAINING_DONE_RST_BYPASS\tBIT(2)\n+#define YT8824_CSR_PMA_CTRL_REG\t\t\t0x4a9\n+#define YT8824_CSR_WATCH_DOG_ALL_BYPASS\t\tBIT(7)\n+#define YT8824_CDR_CTRL_REG\t\t\t0x406\n+#define YT8824_CDR_MODE\t\t\t\tBIT(11)\n+#define YT8824_CSR_PLL_VCO_CTRL_REG\t\t0x438\n+#define YT8824_CSR_PLL_VCO_SEL_VCO2_CURRENT\tGENMASK(15, 12)\n+#define YT8824_CSR_PLL_VCO_ATEMP_R\t\tGENMASK(2, 0)\n+#define YT8824_CSR_PLL_DIVLDO_CTRL_REG\t\t0x439\n+#define YT8824_CSR_PLL_VCO_SEL_VCO2_RM_R\tGENMASK(1, 0)\n+#define YT8824_CSR_PLL_FBDIV_REG\t\t0x043a\n+#define YT8824_CSR_PLL_FBDIV_SYNC_SELB\t\tBIT(1)\n+#define YT8824_CSR_PLL_SPARE_CTRL_REG\t\t0x042a\n+#define YT8824_CSR_PLL_SPARE\t\t\tGENMASK(15, 0)\n+#define YT8824_CDR_MANUAL_REG\t\t\t0x0491\n+#define YT8824_VDAC_AMP_THR_LNG\t\t\tGENMASK(6, 0)\n+#define YT8824_TRAINING_CTRL_REG\t\t0x0492\n+#define YT8824_VDAC_AMP_THR_MED\t\t\tGENMASK(14, 8)\n+#define YT8824_VDAC_AMP_THR_SHT\t\t\tGENMASK(7, 0)\n+#define YT8824_EOM_CTRL_REG\t\t\t0x0454\n+#define YT8824_EOD_DURATION_SEL\t\t\tGENMASK(11, 8)\n+#define YT8824_EOD_VTH\t\t\t\tGENMASK(6, 0)\n+#define YT8824_PGA_GAIN_CTRL_REG\t\t0x0497\n+#define YT8824_CDR_OFFSET_ERR_WTH\t\tGENMASK(14, 8)\n+#define YT8824_PGA_GAIN_MAX\t\t\tGENMASK(6, 4)\n+#define YT8824_PGA_GAIN_INIT\t\t\tGENMASK(2, 0)\n+#define YT8824_EOD_CTRL_REG\t\t\t0x04cd\n+#define YT8824_EOD_ERR_CNT_THR\t\t\tGENMASK(15, 0)\n+#define YT8824_CSR_AFE_CTRL_REG\t\t\t0x04af\n+#define YT8824_CSR_AFE_VCM_CFG\t\t\tGENMASK(10, 8)\n+#define YT8824_CSR_AFE_MANUAL_CTRL_1P25G\tBIT(4)\n+#define YT8824_CSR_AFE_MANUAL_CTRL_3P125G\tBIT(3)\n+#define YT8824_CSR_AFE_MANUAL_CTRL_10P3125G\tBIT(2)\n+#define YT8824_DFE_CTRL_REG\t\t\t0x048a\n+#define YT8824_DFE_TAP_POLARITY\t\t\tBIT(12)\n+#define YT8824_DFE_IDAC_TUNE\t\t\tGENMASK(11, 10)\n+#define YT8824_CSR_CDR_CTRL_REG\t\t\t0x0408\n+#define YT8824_CSR_CDR_OFFSET_DATA\t\tGENMASK(14, 8)\n+#define YT8824_DFE_VDAC_CODE_REG\t\t0x04d6\n+#define YT8824_DFE_VDAC_CODE_THR\t\t\tGENMASK(6, 0)\n+#define YT8824_RX_SPARE_CTRL_REG\t\t0x044f\n+#define YT8824_RX_SPARE_REG\t\t\tGENMASK(15, 0)\n+#define YT8824_DFE_VDAC_CTRL_REG\t\t0x048e\n+#define YT8824_DFE_VDAC_TUNE\t\t\tGENMASK(11, 10)\n+#define YT8824_DFE_VDAC_SEL\t\t\tGENMASK(9, 8)\n+#define YT8824_CSR_TX_PRE_REG\t\t\t0x000d\n+#define YT8824_CSR_TX_PRE_SEL\t\t\tGENMASK(4, 0)\n+#define YT8824_CSR_AFE_CTRL1_REG\t\t0x04b0\n+#define YT8824_CSR_AFE_CTLE_BW\t\t\tGENMASK(6, 4)\n+#define YT8824_CSR_AFE_CTRL2_REG\t\t0x04b1\n+#define YT8824_CSR_AFE_PGA_BW\t\t\tGENMASK(14, 12)\n+#define YT8824_CSR_AFE_BUF_BW\t\t\tGENMASK(6, 4)\n+#define YT8824_CSR_DCC_CAL_CTRL_REG\t\t0x0003\n+#define YT8824_CUR_TX_SEQ\t\t\tGENMASK(15, 12)\n+#define YT8824_CUR_RX_SEQ\t\t\tGENMASK(11, 8)\n+#define YT8824_CALIB_SEQ_FINISH\t\t\tBIT(1)\n+#define YT8824_CALIB_SEQ_SW_RST\t\t\tBIT(0)\n+#define YT8824_RESTART_CAL_CTRL_REG\t\t0x2000\n+#define YT8824_DAC_TRIM_MAIN_CFG_REG\t\t0x429\n+#define YT8824_PLL_VCO_CFG_REG\t\t\t0x441\n+#define YT8824_TX_MUX_CH3_CH2_REG\t\t0x42b\n+#define YT8824_C1_COARSE_CFG_REG\t\t0x4b4\n+#define YT8824_FFE_CTRL_REG\t\t\t0x4b5\n+\n struct yt8521_priv {\n \t/* combo_advertising is used for case of YT8521 in combo mode,\n \t * this means that yt8521 may work in utp or fiber mode which depends\n@@ -415,6 +654,14 @@ struct yt8521_priv {\n \tu8 reg_page;\n };\n \n+struct yt8824_shared_priv {\n+\tphy_interface_t package_mode;\n+\t/* shared_lock used to UTPs operation isolation during swap reg space */\n+\tstruct mutex shared_lock;\n+\t/* true once the package-wide SERDES init has been done */\n+\tbool sds_initialized;\n+};\n+\n /**\n * ytphy_read_ext() - read a PHY's extended register\n * @phydev: a pointer to a \u0026struct phy_device\n@@ -453,6 +700,70 @@ static int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum)\n \treturn ret;\n }\n \n+/**\n+ * ytphy_read_top_ext() - read a PHY's top extended register for YT8824\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @regnum: register number to read\n+ *\n+ * Returns: the value of regnum reg or negative error code\n+ */\n+static int ytphy_read_top_ext(struct phy_device *phydev, u16 regnum)\n+{\n+\tint ret;\n+\n+\tlockdep_assert_held(\u0026phydev-\u003emdio.bus-\u003emdio_lock);\n+\tret = __phy_package_write(phydev, 0, YTPHY_PAGE_SELECT, regnum);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn __phy_package_read(phydev, 0, YTPHY_PAGE_DATA);\n+}\n+\n+/**\n+ * ytphy_write_top_ext() - write a PHY's top extended register for YT8824\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @regnum: register number to write\n+ * @val: register val to write\n+ *\n+ * Returns: 0 or negative error code\n+ */\n+static int ytphy_write_top_ext(struct phy_device *phydev, u16 regnum,\n+\t\t\t u16 val)\n+{\n+\tint ret;\n+\n+\tlockdep_assert_held(\u0026phydev-\u003emdio.bus-\u003emdio_lock);\n+\tret = __phy_package_write(phydev, 0, YTPHY_PAGE_SELECT, regnum);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn __phy_package_write(phydev, 0, YTPHY_PAGE_DATA, val);\n+}\n+\n+/**\n+ * phy8824_page_write_with_lock() - write page for YT8824\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @page: reg page(YT8824_RSSR_SERDES_SPACE/YT8824_RSSR_UTP_SPACE).\n+ *\n+ * Returns: 0 or negative error code\n+ */\n+static int phy8824_page_write_with_lock(struct phy_device *phydev, int page)\n+{\n+\tint ret;\n+\n+\tphy_lock_mdio_bus(phydev);\n+\tret = ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err;\n+\tret \u0026= ~YT8824_RSSR_SPACE_MASK;\n+\tret |= (page \u0026 YT8824_RSSR_SPACE_MASK);\n+\tret = ytphy_write_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG, ret);\n+\n+err:\n+\tphy_unlock_mdio_bus(phydev);\n+\treturn ret;\n+}\n+\n /**\n * ytphy_write_ext() - write a PHY's extended register\n * @phydev: a pointer to a \u0026struct phy_device\n@@ -638,15 +949,1165 @@ static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)\n \t\tmask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;\n \t\tret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, 0);\n \n-\t\t/* Disable WOL interrupt */\n-\t\tret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,\n-\t\t\t\t YTPHY_IER_WOL, 0);\n+\t\t/* Disable WOL interrupt */\n+\t\tret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,\n+\t\t\t\t YTPHY_IER_WOL, 0);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_read_page() - read PHY8824 reg page\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: current reg space of yt8824 (YT8824_RSSR_SERDES_SPACE/\n+ * YT8824_RSSR_UTP_SPACE) or negative errno code\n+ */\n+static int yt8824_read_page(struct phy_device *phydev)\n+{\n+\tint old_page;\n+\n+\told_page = ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG);\n+\tif (old_page \u003c 0)\n+\t\treturn old_page;\n+\n+\treturn old_page \u0026 YT8824_RSSR_SPACE_MASK;\n+};\n+\n+/**\n+ * yt8824_write_page() - write reg page\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @page: Reg page(YT8824_RSSR_SERDES_SPACE/YT8824_RSSR_UTP_SPACE) to write.\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_write_page(struct phy_device *phydev, int page)\n+{\n+\tint old_page;\n+\tu16 data;\n+\n+\told_page = ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG);\n+\tif (old_page \u003c 0)\n+\t\treturn old_page;\n+\tdata = old_page \u0026 (~YT8824_RSSR_SPACE_MASK);\n+\tdata |= page;\n+\n+\treturn ytphy_write_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG, data);\n+};\n+\n+/**\n+ * yt8824_utp_set_template_test_mode() - config YT8824 UTP test mode.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @test_mode: template test mode from normal, testmode1 to testmode7\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_utp_set_template_test_mode(struct phy_device *phydev,\n+\t\t\t\t\t u16 test_mode)\n+{\n+\tint ret;\n+\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn genphy_c45_template_testmode(phydev, test_mode);\n+}\n+\n+/**\n+ * yt8824_sds_isolate_paged() - enable YT8824 serdes isolate.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_sds_isolate_paged(struct phy_device *phydev)\n+{\n+\tint old_page = YT8824_RSSR_UTP_SPACE;\n+\tint ret = 0;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* enable sds isolate */\n+\tret = __phy_modify(phydev, MII_BMCR, BMCR_ISOLATE, BMCR_ISOLATE);\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_utp_softreset_paged() - config YT8824 UTP softreset.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_utp_softreset_paged(struct phy_device *phydev)\n+{\n+\tint ret = 0;\n+\tint val;\n+\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\tret = phy_modify(phydev, MII_BMCR, BMCR_RESET, BMCR_RESET);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\t/* wait until softreset done. */\n+\treturn phy_read_poll_timeout(phydev, MII_BMCR, val, !(val \u0026 BMCR_RESET),\n+\t\t\t\t 50000, 600000, true);\n+}\n+\n+/**\n+ * yt8824_sds_isolate_and_softreset_paged() - disable YT8824 serdes isolate\n+ * and sds softreset.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_sds_isolate_and_softreset_paged(struct phy_device *phydev)\n+{\n+\tint old_page = YT8824_RSSR_UTP_SPACE;\n+\tint val = 0;\n+\tint ret = -1;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* sds softreset and disable isolate */\n+\tret = __phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ISOLATE,\n+\t\t\t BMCR_RESET \u0026 ~BMCR_ISOLATE);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* poll while still holding the lock */\n+\tret = read_poll_timeout(__phy_read, val,\n+\t\t\t\t(val \u003c 0) || !(val \u0026 BMCR_RESET), 50000, 600000,\n+\t\t\t\ttrue, phydev, MII_BMCR);\n+\tif (val \u003c 0)\n+\t\tret = val;\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_restore_working_status() - called to do store working status\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @ret: operation's return code\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_restore_working_status(struct phy_device *phydev, int ret)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint r;\n+\n+\tr = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n+\t\tret = r;\n+\tif (priv-\u003epackage_mode != PHY_INTERFACE_MODE_INTERNAL) {\n+\t\tr = yt8824_sds_isolate_and_softreset_paged(phydev);\n+\t\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n+\t\t\tret = r;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_soft_reset() - called to do PHY software reset\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_soft_reset(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tif (priv-\u003epackage_mode == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_softreset_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\t} else {\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_sds_isolate_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_softreset_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_sds_isolate_and_softreset_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\t}\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\treturn ret;\n+retry:\n+\tret = yt8824_restore_working_status(phydev, ret);\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_config_utp_init_paged() - config external phy8824 utp init\n+ * @phydev: target phy_device struct\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_config_utp_init_paged(struct phy_device *phydev)\n+{\n+\tint ctrl = 0;\n+\tint mask = 0;\n+\tint ret = 0;\n+\tint val = 0;\n+\tint r;\n+\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tret = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* write protecting */\n+\tmask = YT8824_WRITE_PROTECT;\n+\tctrl = YT8824_WRITE_PROTECT;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_WRITE_PROTECT_CAL_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* PLL calibration */\n+\tctrl = FIELD_PREP(YT8824_PLL_VCO_SEL_CURRENT, 0xb);\n+\tmask = YT8824_PLL_VCO_SEL_CURRENT;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_PLL_VCO_ATEMP_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PLL_VCO_ICOSTANT, 0xf);\n+\tmask = YT8824_PLL_VCO_ICOSTANT;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_PLL_PFD_CTRL_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PLL_VCO_IPTAT, 0xf);\n+\tmask = YT8824_PLL_VCO_IPTAT;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_PLL_VCO_ATEMP_1_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PLL_DAC_RST, 0);\n+\tmask = YT8824_PLL_DAC_RST;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_PLL_DAC_0_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PLL_DAC_RST, 1);\n+\tmask = YT8824_PLL_DAC_RST;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_PLL_DAC_0_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* enable nibble */\n+\tctrl = FIELD_PREP(YT8824_U0_U1_ENABLE_ODD_PREAMBLE, 3);\n+\tmask = YT8824_U0_U1_ENABLE_ODD_PREAMBLE;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_IF_CTRL_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* idle err detect enable */\n+\tctrl = YT8824_IDLE_DETECT;\n+\tmask = YT8824_IDLE_DETECT;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_IDLE_CTRL_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized 2.5G long cable performance */\n+\tctrl = FIELD_PREP(YT8824_TRACE_LNG_GAIN_THR_2500, 0x50);\n+\tctrl |= FIELD_PREP(YT8824_TRACE_MED_GAIN_THR_2500, 0x38);\n+\tmask = YT8824_TRACE_LNG_GAIN_THR_2500 |\n+\t YT8824_TRACE_MED_GAIN_THR_2500;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_TRACE_GAIN_THR_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PRM_LARGE_SLAVE_2500, 0x68);\n+\tmask = YT8824_PRM_LARGE_SLAVE_2500;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_PRM_LONG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PRM_SMALL_LNG_2500, 0xa0);\n+\tmask = YT8824_PRM_SMALL_LNG_2500;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_PRM_SMALL_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized fast retrain */\n+\tctrl = FIELD_PREP(YT8824_LINK_FAIL_SIG, 0x21);\n+\tmask = YT8824_LINK_FAIL_SIG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_FAST_RETRAIN_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_EN_GATE_GMII_CLK, 0);\n+\tmask = YT8824_EN_GATE_GMII_CLK;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_EN_GATE_CTRL_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* 2.5G template tone */\n+\tctrl = FIELD_PREP(YT8824_POWER_SAVE, 0x83);\n+\tmask = YT8824_POWER_SAVE;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_CFG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_BIAS_CFG_2500, 0xa);\n+\tmask = YT8824_DAC_BIAS_CFG_2500;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_BIAS_CFG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized 2.5G template */\n+\tctrl = FIELD_PREP(YT8824_DAC_IMID_CH2, 0x39);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMID_CH3, 0x39);\n+\tmask = YT8824_DAC_IMID_CH2 | YT8824_DAC_IMID_CH3;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMID_CFG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_IMID_CH0, 0x39);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMID_CH1, 0x39);\n+\tmask = YT8824_DAC_IMID_CH0 | YT8824_DAC_IMID_CH1;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMID_CFG1_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_IMSB_CH2, 0x39);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH3, 0x39);\n+\tmask = YT8824_DAC_IMSB_CH2 | YT8824_DAC_IMSB_CH3;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMSB_CFG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_IMSB_CH0, 0x39);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH1, 0x39);\n+\tmask = YT8824_DAC_IMSB_CH0 | YT8824_DAC_IMSB_CH1;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMSB_CFG1_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized 1000M cable length threshold */\n+\tctrl = FIELD_PREP(YT8824_TRACE_LNG_GAIN_THR, 0x2b);\n+\tmask = YT8824_TRACE_LNG_GAIN_THR;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_TRACE_LNG_GAIN_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_TRACE_MED_GAIN_THR, 0x1d);\n+\tmask = YT8824_TRACE_MED_GAIN_THR;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_TRACE_MED_GAIN_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* 100M template amplitude */\n+\tctrl = FIELD_PREP(YT8824_DAC_IMID_CH3_ORG, 0x45);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMID_CH2_ORG, 0x45);\n+\tmask = YT8824_DAC_IMID_CH3_ORG | YT8824_DAC_IMID_CH2_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMID_CH2_CH3_CFG_ORG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_IMID_CH1_ORG, 0x45);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMID_CH0_ORG, 0x45);\n+\tmask = YT8824_DAC_IMID_CH1_ORG | YT8824_DAC_IMID_CH0_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMID_CH0_CH1_CFG_ORG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_IMSB_CH3_ORG, 0x45);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH2_ORG, 0x45);\n+\tmask = YT8824_DAC_IMSB_CH2_ORG | YT8824_DAC_IMSB_CH3_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMSB_CH2_CH3_CFG_ORG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_IMSB_CH1_ORG, 0x45);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH0_ORG, 0x45);\n+\tmask = YT8824_DAC_IMSB_CH1_ORG | YT8824_DAC_IMSB_CH0_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMSB_CH0_CH1_CFG_ORG_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized 100M cable length threshold */\n+\tctrl = FIELD_PREP(YT8824_TRACE_LNG_GAIN_THR_100, 0x2A);\n+\tctrl |= FIELD_PREP(YT8824_TRACE_MED_GAIN_THR_100, 0x1D);\n+\tmask = YT8824_TRACE_LNG_GAIN_THR_100 | YT8824_TRACE_MED_GAIN_THR_100;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_TRACE_LNG_GAIN_100_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_CABLE_VSHT_THR_S, 0x36);\n+\tmask = YT8824_CABLE_VSHT_THR_S;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_CABLE_VSHT_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* 10M template amplitude */\n+\tctrl = FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH3_10, 0x18);\n+\tctrl |= FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH2_10, 0x18);\n+\tmask = YT8824_DAC_LPFIL_ADJ_CH3_10 | YT8824_DAC_LPFIL_ADJ_CH2_10;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_LPFIL_CH2_CH3_ADJ_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH1_10, 0x18);\n+\tctrl |= FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH0_10, 0x18);\n+\tmask = YT8824_DAC_LPFIL_ADJ_CH1_10 | YT8824_DAC_LPFIL_ADJ_CH0_10;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_LPFIL_CH0_CH1_ADJ_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized 10M cable length threshold */\n+\tctrl = FIELD_PREP(YT8824_DAC_IMID_CFG_CH3_10_ORG, 0x6C);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMID_CFG_CH2_10_ORG, 0x6C);\n+\tmask = YT8824_DAC_IMID_CFG_CH3_10_ORG | YT8824_DAC_IMID_CFG_CH2_10_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMID_CFG_CH2_CH3_10_ORG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_DAC_IMID_CFG_CH1_10_ORG, 0x6C);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMID_CFG_CH0_10_ORG, 0x6C);\n+\tmask = YT8824_DAC_IMID_CFG_CH1_10_ORG | YT8824_DAC_IMID_CFG_CH0_10_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMID_CFG_CH0_CH1_10_ORG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized DAC IMSB config for CH2/CH3 */\n+\tctrl = FIELD_PREP(YT8824_DAC_IMSB_CFG_CH3_10_ORG, 0x6C);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMSB_CFG_CH2_10_ORG, 0x6C);\n+\tmask = YT8824_DAC_IMSB_CFG_CH3_10_ORG | YT8824_DAC_IMSB_CFG_CH2_10_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMSB_CFG_CH2_CH3_10_ORG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized DAC IMSB config for CH0/CH1 */\n+\tctrl = FIELD_PREP(YT8824_DAC_IMSB_CFG_CH1_10_ORG, 0x6C);\n+\tctrl |= FIELD_PREP(YT8824_DAC_IMSB_CFG_CH0_10_ORG, 0x6C);\n+\tmask = YT8824_DAC_IMSB_CFG_CH1_10_ORG | YT8824_DAC_IMSB_CFG_CH0_10_ORG;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_IMSB_CFG_CH0_CH1_10_ORG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimize utp 1000M performance */\n+\tctrl = FIELD_PREP(YT8824_WAIT_TO_1000, 0xFF);\n+\tmask = YT8824_WAIT_TO_1000;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_FFE_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_EN_GATE_PHYDBG, 0);\n+\tctrl |= FIELD_PREP(YT8824_EN_GATE_BT1000, 0);\n+\tmask = YT8824_EN_GATE_PHYDBG | YT8824_EN_GATE_BT1000;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_EN_GATE_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_CNT_ERR_AUTO, 1);\n+\tmask = YT8824_CNT_ERR_AUTO;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_CNT_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PRM_LARGE_MASTER_1000, 0x94);\n+\tmask = YT8824_PRM_LARGE_MASTER_1000;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_PRM_LARGE_MASTER_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PRM_LARGE_SLAVE_1000, 0x094);\n+\tmask = YT8824_PRM_LARGE_SLAVE_1000;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_PRM_LARGE_SLAVE_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_SIG_GONE_THR_1000, 0x08);\n+\tmask = YT8824_SIG_GONE_THR_1000;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_SIG_GONE_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_EC_NX_TRAIN_COARSE_TO_1000, 0x40);\n+\tmask = YT8824_EC_NX_TRAIN_COARSE_TO_1000;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_EC_NX_TRAIN_COARSE_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_VGA_IN_LPF2_CAP_OTHER, 0x2);\n+\tmask = YT8824_VGA_IN_LPF2_CAP_OTHER;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_VGA_IN_LPF2_CAP_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_VGA_IN_LPF1_CAP_OTHER, 0x2);\n+\tmask = YT8824_VGA_IN_LPF1_CAP_OTHER;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_VGA_IN_LPF1_CAP_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized EMC CS */\n+\tctrl = FIELD_PREP(YT8824_LDPC_FAIL_THR, 0xFF);\n+\tctrl |= FIELD_PREP(YT8824_LFER_FAIL_THR, 0xFF);\n+\tmask = YT8824_LDPC_FAIL_THR | YT8824_LFER_FAIL_THR;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_LDPC_LFER_FAIL_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_FR_REQ_THR, 0x06);\n+\tmask = YT8824_FR_REQ_THR;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_FR_REQ_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_PRM_SMALL_SHT_2500, 0x0FF);\n+\tmask = YT8824_PRM_SMALL_SHT_2500;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_GN_MU_COARSE_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\t/* optimized EMC RE */\n+\tctrl = FIELD_PREP(YT8824_DAC_AMP_ADJ_CH3_PBO0_2500, 0xF);\n+\tctrl |= FIELD_PREP(YT8824_DAC_AMP_ADJ_CH2_PBO0_2500, 0xF);\n+\tctrl |= FIELD_PREP(YT8824_DAC_AMP_ADJ_CH1_PBO0_2500, 0xF);\n+\tctrl |= FIELD_PREP(YT8824_DAC_AMP_ADJ_CH0_PBO0_2500, 0xF);\n+\tmask = YT8824_DAC_AMP_ADJ_CH3_PBO0_2500 |\n+\t YT8824_DAC_AMP_ADJ_CH2_PBO0_2500 |\n+\t YT8824_DAC_AMP_ADJ_CH1_PBO0_2500 |\n+\t YT8824_DAC_AMP_ADJ_CH0_PBO0_2500;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_DAC_AMP_ADJ_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH3, 0x1F);\n+\tctrl |= FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH2, 0x1F);\n+\tmask = YT8824_P0_DAC_BIAS_CAS_CFG_CH3 | YT8824_P0_DAC_BIAS_CAS_CFG_CH2;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_P0_DAC_BIAS_CAS_CH3_CH2_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH1, 0x1F);\n+\tctrl |= FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH0, 0x1F);\n+\tmask = YT8824_P0_DAC_BIAS_CAS_CFG_CH1 | YT8824_P0_DAC_BIAS_CAS_CFG_CH0;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_P0_DAC_BIAS_CAS_CH1_CH0_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH3, 0x1F);\n+\tctrl |= FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH2, 0x1F);\n+\tmask = YT8824_P1_DAC_BIAS_CAS_CFG_CH3 | YT8824_P1_DAC_BIAS_CAS_CFG_CH2;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_P1_DAC_BIAS_CAS_CH3_CH2_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH1, 0x1F);\n+\tctrl |= FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH0, 0x1F);\n+\tmask = YT8824_P1_DAC_BIAS_CAS_CFG_CH1 | YT8824_P1_DAC_BIAS_CAS_CFG_CH0;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_P1_DAC_BIAS_CAS_CH1_CH0_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_EFUSE_BYPASS_ANALOG_SECOND_RESET, 1);\n+\tctrl |= FIELD_PREP(YT8824_CSR_EFUSE_BYPASS_PLL_TXRX_RESET, 1);\n+\tmask = YT8824_CSR_EFUSE_BYPASS_ANALOG_SECOND_RESET |\n+\t\tYT8824_CSR_EFUSE_BYPASS_PLL_TXRX_RESET;\n+\tret = ytphy_modify_ext_with_lock(phydev,\n+\t\t\t\t\t YT8824_P01_PLL_EN_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH0, 0);\n+\tctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH1, 0);\n+\tctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH2, 0);\n+\tctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH3, 0);\n+\tmask = YT8824_U0_CSR_RESETB_TX_CH0 | YT8824_U0_CSR_RESETB_TX_CH1 |\n+\t\tYT8824_U0_CSR_RESETB_TX_CH2 | YT8824_U0_CSR_RESETB_TX_CH3;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_U0_CSR_RESET_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH0, 0);\n+\tctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH1, 0);\n+\tctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH2, 0);\n+\tctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH3, 0);\n+\tmask = YT8824_U1_CSR_RESETB_TX_CH0 | YT8824_U1_CSR_RESETB_TX_CH1 |\n+\t YT8824_U1_CSR_RESETB_TX_CH2 | YT8824_U1_CSR_RESETB_TX_CH3;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_U1_CSR_RESET_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH0, 1);\n+\tctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH1, 1);\n+\tctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH2, 1);\n+\tctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH3, 1);\n+\tmask = YT8824_U0_CSR_RESETB_TX_CH0 | YT8824_U0_CSR_RESETB_TX_CH1 |\n+\t YT8824_U0_CSR_RESETB_TX_CH2 | YT8824_U0_CSR_RESETB_TX_CH3;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_U0_CSR_RESET_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\n+\tctrl = FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH0, 1);\n+\tctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH1, 1);\n+\tctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH2, 1);\n+\tctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH3, 1);\n+\tmask = YT8824_U1_CSR_RESETB_TX_CH0 | YT8824_U1_CSR_RESETB_TX_CH1 |\n+\t YT8824_U1_CSR_RESETB_TX_CH2 | YT8824_U1_CSR_RESETB_TX_CH3;\n+\tret = ytphy_modify_ext_with_lock(phydev, YT8824_U1_CSR_RESET_REG,\n+\t\t\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore;\n+\t/* reset */\n+\tret = genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_normal;\n+\n+\tret = phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE,\n+\t\t\t BMCR_RESET | BMCR_ANENABLE);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_normal;\n+\tret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val \u0026 BMCR_RESET),\n+\t\t\t\t 50000, 600000, true);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_normal;\n+\n+\tret = genphy_c45_template_testmode(phydev,\n+\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_normal;\n+\treturn 0;\n+\n+err_restore:\n+\tr = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);\n+\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n+\t\tret = r;\n+\treturn ret;\n+\n+err_restore_normal:\n+\tr = genphy_c45_template_testmode(phydev,\n+\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n+\t\tret = r;\n+\tr = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);\n+\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n+\t\tret = r;\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_extern_sds_softreset() - config external phy8824 sds softrest\n+ * @phydev: target phy_device struct\n+ *\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_extern_sds_softreset(struct phy_device *phydev)\n+{\n+\tint old_page = YT8824_RSSR_UTP_SPACE;\n+\tint ret = -1;\n+\tint val = 0;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* TX preamble padded to 8; RX IPG always \u003e 8 */\n+\tret = __phy_read(phydev, MII_RESV1);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret \u0026= ~YT8824_SDS_CFG_MIN_PRE_MASK;\n+\tret |= YT8824_SDS_TX_PRE_PADDING;\n+\tret |= YT8824_SDS_EN_FILL_PRE;\n+\tret = __phy_write(phydev, MII_RESV1, ret);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = __phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE,\n+\t\t\t BMCR_RESET | BMCR_ANENABLE);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* poll while still holding the lock; __phy_read takes no lock */\n+\tret = read_poll_timeout(__phy_read, val,\n+\t\t\t\t(val \u003c 0) || !(val \u0026 BMCR_RESET), 50000, 600000,\n+\t\t\t\ttrue, phydev, MII_BMCR);\n+\tif (val \u003c 0)\n+\t\tret = val;\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_extern_config_sds_init_paged() - config external phy8824 sds init\n+ * @phydev: target phy_device struct\n+ *\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_extern_config_sds_init_paged(struct phy_device *phydev)\n+{\n+\tint old_page = YT8824_RSSR_UTP_SPACE;\n+\tint val_1, val_2, val_3, tmp;\n+\tint ctrl = 0;\n+\tint mask = 0;\n+\tint ret = -1;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* read efuse */\n+\tret = ytphy_read_top_ext(phydev, YT8824_SERDES_PLL_CTRL1_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\telse\n+\t\tval_1 = ret;\n+\n+\tret = ytphy_read_top_ext(phydev, YT8824_SERDES_PLL_CTRL2_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\telse\n+\t\tval_2 = ret;\n+\n+\tret = ytphy_read_top_ext(phydev, YT8824_SERDES_PLL_CTRL3_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\telse\n+\t\tval_3 = ret;\n+\n+\t/* Serdes optimization */\n+\tctrl = FIELD_PREP(YT8824_SERDES_REG_WR_PRT, 1);\n+\tmask = YT8824_SERDES_REG_WR_PRT;\n+\tret = ytphy_modify_ext(phydev, YT8824_WRITE_PROTECT_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_PCS_GLB_RST_BYPASS, 1);\n+\tctrl |= FIELD_PREP(YT8824_CSR_SG_MODE_RST_BYPASS, 1);\n+\tctrl |= FIELD_PREP(YT8824_CSR_US_GLB_RESET_N, 0);\n+\tctrl |= FIELD_PREP(YT8824_CSR_PCS_BEF_TRAINING_DONE_RST_BYPASS, 1);\n+\tmask = YT8824_CSR_PCS_GLB_RST_BYPASS | YT8824_CSR_SG_MODE_RST_BYPASS |\n+\t YT8824_CSR_US_GLB_RESET_N |\n+\t YT8824_CSR_PCS_BEF_TRAINING_DONE_RST_BYPASS;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_WATCH_DOG_ALL_BYPASS, 1);\n+\tmask = YT8824_CSR_WATCH_DOG_ALL_BYPASS;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_PMA_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* analog CDR */\n+\tctrl = FIELD_PREP(YT8824_CDR_MODE, 1);\n+\tmask = YT8824_CDR_MODE;\n+\tret = ytphy_modify_ext(phydev, YT8824_CDR_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* optimized VCO */\n+\tctrl = FIELD_PREP(YT8824_CSR_PLL_VCO_SEL_VCO2_CURRENT, 0x9);\n+\tctrl |= FIELD_PREP(YT8824_CSR_PLL_VCO_ATEMP_R, 0x4);\n+\tmask = YT8824_CSR_PLL_VCO_SEL_VCO2_CURRENT | YT8824_CSR_PLL_VCO_ATEMP_R;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_VCO_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_PLL_VCO_SEL_VCO2_RM_R, 0x0);\n+\tmask = YT8824_CSR_PLL_VCO_SEL_VCO2_RM_R;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_DIVLDO_CTRL_REG,\n+\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* optimized PLL lock */\n+\tret = ytphy_read_ext(phydev, YT8824_DAC_TRIM_MAIN_CFG_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret \u0026= ~(BIT(13) | BIT(12));\n+\ttmp = (val_1 \u0026 (BIT(7) | BIT(6))) \u003e\u003e 6;\n+\tret |= (tmp \u003c\u003c 12);\n+\tret = ytphy_write_ext(phydev, YT8824_DAC_TRIM_MAIN_CFG_REG, ret);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = ytphy_read_ext(phydev, YT8824_PLL_VCO_CFG_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret \u0026= ~(BIT(1) | BIT(0));\n+\ttmp = (val_1 \u0026 (BIT(5) | BIT(4))) \u003e\u003e 4;\n+\tret |= tmp;\n+\tret = ytphy_write_ext(phydev, YT8824_PLL_VCO_CFG_REG, ret);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = ytphy_read_ext(phydev, YT8824_TX_MUX_CH3_CH2_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret \u0026= ~(BIT(13) | BIT(12));\n+\ttmp = (val_3 \u0026 (BIT(1) | BIT(0)));\n+\tret |= (tmp \u003c\u003c 12);\n+\tret = ytphy_write_ext(phydev, YT8824_TX_MUX_CH3_CH2_REG, ret);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_PLL_FBDIV_SYNC_SELB, 1);\n+\tmask = YT8824_CSR_PLL_FBDIV_SYNC_SELB;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_FBDIV_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_PLL_SPARE, 0xf070);\n+\tmask = YT8824_CSR_PLL_SPARE;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_SPARE_CTRL_REG,\n+\t\t\t mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* cable length threshold */\n+\tctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_LNG, 0x7F);\n+\tmask = YT8824_VDAC_AMP_THR_LNG;\n+\tret = ytphy_modify_ext(phydev, YT8824_CDR_MANUAL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_MED, 0x7F);\n+\tctrl |= FIELD_PREP(YT8824_VDAC_AMP_THR_SHT, 0x7F);\n+\tmask = YT8824_VDAC_AMP_THR_MED | YT8824_VDAC_AMP_THR_SHT;\n+\tret = ytphy_modify_ext(phydev, YT8824_TRAINING_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* Serdes training threshold */\n+\tctrl = FIELD_PREP(YT8824_EOD_DURATION_SEL, 0xF);\n+\tctrl |= FIELD_PREP(YT8824_EOD_VTH, 0x14);\n+\tmask = YT8824_EOD_DURATION_SEL | YT8824_EOD_VTH;\n+\tret = ytphy_modify_ext(phydev, YT8824_EOM_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CDR_OFFSET_ERR_WTH, 0x0A);\n+\tctrl |= FIELD_PREP(YT8824_PGA_GAIN_MAX, 0x4);\n+\tctrl |= FIELD_PREP(YT8824_PGA_GAIN_INIT, 0x4);\n+\tmask = YT8824_CDR_OFFSET_ERR_WTH | YT8824_PGA_GAIN_MAX |\n+\t YT8824_PGA_GAIN_INIT;\n+\tret = ytphy_modify_ext(phydev, YT8824_PGA_GAIN_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* digital eye diagram of SerDes */\n+\tctrl = FIELD_PREP(YT8824_EOD_ERR_CNT_THR, 0x0000);\n+\tmask = YT8824_EOD_ERR_CNT_THR;\n+\tret = ytphy_modify_ext(phydev, YT8824_EOD_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* Serdes LDO */\n+\tret = ytphy_read_ext(phydev, YT8824_FFE_CTRL_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret \u0026= ~(BIT(6) | BIT(5) | BIT(4));\n+\ttmp = (val_2 \u0026 (BIT(4) | BIT(3) | BIT(2))) \u003e\u003e 2;\n+\tret |= (tmp \u003c\u003c 4);\n+\tret = ytphy_write_ext(phydev, YT8824_FFE_CTRL_REG, ret);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = ytphy_read_ext(phydev, YT8824_C1_COARSE_CFG_REG);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret \u0026= ~(BIT(10) | BIT(9) | BIT(8));\n+\ttmp = (val_2 \u0026 (BIT(7) | BIT(6) | BIT(5))) \u003e\u003e 5;\n+\tret |= (tmp \u003c\u003c 8);\n+\tret = ytphy_write_ext(phydev, YT8824_C1_COARSE_CFG_REG, ret);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* optimized Serdes RX */\n+\tctrl = FIELD_PREP(YT8824_CSR_AFE_VCM_CFG, 0x5);\n+\tctrl |= FIELD_PREP(YT8824_CSR_AFE_MANUAL_CTRL_1P25G, 0);\n+\tctrl |= FIELD_PREP(YT8824_CSR_AFE_MANUAL_CTRL_3P125G, 0);\n+\tmask = YT8824_CSR_AFE_VCM_CFG | YT8824_CSR_AFE_MANUAL_CTRL_1P25G |\n+\t YT8824_CSR_AFE_MANUAL_CTRL_3P125G;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_DFE_TAP_POLARITY, 1);\n+\tctrl |= FIELD_PREP(YT8824_DFE_IDAC_TUNE, 0x3);\n+\tmask = YT8824_DFE_TAP_POLARITY | YT8824_DFE_IDAC_TUNE;\n+\tret = ytphy_modify_ext(phydev, YT8824_DFE_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_CDR_OFFSET_DATA, 0x7C);\n+\tmask = YT8824_CSR_CDR_OFFSET_DATA;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_CDR_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_DFE_VDAC_CODE_THR, 0x7F);\n+\tmask = YT8824_DFE_VDAC_CODE_THR;\n+\tret = ytphy_modify_ext(phydev, YT8824_DFE_VDAC_CODE_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_RX_SPARE_REG, 0xff08);\n+\tmask = YT8824_RX_SPARE_REG;\n+\tret = ytphy_modify_ext(phydev, YT8824_RX_SPARE_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* optimized Serdes TX */\n+\tctrl = FIELD_PREP(YT8824_DFE_VDAC_TUNE, 0x1);\n+\tctrl |= FIELD_PREP(YT8824_DFE_VDAC_SEL, 0x0);\n+\tmask = YT8824_DFE_VDAC_TUNE | YT8824_DFE_VDAC_SEL;\n+\tret = ytphy_modify_ext(phydev, YT8824_DFE_VDAC_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_TX_PRE_SEL, 0x6);\n+\tmask = YT8824_CSR_TX_PRE_SEL;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_TX_PRE_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* Serdes manual config */\n+\tctrl = FIELD_PREP(YT8824_CSR_AFE_CTLE_BW, 0x0);\n+\tmask = YT8824_CSR_AFE_CTLE_BW;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL1_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_AFE_PGA_BW, 0x7);\n+\tctrl |= FIELD_PREP(YT8824_CSR_AFE_BUF_BW, 0x7);\n+\tmask = YT8824_CSR_AFE_PGA_BW | YT8824_CSR_AFE_BUF_BW;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL2_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_CSR_AFE_MANUAL_CTRL_10P3125G, 0x1);\n+\tmask = YT8824_CSR_AFE_MANUAL_CTRL_10P3125G;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* restart calibration */\n+\tctrl = FIELD_PREP(YT8824_CUR_TX_SEQ, 0x5);\n+\tctrl |= FIELD_PREP(YT8824_CUR_RX_SEQ, 0x6);\n+\tctrl |= FIELD_PREP(YT8824_CALIB_SEQ_FINISH, 1);\n+\tctrl |= FIELD_PREP(YT8824_CALIB_SEQ_SW_RST, 1);\n+\tmask = YT8824_CUR_TX_SEQ | YT8824_CUR_RX_SEQ |\n+\t YT8824_CALIB_SEQ_FINISH | YT8824_CALIB_SEQ_SW_RST;\n+\tret = ytphy_modify_ext(phydev, YT8824_CSR_DCC_CAL_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_MED, 0x7F);\n+\tctrl |= FIELD_PREP(YT8824_VDAC_AMP_THR_SHT, 0xFF);\n+\tmask = YT8824_VDAC_AMP_THR_MED | YT8824_VDAC_AMP_THR_SHT;\n+\tret = ytphy_modify_ext(phydev, YT8824_TRAINING_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_MED, 0x7F);\n+\tctrl |= FIELD_PREP(YT8824_VDAC_AMP_THR_SHT, 0x7F);\n+\tmask = YT8824_VDAC_AMP_THR_MED | YT8824_VDAC_AMP_THR_SHT;\n+\tret = ytphy_modify_ext(phydev, YT8824_TRAINING_CTRL_REG, mask, ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* restart to calibration */\n+\tret = ytphy_write_ext(phydev, YT8824_RESTART_CAL_CTRL_REG, 0x0040);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = ytphy_write_ext(phydev, YT8824_RESTART_CAL_CTRL_REG, 0x0);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_config_init() - phy initializatioin\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_config_init(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tif (priv-\u003epackage_mode == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\tret = yt8824_config_utp_init_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err;\n+\t} else {\n+\t\tif (!priv-\u003esds_initialized) {\n+\t\t\tret = yt8824_extern_config_sds_init_paged(phydev);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err;\n+\t\t\tpriv-\u003esds_initialized = true;\n+\t\t}\n+\t\t/*\n+\t\t * Configuring the MII registers of the SDS,\n+\t\t * which are private to each channel.\n+\t\t */\n+\t\tret = yt8824_extern_sds_softreset(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err;\n+\n+\t\tret = yt8824_config_utp_init_paged(phydev);\n \t\tif (ret \u003c 0)\n-\t\t\tgoto err_restore_page;\n+\t\t\tgoto err;\n \t}\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\tret = yt8824_soft_reset(phydev);\n \n-err_restore_page:\n-\treturn phy_restore_page(phydev, old_page, ret);\n+\tphydev_dbg(phydev, \"%s done, phy addr: %d\\n\", __func__,\n+\t\t phydev-\u003emdio.addr);\n+\treturn ret;\n+err:\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\treturn ret;\n }\n \n static int yt8531_set_wol(struct phy_device *phydev,\n@@ -3240,6 +4701,450 @@ static int yt8821_resume(struct phy_device *phydev)\n \treturn yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);\n }\n \n+/**\n+ * yt8824_get_features - read mmd register to get 2.5G capability\n+ * @phydev: target phy_device struct\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_get_features(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\tgoto err;\n+\tret = yt8821_get_features(phydev);\n+\n+err:\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_aneg_done() - check negotiation state.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: auto-negotiation complete status or negative errno code\n+ */\n+static int yt8824_aneg_done(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint auto_neg;\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\tgoto err;\n+\n+\tret = phy_read(phydev, MII_BMSR);\n+\tif (ret \u003c 0)\n+\t\tgoto err;\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\tauto_neg = !!(ret \u0026 BMSR_ANEGCOMPLETE);\n+\n+\tphydev_dbg(phydev, \"%s, phy addr: %d, auto negotiation done: %d\\n\",\n+\t\t __func__, phydev-\u003emdio.addr, auto_neg);\n+\treturn auto_neg;\n+err:\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_read_status_paged() - determines the speed and duplex of one page\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_read_status_paged(struct phy_device *phydev)\n+{\n+\tint ret;\n+\tint val;\n+\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tret = genphy_read_status(phydev);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tif (phydev-\u003eautoneg == AUTONEG_ENABLE \u0026\u0026 phydev-\u003eautoneg_complete) {\n+\t\tret = genphy_c45_read_lpa(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t}\n+\n+\tif (!phydev-\u003elink) {\n+\t\tphydev-\u003espeed = SPEED_UNKNOWN;\n+\t\tphydev-\u003eduplex = DUPLEX_UNKNOWN;\n+\t\tif (phydev-\u003eautoneg == AUTONEG_ENABLE)\n+\t\t\tphy_resolve_aneg_pause(phydev);\n+\t\treturn 0;\n+\t}\n+\n+\tret = phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tval = ret;\n+\n+\tyt8821_adjust_status(phydev, val);\n+\n+\tif (phydev-\u003eautoneg == AUTONEG_ENABLE)\n+\t\tphy_resolve_aneg_pause(phydev);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * yt8824_read_status() - determines the negotiated speed and duplex\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_read_status(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tret = yt8824_read_status_paged(phydev);\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_utp_power_on(): utp power on.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_utp_power_on(struct phy_device *phydev)\n+{\n+\tint ret = 0;\n+\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0x0);\n+}\n+\n+/**\n+ * yt8824_utp_power_down(): utp power down.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_utp_power_down(struct phy_device *phydev)\n+{\n+\tint ret;\n+\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);\n+}\n+\n+/**\n+ * yt8824_power_on() - set utp power on.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * NOTE: need WA like softreset\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_power_on(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\tint r;\n+\n+\tif (priv-\u003epackage_mode == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_power_on(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\t} else {\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_sds_isolate_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_power_on(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_sds_isolate_and_softreset_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\t}\n+\treturn 0;\n+\n+retry:\n+\t/*\n+\t * If the PHY up operation succeeds but the subsequent operation\n+\t * fails, revert to the default state.\n+\t */\n+\tr = yt8824_utp_power_down(phydev);\n+\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n+\t\tret = r;\n+\tret = yt8824_restore_working_status(phydev, ret);\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_resume() - resume the hardware\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_resume(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tret = yt8824_power_on(phydev);\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_power_down() - set utp power down.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * NOTE: need WA like softreset\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_power_down(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\tint r;\n+\n+\tif (priv-\u003epackage_mode == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_power_down(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\t} else {\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_sds_isolate_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_power_down(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_utp_set_template_test_mode(phydev,\n+\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\n+\t\tret = yt8824_sds_isolate_and_softreset_paged(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto retry;\n+\t}\n+\treturn 0;\n+\n+retry:\n+\t/*\n+\t * If the PHY down operation succeeds but the subsequent operation\n+\t * fails, revert to the default state.\n+\t */\n+\tr = yt8824_utp_power_on(phydev);\n+\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n+\t\tret = r;\n+\tret = yt8824_restore_working_status(phydev, ret);\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_suspend() - suspend the hardware\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_suspend(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tret = yt8824_power_down(phydev);\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * yt8824_config_aneg() - config negotiation\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_config_aneg(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tint phy_ctrl = 0;\n+\tint ret;\n+\n+\tmutex_lock(\u0026priv-\u003eshared_lock);\n+\tret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (ret \u003c 0)\n+\t\tgoto err;\n+\n+\t/*\n+\t * Only advertise 2.5G when autoneg is enabled, or when 2.5G is\n+\t * explicitly forced. When a different speed is forced, clear\n+\t * ADV2_5G so a 2.5G-capable link partner cannot negotiate 2.5G.\n+\t * __genphy_config_aneg() only rewrites the\n+\t * clause 22 registers on the forced-speed path, so it will not\n+\t * clear this bit.\n+\t */\n+\tif ((phydev-\u003eautoneg == AUTONEG_ENABLE ||\n+\t phydev-\u003espeed == SPEED_2500) \u0026\u0026\n+\t linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,\n+\t\t\t phydev-\u003eadvertising))\n+\t\tphy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;\n+\n+\tret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,\n+\t\t\t\t MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);\n+\tif (ret \u003c 0)\n+\t\tgoto err;\n+\n+\tret = __genphy_config_aneg(phydev, ret);\n+\n+err:\n+\tmutex_unlock(\u0026priv-\u003eshared_lock);\n+\treturn ret;\n+}\n+\n+/**\n+ * phy_mode_check() - check if mode names the PHY interface.\n+ * @mode: PHY interface mode string\n+ * @interface: PHY interface mode to compare against\n+ *\n+ * Return: true if @mode matches @interface, false otherwise.\n+ */\n+static bool phy_mode_check(const char *mode, int interface)\n+{\n+\treturn !strcasecmp(mode, phy_modes(interface));\n+}\n+\n+/**\n+ * yt8824_phy_package_probe_once() - init phy package for phy8824.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_phy_package_probe_once(struct phy_device *phydev)\n+{\n+\tstruct yt8824_shared_priv *priv = phy_package_get_priv(phydev);\n+\tstruct device_node *np = phy_package_get_node(phydev);\n+\tconst char *mode;\n+\n+\tif (!priv || !np) {\n+\t\tphydev_err(phydev, \"%s: missing shared priv or DT node\\n\",\n+\t\t\t __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\t/* Initialise shared lock for YT8824 */\n+\tmutex_init(\u0026priv-\u003eshared_lock);\n+\tpriv-\u003esds_initialized = false;\n+\tpriv-\u003epackage_mode = PHY_INTERFACE_MODE_INTERNAL;\n+\tif (!of_property_read_string(np, \"motorcomm,package-mode\",\n+\t\t\t\t \u0026mode)) {\n+\t\tif (phy_mode_check(mode, PHY_INTERFACE_MODE_INTERNAL)) {\n+\t\t\tpriv-\u003epackage_mode = PHY_INTERFACE_MODE_INTERNAL;\n+\t\t} else if (phy_mode_check(mode,\n+\t\t\t\t\t PHY_INTERFACE_MODE_10G_QXGMII)) {\n+\t\t\tpriv-\u003epackage_mode = PHY_INTERFACE_MODE_10G_QXGMII;\n+\t\t} else {\n+\t\t\tphydev_err(phydev, \"unsupported package-mode %s\\n\",\n+\t\t\t\t mode);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t} else {\n+\t\tphydev_err(phydev, \"missing package-mode in PHY package node.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * yt8824_probe() - phy8824 probe.\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_probe(struct phy_device *phydev)\n+{\n+\tstruct device *dev = \u0026phydev-\u003emdio.dev;\n+\tstruct yt8824_shared_priv *shared_priv;\n+\tint ret;\n+\n+\tret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Ensure other PHY probes wait for shared mutex initialization. */\n+\tphy_package_lock(phydev);\n+\tif (phy_package_probe_once(phydev)) {\n+\t\tret = yt8824_phy_package_probe_once(phydev);\n+\t\tif (ret) {\n+\t\t\tphy_package_unlock(phydev);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\tphy_package_unlock(phydev);\n+\n+\treturn 0;\n+}\n+\n static struct phy_driver motorcomm_phy_drvs[] = {\n \t{\n \t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8511),\n@@ -3337,13 +5242,29 @@ static struct phy_driver motorcomm_phy_drvs[] = {\n \t\t.suspend\t\t= yt8821_suspend,\n \t\t.resume\t\t\t= yt8821_resume,\n \t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8824),\n+\t\t.name = \"YT8824 Quad Ports 2.5Gbps Ethernet\",\n+\t\t.get_features = yt8824_get_features,\n+\t\t.read_page = yt8824_read_page,\n+\t\t.write_page = yt8824_write_page,\n+\t\t.probe = yt8824_probe,\n+\t\t.config_aneg = yt8824_config_aneg,\n+\t\t.aneg_done = yt8824_aneg_done,\n+\t\t.config_init = yt8824_config_init,\n+\t\t.read_status = yt8824_read_status,\n+\t\t.soft_reset = yt8824_soft_reset,\n+\t\t.suspend = yt8824_suspend,\n+\t\t.resume = yt8824_resume,\n+\t},\n };\n \n module_phy_driver(motorcomm_phy_drvs);\n \n-MODULE_DESCRIPTION(\"Motorcomm 8511/8521/8531/8531S/861x/8821 PHY driver\");\n+MODULE_DESCRIPTION(\"Motorcomm 8511/8521/8531/8531S/861x/8821/8824 PHY driver\");\n MODULE_AUTHOR(\"Peter Geis\");\n MODULE_AUTHOR(\"Frank\");\n+MODULE_AUTHOR(\"Kyle\");\n MODULE_LICENSE(\"GPL\");\n \n static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {\n@@ -3354,6 +5275,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {\n \t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },\n \t{ PHY_ID_MATCH_EXACT(PHY_ID_INT861X) },\n \t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8821) },\n+\t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8824) },\n \t{ /* sentinel */ }\n };\n \ndiff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c\nindex 870920311f9a0..c5f5753f7194b 100644\n--- a/drivers/net/phy/phy-c45.c\n+++ b/drivers/net/phy/phy-c45.c\n@@ -1408,6 +1408,29 @@ int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable)\n }\n EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain);\n \n+/**\n+ * genphy_c45_template_testmode - configure template testmode registers\n+ * @phydev: target phy_device struct\n+ * @test_mode: testmode includes Normal to Test mode 7\n+ *\n+ * Description: Set template testmode include Normal to Test mode 7\n+ *\n+ * Return: 0 on success, or a negative error code on failure (e.g. register\n+ * read/write error).\n+ */\n+int genphy_c45_template_testmode(struct phy_device *phydev, u16 test_mode)\n+{\n+\tu16 ctrl;\n+\n+\tif (test_mode \u003e MDIO_PMA_10GBT_TESTMODE_7)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tctrl = FIELD_PREP(MDIO_PMA_10GBT_TESTMODE_MASK, test_mode);\n+\treturn phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TESTMODE,\n+\t\t\t MDIO_PMA_10GBT_TESTMODE_MASK, ctrl);\n+}\n+EXPORT_SYMBOL_GPL(genphy_c45_template_testmode);\n+\n /**\n * genphy_c45_plca_get_cfg - get PLCA configuration from standard registers\n * @phydev: target phy_device struct\ndiff --git a/include/linux/phy.h b/include/linux/phy.h\nindex a5a419bc400ec..81cb7f15bb72e 100644\n--- a/include/linux/phy.h\n+++ b/include/linux/phy.h\n@@ -2359,6 +2359,7 @@ int genphy_c45_loopback(struct phy_device *phydev, bool enable, int speed);\n int genphy_c45_pma_resume(struct phy_device *phydev);\n int genphy_c45_pma_suspend(struct phy_device *phydev);\n int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable);\n+int genphy_c45_template_testmode(struct phy_device *phydev, u16 test_mode);\n int genphy_c45_plca_get_cfg(struct phy_device *phydev,\n \t\t\t struct phy_plca_cfg *plca_cfg);\n int genphy_c45_plca_set_cfg(struct phy_device *phydev,\ndiff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h\nindex 06f4bc3c20c71..353ca13c64fca 100644\n--- a/include/uapi/linux/mdio.h\n+++ b/include/uapi/linux/mdio.h\n@@ -63,6 +63,7 @@\n /* Media-dependent registers. */\n #define MDIO_PMA_10GBT_SWAPPOL\t130\t/* 10GBASE-T pair swap \u0026 polarity */\n #define MDIO_PMA_10GBT_TXPWR\t131\t/* 10GBASE-T TX power control */\n+#define MDIO_PMA_10GBT_TESTMODE 132 /* Test mode control */\n #define MDIO_PMA_10GBT_SNR\t133\t/* 10GBASE-T SNR margin, lane A.\n \t\t\t\t\t * Lanes B-D are numbered 134-136. */\n #define MDIO_PMA_10GBR_FSRT_CSR\t147\t/* 10GBASE-R fast retrain status and control */\n@@ -320,6 +321,17 @@\n /* PMA 10GBASE-R Fast Retrain status and control register. */\n #define MDIO_PMA_10GBR_FSRT_ENABLE\t0x0001\t/* Fast retrain enable */\n \n+/* PMA 10GBASE-T Template Test Mode Register*/\n+#define MDIO_PMA_10GBT_TESTMODE_MASK GENMASK(15, 13) /* Template test mode */\n+#define MDIO_PMA_10GBT_TESTMODE_NORMAL 0x0 /* Template Normal */\n+#define MDIO_PMA_10GBT_TESTMODE_1 0x1 /* Template TestMode1 */\n+#define MDIO_PMA_10GBT_TESTMODE_2 0x2 /* Template TestMode2 */\n+#define MDIO_PMA_10GBT_TESTMODE_3 0x3 /* Template TestMode3 */\n+#define MDIO_PMA_10GBT_TESTMODE_4 0x4 /* Template TestMode4 */\n+#define MDIO_PMA_10GBT_TESTMODE_5 0x5 /* Template TestMode5 */\n+#define MDIO_PMA_10GBT_TESTMODE_6 0x6 /* Template TestMode6 */\n+#define MDIO_PMA_10GBT_TESTMODE_7 0x7 /* Template TestMode7 */\n+\n /* PCS 10GBASE-R/-T status register 1. */\n #define MDIO_PCS_10GBRT_STAT1_BLKLK\t0x0001\t/* Block lock attained */\n \n"
} |
| 2/1 | 2026/10/20 06:14 | agent | patch-evaluator |
1mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series introduces support for the Motorcomm YT8824 Quad 2.5Gbps Ethernet PHY in drivers/net/phy/motorcomm.c, along with a Device Tree binding and a Clause 45 PMA testmode helper in drivers/net/phy/phy-c45.c. The YT8824 driver represents physical ASIC Ethernet PHY hardware that strictly requires specific Device Tree structures (an ethernet-phy-package parent node with motorcomm,package-mode property checked in yt8824_probe via devm_of_phy_package_join). This hardware is not present or emulated in standard virtualized fuzzing environments (QEMU/GCE on amd64). The helper function genphy_c45_template_testmode() is only called by the YT8824 driver, and the minor change in ytphy_set_wol() is functionally identical to the existing code. Consequently, the modified executable code is structurally unreachable.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit e5aba756d67e6212999c9444868981aaf3cf7351
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Oct 20 06:14:18 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml b/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml
new file mode 100644
index 0000000000000..4c67f8afcf27a
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/motorcomm,yt8824.yaml
@@ -0,0 +1,78 @@
+# 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 <kyle.switch@motor-comm.com>
+
+description:
+ Motorcomm YT8824 Ethernet PHY is a PHY package of 4 PHYs.
+
+$ref: ethernet-phy-package.yaml#
+
+properties:
+ compatible:
+ enum:
+ - motorcomm,yt8824-package
+
+ motorcomm,package-mode:
+ description: |
+ PHY package can be configured in 2 modes:
+ - internal: YT8824 is embedded in the switch, using
+ an internal interface to the MAC.
+ - 10g-qxgmii: YT8824 is a standalone external PHY,
+ connected via 10G QXGMII.
+ $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 the base MDIO address of the four
+ member PHYs plus 4, where base is typically 0x0.
+ Note that this is NOT the reg of the first member PHY.
+
+required:
+ - compatible
+ - motorcomm,package-mode
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet-phy-package@9 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "motorcomm,yt8824-package";
+ reg = <9>;
+
+ motorcomm,package-mode = "internal";
+
+ ethernet-phy@4 {
+ reg = <4>;
+ };
+
+ ethernet-phy@5 {
+ reg = <5>;
+ };
+
+ ethernet-phy@6 {
+ reg = <6>;
+ };
+
+ ethernet-phy@7 {
+ reg = <7>;
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 23e9194483d9b..ac8e12e7b8392 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18424,8 +18424,10 @@ F: drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c
MOTORCOMM PHY DRIVER
M: Frank <Frank.Sae@motor-comm.com>
+M: Kyle Switch <kyle.switch@motor-comm.com>
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
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 30e9d22c8d1a3..04593a770e433 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -361,10 +361,12 @@ config MICROSEMI_PHY
config MOTORCOMM_PHY
tristate "Motorcomm PHYs"
+ select PHY_PACKAGE
help
Enables support for Motorcomm network PHYs.
Currently supports YT85xx Gigabit Ethernet PHYs, YT861x PHYs
- integrated in YT921x switches, and YT8821 2.5Gbps PHYs.
+ integrated in YT921x switches, YT8821 2.5Gbps PHYs and YT8824 4 * 2.5G
+ PHYs.
config NATIONAL_PHY
tristate "National Semiconductor PHYs"
diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
index 463e1ea3efc93..6628ebcca0819 100644
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -1,19 +1,25 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Motorcomm 8511/8521/8522/8531/8531S/861x/8821 PHY driver.
+ * Motorcomm 8511/8521/8522/8531/8531S/861x/8821/8824 PHY driver.
*
* Author: Peter Geis <pgwipeout@gmail.com>
* Author: Frank <Frank.Sae@motor-comm.com>
+ * Author: Kyle <kyle.switch@motor-comm.com>
*/
#include <linux/clk.h>
#include <linux/etherdevice.h>
#include <linux/ethtool_netlink.h>
#include <linux/kernel.h>
+#include <linux/mdio.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/property.h>
+#include "phylib.h"
+
#define PHY_ID_YT8511 0x0000010a
#define PHY_ID_YT8521 0x0000011a
#define PHY_ID_YT8522 0x4f51e928
@@ -22,6 +28,7 @@
/* Live captured from YT921x switch internal MDIO bus */
#define PHY_ID_INT861X 0x01e04281
#define PHY_ID_YT8821 0x4f51ea19
+#define PHY_ID_YT8824 0x4f51e8b8
/* YT8521/YT8531S/YT8821 Register Overview
* UTP Register space | FIBER Register space
* ------------------------------------------------------------
@@ -33,6 +40,18 @@
* ------------------------------------------------------------
*/
+/* 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 */
/* Specific Function Control Register */
@@ -397,6 +416,226 @@
#define YT8821_CHIP_MODE_AUTO_BX2500_SGMII 0
#define YT8821_CHIP_MODE_FORCE_BX2500 1
+#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)
+
+/* PHY8824 UTP init registers */
+#define YT8824_WRITE_PROTECT_CAL_REG 0x1
+#define YT8824_WRITE_PROTECT BIT(0)
+#define YT8824_PLL_VCO_ATEMP_REG 0xa20e
+#define YT8824_PLL_VCO_SEL_CURRENT GENMASK(7, 4)
+#define YT8824_PLL_VCO_SEL_CURRENT_B 0xb
+#define YT8824_PLL_PFD_CTRL_REG 0xa20a
+#define YT8824_PLL_VCO_ICOSTANT GENMASK(9, 4)
+#define YT8824_PLL_VCO_ATEMP_1_REG 0xa20c
+#define YT8824_PLL_VCO_IPTAT GENMASK(5, 0)
+#define YT8824_PLL_DAC_0_REG 0xa2b6
+#define YT8824_PLL_DAC_RST BIT(10)
+#define YT8824_IF_CTRL_REG 0xa003
+#define YT8824_U0_U1_ENABLE_ODD_PREAMBLE GENMASK(1, 0)
+#define YT8824_IDLE_CTRL_REG 0x3d0
+#define YT8824_IDLE_DETECT BIT(9)
+#define YT8824_TRACE_GAIN_THR_REG 0x372
+#define YT8824_TRACE_LNG_GAIN_THR_2500 GENMASK(14, 8)
+#define YT8824_TRACE_MED_GAIN_THR_2500 GENMASK(6, 0)
+#define YT8824_PRM_LONG_REG 0x37C
+#define YT8824_PRM_LARGE_SLAVE_2500 GENMASK(10, 0)
+#define YT8824_PRM_SMALL_REG 0x388
+#define YT8824_PRM_SMALL_LNG_2500 GENMASK(10, 0)
+#define YT8824_FAST_RETRAIN_REG 0x359
+#define YT8824_LINK_FAIL_SIG GENMASK(13, 8)
+#define YT8824_EN_GATE_CTRL_REG 0xc
+#define YT8824_EN_GATE_GMII_CLK BIT(0)
+#define YT8824_DAC_CFG_REG 0xa2fa
+#define YT8824_POWER_SAVE GENMASK(15, 0)
+#define YT8824_DAC_BIAS_CFG_REG 0x4e2
+#define YT8824_DAC_BIAS_CFG_2500 GENMASK(9, 5)
+#define YT8824_DAC_IMID_CFG_REG 0x47e
+#define YT8824_DAC_IMID_CH2 GENMASK(6, 0)
+#define YT8824_DAC_IMID_CH3 GENMASK(14, 8)
+#define YT8824_DAC_IMID_CFG1_REG 0x47f
+#define YT8824_DAC_IMID_CH0 GENMASK(6, 0)
+#define YT8824_DAC_IMID_CH1 GENMASK(14, 8)
+#define YT8824_DAC_IMSB_CFG_REG 0x480
+#define YT8824_DAC_IMSB_CH2 GENMASK(6, 0)
+#define YT8824_DAC_IMSB_CH3 GENMASK(14, 8)
+#define YT8824_DAC_IMSB_CFG1_REG 0x481
+#define YT8824_DAC_IMSB_CH0 GENMASK(6, 0)
+#define YT8824_DAC_IMSB_CH1 GENMASK(14, 8)
+#define YT8824_TRACE_LNG_GAIN_REG 0x336
+#define YT8824_TRACE_LNG_GAIN_THR GENMASK(14, 8)
+#define YT8824_TRACE_MED_GAIN_REG 0x340
+#define YT8824_TRACE_MED_GAIN_THR GENMASK(6, 0)
+#define YT8824_DAC_IMID_CH2_CH3_CFG_ORG_REG 0x46e
+#define YT8824_DAC_IMID_CH3_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMID_CH2_ORG GENMASK(6, 0)
+#define YT8824_DAC_IMID_CH0_CH1_CFG_ORG_REG 0x46f
+#define YT8824_DAC_IMID_CH1_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMID_CH0_ORG GENMASK(6, 0)
+#define YT8824_DAC_IMSB_CH2_CH3_CFG_ORG_REG 0x470
+#define YT8824_DAC_IMSB_CH3_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMSB_CH2_ORG GENMASK(6, 0)
+#define YT8824_DAC_IMSB_CH0_CH1_CFG_ORG_REG 0x471
+#define YT8824_DAC_IMSB_CH1_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMSB_CH0_ORG GENMASK(6, 0)
+#define YT8824_TRACE_LNG_GAIN_100_REG 0x030b
+#define YT8824_TRACE_LNG_GAIN_THR_100 GENMASK(14, 8)
+#define YT8824_TRACE_MED_GAIN_THR_100 GENMASK(6, 0)
+#define YT8824_CABLE_VSHT_REG 0x071f
+#define YT8824_CABLE_VSHT_THR_S GENMASK(6, 0)
+#define YT8824_DAC_LPFIL_CH2_CH3_ADJ_REG 0x046b
+#define YT8824_DAC_LPFIL_ADJ_CH3_10 GENMASK(12, 8)
+#define YT8824_DAC_LPFIL_ADJ_CH2_10 GENMASK(4, 0)
+#define YT8824_DAC_LPFIL_CH0_CH1_ADJ_REG 0x046c
+#define YT8824_DAC_LPFIL_ADJ_CH1_10 GENMASK(12, 8)
+#define YT8824_DAC_LPFIL_ADJ_CH0_10 GENMASK(4, 0)
+#define YT8824_DAC_IMID_CFG_CH2_CH3_10_ORG 0x0466
+#define YT8824_DAC_IMID_CFG_CH3_10_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMID_CFG_CH2_10_ORG GENMASK(6, 0)
+#define YT8824_DAC_IMID_CFG_CH0_CH1_10_ORG 0x0467
+#define YT8824_DAC_IMID_CFG_CH1_10_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMID_CFG_CH0_10_ORG GENMASK(6, 0)
+#define YT8824_DAC_IMSB_CFG_CH2_CH3_10_ORG 0x0468
+#define YT8824_DAC_IMSB_CFG_CH3_10_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMSB_CFG_CH2_10_ORG GENMASK(6, 0)
+#define YT8824_DAC_IMSB_CFG_CH0_CH1_10_ORG 0x0469
+#define YT8824_DAC_IMSB_CFG_CH1_10_ORG GENMASK(14, 8)
+#define YT8824_DAC_IMSB_CFG_CH0_10_ORG GENMASK(6, 0)
+#define YT8824_FFE_REG 0x034a
+#define YT8824_WAIT_TO_1000 GENMASK(15, 8)
+#define YT8824_FFE_SUM_THRES GENMASK(2, 0)
+#define YT8824_EN_GATE_REG 0x00f8
+#define YT8824_EN_GATE_PHYDBG BIT(10)
+#define YT8824_EN_GATE_BT1000 BIT(9)
+#define YT8824_CNT_REG 0x0059
+#define YT8824_CNT_ERR_AUTO BIT(14)
+#define YT8824_PRM_LARGE_MASTER_REG 0x032c
+#define YT8824_PRM_LARGE_MASTER_1000 GENMASK(10, 0)
+#define YT8824_PRM_LARGE_SLAVE_REG 0x032d
+#define YT8824_PRM_LARGE_SLAVE_1000 GENMASK(10, 0)
+#define YT8824_SIG_GONE_REG 0x032e
+#define YT8824_SIG_GONE_THR_1000 GENMASK(7, 0)
+#define YT8824_EC_NX_TRAIN_COARSE_REG 0x0322
+#define YT8824_EC_NX_TRAIN_COARSE_TO_1000 GENMASK(7, 0)
+#define YT8824_VGA_IN_LPF2_CAP_REG 0x04d3
+#define YT8824_VGA_IN_LPF2_CAP_OTHER GENMASK(7, 4)
+#define YT8824_VGA_IN_LPF1_CAP_REG 0x04d2
+#define YT8824_VGA_IN_LPF1_CAP_OTHER GENMASK(7, 4)
+#define YT8824_LDPC_LFER_FAIL_REG 0x00c8
+#define YT8824_LDPC_FAIL_THR GENMASK(15, 8)
+#define YT8824_LFER_FAIL_THR GENMASK(7, 0)
+#define YT8824_FR_REQ_REG 0x00be
+#define YT8824_FR_REQ_THR GENMASK(4, 0)
+#define YT8824_GN_MU_COARSE_REG 0x037a
+#define YT8824_PRM_SMALL_SHT_2500 GENMASK(10, 0)
+#define YT8824_DAC_AMP_ADJ_REG 0x0482
+#define YT8824_DAC_AMP_ADJ_CH3_PBO0_2500 GENMASK(15, 12)
+#define YT8824_DAC_AMP_ADJ_CH2_PBO0_2500 GENMASK(11, 8)
+#define YT8824_DAC_AMP_ADJ_CH1_PBO0_2500 GENMASK(7, 4)
+#define YT8824_DAC_AMP_ADJ_CH0_PBO0_2500 GENMASK(3, 0)
+#define YT8824_P0_DAC_BIAS_CAS_CH3_CH2_REG 0xa2d5
+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH3 GENMASK(12, 8)
+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH2 GENMASK(4, 0)
+#define YT8824_P0_DAC_BIAS_CAS_CH1_CH0_REG 0xa2d6
+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH1 GENMASK(12, 8)
+#define YT8824_P0_DAC_BIAS_CAS_CFG_CH0 GENMASK(4, 0)
+#define YT8824_P1_DAC_BIAS_CAS_CH3_CH2_REG 0xa2d7
+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH3 GENMASK(12, 8)
+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH2 GENMASK(4, 0)
+#define YT8824_P1_DAC_BIAS_CAS_CH1_CH0_REG 0xa2d8
+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH1 GENMASK(12, 8)
+#define YT8824_P1_DAC_BIAS_CAS_CFG_CH0 GENMASK(4, 0)
+#define YT8824_P01_PLL_EN_REG 0xa218
+#define YT8824_CSR_EFUSE_BYPASS_ANALOG_SECOND_RESET BIT(6)
+#define YT8824_CSR_EFUSE_BYPASS_PLL_TXRX_RESET BIT(5)
+#define YT8824_U0_CSR_RESET_REG 0xa01d
+#define YT8824_U0_CSR_RESETB_TX_CH0 BIT(3)
+#define YT8824_U0_CSR_RESETB_TX_CH1 BIT(2)
+#define YT8824_U0_CSR_RESETB_TX_CH2 BIT(1)
+#define YT8824_U0_CSR_RESETB_TX_CH3 BIT(0)
+#define YT8824_U1_CSR_RESET_REG 0xa01e
+#define YT8824_U1_CSR_RESETB_TX_CH0 BIT(3)
+#define YT8824_U1_CSR_RESETB_TX_CH1 BIT(2)
+#define YT8824_U1_CSR_RESETB_TX_CH2 BIT(1)
+#define YT8824_U1_CSR_RESETB_TX_CH3 BIT(0)
+/* External PHY8824 serdes init registers */
+#define YT8824_SERDES_PLL_CTRL1_REG 0xa13e
+#define YT8824_SERDES_PLL_CTRL2_REG 0xa13f
+#define YT8824_SERDES_PLL_CTRL3_REG 0xa140
+#define YT8824_WRITE_PROTECT_REG 0x4be
+#define YT8824_SERDES_REG_WR_PRT BIT(2)
+#define YT8824_CSR_CTRL_REG 0x49f
+#define YT8824_CSR_PCS_GLB_RST_BYPASS BIT(10)
+#define YT8824_CSR_SG_MODE_RST_BYPASS BIT(9)
+#define YT8824_CSR_US_GLB_RESET_N BIT(7)
+#define YT8824_CSR_PCS_BEF_TRAINING_DONE_RST_BYPASS BIT(2)
+#define YT8824_CSR_PMA_CTRL_REG 0x4a9
+#define YT8824_CSR_WATCH_DOG_ALL_BYPASS BIT(7)
+#define YT8824_CDR_CTRL_REG 0x406
+#define YT8824_CDR_MODE BIT(11)
+#define YT8824_CSR_PLL_VCO_CTRL_REG 0x438
+#define YT8824_CSR_PLL_VCO_SEL_VCO2_CURRENT GENMASK(15, 12)
+#define YT8824_CSR_PLL_VCO_ATEMP_R GENMASK(2, 0)
+#define YT8824_CSR_PLL_DIVLDO_CTRL_REG 0x439
+#define YT8824_CSR_PLL_VCO_SEL_VCO2_RM_R GENMASK(1, 0)
+#define YT8824_CSR_PLL_FBDIV_REG 0x043a
+#define YT8824_CSR_PLL_FBDIV_SYNC_SELB BIT(1)
+#define YT8824_CSR_PLL_SPARE_CTRL_REG 0x042a
+#define YT8824_CSR_PLL_SPARE GENMASK(15, 0)
+#define YT8824_CDR_MANUAL_REG 0x0491
+#define YT8824_VDAC_AMP_THR_LNG GENMASK(6, 0)
+#define YT8824_TRAINING_CTRL_REG 0x0492
+#define YT8824_VDAC_AMP_THR_MED GENMASK(14, 8)
+#define YT8824_VDAC_AMP_THR_SHT GENMASK(7, 0)
+#define YT8824_EOM_CTRL_REG 0x0454
+#define YT8824_EOD_DURATION_SEL GENMASK(11, 8)
+#define YT8824_EOD_VTH GENMASK(6, 0)
+#define YT8824_PGA_GAIN_CTRL_REG 0x0497
+#define YT8824_CDR_OFFSET_ERR_WTH GENMASK(14, 8)
+#define YT8824_PGA_GAIN_MAX GENMASK(6, 4)
+#define YT8824_PGA_GAIN_INIT GENMASK(2, 0)
+#define YT8824_EOD_CTRL_REG 0x04cd
+#define YT8824_EOD_ERR_CNT_THR GENMASK(15, 0)
+#define YT8824_CSR_AFE_CTRL_REG 0x04af
+#define YT8824_CSR_AFE_VCM_CFG GENMASK(10, 8)
+#define YT8824_CSR_AFE_MANUAL_CTRL_1P25G BIT(4)
+#define YT8824_CSR_AFE_MANUAL_CTRL_3P125G BIT(3)
+#define YT8824_CSR_AFE_MANUAL_CTRL_10P3125G BIT(2)
+#define YT8824_DFE_CTRL_REG 0x048a
+#define YT8824_DFE_TAP_POLARITY BIT(12)
+#define YT8824_DFE_IDAC_TUNE GENMASK(11, 10)
+#define YT8824_CSR_CDR_CTRL_REG 0x0408
+#define YT8824_CSR_CDR_OFFSET_DATA GENMASK(14, 8)
+#define YT8824_DFE_VDAC_CODE_REG 0x04d6
+#define YT8824_DFE_VDAC_CODE_THR GENMASK(6, 0)
+#define YT8824_RX_SPARE_CTRL_REG 0x044f
+#define YT8824_RX_SPARE_REG GENMASK(15, 0)
+#define YT8824_DFE_VDAC_CTRL_REG 0x048e
+#define YT8824_DFE_VDAC_TUNE GENMASK(11, 10)
+#define YT8824_DFE_VDAC_SEL GENMASK(9, 8)
+#define YT8824_CSR_TX_PRE_REG 0x000d
+#define YT8824_CSR_TX_PRE_SEL GENMASK(4, 0)
+#define YT8824_CSR_AFE_CTRL1_REG 0x04b0
+#define YT8824_CSR_AFE_CTLE_BW GENMASK(6, 4)
+#define YT8824_CSR_AFE_CTRL2_REG 0x04b1
+#define YT8824_CSR_AFE_PGA_BW GENMASK(14, 12)
+#define YT8824_CSR_AFE_BUF_BW GENMASK(6, 4)
+#define YT8824_CSR_DCC_CAL_CTRL_REG 0x0003
+#define YT8824_CUR_TX_SEQ GENMASK(15, 12)
+#define YT8824_CUR_RX_SEQ GENMASK(11, 8)
+#define YT8824_CALIB_SEQ_FINISH BIT(1)
+#define YT8824_CALIB_SEQ_SW_RST BIT(0)
+#define YT8824_RESTART_CAL_CTRL_REG 0x2000
+#define YT8824_DAC_TRIM_MAIN_CFG_REG 0x429
+#define YT8824_PLL_VCO_CFG_REG 0x441
+#define YT8824_TX_MUX_CH3_CH2_REG 0x42b
+#define YT8824_C1_COARSE_CFG_REG 0x4b4
+#define YT8824_FFE_CTRL_REG 0x4b5
+
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
@@ -415,6 +654,14 @@ struct yt8521_priv {
u8 reg_page;
};
+struct yt8824_shared_priv {
+ phy_interface_t package_mode;
+ /* shared_lock used to UTPs operation isolation during swap reg space */
+ struct mutex shared_lock;
+ /* true once the package-wide SERDES init has been done */
+ bool sds_initialized;
+};
+
/**
* ytphy_read_ext() - read a PHY's extended register
* @phydev: a pointer to a &struct phy_device
@@ -453,6 +700,70 @@ static int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum)
return ret;
}
+/**
+ * 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 = __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 = __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 page)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG);
+ if (ret < 0)
+ goto err;
+ ret &= ~YT8824_RSSR_SPACE_MASK;
+ ret |= (page & YT8824_RSSR_SPACE_MASK);
+ ret = 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
@@ -638,15 +949,1165 @@ static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
ret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, 0);
- /* Disable WOL interrupt */
- ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,
- YTPHY_IER_WOL, 0);
+ /* Disable WOL interrupt */
+ ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,
+ YTPHY_IER_WOL, 0);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * 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 = 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 write.
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_write_page(struct phy_device *phydev, int page)
+{
+ int old_page;
+ u16 data;
+
+ old_page = ytphy_read_top_ext(phydev, YT8521_REG_SPACE_SELECT_REG);
+ if (old_page < 0)
+ return old_page;
+ data = old_page & (~YT8824_RSSR_SPACE_MASK);
+ data |= 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 = 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 = YT8824_RSSR_UTP_SPACE;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* enable sds isolate */
+ ret = __phy_modify(phydev, MII_BMCR, BMCR_ISOLATE, BMCR_ISOLATE);
+
+err_restore_page:
+ 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 = 0;
+ int val;
+
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ ret = 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 *phydev)
+{
+ int old_page = YT8824_RSSR_UTP_SPACE;
+ int val = 0;
+ int ret = -1;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* sds softreset and disable isolate */
+ ret = __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 = read_poll_timeout(__phy_read, val,
+ (val < 0) || !(val & BMCR_RESET), 50000, 600000,
+ true, phydev, MII_BMCR);
+ if (val < 0)
+ ret = val;
+
+err_restore_page:
+ 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 ret)
+{
+ struct yt8824_shared_priv *priv = phy_package_get_priv(phydev);
+ int r;
+
+ r = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ if (priv->package_mode != PHY_INTERFACE_MODE_INTERNAL) {
+ r = yt8824_sds_isolate_and_softreset_paged(phydev);
+ if (ret >= 0 && r < 0)
+ ret = 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 = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ if (priv->package_mode == PHY_INTERFACE_MODE_INTERNAL) {
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_softreset_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto retry;
+ } else {
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_sds_isolate_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_softreset_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_sds_isolate_and_softreset_paged(phydev);
+ if (ret < 0)
+ goto retry;
+ }
+ mutex_unlock(&priv->shared_lock);
+ return ret;
+retry:
+ ret = yt8824_restore_working_status(phydev, ret);
+ mutex_unlock(&priv->shared_lock);
+
+ return ret;
+}
+
+/**
+ * yt8824_config_utp_init_paged() - config external phy8824 utp init
+ * @phydev: target phy_device struct
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_config_utp_init_paged(struct phy_device *phydev)
+{
+ int ctrl = 0;
+ int mask = 0;
+ int ret = 0;
+ int val = 0;
+ int r;
+
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
+ if (ret < 0)
+ goto err_restore;
+
+ /* write protecting */
+ mask = YT8824_WRITE_PROTECT;
+ ctrl = YT8824_WRITE_PROTECT;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_WRITE_PROTECT_CAL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* PLL calibration */
+ ctrl = FIELD_PREP(YT8824_PLL_VCO_SEL_CURRENT, 0xb);
+ mask = YT8824_PLL_VCO_SEL_CURRENT;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_PLL_VCO_ATEMP_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PLL_VCO_ICOSTANT, 0xf);
+ mask = YT8824_PLL_VCO_ICOSTANT;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_PLL_PFD_CTRL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PLL_VCO_IPTAT, 0xf);
+ mask = YT8824_PLL_VCO_IPTAT;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_PLL_VCO_ATEMP_1_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PLL_DAC_RST, 0);
+ mask = YT8824_PLL_DAC_RST;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_PLL_DAC_0_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PLL_DAC_RST, 1);
+ mask = YT8824_PLL_DAC_RST;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_PLL_DAC_0_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* enable nibble */
+ ctrl = FIELD_PREP(YT8824_U0_U1_ENABLE_ODD_PREAMBLE, 3);
+ mask = YT8824_U0_U1_ENABLE_ODD_PREAMBLE;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_IF_CTRL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* idle err detect enable */
+ ctrl = YT8824_IDLE_DETECT;
+ mask = YT8824_IDLE_DETECT;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_IDLE_CTRL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 2.5G long cable performance */
+ ctrl = FIELD_PREP(YT8824_TRACE_LNG_GAIN_THR_2500, 0x50);
+ ctrl |= FIELD_PREP(YT8824_TRACE_MED_GAIN_THR_2500, 0x38);
+ mask = YT8824_TRACE_LNG_GAIN_THR_2500 |
+ YT8824_TRACE_MED_GAIN_THR_2500;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_TRACE_GAIN_THR_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PRM_LARGE_SLAVE_2500, 0x68);
+ mask = YT8824_PRM_LARGE_SLAVE_2500;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_PRM_LONG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PRM_SMALL_LNG_2500, 0xa0);
+ mask = YT8824_PRM_SMALL_LNG_2500;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_PRM_SMALL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized fast retrain */
+ ctrl = FIELD_PREP(YT8824_LINK_FAIL_SIG, 0x21);
+ mask = YT8824_LINK_FAIL_SIG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_FAST_RETRAIN_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_EN_GATE_GMII_CLK, 0);
+ mask = YT8824_EN_GATE_GMII_CLK;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_EN_GATE_CTRL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* 2.5G template tone */
+ ctrl = FIELD_PREP(YT8824_POWER_SAVE, 0x83);
+ mask = YT8824_POWER_SAVE;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_CFG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_BIAS_CFG_2500, 0xa);
+ mask = YT8824_DAC_BIAS_CFG_2500;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_BIAS_CFG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 2.5G template */
+ ctrl = FIELD_PREP(YT8824_DAC_IMID_CH2, 0x39);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMID_CH3, 0x39);
+ mask = YT8824_DAC_IMID_CH2 | YT8824_DAC_IMID_CH3;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMID_CFG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_IMID_CH0, 0x39);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMID_CH1, 0x39);
+ mask = YT8824_DAC_IMID_CH0 | YT8824_DAC_IMID_CH1;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMID_CFG1_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_IMSB_CH2, 0x39);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH3, 0x39);
+ mask = YT8824_DAC_IMSB_CH2 | YT8824_DAC_IMSB_CH3;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMSB_CFG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_IMSB_CH0, 0x39);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH1, 0x39);
+ mask = YT8824_DAC_IMSB_CH0 | YT8824_DAC_IMSB_CH1;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMSB_CFG1_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 1000M cable length threshold */
+ ctrl = FIELD_PREP(YT8824_TRACE_LNG_GAIN_THR, 0x2b);
+ mask = YT8824_TRACE_LNG_GAIN_THR;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_TRACE_LNG_GAIN_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_TRACE_MED_GAIN_THR, 0x1d);
+ mask = YT8824_TRACE_MED_GAIN_THR;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_TRACE_MED_GAIN_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* 100M template amplitude */
+ ctrl = FIELD_PREP(YT8824_DAC_IMID_CH3_ORG, 0x45);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMID_CH2_ORG, 0x45);
+ mask = YT8824_DAC_IMID_CH3_ORG | YT8824_DAC_IMID_CH2_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMID_CH2_CH3_CFG_ORG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_IMID_CH1_ORG, 0x45);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMID_CH0_ORG, 0x45);
+ mask = YT8824_DAC_IMID_CH1_ORG | YT8824_DAC_IMID_CH0_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMID_CH0_CH1_CFG_ORG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_IMSB_CH3_ORG, 0x45);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH2_ORG, 0x45);
+ mask = YT8824_DAC_IMSB_CH2_ORG | YT8824_DAC_IMSB_CH3_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMSB_CH2_CH3_CFG_ORG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_IMSB_CH1_ORG, 0x45);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMSB_CH0_ORG, 0x45);
+ mask = YT8824_DAC_IMSB_CH1_ORG | YT8824_DAC_IMSB_CH0_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMSB_CH0_CH1_CFG_ORG_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 100M cable length threshold */
+ ctrl = FIELD_PREP(YT8824_TRACE_LNG_GAIN_THR_100, 0x2A);
+ ctrl |= FIELD_PREP(YT8824_TRACE_MED_GAIN_THR_100, 0x1D);
+ mask = YT8824_TRACE_LNG_GAIN_THR_100 | YT8824_TRACE_MED_GAIN_THR_100;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_TRACE_LNG_GAIN_100_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_CABLE_VSHT_THR_S, 0x36);
+ mask = YT8824_CABLE_VSHT_THR_S;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_CABLE_VSHT_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* 10M template amplitude */
+ ctrl = FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH3_10, 0x18);
+ ctrl |= FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH2_10, 0x18);
+ mask = YT8824_DAC_LPFIL_ADJ_CH3_10 | YT8824_DAC_LPFIL_ADJ_CH2_10;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_LPFIL_CH2_CH3_ADJ_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH1_10, 0x18);
+ ctrl |= FIELD_PREP(YT8824_DAC_LPFIL_ADJ_CH0_10, 0x18);
+ mask = YT8824_DAC_LPFIL_ADJ_CH1_10 | YT8824_DAC_LPFIL_ADJ_CH0_10;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_LPFIL_CH0_CH1_ADJ_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized 10M cable length threshold */
+ ctrl = FIELD_PREP(YT8824_DAC_IMID_CFG_CH3_10_ORG, 0x6C);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMID_CFG_CH2_10_ORG, 0x6C);
+ mask = YT8824_DAC_IMID_CFG_CH3_10_ORG | YT8824_DAC_IMID_CFG_CH2_10_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMID_CFG_CH2_CH3_10_ORG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_DAC_IMID_CFG_CH1_10_ORG, 0x6C);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMID_CFG_CH0_10_ORG, 0x6C);
+ mask = YT8824_DAC_IMID_CFG_CH1_10_ORG | YT8824_DAC_IMID_CFG_CH0_10_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMID_CFG_CH0_CH1_10_ORG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized DAC IMSB config for CH2/CH3 */
+ ctrl = FIELD_PREP(YT8824_DAC_IMSB_CFG_CH3_10_ORG, 0x6C);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMSB_CFG_CH2_10_ORG, 0x6C);
+ mask = YT8824_DAC_IMSB_CFG_CH3_10_ORG | YT8824_DAC_IMSB_CFG_CH2_10_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMSB_CFG_CH2_CH3_10_ORG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized DAC IMSB config for CH0/CH1 */
+ ctrl = FIELD_PREP(YT8824_DAC_IMSB_CFG_CH1_10_ORG, 0x6C);
+ ctrl |= FIELD_PREP(YT8824_DAC_IMSB_CFG_CH0_10_ORG, 0x6C);
+ mask = YT8824_DAC_IMSB_CFG_CH1_10_ORG | YT8824_DAC_IMSB_CFG_CH0_10_ORG;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_IMSB_CFG_CH0_CH1_10_ORG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimize utp 1000M performance */
+ ctrl = FIELD_PREP(YT8824_WAIT_TO_1000, 0xFF);
+ mask = YT8824_WAIT_TO_1000;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_FFE_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_EN_GATE_PHYDBG, 0);
+ ctrl |= FIELD_PREP(YT8824_EN_GATE_BT1000, 0);
+ mask = YT8824_EN_GATE_PHYDBG | YT8824_EN_GATE_BT1000;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_EN_GATE_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_CNT_ERR_AUTO, 1);
+ mask = YT8824_CNT_ERR_AUTO;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_CNT_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PRM_LARGE_MASTER_1000, 0x94);
+ mask = YT8824_PRM_LARGE_MASTER_1000;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_PRM_LARGE_MASTER_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PRM_LARGE_SLAVE_1000, 0x094);
+ mask = YT8824_PRM_LARGE_SLAVE_1000;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_PRM_LARGE_SLAVE_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_SIG_GONE_THR_1000, 0x08);
+ mask = YT8824_SIG_GONE_THR_1000;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_SIG_GONE_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_EC_NX_TRAIN_COARSE_TO_1000, 0x40);
+ mask = YT8824_EC_NX_TRAIN_COARSE_TO_1000;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_EC_NX_TRAIN_COARSE_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_VGA_IN_LPF2_CAP_OTHER, 0x2);
+ mask = YT8824_VGA_IN_LPF2_CAP_OTHER;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_VGA_IN_LPF2_CAP_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_VGA_IN_LPF1_CAP_OTHER, 0x2);
+ mask = YT8824_VGA_IN_LPF1_CAP_OTHER;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_VGA_IN_LPF1_CAP_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized EMC CS */
+ ctrl = FIELD_PREP(YT8824_LDPC_FAIL_THR, 0xFF);
+ ctrl |= FIELD_PREP(YT8824_LFER_FAIL_THR, 0xFF);
+ mask = YT8824_LDPC_FAIL_THR | YT8824_LFER_FAIL_THR;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_LDPC_LFER_FAIL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_FR_REQ_THR, 0x06);
+ mask = YT8824_FR_REQ_THR;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_FR_REQ_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_PRM_SMALL_SHT_2500, 0x0FF);
+ mask = YT8824_PRM_SMALL_SHT_2500;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_GN_MU_COARSE_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ /* optimized EMC RE */
+ ctrl = FIELD_PREP(YT8824_DAC_AMP_ADJ_CH3_PBO0_2500, 0xF);
+ ctrl |= FIELD_PREP(YT8824_DAC_AMP_ADJ_CH2_PBO0_2500, 0xF);
+ ctrl |= FIELD_PREP(YT8824_DAC_AMP_ADJ_CH1_PBO0_2500, 0xF);
+ ctrl |= FIELD_PREP(YT8824_DAC_AMP_ADJ_CH0_PBO0_2500, 0xF);
+ mask = YT8824_DAC_AMP_ADJ_CH3_PBO0_2500 |
+ YT8824_DAC_AMP_ADJ_CH2_PBO0_2500 |
+ YT8824_DAC_AMP_ADJ_CH1_PBO0_2500 |
+ YT8824_DAC_AMP_ADJ_CH0_PBO0_2500;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_DAC_AMP_ADJ_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH3, 0x1F);
+ ctrl |= FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH2, 0x1F);
+ mask = YT8824_P0_DAC_BIAS_CAS_CFG_CH3 | YT8824_P0_DAC_BIAS_CAS_CFG_CH2;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_P0_DAC_BIAS_CAS_CH3_CH2_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH1, 0x1F);
+ ctrl |= FIELD_PREP(YT8824_P0_DAC_BIAS_CAS_CFG_CH0, 0x1F);
+ mask = YT8824_P0_DAC_BIAS_CAS_CFG_CH1 | YT8824_P0_DAC_BIAS_CAS_CFG_CH0;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_P0_DAC_BIAS_CAS_CH1_CH0_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH3, 0x1F);
+ ctrl |= FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH2, 0x1F);
+ mask = YT8824_P1_DAC_BIAS_CAS_CFG_CH3 | YT8824_P1_DAC_BIAS_CAS_CFG_CH2;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_P1_DAC_BIAS_CAS_CH3_CH2_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH1, 0x1F);
+ ctrl |= FIELD_PREP(YT8824_P1_DAC_BIAS_CAS_CFG_CH0, 0x1F);
+ mask = YT8824_P1_DAC_BIAS_CAS_CFG_CH1 | YT8824_P1_DAC_BIAS_CAS_CFG_CH0;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_P1_DAC_BIAS_CAS_CH1_CH0_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_CSR_EFUSE_BYPASS_ANALOG_SECOND_RESET, 1);
+ ctrl |= FIELD_PREP(YT8824_CSR_EFUSE_BYPASS_PLL_TXRX_RESET, 1);
+ mask = YT8824_CSR_EFUSE_BYPASS_ANALOG_SECOND_RESET |
+ YT8824_CSR_EFUSE_BYPASS_PLL_TXRX_RESET;
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8824_P01_PLL_EN_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH0, 0);
+ ctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH1, 0);
+ ctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH2, 0);
+ ctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH3, 0);
+ mask = YT8824_U0_CSR_RESETB_TX_CH0 | YT8824_U0_CSR_RESETB_TX_CH1 |
+ YT8824_U0_CSR_RESETB_TX_CH2 | YT8824_U0_CSR_RESETB_TX_CH3;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_U0_CSR_RESET_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH0, 0);
+ ctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH1, 0);
+ ctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH2, 0);
+ ctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH3, 0);
+ mask = YT8824_U1_CSR_RESETB_TX_CH0 | YT8824_U1_CSR_RESETB_TX_CH1 |
+ YT8824_U1_CSR_RESETB_TX_CH2 | YT8824_U1_CSR_RESETB_TX_CH3;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_U1_CSR_RESET_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH0, 1);
+ ctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH1, 1);
+ ctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH2, 1);
+ ctrl |= FIELD_PREP(YT8824_U0_CSR_RESETB_TX_CH3, 1);
+ mask = YT8824_U0_CSR_RESETB_TX_CH0 | YT8824_U0_CSR_RESETB_TX_CH1 |
+ YT8824_U0_CSR_RESETB_TX_CH2 | YT8824_U0_CSR_RESETB_TX_CH3;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_U0_CSR_RESET_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+
+ ctrl = FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH0, 1);
+ ctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH1, 1);
+ ctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH2, 1);
+ ctrl |= FIELD_PREP(YT8824_U1_CSR_RESETB_TX_CH3, 1);
+ mask = YT8824_U1_CSR_RESETB_TX_CH0 | YT8824_U1_CSR_RESETB_TX_CH1 |
+ YT8824_U1_CSR_RESETB_TX_CH2 | YT8824_U1_CSR_RESETB_TX_CH3;
+ ret = ytphy_modify_ext_with_lock(phydev, YT8824_U1_CSR_RESET_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore;
+ /* reset */
+ ret = genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto err_restore_normal;
+
+ ret = phy_modify(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE,
+ BMCR_RESET | BMCR_ANENABLE);
+ if (ret < 0)
+ goto err_restore_normal;
+ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
+ 50000, 600000, true);
+ if (ret < 0)
+ goto err_restore_normal;
+
+ ret = genphy_c45_template_testmode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto err_restore_normal;
+ return 0;
+
+err_restore:
+ r = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ return ret;
+
+err_restore_normal:
+ r = genphy_c45_template_testmode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ r = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ return ret;
+}
+
+/**
+ * yt8824_extern_sds_softreset() - config external phy8824 sds softrest
+ * @phydev: target phy_device struct
+ *
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_extern_sds_softreset(struct phy_device *phydev)
+{
+ int old_page = YT8824_RSSR_UTP_SPACE;
+ int ret = -1;
+ int val = 0;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* TX preamble padded to 8; RX IPG always > 8 */
+ ret = __phy_read(phydev, MII_RESV1);
+ if (ret < 0)
+ goto err_restore_page;
+ ret &= ~YT8824_SDS_CFG_MIN_PRE_MASK;
+ ret |= YT8824_SDS_TX_PRE_PADDING;
+ ret |= YT8824_SDS_EN_FILL_PRE;
+ ret = __phy_write(phydev, MII_RESV1, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = __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 = read_poll_timeout(__phy_read, val,
+ (val < 0) || !(val & BMCR_RESET), 50000, 600000,
+ true, phydev, MII_BMCR);
+ if (val < 0)
+ ret = val;
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, 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 = YT8824_RSSR_UTP_SPACE;
+ int val_1, val_2, val_3, tmp;
+ int ctrl = 0;
+ int mask = 0;
+ int ret = -1;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_SERDES_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* read efuse */
+ ret = ytphy_read_top_ext(phydev, YT8824_SERDES_PLL_CTRL1_REG);
+ if (ret < 0)
+ goto err_restore_page;
+ else
+ val_1 = ret;
+
+ ret = ytphy_read_top_ext(phydev, YT8824_SERDES_PLL_CTRL2_REG);
+ if (ret < 0)
+ goto err_restore_page;
+ else
+ val_2 = ret;
+
+ ret = ytphy_read_top_ext(phydev, YT8824_SERDES_PLL_CTRL3_REG);
+ if (ret < 0)
+ goto err_restore_page;
+ else
+ val_3 = ret;
+
+ /* Serdes optimization */
+ ctrl = FIELD_PREP(YT8824_SERDES_REG_WR_PRT, 1);
+ mask = YT8824_SERDES_REG_WR_PRT;
+ ret = ytphy_modify_ext(phydev, YT8824_WRITE_PROTECT_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_PCS_GLB_RST_BYPASS, 1);
+ ctrl |= FIELD_PREP(YT8824_CSR_SG_MODE_RST_BYPASS, 1);
+ ctrl |= FIELD_PREP(YT8824_CSR_US_GLB_RESET_N, 0);
+ ctrl |= FIELD_PREP(YT8824_CSR_PCS_BEF_TRAINING_DONE_RST_BYPASS, 1);
+ mask = YT8824_CSR_PCS_GLB_RST_BYPASS | YT8824_CSR_SG_MODE_RST_BYPASS |
+ YT8824_CSR_US_GLB_RESET_N |
+ YT8824_CSR_PCS_BEF_TRAINING_DONE_RST_BYPASS;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_WATCH_DOG_ALL_BYPASS, 1);
+ mask = YT8824_CSR_WATCH_DOG_ALL_BYPASS;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_PMA_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* analog CDR */
+ ctrl = FIELD_PREP(YT8824_CDR_MODE, 1);
+ mask = YT8824_CDR_MODE;
+ ret = ytphy_modify_ext(phydev, YT8824_CDR_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized VCO */
+ ctrl = FIELD_PREP(YT8824_CSR_PLL_VCO_SEL_VCO2_CURRENT, 0x9);
+ ctrl |= FIELD_PREP(YT8824_CSR_PLL_VCO_ATEMP_R, 0x4);
+ mask = YT8824_CSR_PLL_VCO_SEL_VCO2_CURRENT | YT8824_CSR_PLL_VCO_ATEMP_R;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_VCO_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_PLL_VCO_SEL_VCO2_RM_R, 0x0);
+ mask = YT8824_CSR_PLL_VCO_SEL_VCO2_RM_R;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_DIVLDO_CTRL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized PLL lock */
+ ret = ytphy_read_ext(phydev, YT8824_DAC_TRIM_MAIN_CFG_REG);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(13) | BIT(12));
+ tmp = (val_1 & (BIT(7) | BIT(6))) >> 6;
+ ret |= (tmp << 12);
+ ret = ytphy_write_ext(phydev, YT8824_DAC_TRIM_MAIN_CFG_REG, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, YT8824_PLL_VCO_CFG_REG);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(1) | BIT(0));
+ tmp = (val_1 & (BIT(5) | BIT(4))) >> 4;
+ ret |= tmp;
+ ret = ytphy_write_ext(phydev, YT8824_PLL_VCO_CFG_REG, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, YT8824_TX_MUX_CH3_CH2_REG);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(13) | BIT(12));
+ tmp = (val_3 & (BIT(1) | BIT(0)));
+ ret |= (tmp << 12);
+ ret = ytphy_write_ext(phydev, YT8824_TX_MUX_CH3_CH2_REG, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_PLL_FBDIV_SYNC_SELB, 1);
+ mask = YT8824_CSR_PLL_FBDIV_SYNC_SELB;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_FBDIV_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_PLL_SPARE, 0xf070);
+ mask = YT8824_CSR_PLL_SPARE;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_PLL_SPARE_CTRL_REG,
+ mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* cable length threshold */
+ ctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_LNG, 0x7F);
+ mask = YT8824_VDAC_AMP_THR_LNG;
+ ret = ytphy_modify_ext(phydev, YT8824_CDR_MANUAL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_MED, 0x7F);
+ ctrl |= FIELD_PREP(YT8824_VDAC_AMP_THR_SHT, 0x7F);
+ mask = YT8824_VDAC_AMP_THR_MED | YT8824_VDAC_AMP_THR_SHT;
+ ret = ytphy_modify_ext(phydev, YT8824_TRAINING_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes training threshold */
+ ctrl = FIELD_PREP(YT8824_EOD_DURATION_SEL, 0xF);
+ ctrl |= FIELD_PREP(YT8824_EOD_VTH, 0x14);
+ mask = YT8824_EOD_DURATION_SEL | YT8824_EOD_VTH;
+ ret = ytphy_modify_ext(phydev, YT8824_EOM_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CDR_OFFSET_ERR_WTH, 0x0A);
+ ctrl |= FIELD_PREP(YT8824_PGA_GAIN_MAX, 0x4);
+ ctrl |= FIELD_PREP(YT8824_PGA_GAIN_INIT, 0x4);
+ mask = YT8824_CDR_OFFSET_ERR_WTH | YT8824_PGA_GAIN_MAX |
+ YT8824_PGA_GAIN_INIT;
+ ret = ytphy_modify_ext(phydev, YT8824_PGA_GAIN_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* digital eye diagram of SerDes */
+ ctrl = FIELD_PREP(YT8824_EOD_ERR_CNT_THR, 0x0000);
+ mask = YT8824_EOD_ERR_CNT_THR;
+ ret = ytphy_modify_ext(phydev, YT8824_EOD_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes LDO */
+ ret = ytphy_read_ext(phydev, YT8824_FFE_CTRL_REG);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(6) | BIT(5) | BIT(4));
+ tmp = (val_2 & (BIT(4) | BIT(3) | BIT(2))) >> 2;
+ ret |= (tmp << 4);
+ ret = ytphy_write_ext(phydev, YT8824_FFE_CTRL_REG, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, YT8824_C1_COARSE_CFG_REG);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(10) | BIT(9) | BIT(8));
+ tmp = (val_2 & (BIT(7) | BIT(6) | BIT(5))) >> 5;
+ ret |= (tmp << 8);
+ ret = ytphy_write_ext(phydev, YT8824_C1_COARSE_CFG_REG, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized Serdes RX */
+ ctrl = FIELD_PREP(YT8824_CSR_AFE_VCM_CFG, 0x5);
+ ctrl |= FIELD_PREP(YT8824_CSR_AFE_MANUAL_CTRL_1P25G, 0);
+ ctrl |= FIELD_PREP(YT8824_CSR_AFE_MANUAL_CTRL_3P125G, 0);
+ mask = YT8824_CSR_AFE_VCM_CFG | YT8824_CSR_AFE_MANUAL_CTRL_1P25G |
+ YT8824_CSR_AFE_MANUAL_CTRL_3P125G;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_DFE_TAP_POLARITY, 1);
+ ctrl |= FIELD_PREP(YT8824_DFE_IDAC_TUNE, 0x3);
+ mask = YT8824_DFE_TAP_POLARITY | YT8824_DFE_IDAC_TUNE;
+ ret = ytphy_modify_ext(phydev, YT8824_DFE_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_CDR_OFFSET_DATA, 0x7C);
+ mask = YT8824_CSR_CDR_OFFSET_DATA;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_CDR_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_DFE_VDAC_CODE_THR, 0x7F);
+ mask = YT8824_DFE_VDAC_CODE_THR;
+ ret = ytphy_modify_ext(phydev, YT8824_DFE_VDAC_CODE_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_RX_SPARE_REG, 0xff08);
+ mask = YT8824_RX_SPARE_REG;
+ ret = ytphy_modify_ext(phydev, YT8824_RX_SPARE_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized Serdes TX */
+ ctrl = FIELD_PREP(YT8824_DFE_VDAC_TUNE, 0x1);
+ ctrl |= FIELD_PREP(YT8824_DFE_VDAC_SEL, 0x0);
+ mask = YT8824_DFE_VDAC_TUNE | YT8824_DFE_VDAC_SEL;
+ ret = ytphy_modify_ext(phydev, YT8824_DFE_VDAC_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_TX_PRE_SEL, 0x6);
+ mask = YT8824_CSR_TX_PRE_SEL;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_TX_PRE_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes manual config */
+ ctrl = FIELD_PREP(YT8824_CSR_AFE_CTLE_BW, 0x0);
+ mask = YT8824_CSR_AFE_CTLE_BW;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL1_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_AFE_PGA_BW, 0x7);
+ ctrl |= FIELD_PREP(YT8824_CSR_AFE_BUF_BW, 0x7);
+ mask = YT8824_CSR_AFE_PGA_BW | YT8824_CSR_AFE_BUF_BW;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL2_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_CSR_AFE_MANUAL_CTRL_10P3125G, 0x1);
+ mask = YT8824_CSR_AFE_MANUAL_CTRL_10P3125G;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_AFE_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* restart calibration */
+ ctrl = FIELD_PREP(YT8824_CUR_TX_SEQ, 0x5);
+ ctrl |= FIELD_PREP(YT8824_CUR_RX_SEQ, 0x6);
+ ctrl |= FIELD_PREP(YT8824_CALIB_SEQ_FINISH, 1);
+ ctrl |= FIELD_PREP(YT8824_CALIB_SEQ_SW_RST, 1);
+ mask = YT8824_CUR_TX_SEQ | YT8824_CUR_RX_SEQ |
+ YT8824_CALIB_SEQ_FINISH | YT8824_CALIB_SEQ_SW_RST;
+ ret = ytphy_modify_ext(phydev, YT8824_CSR_DCC_CAL_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_MED, 0x7F);
+ ctrl |= FIELD_PREP(YT8824_VDAC_AMP_THR_SHT, 0xFF);
+ mask = YT8824_VDAC_AMP_THR_MED | YT8824_VDAC_AMP_THR_SHT;
+ ret = ytphy_modify_ext(phydev, YT8824_TRAINING_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ctrl = FIELD_PREP(YT8824_VDAC_AMP_THR_MED, 0x7F);
+ ctrl |= FIELD_PREP(YT8824_VDAC_AMP_THR_SHT, 0x7F);
+ mask = YT8824_VDAC_AMP_THR_MED | YT8824_VDAC_AMP_THR_SHT;
+ ret = ytphy_modify_ext(phydev, YT8824_TRAINING_CTRL_REG, mask, ctrl);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* restart to calibration */
+ ret = ytphy_write_ext(phydev, YT8824_RESTART_CAL_CTRL_REG, 0x0040);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, YT8824_RESTART_CAL_CTRL_REG, 0x0);
+ if (ret < 0)
+ goto err_restore_page;
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, 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 = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ if (priv->package_mode == PHY_INTERFACE_MODE_INTERNAL) {
+ ret = yt8824_config_utp_init_paged(phydev);
+ if (ret < 0)
+ goto err;
+ } else {
+ if (!priv->sds_initialized) {
+ ret = yt8824_extern_config_sds_init_paged(phydev);
+ if (ret < 0)
+ goto err;
+ priv->sds_initialized = true;
+ }
+ /*
+ * Configuring the MII registers of the SDS,
+ * which are private to each channel.
+ */
+ ret = yt8824_extern_sds_softreset(phydev);
+ if (ret < 0)
+ goto err;
+
+ ret = yt8824_config_utp_init_paged(phydev);
if (ret < 0)
- goto err_restore_page;
+ goto err;
}
+ mutex_unlock(&priv->shared_lock);
+ ret = yt8824_soft_reset(phydev);
-err_restore_page:
- return phy_restore_page(phydev, old_page, ret);
+ 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,
@@ -3240,6 +4701,450 @@ static int yt8821_resume(struct phy_device *phydev)
return yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
}
+/**
+ * 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 = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ goto err;
+ ret = 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 = phy_package_get_priv(phydev);
+ int auto_neg;
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ ret = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ goto err;
+
+ ret = phy_read(phydev, MII_BMSR);
+ if (ret < 0)
+ goto err;
+ mutex_unlock(&priv->shared_lock);
+ auto_neg = !!(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 page
+ * @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 = phy8824_page_write_with_lock(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ ret = genphy_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
+ ret = genphy_c45_read_lpa(phydev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (!phydev->link) {
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+ if (phydev->autoneg == AUTONEG_ENABLE)
+ phy_resolve_aneg_pause(phydev);
+ return 0;
+ }
+
+ ret = phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+
+ yt8821_adjust_status(phydev, val);
+
+ if (phydev->autoneg == 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 = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ ret = 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 = 0;
+
+ ret = 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 = 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 = phy_package_get_priv(phydev);
+ int ret;
+ int r;
+
+ if (priv->package_mode == PHY_INTERFACE_MODE_INTERNAL) {
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_power_on(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto retry;
+ } else {
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_sds_isolate_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_power_on(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto retry;
+
+ ret = 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 = yt8824_utp_power_down(phydev);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ ret = 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 = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ ret = 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 = phy_package_get_priv(phydev);
+ int ret;
+ int r;
+
+ if (priv->package_mode == PHY_INTERFACE_MODE_INTERNAL) {
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_power_down(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto retry;
+ } else {
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_1);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_sds_isolate_paged(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_power_down(phydev);
+ if (ret < 0)
+ goto retry;
+
+ ret = yt8824_utp_set_template_test_mode(phydev,
+ MDIO_PMA_10GBT_TESTMODE_NORMAL);
+ if (ret < 0)
+ goto retry;
+
+ ret = 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 = yt8824_utp_power_on(phydev);
+ if (ret >= 0 && r < 0)
+ ret = r;
+ ret = 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 = phy_package_get_priv(phydev);
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ ret = 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 = phy_package_get_priv(phydev);
+ int phy_ctrl = 0;
+ int ret;
+
+ mutex_lock(&priv->shared_lock);
+ ret = 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 == AUTONEG_ENABLE ||
+ phydev->speed == SPEED_2500) &&
+ linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ phydev->advertising))
+ phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
+
+ ret = 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 = __genphy_config_aneg(phydev, ret);
+
+err:
+ mutex_unlock(&priv->shared_lock);
+ return ret;
+}
+
+/**
+ * phy_mode_check() - check if mode names the PHY interface.
+ * @mode: PHY interface mode string
+ * @interface: PHY interface mode to compare against
+ *
+ * Return: true if @mode matches @interface, false otherwise.
+ */
+static bool phy_mode_check(const char *mode, int interface)
+{
+ return !strcasecmp(mode, phy_modes(interface));
+}
+
+/**
+ * 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 = phy_package_get_priv(phydev);
+ struct device_node *np = phy_package_get_node(phydev);
+ const char *mode;
+
+ 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);
+ priv->sds_initialized = false;
+ priv->package_mode = PHY_INTERFACE_MODE_INTERNAL;
+ if (!of_property_read_string(np, "motorcomm,package-mode",
+ &mode)) {
+ if (phy_mode_check(mode, PHY_INTERFACE_MODE_INTERNAL)) {
+ priv->package_mode = PHY_INTERFACE_MODE_INTERNAL;
+ } else if (phy_mode_check(mode,
+ PHY_INTERFACE_MODE_10G_QXGMII)) {
+ priv->package_mode = PHY_INTERFACE_MODE_10G_QXGMII;
+ } else {
+ phydev_err(phydev, "unsupported package-mode %s\n",
+ mode);
+ return -EINVAL;
+ }
+ } else {
+ phydev_err(phydev, "missing package-mode in PHY package node.\n");
+ 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 = &phydev->mdio.dev;
+ struct yt8824_shared_priv *shared_priv;
+ int ret;
+
+ ret = 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 = 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[] = {
{
PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
@@ -3337,13 +5242,29 @@ static struct phy_driver motorcomm_phy_drvs[] = {
.suspend = yt8821_suspend,
.resume = yt8821_resume,
},
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8824),
+ .name = "YT8824 Quad Ports 2.5Gbps Ethernet",
+ .get_features = yt8824_get_features,
+ .read_page = yt8824_read_page,
+ .write_page = yt8824_write_page,
+ .probe = yt8824_probe,
+ .config_aneg = yt8824_config_aneg,
+ .aneg_done = yt8824_aneg_done,
+ .config_init = yt8824_config_init,
+ .read_status = yt8824_read_status,
+ .soft_reset = yt8824_soft_reset,
+ .suspend = yt8824_suspend,
+ .resume = yt8824_resume,
+ },
};
module_phy_driver(motorcomm_phy_drvs);
-MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/861x/8821 PHY driver");
+MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/861x/8821/8824 PHY driver");
MODULE_AUTHOR("Peter Geis");
MODULE_AUTHOR("Frank");
+MODULE_AUTHOR("Kyle");
MODULE_LICENSE("GPL");
static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
@@ -3354,6 +5275,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
{ PHY_ID_MATCH_EXACT(PHY_ID_INT861X) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8821) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_YT8824) },
{ /* sentinel */ }
};
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 870920311f9a0..c5f5753f7194b 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 *phydev, bool enable)
}
EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain);
+/**
+ * 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 = 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 a5a419bc400ec..81cb7f15bb72e 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -2359,6 +2359,7 @@ int genphy_c45_loopback(struct phy_device *phydev, bool 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 06f4bc3c20c71..353ca13c64fca 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 control */
@@ -320,6 +321,17 @@
/* PMA 10GBASE-R Fast Retrain status and control register. */
#define MDIO_PMA_10GBR_FSRT_ENABLE 0x0001 /* Fast retrain enable */
+/* 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 */
|
| 3/2 | 2026/10/20 06:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 37275 output: 23 thoughts: 679 Thoughts: **Analyzing the Patch for Syzkaller Fuzzing Potential** Okay, let's break this down. My primary concern is whether this patch, specifically the changes related to the Motorcomm YT8824 Ethernet PHY, is a viable target for syzkaller. I need to assess if it's reachable and if the nature of the driver lends itself to effective fuzzing. First, the patch summary gives me the basic picture: a new DT binding (`motorcomm,yt8824.yaml`), maintainer updates, a Kconfig entry, and the core driver implementation (`motorcomm.c`). The driver itself seems comprehensive, with probe, initialization, reset, suspend/resume, and various config functions. I'm especially interested in that `ytphy_set_wol` modification, particularly the error handling related to page restoration. This is an area that might contain subtle flaws. The addition of `genphy_c45_template_testmode` and associated definitions are less immediately concerning but still worth noting. My next step is to evaluate reachability. The target architecture is amd64, which is expected. The immediate question is whether this involves physical hardware or if it's something that can be emulated or instantiated in a virtualized setting, which is crucial for syzkaller's effectiveness. Since it's an MDIO Ethernet PHY driver, `drivers/net/phy/motorcomm.c` specifically, I need to understand how these drivers are typically probed and instantiated. Can they be triggered in a virtual environment, like QEMU, which syzkaller leverages? Are there ways to mock or simulate an MDIO bus or create MDIO devices via userspace interfaces, netlink, or virtual buses? I need to figure out if MDIO devices are accessible to syzkaller, or if their creation is tied to the physical hardware or specific hardware configurations. I'll need to dig into the kernel source or use tools like grepper to investigate how MDIO/PHY drivers are probed or instantiated. Past experience tells me this is the critical area: can I get an instance of this driver running on a simulated MDIO bus to fuzz it with syzkaller? If not, it's going to be a significantly more involved setup. |
| 4/2 | 2026/10/20 06:14 | tool | grepper |
0mArgs:{
"Expression": "PHY_ID_YT8824"
}Results: {
"Output": "drivers/net/phy/motorcomm.c-30-#define PHY_ID_YT8821\t\t0x4f51ea19\ndrivers/net/phy/motorcomm.c:31:#define PHY_ID_YT8824\t\t0x4f51e8b8\ndrivers/net/phy/motorcomm.c-32-/* YT8521/YT8531S/YT8821 Register Overview\n--\ndrivers/net/phy/motorcomm.c=5148=static struct phy_driver motorcomm_phy_drvs[] = {\n--\ndrivers/net/phy/motorcomm.c-5245-\t{\ndrivers/net/phy/motorcomm.c:5246:\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8824),\ndrivers/net/phy/motorcomm.c-5247-\t\t.name = \"YT8824 Quad Ports 2.5Gbps Ethernet\",\n--\ndrivers/net/phy/motorcomm.c=5270=static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {\n--\ndrivers/net/phy/motorcomm.c-5277-\t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8821) },\ndrivers/net/phy/motorcomm.c:5278:\t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8824) },\ndrivers/net/phy/motorcomm.c-5279-\t{ /* sentinel */ }\n"
} |
| 5/2 | 2026/10/20 06:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 38838 output: 24 thoughts: 255 Thoughts: **Probing an MDIO Device** Okay, so I'm thinking about how this MDIO device, specifically the one with PHY ID 0x4f51e8b8, gets probed. Right, so a PHY driver needs to match it. That happens when the MDIO bus scans those PHY addresses, addresses 0 through 31. Then, it reads `MII_PHYSID1` and `MII_PHYSID2`, gets the PHY ID, and checks if it matches against the driver's `phy_driver.phy_id` and `phy_driver.phy_id_mask`. Or, of course, device tree can also be used. Now, let's look at the `yt8824_probe` function. I see that it uses `devm_of_phy_package_join`, and that is interesting. Let's check what `devm_of_phy_package_join` is doing... |
| 6/2 | 2026/10/20 06:14 | tool | grepper |
0mArgs:{
"Expression": "devm_of_phy_package_join"
}Results: {
"Output": "drivers/net/phy/motorcomm.c=5124=static int yt8824_probe(struct phy_device *phydev)\n--\ndrivers/net/phy/motorcomm.c-5129-\ndrivers/net/phy/motorcomm.c:5130:\tret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));\ndrivers/net/phy/motorcomm.c-5131-\tif (ret)\n--\ndrivers/net/phy/phy_package.c=405=EXPORT_SYMBOL_GPL(devm_phy_package_join);\n--\ndrivers/net/phy/phy_package.c-407-/**\ndrivers/net/phy/phy_package.c:408: * devm_of_phy_package_join - resource managed of_phy_package_join()\ndrivers/net/phy/phy_package.c-409- * @dev: device that is registering this PHY package\n--\ndrivers/net/phy/phy_package.c-416- */\ndrivers/net/phy/phy_package.c:417:int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,\ndrivers/net/phy/phy_package.c-418-\t\t\t size_t priv_size)\n--\ndrivers/net/phy/phy_package.c-438-}\ndrivers/net/phy/phy_package.c:439:EXPORT_SYMBOL_GPL(devm_of_phy_package_join);\ndrivers/net/phy/phy_package.c-440-\n--\ndrivers/net/phy/phylib.h=32=int devm_phy_package_join(struct device *dev, struct phy_device *phydev,\ndrivers/net/phy/phylib.h-33-\t\t\t int base_addr, size_t priv_size);\ndrivers/net/phy/phylib.h:34:int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,\ndrivers/net/phy/phylib.h-35-\t\t\t size_t priv_size);\n--\ndrivers/net/phy/qcom/qca807x.c=694=static int qca807x_probe(struct phy_device *phydev)\n--\ndrivers/net/phy/qcom/qca807x.c-701-\ndrivers/net/phy/qcom/qca807x.c:702:\tret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));\ndrivers/net/phy/qcom/qca807x.c-703-\tif (ret)\n--\ndrivers/net/phy/xpowers/acx00.c=195=static int acx00_ephy_init_package(struct phy_device *phydev,\n--\ndrivers/net/phy/xpowers/acx00.c-235-\ndrivers/net/phy/xpowers/acx00.c:236:\tret = devm_of_phy_package_join(dev, phydev, 0);\ndrivers/net/phy/xpowers/acx00.c-237-\tif (ret)\n"
} |
| 7/2 | 2026/10/20 06:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 40151 output: 39 thoughts: 40 Thoughts: Okay, let's dive into this. Here's my take on those functions: **Investigating PHY Package Join Functions** Right, let's get down to brass tacks. I'm focusing on `devm_of_phy_package_join` and `of_phy_package_join` in `drivers/net/phy/phy_package.c`. I need to understand the connection management from a driver's perspective. It's crucial, obviously, to get the PHY configured properly during device bring-up, and these likely hold the key to connecting a device to a PHY package. I'll need to scrutinize how they handle resource allocation, error checking, and the actual "joining" process. Is this an early-stage operation during device initialization? Perhaps it involves looking up the PHY based on the device tree and making sure everything aligns properly. Are there different error handling routines in the managed (`devm`) and unmanaged versions? It's all about ensuring that the PHY is properly attached, configured, and ready for data transmission. I expect `devm_` variants handle resources automatically. I'm looking for where and how the phy is actually "attached" in this file. I have to see how it can be used to join the PHY to the specified device. |
| 8/2 | 2026/10/20 06:14 | tool | read-file |
0mArgs:{
"File": "drivers/net/phy/phy_package.c",
"FirstLine": 400,
"LineCount": 45
}Results: {
"Contents": " 400:\t\t\tdevres_free(ptr);\n 401:\t\t}\n 402:\t\n 403:\t\treturn ret;\n 404:\t}\n 405:\tEXPORT_SYMBOL_GPL(devm_phy_package_join);\n 406:\t\n 407:\t/**\n 408:\t * devm_of_phy_package_join - resource managed of_phy_package_join()\n 409:\t * @dev: device that is registering this PHY package\n 410:\t * @phydev: target phy_device struct\n 411:\t * @priv_size: if non-zero allocate this amount of bytes for private data\n 412:\t *\n 413:\t * Managed of_phy_package_join(). Shared storage fetched by this function,\n 414:\t * phy_package_leave() is automatically called on driver detach. See\n 415:\t * of_phy_package_join() for more information.\n 416:\t */\n 417:\tint devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,\n 418:\t\t\t\t size_t priv_size)\n 419:\t{\n 420:\t\tstruct phy_device **ptr;\n 421:\t\tint ret;\n 422:\t\n 423:\t\tptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),\n 424:\t\t\t\t GFP_KERNEL);\n 425:\t\tif (!ptr)\n 426:\t\t\treturn -ENOMEM;\n 427:\t\n 428:\t\tret = of_phy_package_join(phydev, priv_size);\n 429:\t\n 430:\t\tif (!ret) {\n 431:\t\t\t*ptr = phydev;\n 432:\t\t\tdevres_add(dev, ptr);\n 433:\t\t} else {\n 434:\t\t\tdevres_free(ptr);\n 435:\t\t}\n 436:\t\n 437:\t\treturn ret;\n 438:\t}\n 439:\tEXPORT_SYMBOL_GPL(devm_of_phy_package_join);\n 440:\t\n 441:\tMODULE_DESCRIPTION(\"PHY package support\");\n 442:\tMODULE_LICENSE(\"GPL\");\n"
} |
| 9/2 | 2026/10/20 06:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 41117 output: 34 thoughts: 16 Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person: **Analyzing `of_phy_package_join` Functionality** Alright, let's dive into this `of_phy_package_join` function. My initial thought process involves a careful unpacking of the function's naming conventions. The "of" suggests an OpenFlow context, so I'm immediately picturing the data structures and control messages associated with that protocol. "Phy" implies a physical layer component, hinting that this function might be dealing with the interaction between the OpenFlow controller and the underlying physical network infrastructure—potentially even hardware. The "package_join" aspect really solidifies this. I'm assuming it relates to bringing new physical resources, perhaps network interface cards, switches, or even entire physical links, into an OpenFlow management domain. It’s likely involved in the admission and registration phases of a new physical entity. My mind immediately begins to generate some key questions: what specific information is being exchanged? Does it involve authentication? How does the controller verify the physical device's capabilities and identity? What security measures are in place? Is there a process for discovering these physical components within the network, or does this function work after the device has been made known? How is the hardware represented within the controller and what data structures are associated with it? This also makes me consider different implementations. Is it a synchronous or asynchronous event, is the underlying transport reliable, and how can the behaviour be tuned? Is it a single device or a set of devices? I'm mentally mapping this function's place in the broader OpenFlow framework: where does it sit relative to the switch discovery process, the table configuration, the flow installation, and the event handling? Is this a core functionality, or something more esoteric? The implementation details could be critical. Does it employ standard OpenFlow messages, proprietary extensions, or a combination of both? Looking at a codebase, I'd need to consider how this function interacts with the device, and the other methods, to verify what it is doing, and what it does not do. |
| 10/2 | 2026/10/20 06:14 | tool | grepper |
0mArgs:{
"Expression": "of_phy_package_join",
"PathPrefixes": [
"drivers/net/phy/"
]
}Results: {
"Output": "drivers/net/phy/motorcomm.c=5124=static int yt8824_probe(struct phy_device *phydev)\n--\ndrivers/net/phy/motorcomm.c-5129-\ndrivers/net/phy/motorcomm.c:5130:\tret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));\ndrivers/net/phy/motorcomm.c-5131-\tif (ret)\n--\ndrivers/net/phy/phy_package.c=276=EXPORT_SYMBOL_GPL(phy_package_join);\n--\ndrivers/net/phy/phy_package.c-278-/**\ndrivers/net/phy/phy_package.c:279: * of_phy_package_join - join a common PHY group in PHY package\ndrivers/net/phy/phy_package.c-280- * @phydev: target phy_device struct\n--\ndrivers/net/phy/phy_package.c-297- */\ndrivers/net/phy/phy_package.c:298:int of_phy_package_join(struct phy_device *phydev, size_t priv_size)\ndrivers/net/phy/phy_package.c-299-{\n--\ndrivers/net/phy/phy_package.c-332-}\ndrivers/net/phy/phy_package.c:333:EXPORT_SYMBOL_GPL(of_phy_package_join);\ndrivers/net/phy/phy_package.c-334-\n--\ndrivers/net/phy/phy_package.c=405=EXPORT_SYMBOL_GPL(devm_phy_package_join);\n--\ndrivers/net/phy/phy_package.c-407-/**\ndrivers/net/phy/phy_package.c:408: * devm_of_phy_package_join - resource managed of_phy_package_join()\ndrivers/net/phy/phy_package.c-409- * @dev: device that is registering this PHY package\n--\ndrivers/net/phy/phy_package.c-412- *\ndrivers/net/phy/phy_package.c:413: * Managed of_phy_package_join(). Shared storage fetched by this function,\ndrivers/net/phy/phy_package.c-414- * phy_package_leave() is automatically called on driver detach. See\ndrivers/net/phy/phy_package.c:415: * of_phy_package_join() for more information.\ndrivers/net/phy/phy_package.c-416- */\ndrivers/net/phy/phy_package.c:417:int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,\ndrivers/net/phy/phy_package.c-418-\t\t\t size_t priv_size)\n--\ndrivers/net/phy/phy_package.c-427-\ndrivers/net/phy/phy_package.c:428:\tret = of_phy_package_join(phydev, priv_size);\ndrivers/net/phy/phy_package.c-429-\n--\ndrivers/net/phy/phy_package.c-438-}\ndrivers/net/phy/phy_package.c:439:EXPORT_SYMBOL_GPL(devm_of_phy_package_join);\ndrivers/net/phy/phy_package.c-440-\n--\ndrivers/net/phy/phylib.h=29=int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);\ndrivers/net/phy/phylib.h:30:int of_phy_package_join(struct phy_device *phydev, size_t priv_size);\ndrivers/net/phy/phylib.h-31-void phy_package_leave(struct phy_device *phydev);\ndrivers/net/phy/phylib.h=32=int devm_phy_package_join(struct device *dev, struct phy_device *phydev,\ndrivers/net/phy/phylib.h-33-\t\t\t int base_addr, size_t priv_size);\ndrivers/net/phy/phylib.h:34:int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,\ndrivers/net/phy/phylib.h-35-\t\t\t size_t priv_size);\n--\ndrivers/net/phy/qcom/qca807x.c=694=static int qca807x_probe(struct phy_device *phydev)\n--\ndrivers/net/phy/qcom/qca807x.c-701-\ndrivers/net/phy/qcom/qca807x.c:702:\tret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));\ndrivers/net/phy/qcom/qca807x.c-703-\tif (ret)\n--\ndrivers/net/phy/xpowers/acx00.c=195=static int acx00_ephy_init_package(struct phy_device *phydev,\n--\ndrivers/net/phy/xpowers/acx00.c-235-\ndrivers/net/phy/xpowers/acx00.c:236:\tret = devm_of_phy_package_join(dev, phydev, 0);\ndrivers/net/phy/xpowers/acx00.c-237-\tif (ret)\n"
} |
| 11/2 | 2026/10/20 06:14 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 42994 output: 39 thoughts: 28 Thoughts: Here's a first-person summary, tailored for an expert audience, as requested: **Diving into phy_package.c: A Targeted Look at PHY Initialization** Okay, let's zero in on `drivers/net/phy/phy_package.c`, specifically the region around line 280 to 332. My interest is piqued by this specific chunk of code. I'm guessing it's handling some crucial aspects of PHY initialization or perhaps power management within the PHY package driver. Given the context, I'm anticipating this is where the core interaction with the underlying PHY hardware is likely defined - I'm thinking device detection, register configuration, or perhaps the initial sequence of commands sent to bring the PHY online. I'll need to closely examine the data structures used, likely structures representing the PHY's registers or the operational state. Hopefully, the code is well-commented; that would certainly speed things up. I'll be keeping an eye out for any potentially complex interrupt handling or race conditions. This section will hopefully reveal how the driver deals with diverse PHY types or common initialization routines. I anticipate seeing conditional logic based on PHY device IDs, as well as error checking to ensure proper operation. |
| 12/2 | 2026/10/20 06:15 | tool | read-file |
0mArgs:{
"File": "drivers/net/phy/phy_package.c",
"FirstLine": 280,
"LineCount": 55
}Results: {
"Contents": " 280:\t * @phydev: target phy_device struct\n 281:\t * @priv_size: if non-zero allocate this amount of bytes for private data\n 282:\t *\n 283:\t * This is a variant of phy_package_join for PHY package defined in DT.\n 284:\t *\n 285:\t * The parent node of the @phydev is checked as a valid PHY package node\n 286:\t * structure (by matching the node name \"ethernet-phy-package\") and the\n 287:\t * base_addr for the PHY package is passed to phy_package_join.\n 288:\t *\n 289:\t * With this configuration the shared struct will also have the np value\n 290:\t * filled to use additional DT defined properties in PHY specific\n 291:\t * probe_once and config_init_once PHY package OPs.\n 292:\t *\n 293:\t * Returns \u003c 0 on error, 0 on success. Esp. calling phy_package_join()\n 294:\t * with the same cookie but a different priv_size is an error. Or a parent\n 295:\t * node is not detected or is not valid or doesn't match the expected node\n 296:\t * name for PHY package.\n 297:\t */\n 298:\tint of_phy_package_join(struct phy_device *phydev, size_t priv_size)\n 299:\t{\n 300:\t\tstruct device_node *node = phydev-\u003emdio.dev.of_node;\n 301:\t\tstruct device_node *package_node;\n 302:\t\tu32 base_addr;\n 303:\t\tint ret;\n 304:\t\n 305:\t\tif (!node)\n 306:\t\t\treturn -EINVAL;\n 307:\t\n 308:\t\tpackage_node = of_get_parent(node);\n 309:\t\tif (!package_node)\n 310:\t\t\treturn -EINVAL;\n 311:\t\n 312:\t\tif (!of_node_name_eq(package_node, \"ethernet-phy-package\")) {\n 313:\t\t\tret = -EINVAL;\n 314:\t\t\tgoto exit;\n 315:\t\t}\n 316:\t\n 317:\t\tif (of_property_read_u32(package_node, \"reg\", \u0026base_addr)) {\n 318:\t\t\tret = -EINVAL;\n 319:\t\t\tgoto exit;\n 320:\t\t}\n 321:\t\n 322:\t\tret = phy_package_join(phydev, base_addr, priv_size);\n 323:\t\tif (ret)\n 324:\t\t\tgoto exit;\n 325:\t\n 326:\t\tphydev-\u003eshared-\u003enp = package_node;\n 327:\t\n 328:\t\treturn 0;\n 329:\texit:\n 330:\t\tof_node_put(package_node);\n 331:\t\treturn ret;\n 332:\t}\n 333:\tEXPORT_SYMBOL_GPL(of_phy_package_join);\n 334:\t\n"
} |
| 13/2 | 2026/10/20 06:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 44155 output: 40 thoughts: 897 Thoughts: **Analyzing the Reachability of `of_phy_package_join` and the YT8824 PHY Driver** Okay, so I'm looking at this `of_phy_package_join` function and its use in the `yt8824_probe` driver. It's immediately apparent that `yt8824_probe` calls `of_phy_package_join`, and this function is going to fail badly unless the Device Tree is set up in a very specific way: the PHY's device node needs to have an "ethernet-phy-package" parent node with a "reg" property. That screams "Devicetree dependency" to me. My immediate thought is, "Wait, is this even *used* on x86/amd64?" Those platforms generally don't use Device Tree unless there's something specific going on, like OF_UNITTEST or a fake DT. Standard amd64 networking configurations usually don't rely on DT for the PHYs! Then, the critical question arises: "Can this PHY, and by extension, this code path, even *be reached* in a standard QEMU environment, or in a fuzzing setup?" This is where the triage philosophy kicks in: reachability is the primary gatekeeper. We can't fuzz code that's fundamentally unreachable. I have to consider Section 2 again. Are we looking at structurally unreachable hardware or an execution path only used in a limited situation? I quickly run through the possibilities: can an Ethernet PHY driver ever be reached in QEMU? Then I think about the available Ethernet controllers in QEMU: e1000, e1000e, igb, virtio-net, rtl8139, ne2k_pci, pcnet, etc. Do any of them, in their standard configurations, have an *external* MDIO bus connected to an YT8824 PHY? Nope. That's a huge problem. What about USB Ethernet? That could be a possibility, but I have to carefully consider it. I need to know if any USB Ethernet adapter *emulates* or *connects* to a PHY via MDIO. So, it is time to check in the USB net driver. I must look for any mention of mdio and phy_connect in drivers/net/usb/ |
| 14/2 | 2026/10/20 06:15 | tool | grepper |
0mArgs:{
"Expression": "phy_connect|phy_attach|mdiobus_register",
"PathPrefixes": [
"drivers/net/usb/"
]
}Results: {
"Output": "drivers/net/usb/asix_devices.c=669=static int ax88772_init_mdio(struct usbnet *dev)\n--\ndrivers/net/usb/asix_devices.c-686-\ndrivers/net/usb/asix_devices.c:687:\tret = mdiobus_register(priv-\u003emdio);\ndrivers/net/usb/asix_devices.c-688-\tif (ret) {\n--\ndrivers/net/usb/asix_devices.c=703=static int ax88772_init_phy(struct usbnet *dev)\n--\ndrivers/net/usb/asix_devices.c-722-\ndrivers/net/usb/asix_devices.c:723:\tphy_attached_info(priv-\u003ephydev);\ndrivers/net/usb/asix_devices.c-724-\n--\ndrivers/net/usb/ax88172a.c=61=static int ax88172a_init_mdio(struct usbnet *dev)\n--\ndrivers/net/usb/ax88172a.c-79-\ndrivers/net/usb/ax88172a.c:80:\tret = mdiobus_register(priv-\u003emdio);\ndrivers/net/usb/ax88172a.c-81-\tif (ret) {\n--\ndrivers/net/usb/ax88172a.c=260=static int ax88172a_reset(struct usbnet *dev)\n--\ndrivers/net/usb/ax88172a.c-312-\ndrivers/net/usb/ax88172a.c:313:\tpriv-\u003ephydev = phy_connect(dev-\u003enet, priv-\u003ephy_name,\ndrivers/net/usb/ax88172a.c-314-\t\t\t\t \u0026ax88172a_adjust_link,\n--\ndrivers/net/usb/lan78xx.c=2094=static int lan78xx_mdio_init(struct lan78xx_net *dev)\n--\ndrivers/net/usb/lan78xx.c-2124-\tnode = of_get_child_by_name(dev-\u003eudev-\u003edev.of_node, \"mdio\");\ndrivers/net/usb/lan78xx.c:2125:\tret = of_mdiobus_register(dev-\u003emdiobus, node);\ndrivers/net/usb/lan78xx.c-2126-\tof_node_put(node);\n--\ndrivers/net/usb/smsc95xx.c=1147=static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/smsc95xx.c-1241-\ndrivers/net/usb/smsc95xx.c:1242:\tret = mdiobus_register(pdata-\u003emdiobus);\ndrivers/net/usb/smsc95xx.c-1243-\tif (ret) {\n--\ndrivers/net/usb/smsc95xx.c-1285-\ndrivers/net/usb/smsc95xx.c:1286:\tret = phy_connect_direct(dev-\u003enet, pdata-\u003ephydev,\ndrivers/net/usb/smsc95xx.c-1287-\t\t\t\t \u0026smsc95xx_handle_link_change,\n--\ndrivers/net/usb/smsc95xx.c-1293-\ndrivers/net/usb/smsc95xx.c:1294:\tphy_attached_info(dev-\u003enet-\u003ephydev);\ndrivers/net/usb/smsc95xx.c-1295-\n"
} |
| 15/2 | 2026/10/20 06:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 46551 output: 38 thoughts: 1425 Thoughts: **Analyzing the Hypothetical YT8824 Emulation** Okay, so the question is, if a USB gadget somehow emulates a network device with an MDIO bus, could `yt8824_probe` succeed? Let's break this down. From what I see in the code, `yt8824_probe` immediately calls `devm_of_phy_package_join`, which then calls `of_phy_package_join`. This function is immediately suspicious. It requires a Device Tree node (`of_node`), a parent node called "ethernet-phy-package", and a "reg" property. Crucially, it uses `of_property_read_u32` and `of_property_read_string`. So the presence and correct formatting of Device Tree properties are *critical* here. Now, let's look at the subsequent calls to `phy_package_lock`, `phy_package_probe_once`, and related functions. Inside `yt8824_phy_package_probe_once`, it's pulling information from `phy_package_get_priv` (which is filled earlier) and `phy_package_get_node` which depends on the previously described DT requirements. It's initializing a mutex (`shared_lock`) and reading a "motorcomm,package-mode" property. Here's the rub: on amd64, Device Tree isn't normally present in standard ACPI-based boots or QEMU/GCE, unless a custom DTB is specifically provided, or CONFIG_OF is enabled for some other reason (e.g. for unit tests, etc). And even if it were, there's no physical YT8824 hardware in these emulated environments anyway. This means `yt8824_probe` is very unlikely to succeed, even if MDIO bus emulation were perfect, because the code *mandates* Device Tree and specific properties. Even if the MDIO bus is there, the probe would fail early, specifically due to the *lack* of the required Device Tree and properties. But let's not be hasty, let's make sure there aren't *any* regressions. So let me check every change in the diff. First, there's a new YAML file for DT bindings, that's not relevant to any *existing* PHY. Same for the MAINTAINERS file. `Kconfig` for the driver might be important later, but is not relevant to my question. But wait a minute, the `motorcomm.c` driver file might be worth investigating! Let's check `ytphy_set_wol`. Ah, I see a significant change in `ytphy_set_wol` - there has been a large addition to the code. This changes the way Wake-on-LAN is handled. But even though this is a significant change, I don't see anything here that affects the *detection* of existing PHYs. It's all about *configuration* of Wake-on-LAN once a MotorComm PHY is *already* present. This change is unlikely to cause a regression, because it only affects wake-on-lan *behavior*, and specifically does not change any of the existing probe behavior or DT assumptions. The change is safe as far as existing PHYs are concerned. |
| 16/2 | 2026/10/20 06:15 | tool | read-file |
0mArgs:{
"File": "drivers/net/phy/motorcomm.c",
"FirstLine": 930,
"LineCount": 40
}Results: {
"Contents": " 930:\t\t\tmask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL;\n 931:\t\t\tval = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;\n 932:\t\t\tval |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS;\n 933:\t\t\tret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, val);\n 934:\t\t\tif (ret \u003c 0)\n 935:\t\t\t\tgoto err_restore_page;\n 936:\t\n 937:\t\t\t/* Enable WOL interrupt */\n 938:\t\t\tret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0,\n 939:\t\t\t\t\t YTPHY_IER_WOL);\n 940:\t\t\tif (ret \u003c 0)\n 941:\t\t\t\tgoto err_restore_page;\n 942:\t\n 943:\t\t} else {\n 944:\t\t\told_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);\n 945:\t\t\tif (old_page \u003c 0)\n 946:\t\t\t\tgoto err_restore_page;\n 947:\t\n 948:\t\t\t/* Disable WOL feature */\n 949:\t\t\tmask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;\n 950:\t\t\tret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, 0);\n 951:\t\n 952:\t\t\t/* Disable WOL interrupt */\n 953:\t\t\tret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,\n 954:\t\t\t\t\t YTPHY_IER_WOL, 0);\n 955:\t\t\tif (ret \u003c 0)\n 956:\t\t\t\tgoto err_restore_page;\n 957:\t\t}\n 958:\t\n 959:\terr_restore_page:\n 960:\t\treturn phy_restore_page(phydev, old_page, ret);\n 961:\t}\n 962:\t\n 963:\t/**\n 964:\t * yt8824_read_page() - read PHY8824 reg page\n 965:\t * @phydev: a pointer to a \u0026struct phy_device\n 966:\t *\n 967:\t * Returns: current reg space of yt8824 (YT8824_RSSR_SERDES_SPACE/\n 968:\t * YT8824_RSSR_UTP_SPACE) or negative errno code\n 969:\t */\n"
} |
| 17/2 | 2026/10/20 06:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 49455 output: 25 thoughts: 504 Thoughts: **Analyzing a Recent Code Change** Okay, hold on a second. I was just reviewing this commit, specifically the change in `ytphy_set_wol`. I'm looking at the diff and it's got me scratching my head. The change adds an `if (ret < 0) goto err_restore_page;` right after the call to `__phy_modify`. But hang on... even without that conditional, the code *immediately* jumps to `err_restore_page:` after that closing curly brace! It's as if that `goto` is completely redundant, a literal no-op. It appears to be an irrelevant change. I need to be sure; it is very likely a mistake. Now, let's switch gears and investigate `phy-c45.c`. I'm focusing on the `genphy_c45_template_testmode` function. I'm taking a quick look at its implementation. It checks `test_mode` against a maximum value and then calls `phy_modify_mmd`. The question now is: Where is this function actually used in the broader project? I'm going to run a full search through the codebase to find all its callers. This is essential to understand the potential impact of changes within this module. |
| 18/2 | 2026/10/20 06:15 | tool | grepper |
0mArgs:{
"Expression": "genphy_c45_template_testmode"
}Results: {
"Output": "drivers/net/phy/motorcomm.c=1009=static int yt8824_utp_set_template_test_mode(struct phy_device *phydev,\n--\ndrivers/net/phy/motorcomm.c-1017-\ndrivers/net/phy/motorcomm.c:1018:\treturn genphy_c45_template_testmode(phydev, test_mode);\ndrivers/net/phy/motorcomm.c-1019-}\n--\ndrivers/net/phy/motorcomm.c=1188=static int yt8824_config_utp_init_paged(struct phy_device *phydev)\n--\ndrivers/net/phy/motorcomm.c-1688-\t/* reset */\ndrivers/net/phy/motorcomm.c:1689:\tret = genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-1690-\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-1701-\ndrivers/net/phy/motorcomm.c:1702:\tret = genphy_c45_template_testmode(phydev,\ndrivers/net/phy/motorcomm.c-1703-\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\n--\ndrivers/net/phy/motorcomm.c-1714-err_restore_normal:\ndrivers/net/phy/motorcomm.c:1715:\tr = genphy_c45_template_testmode(phydev,\ndrivers/net/phy/motorcomm.c-1716-\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\n--\ndrivers/net/phy/phy-c45.c=1409=EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain);\n--\ndrivers/net/phy/phy-c45.c-1411-/**\ndrivers/net/phy/phy-c45.c:1412: * genphy_c45_template_testmode - configure template testmode registers\ndrivers/net/phy/phy-c45.c-1413- * @phydev: target phy_device struct\n--\ndrivers/net/phy/phy-c45.c-1420- */\ndrivers/net/phy/phy-c45.c:1421:int genphy_c45_template_testmode(struct phy_device *phydev, u16 test_mode)\ndrivers/net/phy/phy-c45.c-1422-{\n--\ndrivers/net/phy/phy-c45.c-1431-}\ndrivers/net/phy/phy-c45.c:1432:EXPORT_SYMBOL_GPL(genphy_c45_template_testmode);\ndrivers/net/phy/phy-c45.c-1433-\n--\ninclude/linux/phy.h=2361=int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable);\ninclude/linux/phy.h:2362:int genphy_c45_template_testmode(struct phy_device *phydev, u16 test_mode);\ninclude/linux/phy.h-2363-int genphy_c45_plca_get_cfg(struct phy_device *phydev,\n"
} |
| 19/2 | 2026/10/20 06:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 51134 output: 26 thoughts: 1538 Thoughts: **Analysis of Code Reachability and Fuzzing Worthiness** Okay, so the only place in the entire kernel that calls `genphy_c45_template_testmode` is `motorcomm.c`, specifically within the `yt8824_*` functions. My immediate concern is whether any of this code, the `yt8824_*` functions, can *actually* be executed in a standard virtualized environment like GCE or QEMU. That's the key question. Let's break this down. First, `yt8824` is a physical Ethernet PHY chip from Motorcomm – a hardware component. It's an MDIO device. In Linux, MDIO devices are probed either through MDIO bus scanning (looking for specific PHY IDs) or, more importantly in this case, through Device Tree (DT). The code specifically checks for an associated DT node. The `yt8824_probe` function is the gatekeeper. It relies on `devm_of_phy_package_join`, which eventually calls `of_phy_package_join`. This is where it gets interesting. `of_phy_package_join` *requires* a valid Device Tree node for the PHY (`phydev->mdio.dev.of_node`). Without it, the probe fails immediately with `-EINVAL`. It also demands the `package_node` has the name "ethernet-phy-package", and the property `motorcomm,package-mode` is present. Now, here's the clincher: Does QEMU, or any standard x86/amd64 virtualized environment, emulate this specific Motorcomm YT8824 PHY? The answer is a definitive "no." There's no QEMU emulation of this hardware, and critically, there is *no* virtual driver (like virtio, USB gadget, loopback, netlink, or tun/tap) that provides an MDIO bus and *specifically* this YT8824 PHY or the corresponding Device Tree package node. USB gadgets *could* emulate a network card, like asix or smsc95xx, but they would *not* have the required DT node (or if they had a dynamic node, it wouldn't have the required data). Consequently, `yt8824_probe` *cannot* succeed. Therefore, none of the `yt8824_*` functions (configuration, reset, suspend, resume, etc.) can ever be called in a standard virtualized setup. This particular hardware is designed for specific boards, switches, or other devices often based on ARM or MIPS architectures, and that use Device Tree. Let's revisit the fuzzing criteria. I need to make sure I'm not wasting time on this. According to the "NEGATIVE CRITERIA," I need to confirm if this falls under "Structurally unreachable hardware." This specifically cites vendor-specific devices requiring physical hardware not emulated in standard QEMU. Bingo. This YT8824 PHY is precisely that: vendor-specific hardware requiring specific DT binding. The change in `ytphy_set_wol` with the `err_restore_page` label is a non-functional change, it does not alter execution flow. Furthermore, let's verify if `genphy_c45_template_testmode` can somehow be reached from *elsewhere* – maybe through a syscall or ethtool interface, even indirectly? I need to double-check that `MDIO_PMA_10GBT_TESTMODE` or `genphy_c45_template_testmode` are not exposed via ethtool or an ioctl. In conclusion, because the underlying hardware is structurally unreachable in standard virtualization, and `genphy_c45_template_testmode` is only called by this unreachable code, this is not worth fuzzing. |
| 20/2 | 2026/10/20 06:15 | tool | grepper |
0mArgs:{
"Expression": "MDIO_PMA_10GBT_TESTMODE"
}Results: {
"Output": "drivers/net/phy/motorcomm.c=1106=static int yt8824_restore_working_status(struct phy_device *phydev, int ret)\n--\ndrivers/net/phy/motorcomm.c-1111-\tr = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:1112:\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-1113-\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n--\ndrivers/net/phy/motorcomm.c=1130=static int yt8824_soft_reset(struct phy_device *phydev)\n--\ndrivers/net/phy/motorcomm.c-1137-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:1138:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-1139-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-1146-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:1147:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-1148-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-1151-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:1152:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-1153-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-1164-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:1165:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-1166-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c=1188=static int yt8824_config_utp_init_paged(struct phy_device *phydev)\n--\ndrivers/net/phy/motorcomm.c-1688-\t/* reset */\ndrivers/net/phy/motorcomm.c:1689:\tret = genphy_c45_template_testmode(phydev, MDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-1690-\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-1702-\tret = genphy_c45_template_testmode(phydev,\ndrivers/net/phy/motorcomm.c:1703:\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-1704-\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-1715-\tr = genphy_c45_template_testmode(phydev,\ndrivers/net/phy/motorcomm.c:1716:\t\t\t\t\t MDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-1717-\tif (ret \u003e= 0 \u0026\u0026 r \u003c 0)\n--\ndrivers/net/phy/motorcomm.c=4864=static int yt8824_power_on(struct phy_device *phydev)\n--\ndrivers/net/phy/motorcomm.c-4871-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4872:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-4873-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-4880-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4881:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-4882-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-4885-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4886:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-4887-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-4898-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4899:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-4900-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c=4947=static int yt8824_power_down(struct phy_device *phydev)\n--\ndrivers/net/phy/motorcomm.c-4954-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4955:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-4956-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-4963-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4964:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-4965-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-4968-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4969:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_1);\ndrivers/net/phy/motorcomm.c-4970-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/motorcomm.c-4981-\t\tret = yt8824_utp_set_template_test_mode(phydev,\ndrivers/net/phy/motorcomm.c:4982:\t\t\t\t\t\t\tMDIO_PMA_10GBT_TESTMODE_NORMAL);\ndrivers/net/phy/motorcomm.c-4983-\t\tif (ret \u003c 0)\n--\ndrivers/net/phy/phy-c45.c=1421=int genphy_c45_template_testmode(struct phy_device *phydev, u16 test_mode)\n--\ndrivers/net/phy/phy-c45.c-1424-\ndrivers/net/phy/phy-c45.c:1425:\tif (test_mode \u003e MDIO_PMA_10GBT_TESTMODE_7)\ndrivers/net/phy/phy-c45.c-1426-\t\treturn -EOPNOTSUPP;\ndrivers/net/phy/phy-c45.c-1427-\ndrivers/net/phy/phy-c45.c:1428:\tctrl = FIELD_PREP(MDIO_PMA_10GBT_TESTMODE_MASK, test_mode);\ndrivers/net/phy/phy-c45.c:1429:\treturn phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TESTMODE,\ndrivers/net/phy/phy-c45.c:1430:\t\t\t MDIO_PMA_10GBT_TESTMODE_MASK, ctrl);\ndrivers/net/phy/phy-c45.c-1431-}\n--\ninclude/uapi/linux/mdio.h-65-#define MDIO_PMA_10GBT_TXPWR\t131\t/* 10GBASE-T TX power control */\ninclude/uapi/linux/mdio.h:66:#define MDIO_PMA_10GBT_TESTMODE 132 /* Test mode control */\ninclude/uapi/linux/mdio.h-67-#define MDIO_PMA_10GBT_SNR\t133\t/* 10GBASE-T SNR margin, lane A.\n--\ninclude/uapi/linux/mdio.h-324-/* PMA 10GBASE-T Template Test Mode Register*/\ninclude/uapi/linux/mdio.h:325:#define MDIO_PMA_10GBT_TESTMODE_MASK GENMASK(15, 13) /* Template test mode */\ninclude/uapi/linux/mdio.h:326:#define MDIO_PMA_10GBT_TESTMODE_NORMAL 0x0 /* Template Normal */\ninclude/uapi/linux/mdio.h:327:#define MDIO_PMA_10GBT_TESTMODE_1 0x1 /* Template TestMode1 */\ninclude/uapi/linux/mdio.h:328:#define MDIO_PMA_10GBT_TESTMODE_2 0x2 /* Template TestMode2 */\ninclude/uapi/linux/mdio.h:329:#define MDIO_PMA_10GBT_TESTMODE_3 0x3 /* Template TestMode3 */\ninclude/uapi/linux/mdio.h:330:#define MDIO_PMA_10GBT_TESTMODE_4 0x4 /* Template TestMode4 */\ninclude/uapi/linux/mdio.h:331:#define MDIO_PMA_10GBT_TESTMODE_5 0x5 /* Template TestMode5 */\ninclude/uapi/linux/mdio.h:332:#define MDIO_PMA_10GBT_TESTMODE_6 0x6 /* Template TestMode6 */\ninclude/uapi/linux/mdio.h:333:#define MDIO_PMA_10GBT_TESTMODE_7 0x7 /* Template TestMode7 */\ninclude/uapi/linux/mdio.h-334-\n"
} |
| 21/2 | 2026/10/20 06:15 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 56233 output: 239 thoughts: 360 Thoughts: **My Assessment of the Code's Reachability** Okay, so here's what I've got. It looks like `genphy_c45_template_testmode` and `MDIO_PMA_10GBT_TESTMODE` are exclusively used within `motorcomm.c`, specifically by the `yt8824_*` functions. And the `yt8824` itself is a physical Ethernet PHY chip, meaning it's real hardware. This isn't just some abstract driver; it's something that plugs into an actual circuit board. Crucially, this `yt8824` needs a very specific Device Tree configuration – the `motorcomm,yt8824-package` property. And that's the kicker. This configuration is *not* present in the standard virtualized environments, like QEMU or Google Compute Engine, that we typically use on amd64 architectures. So, let me make sure I've got this straight. The new code supports the Motorcomm YT8824 PHY. This PHY relies on a specific Device Tree node. It also makes use of a helper function `genphy_c45_template_testmode` in `phy-c45.c`, which is also exclusive to the `yt8824` driver. Because the hardware isn't emulated in a typical development setup, the code isn't reachable. There's also that redundant `goto` statement in `ytphy_set_wol()`, but that's not changing the control flow. Therefore, because this is all based on physical hardware with very specific configuration requirements, it's structurally unreachable. I am confident that syzkaller will not be able to exercise this code. I'm marking the `WorthFuzzing` flag as false and have identified that reasoning for this triage. I will now call `set-results`. |
| 22/2 | 2026/10/20 06:16 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch series introduces support for the Motorcomm YT8824 Quad 2.5Gbps Ethernet PHY in drivers/net/phy/motorcomm.c, along with a Device Tree binding and a Clause 45 PMA testmode helper in drivers/net/phy/phy-c45.c. The YT8824 driver represents physical ASIC Ethernet PHY hardware that strictly requires specific Device Tree structures (an ethernet-phy-package parent node with motorcomm,package-mode property checked in yt8824_probe via devm_of_phy_package_join). This hardware is not present or emulated in standard virtualized fuzzing environments (QEMU/GCE on amd64). The helper function genphy_c45_template_testmode() is only called by the YT8824 driver, and the minor change in ytphy_set_wol() is functionally identical to the existing code. Consequently, the modified executable code is structurally unreachable.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series introduces support for the Motorcomm YT8824 Quad 2.5Gbps Ethernet PHY in drivers/net/phy/motorcomm.c, along with a Device Tree binding and a Clause 45 PMA testmode helper in drivers/net/phy/phy-c45.c. The YT8824 driver represents physical ASIC Ethernet PHY hardware that strictly requires specific Device Tree structures (an ethernet-phy-package parent node with motorcomm,package-mode property checked in yt8824_probe via devm_of_phy_package_join). This hardware is not present or emulated in standard virtualized fuzzing environments (QEMU/GCE on amd64). The helper function genphy_c45_template_testmode() is only called by the YT8824 driver, and the minor change in ytphy_set_wol() is functionally identical to the existing code. Consequently, the modified executable code is structurally unreachable.",
"WorthFuzzing": false
} |
| 23/1 | 2026/10/20 06:16 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|