2 * PHY drivers for the sungem ethernet driver.
4 * This file could be shared with other drivers.
6 * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
9 * - Add support for PHYs that provide an IRQ line
10 * - Eventually moved the entire polling state machine in
11 * there (out of the eth driver), so that it can easily be
12 * skipped on PHYs that implement it in hardware.
13 * - On LXT971 & BCM5201, Apple uses some chip specific regs
14 * to read the link status. Figure out why and if it makes
15 * sense to do the same (magic aneg ?)
16 * - Apple has some additional power management code for some
17 * Broadcom PHYs that they "hide" from the OpenSource version
18 * of darwin, still need to reverse engineer that
22 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/types.h>
26 #include <linux/netdevice.h>
27 #include <linux/etherdevice.h>
28 #include <linux/mii.h>
29 #include <linux/ethtool.h>
30 #include <linux/delay.h>
32 #ifdef CONFIG_PPC_PMAC
36 #include <linux/sungem_phy.h>
38 /* Link modes of the BCM5400 PHY */
39 static const int phy_BCM5400_link_table
[8][3] = {
40 { 0, 0, 0 }, /* No link */
41 { 0, 0, 0 }, /* 10BT Half Duplex */
42 { 1, 0, 0 }, /* 10BT Full Duplex */
43 { 0, 1, 0 }, /* 100BT Half Duplex */
44 { 0, 1, 0 }, /* 100BT Half Duplex */
45 { 1, 1, 0 }, /* 100BT Full Duplex*/
46 { 1, 0, 1 }, /* 1000BT */
47 { 1, 0, 1 }, /* 1000BT */
50 static inline int __sungem_phy_read(struct mii_phy
* phy
, int id
, int reg
)
52 return phy
->mdio_read(phy
->dev
, id
, reg
);
55 static inline void __sungem_phy_write(struct mii_phy
* phy
, int id
, int reg
, int val
)
57 phy
->mdio_write(phy
->dev
, id
, reg
, val
);
60 static inline int sungem_phy_read(struct mii_phy
* phy
, int reg
)
62 return phy
->mdio_read(phy
->dev
, phy
->mii_id
, reg
);
65 static inline void sungem_phy_write(struct mii_phy
* phy
, int reg
, int val
)
67 phy
->mdio_write(phy
->dev
, phy
->mii_id
, reg
, val
);
70 static int reset_one_mii_phy(struct mii_phy
* phy
, int phy_id
)
75 val
= __sungem_phy_read(phy
, phy_id
, MII_BMCR
);
76 val
&= ~(BMCR_ISOLATE
| BMCR_PDOWN
);
78 __sungem_phy_write(phy
, phy_id
, MII_BMCR
, val
);
83 val
= __sungem_phy_read(phy
, phy_id
, MII_BMCR
);
84 if ((val
& BMCR_RESET
) == 0)
88 if ((val
& BMCR_ISOLATE
) && limit
> 0)
89 __sungem_phy_write(phy
, phy_id
, MII_BMCR
, val
& ~BMCR_ISOLATE
);
94 static int bcm5201_init(struct mii_phy
* phy
)
98 data
= sungem_phy_read(phy
, MII_BCM5201_MULTIPHY
);
99 data
&= ~MII_BCM5201_MULTIPHY_SUPERISOLATE
;
100 sungem_phy_write(phy
, MII_BCM5201_MULTIPHY
, data
);
102 sungem_phy_write(phy
, MII_BCM5201_INTERRUPT
, 0);
107 static int bcm5201_suspend(struct mii_phy
* phy
)
109 sungem_phy_write(phy
, MII_BCM5201_INTERRUPT
, 0);
110 sungem_phy_write(phy
, MII_BCM5201_MULTIPHY
, MII_BCM5201_MULTIPHY_SUPERISOLATE
);
115 static int bcm5221_init(struct mii_phy
* phy
)
119 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
120 sungem_phy_write(phy
, MII_BCM5221_TEST
,
121 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
123 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_STAT2
);
124 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_STAT2
,
125 data
| MII_BCM5221_SHDOW_AUX_STAT2_APD
);
127 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
128 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
129 data
| MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR
);
131 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
132 sungem_phy_write(phy
, MII_BCM5221_TEST
,
133 data
& ~MII_BCM5221_TEST_ENABLE_SHADOWS
);
138 static int bcm5221_suspend(struct mii_phy
* phy
)
142 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
143 sungem_phy_write(phy
, MII_BCM5221_TEST
,
144 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
146 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
147 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
148 data
| MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE
);
153 static int bcm5241_init(struct mii_phy
* phy
)
157 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
158 sungem_phy_write(phy
, MII_BCM5221_TEST
,
159 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
161 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_STAT2
);
162 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_STAT2
,
163 data
| MII_BCM5221_SHDOW_AUX_STAT2_APD
);
165 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
166 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
167 data
& ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR
);
169 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
170 sungem_phy_write(phy
, MII_BCM5221_TEST
,
171 data
& ~MII_BCM5221_TEST_ENABLE_SHADOWS
);
176 static int bcm5241_suspend(struct mii_phy
* phy
)
180 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
181 sungem_phy_write(phy
, MII_BCM5221_TEST
,
182 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
184 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
185 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
186 data
| MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR
);
191 static int bcm5400_init(struct mii_phy
* phy
)
195 /* Configure for gigabit full duplex */
196 data
= sungem_phy_read(phy
, MII_BCM5400_AUXCONTROL
);
197 data
|= MII_BCM5400_AUXCONTROL_PWR10BASET
;
198 sungem_phy_write(phy
, MII_BCM5400_AUXCONTROL
, data
);
200 data
= sungem_phy_read(phy
, MII_BCM5400_GB_CONTROL
);
201 data
|= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP
;
202 sungem_phy_write(phy
, MII_BCM5400_GB_CONTROL
, data
);
206 /* Reset and configure cascaded 10/100 PHY */
207 (void)reset_one_mii_phy(phy
, 0x1f);
209 data
= __sungem_phy_read(phy
, 0x1f, MII_BCM5201_MULTIPHY
);
210 data
|= MII_BCM5201_MULTIPHY_SERIALMODE
;
211 __sungem_phy_write(phy
, 0x1f, MII_BCM5201_MULTIPHY
, data
);
213 data
= sungem_phy_read(phy
, MII_BCM5400_AUXCONTROL
);
214 data
&= ~MII_BCM5400_AUXCONTROL_PWR10BASET
;
215 sungem_phy_write(phy
, MII_BCM5400_AUXCONTROL
, data
);
220 static int bcm5400_suspend(struct mii_phy
* phy
)
222 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
223 sungem_phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
228 static int bcm5401_init(struct mii_phy
* phy
)
233 rev
= sungem_phy_read(phy
, MII_PHYSID2
) & 0x000f;
234 if (rev
== 0 || rev
== 3) {
235 /* Some revisions of 5401 appear to need this
236 * initialisation sequence to disable, according
237 * to OF, "tap power management"
239 * WARNING ! OF and Darwin don't agree on the
240 * register addresses. OF seem to interpret the
241 * register numbers below as decimal
243 * Note: This should (and does) match tg3_init_5401phy_dsp
244 * in the tg3.c driver. -DaveM
246 sungem_phy_write(phy
, 0x18, 0x0c20);
247 sungem_phy_write(phy
, 0x17, 0x0012);
248 sungem_phy_write(phy
, 0x15, 0x1804);
249 sungem_phy_write(phy
, 0x17, 0x0013);
250 sungem_phy_write(phy
, 0x15, 0x1204);
251 sungem_phy_write(phy
, 0x17, 0x8006);
252 sungem_phy_write(phy
, 0x15, 0x0132);
253 sungem_phy_write(phy
, 0x17, 0x8006);
254 sungem_phy_write(phy
, 0x15, 0x0232);
255 sungem_phy_write(phy
, 0x17, 0x201f);
256 sungem_phy_write(phy
, 0x15, 0x0a20);
259 /* Configure for gigabit full duplex */
260 data
= sungem_phy_read(phy
, MII_BCM5400_GB_CONTROL
);
261 data
|= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP
;
262 sungem_phy_write(phy
, MII_BCM5400_GB_CONTROL
, data
);
266 /* Reset and configure cascaded 10/100 PHY */
267 (void)reset_one_mii_phy(phy
, 0x1f);
269 data
= __sungem_phy_read(phy
, 0x1f, MII_BCM5201_MULTIPHY
);
270 data
|= MII_BCM5201_MULTIPHY_SERIALMODE
;
271 __sungem_phy_write(phy
, 0x1f, MII_BCM5201_MULTIPHY
, data
);
276 static int bcm5401_suspend(struct mii_phy
* phy
)
278 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
279 sungem_phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
284 static int bcm5411_init(struct mii_phy
* phy
)
288 /* Here's some more Apple black magic to setup
289 * some voltage stuffs.
291 sungem_phy_write(phy
, 0x1c, 0x8c23);
292 sungem_phy_write(phy
, 0x1c, 0x8ca3);
293 sungem_phy_write(phy
, 0x1c, 0x8c23);
295 /* Here, Apple seems to want to reset it, do
298 sungem_phy_write(phy
, MII_BMCR
, BMCR_RESET
);
299 sungem_phy_write(phy
, MII_BMCR
, 0x1340);
301 data
= sungem_phy_read(phy
, MII_BCM5400_GB_CONTROL
);
302 data
|= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP
;
303 sungem_phy_write(phy
, MII_BCM5400_GB_CONTROL
, data
);
307 /* Reset and configure cascaded 10/100 PHY */
308 (void)reset_one_mii_phy(phy
, 0x1f);
313 static int genmii_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
318 phy
->speed
= SPEED_10
;
319 phy
->duplex
= DUPLEX_HALF
;
321 phy
->advertising
= advertise
;
323 /* Setup standard advertise */
324 adv
= sungem_phy_read(phy
, MII_ADVERTISE
);
325 adv
&= ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
326 if (advertise
& ADVERTISED_10baseT_Half
)
327 adv
|= ADVERTISE_10HALF
;
328 if (advertise
& ADVERTISED_10baseT_Full
)
329 adv
|= ADVERTISE_10FULL
;
330 if (advertise
& ADVERTISED_100baseT_Half
)
331 adv
|= ADVERTISE_100HALF
;
332 if (advertise
& ADVERTISED_100baseT_Full
)
333 adv
|= ADVERTISE_100FULL
;
334 sungem_phy_write(phy
, MII_ADVERTISE
, adv
);
336 /* Start/Restart aneg */
337 ctl
= sungem_phy_read(phy
, MII_BMCR
);
338 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
339 sungem_phy_write(phy
, MII_BMCR
, ctl
);
344 static int genmii_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
353 ctl
= sungem_phy_read(phy
, MII_BMCR
);
354 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_ANENABLE
);
356 /* First reset the PHY */
357 sungem_phy_write(phy
, MII_BMCR
, ctl
| BMCR_RESET
);
359 /* Select speed & duplex */
364 ctl
|= BMCR_SPEED100
;
370 if (fd
== DUPLEX_FULL
)
371 ctl
|= BMCR_FULLDPLX
;
372 sungem_phy_write(phy
, MII_BMCR
, ctl
);
377 static int genmii_poll_link(struct mii_phy
*phy
)
381 (void)sungem_phy_read(phy
, MII_BMSR
);
382 status
= sungem_phy_read(phy
, MII_BMSR
);
383 if ((status
& BMSR_LSTATUS
) == 0)
385 if (phy
->autoneg
&& !(status
& BMSR_ANEGCOMPLETE
))
390 static int genmii_read_link(struct mii_phy
*phy
)
395 lpa
= sungem_phy_read(phy
, MII_LPA
);
397 if (lpa
& (LPA_10FULL
| LPA_100FULL
))
398 phy
->duplex
= DUPLEX_FULL
;
400 phy
->duplex
= DUPLEX_HALF
;
401 if (lpa
& (LPA_100FULL
| LPA_100HALF
))
402 phy
->speed
= SPEED_100
;
404 phy
->speed
= SPEED_10
;
407 /* On non-aneg, we assume what we put in BMCR is the speed,
408 * though magic-aneg shouldn't prevent this case from occurring
414 static int generic_suspend(struct mii_phy
* phy
)
416 sungem_phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
421 static int bcm5421_init(struct mii_phy
* phy
)
426 id
= (sungem_phy_read(phy
, MII_PHYSID1
) << 16 | sungem_phy_read(phy
, MII_PHYSID2
));
428 /* Revision 0 of 5421 needs some fixups */
429 if (id
== 0x002060e0) {
430 /* This is borrowed from MacOS
432 sungem_phy_write(phy
, 0x18, 0x1007);
433 data
= sungem_phy_read(phy
, 0x18);
434 sungem_phy_write(phy
, 0x18, data
| 0x0400);
435 sungem_phy_write(phy
, 0x18, 0x0007);
436 data
= sungem_phy_read(phy
, 0x18);
437 sungem_phy_write(phy
, 0x18, data
| 0x0800);
438 sungem_phy_write(phy
, 0x17, 0x000a);
439 data
= sungem_phy_read(phy
, 0x15);
440 sungem_phy_write(phy
, 0x15, data
| 0x0200);
443 /* Pick up some init code from OF for K2 version */
444 if ((id
& 0xfffffff0) == 0x002062e0) {
445 sungem_phy_write(phy
, 4, 0x01e1);
446 sungem_phy_write(phy
, 9, 0x0300);
449 /* Check if we can enable automatic low power */
450 #ifdef CONFIG_PPC_PMAC
451 if (phy
->platform_data
) {
452 struct device_node
*np
= of_get_parent(phy
->platform_data
);
453 int can_low_power
= 1;
454 if (np
== NULL
|| of_get_property(np
, "no-autolowpower", NULL
))
457 /* Enable automatic low-power */
458 sungem_phy_write(phy
, 0x1c, 0x9002);
459 sungem_phy_write(phy
, 0x1c, 0xa821);
460 sungem_phy_write(phy
, 0x1c, 0x941d);
463 #endif /* CONFIG_PPC_PMAC */
468 static int bcm54xx_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
473 phy
->speed
= SPEED_10
;
474 phy
->duplex
= DUPLEX_HALF
;
476 phy
->advertising
= advertise
;
478 /* Setup standard advertise */
479 adv
= sungem_phy_read(phy
, MII_ADVERTISE
);
480 adv
&= ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
481 if (advertise
& ADVERTISED_10baseT_Half
)
482 adv
|= ADVERTISE_10HALF
;
483 if (advertise
& ADVERTISED_10baseT_Full
)
484 adv
|= ADVERTISE_10FULL
;
485 if (advertise
& ADVERTISED_100baseT_Half
)
486 adv
|= ADVERTISE_100HALF
;
487 if (advertise
& ADVERTISED_100baseT_Full
)
488 adv
|= ADVERTISE_100FULL
;
489 if (advertise
& ADVERTISED_Pause
)
490 adv
|= ADVERTISE_PAUSE_CAP
;
491 if (advertise
& ADVERTISED_Asym_Pause
)
492 adv
|= ADVERTISE_PAUSE_ASYM
;
493 sungem_phy_write(phy
, MII_ADVERTISE
, adv
);
495 /* Setup 1000BT advertise */
496 adv
= sungem_phy_read(phy
, MII_1000BASETCONTROL
);
497 adv
&= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP
|MII_1000BASETCONTROL_HALFDUPLEXCAP
);
498 if (advertise
& SUPPORTED_1000baseT_Half
)
499 adv
|= MII_1000BASETCONTROL_HALFDUPLEXCAP
;
500 if (advertise
& SUPPORTED_1000baseT_Full
)
501 adv
|= MII_1000BASETCONTROL_FULLDUPLEXCAP
;
502 sungem_phy_write(phy
, MII_1000BASETCONTROL
, adv
);
504 /* Start/Restart aneg */
505 ctl
= sungem_phy_read(phy
, MII_BMCR
);
506 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
507 sungem_phy_write(phy
, MII_BMCR
, ctl
);
512 static int bcm54xx_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
521 ctl
= sungem_phy_read(phy
, MII_BMCR
);
522 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_SPD2
|BMCR_ANENABLE
);
524 /* First reset the PHY */
525 sungem_phy_write(phy
, MII_BMCR
, ctl
| BMCR_RESET
);
527 /* Select speed & duplex */
532 ctl
|= BMCR_SPEED100
;
537 if (fd
== DUPLEX_FULL
)
538 ctl
|= BMCR_FULLDPLX
;
540 // XXX Should we set the sungem to GII now on 1000BT ?
542 sungem_phy_write(phy
, MII_BMCR
, ctl
);
547 static int bcm54xx_read_link(struct mii_phy
*phy
)
553 val
= sungem_phy_read(phy
, MII_BCM5400_AUXSTATUS
);
554 link_mode
= ((val
& MII_BCM5400_AUXSTATUS_LINKMODE_MASK
) >>
555 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT
);
556 phy
->duplex
= phy_BCM5400_link_table
[link_mode
][0] ?
557 DUPLEX_FULL
: DUPLEX_HALF
;
558 phy
->speed
= phy_BCM5400_link_table
[link_mode
][2] ?
560 (phy_BCM5400_link_table
[link_mode
][1] ?
561 SPEED_100
: SPEED_10
);
562 val
= sungem_phy_read(phy
, MII_LPA
);
563 phy
->pause
= (phy
->duplex
== DUPLEX_FULL
) &&
564 ((val
& LPA_PAUSE
) != 0);
566 /* On non-aneg, we assume what we put in BMCR is the speed,
567 * though magic-aneg shouldn't prevent this case from occurring
573 static int marvell88e1111_init(struct mii_phy
* phy
)
577 /* magic init sequence for rev 0 */
578 rev
= sungem_phy_read(phy
, MII_PHYSID2
) & 0x000f;
580 sungem_phy_write(phy
, 0x1d, 0x000a);
581 sungem_phy_write(phy
, 0x1e, 0x0821);
583 sungem_phy_write(phy
, 0x1d, 0x0006);
584 sungem_phy_write(phy
, 0x1e, 0x8600);
586 sungem_phy_write(phy
, 0x1d, 0x000b);
587 sungem_phy_write(phy
, 0x1e, 0x0100);
589 sungem_phy_write(phy
, 0x1d, 0x0004);
590 sungem_phy_write(phy
, 0x1e, 0x4850);
595 #define BCM5421_MODE_MASK (1 << 5)
597 static int bcm5421_poll_link(struct mii_phy
* phy
)
602 /* find out in what mode we are */
603 sungem_phy_write(phy
, MII_NCONFIG
, 0x1000);
604 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
606 mode
= (phy_reg
& BCM5421_MODE_MASK
) >> 5;
608 if ( mode
== BCM54XX_COPPER
)
609 return genmii_poll_link(phy
);
611 /* try to find out whether we have a link */
612 sungem_phy_write(phy
, MII_NCONFIG
, 0x2000);
613 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
615 if (phy_reg
& 0x0020)
621 static int bcm5421_read_link(struct mii_phy
* phy
)
626 /* find out in what mode we are */
627 sungem_phy_write(phy
, MII_NCONFIG
, 0x1000);
628 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
630 mode
= (phy_reg
& BCM5421_MODE_MASK
) >> 5;
632 if ( mode
== BCM54XX_COPPER
)
633 return bcm54xx_read_link(phy
);
635 phy
->speed
= SPEED_1000
;
637 /* find out whether we are running half- or full duplex */
638 sungem_phy_write(phy
, MII_NCONFIG
, 0x2000);
639 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
641 if ( (phy_reg
& 0x0080) >> 7)
642 phy
->duplex
|= DUPLEX_HALF
;
644 phy
->duplex
|= DUPLEX_FULL
;
649 static int bcm5421_enable_fiber(struct mii_phy
* phy
, int autoneg
)
651 /* enable fiber mode */
652 sungem_phy_write(phy
, MII_NCONFIG
, 0x9020);
653 /* LEDs active in both modes, autosense prio = fiber */
654 sungem_phy_write(phy
, MII_NCONFIG
, 0x945f);
657 /* switch off fibre autoneg */
658 sungem_phy_write(phy
, MII_NCONFIG
, 0xfc01);
659 sungem_phy_write(phy
, 0x0b, 0x0004);
662 phy
->autoneg
= autoneg
;
667 #define BCM5461_FIBER_LINK (1 << 2)
668 #define BCM5461_MODE_MASK (3 << 1)
670 static int bcm5461_poll_link(struct mii_phy
* phy
)
675 /* find out in what mode we are */
676 sungem_phy_write(phy
, MII_NCONFIG
, 0x7c00);
677 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
679 mode
= (phy_reg
& BCM5461_MODE_MASK
) >> 1;
681 if ( mode
== BCM54XX_COPPER
)
682 return genmii_poll_link(phy
);
684 /* find out whether we have a link */
685 sungem_phy_write(phy
, MII_NCONFIG
, 0x7000);
686 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
688 if (phy_reg
& BCM5461_FIBER_LINK
)
694 #define BCM5461_FIBER_DUPLEX (1 << 3)
696 static int bcm5461_read_link(struct mii_phy
* phy
)
701 /* find out in what mode we are */
702 sungem_phy_write(phy
, MII_NCONFIG
, 0x7c00);
703 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
705 mode
= (phy_reg
& BCM5461_MODE_MASK
) >> 1;
707 if ( mode
== BCM54XX_COPPER
) {
708 return bcm54xx_read_link(phy
);
711 phy
->speed
= SPEED_1000
;
713 /* find out whether we are running half- or full duplex */
714 sungem_phy_write(phy
, MII_NCONFIG
, 0x7000);
715 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
717 if (phy_reg
& BCM5461_FIBER_DUPLEX
)
718 phy
->duplex
|= DUPLEX_FULL
;
720 phy
->duplex
|= DUPLEX_HALF
;
725 static int bcm5461_enable_fiber(struct mii_phy
* phy
, int autoneg
)
727 /* select fiber mode, enable 1000 base-X registers */
728 sungem_phy_write(phy
, MII_NCONFIG
, 0xfc0b);
731 /* enable fiber with no autonegotiation */
732 sungem_phy_write(phy
, MII_ADVERTISE
, 0x01e0);
733 sungem_phy_write(phy
, MII_BMCR
, 0x1140);
735 /* enable fiber with autonegotiation */
736 sungem_phy_write(phy
, MII_BMCR
, 0x0140);
739 phy
->autoneg
= autoneg
;
744 static int marvell_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
749 phy
->speed
= SPEED_10
;
750 phy
->duplex
= DUPLEX_HALF
;
752 phy
->advertising
= advertise
;
754 /* Setup standard advertise */
755 adv
= sungem_phy_read(phy
, MII_ADVERTISE
);
756 adv
&= ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
757 if (advertise
& ADVERTISED_10baseT_Half
)
758 adv
|= ADVERTISE_10HALF
;
759 if (advertise
& ADVERTISED_10baseT_Full
)
760 adv
|= ADVERTISE_10FULL
;
761 if (advertise
& ADVERTISED_100baseT_Half
)
762 adv
|= ADVERTISE_100HALF
;
763 if (advertise
& ADVERTISED_100baseT_Full
)
764 adv
|= ADVERTISE_100FULL
;
765 if (advertise
& ADVERTISED_Pause
)
766 adv
|= ADVERTISE_PAUSE_CAP
;
767 if (advertise
& ADVERTISED_Asym_Pause
)
768 adv
|= ADVERTISE_PAUSE_ASYM
;
769 sungem_phy_write(phy
, MII_ADVERTISE
, adv
);
771 /* Setup 1000BT advertise & enable crossover detect
772 * XXX How do we advertise 1000BT ? Darwin source is
773 * confusing here, they read from specific control and
774 * write to control... Someone has specs for those
777 adv
= sungem_phy_read(phy
, MII_M1011_PHY_SPEC_CONTROL
);
778 adv
|= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX
;
779 adv
&= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP
|
780 MII_1000BASETCONTROL_HALFDUPLEXCAP
);
781 if (advertise
& SUPPORTED_1000baseT_Half
)
782 adv
|= MII_1000BASETCONTROL_HALFDUPLEXCAP
;
783 if (advertise
& SUPPORTED_1000baseT_Full
)
784 adv
|= MII_1000BASETCONTROL_FULLDUPLEXCAP
;
785 sungem_phy_write(phy
, MII_1000BASETCONTROL
, adv
);
787 /* Start/Restart aneg */
788 ctl
= sungem_phy_read(phy
, MII_BMCR
);
789 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
790 sungem_phy_write(phy
, MII_BMCR
, ctl
);
795 static int marvell_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
804 ctl
= sungem_phy_read(phy
, MII_BMCR
);
805 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_SPD2
|BMCR_ANENABLE
);
808 /* Select speed & duplex */
813 ctl
|= BMCR_SPEED100
;
815 /* I'm not sure about the one below, again, Darwin source is
816 * quite confusing and I lack chip specs
821 if (fd
== DUPLEX_FULL
)
822 ctl
|= BMCR_FULLDPLX
;
824 /* Disable crossover. Again, the way Apple does it is strange,
825 * though I don't assume they are wrong ;)
827 ctl2
= sungem_phy_read(phy
, MII_M1011_PHY_SPEC_CONTROL
);
828 ctl2
&= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX
|
829 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX
|
830 MII_1000BASETCONTROL_FULLDUPLEXCAP
|
831 MII_1000BASETCONTROL_HALFDUPLEXCAP
);
832 if (speed
== SPEED_1000
)
833 ctl2
|= (fd
== DUPLEX_FULL
) ?
834 MII_1000BASETCONTROL_FULLDUPLEXCAP
:
835 MII_1000BASETCONTROL_HALFDUPLEXCAP
;
836 sungem_phy_write(phy
, MII_1000BASETCONTROL
, ctl2
);
838 // XXX Should we set the sungem to GII now on 1000BT ?
840 sungem_phy_write(phy
, MII_BMCR
, ctl
);
845 static int marvell_read_link(struct mii_phy
*phy
)
850 status
= sungem_phy_read(phy
, MII_M1011_PHY_SPEC_STATUS
);
851 if ((status
& MII_M1011_PHY_SPEC_STATUS_RESOLVED
) == 0)
853 if (status
& MII_M1011_PHY_SPEC_STATUS_1000
)
854 phy
->speed
= SPEED_1000
;
855 else if (status
& MII_M1011_PHY_SPEC_STATUS_100
)
856 phy
->speed
= SPEED_100
;
858 phy
->speed
= SPEED_10
;
859 if (status
& MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX
)
860 phy
->duplex
= DUPLEX_FULL
;
862 phy
->duplex
= DUPLEX_HALF
;
863 pmask
= MII_M1011_PHY_SPEC_STATUS_TX_PAUSE
|
864 MII_M1011_PHY_SPEC_STATUS_RX_PAUSE
;
865 phy
->pause
= (status
& pmask
) == pmask
;
867 /* On non-aneg, we assume what we put in BMCR is the speed,
868 * though magic-aneg shouldn't prevent this case from occurring
874 #define MII_BASIC_FEATURES \
875 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
876 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
877 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
880 /* On gigabit capable PHYs, we advertise Pause support but not asym pause
881 * support for now as I'm not sure it's supported and Darwin doesn't do
882 * it neither. --BenH.
884 #define MII_GBIT_FEATURES \
885 (MII_BASIC_FEATURES | \
886 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
888 /* Broadcom BCM 5201 */
889 static struct mii_phy_ops bcm5201_phy_ops
= {
890 .init
= bcm5201_init
,
891 .suspend
= bcm5201_suspend
,
892 .setup_aneg
= genmii_setup_aneg
,
893 .setup_forced
= genmii_setup_forced
,
894 .poll_link
= genmii_poll_link
,
895 .read_link
= genmii_read_link
,
898 static struct mii_phy_def bcm5201_phy_def
= {
899 .phy_id
= 0x00406210,
900 .phy_id_mask
= 0xfffffff0,
902 .features
= MII_BASIC_FEATURES
,
904 .ops
= &bcm5201_phy_ops
907 /* Broadcom BCM 5221 */
908 static struct mii_phy_ops bcm5221_phy_ops
= {
909 .suspend
= bcm5221_suspend
,
910 .init
= bcm5221_init
,
911 .setup_aneg
= genmii_setup_aneg
,
912 .setup_forced
= genmii_setup_forced
,
913 .poll_link
= genmii_poll_link
,
914 .read_link
= genmii_read_link
,
917 static struct mii_phy_def bcm5221_phy_def
= {
918 .phy_id
= 0x004061e0,
919 .phy_id_mask
= 0xfffffff0,
921 .features
= MII_BASIC_FEATURES
,
923 .ops
= &bcm5221_phy_ops
926 /* Broadcom BCM 5241 */
927 static struct mii_phy_ops bcm5241_phy_ops
= {
928 .suspend
= bcm5241_suspend
,
929 .init
= bcm5241_init
,
930 .setup_aneg
= genmii_setup_aneg
,
931 .setup_forced
= genmii_setup_forced
,
932 .poll_link
= genmii_poll_link
,
933 .read_link
= genmii_read_link
,
935 static struct mii_phy_def bcm5241_phy_def
= {
936 .phy_id
= 0x0143bc30,
937 .phy_id_mask
= 0xfffffff0,
939 .features
= MII_BASIC_FEATURES
,
941 .ops
= &bcm5241_phy_ops
944 /* Broadcom BCM 5400 */
945 static struct mii_phy_ops bcm5400_phy_ops
= {
946 .init
= bcm5400_init
,
947 .suspend
= bcm5400_suspend
,
948 .setup_aneg
= bcm54xx_setup_aneg
,
949 .setup_forced
= bcm54xx_setup_forced
,
950 .poll_link
= genmii_poll_link
,
951 .read_link
= bcm54xx_read_link
,
954 static struct mii_phy_def bcm5400_phy_def
= {
955 .phy_id
= 0x00206040,
956 .phy_id_mask
= 0xfffffff0,
958 .features
= MII_GBIT_FEATURES
,
960 .ops
= &bcm5400_phy_ops
963 /* Broadcom BCM 5401 */
964 static struct mii_phy_ops bcm5401_phy_ops
= {
965 .init
= bcm5401_init
,
966 .suspend
= bcm5401_suspend
,
967 .setup_aneg
= bcm54xx_setup_aneg
,
968 .setup_forced
= bcm54xx_setup_forced
,
969 .poll_link
= genmii_poll_link
,
970 .read_link
= bcm54xx_read_link
,
973 static struct mii_phy_def bcm5401_phy_def
= {
974 .phy_id
= 0x00206050,
975 .phy_id_mask
= 0xfffffff0,
977 .features
= MII_GBIT_FEATURES
,
979 .ops
= &bcm5401_phy_ops
982 /* Broadcom BCM 5411 */
983 static struct mii_phy_ops bcm5411_phy_ops
= {
984 .init
= bcm5411_init
,
985 .suspend
= generic_suspend
,
986 .setup_aneg
= bcm54xx_setup_aneg
,
987 .setup_forced
= bcm54xx_setup_forced
,
988 .poll_link
= genmii_poll_link
,
989 .read_link
= bcm54xx_read_link
,
992 static struct mii_phy_def bcm5411_phy_def
= {
993 .phy_id
= 0x00206070,
994 .phy_id_mask
= 0xfffffff0,
996 .features
= MII_GBIT_FEATURES
,
998 .ops
= &bcm5411_phy_ops
1001 /* Broadcom BCM 5421 */
1002 static struct mii_phy_ops bcm5421_phy_ops
= {
1003 .init
= bcm5421_init
,
1004 .suspend
= generic_suspend
,
1005 .setup_aneg
= bcm54xx_setup_aneg
,
1006 .setup_forced
= bcm54xx_setup_forced
,
1007 .poll_link
= bcm5421_poll_link
,
1008 .read_link
= bcm5421_read_link
,
1009 .enable_fiber
= bcm5421_enable_fiber
,
1012 static struct mii_phy_def bcm5421_phy_def
= {
1013 .phy_id
= 0x002060e0,
1014 .phy_id_mask
= 0xfffffff0,
1016 .features
= MII_GBIT_FEATURES
,
1018 .ops
= &bcm5421_phy_ops
1021 /* Broadcom BCM 5421 built-in K2 */
1022 static struct mii_phy_ops bcm5421k2_phy_ops
= {
1023 .init
= bcm5421_init
,
1024 .suspend
= generic_suspend
,
1025 .setup_aneg
= bcm54xx_setup_aneg
,
1026 .setup_forced
= bcm54xx_setup_forced
,
1027 .poll_link
= genmii_poll_link
,
1028 .read_link
= bcm54xx_read_link
,
1031 static struct mii_phy_def bcm5421k2_phy_def
= {
1032 .phy_id
= 0x002062e0,
1033 .phy_id_mask
= 0xfffffff0,
1034 .name
= "BCM5421-K2",
1035 .features
= MII_GBIT_FEATURES
,
1037 .ops
= &bcm5421k2_phy_ops
1040 static struct mii_phy_ops bcm5461_phy_ops
= {
1041 .init
= bcm5421_init
,
1042 .suspend
= generic_suspend
,
1043 .setup_aneg
= bcm54xx_setup_aneg
,
1044 .setup_forced
= bcm54xx_setup_forced
,
1045 .poll_link
= bcm5461_poll_link
,
1046 .read_link
= bcm5461_read_link
,
1047 .enable_fiber
= bcm5461_enable_fiber
,
1050 static struct mii_phy_def bcm5461_phy_def
= {
1051 .phy_id
= 0x002060c0,
1052 .phy_id_mask
= 0xfffffff0,
1054 .features
= MII_GBIT_FEATURES
,
1056 .ops
= &bcm5461_phy_ops
1059 /* Broadcom BCM 5462 built-in Vesta */
1060 static struct mii_phy_ops bcm5462V_phy_ops
= {
1061 .init
= bcm5421_init
,
1062 .suspend
= generic_suspend
,
1063 .setup_aneg
= bcm54xx_setup_aneg
,
1064 .setup_forced
= bcm54xx_setup_forced
,
1065 .poll_link
= genmii_poll_link
,
1066 .read_link
= bcm54xx_read_link
,
1069 static struct mii_phy_def bcm5462V_phy_def
= {
1070 .phy_id
= 0x002060d0,
1071 .phy_id_mask
= 0xfffffff0,
1072 .name
= "BCM5462-Vesta",
1073 .features
= MII_GBIT_FEATURES
,
1075 .ops
= &bcm5462V_phy_ops
1078 /* Marvell 88E1101 amd 88E1111 */
1079 static struct mii_phy_ops marvell88e1101_phy_ops
= {
1080 .suspend
= generic_suspend
,
1081 .setup_aneg
= marvell_setup_aneg
,
1082 .setup_forced
= marvell_setup_forced
,
1083 .poll_link
= genmii_poll_link
,
1084 .read_link
= marvell_read_link
1087 static struct mii_phy_ops marvell88e1111_phy_ops
= {
1088 .init
= marvell88e1111_init
,
1089 .suspend
= generic_suspend
,
1090 .setup_aneg
= marvell_setup_aneg
,
1091 .setup_forced
= marvell_setup_forced
,
1092 .poll_link
= genmii_poll_link
,
1093 .read_link
= marvell_read_link
1096 /* two revs in darwin for the 88e1101 ... I could use a datasheet
1097 * to get the proper names...
1099 static struct mii_phy_def marvell88e1101v1_phy_def
= {
1100 .phy_id
= 0x01410c20,
1101 .phy_id_mask
= 0xfffffff0,
1102 .name
= "Marvell 88E1101v1",
1103 .features
= MII_GBIT_FEATURES
,
1105 .ops
= &marvell88e1101_phy_ops
1107 static struct mii_phy_def marvell88e1101v2_phy_def
= {
1108 .phy_id
= 0x01410c60,
1109 .phy_id_mask
= 0xfffffff0,
1110 .name
= "Marvell 88E1101v2",
1111 .features
= MII_GBIT_FEATURES
,
1113 .ops
= &marvell88e1101_phy_ops
1115 static struct mii_phy_def marvell88e1111_phy_def
= {
1116 .phy_id
= 0x01410cc0,
1117 .phy_id_mask
= 0xfffffff0,
1118 .name
= "Marvell 88E1111",
1119 .features
= MII_GBIT_FEATURES
,
1121 .ops
= &marvell88e1111_phy_ops
1124 /* Generic implementation for most 10/100 PHYs */
1125 static struct mii_phy_ops generic_phy_ops
= {
1126 .setup_aneg
= genmii_setup_aneg
,
1127 .setup_forced
= genmii_setup_forced
,
1128 .poll_link
= genmii_poll_link
,
1129 .read_link
= genmii_read_link
1132 static struct mii_phy_def genmii_phy_def
= {
1133 .phy_id
= 0x00000000,
1134 .phy_id_mask
= 0x00000000,
1135 .name
= "Generic MII",
1136 .features
= MII_BASIC_FEATURES
,
1138 .ops
= &generic_phy_ops
1141 static struct mii_phy_def
* mii_phy_table
[] = {
1152 &marvell88e1101v1_phy_def
,
1153 &marvell88e1101v2_phy_def
,
1154 &marvell88e1111_phy_def
,
1159 int sungem_phy_probe(struct mii_phy
*phy
, int mii_id
)
1163 struct mii_phy_def
* def
;
1166 /* We do not reset the mii_phy structure as the driver
1167 * may re-probe the PHY regulary
1169 phy
->mii_id
= mii_id
;
1171 /* Take PHY out of isloate mode and reset it. */
1172 rc
= reset_one_mii_phy(phy
, mii_id
);
1176 /* Read ID and find matching entry */
1177 id
= (sungem_phy_read(phy
, MII_PHYSID1
) << 16 | sungem_phy_read(phy
, MII_PHYSID2
));
1178 printk(KERN_DEBUG KBUILD_MODNAME
": " "PHY ID: %x, addr: %x\n",
1180 for (i
=0; (def
= mii_phy_table
[i
]) != NULL
; i
++)
1181 if ((id
& def
->phy_id_mask
) == def
->phy_id
)
1183 /* Should never be NULL (we have a generic entry), but... */
1194 phy
->advertising
= 0;
1198 EXPORT_SYMBOL(sungem_phy_probe
);
1199 MODULE_LICENSE("GPL");