]>
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 | ||
5b0a447e AL |
48 | static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, |
49 | int devad, int phyreg, u32 *hw_addr) | |
04d1190a JA |
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); | |
5b0a447e | 59 | *hw_addr |= devad << MII_XGMAC_DA_SHIFT; |
04d1190a | 60 | } |
6fc21117 | 61 | |
5b0a447e AL |
62 | static void stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, |
63 | int phyreg, u32 *hw_addr) | |
6fc21117 | 64 | { |
10857e67 RT |
65 | u32 tmp = 0; |
66 | ||
67 | if (priv->synopsys_id < DWXGMAC_CORE_2_20) { | |
68 | /* Until ver 2.20 XGMAC does not support C22 addr >= 4. Those | |
69 | * bits above bit 3 of XGMAC_MDIO_C22P register are reserved. | |
70 | */ | |
71 | tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); | |
72 | tmp &= ~MII_XGMAC_C22P_MASK; | |
73 | } | |
6fc21117 | 74 | /* Set port as Clause 22 */ |
6fc21117 JA |
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 | } |
80 | ||
5b0a447e AL |
81 | static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr, |
82 | u32 value) | |
6fc21117 | 83 | { |
6fc21117 JA |
84 | unsigned int mii_address = priv->hw->mii.addr; |
85 | unsigned int mii_data = priv->hw->mii.data; | |
5b0a447e | 86 | u32 tmp; |
6fc21117 JA |
87 | int ret; |
88 | ||
e2d0acd4 MC |
89 | ret = pm_runtime_resume_and_get(priv->device); |
90 | if (ret < 0) | |
5ec55823 | 91 | return ret; |
5ec55823 | 92 | |
04d1190a JA |
93 | /* Wait until any existing MII operation is complete */ |
94 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
95 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
96 | ret = -EBUSY; | |
97 | goto err_disable_clks; | |
98 | } | |
04d1190a | 99 | |
6fc21117 JA |
100 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
101 | & priv->hw->mii.clk_csr_mask; | |
04d1190a | 102 | value |= MII_XGMAC_READ; |
6fc21117 JA |
103 | |
104 | /* Wait until any existing MII operation is complete */ | |
105 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
106 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
107 | ret = -EBUSY; | |
108 | goto err_disable_clks; | |
109 | } | |
6fc21117 JA |
110 | |
111 | /* Set the MII address register to read */ | |
112 | writel(addr, priv->ioaddr + mii_address); | |
113 | writel(value, priv->ioaddr + mii_data); | |
114 | ||
115 | /* Wait until any existing MII operation is complete */ | |
116 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
117 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
118 | ret = -EBUSY; | |
119 | goto err_disable_clks; | |
120 | } | |
6fc21117 JA |
121 | |
122 | /* Read the data from the MII data register */ | |
5ec55823 JZ |
123 | ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0); |
124 | ||
125 | err_disable_clks: | |
126 | pm_runtime_put(priv->device); | |
127 | ||
128 | return ret; | |
6fc21117 JA |
129 | } |
130 | ||
5b0a447e AL |
131 | static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr, |
132 | int phyreg) | |
6fc21117 JA |
133 | { |
134 | struct net_device *ndev = bus->priv; | |
5b0a447e AL |
135 | struct stmmac_priv *priv; |
136 | u32 addr; | |
137 | ||
138 | priv = netdev_priv(ndev); | |
139 | ||
10857e67 RT |
140 | /* Until ver 2.20 XGMAC does not support C22 addr >= 4 */ |
141 | if (priv->synopsys_id < DWXGMAC_CORE_2_20 && | |
142 | phyaddr > MII_XGMAC_MAX_C22ADDR) | |
5b0a447e AL |
143 | return -ENODEV; |
144 | ||
145 | stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | |
146 | ||
147 | return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY); | |
148 | } | |
149 | ||
150 | static int stmmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr, | |
151 | int devad, int phyreg) | |
152 | { | |
153 | struct net_device *ndev = bus->priv; | |
154 | struct stmmac_priv *priv; | |
155 | u32 addr; | |
156 | ||
157 | priv = netdev_priv(ndev); | |
158 | ||
159 | stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr); | |
160 | ||
161 | return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY); | |
162 | } | |
163 | ||
164 | static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr, | |
165 | u32 value, u16 phydata) | |
166 | { | |
6fc21117 JA |
167 | unsigned int mii_address = priv->hw->mii.addr; |
168 | unsigned int mii_data = priv->hw->mii.data; | |
5b0a447e | 169 | u32 tmp; |
6fc21117 JA |
170 | int ret; |
171 | ||
e2d0acd4 MC |
172 | ret = pm_runtime_resume_and_get(priv->device); |
173 | if (ret < 0) | |
5ec55823 | 174 | return ret; |
5ec55823 | 175 | |
04d1190a JA |
176 | /* Wait until any existing MII operation is complete */ |
177 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
178 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
179 | ret = -EBUSY; | |
180 | goto err_disable_clks; | |
181 | } | |
04d1190a | 182 | |
6fc21117 JA |
183 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
184 | & priv->hw->mii.clk_csr_mask; | |
04d1190a | 185 | value |= phydata; |
6fc21117 JA |
186 | value |= MII_XGMAC_WRITE; |
187 | ||
188 | /* Wait until any existing MII operation is complete */ | |
189 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | |
5ec55823 JZ |
190 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
191 | ret = -EBUSY; | |
192 | goto err_disable_clks; | |
193 | } | |
6fc21117 JA |
194 | |
195 | /* Set the MII address register to write */ | |
196 | writel(addr, priv->ioaddr + mii_address); | |
197 | writel(value, priv->ioaddr + mii_data); | |
198 | ||
199 | /* Wait until any existing MII operation is complete */ | |
5ec55823 JZ |
200 | ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
201 | !(tmp & MII_XGMAC_BUSY), 100, 10000); | |
202 | ||
203 | err_disable_clks: | |
204 | pm_runtime_put(priv->device); | |
205 | ||
206 | return ret; | |
6fc21117 JA |
207 | } |
208 | ||
5b0a447e AL |
209 | static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr, |
210 | int phyreg, u16 phydata) | |
211 | { | |
212 | struct net_device *ndev = bus->priv; | |
213 | struct stmmac_priv *priv; | |
214 | u32 addr; | |
215 | ||
216 | priv = netdev_priv(ndev); | |
217 | ||
10857e67 RT |
218 | /* Until ver 2.20 XGMAC does not support C22 addr >= 4 */ |
219 | if (priv->synopsys_id < DWXGMAC_CORE_2_20 && | |
220 | phyaddr > MII_XGMAC_MAX_C22ADDR) | |
5b0a447e AL |
221 | return -ENODEV; |
222 | ||
223 | stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | |
224 | ||
225 | return stmmac_xgmac2_mdio_write(priv, addr, | |
226 | MII_XGMAC_BUSY | MII_XGMAC_SADDR, phydata); | |
227 | } | |
228 | ||
229 | static int stmmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr, | |
230 | int devad, int phyreg, u16 phydata) | |
231 | { | |
232 | struct net_device *ndev = bus->priv; | |
233 | struct stmmac_priv *priv; | |
234 | u32 addr; | |
235 | ||
236 | priv = netdev_priv(ndev); | |
237 | ||
238 | stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr); | |
239 | ||
240 | return stmmac_xgmac2_mdio_write(priv, addr, MII_XGMAC_BUSY, | |
241 | phydata); | |
242 | } | |
243 | ||
3c7826d0 AL |
244 | static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value) |
245 | { | |
246 | unsigned int mii_address = priv->hw->mii.addr; | |
247 | unsigned int mii_data = priv->hw->mii.data; | |
248 | u32 v; | |
249 | ||
250 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), | |
251 | 100, 10000)) | |
252 | return -EBUSY; | |
253 | ||
254 | writel(data, priv->ioaddr + mii_data); | |
255 | writel(value, priv->ioaddr + mii_address); | |
256 | ||
257 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), | |
258 | 100, 10000)) | |
259 | return -EBUSY; | |
260 | ||
261 | /* Read the data from the MII data register */ | |
262 | return readl(priv->ioaddr + mii_data) & MII_DATA_MASK; | |
263 | } | |
264 | ||
47dd7a54 | 265 | /** |
3c7826d0 | 266 | * stmmac_mdio_read_c22 |
47dd7a54 | 267 | * @bus: points to the mii_bus structure |
b91dce4c LC |
268 | * @phyaddr: MII addr |
269 | * @phyreg: MII reg | |
47dd7a54 GC |
270 | * Description: it reads data from the MII register from within the phy device. |
271 | * For the 7111 GMAC, we must set the bit 0 in the MII address register while | |
272 | * accessing the PHY registers. | |
273 | * Fortunately, it seems this has no drawback for the 7109 MAC. | |
274 | */ | |
3c7826d0 | 275 | static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg) |
47dd7a54 GC |
276 | { |
277 | struct net_device *ndev = bus->priv; | |
278 | struct stmmac_priv *priv = netdev_priv(ndev); | |
b91dce4c | 279 | u32 value = MII_BUSY; |
d4117d63 | 280 | int data = 0; |
b91dce4c | 281 | |
e2d0acd4 MC |
282 | data = pm_runtime_resume_and_get(priv->device); |
283 | if (data < 0) | |
5ec55823 | 284 | return data; |
5ec55823 | 285 | |
b91dce4c LC |
286 | value |= (phyaddr << priv->hw->mii.addr_shift) |
287 | & priv->hw->mii.addr_mask; | |
288 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
567be786 | 289 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
290 | & priv->hw->mii.clk_csr_mask; | |
7c6b942b | 291 | if (priv->plat->has_gmac4) |
b91dce4c | 292 | value |= MII_GMAC4_READ; |
47dd7a54 | 293 | |
3c7826d0 | 294 | data = stmmac_mdio_read(priv, data, value); |
39b401db | 295 | |
3c7826d0 | 296 | pm_runtime_put(priv->device); |
39b401db | 297 | |
3c7826d0 AL |
298 | return data; |
299 | } | |
300 | ||
301 | /** | |
302 | * stmmac_mdio_read_c45 | |
303 | * @bus: points to the mii_bus structure | |
304 | * @phyaddr: MII addr | |
305 | * @devad: device address to read | |
306 | * @phyreg: MII reg | |
307 | * Description: it reads data from the MII register from within the phy device. | |
308 | * For the 7111 GMAC, we must set the bit 0 in the MII address register while | |
309 | * accessing the PHY registers. | |
310 | * Fortunately, it seems this has no drawback for the 7109 MAC. | |
311 | */ | |
312 | static int stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad, | |
313 | int phyreg) | |
314 | { | |
315 | struct net_device *ndev = bus->priv; | |
316 | struct stmmac_priv *priv = netdev_priv(ndev); | |
317 | u32 value = MII_BUSY; | |
318 | int data = 0; | |
319 | ||
320 | data = pm_runtime_get_sync(priv->device); | |
321 | if (data < 0) { | |
322 | pm_runtime_put_noidle(priv->device); | |
323 | return data; | |
5ec55823 | 324 | } |
47dd7a54 | 325 | |
3c7826d0 AL |
326 | value |= (phyaddr << priv->hw->mii.addr_shift) |
327 | & priv->hw->mii.addr_mask; | |
328 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
329 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) | |
330 | & priv->hw->mii.clk_csr_mask; | |
331 | value |= MII_GMAC4_READ; | |
332 | value |= MII_GMAC4_C45E; | |
333 | value &= ~priv->hw->mii.reg_mask; | |
334 | value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
335 | ||
336 | data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT; | |
337 | ||
338 | data = stmmac_mdio_read(priv, data, value); | |
47dd7a54 | 339 | |
5ec55823 JZ |
340 | pm_runtime_put(priv->device); |
341 | ||
47dd7a54 GC |
342 | return data; |
343 | } | |
344 | ||
3c7826d0 AL |
345 | static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value) |
346 | { | |
347 | unsigned int mii_address = priv->hw->mii.addr; | |
348 | unsigned int mii_data = priv->hw->mii.data; | |
349 | u32 v; | |
350 | ||
351 | /* Wait until any existing MII operation is complete */ | |
352 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), | |
353 | 100, 10000)) | |
354 | return -EBUSY; | |
355 | ||
356 | /* Set the MII address register to write */ | |
357 | writel(data, priv->ioaddr + mii_data); | |
358 | writel(value, priv->ioaddr + mii_address); | |
359 | ||
360 | /* Wait until any existing MII operation is complete */ | |
361 | return readl_poll_timeout(priv->ioaddr + mii_address, v, | |
362 | !(v & MII_BUSY), 100, 10000); | |
363 | } | |
364 | ||
47dd7a54 | 365 | /** |
3c7826d0 | 366 | * stmmac_mdio_write_c22 |
47dd7a54 | 367 | * @bus: points to the mii_bus structure |
b91dce4c LC |
368 | * @phyaddr: MII addr |
369 | * @phyreg: MII reg | |
47dd7a54 GC |
370 | * @phydata: phy data |
371 | * Description: it writes the data into the MII register from within the device. | |
372 | */ | |
3c7826d0 AL |
373 | static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg, |
374 | u16 phydata) | |
47dd7a54 GC |
375 | { |
376 | struct net_device *ndev = bus->priv; | |
377 | struct stmmac_priv *priv = netdev_priv(ndev); | |
5ec55823 | 378 | int ret, data = phydata; |
5799fc90 | 379 | u32 value = MII_BUSY; |
47dd7a54 | 380 | |
e2d0acd4 MC |
381 | ret = pm_runtime_resume_and_get(priv->device); |
382 | if (ret < 0) | |
5ec55823 | 383 | return ret; |
5ec55823 | 384 | |
b91dce4c LC |
385 | value |= (phyaddr << priv->hw->mii.addr_shift) |
386 | & priv->hw->mii.addr_mask; | |
387 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
dfb8fb96 | 388 | |
567be786 | 389 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
390 | & priv->hw->mii.clk_csr_mask; | |
3c7826d0 | 391 | if (priv->plat->has_gmac4) |
b91dce4c | 392 | value |= MII_GMAC4_WRITE; |
3c7826d0 | 393 | else |
5799fc90 | 394 | value |= MII_WRITE; |
ac1f74a7 | 395 | |
3c7826d0 AL |
396 | ret = stmmac_mdio_write(priv, data, value); |
397 | ||
398 | pm_runtime_put(priv->device); | |
399 | ||
400 | return ret; | |
401 | } | |
402 | ||
403 | /** | |
404 | * stmmac_mdio_write_c45 | |
405 | * @bus: points to the mii_bus structure | |
406 | * @phyaddr: MII addr | |
407 | * @phyreg: MII reg | |
408 | * @devad: device address to read | |
409 | * @phydata: phy data | |
410 | * Description: it writes the data into the MII register from within the device. | |
411 | */ | |
412 | static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr, | |
413 | int devad, int phyreg, u16 phydata) | |
414 | { | |
415 | struct net_device *ndev = bus->priv; | |
416 | struct stmmac_priv *priv = netdev_priv(ndev); | |
417 | int ret, data = phydata; | |
418 | u32 value = MII_BUSY; | |
419 | ||
420 | ret = pm_runtime_get_sync(priv->device); | |
421 | if (ret < 0) { | |
422 | pm_runtime_put_noidle(priv->device); | |
423 | return ret; | |
5ec55823 | 424 | } |
ac1f74a7 | 425 | |
3c7826d0 AL |
426 | value |= (phyaddr << priv->hw->mii.addr_shift) |
427 | & priv->hw->mii.addr_mask; | |
428 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
ac1f74a7 | 429 | |
3c7826d0 AL |
430 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
431 | & priv->hw->mii.clk_csr_mask; | |
432 | ||
433 | value |= MII_GMAC4_WRITE; | |
434 | value |= MII_GMAC4_C45E; | |
435 | value &= ~priv->hw->mii.reg_mask; | |
436 | value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
437 | ||
438 | data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT; | |
439 | ||
440 | ret = stmmac_mdio_write(priv, data, value); | |
5ec55823 | 441 | |
5ec55823 JZ |
442 | pm_runtime_put(priv->device); |
443 | ||
444 | return ret; | |
ac1f74a7 AT |
445 | } |
446 | ||
47dd7a54 GC |
447 | /** |
448 | * stmmac_mdio_reset | |
449 | * @bus: points to the mii_bus structure | |
450 | * Description: reset the MII bus | |
451 | */ | |
073752aa | 452 | int stmmac_mdio_reset(struct mii_bus *bus) |
47dd7a54 | 453 | { |
30549aab | 454 | #if IS_ENABLED(CONFIG_STMMAC_PLATFORM) |
47dd7a54 GC |
455 | struct net_device *ndev = bus->priv; |
456 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 | 457 | unsigned int mii_address = priv->hw->mii.addr; |
0e076471 SK |
458 | |
459 | #ifdef CONFIG_OF | |
460 | if (priv->device->of_node) { | |
7c86f20d | 461 | struct gpio_desc *reset_gpio; |
84ce4d0f | 462 | u32 delays[3] = { 0, 0, 0 }; |
7c86f20d | 463 | |
7e770b25 MB |
464 | reset_gpio = devm_gpiod_get_optional(priv->device, |
465 | "snps,reset", | |
466 | GPIOD_OUT_LOW); | |
467 | if (IS_ERR(reset_gpio)) | |
468 | return PTR_ERR(reset_gpio); | |
469 | ||
cc5e92c2 MB |
470 | device_property_read_u32_array(priv->device, |
471 | "snps,reset-delays-us", | |
472 | delays, ARRAY_SIZE(delays)); | |
0e076471 | 473 | |
ce4ab73a MB |
474 | if (delays[0]) |
475 | msleep(DIV_ROUND_UP(delays[0], 1000)); | |
892aa01d | 476 | |
7c86f20d | 477 | gpiod_set_value_cansleep(reset_gpio, 1); |
ce4ab73a MB |
478 | if (delays[1]) |
479 | msleep(DIV_ROUND_UP(delays[1], 1000)); | |
892aa01d | 480 | |
7c86f20d | 481 | gpiod_set_value_cansleep(reset_gpio, 0); |
ce4ab73a MB |
482 | if (delays[2]) |
483 | msleep(DIV_ROUND_UP(delays[2], 1000)); | |
0e076471 SK |
484 | } |
485 | #endif | |
47dd7a54 | 486 | |
47dd7a54 GC |
487 | /* This is a workaround for problems with the STE101P PHY. |
488 | * It doesn't complete its reset until at least one clock cycle | |
8d45e42b | 489 | * on MDC, so perform a dummy mdio read. To be updated for GMAC4 |
ac1f74a7 | 490 | * if needed. |
47dd7a54 | 491 | */ |
ac1f74a7 AT |
492 | if (!priv->plat->has_gmac4) |
493 | writel(0, priv->ioaddr + mii_address); | |
bfab27a1 | 494 | #endif |
47dd7a54 GC |
495 | return 0; |
496 | } | |
497 | ||
597a68ce VW |
498 | int stmmac_xpcs_setup(struct mii_bus *bus) |
499 | { | |
597a68ce | 500 | struct net_device *ndev = bus->priv; |
47538dbe VO |
501 | struct stmmac_priv *priv; |
502 | struct dw_xpcs *xpcs; | |
503 | int mode, addr; | |
597a68ce VW |
504 | |
505 | priv = netdev_priv(ndev); | |
506 | mode = priv->plat->phy_interface; | |
507 | ||
508 | /* Try to probe the XPCS by scanning all addresses. */ | |
509 | for (addr = 0; addr < PHY_MAX_ADDR; addr++) { | |
727e373f RKO |
510 | xpcs = xpcs_create_mdiodev(bus, addr, mode); |
511 | if (IS_ERR(xpcs)) | |
597a68ce VW |
512 | continue; |
513 | ||
597a68ce VW |
514 | priv->hw->xpcs = xpcs; |
515 | break; | |
516 | } | |
517 | ||
518 | if (!priv->hw->xpcs) { | |
519 | dev_warn(priv->device, "No xPCS found\n"); | |
520 | return -ENODEV; | |
521 | } | |
522 | ||
523 | return 0; | |
524 | } | |
525 | ||
47dd7a54 GC |
526 | /** |
527 | * stmmac_mdio_register | |
528 | * @ndev: net device structure | |
529 | * Description: it registers the MII bus | |
530 | */ | |
531 | int stmmac_mdio_register(struct net_device *ndev) | |
532 | { | |
533 | int err = 0; | |
534 | struct mii_bus *new_bus; | |
47dd7a54 | 535 | struct stmmac_priv *priv = netdev_priv(ndev); |
36bcfe7d | 536 | struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; |
a7657f12 | 537 | struct device_node *mdio_node = priv->plat->mdio_node; |
fbca1647 | 538 | struct device *dev = ndev->dev.parent; |
ab21cf92 | 539 | struct fwnode_handle *fixed_node; |
e80af2ac | 540 | struct fwnode_handle *fwnode; |
6fc21117 | 541 | int addr, found, max_addr; |
47dd7a54 | 542 | |
36bcfe7d GC |
543 | if (!mdio_bus_data) |
544 | return 0; | |
545 | ||
47dd7a54 | 546 | new_bus = mdiobus_alloc(); |
efd89b60 | 547 | if (!new_bus) |
47dd7a54 GC |
548 | return -ENOMEM; |
549 | ||
e7f4dc35 | 550 | if (mdio_bus_data->irqs) |
643d60bf | 551 | memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); |
47dd7a54 | 552 | |
90b9a545 | 553 | new_bus->name = "stmmac"; |
6fc21117 JA |
554 | |
555 | if (priv->plat->has_xgmac) { | |
5b0a447e AL |
556 | new_bus->read = &stmmac_xgmac2_mdio_read_c22; |
557 | new_bus->write = &stmmac_xgmac2_mdio_write_c22; | |
558 | new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45; | |
559 | new_bus->write_c45 = &stmmac_xgmac2_mdio_write_c45; | |
6fc21117 | 560 | |
10857e67 RT |
561 | if (priv->synopsys_id < DWXGMAC_CORE_2_20) { |
562 | /* Right now only C22 phys are supported */ | |
563 | max_addr = MII_XGMAC_MAX_C22ADDR + 1; | |
6fc21117 | 564 | |
10857e67 RT |
565 | /* Check if DT specified an unsupported phy addr */ |
566 | if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR) | |
567 | dev_err(dev, "Unsupported phy_addr (max=%d)\n", | |
6fc21117 | 568 | MII_XGMAC_MAX_C22ADDR); |
10857e67 RT |
569 | } else { |
570 | /* XGMAC version 2.20 onwards support 32 phy addr */ | |
571 | max_addr = PHY_MAX_ADDR; | |
572 | } | |
6fc21117 | 573 | } else { |
3c7826d0 AL |
574 | new_bus->read = &stmmac_mdio_read_c22; |
575 | new_bus->write = &stmmac_mdio_write_c22; | |
576 | if (priv->plat->has_gmac4) { | |
577 | new_bus->read_c45 = &stmmac_mdio_read_c45; | |
578 | new_bus->write_c45 = &stmmac_mdio_write_c45; | |
579 | } | |
580 | ||
6fc21117 JA |
581 | max_addr = PHY_MAX_ADDR; |
582 | } | |
ac1f74a7 | 583 | |
1a981c05 TR |
584 | if (mdio_bus_data->needs_reset) |
585 | new_bus->reset = &stmmac_mdio_reset; | |
586 | ||
db8857bf | 587 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", |
ceb69499 | 588 | new_bus->name, priv->plat->bus_id); |
47dd7a54 | 589 | new_bus->priv = ndev; |
36bcfe7d | 590 | new_bus->phy_mask = mdio_bus_data->phy_mask; |
47dd7a54 | 591 | new_bus->parent = priv->device; |
e34d6569 | 592 | |
00e798c7 | 593 | err = of_mdiobus_register(new_bus, mdio_node); |
e23c0d21 AH |
594 | if (err == -ENODEV) { |
595 | err = 0; | |
596 | dev_info(dev, "MDIO bus is disabled\n"); | |
597 | goto bus_register_fail; | |
598 | } else if (err) { | |
839612d2 | 599 | dev_err_probe(dev, err, "Cannot register the MDIO bus\n"); |
47dd7a54 GC |
600 | goto bus_register_fail; |
601 | } | |
602 | ||
04d1190a JA |
603 | /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ |
604 | if (priv->plat->has_xgmac) | |
5b0a447e | 605 | stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0); |
04d1190a | 606 | |
ab21cf92 | 607 | /* If fixed-link is set, skip PHY scanning */ |
e80af2ac | 608 | fwnode = priv->plat->port_node; |
ab21cf92 OBL |
609 | if (!fwnode) |
610 | fwnode = dev_fwnode(priv->device); | |
611 | ||
612 | if (fwnode) { | |
613 | fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link"); | |
614 | if (fixed_node) { | |
615 | fwnode_handle_put(fixed_node); | |
616 | goto bus_register_done; | |
617 | } | |
618 | } | |
619 | ||
cc2fa619 PR |
620 | if (priv->plat->phy_node || mdio_node) |
621 | goto bus_register_done; | |
622 | ||
47dd7a54 | 623 | found = 0; |
6fc21117 | 624 | for (addr = 0; addr < max_addr; addr++) { |
7f854420 | 625 | struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); |
cc26dc67 LC |
626 | |
627 | if (!phydev) | |
628 | continue; | |
629 | ||
630 | /* | |
631 | * If an IRQ was provided to be assigned after | |
632 | * the bus probe, do it here. | |
633 | */ | |
634 | if (!mdio_bus_data->irqs && | |
635 | (mdio_bus_data->probed_phy_irq > 0)) { | |
636 | new_bus->irq[addr] = mdio_bus_data->probed_phy_irq; | |
637 | phydev->irq = mdio_bus_data->probed_phy_irq; | |
638 | } | |
efd89b60 | 639 | |
cc26dc67 LC |
640 | /* |
641 | * If we're going to bind the MAC to this PHY bus, | |
642 | * and no PHY number was provided to the MAC, | |
643 | * use the one probed here. | |
644 | */ | |
645 | if (priv->plat->phy_addr == -1) | |
646 | priv->plat->phy_addr = addr; | |
647 | ||
fbca1647 | 648 | phy_attached_info(phydev); |
cc26dc67 | 649 | found = 1; |
47dd7a54 GC |
650 | } |
651 | ||
4751d2aa VO |
652 | if (!found && !mdio_node) { |
653 | dev_warn(dev, "No PHY found\n"); | |
654 | err = -ENODEV; | |
655 | goto no_phy_found; | |
656 | } | |
657 | ||
cc2fa619 | 658 | bus_register_done: |
3955b22b | 659 | priv->mii = new_bus; |
47dd7a54 GC |
660 | |
661 | return 0; | |
36bcfe7d | 662 | |
4751d2aa VO |
663 | no_phy_found: |
664 | mdiobus_unregister(new_bus); | |
47dd7a54 | 665 | bus_register_fail: |
36bcfe7d | 666 | mdiobus_free(new_bus); |
47dd7a54 GC |
667 | return err; |
668 | } | |
669 | ||
670 | /** | |
671 | * stmmac_mdio_unregister | |
672 | * @ndev: net device structure | |
673 | * Description: it unregisters the MII bus | |
674 | */ | |
675 | int stmmac_mdio_unregister(struct net_device *ndev) | |
676 | { | |
677 | struct stmmac_priv *priv = netdev_priv(ndev); | |
678 | ||
a5cf5ce9 SK |
679 | if (!priv->mii) |
680 | return 0; | |
681 | ||
727e373f | 682 | if (priv->hw->xpcs) |
11059740 | 683 | xpcs_destroy(priv->hw->xpcs); |
2cac15da | 684 | |
47dd7a54 GC |
685 | mdiobus_unregister(priv->mii); |
686 | priv->mii->priv = NULL; | |
36bcfe7d GC |
687 | mdiobus_free(priv->mii); |
688 | priv->mii = NULL; | |
47dd7a54 GC |
689 | |
690 | return 0; | |
691 | } |