File Index
Files and directories
Sign in
FILE

hbg_mdio.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c C
  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
 24static 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
 29static 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
 34static 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
 40static 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
 47static 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
 61static 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
 81static 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
 94static 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
104static 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
121static 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
134void 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
158unlock:
159	rtnl_unlock();
160}
161
162static 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
196static void hbg_phy_disconnect(void *data)
197{
198	phy_disconnect((struct phy_device *)data);
199}
200
201static 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
223void hbg_phy_start(struct hbg_priv *priv)
224{
225	phy_start(priv->mac.phydev);
226}
227
228void hbg_phy_stop(struct hbg_priv *priv)
229{
230	phy_stop(priv->mac.phydev);
231}
232
233static void hbg_fixed_phy_uninit(void *data)
234{
235	fixed_phy_unregister((struct phy_device *)data);
236}
237
238static 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
266int 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}
~/ Read-only file preview.