1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Clause 45 PHY support
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun #include <linux/ethtool.h>
6*4882a593Smuzhiyun #include <linux/export.h>
7*4882a593Smuzhiyun #include <linux/mdio.h>
8*4882a593Smuzhiyun #include <linux/mii.h>
9*4882a593Smuzhiyun #include <linux/phy.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun /**
12*4882a593Smuzhiyun * genphy_c45_setup_forced - configures a forced speed
13*4882a593Smuzhiyun * @phydev: target phy_device struct
14*4882a593Smuzhiyun */
genphy_c45_pma_setup_forced(struct phy_device * phydev)15*4882a593Smuzhiyun int genphy_c45_pma_setup_forced(struct phy_device *phydev)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun int ctrl1, ctrl2, ret;
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /* Half duplex is not supported */
20*4882a593Smuzhiyun if (phydev->duplex != DUPLEX_FULL)
21*4882a593Smuzhiyun return -EINVAL;
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
24*4882a593Smuzhiyun if (ctrl1 < 0)
25*4882a593Smuzhiyun return ctrl1;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2);
28*4882a593Smuzhiyun if (ctrl2 < 0)
29*4882a593Smuzhiyun return ctrl2;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun ctrl1 &= ~MDIO_CTRL1_SPEEDSEL;
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun * PMA/PMD type selection is 1.7.5:0 not 1.7.3:0. See 45.2.1.6.1
34*4882a593Smuzhiyun * in 802.3-2012 and 802.3-2015.
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun ctrl2 &= ~(MDIO_PMA_CTRL2_TYPE | 0x30);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun switch (phydev->speed) {
39*4882a593Smuzhiyun case SPEED_10:
40*4882a593Smuzhiyun ctrl2 |= MDIO_PMA_CTRL2_10BT;
41*4882a593Smuzhiyun break;
42*4882a593Smuzhiyun case SPEED_100:
43*4882a593Smuzhiyun ctrl1 |= MDIO_PMA_CTRL1_SPEED100;
44*4882a593Smuzhiyun ctrl2 |= MDIO_PMA_CTRL2_100BTX;
45*4882a593Smuzhiyun break;
46*4882a593Smuzhiyun case SPEED_1000:
47*4882a593Smuzhiyun ctrl1 |= MDIO_PMA_CTRL1_SPEED1000;
48*4882a593Smuzhiyun /* Assume 1000base-T */
49*4882a593Smuzhiyun ctrl2 |= MDIO_PMA_CTRL2_1000BT;
50*4882a593Smuzhiyun break;
51*4882a593Smuzhiyun case SPEED_2500:
52*4882a593Smuzhiyun ctrl1 |= MDIO_CTRL1_SPEED2_5G;
53*4882a593Smuzhiyun /* Assume 2.5Gbase-T */
54*4882a593Smuzhiyun ctrl2 |= MDIO_PMA_CTRL2_2_5GBT;
55*4882a593Smuzhiyun break;
56*4882a593Smuzhiyun case SPEED_5000:
57*4882a593Smuzhiyun ctrl1 |= MDIO_CTRL1_SPEED5G;
58*4882a593Smuzhiyun /* Assume 5Gbase-T */
59*4882a593Smuzhiyun ctrl2 |= MDIO_PMA_CTRL2_5GBT;
60*4882a593Smuzhiyun break;
61*4882a593Smuzhiyun case SPEED_10000:
62*4882a593Smuzhiyun ctrl1 |= MDIO_CTRL1_SPEED10G;
63*4882a593Smuzhiyun /* Assume 10Gbase-T */
64*4882a593Smuzhiyun ctrl2 |= MDIO_PMA_CTRL2_10GBT;
65*4882a593Smuzhiyun break;
66*4882a593Smuzhiyun default:
67*4882a593Smuzhiyun return -EINVAL;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ctrl1);
71*4882a593Smuzhiyun if (ret < 0)
72*4882a593Smuzhiyun return ret;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2, ctrl2);
75*4882a593Smuzhiyun if (ret < 0)
76*4882a593Smuzhiyun return ret;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun return genphy_c45_an_disable_aneg(phydev);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_pma_setup_forced);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /**
83*4882a593Smuzhiyun * genphy_c45_an_config_aneg - configure advertisement registers
84*4882a593Smuzhiyun * @phydev: target phy_device struct
85*4882a593Smuzhiyun *
86*4882a593Smuzhiyun * Configure advertisement registers based on modes set in phydev->advertising
87*4882a593Smuzhiyun *
88*4882a593Smuzhiyun * Returns negative errno code on failure, 0 if advertisement didn't change,
89*4882a593Smuzhiyun * or 1 if advertised modes changed.
90*4882a593Smuzhiyun */
genphy_c45_an_config_aneg(struct phy_device * phydev)91*4882a593Smuzhiyun int genphy_c45_an_config_aneg(struct phy_device *phydev)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun int changed, ret;
94*4882a593Smuzhiyun u32 adv;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun linkmode_and(phydev->advertising, phydev->advertising,
97*4882a593Smuzhiyun phydev->supported);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun changed = genphy_config_eee_advert(phydev);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
104*4882a593Smuzhiyun ADVERTISE_ALL | ADVERTISE_100BASE4 |
105*4882a593Smuzhiyun ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
106*4882a593Smuzhiyun adv);
107*4882a593Smuzhiyun if (ret < 0)
108*4882a593Smuzhiyun return ret;
109*4882a593Smuzhiyun if (ret > 0)
110*4882a593Smuzhiyun changed = 1;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
115*4882a593Smuzhiyun MDIO_AN_10GBT_CTRL_ADV10G |
116*4882a593Smuzhiyun MDIO_AN_10GBT_CTRL_ADV5G |
117*4882a593Smuzhiyun MDIO_AN_10GBT_CTRL_ADV2_5G, adv);
118*4882a593Smuzhiyun if (ret < 0)
119*4882a593Smuzhiyun return ret;
120*4882a593Smuzhiyun if (ret > 0)
121*4882a593Smuzhiyun changed = 1;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun return changed;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_an_config_aneg);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /**
128*4882a593Smuzhiyun * genphy_c45_an_disable_aneg - disable auto-negotiation
129*4882a593Smuzhiyun * @phydev: target phy_device struct
130*4882a593Smuzhiyun *
131*4882a593Smuzhiyun * Disable auto-negotiation in the Clause 45 PHY. The link parameters
132*4882a593Smuzhiyun * parameters are controlled through the PMA/PMD MMD registers.
133*4882a593Smuzhiyun *
134*4882a593Smuzhiyun * Returns zero on success, negative errno code on failure.
135*4882a593Smuzhiyun */
genphy_c45_an_disable_aneg(struct phy_device * phydev)136*4882a593Smuzhiyun int genphy_c45_an_disable_aneg(struct phy_device *phydev)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1,
140*4882a593Smuzhiyun MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /**
145*4882a593Smuzhiyun * genphy_c45_restart_aneg - Enable and restart auto-negotiation
146*4882a593Smuzhiyun * @phydev: target phy_device struct
147*4882a593Smuzhiyun *
148*4882a593Smuzhiyun * This assumes that the auto-negotiation MMD is present.
149*4882a593Smuzhiyun *
150*4882a593Smuzhiyun * Enable and restart auto-negotiation.
151*4882a593Smuzhiyun */
genphy_c45_restart_aneg(struct phy_device * phydev)152*4882a593Smuzhiyun int genphy_c45_restart_aneg(struct phy_device *phydev)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun return phy_set_bits_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1,
155*4882a593Smuzhiyun MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /**
160*4882a593Smuzhiyun * genphy_c45_check_and_restart_aneg - Enable and restart auto-negotiation
161*4882a593Smuzhiyun * @phydev: target phy_device struct
162*4882a593Smuzhiyun * @restart: whether aneg restart is requested
163*4882a593Smuzhiyun *
164*4882a593Smuzhiyun * This assumes that the auto-negotiation MMD is present.
165*4882a593Smuzhiyun *
166*4882a593Smuzhiyun * Check, and restart auto-negotiation if needed.
167*4882a593Smuzhiyun */
genphy_c45_check_and_restart_aneg(struct phy_device * phydev,bool restart)168*4882a593Smuzhiyun int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun int ret;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (!restart) {
173*4882a593Smuzhiyun /* Configure and restart aneg if it wasn't set before */
174*4882a593Smuzhiyun ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
175*4882a593Smuzhiyun if (ret < 0)
176*4882a593Smuzhiyun return ret;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (!(ret & MDIO_AN_CTRL1_ENABLE))
179*4882a593Smuzhiyun restart = true;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (restart)
183*4882a593Smuzhiyun return genphy_c45_restart_aneg(phydev);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun return 0;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /**
190*4882a593Smuzhiyun * genphy_c45_aneg_done - return auto-negotiation complete status
191*4882a593Smuzhiyun * @phydev: target phy_device struct
192*4882a593Smuzhiyun *
193*4882a593Smuzhiyun * This assumes that the auto-negotiation MMD is present.
194*4882a593Smuzhiyun *
195*4882a593Smuzhiyun * Reads the status register from the auto-negotiation MMD, returning:
196*4882a593Smuzhiyun * - positive if auto-negotiation is complete
197*4882a593Smuzhiyun * - negative errno code on error
198*4882a593Smuzhiyun * - zero otherwise
199*4882a593Smuzhiyun */
genphy_c45_aneg_done(struct phy_device * phydev)200*4882a593Smuzhiyun int genphy_c45_aneg_done(struct phy_device *phydev)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun int val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun return val < 0 ? val : val & MDIO_AN_STAT1_COMPLETE ? 1 : 0;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_aneg_done);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /**
209*4882a593Smuzhiyun * genphy_c45_read_link - read the overall link status from the MMDs
210*4882a593Smuzhiyun * @phydev: target phy_device struct
211*4882a593Smuzhiyun *
212*4882a593Smuzhiyun * Read the link status from the specified MMDs, and if they all indicate
213*4882a593Smuzhiyun * that the link is up, set phydev->link to 1. If an error is encountered,
214*4882a593Smuzhiyun * a negative errno will be returned, otherwise zero.
215*4882a593Smuzhiyun */
genphy_c45_read_link(struct phy_device * phydev)216*4882a593Smuzhiyun int genphy_c45_read_link(struct phy_device *phydev)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun u32 mmd_mask = MDIO_DEVS_PMAPMD;
219*4882a593Smuzhiyun int val, devad;
220*4882a593Smuzhiyun bool link = true;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (phydev->c45_ids.mmds_present & MDIO_DEVS_AN) {
223*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
224*4882a593Smuzhiyun if (val < 0)
225*4882a593Smuzhiyun return val;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /* Autoneg is being started, therefore disregard current
228*4882a593Smuzhiyun * link status and report link as down.
229*4882a593Smuzhiyun */
230*4882a593Smuzhiyun if (val & MDIO_AN_CTRL1_RESTART) {
231*4882a593Smuzhiyun phydev->link = 0;
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun while (mmd_mask && link) {
237*4882a593Smuzhiyun devad = __ffs(mmd_mask);
238*4882a593Smuzhiyun mmd_mask &= ~BIT(devad);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /* The link state is latched low so that momentary link
241*4882a593Smuzhiyun * drops can be detected. Do not double-read the status
242*4882a593Smuzhiyun * in polling mode to detect such short link drops except
243*4882a593Smuzhiyun * the link was already down.
244*4882a593Smuzhiyun */
245*4882a593Smuzhiyun if (!phy_polling_mode(phydev) || !phydev->link) {
246*4882a593Smuzhiyun val = phy_read_mmd(phydev, devad, MDIO_STAT1);
247*4882a593Smuzhiyun if (val < 0)
248*4882a593Smuzhiyun return val;
249*4882a593Smuzhiyun else if (val & MDIO_STAT1_LSTATUS)
250*4882a593Smuzhiyun continue;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun val = phy_read_mmd(phydev, devad, MDIO_STAT1);
254*4882a593Smuzhiyun if (val < 0)
255*4882a593Smuzhiyun return val;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if (!(val & MDIO_STAT1_LSTATUS))
258*4882a593Smuzhiyun link = false;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun phydev->link = link;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun return 0;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_read_link);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /**
268*4882a593Smuzhiyun * genphy_c45_read_lpa - read the link partner advertisement and pause
269*4882a593Smuzhiyun * @phydev: target phy_device struct
270*4882a593Smuzhiyun *
271*4882a593Smuzhiyun * Read the Clause 45 defined base (7.19) and 10G (7.33) status registers,
272*4882a593Smuzhiyun * filling in the link partner advertisement, pause and asym_pause members
273*4882a593Smuzhiyun * in @phydev. This assumes that the auto-negotiation MMD is present, and
274*4882a593Smuzhiyun * the backplane bit (7.48.0) is clear. Clause 45 PHY drivers are expected
275*4882a593Smuzhiyun * to fill in the remainder of the link partner advert from vendor registers.
276*4882a593Smuzhiyun */
genphy_c45_read_lpa(struct phy_device * phydev)277*4882a593Smuzhiyun int genphy_c45_read_lpa(struct phy_device *phydev)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun int val;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
282*4882a593Smuzhiyun if (val < 0)
283*4882a593Smuzhiyun return val;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (!(val & MDIO_AN_STAT1_COMPLETE)) {
286*4882a593Smuzhiyun linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
287*4882a593Smuzhiyun phydev->lp_advertising);
288*4882a593Smuzhiyun mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
289*4882a593Smuzhiyun mii_adv_mod_linkmode_adv_t(phydev->lp_advertising, 0);
290*4882a593Smuzhiyun phydev->pause = 0;
291*4882a593Smuzhiyun phydev->asym_pause = 0;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun return 0;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->lp_advertising,
297*4882a593Smuzhiyun val & MDIO_AN_STAT1_LPABLE);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun /* Read the link partner's base page advertisement */
300*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
301*4882a593Smuzhiyun if (val < 0)
302*4882a593Smuzhiyun return val;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun mii_adv_mod_linkmode_adv_t(phydev->lp_advertising, val);
305*4882a593Smuzhiyun phydev->pause = val & LPA_PAUSE_CAP ? 1 : 0;
306*4882a593Smuzhiyun phydev->asym_pause = val & LPA_PAUSE_ASYM ? 1 : 0;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun /* Read the link partner's 10G advertisement */
309*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
310*4882a593Smuzhiyun if (val < 0)
311*4882a593Smuzhiyun return val;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, val);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return 0;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_read_lpa);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /**
320*4882a593Smuzhiyun * genphy_c45_read_pma - read link speed etc from PMA
321*4882a593Smuzhiyun * @phydev: target phy_device struct
322*4882a593Smuzhiyun */
genphy_c45_read_pma(struct phy_device * phydev)323*4882a593Smuzhiyun int genphy_c45_read_pma(struct phy_device *phydev)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun int val;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun linkmode_zero(phydev->lp_advertising);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
330*4882a593Smuzhiyun if (val < 0)
331*4882a593Smuzhiyun return val;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun switch (val & MDIO_CTRL1_SPEEDSEL) {
334*4882a593Smuzhiyun case 0:
335*4882a593Smuzhiyun phydev->speed = SPEED_10;
336*4882a593Smuzhiyun break;
337*4882a593Smuzhiyun case MDIO_PMA_CTRL1_SPEED100:
338*4882a593Smuzhiyun phydev->speed = SPEED_100;
339*4882a593Smuzhiyun break;
340*4882a593Smuzhiyun case MDIO_PMA_CTRL1_SPEED1000:
341*4882a593Smuzhiyun phydev->speed = SPEED_1000;
342*4882a593Smuzhiyun break;
343*4882a593Smuzhiyun case MDIO_CTRL1_SPEED2_5G:
344*4882a593Smuzhiyun phydev->speed = SPEED_2500;
345*4882a593Smuzhiyun break;
346*4882a593Smuzhiyun case MDIO_CTRL1_SPEED5G:
347*4882a593Smuzhiyun phydev->speed = SPEED_5000;
348*4882a593Smuzhiyun break;
349*4882a593Smuzhiyun case MDIO_CTRL1_SPEED10G:
350*4882a593Smuzhiyun phydev->speed = SPEED_10000;
351*4882a593Smuzhiyun break;
352*4882a593Smuzhiyun default:
353*4882a593Smuzhiyun phydev->speed = SPEED_UNKNOWN;
354*4882a593Smuzhiyun break;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun phydev->duplex = DUPLEX_FULL;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun return 0;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_read_pma);
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun /**
364*4882a593Smuzhiyun * genphy_c45_read_mdix - read mdix status from PMA
365*4882a593Smuzhiyun * @phydev: target phy_device struct
366*4882a593Smuzhiyun */
genphy_c45_read_mdix(struct phy_device * phydev)367*4882a593Smuzhiyun int genphy_c45_read_mdix(struct phy_device *phydev)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun int val;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (phydev->speed == SPEED_10000) {
372*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
373*4882a593Smuzhiyun MDIO_PMA_10GBT_SWAPPOL);
374*4882a593Smuzhiyun if (val < 0)
375*4882a593Smuzhiyun return val;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun switch (val) {
378*4882a593Smuzhiyun case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
379*4882a593Smuzhiyun phydev->mdix = ETH_TP_MDI;
380*4882a593Smuzhiyun break;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun case 0:
383*4882a593Smuzhiyun phydev->mdix = ETH_TP_MDI_X;
384*4882a593Smuzhiyun break;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun default:
387*4882a593Smuzhiyun phydev->mdix = ETH_TP_MDI_INVALID;
388*4882a593Smuzhiyun break;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun return 0;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_read_mdix);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun /**
397*4882a593Smuzhiyun * genphy_c45_pma_read_abilities - read supported link modes from PMA
398*4882a593Smuzhiyun * @phydev: target phy_device struct
399*4882a593Smuzhiyun *
400*4882a593Smuzhiyun * Read the supported link modes from the PMA Status 2 (1.8) register. If bit
401*4882a593Smuzhiyun * 1.8.9 is set, the list of supported modes is build using the values in the
402*4882a593Smuzhiyun * PMA Extended Abilities (1.11) register, indicating 1000BASET an 10G related
403*4882a593Smuzhiyun * modes. If bit 1.11.14 is set, then the list is also extended with the modes
404*4882a593Smuzhiyun * in the 2.5G/5G PMA Extended register (1.21), indicating if 2.5GBASET and
405*4882a593Smuzhiyun * 5GBASET are supported.
406*4882a593Smuzhiyun */
genphy_c45_pma_read_abilities(struct phy_device * phydev)407*4882a593Smuzhiyun int genphy_c45_pma_read_abilities(struct phy_device *phydev)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun int val;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
412*4882a593Smuzhiyun if (phydev->c45_ids.mmds_present & MDIO_DEVS_AN) {
413*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
414*4882a593Smuzhiyun if (val < 0)
415*4882a593Smuzhiyun return val;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (val & MDIO_AN_STAT1_ABLE)
418*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
419*4882a593Smuzhiyun phydev->supported);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2);
423*4882a593Smuzhiyun if (val < 0)
424*4882a593Smuzhiyun return val;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
427*4882a593Smuzhiyun phydev->supported,
428*4882a593Smuzhiyun val & MDIO_PMA_STAT2_10GBSR);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
431*4882a593Smuzhiyun phydev->supported,
432*4882a593Smuzhiyun val & MDIO_PMA_STAT2_10GBLR);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
435*4882a593Smuzhiyun phydev->supported,
436*4882a593Smuzhiyun val & MDIO_PMA_STAT2_10GBER);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (val & MDIO_PMA_STAT2_EXTABLE) {
439*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
440*4882a593Smuzhiyun if (val < 0)
441*4882a593Smuzhiyun return val;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
444*4882a593Smuzhiyun phydev->supported,
445*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_10GBLRM);
446*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
447*4882a593Smuzhiyun phydev->supported,
448*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_10GBT);
449*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
450*4882a593Smuzhiyun phydev->supported,
451*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_10GBKX4);
452*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
453*4882a593Smuzhiyun phydev->supported,
454*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_10GBKR);
455*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
456*4882a593Smuzhiyun phydev->supported,
457*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_1000BT);
458*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
459*4882a593Smuzhiyun phydev->supported,
460*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_1000BKX);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
463*4882a593Smuzhiyun phydev->supported,
464*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_100BTX);
465*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
466*4882a593Smuzhiyun phydev->supported,
467*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_100BTX);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
470*4882a593Smuzhiyun phydev->supported,
471*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_10BT);
472*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
473*4882a593Smuzhiyun phydev->supported,
474*4882a593Smuzhiyun val & MDIO_PMA_EXTABLE_10BT);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun if (val & MDIO_PMA_EXTABLE_NBT) {
477*4882a593Smuzhiyun val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
478*4882a593Smuzhiyun MDIO_PMA_NG_EXTABLE);
479*4882a593Smuzhiyun if (val < 0)
480*4882a593Smuzhiyun return val;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
483*4882a593Smuzhiyun phydev->supported,
484*4882a593Smuzhiyun val & MDIO_PMA_NG_EXTABLE_2_5GBT);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
487*4882a593Smuzhiyun phydev->supported,
488*4882a593Smuzhiyun val & MDIO_PMA_NG_EXTABLE_5GBT);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_pma_read_abilities);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun /**
497*4882a593Smuzhiyun * genphy_c45_read_status - read PHY status
498*4882a593Smuzhiyun * @phydev: target phy_device struct
499*4882a593Smuzhiyun *
500*4882a593Smuzhiyun * Reads status from PHY and sets phy_device members accordingly.
501*4882a593Smuzhiyun */
genphy_c45_read_status(struct phy_device * phydev)502*4882a593Smuzhiyun int genphy_c45_read_status(struct phy_device *phydev)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun int ret;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun ret = genphy_c45_read_link(phydev);
507*4882a593Smuzhiyun if (ret)
508*4882a593Smuzhiyun return ret;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun phydev->speed = SPEED_UNKNOWN;
511*4882a593Smuzhiyun phydev->duplex = DUPLEX_UNKNOWN;
512*4882a593Smuzhiyun phydev->pause = 0;
513*4882a593Smuzhiyun phydev->asym_pause = 0;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun if (phydev->autoneg == AUTONEG_ENABLE) {
516*4882a593Smuzhiyun ret = genphy_c45_read_lpa(phydev);
517*4882a593Smuzhiyun if (ret)
518*4882a593Smuzhiyun return ret;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun phy_resolve_aneg_linkmode(phydev);
521*4882a593Smuzhiyun } else {
522*4882a593Smuzhiyun ret = genphy_c45_read_pma(phydev);
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun return ret;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_read_status);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /**
530*4882a593Smuzhiyun * genphy_c45_config_aneg - restart auto-negotiation or forced setup
531*4882a593Smuzhiyun * @phydev: target phy_device struct
532*4882a593Smuzhiyun *
533*4882a593Smuzhiyun * Description: If auto-negotiation is enabled, we configure the
534*4882a593Smuzhiyun * advertising, and then restart auto-negotiation. If it is not
535*4882a593Smuzhiyun * enabled, then we force a configuration.
536*4882a593Smuzhiyun */
genphy_c45_config_aneg(struct phy_device * phydev)537*4882a593Smuzhiyun int genphy_c45_config_aneg(struct phy_device *phydev)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun bool changed = false;
540*4882a593Smuzhiyun int ret;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun if (phydev->autoneg == AUTONEG_DISABLE)
543*4882a593Smuzhiyun return genphy_c45_pma_setup_forced(phydev);
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun ret = genphy_c45_an_config_aneg(phydev);
546*4882a593Smuzhiyun if (ret < 0)
547*4882a593Smuzhiyun return ret;
548*4882a593Smuzhiyun if (ret > 0)
549*4882a593Smuzhiyun changed = true;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun return genphy_c45_check_and_restart_aneg(phydev, changed);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(genphy_c45_config_aneg);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun /* The gen10g_* functions are the old Clause 45 stub */
556*4882a593Smuzhiyun
gen10g_config_aneg(struct phy_device * phydev)557*4882a593Smuzhiyun int gen10g_config_aneg(struct phy_device *phydev)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun return 0;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gen10g_config_aneg);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun struct phy_driver genphy_c45_driver = {
564*4882a593Smuzhiyun .phy_id = 0xffffffff,
565*4882a593Smuzhiyun .phy_id_mask = 0xffffffff,
566*4882a593Smuzhiyun .name = "Generic Clause 45 PHY",
567*4882a593Smuzhiyun .read_status = genphy_c45_read_status,
568*4882a593Smuzhiyun };
569