aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sungem_phy.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/sungem_phy.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/net/sungem_phy.c')
-rw-r--r--drivers/net/sungem_phy.c872
1 files changed, 872 insertions, 0 deletions
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
new file mode 100644
index 000000000000..0fca414d3657
--- /dev/null
+++ b/drivers/net/sungem_phy.c
@@ -0,0 +1,872 @@
1/*
2 * PHY drivers for the sungem ethernet driver.
3 *
4 * This file could be shared with other drivers.
5 *
6 * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
7 *
8 * TODO:
9 * - Implement WOL
10 * - Add support for PHYs that provide an IRQ line
11 * - Eventually moved the entire polling state machine in
12 * there (out of the eth driver), so that it can easily be
13 * skipped on PHYs that implement it in hardware.
14 * - On LXT971 & BCM5201, Apple uses some chip specific regs
15 * to read the link status. Figure out why and if it makes
16 * sense to do the same (magic aneg ?)
17 * - Apple has some additional power management code for some
18 * Broadcom PHYs that they "hide" from the OpenSource version
19 * of darwin, still need to reverse engineer that
20 */
21
22#include <linux/config.h>
23
24#include <linux/module.h>
25
26#include <linux/kernel.h>
27#include <linux/sched.h>
28#include <linux/types.h>
29#include <linux/netdevice.h>
30#include <linux/etherdevice.h>
31#include <linux/mii.h>
32#include <linux/ethtool.h>
33#include <linux/delay.h>
34
35#include "sungem_phy.h"
36
37/* Link modes of the BCM5400 PHY */
38static int phy_BCM5400_link_table[8][3] = {
39 { 0, 0, 0 }, /* No link */
40 { 0, 0, 0 }, /* 10BT Half Duplex */
41 { 1, 0, 0 }, /* 10BT Full Duplex */
42 { 0, 1, 0 }, /* 100BT Half Duplex */
43 { 0, 1, 0 }, /* 100BT Half Duplex */
44 { 1, 1, 0 }, /* 100BT Full Duplex*/
45 { 1, 0, 1 }, /* 1000BT */
46 { 1, 0, 1 }, /* 1000BT */
47};
48
49static inline int __phy_read(struct mii_phy* phy, int id, int reg)
50{
51 return phy->mdio_read(phy->dev, id, reg);
52}
53
54static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
55{
56 phy->mdio_write(phy->dev, id, reg, val);
57}
58
59static inline int phy_read(struct mii_phy* phy, int reg)
60{
61 return phy->mdio_read(phy->dev, phy->mii_id, reg);
62}
63
64static inline void phy_write(struct mii_phy* phy, int reg, int val)
65{
66 phy->mdio_write(phy->dev, phy->mii_id, reg, val);
67}
68
69static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
70{
71 u16 val;
72 int limit = 10000;
73
74 val = __phy_read(phy, phy_id, MII_BMCR);
75 val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
76 val |= BMCR_RESET;
77 __phy_write(phy, phy_id, MII_BMCR, val);
78
79 udelay(100);
80
81 while (limit--) {
82 val = __phy_read(phy, phy_id, MII_BMCR);
83 if ((val & BMCR_RESET) == 0)
84 break;
85 udelay(10);
86 }
87 if ((val & BMCR_ISOLATE) && limit > 0)
88 __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
89
90 return (limit <= 0);
91}
92
93static int bcm5201_init(struct mii_phy* phy)
94{
95 u16 data;
96
97 data = phy_read(phy, MII_BCM5201_MULTIPHY);
98 data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
99 phy_write(phy, MII_BCM5201_MULTIPHY, data);
100
101 phy_write(phy, MII_BCM5201_INTERRUPT, 0);
102
103 return 0;
104}
105
106static int bcm5201_suspend(struct mii_phy* phy)
107{
108 phy_write(phy, MII_BCM5201_INTERRUPT, 0);
109 phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
110
111 return 0;
112}
113
114static int bcm5221_init(struct mii_phy* phy)
115{
116 u16 data;
117
118 data = phy_read(phy, MII_BCM5221_TEST);
119 phy_write(phy, MII_BCM5221_TEST,
120 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
121
122 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
123 phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
124 data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
125
126 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
127 phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
128 data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
129
130 data = phy_read(phy, MII_BCM5221_TEST);
131 phy_write(phy, MII_BCM5221_TEST,
132 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
133
134 return 0;
135}
136
137static int bcm5221_suspend(struct mii_phy* phy)
138{
139 u16 data;
140
141 data = phy_read(phy, MII_BCM5221_TEST);
142 phy_write(phy, MII_BCM5221_TEST,
143 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
144
145 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
146 phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
147 data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
148
149 return 0;
150}
151
152static int bcm5400_init(struct mii_phy* phy)
153{
154 u16 data;
155
156 /* Configure for gigabit full duplex */
157 data = phy_read(phy, MII_BCM5400_AUXCONTROL);
158 data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
159 phy_write(phy, MII_BCM5400_AUXCONTROL, data);
160
161 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
162 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
163 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
164
165 udelay(100);
166
167 /* Reset and configure cascaded 10/100 PHY */
168 (void)reset_one_mii_phy(phy, 0x1f);
169
170 data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
171 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
172 __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
173
174 data = phy_read(phy, MII_BCM5400_AUXCONTROL);
175 data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
176 phy_write(phy, MII_BCM5400_AUXCONTROL, data);
177
178 return 0;
179}
180
181static int bcm5400_suspend(struct mii_phy* phy)
182{
183#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
184 phy_write(phy, MII_BMCR, BMCR_PDOWN);
185#endif
186 return 0;
187}
188
189static int bcm5401_init(struct mii_phy* phy)
190{
191 u16 data;
192 int rev;
193
194 rev = phy_read(phy, MII_PHYSID2) & 0x000f;
195 if (rev == 0 || rev == 3) {
196 /* Some revisions of 5401 appear to need this
197 * initialisation sequence to disable, according
198 * to OF, "tap power management"
199 *
200 * WARNING ! OF and Darwin don't agree on the
201 * register addresses. OF seem to interpret the
202 * register numbers below as decimal
203 *
204 * Note: This should (and does) match tg3_init_5401phy_dsp
205 * in the tg3.c driver. -DaveM
206 */
207 phy_write(phy, 0x18, 0x0c20);
208 phy_write(phy, 0x17, 0x0012);
209 phy_write(phy, 0x15, 0x1804);
210 phy_write(phy, 0x17, 0x0013);
211 phy_write(phy, 0x15, 0x1204);
212 phy_write(phy, 0x17, 0x8006);
213 phy_write(phy, 0x15, 0x0132);
214 phy_write(phy, 0x17, 0x8006);
215 phy_write(phy, 0x15, 0x0232);
216 phy_write(phy, 0x17, 0x201f);
217 phy_write(phy, 0x15, 0x0a20);
218 }
219
220 /* Configure for gigabit full duplex */
221 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
222 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
223 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
224
225 udelay(10);
226
227 /* Reset and configure cascaded 10/100 PHY */
228 (void)reset_one_mii_phy(phy, 0x1f);
229
230 data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
231 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
232 __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
233
234 return 0;
235}
236
237static int bcm5401_suspend(struct mii_phy* phy)
238{
239#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
240 phy_write(phy, MII_BMCR, BMCR_PDOWN);
241#endif
242 return 0;
243}
244
245static int bcm5411_init(struct mii_phy* phy)
246{
247 u16 data;
248
249 /* Here's some more Apple black magic to setup
250 * some voltage stuffs.
251 */
252 phy_write(phy, 0x1c, 0x8c23);
253 phy_write(phy, 0x1c, 0x8ca3);
254 phy_write(phy, 0x1c, 0x8c23);
255
256 /* Here, Apple seems to want to reset it, do
257 * it as well
258 */
259 phy_write(phy, MII_BMCR, BMCR_RESET);
260 phy_write(phy, MII_BMCR, 0x1340);
261
262 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
263 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
264 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
265
266 udelay(10);
267
268 /* Reset and configure cascaded 10/100 PHY */
269 (void)reset_one_mii_phy(phy, 0x1f);
270
271 return 0;
272}
273
274static int bcm5411_suspend(struct mii_phy* phy)
275{
276 phy_write(phy, MII_BMCR, BMCR_PDOWN);
277
278 return 0;
279}
280
281static int bcm5421_init(struct mii_phy* phy)
282{
283 u16 data;
284 int rev;
285
286 rev = phy_read(phy, MII_PHYSID2) & 0x000f;
287 if (rev == 0) {
288 /* This is borrowed from MacOS
289 */
290 phy_write(phy, 0x18, 0x1007);
291 data = phy_read(phy, 0x18);
292 phy_write(phy, 0x18, data | 0x0400);
293 phy_write(phy, 0x18, 0x0007);
294 data = phy_read(phy, 0x18);
295 phy_write(phy, 0x18, data | 0x0800);
296 phy_write(phy, 0x17, 0x000a);
297 data = phy_read(phy, 0x15);
298 phy_write(phy, 0x15, data | 0x0200);
299 }
300#if 0
301 /* This has to be verified before I enable it */
302 /* Enable automatic low-power */
303 phy_write(phy, 0x1c, 0x9002);
304 phy_write(phy, 0x1c, 0xa821);
305 phy_write(phy, 0x1c, 0x941d);
306#endif
307 return 0;
308}
309
310static int bcm5421k2_init(struct mii_phy* phy)
311{
312 /* Init code borrowed from OF */
313 phy_write(phy, 4, 0x01e1);
314 phy_write(phy, 9, 0x0300);
315
316 return 0;
317}
318
319static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
320{
321 u16 ctl, adv;
322
323 phy->autoneg = 1;
324 phy->speed = SPEED_10;
325 phy->duplex = DUPLEX_HALF;
326 phy->pause = 0;
327 phy->advertising = advertise;
328
329 /* Setup standard advertise */
330 adv = phy_read(phy, MII_ADVERTISE);
331 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
332 if (advertise & ADVERTISED_10baseT_Half)
333 adv |= ADVERTISE_10HALF;
334 if (advertise & ADVERTISED_10baseT_Full)
335 adv |= ADVERTISE_10FULL;
336 if (advertise & ADVERTISED_100baseT_Half)
337 adv |= ADVERTISE_100HALF;
338 if (advertise & ADVERTISED_100baseT_Full)
339 adv |= ADVERTISE_100FULL;
340 phy_write(phy, MII_ADVERTISE, adv);
341
342 /* Setup 1000BT advertise */
343 adv = phy_read(phy, MII_1000BASETCONTROL);
344 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
345 if (advertise & SUPPORTED_1000baseT_Half)
346 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
347 if (advertise & SUPPORTED_1000baseT_Full)
348 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
349 phy_write(phy, MII_1000BASETCONTROL, adv);
350
351 /* Start/Restart aneg */
352 ctl = phy_read(phy, MII_BMCR);
353 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
354 phy_write(phy, MII_BMCR, ctl);
355
356 return 0;
357}
358
359static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
360{
361 u16 ctl;
362
363 phy->autoneg = 0;
364 phy->speed = speed;
365 phy->duplex = fd;
366 phy->pause = 0;
367
368 ctl = phy_read(phy, MII_BMCR);
369 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
370
371 /* First reset the PHY */
372 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
373
374 /* Select speed & duplex */
375 switch(speed) {
376 case SPEED_10:
377 break;
378 case SPEED_100:
379 ctl |= BMCR_SPEED100;
380 break;
381 case SPEED_1000:
382 ctl |= BMCR_SPD2;
383 }
384 if (fd == DUPLEX_FULL)
385 ctl |= BMCR_FULLDPLX;
386
387 // XXX Should we set the sungem to GII now on 1000BT ?
388
389 phy_write(phy, MII_BMCR, ctl);
390
391 return 0;
392}
393
394static int bcm54xx_read_link(struct mii_phy *phy)
395{
396 int link_mode;
397 u16 val;
398
399 if (phy->autoneg) {
400 val = phy_read(phy, MII_BCM5400_AUXSTATUS);
401 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
402 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
403 phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
404 phy->speed = phy_BCM5400_link_table[link_mode][2] ?
405 SPEED_1000 :
406 (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
407 val = phy_read(phy, MII_LPA);
408 phy->pause = ((val & LPA_PAUSE) != 0);
409 }
410 /* On non-aneg, we assume what we put in BMCR is the speed,
411 * though magic-aneg shouldn't prevent this case from occurring
412 */
413
414 return 0;
415}
416
417static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
418{
419 u16 ctl, adv;
420
421 phy->autoneg = 1;
422 phy->speed = SPEED_10;
423 phy->duplex = DUPLEX_HALF;
424 phy->pause = 0;
425 phy->advertising = advertise;
426
427 /* Setup standard advertise */
428 adv = phy_read(phy, MII_ADVERTISE);
429 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
430 if (advertise & ADVERTISED_10baseT_Half)
431 adv |= ADVERTISE_10HALF;
432 if (advertise & ADVERTISED_10baseT_Full)
433 adv |= ADVERTISE_10FULL;
434 if (advertise & ADVERTISED_100baseT_Half)
435 adv |= ADVERTISE_100HALF;
436 if (advertise & ADVERTISED_100baseT_Full)
437 adv |= ADVERTISE_100FULL;
438 phy_write(phy, MII_ADVERTISE, adv);
439
440 /* Setup 1000BT advertise & enable crossover detect
441 * XXX How do we advertise 1000BT ? Darwin source is
442 * confusing here, they read from specific control and
443 * write to control... Someone has specs for those
444 * beasts ?
445 */
446 adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
447 adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
448 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
449 MII_1000BASETCONTROL_HALFDUPLEXCAP);
450 if (advertise & SUPPORTED_1000baseT_Half)
451 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
452 if (advertise & SUPPORTED_1000baseT_Full)
453 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
454 phy_write(phy, MII_1000BASETCONTROL, adv);
455
456 /* Start/Restart aneg */
457 ctl = phy_read(phy, MII_BMCR);
458 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
459 phy_write(phy, MII_BMCR, ctl);
460
461 return 0;
462}
463
464static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
465{
466 u16 ctl, ctl2;
467
468 phy->autoneg = 0;
469 phy->speed = speed;
470 phy->duplex = fd;
471 phy->pause = 0;
472
473 ctl = phy_read(phy, MII_BMCR);
474 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
475 ctl |= BMCR_RESET;
476
477 /* Select speed & duplex */
478 switch(speed) {
479 case SPEED_10:
480 break;
481 case SPEED_100:
482 ctl |= BMCR_SPEED100;
483 break;
484 /* I'm not sure about the one below, again, Darwin source is
485 * quite confusing and I lack chip specs
486 */
487 case SPEED_1000:
488 ctl |= BMCR_SPD2;
489 }
490 if (fd == DUPLEX_FULL)
491 ctl |= BMCR_FULLDPLX;
492
493 /* Disable crossover. Again, the way Apple does it is strange,
494 * though I don't assume they are wrong ;)
495 */
496 ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
497 ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
498 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
499 MII_1000BASETCONTROL_FULLDUPLEXCAP |
500 MII_1000BASETCONTROL_HALFDUPLEXCAP);
501 if (speed == SPEED_1000)
502 ctl2 |= (fd == DUPLEX_FULL) ?
503 MII_1000BASETCONTROL_FULLDUPLEXCAP :
504 MII_1000BASETCONTROL_HALFDUPLEXCAP;
505 phy_write(phy, MII_1000BASETCONTROL, ctl2);
506
507 // XXX Should we set the sungem to GII now on 1000BT ?
508
509 phy_write(phy, MII_BMCR, ctl);
510
511 return 0;
512}
513
514static int marvell_read_link(struct mii_phy *phy)
515{
516 u16 status;
517
518 if (phy->autoneg) {
519 status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
520 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
521 return -EAGAIN;
522 if (status & MII_M1011_PHY_SPEC_STATUS_1000)
523 phy->speed = SPEED_1000;
524 else if (status & MII_M1011_PHY_SPEC_STATUS_100)
525 phy->speed = SPEED_100;
526 else
527 phy->speed = SPEED_10;
528 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
529 phy->duplex = DUPLEX_FULL;
530 else
531 phy->duplex = DUPLEX_HALF;
532 phy->pause = 0; /* XXX Check against spec ! */
533 }
534 /* On non-aneg, we assume what we put in BMCR is the speed,
535 * though magic-aneg shouldn't prevent this case from occurring
536 */
537
538 return 0;
539}
540
541static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
542{
543 u16 ctl, adv;
544
545 phy->autoneg = 1;
546 phy->speed = SPEED_10;
547 phy->duplex = DUPLEX_HALF;
548 phy->pause = 0;
549 phy->advertising = advertise;
550
551 /* Setup standard advertise */
552 adv = phy_read(phy, MII_ADVERTISE);
553 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
554 if (advertise & ADVERTISED_10baseT_Half)
555 adv |= ADVERTISE_10HALF;
556 if (advertise & ADVERTISED_10baseT_Full)
557 adv |= ADVERTISE_10FULL;
558 if (advertise & ADVERTISED_100baseT_Half)
559 adv |= ADVERTISE_100HALF;
560 if (advertise & ADVERTISED_100baseT_Full)
561 adv |= ADVERTISE_100FULL;
562 phy_write(phy, MII_ADVERTISE, adv);
563
564 /* Start/Restart aneg */
565 ctl = phy_read(phy, MII_BMCR);
566 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
567 phy_write(phy, MII_BMCR, ctl);
568
569 return 0;
570}
571
572static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
573{
574 u16 ctl;
575
576 phy->autoneg = 0;
577 phy->speed = speed;
578 phy->duplex = fd;
579 phy->pause = 0;
580
581 ctl = phy_read(phy, MII_BMCR);
582 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
583
584 /* First reset the PHY */
585 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
586
587 /* Select speed & duplex */
588 switch(speed) {
589 case SPEED_10:
590 break;
591 case SPEED_100:
592 ctl |= BMCR_SPEED100;
593 break;
594 case SPEED_1000:
595 default:
596 return -EINVAL;
597 }
598 if (fd == DUPLEX_FULL)
599 ctl |= BMCR_FULLDPLX;
600 phy_write(phy, MII_BMCR, ctl);
601
602 return 0;
603}
604
605static int genmii_poll_link(struct mii_phy *phy)
606{
607 u16 status;
608
609 (void)phy_read(phy, MII_BMSR);
610 status = phy_read(phy, MII_BMSR);
611 if ((status & BMSR_LSTATUS) == 0)
612 return 0;
613 if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
614 return 0;
615 return 1;
616}
617
618static int genmii_read_link(struct mii_phy *phy)
619{
620 u16 lpa;
621
622 if (phy->autoneg) {
623 lpa = phy_read(phy, MII_LPA);
624
625 if (lpa & (LPA_10FULL | LPA_100FULL))
626 phy->duplex = DUPLEX_FULL;
627 else
628 phy->duplex = DUPLEX_HALF;
629 if (lpa & (LPA_100FULL | LPA_100HALF))
630 phy->speed = SPEED_100;
631 else
632 phy->speed = SPEED_10;
633 phy->pause = 0;
634 }
635 /* On non-aneg, we assume what we put in BMCR is the speed,
636 * though magic-aneg shouldn't prevent this case from occurring
637 */
638
639 return 0;
640}
641
642
643#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
644 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
645 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
646#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
647 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
648
649/* Broadcom BCM 5201 */
650static struct mii_phy_ops bcm5201_phy_ops = {
651 .init = bcm5201_init,
652 .suspend = bcm5201_suspend,
653 .setup_aneg = genmii_setup_aneg,
654 .setup_forced = genmii_setup_forced,
655 .poll_link = genmii_poll_link,
656 .read_link = genmii_read_link,
657};
658
659static struct mii_phy_def bcm5201_phy_def = {
660 .phy_id = 0x00406210,
661 .phy_id_mask = 0xfffffff0,
662 .name = "BCM5201",
663 .features = MII_BASIC_FEATURES,
664 .magic_aneg = 1,
665 .ops = &bcm5201_phy_ops
666};
667
668/* Broadcom BCM 5221 */
669static struct mii_phy_ops bcm5221_phy_ops = {
670 .suspend = bcm5221_suspend,
671 .init = bcm5221_init,
672 .setup_aneg = genmii_setup_aneg,
673 .setup_forced = genmii_setup_forced,
674 .poll_link = genmii_poll_link,
675 .read_link = genmii_read_link,
676};
677
678static struct mii_phy_def bcm5221_phy_def = {
679 .phy_id = 0x004061e0,
680 .phy_id_mask = 0xfffffff0,
681 .name = "BCM5221",
682 .features = MII_BASIC_FEATURES,
683 .magic_aneg = 1,
684 .ops = &bcm5221_phy_ops
685};
686
687/* Broadcom BCM 5400 */
688static struct mii_phy_ops bcm5400_phy_ops = {
689 .init = bcm5400_init,
690 .suspend = bcm5400_suspend,
691 .setup_aneg = bcm54xx_setup_aneg,
692 .setup_forced = bcm54xx_setup_forced,
693 .poll_link = genmii_poll_link,
694 .read_link = bcm54xx_read_link,
695};
696
697static struct mii_phy_def bcm5400_phy_def = {
698 .phy_id = 0x00206040,
699 .phy_id_mask = 0xfffffff0,
700 .name = "BCM5400",
701 .features = MII_GBIT_FEATURES,
702 .magic_aneg = 1,
703 .ops = &bcm5400_phy_ops
704};
705
706/* Broadcom BCM 5401 */
707static struct mii_phy_ops bcm5401_phy_ops = {
708 .init = bcm5401_init,
709 .suspend = bcm5401_suspend,
710 .setup_aneg = bcm54xx_setup_aneg,
711 .setup_forced = bcm54xx_setup_forced,
712 .poll_link = genmii_poll_link,
713 .read_link = bcm54xx_read_link,
714};
715
716static struct mii_phy_def bcm5401_phy_def = {
717 .phy_id = 0x00206050,
718 .phy_id_mask = 0xfffffff0,
719 .name = "BCM5401",
720 .features = MII_GBIT_FEATURES,
721 .magic_aneg = 1,
722 .ops = &bcm5401_phy_ops
723};
724
725/* Broadcom BCM 5411 */
726static struct mii_phy_ops bcm5411_phy_ops = {
727 .init = bcm5411_init,
728 .suspend = bcm5411_suspend,
729 .setup_aneg = bcm54xx_setup_aneg,
730 .setup_forced = bcm54xx_setup_forced,
731 .poll_link = genmii_poll_link,
732 .read_link = bcm54xx_read_link,
733};
734
735static struct mii_phy_def bcm5411_phy_def = {
736 .phy_id = 0x00206070,
737 .phy_id_mask = 0xfffffff0,
738 .name = "BCM5411",
739 .features = MII_GBIT_FEATURES,
740 .magic_aneg = 1,
741 .ops = &bcm5411_phy_ops
742};
743
744/* Broadcom BCM 5421 */
745static struct mii_phy_ops bcm5421_phy_ops = {
746 .init = bcm5421_init,
747 .suspend = bcm5411_suspend,
748 .setup_aneg = bcm54xx_setup_aneg,
749 .setup_forced = bcm54xx_setup_forced,
750 .poll_link = genmii_poll_link,
751 .read_link = bcm54xx_read_link,
752};
753
754static struct mii_phy_def bcm5421_phy_def = {
755 .phy_id = 0x002060e0,
756 .phy_id_mask = 0xfffffff0,
757 .name = "BCM5421",
758 .features = MII_GBIT_FEATURES,
759 .magic_aneg = 1,
760 .ops = &bcm5421_phy_ops
761};
762
763/* Broadcom BCM 5421 built-in K2 */
764static struct mii_phy_ops bcm5421k2_phy_ops = {
765 .init = bcm5421k2_init,
766 .suspend = bcm5411_suspend,
767 .setup_aneg = bcm54xx_setup_aneg,
768 .setup_forced = bcm54xx_setup_forced,
769 .poll_link = genmii_poll_link,
770 .read_link = bcm54xx_read_link,
771};
772
773static struct mii_phy_def bcm5421k2_phy_def = {
774 .phy_id = 0x002062e0,
775 .phy_id_mask = 0xfffffff0,
776 .name = "BCM5421-K2",
777 .features = MII_GBIT_FEATURES,
778 .magic_aneg = 1,
779 .ops = &bcm5421k2_phy_ops
780};
781
782/* Marvell 88E1101 (Apple seem to deal with 2 different revs,
783 * I masked out the 8 last bits to get both, but some specs
784 * would be useful here) --BenH.
785 */
786static struct mii_phy_ops marvell_phy_ops = {
787 .setup_aneg = marvell_setup_aneg,
788 .setup_forced = marvell_setup_forced,
789 .poll_link = genmii_poll_link,
790 .read_link = marvell_read_link
791};
792
793static struct mii_phy_def marvell_phy_def = {
794 .phy_id = 0x01410c00,
795 .phy_id_mask = 0xffffff00,
796 .name = "Marvell 88E1101",
797 .features = MII_GBIT_FEATURES,
798 .magic_aneg = 1,
799 .ops = &marvell_phy_ops
800};
801
802/* Generic implementation for most 10/100 PHYs */
803static struct mii_phy_ops generic_phy_ops = {
804 .setup_aneg = genmii_setup_aneg,
805 .setup_forced = genmii_setup_forced,
806 .poll_link = genmii_poll_link,
807 .read_link = genmii_read_link
808};
809
810static struct mii_phy_def genmii_phy_def = {
811 .phy_id = 0x00000000,
812 .phy_id_mask = 0x00000000,
813 .name = "Generic MII",
814 .features = MII_BASIC_FEATURES,
815 .magic_aneg = 0,
816 .ops = &generic_phy_ops
817};
818
819static struct mii_phy_def* mii_phy_table[] = {
820 &bcm5201_phy_def,
821 &bcm5221_phy_def,
822 &bcm5400_phy_def,
823 &bcm5401_phy_def,
824 &bcm5411_phy_def,
825 &bcm5421_phy_def,
826 &bcm5421k2_phy_def,
827 &marvell_phy_def,
828 &genmii_phy_def,
829 NULL
830};
831
832int mii_phy_probe(struct mii_phy *phy, int mii_id)
833{
834 int rc;
835 u32 id;
836 struct mii_phy_def* def;
837 int i;
838
839 /* We do not reset the mii_phy structure as the driver
840 * may re-probe the PHY regulary
841 */
842 phy->mii_id = mii_id;
843
844 /* Take PHY out of isloate mode and reset it. */
845 rc = reset_one_mii_phy(phy, mii_id);
846 if (rc)
847 goto fail;
848
849 /* Read ID and find matching entry */
850 id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
851 printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
852 for (i=0; (def = mii_phy_table[i]) != NULL; i++)
853 if ((id & def->phy_id_mask) == def->phy_id)
854 break;
855 /* Should never be NULL (we have a generic entry), but... */
856 if (def == NULL)
857 goto fail;
858
859 phy->def = def;
860
861 return 0;
862fail:
863 phy->speed = 0;
864 phy->duplex = 0;
865 phy->pause = 0;
866 phy->advertising = 0;
867 return -ENODEV;
868}
869
870EXPORT_SYMBOL(mii_phy_probe);
871MODULE_LICENSE("GPL");
872