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