aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/fs_enet/mii-bitbang.c
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2007-10-02 11:55:58 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:54:03 -0400
commit976de6a8c304dcc43e38efcb8a0bace7866b6242 (patch)
treebae132693bbcfa65c03cf44c7db924fdebf13158 /drivers/net/fs_enet/mii-bitbang.c
parent0d0d9c150c046cbd3e507adcfa2d78db82f1f452 (diff)
fs_enet: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set.
The existing OF glue code was crufty and broken. Rather than fix it, it will be removed, and the ethernet driver now talks to the device tree directly. The old, non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM platforms are dropped from arch/ppc (which will hopefully be soon), and existing arch/powerpc boards that I wasn't able to test on for this patchset get converted (which should be even sooner). Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/fs_enet/mii-bitbang.c')
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c269
1 files changed, 202 insertions, 67 deletions
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 422f82877873..7cf132f0f952 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -13,11 +13,6 @@
13 */ 13 */
14 14
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/ptrace.h>
20#include <linux/errno.h>
21#include <linux/ioport.h> 16#include <linux/ioport.h>
22#include <linux/slab.h> 17#include <linux/slab.h>
23#include <linux/interrupt.h> 18#include <linux/interrupt.h>
@@ -25,86 +20,77 @@
25#include <linux/delay.h> 20#include <linux/delay.h>
26#include <linux/netdevice.h> 21#include <linux/netdevice.h>
27#include <linux/etherdevice.h> 22#include <linux/etherdevice.h>
28#include <linux/skbuff.h>
29#include <linux/spinlock.h>
30#include <linux/mii.h> 23#include <linux/mii.h>
31#include <linux/ethtool.h> 24#include <linux/ethtool.h>
32#include <linux/bitops.h> 25#include <linux/bitops.h>
33#include <linux/platform_device.h> 26#include <linux/platform_device.h>
34 27
35#include <asm/pgtable.h> 28#ifdef CONFIG_PPC_CPM_NEW_BINDING
36#include <asm/irq.h> 29#include <linux/of_platform.h>
37#include <asm/uaccess.h> 30#endif
38 31
39#include "fs_enet.h" 32#include "fs_enet.h"
40 33
41static int bitbang_prep_bit(u8 **datp, u8 *mskp, 34struct bb_info {
42 struct fs_mii_bit *mii_bit) 35 __be32 __iomem *dir;
43{ 36 __be32 __iomem *dat;
44 void *dat; 37 u32 mdio_msk;
45 int adv; 38 u32 mdc_msk;
46 u8 msk; 39 int delay;
47 40};
48 dat = (void*) mii_bit->offset;
49
50 adv = mii_bit->bit >> 3;
51 dat = (char *)dat + adv;
52
53 msk = 1 << (7 - (mii_bit->bit & 7));
54
55 *datp = dat;
56 *mskp = msk;
57
58 return 0;
59}
60 41
61static inline void bb_set(u8 *p, u8 m) 42/* FIXME: If any other users of GPIO crop up, then these will have to
43 * have some sort of global synchronization to avoid races with other
44 * pins on the same port. The ideal solution would probably be to
45 * bind the ports to a GPIO driver, and have this be a client of it.
46 */
47static inline void bb_set(u32 __iomem *p, u32 m)
62{ 48{
63 out_8(p, in_8(p) | m); 49 out_be32(p, in_be32(p) | m);
64} 50}
65 51
66static inline void bb_clr(u8 *p, u8 m) 52static inline void bb_clr(u32 __iomem *p, u32 m)
67{ 53{
68 out_8(p, in_8(p) & ~m); 54 out_be32(p, in_be32(p) & ~m);
69} 55}
70 56
71static inline int bb_read(u8 *p, u8 m) 57static inline int bb_read(u32 __iomem *p, u32 m)
72{ 58{
73 return (in_8(p) & m) != 0; 59 return (in_be32(p) & m) != 0;
74} 60}
75 61
76static inline void mdio_active(struct bb_info *bitbang) 62static inline void mdio_active(struct bb_info *bitbang)
77{ 63{
78 bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk); 64 bb_set(bitbang->dir, bitbang->mdio_msk);
79} 65}
80 66
81static inline void mdio_tristate(struct bb_info *bitbang ) 67static inline void mdio_tristate(struct bb_info *bitbang)
82{ 68{
83 bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk); 69 bb_clr(bitbang->dir, bitbang->mdio_msk);
84} 70}
85 71
86static inline int mdio_read(struct bb_info *bitbang ) 72static inline int mdio_read(struct bb_info *bitbang)
87{ 73{
88 return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk); 74 return bb_read(bitbang->dat, bitbang->mdio_msk);
89} 75}
90 76
91static inline void mdio(struct bb_info *bitbang , int what) 77static inline void mdio(struct bb_info *bitbang, int what)
92{ 78{
93 if (what) 79 if (what)
94 bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk); 80 bb_set(bitbang->dat, bitbang->mdio_msk);
95 else 81 else
96 bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk); 82 bb_clr(bitbang->dat, bitbang->mdio_msk);
97} 83}
98 84
99static inline void mdc(struct bb_info *bitbang , int what) 85static inline void mdc(struct bb_info *bitbang, int what)
100{ 86{
101 if (what) 87 if (what)
102 bb_set(bitbang->mdc_dat, bitbang->mdc_msk); 88 bb_set(bitbang->dat, bitbang->mdc_msk);
103 else 89 else
104 bb_clr(bitbang->mdc_dat, bitbang->mdc_msk); 90 bb_clr(bitbang->dat, bitbang->mdc_msk);
105} 91}
106 92
107static inline void mii_delay(struct bb_info *bitbang ) 93static inline void mii_delay(struct bb_info *bitbang)
108{ 94{
109 udelay(bitbang->delay); 95 udelay(bitbang->delay);
110} 96}
@@ -280,29 +266,178 @@ static int fs_enet_mii_bb_reset(struct mii_bus *bus)
280 return 0; 266 return 0;
281} 267}
282 268
283static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi) 269#ifdef CONFIG_PPC_CPM_NEW_BINDING
270static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
271 struct device_node *np)
284{ 272{
285 int r; 273 struct resource res;
274 const u32 *data;
275 int mdio_pin, mdc_pin, len;
276 struct bb_info *bitbang = bus->priv;
286 277
287 bitbang->delay = fmpi->delay; 278 int ret = of_address_to_resource(np, 0, &res);
279 if (ret)
280 return ret;
281
282 if (res.end - res.start < 13)
283 return -ENODEV;
284
285 /* This should really encode the pin number as well, but all
286 * we get is an int, and the odds of multiple bitbang mdio buses
287 * is low enough that it's not worth going too crazy.
288 */
289 bus->id = res.start;
290
291 data = of_get_property(np, "fsl,mdio-pin", &len);
292 if (!data || len != 4)
293 return -ENODEV;
294 mdio_pin = *data;
295
296 data = of_get_property(np, "fsl,mdc-pin", &len);
297 if (!data || len != 4)
298 return -ENODEV;
299 mdc_pin = *data;
300
301 bitbang->dir = ioremap(res.start, res.end - res.start + 1);
302 if (!bitbang->dir)
303 return -ENOMEM;
304
305 bitbang->dat = bitbang->dir + 4;
306 bitbang->mdio_msk = 1 << (31 - mdio_pin);
307 bitbang->mdc_msk = 1 << (31 - mdc_pin);
308 bitbang->delay = 1; /* 1 us between operations */
288 309
289 r = bitbang_prep_bit(&bitbang->mdio_dir, 310 return 0;
290 &bitbang->mdio_dir_msk, 311}
291 &fmpi->mdio_dir); 312
292 if (r != 0) 313static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
293 return r; 314{
294 315 const u32 *data;
295 r = bitbang_prep_bit(&bitbang->mdio_dat, 316 int len, id, irq;
296 &bitbang->mdio_dat_msk, 317
297 &fmpi->mdio_dat); 318 data = of_get_property(np, "reg", &len);
298 if (r != 0) 319 if (!data || len != 4)
299 return r; 320 return;
300 321
301 r = bitbang_prep_bit(&bitbang->mdc_dat, 322 id = *data;
302 &bitbang->mdc_msk, 323 bus->phy_mask &= ~(1 << id);
303 &fmpi->mdc_dat); 324
304 if (r != 0) 325 irq = of_irq_to_resource(np, 0, NULL);
305 return r; 326 if (irq != NO_IRQ)
327 bus->irq[id] = irq;
328}
329
330static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
331 const struct of_device_id *match)
332{
333 struct device_node *np = NULL;
334 struct mii_bus *new_bus;
335 struct bb_info *bitbang;
336 int ret = -ENOMEM;
337 int i;
338
339 new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
340 if (!new_bus)
341 goto out;
342
343 bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
344 if (!bitbang)
345 goto out_free_bus;
346
347 new_bus->priv = bitbang;
348 new_bus->name = "CPM2 Bitbanged MII",
349 new_bus->read = &fs_enet_mii_bb_read,
350 new_bus->write = &fs_enet_mii_bb_write,
351 new_bus->reset = &fs_enet_mii_bb_reset,
352
353 ret = fs_mii_bitbang_init(new_bus, ofdev->node);
354 if (ret)
355 goto out_free_bitbang;
356
357 new_bus->phy_mask = ~0;
358 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
359 if (!new_bus->irq)
360 goto out_unmap_regs;
361
362 for (i = 0; i < PHY_MAX_ADDR; i++)
363 new_bus->irq[i] = -1;
364
365 while ((np = of_get_next_child(ofdev->node, np)))
366 if (!strcmp(np->type, "ethernet-phy"))
367 add_phy(new_bus, np);
368
369 new_bus->dev = &ofdev->dev;
370 dev_set_drvdata(&ofdev->dev, new_bus);
371
372 ret = mdiobus_register(new_bus);
373 if (ret)
374 goto out_free_irqs;
375
376 return 0;
377
378out_free_irqs:
379 dev_set_drvdata(&ofdev->dev, NULL);
380 kfree(new_bus->irq);
381out_unmap_regs:
382 iounmap(bitbang->dir);
383out_free_bitbang:
384 kfree(bitbang);
385out_free_bus:
386 kfree(new_bus);
387out:
388 return ret;
389}
390
391static int fs_enet_mdio_remove(struct of_device *ofdev)
392{
393 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
394 struct bb_info *bitbang = bus->priv;
395
396 mdiobus_unregister(bus);
397 dev_set_drvdata(&ofdev->dev, NULL);
398 kfree(bus->irq);
399 iounmap(bitbang->dir);
400 kfree(bitbang);
401 kfree(bus);
402
403 return 0;
404}
405
406static struct of_device_id fs_enet_mdio_bb_match[] = {
407 {
408 .compatible = "fsl,cpm2-mdio-bitbang",
409 },
410 {},
411};
412
413static struct of_platform_driver fs_enet_bb_mdio_driver = {
414 .name = "fsl-bb-mdio",
415 .match_table = fs_enet_mdio_bb_match,
416 .probe = fs_enet_mdio_probe,
417 .remove = fs_enet_mdio_remove,
418};
419
420int fs_enet_mdio_bb_init(void)
421{
422 return of_register_platform_driver(&fs_enet_bb_mdio_driver);
423}
424
425void fs_enet_mdio_bb_exit(void)
426{
427 of_unregister_platform_driver(&fs_enet_bb_mdio_driver);
428}
429
430module_init(fs_enet_mdio_bb_init);
431module_exit(fs_enet_mdio_bb_exit);
432#else
433static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang,
434 struct fs_mii_bb_platform_info *fmpi)
435{
436 bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset;
437 bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset;
438 bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit);
439 bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit);
440 bitbang->delay = fmpi->delay;
306 441
307 return 0; 442 return 0;
308} 443}