diff options
-rw-r--r-- | drivers/net/Kconfig | 9 | ||||
-rw-r--r-- | drivers/net/Makefile | 5 | ||||
-rw-r--r-- | drivers/net/fsl_pq_mdio.c | 463 | ||||
-rw-r--r-- | drivers/net/fsl_pq_mdio.h | 45 | ||||
-rw-r--r-- | drivers/net/gianfar.c | 23 | ||||
-rw-r--r-- | drivers/net/gianfar.h | 13 | ||||
-rw-r--r-- | drivers/net/gianfar_mii.h | 54 | ||||
-rw-r--r-- | drivers/net/ucc_geth.c | 16 | ||||
-rw-r--r-- | drivers/net/ucc_geth.h | 14 | ||||
-rw-r--r-- | drivers/net/ucc_geth_ethtool.c | 1 | ||||
-rw-r--r-- | drivers/net/ucc_geth_mii.c | 295 | ||||
-rw-r--r-- | drivers/net/ucc_geth_mii.h | 101 |
12 files changed, 549 insertions, 490 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 49f4d50abc56..62bc0223a8ed 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2272,9 +2272,17 @@ config GELIC_WIRELESS_OLD_PSK_INTERFACE | |||
2272 | 2272 | ||
2273 | If unsure, say N. | 2273 | If unsure, say N. |
2274 | 2274 | ||
2275 | config FSL_PQ_MDIO | ||
2276 | tristate "Freescale PQ MDIO" | ||
2277 | depends on FSL_SOC | ||
2278 | select PHYLIB | ||
2279 | help | ||
2280 | This driver supports the MDIO bus used by the gianfar and UCC drivers. | ||
2281 | |||
2275 | config GIANFAR | 2282 | config GIANFAR |
2276 | tristate "Gianfar Ethernet" | 2283 | tristate "Gianfar Ethernet" |
2277 | depends on FSL_SOC | 2284 | depends on FSL_SOC |
2285 | select FSL_PQ_MDIO | ||
2278 | select PHYLIB | 2286 | select PHYLIB |
2279 | select CRC32 | 2287 | select CRC32 |
2280 | help | 2288 | help |
@@ -2284,6 +2292,7 @@ config GIANFAR | |||
2284 | config UCC_GETH | 2292 | config UCC_GETH |
2285 | tristate "Freescale QE Gigabit Ethernet" | 2293 | tristate "Freescale QE Gigabit Ethernet" |
2286 | depends on QUICC_ENGINE | 2294 | depends on QUICC_ENGINE |
2295 | select FSL_PQ_MDIO | ||
2287 | select PHYLIB | 2296 | select PHYLIB |
2288 | help | 2297 | help |
2289 | This driver supports the Gigabit Ethernet mode of the QUICC Engine, | 2298 | This driver supports the Gigabit Ethernet mode of the QUICC Engine, |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a3c5c002f224..ad87ba72cf1f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -24,11 +24,12 @@ obj-$(CONFIG_JME) += jme.o | |||
24 | 24 | ||
25 | gianfar_driver-objs := gianfar.o \ | 25 | gianfar_driver-objs := gianfar.o \ |
26 | gianfar_ethtool.o \ | 26 | gianfar_ethtool.o \ |
27 | gianfar_mii.o \ | ||
28 | gianfar_sysfs.o | 27 | gianfar_sysfs.o |
29 | 28 | ||
30 | obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o | 29 | obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o |
31 | ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o ucc_geth_ethtool.o | 30 | ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o |
31 | |||
32 | obj-$(CONFIG_FSL_PQ_MDIO) += fsl_pq_mdio.o | ||
32 | 33 | ||
33 | # | 34 | # |
34 | # link order important here | 35 | # link order important here |
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c new file mode 100644 index 000000000000..c434a156d7a9 --- /dev/null +++ b/drivers/net/fsl_pq_mdio.c | |||
@@ -0,0 +1,463 @@ | |||
1 | /* | ||
2 | * Freescale PowerQUICC Ethernet Driver -- MIIM bus implementation | ||
3 | * Provides Bus interface for MIIM regs | ||
4 | * | ||
5 | * Author: Andy Fleming <afleming@freescale.com> | ||
6 | * | ||
7 | * Copyright (c) 2002-2004,2008 Freescale Semiconductor, Inc. | ||
8 | * | ||
9 | * Based on gianfar_mii.c and ucc_geth_mii.c (Li Yang, Kim Phillips) | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/crc32.h> | ||
34 | #include <linux/mii.h> | ||
35 | #include <linux/phy.h> | ||
36 | #include <linux/of.h> | ||
37 | #include <linux/of_platform.h> | ||
38 | |||
39 | #include <asm/io.h> | ||
40 | #include <asm/irq.h> | ||
41 | #include <asm/uaccess.h> | ||
42 | #include <asm/ucc.h> | ||
43 | |||
44 | #include "gianfar.h" | ||
45 | #include "fsl_pq_mdio.h" | ||
46 | |||
47 | /* | ||
48 | * Write value to the PHY at mii_id at register regnum, | ||
49 | * on the bus attached to the local interface, which may be different from the | ||
50 | * generic mdio bus (tied to a single interface), waiting until the write is | ||
51 | * done before returning. This is helpful in programming interfaces like | ||
52 | * the TBI which control interfaces like onchip SERDES and are always tied to | ||
53 | * the local mdio pins, which may not be the same as system mdio bus, used for | ||
54 | * controlling the external PHYs, for example. | ||
55 | */ | ||
56 | int fsl_pq_local_mdio_write(struct fsl_pq_mdio __iomem *regs, int mii_id, | ||
57 | int regnum, u16 value) | ||
58 | { | ||
59 | /* Set the PHY address and the register address we want to write */ | ||
60 | out_be32(®s->miimadd, (mii_id << 8) | regnum); | ||
61 | |||
62 | /* Write out the value we want */ | ||
63 | out_be32(®s->miimcon, value); | ||
64 | |||
65 | /* Wait for the transaction to finish */ | ||
66 | while (in_be32(®s->miimind) & MIIMIND_BUSY) | ||
67 | cpu_relax(); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * Read the bus for PHY at addr mii_id, register regnum, and | ||
74 | * return the value. Clears miimcom first. All PHY operation | ||
75 | * done on the bus attached to the local interface, | ||
76 | * which may be different from the generic mdio bus | ||
77 | * This is helpful in programming interfaces like | ||
78 | * the TBI which, in turn, control interfaces like onchip SERDES | ||
79 | * and are always tied to the local mdio pins, which may not be the | ||
80 | * same as system mdio bus, used for controlling the external PHYs, for eg. | ||
81 | */ | ||
82 | int fsl_pq_local_mdio_read(struct fsl_pq_mdio __iomem *regs, | ||
83 | int mii_id, int regnum) | ||
84 | { | ||
85 | u16 value; | ||
86 | |||
87 | /* Set the PHY address and the register address we want to read */ | ||
88 | out_be32(®s->miimadd, (mii_id << 8) | regnum); | ||
89 | |||
90 | /* Clear miimcom, and then initiate a read */ | ||
91 | out_be32(®s->miimcom, 0); | ||
92 | out_be32(®s->miimcom, MII_READ_COMMAND); | ||
93 | |||
94 | /* Wait for the transaction to finish */ | ||
95 | while (in_be32(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) | ||
96 | cpu_relax(); | ||
97 | |||
98 | /* Grab the value of the register from miimstat */ | ||
99 | value = in_be32(®s->miimstat); | ||
100 | |||
101 | return value; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Write value to the PHY at mii_id at register regnum, | ||
106 | * on the bus, waiting until the write is done before returning. | ||
107 | */ | ||
108 | int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | ||
109 | { | ||
110 | struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv; | ||
111 | |||
112 | /* Write to the local MII regs */ | ||
113 | return(fsl_pq_local_mdio_write(regs, mii_id, regnum, value)); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Read the bus for PHY at addr mii_id, register regnum, and | ||
118 | * return the value. Clears miimcom first. | ||
119 | */ | ||
120 | int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | ||
121 | { | ||
122 | struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv; | ||
123 | |||
124 | /* Read the local MII regs */ | ||
125 | return(fsl_pq_local_mdio_read(regs, mii_id, regnum)); | ||
126 | } | ||
127 | |||
128 | /* Reset the MIIM registers, and wait for the bus to free */ | ||
129 | static int fsl_pq_mdio_reset(struct mii_bus *bus) | ||
130 | { | ||
131 | struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv; | ||
132 | unsigned int timeout = PHY_INIT_TIMEOUT; | ||
133 | |||
134 | mutex_lock(&bus->mdio_lock); | ||
135 | |||
136 | /* Reset the management interface */ | ||
137 | out_be32(®s->miimcfg, MIIMCFG_RESET); | ||
138 | |||
139 | /* Setup the MII Mgmt clock speed */ | ||
140 | out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); | ||
141 | |||
142 | /* Wait until the bus is free */ | ||
143 | while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) | ||
144 | cpu_relax(); | ||
145 | |||
146 | mutex_unlock(&bus->mdio_lock); | ||
147 | |||
148 | if(timeout == 0) { | ||
149 | printk(KERN_ERR "%s: The MII Bus is stuck!\n", | ||
150 | bus->name); | ||
151 | return -EBUSY; | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | /* Allocate an array which provides irq #s for each PHY on the given bus */ | ||
158 | static int *create_irq_map(struct device_node *np) | ||
159 | { | ||
160 | int *irqs; | ||
161 | int i; | ||
162 | struct device_node *child = NULL; | ||
163 | |||
164 | irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); | ||
165 | |||
166 | if (!irqs) | ||
167 | return NULL; | ||
168 | |||
169 | for (i = 0; i < PHY_MAX_ADDR; i++) | ||
170 | irqs[i] = PHY_POLL; | ||
171 | |||
172 | while ((child = of_get_next_child(np, child)) != NULL) { | ||
173 | int irq = irq_of_parse_and_map(child, 0); | ||
174 | const u32 *id; | ||
175 | |||
176 | if (irq == NO_IRQ) | ||
177 | continue; | ||
178 | |||
179 | id = of_get_property(child, "reg", NULL); | ||
180 | |||
181 | if (!id) | ||
182 | continue; | ||
183 | |||
184 | if (*id < PHY_MAX_ADDR && *id >= 0) | ||
185 | irqs[*id] = irq; | ||
186 | else | ||
187 | printk(KERN_WARNING "%s: " | ||
188 | "%d is not a valid PHY address\n", | ||
189 | np->full_name, *id); | ||
190 | } | ||
191 | |||
192 | return irqs; | ||
193 | } | ||
194 | |||
195 | void fsl_pq_mdio_bus_name(char *name, struct device_node *np) | ||
196 | { | ||
197 | const u32 *reg; | ||
198 | |||
199 | reg = of_get_property(np, "reg", NULL); | ||
200 | |||
201 | snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0); | ||
202 | } | ||
203 | |||
204 | /* Scan the bus in reverse, looking for an empty spot */ | ||
205 | static int fsl_pq_mdio_find_free(struct mii_bus *new_bus) | ||
206 | { | ||
207 | int i; | ||
208 | |||
209 | for (i = PHY_MAX_ADDR; i > 0; i--) { | ||
210 | u32 phy_id; | ||
211 | |||
212 | if (get_phy_id(new_bus, i, &phy_id)) | ||
213 | return -1; | ||
214 | |||
215 | if (phy_id == 0xffffffff) | ||
216 | break; | ||
217 | } | ||
218 | |||
219 | return i; | ||
220 | } | ||
221 | |||
222 | |||
223 | #ifdef CONFIG_GIANFAR | ||
224 | static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs) | ||
225 | { | ||
226 | struct gfar __iomem *enet_regs; | ||
227 | |||
228 | /* | ||
229 | * This is mildly evil, but so is our hardware for doing this. | ||
230 | * Also, we have to cast back to struct gfar because of | ||
231 | * definition weirdness done in gianfar.h. | ||
232 | */ | ||
233 | enet_regs = (struct gfar __iomem *) | ||
234 | ((char __iomem *)regs - offsetof(struct gfar, gfar_mii_regs)); | ||
235 | |||
236 | return &enet_regs->tbipa; | ||
237 | } | ||
238 | #endif | ||
239 | |||
240 | |||
241 | #ifdef CONFIG_UCC_GETH | ||
242 | static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id) | ||
243 | { | ||
244 | struct device_node *np = NULL; | ||
245 | int err = 0; | ||
246 | |||
247 | for_each_compatible_node(np, NULL, "ucc_geth") { | ||
248 | struct resource tempres; | ||
249 | |||
250 | err = of_address_to_resource(np, 0, &tempres); | ||
251 | if (err) | ||
252 | continue; | ||
253 | |||
254 | /* if our mdio regs fall within this UCC regs range */ | ||
255 | if ((start >= tempres.start) && (end <= tempres.end)) { | ||
256 | /* Find the id of the UCC */ | ||
257 | const u32 *id; | ||
258 | |||
259 | id = of_get_property(np, "cell-index", NULL); | ||
260 | if (!id) { | ||
261 | id = of_get_property(np, "device-id", NULL); | ||
262 | if (!id) | ||
263 | continue; | ||
264 | } | ||
265 | |||
266 | *ucc_id = *id; | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | if (err) | ||
273 | return err; | ||
274 | else | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | #endif | ||
278 | |||
279 | |||
280 | static int fsl_pq_mdio_probe(struct of_device *ofdev, | ||
281 | const struct of_device_id *match) | ||
282 | { | ||
283 | struct device_node *np = ofdev->node; | ||
284 | struct device_node *tbi; | ||
285 | struct fsl_pq_mdio __iomem *regs; | ||
286 | u32 __iomem *tbipa; | ||
287 | struct mii_bus *new_bus; | ||
288 | int tbiaddr = -1; | ||
289 | u64 addr, size; | ||
290 | int err = 0; | ||
291 | |||
292 | new_bus = mdiobus_alloc(); | ||
293 | if (NULL == new_bus) | ||
294 | return -ENOMEM; | ||
295 | |||
296 | new_bus->name = "Freescale PowerQUICC MII Bus", | ||
297 | new_bus->read = &fsl_pq_mdio_read, | ||
298 | new_bus->write = &fsl_pq_mdio_write, | ||
299 | new_bus->reset = &fsl_pq_mdio_reset, | ||
300 | fsl_pq_mdio_bus_name(new_bus->id, np); | ||
301 | |||
302 | /* Set the PHY base address */ | ||
303 | addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); | ||
304 | regs = ioremap(addr, size); | ||
305 | |||
306 | if (NULL == regs) { | ||
307 | err = -ENOMEM; | ||
308 | goto err_free_bus; | ||
309 | } | ||
310 | |||
311 | new_bus->priv = (void __force *)regs; | ||
312 | |||
313 | new_bus->irq = create_irq_map(np); | ||
314 | |||
315 | if (NULL == new_bus->irq) { | ||
316 | err = -ENOMEM; | ||
317 | goto err_unmap_regs; | ||
318 | } | ||
319 | |||
320 | new_bus->parent = &ofdev->dev; | ||
321 | dev_set_drvdata(&ofdev->dev, new_bus); | ||
322 | |||
323 | if (of_device_is_compatible(np, "fsl,gianfar-mdio") || | ||
324 | of_device_is_compatible(np, "gianfar")) { | ||
325 | #ifdef CONFIG_GIANFAR | ||
326 | tbipa = get_gfar_tbipa(regs); | ||
327 | #else | ||
328 | err = -ENODEV; | ||
329 | goto err_free_irqs; | ||
330 | #endif | ||
331 | } else if (of_device_is_compatible(np, "fsl,ucc-mdio") || | ||
332 | of_device_is_compatible(np, "ucc_geth_phy")) { | ||
333 | #ifdef CONFIG_UCC_GETH | ||
334 | u32 id; | ||
335 | |||
336 | tbipa = ®s->utbipar; | ||
337 | |||
338 | if ((err = get_ucc_id_for_range(addr, addr + size, &id))) | ||
339 | goto err_free_irqs; | ||
340 | |||
341 | ucc_set_qe_mux_mii_mng(id - 1); | ||
342 | #else | ||
343 | err = -ENODEV; | ||
344 | goto err_free_irqs; | ||
345 | #endif | ||
346 | } else { | ||
347 | err = -ENODEV; | ||
348 | goto err_free_irqs; | ||
349 | } | ||
350 | |||
351 | for_each_child_of_node(np, tbi) { | ||
352 | if (!strncmp(tbi->type, "tbi-phy", 8)) | ||
353 | break; | ||
354 | } | ||
355 | |||
356 | if (tbi) { | ||
357 | const u32 *prop = of_get_property(tbi, "reg", NULL); | ||
358 | |||
359 | if (prop) | ||
360 | tbiaddr = *prop; | ||
361 | } | ||
362 | |||
363 | if (tbiaddr == -1) { | ||
364 | out_be32(tbipa, 0); | ||
365 | |||
366 | tbiaddr = fsl_pq_mdio_find_free(new_bus); | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * We define TBIPA at 0 to be illegal, opting to fail for boards that | ||
371 | * have PHYs at 1-31, rather than change tbipa and rescan. | ||
372 | */ | ||
373 | if (tbiaddr == 0) { | ||
374 | err = -EBUSY; | ||
375 | |||
376 | goto err_free_irqs; | ||
377 | } | ||
378 | |||
379 | out_be32(tbipa, tbiaddr); | ||
380 | |||
381 | /* | ||
382 | * The TBIPHY-only buses will find PHYs at every address, | ||
383 | * so we mask them all but the TBI | ||
384 | */ | ||
385 | if (!of_device_is_compatible(np, "fsl,gianfar-mdio")) | ||
386 | new_bus->phy_mask = ~(1 << tbiaddr); | ||
387 | |||
388 | err = mdiobus_register(new_bus); | ||
389 | |||
390 | if (err) { | ||
391 | printk (KERN_ERR "%s: Cannot register as MDIO bus\n", | ||
392 | new_bus->name); | ||
393 | goto err_free_irqs; | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | |||
398 | err_free_irqs: | ||
399 | kfree(new_bus->irq); | ||
400 | err_unmap_regs: | ||
401 | iounmap(regs); | ||
402 | err_free_bus: | ||
403 | kfree(new_bus); | ||
404 | |||
405 | return err; | ||
406 | } | ||
407 | |||
408 | |||
409 | static int fsl_pq_mdio_remove(struct of_device *ofdev) | ||
410 | { | ||
411 | struct device *device = &ofdev->dev; | ||
412 | struct mii_bus *bus = dev_get_drvdata(device); | ||
413 | |||
414 | mdiobus_unregister(bus); | ||
415 | |||
416 | dev_set_drvdata(device, NULL); | ||
417 | |||
418 | iounmap((void __iomem *)bus->priv); | ||
419 | bus->priv = NULL; | ||
420 | mdiobus_free(bus); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static struct of_device_id fsl_pq_mdio_match[] = { | ||
426 | { | ||
427 | .type = "mdio", | ||
428 | .compatible = "ucc_geth_phy", | ||
429 | }, | ||
430 | { | ||
431 | .type = "mdio", | ||
432 | .compatible = "gianfar", | ||
433 | }, | ||
434 | { | ||
435 | .compatible = "fsl,ucc-mdio", | ||
436 | }, | ||
437 | { | ||
438 | .compatible = "fsl,gianfar-tbi", | ||
439 | }, | ||
440 | { | ||
441 | .compatible = "fsl,gianfar-mdio", | ||
442 | }, | ||
443 | {}, | ||
444 | }; | ||
445 | |||
446 | static struct of_platform_driver fsl_pq_mdio_driver = { | ||
447 | .name = "fsl-pq_mdio", | ||
448 | .probe = fsl_pq_mdio_probe, | ||
449 | .remove = fsl_pq_mdio_remove, | ||
450 | .match_table = fsl_pq_mdio_match, | ||
451 | }; | ||
452 | |||
453 | int __init fsl_pq_mdio_init(void) | ||
454 | { | ||
455 | return of_register_platform_driver(&fsl_pq_mdio_driver); | ||
456 | } | ||
457 | |||
458 | void fsl_pq_mdio_exit(void) | ||
459 | { | ||
460 | of_unregister_platform_driver(&fsl_pq_mdio_driver); | ||
461 | } | ||
462 | subsys_initcall_sync(fsl_pq_mdio_init); | ||
463 | module_exit(fsl_pq_mdio_exit); | ||
diff --git a/drivers/net/fsl_pq_mdio.h b/drivers/net/fsl_pq_mdio.h new file mode 100644 index 000000000000..36dad527410b --- /dev/null +++ b/drivers/net/fsl_pq_mdio.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Freescale PowerQUICC MDIO Driver -- MII Management Bus Implementation | ||
3 | * Driver for the MDIO bus controller on Freescale PowerQUICC processors | ||
4 | * | ||
5 | * Author: Andy Fleming | ||
6 | * | ||
7 | * Copyright (c) 2002-2004,2008 Freescale Semiconductor, Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | #ifndef __FSL_PQ_MDIO_H | ||
16 | #define __FSL_PQ_MDIO_H | ||
17 | |||
18 | #define MIIMIND_BUSY 0x00000001 | ||
19 | #define MIIMIND_NOTVALID 0x00000004 | ||
20 | #define MIIMCFG_INIT_VALUE 0x00000007 | ||
21 | #define MIIMCFG_RESET 0x80000000 | ||
22 | |||
23 | #define MII_READ_COMMAND 0x00000001 | ||
24 | |||
25 | struct fsl_pq_mdio { | ||
26 | u32 miimcfg; /* MII management configuration reg */ | ||
27 | u32 miimcom; /* MII management command reg */ | ||
28 | u32 miimadd; /* MII management address reg */ | ||
29 | u32 miimcon; /* MII management control reg */ | ||
30 | u32 miimstat; /* MII management status reg */ | ||
31 | u32 miimind; /* MII management indication reg */ | ||
32 | u8 reserved[28]; /* Space holder */ | ||
33 | u32 utbipar; /* TBI phy address reg (only on UCC) */ | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | |||
37 | int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum); | ||
38 | int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); | ||
39 | int fsl_pq_local_mdio_write(struct fsl_pq_mdio __iomem *regs, int mii_id, | ||
40 | int regnum, u16 value); | ||
41 | int fsl_pq_local_mdio_read(struct fsl_pq_mdio __iomem *regs, int mii_id, int regnum); | ||
42 | int __init fsl_pq_mdio_init(void); | ||
43 | void fsl_pq_mdio_exit(void); | ||
44 | void fsl_pq_mdio_bus_name(char *name, struct device_node *np); | ||
45 | #endif /* FSL_PQ_MDIO_H */ | ||
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index eb8302c5ba8c..bd21b6d5f13c 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -93,7 +93,7 @@ | |||
93 | #include <linux/of.h> | 93 | #include <linux/of.h> |
94 | 94 | ||
95 | #include "gianfar.h" | 95 | #include "gianfar.h" |
96 | #include "gianfar_mii.h" | 96 | #include "fsl_pq_mdio.h" |
97 | 97 | ||
98 | #define TX_TIMEOUT (1*HZ) | 98 | #define TX_TIMEOUT (1*HZ) |
99 | #undef BRIEF_GFAR_ERRORS | 99 | #undef BRIEF_GFAR_ERRORS |
@@ -253,7 +253,7 @@ static int gfar_of_init(struct net_device *dev) | |||
253 | of_node_put(phy); | 253 | of_node_put(phy); |
254 | of_node_put(mdio); | 254 | of_node_put(mdio); |
255 | 255 | ||
256 | gfar_mdio_bus_name(bus_name, mdio); | 256 | fsl_pq_mdio_bus_name(bus_name, mdio); |
257 | snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x", | 257 | snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x", |
258 | bus_name, *id); | 258 | bus_name, *id); |
259 | } | 259 | } |
@@ -420,7 +420,7 @@ static int gfar_probe(struct of_device *ofdev, | |||
420 | priv->hash_width = 8; | 420 | priv->hash_width = 8; |
421 | 421 | ||
422 | priv->hash_regs[0] = &priv->regs->gaddr0; | 422 | priv->hash_regs[0] = &priv->regs->gaddr0; |
423 | priv->hash_regs[1] = &priv->regs->gaddr1; | 423 | priv->hash_regs[1] = &priv->regs->gaddr1; |
424 | priv->hash_regs[2] = &priv->regs->gaddr2; | 424 | priv->hash_regs[2] = &priv->regs->gaddr2; |
425 | priv->hash_regs[3] = &priv->regs->gaddr3; | 425 | priv->hash_regs[3] = &priv->regs->gaddr3; |
426 | priv->hash_regs[4] = &priv->regs->gaddr4; | 426 | priv->hash_regs[4] = &priv->regs->gaddr4; |
@@ -836,7 +836,7 @@ void stop_gfar(struct net_device *dev) | |||
836 | free_irq(priv->interruptTransmit, dev); | 836 | free_irq(priv->interruptTransmit, dev); |
837 | free_irq(priv->interruptReceive, dev); | 837 | free_irq(priv->interruptReceive, dev); |
838 | } else { | 838 | } else { |
839 | free_irq(priv->interruptTransmit, dev); | 839 | free_irq(priv->interruptTransmit, dev); |
840 | } | 840 | } |
841 | 841 | ||
842 | free_skb_resources(priv); | 842 | free_skb_resources(priv); |
@@ -1829,6 +1829,8 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) | |||
1829 | skb_put(skb, pkt_len); | 1829 | skb_put(skb, pkt_len); |
1830 | dev->stats.rx_bytes += pkt_len; | 1830 | dev->stats.rx_bytes += pkt_len; |
1831 | 1831 | ||
1832 | if (in_irq() || irqs_disabled()) | ||
1833 | printk("Interrupt problem!\n"); | ||
1832 | gfar_process_frame(dev, skb, amount_pull); | 1834 | gfar_process_frame(dev, skb, amount_pull); |
1833 | 1835 | ||
1834 | } else { | 1836 | } else { |
@@ -2302,23 +2304,12 @@ static struct of_platform_driver gfar_driver = { | |||
2302 | 2304 | ||
2303 | static int __init gfar_init(void) | 2305 | static int __init gfar_init(void) |
2304 | { | 2306 | { |
2305 | int err = gfar_mdio_init(); | 2307 | return of_register_platform_driver(&gfar_driver); |
2306 | |||
2307 | if (err) | ||
2308 | return err; | ||
2309 | |||
2310 | err = of_register_platform_driver(&gfar_driver); | ||
2311 | |||
2312 | if (err) | ||
2313 | gfar_mdio_exit(); | ||
2314 | |||
2315 | return err; | ||
2316 | } | 2308 | } |
2317 | 2309 | ||
2318 | static void __exit gfar_exit(void) | 2310 | static void __exit gfar_exit(void) |
2319 | { | 2311 | { |
2320 | of_unregister_platform_driver(&gfar_driver); | 2312 | of_unregister_platform_driver(&gfar_driver); |
2321 | gfar_mdio_exit(); | ||
2322 | } | 2313 | } |
2323 | 2314 | ||
2324 | module_init(gfar_init); | 2315 | module_init(gfar_init); |
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 7820720ceeed..3cb901b2e240 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <linux/workqueue.h> | 46 | #include <linux/workqueue.h> |
47 | #include <linux/ethtool.h> | 47 | #include <linux/ethtool.h> |
48 | #include <linux/fsl_devices.h> | 48 | #include <linux/fsl_devices.h> |
49 | #include "gianfar_mii.h" | ||
50 | 49 | ||
51 | /* The maximum number of packets to be handled in one call of gfar_poll */ | 50 | /* The maximum number of packets to be handled in one call of gfar_poll */ |
52 | #define GFAR_DEV_WEIGHT 64 | 51 | #define GFAR_DEV_WEIGHT 64 |
@@ -126,9 +125,12 @@ extern const char gfar_driver_version[]; | |||
126 | #define DEFAULT_RX_COALESCE 0 | 125 | #define DEFAULT_RX_COALESCE 0 |
127 | #define DEFAULT_RXCOUNT 0 | 126 | #define DEFAULT_RXCOUNT 0 |
128 | 127 | ||
129 | #define MIIMCFG_INIT_VALUE 0x00000007 | 128 | #define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \ |
130 | #define MIIMCFG_RESET 0x80000000 | 129 | | SUPPORTED_10baseT_Full \ |
131 | #define MIIMIND_BUSY 0x00000001 | 130 | | SUPPORTED_100baseT_Half \ |
131 | | SUPPORTED_100baseT_Full \ | ||
132 | | SUPPORTED_Autoneg \ | ||
133 | | SUPPORTED_MII) | ||
132 | 134 | ||
133 | /* TBI register addresses */ | 135 | /* TBI register addresses */ |
134 | #define MII_TBICON 0x11 | 136 | #define MII_TBICON 0x11 |
@@ -826,9 +828,6 @@ extern void gfar_halt(struct net_device *dev); | |||
826 | extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, | 828 | extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, |
827 | int enable, u32 regnum, u32 read); | 829 | int enable, u32 regnum, u32 read); |
828 | void gfar_init_sysfs(struct net_device *dev); | 830 | void gfar_init_sysfs(struct net_device *dev); |
829 | int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, | ||
830 | int regnum, u16 value); | ||
831 | int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); | ||
832 | 831 | ||
833 | extern const struct ethtool_ops gfar_ethtool_ops; | 832 | extern const struct ethtool_ops gfar_ethtool_ops; |
834 | 833 | ||
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h deleted file mode 100644 index 65c242cd468a..000000000000 --- a/drivers/net/gianfar_mii.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/net/gianfar_mii.h | ||
3 | * | ||
4 | * Gianfar Ethernet Driver -- MII Management Bus Implementation | ||
5 | * Driver for the MDIO bus controller in the Gianfar register space | ||
6 | * | ||
7 | * Author: Andy Fleming | ||
8 | * Maintainer: Kumar Gala | ||
9 | * | ||
10 | * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | */ | ||
18 | #ifndef __GIANFAR_MII_H | ||
19 | #define __GIANFAR_MII_H | ||
20 | |||
21 | struct gfar_private; /* forward ref */ | ||
22 | |||
23 | #define MIIMIND_BUSY 0x00000001 | ||
24 | #define MIIMIND_NOTVALID 0x00000004 | ||
25 | |||
26 | #define MII_READ_COMMAND 0x00000001 | ||
27 | |||
28 | #define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \ | ||
29 | | SUPPORTED_10baseT_Full \ | ||
30 | | SUPPORTED_100baseT_Half \ | ||
31 | | SUPPORTED_100baseT_Full \ | ||
32 | | SUPPORTED_Autoneg \ | ||
33 | | SUPPORTED_MII) | ||
34 | |||
35 | struct gfar_mii { | ||
36 | u32 miimcfg; /* 0x.520 - MII Management Config Register */ | ||
37 | u32 miimcom; /* 0x.524 - MII Management Command Register */ | ||
38 | u32 miimadd; /* 0x.528 - MII Management Address Register */ | ||
39 | u32 miimcon; /* 0x.52c - MII Management Control Register */ | ||
40 | u32 miimstat; /* 0x.530 - MII Management Status Register */ | ||
41 | u32 miimind; /* 0x.534 - MII Management Indicator Register */ | ||
42 | }; | ||
43 | |||
44 | int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum); | ||
45 | int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); | ||
46 | int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, | ||
47 | int regnum, u16 value); | ||
48 | int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); | ||
49 | struct mii_bus *gfar_get_miibus(const struct gfar_private *priv); | ||
50 | int __init gfar_mdio_init(void); | ||
51 | void gfar_mdio_exit(void); | ||
52 | |||
53 | void gfar_mdio_bus_name(char *name, struct device_node *np); | ||
54 | #endif /* GIANFAR_PHY_H */ | ||
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 4a8d5747204a..1c095c63f98f 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/ucc_fast.h> | 39 | #include <asm/ucc_fast.h> |
40 | 40 | ||
41 | #include "ucc_geth.h" | 41 | #include "ucc_geth.h" |
42 | #include "ucc_geth_mii.h" | 42 | #include "fsl_pq_mdio.h" |
43 | 43 | ||
44 | #undef DEBUG | 44 | #undef DEBUG |
45 | 45 | ||
@@ -1557,7 +1557,7 @@ static int init_phy(struct net_device *dev) | |||
1557 | of_node_put(phy); | 1557 | of_node_put(phy); |
1558 | of_node_put(mdio); | 1558 | of_node_put(mdio); |
1559 | 1559 | ||
1560 | uec_mdio_bus_name(bus_name, mdio); | 1560 | fsl_pq_mdio_bus_name(bus_name, mdio); |
1561 | snprintf(phy_id, sizeof(phy_id), "%s:%02x", | 1561 | snprintf(phy_id, sizeof(phy_id), "%s:%02x", |
1562 | bus_name, *id); | 1562 | bus_name, *id); |
1563 | 1563 | ||
@@ -3657,7 +3657,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3657 | if (err) | 3657 | if (err) |
3658 | return -1; | 3658 | return -1; |
3659 | 3659 | ||
3660 | snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x", res.start); | 3660 | snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x", |
3661 | res.start&0xfffff); | ||
3661 | } | 3662 | } |
3662 | 3663 | ||
3663 | /* get the phy interface type, or default to MII */ | 3664 | /* get the phy interface type, or default to MII */ |
@@ -3803,11 +3804,6 @@ static int __init ucc_geth_init(void) | |||
3803 | { | 3804 | { |
3804 | int i, ret; | 3805 | int i, ret; |
3805 | 3806 | ||
3806 | ret = uec_mdio_init(); | ||
3807 | |||
3808 | if (ret) | ||
3809 | return ret; | ||
3810 | |||
3811 | if (netif_msg_drv(&debug)) | 3807 | if (netif_msg_drv(&debug)) |
3812 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); | 3808 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); |
3813 | for (i = 0; i < 8; i++) | 3809 | for (i = 0; i < 8; i++) |
@@ -3816,16 +3812,12 @@ static int __init ucc_geth_init(void) | |||
3816 | 3812 | ||
3817 | ret = of_register_platform_driver(&ucc_geth_driver); | 3813 | ret = of_register_platform_driver(&ucc_geth_driver); |
3818 | 3814 | ||
3819 | if (ret) | ||
3820 | uec_mdio_exit(); | ||
3821 | |||
3822 | return ret; | 3815 | return ret; |
3823 | } | 3816 | } |
3824 | 3817 | ||
3825 | static void __exit ucc_geth_exit(void) | 3818 | static void __exit ucc_geth_exit(void) |
3826 | { | 3819 | { |
3827 | of_unregister_platform_driver(&ucc_geth_driver); | 3820 | of_unregister_platform_driver(&ucc_geth_driver); |
3828 | uec_mdio_exit(); | ||
3829 | } | 3821 | } |
3830 | 3822 | ||
3831 | module_init(ucc_geth_init); | 3823 | module_init(ucc_geth_init); |
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 16cbe42ba43c..66d18971fa0c 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h | |||
@@ -28,8 +28,6 @@ | |||
28 | #include <asm/ucc.h> | 28 | #include <asm/ucc.h> |
29 | #include <asm/ucc_fast.h> | 29 | #include <asm/ucc_fast.h> |
30 | 30 | ||
31 | #include "ucc_geth_mii.h" | ||
32 | |||
33 | #define DRV_DESC "QE UCC Gigabit Ethernet Controller" | 31 | #define DRV_DESC "QE UCC Gigabit Ethernet Controller" |
34 | #define DRV_NAME "ucc_geth" | 32 | #define DRV_NAME "ucc_geth" |
35 | #define DRV_VERSION "1.1" | 33 | #define DRV_VERSION "1.1" |
@@ -184,6 +182,18 @@ struct ucc_geth { | |||
184 | #define UCCE_RX_EVENTS (UCCE_RXF | UCC_GETH_UCCE_BSY) | 182 | #define UCCE_RX_EVENTS (UCCE_RXF | UCC_GETH_UCCE_BSY) |
185 | #define UCCE_TX_EVENTS (UCCE_TXB | UCC_GETH_UCCE_TXE) | 183 | #define UCCE_TX_EVENTS (UCCE_TXB | UCC_GETH_UCCE_TXE) |
186 | 184 | ||
185 | /* TBI defines */ | ||
186 | #define ENET_TBI_MII_CR 0x00 /* Control */ | ||
187 | #define ENET_TBI_MII_SR 0x01 /* Status */ | ||
188 | #define ENET_TBI_MII_ANA 0x04 /* AN advertisement */ | ||
189 | #define ENET_TBI_MII_ANLPBPA 0x05 /* AN link partner base page ability */ | ||
190 | #define ENET_TBI_MII_ANEX 0x06 /* AN expansion */ | ||
191 | #define ENET_TBI_MII_ANNPT 0x07 /* AN next page transmit */ | ||
192 | #define ENET_TBI_MII_ANLPANP 0x08 /* AN link partner ability next page */ | ||
193 | #define ENET_TBI_MII_EXST 0x0F /* Extended status */ | ||
194 | #define ENET_TBI_MII_JD 0x10 /* Jitter diagnostics */ | ||
195 | #define ENET_TBI_MII_TBICON 0x11 /* TBI control */ | ||
196 | |||
187 | /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ | 197 | /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ |
188 | #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control | 198 | #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control |
189 | Rx */ | 199 | Rx */ |
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c index 68a7f5414133..a755bea559b9 100644 --- a/drivers/net/ucc_geth_ethtool.c +++ b/drivers/net/ucc_geth_ethtool.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <asm/types.h> | 39 | #include <asm/types.h> |
40 | 40 | ||
41 | #include "ucc_geth.h" | 41 | #include "ucc_geth.h" |
42 | #include "ucc_geth_mii.h" | ||
43 | 42 | ||
44 | static char hw_stat_gstrings[][ETH_GSTRING_LEN] = { | 43 | static char hw_stat_gstrings[][ETH_GSTRING_LEN] = { |
45 | "tx-64-frames", | 44 | "tx-64-frames", |
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c deleted file mode 100644 index 54635911305c..000000000000 --- a/drivers/net/ucc_geth_mii.c +++ /dev/null | |||
@@ -1,295 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/net/ucc_geth_mii.c | ||
3 | * | ||
4 | * QE UCC Gigabit Ethernet Driver -- MII Management Bus Implementation | ||
5 | * Provides Bus interface for MII Management regs in the UCC register space | ||
6 | * | ||
7 | * Copyright (C) 2007 Freescale Semiconductor, Inc. | ||
8 | * | ||
9 | * Authors: Li Yang <leoli@freescale.com> | ||
10 | * Kim Phillips <kim.phillips@freescale.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/unistd.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/netdevice.h> | ||
29 | #include <linux/etherdevice.h> | ||
30 | #include <linux/skbuff.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/crc32.h> | ||
36 | #include <linux/mii.h> | ||
37 | #include <linux/phy.h> | ||
38 | #include <linux/fsl_devices.h> | ||
39 | #include <linux/of_platform.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | #include <asm/irq.h> | ||
43 | #include <asm/uaccess.h> | ||
44 | #include <asm/ucc.h> | ||
45 | |||
46 | #include "ucc_geth_mii.h" | ||
47 | #include "ucc_geth.h" | ||
48 | |||
49 | #define DEBUG | ||
50 | #ifdef DEBUG | ||
51 | #define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg) | ||
52 | #else | ||
53 | #define vdbg(format, arg...) do {} while(0) | ||
54 | #endif | ||
55 | |||
56 | #define MII_DRV_DESC "QE UCC Ethernet Controller MII Bus" | ||
57 | #define MII_DRV_NAME "fsl-uec_mdio" | ||
58 | |||
59 | /* Write value to the PHY for this device to the register at regnum, */ | ||
60 | /* waiting until the write is done before it returns. All PHY */ | ||
61 | /* configuration has to be done through the master UEC MIIM regs */ | ||
62 | int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | ||
63 | { | ||
64 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
65 | |||
66 | /* Setting up the MII Mangement Address Register */ | ||
67 | out_be32(®s->miimadd, | ||
68 | (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); | ||
69 | |||
70 | /* Setting up the MII Mangement Control Register with the value */ | ||
71 | out_be32(®s->miimcon, value); | ||
72 | |||
73 | /* Wait till MII management write is complete */ | ||
74 | while ((in_be32(®s->miimind)) & MIIMIND_BUSY) | ||
75 | cpu_relax(); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* Reads from register regnum in the PHY for device dev, */ | ||
81 | /* returning the value. Clears miimcom first. All PHY */ | ||
82 | /* configuration has to be done through the TSEC1 MIIM regs */ | ||
83 | int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | ||
84 | { | ||
85 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
86 | u16 value; | ||
87 | |||
88 | /* Setting up the MII Mangement Address Register */ | ||
89 | out_be32(®s->miimadd, | ||
90 | (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); | ||
91 | |||
92 | /* Clear miimcom, perform an MII management read cycle */ | ||
93 | out_be32(®s->miimcom, 0); | ||
94 | out_be32(®s->miimcom, MIIMCOM_READ_CYCLE); | ||
95 | |||
96 | /* Wait till MII management write is complete */ | ||
97 | while ((in_be32(®s->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID)) | ||
98 | cpu_relax(); | ||
99 | |||
100 | /* Read MII management status */ | ||
101 | value = in_be32(®s->miimstat); | ||
102 | |||
103 | return value; | ||
104 | } | ||
105 | |||
106 | /* Reset the MIIM registers, and wait for the bus to free */ | ||
107 | static int uec_mdio_reset(struct mii_bus *bus) | ||
108 | { | ||
109 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
110 | unsigned int timeout = PHY_INIT_TIMEOUT; | ||
111 | |||
112 | mutex_lock(&bus->mdio_lock); | ||
113 | |||
114 | /* Reset the management interface */ | ||
115 | out_be32(®s->miimcfg, MIIMCFG_RESET_MANAGEMENT); | ||
116 | |||
117 | /* Setup the MII Mgmt clock speed */ | ||
118 | out_be32(®s->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112); | ||
119 | |||
120 | /* Wait until the bus is free */ | ||
121 | while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) | ||
122 | cpu_relax(); | ||
123 | |||
124 | mutex_unlock(&bus->mdio_lock); | ||
125 | |||
126 | if (timeout <= 0) { | ||
127 | printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name); | ||
128 | return -EBUSY; | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) | ||
135 | { | ||
136 | struct device *device = &ofdev->dev; | ||
137 | struct device_node *np = ofdev->node, *tempnp = NULL; | ||
138 | struct device_node *child = NULL; | ||
139 | struct ucc_mii_mng __iomem *regs; | ||
140 | struct mii_bus *new_bus; | ||
141 | struct resource res; | ||
142 | int k, err = 0; | ||
143 | |||
144 | new_bus = mdiobus_alloc(); | ||
145 | if (NULL == new_bus) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | new_bus->name = "UCC Ethernet Controller MII Bus"; | ||
149 | new_bus->read = &uec_mdio_read; | ||
150 | new_bus->write = &uec_mdio_write; | ||
151 | new_bus->reset = &uec_mdio_reset; | ||
152 | |||
153 | memset(&res, 0, sizeof(res)); | ||
154 | |||
155 | err = of_address_to_resource(np, 0, &res); | ||
156 | if (err) | ||
157 | goto reg_map_fail; | ||
158 | |||
159 | uec_mdio_bus_name(new_bus->id, np); | ||
160 | |||
161 | new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL); | ||
162 | |||
163 | if (NULL == new_bus->irq) { | ||
164 | err = -ENOMEM; | ||
165 | goto reg_map_fail; | ||
166 | } | ||
167 | |||
168 | for (k = 0; k < 32; k++) | ||
169 | new_bus->irq[k] = PHY_POLL; | ||
170 | |||
171 | while ((child = of_get_next_child(np, child)) != NULL) { | ||
172 | int irq = irq_of_parse_and_map(child, 0); | ||
173 | if (irq != NO_IRQ) { | ||
174 | const u32 *id = of_get_property(child, "reg", NULL); | ||
175 | new_bus->irq[*id] = irq; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | /* Set the base address */ | ||
180 | regs = ioremap(res.start, sizeof(struct ucc_mii_mng)); | ||
181 | |||
182 | if (NULL == regs) { | ||
183 | err = -ENOMEM; | ||
184 | goto ioremap_fail; | ||
185 | } | ||
186 | |||
187 | new_bus->priv = (void __force *)regs; | ||
188 | |||
189 | new_bus->parent = device; | ||
190 | dev_set_drvdata(device, new_bus); | ||
191 | |||
192 | /* Read MII management master from device tree */ | ||
193 | while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth")) | ||
194 | != NULL) { | ||
195 | struct resource tempres; | ||
196 | |||
197 | err = of_address_to_resource(tempnp, 0, &tempres); | ||
198 | if (err) | ||
199 | goto bus_register_fail; | ||
200 | |||
201 | /* if our mdio regs fall within this UCC regs range */ | ||
202 | if ((res.start >= tempres.start) && | ||
203 | (res.end <= tempres.end)) { | ||
204 | /* set this UCC to be the MII master */ | ||
205 | const u32 *id; | ||
206 | |||
207 | id = of_get_property(tempnp, "cell-index", NULL); | ||
208 | if (!id) { | ||
209 | id = of_get_property(tempnp, "device-id", NULL); | ||
210 | if (!id) | ||
211 | goto bus_register_fail; | ||
212 | } | ||
213 | |||
214 | ucc_set_qe_mux_mii_mng(*id - 1); | ||
215 | |||
216 | /* assign the TBI an address which won't | ||
217 | * conflict with the PHYs */ | ||
218 | out_be32(®s->utbipar, UTBIPAR_INIT_TBIPA); | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | err = mdiobus_register(new_bus); | ||
224 | if (0 != err) { | ||
225 | printk(KERN_ERR "%s: Cannot register as MDIO bus\n", | ||
226 | new_bus->name); | ||
227 | goto bus_register_fail; | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | |||
232 | bus_register_fail: | ||
233 | iounmap(regs); | ||
234 | ioremap_fail: | ||
235 | kfree(new_bus->irq); | ||
236 | reg_map_fail: | ||
237 | mdiobus_free(new_bus); | ||
238 | |||
239 | return err; | ||
240 | } | ||
241 | |||
242 | static int uec_mdio_remove(struct of_device *ofdev) | ||
243 | { | ||
244 | struct device *device = &ofdev->dev; | ||
245 | struct mii_bus *bus = dev_get_drvdata(device); | ||
246 | |||
247 | mdiobus_unregister(bus); | ||
248 | |||
249 | dev_set_drvdata(device, NULL); | ||
250 | |||
251 | iounmap((void __iomem *)bus->priv); | ||
252 | bus->priv = NULL; | ||
253 | mdiobus_free(bus); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static struct of_device_id uec_mdio_match[] = { | ||
259 | { | ||
260 | .type = "mdio", | ||
261 | .compatible = "ucc_geth_phy", | ||
262 | }, | ||
263 | { | ||
264 | .compatible = "fsl,ucc-mdio", | ||
265 | }, | ||
266 | {}, | ||
267 | }; | ||
268 | |||
269 | static struct of_platform_driver uec_mdio_driver = { | ||
270 | .name = MII_DRV_NAME, | ||
271 | .probe = uec_mdio_probe, | ||
272 | .remove = uec_mdio_remove, | ||
273 | .match_table = uec_mdio_match, | ||
274 | }; | ||
275 | |||
276 | int __init uec_mdio_init(void) | ||
277 | { | ||
278 | return of_register_platform_driver(&uec_mdio_driver); | ||
279 | } | ||
280 | |||
281 | /* called from __init ucc_geth_init, therefore can not be __exit */ | ||
282 | void uec_mdio_exit(void) | ||
283 | { | ||
284 | of_unregister_platform_driver(&uec_mdio_driver); | ||
285 | } | ||
286 | |||
287 | void uec_mdio_bus_name(char *name, struct device_node *np) | ||
288 | { | ||
289 | const u32 *reg; | ||
290 | |||
291 | reg = of_get_property(np, "reg", NULL); | ||
292 | |||
293 | snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0); | ||
294 | } | ||
295 | |||
diff --git a/drivers/net/ucc_geth_mii.h b/drivers/net/ucc_geth_mii.h deleted file mode 100644 index 840cf80235b7..000000000000 --- a/drivers/net/ucc_geth_mii.h +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/net/ucc_geth_mii.h | ||
3 | * | ||
4 | * QE UCC Gigabit Ethernet Driver -- MII Management Bus Implementation | ||
5 | * Provides Bus interface for MII Management regs in the UCC register space | ||
6 | * | ||
7 | * Copyright (C) 2007 Freescale Semiconductor, Inc. | ||
8 | * | ||
9 | * Authors: Li Yang <leoli@freescale.com> | ||
10 | * Kim Phillips <kim.phillips@freescale.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | */ | ||
18 | #ifndef __UEC_MII_H | ||
19 | #define __UEC_MII_H | ||
20 | |||
21 | /* UCC GETH MIIMCFG (MII Management Configuration Register) */ | ||
22 | #define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset | ||
23 | management */ | ||
24 | #define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble | ||
25 | suppress */ | ||
26 | #define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide | ||
27 | << shift */ | ||
28 | #define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* max clock divide */ | ||
29 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 | ||
30 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 | ||
31 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 | ||
32 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 | ||
33 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 | ||
34 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 | ||
35 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 | ||
36 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 | ||
37 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 | ||
38 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 | ||
39 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a | ||
40 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b | ||
41 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c | ||
42 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d | ||
43 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e | ||
44 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f | ||
45 | |||
46 | /* UCC GETH MIIMCOM (MII Management Command Register) */ | ||
47 | #define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ | ||
48 | #define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ | ||
49 | |||
50 | /* UCC GETH MIIMADD (MII Management Address Register) */ | ||
51 | #define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address | ||
52 | << shift */ | ||
53 | #define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register | ||
54 | << shift */ | ||
55 | |||
56 | /* UCC GETH MIIMCON (MII Management Control Register) */ | ||
57 | #define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control | ||
58 | << shift */ | ||
59 | #define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status | ||
60 | << shift */ | ||
61 | |||
62 | /* UCC GETH MIIMIND (MII Management Indicator Register) */ | ||
63 | #define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ | ||
64 | #define MIIMIND_SCAN 0x00000002 /* Scan in | ||
65 | progress */ | ||
66 | #define MIIMIND_BUSY 0x00000001 | ||
67 | |||
68 | /* Initial TBI Physical Address */ | ||
69 | #define UTBIPAR_INIT_TBIPA 0x1f | ||
70 | |||
71 | struct ucc_mii_mng { | ||
72 | u32 miimcfg; /* MII management configuration reg */ | ||
73 | u32 miimcom; /* MII management command reg */ | ||
74 | u32 miimadd; /* MII management address reg */ | ||
75 | u32 miimcon; /* MII management control reg */ | ||
76 | u32 miimstat; /* MII management status reg */ | ||
77 | u32 miimind; /* MII management indication reg */ | ||
78 | u8 notcare[28]; /* Space holder */ | ||
79 | u32 utbipar; /* TBI phy address reg */ | ||
80 | } __attribute__ ((packed)); | ||
81 | |||
82 | /* TBI / MII Set Register */ | ||
83 | enum enet_tbi_mii_reg { | ||
84 | ENET_TBI_MII_CR = 0x00, /* Control */ | ||
85 | ENET_TBI_MII_SR = 0x01, /* Status */ | ||
86 | ENET_TBI_MII_ANA = 0x04, /* AN advertisement */ | ||
87 | ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability */ | ||
88 | ENET_TBI_MII_ANEX = 0x06, /* AN expansion */ | ||
89 | ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit */ | ||
90 | ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page */ | ||
91 | ENET_TBI_MII_EXST = 0x0F, /* Extended status */ | ||
92 | ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */ | ||
93 | ENET_TBI_MII_TBICON = 0x11 /* TBI control */ | ||
94 | }; | ||
95 | |||
96 | int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum); | ||
97 | int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); | ||
98 | int __init uec_mdio_init(void); | ||
99 | void uec_mdio_exit(void); | ||
100 | void uec_mdio_bus_name(char *name, struct device_node *np); | ||
101 | #endif /* __UEC_MII_H */ | ||