lan966x_phylink.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include <linux/module.h>
  3. #include <linux/phylink.h>
  4. #include <linux/device.h>
  5. #include <linux/netdevice.h>
  6. #include <linux/phy/phy.h>
  7. #include "lan966x_main.h"
  8. static struct phylink_pcs *lan966x_phylink_mac_select(struct phylink_config *config,
  9. phy_interface_t interface)
  10. {
  11. struct lan966x_port *port = netdev_priv(to_net_dev(config->dev));
  12. return &port->phylink_pcs;
  13. }
  14. static void lan966x_phylink_mac_config(struct phylink_config *config,
  15. unsigned int mode,
  16. const struct phylink_link_state *state)
  17. {
  18. }
  19. static int lan966x_phylink_mac_prepare(struct phylink_config *config,
  20. unsigned int mode,
  21. phy_interface_t iface)
  22. {
  23. struct lan966x_port *port = netdev_priv(to_net_dev(config->dev));
  24. phy_interface_t serdes_mode = iface;
  25. int err;
  26. if (port->serdes) {
  27. err = phy_set_mode_ext(port->serdes, PHY_MODE_ETHERNET,
  28. serdes_mode);
  29. if (err) {
  30. netdev_err(to_net_dev(config->dev),
  31. "Could not set mode of SerDes\n");
  32. return err;
  33. }
  34. }
  35. return 0;
  36. }
  37. static void lan966x_phylink_mac_link_up(struct phylink_config *config,
  38. struct phy_device *phy,
  39. unsigned int mode,
  40. phy_interface_t interface,
  41. int speed, int duplex,
  42. bool tx_pause, bool rx_pause)
  43. {
  44. struct lan966x_port *port = netdev_priv(to_net_dev(config->dev));
  45. struct lan966x_port_config *port_config = &port->config;
  46. port_config->duplex = duplex;
  47. port_config->speed = speed;
  48. port_config->pause = 0;
  49. port_config->pause |= tx_pause ? MLO_PAUSE_TX : 0;
  50. port_config->pause |= rx_pause ? MLO_PAUSE_RX : 0;
  51. if (phy_interface_mode_is_rgmii(interface))
  52. phy_set_speed(port->serdes, speed);
  53. lan966x_port_config_up(port);
  54. }
  55. static void lan966x_phylink_mac_link_down(struct phylink_config *config,
  56. unsigned int mode,
  57. phy_interface_t interface)
  58. {
  59. struct lan966x_port *port = netdev_priv(to_net_dev(config->dev));
  60. struct lan966x *lan966x = port->lan966x;
  61. lan966x_port_config_down(port);
  62. /* Take PCS out of reset */
  63. lan_rmw(DEV_CLOCK_CFG_PCS_RX_RST_SET(0) |
  64. DEV_CLOCK_CFG_PCS_TX_RST_SET(0),
  65. DEV_CLOCK_CFG_PCS_RX_RST |
  66. DEV_CLOCK_CFG_PCS_TX_RST,
  67. lan966x, DEV_CLOCK_CFG(port->chip_port));
  68. }
  69. static struct lan966x_port *lan966x_pcs_to_port(struct phylink_pcs *pcs)
  70. {
  71. return container_of(pcs, struct lan966x_port, phylink_pcs);
  72. }
  73. static void lan966x_pcs_get_state(struct phylink_pcs *pcs,
  74. struct phylink_link_state *state)
  75. {
  76. struct lan966x_port *port = lan966x_pcs_to_port(pcs);
  77. lan966x_port_status_get(port, state);
  78. }
  79. static int lan966x_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
  80. phy_interface_t interface,
  81. const unsigned long *advertising,
  82. bool permit_pause_to_mac)
  83. {
  84. struct lan966x_port *port = lan966x_pcs_to_port(pcs);
  85. struct lan966x_port_config config;
  86. int ret;
  87. config = port->config;
  88. config.portmode = interface;
  89. config.inband = neg_mode & PHYLINK_PCS_NEG_INBAND;
  90. config.autoneg = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED;
  91. config.advertising = advertising;
  92. ret = lan966x_port_pcs_set(port, &config);
  93. if (ret)
  94. netdev_err(port->dev, "port PCS config failed: %d\n", ret);
  95. return ret;
  96. }
  97. static void lan966x_pcs_aneg_restart(struct phylink_pcs *pcs)
  98. {
  99. /* Currently not used */
  100. }
  101. const struct phylink_mac_ops lan966x_phylink_mac_ops = {
  102. .mac_select_pcs = lan966x_phylink_mac_select,
  103. .mac_config = lan966x_phylink_mac_config,
  104. .mac_prepare = lan966x_phylink_mac_prepare,
  105. .mac_link_down = lan966x_phylink_mac_link_down,
  106. .mac_link_up = lan966x_phylink_mac_link_up,
  107. };
  108. const struct phylink_pcs_ops lan966x_phylink_pcs_ops = {
  109. .pcs_get_state = lan966x_pcs_get_state,
  110. .pcs_config = lan966x_pcs_config,
  111. .pcs_an_restart = lan966x_pcs_aneg_restart,
  112. };