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