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