2 * PHY drivers for the sungem ethernet driver.
4 * This file could be shared with other drivers.
6 * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
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
)
74 val
= __phy_read(phy
, phy_id
, MII_BMCR
);
75 val
&= ~(BMCR_ISOLATE
| BMCR_PDOWN
);
77 __phy_write(phy
, phy_id
, MII_BMCR
, val
);
82 val
= __phy_read(phy
, phy_id
, MII_BMCR
);
83 if ((val
& BMCR_RESET
) == 0)
87 if ((val
& BMCR_ISOLATE
) && limit
> 0)
88 __phy_write(phy
, phy_id
, MII_BMCR
, val
& ~BMCR_ISOLATE
);
93 static int bcm5201_init(struct mii_phy
* phy
)
97 data
= phy_read(phy
, MII_BCM5201_MULTIPHY
);
98 data
&= ~MII_BCM5201_MULTIPHY_SUPERISOLATE
;
99 phy_write(phy
, MII_BCM5201_MULTIPHY
, data
);
104 static int bcm5201_suspend(struct mii_phy
* phy
, int 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
));
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
);
118 phy_write(phy
, MII_BCM5201_MULTIPHY
, MII_BCM5201_MULTIPHY_SUPERISOLATE
);
124 static int bcm5221_init(struct mii_phy
* phy
)
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
);
147 static int bcm5400_init(struct mii_phy
* phy
)
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
);
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
);
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
);
184 static int bcm5401_init(struct mii_phy
* phy
)
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
);
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
);
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
);
240 static int bcm5411_init(struct mii_phy
* phy
)
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
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
);
263 /* Reset and configure cascaded 10/100 PHY */
264 (void)reset_one_mii_phy(phy
, 0x1f);
269 static int bcm5411_suspend(struct mii_phy
* phy
, int wol_options
)
271 phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
276 static int bcm5421_init(struct mii_phy
* phy
)
281 rev
= phy_read(phy
, MII_PHYSID2
) & 0x000f;
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);
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);
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);
314 static int bcm54xx_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
319 phy
->speed
= SPEED_10
;
320 phy
->duplex
= DUPLEX_HALF
;
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
);
354 static int bcm54xx_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
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 */
374 ctl
|= BMCR_SPEED100
;
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
);
389 static int bcm54xx_read_link(struct mii_phy
*phy
)
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] ?
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
412 static int marvell_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
417 phy
->speed
= SPEED_10
;
418 phy
->duplex
= DUPLEX_HALF
;
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
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
);
459 static int marvell_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
468 ctl
= phy_read(phy
, MII_BMCR
);
469 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_SPD2
|BMCR_ANENABLE
);
472 /* Select speed & duplex */
477 ctl
|= BMCR_SPEED100
;
479 /* I'm not sure about the one below, again, Darwin source is
480 * quite confusing and I lack chip specs
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
);
509 static int marvell_read_link(struct mii_phy
*phy
)
514 status
= phy_read(phy
, MII_M1011_PHY_SPEC_STATUS
);
515 if ((status
& MII_M1011_PHY_SPEC_STATUS_RESOLVED
) == 0)
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
;
522 phy
->speed
= SPEED_10
;
523 if (status
& MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX
)
524 phy
->duplex
= DUPLEX_FULL
;
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
536 static int genmii_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
541 phy
->speed
= SPEED_10
;
542 phy
->duplex
= DUPLEX_HALF
;
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
);
567 static int genmii_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
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 */
587 ctl
|= BMCR_SPEED100
;
593 if (fd
== DUPLEX_FULL
)
594 ctl
|= BMCR_FULLDPLX
;
595 phy_write(phy
, MII_BMCR
, ctl
);
600 static int genmii_poll_link(struct mii_phy
*phy
)
604 (void)phy_read(phy
, MII_BMSR
);
605 status
= phy_read(phy
, MII_BMSR
);
606 if ((status
& BMSR_LSTATUS
) == 0)
608 if (phy
->autoneg
&& !(status
& BMSR_ANEGCOMPLETE
))
613 static int genmii_read_link(struct mii_phy
*phy
)
618 lpa
= phy_read(phy
, MII_LPA
);
620 if (lpa
& (LPA_10FULL
| LPA_100FULL
))
621 phy
->duplex
= DUPLEX_FULL
;
623 phy
->duplex
= DUPLEX_HALF
;
624 if (lpa
& (LPA_100FULL
| LPA_100HALF
))
625 phy
->speed
= SPEED_100
;
627 phy
->speed
= SPEED_10
;
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
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,
658 .features
= MII_BASIC_FEATURES
,
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,
677 .features
= MII_BASIC_FEATURES
,
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,
696 .features
= MII_GBIT_FEATURES
,
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,
715 .features
= MII_GBIT_FEATURES
,
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,
734 .features
= MII_GBIT_FEATURES
,
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,
753 .features
= MII_GBIT_FEATURES
,
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
,
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
,
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
,
811 .ops
= &generic_phy_ops
814 static struct mii_phy_def
* mii_phy_table
[] = {
827 int mii_phy_probe(struct mii_phy
*phy
, int mii_id
)
831 struct mii_phy_def
* def
;
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
);
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
)
850 /* Should never be NULL (we have a generic entry), but... */
861 phy
->advertising
= 0;
865 EXPORT_SYMBOL(mii_phy_probe
);
866 MODULE_LICENSE("GPL");