MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / net / sungem_phy.c
blobdd3786097bbcf13f19affba1acb897ebf35c0a52
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)
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
22 #include <linux/config.h>
24 #include <linux/module.h>
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>
35 #include "sungem_phy.h"
37 /* Link modes of the BCM5400 PHY */
38 static 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 */
49 static inline int __phy_read(struct mii_phy* phy, int id, int reg)
51 return phy->mdio_read(phy->dev, id, reg);
54 static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
56 phy->mdio_write(phy->dev, id, reg, val);
59 static inline int phy_read(struct mii_phy* phy, int reg)
61 return phy->mdio_read(phy->dev, phy->mii_id, reg);
64 static inline void phy_write(struct mii_phy* phy, int reg, int val)
66 phy->mdio_write(phy->dev, phy->mii_id, reg, val);
69 static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
71 u16 val;
72 int limit = 10000;
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);
79 udelay(100);
81 while (limit--) {
82 val = __phy_read(phy, phy_id, MII_BMCR);
83 if ((val & BMCR_RESET) == 0)
84 break;
85 udelay(10);
87 if ((val & BMCR_ISOLATE) && limit > 0)
88 __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
90 return (limit <= 0);
93 static int bcm5201_init(struct mii_phy* phy)
95 u16 data;
97 data = phy_read(phy, MII_BCM5201_MULTIPHY);
98 data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
99 phy_write(phy, MII_BCM5201_MULTIPHY, data);
101 return 0;
104 static int bcm5201_suspend(struct mii_phy* phy, int wol_options)
106 if (!wol_options)
107 phy_write(phy, MII_BCM5201_INTERRUPT, 0);
109 /* Here's a strange hack used by both MacOS 9 and X */
110 phy_write(phy, MII_LPA, phy_read(phy, MII_LPA));
112 if (!wol_options) {
113 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
114 u16 val = phy_read(phy, MII_BCM5201_AUXMODE2)
115 phy_write(phy, MII_BCM5201_AUXMODE2,
116 val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
117 #endif
118 phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
121 return 0;
124 static int bcm5221_init(struct mii_phy* phy)
126 u16 data;
128 data = phy_read(phy, MII_BCM5221_TEST);
129 phy_write(phy, MII_BCM5221_TEST,
130 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
132 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
133 phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
134 data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
136 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
137 phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
138 data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
140 data = phy_read(phy, MII_BCM5221_TEST);
141 phy_write(phy, MII_BCM5221_TEST,
142 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
144 return 0;
147 static int bcm5400_init(struct mii_phy* phy)
149 u16 data;
151 /* Configure for gigabit full duplex */
152 data = phy_read(phy, MII_BCM5400_AUXCONTROL);
153 data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
154 phy_write(phy, MII_BCM5400_AUXCONTROL, data);
156 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
157 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
158 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
160 udelay(100);
162 /* Reset and configure cascaded 10/100 PHY */
163 (void)reset_one_mii_phy(phy, 0x1f);
165 data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
166 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
167 __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
169 data = phy_read(phy, MII_BCM5400_AUXCONTROL);
170 data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
171 phy_write(phy, MII_BCM5400_AUXCONTROL, data);
173 return 0;
176 static int bcm5400_suspend(struct mii_phy* phy, int wol_options)
178 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
179 phy_write(phy, MII_BMCR, BMCR_PDOWN);
180 #endif
181 return 0;
184 static int bcm5401_init(struct mii_phy* phy)
186 u16 data;
187 int rev;
189 rev = phy_read(phy, MII_PHYSID2) & 0x000f;
190 if (rev == 0 || rev == 3) {
191 /* Some revisions of 5401 appear to need this
192 * initialisation sequence to disable, according
193 * to OF, "tap power management"
195 * WARNING ! OF and Darwin don't agree on the
196 * register addresses. OF seem to interpret the
197 * register numbers below as decimal
199 * Note: This should (and does) match tg3_init_5401phy_dsp
200 * in the tg3.c driver. -DaveM
202 phy_write(phy, 0x18, 0x0c20);
203 phy_write(phy, 0x17, 0x0012);
204 phy_write(phy, 0x15, 0x1804);
205 phy_write(phy, 0x17, 0x0013);
206 phy_write(phy, 0x15, 0x1204);
207 phy_write(phy, 0x17, 0x8006);
208 phy_write(phy, 0x15, 0x0132);
209 phy_write(phy, 0x17, 0x8006);
210 phy_write(phy, 0x15, 0x0232);
211 phy_write(phy, 0x17, 0x201f);
212 phy_write(phy, 0x15, 0x0a20);
215 /* Configure for gigabit full duplex */
216 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
217 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
218 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
220 udelay(10);
222 /* Reset and configure cascaded 10/100 PHY */
223 (void)reset_one_mii_phy(phy, 0x1f);
225 data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
226 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
227 __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
229 return 0;
232 static int bcm5401_suspend(struct mii_phy* phy, int wol_options)
234 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
235 phy_write(phy, MII_BMCR, BMCR_PDOWN);
236 #endif
237 return 0;
240 static int bcm5411_init(struct mii_phy* phy)
242 u16 data;
244 /* Here's some more Apple black magic to setup
245 * some voltage stuffs.
247 phy_write(phy, 0x1c, 0x8c23);
248 phy_write(phy, 0x1c, 0x8ca3);
249 phy_write(phy, 0x1c, 0x8c23);
251 /* Here, Apple seems to want to reset it, do
252 * it as well
254 phy_write(phy, MII_BMCR, BMCR_RESET);
255 phy_write(phy, MII_BMCR, 0x1340);
257 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
258 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
259 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
261 udelay(10);
263 /* Reset and configure cascaded 10/100 PHY */
264 (void)reset_one_mii_phy(phy, 0x1f);
266 return 0;
269 static int bcm5411_suspend(struct mii_phy* phy, int wol_options)
271 phy_write(phy, MII_BMCR, BMCR_PDOWN);
273 return 0;
276 static int bcm5421_init(struct mii_phy* phy)
278 u16 data;
279 int rev;
281 rev = phy_read(phy, MII_PHYSID2) & 0x000f;
282 if (rev == 0) {
283 /* This is borrowed from MacOS
285 phy_write(phy, 0x18, 0x1007);
286 data = phy_read(phy, 0x18);
287 phy_write(phy, 0x18, data | 0x0400);
288 phy_write(phy, 0x18, 0x0007);
289 data = phy_read(phy, 0x18);
290 phy_write(phy, 0x18, data | 0x0800);
291 phy_write(phy, 0x17, 0x000a);
292 data = phy_read(phy, 0x15);
293 phy_write(phy, 0x15, data | 0x0200);
295 #if 0
296 /* This has to be verified before I enable it */
297 /* Enable automatic low-power */
298 phy_write(phy, 0x1c, 0x9002);
299 phy_write(phy, 0x1c, 0xa821);
300 phy_write(phy, 0x1c, 0x941d);
301 #endif
302 return 0;
305 static int bcm5421k2_init(struct mii_phy* phy)
307 /* Init code borrowed from OF */
308 phy_write(phy, 4, 0x01e1);
309 phy_write(phy, 9, 0x0300);
311 return 0;
314 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
316 u16 ctl, adv;
318 phy->autoneg = 1;
319 phy->speed = SPEED_10;
320 phy->duplex = DUPLEX_HALF;
321 phy->pause = 0;
322 phy->advertising = advertise;
324 /* Setup standard advertise */
325 adv = phy_read(phy, MII_ADVERTISE);
326 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
327 if (advertise & ADVERTISED_10baseT_Half)
328 adv |= ADVERTISE_10HALF;
329 if (advertise & ADVERTISED_10baseT_Full)
330 adv |= ADVERTISE_10FULL;
331 if (advertise & ADVERTISED_100baseT_Half)
332 adv |= ADVERTISE_100HALF;
333 if (advertise & ADVERTISED_100baseT_Full)
334 adv |= ADVERTISE_100FULL;
335 phy_write(phy, MII_ADVERTISE, adv);
337 /* Setup 1000BT advertise */
338 adv = phy_read(phy, MII_1000BASETCONTROL);
339 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
340 if (advertise & SUPPORTED_1000baseT_Half)
341 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
342 if (advertise & SUPPORTED_1000baseT_Full)
343 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
344 phy_write(phy, MII_1000BASETCONTROL, adv);
346 /* Start/Restart aneg */
347 ctl = phy_read(phy, MII_BMCR);
348 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
349 phy_write(phy, MII_BMCR, ctl);
351 return 0;
354 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
356 u16 ctl;
358 phy->autoneg = 0;
359 phy->speed = speed;
360 phy->duplex = fd;
361 phy->pause = 0;
363 ctl = phy_read(phy, MII_BMCR);
364 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
366 /* First reset the PHY */
367 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
369 /* Select speed & duplex */
370 switch(speed) {
371 case SPEED_10:
372 break;
373 case SPEED_100:
374 ctl |= BMCR_SPEED100;
375 break;
376 case SPEED_1000:
377 ctl |= BMCR_SPD2;
379 if (fd == DUPLEX_FULL)
380 ctl |= BMCR_FULLDPLX;
382 // XXX Should we set the sungem to GII now on 1000BT ?
384 phy_write(phy, MII_BMCR, ctl);
386 return 0;
389 static int bcm54xx_read_link(struct mii_phy *phy)
391 int link_mode;
392 u16 val;
394 if (phy->autoneg) {
395 val = phy_read(phy, MII_BCM5400_AUXSTATUS);
396 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
397 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
398 phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
399 phy->speed = phy_BCM5400_link_table[link_mode][2] ?
400 SPEED_1000 :
401 (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
402 val = phy_read(phy, MII_LPA);
403 phy->pause = ((val & LPA_PAUSE) != 0);
405 /* On non-aneg, we assume what we put in BMCR is the speed,
406 * though magic-aneg shouldn't prevent this case from occurring
409 return 0;
412 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
414 u16 ctl, adv;
416 phy->autoneg = 1;
417 phy->speed = SPEED_10;
418 phy->duplex = DUPLEX_HALF;
419 phy->pause = 0;
420 phy->advertising = advertise;
422 /* Setup standard advertise */
423 adv = phy_read(phy, MII_ADVERTISE);
424 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
425 if (advertise & ADVERTISED_10baseT_Half)
426 adv |= ADVERTISE_10HALF;
427 if (advertise & ADVERTISED_10baseT_Full)
428 adv |= ADVERTISE_10FULL;
429 if (advertise & ADVERTISED_100baseT_Half)
430 adv |= ADVERTISE_100HALF;
431 if (advertise & ADVERTISED_100baseT_Full)
432 adv |= ADVERTISE_100FULL;
433 phy_write(phy, MII_ADVERTISE, adv);
435 /* Setup 1000BT advertise & enable crossover detect
436 * XXX How do we advertise 1000BT ? Darwin source is
437 * confusing here, they read from specific control and
438 * write to control... Someone has specs for those
439 * beasts ?
441 adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
442 adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
443 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
444 MII_1000BASETCONTROL_HALFDUPLEXCAP);
445 if (advertise & SUPPORTED_1000baseT_Half)
446 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
447 if (advertise & SUPPORTED_1000baseT_Full)
448 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
449 phy_write(phy, MII_1000BASETCONTROL, adv);
451 /* Start/Restart aneg */
452 ctl = phy_read(phy, MII_BMCR);
453 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
454 phy_write(phy, MII_BMCR, ctl);
456 return 0;
459 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
461 u16 ctl, ctl2;
463 phy->autoneg = 0;
464 phy->speed = speed;
465 phy->duplex = fd;
466 phy->pause = 0;
468 ctl = phy_read(phy, MII_BMCR);
469 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
470 ctl |= BMCR_RESET;
472 /* Select speed & duplex */
473 switch(speed) {
474 case SPEED_10:
475 break;
476 case SPEED_100:
477 ctl |= BMCR_SPEED100;
478 break;
479 /* I'm not sure about the one below, again, Darwin source is
480 * quite confusing and I lack chip specs
482 case SPEED_1000:
483 ctl |= BMCR_SPD2;
485 if (fd == DUPLEX_FULL)
486 ctl |= BMCR_FULLDPLX;
488 /* Disable crossover. Again, the way Apple does it is strange,
489 * though I don't assume they are wrong ;)
491 ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
492 ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
493 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
494 MII_1000BASETCONTROL_FULLDUPLEXCAP |
495 MII_1000BASETCONTROL_HALFDUPLEXCAP);
496 if (speed == SPEED_1000)
497 ctl2 |= (fd == DUPLEX_FULL) ?
498 MII_1000BASETCONTROL_FULLDUPLEXCAP :
499 MII_1000BASETCONTROL_HALFDUPLEXCAP;
500 phy_write(phy, MII_1000BASETCONTROL, ctl2);
502 // XXX Should we set the sungem to GII now on 1000BT ?
504 phy_write(phy, MII_BMCR, ctl);
506 return 0;
509 static int marvell_read_link(struct mii_phy *phy)
511 u16 status;
513 if (phy->autoneg) {
514 status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
515 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
516 return -EAGAIN;
517 if (status & MII_M1011_PHY_SPEC_STATUS_1000)
518 phy->speed = SPEED_1000;
519 else if (status & MII_M1011_PHY_SPEC_STATUS_100)
520 phy->speed = SPEED_100;
521 else
522 phy->speed = SPEED_10;
523 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
524 phy->duplex = DUPLEX_FULL;
525 else
526 phy->duplex = DUPLEX_HALF;
527 phy->pause = 0; /* XXX Check against spec ! */
529 /* On non-aneg, we assume what we put in BMCR is the speed,
530 * though magic-aneg shouldn't prevent this case from occurring
533 return 0;
536 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
538 u16 ctl, adv;
540 phy->autoneg = 1;
541 phy->speed = SPEED_10;
542 phy->duplex = DUPLEX_HALF;
543 phy->pause = 0;
544 phy->advertising = advertise;
546 /* Setup standard advertise */
547 adv = phy_read(phy, MII_ADVERTISE);
548 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
549 if (advertise & ADVERTISED_10baseT_Half)
550 adv |= ADVERTISE_10HALF;
551 if (advertise & ADVERTISED_10baseT_Full)
552 adv |= ADVERTISE_10FULL;
553 if (advertise & ADVERTISED_100baseT_Half)
554 adv |= ADVERTISE_100HALF;
555 if (advertise & ADVERTISED_100baseT_Full)
556 adv |= ADVERTISE_100FULL;
557 phy_write(phy, MII_ADVERTISE, adv);
559 /* Start/Restart aneg */
560 ctl = phy_read(phy, MII_BMCR);
561 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
562 phy_write(phy, MII_BMCR, ctl);
564 return 0;
567 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
569 u16 ctl;
571 phy->autoneg = 0;
572 phy->speed = speed;
573 phy->duplex = fd;
574 phy->pause = 0;
576 ctl = phy_read(phy, MII_BMCR);
577 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
579 /* First reset the PHY */
580 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
582 /* Select speed & duplex */
583 switch(speed) {
584 case SPEED_10:
585 break;
586 case SPEED_100:
587 ctl |= BMCR_SPEED100;
588 break;
589 case SPEED_1000:
590 default:
591 return -EINVAL;
593 if (fd == DUPLEX_FULL)
594 ctl |= BMCR_FULLDPLX;
595 phy_write(phy, MII_BMCR, ctl);
597 return 0;
600 static int genmii_poll_link(struct mii_phy *phy)
602 u16 status;
604 (void)phy_read(phy, MII_BMSR);
605 status = phy_read(phy, MII_BMSR);
606 if ((status & BMSR_LSTATUS) == 0)
607 return 0;
608 if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
609 return 0;
610 return 1;
613 static int genmii_read_link(struct mii_phy *phy)
615 u16 lpa;
617 if (phy->autoneg) {
618 lpa = phy_read(phy, MII_LPA);
620 if (lpa & (LPA_10FULL | LPA_100FULL))
621 phy->duplex = DUPLEX_FULL;
622 else
623 phy->duplex = DUPLEX_HALF;
624 if (lpa & (LPA_100FULL | LPA_100HALF))
625 phy->speed = SPEED_100;
626 else
627 phy->speed = SPEED_10;
628 phy->pause = 0;
630 /* On non-aneg, we assume what we put in BMCR is the speed,
631 * though magic-aneg shouldn't prevent this case from occurring
634 return 0;
638 #define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
639 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
640 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
641 #define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
642 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
644 /* Broadcom BCM 5201 */
645 static struct mii_phy_ops bcm5201_phy_ops = {
646 .init = bcm5201_init,
647 .suspend = bcm5201_suspend,
648 .setup_aneg = genmii_setup_aneg,
649 .setup_forced = genmii_setup_forced,
650 .poll_link = genmii_poll_link,
651 .read_link = genmii_read_link,
654 static struct mii_phy_def bcm5201_phy_def = {
655 .phy_id = 0x00406210,
656 .phy_id_mask = 0xfffffff0,
657 .name = "BCM5201",
658 .features = MII_BASIC_FEATURES,
659 .magic_aneg = 1,
660 .ops = &bcm5201_phy_ops
663 /* Broadcom BCM 5221 */
664 static struct mii_phy_ops bcm5221_phy_ops = {
665 .suspend = bcm5201_suspend,
666 .init = bcm5221_init,
667 .setup_aneg = genmii_setup_aneg,
668 .setup_forced = genmii_setup_forced,
669 .poll_link = genmii_poll_link,
670 .read_link = genmii_read_link,
673 static struct mii_phy_def bcm5221_phy_def = {
674 .phy_id = 0x004061e0,
675 .phy_id_mask = 0xfffffff0,
676 .name = "BCM5221",
677 .features = MII_BASIC_FEATURES,
678 .magic_aneg = 1,
679 .ops = &bcm5221_phy_ops
682 /* Broadcom BCM 5400 */
683 static struct mii_phy_ops bcm5400_phy_ops = {
684 .init = bcm5400_init,
685 .suspend = bcm5400_suspend,
686 .setup_aneg = bcm54xx_setup_aneg,
687 .setup_forced = bcm54xx_setup_forced,
688 .poll_link = genmii_poll_link,
689 .read_link = bcm54xx_read_link,
692 static struct mii_phy_def bcm5400_phy_def = {
693 .phy_id = 0x00206040,
694 .phy_id_mask = 0xfffffff0,
695 .name = "BCM5400",
696 .features = MII_GBIT_FEATURES,
697 .magic_aneg = 1,
698 .ops = &bcm5400_phy_ops
701 /* Broadcom BCM 5401 */
702 static struct mii_phy_ops bcm5401_phy_ops = {
703 .init = bcm5401_init,
704 .suspend = bcm5401_suspend,
705 .setup_aneg = bcm54xx_setup_aneg,
706 .setup_forced = bcm54xx_setup_forced,
707 .poll_link = genmii_poll_link,
708 .read_link = bcm54xx_read_link,
711 static struct mii_phy_def bcm5401_phy_def = {
712 .phy_id = 0x00206050,
713 .phy_id_mask = 0xfffffff0,
714 .name = "BCM5401",
715 .features = MII_GBIT_FEATURES,
716 .magic_aneg = 1,
717 .ops = &bcm5401_phy_ops
720 /* Broadcom BCM 5411 */
721 static struct mii_phy_ops bcm5411_phy_ops = {
722 .init = bcm5411_init,
723 .suspend = bcm5411_suspend,
724 .setup_aneg = bcm54xx_setup_aneg,
725 .setup_forced = bcm54xx_setup_forced,
726 .poll_link = genmii_poll_link,
727 .read_link = bcm54xx_read_link,
730 static struct mii_phy_def bcm5411_phy_def = {
731 .phy_id = 0x00206070,
732 .phy_id_mask = 0xfffffff0,
733 .name = "BCM5411",
734 .features = MII_GBIT_FEATURES,
735 .magic_aneg = 1,
736 .ops = &bcm5411_phy_ops
739 /* Broadcom BCM 5421 */
740 static struct mii_phy_ops bcm5421_phy_ops = {
741 .init = bcm5421_init,
742 .suspend = bcm5411_suspend,
743 .setup_aneg = bcm54xx_setup_aneg,
744 .setup_forced = bcm54xx_setup_forced,
745 .poll_link = genmii_poll_link,
746 .read_link = bcm54xx_read_link,
749 static struct mii_phy_def bcm5421_phy_def = {
750 .phy_id = 0x002060e0,
751 .phy_id_mask = 0xfffffff0,
752 .name = "BCM5421",
753 .features = MII_GBIT_FEATURES,
754 .magic_aneg = 1,
755 .ops = &bcm5421_phy_ops
758 /* Broadcom BCM 5421 built-in K2 */
759 static struct mii_phy_ops bcm5421k2_phy_ops = {
760 .init = bcm5421k2_init,
761 .suspend = bcm5411_suspend,
762 .setup_aneg = bcm54xx_setup_aneg,
763 .setup_forced = bcm54xx_setup_forced,
764 .poll_link = genmii_poll_link,
765 .read_link = bcm54xx_read_link,
768 static struct mii_phy_def bcm5421k2_phy_def = {
769 .phy_id = 0x002062e0,
770 .phy_id_mask = 0xfffffff0,
771 .name = "BCM5421-K2",
772 .features = MII_GBIT_FEATURES,
773 .magic_aneg = 1,
774 .ops = &bcm5421k2_phy_ops
777 /* Marvell 88E1101 (Apple seem to deal with 2 different revs,
778 * I masked out the 8 last bits to get both, but some specs
779 * would be useful here) --BenH.
781 static struct mii_phy_ops marvell_phy_ops = {
782 .setup_aneg = marvell_setup_aneg,
783 .setup_forced = marvell_setup_forced,
784 .poll_link = genmii_poll_link,
785 .read_link = marvell_read_link
788 static struct mii_phy_def marvell_phy_def = {
789 .phy_id = 0x01410c00,
790 .phy_id_mask = 0xffffff00,
791 .name = "Marvell 88E1101",
792 .features = MII_GBIT_FEATURES,
793 .magic_aneg = 1,
794 .ops = &marvell_phy_ops
797 /* Generic implementation for most 10/100 PHYs */
798 static struct mii_phy_ops generic_phy_ops = {
799 .setup_aneg = genmii_setup_aneg,
800 .setup_forced = genmii_setup_forced,
801 .poll_link = genmii_poll_link,
802 .read_link = genmii_read_link
805 static struct mii_phy_def genmii_phy_def = {
806 .phy_id = 0x00000000,
807 .phy_id_mask = 0x00000000,
808 .name = "Generic MII",
809 .features = MII_BASIC_FEATURES,
810 .magic_aneg = 0,
811 .ops = &generic_phy_ops
814 static struct mii_phy_def* mii_phy_table[] = {
815 &bcm5201_phy_def,
816 &bcm5221_phy_def,
817 &bcm5400_phy_def,
818 &bcm5401_phy_def,
819 &bcm5411_phy_def,
820 &bcm5421_phy_def,
821 &bcm5421k2_phy_def,
822 &marvell_phy_def,
823 &genmii_phy_def,
824 NULL
827 int mii_phy_probe(struct mii_phy *phy, int mii_id)
829 int rc;
830 u32 id;
831 struct mii_phy_def* def;
832 int i;
834 /* We do not reset the mii_phy structure as the driver
835 * may re-probe the PHY regulary
837 phy->mii_id = mii_id;
839 /* Take PHY out of isloate mode and reset it. */
840 rc = reset_one_mii_phy(phy, mii_id);
841 if (rc)
842 goto fail;
844 /* Read ID and find matching entry */
845 id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
846 printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
847 for (i=0; (def = mii_phy_table[i]) != NULL; i++)
848 if ((id & def->phy_id_mask) == def->phy_id)
849 break;
850 /* Should never be NULL (we have a generic entry), but... */
851 if (def == NULL)
852 goto fail;
854 phy->def = def;
856 return 0;
857 fail:
858 phy->speed = 0;
859 phy->duplex = 0;
860 phy->pause = 0;
861 phy->advertising = 0;
862 return -ENODEV;
865 EXPORT_SYMBOL(mii_phy_probe);
866 MODULE_LICENSE("GPL");