1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Marvell 88x2222 dual-port multi-speed ethernet transceiver. |
4 | * |
5 | * Supports: |
6 | * XAUI on the host side. |
7 | * 1000Base-X or 10GBase-R on the line side. |
8 | * SGMII over 1000Base-X. |
9 | */ |
10 | #include <linux/module.h> |
11 | #include <linux/phy.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/mdio.h> |
14 | #include <linux/marvell_phy.h> |
15 | #include <linux/of.h> |
16 | #include <linux/sfp.h> |
17 | #include <linux/netdevice.h> |
18 | |
19 | /* Port PCS Configuration */ |
20 | #define MV_PCS_CONFIG 0xF002 |
21 | #define MV_PCS_HOST_XAUI 0x73 |
22 | #define MV_PCS_LINE_10GBR (0x71 << 8) |
23 | #define MV_PCS_LINE_1GBX_AN (0x7B << 8) |
24 | #define MV_PCS_LINE_SGMII_AN (0x7F << 8) |
25 | |
26 | /* Port Reset and Power Down */ |
27 | #define MV_PORT_RST 0xF003 |
28 | #define MV_LINE_RST_SW BIT(15) |
29 | #define MV_HOST_RST_SW BIT(7) |
30 | #define MV_PORT_RST_SW (MV_LINE_RST_SW | MV_HOST_RST_SW) |
31 | |
32 | /* PMD Receive Signal Detect */ |
33 | #define MV_RX_SIGNAL_DETECT 0x000A |
34 | #define MV_RX_SIGNAL_DETECT_GLOBAL BIT(0) |
35 | |
36 | /* 1000Base-X/SGMII Control Register */ |
37 | #define MV_1GBX_CTRL (0x2000 + MII_BMCR) |
38 | |
39 | /* 1000BASE-X/SGMII Status Register */ |
40 | #define MV_1GBX_STAT (0x2000 + MII_BMSR) |
41 | |
42 | /* 1000Base-X Auto-Negotiation Advertisement Register */ |
43 | #define MV_1GBX_ADVERTISE (0x2000 + MII_ADVERTISE) |
44 | |
45 | /* 1000Base-X PHY Specific Status Register */ |
46 | #define MV_1GBX_PHY_STAT 0xA003 |
47 | #define MV_1GBX_PHY_STAT_AN_RESOLVED BIT(11) |
48 | #define MV_1GBX_PHY_STAT_DUPLEX BIT(13) |
49 | #define MV_1GBX_PHY_STAT_SPEED100 BIT(14) |
50 | #define MV_1GBX_PHY_STAT_SPEED1000 BIT(15) |
51 | |
52 | #define AUTONEG_TIMEOUT 3 |
53 | |
54 | struct mv2222_data { |
55 | phy_interface_t line_interface; |
56 | __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); |
57 | bool sfp_link; |
58 | }; |
59 | |
60 | /* SFI PMA transmit enable */ |
61 | static int mv2222_tx_enable(struct phy_device *phydev) |
62 | { |
63 | return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, |
64 | MDIO_PMD_TXDIS_GLOBAL); |
65 | } |
66 | |
67 | /* SFI PMA transmit disable */ |
68 | static int mv2222_tx_disable(struct phy_device *phydev) |
69 | { |
70 | return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, |
71 | MDIO_PMD_TXDIS_GLOBAL); |
72 | } |
73 | |
74 | static int mv2222_soft_reset(struct phy_device *phydev) |
75 | { |
76 | int val, ret; |
77 | |
78 | ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PORT_RST, |
79 | MV_PORT_RST_SW); |
80 | if (ret < 0) |
81 | return ret; |
82 | |
83 | return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND2, MV_PORT_RST, |
84 | val, !(val & MV_PORT_RST_SW), |
85 | 5000, 1000000, true); |
86 | } |
87 | |
88 | static int mv2222_disable_aneg(struct phy_device *phydev) |
89 | { |
90 | int ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL, |
91 | BMCR_ANENABLE | BMCR_ANRESTART); |
92 | if (ret < 0) |
93 | return ret; |
94 | |
95 | return mv2222_soft_reset(phydev); |
96 | } |
97 | |
98 | static int mv2222_enable_aneg(struct phy_device *phydev) |
99 | { |
100 | int ret = phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL, |
101 | BMCR_ANENABLE | BMCR_RESET); |
102 | if (ret < 0) |
103 | return ret; |
104 | |
105 | return mv2222_soft_reset(phydev); |
106 | } |
107 | |
108 | static int mv2222_set_sgmii_speed(struct phy_device *phydev) |
109 | { |
110 | struct mv2222_data *priv = phydev->priv; |
111 | |
112 | switch (phydev->speed) { |
113 | default: |
114 | case SPEED_1000: |
115 | if ((linkmode_test_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Full_BIT, |
116 | addr: priv->supported) || |
117 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Half_BIT, |
118 | addr: priv->supported))) |
119 | return phy_modify_mmd(phydev, MDIO_MMD_PCS, |
120 | MV_1GBX_CTRL, |
121 | BMCR_SPEED1000 | BMCR_SPEED100, |
122 | BMCR_SPEED1000); |
123 | |
124 | fallthrough; |
125 | case SPEED_100: |
126 | if ((linkmode_test_bit(nr: ETHTOOL_LINK_MODE_100baseT_Full_BIT, |
127 | addr: priv->supported) || |
128 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_100baseT_Half_BIT, |
129 | addr: priv->supported))) |
130 | return phy_modify_mmd(phydev, MDIO_MMD_PCS, |
131 | MV_1GBX_CTRL, |
132 | BMCR_SPEED1000 | BMCR_SPEED100, |
133 | BMCR_SPEED100); |
134 | fallthrough; |
135 | case SPEED_10: |
136 | if ((linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10baseT_Full_BIT, |
137 | addr: priv->supported) || |
138 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10baseT_Half_BIT, |
139 | addr: priv->supported))) |
140 | return phy_modify_mmd(phydev, MDIO_MMD_PCS, |
141 | MV_1GBX_CTRL, |
142 | BMCR_SPEED1000 | BMCR_SPEED100, |
143 | BMCR_SPEED10); |
144 | |
145 | return -EINVAL; |
146 | } |
147 | } |
148 | |
149 | static bool mv2222_is_10g_capable(struct phy_device *phydev) |
150 | { |
151 | struct mv2222_data *priv = phydev->priv; |
152 | |
153 | return (linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
154 | addr: priv->supported) || |
155 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, |
156 | addr: priv->supported) || |
157 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, |
158 | addr: priv->supported) || |
159 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, |
160 | addr: priv->supported) || |
161 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, |
162 | addr: priv->supported) || |
163 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10000baseER_Full_BIT, |
164 | addr: priv->supported)); |
165 | } |
166 | |
167 | static bool mv2222_is_1gbx_capable(struct phy_device *phydev) |
168 | { |
169 | struct mv2222_data *priv = phydev->priv; |
170 | |
171 | return linkmode_test_bit(nr: ETHTOOL_LINK_MODE_1000baseX_Full_BIT, |
172 | addr: priv->supported); |
173 | } |
174 | |
175 | static bool mv2222_is_sgmii_capable(struct phy_device *phydev) |
176 | { |
177 | struct mv2222_data *priv = phydev->priv; |
178 | |
179 | return (linkmode_test_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Full_BIT, |
180 | addr: priv->supported) || |
181 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Half_BIT, |
182 | addr: priv->supported) || |
183 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_100baseT_Full_BIT, |
184 | addr: priv->supported) || |
185 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_100baseT_Half_BIT, |
186 | addr: priv->supported) || |
187 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10baseT_Full_BIT, |
188 | addr: priv->supported) || |
189 | linkmode_test_bit(nr: ETHTOOL_LINK_MODE_10baseT_Half_BIT, |
190 | addr: priv->supported)); |
191 | } |
192 | |
193 | static int mv2222_config_line(struct phy_device *phydev) |
194 | { |
195 | struct mv2222_data *priv = phydev->priv; |
196 | |
197 | switch (priv->line_interface) { |
198 | case PHY_INTERFACE_MODE_10GBASER: |
199 | return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG, |
200 | MV_PCS_HOST_XAUI | MV_PCS_LINE_10GBR); |
201 | case PHY_INTERFACE_MODE_1000BASEX: |
202 | return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG, |
203 | MV_PCS_HOST_XAUI | MV_PCS_LINE_1GBX_AN); |
204 | case PHY_INTERFACE_MODE_SGMII: |
205 | return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG, |
206 | MV_PCS_HOST_XAUI | MV_PCS_LINE_SGMII_AN); |
207 | default: |
208 | return -EINVAL; |
209 | } |
210 | } |
211 | |
212 | /* Switch between 1G (1000Base-X/SGMII) and 10G (10GBase-R) modes */ |
213 | static int mv2222_swap_line_type(struct phy_device *phydev) |
214 | { |
215 | struct mv2222_data *priv = phydev->priv; |
216 | bool changed = false; |
217 | int ret; |
218 | |
219 | switch (priv->line_interface) { |
220 | case PHY_INTERFACE_MODE_10GBASER: |
221 | if (mv2222_is_1gbx_capable(phydev)) { |
222 | priv->line_interface = PHY_INTERFACE_MODE_1000BASEX; |
223 | changed = true; |
224 | } |
225 | |
226 | if (mv2222_is_sgmii_capable(phydev)) { |
227 | priv->line_interface = PHY_INTERFACE_MODE_SGMII; |
228 | changed = true; |
229 | } |
230 | |
231 | break; |
232 | case PHY_INTERFACE_MODE_1000BASEX: |
233 | case PHY_INTERFACE_MODE_SGMII: |
234 | if (mv2222_is_10g_capable(phydev)) { |
235 | priv->line_interface = PHY_INTERFACE_MODE_10GBASER; |
236 | changed = true; |
237 | } |
238 | |
239 | break; |
240 | default: |
241 | return -EINVAL; |
242 | } |
243 | |
244 | if (changed) { |
245 | ret = mv2222_config_line(phydev); |
246 | if (ret < 0) |
247 | return ret; |
248 | } |
249 | |
250 | return 0; |
251 | } |
252 | |
253 | static int mv2222_setup_forced(struct phy_device *phydev) |
254 | { |
255 | struct mv2222_data *priv = phydev->priv; |
256 | int ret; |
257 | |
258 | if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER) { |
259 | if (phydev->speed < SPEED_10000 && |
260 | phydev->speed != SPEED_UNKNOWN) { |
261 | ret = mv2222_swap_line_type(phydev); |
262 | if (ret < 0) |
263 | return ret; |
264 | } |
265 | } |
266 | |
267 | if (priv->line_interface == PHY_INTERFACE_MODE_SGMII) { |
268 | ret = mv2222_set_sgmii_speed(phydev); |
269 | if (ret < 0) |
270 | return ret; |
271 | } |
272 | |
273 | return mv2222_disable_aneg(phydev); |
274 | } |
275 | |
276 | static int mv2222_config_aneg(struct phy_device *phydev) |
277 | { |
278 | struct mv2222_data *priv = phydev->priv; |
279 | int ret, adv; |
280 | |
281 | /* SFP is not present, do nothing */ |
282 | if (priv->line_interface == PHY_INTERFACE_MODE_NA) |
283 | return 0; |
284 | |
285 | if (phydev->autoneg == AUTONEG_DISABLE || |
286 | priv->line_interface == PHY_INTERFACE_MODE_10GBASER) |
287 | return mv2222_setup_forced(phydev); |
288 | |
289 | adv = linkmode_adv_to_mii_adv_x(linkmodes: priv->supported, |
290 | fd_bit: ETHTOOL_LINK_MODE_1000baseX_Full_BIT); |
291 | |
292 | ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_ADVERTISE, |
293 | ADVERTISE_1000XFULL | |
294 | ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM, |
295 | set: adv); |
296 | if (ret < 0) |
297 | return ret; |
298 | |
299 | return mv2222_enable_aneg(phydev); |
300 | } |
301 | |
302 | static int mv2222_aneg_done(struct phy_device *phydev) |
303 | { |
304 | int ret; |
305 | |
306 | if (mv2222_is_10g_capable(phydev)) { |
307 | ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); |
308 | if (ret < 0) |
309 | return ret; |
310 | |
311 | if (ret & MDIO_STAT1_LSTATUS) |
312 | return 1; |
313 | } |
314 | |
315 | ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT); |
316 | if (ret < 0) |
317 | return ret; |
318 | |
319 | return (ret & BMSR_ANEGCOMPLETE); |
320 | } |
321 | |
322 | /* Returns negative on error, 0 if link is down, 1 if link is up */ |
323 | static int mv2222_read_status_10g(struct phy_device *phydev) |
324 | { |
325 | static int timeout; |
326 | int val, link = 0; |
327 | |
328 | val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); |
329 | if (val < 0) |
330 | return val; |
331 | |
332 | if (val & MDIO_STAT1_LSTATUS) { |
333 | link = 1; |
334 | |
335 | /* 10GBASE-R do not support auto-negotiation */ |
336 | phydev->autoneg = AUTONEG_DISABLE; |
337 | phydev->speed = SPEED_10000; |
338 | phydev->duplex = DUPLEX_FULL; |
339 | } else { |
340 | if (phydev->autoneg == AUTONEG_ENABLE) { |
341 | timeout++; |
342 | |
343 | if (timeout > AUTONEG_TIMEOUT) { |
344 | timeout = 0; |
345 | |
346 | val = mv2222_swap_line_type(phydev); |
347 | if (val < 0) |
348 | return val; |
349 | |
350 | return mv2222_config_aneg(phydev); |
351 | } |
352 | } |
353 | } |
354 | |
355 | return link; |
356 | } |
357 | |
358 | /* Returns negative on error, 0 if link is down, 1 if link is up */ |
359 | static int mv2222_read_status_1g(struct phy_device *phydev) |
360 | { |
361 | static int timeout; |
362 | int val, link = 0; |
363 | |
364 | val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT); |
365 | if (val < 0) |
366 | return val; |
367 | |
368 | if (phydev->autoneg == AUTONEG_ENABLE && |
369 | !(val & BMSR_ANEGCOMPLETE)) { |
370 | timeout++; |
371 | |
372 | if (timeout > AUTONEG_TIMEOUT) { |
373 | timeout = 0; |
374 | |
375 | val = mv2222_swap_line_type(phydev); |
376 | if (val < 0) |
377 | return val; |
378 | |
379 | return mv2222_config_aneg(phydev); |
380 | } |
381 | |
382 | return 0; |
383 | } |
384 | |
385 | if (!(val & BMSR_LSTATUS)) |
386 | return 0; |
387 | |
388 | link = 1; |
389 | |
390 | val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_PHY_STAT); |
391 | if (val < 0) |
392 | return val; |
393 | |
394 | if (val & MV_1GBX_PHY_STAT_AN_RESOLVED) { |
395 | if (val & MV_1GBX_PHY_STAT_DUPLEX) |
396 | phydev->duplex = DUPLEX_FULL; |
397 | else |
398 | phydev->duplex = DUPLEX_HALF; |
399 | |
400 | if (val & MV_1GBX_PHY_STAT_SPEED1000) |
401 | phydev->speed = SPEED_1000; |
402 | else if (val & MV_1GBX_PHY_STAT_SPEED100) |
403 | phydev->speed = SPEED_100; |
404 | else |
405 | phydev->speed = SPEED_10; |
406 | } |
407 | |
408 | return link; |
409 | } |
410 | |
411 | static bool mv2222_link_is_operational(struct phy_device *phydev) |
412 | { |
413 | struct mv2222_data *priv = phydev->priv; |
414 | int val; |
415 | |
416 | val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_RX_SIGNAL_DETECT); |
417 | if (val < 0 || !(val & MV_RX_SIGNAL_DETECT_GLOBAL)) |
418 | return false; |
419 | |
420 | if (phydev->sfp_bus && !priv->sfp_link) |
421 | return false; |
422 | |
423 | return true; |
424 | } |
425 | |
426 | static int mv2222_read_status(struct phy_device *phydev) |
427 | { |
428 | struct mv2222_data *priv = phydev->priv; |
429 | int link; |
430 | |
431 | phydev->link = 0; |
432 | phydev->speed = SPEED_UNKNOWN; |
433 | phydev->duplex = DUPLEX_UNKNOWN; |
434 | |
435 | if (!mv2222_link_is_operational(phydev)) |
436 | return 0; |
437 | |
438 | if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER) |
439 | link = mv2222_read_status_10g(phydev); |
440 | else |
441 | link = mv2222_read_status_1g(phydev); |
442 | |
443 | if (link < 0) |
444 | return link; |
445 | |
446 | phydev->link = link; |
447 | |
448 | return 0; |
449 | } |
450 | |
451 | static int mv2222_resume(struct phy_device *phydev) |
452 | { |
453 | return mv2222_tx_enable(phydev); |
454 | } |
455 | |
456 | static int mv2222_suspend(struct phy_device *phydev) |
457 | { |
458 | return mv2222_tx_disable(phydev); |
459 | } |
460 | |
461 | static int mv2222_get_features(struct phy_device *phydev) |
462 | { |
463 | /* All supported linkmodes are set at probe */ |
464 | |
465 | return 0; |
466 | } |
467 | |
468 | static int mv2222_config_init(struct phy_device *phydev) |
469 | { |
470 | if (phydev->interface != PHY_INTERFACE_MODE_XAUI) |
471 | return -EINVAL; |
472 | |
473 | return 0; |
474 | } |
475 | |
476 | static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) |
477 | { |
478 | DECLARE_PHY_INTERFACE_MASK(interfaces); |
479 | struct phy_device *phydev = upstream; |
480 | phy_interface_t sfp_interface; |
481 | struct mv2222_data *priv; |
482 | struct device *dev; |
483 | int ret; |
484 | |
485 | __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_supported) = { 0, }; |
486 | |
487 | priv = phydev->priv; |
488 | dev = &phydev->mdio.dev; |
489 | |
490 | sfp_parse_support(bus: phydev->sfp_bus, id, support: sfp_supported, interfaces); |
491 | phydev->port = sfp_parse_port(bus: phydev->sfp_bus, id, support: sfp_supported); |
492 | sfp_interface = sfp_select_interface(bus: phydev->sfp_bus, link_modes: sfp_supported); |
493 | |
494 | dev_info(dev, "%s SFP module inserted\n" , phy_modes(sfp_interface)); |
495 | |
496 | if (sfp_interface != PHY_INTERFACE_MODE_10GBASER && |
497 | sfp_interface != PHY_INTERFACE_MODE_1000BASEX && |
498 | sfp_interface != PHY_INTERFACE_MODE_SGMII) { |
499 | dev_err(dev, "Incompatible SFP module inserted\n" ); |
500 | |
501 | return -EINVAL; |
502 | } |
503 | |
504 | priv->line_interface = sfp_interface; |
505 | linkmode_and(dst: priv->supported, a: phydev->supported, b: sfp_supported); |
506 | |
507 | ret = mv2222_config_line(phydev); |
508 | if (ret < 0) |
509 | return ret; |
510 | |
511 | if (mutex_trylock(lock: &phydev->lock)) { |
512 | ret = mv2222_config_aneg(phydev); |
513 | mutex_unlock(lock: &phydev->lock); |
514 | } |
515 | |
516 | return ret; |
517 | } |
518 | |
519 | static void mv2222_sfp_remove(void *upstream) |
520 | { |
521 | struct phy_device *phydev = upstream; |
522 | struct mv2222_data *priv; |
523 | |
524 | priv = phydev->priv; |
525 | |
526 | priv->line_interface = PHY_INTERFACE_MODE_NA; |
527 | linkmode_zero(dst: priv->supported); |
528 | phydev->port = PORT_NONE; |
529 | } |
530 | |
531 | static void mv2222_sfp_link_up(void *upstream) |
532 | { |
533 | struct phy_device *phydev = upstream; |
534 | struct mv2222_data *priv; |
535 | |
536 | priv = phydev->priv; |
537 | priv->sfp_link = true; |
538 | } |
539 | |
540 | static void mv2222_sfp_link_down(void *upstream) |
541 | { |
542 | struct phy_device *phydev = upstream; |
543 | struct mv2222_data *priv; |
544 | |
545 | priv = phydev->priv; |
546 | priv->sfp_link = false; |
547 | } |
548 | |
549 | static const struct sfp_upstream_ops sfp_phy_ops = { |
550 | .module_insert = mv2222_sfp_insert, |
551 | .module_remove = mv2222_sfp_remove, |
552 | .link_up = mv2222_sfp_link_up, |
553 | .link_down = mv2222_sfp_link_down, |
554 | .attach = phy_sfp_attach, |
555 | .detach = phy_sfp_detach, |
556 | }; |
557 | |
558 | static int mv2222_probe(struct phy_device *phydev) |
559 | { |
560 | struct device *dev = &phydev->mdio.dev; |
561 | struct mv2222_data *priv = NULL; |
562 | |
563 | __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; |
564 | |
565 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Autoneg_BIT, addr: supported); |
566 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Pause_BIT, addr: supported); |
567 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_Asym_Pause_BIT, addr: supported); |
568 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_FIBRE_BIT, addr: supported); |
569 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_TP_BIT, addr: supported); |
570 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10baseT_Half_BIT, addr: supported); |
571 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10baseT_Full_BIT, addr: supported); |
572 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_100baseT_Half_BIT, addr: supported); |
573 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_100baseT_Full_BIT, addr: supported); |
574 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Half_BIT, addr: supported); |
575 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_1000baseT_Full_BIT, addr: supported); |
576 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_1000baseX_Full_BIT, addr: supported); |
577 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10000baseT_Full_BIT, addr: supported); |
578 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, addr: supported); |
579 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, addr: supported); |
580 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, addr: supported); |
581 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, addr: supported); |
582 | linkmode_set_bit(nr: ETHTOOL_LINK_MODE_10000baseER_Full_BIT, addr: supported); |
583 | |
584 | linkmode_copy(dst: phydev->supported, src: supported); |
585 | |
586 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
587 | if (!priv) |
588 | return -ENOMEM; |
589 | |
590 | priv->line_interface = PHY_INTERFACE_MODE_NA; |
591 | phydev->priv = priv; |
592 | |
593 | return phy_sfp_probe(phydev, ops: &sfp_phy_ops); |
594 | } |
595 | |
596 | static struct phy_driver mv2222_drivers[] = { |
597 | { |
598 | .phy_id = MARVELL_PHY_ID_88X2222, |
599 | .phy_id_mask = MARVELL_PHY_ID_MASK, |
600 | .name = "Marvell 88X2222" , |
601 | .get_features = mv2222_get_features, |
602 | .soft_reset = mv2222_soft_reset, |
603 | .config_init = mv2222_config_init, |
604 | .config_aneg = mv2222_config_aneg, |
605 | .aneg_done = mv2222_aneg_done, |
606 | .probe = mv2222_probe, |
607 | .suspend = mv2222_suspend, |
608 | .resume = mv2222_resume, |
609 | .read_status = mv2222_read_status, |
610 | }, |
611 | }; |
612 | module_phy_driver(mv2222_drivers); |
613 | |
614 | static struct mdio_device_id __maybe_unused mv2222_tbl[] = { |
615 | { MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK }, |
616 | { } |
617 | }; |
618 | MODULE_DEVICE_TABLE(mdio, mv2222_tbl); |
619 | |
620 | MODULE_DESCRIPTION("Marvell 88x2222 ethernet transceiver driver" ); |
621 | MODULE_LICENSE("GPL" ); |
622 | |