1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Marvell 88E6352 family SERDES PCS support
5 * Copyright (c) 2008 Marvell Semiconductor
7 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
9 #include <linux/interrupt.h>
10 #include <linux/irqdomain.h>
11 #include <linux/mii.h>
19 struct mv88e639x_pcs
{
20 struct mdio_device mdio
;
21 struct phylink_pcs sgmii_pcs
;
22 struct phylink_pcs xg_pcs
;
25 phy_interface_t interface
;
28 irqreturn_t (*handle_irq
)(struct mv88e639x_pcs
*mpcs
);
31 static int mv88e639x_read(struct mv88e639x_pcs
*mpcs
, u16 regnum
, u16
*val
)
35 err
= mdiodev_c45_read(&mpcs
->mdio
, MDIO_MMD_PHYXS
, regnum
);
44 static int mv88e639x_write(struct mv88e639x_pcs
*mpcs
, u16 regnum
, u16 val
)
46 return mdiodev_c45_write(&mpcs
->mdio
, MDIO_MMD_PHYXS
, regnum
, val
);
49 static int mv88e639x_modify(struct mv88e639x_pcs
*mpcs
, u16 regnum
, u16 mask
,
52 return mdiodev_c45_modify(&mpcs
->mdio
, MDIO_MMD_PHYXS
, regnum
, mask
,
56 static int mv88e639x_modify_changed(struct mv88e639x_pcs
*mpcs
, u16 regnum
,
59 return mdiodev_c45_modify_changed(&mpcs
->mdio
, MDIO_MMD_PHYXS
, regnum
,
63 static struct mv88e639x_pcs
*
64 mv88e639x_pcs_alloc(struct device
*dev
, struct mii_bus
*bus
, unsigned int addr
,
67 struct mv88e639x_pcs
*mpcs
;
69 mpcs
= kzalloc(sizeof(*mpcs
), GFP_KERNEL
);
73 mpcs
->mdio
.dev
.parent
= dev
;
75 mpcs
->mdio
.addr
= addr
;
77 snprintf(mpcs
->name
, sizeof(mpcs
->name
),
78 "mv88e6xxx-%s-serdes-%d", dev_name(dev
), port
);
83 static irqreturn_t
mv88e639x_pcs_handle_irq(int irq
, void *dev_id
)
85 struct mv88e639x_pcs
*mpcs
= dev_id
;
86 irqreturn_t (*handler
)(struct mv88e639x_pcs
*);
88 handler
= READ_ONCE(mpcs
->handle_irq
);
95 static int mv88e639x_pcs_setup_irq(struct mv88e639x_pcs
*mpcs
,
96 struct mv88e6xxx_chip
*chip
, int port
)
100 irq
= mv88e6xxx_serdes_irq_mapping(chip
, port
);
102 /* Use polling mode */
103 mpcs
->sgmii_pcs
.poll
= true;
104 mpcs
->xg_pcs
.poll
= true;
110 return request_threaded_irq(irq
, NULL
, mv88e639x_pcs_handle_irq
,
111 IRQF_ONESHOT
, mpcs
->name
, mpcs
);
114 static void mv88e639x_pcs_teardown(struct mv88e6xxx_chip
*chip
, int port
)
116 struct mv88e639x_pcs
*mpcs
= chip
->ports
[port
].pcs_private
;
122 free_irq(mpcs
->irq
, mpcs
);
126 chip
->ports
[port
].pcs_private
= NULL
;
129 static struct mv88e639x_pcs
*sgmii_pcs_to_mv88e639x_pcs(struct phylink_pcs
*pcs
)
131 return container_of(pcs
, struct mv88e639x_pcs
, sgmii_pcs
);
134 static irqreturn_t
mv88e639x_sgmii_handle_irq(struct mv88e639x_pcs
*mpcs
)
139 err
= mv88e639x_read(mpcs
, MV88E6390_SGMII_INT_STATUS
, &int_status
);
143 if (int_status
& (MV88E6390_SGMII_INT_LINK_DOWN
|
144 MV88E6390_SGMII_INT_LINK_UP
)) {
145 phylink_pcs_change(&mpcs
->sgmii_pcs
,
146 int_status
& MV88E6390_SGMII_INT_LINK_UP
);
154 static int mv88e639x_sgmii_pcs_control_irq(struct mv88e639x_pcs
*mpcs
,
160 val
|= MV88E6390_SGMII_INT_LINK_DOWN
|
161 MV88E6390_SGMII_INT_LINK_UP
;
163 return mv88e639x_modify(mpcs
, MV88E6390_SGMII_INT_ENABLE
,
164 MV88E6390_SGMII_INT_LINK_DOWN
|
165 MV88E6390_SGMII_INT_LINK_UP
, val
);
168 static int mv88e639x_sgmii_pcs_control_pwr(struct mv88e639x_pcs
*mpcs
,
174 mask
= BMCR_RESET
| BMCR_LOOPBACK
| BMCR_PDOWN
;
177 mask
= val
= BMCR_PDOWN
;
180 return mv88e639x_modify(mpcs
, MV88E6390_SGMII_BMCR
, mask
, val
);
183 static int mv88e639x_sgmii_pcs_enable(struct phylink_pcs
*pcs
)
185 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
187 /* power enable done in post_config */
188 mpcs
->handle_irq
= mv88e639x_sgmii_handle_irq
;
190 return mv88e639x_sgmii_pcs_control_irq(mpcs
, !!mpcs
->irq
);
193 static void mv88e639x_sgmii_pcs_disable(struct phylink_pcs
*pcs
)
195 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
197 mv88e639x_sgmii_pcs_control_irq(mpcs
, false);
198 mv88e639x_sgmii_pcs_control_pwr(mpcs
, false);
201 static void mv88e639x_sgmii_pcs_pre_config(struct phylink_pcs
*pcs
,
202 phy_interface_t interface
)
204 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
206 mv88e639x_sgmii_pcs_control_pwr(mpcs
, false);
209 static int mv88e6390_erratum_3_14(struct mv88e639x_pcs
*mpcs
)
211 static const int lanes
[] = { MV88E6390_PORT9_LANE0
, MV88E6390_PORT9_LANE1
,
212 MV88E6390_PORT9_LANE2
, MV88E6390_PORT9_LANE3
,
213 MV88E6390_PORT10_LANE0
, MV88E6390_PORT10_LANE1
,
214 MV88E6390_PORT10_LANE2
, MV88E6390_PORT10_LANE3
};
217 /* 88e6190x and 88e6390x errata 3.14:
218 * After chip reset, SERDES reconfiguration or SERDES core
219 * Software Reset, the SERDES lanes may not be properly aligned
220 * resulting in CRC errors
223 for (i
= 0; i
< ARRAY_SIZE(lanes
); i
++) {
224 err
= mdiobus_c45_write(mpcs
->mdio
.bus
, lanes
[i
],
230 err
= mdiobus_c45_write(mpcs
->mdio
.bus
, lanes
[i
],
240 static int mv88e639x_sgmii_pcs_post_config(struct phylink_pcs
*pcs
,
241 phy_interface_t interface
)
243 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
246 mv88e639x_sgmii_pcs_control_pwr(mpcs
, true);
248 if (mpcs
->erratum_3_14
) {
249 err
= mv88e6390_erratum_3_14(mpcs
);
251 dev_err(mpcs
->mdio
.dev
.parent
,
252 "failed to apply erratum 3.14: %pe\n",
259 static void mv88e639x_sgmii_pcs_get_state(struct phylink_pcs
*pcs
,
260 struct phylink_link_state
*state
)
262 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
263 u16 bmsr
, lpa
, status
;
266 err
= mv88e639x_read(mpcs
, MV88E6390_SGMII_BMSR
, &bmsr
);
268 dev_err(mpcs
->mdio
.dev
.parent
,
269 "can't read Serdes PHY %s: %pe\n",
270 "BMSR", ERR_PTR(err
));
275 err
= mv88e639x_read(mpcs
, MV88E6390_SGMII_LPA
, &lpa
);
277 dev_err(mpcs
->mdio
.dev
.parent
,
278 "can't read Serdes PHY %s: %pe\n",
279 "LPA", ERR_PTR(err
));
284 err
= mv88e639x_read(mpcs
, MV88E6390_SGMII_PHY_STATUS
, &status
);
286 dev_err(mpcs
->mdio
.dev
.parent
,
287 "can't read Serdes PHY %s: %pe\n",
288 "status", ERR_PTR(err
));
293 mv88e6xxx_pcs_decode_state(mpcs
->mdio
.dev
.parent
, bmsr
, lpa
, status
,
297 static int mv88e639x_sgmii_pcs_config(struct phylink_pcs
*pcs
,
298 unsigned int neg_mode
,
299 phy_interface_t interface
,
300 const unsigned long *advertising
,
301 bool permit_pause_to_mac
)
303 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
308 adv
= phylink_mii_c22_pcs_encode_advertisement(interface
, advertising
);
312 mpcs
->interface
= interface
;
314 err
= mv88e639x_modify_changed(mpcs
, MV88E6390_SGMII_ADVERTISE
,
321 err
= mv88e639x_read(mpcs
, MV88E6390_SGMII_BMCR
, &val
);
325 if (neg_mode
== PHYLINK_PCS_NEG_INBAND_ENABLED
)
326 bmcr
= val
| BMCR_ANENABLE
;
328 bmcr
= val
& ~BMCR_ANENABLE
;
330 /* setting ANENABLE triggers a restart of negotiation */
334 return mv88e639x_write(mpcs
, MV88E6390_SGMII_BMCR
, bmcr
);
337 static void mv88e639x_sgmii_pcs_an_restart(struct phylink_pcs
*pcs
)
339 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
341 mv88e639x_modify(mpcs
, MV88E6390_SGMII_BMCR
,
342 BMCR_ANRESTART
, BMCR_ANRESTART
);
345 static void mv88e639x_sgmii_pcs_link_up(struct phylink_pcs
*pcs
,
347 phy_interface_t interface
,
348 int speed
, int duplex
)
350 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
354 if (phylink_autoneg_inband(mode
))
357 bmcr
= mii_bmcr_encode_fixed(speed
, duplex
);
359 err
= mv88e639x_modify(mpcs
, MV88E6390_SGMII_BMCR
,
360 BMCR_SPEED1000
| BMCR_SPEED100
| BMCR_FULLDPLX
,
363 dev_err(mpcs
->mdio
.dev
.parent
,
364 "can't access Serdes PHY %s: %pe\n",
365 "BMCR", ERR_PTR(err
));
368 static const struct phylink_pcs_ops mv88e639x_sgmii_pcs_ops
= {
369 .pcs_enable
= mv88e639x_sgmii_pcs_enable
,
370 .pcs_disable
= mv88e639x_sgmii_pcs_disable
,
371 .pcs_pre_config
= mv88e639x_sgmii_pcs_pre_config
,
372 .pcs_post_config
= mv88e639x_sgmii_pcs_post_config
,
373 .pcs_get_state
= mv88e639x_sgmii_pcs_get_state
,
374 .pcs_an_restart
= mv88e639x_sgmii_pcs_an_restart
,
375 .pcs_config
= mv88e639x_sgmii_pcs_config
,
376 .pcs_link_up
= mv88e639x_sgmii_pcs_link_up
,
379 static struct mv88e639x_pcs
*xg_pcs_to_mv88e639x_pcs(struct phylink_pcs
*pcs
)
381 return container_of(pcs
, struct mv88e639x_pcs
, xg_pcs
);
384 static int mv88e639x_xg_pcs_enable(struct mv88e639x_pcs
*mpcs
)
386 return mv88e639x_modify(mpcs
, MV88E6390_10G_CTRL1
,
387 MDIO_CTRL1_RESET
| MDIO_PCS_CTRL1_LOOPBACK
|
388 MDIO_CTRL1_LPOWER
, 0);
391 static void mv88e639x_xg_pcs_disable(struct mv88e639x_pcs
*mpcs
)
393 mv88e639x_modify(mpcs
, MV88E6390_10G_CTRL1
, MDIO_CTRL1_LPOWER
,
397 static void mv88e639x_xg_pcs_get_state(struct phylink_pcs
*pcs
,
398 struct phylink_link_state
*state
)
400 struct mv88e639x_pcs
*mpcs
= xg_pcs_to_mv88e639x_pcs(pcs
);
406 err
= mv88e639x_read(mpcs
, MV88E6390_10G_STAT1
, &status
);
408 dev_err(mpcs
->mdio
.dev
.parent
,
409 "can't read Serdes PHY %s: %pe\n",
410 "STAT1", ERR_PTR(err
));
414 state
->link
= !!(status
& MDIO_STAT1_LSTATUS
);
416 switch (state
->interface
) {
417 case PHY_INTERFACE_MODE_5GBASER
:
418 state
->speed
= SPEED_5000
;
421 case PHY_INTERFACE_MODE_10GBASER
:
422 case PHY_INTERFACE_MODE_RXAUI
:
423 case PHY_INTERFACE_MODE_XAUI
:
424 state
->speed
= SPEED_10000
;
432 state
->duplex
= DUPLEX_FULL
;
436 static int mv88e639x_xg_pcs_config(struct phylink_pcs
*pcs
,
437 unsigned int neg_mode
,
438 phy_interface_t interface
,
439 const unsigned long *advertising
,
440 bool permit_pause_to_mac
)
445 static struct phylink_pcs
*
446 mv88e639x_pcs_select(struct mv88e6xxx_chip
*chip
, int port
,
447 phy_interface_t mode
)
449 struct mv88e639x_pcs
*mpcs
;
451 mpcs
= chip
->ports
[port
].pcs_private
;
456 case PHY_INTERFACE_MODE_SGMII
:
457 case PHY_INTERFACE_MODE_1000BASEX
:
458 case PHY_INTERFACE_MODE_2500BASEX
:
459 return &mpcs
->sgmii_pcs
;
461 case PHY_INTERFACE_MODE_5GBASER
:
462 if (!mpcs
->supports_5g
)
465 case PHY_INTERFACE_MODE_10GBASER
:
466 case PHY_INTERFACE_MODE_XAUI
:
467 case PHY_INTERFACE_MODE_RXAUI
:
468 return &mpcs
->xg_pcs
;
475 /* Marvell 88E6390 Specific support */
477 static irqreturn_t
mv88e6390_xg_handle_irq(struct mv88e639x_pcs
*mpcs
)
482 err
= mv88e639x_read(mpcs
, MV88E6390_10G_INT_STATUS
, &int_status
);
486 if (int_status
& (MV88E6390_10G_INT_LINK_DOWN
|
487 MV88E6390_10G_INT_LINK_UP
)) {
488 phylink_pcs_change(&mpcs
->xg_pcs
,
489 int_status
& MV88E6390_10G_INT_LINK_UP
);
497 static int mv88e6390_xg_control_irq(struct mv88e639x_pcs
*mpcs
, bool enable
)
502 val
= MV88E6390_10G_INT_LINK_DOWN
| MV88E6390_10G_INT_LINK_UP
;
504 return mv88e639x_modify(mpcs
, MV88E6390_10G_INT_ENABLE
,
505 MV88E6390_10G_INT_LINK_DOWN
|
506 MV88E6390_10G_INT_LINK_UP
, val
);
509 static int mv88e6390_xg_pcs_enable(struct phylink_pcs
*pcs
)
511 struct mv88e639x_pcs
*mpcs
= xg_pcs_to_mv88e639x_pcs(pcs
);
514 err
= mv88e639x_xg_pcs_enable(mpcs
);
518 mpcs
->handle_irq
= mv88e6390_xg_handle_irq
;
520 return mv88e6390_xg_control_irq(mpcs
, !!mpcs
->irq
);
523 static void mv88e6390_xg_pcs_disable(struct phylink_pcs
*pcs
)
525 struct mv88e639x_pcs
*mpcs
= xg_pcs_to_mv88e639x_pcs(pcs
);
527 mv88e6390_xg_control_irq(mpcs
, false);
528 mv88e639x_xg_pcs_disable(mpcs
);
531 static const struct phylink_pcs_ops mv88e6390_xg_pcs_ops
= {
532 .pcs_enable
= mv88e6390_xg_pcs_enable
,
533 .pcs_disable
= mv88e6390_xg_pcs_disable
,
534 .pcs_get_state
= mv88e639x_xg_pcs_get_state
,
535 .pcs_config
= mv88e639x_xg_pcs_config
,
538 static int mv88e6390_pcs_enable_checker(struct mv88e639x_pcs
*mpcs
)
540 return mv88e639x_modify(mpcs
, MV88E6390_PG_CONTROL
,
541 MV88E6390_PG_CONTROL_ENABLE_PC
,
542 MV88E6390_PG_CONTROL_ENABLE_PC
);
545 static int mv88e6390_pcs_init(struct mv88e6xxx_chip
*chip
, int port
)
547 struct mv88e639x_pcs
*mpcs
;
552 lane
= mv88e6xxx_serdes_get_lane(chip
, port
);
556 bus
= mv88e6xxx_default_mdio_bus(chip
);
559 mpcs
= mv88e639x_pcs_alloc(dev
, bus
, lane
, port
);
563 mpcs
->sgmii_pcs
.ops
= &mv88e639x_sgmii_pcs_ops
;
564 mpcs
->sgmii_pcs
.neg_mode
= true;
565 mpcs
->xg_pcs
.ops
= &mv88e6390_xg_pcs_ops
;
566 mpcs
->xg_pcs
.neg_mode
= true;
568 if (chip
->info
->prod_num
== MV88E6XXX_PORT_SWITCH_ID_PROD_6190X
||
569 chip
->info
->prod_num
== MV88E6XXX_PORT_SWITCH_ID_PROD_6390X
)
570 mpcs
->erratum_3_14
= true;
572 err
= mv88e639x_pcs_setup_irq(mpcs
, chip
, port
);
576 /* 6390 and 6390x has the checker, 6393x doesn't appear to? */
577 /* This is to enable gathering the statistics. Maybe this
578 * should call out to a helper? Or we could do this at init time.
580 err
= mv88e6390_pcs_enable_checker(mpcs
);
584 chip
->ports
[port
].pcs_private
= mpcs
;
593 const struct mv88e6xxx_pcs_ops mv88e6390_pcs_ops
= {
594 .pcs_init
= mv88e6390_pcs_init
,
595 .pcs_teardown
= mv88e639x_pcs_teardown
,
596 .pcs_select
= mv88e639x_pcs_select
,
599 /* Marvell 88E6393X Specific support */
601 static int mv88e6393x_power_lane(struct mv88e639x_pcs
*mpcs
, bool enable
)
603 u16 val
= MV88E6393X_SERDES_CTRL1_TX_PDOWN
|
604 MV88E6393X_SERDES_CTRL1_RX_PDOWN
;
606 return mv88e639x_modify(mpcs
, MV88E6393X_SERDES_CTRL1
, val
,
610 /* mv88e6393x family errata 4.6:
611 * Cannot clear PwrDn bit on SERDES if device is configured CPU_MGD mode or
612 * P0_mode is configured for [x]MII.
613 * Workaround: Set SERDES register 4.F002 bit 5=0 and bit 15=1.
615 * It seems that after this workaround the SERDES is automatically powered up
616 * (the bit is cleared), so power it down.
618 static int mv88e6393x_erratum_4_6(struct mv88e639x_pcs
*mpcs
)
622 err
= mv88e639x_modify(mpcs
, MV88E6393X_SERDES_POC
,
623 MV88E6393X_SERDES_POC_PDOWN
|
624 MV88E6393X_SERDES_POC_RESET
,
625 MV88E6393X_SERDES_POC_RESET
);
629 err
= mv88e639x_modify(mpcs
, MV88E6390_SGMII_BMCR
,
630 BMCR_PDOWN
, BMCR_PDOWN
);
634 err
= mv88e639x_sgmii_pcs_control_pwr(mpcs
, false);
638 return mv88e6393x_power_lane(mpcs
, false);
641 /* mv88e6393x family errata 4.8:
642 * When a SERDES port is operating in 1000BASE-X or SGMII mode link may not
643 * come up after hardware reset or software reset of SERDES core. Workaround
644 * is to write SERDES register 4.F074.14=1 for only those modes and 0 in all
647 static int mv88e6393x_erratum_4_8(struct mv88e639x_pcs
*mpcs
)
652 err
= mv88e639x_read(mpcs
, MV88E6393X_SERDES_POC
, &poc
);
656 poc
&= MV88E6393X_SERDES_POC_PCS_MASK
;
657 if (poc
== MV88E6393X_SERDES_POC_PCS_1000BASEX
||
658 poc
== MV88E6393X_SERDES_POC_PCS_SGMII_PHY
||
659 poc
== MV88E6393X_SERDES_POC_PCS_SGMII_MAC
)
660 reg
= MV88E6393X_ERRATA_4_8_BIT
;
664 return mv88e639x_modify(mpcs
, MV88E6393X_ERRATA_4_8_REG
,
665 MV88E6393X_ERRATA_4_8_BIT
, reg
);
668 /* mv88e6393x family errata 5.2:
669 * For optimal signal integrity the following sequence should be applied to
670 * SERDES operating in 10G mode. These registers only apply to 10G operation
671 * and have no effect on other speeds.
673 static int mv88e6393x_erratum_5_2(struct mv88e639x_pcs
*mpcs
)
675 static const struct {
676 u16 dev
, reg
, val
, mask
;
678 { MDIO_MMD_VEND1
, 0x8093, 0xcb5a, 0xffff },
679 { MDIO_MMD_VEND1
, 0x8171, 0x7088, 0xffff },
680 { MDIO_MMD_VEND1
, 0x80c9, 0x311a, 0xffff },
681 { MDIO_MMD_VEND1
, 0x80a2, 0x8000, 0xff7f },
682 { MDIO_MMD_VEND1
, 0x80a9, 0x0000, 0xfff0 },
683 { MDIO_MMD_VEND1
, 0x80a3, 0x0000, 0xf8ff },
684 { MDIO_MMD_PHYXS
, MV88E6393X_SERDES_POC
,
685 MV88E6393X_SERDES_POC_RESET
, MV88E6393X_SERDES_POC_RESET
},
689 for (i
= 0; i
< ARRAY_SIZE(fixes
); ++i
) {
690 err
= mdiodev_c45_modify(&mpcs
->mdio
, fixes
[i
].dev
,
691 fixes
[i
].reg
, fixes
[i
].mask
,
700 /* Inband AN is broken on Amethyst in 2500base-x mode when set by standard
701 * mechanism (via cmode).
702 * We can get around this by configuring the PCS mode to 1000base-x and then
703 * writing value 0x58 to register 1e.8000. (This must be done while SerDes
704 * receiver and transmitter are disabled, which is, when this function is
706 * It seem that when we do this configuration to 2500base-x mode (by changing
707 * PCS mode to 1000base-x and frequency to 3.125 GHz from 1.25 GHz) and then
708 * configure to sgmii or 1000base-x, the device thinks that it already has
709 * SerDes at 1.25 GHz and does not change the 1e.8000 register, leaving SerDes
711 * To avoid this, change PCS mode back to 2500base-x when disabling SerDes from
714 static int mv88e6393x_fix_2500basex_an(struct mv88e639x_pcs
*mpcs
, bool on
)
720 reg
= MV88E6393X_SERDES_POC_PCS_1000BASEX
|
721 MV88E6393X_SERDES_POC_AN
;
723 reg
= MV88E6393X_SERDES_POC_PCS_2500BASEX
;
725 reg
|= MV88E6393X_SERDES_POC_RESET
;
727 err
= mv88e639x_modify(mpcs
, MV88E6393X_SERDES_POC
,
728 MV88E6393X_SERDES_POC_PCS_MASK
|
729 MV88E6393X_SERDES_POC_AN
|
730 MV88E6393X_SERDES_POC_RESET
, reg
);
734 return mdiodev_c45_write(&mpcs
->mdio
, MDIO_MMD_VEND1
, 0x8000, 0x58);
737 static int mv88e6393x_sgmii_apply_2500basex_an(struct mv88e639x_pcs
*mpcs
,
738 phy_interface_t interface
,
743 if (interface
!= PHY_INTERFACE_MODE_2500BASEX
)
746 err
= mv88e6393x_fix_2500basex_an(mpcs
, enable
);
748 dev_err(mpcs
->mdio
.dev
.parent
,
749 "failed to %s 2500basex fix: %pe\n",
750 enable
? "enable" : "disable", ERR_PTR(err
));
755 static void mv88e6393x_sgmii_pcs_disable(struct phylink_pcs
*pcs
)
757 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
759 mv88e639x_sgmii_pcs_disable(pcs
);
760 mv88e6393x_power_lane(mpcs
, false);
761 mv88e6393x_sgmii_apply_2500basex_an(mpcs
, mpcs
->interface
, false);
764 static void mv88e6393x_sgmii_pcs_pre_config(struct phylink_pcs
*pcs
,
765 phy_interface_t interface
)
767 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
769 mv88e639x_sgmii_pcs_pre_config(pcs
, interface
);
770 mv88e6393x_power_lane(mpcs
, false);
771 mv88e6393x_sgmii_apply_2500basex_an(mpcs
, mpcs
->interface
, false);
774 static int mv88e6393x_sgmii_pcs_post_config(struct phylink_pcs
*pcs
,
775 phy_interface_t interface
)
777 struct mv88e639x_pcs
*mpcs
= sgmii_pcs_to_mv88e639x_pcs(pcs
);
780 err
= mv88e6393x_erratum_4_8(mpcs
);
784 err
= mv88e6393x_sgmii_apply_2500basex_an(mpcs
, interface
, true);
788 err
= mv88e6393x_power_lane(mpcs
, true);
792 return mv88e639x_sgmii_pcs_post_config(pcs
, interface
);
795 static const struct phylink_pcs_ops mv88e6393x_sgmii_pcs_ops
= {
796 .pcs_enable
= mv88e639x_sgmii_pcs_enable
,
797 .pcs_disable
= mv88e6393x_sgmii_pcs_disable
,
798 .pcs_pre_config
= mv88e6393x_sgmii_pcs_pre_config
,
799 .pcs_post_config
= mv88e6393x_sgmii_pcs_post_config
,
800 .pcs_get_state
= mv88e639x_sgmii_pcs_get_state
,
801 .pcs_an_restart
= mv88e639x_sgmii_pcs_an_restart
,
802 .pcs_config
= mv88e639x_sgmii_pcs_config
,
803 .pcs_link_up
= mv88e639x_sgmii_pcs_link_up
,
806 static irqreturn_t
mv88e6393x_xg_handle_irq(struct mv88e639x_pcs
*mpcs
)
808 u16 int_status
, stat1
;
812 err
= mv88e639x_read(mpcs
, MV88E6393X_10G_INT_STATUS
, &int_status
);
816 if (int_status
& MV88E6393X_10G_INT_LINK_CHANGE
) {
817 err
= mv88e639x_read(mpcs
, MV88E6390_10G_STAT1
, &stat1
);
821 link_down
= !(stat1
& MDIO_STAT1_LSTATUS
);
823 phylink_pcs_change(&mpcs
->xg_pcs
, !link_down
);
831 static int mv88e6393x_xg_control_irq(struct mv88e639x_pcs
*mpcs
, bool enable
)
836 val
= MV88E6393X_10G_INT_LINK_CHANGE
;
838 return mv88e639x_modify(mpcs
, MV88E6393X_10G_INT_ENABLE
,
839 MV88E6393X_10G_INT_LINK_CHANGE
, val
);
842 static int mv88e6393x_xg_pcs_enable(struct phylink_pcs
*pcs
)
844 struct mv88e639x_pcs
*mpcs
= xg_pcs_to_mv88e639x_pcs(pcs
);
846 mpcs
->handle_irq
= mv88e6393x_xg_handle_irq
;
848 return mv88e6393x_xg_control_irq(mpcs
, !!mpcs
->irq
);
851 static void mv88e6393x_xg_pcs_disable(struct phylink_pcs
*pcs
)
853 struct mv88e639x_pcs
*mpcs
= xg_pcs_to_mv88e639x_pcs(pcs
);
855 mv88e6393x_xg_control_irq(mpcs
, false);
856 mv88e639x_xg_pcs_disable(mpcs
);
857 mv88e6393x_power_lane(mpcs
, false);
860 /* The PCS has to be powered down while CMODE is changed */
861 static void mv88e6393x_xg_pcs_pre_config(struct phylink_pcs
*pcs
,
862 phy_interface_t interface
)
864 struct mv88e639x_pcs
*mpcs
= xg_pcs_to_mv88e639x_pcs(pcs
);
866 mv88e639x_xg_pcs_disable(mpcs
);
867 mv88e6393x_power_lane(mpcs
, false);
870 static int mv88e6393x_xg_pcs_post_config(struct phylink_pcs
*pcs
,
871 phy_interface_t interface
)
873 struct mv88e639x_pcs
*mpcs
= xg_pcs_to_mv88e639x_pcs(pcs
);
876 if (interface
== PHY_INTERFACE_MODE_10GBASER
) {
877 err
= mv88e6393x_erratum_5_2(mpcs
);
882 err
= mv88e6393x_power_lane(mpcs
, true);
886 return mv88e639x_xg_pcs_enable(mpcs
);
889 static const struct phylink_pcs_ops mv88e6393x_xg_pcs_ops
= {
890 .pcs_enable
= mv88e6393x_xg_pcs_enable
,
891 .pcs_disable
= mv88e6393x_xg_pcs_disable
,
892 .pcs_pre_config
= mv88e6393x_xg_pcs_pre_config
,
893 .pcs_post_config
= mv88e6393x_xg_pcs_post_config
,
894 .pcs_get_state
= mv88e639x_xg_pcs_get_state
,
895 .pcs_config
= mv88e639x_xg_pcs_config
,
898 static int mv88e6393x_pcs_init(struct mv88e6xxx_chip
*chip
, int port
)
900 struct mv88e639x_pcs
*mpcs
;
905 lane
= mv88e6xxx_serdes_get_lane(chip
, port
);
909 bus
= mv88e6xxx_default_mdio_bus(chip
);
912 mpcs
= mv88e639x_pcs_alloc(dev
, bus
, lane
, port
);
916 mpcs
->sgmii_pcs
.ops
= &mv88e6393x_sgmii_pcs_ops
;
917 mpcs
->sgmii_pcs
.neg_mode
= true;
918 mpcs
->xg_pcs
.ops
= &mv88e6393x_xg_pcs_ops
;
919 mpcs
->xg_pcs
.neg_mode
= true;
920 mpcs
->supports_5g
= true;
922 err
= mv88e6393x_erratum_4_6(mpcs
);
926 err
= mv88e639x_pcs_setup_irq(mpcs
, chip
, port
);
930 chip
->ports
[port
].pcs_private
= mpcs
;
939 const struct mv88e6xxx_pcs_ops mv88e6393x_pcs_ops
= {
940 .pcs_init
= mv88e6393x_pcs_init
,
941 .pcs_teardown
= mv88e639x_pcs_teardown
,
942 .pcs_select
= mv88e639x_pcs_select
,