Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'airoha-an8811hb-2-5-gbps-phy-support'

Bjørn Mork says:

====================
Airoha AN8811HB 2.5 Gbps phy support

The RFC patch posted earlier has been split into a series based on the
feedback received:

1/3: preparing the EN8811H driver for maximum reuse
2/3: adding support for the new AN8811HB hardware
3/3: adding (optional) clock driver for AN8811HB

Patch 3/3 is not required for a functional device. It is included here
for full feature parity between the EN8811H and AN8811HB drivers.

The AN8811HB phy requires new firmware, which is now available with
the 20260110 release of linux-firmware,
====================

Link: https://patch.msgid.link/20260127125547.1475164-1-bjorn@mork.no
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+412 -34
+412 -34
drivers/net/phy/air_en8811h.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0+ 2 2 /* 3 - * Driver for the Airoha EN8811H 2.5 Gigabit PHY. 3 + * Driver for the Airoha EN8811H and AN8811HB 2.5 Gigabit PHYs. 4 4 * 5 - * Limitations of the EN8811H: 5 + * Limitations: 6 6 * - Only full duplex supported 7 7 * - Forced speed (AN off) is not supported by hardware (100Mbps) 8 8 * 9 9 * Source originated from airoha's en8811h.c and en8811h.h v1.2.1 10 + * with AN8811HB bits from air_an8811hb.c v0.0.4 10 11 * 11 - * Copyright (C) 2023 Airoha Technology Corp. 12 + * Copyright (C) 2023, 2026 Airoha Technology Corp. 12 13 */ 13 14 14 15 #include <linux/clk.h> ··· 22 21 #include <linux/unaligned.h> 23 22 24 23 #define EN8811H_PHY_ID 0x03a2a411 24 + #define AN8811HB_PHY_ID 0xc0ff04a0 25 25 26 26 #define EN8811H_MD32_DM "airoha/EthMD32.dm.bin" 27 27 #define EN8811H_MD32_DSP "airoha/EthMD32.DSP.bin" 28 + #define AN8811HB_MD32_DM "airoha/an8811hb/EthMD32_CRC.DM.bin" 29 + #define AN8811HB_MD32_DSP "airoha/an8811hb/EthMD32_CRC.DSP.bin" 28 30 29 31 #define AIR_FW_ADDR_DM 0x00000000 30 32 #define AIR_FW_ADDR_DSP 0x00100000 ··· 35 31 /* MII Registers */ 36 32 #define AIR_AUX_CTRL_STATUS 0x1d 37 33 #define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2) 34 + #define AIR_AUX_CTRL_STATUS_SPEED_10 0x0 38 35 #define AIR_AUX_CTRL_STATUS_SPEED_100 0x4 39 36 #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 40 37 #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc ··· 61 56 #define EN8811H_PHY_FW_STATUS 0x8009 62 57 #define EN8811H_PHY_READY 0x02 63 58 59 + #define AIR_PHY_MCU_CMD_0 0x800b 64 60 #define AIR_PHY_MCU_CMD_1 0x800c 65 61 #define AIR_PHY_MCU_CMD_1_MODE1 0x0 66 62 #define AIR_PHY_MCU_CMD_2 0x800d ··· 71 65 #define AIR_PHY_MCU_CMD_3_DOCMD 0x1100 72 66 #define AIR_PHY_MCU_CMD_4 0x800f 73 67 #define AIR_PHY_MCU_CMD_4_MODE1 0x0002 68 + #define AIR_PHY_MCU_CMD_4_CABLE_PAIR_A 0x00d7 69 + #define AIR_PHY_MCU_CMD_4_CABLE_PAIR_B 0x00d8 70 + #define AIR_PHY_MCU_CMD_4_CABLE_PAIR_C 0x00d9 71 + #define AIR_PHY_MCU_CMD_4_CABLE_PAIR_D 0x00da 74 72 #define AIR_PHY_MCU_CMD_4_INTCLR 0x00e4 75 73 76 74 /* Registers on MDIO_MMD_VEND2 */ ··· 116 106 #define AIR_PHY_LED_BLINK_2500RX BIT(11) 117 107 118 108 /* Registers on BUCKPBUS */ 109 + #define AIR_PHY_CONTROL 0x3a9c 110 + #define AIR_PHY_CONTROL_INTERNAL BIT(11) 111 + 119 112 #define EN8811H_2P5G_LPA 0x3b30 120 113 #define EN8811H_2P5G_LPA_2P5G BIT(0) 121 114 ··· 141 128 #define EN8811H_FW_CTRL_1_FINISH 0x1 142 129 #define EN8811H_FW_CTRL_2 0x800000 143 130 #define EN8811H_FW_CTRL_2_LOADING BIT(11) 131 + 132 + #define AN8811HB_CRC_PM_SET1 0xf020c 133 + #define AN8811HB_CRC_PM_MON2 0xf0218 134 + #define AN8811HB_CRC_PM_MON3 0xf021c 135 + #define AN8811HB_CRC_DM_SET1 0xf0224 136 + #define AN8811HB_CRC_DM_MON2 0xf0230 137 + #define AN8811HB_CRC_DM_MON3 0xf0234 138 + #define AN8811HB_CRC_RD_EN BIT(0) 139 + #define AN8811HB_CRC_ST (BIT(0) | BIT(1)) 140 + #define AN8811HB_CRC_CHECK_PASS BIT(0) 141 + 142 + #define AN8811HB_TX_POLARITY 0x5ce004 143 + #define AN8811HB_TX_POLARITY_NORMAL BIT(7) 144 + #define AN8811HB_RX_POLARITY 0x5ce61c 145 + #define AN8811HB_RX_POLARITY_NORMAL BIT(7) 146 + 147 + #define AN8811HB_GPIO_OUTPUT 0x5cf8b8 148 + #define AN8811HB_GPIO_OUTPUT_345 (BIT(3) | BIT(4) | BIT(5)) 149 + 150 + #define AN8811HB_HWTRAP1 0x5cf910 151 + #define AN8811HB_HWTRAP2 0x5cf914 152 + #define AN8811HB_HWTRAP2_CKO BIT(28) 153 + 154 + #define AN8811HB_CLK_DRV 0x5cf9e4 155 + #define AN8811HB_CLK_DRV_CKO_MASK GENMASK(14, 12) 156 + #define AN8811HB_CLK_DRV_CKOPWD BIT(12) 157 + #define AN8811HB_CLK_DRV_CKO_LDPWD BIT(13) 158 + #define AN8811HB_CLK_DRV_CKO_LPPWD BIT(14) 144 159 145 160 /* Led definitions */ 146 161 #define EN8811H_LED_COUNT 3 ··· 489 448 { 490 449 int ret, reg_value; 491 450 451 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 452 + EN8811H_FW_CTRL_1_FINISH); 453 + if (ret) 454 + return ret; 455 + 492 456 /* Because of mdio-lock, may have to wait for multiple loads */ 493 457 ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 494 458 EN8811H_PHY_FW_STATUS, reg_value, ··· 507 461 return 0; 508 462 } 509 463 510 - static int en8811h_load_firmware(struct phy_device *phydev) 464 + static int an8811hb_check_crc(struct phy_device *phydev, u32 set1, 465 + u32 mon2, u32 mon3) 466 + { 467 + u32 pbus_value; 468 + int retry = 25; 469 + int ret; 470 + 471 + /* Configure CRC */ 472 + ret = air_buckpbus_reg_modify(phydev, set1, 473 + AN8811HB_CRC_RD_EN, 474 + AN8811HB_CRC_RD_EN); 475 + if (ret < 0) 476 + return ret; 477 + air_buckpbus_reg_read(phydev, set1, &pbus_value); 478 + 479 + do { 480 + msleep(300); 481 + air_buckpbus_reg_read(phydev, mon2, &pbus_value); 482 + 483 + /* We do not know what errors this check is supposed 484 + * catch or what to do about a failure. So print the 485 + * result and continue like the vendor driver does. 486 + */ 487 + if (pbus_value & AN8811HB_CRC_ST) { 488 + air_buckpbus_reg_read(phydev, mon3, &pbus_value); 489 + phydev_dbg(phydev, "CRC Check %s!\n", 490 + pbus_value & AN8811HB_CRC_CHECK_PASS ? 491 + "PASS" : "FAIL"); 492 + return air_buckpbus_reg_modify(phydev, set1, 493 + AN8811HB_CRC_RD_EN, 0); 494 + } 495 + } while (--retry); 496 + 497 + phydev_err(phydev, "CRC Check is not ready (%u)\n", pbus_value); 498 + return -ENODEV; 499 + } 500 + 501 + static void en8811h_print_fw_version(struct phy_device *phydev) 511 502 { 512 503 struct en8811h_priv *priv = phydev->priv; 504 + 505 + air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, 506 + &priv->firmware_version); 507 + phydev_info(phydev, "MD32 firmware version: %08x\n", 508 + priv->firmware_version); 509 + } 510 + 511 + static int an8811hb_load_file(struct phy_device *phydev, const char *name, 512 + u32 address) 513 + { 514 + struct device *dev = &phydev->mdio.dev; 515 + const struct firmware *fw; 516 + int ret; 517 + 518 + ret = request_firmware_direct(&fw, name, dev); 519 + if (ret < 0) 520 + return ret; 521 + 522 + ret = air_write_buf(phydev, address, fw); 523 + release_firmware(fw); 524 + return ret; 525 + } 526 + 527 + static int an8811hb_load_firmware(struct phy_device *phydev) 528 + { 529 + int ret; 530 + 531 + ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 532 + EN8811H_FW_CTRL_1_START); 533 + if (ret < 0) 534 + return ret; 535 + 536 + ret = an8811hb_load_file(phydev, AN8811HB_MD32_DM, AIR_FW_ADDR_DM); 537 + if (ret < 0) 538 + return ret; 539 + 540 + ret = an8811hb_check_crc(phydev, AN8811HB_CRC_DM_SET1, 541 + AN8811HB_CRC_DM_MON2, 542 + AN8811HB_CRC_DM_MON3); 543 + if (ret < 0) 544 + return ret; 545 + 546 + ret = an8811hb_load_file(phydev, AN8811HB_MD32_DSP, AIR_FW_ADDR_DSP); 547 + if (ret < 0) 548 + return ret; 549 + 550 + ret = an8811hb_check_crc(phydev, AN8811HB_CRC_PM_SET1, 551 + AN8811HB_CRC_PM_MON2, 552 + AN8811HB_CRC_PM_MON3); 553 + if (ret < 0) 554 + return ret; 555 + 556 + return en8811h_wait_mcu_ready(phydev); 557 + } 558 + 559 + static int en8811h_load_firmware(struct phy_device *phydev) 560 + { 513 561 struct device *dev = &phydev->mdio.dev; 514 562 const struct firmware *fw1, *fw2; 515 563 int ret; ··· 640 500 if (ret < 0) 641 501 goto en8811h_load_firmware_out; 642 502 643 - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 644 - EN8811H_FW_CTRL_1_FINISH); 503 + ret = en8811h_wait_mcu_ready(phydev); 645 504 if (ret < 0) 646 505 goto en8811h_load_firmware_out; 647 506 648 - ret = en8811h_wait_mcu_ready(phydev); 649 - 650 - air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, 651 - &priv->firmware_version); 652 - phydev_info(phydev, "MD32 firmware version: %08x\n", 653 - priv->firmware_version); 507 + en8811h_print_fw_version(phydev); 654 508 655 509 en8811h_load_firmware_out: 656 510 release_firmware(fw2); ··· 664 530 665 531 ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 666 532 EN8811H_FW_CTRL_1_START); 667 - if (ret < 0) 668 - return ret; 669 - 670 - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, 671 - EN8811H_FW_CTRL_1_FINISH); 672 533 if (ret < 0) 673 534 return ret; 674 535 ··· 949 820 return 0; 950 821 }; 951 822 823 + static unsigned long an8811hb_clk_recalc_rate(struct clk_hw *hw, 824 + unsigned long parent) 825 + { 826 + struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw); 827 + struct phy_device *phydev = priv->phydev; 828 + u32 pbus_value; 829 + int ret; 830 + 831 + ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); 832 + if (ret < 0) 833 + return ret; 834 + 835 + return (pbus_value & AN8811HB_HWTRAP2_CKO) ? 50000000 : 25000000; 836 + } 837 + 838 + static int an8811hb_clk_enable(struct clk_hw *hw) 839 + { 840 + struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw); 841 + struct phy_device *phydev = priv->phydev; 842 + 843 + return air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, 844 + AN8811HB_CLK_DRV_CKO_MASK, 845 + AN8811HB_CLK_DRV_CKO_MASK); 846 + } 847 + 848 + static void an8811hb_clk_disable(struct clk_hw *hw) 849 + { 850 + struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw); 851 + struct phy_device *phydev = priv->phydev; 852 + 853 + air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, 854 + AN8811HB_CLK_DRV_CKO_MASK, 0); 855 + } 856 + 857 + static int an8811hb_clk_is_enabled(struct clk_hw *hw) 858 + { 859 + struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw); 860 + struct phy_device *phydev = priv->phydev; 861 + u32 pbus_value; 862 + int ret; 863 + 864 + ret = air_buckpbus_reg_read(phydev, AN8811HB_CLK_DRV, &pbus_value); 865 + if (ret < 0) 866 + return ret; 867 + 868 + return (pbus_value & AN8811HB_CLK_DRV_CKO_MASK); 869 + } 870 + 871 + static int an8811hb_clk_save_context(struct clk_hw *hw) 872 + { 873 + struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw); 874 + 875 + priv->cko_is_enabled = an8811hb_clk_is_enabled(hw); 876 + 877 + return 0; 878 + } 879 + 880 + static void an8811hb_clk_restore_context(struct clk_hw *hw) 881 + { 882 + struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw); 883 + 884 + if (!priv->cko_is_enabled) 885 + an8811hb_clk_disable(hw); 886 + } 887 + 888 + static const struct clk_ops an8811hb_clk_ops = { 889 + .recalc_rate = an8811hb_clk_recalc_rate, 890 + .enable = an8811hb_clk_enable, 891 + .disable = an8811hb_clk_disable, 892 + .is_enabled = an8811hb_clk_is_enabled, 893 + .save_context = an8811hb_clk_save_context, 894 + .restore_context = an8811hb_clk_restore_context, 895 + }; 896 + 897 + static int an8811hb_clk_provider_setup(struct device *dev, struct clk_hw *hw) 898 + { 899 + struct clk_init_data init; 900 + int ret; 901 + 902 + if (!IS_ENABLED(CONFIG_COMMON_CLK)) 903 + return 0; 904 + 905 + init.name = devm_kasprintf(dev, GFP_KERNEL, "%s-cko", 906 + fwnode_get_name(dev_fwnode(dev))); 907 + if (!init.name) 908 + return -ENOMEM; 909 + 910 + init.ops = &an8811hb_clk_ops; 911 + init.flags = 0; 912 + init.num_parents = 0; 913 + hw->init = &init; 914 + 915 + ret = devm_clk_hw_register(dev, hw); 916 + if (ret) 917 + return ret; 918 + 919 + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); 920 + } 921 + 952 922 static unsigned long en8811h_clk_recalc_rate(struct clk_hw *hw, 953 923 unsigned long parent) 954 924 { ··· 1147 919 return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); 1148 920 } 1149 921 922 + static int en8811h_leds_setup(struct phy_device *phydev) 923 + { 924 + struct en8811h_priv *priv = phydev->priv; 925 + int ret; 926 + 927 + priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0; 928 + priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1; 929 + priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2; 930 + 931 + ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, 932 + AIR_LED_MODE_DISABLE); 933 + if (ret < 0) 934 + phydev_err(phydev, "Failed to disable leds: %d\n", ret); 935 + 936 + return ret; 937 + } 938 + 939 + static int an8811hb_probe(struct phy_device *phydev) 940 + { 941 + struct en8811h_priv *priv; 942 + int ret; 943 + 944 + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct en8811h_priv), 945 + GFP_KERNEL); 946 + if (!priv) 947 + return -ENOMEM; 948 + phydev->priv = priv; 949 + 950 + ret = an8811hb_load_firmware(phydev); 951 + if (ret < 0) { 952 + phydev_err(phydev, "Load firmware failed: %d\n", ret); 953 + return ret; 954 + } 955 + 956 + en8811h_print_fw_version(phydev); 957 + 958 + /* mcu has just restarted after firmware load */ 959 + priv->mcu_needs_restart = false; 960 + 961 + /* MDIO_DEVS1/2 empty, so set mmds_present bits here */ 962 + phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; 963 + 964 + ret = en8811h_leds_setup(phydev); 965 + if (ret < 0) 966 + return ret; 967 + 968 + priv->phydev = phydev; 969 + /* Co-Clock Output */ 970 + ret = an8811hb_clk_provider_setup(&phydev->mdio.dev, &priv->hw); 971 + if (ret) 972 + return ret; 973 + 974 + /* Configure led gpio pins as output */ 975 + ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, 976 + AN8811HB_GPIO_OUTPUT_345, 977 + AN8811HB_GPIO_OUTPUT_345); 978 + if (ret < 0) 979 + return ret; 980 + 981 + return 0; 982 + } 983 + 1150 984 static int en8811h_probe(struct phy_device *phydev) 1151 985 { 1152 986 struct en8811h_priv *priv; ··· 1227 937 /* mcu has just restarted after firmware load */ 1228 938 priv->mcu_needs_restart = false; 1229 939 1230 - priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0; 1231 - priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1; 1232 - priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2; 1233 - 1234 940 /* MDIO_DEVS1/2 empty, so set mmds_present bits here */ 1235 941 phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; 1236 942 1237 - ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, 1238 - AIR_LED_MODE_DISABLE); 1239 - if (ret < 0) { 1240 - phydev_err(phydev, "Failed to disable leds: %d\n", ret); 943 + ret = en8811h_leds_setup(phydev); 944 + if (ret < 0) 1241 945 return ret; 1242 - } 1243 946 1244 947 priv->phydev = phydev; 1245 948 /* Co-Clock Output */ ··· 1248 965 return ret; 1249 966 1250 967 return 0; 968 + } 969 + 970 + static int an8811hb_config_serdes_polarity(struct phy_device *phydev) 971 + { 972 + struct device *dev = &phydev->mdio.dev; 973 + u32 pbus_value = 0; 974 + unsigned int pol; 975 + int ret; 976 + 977 + ret = phy_get_manual_rx_polarity(dev_fwnode(dev), 978 + phy_modes(phydev->interface), &pol); 979 + if (ret) 980 + return ret; 981 + if (pol == PHY_POL_NORMAL) 982 + pbus_value |= AN8811HB_RX_POLARITY_NORMAL; 983 + ret = air_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY, 984 + AN8811HB_RX_POLARITY_NORMAL, 985 + pbus_value); 986 + if (ret < 0) 987 + return ret; 988 + 989 + ret = phy_get_manual_tx_polarity(dev_fwnode(dev), 990 + phy_modes(phydev->interface), &pol); 991 + if (ret) 992 + return ret; 993 + pbus_value = 0; 994 + if (pol == PHY_POL_NORMAL) 995 + pbus_value |= AN8811HB_TX_POLARITY_NORMAL; 996 + return air_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY, 997 + AN8811HB_TX_POLARITY_NORMAL, 998 + pbus_value); 1251 999 } 1252 1000 1253 1001 static int en8811h_config_serdes_polarity(struct phy_device *phydev) ··· 1315 1001 return air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, 1316 1002 EN8811H_POLARITY_RX_REVERSE | 1317 1003 EN8811H_POLARITY_TX_NORMAL, pbus_value); 1004 + } 1005 + 1006 + static int an8811hb_config_init(struct phy_device *phydev) 1007 + { 1008 + struct en8811h_priv *priv = phydev->priv; 1009 + int ret; 1010 + 1011 + /* If restart happened in .probe(), no need to restart now */ 1012 + if (priv->mcu_needs_restart) { 1013 + ret = en8811h_restart_mcu(phydev); 1014 + if (ret < 0) 1015 + return ret; 1016 + } else { 1017 + /* Next calls to .config_init() mcu needs to restart */ 1018 + priv->mcu_needs_restart = true; 1019 + } 1020 + 1021 + ret = an8811hb_config_serdes_polarity(phydev); 1022 + if (ret < 0) 1023 + return ret; 1024 + 1025 + ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, 1026 + AIR_LED_MODE_USER_DEFINE); 1027 + if (ret < 0) 1028 + phydev_err(phydev, "Failed to initialize leds: %d\n", ret); 1029 + 1030 + return ret; 1318 1031 } 1319 1032 1320 1033 static int en8811h_config_init(struct phy_device *phydev) ··· 1457 1116 if (ret < 0) 1458 1117 return ret; 1459 1118 1460 - /* Get link partner 2.5GBASE-T ability from vendor register */ 1461 - ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, &pbus_value); 1462 - if (ret < 0) 1463 - return ret; 1464 - linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, 1465 - phydev->lp_advertising, 1466 - pbus_value & EN8811H_2P5G_LPA_2P5G); 1119 + if (phy_id_compare_model(phydev->phy_id, AN8811HB_PHY_ID)) { 1120 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); 1121 + if (val < 0) 1122 + return val; 1123 + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, 1124 + phydev->lp_advertising, 1125 + val & MDIO_AN_10GBT_STAT_LP2_5G); 1126 + } else { 1127 + /* Get link partner 2.5GBASE-T ability from vendor register */ 1128 + ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA, 1129 + &pbus_value); 1130 + if (ret < 0) 1131 + return ret; 1132 + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, 1133 + phydev->lp_advertising, 1134 + pbus_value & EN8811H_2P5G_LPA_2P5G); 1135 + } 1467 1136 1468 1137 if (phydev->autoneg_complete) 1469 1138 phy_resolve_aneg_pause(phydev); ··· 1494 1143 break; 1495 1144 case AIR_AUX_CTRL_STATUS_SPEED_100: 1496 1145 phydev->speed = SPEED_100; 1146 + break; 1147 + case AIR_AUX_CTRL_STATUS_SPEED_10: 1148 + phydev->speed = SPEED_10; 1497 1149 break; 1498 1150 } 1499 1151 ··· 1582 1228 .led_brightness_set = air_led_brightness_set, 1583 1229 .led_hw_control_set = air_led_hw_control_set, 1584 1230 .led_hw_control_get = air_led_hw_control_get, 1231 + }, 1232 + { 1233 + PHY_ID_MATCH_MODEL(AN8811HB_PHY_ID), 1234 + .name = "Airoha AN8811HB", 1235 + .probe = an8811hb_probe, 1236 + .get_features = en8811h_get_features, 1237 + .config_init = an8811hb_config_init, 1238 + .get_rate_matching = en8811h_get_rate_matching, 1239 + .config_aneg = en8811h_config_aneg, 1240 + .read_status = en8811h_read_status, 1241 + .resume = en8811h_resume, 1242 + .suspend = en8811h_suspend, 1243 + .config_intr = en8811h_clear_intr, 1244 + .handle_interrupt = en8811h_handle_interrupt, 1245 + .led_hw_is_supported = en8811h_led_hw_is_supported, 1246 + .read_page = air_phy_read_page, 1247 + .write_page = air_phy_write_page, 1248 + .led_blink_set = air_led_blink_set, 1249 + .led_brightness_set = air_led_brightness_set, 1250 + .led_hw_control_set = air_led_hw_control_set, 1251 + .led_hw_control_get = air_led_hw_control_get, 1585 1252 } }; 1586 1253 1587 1254 module_phy_driver(en8811h_driver); 1588 1255 1589 1256 static const struct mdio_device_id __maybe_unused en8811h_tbl[] = { 1590 1257 { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) }, 1258 + { PHY_ID_MATCH_MODEL(AN8811HB_PHY_ID) }, 1591 1259 { } 1592 1260 }; 1593 1261 1594 1262 MODULE_DEVICE_TABLE(mdio, en8811h_tbl); 1595 1263 MODULE_FIRMWARE(EN8811H_MD32_DM); 1596 1264 MODULE_FIRMWARE(EN8811H_MD32_DSP); 1265 + MODULE_FIRMWARE(AN8811HB_MD32_DM); 1266 + MODULE_FIRMWARE(AN8811HB_MD32_DSP); 1597 1267 1598 - MODULE_DESCRIPTION("Airoha EN8811H PHY drivers"); 1268 + MODULE_DESCRIPTION("Airoha EN8811H and AN8811HB PHY drivers"); 1599 1269 MODULE_AUTHOR("Airoha"); 1600 1270 MODULE_AUTHOR("Eric Woudstra <ericwouds@gmail.com>"); 1601 1271 MODULE_LICENSE("GPL");