1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Marvell 88E6xxx SERDES manipulation, via SMI bus
5 * Copyright (c) 2008 Marvell Semiconductor
7 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
10 #include <linux/interrupt.h>
11 #include <linux/irqdomain.h>
12 #include <linux/mii.h>
20 static int mv88e6352_serdes_read(struct mv88e6xxx_chip
*chip
, int reg
,
23 return mv88e6xxx_phy_page_read(chip
, MV88E6352_ADDR_SERDES
,
24 MV88E6352_SERDES_PAGE_FIBER
,
28 static int mv88e6352_serdes_write(struct mv88e6xxx_chip
*chip
, int reg
,
31 return mv88e6xxx_phy_page_write(chip
, MV88E6352_ADDR_SERDES
,
32 MV88E6352_SERDES_PAGE_FIBER
,
36 static int mv88e6390_serdes_read(struct mv88e6xxx_chip
*chip
,
37 int lane
, int device
, int reg
, u16
*val
)
39 int reg_c45
= MII_ADDR_C45
| device
<< 16 | reg
;
41 return mv88e6xxx_phy_read(chip
, lane
, reg_c45
, val
);
44 static int mv88e6390_serdes_write(struct mv88e6xxx_chip
*chip
,
45 int lane
, int device
, int reg
, u16 val
)
47 int reg_c45
= MII_ADDR_C45
| device
<< 16 | reg
;
49 return mv88e6xxx_phy_write(chip
, lane
, reg_c45
, val
);
52 int mv88e6352_serdes_power(struct mv88e6xxx_chip
*chip
, int port
, u8 lane
,
58 err
= mv88e6352_serdes_read(chip
, MII_BMCR
, &val
);
63 new_val
= val
& ~BMCR_PDOWN
;
65 new_val
= val
| BMCR_PDOWN
;
68 err
= mv88e6352_serdes_write(chip
, MII_BMCR
, new_val
);
73 u8
mv88e6352_serdes_get_lane(struct mv88e6xxx_chip
*chip
, int port
)
75 u8 cmode
= chip
->ports
[port
].cmode
;
78 if ((cmode
== MV88E6XXX_PORT_STS_CMODE_100BASEX
) ||
79 (cmode
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
) ||
80 (cmode
== MV88E6XXX_PORT_STS_CMODE_SGMII
))
81 lane
= 0xff; /* Unused */
86 static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip
*chip
, int port
)
88 if (mv88e6xxx_serdes_get_lane(chip
, port
))
94 struct mv88e6352_serdes_hw_stat
{
95 char string
[ETH_GSTRING_LEN
];
100 static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats
[] = {
101 { "serdes_fibre_rx_error", 16, 21 },
102 { "serdes_PRBS_error", 32, 24 },
105 int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip
*chip
, int port
)
107 if (mv88e6352_port_has_serdes(chip
, port
))
108 return ARRAY_SIZE(mv88e6352_serdes_hw_stats
);
113 int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip
*chip
,
114 int port
, uint8_t *data
)
116 struct mv88e6352_serdes_hw_stat
*stat
;
119 if (!mv88e6352_port_has_serdes(chip
, port
))
122 for (i
= 0; i
< ARRAY_SIZE(mv88e6352_serdes_hw_stats
); i
++) {
123 stat
= &mv88e6352_serdes_hw_stats
[i
];
124 memcpy(data
+ i
* ETH_GSTRING_LEN
, stat
->string
,
127 return ARRAY_SIZE(mv88e6352_serdes_hw_stats
);
130 static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip
*chip
,
131 struct mv88e6352_serdes_hw_stat
*stat
)
137 err
= mv88e6352_serdes_read(chip
, stat
->reg
, ®
);
139 dev_err(chip
->dev
, "failed to read statistic\n");
145 if (stat
->sizeof_stat
== 32) {
146 err
= mv88e6352_serdes_read(chip
, stat
->reg
+ 1, ®
);
148 dev_err(chip
->dev
, "failed to read statistic\n");
151 val
= val
<< 16 | reg
;
157 int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip
*chip
, int port
,
160 struct mv88e6xxx_port
*mv88e6xxx_port
= &chip
->ports
[port
];
161 struct mv88e6352_serdes_hw_stat
*stat
;
165 if (!mv88e6352_port_has_serdes(chip
, port
))
168 BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats
) >
169 ARRAY_SIZE(mv88e6xxx_port
->serdes_stats
));
171 for (i
= 0; i
< ARRAY_SIZE(mv88e6352_serdes_hw_stats
); i
++) {
172 stat
= &mv88e6352_serdes_hw_stats
[i
];
173 value
= mv88e6352_serdes_get_stat(chip
, stat
);
174 mv88e6xxx_port
->serdes_stats
[i
] += value
;
175 data
[i
] = mv88e6xxx_port
->serdes_stats
[i
];
178 return ARRAY_SIZE(mv88e6352_serdes_hw_stats
);
181 static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip
*chip
, int port
)
183 struct dsa_switch
*ds
= chip
->ds
;
188 err
= mv88e6352_serdes_read(chip
, MII_BMSR
, &status
);
192 /* Status must be read twice in order to give the current link
193 * status. Otherwise the change in link status since the last
194 * read of the register is returned.
196 err
= mv88e6352_serdes_read(chip
, MII_BMSR
, &status
);
200 up
= status
& BMSR_LSTATUS
;
202 dsa_port_phylink_mac_change(ds
, port
, up
);
205 irqreturn_t
mv88e6352_serdes_irq_status(struct mv88e6xxx_chip
*chip
, int port
,
208 irqreturn_t ret
= IRQ_NONE
;
212 err
= mv88e6352_serdes_read(chip
, MV88E6352_SERDES_INT_STATUS
, &status
);
216 if (status
& MV88E6352_SERDES_INT_LINK_CHANGE
) {
218 mv88e6352_serdes_irq_link(chip
, port
);
224 int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip
*chip
, int port
, u8 lane
,
230 val
|= MV88E6352_SERDES_INT_LINK_CHANGE
;
232 return mv88e6352_serdes_write(chip
, MV88E6352_SERDES_INT_ENABLE
, val
);
235 unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip
*chip
, int port
)
237 return irq_find_mapping(chip
->g2_irq
.domain
, MV88E6352_SERDES_IRQ
);
240 u8
mv88e6341_serdes_get_lane(struct mv88e6xxx_chip
*chip
, int port
)
242 u8 cmode
= chip
->ports
[port
].cmode
;
247 if (cmode
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
248 cmode
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
249 cmode
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
)
250 lane
= MV88E6341_PORT5_LANE
;
257 u8
mv88e6390_serdes_get_lane(struct mv88e6xxx_chip
*chip
, int port
)
259 u8 cmode
= chip
->ports
[port
].cmode
;
264 if (cmode
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
265 cmode
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
266 cmode
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
)
267 lane
= MV88E6390_PORT9_LANE0
;
270 if (cmode
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
271 cmode
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
272 cmode
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
)
273 lane
= MV88E6390_PORT10_LANE0
;
280 u8
mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip
*chip
, int port
)
282 u8 cmode_port
= chip
->ports
[port
].cmode
;
283 u8 cmode_port10
= chip
->ports
[10].cmode
;
284 u8 cmode_port9
= chip
->ports
[9].cmode
;
289 if (cmode_port9
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
290 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
291 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
)
292 if (cmode_port
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
)
293 lane
= MV88E6390_PORT9_LANE1
;
296 if (cmode_port9
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
297 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
298 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
||
299 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_RXAUI
)
300 if (cmode_port
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
)
301 lane
= MV88E6390_PORT9_LANE2
;
304 if (cmode_port9
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
305 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
306 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
||
307 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_RXAUI
)
308 if (cmode_port
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
)
309 lane
= MV88E6390_PORT9_LANE3
;
312 if (cmode_port10
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
313 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
314 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
)
315 if (cmode_port
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
)
316 lane
= MV88E6390_PORT10_LANE1
;
319 if (cmode_port10
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
320 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
321 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
||
322 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_RXAUI
)
323 if (cmode_port
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
)
324 lane
= MV88E6390_PORT10_LANE2
;
327 if (cmode_port10
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
328 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
329 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
||
330 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_RXAUI
)
331 if (cmode_port
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
)
332 lane
= MV88E6390_PORT10_LANE3
;
335 if (cmode_port9
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
336 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
337 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
||
338 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_XAUI
||
339 cmode_port9
== MV88E6XXX_PORT_STS_CMODE_RXAUI
)
340 lane
= MV88E6390_PORT9_LANE0
;
343 if (cmode_port10
== MV88E6XXX_PORT_STS_CMODE_1000BASEX
||
344 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_SGMII
||
345 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
||
346 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_XAUI
||
347 cmode_port10
== MV88E6XXX_PORT_STS_CMODE_RXAUI
)
348 lane
= MV88E6390_PORT10_LANE0
;
355 /* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
356 static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip
*chip
, u8 lane
,
362 err
= mv88e6390_serdes_read(chip
, lane
, MDIO_MMD_PHYXS
,
363 MV88E6390_PCS_CONTROL_1
, &val
);
369 new_val
= val
& ~(MV88E6390_PCS_CONTROL_1_RESET
|
370 MV88E6390_PCS_CONTROL_1_LOOPBACK
|
371 MV88E6390_PCS_CONTROL_1_PDOWN
);
373 new_val
= val
| MV88E6390_PCS_CONTROL_1_PDOWN
;
376 err
= mv88e6390_serdes_write(chip
, lane
, MDIO_MMD_PHYXS
,
377 MV88E6390_PCS_CONTROL_1
, new_val
);
382 /* Set power up/down for SGMII and 1000Base-X */
383 static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip
*chip
, u8 lane
,
389 err
= mv88e6390_serdes_read(chip
, lane
, MDIO_MMD_PHYXS
,
390 MV88E6390_SGMII_CONTROL
, &val
);
395 new_val
= val
& ~(MV88E6390_SGMII_CONTROL_RESET
|
396 MV88E6390_SGMII_CONTROL_LOOPBACK
|
397 MV88E6390_SGMII_CONTROL_PDOWN
);
399 new_val
= val
| MV88E6390_SGMII_CONTROL_PDOWN
;
402 err
= mv88e6390_serdes_write(chip
, lane
, MDIO_MMD_PHYXS
,
403 MV88E6390_SGMII_CONTROL
, new_val
);
408 struct mv88e6390_serdes_hw_stat
{
409 char string
[ETH_GSTRING_LEN
];
413 static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats
[] = {
414 { "serdes_rx_pkts", 0xf021 },
415 { "serdes_rx_bytes", 0xf024 },
416 { "serdes_rx_pkts_error", 0xf027 },
419 int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip
*chip
, int port
)
421 if (mv88e6390_serdes_get_lane(chip
, port
) == 0)
424 return ARRAY_SIZE(mv88e6390_serdes_hw_stats
);
427 int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip
*chip
,
428 int port
, uint8_t *data
)
430 struct mv88e6390_serdes_hw_stat
*stat
;
433 if (mv88e6390_serdes_get_lane(chip
, port
) == 0)
436 for (i
= 0; i
< ARRAY_SIZE(mv88e6390_serdes_hw_stats
); i
++) {
437 stat
= &mv88e6390_serdes_hw_stats
[i
];
438 memcpy(data
+ i
* ETH_GSTRING_LEN
, stat
->string
,
441 return ARRAY_SIZE(mv88e6390_serdes_hw_stats
);
444 static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip
*chip
, int lane
,
445 struct mv88e6390_serdes_hw_stat
*stat
)
450 for (i
= 0; i
< 3; i
++) {
451 err
= mv88e6390_serdes_read(chip
, lane
, MDIO_MMD_PHYXS
,
452 stat
->reg
+ i
, ®
[i
]);
454 dev_err(chip
->dev
, "failed to read statistic\n");
459 return reg
[0] | ((u64
)reg
[1] << 16) | ((u64
)reg
[2] << 32);
462 int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip
*chip
, int port
,
465 struct mv88e6390_serdes_hw_stat
*stat
;
469 lane
= mv88e6390_serdes_get_lane(chip
, port
);
473 for (i
= 0; i
< ARRAY_SIZE(mv88e6390_serdes_hw_stats
); i
++) {
474 stat
= &mv88e6390_serdes_hw_stats
[i
];
475 data
[i
] = mv88e6390_serdes_get_stat(chip
, lane
, stat
);
478 return ARRAY_SIZE(mv88e6390_serdes_hw_stats
);
481 static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip
*chip
, u8 lane
)
486 err
= mv88e6390_serdes_read(chip
, lane
, MDIO_MMD_PHYXS
,
487 MV88E6390_PG_CONTROL
, ®
);
491 reg
|= MV88E6390_PG_CONTROL_ENABLE_PC
;
492 return mv88e6390_serdes_write(chip
, lane
, MDIO_MMD_PHYXS
,
493 MV88E6390_PG_CONTROL
, reg
);
496 int mv88e6390_serdes_power(struct mv88e6xxx_chip
*chip
, int port
, u8 lane
,
499 u8 cmode
= chip
->ports
[port
].cmode
;
503 case MV88E6XXX_PORT_STS_CMODE_SGMII
:
504 case MV88E6XXX_PORT_STS_CMODE_1000BASEX
:
505 case MV88E6XXX_PORT_STS_CMODE_2500BASEX
:
506 err
= mv88e6390_serdes_power_sgmii(chip
, lane
, up
);
508 case MV88E6XXX_PORT_STS_CMODE_XAUI
:
509 case MV88E6XXX_PORT_STS_CMODE_RXAUI
:
510 err
= mv88e6390_serdes_power_10g(chip
, lane
, up
);
515 err
= mv88e6390_serdes_enable_checker(chip
, lane
);
520 static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip
*chip
,
523 u8 cmode
= chip
->ports
[port
].cmode
;
524 struct dsa_switch
*ds
= chip
->ds
;
525 int duplex
= DUPLEX_UNKNOWN
;
526 int speed
= SPEED_UNKNOWN
;
527 phy_interface_t mode
;
531 err
= mv88e6390_serdes_read(chip
, lane
, MDIO_MMD_PHYXS
,
532 MV88E6390_SGMII_PHY_STATUS
, &status
);
534 dev_err(chip
->dev
, "can't read SGMII PHY status: %d\n", err
);
538 link
= status
& MV88E6390_SGMII_PHY_STATUS_LINK
?
539 LINK_FORCED_UP
: LINK_FORCED_DOWN
;
541 if (status
& MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID
) {
542 duplex
= status
& MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL
?
543 DUPLEX_FULL
: DUPLEX_HALF
;
545 switch (status
& MV88E6390_SGMII_PHY_STATUS_SPEED_MASK
) {
546 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000
:
547 if (cmode
== MV88E6XXX_PORT_STS_CMODE_2500BASEX
)
552 case MV88E6390_SGMII_PHY_STATUS_SPEED_100
:
555 case MV88E6390_SGMII_PHY_STATUS_SPEED_10
:
559 dev_err(chip
->dev
, "invalid PHY speed\n");
565 case MV88E6XXX_PORT_STS_CMODE_SGMII
:
566 mode
= PHY_INTERFACE_MODE_SGMII
;
568 case MV88E6XXX_PORT_STS_CMODE_1000BASEX
:
569 mode
= PHY_INTERFACE_MODE_1000BASEX
;
571 case MV88E6XXX_PORT_STS_CMODE_2500BASEX
:
572 mode
= PHY_INTERFACE_MODE_2500BASEX
;
575 mode
= PHY_INTERFACE_MODE_NA
;
578 err
= mv88e6xxx_port_setup_mac(chip
, port
, link
, speed
, duplex
,
581 dev_err(chip
->dev
, "can't propagate PHY settings to MAC: %d\n",
584 dsa_port_phylink_mac_change(ds
, port
, link
== LINK_FORCED_UP
);
587 static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip
*chip
,
588 u8 lane
, bool enable
)
593 val
|= MV88E6390_SGMII_INT_LINK_DOWN
|
594 MV88E6390_SGMII_INT_LINK_UP
;
596 return mv88e6390_serdes_write(chip
, lane
, MDIO_MMD_PHYXS
,
597 MV88E6390_SGMII_INT_ENABLE
, val
);
600 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip
*chip
, int port
, u8 lane
,
603 u8 cmode
= chip
->ports
[port
].cmode
;
606 case MV88E6XXX_PORT_STS_CMODE_SGMII
:
607 case MV88E6XXX_PORT_STS_CMODE_1000BASEX
:
608 case MV88E6XXX_PORT_STS_CMODE_2500BASEX
:
609 return mv88e6390_serdes_irq_enable_sgmii(chip
, lane
, enable
);
615 static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip
*chip
,
616 u8 lane
, u16
*status
)
620 err
= mv88e6390_serdes_read(chip
, lane
, MDIO_MMD_PHYXS
,
621 MV88E6390_SGMII_INT_STATUS
, status
);
626 irqreturn_t
mv88e6390_serdes_irq_status(struct mv88e6xxx_chip
*chip
, int port
,
629 u8 cmode
= chip
->ports
[port
].cmode
;
630 irqreturn_t ret
= IRQ_NONE
;
635 case MV88E6XXX_PORT_STS_CMODE_SGMII
:
636 case MV88E6XXX_PORT_STS_CMODE_1000BASEX
:
637 case MV88E6XXX_PORT_STS_CMODE_2500BASEX
:
638 err
= mv88e6390_serdes_irq_status_sgmii(chip
, lane
, &status
);
641 if (status
& (MV88E6390_SGMII_INT_LINK_DOWN
|
642 MV88E6390_SGMII_INT_LINK_UP
)) {
644 mv88e6390_serdes_irq_link_sgmii(chip
, port
, lane
);
651 unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip
*chip
, int port
)
653 return irq_find_mapping(chip
->g2_irq
.domain
, port
);