diff options
author | Scott Wood <scottwood@freescale.com> | 2007-10-01 15:20:57 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:54:04 -0400 |
commit | 2b5b3a604a672be1d41728ed9e448ca3c9c23242 (patch) | |
tree | f396075face85b4a686ef59adc4a9df0120dd01f /drivers/net | |
parent | e2ec4581adf7e288c193e981c39ca01cdb20a272 (diff) |
fs_enet: Convert mii-bitbang to use the generic bitbang MDIO code.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/fs_enet/mii-bitbang.c | 270 |
1 files changed, 54 insertions, 216 deletions
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 7cf132f0f952..b8e4a736a130 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c | |||
@@ -15,15 +15,13 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/ioport.h> | 16 | #include <linux/ioport.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/init.h> | 18 | #include <linux/init.h> |
20 | #include <linux/delay.h> | 19 | #include <linux/interrupt.h> |
21 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
22 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
23 | #include <linux/mii.h> | 22 | #include <linux/mii.h> |
24 | #include <linux/ethtool.h> | ||
25 | #include <linux/bitops.h> | ||
26 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/mdio-bitbang.h> | ||
27 | 25 | ||
28 | #ifdef CONFIG_PPC_CPM_NEW_BINDING | 26 | #ifdef CONFIG_PPC_CPM_NEW_BINDING |
29 | #include <linux/of_platform.h> | 27 | #include <linux/of_platform.h> |
@@ -32,11 +30,11 @@ | |||
32 | #include "fs_enet.h" | 30 | #include "fs_enet.h" |
33 | 31 | ||
34 | struct bb_info { | 32 | struct bb_info { |
33 | struct mdiobb_ctrl ctrl; | ||
35 | __be32 __iomem *dir; | 34 | __be32 __iomem *dir; |
36 | __be32 __iomem *dat; | 35 | __be32 __iomem *dat; |
37 | u32 mdio_msk; | 36 | u32 mdio_msk; |
38 | u32 mdc_msk; | 37 | u32 mdc_msk; |
39 | int delay; | ||
40 | }; | 38 | }; |
41 | 39 | ||
42 | /* FIXME: If any other users of GPIO crop up, then these will have to | 40 | /* FIXME: If any other users of GPIO crop up, then these will have to |
@@ -59,212 +57,58 @@ static inline int bb_read(u32 __iomem *p, u32 m) | |||
59 | return (in_be32(p) & m) != 0; | 57 | return (in_be32(p) & m) != 0; |
60 | } | 58 | } |
61 | 59 | ||
62 | static inline void mdio_active(struct bb_info *bitbang) | 60 | static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) |
63 | { | 61 | { |
64 | bb_set(bitbang->dir, bitbang->mdio_msk); | 62 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); |
65 | } | ||
66 | 63 | ||
67 | static inline void mdio_tristate(struct bb_info *bitbang) | 64 | if (dir) |
68 | { | 65 | bb_set(bitbang->dir, bitbang->mdio_msk); |
69 | bb_clr(bitbang->dir, bitbang->mdio_msk); | 66 | else |
67 | bb_clr(bitbang->dir, bitbang->mdio_msk); | ||
68 | |||
69 | /* Read back to flush the write. */ | ||
70 | in_be32(bitbang->dir); | ||
70 | } | 71 | } |
71 | 72 | ||
72 | static inline int mdio_read(struct bb_info *bitbang) | 73 | static inline int mdio_read(struct mdiobb_ctrl *ctrl) |
73 | { | 74 | { |
75 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
74 | return bb_read(bitbang->dat, bitbang->mdio_msk); | 76 | return bb_read(bitbang->dat, bitbang->mdio_msk); |
75 | } | 77 | } |
76 | 78 | ||
77 | static inline void mdio(struct bb_info *bitbang, int what) | 79 | static inline void mdio(struct mdiobb_ctrl *ctrl, int what) |
78 | { | 80 | { |
81 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
82 | |||
79 | if (what) | 83 | if (what) |
80 | bb_set(bitbang->dat, bitbang->mdio_msk); | 84 | bb_set(bitbang->dat, bitbang->mdio_msk); |
81 | else | 85 | else |
82 | bb_clr(bitbang->dat, bitbang->mdio_msk); | 86 | bb_clr(bitbang->dat, bitbang->mdio_msk); |
87 | |||
88 | /* Read back to flush the write. */ | ||
89 | in_be32(bitbang->dat); | ||
83 | } | 90 | } |
84 | 91 | ||
85 | static inline void mdc(struct bb_info *bitbang, int what) | 92 | static inline void mdc(struct mdiobb_ctrl *ctrl, int what) |
86 | { | 93 | { |
94 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
95 | |||
87 | if (what) | 96 | if (what) |
88 | bb_set(bitbang->dat, bitbang->mdc_msk); | 97 | bb_set(bitbang->dat, bitbang->mdc_msk); |
89 | else | 98 | else |
90 | bb_clr(bitbang->dat, bitbang->mdc_msk); | 99 | bb_clr(bitbang->dat, bitbang->mdc_msk); |
91 | } | ||
92 | |||
93 | static inline void mii_delay(struct bb_info *bitbang) | ||
94 | { | ||
95 | udelay(bitbang->delay); | ||
96 | } | ||
97 | |||
98 | /* Utility to send the preamble, address, and register (common to read and write). */ | ||
99 | static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg) | ||
100 | { | ||
101 | int j; | ||
102 | |||
103 | /* | ||
104 | * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. | ||
105 | * The IEEE spec says this is a PHY optional requirement. The AMD | ||
106 | * 79C874 requires one after power up and one after a MII communications | ||
107 | * error. This means that we are doing more preambles than we need, | ||
108 | * but it is safer and will be much more robust. | ||
109 | */ | ||
110 | |||
111 | mdio_active(bitbang); | ||
112 | mdio(bitbang, 1); | ||
113 | for (j = 0; j < 32; j++) { | ||
114 | mdc(bitbang, 0); | ||
115 | mii_delay(bitbang); | ||
116 | mdc(bitbang, 1); | ||
117 | mii_delay(bitbang); | ||
118 | } | ||
119 | |||
120 | /* send the start bit (01) and the read opcode (10) or write (10) */ | ||
121 | mdc(bitbang, 0); | ||
122 | mdio(bitbang, 0); | ||
123 | mii_delay(bitbang); | ||
124 | mdc(bitbang, 1); | ||
125 | mii_delay(bitbang); | ||
126 | mdc(bitbang, 0); | ||
127 | mdio(bitbang, 1); | ||
128 | mii_delay(bitbang); | ||
129 | mdc(bitbang, 1); | ||
130 | mii_delay(bitbang); | ||
131 | mdc(bitbang, 0); | ||
132 | mdio(bitbang, read); | ||
133 | mii_delay(bitbang); | ||
134 | mdc(bitbang, 1); | ||
135 | mii_delay(bitbang); | ||
136 | mdc(bitbang, 0); | ||
137 | mdio(bitbang, !read); | ||
138 | mii_delay(bitbang); | ||
139 | mdc(bitbang, 1); | ||
140 | mii_delay(bitbang); | ||
141 | |||
142 | /* send the PHY address */ | ||
143 | for (j = 0; j < 5; j++) { | ||
144 | mdc(bitbang, 0); | ||
145 | mdio(bitbang, (addr & 0x10) != 0); | ||
146 | mii_delay(bitbang); | ||
147 | mdc(bitbang, 1); | ||
148 | mii_delay(bitbang); | ||
149 | addr <<= 1; | ||
150 | } | ||
151 | 100 | ||
152 | /* send the register address */ | 101 | /* Read back to flush the write. */ |
153 | for (j = 0; j < 5; j++) { | 102 | in_be32(bitbang->dat); |
154 | mdc(bitbang, 0); | ||
155 | mdio(bitbang, (reg & 0x10) != 0); | ||
156 | mii_delay(bitbang); | ||
157 | mdc(bitbang, 1); | ||
158 | mii_delay(bitbang); | ||
159 | reg <<= 1; | ||
160 | } | ||
161 | } | 103 | } |
162 | 104 | ||
163 | static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location) | 105 | static struct mdiobb_ops bb_ops = { |
164 | { | 106 | .owner = THIS_MODULE, |
165 | u16 rdreg; | 107 | .set_mdc = mdc, |
166 | int ret, j; | 108 | .set_mdio_dir = mdio_dir, |
167 | u8 addr = phy_id & 0xff; | 109 | .set_mdio_data = mdio, |
168 | u8 reg = location & 0xff; | 110 | .get_mdio_data = mdio_read, |
169 | struct bb_info* bitbang = bus->priv; | 111 | }; |
170 | |||
171 | bitbang_pre(bitbang, 1, addr, reg); | ||
172 | |||
173 | /* tri-state our MDIO I/O pin so we can read */ | ||
174 | mdc(bitbang, 0); | ||
175 | mdio_tristate(bitbang); | ||
176 | mii_delay(bitbang); | ||
177 | mdc(bitbang, 1); | ||
178 | mii_delay(bitbang); | ||
179 | |||
180 | /* check the turnaround bit: the PHY should be driving it to zero */ | ||
181 | if (mdio_read(bitbang) != 0) { | ||
182 | /* PHY didn't drive TA low */ | ||
183 | for (j = 0; j < 32; j++) { | ||
184 | mdc(bitbang, 0); | ||
185 | mii_delay(bitbang); | ||
186 | mdc(bitbang, 1); | ||
187 | mii_delay(bitbang); | ||
188 | } | ||
189 | ret = -1; | ||
190 | goto out; | ||
191 | } | ||
192 | |||
193 | mdc(bitbang, 0); | ||
194 | mii_delay(bitbang); | ||
195 | |||
196 | /* read 16 bits of register data, MSB first */ | ||
197 | rdreg = 0; | ||
198 | for (j = 0; j < 16; j++) { | ||
199 | mdc(bitbang, 1); | ||
200 | mii_delay(bitbang); | ||
201 | rdreg <<= 1; | ||
202 | rdreg |= mdio_read(bitbang); | ||
203 | mdc(bitbang, 0); | ||
204 | mii_delay(bitbang); | ||
205 | } | ||
206 | |||
207 | mdc(bitbang, 1); | ||
208 | mii_delay(bitbang); | ||
209 | mdc(bitbang, 0); | ||
210 | mii_delay(bitbang); | ||
211 | mdc(bitbang, 1); | ||
212 | mii_delay(bitbang); | ||
213 | |||
214 | ret = rdreg; | ||
215 | out: | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val) | ||
220 | { | ||
221 | int j; | ||
222 | struct bb_info* bitbang = bus->priv; | ||
223 | |||
224 | u8 addr = phy_id & 0xff; | ||
225 | u8 reg = location & 0xff; | ||
226 | u16 value = val & 0xffff; | ||
227 | |||
228 | bitbang_pre(bitbang, 0, addr, reg); | ||
229 | |||
230 | /* send the turnaround (10) */ | ||
231 | mdc(bitbang, 0); | ||
232 | mdio(bitbang, 1); | ||
233 | mii_delay(bitbang); | ||
234 | mdc(bitbang, 1); | ||
235 | mii_delay(bitbang); | ||
236 | mdc(bitbang, 0); | ||
237 | mdio(bitbang, 0); | ||
238 | mii_delay(bitbang); | ||
239 | mdc(bitbang, 1); | ||
240 | mii_delay(bitbang); | ||
241 | |||
242 | /* write 16 bits of register data, MSB first */ | ||
243 | for (j = 0; j < 16; j++) { | ||
244 | mdc(bitbang, 0); | ||
245 | mdio(bitbang, (value & 0x8000) != 0); | ||
246 | mii_delay(bitbang); | ||
247 | mdc(bitbang, 1); | ||
248 | mii_delay(bitbang); | ||
249 | value <<= 1; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Tri-state the MDIO line. | ||
254 | */ | ||
255 | mdio_tristate(bitbang); | ||
256 | mdc(bitbang, 0); | ||
257 | mii_delay(bitbang); | ||
258 | mdc(bitbang, 1); | ||
259 | mii_delay(bitbang); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int fs_enet_mii_bb_reset(struct mii_bus *bus) | ||
264 | { | ||
265 | /*nothing here - dunno how to reset it*/ | ||
266 | return 0; | ||
267 | } | ||
268 | 112 | ||
269 | #ifdef CONFIG_PPC_CPM_NEW_BINDING | 113 | #ifdef CONFIG_PPC_CPM_NEW_BINDING |
270 | static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, | 114 | static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, |
@@ -305,7 +149,6 @@ static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, | |||
305 | bitbang->dat = bitbang->dir + 4; | 149 | bitbang->dat = bitbang->dir + 4; |
306 | bitbang->mdio_msk = 1 << (31 - mdio_pin); | 150 | bitbang->mdio_msk = 1 << (31 - mdio_pin); |
307 | bitbang->mdc_msk = 1 << (31 - mdc_pin); | 151 | bitbang->mdc_msk = 1 << (31 - mdc_pin); |
308 | bitbang->delay = 1; /* 1 us between operations */ | ||
309 | 152 | ||
310 | return 0; | 153 | return 0; |
311 | } | 154 | } |
@@ -336,23 +179,21 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, | |||
336 | int ret = -ENOMEM; | 179 | int ret = -ENOMEM; |
337 | int i; | 180 | int i; |
338 | 181 | ||
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); | 182 | bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); |
344 | if (!bitbang) | 183 | if (!bitbang) |
345 | goto out_free_bus; | 184 | goto out; |
185 | |||
186 | bitbang->ctrl.ops = &bb_ops; | ||
187 | |||
188 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); | ||
189 | if (!new_bus) | ||
190 | goto out_free_priv; | ||
346 | 191 | ||
347 | new_bus->priv = bitbang; | ||
348 | new_bus->name = "CPM2 Bitbanged MII", | 192 | 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 | 193 | ||
353 | ret = fs_mii_bitbang_init(new_bus, ofdev->node); | 194 | ret = fs_mii_bitbang_init(new_bus, ofdev->node); |
354 | if (ret) | 195 | if (ret) |
355 | goto out_free_bitbang; | 196 | goto out_free_bus; |
356 | 197 | ||
357 | new_bus->phy_mask = ~0; | 198 | new_bus->phy_mask = ~0; |
358 | new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | 199 | new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); |
@@ -380,10 +221,10 @@ out_free_irqs: | |||
380 | kfree(new_bus->irq); | 221 | kfree(new_bus->irq); |
381 | out_unmap_regs: | 222 | out_unmap_regs: |
382 | iounmap(bitbang->dir); | 223 | iounmap(bitbang->dir); |
383 | out_free_bitbang: | ||
384 | kfree(bitbang); | ||
385 | out_free_bus: | 224 | out_free_bus: |
386 | kfree(new_bus); | 225 | kfree(new_bus); |
226 | out_free_priv: | ||
227 | free_mdio_bitbang(new_bus); | ||
387 | out: | 228 | out: |
388 | return ret; | 229 | return ret; |
389 | } | 230 | } |
@@ -394,6 +235,7 @@ static int fs_enet_mdio_remove(struct of_device *ofdev) | |||
394 | struct bb_info *bitbang = bus->priv; | 235 | struct bb_info *bitbang = bus->priv; |
395 | 236 | ||
396 | mdiobus_unregister(bus); | 237 | mdiobus_unregister(bus); |
238 | free_mdio_bitbang(bus); | ||
397 | dev_set_drvdata(&ofdev->dev, NULL); | 239 | dev_set_drvdata(&ofdev->dev, NULL); |
398 | kfree(bus->irq); | 240 | kfree(bus->irq); |
399 | iounmap(bitbang->dir); | 241 | iounmap(bitbang->dir); |
@@ -417,12 +259,12 @@ static struct of_platform_driver fs_enet_bb_mdio_driver = { | |||
417 | .remove = fs_enet_mdio_remove, | 259 | .remove = fs_enet_mdio_remove, |
418 | }; | 260 | }; |
419 | 261 | ||
420 | int fs_enet_mdio_bb_init(void) | 262 | static int fs_enet_mdio_bb_init(void) |
421 | { | 263 | { |
422 | return of_register_platform_driver(&fs_enet_bb_mdio_driver); | 264 | return of_register_platform_driver(&fs_enet_bb_mdio_driver); |
423 | } | 265 | } |
424 | 266 | ||
425 | void fs_enet_mdio_bb_exit(void) | 267 | static void fs_enet_mdio_bb_exit(void) |
426 | { | 268 | { |
427 | of_unregister_platform_driver(&fs_enet_bb_mdio_driver); | 269 | of_unregister_platform_driver(&fs_enet_bb_mdio_driver); |
428 | } | 270 | } |
@@ -437,7 +279,6 @@ static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang, | |||
437 | bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset; | 279 | bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset; |
438 | bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit); | 280 | bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit); |
439 | bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit); | 281 | bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit); |
440 | bitbang->delay = fmpi->delay; | ||
441 | 282 | ||
442 | return 0; | 283 | return 0; |
443 | } | 284 | } |
@@ -453,20 +294,19 @@ static int __devinit fs_enet_mdio_probe(struct device *dev) | |||
453 | if (NULL == dev) | 294 | if (NULL == dev) |
454 | return -EINVAL; | 295 | return -EINVAL; |
455 | 296 | ||
456 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | 297 | bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); |
457 | 298 | ||
458 | if (NULL == new_bus) | 299 | if (NULL == bitbang) |
459 | return -ENOMEM; | 300 | return -ENOMEM; |
460 | 301 | ||
461 | bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); | 302 | bitbang->ctrl.ops = &bb_ops; |
462 | 303 | ||
463 | if (NULL == bitbang) | 304 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); |
305 | |||
306 | if (NULL == new_bus) | ||
464 | return -ENOMEM; | 307 | return -ENOMEM; |
465 | 308 | ||
466 | new_bus->name = "BB MII Bus", | 309 | new_bus->name = "BB MII Bus", |
467 | new_bus->read = &fs_enet_mii_bb_read, | ||
468 | new_bus->write = &fs_enet_mii_bb_write, | ||
469 | new_bus->reset = &fs_enet_mii_bb_reset, | ||
470 | new_bus->id = pdev->id; | 310 | new_bus->id = pdev->id; |
471 | 311 | ||
472 | new_bus->phy_mask = ~0x9; | 312 | new_bus->phy_mask = ~0x9; |
@@ -498,8 +338,8 @@ static int __devinit fs_enet_mdio_probe(struct device *dev) | |||
498 | return 0; | 338 | return 0; |
499 | 339 | ||
500 | bus_register_fail: | 340 | bus_register_fail: |
341 | free_mdio_bitbang(new_bus); | ||
501 | kfree(bitbang); | 342 | kfree(bitbang); |
502 | kfree(new_bus); | ||
503 | 343 | ||
504 | return err; | 344 | return err; |
505 | } | 345 | } |
@@ -512,9 +352,7 @@ static int fs_enet_mdio_remove(struct device *dev) | |||
512 | 352 | ||
513 | dev_set_drvdata(dev, NULL); | 353 | dev_set_drvdata(dev, NULL); |
514 | 354 | ||
515 | iounmap((void *) (&bus->priv)); | 355 | free_mdio_bitbang(bus); |
516 | bus->priv = NULL; | ||
517 | kfree(bus); | ||
518 | 356 | ||
519 | return 0; | 357 | return 0; |
520 | } | 358 | } |
@@ -535,4 +373,4 @@ void fs_enet_mdio_bb_exit(void) | |||
535 | { | 373 | { |
536 | driver_unregister(&fs_enet_bb_mdio_driver); | 374 | driver_unregister(&fs_enet_bb_mdio_driver); |
537 | } | 375 | } |
538 | 376 | #endif | |