]>
Commit | Line | Data |
---|---|---|
4fa9c49f | 1 | // SPDX-License-Identifier: GPL-2.0-only |
47dd7a54 GC |
2 | /******************************************************************************* |
3 | STMMAC Ethernet Driver -- MDIO bus implementation | |
4 | Provides Bus interface for MII registers | |
5 | ||
6 | Copyright (C) 2007-2009 STMicroelectronics Ltd | |
7 | ||
47dd7a54 GC |
8 | |
9 | Author: Carl Shaw <carl.shaw@st.com> | |
10 | Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com> | |
11 | *******************************************************************************/ | |
12 | ||
bbf89284 | 13 | #include <linux/io.h> |
a5f48adc | 14 | #include <linux/iopoll.h> |
47dd7a54 | 15 | #include <linux/mii.h> |
0e076471 SK |
16 | #include <linux/of.h> |
17 | #include <linux/of_gpio.h> | |
e34d6569 | 18 | #include <linux/of_mdio.h> |
bbf89284 LC |
19 | #include <linux/phy.h> |
20 | #include <linux/slab.h> | |
47dd7a54 | 21 | |
6fc21117 | 22 | #include "dwxgmac2.h" |
47dd7a54 GC |
23 | #include "stmmac.h" |
24 | ||
25 | #define MII_BUSY 0x00000001 | |
26 | #define MII_WRITE 0x00000002 | |
27 | ||
ac1f74a7 AT |
28 | /* GMAC4 defines */ |
29 | #define MII_GMAC4_GOC_SHIFT 2 | |
30 | #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT) | |
31 | #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT) | |
32 | ||
6fc21117 JA |
33 | /* XGMAC defines */ |
34 | #define MII_XGMAC_SADDR BIT(18) | |
35 | #define MII_XGMAC_CMD_SHIFT 16 | |
36 | #define MII_XGMAC_WRITE (1 << MII_XGMAC_CMD_SHIFT) | |
37 | #define MII_XGMAC_READ (3 << MII_XGMAC_CMD_SHIFT) | |
38 | #define MII_XGMAC_BUSY BIT(22) | |
39 | #define MII_XGMAC_MAX_C22ADDR 3 | |
40 | #define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0) | |
41 | ||
42 | static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, | |
43 | int phyreg, u32 *hw_addr) | |
44 | { | |
45 | unsigned int mii_data = priv->hw->mii.data; | |
46 | u32 tmp; | |
47 | ||
48 | /* HW does not support C22 addr >= 4 */ | |
49 | if (phyaddr > MII_XGMAC_MAX_C22ADDR) | |
50 | return -ENODEV; | |
51 | /* Wait until any existing MII operation is complete */ | |
52 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
53 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | |
54 | return -EBUSY; | |
55 | ||
56 | /* Set port as Clause 22 */ | |
57 | tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); | |
58 | tmp &= ~MII_XGMAC_C22P_MASK; | |
59 | tmp |= BIT(phyaddr); | |
60 | writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); | |
61 | ||
62 | *hw_addr = (phyaddr << 16) | (phyreg & 0x1f); | |
63 | return 0; | |
64 | } | |
65 | ||
66 | static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) | |
67 | { | |
68 | struct net_device *ndev = bus->priv; | |
69 | struct stmmac_priv *priv = netdev_priv(ndev); | |
70 | unsigned int mii_address = priv->hw->mii.addr; | |
71 | unsigned int mii_data = priv->hw->mii.data; | |
72 | u32 tmp, addr, value = MII_XGMAC_BUSY; | |
73 | int ret; | |
74 | ||
75 | if (phyreg & MII_ADDR_C45) { | |
76 | return -EOPNOTSUPP; | |
77 | } else { | |
78 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | |
79 | if (ret) | |
80 | return ret; | |
81 | } | |
82 | ||
83 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) | |
84 | & priv->hw->mii.clk_csr_mask; | |
85 | value |= MII_XGMAC_SADDR | MII_XGMAC_READ; | |
86 | ||
87 | /* Wait until any existing MII operation is complete */ | |
88 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
89 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | |
90 | return -EBUSY; | |
91 | ||
92 | /* Set the MII address register to read */ | |
93 | writel(addr, priv->ioaddr + mii_address); | |
94 | writel(value, priv->ioaddr + mii_data); | |
95 | ||
96 | /* Wait until any existing MII operation is complete */ | |
97 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
98 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | |
99 | return -EBUSY; | |
100 | ||
101 | /* Read the data from the MII data register */ | |
102 | return readl(priv->ioaddr + mii_data) & GENMASK(15, 0); | |
103 | } | |
104 | ||
105 | static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, | |
106 | int phyreg, u16 phydata) | |
107 | { | |
108 | struct net_device *ndev = bus->priv; | |
109 | struct stmmac_priv *priv = netdev_priv(ndev); | |
110 | unsigned int mii_address = priv->hw->mii.addr; | |
111 | unsigned int mii_data = priv->hw->mii.data; | |
112 | u32 addr, tmp, value = MII_XGMAC_BUSY; | |
113 | int ret; | |
114 | ||
115 | if (phyreg & MII_ADDR_C45) { | |
116 | return -EOPNOTSUPP; | |
117 | } else { | |
118 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | |
119 | if (ret) | |
120 | return ret; | |
121 | } | |
122 | ||
123 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) | |
124 | & priv->hw->mii.clk_csr_mask; | |
125 | value |= phydata | MII_XGMAC_SADDR; | |
126 | value |= MII_XGMAC_WRITE; | |
127 | ||
128 | /* Wait until any existing MII operation is complete */ | |
129 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
130 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | |
131 | return -EBUSY; | |
132 | ||
133 | /* Set the MII address register to write */ | |
134 | writel(addr, priv->ioaddr + mii_address); | |
135 | writel(value, priv->ioaddr + mii_data); | |
136 | ||
137 | /* Wait until any existing MII operation is complete */ | |
138 | return readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
139 | !(tmp & MII_XGMAC_BUSY), 100, 10000); | |
140 | } | |
141 | ||
47dd7a54 GC |
142 | /** |
143 | * stmmac_mdio_read | |
144 | * @bus: points to the mii_bus structure | |
b91dce4c LC |
145 | * @phyaddr: MII addr |
146 | * @phyreg: MII reg | |
47dd7a54 GC |
147 | * Description: it reads data from the MII register from within the phy device. |
148 | * For the 7111 GMAC, we must set the bit 0 in the MII address register while | |
149 | * accessing the PHY registers. | |
150 | * Fortunately, it seems this has no drawback for the 7109 MAC. | |
151 | */ | |
152 | static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) | |
153 | { | |
154 | struct net_device *ndev = bus->priv; | |
155 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 GC |
156 | unsigned int mii_address = priv->hw->mii.addr; |
157 | unsigned int mii_data = priv->hw->mii.data; | |
a5f48adc | 158 | u32 v; |
47dd7a54 | 159 | int data; |
b91dce4c LC |
160 | u32 value = MII_BUSY; |
161 | ||
162 | value |= (phyaddr << priv->hw->mii.addr_shift) | |
163 | & priv->hw->mii.addr_mask; | |
164 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
567be786 | 165 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
166 | & priv->hw->mii.clk_csr_mask; | |
b91dce4c LC |
167 | if (priv->plat->has_gmac4) |
168 | value |= MII_GMAC4_READ; | |
47dd7a54 | 169 | |
a5f48adc LC |
170 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
171 | 100, 10000)) | |
39b401db DS |
172 | return -EBUSY; |
173 | ||
01f1f615 | 174 | writel(value, priv->ioaddr + mii_address); |
39b401db | 175 | |
a5f48adc LC |
176 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
177 | 100, 10000)) | |
39b401db | 178 | return -EBUSY; |
47dd7a54 GC |
179 | |
180 | /* Read the data from the MII data register */ | |
ad01b7d4 | 181 | data = (int)readl(priv->ioaddr + mii_data); |
47dd7a54 GC |
182 | |
183 | return data; | |
184 | } | |
185 | ||
186 | /** | |
187 | * stmmac_mdio_write | |
188 | * @bus: points to the mii_bus structure | |
b91dce4c LC |
189 | * @phyaddr: MII addr |
190 | * @phyreg: MII reg | |
47dd7a54 GC |
191 | * @phydata: phy data |
192 | * Description: it writes the data into the MII register from within the device. | |
193 | */ | |
194 | static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, | |
195 | u16 phydata) | |
196 | { | |
197 | struct net_device *ndev = bus->priv; | |
198 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 GC |
199 | unsigned int mii_address = priv->hw->mii.addr; |
200 | unsigned int mii_data = priv->hw->mii.data; | |
a5f48adc | 201 | u32 v; |
5799fc90 | 202 | u32 value = MII_BUSY; |
47dd7a54 | 203 | |
b91dce4c LC |
204 | value |= (phyaddr << priv->hw->mii.addr_shift) |
205 | & priv->hw->mii.addr_mask; | |
206 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
dfb8fb96 | 207 | |
567be786 | 208 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
209 | & priv->hw->mii.clk_csr_mask; | |
b91dce4c LC |
210 | if (priv->plat->has_gmac4) |
211 | value |= MII_GMAC4_WRITE; | |
5799fc90 KHL |
212 | else |
213 | value |= MII_WRITE; | |
ac1f74a7 AT |
214 | |
215 | /* Wait until any existing MII operation is complete */ | |
a5f48adc LC |
216 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
217 | 100, 10000)) | |
ac1f74a7 AT |
218 | return -EBUSY; |
219 | ||
220 | /* Set the MII address register to write */ | |
221 | writel(phydata, priv->ioaddr + mii_data); | |
222 | writel(value, priv->ioaddr + mii_address); | |
223 | ||
224 | /* Wait until any existing MII operation is complete */ | |
a5f48adc LC |
225 | return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
226 | 100, 10000); | |
ac1f74a7 AT |
227 | } |
228 | ||
47dd7a54 GC |
229 | /** |
230 | * stmmac_mdio_reset | |
231 | * @bus: points to the mii_bus structure | |
232 | * Description: reset the MII bus | |
233 | */ | |
073752aa | 234 | int stmmac_mdio_reset(struct mii_bus *bus) |
47dd7a54 | 235 | { |
30549aab | 236 | #if IS_ENABLED(CONFIG_STMMAC_PLATFORM) |
47dd7a54 GC |
237 | struct net_device *ndev = bus->priv; |
238 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 | 239 | unsigned int mii_address = priv->hw->mii.addr; |
0e076471 SK |
240 | struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data; |
241 | ||
242 | #ifdef CONFIG_OF | |
243 | if (priv->device->of_node) { | |
0e076471 SK |
244 | if (data->reset_gpio < 0) { |
245 | struct device_node *np = priv->device->of_node; | |
efd89b60 | 246 | |
0e076471 SK |
247 | if (!np) |
248 | return 0; | |
249 | ||
250 | data->reset_gpio = of_get_named_gpio(np, | |
251 | "snps,reset-gpio", 0); | |
252 | if (data->reset_gpio < 0) | |
253 | return 0; | |
254 | ||
255 | data->active_low = of_property_read_bool(np, | |
256 | "snps,reset-active-low"); | |
257 | of_property_read_u32_array(np, | |
258 | "snps,reset-delays-us", data->delays, 3); | |
0e076471 | 259 | |
49ce881c JZ |
260 | if (devm_gpio_request(priv->device, data->reset_gpio, |
261 | "mdio-reset")) | |
ae26c1c6 GC |
262 | return 0; |
263 | } | |
0e076471 | 264 | |
ae26c1c6 GC |
265 | gpio_direction_output(data->reset_gpio, |
266 | data->active_low ? 1 : 0); | |
267 | if (data->delays[0]) | |
268 | msleep(DIV_ROUND_UP(data->delays[0], 1000)); | |
892aa01d | 269 | |
ae26c1c6 GC |
270 | gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1); |
271 | if (data->delays[1]) | |
272 | msleep(DIV_ROUND_UP(data->delays[1], 1000)); | |
892aa01d | 273 | |
ae26c1c6 GC |
274 | gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0); |
275 | if (data->delays[2]) | |
276 | msleep(DIV_ROUND_UP(data->delays[2], 1000)); | |
0e076471 SK |
277 | } |
278 | #endif | |
47dd7a54 | 279 | |
0e076471 | 280 | if (data->phy_reset) { |
38ddc59d | 281 | netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n"); |
0e076471 | 282 | data->phy_reset(priv->plat->bsp_priv); |
47dd7a54 GC |
283 | } |
284 | ||
285 | /* This is a workaround for problems with the STE101P PHY. | |
286 | * It doesn't complete its reset until at least one clock cycle | |
8d45e42b | 287 | * on MDC, so perform a dummy mdio read. To be updated for GMAC4 |
ac1f74a7 | 288 | * if needed. |
47dd7a54 | 289 | */ |
ac1f74a7 AT |
290 | if (!priv->plat->has_gmac4) |
291 | writel(0, priv->ioaddr + mii_address); | |
bfab27a1 | 292 | #endif |
47dd7a54 GC |
293 | return 0; |
294 | } | |
295 | ||
296 | /** | |
297 | * stmmac_mdio_register | |
298 | * @ndev: net device structure | |
299 | * Description: it registers the MII bus | |
300 | */ | |
301 | int stmmac_mdio_register(struct net_device *ndev) | |
302 | { | |
303 | int err = 0; | |
304 | struct mii_bus *new_bus; | |
47dd7a54 | 305 | struct stmmac_priv *priv = netdev_priv(ndev); |
36bcfe7d | 306 | struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; |
a7657f12 | 307 | struct device_node *mdio_node = priv->plat->mdio_node; |
fbca1647 | 308 | struct device *dev = ndev->dev.parent; |
6fc21117 | 309 | int addr, found, max_addr; |
47dd7a54 | 310 | |
36bcfe7d GC |
311 | if (!mdio_bus_data) |
312 | return 0; | |
313 | ||
47dd7a54 | 314 | new_bus = mdiobus_alloc(); |
efd89b60 | 315 | if (!new_bus) |
47dd7a54 GC |
316 | return -ENOMEM; |
317 | ||
e7f4dc35 | 318 | if (mdio_bus_data->irqs) |
643d60bf | 319 | memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); |
47dd7a54 | 320 | |
0e076471 SK |
321 | #ifdef CONFIG_OF |
322 | if (priv->device->of_node) | |
323 | mdio_bus_data->reset_gpio = -1; | |
324 | #endif | |
325 | ||
90b9a545 | 326 | new_bus->name = "stmmac"; |
6fc21117 JA |
327 | |
328 | if (priv->plat->has_xgmac) { | |
329 | new_bus->read = &stmmac_xgmac2_mdio_read; | |
330 | new_bus->write = &stmmac_xgmac2_mdio_write; | |
331 | ||
332 | /* Right now only C22 phys are supported */ | |
333 | max_addr = MII_XGMAC_MAX_C22ADDR + 1; | |
334 | ||
335 | /* Check if DT specified an unsupported phy addr */ | |
336 | if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR) | |
337 | dev_err(dev, "Unsupported phy_addr (max=%d)\n", | |
338 | MII_XGMAC_MAX_C22ADDR); | |
339 | } else { | |
340 | new_bus->read = &stmmac_mdio_read; | |
341 | new_bus->write = &stmmac_mdio_write; | |
342 | max_addr = PHY_MAX_ADDR; | |
343 | } | |
ac1f74a7 | 344 | |
47dd7a54 | 345 | new_bus->reset = &stmmac_mdio_reset; |
db8857bf | 346 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", |
ceb69499 | 347 | new_bus->name, priv->plat->bus_id); |
47dd7a54 | 348 | new_bus->priv = ndev; |
36bcfe7d | 349 | new_bus->phy_mask = mdio_bus_data->phy_mask; |
47dd7a54 | 350 | new_bus->parent = priv->device; |
e34d6569 | 351 | |
00e798c7 | 352 | err = of_mdiobus_register(new_bus, mdio_node); |
47dd7a54 | 353 | if (err != 0) { |
fbca1647 | 354 | dev_err(dev, "Cannot register the MDIO bus\n"); |
47dd7a54 GC |
355 | goto bus_register_fail; |
356 | } | |
357 | ||
cc2fa619 PR |
358 | if (priv->plat->phy_node || mdio_node) |
359 | goto bus_register_done; | |
360 | ||
47dd7a54 | 361 | found = 0; |
6fc21117 | 362 | for (addr = 0; addr < max_addr; addr++) { |
7f854420 | 363 | struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); |
cc26dc67 LC |
364 | |
365 | if (!phydev) | |
366 | continue; | |
367 | ||
368 | /* | |
369 | * If an IRQ was provided to be assigned after | |
370 | * the bus probe, do it here. | |
371 | */ | |
372 | if (!mdio_bus_data->irqs && | |
373 | (mdio_bus_data->probed_phy_irq > 0)) { | |
374 | new_bus->irq[addr] = mdio_bus_data->probed_phy_irq; | |
375 | phydev->irq = mdio_bus_data->probed_phy_irq; | |
376 | } | |
efd89b60 | 377 | |
cc26dc67 LC |
378 | /* |
379 | * If we're going to bind the MAC to this PHY bus, | |
380 | * and no PHY number was provided to the MAC, | |
381 | * use the one probed here. | |
382 | */ | |
383 | if (priv->plat->phy_addr == -1) | |
384 | priv->plat->phy_addr = addr; | |
385 | ||
fbca1647 | 386 | phy_attached_info(phydev); |
cc26dc67 | 387 | found = 1; |
47dd7a54 GC |
388 | } |
389 | ||
e34d6569 | 390 | if (!found && !mdio_node) { |
fbca1647 | 391 | dev_warn(dev, "No PHY found\n"); |
3955b22b GC |
392 | mdiobus_unregister(new_bus); |
393 | mdiobus_free(new_bus); | |
394 | return -ENODEV; | |
395 | } | |
396 | ||
cc2fa619 | 397 | bus_register_done: |
3955b22b | 398 | priv->mii = new_bus; |
47dd7a54 GC |
399 | |
400 | return 0; | |
36bcfe7d | 401 | |
47dd7a54 | 402 | bus_register_fail: |
36bcfe7d | 403 | mdiobus_free(new_bus); |
47dd7a54 GC |
404 | return err; |
405 | } | |
406 | ||
407 | /** | |
408 | * stmmac_mdio_unregister | |
409 | * @ndev: net device structure | |
410 | * Description: it unregisters the MII bus | |
411 | */ | |
412 | int stmmac_mdio_unregister(struct net_device *ndev) | |
413 | { | |
414 | struct stmmac_priv *priv = netdev_priv(ndev); | |
415 | ||
a5cf5ce9 SK |
416 | if (!priv->mii) |
417 | return 0; | |
418 | ||
47dd7a54 GC |
419 | mdiobus_unregister(priv->mii); |
420 | priv->mii->priv = NULL; | |
36bcfe7d GC |
421 | mdiobus_free(priv->mii); |
422 | priv->mii = NULL; | |
47dd7a54 GC |
423 | |
424 | return 0; | |
425 | } |