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
);
101 phy_write(phy
, MII_BCM5201_INTERRUPT
, 0);
106 static int bcm5201_suspend(struct mii_phy
* phy
)
108 phy_write(phy
, MII_BCM5201_INTERRUPT
, 0);
109 phy_write(phy
, MII_BCM5201_MULTIPHY
, MII_BCM5201_MULTIPHY_SUPERISOLATE
);
114 static int bcm5221_init(struct mii_phy
* phy
)
118 data
= phy_read(phy
, MII_BCM5221_TEST
);
119 phy_write(phy
, MII_BCM5221_TEST
,
120 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
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
);
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
);
130 data
= phy_read(phy
, MII_BCM5221_TEST
);
131 phy_write(phy
, MII_BCM5221_TEST
,
132 data
& ~MII_BCM5221_TEST_ENABLE_SHADOWS
);
137 static int bcm5221_suspend(struct mii_phy
* phy
)
141 data
= phy_read(phy
, MII_BCM5221_TEST
);
142 phy_write(phy
, MII_BCM5221_TEST
,
143 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
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
);
152 static int bcm5400_init(struct mii_phy
* phy
)
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
);
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
);
167 /* Reset and configure cascaded 10/100 PHY */
168 (void)reset_one_mii_phy(phy
, 0x1f);
170 data
= __phy_read(phy
, 0x1f, MII_BCM5201_MULTIPHY
);
171 data
|= MII_BCM5201_MULTIPHY_SERIALMODE
;
172 __phy_write(phy
, 0x1f, MII_BCM5201_MULTIPHY
, data
);
174 data
= phy_read(phy
, MII_BCM5400_AUXCONTROL
);
175 data
&= ~MII_BCM5400_AUXCONTROL_PWR10BASET
;
176 phy_write(phy
, MII_BCM5400_AUXCONTROL
, data
);
181 static int bcm5400_suspend(struct mii_phy
* phy
)
183 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
184 phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
189 static int bcm5401_init(struct mii_phy
* phy
)
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"
200 * WARNING ! OF and Darwin don't agree on the
201 * register addresses. OF seem to interpret the
202 * register numbers below as decimal
204 * Note: This should (and does) match tg3_init_5401phy_dsp
205 * in the tg3.c driver. -DaveM
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);
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
);
227 /* Reset and configure cascaded 10/100 PHY */
228 (void)reset_one_mii_phy(phy
, 0x1f);
230 data
= __phy_read(phy
, 0x1f, MII_BCM5201_MULTIPHY
);
231 data
|= MII_BCM5201_MULTIPHY_SERIALMODE
;
232 __phy_write(phy
, 0x1f, MII_BCM5201_MULTIPHY
, data
);
237 static int bcm5401_suspend(struct mii_phy
* phy
)
239 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
240 phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
245 static int bcm5411_init(struct mii_phy
* phy
)
249 /* Here's some more Apple black magic to setup
250 * some voltage stuffs.
252 phy_write(phy
, 0x1c, 0x8c23);
253 phy_write(phy
, 0x1c, 0x8ca3);
254 phy_write(phy
, 0x1c, 0x8c23);
256 /* Here, Apple seems to want to reset it, do
259 phy_write(phy
, MII_BMCR
, BMCR_RESET
);
260 phy_write(phy
, MII_BMCR
, 0x1340);
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
);
268 /* Reset and configure cascaded 10/100 PHY */
269 (void)reset_one_mii_phy(phy
, 0x1f);
274 static int bcm5411_suspend(struct mii_phy
* phy
)
276 phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
281 static int bcm5421_init(struct mii_phy
* phy
)
286 rev
= phy_read(phy
, MII_PHYSID2
) & 0x000f;
288 /* This is borrowed from MacOS
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);
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);
310 static int bcm5421k2_init(struct mii_phy
* phy
)
312 /* Init code borrowed from OF */
313 phy_write(phy
, 4, 0x01e1);
314 phy_write(phy
, 9, 0x0300);
319 static int bcm54xx_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
324 phy
->speed
= SPEED_10
;
325 phy
->duplex
= DUPLEX_HALF
;
327 phy
->advertising
= advertise
;
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
);
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
);
351 /* Start/Restart aneg */
352 ctl
= phy_read(phy
, MII_BMCR
);
353 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
354 phy_write(phy
, MII_BMCR
, ctl
);
359 static int bcm54xx_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
368 ctl
= phy_read(phy
, MII_BMCR
);
369 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_SPD2
|BMCR_ANENABLE
);
371 /* First reset the PHY */
372 phy_write(phy
, MII_BMCR
, ctl
| BMCR_RESET
);
374 /* Select speed & duplex */
379 ctl
|= BMCR_SPEED100
;
384 if (fd
== DUPLEX_FULL
)
385 ctl
|= BMCR_FULLDPLX
;
387 // XXX Should we set the sungem to GII now on 1000BT ?
389 phy_write(phy
, MII_BMCR
, ctl
);
394 static int bcm54xx_read_link(struct mii_phy
*phy
)
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] ?
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);
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
417 static int marvell_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
422 phy
->speed
= SPEED_10
;
423 phy
->duplex
= DUPLEX_HALF
;
425 phy
->advertising
= advertise
;
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
);
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
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
);
456 /* Start/Restart aneg */
457 ctl
= phy_read(phy
, MII_BMCR
);
458 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
459 phy_write(phy
, MII_BMCR
, ctl
);
464 static int marvell_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
473 ctl
= phy_read(phy
, MII_BMCR
);
474 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_SPD2
|BMCR_ANENABLE
);
477 /* Select speed & duplex */
482 ctl
|= BMCR_SPEED100
;
484 /* I'm not sure about the one below, again, Darwin source is
485 * quite confusing and I lack chip specs
490 if (fd
== DUPLEX_FULL
)
491 ctl
|= BMCR_FULLDPLX
;
493 /* Disable crossover. Again, the way Apple does it is strange,
494 * though I don't assume they are wrong ;)
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
);
507 // XXX Should we set the sungem to GII now on 1000BT ?
509 phy_write(phy
, MII_BMCR
, ctl
);
514 static int marvell_read_link(struct mii_phy
*phy
)
519 status
= phy_read(phy
, MII_M1011_PHY_SPEC_STATUS
);
520 if ((status
& MII_M1011_PHY_SPEC_STATUS_RESOLVED
) == 0)
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
;
527 phy
->speed
= SPEED_10
;
528 if (status
& MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX
)
529 phy
->duplex
= DUPLEX_FULL
;
531 phy
->duplex
= DUPLEX_HALF
;
532 phy
->pause
= 0; /* XXX Check against spec ! */
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
541 static int genmii_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
546 phy
->speed
= SPEED_10
;
547 phy
->duplex
= DUPLEX_HALF
;
549 phy
->advertising
= advertise
;
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
);
564 /* Start/Restart aneg */
565 ctl
= phy_read(phy
, MII_BMCR
);
566 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
567 phy_write(phy
, MII_BMCR
, ctl
);
572 static int genmii_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
581 ctl
= phy_read(phy
, MII_BMCR
);
582 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_ANENABLE
);
584 /* First reset the PHY */
585 phy_write(phy
, MII_BMCR
, ctl
| BMCR_RESET
);
587 /* Select speed & duplex */
592 ctl
|= BMCR_SPEED100
;
598 if (fd
== DUPLEX_FULL
)
599 ctl
|= BMCR_FULLDPLX
;
600 phy_write(phy
, MII_BMCR
, ctl
);
605 static int genmii_poll_link(struct mii_phy
*phy
)
609 (void)phy_read(phy
, MII_BMSR
);
610 status
= phy_read(phy
, MII_BMSR
);
611 if ((status
& BMSR_LSTATUS
) == 0)
613 if (phy
->autoneg
&& !(status
& BMSR_ANEGCOMPLETE
))
618 static int genmii_read_link(struct mii_phy
*phy
)
623 lpa
= phy_read(phy
, MII_LPA
);
625 if (lpa
& (LPA_10FULL
| LPA_100FULL
))
626 phy
->duplex
= DUPLEX_FULL
;
628 phy
->duplex
= DUPLEX_HALF
;
629 if (lpa
& (LPA_100FULL
| LPA_100HALF
))
630 phy
->speed
= SPEED_100
;
632 phy
->speed
= SPEED_10
;
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
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)
649 /* Broadcom BCM 5201 */
650 static 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
,
659 static struct mii_phy_def bcm5201_phy_def
= {
660 .phy_id
= 0x00406210,
661 .phy_id_mask
= 0xfffffff0,
663 .features
= MII_BASIC_FEATURES
,
665 .ops
= &bcm5201_phy_ops
668 /* Broadcom BCM 5221 */
669 static 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
,
678 static struct mii_phy_def bcm5221_phy_def
= {
679 .phy_id
= 0x004061e0,
680 .phy_id_mask
= 0xfffffff0,
682 .features
= MII_BASIC_FEATURES
,
684 .ops
= &bcm5221_phy_ops
687 /* Broadcom BCM 5400 */
688 static 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
,
697 static struct mii_phy_def bcm5400_phy_def
= {
698 .phy_id
= 0x00206040,
699 .phy_id_mask
= 0xfffffff0,
701 .features
= MII_GBIT_FEATURES
,
703 .ops
= &bcm5400_phy_ops
706 /* Broadcom BCM 5401 */
707 static 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
,
716 static struct mii_phy_def bcm5401_phy_def
= {
717 .phy_id
= 0x00206050,
718 .phy_id_mask
= 0xfffffff0,
720 .features
= MII_GBIT_FEATURES
,
722 .ops
= &bcm5401_phy_ops
725 /* Broadcom BCM 5411 */
726 static 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
,
735 static struct mii_phy_def bcm5411_phy_def
= {
736 .phy_id
= 0x00206070,
737 .phy_id_mask
= 0xfffffff0,
739 .features
= MII_GBIT_FEATURES
,
741 .ops
= &bcm5411_phy_ops
744 /* Broadcom BCM 5421 */
745 static 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
,
754 static struct mii_phy_def bcm5421_phy_def
= {
755 .phy_id
= 0x002060e0,
756 .phy_id_mask
= 0xfffffff0,
758 .features
= MII_GBIT_FEATURES
,
760 .ops
= &bcm5421_phy_ops
763 /* Broadcom BCM 5421 built-in K2 */
764 static 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
,
773 static 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
,
779 .ops
= &bcm5421k2_phy_ops
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.
786 static 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
793 static 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
,
799 .ops
= &marvell_phy_ops
802 /* Generic implementation for most 10/100 PHYs */
803 static 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
810 static 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
,
816 .ops
= &generic_phy_ops
819 static struct mii_phy_def
* mii_phy_table
[] = {
832 int mii_phy_probe(struct mii_phy
*phy
, int mii_id
)
836 struct mii_phy_def
* def
;
839 /* We do not reset the mii_phy structure as the driver
840 * may re-probe the PHY regulary
842 phy
->mii_id
= mii_id
;
844 /* Take PHY out of isloate mode and reset it. */
845 rc
= reset_one_mii_phy(phy
, mii_id
);
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
)
855 /* Should never be NULL (we have a generic entry), but... */
866 phy
->advertising
= 0;
870 EXPORT_SYMBOL(mii_phy_probe
);
871 MODULE_LICENSE("GPL");