AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/09 01:11 flow patch-triage
1m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch introduces a new hardware-specific Ethernet PHY driver for Airoha SoCs and refactors the existing MediaTek PHY driver to share code. Since PHY devices are instantiated by the MDIO bus based on hardware probing (reading PHY ID registers) or device tree, and there is no virtual MDIO bus or software-emulated hardware in virtualized environments (like QEMU/GCE) that can instantiate this specific PHY, the code is impossible to reach and test via fuzzing.",
  "WorthFuzzing": false
}

1/1 2026/07/09 01:11 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit e27b55cd6a9ebb4a6bccb12c9f602b617fb0d0eb\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Thu Jul 9 01:11:53 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 52f1a55eca99bf..65cc21b39c3dbc 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -760,6 +760,14 @@ S:\tMaintained\n F:\tDocumentation/devicetree/bindings/net/airoha,en7581-eth.yaml\n F:\tdrivers/net/ethernet/airoha/\n \n+AIROHA ETHERNET PHY DRIVER\n+M:\tChristian Marangi \u003cansuelsmth@gmail.com\u003e\n+L:\tlinux-arm-kernel@lists.infradead.org (moderated for non-subscribers)\n+L:\tlinux-mediatek@lists.infradead.org (moderated for non-subscribers)\n+L:\tnetdev@vger.kernel.org\n+S:\tMaintained\n+F:\tdrivers/net/phy/mediatek/airoha-ge-soc.c\n+\n AIROHA PCIE PHY DRIVER\n M:\tLorenzo Bianconi \u003clorenzo@kernel.org\u003e\n L:\tlinux-arm-kernel@lists.infradead.org (moderated for non-subscribers)\n@@ -16483,6 +16491,7 @@ L:\tnetdev@vger.kernel.org\n S:\tMaintained\n F:\tdrivers/net/phy/mediatek/mtk-2p5ge.c\n F:\tdrivers/net/phy/mediatek/mtk-ge-soc.c\n+F:\tdrivers/net/phy/mediatek/mtk-ge-soc.h\n F:\tdrivers/net/phy/mediatek/mtk-phy-lib.c\n F:\tdrivers/net/phy/mediatek/mtk-ge.c\n F:\tdrivers/net/phy/mediatek/mtk.h\ndiff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig\nindex bb7dc876271e83..fe51f4616c544f 100644\n--- a/drivers/net/phy/mediatek/Kconfig\n+++ b/drivers/net/phy/mediatek/Kconfig\n@@ -1,4 +1,17 @@\n # SPDX-License-Identifier: GPL-2.0-only\n+config AIROHA_GE_SOC_PHY\n+\ttristate \"Airoha SoC Ethernet PHYs\"\n+\tdepends on ARM64 || COMPILE_TEST\n+\tdepends on ARCH_AIROHA || COMPILE_TEST\n+\tselect MTK_NET_PHYLIB\n+\tselect PHY_PACKAGE\n+\thelp\n+\t  Supports Airoha SoC built-in Gigabit Ethernet PHYs.\n+\n+\t  Include support for built-in Ethernet PHYs which are present in\n+\t  the AN7581 and AN7583 SoCs. These PHYs d will dynamically\n+\t  calibrate during startup.\n+\n config MEDIATEK_2P5GE_PHY\n \ttristate \"MediaTek 2.5Gb Ethernet PHYs\"\n \tdepends on (ARM64 \u0026\u0026 ARCH_MEDIATEK) || COMPILE_TEST\n@@ -24,8 +37,7 @@ config MEDIATEK_GE_PHY\n config MEDIATEK_GE_SOC_PHY\n \ttristate \"MediaTek SoC Ethernet PHYs\"\n \tdepends on ARM64 || COMPILE_TEST\n-\tdepends on ARCH_AIROHA || (ARCH_MEDIATEK \u0026\u0026 NVMEM_MTK_EFUSE) || \\\n-\t\t   COMPILE_TEST\n+\tdepends on (ARCH_MEDIATEK \u0026\u0026 NVMEM_MTK_EFUSE) || COMPILE_TEST\n \tselect MTK_NET_PHYLIB\n \tselect PHY_PACKAGE\n \thelp\ndiff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile\nindex ac57ecc799fc81..eb430f008169e2 100644\n--- a/drivers/net/phy/mediatek/Makefile\n+++ b/drivers/net/phy/mediatek/Makefile\n@@ -1,4 +1,5 @@\n # SPDX-License-Identifier: GPL-2.0\n+obj-$(CONFIG_AIROHA_GE_SOC_PHY)\t\t+= airoha-ge-soc.o\n obj-$(CONFIG_MEDIATEK_2P5GE_PHY)\t+= mtk-2p5ge.o\n obj-$(CONFIG_MEDIATEK_GE_PHY)\t\t+= mtk-ge.o\n obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)\t+= mtk-ge-soc.o\ndiff --git a/drivers/net/phy/mediatek/airoha-ge-soc.c b/drivers/net/phy/mediatek/airoha-ge-soc.c\nnew file mode 100644\nindex 00000000000000..601a64d8336542\n--- /dev/null\n+++ b/drivers/net/phy/mediatek/airoha-ge-soc.c\n@@ -0,0 +1,1812 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+#include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/pinctrl/consumer.h\u003e\n+#include \u003clinux/phy.h\u003e\n+\n+#include \"../phylib.h\"\n+#include \"mtk.h\"\n+#include \"mtk-ge-soc.h\"\n+\n+#define AIROHA_DEFAULT_PORT0_ADDR\t\t0x9\n+#define AIROHA_PHY_MAX_LEDS\t\t\t2\n+\n+enum airoha_mdi_resister_type {\n+\tMDI_0R,\n+\tMDI_5R,\n+\n+\tMDI_TYPE_MAX,\n+};\n+\n+enum airoha_transformer_type {\n+\tTXMR,\n+\tDISCRETE,\n+\n+\tTRANSFORMER_TYPE_MAX,\n+};\n+\n+enum airoha_calib_const_type {\n+\tTX_AMP_TEST_A,\n+\tTX_AMP_TEST_B,\n+\tTX_AMP_TEST_C,\n+\tTX_AMP_TEST_D,\n+\tTX_AMP_1G_A,\n+\tTX_AMP_1G_B,\n+\tTX_AMP_1G_C,\n+\tTX_AMP_1G_D,\n+\tTX_AMP_100M_A,\n+\tTX_AMP_100M_B,\n+\tTX_AMP_10M_A,\n+\tTX_AMP_10M_B,\n+\tR50_A,\n+\tR50_B,\n+\tR50_C,\n+\tR50_D,\n+\n+\tCALIB_CONST_TYPE_MAX,\n+};\n+\n+struct airoha_socphy_shared {\n+\tstruct phy_device *phydev_p0;\n+\tenum airoha_transformer_type transformer_type[4];\n+\tenum airoha_mdi_resister_type mdi_resister_type;\n+\tbool rext_sw_calib_done;\n+\tint (*tx_amp_compensation_tbl)[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4];\n+\tu8 *r50_cal_tbl;\n+};\n+\n+/*\n+ * 2 chip revision\n+ * TXMR or discrete\n+ * 2 MDI type\n+ * TX AMP test/TX AMP 1G/TX AMP 100M/TX AMP 10M/R50\n+ * 4 PHY\n+ */\n+static int an7581_tx_amp_compensation_tbl[2][TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {\n+\t{ /* IC version 1 */\n+\t\t[TXMR] = {\n+\t\t\t{ },\n+\t\t\t{\n+\t\t\t\t[TX_AMP_TEST_A] = { -12, -11, -9, -6 },\n+\t\t\t\t[TX_AMP_TEST_B] = { -9, -13, -9, -5 },\n+\t\t\t\t[TX_AMP_TEST_C] = { -5, -4, -3, 1 },\n+\t\t\t\t[TX_AMP_TEST_D] = { -9, -8, -7, -5 },\n+\t\t\t\t[TX_AMP_1G_A] = { -12, -11, -9, -6 },\n+\t\t\t\t[TX_AMP_1G_B] = { -9, -13, -9, -5 },\n+\t\t\t\t[TX_AMP_1G_C] = { -5, -4, -3, 1 },\n+\t\t\t\t[TX_AMP_1G_D] = { -9, -8, -7, -5 },\n+\t\t\t\t[TX_AMP_100M_A] = { -2, -2, 0, 2 },\n+\t\t\t\t[TX_AMP_100M_B] = { -2, -2, 1, 1 },\n+\t\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t\t[R50_A] = { 15, 15, 15, 15 },\n+\t\t\t\t[R50_B] = { 15, 15, 18, 15 },\n+\t\t\t\t[R50_C] = { -8, -8, -8, -8 },\n+\t\t\t\t[R50_D] = { -8, -8, -8, -8 },\n+\t\t\t},\n+\t\t},\n+\t\t[DISCRETE] = {\n+\t\t\t{ },\n+\t\t\t{\n+\t\t\t\t[TX_AMP_TEST_A] = { -9, -7, -7, -5 },\n+\t\t\t\t[TX_AMP_TEST_B] = { -9, -9, -7, -4 },\n+\t\t\t\t[TX_AMP_TEST_C] = { -9, -7, -9, -6 },\n+\t\t\t\t[TX_AMP_TEST_D] = { -11, -9, -10, -8 },\n+\t\t\t\t[TX_AMP_1G_A] = { -9, -7, -7, -5 },\n+\t\t\t\t[TX_AMP_1G_B] = { -9, -8, -7, -4 },\n+\t\t\t\t[TX_AMP_1G_C] = { -9, -7, -9, -6 },\n+\t\t\t\t[TX_AMP_1G_D] = { -11, -8, -10, -8 },\n+\t\t\t\t[TX_AMP_100M_A] = { 4, 3, 4, 4 },\n+\t\t\t\t[TX_AMP_100M_B] = { 4, 4, 5, 4 },\n+\t\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t\t[R50_A] = { 0, 0, 0, 0 },\n+\t\t\t\t[R50_B] = { 0, 0, 0, 0 },\n+\t\t\t\t[R50_C] = { 0, 0, 0, 0 },\n+\t\t\t\t[R50_D] = { 0, 0, 0, 0 },\n+\t\t\t},\n+\t\t},\n+\t},\n+\t{ /* IC version 2 */\n+\t\t[TXMR] = {\n+\t\t\t{ },\n+\t\t\t{\n+\t\t\t\t[TX_AMP_TEST_A] = { -10, -12, -12, -11 },\n+\t\t\t\t[TX_AMP_TEST_B] = { -10, -11, -11, -10 },\n+\t\t\t\t[TX_AMP_TEST_C] = { -5, -7, -9, -3 },\n+\t\t\t\t[TX_AMP_TEST_D] = { -8, -10, -7, -8 },\n+\t\t\t\t[TX_AMP_1G_A] = { -12, -6, -6, 4 },\n+\t\t\t\t[TX_AMP_1G_B] = { -10, -5, -5, 1 },\n+\t\t\t\t[TX_AMP_1G_C] = { -5, -3, -4, 11 },\n+\t\t\t\t[TX_AMP_1G_D] = { -8, -3, -3, 4 },\n+\t\t\t\t[TX_AMP_100M_A] = { 2, 1, 0, 3 },\n+\t\t\t\t[TX_AMP_100M_B] = { 0, 0, 0, 3 },\n+\t\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t\t[R50_A] = { 15, 15, 15, 15 },\n+\t\t\t\t[R50_B] = { 15, 15, 18, 15 },\n+\t\t\t\t[R50_C] = { 4, 4, 4, 4 },\n+\t\t\t\t[R50_D] = { 4, 4, 4, 4 },\n+\t\t\t},\n+\t\t},\n+\t\t[DISCRETE] = {\n+\t\t\t{ },\n+\t\t\t{\n+\t\t\t\t[TX_AMP_TEST_A] = { -11, 11, -12, -7 },\n+\t\t\t\t[TX_AMP_TEST_B] = { -9, -10, -9, -8 },\n+\t\t\t\t[TX_AMP_TEST_C] = { -6, -3, -7, -4 },\n+\t\t\t\t[TX_AMP_TEST_D] = { -7, -8, -10, -7 },\n+\t\t\t\t[TX_AMP_1G_A] = { -11, -11, -12, -7 },\n+\t\t\t\t[TX_AMP_1G_B] = { -9, -10, -9, -8 },\n+\t\t\t\t[TX_AMP_1G_C] = { -6, -3, -7, -4 },\n+\t\t\t\t[TX_AMP_1G_D] = { -7, -8, -10, -7 },\n+\t\t\t\t[TX_AMP_100M_A] = { 2, 2, 1, 2 },\n+\t\t\t\t[TX_AMP_100M_B] = { 3, 3, 3, 3 },\n+\t\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t\t[R50_A] = { 12, 12, 12, 12 },\n+\t\t\t\t[R50_B] = { 7, 7, 7, 7 },\n+\t\t\t\t[R50_C] = { 2, 2, 0, 0 },\n+\t\t\t\t[R50_D] = { 0, 0, 2, 2 },\n+\t\t\t},\n+\t\t},\n+\t},\n+};\n+\n+static u8 an7581_zcal_to_r45ohm[64] = {\n+\t127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,\n+\t127, 127, 127, 127, 127, 127, 127, 127, 123, 119, 115, 112, 108, 104, 100,  96,\n+\t 94,  92,  88,  85,  82,  80,  76,  74,  72,  68,  66,  64,  62,  60,  56,  55,\n+\t 52,  50,  48,  46,  44,  42,  40,  39,  36,  35,  32,  32,  30,  28,  27,  25\n+};\n+\n+/*\n+ * 2 chip revision\n+ * TXMR or discrete\n+ * 2 MDI type\n+ * TX AMP test/TX AMP 1G/TX AMP 100M/TX AMP 10M/R50\n+ * 4 PHY\n+ */\n+static int an7583_tx_amp_compensation_tbl[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {\n+\t[TXMR] = {\n+\t\t[MDI_0R] = {\n+\t\t\t[TX_AMP_TEST_A] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_B] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_C] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_D] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_1G_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_B] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_C] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_D] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_100M_A] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_100M_B] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t[R50_A] = { 4, 4, 0, 0 },\n+\t\t\t[R50_B] = { 4, 4, 0, 0 },\n+\t\t\t[R50_C] = { 5, 5, 3, 4 },\n+\t\t\t[R50_D] = { 4, 4, 4, 0 },\n+\t\t},\n+\t\t[MDI_5R] = {\n+\t\t\t[TX_AMP_TEST_A] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_B] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_C] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_D] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_1G_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_B] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_C] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_D] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_100M_A] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_100M_B] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t[R50_A] = { -4, -4, -4, -4 },\n+\t\t\t[R50_B] = { -4, -4, -4, -4 },\n+\t\t\t[R50_C] = { -2, -2, -2, -2 },\n+\t\t\t[R50_D] = { -3, -3, -2, -2 },\n+\t\t},\n+\t},\n+\t[DISCRETE] = {\n+\t\t[MDI_0R] = {\n+\t\t\t[TX_AMP_TEST_A] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_B] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_C] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_D] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_1G_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_B] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_C] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_D] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_100M_A] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_100M_B] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t[R50_A] = { 4, 4, 4, 4 },\n+\t\t\t[R50_B] = { 4, 4, 4, 4 },\n+\t\t\t[R50_C] = { 6, 6, 6, 6 },\n+\t\t\t[R50_D] = { 4, 4, 4, 4 },\n+\t\t},\n+\t\t[MDI_5R] = {\n+\t\t\t[TX_AMP_TEST_A] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_B] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_C] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_TEST_D] = { -3, -3, -3, -3 },\n+\t\t\t[TX_AMP_1G_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_B] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_C] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_1G_D] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_100M_A] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_100M_B] = { 4, 4, 4, 4 },\n+\t\t\t[TX_AMP_10M_A] = { 0, 0, 0, 0 },\n+\t\t\t[TX_AMP_10M_B] = { 0, 0, 0, 0 },\n+\t\t\t[R50_A] = { 0, 0, 0, 0 },\n+\t\t\t[R50_B] = { 0, 0, 0, 0 },\n+\t\t\t[R50_C] = { 0, 0, 0, 0 },\n+\t\t\t[R50_D] = { 0, 0, 0, 0 },\n+\t\t},\n+\t},\n+};\n+\n+static u8 an7583_zcal_to_r50ohm_0R[64] = {\n+\t127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,\n+\t127, 127, 127, 122, 118, 114, 110, 106, 102,  98,  96,  92,  88,  85,  82,  80,\n+\t 76,  72,  70,  68,  64,  62,  60,  57,  55,  52,  50,  48,  46,  44,  41,  40,\n+\t 38,  36,  33,  32,  30,  28,  26,  24,  24,  22,  20,  18,  16,  16,  14,  12,\n+};\n+\n+static u8 an7583_zcal_to_r50ohm_5R[64] = {\n+\t127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,\n+\t127, 127, 127, 127, 127, 127, 127, 127, 127, 124, 120, 116, 112, 110, 106, 102,\n+\t 99,  96,  93,  90,  88,  84,  81,  79,  76,  73,  71,  68,  66,  64,  61,  59,\n+\t 56,  54,  52,  50,  48,  46,  44,  42,  40,  39,  37,  36,  33,  32,  31,  29,\n+};\n+\n+static int airoha_cal_cycle(struct phy_device *phydev, int devad,\n+\t\t\t    u32 regnum, u16 mask, u16 cal_val)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tstruct phy_device *phydev_p0;\n+\tint ret;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\n+\tphy_modify_mmd(phydev, devad, regnum, mask, cal_val);\n+\n+\tret = mtk_cal_cycle_wait(phydev_p0);\n+\tphydev_dbg(phydev, \"cal_val: 0x%x, ret: %d\\n\", cal_val, ret);\n+\n+\treturn ret;\n+}\n+\n+static int airoha_rext_cal_sw(struct phy_device *phydev)\n+{\n+\tint calibration_polarity;\n+\tu8 zcal_ctrl = 32;\n+\tint first_calib;\n+\tint ret;\n+\n+\t/* BG voltage output */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x100, 0xc000);\n+\t/* tst_mode2 */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0xff, 0x2);\n+\n+\tphy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xff,\n+\t\t\t   GENMASK(15, 4) | GENMASK(1, 0));\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,\n+\t\t      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN |\n+\t\t      MTK_PHY_RG_REXT_CALEN);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0);\n+\n+\tphydev_dbg(phydev, \"Start REXT SW cal.\\n\");\n+\tfirst_calib = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,\n+\t\t\t\t       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);\n+\n+\tif (first_calib \u003c 0) {\n+\t\tphydev_err(phydev, \"REXT SW calibration failed.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* If REXT calibration failed:\n+\t * - increase dB until calibration succeed.\n+\t * If REXT calibration succeeded:\n+\t * - decrease dB until calibration fail to fine tune it.\n+\t */\n+\tif (first_calib == 1)\n+\t\tcalibration_polarity = -1;\n+\telse\n+\t\tcalibration_polarity = 1;\n+\n+\twhile (zcal_ctrl \u003e 0 \u0026\u0026\n+\t       zcal_ctrl \u003c FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {\n+\t\tzcal_ctrl += calibration_polarity;\n+\n+\t\tret = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,\n+\t\t\t\t       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);\n+\t\t/* Exit if we either failed or succeeded compared to the\n+\t\t * first calibration result. (aka we finished fine tuning or\n+\t\t * we succeeded with calibration)\n+\t\t */\n+\t\tif (ret != first_calib)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (ret \u003c 0) {\n+\t\tphydev_err(phydev, \"REXT SW calibration failed.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (zcal_ctrl == 0 ||\n+\t    zcal_ctrl == FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {\n+\t\tzcal_ctrl = 32;\n+\t\tphydev_err(phydev, \"REXT SW calibration saturation. Defaulting to %x.\\n\",\n+\t\t\t   zcal_ctrl);\n+\t}\n+\n+\tphy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,\n+\t\t       MTK_PHY_RG_REXT_TRIM_MASK,\n+\t\t       FIELD_PREP(MTK_PHY_RG_REXT_TRIM_MASK, zcal_ctrl));\n+\tphy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,\n+\t\t       MTK_PHY_RG_BG_RASEL_MASK,\n+\t\t       FIELD_PREP(MTK_PHY_RG_BG_RASEL_MASK, zcal_ctrl \u003e\u003e 3));\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);\n+\n+\treturn 0;\n+}\n+\n+static int airoha_tx_offset_cal_sw(struct phy_device *phydev, u8 txg_calen_x)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tstruct phy_device *phydev_p0;\n+\tu16 dev1e_145_tmp, bmcr_tmp;\n+\tint calibration_polarity;\n+\tu16 reg_dac1, reg_dac2;\n+\tint zcal_ctrl = 0;\n+\tint first_calib;\n+\tu16 reg, mask;\n+\tint ret;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\n+\t/* BG voltage output */\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0xc000);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,\n+\t\t      MTK_PHY_RG_ANA_CALEN);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,\n+\t\t      MTK_PHY_RG_TXVOS_CALEN);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,\n+\t\t      MTK_PHY_RG_ANA_CALEN);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,\n+\t\t      MTK_PHY_RG_TXVOS_CALEN);\n+\n+\t/* Force 1G full duplex for calibration */\n+\tbmcr_tmp = phy_read(phydev, MII_BMCR);\n+\tphy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);\n+\n+\t/* Force MDI */\n+\tdev1e_145_tmp = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x0145);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, 0x1010);\n+\n+\t/* 1e_96[15]:bypass_tx_offset_cal, Hw bypass, Fw cal */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x96,\n+\t\t      0x8000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e,\n+\t\t      0xf808);\n+\n+\tswitch (txg_calen_x) {\n+\tcase PAIR_A:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(12));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_A;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_A;\n+\t\treg = MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B;\n+\t\tmask = MTK_PHY_CR_TX_AMP_OFFSET_A_MASK;\n+\t\tbreak;\n+\tcase PAIR_B:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(8));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_B;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_B;\n+\t\treg = MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B;\n+\t\tmask = MTK_PHY_CR_TX_AMP_OFFSET_B_MASK;\n+\t\tbreak;\n+\tcase PAIR_C:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(4));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_C;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_C;\n+\t\treg = MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D;\n+\t\tmask = MTK_PHY_CR_TX_AMP_OFFSET_C_MASK;\n+\t\tbreak;\n+\tcase PAIR_D:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(0));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_D;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_D;\n+\t\treg = MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D;\n+\t\tmask = MTK_PHY_CR_TX_AMP_OFFSET_D_MASK;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac1,\n+\t\t      0x8000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac2,\n+\t\t      0x8000);\n+\n+\tphydev_dbg(phydev, \"Start TX Offset SW cal.\\n\");\n+\n+\tfirst_calib = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg, mask,\n+\t\t\t\t       zcal_ctrl \u003c\u003c __ffs(mask));\n+\n+\t/* If TX Offset calibration failed:\n+\t * - increase dB until calibration succeed.\n+\t * If TX Offset calibration succeeded:\n+\t * - decrease dB until calibration fail to fine tune it.\n+\t */\n+\tif (first_calib == 1)\n+\t\tcalibration_polarity = -1;\n+\telse\n+\t\tcalibration_polarity = 1;\n+\n+\twhile (zcal_ctrl \u003e -32 \u0026\u0026 zcal_ctrl \u003c 32) {\n+\t\tu32 val;\n+\n+\t\tzcal_ctrl += calibration_polarity;\n+\t\tif (zcal_ctrl \u003e= 0)\n+\t\t\tval = zcal_ctrl;\n+\t\telse\n+\t\t\t/* BIT(5) signal negative number for TX Offset */\n+\t\t\tval = BIT(5) | abs(zcal_ctrl);\n+\n+\t\tret = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg, mask,\n+\t\t\t\t       val \u003c\u003c __ffs(mask));\n+\t\t/* Exit if we either failed or succeeded compared to the\n+\t\t * first calibration result. (aka we finished fine tuning or\n+\t\t * we succeeded with calibration)\n+\t\t */\n+\t\tif (ret != first_calib)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (ret \u003c 0) {\n+\t\tphydev_err(phydev, \"TX Offset calibration failed.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (zcal_ctrl == -32 ||\n+\t    zcal_ctrl == 32) {\n+\t\tzcal_ctrl = 0;\n+\t\tphydev_err(phydev, \"TX Offset SW calibration saturation. Defaulting to %x.\\n\",\n+\t\t\t   zcal_ctrl);\n+\n+\t\tphy_modify_mmd(phydev, MDIO_MMD_VEND1, reg, mask,\n+\t\t\t       zcal_ctrl \u003c\u003c __ffs(mask));\n+\t}\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x100, 0x0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D, 0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x96, 0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, 0);\n+\n+\t/* Restore BMCR */\n+\tphy_write(phydev, MII_BMCR, bmcr_tmp);\n+\n+\t/* Restore MDI */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, dev1e_145_tmp);\n+\n+\treturn 0;\n+}\n+\n+static int airoha_tx_amp_cal_sw(struct phy_device *phydev, u8 txg_calen_x)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tu16 mask_gbe, mask_tbt, mask_tst, mask_hbt;\n+\tu16 reg, reg_100, reg_dac1, reg_dac2;\n+\tstruct phy_device *phydev_p0;\n+\tint calibration_polarity;\n+\tu8 zcal_ctrl = 32;\n+\tint first_calib;\n+\tint ret;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\n+\t/* BG voltage output */\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0xc000);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x145, 0x1010);\n+\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,\n+\t\t      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,\n+\t\t      MTK_PHY_RG_TXVOS_CALEN);\n+\n+\t/* select 1V */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x10);\n+\n+\t/* enable Tx VLD*/\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xf808);\n+\n+\t/* Force 1G full duplex for calibration */\n+\tphy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);\n+\n+\tswitch (txg_calen_x) {\n+\tcase PAIR_A:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(12));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_A;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_A;\n+\t\treg = MTK_PHY_TXVLD_DA_RG;\n+\t\tmask_gbe = MTK_PHY_DA_TX_I2MPB_A_GBE_MASK;\n+\t\tmask_tbt = MTK_PHY_DA_TX_I2MPB_A_TBT_MASK;\n+\t\treg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_A2;\n+\t\tmask_hbt = MTK_PHY_DA_TX_I2MPB_A_HBT_MASK;\n+\t\tmask_tst = MTK_PHY_DA_TX_I2MPB_A_TST_MASK;\n+\t\tbreak;\n+\tcase PAIR_B:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(8));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_B;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_B;\n+\t\treg = MTK_PHY_TX_I2MPB_TEST_MODE_B1;\n+\t\tmask_gbe = MTK_PHY_DA_TX_I2MPB_B_GBE_MASK;\n+\t\tmask_tbt = MTK_PHY_DA_TX_I2MPB_B_TBT_MASK;\n+\t\treg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_B2;\n+\t\tmask_hbt = MTK_PHY_DA_TX_I2MPB_B_HBT_MASK;\n+\t\tmask_tst = MTK_PHY_DA_TX_I2MPB_B_TST_MASK;\n+\t\tbreak;\n+\tcase PAIR_C:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(4));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_C;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_C;\n+\t\treg = MTK_PHY_TX_I2MPB_TEST_MODE_C1;\n+\t\tmask_gbe = MTK_PHY_DA_TX_I2MPB_C_GBE_MASK;\n+\t\tmask_tbt = MTK_PHY_DA_TX_I2MPB_C_TBT_MASK;\n+\t\treg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_C2;\n+\t\tmask_hbt = MTK_PHY_DA_TX_I2MPB_C_HBT_MASK;\n+\t\tmask_tst = MTK_PHY_DA_TX_I2MPB_C_TST_MASK;\n+\t\tbreak;\n+\tcase PAIR_D:\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(0));\n+\t\treg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_D;\n+\t\treg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_D;\n+\t\treg = MTK_PHY_TX_I2MPB_TEST_MODE_D1;\n+\t\tmask_gbe = MTK_PHY_DA_TX_I2MPB_D_GBE_MASK;\n+\t\tmask_tbt = MTK_PHY_DA_TX_I2MPB_D_TBT_MASK;\n+\t\treg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_D2;\n+\t\tmask_hbt = MTK_PHY_DA_TX_I2MPB_D_HBT_MASK;\n+\t\tmask_tst = MTK_PHY_DA_TX_I2MPB_D_TST_MASK;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac1,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac2,\n+\t\t      0x8000 | 0xf0);\n+\n+\tphydev_dbg(phydev, \"Start TX Amp SW cal.\\n\");\n+\tfirst_calib = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg,\n+\t\t\t\t       mask_gbe, zcal_ctrl \u003c\u003c __ffs(mask_gbe));\n+\n+\t/* If TX Amp calibration failed:\n+\t * - increase dB until calibration succeed.\n+\t * If TX Amp calibration succeeded:\n+\t * - decrease dB until calibration fail to fine tune it.\n+\t */\n+\tif (first_calib == 1)\n+\t\tcalibration_polarity = -1;\n+\telse\n+\t\tcalibration_polarity = 1;\n+\n+\twhile (zcal_ctrl \u003e 0 \u0026\u0026\n+\t       zcal_ctrl \u003c FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {\n+\t\tzcal_ctrl += calibration_polarity;\n+\n+\t\tret = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg,\n+\t\t\t\t       mask_gbe, zcal_ctrl \u003c\u003c __ffs(mask_gbe));\n+\t\t/* Exit if we either failed or succeeded compared to the\n+\t\t * first calibration result. (aka we finished fine tuning or\n+\t\t * we succeeded with calibration)\n+\t\t */\n+\t\tif (ret != first_calib)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (ret \u003c 0) {\n+\t\tphydev_err(phydev, \"TX AMP calibration failed.\\n\");\n+\t\tphy_modify_mmd(phydev, MDIO_MMD_VEND1, reg,\n+\t\t\t       mask_gbe | mask_tbt,\n+\t\t\t       (zcal_ctrl \u003c\u003c __ffs(mask_gbe)) |\n+\t\t\t       (zcal_ctrl \u003c\u003c __ffs(mask_tbt)));\n+\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (zcal_ctrl == 0 ||\n+\t    zcal_ctrl == FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK))\n+\t\tphydev_warn(phydev, \"TX AMP SW calibration saturation.\\n\");\n+\n+\tphy_modify_mmd(phydev, MDIO_MMD_VEND1, reg,\n+\t\t       mask_gbe | mask_tbt,\n+\t\t       (zcal_ctrl \u003c\u003c __ffs(mask_gbe)) |\n+\t\t       (zcal_ctrl \u003c\u003c __ffs(mask_tbt)));\n+\n+\tphy_modify_mmd(phydev, MDIO_MMD_VEND1, reg_100,\n+\t\t       mask_hbt | mask_tst,\n+\t\t       (zcal_ctrl \u003c\u003c __ffs(mask_hbt)) |\n+\t\t       (zcal_ctrl \u003c\u003c __ffs(mask_tst)));\n+\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0x0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D, 0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, 0x145, 0x1000);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, 0);\n+\n+\t/* Restore AN enable */\n+\tphy_write(phydev, MII_BMCR, BMCR_ANENABLE);\n+\n+\treturn 0;\n+}\n+\n+static int airoha_tx_r50_cal_sw(struct phy_device *phydev, u8 txg_calen_x)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tstruct phy_device *phydev_p0;\n+\tu16 dev1e_145_tmp, bmcr_tmp;\n+\tint calibration_polarity;\n+\tu8 zcal_ctrl = 32;\n+\tint first_calib;\n+\tu16 reg;\n+\tint ret;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\n+\t/* BG voltage output */\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0xc000);\n+\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,\n+\t\t      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\t/* select 1V */\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x10);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,\n+\t\t      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\t/* select 1V */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x10);\n+\n+\t/* Force 1G full duplex for calibration */\n+\tbmcr_tmp = phy_read(phydev, MII_BMCR);\n+\tphy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);\n+\n+\t/* Force MDI */\n+\tdev1e_145_tmp = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x0145);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, 0x1010);\n+\n+\t/* disable tx slew control */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0185, 0x0000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00fb, 0x0100);\n+\n+\tswitch (txg_calen_x) {\n+\tcase PAIR_A:\n+\t\tphy_set_bits_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t\t MTK_PHY_RG_ANA_CAL_RG0,\n+\t\t\t\t MTK_PHY_RG_ZCALEN_A);\n+\t\tbreak;\n+\tcase PAIR_B:\n+\t\tphy_set_bits_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t\t MTK_PHY_RG_ANA_CAL_RG1,\n+\t\t\t\t MTK_PHY_RG_ZCALEN_B);\n+\t\tbreak;\n+\tcase PAIR_C:\n+\t\tphy_set_bits_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t\t MTK_PHY_RG_ANA_CAL_RG1,\n+\t\t\t\t MTK_PHY_RG_ZCALEN_C);\n+\t\tbreak;\n+\tcase PAIR_D:\n+\t\tphy_set_bits_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t\t MTK_PHY_RG_ANA_CAL_RG1,\n+\t\t\t\t MTK_PHY_RG_ZCALEN_D);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tphydev_dbg(phydev, \"Start TX r50 SW cal.\\n\");\n+\tfirst_calib = airoha_cal_cycle(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,\n+\t\t\t\t       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);\n+\n+\tif (first_calib \u003c 0) {\n+\t\tphydev_err(phydev, \"TX r50 SW calibration failed.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* If TX r50 calibration failed:\n+\t * - increase dB until calibration succeed.\n+\t * If TX r50 calibration succeeded:\n+\t * - decrease dB until calibration fail to fine tune it.\n+\t */\n+\tif (first_calib == 1)\n+\t\tcalibration_polarity = -1;\n+\telse\n+\t\tcalibration_polarity = 1;\n+\n+\twhile (zcal_ctrl \u003e 0 \u0026\u0026\n+\t       zcal_ctrl \u003c FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {\n+\t\tzcal_ctrl += calibration_polarity;\n+\n+\t\tret = airoha_cal_cycle(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,\n+\t\t\t\t       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);\n+\t\t/* Exit if we either failed or succeeded compared to the\n+\t\t * first calibration result. (aka we finished fine tuning or\n+\t\t * we succeeded with calibration)\n+\t\t */\n+\t\tif (ret != first_calib)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (ret \u003c 0) {\n+\t\tphydev_err(phydev, \"TX r50 SW calibration failed.\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (zcal_ctrl == 0 ||\n+\t    zcal_ctrl == FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK))\n+\t\tphydev_warn(phydev, \"TX r50 SW calibration saturation.\\n\");\n+\n+\tzcal_ctrl = shared-\u003er50_cal_tbl[zcal_ctrl];\n+\n+\tswitch (txg_calen_x) {\n+\tcase PAIR_A:\n+\t\treg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_A_MASK, zcal_ctrl);\n+\t\tphy_modify_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t       MTK_PHY_RG_CR_TX_R50_OFFSET_A_B,\n+\t\t\t       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_A_MASK, reg);\n+\t\tbreak;\n+\tcase PAIR_B:\n+\t\treg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_B_MASK, zcal_ctrl);\n+\t\tphy_modify_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t       MTK_PHY_RG_CR_TX_R50_OFFSET_A_B,\n+\t\t\t       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_B_MASK, reg);\n+\t\tbreak;\n+\tcase PAIR_C:\n+\t\treg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_C_MASK, zcal_ctrl);\n+\t\tphy_modify_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t       MTK_PHY_RG_CR_TX_R50_OFFSET_C_D,\n+\t\t\t       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_C_MASK, reg);\n+\t\tbreak;\n+\tcase PAIR_D:\n+\t\treg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_D_MASK, zcal_ctrl);\n+\t\tphy_modify_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t       MTK_PHY_RG_CR_TX_R50_OFFSET_C_D,\n+\t\t\t       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_D_MASK, reg);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);\n+\n+\t/* Enable tx slew control */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0185, 0x0001);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00fb, 0x0000);\n+\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0x0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x0);\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x0);\n+\n+\t/* Restore BMCR */\n+\tphy_write(phydev, MII_BMCR, bmcr_tmp);\n+\n+\t/* Restore MDI */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, dev1e_145_tmp);\n+\n+\treturn 0;\n+}\n+\n+static int airoha_rx_offset_cal_sw(struct phy_device *phydev)\n+{\n+\t/* Hw bypass, Fw cal */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x96, 0x8000);\n+\t/* tx/rx_cal_criteria_value */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x37, 0x0033);\n+\n+\t/* rx offset cal by Hw setup */\n+\tphy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0x39,\n+\t\t\t   BIT(14) | BIT(11));\n+\n+\t/* disable rtune calibration */\n+\tphy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0x107,\n+\t\t\t   BIT(12));\n+\n+\t/* bypass tx/rx dc offset cancellation process */\n+\tphy_set_bits_mmd(phydev, MDIO_MMD_VEND1, 0x171,\n+\t\t\t BIT(8) | BIT(7));\n+\n+\t/* rx offset calibration start */\n+\tphy_set_bits_mmd(phydev, MDIO_MMD_VEND1, 0x39,\n+\t\t\t BIT(13));\n+\n+\t/* rx offset calibration stop */\n+\tphy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0x39,\n+\t\t\t   BIT(13));\n+\n+\tmdelay(10);\n+\n+\tphy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0x171,\n+\t\t\t   BIT(8) | BIT(7));\n+\n+\tif (phydev-\u003edrv-\u003ephy_id == AIROHA_GPHY_ID_AN7581)\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1,\n+\t\t\t      MTK_PHY_RG_ANA_CAL_RG6, 0x1);\n+\n+\treturn 0;\n+}\n+\n+static int airoha_cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,\n+\t\t\t u8 start_pair, u8 end_pair)\n+{\n+\tu8 pair_n;\n+\tint ret;\n+\n+\tfor (pair_n = start_pair; pair_n \u003c= end_pair; pair_n++) {\n+\t\tswitch (cal_item) {\n+\t\tcase REXT:\n+\t\t\tret = airoha_rext_cal_sw(phydev);\n+\t\t\tbreak;\n+\t\tcase TX_OFFSET:\n+\t\t\tret = airoha_tx_offset_cal_sw(phydev, pair_n);\n+\t\t\tbreak;\n+\t\tcase TX_AMP:\n+\t\t\tret = airoha_tx_amp_cal_sw(phydev, pair_n);\n+\t\t\tbreak;\n+\t\tcase TX_R50:\n+\t\t\tret = airoha_tx_r50_cal_sw(phydev, pair_n);\n+\t\t\tbreak;\n+\t\tcase RX_OFFSET:\n+\t\t\tret = airoha_rx_offset_cal_sw(phydev);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+static int airoha_start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,\n+\t\t\t    enum CAL_MODE cal_mode, u8 start_pair,\n+\t\t\t    u8 end_pair, u32 *buf)\n+{\n+\tint ret;\n+\n+\tswitch (cal_mode) {\n+\tcase SW_M:\n+\t\tret = airoha_cal_sw(phydev, cal_item, start_pair, end_pair);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ret) {\n+\t\tphydev_err(phydev, \"cal %d failed\\n\", cal_item);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int airoha_phy_calib(struct phy_device *phydev)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tstruct phy_device *phydev_p0;\n+\tint ret;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\n+\t/* PreCalibrate Set */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x5c, 0x6666);\n+\n+\tif (!shared-\u003erext_sw_calib_done) {\n+\t\tret = airoha_start_cal(phydev, REXT, SW_M, NO_PAIR, NO_PAIR, NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tshared-\u003erext_sw_calib_done = true;\n+\t}\n+\n+\tret = airoha_start_cal(phydev, TX_R50, SW_M, PAIR_A, PAIR_D, NULL);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = airoha_start_cal(phydev, TX_OFFSET, SW_M, PAIR_A, PAIR_D, NULL);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = airoha_start_cal(phydev, TX_AMP, SW_M, PAIR_A, PAIR_D, NULL);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = airoha_start_cal(phydev, RX_OFFSET, SW_M, NO_PAIR, NO_PAIR, NULL);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Gating, short with other pair */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x15, 0x0);\n+\n+\tphy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0x0);\n+\n+\treturn 0;\n+}\n+\n+static int airoha_phy_auto_select_transformer(struct phy_device *phydev)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tstruct phy_device *phydev_p0;\n+\tu8 phy_offset;\n+\tu16 bmcr_tmp;\n+\tu16 val;\n+\tint i;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\tphy_offset = phydev-\u003emdio.addr - phydev_p0-\u003emdio.addr;\n+\n+\t/* Force 1G full duplex for calibration */\n+\tbmcr_tmp = phy_read(phydev, MII_BMCR);\n+\tphy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);\n+\n+\tphy_modify_mmd(phydev, MDIO_MMD_VEND2, 0x271, GENMASK(4, 0),\n+\t\t       FIELD_PREP(GENMASK(4, 0), 0x3));\n+\n+\tphy_modify_mmd(phydev, MDIO_MMD_VEND2, 0x269, GENMASK(15, 12),\n+\t\t       FIELD_PREP(GENMASK(15, 12), 0x2));\n+\n+\tphy_modify_mmd(phydev, MDIO_MMD_VEND2, 0x26f, GENMASK(14, 12),\n+\t\t       FIELD_PREP(GENMASK(14, 12), 0x0));\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(12));\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D,\n+\t\t      0x8000 | 0xf0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D,\n+\t\t      0x8000 | 0xf0);\n+\n+\t/* Force pGA gain */\n+\tphy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);\n+\t__mtk_tr_modify(phydev, 0x1, 0xf, 0x10,\n+\t\t\tGENMASK(20, 15),\n+\t\t\tFIELD_PREP(GENMASK(20, 15), 0x1f));\n+\n+\t__mtk_tr_modify(phydev, 0x1, 0xf, 0x11,\n+\t\t\tGENMASK(23, 18) | GENMASK(15, 10) | GENMASK(7, 2),\n+\t\t\tFIELD_PREP(GENMASK(23, 18), 0x1f) |\n+\t\t\tFIELD_PREP(GENMASK(15, 10), 0x1f) |\n+\t\t\tFIELD_PREP(GENMASK(7, 2), 0x1f));\n+\tphy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xc9, 0xffff);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x151, 0x12);\n+\n+\tswitch (phy_offset) {\n+\tcase 0:\n+\t\tval = 0x1;\n+\t\tbreak;\n+\tcase 1:\n+\t\tval = 0x3;\n+\t\tbreak;\n+\tcase 2:\n+\t\tval = 0x5;\n+\t\tbreak;\n+\tcase 3:\n+\t\tval = 0x7;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x15,\n+\t\t      FIELD_PREP(GENMASK(14, 12), val) | 0x161);\n+\tmdelay(500);\n+\n+\tfor (i = 0; i \u003c 3; i++)\n+\t\tval = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0x1a);\n+\n+\t/* Check the value and report transformer type for later */\n+\tshared-\u003etransformer_type[phy_offset] = val \u003c 0xe0;\n+\n+\t/* Switch to Default */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x15, 0x1000);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, 0x0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A,\n+\t\t      0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A,\n+\t\t      0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B,\n+\t\t      0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B,\n+\t\t      0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C,\n+\t\t      0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C,\n+\t\t      0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D,\n+\t\t      0x0);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D,\n+\t\t      0x0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xc9, 0xfff);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x151, 0x0);\n+\n+\tphy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);\n+\t__mtk_tr_modify(phydev, 0x1, 0xf, 0x10,\n+\t\t\tGENMASK(20, 15),\n+\t\t\tFIELD_PREP(GENMASK(20, 15), 0x4));\n+\n+\t__mtk_tr_modify(phydev, 0x1, 0xf, 0x11,\n+\t\t\tGENMASK(23, 18) | GENMASK(15, 10) | GENMASK(7, 2),\n+\t\t\tFIELD_PREP(GENMASK(23, 18), 0x0) |\n+\t\t\tFIELD_PREP(GENMASK(15, 10), 0x0) |\n+\t\t\tFIELD_PREP(GENMASK(7, 2), 0x0));\n+\tphy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);\n+\n+\t/* Restore BMCR */\n+\tphy_write(phydev, MII_BMCR, bmcr_tmp);\n+\n+\treturn 0;\n+}\n+\n+static int airoha_phy_tx_amp_compensation(struct phy_device *phydev)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\n+\tu16 reg_1e_12_read;\n+\tu16 reg_1e_16_read;\n+\tu16 reg_1e_17_read;\n+\tu16 reg_1e_18_read;\n+\tu16 reg_1e_19_read;\n+\tu16 reg_1e_20_read;\n+\tu16 reg_1e_21_read;\n+\tu16 reg_1e_22_read;\n+\tu16 reg_1e_174_read;\n+\tu16 reg_1e_175_read;\n+\n+\tint reg_1e_12_header;\n+\tint reg_1e_16_header;\n+\tint reg_1e_17_header;\n+\tint reg_1e_18_header;\n+\tint reg_1e_19_header;\n+\tint reg_1e_21_header;\n+\tint reg_1e_174_header;\n+\tint reg_1e_175_header;\n+\n+\tint reg_1e_12_end;\n+\tint reg_1e_16_end;\n+\tint reg_1e_17_end;\n+\tint reg_1e_18_end;\n+\tint reg_1e_20_end;\n+\tint reg_1e_22_end;\n+\tint reg_1e_174_end;\n+\tint reg_1e_175_end;\n+\n+\tstruct phy_device *phydev_p0;\n+\tu8 phy_offset;\n+\n+\tint txamp_low_limit = -3;\n+\tint txamp_high_limit = 0x42;\n+\n+\tint r50_low_limit = -8;\n+\tint r50_high_limit = 0x88;\n+\n+\tbool overflow;\n+\tint (*tx_amp_table)[CALIB_CONST_TYPE_MAX][4];\n+\tint transformer_type, mdi_resister_type;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\tphy_offset = phydev-\u003emdio.addr - phydev_p0-\u003emdio.addr;\n+\n+\ttransformer_type = shared-\u003etransformer_type[phy_offset];\n+\tmdi_resister_type = shared-\u003emdi_resister_type;\n+\ttx_amp_table = shared-\u003etx_amp_compensation_tbl[transformer_type][mdi_resister_type];\n+\n+\treg_1e_12_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x12);\n+\treg_1e_16_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x16);\n+\treg_1e_17_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x17);\n+\treg_1e_18_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x18);\n+\treg_1e_19_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x19);\n+\treg_1e_20_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x20);\n+\treg_1e_21_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x21);\n+\treg_1e_22_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x22);\n+\treg_1e_174_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x174);\n+\treg_1e_175_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x175);\n+\n+\treg_1e_12_header = ((reg_1e_12_read \u0026 0xfc00) / 1024) + *tx_amp_table[TX_AMP_1G_A][phy_offset];\n+\treg_1e_17_header = ((reg_1e_17_read \u0026 0x3f00) / 256) + *tx_amp_table[TX_AMP_1G_B][phy_offset];\n+\treg_1e_19_header = ((reg_1e_19_read \u0026 0x3f00) / 256) + *tx_amp_table[TX_AMP_1G_C][phy_offset];\n+\treg_1e_21_header = ((reg_1e_21_read \u0026 0x3f00) / 256) + *tx_amp_table[TX_AMP_1G_D][phy_offset];\n+\n+\toverflow = false;\n+\tif (reg_1e_12_header \u003c txamp_low_limit ||\n+\t    reg_1e_12_header \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_17_header \u003c txamp_low_limit ||\n+\t    reg_1e_17_header \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_19_header \u003c txamp_low_limit ||\n+\t    reg_1e_19_header \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_21_header \u003c txamp_low_limit ||\n+\t    reg_1e_21_header \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\n+\tif (overflow) {\n+\t\treg_1e_12_header = 0x20;\n+\t\treg_1e_17_header = 0x20;\n+\t\treg_1e_19_header = 0x20;\n+\t\treg_1e_21_header = 0x20;\n+\t} else {\n+\t\tif (reg_1e_12_header \u003c 0)\n+\t\t\treg_1e_12_header = 0;\n+\t\telse if (reg_1e_12_header \u003e 0x3f)\n+\t\t\treg_1e_12_header = 0x3f;\n+\t\tif (reg_1e_17_header \u003c 0)\n+\t\t\treg_1e_17_header = 0;\n+\t\telse if (reg_1e_17_header \u003e 0x3f)\n+\t\t\treg_1e_17_header = 0x3f;\n+\t\tif (reg_1e_19_header \u003c 0)\n+\t\t\treg_1e_19_header = 0;\n+\t\telse if (reg_1e_19_header \u003e 0x3f)\n+\t\t\treg_1e_19_header = 0x3f;\n+\t\tif (reg_1e_21_header \u003c 0)\n+\t\t\treg_1e_21_header = 0;\n+\t\telse if (reg_1e_21_header \u003e 0x3f)\n+\t\t\treg_1e_21_header = 0x3f;\n+\t}\n+\n+\treg_1e_16_end = (reg_1e_16_read \u0026 0x003f) + *tx_amp_table[TX_AMP_TEST_A][phy_offset];\n+\treg_1e_18_end = (reg_1e_18_read \u0026 0x003f) + *tx_amp_table[TX_AMP_TEST_B][phy_offset];\n+\treg_1e_20_end = (reg_1e_20_read \u0026 0x003f) + *tx_amp_table[TX_AMP_TEST_C][phy_offset];\n+\treg_1e_22_end = (reg_1e_22_read \u0026 0x003f) + *tx_amp_table[TX_AMP_TEST_D][phy_offset];\n+\n+\toverflow = false;\n+\tif (reg_1e_16_end \u003c txamp_low_limit ||\n+\t    reg_1e_16_end \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_18_end \u003c txamp_low_limit ||\n+\t    reg_1e_18_end \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_20_end \u003c txamp_low_limit ||\n+\t    reg_1e_20_end \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_22_end \u003c txamp_low_limit ||\n+\t    reg_1e_22_end \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\n+\tif (overflow) {\n+\t\treg_1e_16_end = 0x20;\n+\t\treg_1e_18_end = 0x20;\n+\t\treg_1e_20_end = 0x20;\n+\t\treg_1e_22_end = 0x20;\n+\t} else {\n+\t\tif (reg_1e_16_end \u003c 0)\n+\t\t\treg_1e_16_end = 0;\n+\t\telse if (reg_1e_16_end \u003e 0x3f)\n+\t\t\treg_1e_16_end = 0x3f;\n+\t\tif (reg_1e_18_end \u003c 0)\n+\t\t\treg_1e_18_end = 0;\n+\t\telse if (reg_1e_18_end \u003e 0x3f)\n+\t\t\treg_1e_18_end = 0x3f;\n+\t\tif (reg_1e_20_end \u003c 0)\n+\t\t\treg_1e_20_end = 0;\n+\t\telse if (reg_1e_20_end \u003e 0x3f)\n+\t\t\treg_1e_20_end = 0x3f;\n+\t\tif (reg_1e_22_end \u003c 0)\n+\t\t\treg_1e_22_end = 0;\n+\t\telse if (reg_1e_22_end \u003e 0x3f)\n+\t\t\treg_1e_22_end = 0x3f;\n+\t}\n+\n+\treg_1e_16_header = ((reg_1e_16_read \u0026 0xfc00) / 1024) + *tx_amp_table[TX_AMP_100M_A][phy_offset];\n+\treg_1e_18_header = ((reg_1e_18_read \u0026 0x3f00) / 256) + *tx_amp_table[TX_AMP_100M_B][phy_offset];\n+\n+\toverflow = false;\n+\tif (reg_1e_16_header \u003c txamp_low_limit ||\n+\t    reg_1e_16_header \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_18_header \u003c txamp_low_limit ||\n+\t    reg_1e_18_header \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\n+\tif (overflow) {\n+\t\treg_1e_16_header = 0x20;\n+\t\treg_1e_18_header = 0x20;\n+\t} else {\n+\t\tif (reg_1e_16_header \u003c 0)\n+\t\t\treg_1e_16_header = 0;\n+\t\telse if (reg_1e_16_header \u003e 0x3f)\n+\t\t\treg_1e_16_header = 0x3f;\n+\t\tif (reg_1e_18_header \u003c 0)\n+\t\t\treg_1e_18_header = 0;\n+\t\telse if (reg_1e_18_header \u003e 0x3f)\n+\t\t\treg_1e_18_header = 0x3f;\n+\t}\n+\n+\treg_1e_12_end = (reg_1e_12_read \u0026 0x003f) + *tx_amp_table[TX_AMP_10M_A][phy_offset];\n+\treg_1e_17_end = (reg_1e_17_read \u0026 0x003f) + *tx_amp_table[TX_AMP_10M_B][phy_offset];\n+\n+\toverflow = false;\n+\tif (reg_1e_12_end \u003c txamp_low_limit ||\n+\t    reg_1e_12_end \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_17_end \u003c txamp_low_limit ||\n+\t    reg_1e_17_end \u003e txamp_high_limit)\n+\t\toverflow = true;\n+\n+\tif (overflow) {\n+\t\treg_1e_12_end = 0x20;\n+\t\treg_1e_17_end = 0x20;\n+\t} else {\n+\t\tif (reg_1e_12_end \u003c 0)\n+\t\t\treg_1e_12_end = 0;\n+\t\telse if (reg_1e_12_end \u003e 0x3f)\n+\t\t\treg_1e_12_end = 0x3f;\n+\t\tif (reg_1e_17_end \u003c 0)\n+\t\t\treg_1e_17_end = 0;\n+\t\telse if (reg_1e_17_end \u003e 0x3f)\n+\t\t\treg_1e_17_end = 0x3f;\n+\t}\n+\n+\treg_1e_174_header = ((reg_1e_174_read \u0026 0x7f00) / 256) + *tx_amp_table[R50_A][phy_offset];\n+\treg_1e_174_end = (reg_1e_174_read \u0026 0x007f) + *tx_amp_table[R50_B][phy_offset];\n+\treg_1e_175_header = ((reg_1e_175_read \u0026 0x7f00) / 256) + *tx_amp_table[R50_C][phy_offset];\n+\treg_1e_175_end = (reg_1e_175_read \u0026 0x007f) + *tx_amp_table[R50_D][phy_offset];\n+\n+\toverflow = false;\n+\tif (reg_1e_174_header \u003c r50_low_limit ||\n+\t    reg_1e_174_header \u003e r50_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_174_end \u003c r50_low_limit ||\n+\t    reg_1e_174_end \u003e r50_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_175_header \u003c r50_low_limit ||\n+\t    reg_1e_175_header \u003e r50_high_limit)\n+\t\toverflow = true;\n+\tif (reg_1e_175_end \u003c r50_low_limit ||\n+\t    reg_1e_175_end \u003e r50_high_limit)\n+\t\toverflow = true;\n+\n+\tif (overflow) {\n+\t\treg_1e_174_header = 0x34;\n+\t\treg_1e_174_end = 0x34;\n+\t\treg_1e_175_header = 0x34;\n+\t\treg_1e_175_end = 0x34;\n+\t} else {\n+\t\tif (reg_1e_174_header \u003c 0)\n+\t\t\treg_1e_174_header = 0;\n+\t\telse if (reg_1e_174_header \u003e 0x7f)\n+\t\t\treg_1e_174_header = 0x7f;\n+\t\tif (reg_1e_174_end \u003c 0)\n+\t\t\treg_1e_174_end = 0;\n+\t\telse if (reg_1e_174_end \u003e 0x7f)\n+\t\t\treg_1e_174_end = 0x7f;\n+\t\tif (reg_1e_175_header \u003c 0)\n+\t\t\treg_1e_175_header = 0;\n+\t\telse if (reg_1e_175_header \u003e 0x7f)\n+\t\t\treg_1e_175_header = 0x7f;\n+\t\tif (reg_1e_175_end \u003c 0)\n+\t\t\treg_1e_175_end = 0;\n+\t\telse if (reg_1e_175_end \u003e 0x7f)\n+\t\t\treg_1e_175_end = 0x7f;\n+\t}\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x12,\n+\t\t      (reg_1e_12_header * 1024) + reg_1e_12_end);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x16,\n+\t\t      (reg_1e_16_header * 1024) + reg_1e_16_end);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x17,\n+\t\t      (reg_1e_17_header * 256) + reg_1e_17_end);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x18,\n+\t\t      (reg_1e_18_header * 256) + reg_1e_18_end);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x19,\n+\t\t      (reg_1e_19_read \u0026 0x00ff) + (reg_1e_19_header * 256));\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x20,\n+\t\t      (reg_1e_20_read \u0026 0xff00) + reg_1e_20_end);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x21,\n+\t\t      (reg_1e_21_read \u0026 0x00ff) + (reg_1e_21_header * 256));\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x22,\n+\t\t      (reg_1e_22_read \u0026 0xff00) + reg_1e_22_end);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x174,\n+\t\t      0x8080 + (reg_1e_174_header * 256) + reg_1e_174_end);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x175,\n+\t\t      0x8080 + (reg_1e_175_header * 256) + reg_1e_175_end);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x176, 0x4400);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x177, 0x0044);\n+\n+\treturn 0;\n+}\n+\n+static int an7581_phy_config_init(struct phy_device *phydev)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tstruct phy_device *phydev_p0;\n+\tu32 soc_pdidr;\n+\tu8 phy_offset;\n+\tint ret;\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\tphy_offset = phydev-\u003emdio.addr - phydev_p0-\u003emdio.addr;\n+\n+\t/* FIXME: Read SoC PDIDR if available or default to 1 */\n+\tsoc_pdidr = 1;\n+\n+\tshared-\u003emdi_resister_type = MDI_5R;\n+\tif (soc_pdidr == 1)\n+\t\tshared-\u003etx_amp_compensation_tbl = \u0026an7581_tx_amp_compensation_tbl[0];\n+\telse\n+\t\tshared-\u003etx_amp_compensation_tbl = \u0026an7581_tx_amp_compensation_tbl[1];\n+\tshared-\u003er50_cal_tbl = an7581_zcal_to_r45ohm;\n+\n+\tret = airoha_phy_calib(phydev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = airoha_phy_auto_select_transformer(phydev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = airoha_phy_tx_amp_compensation(phydev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* RX setting for 5R_TXMR before AN setting */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe6, 0x1111);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe7, 0x5555);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe9, 0x0001);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xfe, 0x0000);\n+\n+\t/* Long Loop Reach setting */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x11, 0xff00);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x202, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x203, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x204, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x205, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x206, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x207, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x208, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x209, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20a, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20b, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20e, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20f, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x210, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x211, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x212, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x213, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x214, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x215, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x216, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x217, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21a, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21b, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21c, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21d, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21e, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21f, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x220, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x221, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x222, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x223, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x226, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x227, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x228, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x229, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22a, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22b, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22c, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22d, 0x0025);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22e, 0x2310);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22f, 0x0025);\n+\n+\t/* RX Setting */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3c, 0xc000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3d, 0x0000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);\n+\n+\t/* EEE setting */\n+\tphy_write_mmd(phydev, MDIO_MMD_AN, 0x3c, 0x0000);\n+\n+\t/* RX */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x41, 0x3333);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x44, 0x00c0);\n+\n+\t/* 10M settings */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a3, 0x00d2);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a4, 0x010e);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27b, 0x1177);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27c, 0x0808);\n+\n+\tphy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_1);\n+\t__phy_write(phydev, 0x14, 0x3a18);\n+\tphy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);\n+\n+\tphy_write(phydev, 0x9, 0x1e00);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x269, 0x2114);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26a, 0x1113);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26f, 0x0000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x2c63);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x272, 0x0c2b);\n+\n+\t/* EEE set because power down can't set tokenring */\n+\tphy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);\n+\t__mtk_tr_write(phydev, 0x0, 0x7, 0x15, 0x0055a0);\n+\t__mtk_tr_write(phydev, 0x0, 0x7, 0x17, 0x07ff3f);\n+\t__mtk_tr_write(phydev, 0x1, 0xf, 0x0, 0x00001e);\n+\t__mtk_tr_write(phydev, 0x1, 0xf, 0x1, 0x6fb90a);\n+\t__mtk_tr_write(phydev, 0x1, 0xf, 0x18, 0x0e2f00);\n+\t__mtk_tr_write(phydev, 0x1, 0xd, 0x26, 0x444444);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0x3, 0x000004);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0x6, 0x2ebaef);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0x8, 0x00000b);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0xc, 0x00504d);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0xd, 0x02314f);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0xf, 0x003028);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0x10, 0x00000a);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0x11, 0x040001);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0x14, 0x00024a);\n+\t__mtk_tr_write(phydev, 0x2, 0xd, 0x1c, 0x003210);\n+\tphy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);\n+\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x120, 0x8014);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x122, 0xffff);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x144, 0x0200);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14a, 0xee20);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x19b, 0x0111);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x234, 0x1181);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x238, 0x0120);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x239, 0x0117);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x2d1, 0x0733);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x323, 0x0011);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x324, 0x013f);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x326, 0x0037);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x268, 0x07f4);\n+\n+\tif (shared-\u003etransformer_type[phy_offset] == TXMR) {\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0187);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cc);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0109);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x020b);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0202);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03c5);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c2);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x09, 0x0309);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x000e);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0002);\n+\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0880);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0880);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0880);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0880);\n+\t} else {\n+\t\tif (soc_pdidr == 2) {\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x269, 0x1114);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26a, 0x1113);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26f, 0x2000);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x4c88);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x272, 0x0c2b);\n+\n+\t\t\t/* 100M sharp */\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0190);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01c8);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c0);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0030);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0208);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0000);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0318);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03c8);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c0);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x09, 0x0230);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x0008);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0200);\n+\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0885);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0885);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0885);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0885);\n+\t\t} else {\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0190);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cf);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c0);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0030);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x020f);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0000);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0318);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03cf);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c0);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x09, 0x0230);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x000f);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0200);\n+\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0003);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0003);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0003);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0003);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int an7581_phy_probe(struct phy_device *phydev)\n+{\n+\tstruct airoha_socphy_shared *shared;\n+\tstruct mtk_socphy_priv *priv;\n+\tstruct pinctrl *pinctrl;\n+\tint ret;\n+\n+\t/* Toggle pinctrl to enable PHY LED */\n+\tpinctrl = devm_pinctrl_get_select(\u0026phydev-\u003emdio.dev, \"gbe-led\");\n+\tif (IS_ERR(pinctrl))\n+\t\tdev_err(\u0026phydev-\u003emdio.bus-\u003edev,\n+\t\t\t\"Failed to setup PHY LED pinctrl\\n\");\n+\n+\tret = devm_phy_package_join(\u0026phydev-\u003emdio.dev, phydev, 0,\n+\t\t\t\t    sizeof(struct airoha_socphy_shared));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tpriv = devm_kzalloc(\u0026phydev-\u003emdio.dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tif (phydev-\u003emdio.addr == AIROHA_DEFAULT_PORT0_ADDR)\n+\t\tshared-\u003ephydev_p0 = phydev;\n+\n+\tphydev-\u003epriv = priv;\n+\n+\treturn 0;\n+}\n+\n+static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,\n+\t\t\t\t       unsigned long modes)\n+{\n+\tu16 val = 0;\n+\tu32 mode;\n+\n+\tif (index \u003e= AIROHA_PHY_MAX_LEDS)\n+\t\treturn -EINVAL;\n+\n+\tfor_each_set_bit(mode, \u0026modes, __PHY_LED_MODES_NUM) {\n+\t\tswitch (mode) {\n+\t\tcase PHY_LED_ACTIVE_LOW:\n+\t\t\tval = MTK_PHY_LED_ON_POLARITY;\n+\t\t\tbreak;\n+\t\tcase PHY_LED_ACTIVE_HIGH:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\treturn phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?\n+\t\t\t      MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,\n+\t\t\t      MTK_PHY_LED_ON_POLARITY, val);\n+}\n+\n+static int an7583_phy_config_init(struct phy_device *phydev)\n+{\n+\tstruct airoha_socphy_shared *shared = phy_package_get_priv(phydev);\n+\tstruct phy_device *phydev_p0;\n+\tu8 phy_offset;\n+\tint ret;\n+\n+\t/* BMCR_PDOWN is enabled by default */\n+\tphy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);\n+\n+\tphydev_p0 = shared-\u003ephydev_p0;\n+\tphy_offset = phydev-\u003emdio.addr - phydev_p0-\u003emdio.addr;\n+\n+\t/* FIXME: Read SoC MDI Resister Type if available or default to 5R */\n+\tshared-\u003emdi_resister_type = MDI_5R;\n+\n+\tshared-\u003emdi_resister_type = MDI_5R;\n+\tif (shared-\u003emdi_resister_type == MDI_0R)\n+\t\tshared-\u003er50_cal_tbl = an7583_zcal_to_r50ohm_0R;\n+\tif (shared-\u003emdi_resister_type == MDI_5R)\n+\t\tshared-\u003er50_cal_tbl = an7583_zcal_to_r50ohm_5R;\n+\tshared-\u003etx_amp_compensation_tbl = \u0026an7583_tx_amp_compensation_tbl;\n+\n+\tret = airoha_phy_calib(phydev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = airoha_phy_auto_select_transformer(phydev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = airoha_phy_tx_amp_compensation(phydev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Enable Idle Mode Power Setting */\n+\tif (phy_offset == 0) {\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x268, 0x07F1);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x703, 0x3111);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x3C24);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x701, 0x1023);\n+\t}\n+\n+\tif (shared-\u003etransformer_type[phy_offset] == TXMR) {\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0881);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0881);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0881);\n+\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0881);\n+\n+\t\tif (shared-\u003emdi_resister_type == MDI_0R)\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);\n+\t\telse\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0200);\n+\t} else {\n+\t\tif (shared-\u003emdi_resister_type == MDI_0R) {\n+\t\t\t/* RX setting for 5R_TXMR before AN setting */\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe7, 0x6666);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe9, 0x0003);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xfe, 0x0006);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe6, 0x1111);\n+\t\t\t/* 100M sharp */\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0c86);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0c86);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0c86);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0c86);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cb);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0108);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0211);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03ce);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c8);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0005);\n+\t\t} else {\n+\t\t\t/* 100M sharp */\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0886);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0886);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0886);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0886);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0195);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cb);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0108);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0211);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03ce);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c3);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x0010);\n+\t\t\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0005);\n+\t\t}\n+\t}\n+\n+\t/* RX Setting */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3c, 0xc000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3d, 0x0000);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);\n+\n+\t/* EEE setting */\n+\tphy_write_mmd(phydev, MDIO_MMD_AN, 0x3c, 0x0000);\n+\n+\t/* 10M settings */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a3, 0x00d2);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a4, 0x010e);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27b, 0x1177);\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27c, 0x0808);\n+\n+\tphy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);\n+\t__phy_write(phydev, 0x14, 0x190);\n+\tphy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);\n+\n+\tphy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_1);\n+\t__phy_write(phydev, 0x14, 0x3a18);\n+\tphy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);\n+\n+\tphy_write(phydev, 0x9, 0x0600);\n+\n+\t/* EEE keep only Pair A ON */\n+\tphy_write_mmd(phydev, MDIO_MMD_VEND1, 0x630, 0x006E);\n+\n+\treturn 0;\n+}\n+\n+static struct phy_driver mtk_socphy_driver[] = {\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7581),\n+\t\t.name\t\t= \"Airoha AN7581 PHY\",\n+\t\t.config_init\t= an7581_phy_config_init,\n+\t\t.config_intr\t= genphy_no_config_intr,\n+\t\t.handle_interrupt = genphy_handle_interrupt_no_ack,\n+\t\t.probe\t\t= an7581_phy_probe,\n+\t\t.led_blink_set\t= mt798x_phy_led_blink_set,\n+\t\t.led_brightness_set = mt798x_phy_led_brightness_set,\n+\t\t.led_hw_is_supported = mt798x_phy_led_hw_is_supported,\n+\t\t.led_hw_control_set = mt798x_phy_led_hw_control_set,\n+\t\t.led_hw_control_get = mt798x_phy_led_hw_control_get,\n+\t\t.led_polarity_set = an7581_phy_led_polarity_set,\n+\t\t.read_page\t= mtk_phy_read_page,\n+\t\t.write_page\t= mtk_phy_write_page,\n+\t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7583),\n+\t\t.name\t\t= \"Airoha AN7583 PHY\",\n+\t\t.config_init\t= an7583_phy_config_init,\n+\t\t.probe\t\t= an7581_phy_probe,\n+\t\t.led_blink_set\t= mt798x_phy_led_blink_set,\n+\t\t.led_brightness_set = mt798x_phy_led_brightness_set,\n+\t\t.led_hw_is_supported = mt798x_phy_led_hw_is_supported,\n+\t\t.led_hw_control_set = mt798x_phy_led_hw_control_set,\n+\t\t.led_hw_control_get = mt798x_phy_led_hw_control_get,\n+\t\t.led_polarity_set = an7581_phy_led_polarity_set,\n+\t\t.read_page\t= mtk_phy_read_page,\n+\t\t.write_page\t= mtk_phy_write_page,\n+\t},\n+};\n+\n+module_phy_driver(mtk_socphy_driver);\n+\n+static const struct mdio_device_id __maybe_unused airoha_socphy_tbl[] = {\n+\t{ PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7581) },\n+\t{ PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7583) },\n+\t{ }\n+};\n+\n+MODULE_DESCRIPTION(\"Airoha SoC Gigabit Ethernet PHY driver\");\n+MODULE_AUTHOR(\"Christian Marangi \u003cansuelsmth@gmail.com\u003e\");\n+MODULE_LICENSE(\"GPL\");\n+MODULE_VERSION(\"01.01.20260306\");\n+\n+MODULE_DEVICE_TABLE(mdio, airoha_socphy_tbl);\ndiff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c\nindex 9a54949644d5a5..868ae089013d3d 100644\n--- a/drivers/net/phy/mediatek/mtk-ge-soc.c\n+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c\n@@ -11,322 +11,10 @@\n \n #include \"../phylib.h\"\n #include \"mtk.h\"\n+#include \"mtk-ge-soc.h\"\n \n #define MTK_PHY_MAX_LEDS\t\t\t2\n \n-#define MTK_GPHY_ID_MT7981\t\t\t0x03a29461\n-#define MTK_GPHY_ID_MT7988\t\t\t0x03a29481\n-#define MTK_GPHY_ID_AN7581\t\t\t0x03a294c1\n-#define MTK_GPHY_ID_AN7583\t\t\t0xc0ff0420\n-\n-#define MTK_EXT_PAGE_ACCESS\t\t\t0x1f\n-#define MTK_PHY_PAGE_STANDARD\t\t\t0x0000\n-#define MTK_PHY_PAGE_EXTENDED_3\t\t\t0x0003\n-\n-#define MTK_PHY_LPI_REG_14\t\t\t0x14\n-#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK\tGENMASK(8, 0)\n-\n-#define MTK_PHY_LPI_REG_1c\t\t\t0x1c\n-#define MTK_PHY_SMI_DET_ON_THRESH_MASK\t\tGENMASK(13, 8)\n-\n-#define MTK_PHY_PAGE_EXTENDED_2A30\t\t0x2a30\n-\n-/* Registers on Token Ring debug nodes */\n-/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */\n-/* NormMseLoThresh */\n-#define NORMAL_MSE_LO_THRESH_MASK\t\tGENMASK(15, 8)\n-\n-/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */\n-/* RemAckCntLimitCtrl */\n-#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK\tGENMASK(2, 1)\n-\n-/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */\n-/* VcoSlicerThreshBitsHigh */\n-#define VCO_SLICER_THRESH_HIGH_MASK\t\tGENMASK(23, 0)\n-\n-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */\n-/* DfeTailEnableVgaThresh1000 */\n-#define DFE_TAIL_EANBLE_VGA_TRHESH_1000\t\tGENMASK(5, 1)\n-\n-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */\n-/* MrvlTrFix100Kp */\n-#define MRVL_TR_FIX_100KP_MASK\t\t\tGENMASK(22, 20)\n-/* MrvlTrFix100Kf */\n-#define MRVL_TR_FIX_100KF_MASK\t\t\tGENMASK(19, 17)\n-/* MrvlTrFix1000Kp */\n-#define MRVL_TR_FIX_1000KP_MASK\t\t\tGENMASK(16, 14)\n-/* MrvlTrFix1000Kf */\n-#define MRVL_TR_FIX_1000KF_MASK\t\t\tGENMASK(13, 11)\n-\n-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */\n-/* VgaDecRate */\n-#define VGA_DECIMATION_RATE_MASK\t\tGENMASK(8, 5)\n-\n-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */\n-/* SlvDSPreadyTime */\n-#define SLAVE_DSP_READY_TIME_MASK\t\tGENMASK(22, 15)\n-/* MasDSPreadyTime */\n-#define MASTER_DSP_READY_TIME_MASK\t\tGENMASK(14, 7)\n-\n-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */\n-/* EnabRandUpdTrig */\n-#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER\tBIT(8)\n-\n-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */\n-/* ResetSyncOffset */\n-#define RESET_SYNC_OFFSET_MASK\t\t\tGENMASK(11, 8)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */\n-/* FfeUpdGainForceVal */\n-#define FFE_UPDATE_GAIN_FORCE_VAL_MASK\t\tGENMASK(9, 7)\n-/* FfeUpdGainForce */\n-#define FFE_UPDATE_GAIN_FORCE\t\t\tBIT(6)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */\n-/* TrFreeze */\n-#define TR_FREEZE_MASK\t\t\t\tGENMASK(11, 0)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */\n-/* SS: Steady-state, KP: Proportional Gain */\n-/* SSTrKp100 */\n-#define SS_TR_KP100_MASK\t\t\tGENMASK(21, 19)\n-/* SSTrKf100 */\n-#define SS_TR_KF100_MASK\t\t\tGENMASK(18, 16)\n-/* SSTrKp1000Mas */\n-#define SS_TR_KP1000_MASTER_MASK\t\tGENMASK(15, 13)\n-/* SSTrKf1000Mas */\n-#define SS_TR_KF1000_MASTER_MASK\t\tGENMASK(12, 10)\n-/* SSTrKp1000Slv */\n-#define SS_TR_KP1000_SLAVE_MASK\t\t\tGENMASK(9, 7)\n-/* SSTrKf1000Slv */\n-#define SS_TR_KF1000_SLAVE_MASK\t\t\tGENMASK(6, 4)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */\n-/* clear this bit if wanna select from AFE */\n-/* Regsigdet_sel_1000 */\n-#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE\tBIT(4)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */\n-/* RegEEE_st2TrKf1000 */\n-#define EEE1000_STAGE2_TR_KF_MASK\t\tGENMASK(13, 11)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */\n-/* RegEEE_slv_waketr_timer_tar */\n-#define SLAVE_WAKETR_TIMER_MASK\t\t\tGENMASK(20, 11)\n-/* RegEEE_slv_remtx_timer_tar */\n-#define SLAVE_REMTX_TIMER_MASK\t\t\tGENMASK(10, 1)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */\n-/* RegEEE_slv_wake_int_timer_tar */\n-#define SLAVE_WAKEINT_TIMER_MASK\t\tGENMASK(10, 1)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */\n-/* RegEEE_trfreeze_timer2 */\n-#define TR_FREEZE_TIMER2_MASK\t\t\tGENMASK(9, 0)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */\n-/* RegEEE100Stg1_tar */\n-#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK\tGENMASK(8, 0)\n-\n-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */\n-/* REGEEE_wake_slv_tr_wait_dfesigdet_en */\n-#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN\tBIT(11)\n-\n-#define ANALOG_INTERNAL_OPERATION_MAX_US\t20\n-#define TXRESERVE_MIN\t\t\t\t0\n-#define TXRESERVE_MAX\t\t\t\t7\n-\n-#define MTK_PHY_ANARG_RG\t\t\t0x10\n-#define   MTK_PHY_TCLKOFFSET_MASK\t\tGENMASK(12, 8)\n-\n-/* Registers on MDIO_MMD_VEND1 */\n-#define MTK_PHY_TXVLD_DA_RG\t\t\t0x12\n-#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK\tGENMASK(15, 10)\n-#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_TX_I2MPB_TEST_MODE_A2\t\t0x16\n-#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK\tGENMASK(15, 10)\n-#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_TX_I2MPB_TEST_MODE_B1\t\t0x17\n-#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_TX_I2MPB_TEST_MODE_B2\t\t0x18\n-#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_TX_I2MPB_TEST_MODE_C1\t\t0x19\n-#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_TX_I2MPB_TEST_MODE_C2\t\t0x20\n-#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_TX_I2MPB_TEST_MODE_D1\t\t0x21\n-#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_TX_I2MPB_TEST_MODE_D2\t\t0x22\n-#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK\tGENMASK(5, 0)\n-\n-#define MTK_PHY_RXADC_CTRL_RG7\t\t\t0xc6\n-#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK\tGENMASK(9, 8)\n-\n-#define MTK_PHY_RXADC_CTRL_RG9\t\t\t0xc8\n-#define   MTK_PHY_DA_RX_PSBN_TBT_MASK\t\tGENMASK(14, 12)\n-#define   MTK_PHY_DA_RX_PSBN_HBT_MASK\t\tGENMASK(10, 8)\n-#define   MTK_PHY_DA_RX_PSBN_GBE_MASK\t\tGENMASK(6, 4)\n-#define   MTK_PHY_DA_RX_PSBN_LP_MASK\t\tGENMASK(2, 0)\n-\n-#define MTK_PHY_LDO_OUTPUT_V\t\t\t0xd7\n-\n-#define MTK_PHY_RG_ANA_CAL_RG0\t\t\t0xdb\n-#define   MTK_PHY_RG_CAL_CKINV\t\t\tBIT(12)\n-#define   MTK_PHY_RG_ANA_CALEN\t\t\tBIT(8)\n-#define   MTK_PHY_RG_ZCALEN_A\t\t\tBIT(0)\n-\n-#define MTK_PHY_RG_ANA_CAL_RG1\t\t\t0xdc\n-#define   MTK_PHY_RG_ZCALEN_B\t\t\tBIT(12)\n-#define   MTK_PHY_RG_ZCALEN_C\t\t\tBIT(8)\n-#define   MTK_PHY_RG_ZCALEN_D\t\t\tBIT(4)\n-#define   MTK_PHY_RG_TXVOS_CALEN\t\tBIT(0)\n-\n-#define MTK_PHY_RG_ANA_CAL_RG5\t\t\t0xe0\n-#define   MTK_PHY_RG_REXT_TRIM_MASK\t\tGENMASK(13, 8)\n-\n-#define MTK_PHY_RG_TX_FILTER\t\t\t0xfe\n-\n-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120\t0x120\n-#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK\tGENMASK(12, 8)\n-#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK\tGENMASK(4, 0)\n-\n-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122\t0x122\n-#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK\tGENMASK(7, 0)\n-\n-#define MTK_PHY_RG_TESTMUX_ADC_CTRL\t\t0x144\n-#define   MTK_PHY_RG_TXEN_DIG_MASK\t\tGENMASK(5, 5)\n-\n-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B\t\t0x172\n-#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK\tGENMASK(6, 0)\n-\n-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D\t\t0x173\n-#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK\tGENMASK(13, 8)\n-#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK\tGENMASK(6, 0)\n-\n-#define MTK_PHY_RG_AD_CAL_COMP\t\t\t0x17a\n-#define   MTK_PHY_AD_CAL_COMP_OUT_MASK\t\tGENMASK(8, 8)\n-\n-#define MTK_PHY_RG_AD_CAL_CLK\t\t\t0x17b\n-#define   MTK_PHY_DA_CAL_CLK\t\t\tBIT(0)\n-\n-#define MTK_PHY_RG_AD_CALIN\t\t\t0x17c\n-#define   MTK_PHY_DA_CALIN_FLAG\t\t\tBIT(0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN0_A\t\t0x17d\n-#define   MTK_PHY_DASN_DAC_IN0_A_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN0_B\t\t0x17e\n-#define   MTK_PHY_DASN_DAC_IN0_B_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN0_C\t\t0x17f\n-#define   MTK_PHY_DASN_DAC_IN0_C_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN0_D\t\t0x180\n-#define   MTK_PHY_DASN_DAC_IN0_D_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN1_A\t\t0x181\n-#define   MTK_PHY_DASN_DAC_IN1_A_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN1_B\t\t0x182\n-#define   MTK_PHY_DASN_DAC_IN1_B_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN1_C\t\t0x183\n-#define   MTK_PHY_DASN_DAC_IN1_C_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DASN_DAC_IN1_D\t\t0x184\n-#define   MTK_PHY_DASN_DAC_IN1_D_MASK\t\tGENMASK(9, 0)\n-\n-#define MTK_PHY_RG_DEV1E_REG19b\t\t\t0x19b\n-#define   MTK_PHY_BYPASS_DSP_LPI_READY\t\tBIT(8)\n-\n-#define MTK_PHY_RG_LP_IIR2_K1_L\t\t\t0x22a\n-#define MTK_PHY_RG_LP_IIR2_K1_U\t\t\t0x22b\n-#define MTK_PHY_RG_LP_IIR2_K2_L\t\t\t0x22c\n-#define MTK_PHY_RG_LP_IIR2_K2_U\t\t\t0x22d\n-#define MTK_PHY_RG_LP_IIR2_K3_L\t\t\t0x22e\n-#define MTK_PHY_RG_LP_IIR2_K3_U\t\t\t0x22f\n-#define MTK_PHY_RG_LP_IIR2_K4_L\t\t\t0x230\n-#define MTK_PHY_RG_LP_IIR2_K4_U\t\t\t0x231\n-#define MTK_PHY_RG_LP_IIR2_K5_L\t\t\t0x232\n-#define MTK_PHY_RG_LP_IIR2_K5_U\t\t\t0x233\n-\n-#define MTK_PHY_RG_DEV1E_REG234\t\t\t0x234\n-#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK\t\tGENMASK(0, 0)\n-#define   MTK_PHY_LPF_X_AVERAGE_MASK\t\tGENMASK(7, 4)\n-#define   MTK_PHY_TR_LP_IIR_EEE_EN\t\tBIT(12)\n-\n-#define MTK_PHY_RG_LPF_CNT_VAL\t\t\t0x235\n-\n-#define MTK_PHY_RG_DEV1E_REG238\t\t\t0x238\n-#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK\tGENMASK(8, 0)\n-#define   MTK_PHY_LPI_SLV_SEND_TX_EN\t\tBIT(12)\n-\n-#define MTK_PHY_RG_DEV1E_REG239\t\t\t0x239\n-#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK\tGENMASK(8, 0)\n-#define   MTK_PHY_LPI_TXPCS_LOC_RCV\t\tBIT(12)\n-\n-#define MTK_PHY_RG_DEV1E_REG27C\t\t\t0x27c\n-#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK\tGENMASK(12, 8)\n-#define MTK_PHY_RG_DEV1E_REG27D\t\t\t0x27d\n-#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK\tGENMASK(4, 0)\n-\n-#define MTK_PHY_RG_DEV1E_REG2C7\t\t\t0x2c7\n-#define   MTK_PHY_MAX_GAIN_MASK\t\t\tGENMASK(4, 0)\n-#define   MTK_PHY_MIN_GAIN_MASK\t\t\tGENMASK(12, 8)\n-\n-#define MTK_PHY_RG_DEV1E_REG2D1\t\t\t0x2d1\n-#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK\tGENMASK(7, 0)\n-#define   MTK_PHY_LPI_SKIP_SD_SLV_TR\t\tBIT(8)\n-#define   MTK_PHY_LPI_TR_READY\t\t\tBIT(9)\n-#define   MTK_PHY_LPI_VCO_EEE_STG0_EN\t\tBIT(10)\n-\n-#define MTK_PHY_RG_DEV1E_REG323\t\t\t0x323\n-#define   MTK_PHY_EEE_WAKE_MAS_INT_DC\t\tBIT(0)\n-#define   MTK_PHY_EEE_WAKE_SLV_INT_DC\t\tBIT(4)\n-\n-#define MTK_PHY_RG_DEV1E_REG324\t\t\t0x324\n-#define   MTK_PHY_SMI_DETCNT_MAX_MASK\t\tGENMASK(5, 0)\n-#define   MTK_PHY_SMI_DET_MAX_EN\t\tBIT(8)\n-\n-#define MTK_PHY_RG_DEV1E_REG326\t\t\t0x326\n-#define   MTK_PHY_LPI_MODE_SD_ON\t\tBIT(0)\n-#define   MTK_PHY_RESET_RANDUPD_CNT\t\tBIT(1)\n-#define   MTK_PHY_TREC_UPDATE_ENAB_CLR\t\tBIT(2)\n-#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF\tBIT(4)\n-#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP\tBIT(5)\n-\n-#define MTK_PHY_LDO_PUMP_EN_PAIRAB\t\t0x502\n-#define MTK_PHY_LDO_PUMP_EN_PAIRCD\t\t0x503\n-\n-#define MTK_PHY_DA_TX_R50_PAIR_A\t\t0x53d\n-#define MTK_PHY_DA_TX_R50_PAIR_B\t\t0x53e\n-#define MTK_PHY_DA_TX_R50_PAIR_C\t\t0x53f\n-#define MTK_PHY_DA_TX_R50_PAIR_D\t\t0x540\n-\n-/* Registers on MDIO_MMD_VEND2 */\n-#define MTK_PHY_LED1_DEFAULT_POLARITIES\t\tBIT(1)\n-\n-#define MTK_PHY_RG_BG_RASEL\t\t\t0x115\n-#define   MTK_PHY_RG_BG_RASEL_MASK\t\tGENMASK(2, 0)\n-\n-/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */\n-#define RG_GPIO_MISC_TPBANK0\t\t\t0x6f0\n-#define   RG_GPIO_MISC_TPBANK0_BOOTMODE\t\tGENMASK(11, 8)\n-\n /* These macro privides efuse parsing for internal phy. */\n #define EFS_DA_TX_I2MPB_A(x)\t\t\t(((x) \u003e\u003e 0) \u0026 GENMASK(5, 0))\n #define EFS_DA_TX_I2MPB_B(x)\t\t\t(((x) \u003e\u003e 6) \u0026 GENMASK(5, 0))\n@@ -346,51 +34,16 @@\n #define EFS_RG_BG_RASEL(x)\t\t\t(((x) \u003e\u003e 4) \u0026 GENMASK(2, 0))\n #define EFS_RG_REXT_TRIM(x)\t\t\t(((x) \u003e\u003e 7) \u0026 GENMASK(5, 0))\n \n-enum {\n-\tNO_PAIR,\n-\tPAIR_A,\n-\tPAIR_B,\n-\tPAIR_C,\n-\tPAIR_D,\n-};\n-\n-enum calibration_mode {\n-\tEFUSE_K,\n-\tSW_K\n-};\n-\n-enum CAL_ITEM {\n-\tREXT,\n-\tTX_OFFSET,\n-\tTX_AMP,\n-\tTX_R50,\n-\tTX_VCM\n-};\n-\n-enum CAL_MODE {\n-\tEFUSE_M,\n-\tSW_M\n-};\n-\n struct mtk_socphy_shared {\n \tu32\t\t\tboottrap;\n \tstruct mtk_socphy_priv\tpriv[4];\n };\n \n-/* One calibration cycle consists of:\n- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high\n- *   until AD_CAL_COMP is ready to output calibration result.\n- * 2.Wait until DA_CAL_CLK is available.\n- * 3.Fetch AD_CAL_COMP_OUT.\n- */\n-static int cal_cycle(struct phy_device *phydev, int devad,\n-\t\t     u32 regnum, u16 mask, u16 cal_val)\n+int mtk_cal_cycle_wait(struct phy_device *phydev)\n {\n \tint reg_val;\n \tint ret;\n \n-\tphy_modify_mmd(phydev, devad, regnum,\n-\t\t       mask, cal_val);\n \tphy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,\n \t\t\t MTK_PHY_DA_CALIN_FLAG);\n \n@@ -409,7 +62,25 @@ static int cal_cycle(struct phy_device *phydev, int devad,\n \tret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);\n \tif (ret \u003c 0)\n \t\treturn ret;\n-\tret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);\n+\n+\treturn FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);\n+}\n+\n+/* One calibration cycle consists of:\n+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high\n+ *   until AD_CAL_COMP is ready to output calibration result.\n+ * 2.Wait until DA_CAL_CLK is available.\n+ * 3.Fetch AD_CAL_COMP_OUT.\n+ */\n+static int cal_cycle(struct phy_device *phydev, int devad,\n+\t\t     u32 regnum, u16 mask, u16 cal_val)\n+{\n+\tint ret;\n+\n+\tphy_modify_mmd(phydev, devad, regnum,\n+\t\t       mask, cal_val);\n+\n+\tret = mtk_cal_cycle_wait(phydev);\n \tphydev_dbg(phydev, \"cal_val: 0x%x, ret: %d\\n\", cal_val, ret);\n \n \treturn ret;\n@@ -1215,73 +886,6 @@ static int mt798x_phy_config_init(struct phy_device *phydev)\n \treturn mt798x_phy_calibration(phydev);\n }\n \n-static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,\n-\t\t\t\t    unsigned long *delay_on,\n-\t\t\t\t    unsigned long *delay_off)\n-{\n-\tbool blinking = false;\n-\tint err;\n-\n-\terr = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, \u0026blinking);\n-\tif (err \u003c 0)\n-\t\treturn err;\n-\n-\terr = mtk_phy_hw_led_blink_set(phydev, index, blinking);\n-\tif (err)\n-\t\treturn err;\n-\n-\treturn mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,\n-\t\t\t\t     false);\n-}\n-\n-static int mt798x_phy_led_brightness_set(struct phy_device *phydev,\n-\t\t\t\t\t u8 index, enum led_brightness value)\n-{\n-\tint err;\n-\n-\terr = mtk_phy_hw_led_blink_set(phydev, index, false);\n-\tif (err)\n-\t\treturn err;\n-\n-\treturn mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,\n-\t\t\t\t     (value != LED_OFF));\n-}\n-\n-static const unsigned long supported_triggers =\n-\tBIT(TRIGGER_NETDEV_FULL_DUPLEX) |\n-\tBIT(TRIGGER_NETDEV_HALF_DUPLEX) |\n-\tBIT(TRIGGER_NETDEV_LINK)        |\n-\tBIT(TRIGGER_NETDEV_LINK_10)     |\n-\tBIT(TRIGGER_NETDEV_LINK_100)    |\n-\tBIT(TRIGGER_NETDEV_LINK_1000)   |\n-\tBIT(TRIGGER_NETDEV_RX)          |\n-\tBIT(TRIGGER_NETDEV_TX);\n-\n-static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,\n-\t\t\t\t\t  unsigned long rules)\n-{\n-\treturn mtk_phy_led_hw_is_supported(phydev, index, rules,\n-\t\t\t\t\t   supported_triggers);\n-}\n-\n-static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,\n-\t\t\t\t\t unsigned long *rules)\n-{\n-\treturn mtk_phy_led_hw_ctrl_get(phydev, index, rules,\n-\t\t\t\t       MTK_GPHY_LED_ON_SET,\n-\t\t\t\t       MTK_GPHY_LED_RX_BLINK_SET,\n-\t\t\t\t       MTK_GPHY_LED_TX_BLINK_SET);\n-};\n-\n-static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,\n-\t\t\t\t\t unsigned long rules)\n-{\n-\treturn mtk_phy_led_hw_ctrl_set(phydev, index, rules,\n-\t\t\t\t       MTK_GPHY_LED_ON_SET,\n-\t\t\t\t       MTK_GPHY_LED_RX_BLINK_SET,\n-\t\t\t\t       MTK_GPHY_LED_TX_BLINK_SET);\n-};\n-\n static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)\n {\n \tstruct mtk_socphy_shared *priv = phy_package_get_priv(phydev);\n@@ -1418,58 +1022,6 @@ static int mt7981_phy_probe(struct phy_device *phydev)\n \treturn mt798x_phy_calibration(phydev);\n }\n \n-static int an7581_phy_probe(struct phy_device *phydev)\n-{\n-\tstruct mtk_socphy_priv *priv;\n-\tstruct pinctrl *pinctrl;\n-\n-\t/* Toggle pinctrl to enable PHY LED */\n-\tpinctrl = devm_pinctrl_get_select(\u0026phydev-\u003emdio.dev, \"gbe-led\");\n-\tif (IS_ERR(pinctrl))\n-\t\tdev_err(\u0026phydev-\u003emdio.bus-\u003edev,\n-\t\t\t\"Failed to setup PHY LED pinctrl\\n\");\n-\n-\tpriv = devm_kzalloc(\u0026phydev-\u003emdio.dev, sizeof(*priv), GFP_KERNEL);\n-\tif (!priv)\n-\t\treturn -ENOMEM;\n-\n-\tphydev-\u003epriv = priv;\n-\n-\treturn 0;\n-}\n-\n-static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,\n-\t\t\t\t       unsigned long modes)\n-{\n-\tu16 val = 0;\n-\tu32 mode;\n-\n-\tif (index \u003e= MTK_PHY_MAX_LEDS)\n-\t\treturn -EINVAL;\n-\n-\tfor_each_set_bit(mode, \u0026modes, __PHY_LED_MODES_NUM) {\n-\t\tswitch (mode) {\n-\t\tcase PHY_LED_ACTIVE_LOW:\n-\t\t\tval = MTK_PHY_LED_ON_POLARITY;\n-\t\t\tbreak;\n-\t\tcase PHY_LED_ACTIVE_HIGH:\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\t}\n-\n-\treturn phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?\n-\t\t\t      MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,\n-\t\t\t      MTK_PHY_LED_ON_POLARITY, val);\n-}\n-\n-static int an7583_phy_config_init(struct phy_device *phydev)\n-{\n-\t/* BMCR_PDOWN is enabled by default */\n-\treturn phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);\n-}\n-\n static struct phy_driver mtk_socphy_driver[] = {\n \t{\n \t\tPHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),\n@@ -1505,31 +1057,6 @@ static struct phy_driver mtk_socphy_driver[] = {\n \t\t.led_hw_control_set = mt798x_phy_led_hw_control_set,\n \t\t.led_hw_control_get = mt798x_phy_led_hw_control_get,\n \t},\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581),\n-\t\t.name\t\t= \"Airoha AN7581 PHY\",\n-\t\t.config_intr\t= genphy_no_config_intr,\n-\t\t.handle_interrupt = genphy_handle_interrupt_no_ack,\n-\t\t.probe\t\t= an7581_phy_probe,\n-\t\t.led_blink_set\t= mt798x_phy_led_blink_set,\n-\t\t.led_brightness_set = mt798x_phy_led_brightness_set,\n-\t\t.led_hw_is_supported = mt798x_phy_led_hw_is_supported,\n-\t\t.led_hw_control_set = mt798x_phy_led_hw_control_set,\n-\t\t.led_hw_control_get = mt798x_phy_led_hw_control_get,\n-\t\t.led_polarity_set = an7581_phy_led_polarity_set,\n-\t},\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7583),\n-\t\t.name\t\t= \"Airoha AN7583 PHY\",\n-\t\t.config_init\t= an7583_phy_config_init,\n-\t\t.probe\t\t= an7581_phy_probe,\n-\t\t.led_blink_set\t= mt798x_phy_led_blink_set,\n-\t\t.led_brightness_set = mt798x_phy_led_brightness_set,\n-\t\t.led_hw_is_supported = mt798x_phy_led_hw_is_supported,\n-\t\t.led_hw_control_set = mt798x_phy_led_hw_control_set,\n-\t\t.led_hw_control_get = mt798x_phy_led_hw_control_get,\n-\t\t.led_polarity_set = an7581_phy_led_polarity_set,\n-\t},\n };\n \n module_phy_driver(mtk_socphy_driver);\n@@ -1537,8 +1064,6 @@ module_phy_driver(mtk_socphy_driver);\n static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {\n \t{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },\n \t{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },\n-\t{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581) },\n-\t{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7583) },\n \t{ }\n };\n \ndiff --git a/drivers/net/phy/mediatek/mtk-ge-soc.h b/drivers/net/phy/mediatek/mtk-ge-soc.h\nnew file mode 100644\nindex 00000000000000..5e9d24a9833c77\n--- /dev/null\n+++ b/drivers/net/phy/mediatek/mtk-ge-soc.h\n@@ -0,0 +1,364 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+#ifndef _MTK_GE_SOC_H_\n+#define _MTK_GE_SOC_H_\n+\n+#include \u003clinux/bitfield.h\u003e\n+\n+#define MTK_GPHY_ID_MT7981\t\t\t0x03a29461\n+#define MTK_GPHY_ID_MT7988\t\t\t0x03a29481\n+#define AIROHA_GPHY_ID_AN7581\t\t\t0x03a294c1\n+#define AIROHA_GPHY_ID_AN7583\t\t\t0xc0ff0420\n+\n+#define MTK_EXT_PAGE_ACCESS\t\t\t0x1f\n+#define MTK_PHY_PAGE_STANDARD\t\t\t0x0000\n+#define MTK_PHY_PAGE_EXTENDED_1\t\t\t0x0001\n+#define MTK_PHY_PAGE_EXTENDED_3\t\t\t0x0003\n+\n+#define MTK_PHY_LPI_REG_14\t\t\t0x14\n+#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK\tGENMASK(8, 0)\n+\n+#define MTK_PHY_LPI_REG_1c\t\t\t0x1c\n+#define MTK_PHY_SMI_DET_ON_THRESH_MASK\t\tGENMASK(13, 8)\n+\n+#define MTK_PHY_PAGE_EXTENDED_2A30\t\t0x2a30\n+\n+/* Registers on Token Ring debug nodes */\n+/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */\n+/* NormMseLoThresh */\n+#define NORMAL_MSE_LO_THRESH_MASK\t\tGENMASK(15, 8)\n+\n+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */\n+/* RemAckCntLimitCtrl */\n+#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK\tGENMASK(2, 1)\n+\n+/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */\n+/* VcoSlicerThreshBitsHigh */\n+#define VCO_SLICER_THRESH_HIGH_MASK\t\tGENMASK(23, 0)\n+\n+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */\n+/* DfeTailEnableVgaThresh1000 */\n+#define DFE_TAIL_EANBLE_VGA_TRHESH_1000\t\tGENMASK(5, 1)\n+\n+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */\n+/* MrvlTrFix100Kp */\n+#define MRVL_TR_FIX_100KP_MASK\t\t\tGENMASK(22, 20)\n+/* MrvlTrFix100Kf */\n+#define MRVL_TR_FIX_100KF_MASK\t\t\tGENMASK(19, 17)\n+/* MrvlTrFix1000Kp */\n+#define MRVL_TR_FIX_1000KP_MASK\t\t\tGENMASK(16, 14)\n+/* MrvlTrFix1000Kf */\n+#define MRVL_TR_FIX_1000KF_MASK\t\t\tGENMASK(13, 11)\n+\n+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */\n+/* VgaDecRate */\n+#define VGA_DECIMATION_RATE_MASK\t\tGENMASK(8, 5)\n+\n+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */\n+/* SlvDSPreadyTime */\n+#define SLAVE_DSP_READY_TIME_MASK\t\tGENMASK(22, 15)\n+/* MasDSPreadyTime */\n+#define MASTER_DSP_READY_TIME_MASK\t\tGENMASK(14, 7)\n+\n+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */\n+/* EnabRandUpdTrig */\n+#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER\tBIT(8)\n+\n+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */\n+/* ResetSyncOffset */\n+#define RESET_SYNC_OFFSET_MASK\t\t\tGENMASK(11, 8)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */\n+/* FfeUpdGainForceVal */\n+#define FFE_UPDATE_GAIN_FORCE_VAL_MASK\t\tGENMASK(9, 7)\n+/* FfeUpdGainForce */\n+#define FFE_UPDATE_GAIN_FORCE\t\t\tBIT(6)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */\n+/* TrFreeze */\n+#define TR_FREEZE_MASK\t\t\t\tGENMASK(11, 0)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */\n+/* SS: Steady-state, KP: Proportional Gain */\n+/* SSTrKp100 */\n+#define SS_TR_KP100_MASK\t\t\tGENMASK(21, 19)\n+/* SSTrKf100 */\n+#define SS_TR_KF100_MASK\t\t\tGENMASK(18, 16)\n+/* SSTrKp1000Mas */\n+#define SS_TR_KP1000_MASTER_MASK\t\tGENMASK(15, 13)\n+/* SSTrKf1000Mas */\n+#define SS_TR_KF1000_MASTER_MASK\t\tGENMASK(12, 10)\n+/* SSTrKp1000Slv */\n+#define SS_TR_KP1000_SLAVE_MASK\t\t\tGENMASK(9, 7)\n+/* SSTrKf1000Slv */\n+#define SS_TR_KF1000_SLAVE_MASK\t\t\tGENMASK(6, 4)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */\n+/* clear this bit if wanna select from AFE */\n+/* Regsigdet_sel_1000 */\n+#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE\tBIT(4)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */\n+/* RegEEE_st2TrKf1000 */\n+#define EEE1000_STAGE2_TR_KF_MASK\t\tGENMASK(13, 11)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */\n+/* RegEEE_slv_waketr_timer_tar */\n+#define SLAVE_WAKETR_TIMER_MASK\t\t\tGENMASK(20, 11)\n+/* RegEEE_slv_remtx_timer_tar */\n+#define SLAVE_REMTX_TIMER_MASK\t\t\tGENMASK(10, 1)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */\n+/* RegEEE_slv_wake_int_timer_tar */\n+#define SLAVE_WAKEINT_TIMER_MASK\t\tGENMASK(10, 1)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */\n+/* RegEEE_trfreeze_timer2 */\n+#define TR_FREEZE_TIMER2_MASK\t\t\tGENMASK(9, 0)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */\n+/* RegEEE100Stg1_tar */\n+#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK\tGENMASK(8, 0)\n+\n+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */\n+/* REGEEE_wake_slv_tr_wait_dfesigdet_en */\n+#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN\tBIT(11)\n+\n+#define ANALOG_INTERNAL_OPERATION_MAX_US\t20\n+#define TXRESERVE_MIN\t\t\t\t0\n+#define TXRESERVE_MAX\t\t\t\t7\n+\n+#define MTK_PHY_ANARG_RG\t\t\t0x10\n+#define   MTK_PHY_TCLKOFFSET_MASK\t\tGENMASK(12, 8)\n+\n+/* Registers on MDIO_MMD_VEND1 */\n+#define MTK_PHY_TXVLD_DA_RG\t\t\t0x12\n+#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK\tGENMASK(15, 10)\n+#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_TX_I2MPB_TEST_MODE_A2\t\t0x16\n+#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK\tGENMASK(15, 10)\n+#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_TX_I2MPB_TEST_MODE_B1\t\t0x17\n+#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_TX_I2MPB_TEST_MODE_B2\t\t0x18\n+#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_TX_I2MPB_TEST_MODE_C1\t\t0x19\n+#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_TX_I2MPB_TEST_MODE_C2\t\t0x20\n+#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_TX_I2MPB_TEST_MODE_D1\t\t0x21\n+#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_TX_I2MPB_TEST_MODE_D2\t\t0x22\n+#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_RXADC_CTRL_RG7\t\t\t0xc6\n+#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK\tGENMASK(9, 8)\n+\n+#define MTK_PHY_RXADC_CTRL_RG9\t\t\t0xc8\n+#define   MTK_PHY_DA_RX_PSBN_TBT_MASK\t\tGENMASK(14, 12)\n+#define   MTK_PHY_DA_RX_PSBN_HBT_MASK\t\tGENMASK(10, 8)\n+#define   MTK_PHY_DA_RX_PSBN_GBE_MASK\t\tGENMASK(6, 4)\n+#define   MTK_PHY_DA_RX_PSBN_LP_MASK\t\tGENMASK(2, 0)\n+\n+#define MTK_PHY_LDO_OUTPUT_V\t\t\t0xd7\n+\n+#define MTK_PHY_RG_ANA_CAL_RG0\t\t\t0xdb\n+#define   MTK_PHY_RG_CAL_CKINV\t\t\tBIT(12)\n+#define   MTK_PHY_RG_ANA_CALEN\t\t\tBIT(8)\n+#define   MTK_PHY_RG_REXT_CALEN\t\t\tBIT(4)\n+#define   MTK_PHY_RG_ZCALEN_A\t\t\tBIT(0)\n+\n+#define MTK_PHY_RG_ANA_CAL_RG1\t\t\t0xdc\n+#define   MTK_PHY_RG_ZCALEN_B\t\t\tBIT(12)\n+#define   MTK_PHY_RG_ZCALEN_C\t\t\tBIT(8)\n+#define   MTK_PHY_RG_ZCALEN_D\t\t\tBIT(4)\n+#define   MTK_PHY_RG_TXVOS_CALEN\t\tBIT(0)\n+\n+#define MTK_PHY_RG_ANA_CAL_RG5\t\t\t0xe0\n+#define   MTK_PHY_RG_REXT_TRIM_MASK\t\tGENMASK(13, 8)\n+#define   MTK_PHY_RG_REXT_ZCAL_CTRL_MASK\tGENMASK(5, 0)\n+\n+#define MTK_PHY_RG_ANA_CAL_RG6\t\t\t0xe1\n+\n+#define MTK_PHY_RG_TX_FILTER\t\t\t0xfe\n+\n+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120\t0x120\n+#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK\tGENMASK(12, 8)\n+#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK\tGENMASK(4, 0)\n+\n+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122\t0x122\n+#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK\tGENMASK(7, 0)\n+\n+#define MTK_PHY_RG_TESTMUX_ADC_CTRL\t\t0x144\n+#define   MTK_PHY_RG_TXEN_DIG_MASK\t\tGENMASK(5, 5)\n+\n+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B\t\t0x172\n+#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK\tGENMASK(6, 0)\n+\n+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D\t\t0x173\n+#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK\tGENMASK(6, 0)\n+\n+#define MTK_PHY_RG_CR_TX_R50_OFFSET_A_B\t\t0x174\n+#define   MTK_PHY_CR_TX_R50_OFFSET_A_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_CR_TX_R50_OFFSET_B_MASK\tGENMASK(6, 0)\n+\n+#define MTK_PHY_RG_CR_TX_R50_OFFSET_C_D\t\t0x175\n+#define   MTK_PHY_CR_TX_R50_OFFSET_C_MASK\tGENMASK(13, 8)\n+#define   MTK_PHY_CR_TX_R50_OFFSET_D_MASK\tGENMASK(6, 0)\n+\n+#define MTK_PHY_RG_AD_CAL_COMP\t\t\t0x17a\n+#define   MTK_PHY_AD_CAL_COMP_OUT_MASK\t\tGENMASK(8, 8)\n+\n+#define MTK_PHY_RG_AD_CAL_CLK\t\t\t0x17b\n+#define   MTK_PHY_DA_CAL_CLK\t\t\tBIT(0)\n+\n+#define MTK_PHY_RG_AD_CALIN\t\t\t0x17c\n+#define   MTK_PHY_DA_CALIN_FLAG\t\t\tBIT(0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN0_A\t\t0x17d\n+#define   MTK_PHY_DASN_DAC_IN0_A_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN0_B\t\t0x17e\n+#define   MTK_PHY_DASN_DAC_IN0_B_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN0_C\t\t0x17f\n+#define   MTK_PHY_DASN_DAC_IN0_C_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN0_D\t\t0x180\n+#define   MTK_PHY_DASN_DAC_IN0_D_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN1_A\t\t0x181\n+#define   MTK_PHY_DASN_DAC_IN1_A_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN1_B\t\t0x182\n+#define   MTK_PHY_DASN_DAC_IN1_B_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN1_C\t\t0x183\n+#define   MTK_PHY_DASN_DAC_IN1_C_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DASN_DAC_IN1_D\t\t0x184\n+#define   MTK_PHY_DASN_DAC_IN1_D_MASK\t\tGENMASK(9, 0)\n+\n+#define MTK_PHY_RG_DEV1E_REG19b\t\t\t0x19b\n+#define   MTK_PHY_BYPASS_DSP_LPI_READY\t\tBIT(8)\n+\n+#define MTK_PHY_RG_LP_IIR2_K1_L\t\t\t0x22a\n+#define MTK_PHY_RG_LP_IIR2_K1_U\t\t\t0x22b\n+#define MTK_PHY_RG_LP_IIR2_K2_L\t\t\t0x22c\n+#define MTK_PHY_RG_LP_IIR2_K2_U\t\t\t0x22d\n+#define MTK_PHY_RG_LP_IIR2_K3_L\t\t\t0x22e\n+#define MTK_PHY_RG_LP_IIR2_K3_U\t\t\t0x22f\n+#define MTK_PHY_RG_LP_IIR2_K4_L\t\t\t0x230\n+#define MTK_PHY_RG_LP_IIR2_K4_U\t\t\t0x231\n+#define MTK_PHY_RG_LP_IIR2_K5_L\t\t\t0x232\n+#define MTK_PHY_RG_LP_IIR2_K5_U\t\t\t0x233\n+\n+#define MTK_PHY_RG_DEV1E_REG234\t\t\t0x234\n+#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK\t\tGENMASK(0, 0)\n+#define   MTK_PHY_LPF_X_AVERAGE_MASK\t\tGENMASK(7, 4)\n+#define   MTK_PHY_TR_LP_IIR_EEE_EN\t\tBIT(12)\n+\n+#define MTK_PHY_RG_LPF_CNT_VAL\t\t\t0x235\n+\n+#define MTK_PHY_RG_DEV1E_REG238\t\t\t0x238\n+#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK\tGENMASK(8, 0)\n+#define   MTK_PHY_LPI_SLV_SEND_TX_EN\t\tBIT(12)\n+\n+#define MTK_PHY_RG_DEV1E_REG239\t\t\t0x239\n+#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK\tGENMASK(8, 0)\n+#define   MTK_PHY_LPI_TXPCS_LOC_RCV\t\tBIT(12)\n+\n+#define MTK_PHY_RG_DEV1E_REG27C\t\t\t0x27c\n+#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK\tGENMASK(12, 8)\n+#define MTK_PHY_RG_DEV1E_REG27D\t\t\t0x27d\n+#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK\tGENMASK(4, 0)\n+\n+#define MTK_PHY_RG_DEV1E_REG2C7\t\t\t0x2c7\n+#define   MTK_PHY_MAX_GAIN_MASK\t\t\tGENMASK(4, 0)\n+#define   MTK_PHY_MIN_GAIN_MASK\t\t\tGENMASK(12, 8)\n+\n+#define MTK_PHY_RG_DEV1E_REG2D1\t\t\t0x2d1\n+#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK\tGENMASK(7, 0)\n+#define   MTK_PHY_LPI_SKIP_SD_SLV_TR\t\tBIT(8)\n+#define   MTK_PHY_LPI_TR_READY\t\t\tBIT(9)\n+#define   MTK_PHY_LPI_VCO_EEE_STG0_EN\t\tBIT(10)\n+\n+#define MTK_PHY_RG_DEV1E_REG323\t\t\t0x323\n+#define   MTK_PHY_EEE_WAKE_MAS_INT_DC\t\tBIT(0)\n+#define   MTK_PHY_EEE_WAKE_SLV_INT_DC\t\tBIT(4)\n+\n+#define MTK_PHY_RG_DEV1E_REG324\t\t\t0x324\n+#define   MTK_PHY_SMI_DETCNT_MAX_MASK\t\tGENMASK(5, 0)\n+#define   MTK_PHY_SMI_DET_MAX_EN\t\tBIT(8)\n+\n+#define MTK_PHY_RG_DEV1E_REG326\t\t\t0x326\n+#define   MTK_PHY_LPI_MODE_SD_ON\t\tBIT(0)\n+#define   MTK_PHY_RESET_RANDUPD_CNT\t\tBIT(1)\n+#define   MTK_PHY_TREC_UPDATE_ENAB_CLR\t\tBIT(2)\n+#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF\tBIT(4)\n+#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP\tBIT(5)\n+\n+#define MTK_PHY_LDO_PUMP_EN_PAIRAB\t\t0x502\n+#define MTK_PHY_LDO_PUMP_EN_PAIRCD\t\t0x503\n+\n+#define MTK_PHY_DA_TX_R50_PAIR_A\t\t0x53d\n+#define MTK_PHY_DA_TX_R50_PAIR_B\t\t0x53e\n+#define MTK_PHY_DA_TX_R50_PAIR_C\t\t0x53f\n+#define MTK_PHY_DA_TX_R50_PAIR_D\t\t0x540\n+\n+/* Registers on MDIO_MMD_VEND2 */\n+#define MTK_PHY_LED1_DEFAULT_POLARITIES\t\tBIT(1)\n+\n+#define MTK_PHY_RG_BG_RASEL\t\t\t0x115\n+#define   MTK_PHY_RG_BG_RASEL_MASK\t\tGENMASK(2, 0)\n+\n+/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */\n+#define RG_GPIO_MISC_TPBANK0\t\t\t0x6f0\n+#define   RG_GPIO_MISC_TPBANK0_BOOTMODE\t\tGENMASK(11, 8)\n+\n+enum CAL_ITEM {\n+\tREXT,\n+\tTX_OFFSET,\n+\tTX_AMP,\n+\tTX_R50,\n+\tTX_VCM,\n+\tRX_OFFSET,\n+};\n+\n+enum {\n+\tNO_PAIR,\n+\tPAIR_A,\n+\tPAIR_B,\n+\tPAIR_C,\n+\tPAIR_D,\n+};\n+\n+enum calibration_mode {\n+\tEFUSE_K,\n+\tSW_K\n+};\n+\n+enum CAL_MODE {\n+\tEFUSE_M,\n+\tSW_M\n+};\n+\n+/* MTK GE SoC common functions */\n+int mtk_cal_cycle_wait(struct phy_device *phydev);\n+\n+#endif /* _MTK_GE_SOC_H_ */\ndiff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c\nindex dfd0f4e439a214..8c2b26f9b8403b 100644\n--- a/drivers/net/phy/mediatek/mtk-phy-lib.c\n+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c\n@@ -36,8 +36,8 @@ static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n \t\t*tr_high, *tr_low);\n }\n \n-static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n-\t\t\t   u8 data_addr, u32 tr_data)\n+void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n+\t\t    u8 data_addr, u32 tr_data)\n {\n \t__phy_write(phydev, 0x11, tr_data \u0026 0xffff);\n \t__phy_write(phydev, 0x12, tr_data \u003e\u003e 16);\n@@ -45,6 +45,7 @@ static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n \t\ttr_data \u003e\u003e 16, tr_data \u0026 0xffff);\n \t__mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);\n }\n+EXPORT_SYMBOL_GPL(__mtk_tr_write);\n \n void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n \t\t     u8 data_addr, u32 mask, u32 set)\n@@ -341,6 +342,78 @@ void mtk_phy_leds_state_init(struct phy_device *phydev)\n }\n EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);\n \n+int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,\n+\t\t\t     unsigned long *delay_on,\n+\t\t\t     unsigned long *delay_off)\n+{\n+\tbool blinking = false;\n+\tint err;\n+\n+\terr = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, \u0026blinking);\n+\tif (err \u003c 0)\n+\t\treturn err;\n+\n+\terr = mtk_phy_hw_led_blink_set(phydev, index, blinking);\n+\tif (err)\n+\t\treturn err;\n+\n+\treturn mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,\n+\t\t\t\t     false);\n+}\n+EXPORT_SYMBOL_GPL(mt798x_phy_led_blink_set);\n+\n+int mt798x_phy_led_brightness_set(struct phy_device *phydev,\n+\t\t\t\t  u8 index, enum led_brightness value)\n+{\n+\tint err;\n+\n+\terr = mtk_phy_hw_led_blink_set(phydev, index, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\treturn mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,\n+\t\t\t\t     (value != LED_OFF));\n+}\n+EXPORT_SYMBOL_GPL(mt798x_phy_led_brightness_set);\n+\n+static const unsigned long supported_triggers =\n+\tBIT(TRIGGER_NETDEV_FULL_DUPLEX) |\n+\tBIT(TRIGGER_NETDEV_HALF_DUPLEX) |\n+\tBIT(TRIGGER_NETDEV_LINK)        |\n+\tBIT(TRIGGER_NETDEV_LINK_10)     |\n+\tBIT(TRIGGER_NETDEV_LINK_100)    |\n+\tBIT(TRIGGER_NETDEV_LINK_1000)   |\n+\tBIT(TRIGGER_NETDEV_RX)          |\n+\tBIT(TRIGGER_NETDEV_TX);\n+\n+int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,\n+\t\t\t\t   unsigned long rules)\n+{\n+\treturn mtk_phy_led_hw_is_supported(phydev, index, rules,\n+\t\t\t\t\t   supported_triggers);\n+}\n+EXPORT_SYMBOL_GPL(mt798x_phy_led_hw_is_supported);\n+\n+int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,\n+\t\t\t\t  unsigned long *rules)\n+{\n+\treturn mtk_phy_led_hw_ctrl_get(phydev, index, rules,\n+\t\t\t\t       MTK_GPHY_LED_ON_SET,\n+\t\t\t\t       MTK_GPHY_LED_RX_BLINK_SET,\n+\t\t\t\t       MTK_GPHY_LED_TX_BLINK_SET);\n+};\n+EXPORT_SYMBOL_GPL(mt798x_phy_led_hw_control_get);\n+\n+int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,\n+\t\t\t\t  unsigned long rules)\n+{\n+\treturn mtk_phy_led_hw_ctrl_set(phydev, index, rules,\n+\t\t\t\t       MTK_GPHY_LED_ON_SET,\n+\t\t\t\t       MTK_GPHY_LED_RX_BLINK_SET,\n+\t\t\t\t       MTK_GPHY_LED_TX_BLINK_SET);\n+};\n+EXPORT_SYMBOL_GPL(mt798x_phy_led_hw_control_set);\n+\n MODULE_DESCRIPTION(\"MediaTek Ethernet PHY driver common\");\n MODULE_AUTHOR(\"Sky Huang \u003cSkyLake.Huang@mediatek.com\u003e\");\n MODULE_AUTHOR(\"Daniel Golle \u003cdaniel@makrotopia.org\u003e\");\ndiff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h\nindex 320f76ffa81fa2..cd9d4c5550c3b7 100644\n--- a/drivers/net/phy/mediatek/mtk.h\n+++ b/drivers/net/phy/mediatek/mtk.h\n@@ -13,6 +13,7 @@\n \n #define MTK_EXT_PAGE_ACCESS\t\t\t0x1f\n #define MTK_PHY_PAGE_EXTENDED_1\t\t\t0x0001\n+#define MTK_PHY_PAGE_EXTENDED_3\t\t\t0x0003\n #define MTK_PHY_PAGE_STANDARD\t\t\t0x0000\n #define MTK_PHY_PAGE_EXTENDED_52B5\t\t0x52b5\n \n@@ -72,6 +73,8 @@ struct mtk_socphy_priv {\n \tunsigned long\t\tled_state;\n };\n \n+void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n+\t\t    u8 data_addr, u32 tr_data);\n void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n \t\t     u8 data_addr, u32 mask, u32 set);\n void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,\n@@ -101,4 +104,16 @@ int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,\n \t\t\t     bool blinking);\n void mtk_phy_leds_state_init(struct phy_device *phydev);\n \n+int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,\n+\t\t\t     unsigned long *delay_on,\n+\t\t\t     unsigned long *delay_off);\n+int mt798x_phy_led_brightness_set(struct phy_device *phydev,\n+\t\t\t\t  u8 index, enum led_brightness value);\n+int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,\n+\t\t\t\t   unsigned long rules);\n+int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,\n+\t\t\t\t  unsigned long *rules);\n+int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,\n+\t\t\t\t  unsigned long rules);\n+\n #endif /* _MTK_EPHY_H_ */\n"
}

2/1 2026/07/09 01:11 agent patch-evaluator
1m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch introduces a new hardware-specific Ethernet PHY driver for Airoha SoCs and refactors the existing MediaTek PHY driver to share code. Since PHY devices are instantiated by the MDIO bus based on hardware probing (reading PHY ID registers) or device tree, and there is no virtual MDIO bus or software-emulated hardware in virtualized environments (like QEMU/GCE) that can instantiate this specific PHY, the code is impossible to reach and test via fuzzing.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a '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:
For your convenience, here is the diff of the changes:
commit e27b55cd6a9ebb4a6bccb12c9f602b617fb0d0eb
Author: syz-cluster <triage@syzkaller.com>
Date:   Thu Jul 9 01:11:53 2026 +0000

    syz-cluster: applied patch under review

diff --git a/MAINTAINERS b/MAINTAINERS
index 52f1a55eca99bf..65cc21b39c3dbc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -760,6 +760,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml
 F:	drivers/net/ethernet/airoha/
 
+AIROHA ETHERNET PHY DRIVER
+M:	Christian Marangi <ansuelsmth@gmail.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:	linux-mediatek@lists.infradead.org (moderated for non-subscribers)
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/phy/mediatek/airoha-ge-soc.c
+
 AIROHA PCIE PHY DRIVER
 M:	Lorenzo Bianconi <lorenzo@kernel.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -16483,6 +16491,7 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/phy/mediatek/mtk-2p5ge.c
 F:	drivers/net/phy/mediatek/mtk-ge-soc.c
+F:	drivers/net/phy/mediatek/mtk-ge-soc.h
 F:	drivers/net/phy/mediatek/mtk-phy-lib.c
 F:	drivers/net/phy/mediatek/mtk-ge.c
 F:	drivers/net/phy/mediatek/mtk.h
diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
index bb7dc876271e83..fe51f4616c544f 100644
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -1,4 +1,17 @@
 # SPDX-License-Identifier: GPL-2.0-only
+config AIROHA_GE_SOC_PHY
+	tristate "Airoha SoC Ethernet PHYs"
+	depends on ARM64 || COMPILE_TEST
+	depends on ARCH_AIROHA || COMPILE_TEST
+	select MTK_NET_PHYLIB
+	select PHY_PACKAGE
+	help
+	  Supports Airoha SoC built-in Gigabit Ethernet PHYs.
+
+	  Include support for built-in Ethernet PHYs which are present in
+	  the AN7581 and AN7583 SoCs. These PHYs d will dynamically
+	  calibrate during startup.
+
 config MEDIATEK_2P5GE_PHY
 	tristate "MediaTek 2.5Gb Ethernet PHYs"
 	depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
@@ -24,8 +37,7 @@ config MEDIATEK_GE_PHY
 config MEDIATEK_GE_SOC_PHY
 	tristate "MediaTek SoC Ethernet PHYs"
 	depends on ARM64 || COMPILE_TEST
-	depends on ARCH_AIROHA || (ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || \
-		   COMPILE_TEST
+	depends on (ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST
 	select MTK_NET_PHYLIB
 	select PHY_PACKAGE
 	help
diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile
index ac57ecc799fc81..eb430f008169e2 100644
--- a/drivers/net/phy/mediatek/Makefile
+++ b/drivers/net/phy/mediatek/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_AIROHA_GE_SOC_PHY)		+= airoha-ge-soc.o
 obj-$(CONFIG_MEDIATEK_2P5GE_PHY)	+= mtk-2p5ge.o
 obj-$(CONFIG_MEDIATEK_GE_PHY)		+= mtk-ge.o
 obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mtk-ge-soc.o
diff --git a/drivers/net/phy/mediatek/airoha-ge-soc.c b/drivers/net/phy/mediatek/airoha-ge-soc.c
new file mode 100644
index 00000000000000..601a64d8336542
--- /dev/null
+++ b/drivers/net/phy/mediatek/airoha-ge-soc.c
@@ -0,0 +1,1812 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/bitfield.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/phy.h>
+
+#include "../phylib.h"
+#include "mtk.h"
+#include "mtk-ge-soc.h"
+
+#define AIROHA_DEFAULT_PORT0_ADDR		0x9
+#define AIROHA_PHY_MAX_LEDS			2
+
+enum airoha_mdi_resister_type {
+	MDI_0R,
+	MDI_5R,
+
+	MDI_TYPE_MAX,
+};
+
+enum airoha_transformer_type {
+	TXMR,
+	DISCRETE,
+
+	TRANSFORMER_TYPE_MAX,
+};
+
+enum airoha_calib_const_type {
+	TX_AMP_TEST_A,
+	TX_AMP_TEST_B,
+	TX_AMP_TEST_C,
+	TX_AMP_TEST_D,
+	TX_AMP_1G_A,
+	TX_AMP_1G_B,
+	TX_AMP_1G_C,
+	TX_AMP_1G_D,
+	TX_AMP_100M_A,
+	TX_AMP_100M_B,
+	TX_AMP_10M_A,
+	TX_AMP_10M_B,
+	R50_A,
+	R50_B,
+	R50_C,
+	R50_D,
+
+	CALIB_CONST_TYPE_MAX,
+};
+
+struct airoha_socphy_shared {
+	struct phy_device *phydev_p0;
+	enum airoha_transformer_type transformer_type[4];
+	enum airoha_mdi_resister_type mdi_resister_type;
+	bool rext_sw_calib_done;
+	int (*tx_amp_compensation_tbl)[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4];
+	u8 *r50_cal_tbl;
+};
+
+/*
+ * 2 chip revision
+ * TXMR or discrete
+ * 2 MDI type
+ * TX AMP test/TX AMP 1G/TX AMP 100M/TX AMP 10M/R50
+ * 4 PHY
+ */
+static int an7581_tx_amp_compensation_tbl[2][TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {
+	{ /* IC version 1 */
+		[TXMR] = {
+			{ },
+			{
+				[TX_AMP_TEST_A] = { -12, -11, -9, -6 },
+				[TX_AMP_TEST_B] = { -9, -13, -9, -5 },
+				[TX_AMP_TEST_C] = { -5, -4, -3, 1 },
+				[TX_AMP_TEST_D] = { -9, -8, -7, -5 },
+				[TX_AMP_1G_A] = { -12, -11, -9, -6 },
+				[TX_AMP_1G_B] = { -9, -13, -9, -5 },
+				[TX_AMP_1G_C] = { -5, -4, -3, 1 },
+				[TX_AMP_1G_D] = { -9, -8, -7, -5 },
+				[TX_AMP_100M_A] = { -2, -2, 0, 2 },
+				[TX_AMP_100M_B] = { -2, -2, 1, 1 },
+				[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+				[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+				[R50_A] = { 15, 15, 15, 15 },
+				[R50_B] = { 15, 15, 18, 15 },
+				[R50_C] = { -8, -8, -8, -8 },
+				[R50_D] = { -8, -8, -8, -8 },
+			},
+		},
+		[DISCRETE] = {
+			{ },
+			{
+				[TX_AMP_TEST_A] = { -9, -7, -7, -5 },
+				[TX_AMP_TEST_B] = { -9, -9, -7, -4 },
+				[TX_AMP_TEST_C] = { -9, -7, -9, -6 },
+				[TX_AMP_TEST_D] = { -11, -9, -10, -8 },
+				[TX_AMP_1G_A] = { -9, -7, -7, -5 },
+				[TX_AMP_1G_B] = { -9, -8, -7, -4 },
+				[TX_AMP_1G_C] = { -9, -7, -9, -6 },
+				[TX_AMP_1G_D] = { -11, -8, -10, -8 },
+				[TX_AMP_100M_A] = { 4, 3, 4, 4 },
+				[TX_AMP_100M_B] = { 4, 4, 5, 4 },
+				[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+				[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+				[R50_A] = { 0, 0, 0, 0 },
+				[R50_B] = { 0, 0, 0, 0 },
+				[R50_C] = { 0, 0, 0, 0 },
+				[R50_D] = { 0, 0, 0, 0 },
+			},
+		},
+	},
+	{ /* IC version 2 */
+		[TXMR] = {
+			{ },
+			{
+				[TX_AMP_TEST_A] = { -10, -12, -12, -11 },
+				[TX_AMP_TEST_B] = { -10, -11, -11, -10 },
+				[TX_AMP_TEST_C] = { -5, -7, -9, -3 },
+				[TX_AMP_TEST_D] = { -8, -10, -7, -8 },
+				[TX_AMP_1G_A] = { -12, -6, -6, 4 },
+				[TX_AMP_1G_B] = { -10, -5, -5, 1 },
+				[TX_AMP_1G_C] = { -5, -3, -4, 11 },
+				[TX_AMP_1G_D] = { -8, -3, -3, 4 },
+				[TX_AMP_100M_A] = { 2, 1, 0, 3 },
+				[TX_AMP_100M_B] = { 0, 0, 0, 3 },
+				[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+				[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+				[R50_A] = { 15, 15, 15, 15 },
+				[R50_B] = { 15, 15, 18, 15 },
+				[R50_C] = { 4, 4, 4, 4 },
+				[R50_D] = { 4, 4, 4, 4 },
+			},
+		},
+		[DISCRETE] = {
+			{ },
+			{
+				[TX_AMP_TEST_A] = { -11, 11, -12, -7 },
+				[TX_AMP_TEST_B] = { -9, -10, -9, -8 },
+				[TX_AMP_TEST_C] = { -6, -3, -7, -4 },
+				[TX_AMP_TEST_D] = { -7, -8, -10, -7 },
+				[TX_AMP_1G_A] = { -11, -11, -12, -7 },
+				[TX_AMP_1G_B] = { -9, -10, -9, -8 },
+				[TX_AMP_1G_C] = { -6, -3, -7, -4 },
+				[TX_AMP_1G_D] = { -7, -8, -10, -7 },
+				[TX_AMP_100M_A] = { 2, 2, 1, 2 },
+				[TX_AMP_100M_B] = { 3, 3, 3, 3 },
+				[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+				[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+				[R50_A] = { 12, 12, 12, 12 },
+				[R50_B] = { 7, 7, 7, 7 },
+				[R50_C] = { 2, 2, 0, 0 },
+				[R50_D] = { 0, 0, 2, 2 },
+			},
+		},
+	},
+};
+
+static u8 an7581_zcal_to_r45ohm[64] = {
+	127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+	127, 127, 127, 127, 127, 127, 127, 127, 123, 119, 115, 112, 108, 104, 100,  96,
+	 94,  92,  88,  85,  82,  80,  76,  74,  72,  68,  66,  64,  62,  60,  56,  55,
+	 52,  50,  48,  46,  44,  42,  40,  39,  36,  35,  32,  32,  30,  28,  27,  25
+};
+
+/*
+ * 2 chip revision
+ * TXMR or discrete
+ * 2 MDI type
+ * TX AMP test/TX AMP 1G/TX AMP 100M/TX AMP 10M/R50
+ * 4 PHY
+ */
+static int an7583_tx_amp_compensation_tbl[TRANSFORMER_TYPE_MAX][MDI_TYPE_MAX][CALIB_CONST_TYPE_MAX][4] = {
+	[TXMR] = {
+		[MDI_0R] = {
+			[TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+			[TX_AMP_1G_A] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_B] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_C] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_D] = { 0, 0, 0, 0 },
+			[TX_AMP_100M_A] = { 4, 4, 4, 4 },
+			[TX_AMP_100M_B] = { 4, 4, 4, 4 },
+			[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+			[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+			[R50_A] = { 4, 4, 0, 0 },
+			[R50_B] = { 4, 4, 0, 0 },
+			[R50_C] = { 5, 5, 3, 4 },
+			[R50_D] = { 4, 4, 4, 0 },
+		},
+		[MDI_5R] = {
+			[TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+			[TX_AMP_1G_A] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_B] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_C] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_D] = { 0, 0, 0, 0 },
+			[TX_AMP_100M_A] = { 4, 4, 4, 4 },
+			[TX_AMP_100M_B] = { 4, 4, 4, 4 },
+			[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+			[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+			[R50_A] = { -4, -4, -4, -4 },
+			[R50_B] = { -4, -4, -4, -4 },
+			[R50_C] = { -2, -2, -2, -2 },
+			[R50_D] = { -3, -3, -2, -2 },
+		},
+	},
+	[DISCRETE] = {
+		[MDI_0R] = {
+			[TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+			[TX_AMP_1G_A] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_B] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_C] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_D] = { 0, 0, 0, 0 },
+			[TX_AMP_100M_A] = { 4, 4, 4, 4 },
+			[TX_AMP_100M_B] = { 4, 4, 4, 4 },
+			[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+			[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+			[R50_A] = { 4, 4, 4, 4 },
+			[R50_B] = { 4, 4, 4, 4 },
+			[R50_C] = { 6, 6, 6, 6 },
+			[R50_D] = { 4, 4, 4, 4 },
+		},
+		[MDI_5R] = {
+			[TX_AMP_TEST_A] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_B] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_C] = { -3, -3, -3, -3 },
+			[TX_AMP_TEST_D] = { -3, -3, -3, -3 },
+			[TX_AMP_1G_A] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_B] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_C] = { 0, 0, 0, 0 },
+			[TX_AMP_1G_D] = { 0, 0, 0, 0 },
+			[TX_AMP_100M_A] = { 4, 4, 4, 4 },
+			[TX_AMP_100M_B] = { 4, 4, 4, 4 },
+			[TX_AMP_10M_A] = { 0, 0, 0, 0 },
+			[TX_AMP_10M_B] = { 0, 0, 0, 0 },
+			[R50_A] = { 0, 0, 0, 0 },
+			[R50_B] = { 0, 0, 0, 0 },
+			[R50_C] = { 0, 0, 0, 0 },
+			[R50_D] = { 0, 0, 0, 0 },
+		},
+	},
+};
+
+static u8 an7583_zcal_to_r50ohm_0R[64] = {
+	127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+	127, 127, 127, 122, 118, 114, 110, 106, 102,  98,  96,  92,  88,  85,  82,  80,
+	 76,  72,  70,  68,  64,  62,  60,  57,  55,  52,  50,  48,  46,  44,  41,  40,
+	 38,  36,  33,  32,  30,  28,  26,  24,  24,  22,  20,  18,  16,  16,  14,  12,
+};
+
+static u8 an7583_zcal_to_r50ohm_5R[64] = {
+	127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+	127, 127, 127, 127, 127, 127, 127, 127, 127, 124, 120, 116, 112, 110, 106, 102,
+	 99,  96,  93,  90,  88,  84,  81,  79,  76,  73,  71,  68,  66,  64,  61,  59,
+	 56,  54,  52,  50,  48,  46,  44,  42,  40,  39,  37,  36,  33,  32,  31,  29,
+};
+
+static int airoha_cal_cycle(struct phy_device *phydev, int devad,
+			    u32 regnum, u16 mask, u16 cal_val)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	struct phy_device *phydev_p0;
+	int ret;
+
+	phydev_p0 = shared->phydev_p0;
+
+	phy_modify_mmd(phydev, devad, regnum, mask, cal_val);
+
+	ret = mtk_cal_cycle_wait(phydev_p0);
+	phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
+
+	return ret;
+}
+
+static int airoha_rext_cal_sw(struct phy_device *phydev)
+{
+	int calibration_polarity;
+	u8 zcal_ctrl = 32;
+	int first_calib;
+	int ret;
+
+	/* BG voltage output */
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x100, 0xc000);
+	/* tst_mode2 */
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xff, 0x2);
+
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xff,
+			   GENMASK(15, 4) | GENMASK(1, 0));
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN |
+		      MTK_PHY_RG_REXT_CALEN);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0);
+
+	phydev_dbg(phydev, "Start REXT SW cal.\n");
+	first_calib = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);
+
+	if (first_calib < 0) {
+		phydev_err(phydev, "REXT SW calibration failed.\n");
+		return -EINVAL;
+	}
+
+	/* If REXT calibration failed:
+	 * - increase dB until calibration succeed.
+	 * If REXT calibration succeeded:
+	 * - decrease dB until calibration fail to fine tune it.
+	 */
+	if (first_calib == 1)
+		calibration_polarity = -1;
+	else
+		calibration_polarity = 1;
+
+	while (zcal_ctrl > 0 &&
+	       zcal_ctrl < FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {
+		zcal_ctrl += calibration_polarity;
+
+		ret = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);
+		/* Exit if we either failed or succeeded compared to the
+		 * first calibration result. (aka we finished fine tuning or
+		 * we succeeded with calibration)
+		 */
+		if (ret != first_calib)
+			break;
+	}
+
+	if (ret < 0) {
+		phydev_err(phydev, "REXT SW calibration failed.\n");
+		return -EINVAL;
+	}
+
+	if (zcal_ctrl == 0 ||
+	    zcal_ctrl == FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {
+		zcal_ctrl = 32;
+		phydev_err(phydev, "REXT SW calibration saturation. Defaulting to %x.\n",
+			   zcal_ctrl);
+	}
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+		       MTK_PHY_RG_REXT_TRIM_MASK,
+		       FIELD_PREP(MTK_PHY_RG_REXT_TRIM_MASK, zcal_ctrl));
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL,
+		       MTK_PHY_RG_BG_RASEL_MASK,
+		       FIELD_PREP(MTK_PHY_RG_BG_RASEL_MASK, zcal_ctrl >> 3));
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
+
+	return 0;
+}
+
+static int airoha_tx_offset_cal_sw(struct phy_device *phydev, u8 txg_calen_x)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	struct phy_device *phydev_p0;
+	u16 dev1e_145_tmp, bmcr_tmp;
+	int calibration_polarity;
+	u16 reg_dac1, reg_dac2;
+	int zcal_ctrl = 0;
+	int first_calib;
+	u16 reg, mask;
+	int ret;
+
+	phydev_p0 = shared->phydev_p0;
+
+	/* BG voltage output */
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0xc000);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		      MTK_PHY_RG_ANA_CALEN);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		      MTK_PHY_RG_TXVOS_CALEN);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		      MTK_PHY_RG_ANA_CALEN);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		      MTK_PHY_RG_TXVOS_CALEN);
+
+	/* Force 1G full duplex for calibration */
+	bmcr_tmp = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);
+
+	/* Force MDI */
+	dev1e_145_tmp = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x0145);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, 0x1010);
+
+	/* 1e_96[15]:bypass_tx_offset_cal, Hw bypass, Fw cal */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x96,
+		      0x8000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e,
+		      0xf808);
+
+	switch (txg_calen_x) {
+	case PAIR_A:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(12));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_A;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_A;
+		reg = MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B;
+		mask = MTK_PHY_CR_TX_AMP_OFFSET_A_MASK;
+		break;
+	case PAIR_B:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(8));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_B;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_B;
+		reg = MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B;
+		mask = MTK_PHY_CR_TX_AMP_OFFSET_B_MASK;
+		break;
+	case PAIR_C:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(4));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_C;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_C;
+		reg = MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D;
+		mask = MTK_PHY_CR_TX_AMP_OFFSET_C_MASK;
+		break;
+	case PAIR_D:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(0));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_D;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_D;
+		reg = MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D;
+		mask = MTK_PHY_CR_TX_AMP_OFFSET_D_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac1,
+		      0x8000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac2,
+		      0x8000);
+
+	phydev_dbg(phydev, "Start TX Offset SW cal.\n");
+
+	first_calib = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg, mask,
+				       zcal_ctrl << __ffs(mask));
+
+	/* If TX Offset calibration failed:
+	 * - increase dB until calibration succeed.
+	 * If TX Offset calibration succeeded:
+	 * - decrease dB until calibration fail to fine tune it.
+	 */
+	if (first_calib == 1)
+		calibration_polarity = -1;
+	else
+		calibration_polarity = 1;
+
+	while (zcal_ctrl > -32 && zcal_ctrl < 32) {
+		u32 val;
+
+		zcal_ctrl += calibration_polarity;
+		if (zcal_ctrl >= 0)
+			val = zcal_ctrl;
+		else
+			/* BIT(5) signal negative number for TX Offset */
+			val = BIT(5) | abs(zcal_ctrl);
+
+		ret = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg, mask,
+				       val << __ffs(mask));
+		/* Exit if we either failed or succeeded compared to the
+		 * first calibration result. (aka we finished fine tuning or
+		 * we succeeded with calibration)
+		 */
+		if (ret != first_calib)
+			break;
+	}
+
+	if (ret < 0) {
+		phydev_err(phydev, "TX Offset calibration failed.\n");
+		return -EINVAL;
+	}
+
+	if (zcal_ctrl == -32 ||
+	    zcal_ctrl == 32) {
+		zcal_ctrl = 0;
+		phydev_err(phydev, "TX Offset SW calibration saturation. Defaulting to %x.\n",
+			   zcal_ctrl);
+
+		phy_modify_mmd(phydev, MDIO_MMD_VEND1, reg, mask,
+			       zcal_ctrl << __ffs(mask));
+	}
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x100, 0x0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D, 0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x96, 0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, 0);
+
+	/* Restore BMCR */
+	phy_write(phydev, MII_BMCR, bmcr_tmp);
+
+	/* Restore MDI */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, dev1e_145_tmp);
+
+	return 0;
+}
+
+static int airoha_tx_amp_cal_sw(struct phy_device *phydev, u8 txg_calen_x)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	u16 mask_gbe, mask_tbt, mask_tst, mask_hbt;
+	u16 reg, reg_100, reg_dac1, reg_dac2;
+	struct phy_device *phydev_p0;
+	int calibration_polarity;
+	u8 zcal_ctrl = 32;
+	int first_calib;
+	int ret;
+
+	phydev_p0 = shared->phydev_p0;
+
+	/* BG voltage output */
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0xc000);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x145, 0x1010);
+
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		      MTK_PHY_RG_TXVOS_CALEN);
+
+	/* select 1V */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x10);
+
+	/* enable Tx VLD*/
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xf808);
+
+	/* Force 1G full duplex for calibration */
+	phy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);
+
+	switch (txg_calen_x) {
+	case PAIR_A:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(12));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_A;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_A;
+		reg = MTK_PHY_TXVLD_DA_RG;
+		mask_gbe = MTK_PHY_DA_TX_I2MPB_A_GBE_MASK;
+		mask_tbt = MTK_PHY_DA_TX_I2MPB_A_TBT_MASK;
+		reg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_A2;
+		mask_hbt = MTK_PHY_DA_TX_I2MPB_A_HBT_MASK;
+		mask_tst = MTK_PHY_DA_TX_I2MPB_A_TST_MASK;
+		break;
+	case PAIR_B:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(8));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_B;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_B;
+		reg = MTK_PHY_TX_I2MPB_TEST_MODE_B1;
+		mask_gbe = MTK_PHY_DA_TX_I2MPB_B_GBE_MASK;
+		mask_tbt = MTK_PHY_DA_TX_I2MPB_B_TBT_MASK;
+		reg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_B2;
+		mask_hbt = MTK_PHY_DA_TX_I2MPB_B_HBT_MASK;
+		mask_tst = MTK_PHY_DA_TX_I2MPB_B_TST_MASK;
+		break;
+	case PAIR_C:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(4));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_C;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_C;
+		reg = MTK_PHY_TX_I2MPB_TEST_MODE_C1;
+		mask_gbe = MTK_PHY_DA_TX_I2MPB_C_GBE_MASK;
+		mask_tbt = MTK_PHY_DA_TX_I2MPB_C_TBT_MASK;
+		reg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_C2;
+		mask_hbt = MTK_PHY_DA_TX_I2MPB_C_HBT_MASK;
+		mask_tst = MTK_PHY_DA_TX_I2MPB_C_TST_MASK;
+		break;
+	case PAIR_D:
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(0));
+		reg_dac1 = MTK_PHY_RG_DASN_DAC_IN0_D;
+		reg_dac2 = MTK_PHY_RG_DASN_DAC_IN1_D;
+		reg = MTK_PHY_TX_I2MPB_TEST_MODE_D1;
+		mask_gbe = MTK_PHY_DA_TX_I2MPB_D_GBE_MASK;
+		mask_tbt = MTK_PHY_DA_TX_I2MPB_D_TBT_MASK;
+		reg_100 = MTK_PHY_TX_I2MPB_TEST_MODE_D2;
+		mask_hbt = MTK_PHY_DA_TX_I2MPB_D_HBT_MASK;
+		mask_tst = MTK_PHY_DA_TX_I2MPB_D_TST_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac1,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, reg_dac2,
+		      0x8000 | 0xf0);
+
+	phydev_dbg(phydev, "Start TX Amp SW cal.\n");
+	first_calib = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg,
+				       mask_gbe, zcal_ctrl << __ffs(mask_gbe));
+
+	/* If TX Amp calibration failed:
+	 * - increase dB until calibration succeed.
+	 * If TX Amp calibration succeeded:
+	 * - decrease dB until calibration fail to fine tune it.
+	 */
+	if (first_calib == 1)
+		calibration_polarity = -1;
+	else
+		calibration_polarity = 1;
+
+	while (zcal_ctrl > 0 &&
+	       zcal_ctrl < FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {
+		zcal_ctrl += calibration_polarity;
+
+		ret = airoha_cal_cycle(phydev, MDIO_MMD_VEND1, reg,
+				       mask_gbe, zcal_ctrl << __ffs(mask_gbe));
+		/* Exit if we either failed or succeeded compared to the
+		 * first calibration result. (aka we finished fine tuning or
+		 * we succeeded with calibration)
+		 */
+		if (ret != first_calib)
+			break;
+	}
+
+	if (ret < 0) {
+		phydev_err(phydev, "TX AMP calibration failed.\n");
+		phy_modify_mmd(phydev, MDIO_MMD_VEND1, reg,
+			       mask_gbe | mask_tbt,
+			       (zcal_ctrl << __ffs(mask_gbe)) |
+			       (zcal_ctrl << __ffs(mask_tbt)));
+
+		return -EINVAL;
+	}
+
+	if (zcal_ctrl == 0 ||
+	    zcal_ctrl == FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK))
+		phydev_warn(phydev, "TX AMP SW calibration saturation.\n");
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, reg,
+		       mask_gbe | mask_tbt,
+		       (zcal_ctrl << __ffs(mask_gbe)) |
+		       (zcal_ctrl << __ffs(mask_tbt)));
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, reg_100,
+		       mask_hbt | mask_tst,
+		       (zcal_ctrl << __ffs(mask_hbt)) |
+		       (zcal_ctrl << __ffs(mask_tst)));
+
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0x0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D, 0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, 0x145, 0x1000);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, 0);
+
+	/* Restore AN enable */
+	phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
+
+	return 0;
+}
+
+static int airoha_tx_r50_cal_sw(struct phy_device *phydev, u8 txg_calen_x)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	struct phy_device *phydev_p0;
+	u16 dev1e_145_tmp, bmcr_tmp;
+	int calibration_polarity;
+	u8 zcal_ctrl = 32;
+	int first_calib;
+	u16 reg;
+	int ret;
+
+	phydev_p0 = shared->phydev_p0;
+
+	/* BG voltage output */
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0xc000);
+
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	/* select 1V */
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x10);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		      MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	/* select 1V */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x10);
+
+	/* Force 1G full duplex for calibration */
+	bmcr_tmp = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);
+
+	/* Force MDI */
+	dev1e_145_tmp = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x0145);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, 0x1010);
+
+	/* disable tx slew control */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0185, 0x0000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00fb, 0x0100);
+
+	switch (txg_calen_x) {
+	case PAIR_A:
+		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+				 MTK_PHY_RG_ANA_CAL_RG0,
+				 MTK_PHY_RG_ZCALEN_A);
+		break;
+	case PAIR_B:
+		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+				 MTK_PHY_RG_ANA_CAL_RG1,
+				 MTK_PHY_RG_ZCALEN_B);
+		break;
+	case PAIR_C:
+		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+				 MTK_PHY_RG_ANA_CAL_RG1,
+				 MTK_PHY_RG_ZCALEN_C);
+		break;
+	case PAIR_D:
+		phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+				 MTK_PHY_RG_ANA_CAL_RG1,
+				 MTK_PHY_RG_ZCALEN_D);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	phydev_dbg(phydev, "Start TX r50 SW cal.\n");
+	first_calib = airoha_cal_cycle(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);
+
+	if (first_calib < 0) {
+		phydev_err(phydev, "TX r50 SW calibration failed.\n");
+		return -EINVAL;
+	}
+
+	/* If TX r50 calibration failed:
+	 * - increase dB until calibration succeed.
+	 * If TX r50 calibration succeeded:
+	 * - decrease dB until calibration fail to fine tune it.
+	 */
+	if (first_calib == 1)
+		calibration_polarity = -1;
+	else
+		calibration_polarity = 1;
+
+	while (zcal_ctrl > 0 &&
+	       zcal_ctrl < FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK)) {
+		zcal_ctrl += calibration_polarity;
+
+		ret = airoha_cal_cycle(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				       MTK_PHY_RG_REXT_ZCAL_CTRL_MASK, zcal_ctrl);
+		/* Exit if we either failed or succeeded compared to the
+		 * first calibration result. (aka we finished fine tuning or
+		 * we succeeded with calibration)
+		 */
+		if (ret != first_calib)
+			break;
+	}
+
+	if (ret < 0) {
+		phydev_err(phydev, "TX r50 SW calibration failed.\n");
+		return -EINVAL;
+	}
+
+	if (zcal_ctrl == 0 ||
+	    zcal_ctrl == FIELD_MAX(MTK_PHY_RG_REXT_ZCAL_CTRL_MASK))
+		phydev_warn(phydev, "TX r50 SW calibration saturation.\n");
+
+	zcal_ctrl = shared->r50_cal_tbl[zcal_ctrl];
+
+	switch (txg_calen_x) {
+	case PAIR_A:
+		reg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_A_MASK, zcal_ctrl);
+		phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			       MTK_PHY_RG_CR_TX_R50_OFFSET_A_B,
+			       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_A_MASK, reg);
+		break;
+	case PAIR_B:
+		reg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_B_MASK, zcal_ctrl);
+		phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			       MTK_PHY_RG_CR_TX_R50_OFFSET_A_B,
+			       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_B_MASK, reg);
+		break;
+	case PAIR_C:
+		reg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_C_MASK, zcal_ctrl);
+		phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			       MTK_PHY_RG_CR_TX_R50_OFFSET_C_D,
+			       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_C_MASK, reg);
+		break;
+	case PAIR_D:
+		reg = BIT(7) | FIELD_PREP(MTK_PHY_CR_TX_R50_OFFSET_D_MASK, zcal_ctrl);
+		phy_modify_mmd(phydev, MDIO_MMD_VEND1,
+			       MTK_PHY_RG_CR_TX_R50_OFFSET_C_D,
+			       BIT(7) | MTK_PHY_CR_TX_R50_OFFSET_D_MASK, reg);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, 0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, 0);
+
+	/* Enable tx slew control */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0185, 0x0001);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00fb, 0x0000);
+
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0x0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x0);
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG6, 0x0);
+
+	/* Restore BMCR */
+	phy_write(phydev, MII_BMCR, bmcr_tmp);
+
+	/* Restore MDI */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0145, dev1e_145_tmp);
+
+	return 0;
+}
+
+static int airoha_rx_offset_cal_sw(struct phy_device *phydev)
+{
+	/* Hw bypass, Fw cal */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x96, 0x8000);
+	/* tx/rx_cal_criteria_value */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x37, 0x0033);
+
+	/* rx offset cal by Hw setup */
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0x39,
+			   BIT(14) | BIT(11));
+
+	/* disable rtune calibration */
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0x107,
+			   BIT(12));
+
+	/* bypass tx/rx dc offset cancellation process */
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, 0x171,
+			 BIT(8) | BIT(7));
+
+	/* rx offset calibration start */
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, 0x39,
+			 BIT(13));
+
+	/* rx offset calibration stop */
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0x39,
+			   BIT(13));
+
+	mdelay(10);
+
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0x171,
+			   BIT(8) | BIT(7));
+
+	if (phydev->drv->phy_id == AIROHA_GPHY_ID_AN7581)
+		phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			      MTK_PHY_RG_ANA_CAL_RG6, 0x1);
+
+	return 0;
+}
+
+static int airoha_cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item,
+			 u8 start_pair, u8 end_pair)
+{
+	u8 pair_n;
+	int ret;
+
+	for (pair_n = start_pair; pair_n <= end_pair; pair_n++) {
+		switch (cal_item) {
+		case REXT:
+			ret = airoha_rext_cal_sw(phydev);
+			break;
+		case TX_OFFSET:
+			ret = airoha_tx_offset_cal_sw(phydev, pair_n);
+			break;
+		case TX_AMP:
+			ret = airoha_tx_amp_cal_sw(phydev, pair_n);
+			break;
+		case TX_R50:
+			ret = airoha_tx_r50_cal_sw(phydev, pair_n);
+			break;
+		case RX_OFFSET:
+			ret = airoha_rx_offset_cal_sw(phydev);
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int airoha_start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item,
+			    enum CAL_MODE cal_mode, u8 start_pair,
+			    u8 end_pair, u32 *buf)
+{
+	int ret;
+
+	switch (cal_mode) {
+	case SW_M:
+		ret = airoha_cal_sw(phydev, cal_item, start_pair, end_pair);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret) {
+		phydev_err(phydev, "cal %d failed\n", cal_item);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int airoha_phy_calib(struct phy_device *phydev)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	struct phy_device *phydev_p0;
+	int ret;
+
+	phydev_p0 = shared->phydev_p0;
+
+	/* PreCalibrate Set */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x5c, 0x6666);
+
+	if (!shared->rext_sw_calib_done) {
+		ret = airoha_start_cal(phydev, REXT, SW_M, NO_PAIR, NO_PAIR, NULL);
+		if (ret)
+			return ret;
+
+		shared->rext_sw_calib_done = true;
+	}
+
+	ret = airoha_start_cal(phydev, TX_R50, SW_M, PAIR_A, PAIR_D, NULL);
+	if (ret)
+		return ret;
+
+	ret = airoha_start_cal(phydev, TX_OFFSET, SW_M, PAIR_A, PAIR_D, NULL);
+	if (ret)
+		return ret;
+
+	ret = airoha_start_cal(phydev, TX_AMP, SW_M, PAIR_A, PAIR_D, NULL);
+	if (ret)
+		return ret;
+
+	ret = airoha_start_cal(phydev, RX_OFFSET, SW_M, NO_PAIR, NO_PAIR, NULL);
+	if (ret)
+		return ret;
+
+	/* Gating, short with other pair */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x15, 0x0);
+
+	phy_write_mmd(phydev_p0, MDIO_MMD_VEND2, 0x100, 0x0);
+
+	return 0;
+}
+
+static int airoha_phy_auto_select_transformer(struct phy_device *phydev)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	struct phy_device *phydev_p0;
+	u8 phy_offset;
+	u16 bmcr_tmp;
+	u16 val;
+	int i;
+
+	phydev_p0 = shared->phydev_p0;
+	phy_offset = phydev->mdio.addr - phydev_p0->mdio.addr;
+
+	/* Force 1G full duplex for calibration */
+	bmcr_tmp = phy_read(phydev, MII_BMCR);
+	phy_write(phydev, MII_BMCR, BMCR_FULLDPLX | BMCR_SPEED1000);
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, 0x271, GENMASK(4, 0),
+		       FIELD_PREP(GENMASK(4, 0), 0x3));
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, 0x269, GENMASK(15, 12),
+		       FIELD_PREP(GENMASK(15, 12), 0x2));
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, 0x26f, GENMASK(14, 12),
+		       FIELD_PREP(GENMASK(14, 12), 0x0));
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, BIT(12));
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D,
+		      0x8000 | 0xf0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D,
+		      0x8000 | 0xf0);
+
+	/* Force pGA gain */
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+	__mtk_tr_modify(phydev, 0x1, 0xf, 0x10,
+			GENMASK(20, 15),
+			FIELD_PREP(GENMASK(20, 15), 0x1f));
+
+	__mtk_tr_modify(phydev, 0x1, 0xf, 0x11,
+			GENMASK(23, 18) | GENMASK(15, 10) | GENMASK(7, 2),
+			FIELD_PREP(GENMASK(23, 18), 0x1f) |
+			FIELD_PREP(GENMASK(15, 10), 0x1f) |
+			FIELD_PREP(GENMASK(7, 2), 0x1f));
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xc9, 0xffff);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x151, 0x12);
+
+	switch (phy_offset) {
+	case 0:
+		val = 0x1;
+		break;
+	case 1:
+		val = 0x3;
+		break;
+	case 2:
+		val = 0x5;
+		break;
+	case 3:
+		val = 0x7;
+		break;
+	default:
+		return -EINVAL;
+	}
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x15,
+		      FIELD_PREP(GENMASK(14, 12), val) | 0x161);
+	mdelay(500);
+
+	for (i = 0; i < 3; i++)
+		val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0x1a);
+
+	/* Check the value and report transformer type for later */
+	shared->transformer_type[phy_offset] = val < 0xe0;
+
+	/* Switch to Default */
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x15, 0x1000);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xdd, 0x0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_A,
+		      0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_A,
+		      0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_B,
+		      0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_B,
+		      0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_C,
+		      0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_C,
+		      0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN0_D,
+		      0x0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DASN_DAC_IN1_D,
+		      0x0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xc9, 0xfff);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x151, 0x0);
+
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+	__mtk_tr_modify(phydev, 0x1, 0xf, 0x10,
+			GENMASK(20, 15),
+			FIELD_PREP(GENMASK(20, 15), 0x4));
+
+	__mtk_tr_modify(phydev, 0x1, 0xf, 0x11,
+			GENMASK(23, 18) | GENMASK(15, 10) | GENMASK(7, 2),
+			FIELD_PREP(GENMASK(23, 18), 0x0) |
+			FIELD_PREP(GENMASK(15, 10), 0x0) |
+			FIELD_PREP(GENMASK(7, 2), 0x0));
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+	/* Restore BMCR */
+	phy_write(phydev, MII_BMCR, bmcr_tmp);
+
+	return 0;
+}
+
+static int airoha_phy_tx_amp_compensation(struct phy_device *phydev)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+
+	u16 reg_1e_12_read;
+	u16 reg_1e_16_read;
+	u16 reg_1e_17_read;
+	u16 reg_1e_18_read;
+	u16 reg_1e_19_read;
+	u16 reg_1e_20_read;
+	u16 reg_1e_21_read;
+	u16 reg_1e_22_read;
+	u16 reg_1e_174_read;
+	u16 reg_1e_175_read;
+
+	int reg_1e_12_header;
+	int reg_1e_16_header;
+	int reg_1e_17_header;
+	int reg_1e_18_header;
+	int reg_1e_19_header;
+	int reg_1e_21_header;
+	int reg_1e_174_header;
+	int reg_1e_175_header;
+
+	int reg_1e_12_end;
+	int reg_1e_16_end;
+	int reg_1e_17_end;
+	int reg_1e_18_end;
+	int reg_1e_20_end;
+	int reg_1e_22_end;
+	int reg_1e_174_end;
+	int reg_1e_175_end;
+
+	struct phy_device *phydev_p0;
+	u8 phy_offset;
+
+	int txamp_low_limit = -3;
+	int txamp_high_limit = 0x42;
+
+	int r50_low_limit = -8;
+	int r50_high_limit = 0x88;
+
+	bool overflow;
+	int (*tx_amp_table)[CALIB_CONST_TYPE_MAX][4];
+	int transformer_type, mdi_resister_type;
+
+	phydev_p0 = shared->phydev_p0;
+	phy_offset = phydev->mdio.addr - phydev_p0->mdio.addr;
+
+	transformer_type = shared->transformer_type[phy_offset];
+	mdi_resister_type = shared->mdi_resister_type;
+	tx_amp_table = shared->tx_amp_compensation_tbl[transformer_type][mdi_resister_type];
+
+	reg_1e_12_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x12);
+	reg_1e_16_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x16);
+	reg_1e_17_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x17);
+	reg_1e_18_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x18);
+	reg_1e_19_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x19);
+	reg_1e_20_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x20);
+	reg_1e_21_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x21);
+	reg_1e_22_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x22);
+	reg_1e_174_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x174);
+	reg_1e_175_read = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x175);
+
+	reg_1e_12_header = ((reg_1e_12_read & 0xfc00) / 1024) + *tx_amp_table[TX_AMP_1G_A][phy_offset];
+	reg_1e_17_header = ((reg_1e_17_read & 0x3f00) / 256) + *tx_amp_table[TX_AMP_1G_B][phy_offset];
+	reg_1e_19_header = ((reg_1e_19_read & 0x3f00) / 256) + *tx_amp_table[TX_AMP_1G_C][phy_offset];
+	reg_1e_21_header = ((reg_1e_21_read & 0x3f00) / 256) + *tx_amp_table[TX_AMP_1G_D][phy_offset];
+
+	overflow = false;
+	if (reg_1e_12_header < txamp_low_limit ||
+	    reg_1e_12_header > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_17_header < txamp_low_limit ||
+	    reg_1e_17_header > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_19_header < txamp_low_limit ||
+	    reg_1e_19_header > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_21_header < txamp_low_limit ||
+	    reg_1e_21_header > txamp_high_limit)
+		overflow = true;
+
+	if (overflow) {
+		reg_1e_12_header = 0x20;
+		reg_1e_17_header = 0x20;
+		reg_1e_19_header = 0x20;
+		reg_1e_21_header = 0x20;
+	} else {
+		if (reg_1e_12_header < 0)
+			reg_1e_12_header = 0;
+		else if (reg_1e_12_header > 0x3f)
+			reg_1e_12_header = 0x3f;
+		if (reg_1e_17_header < 0)
+			reg_1e_17_header = 0;
+		else if (reg_1e_17_header > 0x3f)
+			reg_1e_17_header = 0x3f;
+		if (reg_1e_19_header < 0)
+			reg_1e_19_header = 0;
+		else if (reg_1e_19_header > 0x3f)
+			reg_1e_19_header = 0x3f;
+		if (reg_1e_21_header < 0)
+			reg_1e_21_header = 0;
+		else if (reg_1e_21_header > 0x3f)
+			reg_1e_21_header = 0x3f;
+	}
+
+	reg_1e_16_end = (reg_1e_16_read & 0x003f) + *tx_amp_table[TX_AMP_TEST_A][phy_offset];
+	reg_1e_18_end = (reg_1e_18_read & 0x003f) + *tx_amp_table[TX_AMP_TEST_B][phy_offset];
+	reg_1e_20_end = (reg_1e_20_read & 0x003f) + *tx_amp_table[TX_AMP_TEST_C][phy_offset];
+	reg_1e_22_end = (reg_1e_22_read & 0x003f) + *tx_amp_table[TX_AMP_TEST_D][phy_offset];
+
+	overflow = false;
+	if (reg_1e_16_end < txamp_low_limit ||
+	    reg_1e_16_end > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_18_end < txamp_low_limit ||
+	    reg_1e_18_end > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_20_end < txamp_low_limit ||
+	    reg_1e_20_end > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_22_end < txamp_low_limit ||
+	    reg_1e_22_end > txamp_high_limit)
+		overflow = true;
+
+	if (overflow) {
+		reg_1e_16_end = 0x20;
+		reg_1e_18_end = 0x20;
+		reg_1e_20_end = 0x20;
+		reg_1e_22_end = 0x20;
+	} else {
+		if (reg_1e_16_end < 0)
+			reg_1e_16_end = 0;
+		else if (reg_1e_16_end > 0x3f)
+			reg_1e_16_end = 0x3f;
+		if (reg_1e_18_end < 0)
+			reg_1e_18_end = 0;
+		else if (reg_1e_18_end > 0x3f)
+			reg_1e_18_end = 0x3f;
+		if (reg_1e_20_end < 0)
+			reg_1e_20_end = 0;
+		else if (reg_1e_20_end > 0x3f)
+			reg_1e_20_end = 0x3f;
+		if (reg_1e_22_end < 0)
+			reg_1e_22_end = 0;
+		else if (reg_1e_22_end > 0x3f)
+			reg_1e_22_end = 0x3f;
+	}
+
+	reg_1e_16_header = ((reg_1e_16_read & 0xfc00) / 1024) + *tx_amp_table[TX_AMP_100M_A][phy_offset];
+	reg_1e_18_header = ((reg_1e_18_read & 0x3f00) / 256) + *tx_amp_table[TX_AMP_100M_B][phy_offset];
+
+	overflow = false;
+	if (reg_1e_16_header < txamp_low_limit ||
+	    reg_1e_16_header > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_18_header < txamp_low_limit ||
+	    reg_1e_18_header > txamp_high_limit)
+		overflow = true;
+
+	if (overflow) {
+		reg_1e_16_header = 0x20;
+		reg_1e_18_header = 0x20;
+	} else {
+		if (reg_1e_16_header < 0)
+			reg_1e_16_header = 0;
+		else if (reg_1e_16_header > 0x3f)
+			reg_1e_16_header = 0x3f;
+		if (reg_1e_18_header < 0)
+			reg_1e_18_header = 0;
+		else if (reg_1e_18_header > 0x3f)
+			reg_1e_18_header = 0x3f;
+	}
+
+	reg_1e_12_end = (reg_1e_12_read & 0x003f) + *tx_amp_table[TX_AMP_10M_A][phy_offset];
+	reg_1e_17_end = (reg_1e_17_read & 0x003f) + *tx_amp_table[TX_AMP_10M_B][phy_offset];
+
+	overflow = false;
+	if (reg_1e_12_end < txamp_low_limit ||
+	    reg_1e_12_end > txamp_high_limit)
+		overflow = true;
+	if (reg_1e_17_end < txamp_low_limit ||
+	    reg_1e_17_end > txamp_high_limit)
+		overflow = true;
+
+	if (overflow) {
+		reg_1e_12_end = 0x20;
+		reg_1e_17_end = 0x20;
+	} else {
+		if (reg_1e_12_end < 0)
+			reg_1e_12_end = 0;
+		else if (reg_1e_12_end > 0x3f)
+			reg_1e_12_end = 0x3f;
+		if (reg_1e_17_end < 0)
+			reg_1e_17_end = 0;
+		else if (reg_1e_17_end > 0x3f)
+			reg_1e_17_end = 0x3f;
+	}
+
+	reg_1e_174_header = ((reg_1e_174_read & 0x7f00) / 256) + *tx_amp_table[R50_A][phy_offset];
+	reg_1e_174_end = (reg_1e_174_read & 0x007f) + *tx_amp_table[R50_B][phy_offset];
+	reg_1e_175_header = ((reg_1e_175_read & 0x7f00) / 256) + *tx_amp_table[R50_C][phy_offset];
+	reg_1e_175_end = (reg_1e_175_read & 0x007f) + *tx_amp_table[R50_D][phy_offset];
+
+	overflow = false;
+	if (reg_1e_174_header < r50_low_limit ||
+	    reg_1e_174_header > r50_high_limit)
+		overflow = true;
+	if (reg_1e_174_end < r50_low_limit ||
+	    reg_1e_174_end > r50_high_limit)
+		overflow = true;
+	if (reg_1e_175_header < r50_low_limit ||
+	    reg_1e_175_header > r50_high_limit)
+		overflow = true;
+	if (reg_1e_175_end < r50_low_limit ||
+	    reg_1e_175_end > r50_high_limit)
+		overflow = true;
+
+	if (overflow) {
+		reg_1e_174_header = 0x34;
+		reg_1e_174_end = 0x34;
+		reg_1e_175_header = 0x34;
+		reg_1e_175_end = 0x34;
+	} else {
+		if (reg_1e_174_header < 0)
+			reg_1e_174_header = 0;
+		else if (reg_1e_174_header > 0x7f)
+			reg_1e_174_header = 0x7f;
+		if (reg_1e_174_end < 0)
+			reg_1e_174_end = 0;
+		else if (reg_1e_174_end > 0x7f)
+			reg_1e_174_end = 0x7f;
+		if (reg_1e_175_header < 0)
+			reg_1e_175_header = 0;
+		else if (reg_1e_175_header > 0x7f)
+			reg_1e_175_header = 0x7f;
+		if (reg_1e_175_end < 0)
+			reg_1e_175_end = 0;
+		else if (reg_1e_175_end > 0x7f)
+			reg_1e_175_end = 0x7f;
+	}
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x12,
+		      (reg_1e_12_header * 1024) + reg_1e_12_end);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x16,
+		      (reg_1e_16_header * 1024) + reg_1e_16_end);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x17,
+		      (reg_1e_17_header * 256) + reg_1e_17_end);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x18,
+		      (reg_1e_18_header * 256) + reg_1e_18_end);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x19,
+		      (reg_1e_19_read & 0x00ff) + (reg_1e_19_header * 256));
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x20,
+		      (reg_1e_20_read & 0xff00) + reg_1e_20_end);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x21,
+		      (reg_1e_21_read & 0x00ff) + (reg_1e_21_header * 256));
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x22,
+		      (reg_1e_22_read & 0xff00) + reg_1e_22_end);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x174,
+		      0x8080 + (reg_1e_174_header * 256) + reg_1e_174_end);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x175,
+		      0x8080 + (reg_1e_175_header * 256) + reg_1e_175_end);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x176, 0x4400);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x177, 0x0044);
+
+	return 0;
+}
+
+static int an7581_phy_config_init(struct phy_device *phydev)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	struct phy_device *phydev_p0;
+	u32 soc_pdidr;
+	u8 phy_offset;
+	int ret;
+
+	phydev_p0 = shared->phydev_p0;
+	phy_offset = phydev->mdio.addr - phydev_p0->mdio.addr;
+
+	/* FIXME: Read SoC PDIDR if available or default to 1 */
+	soc_pdidr = 1;
+
+	shared->mdi_resister_type = MDI_5R;
+	if (soc_pdidr == 1)
+		shared->tx_amp_compensation_tbl = &an7581_tx_amp_compensation_tbl[0];
+	else
+		shared->tx_amp_compensation_tbl = &an7581_tx_amp_compensation_tbl[1];
+	shared->r50_cal_tbl = an7581_zcal_to_r45ohm;
+
+	ret = airoha_phy_calib(phydev);
+	if (ret)
+		return ret;
+
+	ret = airoha_phy_auto_select_transformer(phydev);
+	if (ret)
+		return ret;
+
+	ret = airoha_phy_tx_amp_compensation(phydev);
+	if (ret)
+		return ret;
+
+	/* RX setting for 5R_TXMR before AN setting */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe6, 0x1111);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe7, 0x5555);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe9, 0x0001);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xfe, 0x0000);
+
+	/* Long Loop Reach setting */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x11, 0xff00);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x202, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x203, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x204, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x205, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x206, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x207, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x208, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x209, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20a, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20b, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20e, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x20f, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x210, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x211, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x212, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x213, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x214, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x215, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x216, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x217, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21a, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21b, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21c, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21d, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21e, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x21f, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x220, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x221, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x222, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x223, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x226, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x227, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x228, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x229, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22a, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22b, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22c, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22d, 0x0025);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22e, 0x2310);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x22f, 0x0025);
+
+	/* RX Setting */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3c, 0xc000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3d, 0x0000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);
+
+	/* EEE setting */
+	phy_write_mmd(phydev, MDIO_MMD_AN, 0x3c, 0x0000);
+
+	/* RX */
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x41, 0x3333);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x44, 0x00c0);
+
+	/* 10M settings */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a3, 0x00d2);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a4, 0x010e);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27b, 0x1177);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27c, 0x0808);
+
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_1);
+	__phy_write(phydev, 0x14, 0x3a18);
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+	phy_write(phydev, 0x9, 0x1e00);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x269, 0x2114);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26a, 0x1113);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26f, 0x0000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x2c63);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x272, 0x0c2b);
+
+	/* EEE set because power down can't set tokenring */
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+	__mtk_tr_write(phydev, 0x0, 0x7, 0x15, 0x0055a0);
+	__mtk_tr_write(phydev, 0x0, 0x7, 0x17, 0x07ff3f);
+	__mtk_tr_write(phydev, 0x1, 0xf, 0x0, 0x00001e);
+	__mtk_tr_write(phydev, 0x1, 0xf, 0x1, 0x6fb90a);
+	__mtk_tr_write(phydev, 0x1, 0xf, 0x18, 0x0e2f00);
+	__mtk_tr_write(phydev, 0x1, 0xd, 0x26, 0x444444);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0x3, 0x000004);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0x6, 0x2ebaef);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0x8, 0x00000b);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0xc, 0x00504d);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0xd, 0x02314f);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0xf, 0x003028);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0x10, 0x00000a);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0x11, 0x040001);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0x14, 0x00024a);
+	__mtk_tr_write(phydev, 0x2, 0xd, 0x1c, 0x003210);
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x120, 0x8014);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x122, 0xffff);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x144, 0x0200);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14a, 0xee20);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x19b, 0x0111);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x234, 0x1181);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x238, 0x0120);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x239, 0x0117);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x2d1, 0x0733);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x323, 0x0011);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x324, 0x013f);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x326, 0x0037);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x268, 0x07f4);
+
+	if (shared->transformer_type[phy_offset] == TXMR) {
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0187);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cc);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0109);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x020b);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0202);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03c5);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c2);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x09, 0x0309);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x000e);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0002);
+
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0880);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0880);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0880);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0880);
+	} else {
+		if (soc_pdidr == 2) {
+			phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x269, 0x1114);
+			phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26a, 0x1113);
+			phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x26f, 0x2000);
+			phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x4c88);
+			phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x272, 0x0c2b);
+
+			/* 100M sharp */
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0190);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01c8);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c0);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0030);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0208);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0000);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0318);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03c8);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c0);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x09, 0x0230);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x0008);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0200);
+
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0885);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0885);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0885);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0885);
+		} else {
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0190);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cf);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c0);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0030);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x020f);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0000);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0318);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03cf);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c0);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x09, 0x0230);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x000f);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0200);
+
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0003);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0003);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0003);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0003);
+		}
+	}
+
+	return 0;
+}
+
+static int an7581_phy_probe(struct phy_device *phydev)
+{
+	struct airoha_socphy_shared *shared;
+	struct mtk_socphy_priv *priv;
+	struct pinctrl *pinctrl;
+	int ret;
+
+	/* Toggle pinctrl to enable PHY LED */
+	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
+	if (IS_ERR(pinctrl))
+		dev_err(&phydev->mdio.bus->dev,
+			"Failed to setup PHY LED pinctrl\n");
+
+	ret = devm_phy_package_join(&phydev->mdio.dev, phydev, 0,
+				    sizeof(struct airoha_socphy_shared));
+	if (ret)
+		return ret;
+
+	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (phydev->mdio.addr == AIROHA_DEFAULT_PORT0_ADDR)
+		shared->phydev_p0 = phydev;
+
+	phydev->priv = priv;
+
+	return 0;
+}
+
+static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
+				       unsigned long modes)
+{
+	u16 val = 0;
+	u32 mode;
+
+	if (index >= AIROHA_PHY_MAX_LEDS)
+		return -EINVAL;
+
+	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
+		switch (mode) {
+		case PHY_LED_ACTIVE_LOW:
+			val = MTK_PHY_LED_ON_POLARITY;
+			break;
+		case PHY_LED_ACTIVE_HIGH:
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+			      MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+			      MTK_PHY_LED_ON_POLARITY, val);
+}
+
+static int an7583_phy_config_init(struct phy_device *phydev)
+{
+	struct airoha_socphy_shared *shared = phy_package_get_priv(phydev);
+	struct phy_device *phydev_p0;
+	u8 phy_offset;
+	int ret;
+
+	/* BMCR_PDOWN is enabled by default */
+	phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
+
+	phydev_p0 = shared->phydev_p0;
+	phy_offset = phydev->mdio.addr - phydev_p0->mdio.addr;
+
+	/* FIXME: Read SoC MDI Resister Type if available or default to 5R */
+	shared->mdi_resister_type = MDI_5R;
+
+	shared->mdi_resister_type = MDI_5R;
+	if (shared->mdi_resister_type == MDI_0R)
+		shared->r50_cal_tbl = an7583_zcal_to_r50ohm_0R;
+	if (shared->mdi_resister_type == MDI_5R)
+		shared->r50_cal_tbl = an7583_zcal_to_r50ohm_5R;
+	shared->tx_amp_compensation_tbl = &an7583_tx_amp_compensation_tbl;
+
+	ret = airoha_phy_calib(phydev);
+	if (ret)
+		return ret;
+
+	ret = airoha_phy_auto_select_transformer(phydev);
+	if (ret)
+		return ret;
+
+	ret = airoha_phy_tx_amp_compensation(phydev);
+	if (ret)
+		return ret;
+
+	/* Enable Idle Mode Power Setting */
+	if (phy_offset == 0) {
+		phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x268, 0x07F1);
+		phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x703, 0x3111);
+		phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x271, 0x3C24);
+		phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x701, 0x1023);
+	}
+
+	if (shared->transformer_type[phy_offset] == TXMR) {
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0881);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0881);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0881);
+		phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0881);
+
+		if (shared->mdi_resister_type == MDI_0R)
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);
+		else
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0200);
+	} else {
+		if (shared->mdi_resister_type == MDI_0R) {
+			/* RX setting for 5R_TXMR before AN setting */
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe7, 0x6666);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe9, 0x0003);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xfe, 0x0006);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xe6, 0x1111);
+			/* 100M sharp */
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0c86);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0c86);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0c86);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0c86);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cb);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0108);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0211);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03ce);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c8);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0005);
+		} else {
+			/* 100M sharp */
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x23, 0x0886);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x24, 0x0886);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x25, 0x0886);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x26, 0x0886);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x00, 0x0195);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x01, 0x01cb);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x02, 0x01c2);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x03, 0x0108);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x04, 0x0211);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x05, 0x0205);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x06, 0x0387);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x07, 0x03ce);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x08, 0x03c3);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0a, 0x0010);
+			phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x0b, 0x0005);
+		}
+	}
+
+	/* RX Setting */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3c, 0xc000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3d, 0x0000);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x3e, 0xc000);
+
+	/* EEE setting */
+	phy_write_mmd(phydev, MDIO_MMD_AN, 0x3c, 0x0000);
+
+	/* 10M settings */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a3, 0x00d2);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x1a4, 0x010e);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27b, 0x1177);
+	phy_write_mmd(phydev, MDIO_MMD_VEND2, 0x27c, 0x0808);
+
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3);
+	__phy_write(phydev, 0x14, 0x190);
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_1);
+	__phy_write(phydev, 0x14, 0x3a18);
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+	phy_write(phydev, 0x9, 0x0600);
+
+	/* EEE keep only Pair A ON */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x630, 0x006E);
+
+	return 0;
+}
+
+static struct phy_driver mtk_socphy_driver[] = {
+	{
+		PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7581),
+		.name		= "Airoha AN7581 PHY",
+		.config_init	= an7581_phy_config_init,
+		.config_intr	= genphy_no_config_intr,
+		.handle_interrupt = genphy_handle_interrupt_no_ack,
+		.probe		= an7581_phy_probe,
+		.led_blink_set	= mt798x_phy_led_blink_set,
+		.led_brightness_set = mt798x_phy_led_brightness_set,
+		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+		.led_hw_control_set = mt798x_phy_led_hw_control_set,
+		.led_hw_control_get = mt798x_phy_led_hw_control_get,
+		.led_polarity_set = an7581_phy_led_polarity_set,
+		.read_page	= mtk_phy_read_page,
+		.write_page	= mtk_phy_write_page,
+	},
+	{
+		PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7583),
+		.name		= "Airoha AN7583 PHY",
+		.config_init	= an7583_phy_config_init,
+		.probe		= an7581_phy_probe,
+		.led_blink_set	= mt798x_phy_led_blink_set,
+		.led_brightness_set = mt798x_phy_led_brightness_set,
+		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
+		.led_hw_control_set = mt798x_phy_led_hw_control_set,
+		.led_hw_control_get = mt798x_phy_led_hw_control_get,
+		.led_polarity_set = an7581_phy_led_polarity_set,
+		.read_page	= mtk_phy_read_page,
+		.write_page	= mtk_phy_write_page,
+	},
+};
+
+module_phy_driver(mtk_socphy_driver);
+
+static const struct mdio_device_id __maybe_unused airoha_socphy_tbl[] = {
+	{ PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7581) },
+	{ PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7583) },
+	{ }
+};
+
+MODULE_DESCRIPTION("Airoha SoC Gigabit Ethernet PHY driver");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("01.01.20260306");
+
+MODULE_DEVICE_TABLE(mdio, airoha_socphy_tbl);
diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c
index 9a54949644d5a5..868ae089013d3d 100644
--- a/drivers/net/phy/mediatek/mtk-ge-soc.c
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.c
@@ -11,322 +11,10 @@
 
 #include "../phylib.h"
 #include "mtk.h"
+#include "mtk-ge-soc.h"
 
 #define MTK_PHY_MAX_LEDS			2
 
-#define MTK_GPHY_ID_MT7981			0x03a29461
-#define MTK_GPHY_ID_MT7988			0x03a29481
-#define MTK_GPHY_ID_AN7581			0x03a294c1
-#define MTK_GPHY_ID_AN7583			0xc0ff0420
-
-#define MTK_EXT_PAGE_ACCESS			0x1f
-#define MTK_PHY_PAGE_STANDARD			0x0000
-#define MTK_PHY_PAGE_EXTENDED_3			0x0003
-
-#define MTK_PHY_LPI_REG_14			0x14
-#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK	GENMASK(8, 0)
-
-#define MTK_PHY_LPI_REG_1c			0x1c
-#define MTK_PHY_SMI_DET_ON_THRESH_MASK		GENMASK(13, 8)
-
-#define MTK_PHY_PAGE_EXTENDED_2A30		0x2a30
-
-/* Registers on Token Ring debug nodes */
-/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */
-/* NormMseLoThresh */
-#define NORMAL_MSE_LO_THRESH_MASK		GENMASK(15, 8)
-
-/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
-/* RemAckCntLimitCtrl */
-#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK	GENMASK(2, 1)
-
-/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */
-/* VcoSlicerThreshBitsHigh */
-#define VCO_SLICER_THRESH_HIGH_MASK		GENMASK(23, 0)
-
-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */
-/* DfeTailEnableVgaThresh1000 */
-#define DFE_TAIL_EANBLE_VGA_TRHESH_1000		GENMASK(5, 1)
-
-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */
-/* MrvlTrFix100Kp */
-#define MRVL_TR_FIX_100KP_MASK			GENMASK(22, 20)
-/* MrvlTrFix100Kf */
-#define MRVL_TR_FIX_100KF_MASK			GENMASK(19, 17)
-/* MrvlTrFix1000Kp */
-#define MRVL_TR_FIX_1000KP_MASK			GENMASK(16, 14)
-/* MrvlTrFix1000Kf */
-#define MRVL_TR_FIX_1000KF_MASK			GENMASK(13, 11)
-
-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */
-/* VgaDecRate */
-#define VGA_DECIMATION_RATE_MASK		GENMASK(8, 5)
-
-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
-/* SlvDSPreadyTime */
-#define SLAVE_DSP_READY_TIME_MASK		GENMASK(22, 15)
-/* MasDSPreadyTime */
-#define MASTER_DSP_READY_TIME_MASK		GENMASK(14, 7)
-
-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */
-/* EnabRandUpdTrig */
-#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER	BIT(8)
-
-/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
-/* ResetSyncOffset */
-#define RESET_SYNC_OFFSET_MASK			GENMASK(11, 8)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */
-/* FfeUpdGainForceVal */
-#define FFE_UPDATE_GAIN_FORCE_VAL_MASK		GENMASK(9, 7)
-/* FfeUpdGainForce */
-#define FFE_UPDATE_GAIN_FORCE			BIT(6)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */
-/* TrFreeze */
-#define TR_FREEZE_MASK				GENMASK(11, 0)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
-/* SS: Steady-state, KP: Proportional Gain */
-/* SSTrKp100 */
-#define SS_TR_KP100_MASK			GENMASK(21, 19)
-/* SSTrKf100 */
-#define SS_TR_KF100_MASK			GENMASK(18, 16)
-/* SSTrKp1000Mas */
-#define SS_TR_KP1000_MASTER_MASK		GENMASK(15, 13)
-/* SSTrKf1000Mas */
-#define SS_TR_KF1000_MASTER_MASK		GENMASK(12, 10)
-/* SSTrKp1000Slv */
-#define SS_TR_KP1000_SLAVE_MASK			GENMASK(9, 7)
-/* SSTrKf1000Slv */
-#define SS_TR_KF1000_SLAVE_MASK			GENMASK(6, 4)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */
-/* clear this bit if wanna select from AFE */
-/* Regsigdet_sel_1000 */
-#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE	BIT(4)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
-/* RegEEE_st2TrKf1000 */
-#define EEE1000_STAGE2_TR_KF_MASK		GENMASK(13, 11)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */
-/* RegEEE_slv_waketr_timer_tar */
-#define SLAVE_WAKETR_TIMER_MASK			GENMASK(20, 11)
-/* RegEEE_slv_remtx_timer_tar */
-#define SLAVE_REMTX_TIMER_MASK			GENMASK(10, 1)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */
-/* RegEEE_slv_wake_int_timer_tar */
-#define SLAVE_WAKEINT_TIMER_MASK		GENMASK(10, 1)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */
-/* RegEEE_trfreeze_timer2 */
-#define TR_FREEZE_TIMER2_MASK			GENMASK(9, 0)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */
-/* RegEEE100Stg1_tar */
-#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK	GENMASK(8, 0)
-
-/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */
-/* REGEEE_wake_slv_tr_wait_dfesigdet_en */
-#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN	BIT(11)
-
-#define ANALOG_INTERNAL_OPERATION_MAX_US	20
-#define TXRESERVE_MIN				0
-#define TXRESERVE_MAX				7
-
-#define MTK_PHY_ANARG_RG			0x10
-#define   MTK_PHY_TCLKOFFSET_MASK		GENMASK(12, 8)
-
-/* Registers on MDIO_MMD_VEND1 */
-#define MTK_PHY_TXVLD_DA_RG			0x12
-#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK	GENMASK(15, 10)
-#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_TX_I2MPB_TEST_MODE_A2		0x16
-#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK	GENMASK(15, 10)
-#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_TX_I2MPB_TEST_MODE_B1		0x17
-#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK	GENMASK(13, 8)
-#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_TX_I2MPB_TEST_MODE_B2		0x18
-#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK	GENMASK(13, 8)
-#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_TX_I2MPB_TEST_MODE_C1		0x19
-#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK	GENMASK(13, 8)
-#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_TX_I2MPB_TEST_MODE_C2		0x20
-#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK	GENMASK(13, 8)
-#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_TX_I2MPB_TEST_MODE_D1		0x21
-#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK	GENMASK(13, 8)
-#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_TX_I2MPB_TEST_MODE_D2		0x22
-#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK	GENMASK(13, 8)
-#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK	GENMASK(5, 0)
-
-#define MTK_PHY_RXADC_CTRL_RG7			0xc6
-#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK	GENMASK(9, 8)
-
-#define MTK_PHY_RXADC_CTRL_RG9			0xc8
-#define   MTK_PHY_DA_RX_PSBN_TBT_MASK		GENMASK(14, 12)
-#define   MTK_PHY_DA_RX_PSBN_HBT_MASK		GENMASK(10, 8)
-#define   MTK_PHY_DA_RX_PSBN_GBE_MASK		GENMASK(6, 4)
-#define   MTK_PHY_DA_RX_PSBN_LP_MASK		GENMASK(2, 0)
-
-#define MTK_PHY_LDO_OUTPUT_V			0xd7
-
-#define MTK_PHY_RG_ANA_CAL_RG0			0xdb
-#define   MTK_PHY_RG_CAL_CKINV			BIT(12)
-#define   MTK_PHY_RG_ANA_CALEN			BIT(8)
-#define   MTK_PHY_RG_ZCALEN_A			BIT(0)
-
-#define MTK_PHY_RG_ANA_CAL_RG1			0xdc
-#define   MTK_PHY_RG_ZCALEN_B			BIT(12)
-#define   MTK_PHY_RG_ZCALEN_C			BIT(8)
-#define   MTK_PHY_RG_ZCALEN_D			BIT(4)
-#define   MTK_PHY_RG_TXVOS_CALEN		BIT(0)
-
-#define MTK_PHY_RG_ANA_CAL_RG5			0xe0
-#define   MTK_PHY_RG_REXT_TRIM_MASK		GENMASK(13, 8)
-
-#define MTK_PHY_RG_TX_FILTER			0xfe
-
-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120	0x120
-#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK	GENMASK(12, 8)
-#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK	GENMASK(4, 0)
-
-#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122	0x122
-#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK	GENMASK(7, 0)
-
-#define MTK_PHY_RG_TESTMUX_ADC_CTRL		0x144
-#define   MTK_PHY_RG_TXEN_DIG_MASK		GENMASK(5, 5)
-
-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B		0x172
-#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK	GENMASK(13, 8)
-#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK	GENMASK(6, 0)
-
-#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D		0x173
-#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK	GENMASK(13, 8)
-#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK	GENMASK(6, 0)
-
-#define MTK_PHY_RG_AD_CAL_COMP			0x17a
-#define   MTK_PHY_AD_CAL_COMP_OUT_MASK		GENMASK(8, 8)
-
-#define MTK_PHY_RG_AD_CAL_CLK			0x17b
-#define   MTK_PHY_DA_CAL_CLK			BIT(0)
-
-#define MTK_PHY_RG_AD_CALIN			0x17c
-#define   MTK_PHY_DA_CALIN_FLAG			BIT(0)
-
-#define MTK_PHY_RG_DASN_DAC_IN0_A		0x17d
-#define   MTK_PHY_DASN_DAC_IN0_A_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DASN_DAC_IN0_B		0x17e
-#define   MTK_PHY_DASN_DAC_IN0_B_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DASN_DAC_IN0_C		0x17f
-#define   MTK_PHY_DASN_DAC_IN0_C_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DASN_DAC_IN0_D		0x180
-#define   MTK_PHY_DASN_DAC_IN0_D_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DASN_DAC_IN1_A		0x181
-#define   MTK_PHY_DASN_DAC_IN1_A_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DASN_DAC_IN1_B		0x182
-#define   MTK_PHY_DASN_DAC_IN1_B_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DASN_DAC_IN1_C		0x183
-#define   MTK_PHY_DASN_DAC_IN1_C_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DASN_DAC_IN1_D		0x184
-#define   MTK_PHY_DASN_DAC_IN1_D_MASK		GENMASK(9, 0)
-
-#define MTK_PHY_RG_DEV1E_REG19b			0x19b
-#define   MTK_PHY_BYPASS_DSP_LPI_READY		BIT(8)
-
-#define MTK_PHY_RG_LP_IIR2_K1_L			0x22a
-#define MTK_PHY_RG_LP_IIR2_K1_U			0x22b
-#define MTK_PHY_RG_LP_IIR2_K2_L			0x22c
-#define MTK_PHY_RG_LP_IIR2_K2_U			0x22d
-#define MTK_PHY_RG_LP_IIR2_K3_L			0x22e
-#define MTK_PHY_RG_LP_IIR2_K3_U			0x22f
-#define MTK_PHY_RG_LP_IIR2_K4_L			0x230
-#define MTK_PHY_RG_LP_IIR2_K4_U			0x231
-#define MTK_PHY_RG_LP_IIR2_K5_L			0x232
-#define MTK_PHY_RG_LP_IIR2_K5_U			0x233
-
-#define MTK_PHY_RG_DEV1E_REG234			0x234
-#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK		GENMASK(0, 0)
-#define   MTK_PHY_LPF_X_AVERAGE_MASK		GENMASK(7, 4)
-#define   MTK_PHY_TR_LP_IIR_EEE_EN		BIT(12)
-
-#define MTK_PHY_RG_LPF_CNT_VAL			0x235
-
-#define MTK_PHY_RG_DEV1E_REG238			0x238
-#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK	GENMASK(8, 0)
-#define   MTK_PHY_LPI_SLV_SEND_TX_EN		BIT(12)
-
-#define MTK_PHY_RG_DEV1E_REG239			0x239
-#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK	GENMASK(8, 0)
-#define   MTK_PHY_LPI_TXPCS_LOC_RCV		BIT(12)
-
-#define MTK_PHY_RG_DEV1E_REG27C			0x27c
-#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK	GENMASK(12, 8)
-#define MTK_PHY_RG_DEV1E_REG27D			0x27d
-#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK	GENMASK(4, 0)
-
-#define MTK_PHY_RG_DEV1E_REG2C7			0x2c7
-#define   MTK_PHY_MAX_GAIN_MASK			GENMASK(4, 0)
-#define   MTK_PHY_MIN_GAIN_MASK			GENMASK(12, 8)
-
-#define MTK_PHY_RG_DEV1E_REG2D1			0x2d1
-#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK	GENMASK(7, 0)
-#define   MTK_PHY_LPI_SKIP_SD_SLV_TR		BIT(8)
-#define   MTK_PHY_LPI_TR_READY			BIT(9)
-#define   MTK_PHY_LPI_VCO_EEE_STG0_EN		BIT(10)
-
-#define MTK_PHY_RG_DEV1E_REG323			0x323
-#define   MTK_PHY_EEE_WAKE_MAS_INT_DC		BIT(0)
-#define   MTK_PHY_EEE_WAKE_SLV_INT_DC		BIT(4)
-
-#define MTK_PHY_RG_DEV1E_REG324			0x324
-#define   MTK_PHY_SMI_DETCNT_MAX_MASK		GENMASK(5, 0)
-#define   MTK_PHY_SMI_DET_MAX_EN		BIT(8)
-
-#define MTK_PHY_RG_DEV1E_REG326			0x326
-#define   MTK_PHY_LPI_MODE_SD_ON		BIT(0)
-#define   MTK_PHY_RESET_RANDUPD_CNT		BIT(1)
-#define   MTK_PHY_TREC_UPDATE_ENAB_CLR		BIT(2)
-#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF	BIT(4)
-#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP	BIT(5)
-
-#define MTK_PHY_LDO_PUMP_EN_PAIRAB		0x502
-#define MTK_PHY_LDO_PUMP_EN_PAIRCD		0x503
-
-#define MTK_PHY_DA_TX_R50_PAIR_A		0x53d
-#define MTK_PHY_DA_TX_R50_PAIR_B		0x53e
-#define MTK_PHY_DA_TX_R50_PAIR_C		0x53f
-#define MTK_PHY_DA_TX_R50_PAIR_D		0x540
-
-/* Registers on MDIO_MMD_VEND2 */
-#define MTK_PHY_LED1_DEFAULT_POLARITIES		BIT(1)
-
-#define MTK_PHY_RG_BG_RASEL			0x115
-#define   MTK_PHY_RG_BG_RASEL_MASK		GENMASK(2, 0)
-
-/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
-#define RG_GPIO_MISC_TPBANK0			0x6f0
-#define   RG_GPIO_MISC_TPBANK0_BOOTMODE		GENMASK(11, 8)
-
 /* These macro privides efuse parsing for internal phy. */
 #define EFS_DA_TX_I2MPB_A(x)			(((x) >> 0) & GENMASK(5, 0))
 #define EFS_DA_TX_I2MPB_B(x)			(((x) >> 6) & GENMASK(5, 0))
@@ -346,51 +34,16 @@
 #define EFS_RG_BG_RASEL(x)			(((x) >> 4) & GENMASK(2, 0))
 #define EFS_RG_REXT_TRIM(x)			(((x) >> 7) & GENMASK(5, 0))
 
-enum {
-	NO_PAIR,
-	PAIR_A,
-	PAIR_B,
-	PAIR_C,
-	PAIR_D,
-};
-
-enum calibration_mode {
-	EFUSE_K,
-	SW_K
-};
-
-enum CAL_ITEM {
-	REXT,
-	TX_OFFSET,
-	TX_AMP,
-	TX_R50,
-	TX_VCM
-};
-
-enum CAL_MODE {
-	EFUSE_M,
-	SW_M
-};
-
 struct mtk_socphy_shared {
 	u32			boottrap;
 	struct mtk_socphy_priv	priv[4];
 };
 
-/* One calibration cycle consists of:
- * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
- *   until AD_CAL_COMP is ready to output calibration result.
- * 2.Wait until DA_CAL_CLK is available.
- * 3.Fetch AD_CAL_COMP_OUT.
- */
-static int cal_cycle(struct phy_device *phydev, int devad,
-		     u32 regnum, u16 mask, u16 cal_val)
+int mtk_cal_cycle_wait(struct phy_device *phydev)
 {
 	int reg_val;
 	int ret;
 
-	phy_modify_mmd(phydev, devad, regnum,
-		       mask, cal_val);
 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN,
 			 MTK_PHY_DA_CALIN_FLAG);
 
@@ -409,7 +62,25 @@ static int cal_cycle(struct phy_device *phydev, int devad,
 	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP);
 	if (ret < 0)
 		return ret;
-	ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
+
+	return FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret);
+}
+
+/* One calibration cycle consists of:
+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+ *   until AD_CAL_COMP is ready to output calibration result.
+ * 2.Wait until DA_CAL_CLK is available.
+ * 3.Fetch AD_CAL_COMP_OUT.
+ */
+static int cal_cycle(struct phy_device *phydev, int devad,
+		     u32 regnum, u16 mask, u16 cal_val)
+{
+	int ret;
+
+	phy_modify_mmd(phydev, devad, regnum,
+		       mask, cal_val);
+
+	ret = mtk_cal_cycle_wait(phydev);
 	phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
 
 	return ret;
@@ -1215,73 +886,6 @@ static int mt798x_phy_config_init(struct phy_device *phydev)
 	return mt798x_phy_calibration(phydev);
 }
 
-static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
-				    unsigned long *delay_on,
-				    unsigned long *delay_off)
-{
-	bool blinking = false;
-	int err;
-
-	err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
-	if (err < 0)
-		return err;
-
-	err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
-	if (err)
-		return err;
-
-	return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-				     false);
-}
-
-static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
-					 u8 index, enum led_brightness value)
-{
-	int err;
-
-	err = mtk_phy_hw_led_blink_set(phydev, index, false);
-	if (err)
-		return err;
-
-	return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
-				     (value != LED_OFF));
-}
-
-static const unsigned long supported_triggers =
-	BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
-	BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
-	BIT(TRIGGER_NETDEV_LINK)        |
-	BIT(TRIGGER_NETDEV_LINK_10)     |
-	BIT(TRIGGER_NETDEV_LINK_100)    |
-	BIT(TRIGGER_NETDEV_LINK_1000)   |
-	BIT(TRIGGER_NETDEV_RX)          |
-	BIT(TRIGGER_NETDEV_TX);
-
-static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-					  unsigned long rules)
-{
-	return mtk_phy_led_hw_is_supported(phydev, index, rules,
-					   supported_triggers);
-}
-
-static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-					 unsigned long *rules)
-{
-	return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
-				       MTK_GPHY_LED_ON_SET,
-				       MTK_GPHY_LED_RX_BLINK_SET,
-				       MTK_GPHY_LED_TX_BLINK_SET);
-};
-
-static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-					 unsigned long rules)
-{
-	return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
-				       MTK_GPHY_LED_ON_SET,
-				       MTK_GPHY_LED_RX_BLINK_SET,
-				       MTK_GPHY_LED_TX_BLINK_SET);
-};
-
 static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
 {
 	struct mtk_socphy_shared *priv = phy_package_get_priv(phydev);
@@ -1418,58 +1022,6 @@ static int mt7981_phy_probe(struct phy_device *phydev)
 	return mt798x_phy_calibration(phydev);
 }
 
-static int an7581_phy_probe(struct phy_device *phydev)
-{
-	struct mtk_socphy_priv *priv;
-	struct pinctrl *pinctrl;
-
-	/* Toggle pinctrl to enable PHY LED */
-	pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led");
-	if (IS_ERR(pinctrl))
-		dev_err(&phydev->mdio.bus->dev,
-			"Failed to setup PHY LED pinctrl\n");
-
-	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	phydev->priv = priv;
-
-	return 0;
-}
-
-static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index,
-				       unsigned long modes)
-{
-	u16 val = 0;
-	u32 mode;
-
-	if (index >= MTK_PHY_MAX_LEDS)
-		return -EINVAL;
-
-	for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-		switch (mode) {
-		case PHY_LED_ACTIVE_LOW:
-			val = MTK_PHY_LED_ON_POLARITY;
-			break;
-		case PHY_LED_ACTIVE_HIGH:
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-			      MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
-			      MTK_PHY_LED_ON_POLARITY, val);
-}
-
-static int an7583_phy_config_init(struct phy_device *phydev)
-{
-	/* BMCR_PDOWN is enabled by default */
-	return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
-}
-
 static struct phy_driver mtk_socphy_driver[] = {
 	{
 		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981),
@@ -1505,31 +1057,6 @@ static struct phy_driver mtk_socphy_driver[] = {
 		.led_hw_control_set = mt798x_phy_led_hw_control_set,
 		.led_hw_control_get = mt798x_phy_led_hw_control_get,
 	},
-	{
-		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581),
-		.name		= "Airoha AN7581 PHY",
-		.config_intr	= genphy_no_config_intr,
-		.handle_interrupt = genphy_handle_interrupt_no_ack,
-		.probe		= an7581_phy_probe,
-		.led_blink_set	= mt798x_phy_led_blink_set,
-		.led_brightness_set = mt798x_phy_led_brightness_set,
-		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-		.led_hw_control_set = mt798x_phy_led_hw_control_set,
-		.led_hw_control_get = mt798x_phy_led_hw_control_get,
-		.led_polarity_set = an7581_phy_led_polarity_set,
-	},
-	{
-		PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7583),
-		.name		= "Airoha AN7583 PHY",
-		.config_init	= an7583_phy_config_init,
-		.probe		= an7581_phy_probe,
-		.led_blink_set	= mt798x_phy_led_blink_set,
-		.led_brightness_set = mt798x_phy_led_brightness_set,
-		.led_hw_is_supported = mt798x_phy_led_hw_is_supported,
-		.led_hw_control_set = mt798x_phy_led_hw_control_set,
-		.led_hw_control_get = mt798x_phy_led_hw_control_get,
-		.led_polarity_set = an7581_phy_led_polarity_set,
-	},
 };
 
 module_phy_driver(mtk_socphy_driver);
@@ -1537,8 +1064,6 @@ module_phy_driver(mtk_socphy_driver);
 static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = {
 	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) },
 	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) },
-	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581) },
-	{ PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7583) },
 	{ }
 };
 
diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.h b/drivers/net/phy/mediatek/mtk-ge-soc.h
new file mode 100644
index 00000000000000..5e9d24a9833c77
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk-ge-soc.h
@@ -0,0 +1,364 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _MTK_GE_SOC_H_
+#define _MTK_GE_SOC_H_
+
+#include <linux/bitfield.h>
+
+#define MTK_GPHY_ID_MT7981			0x03a29461
+#define MTK_GPHY_ID_MT7988			0x03a29481
+#define AIROHA_GPHY_ID_AN7581			0x03a294c1
+#define AIROHA_GPHY_ID_AN7583			0xc0ff0420
+
+#define MTK_EXT_PAGE_ACCESS			0x1f
+#define MTK_PHY_PAGE_STANDARD			0x0000
+#define MTK_PHY_PAGE_EXTENDED_1			0x0001
+#define MTK_PHY_PAGE_EXTENDED_3			0x0003
+
+#define MTK_PHY_LPI_REG_14			0x14
+#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK	GENMASK(8, 0)
+
+#define MTK_PHY_LPI_REG_1c			0x1c
+#define MTK_PHY_SMI_DET_ON_THRESH_MASK		GENMASK(13, 8)
+
+#define MTK_PHY_PAGE_EXTENDED_2A30		0x2a30
+
+/* Registers on Token Ring debug nodes */
+/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */
+/* NormMseLoThresh */
+#define NORMAL_MSE_LO_THRESH_MASK		GENMASK(15, 8)
+
+/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */
+/* RemAckCntLimitCtrl */
+#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK	GENMASK(2, 1)
+
+/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */
+/* VcoSlicerThreshBitsHigh */
+#define VCO_SLICER_THRESH_HIGH_MASK		GENMASK(23, 0)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */
+/* DfeTailEnableVgaThresh1000 */
+#define DFE_TAIL_EANBLE_VGA_TRHESH_1000		GENMASK(5, 1)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */
+/* MrvlTrFix100Kp */
+#define MRVL_TR_FIX_100KP_MASK			GENMASK(22, 20)
+/* MrvlTrFix100Kf */
+#define MRVL_TR_FIX_100KF_MASK			GENMASK(19, 17)
+/* MrvlTrFix1000Kp */
+#define MRVL_TR_FIX_1000KP_MASK			GENMASK(16, 14)
+/* MrvlTrFix1000Kf */
+#define MRVL_TR_FIX_1000KF_MASK			GENMASK(13, 11)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */
+/* VgaDecRate */
+#define VGA_DECIMATION_RATE_MASK		GENMASK(8, 5)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */
+/* SlvDSPreadyTime */
+#define SLAVE_DSP_READY_TIME_MASK		GENMASK(22, 15)
+/* MasDSPreadyTime */
+#define MASTER_DSP_READY_TIME_MASK		GENMASK(14, 7)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */
+/* EnabRandUpdTrig */
+#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER	BIT(8)
+
+/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */
+/* ResetSyncOffset */
+#define RESET_SYNC_OFFSET_MASK			GENMASK(11, 8)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */
+/* FfeUpdGainForceVal */
+#define FFE_UPDATE_GAIN_FORCE_VAL_MASK		GENMASK(9, 7)
+/* FfeUpdGainForce */
+#define FFE_UPDATE_GAIN_FORCE			BIT(6)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */
+/* TrFreeze */
+#define TR_FREEZE_MASK				GENMASK(11, 0)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */
+/* SS: Steady-state, KP: Proportional Gain */
+/* SSTrKp100 */
+#define SS_TR_KP100_MASK			GENMASK(21, 19)
+/* SSTrKf100 */
+#define SS_TR_KF100_MASK			GENMASK(18, 16)
+/* SSTrKp1000Mas */
+#define SS_TR_KP1000_MASTER_MASK		GENMASK(15, 13)
+/* SSTrKf1000Mas */
+#define SS_TR_KF1000_MASTER_MASK		GENMASK(12, 10)
+/* SSTrKp1000Slv */
+#define SS_TR_KP1000_SLAVE_MASK			GENMASK(9, 7)
+/* SSTrKf1000Slv */
+#define SS_TR_KF1000_SLAVE_MASK			GENMASK(6, 4)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */
+/* clear this bit if wanna select from AFE */
+/* Regsigdet_sel_1000 */
+#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE	BIT(4)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */
+/* RegEEE_st2TrKf1000 */
+#define EEE1000_STAGE2_TR_KF_MASK		GENMASK(13, 11)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */
+/* RegEEE_slv_waketr_timer_tar */
+#define SLAVE_WAKETR_TIMER_MASK			GENMASK(20, 11)
+/* RegEEE_slv_remtx_timer_tar */
+#define SLAVE_REMTX_TIMER_MASK			GENMASK(10, 1)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */
+/* RegEEE_slv_wake_int_timer_tar */
+#define SLAVE_WAKEINT_TIMER_MASK		GENMASK(10, 1)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */
+/* RegEEE_trfreeze_timer2 */
+#define TR_FREEZE_TIMER2_MASK			GENMASK(9, 0)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */
+/* RegEEE100Stg1_tar */
+#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK	GENMASK(8, 0)
+
+/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */
+/* REGEEE_wake_slv_tr_wait_dfesigdet_en */
+#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN	BIT(11)
+
+#define ANALOG_INTERNAL_OPERATION_MAX_US	20
+#define TXRESERVE_MIN				0
+#define TXRESERVE_MAX				7
+
+#define MTK_PHY_ANARG_RG			0x10
+#define   MTK_PHY_TCLKOFFSET_MASK		GENMASK(12, 8)
+
+/* Registers on MDIO_MMD_VEND1 */
+#define MTK_PHY_TXVLD_DA_RG			0x12
+#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK	GENMASK(15, 10)
+#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_A2		0x16
+#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK	GENMASK(15, 10)
+#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_B1		0x17
+#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_B2		0x18
+#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_C1		0x19
+#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_C2		0x20
+#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_D1		0x21
+#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_D2		0x22
+#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_RXADC_CTRL_RG7			0xc6
+#define   MTK_PHY_DA_AD_BUF_BIAS_LP_MASK	GENMASK(9, 8)
+
+#define MTK_PHY_RXADC_CTRL_RG9			0xc8
+#define   MTK_PHY_DA_RX_PSBN_TBT_MASK		GENMASK(14, 12)
+#define   MTK_PHY_DA_RX_PSBN_HBT_MASK		GENMASK(10, 8)
+#define   MTK_PHY_DA_RX_PSBN_GBE_MASK		GENMASK(6, 4)
+#define   MTK_PHY_DA_RX_PSBN_LP_MASK		GENMASK(2, 0)
+
+#define MTK_PHY_LDO_OUTPUT_V			0xd7
+
+#define MTK_PHY_RG_ANA_CAL_RG0			0xdb
+#define   MTK_PHY_RG_CAL_CKINV			BIT(12)
+#define   MTK_PHY_RG_ANA_CALEN			BIT(8)
+#define   MTK_PHY_RG_REXT_CALEN			BIT(4)
+#define   MTK_PHY_RG_ZCALEN_A			BIT(0)
+
+#define MTK_PHY_RG_ANA_CAL_RG1			0xdc
+#define   MTK_PHY_RG_ZCALEN_B			BIT(12)
+#define   MTK_PHY_RG_ZCALEN_C			BIT(8)
+#define   MTK_PHY_RG_ZCALEN_D			BIT(4)
+#define   MTK_PHY_RG_TXVOS_CALEN		BIT(0)
+
+#define MTK_PHY_RG_ANA_CAL_RG5			0xe0
+#define   MTK_PHY_RG_REXT_TRIM_MASK		GENMASK(13, 8)
+#define   MTK_PHY_RG_REXT_ZCAL_CTRL_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_RG_ANA_CAL_RG6			0xe1
+
+#define MTK_PHY_RG_TX_FILTER			0xfe
+
+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120	0x120
+#define   MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK	GENMASK(12, 8)
+#define   MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK	GENMASK(4, 0)
+
+#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122	0x122
+#define   MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK	GENMASK(7, 0)
+
+#define MTK_PHY_RG_TESTMUX_ADC_CTRL		0x144
+#define   MTK_PHY_RG_TXEN_DIG_MASK		GENMASK(5, 5)
+
+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B		0x172
+#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK	GENMASK(13, 8)
+#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D		0x173
+#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK	GENMASK(13, 8)
+#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_CR_TX_R50_OFFSET_A_B		0x174
+#define   MTK_PHY_CR_TX_R50_OFFSET_A_MASK	GENMASK(13, 8)
+#define   MTK_PHY_CR_TX_R50_OFFSET_B_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_CR_TX_R50_OFFSET_C_D		0x175
+#define   MTK_PHY_CR_TX_R50_OFFSET_C_MASK	GENMASK(13, 8)
+#define   MTK_PHY_CR_TX_R50_OFFSET_D_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_AD_CAL_COMP			0x17a
+#define   MTK_PHY_AD_CAL_COMP_OUT_MASK		GENMASK(8, 8)
+
+#define MTK_PHY_RG_AD_CAL_CLK			0x17b
+#define   MTK_PHY_DA_CAL_CLK			BIT(0)
+
+#define MTK_PHY_RG_AD_CALIN			0x17c
+#define   MTK_PHY_DA_CALIN_FLAG			BIT(0)
+
+#define MTK_PHY_RG_DASN_DAC_IN0_A		0x17d
+#define   MTK_PHY_DASN_DAC_IN0_A_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DASN_DAC_IN0_B		0x17e
+#define   MTK_PHY_DASN_DAC_IN0_B_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DASN_DAC_IN0_C		0x17f
+#define   MTK_PHY_DASN_DAC_IN0_C_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DASN_DAC_IN0_D		0x180
+#define   MTK_PHY_DASN_DAC_IN0_D_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DASN_DAC_IN1_A		0x181
+#define   MTK_PHY_DASN_DAC_IN1_A_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DASN_DAC_IN1_B		0x182
+#define   MTK_PHY_DASN_DAC_IN1_B_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DASN_DAC_IN1_C		0x183
+#define   MTK_PHY_DASN_DAC_IN1_C_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DASN_DAC_IN1_D		0x184
+#define   MTK_PHY_DASN_DAC_IN1_D_MASK		GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG19b			0x19b
+#define   MTK_PHY_BYPASS_DSP_LPI_READY		BIT(8)
+
+#define MTK_PHY_RG_LP_IIR2_K1_L			0x22a
+#define MTK_PHY_RG_LP_IIR2_K1_U			0x22b
+#define MTK_PHY_RG_LP_IIR2_K2_L			0x22c
+#define MTK_PHY_RG_LP_IIR2_K2_U			0x22d
+#define MTK_PHY_RG_LP_IIR2_K3_L			0x22e
+#define MTK_PHY_RG_LP_IIR2_K3_U			0x22f
+#define MTK_PHY_RG_LP_IIR2_K4_L			0x230
+#define MTK_PHY_RG_LP_IIR2_K4_U			0x231
+#define MTK_PHY_RG_LP_IIR2_K5_L			0x232
+#define MTK_PHY_RG_LP_IIR2_K5_U			0x233
+
+#define MTK_PHY_RG_DEV1E_REG234			0x234
+#define   MTK_PHY_TR_OPEN_LOOP_EN_MASK		GENMASK(0, 0)
+#define   MTK_PHY_LPF_X_AVERAGE_MASK		GENMASK(7, 4)
+#define   MTK_PHY_TR_LP_IIR_EEE_EN		BIT(12)
+
+#define MTK_PHY_RG_LPF_CNT_VAL			0x235
+
+#define MTK_PHY_RG_DEV1E_REG238			0x238
+#define   MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK	GENMASK(8, 0)
+#define   MTK_PHY_LPI_SLV_SEND_TX_EN		BIT(12)
+
+#define MTK_PHY_RG_DEV1E_REG239			0x239
+#define   MTK_PHY_LPI_SEND_LOC_TIMER_MASK	GENMASK(8, 0)
+#define   MTK_PHY_LPI_TXPCS_LOC_RCV		BIT(12)
+
+#define MTK_PHY_RG_DEV1E_REG27C			0x27c
+#define   MTK_PHY_VGASTATE_FFE_THR_ST1_MASK	GENMASK(12, 8)
+#define MTK_PHY_RG_DEV1E_REG27D			0x27d
+#define   MTK_PHY_VGASTATE_FFE_THR_ST2_MASK	GENMASK(4, 0)
+
+#define MTK_PHY_RG_DEV1E_REG2C7			0x2c7
+#define   MTK_PHY_MAX_GAIN_MASK			GENMASK(4, 0)
+#define   MTK_PHY_MIN_GAIN_MASK			GENMASK(12, 8)
+
+#define MTK_PHY_RG_DEV1E_REG2D1			0x2d1
+#define   MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK	GENMASK(7, 0)
+#define   MTK_PHY_LPI_SKIP_SD_SLV_TR		BIT(8)
+#define   MTK_PHY_LPI_TR_READY			BIT(9)
+#define   MTK_PHY_LPI_VCO_EEE_STG0_EN		BIT(10)
+
+#define MTK_PHY_RG_DEV1E_REG323			0x323
+#define   MTK_PHY_EEE_WAKE_MAS_INT_DC		BIT(0)
+#define   MTK_PHY_EEE_WAKE_SLV_INT_DC		BIT(4)
+
+#define MTK_PHY_RG_DEV1E_REG324			0x324
+#define   MTK_PHY_SMI_DETCNT_MAX_MASK		GENMASK(5, 0)
+#define   MTK_PHY_SMI_DET_MAX_EN		BIT(8)
+
+#define MTK_PHY_RG_DEV1E_REG326			0x326
+#define   MTK_PHY_LPI_MODE_SD_ON		BIT(0)
+#define   MTK_PHY_RESET_RANDUPD_CNT		BIT(1)
+#define   MTK_PHY_TREC_UPDATE_ENAB_CLR		BIT(2)
+#define   MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF	BIT(4)
+#define   MTK_PHY_TR_READY_SKIP_AFE_WAKEUP	BIT(5)
+
+#define MTK_PHY_LDO_PUMP_EN_PAIRAB		0x502
+#define MTK_PHY_LDO_PUMP_EN_PAIRCD		0x503
+
+#define MTK_PHY_DA_TX_R50_PAIR_A		0x53d
+#define MTK_PHY_DA_TX_R50_PAIR_B		0x53e
+#define MTK_PHY_DA_TX_R50_PAIR_C		0x53f
+#define MTK_PHY_DA_TX_R50_PAIR_D		0x540
+
+/* Registers on MDIO_MMD_VEND2 */
+#define MTK_PHY_LED1_DEFAULT_POLARITIES		BIT(1)
+
+#define MTK_PHY_RG_BG_RASEL			0x115
+#define   MTK_PHY_RG_BG_RASEL_MASK		GENMASK(2, 0)
+
+/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */
+#define RG_GPIO_MISC_TPBANK0			0x6f0
+#define   RG_GPIO_MISC_TPBANK0_BOOTMODE		GENMASK(11, 8)
+
+enum CAL_ITEM {
+	REXT,
+	TX_OFFSET,
+	TX_AMP,
+	TX_R50,
+	TX_VCM,
+	RX_OFFSET,
+};
+
+enum {
+	NO_PAIR,
+	PAIR_A,
+	PAIR_B,
+	PAIR_C,
+	PAIR_D,
+};
+
+enum calibration_mode {
+	EFUSE_K,
+	SW_K
+};
+
+enum CAL_MODE {
+	EFUSE_M,
+	SW_M
+};
+
+/* MTK GE SoC common functions */
+int mtk_cal_cycle_wait(struct phy_device *phydev);
+
+#endif /* _MTK_GE_SOC_H_ */
diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c
index dfd0f4e439a214..8c2b26f9b8403b 100644
--- a/drivers/net/phy/mediatek/mtk-phy-lib.c
+++ b/drivers/net/phy/mediatek/mtk-phy-lib.c
@@ -36,8 +36,8 @@ static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
 		*tr_high, *tr_low);
 }
 
-static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
-			   u8 data_addr, u32 tr_data)
+void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+		    u8 data_addr, u32 tr_data)
 {
 	__phy_write(phydev, 0x11, tr_data & 0xffff);
 	__phy_write(phydev, 0x12, tr_data >> 16);
@@ -45,6 +45,7 @@ static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
 		tr_data >> 16, tr_data & 0xffff);
 	__mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr);
 }
+EXPORT_SYMBOL_GPL(__mtk_tr_write);
 
 void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
 		     u8 data_addr, u32 mask, u32 set)
@@ -341,6 +342,78 @@ void mtk_phy_leds_state_init(struct phy_device *phydev)
 }
 EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
 
+int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+			     unsigned long *delay_on,
+			     unsigned long *delay_off)
+{
+	bool blinking = false;
+	int err;
+
+	err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
+	if (err < 0)
+		return err;
+
+	err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
+	if (err)
+		return err;
+
+	return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
+				     false);
+}
+EXPORT_SYMBOL_GPL(mt798x_phy_led_blink_set);
+
+int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+				  u8 index, enum led_brightness value)
+{
+	int err;
+
+	err = mtk_phy_hw_led_blink_set(phydev, index, false);
+	if (err)
+		return err;
+
+	return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
+				     (value != LED_OFF));
+}
+EXPORT_SYMBOL_GPL(mt798x_phy_led_brightness_set);
+
+static const unsigned long supported_triggers =
+	BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
+	BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
+	BIT(TRIGGER_NETDEV_LINK)        |
+	BIT(TRIGGER_NETDEV_LINK_10)     |
+	BIT(TRIGGER_NETDEV_LINK_100)    |
+	BIT(TRIGGER_NETDEV_LINK_1000)   |
+	BIT(TRIGGER_NETDEV_RX)          |
+	BIT(TRIGGER_NETDEV_TX);
+
+int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+				   unsigned long rules)
+{
+	return mtk_phy_led_hw_is_supported(phydev, index, rules,
+					   supported_triggers);
+}
+EXPORT_SYMBOL_GPL(mt798x_phy_led_hw_is_supported);
+
+int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+				  unsigned long *rules)
+{
+	return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
+				       MTK_GPHY_LED_ON_SET,
+				       MTK_GPHY_LED_RX_BLINK_SET,
+				       MTK_GPHY_LED_TX_BLINK_SET);
+};
+EXPORT_SYMBOL_GPL(mt798x_phy_led_hw_control_get);
+
+int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+				  unsigned long rules)
+{
+	return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
+				       MTK_GPHY_LED_ON_SET,
+				       MTK_GPHY_LED_RX_BLINK_SET,
+				       MTK_GPHY_LED_TX_BLINK_SET);
+};
+EXPORT_SYMBOL_GPL(mt798x_phy_led_hw_control_set);
+
 MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
 MODULE_AUTHOR("Sky Huang <SkyLake.Huang@mediatek.com>");
 MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h
index 320f76ffa81fa2..cd9d4c5550c3b7 100644
--- a/drivers/net/phy/mediatek/mtk.h
+++ b/drivers/net/phy/mediatek/mtk.h
@@ -13,6 +13,7 @@
 
 #define MTK_EXT_PAGE_ACCESS			0x1f
 #define MTK_PHY_PAGE_EXTENDED_1			0x0001
+#define MTK_PHY_PAGE_EXTENDED_3			0x0003
 #define MTK_PHY_PAGE_STANDARD			0x0000
 #define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
 
@@ -72,6 +73,8 @@ struct mtk_socphy_priv {
 	unsigned long		led_state;
 };
 
+void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
+		    u8 data_addr, u32 tr_data);
 void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
 		     u8 data_addr, u32 mask, u32 set);
 void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr,
@@ -101,4 +104,16 @@ int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
 			     bool blinking);
 void mtk_phy_leds_state_init(struct phy_device *phydev);
 
+int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
+			     unsigned long *delay_on,
+			     unsigned long *delay_off);
+int mt798x_phy_led_brightness_set(struct phy_device *phydev,
+				  u8 index, enum led_brightness value);
+int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+				   unsigned long rules);
+int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
+				  unsigned long *rules);
+int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
+				  unsigned long rules);
+
 #endif /* _MTK_EPHY_H_ */

3/2 2026/07/09 01:11 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 55665
							output: 19
							thoughts: 961
						

Thoughts:
**A New PHY Driver: Reachability and Fuzzing Considerations**

Okay, so I'm looking at this patch series that introduces a new Ethernet PHY driver, `airoha-ge-soc.c`, specifically for Airoha SoCs. It cleanly separates the Airoha PHY functionality from the existing MediaTek SoC PHY driver (`mtk-ge-soc.c`). We have a new Kconfig option, `AIROHA_GE_SOC_PHY`, the new driver file, and modifications to the MediaTek files to reflect this split.

My immediate thought is about reachability. This is a PHY driver, which means it gets instantiated when the PHY itself is present and detectable. In virtualized environments, things get a bit more complex. Syzkaller usually relies on emulated MDIO buses or dummy PHYs to reach PHY drivers. I need to figure out if it's even *possible* for Syzkaller to trigger this driver. The driver uses `PHY_ID_MATCH_EXACT` with specific IDs: `AIROHA_GPHY_ID_AN7581` and `AIROHA_GPHY_ID_AN7583`. So, if `CONFIG_AIROHA_GE_SOC_PHY` is enabled, the driver will be built.

Is it worth fuzzing? Yes, absolutely. It's a new driver with functional changes, a prime target for finding bugs. The more code that’s added or changed the more the possibility of new bugs being present.

But back to reachability. Syzkaller *can* fuzz PHY drivers, if it's probed. That’s the key here. So, how can this driver be probed? It matches based on PHY IDs, which suggests it's found during an MDIO bus scan. If there’s an emulated MDIO bus, Syzkaller could potentially inject an MDIO device that simulates the Airoha PHY, but I'm not sure if it has that capability.

Now, I'm recalling the instructions which state something like, "Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware". So, even if there were an emulated network card in QEMU, it would need to use this specific PHY, which seems unlikely. Syzkaller doesn't directly instantiate arbitrary PHYs; they’re created by device tree or MDIO bus scanning. Can Sysfs or Netlink instantiate a PHY? No, typically not. It’s the MDIO controller that does the probing.

The bottom line is that unless QEMU emulates the Airoha or MediaTek SoC with this specific MDIO bus and PHY, the driver won't be probed, which renders it unreachable.

However, the instructions also say: "If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true." So, even if the hardware isn't directly reachable, because it is a functional change, it is worth fuzzing. The question, then, is whether there is a virtual MDIO driver, which would allow Syzkaller to inject MDIO devices, to test this.



4/2 2026/07/09 01:12 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "mdio.*mockup"
}

Results:
{
  "error": "no matches"
}

5/2 2026/07/09 01:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 57346
							output: 18
							thoughts: 19
						

Thoughts:
Okay, here's my summary, presented as a stream of thought:

**Checking the PHY Driver Landscape**

Right, let's get down to it. Given the context, my initial thought is to zero in on the physical layer interface drivers, specifically in the `drivers/net/phy/` directory. That's the logical starting point when I'm dealing with networking hardware at a lower level. My intuition tells me that the clue to the problem will probably be found within the PHY driver code. I'm especially keen to look for any instances of a "virtual" or "dummy" MDIO implementation. That would suggest a specific hardware configuration, perhaps for testing or emulation purposes, which is likely to be at the heart of the issue I'm dealing with. Let's see what's there.



6/2 2026/07/09 01:12 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "mdio.*dummy"
}

Results:
{
  "error": "no matches"
}

7/2 2026/07/09 01:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 57567
							output: 19
							thoughts: 17
						

Thoughts:
Here's a summary of my thought process:

**Diving into the Fixed PHY Code**

Alright, time to get my hands dirty. I need to investigate something related to network interfaces, and I have a hunch the issue might be down in the low-level PHY layer. My gut feeling is leading me straight to `drivers/net/phy/fixed_phy.c`. That's the likely spot for fixed PHY configuration and control. I'm expecting to find the standard PHY interface functions implemented there, things like read/write registers, link state detection, and potentially even initialization routines if it's not handled elsewhere. This will be the starting point to understand how the fixed PHY is handled by the driver. I’ll be looking for potential areas of configuration, initialization and link status detection to see if the problem lies with the driver code, or with my expectations of how it should operate.



8/2 2026/07/09 01:12 tool grepper
0m Args:
{
  "Expression": "fixed_phy_register"
}

Results:
{
  "Output": "drivers/net/dsa/dsa_loop.c=482=static int __init dsa_loop_init(void)\n--\ndrivers/net/dsa/dsa_loop.c-491-\tfor (i = 0; i \u003c NUM_FIXED_PHYS; i++)\ndrivers/net/dsa/dsa_loop.c:492:\t\tphydevs[i] = fixed_phy_register_100fd();\ndrivers/net/dsa/dsa_loop.c-493-\n--\ndrivers/net/ethernet/broadcom/b44.c=2234=static int b44_register_phy_one(struct b44 *bp)\n--\ndrivers/net/ethernet/broadcom/b44.c-2272-\ndrivers/net/ethernet/broadcom/b44.c:2273:\t\tphydev = fixed_phy_register_100fd();\ndrivers/net/ethernet/broadcom/b44.c-2274-\t\tif (!IS_ERR(phydev))\n--\ndrivers/net/ethernet/broadcom/bgmac.c=1439=int bgmac_phy_connect_direct(struct bgmac *bgmac)\n--\ndrivers/net/ethernet/broadcom/bgmac.c-1448-\ndrivers/net/ethernet/broadcom/bgmac.c:1449:\tphy_dev = fixed_phy_register(\u0026fphy_status, NULL);\ndrivers/net/ethernet/broadcom/bgmac.c-1450-\tif (IS_ERR(phy_dev)) {\n--\ndrivers/net/ethernet/faraday/ftgmac100.c=1848=static int ftgmac100_probe_ncsi(struct net_device *netdev,\n--\ndrivers/net/ethernet/faraday/ftgmac100.c-1866-\ndrivers/net/ethernet/faraday/ftgmac100.c:1867:\tphydev = fixed_phy_register(\u0026ncsi_phy_status, np);\ndrivers/net/ethernet/faraday/ftgmac100.c-1868-\tif (IS_ERR(phydev)) {\n--\ndrivers/net/ethernet/freescale/fec_main.c=2981=static int fec_enet_mii_probe(struct net_device *ndev)\n--\ndrivers/net/ethernet/freescale/fec_main.c-3002-\t\t\tnetdev_info(ndev, \"no PHY, assuming direct connection to switch\\n\");\ndrivers/net/ethernet/freescale/fec_main.c:3003:\t\t\tphy_dev = fixed_phy_register_100fd();\ndrivers/net/ethernet/freescale/fec_main.c-3004-\t\t\tif (IS_ERR(phy_dev)) {\n--\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c=238=static int hbg_fixed_phy_init(struct hbg_priv *priv)\n--\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c-250-\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c:251:\tphydev = fixed_phy_register(\u0026hbg_fixed_phy_status, NULL);\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c-252-\tif (IS_ERR(phydev)) {\n--\ndrivers/net/mdio/of_mdio.c=412=int of_phy_register_fixed_link(struct device_node *np)\n--\ndrivers/net/mdio/of_mdio.c-459-register_phy:\ndrivers/net/mdio/of_mdio.c:460:\treturn PTR_ERR_OR_ZERO(fixed_phy_register(\u0026status, np));\ndrivers/net/mdio/of_mdio.c-461-}\n--\ndrivers/net/phy/fixed_phy.c=118=static int fixed_phy_get_free_addr(void)\n--\ndrivers/net/phy/fixed_phy.c-130-\ndrivers/net/phy/fixed_phy.c:131:struct phy_device *fixed_phy_register(const struct fixed_phy_status *status,\ndrivers/net/phy/fixed_phy.c-132-\t\t\t\t      struct device_node *np)\n--\ndrivers/net/phy/fixed_phy.c-172-}\ndrivers/net/phy/fixed_phy.c:173:EXPORT_SYMBOL_GPL(fixed_phy_register);\ndrivers/net/phy/fixed_phy.c-174-\ndrivers/net/phy/fixed_phy.c:175:struct phy_device *fixed_phy_register_100fd(void)\ndrivers/net/phy/fixed_phy.c-176-{\n--\ndrivers/net/phy/fixed_phy.c-181-\ndrivers/net/phy/fixed_phy.c:182:\treturn fixed_phy_register(\u0026status, NULL);\ndrivers/net/phy/fixed_phy.c-183-}\ndrivers/net/phy/fixed_phy.c:184:EXPORT_SYMBOL_GPL(fixed_phy_register_100fd);\ndrivers/net/phy/fixed_phy.c-185-\n--\ninclude/linux/phy_fixed.h=19=extern int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier);\ninclude/linux/phy_fixed.h:20:struct phy_device *fixed_phy_register(const struct fixed_phy_status *status,\ninclude/linux/phy_fixed.h-21-\t\t\t\t      struct device_node *np);\ninclude/linux/phy_fixed.h:22:struct phy_device *fixed_phy_register_100fd(void);\ninclude/linux/phy_fixed.h-23-\n--\ninclude/linux/phy_fixed.h=29=static inline struct phy_device *\ninclude/linux/phy_fixed.h:30:fixed_phy_register(const struct fixed_phy_status *status,\ninclude/linux/phy_fixed.h-31-\t\t   struct device_node *np)\n--\ninclude/linux/phy_fixed.h-35-\ninclude/linux/phy_fixed.h:36:static inline struct phy_device *fixed_phy_register_100fd(void)\ninclude/linux/phy_fixed.h-37-{\n"
}

9/2 2026/07/09 01:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 59444
							output: 20
							thoughts: 69
						

Thoughts:
**Analyzing the Fixed PHY Driver**

Okay, so the `fixed_phy` driver seems pretty straightforward – it's designed to register a PHY with a specific, hardcoded ID: `fixed_phy_id`. Hmm, that's not very flexible. It's essentially locking us into a particular configuration. But wait, a thought strikes me: can Syzkaller, with its ability to manipulate and create virtual hardware, potentially create a dummy MDIO bus and register PHYs with *arbitrary* IDs, essentially bypassing this hardcoded restriction? This could have interesting implications. If we could get that working, it could provide some useful fuzzing coverage. The key question is whether Syzkaller's MDIO capabilities include such functionality, and I suspect that is a thing to be examined. Let me do a quick scan of the Syzkaller documentation and code to see what kind of MDIO support is in place. I should be able to get a better answer if I search specifically for keywords relating to Syzkaller and MDIO.



10/2 2026/07/09 01:12 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "syz_.*mdio"
}

Results:
{
  "error": "no matches"
}

11/2 2026/07/09 01:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 59761
							output: 19
							thoughts: 10
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:

**Considering a Specific Naming Convention**

Alright, let's see... I'm thinking about patterns here. I've been working with this dataset, this algorithm, this system, whatever it is... and I keep seeing these entries. Now, I'm trying to wrap my head around a particular convention in this instance - specifically, anything that starts with `syz_` followed by, well, *anything*, really, and then ends with `phy`. That's the key. What is that representing? Are these physical phenomena? Simulations? Experimental results? Is it something specific to the *syz* part? What does it relate to?

I'm probably dealing with some underlying physics model then. That `phy` suffix is screaming "physical", "physics", something physical. I need to understand that. I need to know *what* it indicates. It could be some specific file format, a data category, a particular parameter, a related value, and I need a better understanding of the data context to ensure I use that data appropriately and consider its limitations in whatever my next steps are. This is a very targeted query.



12/2 2026/07/09 01:12 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "syz_.*phy"
}

Results:
{
  "error": "no matches"
}

13/2 2026/07/09 01:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 60070
							output: 16
							thoughts: 170
						

Thoughts:
**My Current Thinking on PHY Driver Instantiation and Reachability**

Okay, so I'm trying to figure out how to get at this PHY driver within the QEMU environment. The first roadblock is the obvious one: if I can't instantiate the damn thing within QEMU, it's basically unreachable for my testing purposes. So, how *do* I instantiate it? I'm immediately thinking, can I maybe get it going from userspace somehow? No, that's not right. PHY devices are created and managed by the MDIO bus driver, which is the entity in control here.

Alright, so the focus shifts to the MDIO bus driver. Is there a way to bring that up from userspace? Potentially through `i2c` or `spi`, maybe? Some MDIO buses *are* on I2C or SPI interfaces, but typically, they're memory-mapped, which would rule those out as easy options. What about `mdio-gpio`? Now we're getting somewhere. Device tree seems like the likely route for `mdio-gpio` and I think that's the key.

But can syzkaller load custom device trees? I can't recall having seen that capability in place and it turns out, it can't. Not arbitrary ones anyway, so that idea gets shot down. Now I'm grasping at straws. Wait… is there a *virtual* MDIO bus, something that would be instantiated within the simulation? Let me check… I'll head over to `drivers/net/mdio/mdio-mockup.c` or something similar, something that might simulate this environment.



14/2 2026/07/09 01:12 tool grepper
0m Args:
{
  "Expression": "mockup"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 1107 lines.\nUse more precise expression if possible.\n\nDocumentation/admin-guide/gpio/gpio-mockup.rst=3=GPIO Testing Driver\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst-13-\nDocumentation/admin-guide/gpio/gpio-mockup.rst:14:The GPIO Testing Driver (gpio-mockup) provides a way to create simulated GPIO\nDocumentation/admin-guide/gpio/gpio-mockup.rst-15-chips for testing purposes. The lines exposed by these chips can be accessed\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst=19=Creating simulated chips using module params\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst-21-\nDocumentation/admin-guide/gpio/gpio-mockup.rst:22:When loading the gpio-mockup driver a number of parameters can be passed to the\nDocumentation/admin-guide/gpio/gpio-mockup.rst-23-module.\nDocumentation/admin-guide/gpio/gpio-mockup.rst-24-\nDocumentation/admin-guide/gpio/gpio-mockup.rst:25:    gpio_mockup_ranges\nDocumentation/admin-guide/gpio/gpio-mockup.rst-26-\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst-32-\nDocumentation/admin-guide/gpio/gpio-mockup.rst:33:        Example: gpio_mockup_ranges=-1,8,-1,16,405,409\nDocumentation/admin-guide/gpio/gpio-mockup.rst-34-\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst-38-\nDocumentation/admin-guide/gpio/gpio-mockup.rst:39:    gpio_mockup_named_lines\nDocumentation/admin-guide/gpio/gpio-mockup.rst-40-\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst-43-\nDocumentation/admin-guide/gpio/gpio-mockup.rst:44:        The name format is: gpio-mockup-X-Y where X is mockup chip's ID\nDocumentation/admin-guide/gpio/gpio-mockup.rst-45-        and Y is the line offset.\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst=47=Manipulating simulated lines\n--\nDocumentation/admin-guide/gpio/gpio-mockup.rst-49-\nDocumentation/admin-guide/gpio/gpio-mockup.rst:50:Each mockup chip creates its own subdirectory in /sys/kernel/debug/gpio-mockup/.\nDocumentation/admin-guide/gpio/gpio-mockup.rst-51-The directory is named after the chip's label. A symlink is also created, named\n--\nDocumentation/admin-guide/gpio/obsolete.rst=4=Obsolete GPIO APIs\n--\nDocumentation/admin-guide/gpio/obsolete.rst-11-    Sysfs Interface \u003c../../userspace-api/gpio/sysfs\u003e\nDocumentation/admin-guide/gpio/obsolete.rst:12:    Mockup Testing Module \u003cgpio-mockup\u003e\nDocumentation/admin-guide/gpio/obsolete.rst-13-\n--\nDocumentation/admin-guide/kernel-parameters.txt=95=Kernel parameters\n--\nDocumentation/admin-guide/kernel-parameters.txt-1877-\nDocumentation/admin-guide/kernel-parameters.txt:1878:\tgpio-mockup.gpio_mockup_ranges\nDocumentation/admin-guide/kernel-parameters.txt-1879-\t\t\t[HW] Sets the ranges of gpiochip of for this device.\nDocumentation/admin-guide/kernel-parameters.txt-1880-\t\t\tFormat: \u003cstart1\u003e,\u003cend1\u003e,\u003cstart2\u003e,\u003cend2\u003e...\nDocumentation/admin-guide/kernel-parameters.txt:1881:\tgpio-mockup.gpio_mockup_named_lines\nDocumentation/admin-guide/kernel-parameters.txt-1882-\t\t\t[HW] Let the driver know GPIO lines should be named.\n--\nDocumentation/devicetree/bindings/incomplete-devices.yaml=26=properties:\n--\nDocumentation/devicetree/bindings/incomplete-devices.yaml-242-          - compat3\nDocumentation/devicetree/bindings/incomplete-devices.yaml:243:          - gpio-mockup\nDocumentation/devicetree/bindings/incomplete-devices.yaml-244-          - gpio-simulator\n--\nDocumentation/networking/dsa/dsa.rst=161=It is desirable that all tagging protocols are testable with the ``dsa_loop``\nDocumentation/networking/dsa/dsa.rst:162:mockup driver, which can be attached to any network interface. The goal is that\nDocumentation/networking/dsa/dsa.rst-163-any network interface should be capable of transmitting the same packet in the\n--\nMAINTAINERS=11152=S:\tMaintained\nMAINTAINERS:11153:F:\tdrivers/gpio/gpio-mockup.c\nMAINTAINERS-11154-F:\ttools/testing/selftests/gpio/\n--\ndrivers/gpio/Kconfig=2064=config GPIO_MOCKUP\n--\ndrivers/gpio/Kconfig-2072-\t  User could use it through the script in\ndrivers/gpio/Kconfig:2073:\t  tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in\ndrivers/gpio/Kconfig-2074-\t  it.\n--\ndrivers/gpio/Makefile=124=obj-$(CONFIG_GPIO_MM_LANTIQ)\t\t+= gpio-mm-lantiq.o\ndrivers/gpio/Makefile:125:obj-$(CONFIG_GPIO_MOCKUP)\t\t+= gpio-mockup.o\ndrivers/gpio/Makefile-126-obj-$(CONFIG_GPIO_MOXTET)\t\t+= gpio-moxtet.o\n--\ndrivers/gpio/gpio-mockup.c-46- */\ndrivers/gpio/gpio-mockup.c:47:struct gpio_mockup_line_status {\ndrivers/gpio/gpio-mockup.c-48-\tint dir;\n--\ndrivers/gpio/gpio-mockup.c-53-\ndrivers/gpio/gpio-mockup.c:54:struct gpio_mockup_chip {\ndrivers/gpio/gpio-mockup.c-55-\tstruct gpio_chip gc;\ndrivers/gpio/gpio-mockup.c:56:\tstruct gpio_mockup_line_status *lines;\ndrivers/gpio/gpio-mockup.c-57-\tstruct irq_domain *irq_sim_domain;\n--\ndrivers/gpio/gpio-mockup.c-61-\ndrivers/gpio/gpio-mockup.c:62:struct gpio_mockup_dbgfs_private {\ndrivers/gpio/gpio-mockup.c:63:\tstruct gpio_mockup_chip *chip;\ndrivers/gpio/gpio-mockup.c-64-\tunsigned int offset;\n--\ndrivers/gpio/gpio-mockup.c-66-\ndrivers/gpio/gpio-mockup.c:67:static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];\ndrivers/gpio/gpio-mockup.c:68:static int gpio_mockup_num_ranges;\ndrivers/gpio/gpio-mockup.c:69:module_param_array(gpio_mockup_ranges, int, \u0026gpio_mockup_num_ranges, 0400);\ndrivers/gpio/gpio-mockup.c-70-\ndrivers/gpio/gpio-mockup.c:71:static bool gpio_mockup_named_lines;\ndrivers/gpio/gpio-mockup.c:72:module_param_named(gpio_mockup_named_lines,\ndrivers/gpio/gpio-mockup.c:73:\t\t   gpio_mockup_named_lines, bool, 0400);\ndrivers/gpio/gpio-mockup.c-74-\ndrivers/gpio/gpio-mockup.c:75:static struct dentry *gpio_mockup_dbg_dir;\ndrivers/gpio/gpio-mockup.c-76-\ndrivers/gpio/gpio-mockup.c:77:static int gpio_mockup_range_base(unsigned int index)\ndrivers/gpio/gpio-mockup.c-78-{\ndrivers/gpio/gpio-mockup.c:79:\treturn gpio_mockup_ranges[index * 2];\ndrivers/gpio/gpio-mockup.c-80-}\ndrivers/gpio/gpio-mockup.c-81-\ndrivers/gpio/gpio-mockup.c:82:static int gpio_mockup_range_ngpio(unsigned int index)\ndrivers/gpio/gpio-mockup.c-83-{\ndrivers/gpio/gpio-mockup.c:84:\treturn gpio_mockup_ranges[index * 2 + 1];\ndrivers/gpio/gpio-mockup.c-85-}\ndrivers/gpio/gpio-mockup.c-86-\ndrivers/gpio/gpio-mockup.c:87:static int __gpio_mockup_get(struct gpio_mockup_chip *chip,\ndrivers/gpio/gpio-mockup.c-88-\t\t\t     unsigned int offset)\n--\ndrivers/gpio/gpio-mockup.c-92-\ndrivers/gpio/gpio-mockup.c:93:static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)\ndrivers/gpio/gpio-mockup.c-94-{\ndrivers/gpio/gpio-mockup.c:95:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-96-\tint val;\n--\ndrivers/gpio/gpio-mockup.c-98-\tscoped_guard(mutex, \u0026chip-\u003elock)\ndrivers/gpio/gpio-mockup.c:99:\t\tval = __gpio_mockup_get(chip, offset);\ndrivers/gpio/gpio-mockup.c-100-\n--\ndrivers/gpio/gpio-mockup.c-103-\ndrivers/gpio/gpio-mockup.c:104:static int gpio_mockup_get_multiple(struct gpio_chip *gc,\ndrivers/gpio/gpio-mockup.c-105-\t\t\t\t    unsigned long *mask, unsigned long *bits)\ndrivers/gpio/gpio-mockup.c-106-{\ndrivers/gpio/gpio-mockup.c:107:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-108-\tunsigned int bit, val;\n--\ndrivers/gpio/gpio-mockup.c-111-\t\tfor_each_set_bit(bit, mask, gc-\u003engpio) {\ndrivers/gpio/gpio-mockup.c:112:\t\t\tval = __gpio_mockup_get(chip, bit);\ndrivers/gpio/gpio-mockup.c-113-\t\t\t__assign_bit(bit, bits, val);\n--\ndrivers/gpio/gpio-mockup.c-119-\ndrivers/gpio/gpio-mockup.c:120:static void __gpio_mockup_set(struct gpio_mockup_chip *chip,\ndrivers/gpio/gpio-mockup.c-121-\t\t\t      unsigned int offset, int value)\n--\ndrivers/gpio/gpio-mockup.c-125-\ndrivers/gpio/gpio-mockup.c:126:static int gpio_mockup_set(struct gpio_chip *gc,\ndrivers/gpio/gpio-mockup.c-127-\t\t\t   unsigned int offset, int value)\ndrivers/gpio/gpio-mockup.c-128-{\ndrivers/gpio/gpio-mockup.c:129:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-130-\n--\ndrivers/gpio/gpio-mockup.c-132-\ndrivers/gpio/gpio-mockup.c:133:\t__gpio_mockup_set(chip, offset, value);\ndrivers/gpio/gpio-mockup.c-134-\n--\ndrivers/gpio/gpio-mockup.c-137-\ndrivers/gpio/gpio-mockup.c:138:static int gpio_mockup_set_multiple(struct gpio_chip *gc,\ndrivers/gpio/gpio-mockup.c-139-\t\t\t\t    unsigned long *mask, unsigned long *bits)\ndrivers/gpio/gpio-mockup.c-140-{\ndrivers/gpio/gpio-mockup.c:141:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-142-\tunsigned int bit;\n--\ndrivers/gpio/gpio-mockup.c-146-\tfor_each_set_bit(bit, mask, gc-\u003engpio)\ndrivers/gpio/gpio-mockup.c:147:\t\t__gpio_mockup_set(chip, bit, test_bit(bit, bits));\ndrivers/gpio/gpio-mockup.c-148-\n--\ndrivers/gpio/gpio-mockup.c-151-\ndrivers/gpio/gpio-mockup.c:152:static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,\ndrivers/gpio/gpio-mockup.c-153-\t\t\t\t  unsigned int offset, int value)\ndrivers/gpio/gpio-mockup.c-154-{\ndrivers/gpio/gpio-mockup.c:155:\tstruct gpio_mockup_line_status *line = \u0026chip-\u003elines[offset];\ndrivers/gpio/gpio-mockup.c-156-\tint curr, irq, irq_type, ret = 0;\n--\ndrivers/gpio/gpio-mockup.c-160-\tif (line-\u003erequested \u0026\u0026 line-\u003edir == GPIO_LINE_DIRECTION_IN) {\ndrivers/gpio/gpio-mockup.c:161:\t\tcurr = __gpio_mockup_get(chip, offset);\ndrivers/gpio/gpio-mockup.c-162-\t\tif (curr == value)\n--\ndrivers/gpio/gpio-mockup.c-188-\tif (!line-\u003erequested || line-\u003edir == GPIO_LINE_DIRECTION_IN)\ndrivers/gpio/gpio-mockup.c:189:\t\t__gpio_mockup_set(chip, offset, value);\ndrivers/gpio/gpio-mockup.c-190-\n--\ndrivers/gpio/gpio-mockup.c-195-\ndrivers/gpio/gpio-mockup.c:196:static int gpio_mockup_set_config(struct gpio_chip *gc,\ndrivers/gpio/gpio-mockup.c-197-\t\t\t\t  unsigned int offset, unsigned long config)\ndrivers/gpio/gpio-mockup.c-198-{\ndrivers/gpio/gpio-mockup.c:199:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-200-\n--\ndrivers/gpio/gpio-mockup.c-202-\tcase PIN_CONFIG_BIAS_PULL_UP:\ndrivers/gpio/gpio-mockup.c:203:\t\treturn gpio_mockup_apply_pull(chip, offset, 1);\ndrivers/gpio/gpio-mockup.c-204-\tcase PIN_CONFIG_BIAS_PULL_DOWN:\ndrivers/gpio/gpio-mockup.c:205:\t\treturn gpio_mockup_apply_pull(chip, offset, 0);\ndrivers/gpio/gpio-mockup.c-206-\tdefault:\n--\ndrivers/gpio/gpio-mockup.c-211-\ndrivers/gpio/gpio-mockup.c:212:static int gpio_mockup_dirout(struct gpio_chip *gc,\ndrivers/gpio/gpio-mockup.c-213-\t\t\t      unsigned int offset, int value)\ndrivers/gpio/gpio-mockup.c-214-{\ndrivers/gpio/gpio-mockup.c:215:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-216-\n--\ndrivers/gpio/gpio-mockup.c-218-\t\tchip-\u003elines[offset].dir = GPIO_LINE_DIRECTION_OUT;\ndrivers/gpio/gpio-mockup.c:219:\t\t__gpio_mockup_set(chip, offset, value);\ndrivers/gpio/gpio-mockup.c-220-\t}\n--\ndrivers/gpio/gpio-mockup.c-224-\ndrivers/gpio/gpio-mockup.c:225:static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)\ndrivers/gpio/gpio-mockup.c-226-{\ndrivers/gpio/gpio-mockup.c:227:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-228-\n--\ndrivers/gpio/gpio-mockup.c-234-\ndrivers/gpio/gpio-mockup.c:235:static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)\ndrivers/gpio/gpio-mockup.c-236-{\ndrivers/gpio/gpio-mockup.c:237:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-238-\tint direction;\n--\ndrivers/gpio/gpio-mockup.c-245-\ndrivers/gpio/gpio-mockup.c:246:static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset)\ndrivers/gpio/gpio-mockup.c-247-{\ndrivers/gpio/gpio-mockup.c:248:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-249-\n--\ndrivers/gpio/gpio-mockup.c-252-\ndrivers/gpio/gpio-mockup.c:253:static int gpio_mockup_request(struct gpio_chip *gc, unsigned int offset)\ndrivers/gpio/gpio-mockup.c-254-{\ndrivers/gpio/gpio-mockup.c:255:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-256-\n--\ndrivers/gpio/gpio-mockup.c-262-\ndrivers/gpio/gpio-mockup.c:263:static void gpio_mockup_free(struct gpio_chip *gc, unsigned int offset)\ndrivers/gpio/gpio-mockup.c-264-{\ndrivers/gpio/gpio-mockup.c:265:\tstruct gpio_mockup_chip *chip = gpiochip_get_data(gc);\ndrivers/gpio/gpio-mockup.c-266-\n--\ndrivers/gpio/gpio-mockup.c-269-\tchip-\u003elines[offset].requested = false;\ndrivers/gpio/gpio-mockup.c:270:\t__gpio_mockup_set(chip, offset, chip-\u003elines[offset].pull);\ndrivers/gpio/gpio-mockup.c-271-}\ndrivers/gpio/gpio-mockup.c-272-\ndrivers/gpio/gpio-mockup.c:273:static ssize_t gpio_mockup_debugfs_read(struct file *file,\ndrivers/gpio/gpio-mockup.c-274-\t\t\t\t\tchar __user *usr_buf,\n--\ndrivers/gpio/gpio-mockup.c-276-{\ndrivers/gpio/gpio-mockup.c:277:\tstruct gpio_mockup_dbgfs_private *priv;\ndrivers/gpio/gpio-mockup.c:278:\tstruct gpio_mockup_chip *chip;\ndrivers/gpio/gpio-mockup.c-279-\tstruct seq_file *sfile;\n--\ndrivers/gpio/gpio-mockup.c-291-\ndrivers/gpio/gpio-mockup.c:292:\tval = gpio_mockup_get(gc, priv-\u003eoffset);\ndrivers/gpio/gpio-mockup.c-293-\tcnt = snprintf(buf, sizeof(buf), \"%d\\n\", val);\n--\ndrivers/gpio/gpio-mockup.c-297-\ndrivers/gpio/gpio-mockup.c:298:static ssize_t gpio_mockup_debugfs_write(struct file *file,\ndrivers/gpio/gpio-mockup.c-299-\t\t\t\t\t const char __user *usr_buf,\n--\ndrivers/gpio/gpio-mockup.c-301-{\ndrivers/gpio/gpio-mockup.c:302:\tstruct gpio_mockup_dbgfs_private *priv;\ndrivers/gpio/gpio-mockup.c-303-\tint rv, val;\n--\ndrivers/gpio/gpio-mockup.c-316-\tpriv = sfile-\u003eprivate;\ndrivers/gpio/gpio-mockup.c:317:\trv = gpio_mockup_apply_pull(priv-\u003echip, priv-\u003eoffset, val);\ndrivers/gpio/gpio-mockup.c-318-\tif (rv)\n--\ndrivers/gpio/gpio-mockup.c-323-\ndrivers/gpio/gpio-mockup.c:324:static int gpio_mockup_debugfs_open(struct inode *inode, struct file *file)\ndrivers/gpio/gpio-mockup.c-325-{\n--\ndrivers/gpio/gpio-mockup.c-329-/*\ndrivers/gpio/gpio-mockup.c:330: * Each mockup chip is represented by a directory named after the chip's device\ndrivers/gpio/gpio-mockup.c:331: * name under /sys/kernel/debug/gpio-mockup/. Each line is represented by\ndrivers/gpio/gpio-mockup.c-332- * a file using the line's offset as the name under the chip's directory.\n--\ndrivers/gpio/gpio-mockup.c-334- * Reading from the line's file yields the current *value*, writing to the\ndrivers/gpio/gpio-mockup.c:335: * line's file changes the current *pull*. Default pull for mockup lines is\ndrivers/gpio/gpio-mockup.c-336- * down.\n--\ndrivers/gpio/gpio-mockup.c-349- */\ndrivers/gpio/gpio-mockup.c:350:static const struct file_operations gpio_mockup_debugfs_ops = {\ndrivers/gpio/gpio-mockup.c-351-\t.owner = THIS_MODULE,\ndrivers/gpio/gpio-mockup.c:352:\t.open = gpio_mockup_debugfs_open,\ndrivers/gpio/gpio-mockup.c:353:\t.read = gpio_mockup_debugfs_read,\ndrivers/gpio/gpio-mockup.c:354:\t.write = gpio_mockup_debugfs_write,\ndrivers/gpio/gpio-mockup.c-355-\t.release = single_release,\n--\ndrivers/gpio/gpio-mockup.c-357-\ndrivers/gpio/gpio-mockup.c:358:static void gpio_mockup_debugfs_setup(struct device *dev,\ndrivers/gpio/gpio-mockup.c:359:\t\t\t\t      struct gpio_mockup_chip *chip)\ndrivers/gpio/gpio-mockup.c-360-{\ndrivers/gpio/gpio-mockup.c:361:\tstruct gpio_mockup_dbgfs_private *priv;\ndrivers/gpio/gpio-mockup.c-362-\tstruct gpio_chip *gc;\n--\ndrivers/gpio/gpio-mockup.c-370-\t * There can only be a single GPIO device per platform device in\ndrivers/gpio/gpio-mockup.c:371:\t * gpio-mockup so using device_find_any_child() is OK.\ndrivers/gpio/gpio-mockup.c-372-\t */\n--\ndrivers/gpio/gpio-mockup.c-377-\tdevname = dev_name(child);\ndrivers/gpio/gpio-mockup.c:378:\tchip-\u003edbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir);\ndrivers/gpio/gpio-mockup.c-379-\n--\ndrivers/gpio/gpio-mockup.c-392-\t\tdebugfs_create_file(name, 0600, chip-\u003edbg_dir, priv,\ndrivers/gpio/gpio-mockup.c:393:\t\t\t\t    \u0026gpio_mockup_debugfs_ops);\ndrivers/gpio/gpio-mockup.c-394-\t}\n--\ndrivers/gpio/gpio-mockup.c-396-\ndrivers/gpio/gpio-mockup.c:397:static void gpio_mockup_debugfs_cleanup(void *data)\ndrivers/gpio/gpio-mockup.c-398-{\ndrivers/gpio/gpio-mockup.c:399:\tstruct gpio_mockup_chip *chip = data;\ndrivers/gpio/gpio-mockup.c-400-\n--\ndrivers/gpio/gpio-mockup.c-403-\ndrivers/gpio/gpio-mockup.c:404:static void gpio_mockup_dispose_mappings(void *data)\ndrivers/gpio/gpio-mockup.c-405-{\ndrivers/gpio/gpio-mockup.c:406:\tstruct gpio_mockup_chip *chip = data;\ndrivers/gpio/gpio-mockup.c-407-\tstruct gpio_chip *gc = \u0026chip-\u003egc;\n--\ndrivers/gpio/gpio-mockup.c-416-\ndrivers/gpio/gpio-mockup.c:417:static int gpio_mockup_probe(struct platform_device *pdev)\ndrivers/gpio/gpio-mockup.c-418-{\ndrivers/gpio/gpio-mockup.c:419:\tstruct gpio_mockup_chip *chip;\ndrivers/gpio/gpio-mockup.c-420-\tstruct gpio_chip *gc;\n--\ndrivers/gpio/gpio-mockup.c-451-\tgc-\u003eparent = dev;\ndrivers/gpio/gpio-mockup.c:452:\tgc-\u003eget = gpio_mockup_get;\ndrivers/gpio/gpio-mockup.c:453:\tgc-\u003eset = gpio_mockup_set;\ndrivers/gpio/gpio-mockup.c:454:\tgc-\u003eget_multiple = gpio_mockup_get_multiple;\ndrivers/gpio/gpio-mockup.c:455:\tgc-\u003eset_multiple = gpio_mockup_set_multiple;\ndrivers/gpio/gpio-mockup.c:456:\tgc-\u003edirection_output = gpio_mockup_dirout;\ndrivers/gpio/gpio-mockup.c:457:\tgc-\u003edirection_input = gpio_mockup_dirin;\ndrivers/gpio/gpio-mockup.c:458:\tgc-\u003eget_direction = gpio_mockup_get_direction;\ndrivers/gpio/gpio-mockup.c:459:\tgc-\u003eset_config = gpio_mockup_set_config;\ndrivers/gpio/gpio-mockup.c:460:\tgc-\u003eto_irq = gpio_mockup_to_irq;\ndrivers/gpio/gpio-mockup.c:461:\tgc-\u003erequest = gpio_mockup_request;\ndrivers/gpio/gpio-mockup.c:462:\tgc-\u003efree = gpio_mockup_free;\ndrivers/gpio/gpio-mockup.c-463-\n--\ndrivers/gpio/gpio-mockup.c-476-\ndrivers/gpio/gpio-mockup.c:477:\trv = devm_add_action_or_reset(dev, gpio_mockup_dispose_mappings, chip);\ndrivers/gpio/gpio-mockup.c-478-\tif (rv)\n--\ndrivers/gpio/gpio-mockup.c-484-\ndrivers/gpio/gpio-mockup.c:485:\tgpio_mockup_debugfs_setup(dev, chip);\ndrivers/gpio/gpio-mockup.c-486-\ndrivers/gpio/gpio-mockup.c:487:\treturn devm_add_action_or_reset(dev, gpio_mockup_debugfs_cleanup, chip);\ndrivers/gpio/gpio-mockup.c-488-}\ndrivers/gpio/gpio-mockup.c-489-\ndrivers/gpio/gpio-mockup.c:490:static const struct of_device_id gpio_mockup_of_match[] = {\ndrivers/gpio/gpio-mockup.c:491:\t{ .compatible = \"gpio-mockup\", },\ndrivers/gpio/gpio-mockup.c-492-\t{},\ndrivers/gpio/gpio-mockup.c-493-};\ndrivers/gpio/gpio-mockup.c:494:MODULE_DEVICE_TABLE(of, gpio_mockup_of_match);\ndrivers/gpio/gpio-mockup.c-495-\ndrivers/gpio/gpio-mockup.c:496:static struct platform_driver gpio_mockup_driver = {\ndrivers/gpio/gpio-mockup.c-497-\t.driver = {\ndrivers/gpio/gpio-mockup.c:498:\t\t.name = \"gpio-mockup\",\ndrivers/gpio/gpio-mockup.c:499:\t\t.of_match_table = gpio_mockup_of_match,\ndrivers/gpio/gpio-mockup.c-500-\t},\ndrivers/gpio/gpio-mockup.c:501:\t.probe = gpio_mockup_probe,\ndrivers/gpio/gpio-mockup.c-502-};\ndrivers/gpio/gpio-mockup.c-503-\ndrivers/gpio/gpio-mockup.c:504:static struct platform_device *gpio_mockup_pdevs[GPIO_MOCKUP_MAX_GC];\ndrivers/gpio/gpio-mockup.c-505-\ndrivers/gpio/gpio-mockup.c:506:static void gpio_mockup_unregister_pdevs(void)\ndrivers/gpio/gpio-mockup.c-507-{\n--\ndrivers/gpio/gpio-mockup.c-512-\tfor (i = 0; i \u003c GPIO_MOCKUP_MAX_GC; i++) {\ndrivers/gpio/gpio-mockup.c:513:\t\tpdev = gpio_mockup_pdevs[i];\ndrivers/gpio/gpio-mockup.c-514-\t\tif (!pdev)\n--\ndrivers/gpio/gpio-mockup.c-522-\ndrivers/gpio/gpio-mockup.c:523:static int __init gpio_mockup_register_chip(int idx)\ndrivers/gpio/gpio-mockup.c-524-{\n--\ndrivers/gpio/gpio-mockup.c-536-\ndrivers/gpio/gpio-mockup.c:537:\tsnprintf(chip_label, sizeof(chip_label), \"gpio-mockup-%c\", idx + 'A');\ndrivers/gpio/gpio-mockup.c-538-\tproperties[prop++] = PROPERTY_ENTRY_STRING(\"chip-label\", chip_label);\ndrivers/gpio/gpio-mockup.c-539-\ndrivers/gpio/gpio-mockup.c:540:\tbase = gpio_mockup_range_base(idx);\ndrivers/gpio/gpio-mockup.c-541-\tif (base \u003e= 0)\n--\ndrivers/gpio/gpio-mockup.c-543-\ndrivers/gpio/gpio-mockup.c:544:\tngpio = base \u003c 0 ? gpio_mockup_range_ngpio(idx)\ndrivers/gpio/gpio-mockup.c:545:\t\t\t : gpio_mockup_range_ngpio(idx) - base;\ndrivers/gpio/gpio-mockup.c-546-\tproperties[prop++] = PROPERTY_ENTRY_U16(\"nr-gpios\", ngpio);\ndrivers/gpio/gpio-mockup.c-547-\ndrivers/gpio/gpio-mockup.c:548:\tif (gpio_mockup_named_lines) {\ndrivers/gpio/gpio-mockup.c-549-\t\tline_names = kasprintf_strarray(GFP_KERNEL, chip_label, ngpio);\n--\ndrivers/gpio/gpio-mockup.c-562-\ndrivers/gpio/gpio-mockup.c:563:\tpdevinfo.name = \"gpio-mockup\";\ndrivers/gpio/gpio-mockup.c-564-\tpdevinfo.id = idx;\n--\ndrivers/gpio/gpio-mockup.c-574-\ndrivers/gpio/gpio-mockup.c:575:\tgpio_mockup_pdevs[idx] = pdev;\ndrivers/gpio/gpio-mockup.c-576-\n--\ndrivers/gpio/gpio-mockup.c-579-\ndrivers/gpio/gpio-mockup.c:580:static int __init gpio_mockup_init(void)\ndrivers/gpio/gpio-mockup.c-581-{\n--\ndrivers/gpio/gpio-mockup.c-583-\ndrivers/gpio/gpio-mockup.c:584:\tif ((gpio_mockup_num_ranges % 2) ||\ndrivers/gpio/gpio-mockup.c:585:\t    (gpio_mockup_num_ranges \u003e GPIO_MOCKUP_MAX_RANGES))\ndrivers/gpio/gpio-mockup.c-586-\t\treturn -EINVAL;\n--\ndrivers/gpio/gpio-mockup.c-588-\t/* Each chip is described by two values. */\ndrivers/gpio/gpio-mockup.c:589:\tnum_chips = gpio_mockup_num_ranges / 2;\ndrivers/gpio/gpio-mockup.c-590-\n--\ndrivers/gpio/gpio-mockup.c-595-\tfor (i = 0; i \u003c num_chips; i++) {\ndrivers/gpio/gpio-mockup.c:596:\t\tbase = gpio_mockup_range_base(i);\ndrivers/gpio/gpio-mockup.c:597:\t\tngpio = gpio_mockup_range_ngpio(i);\ndrivers/gpio/gpio-mockup.c-598-\n--\ndrivers/gpio/gpio-mockup.c-610-\ndrivers/gpio/gpio-mockup.c:611:\tgpio_mockup_dbg_dir = debugfs_create_dir(\"gpio-mockup\", NULL);\ndrivers/gpio/gpio-mockup.c-612-\ndrivers/gpio/gpio-mockup.c:613:\terr = platform_driver_register(\u0026gpio_mockup_driver);\ndrivers/gpio/gpio-mockup.c-614-\tif (err) {\ndrivers/gpio/gpio-mockup.c-615-\t\tpr_err(\"error registering platform driver\\n\");\ndrivers/gpio/gpio-mockup.c:616:\t\tdebugfs_remove_recursive(gpio_mockup_dbg_dir);\ndrivers/gpio/gpio-mockup.c-617-\t\treturn err;\n--\ndrivers/gpio/gpio-mockup.c-620-\tfor (i = 0; i \u003c num_chips; i++) {\ndrivers/gpio/gpio-mockup.c:621:\t\terr = gpio_mockup_register_chip(i);\ndrivers/gpio/gpio-mockup.c-622-\t\tif (err) {\ndrivers/gpio/gpio-mockup.c:623:\t\t\tplatform_driver_unregister(\u0026gpio_mockup_driver);\ndrivers/gpio/gpio-mockup.c:624:\t\t\tgpio_mockup_unregister_pdevs();\ndrivers/gpio/gpio-mockup.c:625:\t\t\tdebugfs_remove_recursive(gpio_mockup_dbg_dir);\ndrivers/gpio/gpio-mockup.c-626-\t\t\treturn err;\n--\ndrivers/gpio/gpio-mockup.c-632-\ndrivers/gpio/gpio-mockup.c:633:static void __exit gpio_mockup_exit(void)\ndrivers/gpio/gpio-mockup.c-634-{\ndrivers/gpio/gpio-mockup.c:635:\tgpio_mockup_unregister_pdevs();\ndrivers/gpio/gpio-mockup.c:636:\tdebugfs_remove_recursive(gpio_mockup_dbg_dir);\ndrivers/gpio/gpio-mockup.c:637:\tplatform_driver_unregister(\u0026gpio_mockup_driver);\ndrivers/gpio/gpio-mockup.c-638-}\ndrivers/gpio/gpio-mockup.c-639-\ndrivers/gpio/gpio-mockup.c:640:module_init(gpio_mockup_init);\ndrivers/gpio/gpio-mockup.c:641:module_exit(gpio_mockup_exit);\ndrivers/gpio/gpio-mockup.c-642-\n--\ndrivers/net/dsa/dsa_loop.c=446=static int __init dsa_loop_create_switch_mdiodev(void)\n--\ndrivers/net/dsa/dsa_loop.c-455-\t\t},\ndrivers/net/dsa/dsa_loop.c:456:\t\t.name = \"DSA mockup driver\",\ndrivers/net/dsa/dsa_loop.c-457-\t\t.enabled_ports = 0x1f,\n--\ndrivers/soundwire/bus.c=415=static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags,\n--\ndrivers/soundwire/bus.c-430-\t\tret = sdw_transfer(slave-\u003ebus, \u0026msg);\ndrivers/soundwire/bus.c:431:\t\tif (ret \u003c 0 \u0026\u0026 !slave-\u003eis_mockup_device)\ndrivers/soundwire/bus.c-432-\t\t\treturn ret;\n--\ndrivers/soundwire/stream.c=132=static int sdw_program_slave_port_params(struct sdw_bus *bus,\n--\ndrivers/soundwire/stream.c-144-\ndrivers/soundwire/stream.c:145:\tif (s_rt-\u003eslave-\u003eis_mockup_device)\ndrivers/soundwire/stream.c-146-\t\treturn 0;\n--\ninclude/linux/soundwire/sdw.h=617=struct sdw_slave_ops {\n--\ninclude/linux/soundwire/sdw.h-660- * for a Slave happens for the first time after enumeration\ninclude/linux/soundwire/sdw.h:661: * @is_mockup_device: status flag used to squelch errors in the command/control\ninclude/linux/soundwire/sdw.h:662: * protocol for SoundWire mockup devices\ninclude/linux/soundwire/sdw.h-663- * @sdw_dev_lock: mutex used to protect callbacks/remove races\n--\ninclude/linux/soundwire/sdw.h=666=struct sdw_slave {\n--\ninclude/linux/soundwire/sdw.h-686-\tbool first_interrupt_done;\ninclude/linux/soundwire/sdw.h:687:\tbool is_mockup_device;\ninclude/linux/soundwire/sdw.h-688-\tstruct mutex sdw_dev_lock; /* protect callbacks/remove races */\n--\nsound/soc/codecs/Kconfig=2025=config SND_SOC_SDW_MOCKUP\nsound/soc/codecs/Kconfig:2026:\ttristate \"SoundWire mockup codec\"\nsound/soc/codecs/Kconfig-2027-\tdepends on EXPERT\n--\nsound/soc/codecs/Kconfig-2029-\thelp\nsound/soc/codecs/Kconfig:2030:\t  This option enables a SoundWire mockup codec that does not drive the\nsound/soc/codecs/Kconfig-2031-\t  bus, take part in the command/command protocol or generate data on a\n--\nsound/soc/codecs/Kconfig-2035-\t  topologies that differ from the actual hardware layout.\nsound/soc/codecs/Kconfig:2036:\t  This mockup device could be totally virtual but could also be a\nsound/soc/codecs/Kconfig-2037-\t  real physical one with one key restriction: it is not allowed by the\n--\nsound/soc/codecs/Makefile=291=snd-soc-rtq9128-y := rtq9128.o\nsound/soc/codecs/Makefile:292:snd-soc-sdw-mockup-y := sdw-mockup.o\nsound/soc/codecs/Makefile-293-snd-soc-sgtl5000-y := sgtl5000.o\n--\nsound/soc/codecs/Makefile=731=obj-$(CONFIG_SND_SOC_RTQ9128)\t+= snd-soc-rtq9128.o\nsound/soc/codecs/Makefile:732:obj-$(CONFIG_SND_SOC_SDW_MOCKUP)     += snd-soc-sdw-mockup.o\nsound/soc/codecs/Makefile-733-obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o\n--\nsound/soc/codecs/sdw-mockup.c-2-//\nsound/soc/codecs/sdw-mockup.c:3:// sdw-mockup.c -- a mockup SoundWire codec for tests where only the host\nsound/soc/codecs/sdw-mockup.c-4-// drives the bus.\n--\nsound/soc/codecs/sdw-mockup.c-21-\nsound/soc/codecs/sdw-mockup.c:22:struct  sdw_mockup_priv {\nsound/soc/codecs/sdw-mockup.c-23-\tstruct sdw_slave *slave;\n--\nsound/soc/codecs/sdw-mockup.c-25-\nsound/soc/codecs/sdw-mockup.c:26:static int sdw_mockup_component_probe(struct snd_soc_component *component)\nsound/soc/codecs/sdw-mockup.c-27-{\n--\nsound/soc/codecs/sdw-mockup.c-30-\nsound/soc/codecs/sdw-mockup.c:31:static void sdw_mockup_component_remove(struct snd_soc_component *component)\nsound/soc/codecs/sdw-mockup.c-32-{\n\n"
}

15/2 2026/07/09 01:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 71329
							output: 29
							thoughts: 1028
						

Thoughts:
**Unreachable PHY Driver Analysis**

Okay, so there's no `mdio-mockup` I can immediately leverage. Let's see how syzkaller handles networking drivers generally. I recall it utilizes various netdevs like `tun`/`tap`, `veth`, `mac80211_hwsim`, and others. However, for hardware-specific drivers, I'm usually stuck unless the hardware can be emulated.

Syzkaller does have clever workarounds: `syz_usb_connect` for USB, `syz_pci_connect` (maybe, I'm not entirely sure about its current status), `syz_vhci` for Bluetooth, and related calls for 802.11. But for MDIO PHYs, there's no equivalent virtual MDIO bus I can use to inject arbitrary PHYs.

Now, the instructions I saw mention something important: "Return WorthFuzzing=false if the patch only contains... code paths that are impossible to reach in virtualized environments... even when utilizing software-emulated hardware". That's what I need to figure out here. Is this PHY driver reachable?

This is either a platform driver or an MDIO driver. If so, it will need a device tree node or a platform device to be instantiated. Can syzkaller do that, maybe with `syz_dev_create`? Nope, not directly. I *could* instantiate MDIO devices if there was a virtual MDIO bus.

Actually, the `dsa_loop` driver uses `fixed_phy_register_100fd()`, which means there might be other ways to do it. Let me check if there is any `mdio` bus that can be created from userspace... nope, nothing. So, is this PHY driver reachable? If it's an MDIO PHY driver, it registers itself with `phy_driver_register()`. When an MDIO bus scans, it reads the PHY ID registers, and if they match, the driver is bound. Since there is no virtual MDIO bus I can control to return arbitrary PHY IDs, this is not going to bind.

Wait, what if QEMU emulates a network card with an MDIO bus? QEMU emulates `e1000`, `rtl8139`, `pcnet`, `ne2k_pci`, `virtio-net`, `vmxnet3`. But none of these use Airoha or MediaTek PHY drivers. I should double-check QEMU for any MDIO emulation syzkaller actually uses, though. QEMU has `imx.fec`, which has an MDIO bus, but it's for ARM machines. Syzkaller usually runs on x86_64 or arm64 `virt`, which uses `virtio-net`.

Yeah, that PHY driver is unreachable. Let's look for other avenues. Can I instantiate a PHY driver via sysfs? Maybe something like `echo "0x03a294c1" > /sys/bus/mdio_bus/drivers/Airoha\ AN7581\ PHY/bind`? You can bind a driver to an *existing* device. But you need an existing MDIO device. Is there one by default? If there's no MDIO bus, there's no MDIO devices. Is there an MDIO bus created by default? Let me check if a `fixed-0` MDIO bus is created. Yes, `fixed_mdio_bus` is created by `fixed_mdio_bus_init()`. Can I bind this driver to a fixed PHY? Fixed PHYs have PHY ID `0x00000000` or similar. The driver matches on `PHY_ID_MATCH_EXACT(AIROHA_GPHY_ID_AN7581)`. If I write to `/sys/bus/mdio_bus/devices/fixed-0:00/driver_override` and then bind? First, let's see if `driver_override` exists for MDIO bus...



16/2 2026/07/09 01:12 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "driver_override",
  "PathPrefix": "drivers/net/phy/"
}

Results:
{
  "error": "no matches"
}

17/2 2026/07/09 01:12 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 73284
							output: 35
							thoughts: 38
						

Thoughts:
Okay, here's my interpretation of those thoughts, summarized from an expert's perspective:

**MDIO Driver Inquiry**

Alright, let's see. I'm looking into the MDIO bus driver situation, and I need to figure out how device overrides are handled... or, rather, why they might *not* be. The first thing that jumps out at me is that the MDIO bus itself doesn't explicitly implement `driver_override`. I need to figure out if that's by design. The way to find out where the driver override functionality for the MDIO bus lies is to look where the MDIO bus is defined. Ah ha! I need to check the `mdio_bus_type` structure. That would be in `drivers/net/phy/mdio_bus.c`. That should point me to the right place to figure out how devices are handled. That's where the heart of the bus lies.



18/2 2026/07/09 01:13 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "driver_override",
  "PathPrefix": "drivers/net/phy/mdio_bus.c"
}

Results:
{
  "error": "no matches"
}

19/2 2026/07/09 01:13 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 73569
							output: 131
							thoughts: 959
						

Thoughts:
**Unreachable PHY Driver: WorthFuzzing=false**

Okay, so I've been looking at this patch and, after some thinking, I've come to the conclusion that it's not worth fuzzing. The core issue is that this patch introduces a new PHY driver, specifically for Airoha SoCs, and it refactors the existing MediaTek PHY driver to share code. My primary concern is that these are hardware-specific PHY drivers, and therefore, their code paths are *impossible* to reach in virtualized environments, like the ones used for fuzzing.

I started by considering the typical instantiation of PHY drivers. You can't just force-bind a PHY driver. I looked at `i2c` and `spi`, but they use the `new_device` sysfs attribute, which MDIO doesn't have. This immediately flags the problem: we can't create MDIO devices from userspace, therefore we can't reliably reach this driver in QEMU or GCE.

I briefly considered if there's some other way, like `dsa_loop` or other existing drivers that might create fixed PHYs. However, I didn't see anything obvious. Given the lack of a virtual MDIO bus or software-emulated hardware in these environments, there is no way to instantiate this particular PHY driver.

Okay, let me break down the patch itself. I see it adds `drivers/net/phy/mediatek/airoha-ge-soc.c`, modifies `drivers/net/phy/mediatek/mtk-ge-soc.c` to remove Airoha PHYs, and updates some header files. It also modifies `drivers/net/phy/mediatek/mtk-phy-lib.c`, making some functions exported to be used. The export is essentially just adding `EXPORT_SYMBOL_GPL`. There are no functional changes to reachable core logic. So the whole patch is adding the new hardware-specific Airoha PHY driver and refactoring the existing MediaTek PHY driver to share code with it.

I'm verifying that there's no way to reach this code. Is there a chance that this driver could be probed via some other driver, like `mdio-bcm-unimac.c`? No, you'd need the actual hardware or an emulator of the hardware. Syzkaller doesn't emulate Airoha or MediaTek SoCs. Therefore, it's unreachable.

So my reasoning is: "The patch introduces a new hardware-specific Ethernet PHY driver for Airoha SoCs and refactors the existing MediaTek PHY driver to share code. Since PHY devices are instantiated by the MDIO bus based on hardware probing (reading PHY ID registers) or device tree, and there is no virtual MDIO bus or software-emulated hardware in virtualized environments (like QEMU/GCE) that can instantiate this specific PHY, the code is impossible to reach and test via fuzzing."

Let's quickly check the guidelines. The instructions say, "Return WorthFuzzing=false if the patch only contains code paths that are impossible to reach in virtualized environments." This *perfectly* aligns with the situation here. I'm going to set `WorthFuzzing=false`.

I want to be thorough, so I'll check any other modified files. Okay, I see `MAINTAINERS` (docs), `Kconfig`, `Makefile`, and the source and header files for the new driver and the refactored code. All the changes are related to the Airoha PHY driver and related code. These are all hardware-specific PHY drivers, so it's a closed case. `WorthFuzzing=false`.



20/2 2026/07/09 01:13 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch introduces a new hardware-specific Ethernet PHY driver for Airoha SoCs and refactors the existing MediaTek PHY driver to share code. Since PHY devices are instantiated by the MDIO bus based on hardware probing (reading PHY ID registers) or device tree, and there is no virtual MDIO bus or software-emulated hardware in virtualized environments (like QEMU/GCE) that can instantiate this specific PHY, the code is impossible to reach and test via fuzzing.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch introduces a new hardware-specific Ethernet PHY driver for Airoha SoCs and refactors the existing MediaTek PHY driver to share code. Since PHY devices are instantiated by the MDIO bus based on hardware probing (reading PHY ID registers) or device tree, and there is no virtual MDIO bus or software-emulated hardware in virtualized environments (like QEMU/GCE) that can instantiate this specific PHY, the code is impossible to reach and test via fuzzing.",
  "WorthFuzzing": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)