18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Aquantia PHY 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Shaohui Xie <Shaohui.Xie@freescale.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2015 Freescale Semiconductor, Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 148c2ecf20Sopenharmony_ci#include <linux/phy.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "aquantia.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define PHY_ID_AQ1202 0x03a1b445 198c2ecf20Sopenharmony_ci#define PHY_ID_AQ2104 0x03a1b460 208c2ecf20Sopenharmony_ci#define PHY_ID_AQR105 0x03a1b4a2 218c2ecf20Sopenharmony_ci#define PHY_ID_AQR106 0x03a1b4d0 228c2ecf20Sopenharmony_ci#define PHY_ID_AQR107 0x03a1b4e0 238c2ecf20Sopenharmony_ci#define PHY_ID_AQCS109 0x03a1b5c2 248c2ecf20Sopenharmony_ci#define PHY_ID_AQR405 0x03a1b4b0 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define MDIO_PHYXS_VEND_IF_STATUS 0xe812 278c2ecf20Sopenharmony_ci#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) 288c2ecf20Sopenharmony_ci#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR 0 298c2ecf20Sopenharmony_ci#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI 2 308c2ecf20Sopenharmony_ci#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII 3 318c2ecf20Sopenharmony_ci#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6 328c2ecf20Sopenharmony_ci#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV 0xc400 358c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15) 368c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14) 378c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV_5000BASET_FULL BIT(11) 388c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV_2500BASET_FULL BIT(10) 398c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV_DOWNSHIFT_EN BIT(4) 408c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0) 418c2ecf20Sopenharmony_ci#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1 0xc800 448c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1) 458c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_10BASET 0 468c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_100BASETX 1 478c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_1000BASET 2 488c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_10GBASET 3 498c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_2500BASET 4 508c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_5000BASET 5 518c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX BIT(0) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_INT_STATUS1 0xcc00 548c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT BIT(1) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_INT_STATUS2 0xcc01 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_INT_MASK2 0xd401 598c2ecf20Sopenharmony_ci#define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT1 0xe820 628c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) 638c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) 648c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT1_SHORT_REACH BIT(13) 658c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT BIT(12) 668c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT1_AQ_PHY BIT(2) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT4 0xe823 698c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT4_FW_MAJOR GENMASK(15, 8) 708c2ecf20Sopenharmony_ci#define MDIO_AN_RX_LP_STAT4_FW_MINOR GENMASK(7, 0) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define MDIO_AN_RX_VEND_STAT3 0xe832 738c2ecf20Sopenharmony_ci#define MDIO_AN_RX_VEND_STAT3_AFR BIT(0) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* MDIO_MMD_C22EXT */ 768c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292 778c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294 788c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297 798c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313 808c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315 818c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317 828c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318 838c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319 848c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a 858c2ecf20Sopenharmony_ci#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* Vendor specific 1, MDIO_MMD_VEND1 */ 888c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_FW_ID 0x0020 898c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8) 908c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_GEN_STAT2 0xc831 938c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_RSVD_STAT1 0xc885 968c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4) 978c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_RSVD_STAT9 0xc88d 1008c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0) 1018c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00 1048c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK 0xff00 1078c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15) 1088c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14) 1098c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13) 1108c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12) 1118c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11) 1128c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10) 1138c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9) 1148c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8) 1158c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7) 1168c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6) 1178c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK 0xff01 1208c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15) 1218c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14) 1228c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13) 1238c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12) 1248c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11) 1258c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2) 1268c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1) 1278c2ecf20Sopenharmony_ci#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0) 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Sleep and timeout for checking if the Processor-Intensive 1308c2ecf20Sopenharmony_ci * MDIO operation is finished 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci#define AQR107_OP_IN_PROG_SLEEP 1000 1338c2ecf20Sopenharmony_ci#define AQR107_OP_IN_PROG_TIMEOUT 100000 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistruct aqr107_hw_stat { 1368c2ecf20Sopenharmony_ci const char *name; 1378c2ecf20Sopenharmony_ci int reg; 1388c2ecf20Sopenharmony_ci int size; 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s } 1428c2ecf20Sopenharmony_cistatic const struct aqr107_hw_stat aqr107_hw_stats[] = { 1438c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26), 1448c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26), 1458c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8), 1468c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26), 1478c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26), 1488c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8), 1498c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8), 1508c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8), 1518c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16), 1528c2ecf20Sopenharmony_ci SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22), 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats) 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistruct aqr107_priv { 1578c2ecf20Sopenharmony_ci u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int aqr107_get_sset_count(struct phy_device *phydev) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return AQR107_SGMII_STAT_SZ; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void aqr107_get_strings(struct phy_device *phydev, u8 *data) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int i; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) 1708c2ecf20Sopenharmony_ci strscpy(data + i * ETH_GSTRING_LEN, aqr107_hw_stats[i].name, 1718c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic u64 aqr107_get_stat(struct phy_device *phydev, int index) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci const struct aqr107_hw_stat *stat = aqr107_hw_stats + index; 1778c2ecf20Sopenharmony_ci int len_l = min(stat->size, 16); 1788c2ecf20Sopenharmony_ci int len_h = stat->size - len_l; 1798c2ecf20Sopenharmony_ci u64 ret; 1808c2ecf20Sopenharmony_ci int val; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg); 1838c2ecf20Sopenharmony_ci if (val < 0) 1848c2ecf20Sopenharmony_ci return U64_MAX; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ret = val & GENMASK(len_l - 1, 0); 1878c2ecf20Sopenharmony_ci if (len_h) { 1888c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_C22EXT, stat->reg + 1); 1898c2ecf20Sopenharmony_ci if (val < 0) 1908c2ecf20Sopenharmony_ci return U64_MAX; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci ret += (val & GENMASK(len_h - 1, 0)) << 16; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return ret; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void aqr107_get_stats(struct phy_device *phydev, 1998c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct aqr107_priv *priv = phydev->priv; 2028c2ecf20Sopenharmony_ci u64 val; 2038c2ecf20Sopenharmony_ci int i; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (i = 0; i < AQR107_SGMII_STAT_SZ; i++) { 2068c2ecf20Sopenharmony_ci val = aqr107_get_stat(phydev, i); 2078c2ecf20Sopenharmony_ci if (val == U64_MAX) 2088c2ecf20Sopenharmony_ci phydev_err(phydev, "Reading HW Statistics failed for %s\n", 2098c2ecf20Sopenharmony_ci aqr107_hw_stats[i].name); 2108c2ecf20Sopenharmony_ci else 2118c2ecf20Sopenharmony_ci priv->sgmii_stats[i] += val; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci data[i] = priv->sgmii_stats[i]; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int aqr_config_aneg(struct phy_device *phydev) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci bool changed = false; 2208c2ecf20Sopenharmony_ci u16 reg; 2218c2ecf20Sopenharmony_ci int ret; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (phydev->autoneg == AUTONEG_DISABLE) 2248c2ecf20Sopenharmony_ci return genphy_c45_pma_setup_forced(phydev); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ret = genphy_c45_an_config_aneg(phydev); 2278c2ecf20Sopenharmony_ci if (ret < 0) 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci if (ret > 0) 2308c2ecf20Sopenharmony_ci changed = true; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Clause 45 has no standardized support for 1000BaseT, therefore 2338c2ecf20Sopenharmony_ci * use vendor registers for this mode. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci reg = 0; 2368c2ecf20Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 2378c2ecf20Sopenharmony_ci phydev->advertising)) 2388c2ecf20Sopenharmony_ci reg |= MDIO_AN_VEND_PROV_1000BASET_FULL; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 2418c2ecf20Sopenharmony_ci phydev->advertising)) 2428c2ecf20Sopenharmony_ci reg |= MDIO_AN_VEND_PROV_1000BASET_HALF; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Handle the case when the 2.5G and 5G speeds are not advertised */ 2458c2ecf20Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, 2468c2ecf20Sopenharmony_ci phydev->advertising)) 2478c2ecf20Sopenharmony_ci reg |= MDIO_AN_VEND_PROV_2500BASET_FULL; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, 2508c2ecf20Sopenharmony_ci phydev->advertising)) 2518c2ecf20Sopenharmony_ci reg |= MDIO_AN_VEND_PROV_5000BASET_FULL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, 2548c2ecf20Sopenharmony_ci MDIO_AN_VEND_PROV_1000BASET_HALF | 2558c2ecf20Sopenharmony_ci MDIO_AN_VEND_PROV_1000BASET_FULL | 2568c2ecf20Sopenharmony_ci MDIO_AN_VEND_PROV_2500BASET_FULL | 2578c2ecf20Sopenharmony_ci MDIO_AN_VEND_PROV_5000BASET_FULL, reg); 2588c2ecf20Sopenharmony_ci if (ret < 0) 2598c2ecf20Sopenharmony_ci return ret; 2608c2ecf20Sopenharmony_ci if (ret > 0) 2618c2ecf20Sopenharmony_ci changed = true; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return genphy_c45_check_and_restart_aneg(phydev, changed); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int aqr_config_intr(struct phy_device *phydev) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; 2698c2ecf20Sopenharmony_ci int err; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci err = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_INT_MASK2, 2728c2ecf20Sopenharmony_ci en ? MDIO_AN_TX_VEND_INT_MASK2_LINK : 0); 2738c2ecf20Sopenharmony_ci if (err < 0) 2748c2ecf20Sopenharmony_ci return err; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci err = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_STD_MASK, 2778c2ecf20Sopenharmony_ci en ? VEND1_GLOBAL_INT_STD_MASK_ALL : 0); 2788c2ecf20Sopenharmony_ci if (err < 0) 2798c2ecf20Sopenharmony_ci return err; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_INT_VEND_MASK, 2828c2ecf20Sopenharmony_ci en ? VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 | 2838c2ecf20Sopenharmony_ci VEND1_GLOBAL_INT_VEND_MASK_AN : 0); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int aqr_ack_interrupt(struct phy_device *phydev) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci int reg; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci reg = phy_read_mmd(phydev, MDIO_MMD_AN, 2918c2ecf20Sopenharmony_ci MDIO_AN_TX_VEND_INT_STATUS2); 2928c2ecf20Sopenharmony_ci return (reg < 0) ? reg : 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int aqr_read_status(struct phy_device *phydev) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int val; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (phydev->autoneg == AUTONEG_ENABLE) { 3008c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1); 3018c2ecf20Sopenharmony_ci if (val < 0) 3028c2ecf20Sopenharmony_ci return val; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 3058c2ecf20Sopenharmony_ci phydev->lp_advertising, 3068c2ecf20Sopenharmony_ci val & MDIO_AN_RX_LP_STAT1_1000BASET_FULL); 3078c2ecf20Sopenharmony_ci linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, 3088c2ecf20Sopenharmony_ci phydev->lp_advertising, 3098c2ecf20Sopenharmony_ci val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return genphy_c45_read_status(phydev); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int aqr107_read_rate(struct phy_device *phydev) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci int val; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1); 3208c2ecf20Sopenharmony_ci if (val < 0) 3218c2ecf20Sopenharmony_ci return val; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) { 3248c2ecf20Sopenharmony_ci case MDIO_AN_TX_VEND_STATUS1_10BASET: 3258c2ecf20Sopenharmony_ci phydev->speed = SPEED_10; 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci case MDIO_AN_TX_VEND_STATUS1_100BASETX: 3288c2ecf20Sopenharmony_ci phydev->speed = SPEED_100; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci case MDIO_AN_TX_VEND_STATUS1_1000BASET: 3318c2ecf20Sopenharmony_ci phydev->speed = SPEED_1000; 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case MDIO_AN_TX_VEND_STATUS1_2500BASET: 3348c2ecf20Sopenharmony_ci phydev->speed = SPEED_2500; 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case MDIO_AN_TX_VEND_STATUS1_5000BASET: 3378c2ecf20Sopenharmony_ci phydev->speed = SPEED_5000; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci case MDIO_AN_TX_VEND_STATUS1_10GBASET: 3408c2ecf20Sopenharmony_ci phydev->speed = SPEED_10000; 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci default: 3438c2ecf20Sopenharmony_ci phydev->speed = SPEED_UNKNOWN; 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX) 3488c2ecf20Sopenharmony_ci phydev->duplex = DUPLEX_FULL; 3498c2ecf20Sopenharmony_ci else 3508c2ecf20Sopenharmony_ci phydev->duplex = DUPLEX_HALF; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int aqr107_read_status(struct phy_device *phydev) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int val, ret; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ret = aqr_read_status(phydev); 3608c2ecf20Sopenharmony_ci if (ret) 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE) 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS); 3678c2ecf20Sopenharmony_ci if (val < 0) 3688c2ecf20Sopenharmony_ci return val; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) { 3718c2ecf20Sopenharmony_ci case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR: 3728c2ecf20Sopenharmony_ci phydev->interface = PHY_INTERFACE_MODE_10GKR; 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI: 3758c2ecf20Sopenharmony_ci phydev->interface = PHY_INTERFACE_MODE_10GBASER; 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII: 3788c2ecf20Sopenharmony_ci phydev->interface = PHY_INTERFACE_MODE_USXGMII; 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII: 3818c2ecf20Sopenharmony_ci phydev->interface = PHY_INTERFACE_MODE_SGMII; 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII: 3848c2ecf20Sopenharmony_ci phydev->interface = PHY_INTERFACE_MODE_2500BASEX; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci default: 3878c2ecf20Sopenharmony_ci phydev->interface = PHY_INTERFACE_MODE_NA; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Read possibly downshifted rate from vendor register */ 3928c2ecf20Sopenharmony_ci return aqr107_read_rate(phydev); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int aqr107_get_downshift(struct phy_device *phydev, u8 *data) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci int val, cnt, enable; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV); 4008c2ecf20Sopenharmony_ci if (val < 0) 4018c2ecf20Sopenharmony_ci return val; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci enable = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_EN, val); 4048c2ecf20Sopenharmony_ci cnt = FIELD_GET(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci *data = enable && cnt ? cnt : DOWNSHIFT_DEV_DISABLE; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int aqr107_set_downshift(struct phy_device *phydev, u8 cnt) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci int val = 0; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (!FIELD_FIT(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt)) 4168c2ecf20Sopenharmony_ci return -E2BIG; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (cnt != DOWNSHIFT_DEV_DISABLE) { 4198c2ecf20Sopenharmony_ci val = MDIO_AN_VEND_PROV_DOWNSHIFT_EN; 4208c2ecf20Sopenharmony_ci val |= FIELD_PREP(MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, cnt); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return phy_modify_mmd(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV, 4248c2ecf20Sopenharmony_ci MDIO_AN_VEND_PROV_DOWNSHIFT_EN | 4258c2ecf20Sopenharmony_ci MDIO_AN_VEND_PROV_DOWNSHIFT_MASK, val); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int aqr107_get_tunable(struct phy_device *phydev, 4298c2ecf20Sopenharmony_ci struct ethtool_tunable *tuna, void *data) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci switch (tuna->id) { 4328c2ecf20Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 4338c2ecf20Sopenharmony_ci return aqr107_get_downshift(phydev, data); 4348c2ecf20Sopenharmony_ci default: 4358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int aqr107_set_tunable(struct phy_device *phydev, 4408c2ecf20Sopenharmony_ci struct ethtool_tunable *tuna, const void *data) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci switch (tuna->id) { 4438c2ecf20Sopenharmony_ci case ETHTOOL_PHY_DOWNSHIFT: 4448c2ecf20Sopenharmony_ci return aqr107_set_downshift(phydev, *(const u8 *)data); 4458c2ecf20Sopenharmony_ci default: 4468c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* If we configure settings whilst firmware is still initializing the chip, 4518c2ecf20Sopenharmony_ci * then these settings may be overwritten. Therefore make sure chip 4528c2ecf20Sopenharmony_ci * initialization has completed. Use presence of the firmware ID as 4538c2ecf20Sopenharmony_ci * indicator for initialization having completed. 4548c2ecf20Sopenharmony_ci * The chip also provides a "reset completed" bit, but it's cleared after 4558c2ecf20Sopenharmony_ci * read. Therefore function would time out if called again. 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_cistatic int aqr107_wait_reset_complete(struct phy_device *phydev) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci int val; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 4628c2ecf20Sopenharmony_ci VEND1_GLOBAL_FW_ID, val, val != 0, 4638c2ecf20Sopenharmony_ci 20000, 2000000, false); 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic void aqr107_chip_info(struct phy_device *phydev) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci u8 fw_major, fw_minor, build_id, prov_id; 4698c2ecf20Sopenharmony_ci int val; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID); 4728c2ecf20Sopenharmony_ci if (val < 0) 4738c2ecf20Sopenharmony_ci return; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci fw_major = FIELD_GET(VEND1_GLOBAL_FW_ID_MAJOR, val); 4768c2ecf20Sopenharmony_ci fw_minor = FIELD_GET(VEND1_GLOBAL_FW_ID_MINOR, val); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT1); 4798c2ecf20Sopenharmony_ci if (val < 0) 4808c2ecf20Sopenharmony_ci return; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val); 4838c2ecf20Sopenharmony_ci prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n", 4868c2ecf20Sopenharmony_ci fw_major, fw_minor, build_id, prov_id); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int aqr107_config_init(struct phy_device *phydev) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci int ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* Check that the PHY interface type is compatible */ 4948c2ecf20Sopenharmony_ci if (phydev->interface != PHY_INTERFACE_MODE_SGMII && 4958c2ecf20Sopenharmony_ci phydev->interface != PHY_INTERFACE_MODE_2500BASEX && 4968c2ecf20Sopenharmony_ci phydev->interface != PHY_INTERFACE_MODE_XGMII && 4978c2ecf20Sopenharmony_ci phydev->interface != PHY_INTERFACE_MODE_USXGMII && 4988c2ecf20Sopenharmony_ci phydev->interface != PHY_INTERFACE_MODE_10GKR && 4998c2ecf20Sopenharmony_ci phydev->interface != PHY_INTERFACE_MODE_10GBASER) 5008c2ecf20Sopenharmony_ci return -ENODEV; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci WARN(phydev->interface == PHY_INTERFACE_MODE_XGMII, 5038c2ecf20Sopenharmony_ci "Your devicetree is out of date, please update it. The AQR107 family doesn't support XGMII, maybe you mean USXGMII.\n"); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci ret = aqr107_wait_reset_complete(phydev); 5068c2ecf20Sopenharmony_ci if (!ret) 5078c2ecf20Sopenharmony_ci aqr107_chip_info(phydev); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int aqcs109_config_init(struct phy_device *phydev) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci int ret; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* Check that the PHY interface type is compatible */ 5178c2ecf20Sopenharmony_ci if (phydev->interface != PHY_INTERFACE_MODE_SGMII && 5188c2ecf20Sopenharmony_ci phydev->interface != PHY_INTERFACE_MODE_2500BASEX) 5198c2ecf20Sopenharmony_ci return -ENODEV; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci ret = aqr107_wait_reset_complete(phydev); 5228c2ecf20Sopenharmony_ci if (!ret) 5238c2ecf20Sopenharmony_ci aqr107_chip_info(phydev); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* AQCS109 belongs to a chip family partially supporting 10G and 5G. 5268c2ecf20Sopenharmony_ci * PMA speed ability bits are the same for all members of the family, 5278c2ecf20Sopenharmony_ci * AQCS109 however supports speeds up to 2.5G only. 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_ci ret = phy_set_max_speed(phydev, SPEED_2500); 5308c2ecf20Sopenharmony_ci if (ret) 5318c2ecf20Sopenharmony_ci return ret; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void aqr107_link_change_notify(struct phy_device *phydev) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci u8 fw_major, fw_minor; 5398c2ecf20Sopenharmony_ci bool downshift, short_reach, afr; 5408c2ecf20Sopenharmony_ci int mode, val; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (phydev->state != PHY_RUNNING || phydev->autoneg == AUTONEG_DISABLE) 5438c2ecf20Sopenharmony_ci return; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1); 5468c2ecf20Sopenharmony_ci /* call failed or link partner is no Aquantia PHY */ 5478c2ecf20Sopenharmony_ci if (val < 0 || !(val & MDIO_AN_RX_LP_STAT1_AQ_PHY)) 5488c2ecf20Sopenharmony_ci return; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci short_reach = val & MDIO_AN_RX_LP_STAT1_SHORT_REACH; 5518c2ecf20Sopenharmony_ci downshift = val & MDIO_AN_RX_LP_STAT1_AQRATE_DOWNSHIFT; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT4); 5548c2ecf20Sopenharmony_ci if (val < 0) 5558c2ecf20Sopenharmony_ci return; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci fw_major = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MAJOR, val); 5588c2ecf20Sopenharmony_ci fw_minor = FIELD_GET(MDIO_AN_RX_LP_STAT4_FW_MINOR, val); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_VEND_STAT3); 5618c2ecf20Sopenharmony_ci if (val < 0) 5628c2ecf20Sopenharmony_ci return; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci afr = val & MDIO_AN_RX_VEND_STAT3_AFR; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci phydev_dbg(phydev, "Link partner is Aquantia PHY, FW %u.%u%s%s%s\n", 5678c2ecf20Sopenharmony_ci fw_major, fw_minor, 5688c2ecf20Sopenharmony_ci short_reach ? ", short reach mode" : "", 5698c2ecf20Sopenharmony_ci downshift ? ", fast-retrain downshift advertised" : "", 5708c2ecf20Sopenharmony_ci afr ? ", fast reframe advertised" : ""); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_RSVD_STAT9); 5738c2ecf20Sopenharmony_ci if (val < 0) 5748c2ecf20Sopenharmony_ci return; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci mode = FIELD_GET(VEND1_GLOBAL_RSVD_STAT9_MODE, val); 5778c2ecf20Sopenharmony_ci if (mode == VEND1_GLOBAL_RSVD_STAT9_1000BT2) 5788c2ecf20Sopenharmony_ci phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n"); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int aqr107_wait_processor_intensive_op(struct phy_device *phydev) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci int val, err; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* The datasheet notes to wait at least 1ms after issuing a 5868c2ecf20Sopenharmony_ci * processor intensive operation before checking. 5878c2ecf20Sopenharmony_ci * We cannot use the 'sleep_before_read' parameter of read_poll_timeout 5888c2ecf20Sopenharmony_ci * because that just determines the maximum time slept, not the minimum. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ci usleep_range(1000, 5000); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 5938c2ecf20Sopenharmony_ci VEND1_GLOBAL_GEN_STAT2, val, 5948c2ecf20Sopenharmony_ci !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG), 5958c2ecf20Sopenharmony_ci AQR107_OP_IN_PROG_SLEEP, 5968c2ecf20Sopenharmony_ci AQR107_OP_IN_PROG_TIMEOUT, false); 5978c2ecf20Sopenharmony_ci if (err) { 5988c2ecf20Sopenharmony_ci phydev_err(phydev, "timeout: processor-intensive MDIO operation\n"); 5998c2ecf20Sopenharmony_ci return err; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int aqr107_suspend(struct phy_device *phydev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci int err; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci err = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, 6108c2ecf20Sopenharmony_ci MDIO_CTRL1_LPOWER); 6118c2ecf20Sopenharmony_ci if (err) 6128c2ecf20Sopenharmony_ci return err; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return aqr107_wait_processor_intensive_op(phydev); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int aqr107_resume(struct phy_device *phydev) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci int err; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci err = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MDIO_CTRL1, 6228c2ecf20Sopenharmony_ci MDIO_CTRL1_LPOWER); 6238c2ecf20Sopenharmony_ci if (err) 6248c2ecf20Sopenharmony_ci return err; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return aqr107_wait_processor_intensive_op(phydev); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int aqr107_probe(struct phy_device *phydev) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci phydev->priv = devm_kzalloc(&phydev->mdio.dev, 6328c2ecf20Sopenharmony_ci sizeof(struct aqr107_priv), GFP_KERNEL); 6338c2ecf20Sopenharmony_ci if (!phydev->priv) 6348c2ecf20Sopenharmony_ci return -ENOMEM; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return aqr_hwmon_probe(phydev); 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic struct phy_driver aqr_driver[] = { 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci PHY_ID_MATCH_MODEL(PHY_ID_AQ1202), 6428c2ecf20Sopenharmony_ci .name = "Aquantia AQ1202", 6438c2ecf20Sopenharmony_ci .config_aneg = aqr_config_aneg, 6448c2ecf20Sopenharmony_ci .config_intr = aqr_config_intr, 6458c2ecf20Sopenharmony_ci .ack_interrupt = aqr_ack_interrupt, 6468c2ecf20Sopenharmony_ci .read_status = aqr_read_status, 6478c2ecf20Sopenharmony_ci}, 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci PHY_ID_MATCH_MODEL(PHY_ID_AQ2104), 6508c2ecf20Sopenharmony_ci .name = "Aquantia AQ2104", 6518c2ecf20Sopenharmony_ci .config_aneg = aqr_config_aneg, 6528c2ecf20Sopenharmony_ci .config_intr = aqr_config_intr, 6538c2ecf20Sopenharmony_ci .ack_interrupt = aqr_ack_interrupt, 6548c2ecf20Sopenharmony_ci .read_status = aqr_read_status, 6558c2ecf20Sopenharmony_ci}, 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci PHY_ID_MATCH_MODEL(PHY_ID_AQR105), 6588c2ecf20Sopenharmony_ci .name = "Aquantia AQR105", 6598c2ecf20Sopenharmony_ci .config_aneg = aqr_config_aneg, 6608c2ecf20Sopenharmony_ci .config_intr = aqr_config_intr, 6618c2ecf20Sopenharmony_ci .ack_interrupt = aqr_ack_interrupt, 6628c2ecf20Sopenharmony_ci .read_status = aqr_read_status, 6638c2ecf20Sopenharmony_ci .suspend = aqr107_suspend, 6648c2ecf20Sopenharmony_ci .resume = aqr107_resume, 6658c2ecf20Sopenharmony_ci}, 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci PHY_ID_MATCH_MODEL(PHY_ID_AQR106), 6688c2ecf20Sopenharmony_ci .name = "Aquantia AQR106", 6698c2ecf20Sopenharmony_ci .config_aneg = aqr_config_aneg, 6708c2ecf20Sopenharmony_ci .config_intr = aqr_config_intr, 6718c2ecf20Sopenharmony_ci .ack_interrupt = aqr_ack_interrupt, 6728c2ecf20Sopenharmony_ci .read_status = aqr_read_status, 6738c2ecf20Sopenharmony_ci}, 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci PHY_ID_MATCH_MODEL(PHY_ID_AQR107), 6768c2ecf20Sopenharmony_ci .name = "Aquantia AQR107", 6778c2ecf20Sopenharmony_ci .probe = aqr107_probe, 6788c2ecf20Sopenharmony_ci .config_init = aqr107_config_init, 6798c2ecf20Sopenharmony_ci .config_aneg = aqr_config_aneg, 6808c2ecf20Sopenharmony_ci .config_intr = aqr_config_intr, 6818c2ecf20Sopenharmony_ci .ack_interrupt = aqr_ack_interrupt, 6828c2ecf20Sopenharmony_ci .read_status = aqr107_read_status, 6838c2ecf20Sopenharmony_ci .get_tunable = aqr107_get_tunable, 6848c2ecf20Sopenharmony_ci .set_tunable = aqr107_set_tunable, 6858c2ecf20Sopenharmony_ci .suspend = aqr107_suspend, 6868c2ecf20Sopenharmony_ci .resume = aqr107_resume, 6878c2ecf20Sopenharmony_ci .get_sset_count = aqr107_get_sset_count, 6888c2ecf20Sopenharmony_ci .get_strings = aqr107_get_strings, 6898c2ecf20Sopenharmony_ci .get_stats = aqr107_get_stats, 6908c2ecf20Sopenharmony_ci .link_change_notify = aqr107_link_change_notify, 6918c2ecf20Sopenharmony_ci}, 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci PHY_ID_MATCH_MODEL(PHY_ID_AQCS109), 6948c2ecf20Sopenharmony_ci .name = "Aquantia AQCS109", 6958c2ecf20Sopenharmony_ci .probe = aqr107_probe, 6968c2ecf20Sopenharmony_ci .config_init = aqcs109_config_init, 6978c2ecf20Sopenharmony_ci .config_aneg = aqr_config_aneg, 6988c2ecf20Sopenharmony_ci .config_intr = aqr_config_intr, 6998c2ecf20Sopenharmony_ci .ack_interrupt = aqr_ack_interrupt, 7008c2ecf20Sopenharmony_ci .read_status = aqr107_read_status, 7018c2ecf20Sopenharmony_ci .get_tunable = aqr107_get_tunable, 7028c2ecf20Sopenharmony_ci .set_tunable = aqr107_set_tunable, 7038c2ecf20Sopenharmony_ci .suspend = aqr107_suspend, 7048c2ecf20Sopenharmony_ci .resume = aqr107_resume, 7058c2ecf20Sopenharmony_ci .get_sset_count = aqr107_get_sset_count, 7068c2ecf20Sopenharmony_ci .get_strings = aqr107_get_strings, 7078c2ecf20Sopenharmony_ci .get_stats = aqr107_get_stats, 7088c2ecf20Sopenharmony_ci .link_change_notify = aqr107_link_change_notify, 7098c2ecf20Sopenharmony_ci}, 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci PHY_ID_MATCH_MODEL(PHY_ID_AQR405), 7128c2ecf20Sopenharmony_ci .name = "Aquantia AQR405", 7138c2ecf20Sopenharmony_ci .config_aneg = aqr_config_aneg, 7148c2ecf20Sopenharmony_ci .config_intr = aqr_config_intr, 7158c2ecf20Sopenharmony_ci .ack_interrupt = aqr_ack_interrupt, 7168c2ecf20Sopenharmony_ci .read_status = aqr_read_status, 7178c2ecf20Sopenharmony_ci}, 7188c2ecf20Sopenharmony_ci}; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cimodule_phy_driver(aqr_driver); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic struct mdio_device_id __maybe_unused aqr_tbl[] = { 7238c2ecf20Sopenharmony_ci { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) }, 7248c2ecf20Sopenharmony_ci { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) }, 7258c2ecf20Sopenharmony_ci { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, 7268c2ecf20Sopenharmony_ci { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, 7278c2ecf20Sopenharmony_ci { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, 7288c2ecf20Sopenharmony_ci { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, 7298c2ecf20Sopenharmony_ci { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, 7308c2ecf20Sopenharmony_ci { } 7318c2ecf20Sopenharmony_ci}; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, aqr_tbl); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Aquantia PHY driver"); 7368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>"); 7378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 738