From: Nicolai Buchwitz <nb@tipi-net.de>
To: netdev@vger.kernel.org
Cc: Phil Elwell <phil@raspberrypi.com>,
Nicolai Buchwitz <nb@tipi-net.de>, Andrew Lunn <andrew@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
linux-kernel@vger.kernel.org
Subject: [PATCH 1/2] net: phy: microchip: add downshift tunable support for LAN88xx
Date: Mon, 30 Mar 2026 00:41:59 +0200 [thread overview]
Message-ID: <20260329224202.500229-2-nb@tipi-net.de> (raw)
In-Reply-To: <20260329224202.500229-1-nb@tipi-net.de>
Implement the standard ETHTOOL_PHY_DOWNSHIFT tunable for the LAN88xx
PHY. This allows runtime configuration of the auto-downshift feature
via ethtool:
ethtool --set-phy-tunable eth0 downshift on count 3
The LAN88xx PHY supports downshifting from 1000BASE-T to 100BASE-TX
after 2-5 failed auto-negotiation attempts. Valid count values are
2, 3, 4 and 5.
This is based on an earlier downstream implementation by Phil Elwell.
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/net/phy/microchip.c | 89 ++++++++++++++++++++++++++++++++++++
include/linux/microchipphy.h | 9 ++++
2 files changed, 98 insertions(+)
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index dc8634e7bcbe..a044be1ade79 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -193,6 +193,93 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
phydev_warn(phydev, "Failed to Set Register[0x1686]\n");
}
+static int lan88xx_get_downshift(struct phy_device *phydev, u8 *data)
+{
+ int val;
+
+ val = phy_read_paged(phydev, 1, LAN78XX_PHY_CTRL3);
+ if (val < 0)
+ return val;
+
+ if (!(val & LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT)) {
+ *data = DOWNSHIFT_DEV_DISABLE;
+ return 0;
+ }
+
+ switch (val & LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK) {
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2:
+ *data = 2;
+ break;
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3:
+ *data = 3;
+ break;
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4:
+ *data = 4;
+ break;
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5:
+ *data = 5;
+ break;
+ }
+
+ return 0;
+}
+
+static int lan88xx_set_downshift(struct phy_device *phydev, u8 cnt)
+{
+ u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK |
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+ u32 val;
+
+ if (cnt == DOWNSHIFT_DEV_DISABLE)
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT, 0);
+
+ if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
+ cnt = 2;
+
+ switch (cnt) {
+ case 2:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
+ break;
+ case 3:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
+ break;
+ case 4:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
+ break;
+ case 5:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3, mask,
+ val | LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT);
+}
+
+static int lan88xx_get_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_get_downshift(phydev, data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lan88xx_set_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, const void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_set_downshift(phydev, *(const u8 *)data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int lan88xx_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -499,6 +586,8 @@ static struct phy_driver microchip_phy_driver[] = {
.set_wol = lan88xx_set_wol,
.read_page = lan88xx_read_page,
.write_page = lan88xx_write_page,
+ .get_tunable = lan88xx_get_tunable,
+ .set_tunable = lan88xx_set_tunable,
},
{
PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX),
diff --git a/include/linux/microchipphy.h b/include/linux/microchipphy.h
index 517288da19fd..a8deae3977e9 100644
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -61,6 +61,15 @@
/* Registers specific to the LAN7800/LAN7850 embedded phy */
#define LAN78XX_PHY_LED_MODE_SELECT (0x1D)
+/* PHY Control 3 register (page 1) */
+#define LAN78XX_PHY_CTRL3 (0x14)
+#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT BIT(4)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK GENMASK(3, 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2 (0 << 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3 (1 << 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4 (2 << 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5 (3 << 2)
+
/* DSP registers */
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A)
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000)
--
2.51.0
next prev parent reply other threads:[~2026-03-29 22:42 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-29 22:41 [PATCH net-next 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2026-03-29 22:41 ` Nicolai Buchwitz [this message]
2026-03-30 13:01 ` [PATCH 1/2] net: phy: microchip: add downshift tunable " Andrew Lunn
2026-03-30 13:02 ` Andrew Lunn
2026-03-29 22:42 ` [PATCH 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
2026-03-30 13:03 ` Andrew Lunn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260329224202.500229-2-nb@tipi-net.de \
--to=nb@tipi-net.de \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=phil@raspberrypi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox