1 From: Russell King <rmk+kernel@armlinux.org.uk>
2 Date: Thu, 29 Dec 2016 11:03:09 +0000
3 Subject: [PATCH] net: phy: add 802.3 clause 45 support to phylib
5 Add generic helpers for 802.3 clause 45 PHYs for >= 10Gbps support.
7 Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
9 create mode 100644 drivers/net/phy/phy-c45.c
11 --- a/drivers/net/phy/Makefile
12 +++ b/drivers/net/phy/Makefile
14 # Makefile for Linux PHY drivers and MDIO bus drivers
16 libphy-y := phy.o phy_device.o mdio_bus.o mdio_device.o \
18 + phy-c45.o phy-core.o
19 libphy-$(CONFIG_SWPHY) += swphy.o
21 obj-$(CONFIG_MDIO_BOARDINFO) += mdio-boardinfo.o
23 +++ b/drivers/net/phy/phy-c45.c
26 + * Clause 45 PHY support
28 +#include <linux/ethtool.h>
29 +#include <linux/export.h>
30 +#include <linux/mdio.h>
31 +#include <linux/mii.h>
32 +#include <linux/phy.h>
35 + * genphy_c45_setup_forced - configures a forced speed
36 + * @phydev: target phy_device struct
38 +int genphy_c45_pma_setup_forced(struct phy_device *phydev)
40 + int ctrl1, ctrl2, ret;
42 + /* Half duplex is not supported */
43 + if (phydev->duplex != DUPLEX_FULL)
46 + ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
50 + ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2);
54 + ctrl1 &= ~MDIO_CTRL1_SPEEDSEL;
55 + /* PMA/PMD type selection is 1.7.5:0 not 1.7.3:0. See 45.2.1.6.1. */
56 + ctrl2 &= ~(MDIO_PMA_CTRL2_TYPE | 0x30);
58 + switch (phydev->speed) {
60 + ctrl2 |= MDIO_PMA_CTRL2_10BT;
63 + ctrl1 |= MDIO_PMA_CTRL1_SPEED100;
64 + ctrl2 |= MDIO_PMA_CTRL2_100BTX;
67 + ctrl1 |= MDIO_PMA_CTRL1_SPEED1000;
68 + /* Assume 1000base-T */
69 + ctrl2 |= MDIO_PMA_CTRL2_1000BT;
72 + ctrl1 |= MDIO_CTRL1_SPEED10G;
73 + /* Assume 10Gbase-T */
74 + ctrl2 |= MDIO_PMA_CTRL2_10GBT;
80 + ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ctrl1);
84 + return phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2, ctrl2);
86 +EXPORT_SYMBOL_GPL(genphy_c45_pma_setup_forced);
89 + * genphy_c45_an_disable_aneg - disable auto-negotiation
90 + * @phydev: target phy_device struct
92 + * Disable auto-negotiation in the Clause 45 PHY. The link parameters
93 + * parameters are controlled through the PMA/PMD MMD registers.
95 + * Returns zero on success, negative errno code on failure.
97 +int genphy_c45_an_disable_aneg(struct phy_device *phydev)
101 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
105 + val &= ~(MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
107 + return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val);
109 +EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg);
112 + * genphy_c45_restart_aneg - Enable and restart auto-negotiation
113 + * @phydev: target phy_device struct
115 + * This assumes that the auto-negotiation MMD is present.
117 + * Enable and restart auto-negotiation.
119 +int genphy_c45_restart_aneg(struct phy_device *phydev)
123 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
127 + val |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
129 + return phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, val);
131 +EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
134 + * genphy_c45_aneg_done - return auto-negotiation complete status
135 + * @phydev: target phy_device struct
137 + * This assumes that the auto-negotiation MMD is present.
139 + * Reads the status register from the auto-negotiation MMD, returning:
140 + * - positive if auto-negotiation is complete
141 + * - negative errno code on error
144 +int genphy_c45_aneg_done(struct phy_device *phydev)
146 + int val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
148 + return val < 0 ? val : val & MDIO_AN_STAT1_COMPLETE ? 1 : 0;
150 +EXPORT_SYMBOL_GPL(genphy_c45_aneg_done);
153 + * genphy_c45_read_link - read the overall link status from the MMDs
154 + * @phydev: target phy_device struct
155 + * @mmd_mask: MMDs to read status from
157 + * Read the link status from the specified MMDs, and if they all indicate
158 + * that the link is up, return positive. If an error is encountered,
159 + * a negative errno will be returned, otherwise zero.
161 +int genphy_c45_read_link(struct phy_device *phydev, u32 mmd_mask)
167 + devad = __ffs(mmd_mask);
168 + mmd_mask &= ~BIT(devad);
170 + val = phy_read_mmd(phydev, devad, MDIO_STAT1);
174 + /* Read twice because link state is latched and a
175 + * read moves the current state into the register
177 + val = phy_read_mmd(phydev, devad, MDIO_STAT1);
181 + if (!(val & MDIO_STAT1_LSTATUS))
187 +EXPORT_SYMBOL_GPL(genphy_c45_read_link);
190 + * genphy_c45_read_lpa - read the link partner advertisment and pause
191 + * @phydev: target phy_device struct
193 + * Read the Clause 45 defined base (7.19) and 10G (7.33) status registers,
194 + * filling in the link partner advertisment, pause and asym_pause members
195 + * in @phydev. This assumes that the auto-negotiation MMD is present, and
196 + * the backplane bit (7.48.0) is clear. Clause 45 PHY drivers are expected
197 + * to fill in the remainder of the link partner advert from vendor registers.
199 +int genphy_c45_read_lpa(struct phy_device *phydev)
203 + /* Read the link partner's base page advertisment */
204 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
208 + phydev->lp_advertising = mii_lpa_to_ethtool_lpa_t(val);
209 + phydev->pause = val & LPA_PAUSE_CAP ? 1 : 0;
210 + phydev->asym_pause = val & LPA_PAUSE_ASYM ? 1 : 0;
212 + /* Read the link partner's 10G advertisment */
213 + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
217 + if (val & MDIO_AN_10GBT_STAT_LP10G)
218 + phydev->lp_advertising |= ADVERTISED_10000baseT_Full;
222 +EXPORT_SYMBOL_GPL(genphy_c45_read_lpa);
225 + * genphy_c45_read_pma - read link speed etc from PMA
226 + * @phydev: target phy_device struct
228 +int genphy_c45_read_pma(struct phy_device *phydev)
232 + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
236 + switch (val & MDIO_CTRL1_SPEEDSEL) {
238 + phydev->speed = SPEED_10;
240 + case MDIO_PMA_CTRL1_SPEED100:
241 + phydev->speed = SPEED_100;
243 + case MDIO_PMA_CTRL1_SPEED1000:
244 + phydev->speed = SPEED_1000;
246 + case MDIO_CTRL1_SPEED10G:
247 + phydev->speed = SPEED_10000;
250 + phydev->speed = SPEED_UNKNOWN;
254 + phydev->duplex = DUPLEX_FULL;
258 +EXPORT_SYMBOL_GPL(genphy_c45_read_pma);
259 --- a/drivers/net/phy/phy_device.c
260 +++ b/drivers/net/phy/phy_device.c
261 @@ -1452,27 +1452,19 @@ EXPORT_SYMBOL(genphy_read_status);
263 static int gen10g_read_status(struct phy_device *phydev)
266 u32 mmd_mask = phydev->c45_ids.devices_in_package;
271 /* For now just lie and say it's 10G all the time */
272 phydev->speed = SPEED_10000;
273 phydev->duplex = DUPLEX_FULL;
275 - for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) {
276 - if (!(mmd_mask & 1))
279 - /* Read twice because link state is latched and a
280 - * read moves the current state into the register
282 - phy_read_mmd(phydev, devad, MDIO_STAT1);
283 - reg = phy_read_mmd(phydev, devad, MDIO_STAT1);
284 - if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
287 + /* Avoid reading the vendor MMDs */
288 + mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2));
290 + ret = genphy_c45_read_link(phydev, mmd_mask);
292 + phydev->link = ret > 0 ? 1 : 0;
296 --- a/include/linux/phy.h
297 +++ b/include/linux/phy.h
298 @@ -806,6 +806,8 @@ static inline const char *phydev_name(co
299 void phy_attached_print(struct phy_device *phydev, const char *fmt, ...)
301 void phy_attached_info(struct phy_device *phydev);
304 int genphy_config_init(struct phy_device *phydev);
305 int genphy_setup_forced(struct phy_device *phydev);
306 int genphy_restart_aneg(struct phy_device *phydev);
307 @@ -820,6 +822,16 @@ static inline int genphy_no_soft_reset(s
313 +int genphy_c45_restart_aneg(struct phy_device *phydev);
314 +int genphy_c45_aneg_done(struct phy_device *phydev);
315 +int genphy_c45_read_link(struct phy_device *phydev, u32 mmd_mask);
316 +int genphy_c45_read_lpa(struct phy_device *phydev);
317 +int genphy_c45_read_pma(struct phy_device *phydev);
318 +int genphy_c45_pma_setup_forced(struct phy_device *phydev);
319 +int genphy_c45_an_disable_aneg(struct phy_device *phydev);
321 void phy_driver_unregister(struct phy_driver *drv);
322 void phy_drivers_unregister(struct phy_driver *drv, int n);
323 int phy_driver_register(struct phy_driver *new_driver, struct module *owner);