1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */ 3 4 #include <linux/ethtool.h> 5 #include <linux/iopoll.h> 6 #include <linux/pci.h> 7 #include <linux/phy.h> 8 9 #include "../libwx/wx_type.h" 10 #include "../libwx/wx_ptp.h" 11 #include "../libwx/wx_hw.h" 12 #include "ngbe_type.h" 13 #include "ngbe_mdio.h" 14 15 static int ngbe_phy_read_reg_internal(struct mii_bus *bus, int phy_addr, int regnum) 16 { 17 struct wx *wx = bus->priv; 18 19 if (phy_addr != 0) 20 return 0xffff; 21 return (u16)rd32(wx, NGBE_PHY_CONFIG(regnum)); 22 } 23 24 static int ngbe_phy_write_reg_internal(struct mii_bus *bus, int phy_addr, int regnum, u16 value) 25 { 26 struct wx *wx = bus->priv; 27 28 if (phy_addr == 0) 29 wr32(wx, NGBE_PHY_CONFIG(regnum), value); 30 return 0; 31 } 32 33 static int ngbe_phy_read_reg_c22(struct mii_bus *bus, int phy_addr, int regnum) 34 { 35 struct wx *wx = bus->priv; 36 u16 phy_data; 37 38 if (wx->mac_type == em_mac_type_mdi) 39 phy_data = ngbe_phy_read_reg_internal(bus, phy_addr, regnum); 40 else 41 phy_data = wx_phy_read_reg_mdi_c22(bus, phy_addr, regnum); 42 43 return phy_data; 44 } 45 46 static int ngbe_phy_write_reg_c22(struct mii_bus *bus, int phy_addr, 47 int regnum, u16 value) 48 { 49 struct wx *wx = bus->priv; 50 int ret; 51 52 if (wx->mac_type == em_mac_type_mdi) 53 ret = ngbe_phy_write_reg_internal(bus, phy_addr, regnum, value); 54 else 55 ret = wx_phy_write_reg_mdi_c22(bus, phy_addr, regnum, value); 56 57 return ret; 58 } 59 60 static void ngbe_mac_config(struct phylink_config *config, unsigned int mode, 61 const struct phylink_link_state *state) 62 { 63 } 64 65 static void ngbe_mac_link_down(struct phylink_config *config, 66 unsigned int mode, phy_interface_t interface) 67 { 68 struct wx *wx = phylink_to_wx(config); 69 70 wx->speed = SPEED_UNKNOWN; 71 if (test_bit(WX_STATE_PTP_RUNNING, wx->state)) 72 wx_ptp_reset_cyclecounter(wx); 73 } 74 75 static void ngbe_mac_link_up(struct phylink_config *config, 76 struct phy_device *phy, 77 unsigned int mode, phy_interface_t interface, 78 int speed, int duplex, 79 bool tx_pause, bool rx_pause) 80 { 81 struct wx *wx = phylink_to_wx(config); 82 u32 lan_speed, reg; 83 84 wx_fc_enable(wx, tx_pause, rx_pause); 85 86 switch (speed) { 87 case SPEED_10: 88 lan_speed = 0; 89 break; 90 case SPEED_100: 91 lan_speed = 1; 92 break; 93 case SPEED_1000: 94 default: 95 lan_speed = 2; 96 break; 97 } 98 99 wr32m(wx, NGBE_CFG_LAN_SPEED, 0x3, lan_speed); 100 101 reg = rd32(wx, WX_MAC_TX_CFG); 102 reg &= ~WX_MAC_TX_CFG_SPEED_MASK; 103 reg |= WX_MAC_TX_CFG_SPEED_1G | WX_MAC_TX_CFG_TE; 104 wr32(wx, WX_MAC_TX_CFG, reg); 105 106 /* Re configure MAC Rx */ 107 reg = rd32(wx, WX_MAC_RX_CFG); 108 wr32(wx, WX_MAC_RX_CFG, reg); 109 wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); 110 reg = rd32(wx, WX_MAC_WDG_TIMEOUT); 111 wr32(wx, WX_MAC_WDG_TIMEOUT, reg); 112 113 wx->speed = speed; 114 wx->last_rx_ptp_check = jiffies; 115 if (test_bit(WX_STATE_PTP_RUNNING, wx->state)) 116 wx_ptp_reset_cyclecounter(wx); 117 } 118 119 static const struct phylink_mac_ops ngbe_mac_ops = { 120 .mac_config = ngbe_mac_config, 121 .mac_link_down = ngbe_mac_link_down, 122 .mac_link_up = ngbe_mac_link_up, 123 }; 124 125 static int ngbe_phylink_init(struct wx *wx) 126 { 127 struct phylink_config *config; 128 phy_interface_t phy_mode; 129 struct phylink *phylink; 130 131 config = &wx->phylink_config; 132 config->dev = &wx->netdev->dev; 133 config->type = PHYLINK_NETDEV; 134 config->mac_capabilities = MAC_1000FD | MAC_100FD | MAC_10FD | 135 MAC_SYM_PAUSE | MAC_ASYM_PAUSE; 136 config->mac_managed_pm = true; 137 138 /* The MAC only has add the Tx delay and it can not be modified. 139 * So just disable TX delay in PHY, and it is does not matter to 140 * internal phy. 141 */ 142 phy_mode = PHY_INTERFACE_MODE_RGMII_RXID; 143 __set_bit(PHY_INTERFACE_MODE_RGMII_RXID, config->supported_interfaces); 144 145 phylink = phylink_create(config, NULL, phy_mode, &ngbe_mac_ops); 146 if (IS_ERR(phylink)) 147 return PTR_ERR(phylink); 148 149 wx->phylink = phylink; 150 151 return 0; 152 } 153 154 int ngbe_mdio_init(struct wx *wx) 155 { 156 struct pci_dev *pdev = wx->pdev; 157 struct mii_bus *mii_bus; 158 int ret; 159 160 mii_bus = devm_mdiobus_alloc(&pdev->dev); 161 if (!mii_bus) 162 return -ENOMEM; 163 164 mii_bus->name = "ngbe_mii_bus"; 165 mii_bus->read = ngbe_phy_read_reg_c22; 166 mii_bus->write = ngbe_phy_write_reg_c22; 167 mii_bus->phy_mask = GENMASK(31, 4); 168 mii_bus->parent = &pdev->dev; 169 mii_bus->priv = wx; 170 171 if (wx->mac_type == em_mac_type_rgmii) { 172 mii_bus->read_c45 = wx_phy_read_reg_mdi_c45; 173 mii_bus->write_c45 = wx_phy_write_reg_mdi_c45; 174 } 175 176 snprintf(mii_bus->id, MII_BUS_ID_SIZE, "ngbe-%x", pci_dev_id(pdev)); 177 ret = devm_mdiobus_register(&pdev->dev, mii_bus); 178 if (ret) 179 return ret; 180 181 wx->phydev = phy_find_first(mii_bus); 182 if (!wx->phydev) 183 return -ENODEV; 184 185 phy_attached_info(wx->phydev); 186 187 wx->link = 0; 188 wx->speed = 0; 189 wx->duplex = 0; 190 191 ret = ngbe_phylink_init(wx); 192 if (ret) { 193 wx_err(wx, "failed to init phylink: %d\n", ret); 194 return ret; 195 } 196 197 return 0; 198 } 199