xref: /linux/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c (revision e5763491237ffee22d9b554febc2d00669f81dee)
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 
hbg_mdio_set_command(struct hbg_mac * mac,u32 cmd)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 
hbg_mdio_get_command(struct hbg_mac * mac,u32 * cmd)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 
hbg_mdio_set_wdata_reg(struct hbg_mac * mac,u16 wdata_value)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 
hbg_mdio_get_rdata_reg(struct hbg_mac * mac)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 
hbg_mdio_wait_ready(struct hbg_mac * mac)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 
hbg_mdio_cmd_send(struct hbg_mac * mac,u32 prt_addr,u32 dev_addr,u32 type,u32 op_code)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 
hbg_mdio_read22(struct mii_bus * bus,int phy_addr,int regnum)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 
hbg_mdio_write22(struct mii_bus * bus,int phy_addr,int regnum,u16 val)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 
hbg_mdio_init_hw(struct hbg_priv * priv)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 
hbg_flowctrl_cfg(struct hbg_priv * priv)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 
hbg_fix_np_link_fail(struct hbg_priv * priv)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 
hbg_phy_adjust_link(struct net_device * netdev)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 
hbg_phy_disconnect(void * data)196 static void hbg_phy_disconnect(void *data)
197 {
198 	phy_disconnect((struct phy_device *)data);
199 }
200 
hbg_phy_connect(struct hbg_priv * priv)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 
hbg_phy_start(struct hbg_priv * priv)223 void hbg_phy_start(struct hbg_priv *priv)
224 {
225 	phy_start(priv->mac.phydev);
226 }
227 
hbg_phy_stop(struct hbg_priv * priv)228 void hbg_phy_stop(struct hbg_priv *priv)
229 {
230 	phy_stop(priv->mac.phydev);
231 }
232 
hbg_fixed_phy_uninit(void * data)233 static void hbg_fixed_phy_uninit(void *data)
234 {
235 	fixed_phy_unregister((struct phy_device *)data);
236 }
237 
hbg_fixed_phy_init(struct hbg_priv * priv)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 
hbg_mdio_init(struct hbg_priv * priv)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