@@ -1386,6 +1386,30 @@ int genphy_c45_eee_is_active(struct phy_device *phydev, unsigned long *adv,
}
EXPORT_SYMBOL(genphy_c45_eee_is_active);
+/**
+ * genphy_c45_eee_clk_stop_enable - Clock should stop during LPI signalling
+ * @phydev: target phy_device struct
+ *
+ * Description: Program the MMD register 3.0 setting the "Clock stop enable"
+ * bit.
+ */
+int genphy_c45_eee_clk_stop_enable(struct phy_device *phydev)
+{
+ int ret;
+
+ /* IEEE 802.3:2018 - 45.2.3.2.6 Clock stop capable (3.1.6) */
+ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
+ if (ret < 0)
+ return ret;
+
+ if (ret & MDIO_STAT1_CLKSTOP_CAPABLE)
+ /* IEEE 802.3-2018 45.2.3.1.4 Clock stop enable (3.0.10) */
+ return phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1,
+ MDIO_PCS_CTRL1_CLKSTOP_EN);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_eee_clk_stop_enable);
+
/**
* genphy_c45_ethtool_get_eee - get EEE supported and status
* @phydev: target phy_device struct
@@ -1573,6 +1573,25 @@ int phy_get_eee_err(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_get_eee_err);
+/**
+ * phy_eee_clk_stop_enable - Clock should stop during LIP
+ * @phydev: target phy_device struct
+ *
+ * Description: Program the PHY to stop the clock when EEE is
+ * signalling LPI
+ */
+int phy_eee_clk_stop_enable(struct phy_device *phydev)
+{
+ int ret;
+
+ mutex_lock(&phydev->lock);
+ ret = genphy_c45_eee_clk_stop_enable(phydev);
+ mutex_unlock(&phydev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_eee_clk_stop_enable);
+
/**
* phy_ethtool_get_eee - get EEE supported and status
* @phydev: target phy_device struct
@@ -1773,6 +1773,7 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv);
int genphy_c45_an_config_eee_aneg(struct phy_device *phydev);
int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv);
+int genphy_c45_eee_clk_stop_enable(struct phy_device *phydev);
/* Generic C45 PHY driver */
extern struct phy_driver genphy_c45_driver;
@@ -1847,6 +1848,7 @@ int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask);
int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable);
int phy_get_eee_err(struct phy_device *phydev);
+int phy_eee_clk_stop_enable(struct phy_device *phydev);
int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data);
int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data);
int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol);
@@ -121,6 +121,7 @@
/* Status register 1. */
#define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */
#define MDIO_STAT1_LSTATUS BMSR_LSTATUS
+#define MDIO_STAT1_CLKSTOP_CAPABLE 0x0040 /* Clock stop capable */
#define MDIO_STAT1_FAULT 0x0080 /* Fault */
#define MDIO_AN_STAT1_LPABLE 0x0001 /* Link partner AN ability */
#define MDIO_AN_STAT1_ABLE BMSR_ANEGCAPABLE
The MAC driver can request that the PHY stops the clock during EEE LPI. This has normally been does as part of phy_init_eee(), however that function is overly complex and often wrongly used. Add a standalone helper, to aid removing phy_init_eee(). The helper currently calls generic code, but it could in the future call a PHY specific op if a PHY exports different registers to 802.3. Signed-off-by: Andrew Lunn <andrew@lunn.ch> --- v2: Add missing EXPORT_SYMBOL_GPL v3: Move register access into phy-c45.c --- drivers/net/phy/phy-c45.c | 24 ++++++++++++++++++++++++ drivers/net/phy/phy.c | 19 +++++++++++++++++++ include/linux/phy.h | 2 ++ include/uapi/linux/mdio.h | 1 + 4 files changed, 46 insertions(+)