Lines Matching +full:core +full:- +full:pcs
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Marvell 88E6352 family SERDES PCS support
36 err = mdiodev_c45_read(&mpcs->mdio, MDIO_MMD_PHYXS, regnum); in mv88e639x_read()
47 return mdiodev_c45_write(&mpcs->mdio, MDIO_MMD_PHYXS, regnum, val); in mv88e639x_write()
53 return mdiodev_c45_modify(&mpcs->mdio, MDIO_MMD_PHYXS, regnum, mask, in mv88e639x_modify()
60 return mdiodev_c45_modify_changed(&mpcs->mdio, MDIO_MMD_PHYXS, regnum, in mv88e639x_modify_changed()
74 mpcs->mdio.dev.parent = dev; in mv88e639x_pcs_alloc()
75 mpcs->mdio.bus = bus; in mv88e639x_pcs_alloc()
76 mpcs->mdio.addr = addr; in mv88e639x_pcs_alloc()
78 snprintf(mpcs->name, sizeof(mpcs->name), in mv88e639x_pcs_alloc()
79 "mv88e6xxx-%s-serdes-%d", dev_name(dev), port); in mv88e639x_pcs_alloc()
89 handler = READ_ONCE(mpcs->handle_irq); in mv88e639x_pcs_handle_irq()
104 mpcs->sgmii_pcs.poll = true; in mv88e639x_pcs_setup_irq()
105 mpcs->xg_pcs.poll = true; in mv88e639x_pcs_setup_irq()
109 mpcs->irq = irq; in mv88e639x_pcs_setup_irq()
112 IRQF_ONESHOT, mpcs->name, mpcs); in mv88e639x_pcs_setup_irq()
117 struct mv88e639x_pcs *mpcs = chip->ports[port].pcs_private; in mv88e639x_pcs_teardown()
122 if (mpcs->irq) in mv88e639x_pcs_teardown()
123 free_irq(mpcs->irq, mpcs); in mv88e639x_pcs_teardown()
127 chip->ports[port].pcs_private = NULL; in mv88e639x_pcs_teardown()
130 static struct mv88e639x_pcs *sgmii_pcs_to_mv88e639x_pcs(struct phylink_pcs *pcs) in sgmii_pcs_to_mv88e639x_pcs() argument
132 return container_of(pcs, struct mv88e639x_pcs, sgmii_pcs); in sgmii_pcs_to_mv88e639x_pcs()
146 phylink_pcs_change(&mpcs->sgmii_pcs, in mv88e639x_sgmii_handle_irq()
184 static int mv88e639x_sgmii_pcs_enable(struct phylink_pcs *pcs) in mv88e639x_sgmii_pcs_enable() argument
186 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_enable()
189 mpcs->handle_irq = mv88e639x_sgmii_handle_irq; in mv88e639x_sgmii_pcs_enable()
191 return mv88e639x_sgmii_pcs_control_irq(mpcs, !!mpcs->irq); in mv88e639x_sgmii_pcs_enable()
194 static void mv88e639x_sgmii_pcs_disable(struct phylink_pcs *pcs) in mv88e639x_sgmii_pcs_disable() argument
196 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_disable()
202 static void mv88e639x_sgmii_pcs_pre_config(struct phylink_pcs *pcs, in mv88e639x_sgmii_pcs_pre_config() argument
205 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_pre_config()
219 * After chip reset, SERDES reconfiguration or SERDES core in mv88e6390_erratum_3_14()
225 err = mdiobus_c45_write(mpcs->mdio.bus, lanes[i], in mv88e6390_erratum_3_14()
231 err = mdiobus_c45_write(mpcs->mdio.bus, lanes[i], in mv88e6390_erratum_3_14()
241 static int mv88e639x_sgmii_pcs_post_config(struct phylink_pcs *pcs, in mv88e639x_sgmii_pcs_post_config() argument
244 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_post_config()
249 if (mpcs->erratum_3_14) { in mv88e639x_sgmii_pcs_post_config()
252 dev_err(mpcs->mdio.dev.parent, in mv88e639x_sgmii_pcs_post_config()
260 static void mv88e639x_sgmii_pcs_get_state(struct phylink_pcs *pcs, in mv88e639x_sgmii_pcs_get_state() argument
264 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_get_state()
270 dev_err(mpcs->mdio.dev.parent, in mv88e639x_sgmii_pcs_get_state()
273 state->link = false; in mv88e639x_sgmii_pcs_get_state()
279 dev_err(mpcs->mdio.dev.parent, in mv88e639x_sgmii_pcs_get_state()
282 state->link = false; in mv88e639x_sgmii_pcs_get_state()
288 dev_err(mpcs->mdio.dev.parent, in mv88e639x_sgmii_pcs_get_state()
291 state->link = false; in mv88e639x_sgmii_pcs_get_state()
295 mv88e6xxx_pcs_decode_state(mpcs->mdio.dev.parent, bmsr, lpa, status, in mv88e639x_sgmii_pcs_get_state()
299 static int mv88e639x_sgmii_pcs_config(struct phylink_pcs *pcs, in mv88e639x_sgmii_pcs_config() argument
305 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_config()
314 mpcs->interface = interface; in mv88e639x_sgmii_pcs_config()
339 static void mv88e639x_sgmii_pcs_an_restart(struct phylink_pcs *pcs) in mv88e639x_sgmii_pcs_an_restart() argument
341 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_an_restart()
347 static void mv88e639x_sgmii_pcs_link_up(struct phylink_pcs *pcs, in mv88e639x_sgmii_pcs_link_up() argument
352 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_sgmii_pcs_link_up()
365 dev_err(mpcs->mdio.dev.parent, in mv88e639x_sgmii_pcs_link_up()
381 static struct mv88e639x_pcs *xg_pcs_to_mv88e639x_pcs(struct phylink_pcs *pcs) in xg_pcs_to_mv88e639x_pcs() argument
383 return container_of(pcs, struct mv88e639x_pcs, xg_pcs); in xg_pcs_to_mv88e639x_pcs()
399 static void mv88e639x_xg_pcs_get_state(struct phylink_pcs *pcs, in mv88e639x_xg_pcs_get_state() argument
403 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e639x_xg_pcs_get_state()
407 state->link = false; in mv88e639x_xg_pcs_get_state()
411 dev_err(mpcs->mdio.dev.parent, in mv88e639x_xg_pcs_get_state()
417 state->link = !!(status & MDIO_STAT1_LSTATUS); in mv88e639x_xg_pcs_get_state()
418 if (state->link) { in mv88e639x_xg_pcs_get_state()
419 switch (state->interface) { in mv88e639x_xg_pcs_get_state()
421 state->speed = SPEED_5000; in mv88e639x_xg_pcs_get_state()
427 state->speed = SPEED_10000; in mv88e639x_xg_pcs_get_state()
431 state->link = false; in mv88e639x_xg_pcs_get_state()
435 state->duplex = DUPLEX_FULL; in mv88e639x_xg_pcs_get_state()
439 static int mv88e639x_xg_pcs_config(struct phylink_pcs *pcs, in mv88e639x_xg_pcs_config() argument
454 mpcs = chip->ports[port].pcs_private; in mv88e639x_pcs_select()
462 return &mpcs->sgmii_pcs; in mv88e639x_pcs_select()
465 if (!mpcs->supports_5g) in mv88e639x_pcs_select()
472 return &mpcs->xg_pcs; in mv88e639x_pcs_select()
492 phylink_pcs_change(&mpcs->xg_pcs, in mv88e6390_xg_handle_irq()
513 static int mv88e6390_xg_pcs_enable(struct phylink_pcs *pcs) in mv88e6390_xg_pcs_enable() argument
515 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e6390_xg_pcs_enable()
522 mpcs->handle_irq = mv88e6390_xg_handle_irq; in mv88e6390_xg_pcs_enable()
524 return mv88e6390_xg_control_irq(mpcs, !!mpcs->irq); in mv88e6390_xg_pcs_enable()
527 static void mv88e6390_xg_pcs_disable(struct phylink_pcs *pcs) in mv88e6390_xg_pcs_disable() argument
529 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e6390_xg_pcs_disable()
561 dev = chip->dev; in mv88e6390_pcs_init()
565 return -ENOMEM; in mv88e6390_pcs_init()
567 mpcs->sgmii_pcs.ops = &mv88e639x_sgmii_pcs_ops; in mv88e6390_pcs_init()
568 mpcs->sgmii_pcs.neg_mode = true; in mv88e6390_pcs_init()
569 mpcs->xg_pcs.ops = &mv88e6390_xg_pcs_ops; in mv88e6390_pcs_init()
570 mpcs->xg_pcs.neg_mode = true; in mv88e6390_pcs_init()
572 if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6190X || in mv88e6390_pcs_init()
573 chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6390X) in mv88e6390_pcs_init()
574 mpcs->erratum_3_14 = true; in mv88e6390_pcs_init()
588 chip->ports[port].pcs_private = mpcs; in mv88e6390_pcs_init()
646 * When a SERDES port is operating in 1000BASE-X or SGMII mode link may not
647 * come up after hardware reset or software reset of SERDES core. Workaround
694 err = mdiodev_c45_modify(&mpcs->mdio, fixes[i].dev, in mv88e6393x_erratum_5_2()
704 /* Inband AN is broken on Amethyst in 2500base-x mode when set by standard
706 * We can get around this by configuring the PCS mode to 1000base-x and then
710 * It seem that when we do this configuration to 2500base-x mode (by changing
711 * PCS mode to 1000base-x and frequency to 3.125 GHz from 1.25 GHz) and then
712 * configure to sgmii or 1000base-x, the device thinks that it already has
715 * To avoid this, change PCS mode back to 2500base-x when disabling SerDes from
716 * 2500base-x mode.
738 return mdiodev_c45_write(&mpcs->mdio, MDIO_MMD_VEND1, 0x8000, 0x58); in mv88e6393x_fix_2500basex_an()
752 dev_err(mpcs->mdio.dev.parent, in mv88e6393x_sgmii_apply_2500basex_an()
759 static void mv88e6393x_sgmii_pcs_disable(struct phylink_pcs *pcs) in mv88e6393x_sgmii_pcs_disable() argument
761 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_sgmii_pcs_disable()
763 mv88e639x_sgmii_pcs_disable(pcs); in mv88e6393x_sgmii_pcs_disable()
765 mv88e6393x_sgmii_apply_2500basex_an(mpcs, mpcs->interface, false); in mv88e6393x_sgmii_pcs_disable()
768 static void mv88e6393x_sgmii_pcs_pre_config(struct phylink_pcs *pcs, in mv88e6393x_sgmii_pcs_pre_config() argument
771 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_sgmii_pcs_pre_config()
773 mv88e639x_sgmii_pcs_pre_config(pcs, interface); in mv88e6393x_sgmii_pcs_pre_config()
775 mv88e6393x_sgmii_apply_2500basex_an(mpcs, mpcs->interface, false); in mv88e6393x_sgmii_pcs_pre_config()
778 static int mv88e6393x_sgmii_pcs_post_config(struct phylink_pcs *pcs, in mv88e6393x_sgmii_pcs_post_config() argument
781 struct mv88e639x_pcs *mpcs = sgmii_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_sgmii_pcs_post_config()
796 return mv88e639x_sgmii_pcs_post_config(pcs, interface); in mv88e6393x_sgmii_pcs_post_config()
827 phylink_pcs_change(&mpcs->xg_pcs, !link_down); in mv88e6393x_xg_handle_irq()
846 static int mv88e6393x_xg_pcs_enable(struct phylink_pcs *pcs) in mv88e6393x_xg_pcs_enable() argument
848 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_xg_pcs_enable()
850 mpcs->handle_irq = mv88e6393x_xg_handle_irq; in mv88e6393x_xg_pcs_enable()
852 return mv88e6393x_xg_control_irq(mpcs, !!mpcs->irq); in mv88e6393x_xg_pcs_enable()
855 static void mv88e6393x_xg_pcs_disable(struct phylink_pcs *pcs) in mv88e6393x_xg_pcs_disable() argument
857 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_xg_pcs_disable()
864 /* The PCS has to be powered down while CMODE is changed */
865 static void mv88e6393x_xg_pcs_pre_config(struct phylink_pcs *pcs, in mv88e6393x_xg_pcs_pre_config() argument
868 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_xg_pcs_pre_config()
874 static int mv88e6393x_xg_pcs_post_config(struct phylink_pcs *pcs, in mv88e6393x_xg_pcs_post_config() argument
877 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_xg_pcs_post_config()
894 static void mv88e6393x_xg_pcs_get_state(struct phylink_pcs *pcs, in mv88e6393x_xg_pcs_get_state() argument
898 struct mv88e639x_pcs *mpcs = xg_pcs_to_mv88e639x_pcs(pcs); in mv88e6393x_xg_pcs_get_state()
902 if (state->interface != PHY_INTERFACE_MODE_USXGMII) in mv88e6393x_xg_pcs_get_state()
903 return mv88e639x_xg_pcs_get_state(pcs, neg_mode, state); in mv88e6393x_xg_pcs_get_state()
905 state->link = false; in mv88e6393x_xg_pcs_get_state()
910 dev_err(mpcs->mdio.dev.parent, in mv88e6393x_xg_pcs_get_state()
915 state->link = !!(status & MDIO_USXGMII_LINK); in mv88e6393x_xg_pcs_get_state()
916 state->an_complete = state->link; in mv88e6393x_xg_pcs_get_state()
941 dev = chip->dev; in mv88e6393x_pcs_init()
945 return -ENOMEM; in mv88e6393x_pcs_init()
947 mpcs->sgmii_pcs.ops = &mv88e6393x_sgmii_pcs_ops; in mv88e6393x_pcs_init()
948 mpcs->sgmii_pcs.neg_mode = true; in mv88e6393x_pcs_init()
949 mpcs->xg_pcs.ops = &mv88e6393x_xg_pcs_ops; in mv88e6393x_pcs_init()
950 mpcs->xg_pcs.neg_mode = true; in mv88e6393x_pcs_init()
951 mpcs->supports_5g = true; in mv88e6393x_pcs_init()
961 chip->ports[port].pcs_private = mpcs; in mv88e6393x_pcs_init()