1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright (c) 2024 Hisilicon Limited. 3 4 #include <linux/phy.h> 5 #include "hbg_common.h" 6 #include "hbg_hw.h" 7 #include "hbg_mdio.h" 8 #include "hbg_reg.h" 9 10 #define HBG_MAC_GET_PRIV(mac) ((struct hbg_priv *)(mac)->mdio_bus->priv) 11 #define HBG_MII_BUS_GET_MAC(bus) (&((struct hbg_priv *)(bus)->priv)->mac) 12 13 #define HBG_MDIO_C22_MODE 0x1 14 #define HBG_MDIO_C22_REG_WRITE 0x1 15 #define HBG_MDIO_C22_REG_READ 0x2 16 17 #define HBG_MDIO_OP_TIMEOUT_US (1 * 1000 * 1000) 18 #define HBG_MDIO_OP_INTERVAL_US (5 * 1000) 19 20 static void hbg_mdio_set_command(struct hbg_mac *mac, u32 cmd) 21 { 22 hbg_reg_write(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR, cmd); 23 } 24 25 static void hbg_mdio_get_command(struct hbg_mac *mac, u32 *cmd) 26 { 27 *cmd = hbg_reg_read(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR); 28 } 29 30 static void hbg_mdio_set_wdata_reg(struct hbg_mac *mac, u16 wdata_value) 31 { 32 hbg_reg_write_field(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_WDATA_ADDR, 33 HBG_REG_MDIO_WDATA_M, wdata_value); 34 } 35 36 static u32 hbg_mdio_get_rdata_reg(struct hbg_mac *mac) 37 { 38 return hbg_reg_read_field(HBG_MAC_GET_PRIV(mac), 39 HBG_REG_MDIO_RDATA_ADDR, 40 HBG_REG_MDIO_WDATA_M); 41 } 42 43 static int hbg_mdio_wait_ready(struct hbg_mac *mac) 44 { 45 struct hbg_priv *priv = HBG_MAC_GET_PRIV(mac); 46 u32 cmd = 0; 47 int ret; 48 49 ret = readl_poll_timeout(priv->io_base + HBG_REG_MDIO_COMMAND_ADDR, cmd, 50 !FIELD_GET(HBG_REG_MDIO_COMMAND_START_B, cmd), 51 HBG_MDIO_OP_INTERVAL_US, 52 HBG_MDIO_OP_TIMEOUT_US); 53 54 return ret ? -ETIMEDOUT : 0; 55 } 56 57 static int hbg_mdio_cmd_send(struct hbg_mac *mac, u32 prt_addr, u32 dev_addr, 58 u32 type, u32 op_code) 59 { 60 u32 cmd = 0; 61 62 hbg_mdio_get_command(mac, &cmd); 63 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_ST_M, type); 64 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_OP_M, op_code); 65 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_PRTAD_M, prt_addr); 66 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_DEVAD_M, dev_addr); 67 68 /* if auto scan enabled, this value need fix to 0 */ 69 hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_START_B, 0x1); 70 71 hbg_mdio_set_command(mac, cmd); 72 73 /* wait operation complete and check the result */ 74 return hbg_mdio_wait_ready(mac); 75 } 76 77 static int hbg_mdio_read22(struct mii_bus *bus, int phy_addr, int regnum) 78 { 79 struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); 80 int ret; 81 82 ret = hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, 83 HBG_MDIO_C22_REG_READ); 84 if (ret) 85 return ret; 86 87 return hbg_mdio_get_rdata_reg(mac); 88 } 89 90 static int hbg_mdio_write22(struct mii_bus *bus, int phy_addr, int regnum, 91 u16 val) 92 { 93 struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); 94 95 hbg_mdio_set_wdata_reg(mac, val); 96 return hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, 97 HBG_MDIO_C22_REG_WRITE); 98 } 99 100 static void hbg_mdio_init_hw(struct hbg_priv *priv) 101 { 102 u32 freq = priv->dev_specs.mdio_frequency; 103 struct hbg_mac *mac = &priv->mac; 104 u32 cmd = 0; 105 106 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_ST_M, HBG_MDIO_C22_MODE); 107 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_AUTO_SCAN_B, HBG_STATUS_DISABLE); 108 109 /* freq use two bits, which are stored in clk_sel and clk_sel_exp */ 110 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_B, freq & 0x1); 111 cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_EXP_B, 112 (freq >> 1) & 0x1); 113 114 hbg_mdio_set_command(mac, cmd); 115 } 116 117 static void hbg_phy_adjust_link(struct net_device *netdev) 118 { 119 struct hbg_priv *priv = netdev_priv(netdev); 120 struct phy_device *phydev = netdev->phydev; 121 u32 speed; 122 123 if (phydev->link != priv->mac.link_status) { 124 if (phydev->link) { 125 switch (phydev->speed) { 126 case SPEED_10: 127 speed = HBG_PORT_MODE_SGMII_10M; 128 break; 129 case SPEED_100: 130 speed = HBG_PORT_MODE_SGMII_100M; 131 break; 132 case SPEED_1000: 133 speed = HBG_PORT_MODE_SGMII_1000M; 134 break; 135 default: 136 return; 137 } 138 139 priv->mac.speed = speed; 140 priv->mac.duplex = phydev->duplex; 141 priv->mac.autoneg = phydev->autoneg; 142 hbg_hw_adjust_link(priv, speed, phydev->duplex); 143 } 144 145 priv->mac.link_status = phydev->link; 146 phy_print_status(phydev); 147 } 148 } 149 150 static void hbg_phy_disconnect(void *data) 151 { 152 phy_disconnect((struct phy_device *)data); 153 } 154 155 static int hbg_phy_connect(struct hbg_priv *priv) 156 { 157 struct phy_device *phydev = priv->mac.phydev; 158 struct device *dev = &priv->pdev->dev; 159 int ret; 160 161 ret = phy_connect_direct(priv->netdev, phydev, hbg_phy_adjust_link, 162 PHY_INTERFACE_MODE_SGMII); 163 if (ret) 164 return dev_err_probe(dev, ret, "failed to connect phy\n"); 165 166 ret = devm_add_action_or_reset(dev, hbg_phy_disconnect, phydev); 167 if (ret) 168 return ret; 169 170 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); 171 phy_attached_info(phydev); 172 173 return 0; 174 } 175 176 void hbg_phy_start(struct hbg_priv *priv) 177 { 178 phy_start(priv->mac.phydev); 179 } 180 181 void hbg_phy_stop(struct hbg_priv *priv) 182 { 183 phy_stop(priv->mac.phydev); 184 } 185 186 int hbg_mdio_init(struct hbg_priv *priv) 187 { 188 struct device *dev = &priv->pdev->dev; 189 struct hbg_mac *mac = &priv->mac; 190 struct phy_device *phydev; 191 struct mii_bus *mdio_bus; 192 int ret; 193 194 mac->phy_addr = priv->dev_specs.phy_addr; 195 mdio_bus = devm_mdiobus_alloc(dev); 196 if (!mdio_bus) 197 return dev_err_probe(dev, -ENOMEM, 198 "failed to alloc MDIO bus\n"); 199 200 mdio_bus->parent = dev; 201 mdio_bus->priv = priv; 202 mdio_bus->phy_mask = ~(1 << mac->phy_addr); 203 mdio_bus->name = "hibmcge mii bus"; 204 mac->mdio_bus = mdio_bus; 205 206 mdio_bus->read = hbg_mdio_read22; 207 mdio_bus->write = hbg_mdio_write22; 208 snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii", dev_name(dev)); 209 210 ret = devm_mdiobus_register(dev, mdio_bus); 211 if (ret) 212 return dev_err_probe(dev, ret, "failed to register MDIO bus\n"); 213 214 phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr); 215 if (!phydev) 216 return dev_err_probe(dev, -ENODEV, 217 "failed to get phy device\n"); 218 219 mac->phydev = phydev; 220 hbg_mdio_init_hw(priv); 221 return hbg_phy_connect(priv); 222 } 223