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