1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright (c) 2024 Hisilicon Limited. 3 4 #include <linux/phy.h> 5 #include <linux/phy_fixed.h> 6 #include <linux/rtnetlink.h> 7 #include "hbg_common.h" 8 #include "hbg_hw.h" 9 #include "hbg_mdio.h" 10 #include "hbg_reg.h" 11 12 #define HBG_MAC_GET_PRIV(mac) ((struct hbg_priv *)(mac)->mdio_bus->priv) 13 #define HBG_MII_BUS_GET_MAC(bus) (&((struct hbg_priv *)(bus)->priv)->mac) 14 15 #define HBG_MDIO_C22_MODE 0x1 16 #define HBG_MDIO_C22_REG_WRITE 0x1 17 #define HBG_MDIO_C22_REG_READ 0x2 18 19 #define HBG_MDIO_OP_TIMEOUT_US (1 * 1000 * 1000) 20 #define HBG_MDIO_OP_INTERVAL_US (5 * 1000) 21 22 #define HBG_NP_LINK_FAIL_RETRY_TIMES 5 23 #define HBG_NO_PHY 0xFF 24 25 static void hbg_mdio_set_command(struct hbg_mac *mac, u32 cmd) 26 { 27 hbg_reg_write(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR, cmd); 28 } 29 30 static void hbg_mdio_get_command(struct hbg_mac *mac, u32 *cmd) 31 { 32 *cmd = hbg_reg_read(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR); 33 } 34 35 static void hbg_mdio_set_wdata_reg(struct hbg_mac *mac, u16 wdata_value) 36 { 37 hbg_reg_write_field(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_WDATA_ADDR, 38 HBG_REG_MDIO_WDATA_M, wdata_value); 39 } 40 41 static u32 hbg_mdio_get_rdata_reg(struct hbg_mac *mac) 42 { 43 return hbg_reg_read_field(HBG_MAC_GET_PRIV(mac), 44 HBG_REG_MDIO_RDATA_ADDR, 45 HBG_REG_MDIO_WDATA_M); 46 } 47 48 static int hbg_mdio_wait_ready(struct hbg_mac *mac) 49 { 50 struct hbg_priv *priv = HBG_MAC_GET_PRIV(mac); 51 u32 cmd = 0; 52 int ret; 53 54 ret = readl_poll_timeout(priv->io_base + HBG_REG_MDIO_COMMAND_ADDR, cmd, 55 !FIELD_GET(HBG_REG_MDIO_COMMAND_START_B, cmd), 56 HBG_MDIO_OP_INTERVAL_US, 57 HBG_MDIO_OP_TIMEOUT_US); 58 59 return ret ? -ETIMEDOUT : 0; 60 } 61 62 static int hbg_mdio_cmd_send(struct hbg_mac *mac, u32 prt_addr, u32 dev_addr, 63 u32 type, u32 op_code) 64 { 65 u32 cmd = 0; 66 67 hbg_mdio_get_command(mac, &cmd); 68 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_ST_M, type); 69 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_OP_M, op_code); 70 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_PRTAD_M, prt_addr); 71 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_DEVAD_M, dev_addr); 72 73 /* if auto scan enabled, this value need fix to 0 */ 74 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_START_B, 0x1); 75 76 hbg_mdio_set_command(mac, cmd); 77 78 /* wait operation complete and check the result */ 79 return hbg_mdio_wait_ready(mac); 80 } 81 82 static int hbg_mdio_read22(struct mii_bus *bus, int phy_addr, int regnum) 83 { 84 struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); 85 int ret; 86 87 ret = hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, 88 HBG_MDIO_C22_REG_READ); 89 if (ret) 90 return ret; 91 92 return hbg_mdio_get_rdata_reg(mac); 93 } 94 95 static int hbg_mdio_write22(struct mii_bus *bus, int phy_addr, int regnum, 96 u16 val) 97 { 98 struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); 99 100 hbg_mdio_set_wdata_reg(mac, val); 101 return hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, 102 HBG_MDIO_C22_REG_WRITE); 103 } 104 105 static void hbg_mdio_init_hw(struct hbg_priv *priv) 106 { 107 u32 freq = priv->dev_specs.mdio_frequency; 108 struct hbg_mac *mac = &priv->mac; 109 u32 cmd = 0; 110 111 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_ST_M, HBG_MDIO_C22_MODE); 112 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_AUTO_SCAN_B, HBG_STATUS_DISABLE); 113 114 /* freq use two bits, which are stored in clk_sel and clk_sel_exp */ 115 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_B, freq & 0x1); 116 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_EXP_B, 117 (freq >> 1) & 0x1); 118 119 hbg_mdio_set_command(mac, cmd); 120 } 121 122 static void hbg_flowctrl_cfg(struct hbg_priv *priv) 123 { 124 struct phy_device *phydev = priv->mac.phydev; 125 bool rx_pause; 126 bool tx_pause; 127 128 if (!priv->mac.pause_autoneg) 129 return; 130 131 phy_get_pause(phydev, &tx_pause, &rx_pause); 132 hbg_hw_set_pause_enable(priv, tx_pause, rx_pause); 133 } 134 135 void hbg_fix_np_link_fail(struct hbg_priv *priv) 136 { 137 struct device *dev = &priv->pdev->dev; 138 139 rtnl_lock(); 140 141 if (priv->stats.np_link_fail_cnt >= HBG_NP_LINK_FAIL_RETRY_TIMES) { 142 dev_err(dev, "failed to fix the MAC link status\n"); 143 priv->stats.np_link_fail_cnt = 0; 144 goto unlock; 145 } 146 147 if (!priv->mac.phydev->link) 148 goto unlock; 149 150 priv->stats.np_link_fail_cnt++; 151 dev_err(dev, "failed to link between MAC and PHY, try to fix...\n"); 152 153 /* Replace phy_reset() with phy_stop() and phy_start(), 154 * as suggested by Andrew. 155 */ 156 hbg_phy_stop(priv); 157 hbg_phy_start(priv); 158 159 unlock: 160 rtnl_unlock(); 161 } 162 163 static void hbg_phy_adjust_link(struct net_device *netdev) 164 { 165 struct hbg_priv *priv = netdev_priv(netdev); 166 struct phy_device *phydev = netdev->phydev; 167 u32 speed; 168 169 if (phydev->link != priv->mac.link_status) { 170 if (phydev->link) { 171 switch (phydev->speed) { 172 case SPEED_10: 173 speed = HBG_PORT_MODE_SGMII_10M; 174 break; 175 case SPEED_100: 176 speed = HBG_PORT_MODE_SGMII_100M; 177 break; 178 case SPEED_1000: 179 speed = HBG_PORT_MODE_SGMII_1000M; 180 break; 181 default: 182 return; 183 } 184 185 priv->mac.speed = speed; 186 priv->mac.duplex = phydev->duplex; 187 priv->mac.autoneg = phydev->autoneg; 188 hbg_hw_adjust_link(priv, speed, phydev->duplex); 189 hbg_flowctrl_cfg(priv); 190 } 191 192 priv->mac.link_status = phydev->link; 193 phy_print_status(phydev); 194 } 195 } 196 197 static void hbg_phy_disconnect(void *data) 198 { 199 phy_disconnect((struct phy_device *)data); 200 } 201 202 static int hbg_phy_connect(struct hbg_priv *priv) 203 { 204 struct phy_device *phydev = priv->mac.phydev; 205 struct device *dev = &priv->pdev->dev; 206 int ret; 207 208 ret = phy_connect_direct(priv->netdev, phydev, hbg_phy_adjust_link, 209 PHY_INTERFACE_MODE_SGMII); 210 if (ret) 211 return dev_err_probe(dev, ret, "failed to connect phy\n"); 212 213 ret = devm_add_action_or_reset(dev, hbg_phy_disconnect, phydev); 214 if (ret) 215 return ret; 216 217 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); 218 phy_support_asym_pause(phydev); 219 phy_attached_info(phydev); 220 221 return 0; 222 } 223 224 void hbg_phy_start(struct hbg_priv *priv) 225 { 226 phy_start(priv->mac.phydev); 227 } 228 229 void hbg_phy_stop(struct hbg_priv *priv) 230 { 231 phy_stop(priv->mac.phydev); 232 } 233 234 static void hbg_fixed_phy_uninit(void *data) 235 { 236 fixed_phy_unregister((struct phy_device *)data); 237 } 238 239 static int hbg_fixed_phy_init(struct hbg_priv *priv) 240 { 241 struct fixed_phy_status hbg_fixed_phy_status = { 242 .link = 1, 243 .speed = SPEED_1000, 244 .duplex = DUPLEX_FULL, 245 .pause = 1, 246 .asym_pause = 1, 247 }; 248 struct device *dev = &priv->pdev->dev; 249 struct phy_device *phydev; 250 int ret; 251 252 phydev = fixed_phy_register(&hbg_fixed_phy_status, NULL); 253 if (IS_ERR(phydev)) { 254 dev_err_probe(dev, PTR_ERR(phydev), 255 "failed to register fixed PHY device\n"); 256 return PTR_ERR(phydev); 257 } 258 259 ret = devm_add_action_or_reset(dev, hbg_fixed_phy_uninit, phydev); 260 if (ret) 261 return ret; 262 263 priv->mac.phydev = phydev; 264 return hbg_phy_connect(priv); 265 } 266 267 int hbg_mdio_init(struct hbg_priv *priv) 268 { 269 struct device *dev = &priv->pdev->dev; 270 struct hbg_mac *mac = &priv->mac; 271 struct phy_device *phydev; 272 struct mii_bus *mdio_bus; 273 int ret; 274 275 mac->phy_addr = priv->dev_specs.phy_addr; 276 if (mac->phy_addr == HBG_NO_PHY) 277 return hbg_fixed_phy_init(priv); 278 279 mdio_bus = devm_mdiobus_alloc(dev); 280 if (!mdio_bus) 281 return dev_err_probe(dev, -ENOMEM, 282 "failed to alloc MDIO bus\n"); 283 284 mdio_bus->parent = dev; 285 mdio_bus->priv = priv; 286 mdio_bus->phy_mask = ~(1 << mac->phy_addr); 287 mdio_bus->name = "hibmcge mii bus"; 288 mac->mdio_bus = mdio_bus; 289 290 mdio_bus->read = hbg_mdio_read22; 291 mdio_bus->write = hbg_mdio_write22; 292 snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii", dev_name(dev)); 293 294 ret = devm_mdiobus_register(dev, mdio_bus); 295 if (ret) 296 return dev_err_probe(dev, ret, "failed to register MDIO bus\n"); 297 298 phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr); 299 if (!phydev) 300 return dev_err_probe(dev, -ENODEV, 301 "failed to get phy device\n"); 302 303 mac->phydev = phydev; 304 hbg_mdio_init_hw(priv); 305 return hbg_phy_connect(priv); 306 } 307