aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/fs_enet/mii-bitbang.c
diff options
context:
space:
mode:
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}