xref: /linux/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c (revision a339dd699a7aa01bce4b38c8d81def310cf2bca0)
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