.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /******************************************************************************* |
---|
2 | 3 | STMMAC Ethernet Driver -- MDIO bus implementation |
---|
3 | 4 | Provides Bus interface for MII registers |
---|
4 | 5 | |
---|
5 | 6 | Copyright (C) 2007-2009 STMicroelectronics Ltd |
---|
6 | 7 | |
---|
7 | | - This program is free software; you can redistribute it and/or modify it |
---|
8 | | - under the terms and conditions of the GNU General Public License, |
---|
9 | | - version 2, as published by the Free Software Foundation. |
---|
10 | | - |
---|
11 | | - This program is distributed in the hope it will be useful, but WITHOUT |
---|
12 | | - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
13 | | - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
14 | | - more details. |
---|
15 | | - |
---|
16 | | - The full GNU General Public License is included in this distribution in |
---|
17 | | - the file called "COPYING". |
---|
18 | 8 | |
---|
19 | 9 | Author: Carl Shaw <carl.shaw@st.com> |
---|
20 | 10 | Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com> |
---|
21 | 11 | *******************************************************************************/ |
---|
22 | 12 | |
---|
| 13 | +#include <linux/gpio/consumer.h> |
---|
23 | 14 | #include <linux/io.h> |
---|
24 | 15 | #include <linux/iopoll.h> |
---|
25 | 16 | #include <linux/mii.h> |
---|
26 | | -#include <linux/of.h> |
---|
27 | | -#include <linux/of_gpio.h> |
---|
28 | 17 | #include <linux/of_mdio.h> |
---|
| 18 | +#include <linux/pm_runtime.h> |
---|
29 | 19 | #include <linux/phy.h> |
---|
| 20 | +#include <linux/property.h> |
---|
30 | 21 | #include <linux/slab.h> |
---|
31 | 22 | |
---|
32 | 23 | #include "dwxgmac2.h" |
---|
.. | .. |
---|
34 | 25 | |
---|
35 | 26 | #define MII_BUSY 0x00000001 |
---|
36 | 27 | #define MII_WRITE 0x00000002 |
---|
| 28 | +#define MII_DATA_MASK GENMASK(15, 0) |
---|
37 | 29 | |
---|
38 | 30 | /* GMAC4 defines */ |
---|
39 | 31 | #define MII_GMAC4_GOC_SHIFT 2 |
---|
| 32 | +#define MII_GMAC4_REG_ADDR_SHIFT 16 |
---|
40 | 33 | #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT) |
---|
41 | 34 | #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT) |
---|
| 35 | +#define MII_GMAC4_C45E BIT(1) |
---|
42 | 36 | |
---|
43 | 37 | /* XGMAC defines */ |
---|
44 | 38 | #define MII_XGMAC_SADDR BIT(18) |
---|
.. | .. |
---|
48 | 42 | #define MII_XGMAC_BUSY BIT(22) |
---|
49 | 43 | #define MII_XGMAC_MAX_C22ADDR 3 |
---|
50 | 44 | #define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0) |
---|
| 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 | +} |
---|
51 | 62 | |
---|
52 | 63 | static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, |
---|
53 | 64 | int phyreg, u32 *hw_addr) |
---|
54 | 65 | { |
---|
55 | | - unsigned int mii_data = priv->hw->mii.data; |
---|
56 | 66 | u32 tmp; |
---|
57 | 67 | |
---|
58 | 68 | /* HW does not support C22 addr >= 4 */ |
---|
59 | 69 | if (phyaddr > MII_XGMAC_MAX_C22ADDR) |
---|
60 | 70 | return -ENODEV; |
---|
61 | | - /* Wait until any existing MII operation is complete */ |
---|
62 | | - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
---|
63 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
---|
64 | | - return -EBUSY; |
---|
65 | 71 | |
---|
66 | 72 | /* Set port as Clause 22 */ |
---|
67 | 73 | tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); |
---|
.. | .. |
---|
69 | 75 | tmp |= BIT(phyaddr); |
---|
70 | 76 | writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); |
---|
71 | 77 | |
---|
72 | | - *hw_addr = (phyaddr << 16) | (phyreg & 0x1f); |
---|
| 78 | + *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f); |
---|
73 | 79 | return 0; |
---|
74 | 80 | } |
---|
75 | 81 | |
---|
.. | .. |
---|
82 | 88 | u32 tmp, addr, value = MII_XGMAC_BUSY; |
---|
83 | 89 | int ret; |
---|
84 | 90 | |
---|
| 91 | + ret = pm_runtime_get_sync(priv->device); |
---|
| 92 | + if (ret < 0) { |
---|
| 93 | + pm_runtime_put_noidle(priv->device); |
---|
| 94 | + return ret; |
---|
| 95 | + } |
---|
| 96 | + |
---|
| 97 | + /* Wait until any existing MII operation is complete */ |
---|
| 98 | + if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
---|
| 99 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
---|
| 100 | + ret = -EBUSY; |
---|
| 101 | + goto err_disable_clks; |
---|
| 102 | + } |
---|
| 103 | + |
---|
85 | 104 | if (phyreg & MII_ADDR_C45) { |
---|
86 | | - return -EOPNOTSUPP; |
---|
| 105 | + phyreg &= ~MII_ADDR_C45; |
---|
| 106 | + |
---|
| 107 | + ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); |
---|
| 108 | + if (ret) |
---|
| 109 | + goto err_disable_clks; |
---|
87 | 110 | } else { |
---|
88 | 111 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); |
---|
89 | 112 | if (ret) |
---|
90 | | - return ret; |
---|
| 113 | + goto err_disable_clks; |
---|
| 114 | + |
---|
| 115 | + value |= MII_XGMAC_SADDR; |
---|
91 | 116 | } |
---|
92 | 117 | |
---|
93 | 118 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
---|
94 | 119 | & priv->hw->mii.clk_csr_mask; |
---|
95 | | - value |= MII_XGMAC_SADDR | MII_XGMAC_READ; |
---|
| 120 | + value |= MII_XGMAC_READ; |
---|
96 | 121 | |
---|
97 | 122 | /* Wait until any existing MII operation is complete */ |
---|
98 | 123 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
---|
99 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
---|
100 | | - return -EBUSY; |
---|
| 124 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
---|
| 125 | + ret = -EBUSY; |
---|
| 126 | + goto err_disable_clks; |
---|
| 127 | + } |
---|
101 | 128 | |
---|
102 | 129 | /* Set the MII address register to read */ |
---|
103 | 130 | writel(addr, priv->ioaddr + mii_address); |
---|
.. | .. |
---|
105 | 132 | |
---|
106 | 133 | /* Wait until any existing MII operation is complete */ |
---|
107 | 134 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
---|
108 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
---|
109 | | - return -EBUSY; |
---|
| 135 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
---|
| 136 | + ret = -EBUSY; |
---|
| 137 | + goto err_disable_clks; |
---|
| 138 | + } |
---|
110 | 139 | |
---|
111 | 140 | /* Read the data from the MII data register */ |
---|
112 | | - return readl(priv->ioaddr + mii_data) & GENMASK(15, 0); |
---|
| 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; |
---|
113 | 147 | } |
---|
114 | 148 | |
---|
115 | 149 | static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, |
---|
.. | .. |
---|
122 | 156 | u32 addr, tmp, value = MII_XGMAC_BUSY; |
---|
123 | 157 | int ret; |
---|
124 | 158 | |
---|
| 159 | + ret = pm_runtime_get_sync(priv->device); |
---|
| 160 | + if (ret < 0) { |
---|
| 161 | + pm_runtime_put_noidle(priv->device); |
---|
| 162 | + return ret; |
---|
| 163 | + } |
---|
| 164 | + |
---|
| 165 | + /* Wait until any existing MII operation is complete */ |
---|
| 166 | + if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
---|
| 167 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
---|
| 168 | + ret = -EBUSY; |
---|
| 169 | + goto err_disable_clks; |
---|
| 170 | + } |
---|
| 171 | + |
---|
125 | 172 | if (phyreg & MII_ADDR_C45) { |
---|
126 | | - return -EOPNOTSUPP; |
---|
| 173 | + phyreg &= ~MII_ADDR_C45; |
---|
| 174 | + |
---|
| 175 | + ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); |
---|
| 176 | + if (ret) |
---|
| 177 | + goto err_disable_clks; |
---|
127 | 178 | } else { |
---|
128 | 179 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); |
---|
129 | 180 | if (ret) |
---|
130 | | - return ret; |
---|
| 181 | + goto err_disable_clks; |
---|
| 182 | + |
---|
| 183 | + value |= MII_XGMAC_SADDR; |
---|
131 | 184 | } |
---|
132 | 185 | |
---|
133 | 186 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
---|
134 | 187 | & priv->hw->mii.clk_csr_mask; |
---|
135 | | - value |= phydata | MII_XGMAC_SADDR; |
---|
| 188 | + value |= phydata; |
---|
136 | 189 | value |= MII_XGMAC_WRITE; |
---|
137 | 190 | |
---|
138 | 191 | /* Wait until any existing MII operation is complete */ |
---|
139 | 192 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
---|
140 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
---|
141 | | - return -EBUSY; |
---|
| 193 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
---|
| 194 | + ret = -EBUSY; |
---|
| 195 | + goto err_disable_clks; |
---|
| 196 | + } |
---|
142 | 197 | |
---|
143 | 198 | /* Set the MII address register to write */ |
---|
144 | 199 | writel(addr, priv->ioaddr + mii_address); |
---|
145 | 200 | writel(value, priv->ioaddr + mii_data); |
---|
146 | 201 | |
---|
147 | 202 | /* Wait until any existing MII operation is complete */ |
---|
148 | | - return readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
---|
149 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000); |
---|
| 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; |
---|
150 | 210 | } |
---|
151 | 211 | |
---|
152 | 212 | /** |
---|
.. | .. |
---|
165 | 225 | struct stmmac_priv *priv = netdev_priv(ndev); |
---|
166 | 226 | unsigned int mii_address = priv->hw->mii.addr; |
---|
167 | 227 | unsigned int mii_data = priv->hw->mii.data; |
---|
168 | | - u32 v; |
---|
169 | | - int data; |
---|
170 | 228 | u32 value = MII_BUSY; |
---|
| 229 | + int data = 0; |
---|
| 230 | + u32 v; |
---|
| 231 | + |
---|
| 232 | + data = pm_runtime_get_sync(priv->device); |
---|
| 233 | + if (data < 0) { |
---|
| 234 | + pm_runtime_put_noidle(priv->device); |
---|
| 235 | + return data; |
---|
| 236 | + } |
---|
171 | 237 | |
---|
172 | 238 | value |= (phyaddr << priv->hw->mii.addr_shift) |
---|
173 | 239 | & priv->hw->mii.addr_mask; |
---|
174 | 240 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; |
---|
175 | 241 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
---|
176 | 242 | & priv->hw->mii.clk_csr_mask; |
---|
177 | | - if (priv->plat->has_gmac4) |
---|
| 243 | + if (priv->plat->has_gmac4) { |
---|
178 | 244 | value |= MII_GMAC4_READ; |
---|
| 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 | + } |
---|
179 | 256 | |
---|
180 | 257 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
---|
181 | | - 100, 10000)) |
---|
182 | | - return -EBUSY; |
---|
| 258 | + 100, 10000)) { |
---|
| 259 | + data = -EBUSY; |
---|
| 260 | + goto err_disable_clks; |
---|
| 261 | + } |
---|
183 | 262 | |
---|
| 263 | + writel(data, priv->ioaddr + mii_data); |
---|
184 | 264 | writel(value, priv->ioaddr + mii_address); |
---|
185 | 265 | |
---|
186 | 266 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
---|
187 | | - 100, 10000)) |
---|
188 | | - return -EBUSY; |
---|
| 267 | + 100, 10000)) { |
---|
| 268 | + data = -EBUSY; |
---|
| 269 | + goto err_disable_clks; |
---|
| 270 | + } |
---|
189 | 271 | |
---|
190 | 272 | /* Read the data from the MII data register */ |
---|
191 | | - data = (int)readl(priv->ioaddr + mii_data); |
---|
| 273 | + data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK; |
---|
| 274 | + |
---|
| 275 | +err_disable_clks: |
---|
| 276 | + pm_runtime_put(priv->device); |
---|
192 | 277 | |
---|
193 | 278 | return data; |
---|
194 | 279 | } |
---|
.. | .. |
---|
208 | 293 | struct stmmac_priv *priv = netdev_priv(ndev); |
---|
209 | 294 | unsigned int mii_address = priv->hw->mii.addr; |
---|
210 | 295 | unsigned int mii_data = priv->hw->mii.data; |
---|
211 | | - u32 v; |
---|
| 296 | + int ret, data = phydata; |
---|
212 | 297 | u32 value = MII_BUSY; |
---|
| 298 | + u32 v; |
---|
| 299 | + |
---|
| 300 | + ret = pm_runtime_get_sync(priv->device); |
---|
| 301 | + if (ret < 0) { |
---|
| 302 | + pm_runtime_put_noidle(priv->device); |
---|
| 303 | + return ret; |
---|
| 304 | + } |
---|
213 | 305 | |
---|
214 | 306 | value |= (phyaddr << priv->hw->mii.addr_shift) |
---|
215 | 307 | & priv->hw->mii.addr_mask; |
---|
.. | .. |
---|
217 | 309 | |
---|
218 | 310 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
---|
219 | 311 | & priv->hw->mii.clk_csr_mask; |
---|
220 | | - if (priv->plat->has_gmac4) |
---|
| 312 | + if (priv->plat->has_gmac4) { |
---|
221 | 313 | value |= MII_GMAC4_WRITE; |
---|
222 | | - else |
---|
| 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 { |
---|
223 | 325 | value |= MII_WRITE; |
---|
| 326 | + } |
---|
224 | 327 | |
---|
225 | 328 | /* Wait until any existing MII operation is complete */ |
---|
226 | 329 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
---|
227 | | - 100, 10000)) |
---|
228 | | - return -EBUSY; |
---|
| 330 | + 100, 10000)) { |
---|
| 331 | + ret = -EBUSY; |
---|
| 332 | + goto err_disable_clks; |
---|
| 333 | + } |
---|
229 | 334 | |
---|
230 | 335 | /* Set the MII address register to write */ |
---|
231 | | - writel(phydata, priv->ioaddr + mii_data); |
---|
| 336 | + writel(data, priv->ioaddr + mii_data); |
---|
232 | 337 | writel(value, priv->ioaddr + mii_address); |
---|
233 | 338 | |
---|
234 | 339 | /* Wait until any existing MII operation is complete */ |
---|
235 | | - return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
---|
236 | | - 100, 10000); |
---|
| 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; |
---|
237 | 347 | } |
---|
238 | 348 | |
---|
239 | 349 | /** |
---|
.. | .. |
---|
247 | 357 | struct net_device *ndev = bus->priv; |
---|
248 | 358 | struct stmmac_priv *priv = netdev_priv(ndev); |
---|
249 | 359 | unsigned int mii_address = priv->hw->mii.addr; |
---|
250 | | - struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data; |
---|
251 | 360 | |
---|
252 | 361 | #ifdef CONFIG_OF |
---|
253 | 362 | if (priv->device->of_node) { |
---|
254 | | - if (data->reset_gpio < 0) { |
---|
255 | | - struct device_node *np = priv->device->of_node; |
---|
| 363 | + struct gpio_desc *reset_gpio; |
---|
| 364 | + u32 delays[3] = { 0, 0, 0 }; |
---|
256 | 365 | |
---|
257 | | - if (!np) |
---|
258 | | - return 0; |
---|
| 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); |
---|
259 | 371 | |
---|
260 | | - data->reset_gpio = of_get_named_gpio(np, |
---|
261 | | - "snps,reset-gpio", 0); |
---|
262 | | - if (data->reset_gpio < 0) |
---|
263 | | - return 0; |
---|
| 372 | + device_property_read_u32_array(priv->device, |
---|
| 373 | + "snps,reset-delays-us", |
---|
| 374 | + delays, ARRAY_SIZE(delays)); |
---|
264 | 375 | |
---|
265 | | - data->active_low = of_property_read_bool(np, |
---|
266 | | - "snps,reset-active-low"); |
---|
267 | | - of_property_read_u32_array(np, |
---|
268 | | - "snps,reset-delays-us", data->delays, 3); |
---|
| 376 | + if (delays[0]) |
---|
| 377 | + msleep(DIV_ROUND_UP(delays[0], 1000)); |
---|
269 | 378 | |
---|
270 | | - if (devm_gpio_request(priv->device, data->reset_gpio, |
---|
271 | | - "mdio-reset")) |
---|
272 | | - return 0; |
---|
273 | | - } |
---|
| 379 | + gpiod_set_value_cansleep(reset_gpio, 1); |
---|
| 380 | + if (delays[1]) |
---|
| 381 | + msleep(DIV_ROUND_UP(delays[1], 1000)); |
---|
274 | 382 | |
---|
275 | | - gpio_direction_output(data->reset_gpio, |
---|
276 | | - data->active_low ? 1 : 0); |
---|
277 | | - if (data->delays[0]) |
---|
278 | | - msleep(DIV_ROUND_UP(data->delays[0], 1000)); |
---|
279 | | - |
---|
280 | | - gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1); |
---|
281 | | - if (data->delays[1]) |
---|
282 | | - msleep(DIV_ROUND_UP(data->delays[1], 1000)); |
---|
283 | | - |
---|
284 | | - gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0); |
---|
285 | | - if (data->delays[2]) |
---|
286 | | - msleep(DIV_ROUND_UP(data->delays[2], 1000)); |
---|
| 383 | + gpiod_set_value_cansleep(reset_gpio, 0); |
---|
| 384 | + if (delays[2]) |
---|
| 385 | + msleep(DIV_ROUND_UP(delays[2], 1000)); |
---|
287 | 386 | } |
---|
288 | 387 | #endif |
---|
289 | | - |
---|
290 | | - if (data->phy_reset) { |
---|
291 | | - netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n"); |
---|
292 | | - data->phy_reset(priv->plat->bsp_priv); |
---|
293 | | - } |
---|
294 | 388 | |
---|
295 | 389 | /* This is a workaround for problems with the STE101P PHY. |
---|
296 | 390 | * It doesn't complete its reset until at least one clock cycle |
---|
.. | .. |
---|
329 | 423 | if (mdio_bus_data->irqs) |
---|
330 | 424 | memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); |
---|
331 | 425 | |
---|
332 | | -#ifdef CONFIG_OF |
---|
333 | | - if (priv->device->of_node) |
---|
334 | | - mdio_bus_data->reset_gpio = -1; |
---|
335 | | -#endif |
---|
336 | | - |
---|
337 | 426 | new_bus->name = "stmmac"; |
---|
338 | 427 | |
---|
339 | 428 | if (priv->plat->has_xgmac) { |
---|
.. | .. |
---|
353 | 442 | max_addr = PHY_MAX_ADDR; |
---|
354 | 443 | } |
---|
355 | 444 | |
---|
356 | | - new_bus->reset = &stmmac_mdio_reset; |
---|
| 445 | + if (mdio_bus_data->has_xpcs) { |
---|
| 446 | + priv->hw->xpcs = mdio_xpcs_get_ops(); |
---|
| 447 | + if (!priv->hw->xpcs) { |
---|
| 448 | + err = -ENODEV; |
---|
| 449 | + goto bus_register_fail; |
---|
| 450 | + } |
---|
| 451 | + } |
---|
| 452 | + |
---|
| 453 | + if (mdio_bus_data->needs_reset) |
---|
| 454 | + new_bus->reset = &stmmac_mdio_reset; |
---|
| 455 | + |
---|
357 | 456 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", |
---|
358 | 457 | new_bus->name, priv->plat->bus_id); |
---|
359 | 458 | new_bus->priv = ndev; |
---|
.. | .. |
---|
365 | 464 | dev_err(dev, "Cannot register the MDIO bus\n"); |
---|
366 | 465 | goto bus_register_fail; |
---|
367 | 466 | } |
---|
| 467 | + |
---|
| 468 | + /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ |
---|
| 469 | + if (priv->plat->has_xgmac) |
---|
| 470 | + stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45); |
---|
368 | 471 | |
---|
369 | 472 | if (priv->plat->phy_node || mdio_node) |
---|
370 | 473 | goto bus_register_done; |
---|
.. | .. |
---|
400 | 503 | |
---|
401 | 504 | if (!found && !mdio_node) { |
---|
402 | 505 | dev_warn(dev, "No PHY found\n"); |
---|
403 | | - mdiobus_unregister(new_bus); |
---|
404 | | - mdiobus_free(new_bus); |
---|
405 | | - return -ENODEV; |
---|
| 506 | + err = -ENODEV; |
---|
| 507 | + goto no_phy_found; |
---|
| 508 | + } |
---|
| 509 | + |
---|
| 510 | + /* Try to probe the XPCS by scanning all addresses. */ |
---|
| 511 | + if (priv->hw->xpcs) { |
---|
| 512 | + struct mdio_xpcs_args *xpcs = &priv->hw->xpcs_args; |
---|
| 513 | + int ret, mode = priv->plat->phy_interface; |
---|
| 514 | + max_addr = PHY_MAX_ADDR; |
---|
| 515 | + |
---|
| 516 | + xpcs->bus = new_bus; |
---|
| 517 | + |
---|
| 518 | + found = 0; |
---|
| 519 | + for (addr = 0; addr < max_addr; addr++) { |
---|
| 520 | + xpcs->addr = addr; |
---|
| 521 | + |
---|
| 522 | + ret = stmmac_xpcs_probe(priv, xpcs, mode); |
---|
| 523 | + if (!ret) { |
---|
| 524 | + found = 1; |
---|
| 525 | + break; |
---|
| 526 | + } |
---|
| 527 | + } |
---|
| 528 | + |
---|
| 529 | + if (!found && !mdio_node) { |
---|
| 530 | + dev_warn(dev, "No XPCS found\n"); |
---|
| 531 | + err = -ENODEV; |
---|
| 532 | + goto no_xpcs_found; |
---|
| 533 | + } |
---|
406 | 534 | } |
---|
407 | 535 | |
---|
408 | 536 | bus_register_done: |
---|
.. | .. |
---|
410 | 538 | |
---|
411 | 539 | return 0; |
---|
412 | 540 | |
---|
| 541 | +no_xpcs_found: |
---|
| 542 | +no_phy_found: |
---|
| 543 | + mdiobus_unregister(new_bus); |
---|
413 | 544 | bus_register_fail: |
---|
414 | 545 | mdiobus_free(new_bus); |
---|
415 | 546 | return err; |
---|