diff mbox series

[net-next,RFC,1/2] net: phy: aquantia: setup interface protocols for AQR112

Message ID 20240213182415.17223-2-ansuelsmth@gmail.com (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series net: phy: aquantia: fix system interface provision | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 989 this patch: 989
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 8 of 8 maintainers
netdev/build_clang success Errors and warnings before: 1006 this patch: 1006
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1006 this patch: 1006
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Christian Marangi Feb. 13, 2024, 6:24 p.m. UTC
Aquantia Gen3 PHYs require additional regs to be set to correctly work
and communicate with the MAC.

For each rate, the startup rate needs to be set and the required global
cfg needs to be set.

The global cfg are per Rate and require different configuration based on
the requested interface mode.

Some FW might apply the correct values by default but some OEM might
provide generic FW that require additional fixup at runtime as the FW
doesn't correctly provison the PHY for the attached MAC interface mode.

The default values are taken from various source and SDK and all use the
same values for SGMII, 2500BASEX, 10GBASER and USXGMII.

One common problem that this handle is case where the FW provision for
10BASER but USXGMII is actually requested, hance runtime fixup is
required.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/phy/aquantia/aquantia.h      |  17 ++++
 drivers/net/phy/aquantia/aquantia_main.c | 110 +++++++++++++++++++++++
 2 files changed, 127 insertions(+)
diff mbox series

Patch

diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h
index 1c19ae74ad2b..019528c536c7 100644
--- a/drivers/net/phy/aquantia/aquantia.h
+++ b/drivers/net/phy/aquantia/aquantia.h
@@ -39,6 +39,15 @@ 
 #define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK	GENMASK(15, 0)
 #define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(x)	FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK, (u16)(x))
 
+#define VEND1_GLOBAL_STARTUP_RATE		0x031a
+#define   VEND1_GLOBAL_STARTUP_RATE_MASK	GENMASK(3, 0)
+#define   VEND1_GLOBAL_STARTUP_RATE_LOW_POWER	0
+#define   VEND1_GLOBAL_STARTUP_RATE_100M	1
+#define   VEND1_GLOBAL_STARTUP_RATE_1G		2
+#define   VEND1_GLOBAL_STARTUP_RATE_10G		3
+#define   VEND1_GLOBAL_STARTUP_RATE_2_5G	4
+#define   VEND1_GLOBAL_STARTUP_RATE_5G		5
+
 /* The following registers all have similar layouts; first the registers... */
 #define VEND1_GLOBAL_CFG_10M			0x0310
 #define VEND1_GLOBAL_CFG_100M			0x031b
@@ -52,6 +61,14 @@ 
 #define VEND1_GLOBAL_CFG_SERDES_MODE_SGMII	3
 #define VEND1_GLOBAL_CFG_SERDES_MODE_OCSGMII	4
 #define VEND1_GLOBAL_CFG_SERDES_MODE_XFI5G	6
+/* Enable System Interface Autonegotiation */
+#define VEND1_GLOBAL_CFG_AUTONEG_EN		BIT(3)
+/* Enable System Interface Training */
+#define VEND1_GLOBAL_CFG_TRAINING_EN		BIT(4)
+/* Reset System Interface For Every Transition */
+#define VEND1_GLOBAL_CFG_RESET_ON_TRANSITION_EN	BIT(5)
+/* Keep SERDES Silent During Transition */
+#define VEND1_GLOBAL_CFG_SERDES_SILENCE_EN	BIT(6)
 #define VEND1_GLOBAL_CFG_RATE_ADAPT		GENMASK(8, 7)
 #define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE	0
 #define VEND1_GLOBAL_CFG_RATE_ADAPT_USX		1
diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c
index 97a2fafa15ca..6ee1a134bc60 100644
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
@@ -746,6 +746,114 @@  static int aqr107_probe(struct phy_device *phydev)
 	return aqr_hwmon_probe(phydev);
 }
 
+static int aqr112_setup_interface_protocols(struct phy_device *phydev)
+{
+	phy_interface_t iface = phydev->interface;
+	u16 startup_rate, global_cfg_val;
+	int i, ret;
+
+	/* Default global cfg are taken from Aquantia UBoot Source and various
+	 * source and all makes use of the following reference values.
+	 */
+	switch (iface) {
+	case PHY_INTERFACE_MODE_SGMII:
+		startup_rate = VEND1_GLOBAL_STARTUP_RATE_1G;
+		global_cfg_val = FIELD_PREP(VEND1_GLOBAL_CFG_SERDES_MODE,
+					    VEND1_GLOBAL_CFG_SERDES_MODE_SGMII) |
+				 VEND1_GLOBAL_CFG_AUTONEG_EN |
+				 VEND1_GLOBAL_CFG_SERDES_SILENCE_EN;
+		break;
+	case PHY_INTERFACE_MODE_2500BASEX:
+		startup_rate = VEND1_GLOBAL_STARTUP_RATE_2_5G;
+		global_cfg_val = FIELD_PREP(VEND1_GLOBAL_CFG_SERDES_MODE,
+					    VEND1_GLOBAL_CFG_SERDES_MODE_OCSGMII) |
+				 VEND1_GLOBAL_CFG_SERDES_SILENCE_EN |
+				 FIELD_PREP(VEND1_GLOBAL_CFG_RATE_ADAPT,
+					    VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE);
+		break;
+	case PHY_INTERFACE_MODE_5GBASER:
+		startup_rate = VEND1_GLOBAL_STARTUP_RATE_5G;
+		global_cfg_val = FIELD_PREP(VEND1_GLOBAL_CFG_SERDES_MODE,
+					    VEND1_GLOBAL_CFG_SERDES_MODE_XFI5G) |
+				 FIELD_PREP(VEND1_GLOBAL_CFG_RATE_ADAPT,
+					    VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE);
+		break;
+	case PHY_INTERFACE_MODE_10GBASER:
+	case PHY_INTERFACE_MODE_USXGMII:
+		startup_rate = VEND1_GLOBAL_STARTUP_RATE_10G;
+		global_cfg_val = FIELD_PREP(VEND1_GLOBAL_CFG_SERDES_MODE,
+					    VEND1_GLOBAL_CFG_SERDES_MODE_XFI);
+		if (iface == PHY_INTERFACE_MODE_USXGMII)
+			global_cfg_val |= FIELD_PREP(VEND1_GLOBAL_CFG_RATE_ADAPT,
+						    VEND1_GLOBAL_CFG_RATE_ADAPT_USX);
+		else
+			global_cfg_val |= FIELD_PREP(VEND1_GLOBAL_CFG_RATE_ADAPT,
+						    VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set PHY in low power mode so we can configure protocols */
+	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_SC,
+			       VEND1_GLOBAL_SC_LOW_POWER);
+	if (ret)
+		return ret;
+
+	/* Some dalay is needed to put the chip in low-power */
+	mdelay(10);
+
+	/* Setup the SERDES interface link startup rate */
+	ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_STARTUP_RATE,
+			    FIELD_PREP(VEND1_GLOBAL_STARTUP_RATE_MASK, startup_rate));
+	if (ret)
+		return ret;
+
+	/* Walk the media-speed configuration registers to setup host-side
+	 * serdes modes that may be used by the PHY depending on the
+	 * negotiated media speed.
+	 */
+	for (i = 0; i < ARRAY_SIZE(aqr_global_cfg_regs); i++) {
+		u16 reg = aqr_global_cfg_regs[i];
+		int val;
+
+		val = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg);
+		if (val < 0)
+			return val;
+
+		/* If global_cfg is 0, rate is not supported by FW */
+		if (!val)
+			continue;
+
+		ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, reg,
+				    global_cfg_val);
+		if (ret)
+			return ret;
+	}
+
+	/* set PHY out of low power mode */
+	ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_SC,
+				 VEND1_GLOBAL_SC_LOW_POWER);
+	if (ret)
+		return ret;
+
+	/* Some dalay is needed to put the chip out of low-power */
+	mdelay(10);
+
+	return 0;
+}
+
+static int aqr112_config_init(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = aqr112_setup_interface_protocols(phydev);
+	if (ret)
+		return ret;
+
+	return aqr107_fill_interface_modes(phydev);
+}
+
 static struct phy_driver aqr_driver[] = {
 {
 	PHY_ID_MATCH_MODEL(PHY_ID_AQ1202),
@@ -831,6 +939,7 @@  static struct phy_driver aqr_driver[] = {
 	PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
 	.name		= "Aquantia AQR112",
 	.probe		= aqr107_probe,
+	.config_init	= aqr112_config_init,
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.handle_interrupt = aqr_handle_interrupt,
@@ -849,6 +958,7 @@  static struct phy_driver aqr_driver[] = {
 	PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
 	.name		= "Aquantia AQR412",
 	.probe		= aqr107_probe,
+	.config_init	= aqr112_config_init,
 	.config_aneg    = aqr_config_aneg,
 	.config_intr	= aqr_config_intr,
 	.handle_interrupt = aqr_handle_interrupt,