diff options
| author | Fidelio Lawson <lawson.fidelio@gmail.com> | 2026-06-09 19:19:57 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-06-12 01:47:56 +0300 |
| commit | a1ee1b9beb7dbbc1cd52b08471ccaf4b8399d9eb (patch) | |
| tree | 688b0db86047dd53d6c98e63b97b5120e4219121 | |
| parent | 13655144ddcad532c4e9338788041654a54e5c2f (diff) | |
| download | linux-a1ee1b9beb7dbbc1cd52b08471ccaf4b8399d9eb.tar.xz | |
net: phy: micrel: expose KSZ87xx low-loss cable tunables
Add support for the KSZ87xx low-loss cable PHY tunables in the Micrel
PHY driver by implementing get_tunable and set_tunable callbacks.
These callbacks expose vendor-specific PHY tunables used to control the
KSZ87xx embedded PHY receiver behavior when operating with short or
low-loss Ethernet cables. The tunables provide:
- a boolean short-cable preset applying known good settings;
- an integer LPF bandwidth control;
- an integer DSP EQ initial value control.
The Micrel PHY driver forwards these tunables via standard phy_read() /
phy_write() operations, which are virtualized by the KSZ8 DSA driver and
translated into the appropriate indirect switch register accesses.
Reviewed-by: Marek Vasut <marex@nabladev.com>
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
Signed-off-by: Fidelio Lawson <fidelio.lawson@exotec.com>
Link: https://patch.msgid.link/20260609-ksz87xx_errata_low_loss_connections-v10-3-9ba4418cf3db@exotec.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/phy/micrel.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index e211a523c258..55df5efcfc86 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -287,6 +287,12 @@ /* PHY Control 2 / PHY Control (if no PHY Control 1) */ #define MII_KSZPHY_CTRL_2 0x1f #define MII_KSZPHY_CTRL MII_KSZPHY_CTRL_2 + +/* Vendor-specific Clause 22 register, virtualized by KSZ87xx embedded PHYs DSA driver */ +#define MII_KSZ87XX_SHORT_CABLE 0x1a +#define MII_KSZ87XX_LPF_BW 0x1b +#define MII_KSZ87XX_EQ_INIT 0x1c + /* bitmap of PHY register to set interrupt mode */ #define KSZ8081_CTRL2_HP_MDIX BIT(15) #define KSZ8081_CTRL2_MDI_MDI_X_SELECT BIT(14) @@ -940,6 +946,59 @@ static int ksz8795_match_phy_device(struct phy_device *phydev, return ksz8051_ksz8795_match_phy_device(phydev, false); } +static int ksz8795_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + int ret; + + switch (tuna->id) { + case ETHTOOL_PHY_SHORT_CABLE_PRESET: + ret = phy_read(phydev, MII_KSZ87XX_SHORT_CABLE); + if (ret < 0) + return ret; + *(u8 *)data = ret; + return 0; + case ETHTOOL_PHY_LPF_BW: + ret = phy_read(phydev, MII_KSZ87XX_LPF_BW); + if (ret < 0) + return ret; + *(u32 *)data = ret & 0xff; + return 0; + case ETHTOOL_PHY_DSP_EQ_INIT_VALUE: + ret = phy_read(phydev, MII_KSZ87XX_EQ_INIT); + if (ret < 0) + return ret; + *(u32 *)data = ret & 0xff; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int ksz8795_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + u32 val; + + switch (tuna->id) { + case ETHTOOL_PHY_SHORT_CABLE_PRESET: + return phy_write(phydev, MII_KSZ87XX_SHORT_CABLE, + *(const u8 *)data); + case ETHTOOL_PHY_LPF_BW: + val = *(const u32 *)data; + if (val > 0xff) + return -EINVAL; + return phy_write(phydev, MII_KSZ87XX_LPF_BW, (u8)val); + case ETHTOOL_PHY_DSP_EQ_INIT_VALUE: + val = *(const u32 *)data; + if (val > 0xff) + return -EINVAL; + return phy_write(phydev, MII_KSZ87XX_EQ_INIT, (u8)val); + default: + return -EOPNOTSUPP; + } +} + static int ksz9021_load_values_from_of(struct phy_device *phydev, const struct device_node *of_node, u16 reg, @@ -6961,6 +7020,8 @@ static struct phy_driver ksphy_driver[] = { /* PHY_BASIC_FEATURES */ .config_init = kszphy_config_init, .match_phy_device = ksz8795_match_phy_device, + .get_tunable = ksz8795_get_tunable, + .set_tunable = ksz8795_set_tunable, .suspend = genphy_suspend, .resume = genphy_resume, }, { |
