blob: b2043f563dfbb728eb86494a3121ce2dd42369e3 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001/*
2 * Marvell 10G 88x3310 PHY driver
3 *
4 * Based upon the ID registers, this PHY appears to be a mixture of IPs
5 * from two different companies.
6 *
7 * There appears to be several different data paths through the PHY which
8 * are automatically managed by the PHY. The following has been determined
9 * via observation and experimentation for a setup using single-lane Serdes:
10 *
11 * SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G)
12 * 10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G)
13 * 10GBASE-KR PHYXS -- BASE-R PCS -- Fiber
14 *
15 * With XAUI, observation shows:
16 *
17 * XAUI PHYXS -- <appropriate PCS as above>
18 *
19 * and no switching of the host interface mode occurs.
20 *
21 * If both the fiber and copper ports are connected, the first to gain
22 * link takes priority and the other port is completely locked out.
23 */
24#include <linux/ctype.h>
25#include <linux/hwmon.h>
26#include <linux/marvell_phy.h>
27#include <linux/phy.h>
28#include <linux/sfp.h>
29
30enum {
31 MV_PMA_BOOT = 0xc050,
32 MV_PMA_BOOT_FATAL = BIT(0),
33
34 MV_PCS_BASE_T = 0x0000,
35 MV_PCS_BASE_R = 0x1000,
36 MV_PCS_1000BASEX = 0x2000,
37
38 MV_PCS_PAIRSWAP = 0x8182,
39 MV_PCS_PAIRSWAP_MASK = 0x0003,
40 MV_PCS_PAIRSWAP_AB = 0x0002,
41 MV_PCS_PAIRSWAP_NONE = 0x0003,
42
43 /* These registers appear at 0x800X and 0xa00X - the 0xa00X control
44 * registers appear to set themselves to the 0x800X when AN is
45 * restarted, but status registers appear readable from either.
46 */
47 MV_AN_CTRL1000 = 0x8000, /* 1000base-T control register */
48 MV_AN_STAT1000 = 0x8001, /* 1000base-T status register */
49
50 /* Vendor2 MMD registers */
51 MV_V2_TEMP_CTRL = 0xf08a,
52 MV_V2_TEMP_CTRL_MASK = 0xc000,
53 MV_V2_TEMP_CTRL_SAMPLE = 0x0000,
54 MV_V2_TEMP_CTRL_DISABLE = 0xc000,
55 MV_V2_TEMP = 0xf08c,
56 MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */
57};
58
59struct mv3310_priv {
60 struct device *hwmon_dev;
61 char *hwmon_name;
62};
63
64static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
65 u16 mask, u16 bits)
66{
67 int old, val, ret;
68
69 old = phy_read_mmd(phydev, devad, reg);
70 if (old < 0)
71 return old;
72
73 val = (old & ~mask) | (bits & mask);
74 if (val == old)
75 return 0;
76
77 ret = phy_write_mmd(phydev, devad, reg, val);
78
79 return ret < 0 ? ret : 1;
80}
81
82#ifdef CONFIG_HWMON
83static umode_t mv3310_hwmon_is_visible(const void *data,
84 enum hwmon_sensor_types type,
85 u32 attr, int channel)
86{
87 if (type == hwmon_chip && attr == hwmon_chip_update_interval)
88 return 0444;
89 if (type == hwmon_temp && attr == hwmon_temp_input)
90 return 0444;
91 return 0;
92}
93
94static int mv3310_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
95 u32 attr, int channel, long *value)
96{
97 struct phy_device *phydev = dev_get_drvdata(dev);
98 int temp;
99
100 if (type == hwmon_chip && attr == hwmon_chip_update_interval) {
101 *value = MSEC_PER_SEC;
102 return 0;
103 }
104
105 if (type == hwmon_temp && attr == hwmon_temp_input) {
106 temp = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP);
107 if (temp < 0)
108 return temp;
109
110 *value = ((temp & 0xff) - 75) * 1000;
111
112 return 0;
113 }
114
115 return -EOPNOTSUPP;
116}
117
118static const struct hwmon_ops mv3310_hwmon_ops = {
119 .is_visible = mv3310_hwmon_is_visible,
120 .read = mv3310_hwmon_read,
121};
122
123static u32 mv3310_hwmon_chip_config[] = {
124 HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
125 0,
126};
127
128static const struct hwmon_channel_info mv3310_hwmon_chip = {
129 .type = hwmon_chip,
130 .config = mv3310_hwmon_chip_config,
131};
132
133static u32 mv3310_hwmon_temp_config[] = {
134 HWMON_T_INPUT,
135 0,
136};
137
138static const struct hwmon_channel_info mv3310_hwmon_temp = {
139 .type = hwmon_temp,
140 .config = mv3310_hwmon_temp_config,
141};
142
143static const struct hwmon_channel_info *mv3310_hwmon_info[] = {
144 &mv3310_hwmon_chip,
145 &mv3310_hwmon_temp,
146 NULL,
147};
148
149static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
150 .ops = &mv3310_hwmon_ops,
151 .info = mv3310_hwmon_info,
152};
153
154static int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
155{
156 u16 val;
157 int ret;
158
159 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP,
160 MV_V2_TEMP_UNKNOWN);
161 if (ret < 0)
162 return ret;
163
164 val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE;
165 ret = mv3310_modify(phydev, MDIO_MMD_VEND2, MV_V2_TEMP_CTRL,
166 MV_V2_TEMP_CTRL_MASK, val);
167
168 return ret < 0 ? ret : 0;
169}
170
171static void mv3310_hwmon_disable(void *data)
172{
173 struct phy_device *phydev = data;
174
175 mv3310_hwmon_config(phydev, false);
176}
177
178static int mv3310_hwmon_probe(struct phy_device *phydev)
179{
180 struct device *dev = &phydev->mdio.dev;
181 struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
182 int i, j, ret;
183
184 priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
185 if (!priv->hwmon_name)
186 return -ENODEV;
187
188 for (i = j = 0; priv->hwmon_name[i]; i++) {
189 if (isalnum(priv->hwmon_name[i])) {
190 if (i != j)
191 priv->hwmon_name[j] = priv->hwmon_name[i];
192 j++;
193 }
194 }
195 priv->hwmon_name[j] = '\0';
196
197 ret = mv3310_hwmon_config(phydev, true);
198 if (ret)
199 return ret;
200
201 ret = devm_add_action_or_reset(dev, mv3310_hwmon_disable, phydev);
202 if (ret)
203 return ret;
204
205 priv->hwmon_dev = devm_hwmon_device_register_with_info(dev,
206 priv->hwmon_name, phydev,
207 &mv3310_hwmon_chip_info, NULL);
208
209 return PTR_ERR_OR_ZERO(priv->hwmon_dev);
210}
211#else
212static inline int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
213{
214 return 0;
215}
216
217static int mv3310_hwmon_probe(struct phy_device *phydev)
218{
219 return 0;
220}
221#endif
222
223static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
224{
225 struct phy_device *phydev = upstream;
226 __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
227 phy_interface_t iface;
228
229 sfp_parse_support(phydev->sfp_bus, id, support);
230 iface = sfp_select_interface(phydev->sfp_bus, support);
231
232 if (iface != PHY_INTERFACE_MODE_10GKR) {
233 dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
234 return -EINVAL;
235 }
236 return 0;
237}
238
239static const struct sfp_upstream_ops mv3310_sfp_ops = {
240 .attach = phy_sfp_attach,
241 .detach = phy_sfp_detach,
242 .module_insert = mv3310_sfp_insert,
243};
244
245static int mv3310_probe(struct phy_device *phydev)
246{
247 struct mv3310_priv *priv;
248 u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
249 int ret;
250
251 if (!phydev->is_c45 ||
252 (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
253 return -ENODEV;
254
255 ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT);
256 if (ret < 0)
257 return ret;
258
259 if (ret & MV_PMA_BOOT_FATAL) {
260 dev_warn(&phydev->mdio.dev,
261 "PHY failed to boot firmware, status=%04x\n", ret);
262 return -ENODEV;
263 }
264
265 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
266 if (!priv)
267 return -ENOMEM;
268
269 dev_set_drvdata(&phydev->mdio.dev, priv);
270
271 ret = mv3310_hwmon_probe(phydev);
272 if (ret)
273 return ret;
274
275 return phy_sfp_probe(phydev, &mv3310_sfp_ops);
276}
277
278static int mv3310_suspend(struct phy_device *phydev)
279{
280 return 0;
281}
282
283static int mv3310_resume(struct phy_device *phydev)
284{
285 return mv3310_hwmon_config(phydev, true);
286}
287
288static int mv3310_config_init(struct phy_device *phydev)
289{
290 __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
291 u32 mask;
292 int val;
293
294 /* Check that the PHY interface type is compatible */
295 if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
296 phydev->interface != PHY_INTERFACE_MODE_XAUI &&
297 phydev->interface != PHY_INTERFACE_MODE_RXAUI &&
298 phydev->interface != PHY_INTERFACE_MODE_10GKR)
299 return -ENODEV;
300
301 __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
302 __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
303
304 if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
305 val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
306 if (val < 0)
307 return val;
308
309 if (val & MDIO_AN_STAT1_ABLE)
310 __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
311 }
312
313 val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2);
314 if (val < 0)
315 return val;
316
317 /* Ethtool does not support the WAN mode bits */
318 if (val & (MDIO_PMA_STAT2_10GBSR | MDIO_PMA_STAT2_10GBLR |
319 MDIO_PMA_STAT2_10GBER | MDIO_PMA_STAT2_10GBLX4 |
320 MDIO_PMA_STAT2_10GBSW | MDIO_PMA_STAT2_10GBLW |
321 MDIO_PMA_STAT2_10GBEW))
322 __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
323 if (val & MDIO_PMA_STAT2_10GBSR)
324 __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported);
325 if (val & MDIO_PMA_STAT2_10GBLR)
326 __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported);
327 if (val & MDIO_PMA_STAT2_10GBER)
328 __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported);
329
330 if (val & MDIO_PMA_STAT2_EXTABLE) {
331 val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
332 if (val < 0)
333 return val;
334
335 if (val & (MDIO_PMA_EXTABLE_10GBT | MDIO_PMA_EXTABLE_1000BT |
336 MDIO_PMA_EXTABLE_100BTX | MDIO_PMA_EXTABLE_10BT))
337 __set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
338 if (val & MDIO_PMA_EXTABLE_10GBLRM)
339 __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
340 if (val & (MDIO_PMA_EXTABLE_10GBKX4 | MDIO_PMA_EXTABLE_10GBKR |
341 MDIO_PMA_EXTABLE_1000BKX))
342 __set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, supported);
343 if (val & MDIO_PMA_EXTABLE_10GBLRM)
344 __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
345 supported);
346 if (val & MDIO_PMA_EXTABLE_10GBT)
347 __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
348 supported);
349 if (val & MDIO_PMA_EXTABLE_10GBKX4)
350 __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
351 supported);
352 if (val & MDIO_PMA_EXTABLE_10GBKR)
353 __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
354 supported);
355 if (val & MDIO_PMA_EXTABLE_1000BT)
356 __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
357 supported);
358 if (val & MDIO_PMA_EXTABLE_1000BKX)
359 __set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
360 supported);
361 if (val & MDIO_PMA_EXTABLE_100BTX) {
362 __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
363 supported);
364 __set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
365 supported);
366 }
367 if (val & MDIO_PMA_EXTABLE_10BT) {
368 __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
369 supported);
370 __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
371 supported);
372 }
373 }
374
375 if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported))
376 dev_warn(&phydev->mdio.dev,
377 "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n",
378 __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
379
380 phydev->supported &= mask;
381 phydev->advertising &= phydev->supported;
382
383 return 0;
384}
385
386static int mv3310_config_aneg(struct phy_device *phydev)
387{
388 bool changed = false;
389 u32 advertising;
390 int ret;
391
392 /* We don't support manual MDI control */
393 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
394
395 if (phydev->autoneg == AUTONEG_DISABLE) {
396 ret = genphy_c45_pma_setup_forced(phydev);
397 if (ret < 0)
398 return ret;
399
400 return genphy_c45_an_disable_aneg(phydev);
401 }
402
403 phydev->advertising &= phydev->supported;
404 advertising = phydev->advertising;
405
406 ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
407 ADVERTISE_ALL | ADVERTISE_100BASE4 |
408 ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
409 ethtool_adv_to_mii_adv_t(advertising));
410 if (ret < 0)
411 return ret;
412 if (ret > 0)
413 changed = true;
414
415 ret = mv3310_modify(phydev, MDIO_MMD_AN, MV_AN_CTRL1000,
416 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
417 ethtool_adv_to_mii_ctrl1000_t(advertising));
418 if (ret < 0)
419 return ret;
420 if (ret > 0)
421 changed = true;
422
423 /* 10G control register */
424 ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
425 MDIO_AN_10GBT_CTRL_ADV10G,
426 advertising & ADVERTISED_10000baseT_Full ?
427 MDIO_AN_10GBT_CTRL_ADV10G : 0);
428 if (ret < 0)
429 return ret;
430 if (ret > 0)
431 changed = true;
432
433 if (changed)
434 ret = genphy_c45_restart_aneg(phydev);
435
436 return ret;
437}
438
439static int mv3310_aneg_done(struct phy_device *phydev)
440{
441 int val;
442
443 val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
444 if (val < 0)
445 return val;
446
447 if (val & MDIO_STAT1_LSTATUS)
448 return 1;
449
450 return genphy_c45_aneg_done(phydev);
451}
452
453static void mv3310_update_interface(struct phy_device *phydev)
454{
455 if ((phydev->interface == PHY_INTERFACE_MODE_SGMII ||
456 phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) {
457 /* The PHY automatically switches its serdes interface (and
458 * active PHYXS instance) between Cisco SGMII and 10GBase-KR
459 * modes according to the speed. Florian suggests setting
460 * phydev->interface to communicate this to the MAC. Only do
461 * this if we are already in either SGMII or 10GBase-KR mode.
462 */
463 if (phydev->speed == SPEED_10000)
464 phydev->interface = PHY_INTERFACE_MODE_10GKR;
465 else if (phydev->speed >= SPEED_10 &&
466 phydev->speed < SPEED_10000)
467 phydev->interface = PHY_INTERFACE_MODE_SGMII;
468 }
469}
470
471/* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */
472static int mv3310_read_10gbr_status(struct phy_device *phydev)
473{
474 phydev->link = 1;
475 phydev->speed = SPEED_10000;
476 phydev->duplex = DUPLEX_FULL;
477
478 mv3310_update_interface(phydev);
479
480 return 0;
481}
482
483static int mv3310_read_status(struct phy_device *phydev)
484{
485 u32 mmd_mask = phydev->c45_ids.devices_in_package;
486 int val;
487
488 /* The vendor devads do not report link status. Avoid the PHYXS
489 * instance as there are three, and its status depends on the MAC
490 * being appropriately configured for the negotiated speed.
491 */
492 mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2) |
493 BIT(MDIO_MMD_PHYXS));
494
495 phydev->speed = SPEED_UNKNOWN;
496 phydev->duplex = DUPLEX_UNKNOWN;
497 phydev->lp_advertising = 0;
498 phydev->link = 0;
499 phydev->pause = 0;
500 phydev->asym_pause = 0;
501 phydev->mdix = 0;
502
503 val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
504 if (val < 0)
505 return val;
506
507 if (val & MDIO_STAT1_LSTATUS)
508 return mv3310_read_10gbr_status(phydev);
509
510 val = genphy_c45_read_link(phydev, mmd_mask);
511 if (val < 0)
512 return val;
513
514 phydev->link = val > 0 ? 1 : 0;
515
516 val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
517 if (val < 0)
518 return val;
519
520 if (val & MDIO_AN_STAT1_COMPLETE) {
521 val = genphy_c45_read_lpa(phydev);
522 if (val < 0)
523 return val;
524
525 /* Read the link partner's 1G advertisement */
526 val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_STAT1000);
527 if (val < 0)
528 return val;
529
530 phydev->lp_advertising |= mii_stat1000_to_ethtool_lpa_t(val);
531
532 if (phydev->autoneg == AUTONEG_ENABLE)
533 phy_resolve_aneg_linkmode(phydev);
534 }
535
536 if (phydev->autoneg != AUTONEG_ENABLE) {
537 val = genphy_c45_read_pma(phydev);
538 if (val < 0)
539 return val;
540 }
541
542 if (phydev->speed == SPEED_10000) {
543 val = genphy_c45_read_mdix(phydev);
544 if (val < 0)
545 return val;
546 } else {
547 val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PAIRSWAP);
548 if (val < 0)
549 return val;
550
551 switch (val & MV_PCS_PAIRSWAP_MASK) {
552 case MV_PCS_PAIRSWAP_AB:
553 phydev->mdix = ETH_TP_MDI_X;
554 break;
555 case MV_PCS_PAIRSWAP_NONE:
556 phydev->mdix = ETH_TP_MDI;
557 break;
558 default:
559 phydev->mdix = ETH_TP_MDI_INVALID;
560 break;
561 }
562 }
563
564 mv3310_update_interface(phydev);
565
566 return 0;
567}
568
569static struct phy_driver mv3310_drivers[] = {
570 {
571 .phy_id = 0x002b09aa,
572 .phy_id_mask = MARVELL_PHY_ID_MASK,
573 .name = "mv88x3310",
574 .features = SUPPORTED_10baseT_Full |
575 SUPPORTED_10baseT_Half |
576 SUPPORTED_100baseT_Full |
577 SUPPORTED_100baseT_Half |
578 SUPPORTED_1000baseT_Full |
579 SUPPORTED_Autoneg |
580 SUPPORTED_TP |
581 SUPPORTED_FIBRE |
582 SUPPORTED_10000baseT_Full |
583 SUPPORTED_Backplane,
584 .soft_reset = gen10g_no_soft_reset,
585 .config_init = mv3310_config_init,
586 .probe = mv3310_probe,
587 .suspend = mv3310_suspend,
588 .resume = mv3310_resume,
589 .config_aneg = mv3310_config_aneg,
590 .aneg_done = mv3310_aneg_done,
591 .read_status = mv3310_read_status,
592 },
593};
594
595module_phy_driver(mv3310_drivers);
596
597static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
598 { 0x002b09aa, MARVELL_PHY_ID_MASK },
599 { },
600};
601MODULE_DEVICE_TABLE(mdio, mv3310_tbl);
602MODULE_DESCRIPTION("Marvell Alaska X 10Gigabit Ethernet PHY driver (MV88X3310)");
603MODULE_LICENSE("GPL");