Commit | Line | Data |
---|---|---|
47dd7a54 GC |
1 | /******************************************************************************* |
2 | STMMAC Ethernet Driver -- MDIO bus implementation | |
3 | Provides Bus interface for MII registers | |
4 | ||
5 | Copyright (C) 2007-2009 STMicroelectronics Ltd | |
6 | ||
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 | You should have received a copy of the GNU General Public License along with | |
17 | this program; if not, write to the Free Software Foundation, Inc., | |
18 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
19 | ||
20 | The full GNU General Public License is included in this distribution in | |
21 | the file called "COPYING". | |
22 | ||
23 | Author: Carl Shaw <carl.shaw@st.com> | |
24 | Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com> | |
25 | *******************************************************************************/ | |
26 | ||
47dd7a54 GC |
27 | #include <linux/mii.h> |
28 | #include <linux/phy.h> | |
5a0e3ad6 | 29 | #include <linux/slab.h> |
0e076471 SK |
30 | #include <linux/of.h> |
31 | #include <linux/of_gpio.h> | |
e34d6569 | 32 | #include <linux/of_mdio.h> |
b7f080cf | 33 | #include <asm/io.h> |
47dd7a54 GC |
34 | |
35 | #include "stmmac.h" | |
36 | ||
37 | #define MII_BUSY 0x00000001 | |
38 | #define MII_WRITE 0x00000002 | |
39 | ||
ac1f74a7 AT |
40 | /* GMAC4 defines */ |
41 | #define MII_GMAC4_GOC_SHIFT 2 | |
42 | #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT) | |
43 | #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT) | |
44 | ||
39b401db DS |
45 | static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr) |
46 | { | |
47 | unsigned long curr; | |
48 | unsigned long finish = jiffies + 3 * HZ; | |
49 | ||
50 | do { | |
51 | curr = jiffies; | |
52 | if (readl(ioaddr + mii_addr) & MII_BUSY) | |
53 | cpu_relax(); | |
54 | else | |
55 | return 0; | |
56 | } while (!time_after_eq(curr, finish)); | |
57 | ||
58 | return -EBUSY; | |
59 | } | |
60 | ||
47dd7a54 GC |
61 | /** |
62 | * stmmac_mdio_read | |
63 | * @bus: points to the mii_bus structure | |
b91dce4c LC |
64 | * @phyaddr: MII addr |
65 | * @phyreg: MII reg | |
47dd7a54 GC |
66 | * Description: it reads data from the MII register from within the phy device. |
67 | * For the 7111 GMAC, we must set the bit 0 in the MII address register while | |
68 | * accessing the PHY registers. | |
69 | * Fortunately, it seems this has no drawback for the 7109 MAC. | |
70 | */ | |
71 | static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) | |
72 | { | |
73 | struct net_device *ndev = bus->priv; | |
74 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 GC |
75 | unsigned int mii_address = priv->hw->mii.addr; |
76 | unsigned int mii_data = priv->hw->mii.data; | |
47dd7a54 GC |
77 | |
78 | int data; | |
b91dce4c LC |
79 | u32 value = MII_BUSY; |
80 | ||
81 | value |= (phyaddr << priv->hw->mii.addr_shift) | |
82 | & priv->hw->mii.addr_mask; | |
83 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
567be786 | 84 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
85 | & priv->hw->mii.clk_csr_mask; | |
b91dce4c LC |
86 | if (priv->plat->has_gmac4) |
87 | value |= MII_GMAC4_READ; | |
47dd7a54 | 88 | |
39b401db DS |
89 | if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address)) |
90 | return -EBUSY; | |
91 | ||
01f1f615 | 92 | writel(value, priv->ioaddr + mii_address); |
39b401db DS |
93 | |
94 | if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address)) | |
95 | return -EBUSY; | |
47dd7a54 GC |
96 | |
97 | /* Read the data from the MII data register */ | |
ad01b7d4 | 98 | data = (int)readl(priv->ioaddr + mii_data); |
47dd7a54 GC |
99 | |
100 | return data; | |
101 | } | |
102 | ||
103 | /** | |
104 | * stmmac_mdio_write | |
105 | * @bus: points to the mii_bus structure | |
b91dce4c LC |
106 | * @phyaddr: MII addr |
107 | * @phyreg: MII reg | |
47dd7a54 GC |
108 | * @phydata: phy data |
109 | * Description: it writes the data into the MII register from within the device. | |
110 | */ | |
111 | static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, | |
112 | u16 phydata) | |
113 | { | |
114 | struct net_device *ndev = bus->priv; | |
115 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 GC |
116 | unsigned int mii_address = priv->hw->mii.addr; |
117 | unsigned int mii_data = priv->hw->mii.data; | |
47dd7a54 | 118 | |
5799fc90 | 119 | u32 value = MII_BUSY; |
47dd7a54 | 120 | |
b91dce4c LC |
121 | value |= (phyaddr << priv->hw->mii.addr_shift) |
122 | & priv->hw->mii.addr_mask; | |
123 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; | |
dfb8fb96 | 124 | |
567be786 | 125 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
126 | & priv->hw->mii.clk_csr_mask; | |
b91dce4c LC |
127 | if (priv->plat->has_gmac4) |
128 | value |= MII_GMAC4_WRITE; | |
5799fc90 KHL |
129 | else |
130 | value |= MII_WRITE; | |
ac1f74a7 AT |
131 | |
132 | /* Wait until any existing MII operation is complete */ | |
133 | if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address)) | |
134 | return -EBUSY; | |
135 | ||
136 | /* Set the MII address register to write */ | |
137 | writel(phydata, priv->ioaddr + mii_data); | |
138 | writel(value, priv->ioaddr + mii_address); | |
139 | ||
140 | /* Wait until any existing MII operation is complete */ | |
141 | return stmmac_mdio_busy_wait(priv->ioaddr, mii_address); | |
142 | } | |
143 | ||
47dd7a54 GC |
144 | /** |
145 | * stmmac_mdio_reset | |
146 | * @bus: points to the mii_bus structure | |
147 | * Description: reset the MII bus | |
148 | */ | |
073752aa | 149 | int stmmac_mdio_reset(struct mii_bus *bus) |
47dd7a54 | 150 | { |
bfab27a1 | 151 | #if defined(CONFIG_STMMAC_PLATFORM) |
47dd7a54 GC |
152 | struct net_device *ndev = bus->priv; |
153 | struct stmmac_priv *priv = netdev_priv(ndev); | |
db98a0b0 | 154 | unsigned int mii_address = priv->hw->mii.addr; |
0e076471 SK |
155 | struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data; |
156 | ||
157 | #ifdef CONFIG_OF | |
158 | if (priv->device->of_node) { | |
0e076471 SK |
159 | |
160 | if (data->reset_gpio < 0) { | |
161 | struct device_node *np = priv->device->of_node; | |
162 | if (!np) | |
163 | return 0; | |
164 | ||
165 | data->reset_gpio = of_get_named_gpio(np, | |
166 | "snps,reset-gpio", 0); | |
167 | if (data->reset_gpio < 0) | |
168 | return 0; | |
169 | ||
170 | data->active_low = of_property_read_bool(np, | |
171 | "snps,reset-active-low"); | |
172 | of_property_read_u32_array(np, | |
173 | "snps,reset-delays-us", data->delays, 3); | |
0e076471 | 174 | |
ae26c1c6 GC |
175 | if (gpio_request(data->reset_gpio, "mdio-reset")) |
176 | return 0; | |
177 | } | |
0e076471 | 178 | |
ae26c1c6 GC |
179 | gpio_direction_output(data->reset_gpio, |
180 | data->active_low ? 1 : 0); | |
181 | if (data->delays[0]) | |
182 | msleep(DIV_ROUND_UP(data->delays[0], 1000)); | |
892aa01d | 183 | |
ae26c1c6 GC |
184 | gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1); |
185 | if (data->delays[1]) | |
186 | msleep(DIV_ROUND_UP(data->delays[1], 1000)); | |
892aa01d | 187 | |
ae26c1c6 GC |
188 | gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0); |
189 | if (data->delays[2]) | |
190 | msleep(DIV_ROUND_UP(data->delays[2], 1000)); | |
0e076471 SK |
191 | } |
192 | #endif | |
47dd7a54 | 193 | |
0e076471 | 194 | if (data->phy_reset) { |
38ddc59d | 195 | netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n"); |
0e076471 | 196 | data->phy_reset(priv->plat->bsp_priv); |
47dd7a54 GC |
197 | } |
198 | ||
199 | /* This is a workaround for problems with the STE101P PHY. | |
200 | * It doesn't complete its reset until at least one clock cycle | |
ac1f74a7 AT |
201 | * on MDC, so perform a dummy mdio read. To be upadted for GMAC4 |
202 | * if needed. | |
47dd7a54 | 203 | */ |
ac1f74a7 AT |
204 | if (!priv->plat->has_gmac4) |
205 | writel(0, priv->ioaddr + mii_address); | |
bfab27a1 | 206 | #endif |
47dd7a54 GC |
207 | return 0; |
208 | } | |
209 | ||
210 | /** | |
211 | * stmmac_mdio_register | |
212 | * @ndev: net device structure | |
213 | * Description: it registers the MII bus | |
214 | */ | |
215 | int stmmac_mdio_register(struct net_device *ndev) | |
216 | { | |
217 | int err = 0; | |
218 | struct mii_bus *new_bus; | |
47dd7a54 | 219 | struct stmmac_priv *priv = netdev_priv(ndev); |
36bcfe7d | 220 | struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; |
a7657f12 | 221 | struct device_node *mdio_node = priv->plat->mdio_node; |
47dd7a54 GC |
222 | int addr, found; |
223 | ||
36bcfe7d GC |
224 | if (!mdio_bus_data) |
225 | return 0; | |
226 | ||
47dd7a54 GC |
227 | new_bus = mdiobus_alloc(); |
228 | if (new_bus == NULL) | |
229 | return -ENOMEM; | |
230 | ||
e7f4dc35 | 231 | if (mdio_bus_data->irqs) |
643d60bf | 232 | memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); |
47dd7a54 | 233 | |
0e076471 SK |
234 | #ifdef CONFIG_OF |
235 | if (priv->device->of_node) | |
236 | mdio_bus_data->reset_gpio = -1; | |
237 | #endif | |
238 | ||
90b9a545 | 239 | new_bus->name = "stmmac"; |
b91dce4c LC |
240 | new_bus->read = &stmmac_mdio_read; |
241 | new_bus->write = &stmmac_mdio_write; | |
ac1f74a7 | 242 | |
47dd7a54 | 243 | new_bus->reset = &stmmac_mdio_reset; |
db8857bf | 244 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", |
ceb69499 | 245 | new_bus->name, priv->plat->bus_id); |
47dd7a54 | 246 | new_bus->priv = ndev; |
36bcfe7d | 247 | new_bus->phy_mask = mdio_bus_data->phy_mask; |
47dd7a54 | 248 | new_bus->parent = priv->device; |
e34d6569 | 249 | |
6c672c9b RP |
250 | if (mdio_node) |
251 | err = of_mdiobus_register(new_bus, mdio_node); | |
252 | else | |
253 | err = mdiobus_register(new_bus); | |
47dd7a54 | 254 | if (err != 0) { |
38ddc59d | 255 | netdev_err(ndev, "Cannot register the MDIO bus\n"); |
47dd7a54 GC |
256 | goto bus_register_fail; |
257 | } | |
258 | ||
cc2fa619 PR |
259 | if (priv->plat->phy_node || mdio_node) |
260 | goto bus_register_done; | |
261 | ||
47dd7a54 | 262 | found = 0; |
36bcfe7d | 263 | for (addr = 0; addr < PHY_MAX_ADDR; addr++) { |
7f854420 | 264 | struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); |
47dd7a54 | 265 | if (phydev) { |
36bcfe7d GC |
266 | int act = 0; |
267 | char irq_num[4]; | |
268 | char *irq_str; | |
269 | ||
270 | /* | |
271 | * If an IRQ was provided to be assigned after | |
272 | * the bus probe, do it here. | |
273 | */ | |
274 | if ((mdio_bus_data->irqs == NULL) && | |
275 | (mdio_bus_data->probed_phy_irq > 0)) { | |
e7f4dc35 AL |
276 | new_bus->irq[addr] = |
277 | mdio_bus_data->probed_phy_irq; | |
36bcfe7d | 278 | phydev->irq = mdio_bus_data->probed_phy_irq; |
47dd7a54 | 279 | } |
36bcfe7d GC |
280 | |
281 | /* | |
a77e4acc | 282 | * If we're going to bind the MAC to this PHY bus, |
36bcfe7d GC |
283 | * and no PHY number was provided to the MAC, |
284 | * use the one probed here. | |
285 | */ | |
d56631a6 | 286 | if (priv->plat->phy_addr == -1) |
36bcfe7d GC |
287 | priv->plat->phy_addr = addr; |
288 | ||
d56631a6 | 289 | act = (priv->plat->phy_addr == addr); |
36bcfe7d GC |
290 | switch (phydev->irq) { |
291 | case PHY_POLL: | |
292 | irq_str = "POLL"; | |
293 | break; | |
294 | case PHY_IGNORE_INTERRUPT: | |
295 | irq_str = "IGNORE"; | |
296 | break; | |
297 | default: | |
298 | sprintf(irq_num, "%d", phydev->irq); | |
299 | irq_str = irq_num; | |
300 | break; | |
301 | } | |
38ddc59d LC |
302 | netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n", |
303 | phydev->phy_id, addr, | |
304 | irq_str, phydev_name(phydev), | |
305 | act ? " active" : ""); | |
47dd7a54 GC |
306 | found = 1; |
307 | } | |
308 | } | |
309 | ||
e34d6569 | 310 | if (!found && !mdio_node) { |
38ddc59d | 311 | netdev_warn(ndev, "No PHY found\n"); |
3955b22b GC |
312 | mdiobus_unregister(new_bus); |
313 | mdiobus_free(new_bus); | |
314 | return -ENODEV; | |
315 | } | |
316 | ||
cc2fa619 | 317 | bus_register_done: |
3955b22b | 318 | priv->mii = new_bus; |
47dd7a54 GC |
319 | |
320 | return 0; | |
36bcfe7d | 321 | |
47dd7a54 | 322 | bus_register_fail: |
36bcfe7d | 323 | mdiobus_free(new_bus); |
47dd7a54 GC |
324 | return err; |
325 | } | |
326 | ||
327 | /** | |
328 | * stmmac_mdio_unregister | |
329 | * @ndev: net device structure | |
330 | * Description: it unregisters the MII bus | |
331 | */ | |
332 | int stmmac_mdio_unregister(struct net_device *ndev) | |
333 | { | |
334 | struct stmmac_priv *priv = netdev_priv(ndev); | |
335 | ||
a5cf5ce9 SK |
336 | if (!priv->mii) |
337 | return 0; | |
338 | ||
47dd7a54 GC |
339 | mdiobus_unregister(priv->mii); |
340 | priv->mii->priv = NULL; | |
36bcfe7d GC |
341 | mdiobus_free(priv->mii); |
342 | priv->mii = NULL; | |
47dd7a54 GC |
343 | |
344 | return 0; | |
345 | } |