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);