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