]>
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 | ||
7c86f20d | 13 | #include <linux/gpio/consumer.h> |
bbf89284 | 14 | #include <linux/io.h> |
a5f48adc | 15 | #include <linux/iopoll.h> |
47dd7a54 | 16 | #include <linux/mii.h> |
e34d6569 | 17 | #include <linux/of_mdio.h> |
5ec55823 | 18 | #include <linux/pm_runtime.h> |
bbf89284 | 19 | #include <linux/phy.h> |
42a90766 | 20 | #include <linux/property.h> |
bbf89284 | 21 | #include <linux/slab.h> |
47dd7a54 | 22 | |
6fc21117 | 23 | #include "dwxgmac2.h" |
47dd7a54 GC |
24 | #include "stmmac.h" |
25 | ||
26 | #define MII_BUSY 0x00000001 | |
27 | #define MII_WRITE 0x00000002 | |
d4117d63 | 28 | #define MII_DATA_MASK GENMASK(15, 0) |
47dd7a54 | 29 | |
ac1f74a7 AT |
30 | /* GMAC4 defines */ |
31 | #define MII_GMAC4_GOC_SHIFT 2 | |
d4117d63 | 32 | #define MII_GMAC4_REG_ADDR_SHIFT 16 |
ac1f74a7 AT |
33 | #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT) |
34 | #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT) | |
d4117d63 | 35 | #define MII_GMAC4_C45E BIT(1) |
ac1f74a7 | 36 | |
6fc21117 JA |
37 | /* XGMAC defines */ |
38 | #define MII_XGMAC_SADDR BIT(18) | |
39 | #define MII_XGMAC_CMD_SHIFT 16 | |
40 | #define MII_XGMAC_WRITE (1 << MII_XGMAC_CMD_SHIFT) | |
41 | #define MII_XGMAC_READ (3 << MII_XGMAC_CMD_SHIFT) | |
42 | #define MII_XGMAC_BUSY BIT(22) | |
43 | #define MII_XGMAC_MAX_C22ADDR 3 | |
44 | #define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0) | |
04d1190a JA |
45 | #define MII_XGMAC_PA_SHIFT 16 |
46 | #define MII_XGMAC_DA_SHIFT 21 | |
47 | ||
48 | static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, | |
49 | int phyreg, u32 *hw_addr) | |
50 | { | |
51 | u32 tmp; | |
52 | ||
53 | /* Set port as Clause 45 */ | |
54 | tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); | |
55 | tmp &= ~BIT(phyaddr); | |
56 | writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); | |
57 | ||
58 | *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff); | |
59 | *hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT; | |
60 | return 0; | |
61 | } | |
6fc21117 JA |
62 | |
63 | static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, | |
64 | int phyreg, u32 *hw_addr) | |
65 | { | |
6fc21117 JA |
66 | u32 tmp; |
67 | ||
68 | /* HW does not support C22 addr >= 4 */ | |
69 | if (phyaddr > MII_XGMAC_MAX_C22ADDR) | |
70 | return -ENODEV; | |
6fc21117 JA |
71 | |
72 | /* Set port as Clause 22 */ | |
73 | tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); | |
74 | tmp &= ~MII_XGMAC_C22P_MASK; | |
75 | tmp |= BIT(phyaddr); | |
76 | writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); | |
77 | ||
04d1190a | 78 | *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f); |
6fc21117 JA |
79 | return 0; |
80 | } | |
81 | ||
82 | static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) | |
83 | { | |
84 | struct net_device *ndev = bus->priv; | |
85 | struct stmmac_priv *priv = netdev_priv(ndev); | |
86 | unsigned int mii_address = priv->hw->mii.addr; | |
87 | unsigned int mii_data = priv->hw->mii.data; | |
88 | u32 tmp, addr, value = MII_XGMAC_BUSY; | |
89 | int ret; | |
90 | ||
5ec55823 JZ |
91 | ret = pm_runtime_get_sync(priv->device); |
92 | if (ret < 0) { | |
93 | pm_runtime_put_noidle(priv->device); | |
94 | return ret; | |
95 | } | |
96 | ||
04d1190a JA |
97 | /* Wait until any existing MII operation is complete */ |
98 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
99 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
100 | ret = -EBUSY; | |
101 | goto err_disable_clks; | |
102 | } | |
04d1190a | 103 | |
6fc21117 | 104 | if (phyreg & MII_ADDR_C45) { |
04d1190a JA |
105 | phyreg &= ~MII_ADDR_C45; |
106 | ||
107 | ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); | |
108 | if (ret) | |
5ec55823 | 109 | goto err_disable_clks; |
6fc21117 JA |
110 | } else { |
111 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | |
112 | if (ret) | |
5ec55823 | 113 | goto err_disable_clks; |
04d1190a JA |
114 | |
115 | value |= MII_XGMAC_SADDR; | |
6fc21117 JA |
116 | } |
117 | ||
118 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) | |
119 | & priv->hw->mii.clk_csr_mask; | |
04d1190a | 120 | value |= MII_XGMAC_READ; |
6fc21117 JA |
121 | |
122 | /* Wait until any existing MII operation is complete */ | |
123 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
124 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
125 | ret = -EBUSY; | |
126 | goto err_disable_clks; | |
127 | } | |
6fc21117 JA |
128 | |
129 | /* Set the MII address register to read */ | |
130 | writel(addr, priv->ioaddr + mii_address); | |
131 | writel(value, priv->ioaddr + mii_data); | |
132 | ||
133 | /* Wait until any existing MII operation is complete */ | |
134 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
135 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
136 | ret = -EBUSY; | |
137 | goto err_disable_clks; | |
138 | } | |
6fc21117 JA |
139 | |
140 | /* Read the data from the MII data register */ | |
5ec55823 JZ |
141 | ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0); |
142 | ||
143 | err_disable_clks: | |
144 | pm_runtime_put(priv->device); | |
145 | ||
146 | return ret; | |
6fc21117 JA |
147 | } |
148 | ||
149 | static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, | |
150 | int phyreg, u16 phydata) | |
151 | { | |
152 | struct net_device *ndev = bus->priv; | |
153 | struct stmmac_priv *priv = netdev_priv(ndev); | |
154 | unsigned int mii_address = priv->hw->mii.addr; | |
155 | unsigned int mii_data = priv->hw->mii.data; | |
156 | u32 addr, tmp, value = MII_XGMAC_BUSY; | |
157 | int ret; | |
158 | ||
5ec55823 JZ |
159 | ret = pm_runtime_get_sync(priv->device); |
160 | if (ret < 0) { | |
161 | pm_runtime_put_noidle(priv->device); | |
162 | return ret; | |
163 | } | |
164 | ||
04d1190a JA |
165 | /* Wait until any existing MII operation is complete */ |
166 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
167 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
168 | ret = -EBUSY; | |
169 | goto err_disable_clks; | |
170 | } | |
04d1190a | 171 | |
6fc21117 | 172 | if (phyreg & MII_ADDR_C45) { |
04d1190a JA |
173 | phyreg &= ~MII_ADDR_C45; |
174 | ||
175 | ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); | |
176 | if (ret) | |
5ec55823 | 177 | goto err_disable_clks; |
6fc21117 JA |
178 | } else { |
179 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | |
180 | if (ret) | |
5ec55823 | 181 | goto err_disable_clks; |
04d1190a JA |
182 | |
183 | value |= MII_XGMAC_SADDR; | |
6fc21117 JA |
184 | } |
185 | ||
186 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) | |
187 | & priv->hw->mii.clk_csr_mask; | |
04d1190a | 188 | value |= phydata; |
6fc21117 JA |
189 | value |= MII_XGMAC_WRITE; |
190 | ||
191 | /* Wait until any existing MII operation is complete */ | |
192 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
193 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
194 | ret = -EBUSY; | |
195 | goto err_disable_clks; | |
196 | } | |
6fc21117 JA |
197 | |
198 | /* Set the MII address register to write */ | |
199 | writel(addr, priv->ioaddr + mii_address); | |
200 | writel(value, priv->ioaddr + mii_data); | |
201 | ||
202 | /* Wait until any existing MII operation is complete */ | |
5ec55823 JZ |
203 | ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
204 | !(tmp & MII_XGMAC_BUSY), 100, 10000); | |
205 | ||
206 | err_disable_clks: | |
207 | pm_runtime_put(priv->device); | |
208 | ||
209 | return ret; | |
6fc21117 JA |
210 | } |
211 | ||
47dd7a54 GC |
212 | /** |
213 | * stmmac_mdio_read | |
214 | * @bus: points to the mii_bus structure | |
b91dce4c LC |
215 | * @phyaddr: MII addr |
216 | * @phyreg: MII reg | |
47dd7a54 GC |
217 | * Description: it reads data from the MII register from within the phy device. |
218 | * For the 7111 GMAC, we must set the bit 0 in the MII address register while | |
219 | * accessing the PHY registers. | |
220 | * Fortunately, it seems this has no drawback for the 7109 MAC. | |
221 | */ | |
222 | static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) | |
223 | { | |
224 | struct net_device *ndev = bus->priv; | |
225 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 GC |
226 | unsigned int mii_address = priv->hw->mii.addr; |
227 | unsigned int mii_data = priv->hw->mii.data; | |
b91dce4c | 228 | u32 value = MII_BUSY; |
d4117d63 KHL |
229 | int data = 0; |
230 | u32 v; | |
b91dce4c | 231 | |
5ec55823 JZ |
232 | data = pm_runtime_get_sync(priv->device); |
233 | if (data < 0) { | |
234 | pm_runtime_put_noidle(priv->device); | |
235 | return data; | |
236 | } | |
237 | ||
b91dce4c LC |
238 | value |= (phyaddr << priv->hw->mii.addr_shift) |
239 | & priv->hw->mii.addr_mask; | |
240 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
567be786 | 241 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
242 | & priv->hw->mii.clk_csr_mask; | |
d4117d63 | 243 | if (priv->plat->has_gmac4) { |
b91dce4c | 244 | value |= MII_GMAC4_READ; |
d4117d63 KHL |
245 | if (phyreg & MII_ADDR_C45) { |
246 | value |= MII_GMAC4_C45E; | |
247 | value &= ~priv->hw->mii.reg_mask; | |
248 | value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << | |
249 | priv->hw->mii.reg_shift) & | |
250 | priv->hw->mii.reg_mask; | |
251 | ||
252 | data |= (phyreg & MII_REGADDR_C45_MASK) << | |
253 | MII_GMAC4_REG_ADDR_SHIFT; | |
254 | } | |
255 | } | |
47dd7a54 | 256 | |
a5f48adc | 257 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
5ec55823 JZ |
258 | 100, 10000)) { |
259 | data = -EBUSY; | |
260 | goto err_disable_clks; | |
261 | } | |
39b401db | 262 | |
d4117d63 | 263 | writel(data, priv->ioaddr + mii_data); |
01f1f615 | 264 | writel(value, priv->ioaddr + mii_address); |
39b401db | 265 | |
a5f48adc | 266 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
5ec55823 JZ |
267 | 100, 10000)) { |
268 | data = -EBUSY; | |
269 | goto err_disable_clks; | |
270 | } | |
47dd7a54 GC |
271 | |
272 | /* Read the data from the MII data register */ | |
d4117d63 | 273 | data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK; |
47dd7a54 | 274 | |
5ec55823 JZ |
275 | err_disable_clks: |
276 | pm_runtime_put(priv->device); | |
277 | ||
47dd7a54 GC |
278 | return data; |
279 | } | |
280 | ||
281 | /** | |
282 | * stmmac_mdio_write | |
283 | * @bus: points to the mii_bus structure | |
b91dce4c LC |
284 | * @phyaddr: MII addr |
285 | * @phyreg: MII reg | |
47dd7a54 GC |
286 | * @phydata: phy data |
287 | * Description: it writes the data into the MII register from within the device. | |
288 | */ | |
289 | static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, | |
290 | u16 phydata) | |
291 | { | |
292 | struct net_device *ndev = bus->priv; | |
293 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 GC |
294 | unsigned int mii_address = priv->hw->mii.addr; |
295 | unsigned int mii_data = priv->hw->mii.data; | |
5ec55823 | 296 | int ret, data = phydata; |
5799fc90 | 297 | u32 value = MII_BUSY; |
d4117d63 | 298 | u32 v; |
47dd7a54 | 299 | |
5ec55823 JZ |
300 | ret = pm_runtime_get_sync(priv->device); |
301 | if (ret < 0) { | |
302 | pm_runtime_put_noidle(priv->device); | |
303 | return ret; | |
304 | } | |
305 | ||
b91dce4c LC |
306 | value |= (phyaddr << priv->hw->mii.addr_shift) |
307 | & priv->hw->mii.addr_mask; | |
308 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
dfb8fb96 | 309 | |
567be786 | 310 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
311 | & priv->hw->mii.clk_csr_mask; | |
d4117d63 | 312 | if (priv->plat->has_gmac4) { |
b91dce4c | 313 | value |= MII_GMAC4_WRITE; |
d4117d63 KHL |
314 | if (phyreg & MII_ADDR_C45) { |
315 | value |= MII_GMAC4_C45E; | |
316 | value &= ~priv->hw->mii.reg_mask; | |
317 | value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << | |
318 | priv->hw->mii.reg_shift) & | |
319 | priv->hw->mii.reg_mask; | |
320 | ||
321 | data |= (phyreg & MII_REGADDR_C45_MASK) << | |
322 | MII_GMAC4_REG_ADDR_SHIFT; | |
323 | } | |
324 | } else { | |
5799fc90 | 325 | value |= MII_WRITE; |
d4117d63 | 326 | } |
ac1f74a7 AT |
327 | |
328 | /* Wait until any existing MII operation is complete */ | |
a5f48adc | 329 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
5ec55823 JZ |
330 | 100, 10000)) { |
331 | ret = -EBUSY; | |
332 | goto err_disable_clks; | |
333 | } | |
ac1f74a7 AT |
334 | |
335 | /* Set the MII address register to write */ | |
d4117d63 | 336 | writel(data, priv->ioaddr + mii_data); |
ac1f74a7 AT |
337 | writel(value, priv->ioaddr + mii_address); |
338 | ||
339 | /* Wait until any existing MII operation is complete */ | |
5ec55823 JZ |
340 | ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
341 | 100, 10000); | |
342 | ||
343 | err_disable_clks: | |
344 | pm_runtime_put(priv->device); | |
345 | ||
346 | return ret; | |
ac1f74a7 AT |
347 | } |
348 | ||
47dd7a54 GC |
349 | /** |
350 | * stmmac_mdio_reset | |
351 | * @bus: points to the mii_bus structure | |
352 | * Description: reset the MII bus | |
353 | */ | |
073752aa | 354 | int stmmac_mdio_reset(struct mii_bus *bus) |
47dd7a54 | 355 | { |
30549aab | 356 | #if IS_ENABLED(CONFIG_STMMAC_PLATFORM) |
47dd7a54 GC |
357 | struct net_device *ndev = bus->priv; |
358 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 | 359 | unsigned int mii_address = priv->hw->mii.addr; |
0e076471 SK |
360 | |
361 | #ifdef CONFIG_OF | |
362 | if (priv->device->of_node) { | |
7c86f20d | 363 | struct gpio_desc *reset_gpio; |
84ce4d0f | 364 | u32 delays[3] = { 0, 0, 0 }; |
7c86f20d | 365 | |
7e770b25 MB |
366 | reset_gpio = devm_gpiod_get_optional(priv->device, |
367 | "snps,reset", | |
368 | GPIOD_OUT_LOW); | |
369 | if (IS_ERR(reset_gpio)) | |
370 | return PTR_ERR(reset_gpio); | |
371 | ||
cc5e92c2 MB |
372 | device_property_read_u32_array(priv->device, |
373 | "snps,reset-delays-us", | |
374 | delays, ARRAY_SIZE(delays)); | |
0e076471 | 375 | |
ce4ab73a MB |
376 | if (delays[0]) |
377 | msleep(DIV_ROUND_UP(delays[0], 1000)); | |
892aa01d | 378 | |
7c86f20d | 379 | gpiod_set_value_cansleep(reset_gpio, 1); |
ce4ab73a MB |
380 | if (delays[1]) |
381 | msleep(DIV_ROUND_UP(delays[1], 1000)); | |
892aa01d | 382 | |
7c86f20d | 383 | gpiod_set_value_cansleep(reset_gpio, 0); |
ce4ab73a MB |
384 | if (delays[2]) |
385 | msleep(DIV_ROUND_UP(delays[2], 1000)); | |
0e076471 SK |
386 | } |
387 | #endif | |
47dd7a54 | 388 | |
47dd7a54 GC |
389 | /* This is a workaround for problems with the STE101P PHY. |
390 | * It doesn't complete its reset until at least one clock cycle | |
8d45e42b | 391 | * on MDC, so perform a dummy mdio read. To be updated for GMAC4 |
ac1f74a7 | 392 | * if needed. |
47dd7a54 | 393 | */ |
ac1f74a7 AT |
394 | if (!priv->plat->has_gmac4) |
395 | writel(0, priv->ioaddr + mii_address); | |
bfab27a1 | 396 | #endif |
47dd7a54 GC |
397 | return 0; |
398 | } | |
399 | ||
597a68ce VW |
400 | int stmmac_xpcs_setup(struct mii_bus *bus) |
401 | { | |
597a68ce | 402 | struct net_device *ndev = bus->priv; |
597a68ce | 403 | struct mdio_device *mdiodev; |
47538dbe VO |
404 | struct stmmac_priv *priv; |
405 | struct dw_xpcs *xpcs; | |
406 | int mode, addr; | |
597a68ce VW |
407 | |
408 | priv = netdev_priv(ndev); | |
409 | mode = priv->plat->phy_interface; | |
410 | ||
411 | /* Try to probe the XPCS by scanning all addresses. */ | |
412 | for (addr = 0; addr < PHY_MAX_ADDR; addr++) { | |
413 | mdiodev = mdio_device_create(bus, addr); | |
414 | if (IS_ERR(mdiodev)) | |
415 | continue; | |
416 | ||
417 | xpcs = xpcs_create(mdiodev, mode); | |
418 | if (IS_ERR_OR_NULL(xpcs)) { | |
419 | mdio_device_free(mdiodev); | |
420 | continue; | |
421 | } | |
422 | ||
423 | priv->hw->xpcs = xpcs; | |
424 | break; | |
425 | } | |
426 | ||
427 | if (!priv->hw->xpcs) { | |
428 | dev_warn(priv->device, "No xPCS found\n"); | |
429 | return -ENODEV; | |
430 | } | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
47dd7a54 GC |
435 | /** |
436 | * stmmac_mdio_register | |
437 | * @ndev: net device structure | |
438 | * Description: it registers the MII bus | |
439 | */ | |
440 | int stmmac_mdio_register(struct net_device *ndev) | |
441 | { | |
442 | int err = 0; | |
443 | struct mii_bus *new_bus; | |
47dd7a54 | 444 | struct stmmac_priv *priv = netdev_priv(ndev); |
36bcfe7d | 445 | struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; |
a7657f12 | 446 | struct device_node *mdio_node = priv->plat->mdio_node; |
fbca1647 | 447 | struct device *dev = ndev->dev.parent; |
6fc21117 | 448 | int addr, found, max_addr; |
47dd7a54 | 449 | |
36bcfe7d GC |
450 | if (!mdio_bus_data) |
451 | return 0; | |
452 | ||
47dd7a54 | 453 | new_bus = mdiobus_alloc(); |
efd89b60 | 454 | if (!new_bus) |
47dd7a54 GC |
455 | return -ENOMEM; |
456 | ||
e7f4dc35 | 457 | if (mdio_bus_data->irqs) |
643d60bf | 458 | memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); |
47dd7a54 | 459 | |
90b9a545 | 460 | new_bus->name = "stmmac"; |
6fc21117 | 461 | |
523437d7 WVK |
462 | if (priv->plat->has_gmac4) |
463 | new_bus->probe_capabilities = MDIOBUS_C22_C45; | |
464 | ||
6fc21117 JA |
465 | if (priv->plat->has_xgmac) { |
466 | new_bus->read = &stmmac_xgmac2_mdio_read; | |
467 | new_bus->write = &stmmac_xgmac2_mdio_write; | |
468 | ||
469 | /* Right now only C22 phys are supported */ | |
470 | max_addr = MII_XGMAC_MAX_C22ADDR + 1; | |
471 | ||
472 | /* Check if DT specified an unsupported phy addr */ | |
473 | if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR) | |
474 | dev_err(dev, "Unsupported phy_addr (max=%d)\n", | |
475 | MII_XGMAC_MAX_C22ADDR); | |
476 | } else { | |
477 | new_bus->read = &stmmac_mdio_read; | |
478 | new_bus->write = &stmmac_mdio_write; | |
479 | max_addr = PHY_MAX_ADDR; | |
480 | } | |
ac1f74a7 | 481 | |
1a981c05 TR |
482 | if (mdio_bus_data->needs_reset) |
483 | new_bus->reset = &stmmac_mdio_reset; | |
484 | ||
db8857bf | 485 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", |
ceb69499 | 486 | new_bus->name, priv->plat->bus_id); |
47dd7a54 | 487 | new_bus->priv = ndev; |
36bcfe7d | 488 | new_bus->phy_mask = mdio_bus_data->phy_mask; |
47dd7a54 | 489 | new_bus->parent = priv->device; |
e34d6569 | 490 | |
00e798c7 | 491 | err = of_mdiobus_register(new_bus, mdio_node); |
47dd7a54 | 492 | if (err != 0) { |
fbca1647 | 493 | dev_err(dev, "Cannot register the MDIO bus\n"); |
47dd7a54 GC |
494 | goto bus_register_fail; |
495 | } | |
496 | ||
04d1190a JA |
497 | /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ |
498 | if (priv->plat->has_xgmac) | |
499 | stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45); | |
500 | ||
cc2fa619 PR |
501 | if (priv->plat->phy_node || mdio_node) |
502 | goto bus_register_done; | |
503 | ||
47dd7a54 | 504 | found = 0; |
6fc21117 | 505 | for (addr = 0; addr < max_addr; addr++) { |
7f854420 | 506 | struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); |
cc26dc67 LC |
507 | |
508 | if (!phydev) | |
509 | continue; | |
510 | ||
511 | /* | |
512 | * If an IRQ was provided to be assigned after | |
513 | * the bus probe, do it here. | |
514 | */ | |
515 | if (!mdio_bus_data->irqs && | |
516 | (mdio_bus_data->probed_phy_irq > 0)) { | |
517 | new_bus->irq[addr] = mdio_bus_data->probed_phy_irq; | |
518 | phydev->irq = mdio_bus_data->probed_phy_irq; | |
519 | } | |
efd89b60 | 520 | |
cc26dc67 LC |
521 | /* |
522 | * If we're going to bind the MAC to this PHY bus, | |
523 | * and no PHY number was provided to the MAC, | |
524 | * use the one probed here. | |
525 | */ | |
526 | if (priv->plat->phy_addr == -1) | |
527 | priv->plat->phy_addr = addr; | |
528 | ||
fbca1647 | 529 | phy_attached_info(phydev); |
cc26dc67 | 530 | found = 1; |
47dd7a54 GC |
531 | } |
532 | ||
4751d2aa VO |
533 | if (!found && !mdio_node) { |
534 | dev_warn(dev, "No PHY found\n"); | |
535 | err = -ENODEV; | |
536 | goto no_phy_found; | |
537 | } | |
538 | ||
cc2fa619 | 539 | bus_register_done: |
3955b22b | 540 | priv->mii = new_bus; |
47dd7a54 GC |
541 | |
542 | return 0; | |
36bcfe7d | 543 | |
4751d2aa VO |
544 | no_phy_found: |
545 | mdiobus_unregister(new_bus); | |
47dd7a54 | 546 | bus_register_fail: |
36bcfe7d | 547 | mdiobus_free(new_bus); |
47dd7a54 GC |
548 | return err; |
549 | } | |
550 | ||
551 | /** | |
552 | * stmmac_mdio_unregister | |
553 | * @ndev: net device structure | |
554 | * Description: it unregisters the MII bus | |
555 | */ | |
556 | int stmmac_mdio_unregister(struct net_device *ndev) | |
557 | { | |
558 | struct stmmac_priv *priv = netdev_priv(ndev); | |
559 | ||
a5cf5ce9 SK |
560 | if (!priv->mii) |
561 | return 0; | |
562 | ||
2cac15da | 563 | if (priv->hw->xpcs) { |
11059740 VO |
564 | mdio_device_free(priv->hw->xpcs->mdiodev); |
565 | xpcs_destroy(priv->hw->xpcs); | |
2cac15da VO |
566 | } |
567 | ||
47dd7a54 GC |
568 | mdiobus_unregister(priv->mii); |
569 | priv->mii->priv = NULL; | |
36bcfe7d GC |
570 | mdiobus_free(priv->mii); |
571 | priv->mii = NULL; | |
47dd7a54 GC |
572 | |
573 | return 0; | |
574 | } |