1 // SPDX-License-Identifier: GPL-2.0-only
3 * PHY drivers for the sungem ethernet driver.
5 * This file could be shared with other drivers.
7 * (c) 2002-2007, 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
23 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/types.h>
27 #include <linux/netdevice.h>
28 #include <linux/etherdevice.h>
29 #include <linux/mii.h>
30 #include <linux/ethtool.h>
31 #include <linux/delay.h>
33 #include <linux/sungem_phy.h>
35 /* Link modes of the BCM5400 PHY */
36 static const int phy_BCM5400_link_table
[8][3] = {
37 { 0, 0, 0 }, /* No link */
38 { 0, 0, 0 }, /* 10BT Half Duplex */
39 { 1, 0, 0 }, /* 10BT Full Duplex */
40 { 0, 1, 0 }, /* 100BT Half Duplex */
41 { 0, 1, 0 }, /* 100BT Half Duplex */
42 { 1, 1, 0 }, /* 100BT Full Duplex*/
43 { 1, 0, 1 }, /* 1000BT */
44 { 1, 0, 1 }, /* 1000BT */
47 static inline int __sungem_phy_read(struct mii_phy
* phy
, int id
, int reg
)
49 return phy
->mdio_read(phy
->dev
, id
, reg
);
52 static inline void __sungem_phy_write(struct mii_phy
* phy
, int id
, int reg
, int val
)
54 phy
->mdio_write(phy
->dev
, id
, reg
, val
);
57 static inline int sungem_phy_read(struct mii_phy
* phy
, int reg
)
59 return phy
->mdio_read(phy
->dev
, phy
->mii_id
, reg
);
62 static inline void sungem_phy_write(struct mii_phy
* phy
, int reg
, int val
)
64 phy
->mdio_write(phy
->dev
, phy
->mii_id
, reg
, val
);
67 static int reset_one_mii_phy(struct mii_phy
* phy
, int phy_id
)
72 val
= __sungem_phy_read(phy
, phy_id
, MII_BMCR
);
73 val
&= ~(BMCR_ISOLATE
| BMCR_PDOWN
);
75 __sungem_phy_write(phy
, phy_id
, MII_BMCR
, val
);
80 val
= __sungem_phy_read(phy
, phy_id
, MII_BMCR
);
81 if ((val
& BMCR_RESET
) == 0)
85 if ((val
& BMCR_ISOLATE
) && limit
> 0)
86 __sungem_phy_write(phy
, phy_id
, MII_BMCR
, val
& ~BMCR_ISOLATE
);
91 static int bcm5201_init(struct mii_phy
* phy
)
95 data
= sungem_phy_read(phy
, MII_BCM5201_MULTIPHY
);
96 data
&= ~MII_BCM5201_MULTIPHY_SUPERISOLATE
;
97 sungem_phy_write(phy
, MII_BCM5201_MULTIPHY
, data
);
99 sungem_phy_write(phy
, MII_BCM5201_INTERRUPT
, 0);
104 static int bcm5201_suspend(struct mii_phy
* phy
)
106 sungem_phy_write(phy
, MII_BCM5201_INTERRUPT
, 0);
107 sungem_phy_write(phy
, MII_BCM5201_MULTIPHY
, MII_BCM5201_MULTIPHY_SUPERISOLATE
);
112 static int bcm5221_init(struct mii_phy
* phy
)
116 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
117 sungem_phy_write(phy
, MII_BCM5221_TEST
,
118 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
120 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_STAT2
);
121 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_STAT2
,
122 data
| MII_BCM5221_SHDOW_AUX_STAT2_APD
);
124 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
125 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
126 data
| MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR
);
128 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
129 sungem_phy_write(phy
, MII_BCM5221_TEST
,
130 data
& ~MII_BCM5221_TEST_ENABLE_SHADOWS
);
135 static int bcm5221_suspend(struct mii_phy
* phy
)
139 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
140 sungem_phy_write(phy
, MII_BCM5221_TEST
,
141 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
143 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
144 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
145 data
| MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE
);
150 static int bcm5241_init(struct mii_phy
* phy
)
154 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
155 sungem_phy_write(phy
, MII_BCM5221_TEST
,
156 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
158 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_STAT2
);
159 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_STAT2
,
160 data
| MII_BCM5221_SHDOW_AUX_STAT2_APD
);
162 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
163 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
164 data
& ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR
);
166 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
167 sungem_phy_write(phy
, MII_BCM5221_TEST
,
168 data
& ~MII_BCM5221_TEST_ENABLE_SHADOWS
);
173 static int bcm5241_suspend(struct mii_phy
* phy
)
177 data
= sungem_phy_read(phy
, MII_BCM5221_TEST
);
178 sungem_phy_write(phy
, MII_BCM5221_TEST
,
179 data
| MII_BCM5221_TEST_ENABLE_SHADOWS
);
181 data
= sungem_phy_read(phy
, MII_BCM5221_SHDOW_AUX_MODE4
);
182 sungem_phy_write(phy
, MII_BCM5221_SHDOW_AUX_MODE4
,
183 data
| MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR
);
188 static int bcm5400_init(struct mii_phy
* phy
)
192 /* Configure for gigabit full duplex */
193 data
= sungem_phy_read(phy
, MII_BCM5400_AUXCONTROL
);
194 data
|= MII_BCM5400_AUXCONTROL_PWR10BASET
;
195 sungem_phy_write(phy
, MII_BCM5400_AUXCONTROL
, data
);
197 data
= sungem_phy_read(phy
, MII_BCM5400_GB_CONTROL
);
198 data
|= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP
;
199 sungem_phy_write(phy
, MII_BCM5400_GB_CONTROL
, data
);
203 /* Reset and configure cascaded 10/100 PHY */
204 (void)reset_one_mii_phy(phy
, 0x1f);
206 data
= __sungem_phy_read(phy
, 0x1f, MII_BCM5201_MULTIPHY
);
207 data
|= MII_BCM5201_MULTIPHY_SERIALMODE
;
208 __sungem_phy_write(phy
, 0x1f, MII_BCM5201_MULTIPHY
, data
);
210 data
= sungem_phy_read(phy
, MII_BCM5400_AUXCONTROL
);
211 data
&= ~MII_BCM5400_AUXCONTROL_PWR10BASET
;
212 sungem_phy_write(phy
, MII_BCM5400_AUXCONTROL
, data
);
217 static int bcm5400_suspend(struct mii_phy
* phy
)
219 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
220 sungem_phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
225 static int bcm5401_init(struct mii_phy
* phy
)
230 rev
= sungem_phy_read(phy
, MII_PHYSID2
) & 0x000f;
231 if (rev
== 0 || rev
== 3) {
232 /* Some revisions of 5401 appear to need this
233 * initialisation sequence to disable, according
234 * to OF, "tap power management"
236 * WARNING ! OF and Darwin don't agree on the
237 * register addresses. OF seem to interpret the
238 * register numbers below as decimal
240 * Note: This should (and does) match tg3_init_5401phy_dsp
241 * in the tg3.c driver. -DaveM
243 sungem_phy_write(phy
, 0x18, 0x0c20);
244 sungem_phy_write(phy
, 0x17, 0x0012);
245 sungem_phy_write(phy
, 0x15, 0x1804);
246 sungem_phy_write(phy
, 0x17, 0x0013);
247 sungem_phy_write(phy
, 0x15, 0x1204);
248 sungem_phy_write(phy
, 0x17, 0x8006);
249 sungem_phy_write(phy
, 0x15, 0x0132);
250 sungem_phy_write(phy
, 0x17, 0x8006);
251 sungem_phy_write(phy
, 0x15, 0x0232);
252 sungem_phy_write(phy
, 0x17, 0x201f);
253 sungem_phy_write(phy
, 0x15, 0x0a20);
256 /* Configure for gigabit full duplex */
257 data
= sungem_phy_read(phy
, MII_BCM5400_GB_CONTROL
);
258 data
|= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP
;
259 sungem_phy_write(phy
, MII_BCM5400_GB_CONTROL
, data
);
263 /* Reset and configure cascaded 10/100 PHY */
264 (void)reset_one_mii_phy(phy
, 0x1f);
266 data
= __sungem_phy_read(phy
, 0x1f, MII_BCM5201_MULTIPHY
);
267 data
|= MII_BCM5201_MULTIPHY_SERIALMODE
;
268 __sungem_phy_write(phy
, 0x1f, MII_BCM5201_MULTIPHY
, data
);
273 static int bcm5401_suspend(struct mii_phy
* phy
)
275 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
276 sungem_phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
281 static int bcm5411_init(struct mii_phy
* phy
)
285 /* Here's some more Apple black magic to setup
286 * some voltage stuffs.
288 sungem_phy_write(phy
, 0x1c, 0x8c23);
289 sungem_phy_write(phy
, 0x1c, 0x8ca3);
290 sungem_phy_write(phy
, 0x1c, 0x8c23);
292 /* Here, Apple seems to want to reset it, do
295 sungem_phy_write(phy
, MII_BMCR
, BMCR_RESET
);
296 sungem_phy_write(phy
, MII_BMCR
, 0x1340);
298 data
= sungem_phy_read(phy
, MII_BCM5400_GB_CONTROL
);
299 data
|= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP
;
300 sungem_phy_write(phy
, MII_BCM5400_GB_CONTROL
, data
);
304 /* Reset and configure cascaded 10/100 PHY */
305 (void)reset_one_mii_phy(phy
, 0x1f);
310 static int genmii_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
315 phy
->speed
= SPEED_10
;
316 phy
->duplex
= DUPLEX_HALF
;
318 phy
->advertising
= advertise
;
320 /* Setup standard advertise */
321 adv
= sungem_phy_read(phy
, MII_ADVERTISE
);
322 adv
&= ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
323 if (advertise
& ADVERTISED_10baseT_Half
)
324 adv
|= ADVERTISE_10HALF
;
325 if (advertise
& ADVERTISED_10baseT_Full
)
326 adv
|= ADVERTISE_10FULL
;
327 if (advertise
& ADVERTISED_100baseT_Half
)
328 adv
|= ADVERTISE_100HALF
;
329 if (advertise
& ADVERTISED_100baseT_Full
)
330 adv
|= ADVERTISE_100FULL
;
331 sungem_phy_write(phy
, MII_ADVERTISE
, adv
);
333 /* Start/Restart aneg */
334 ctl
= sungem_phy_read(phy
, MII_BMCR
);
335 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
336 sungem_phy_write(phy
, MII_BMCR
, ctl
);
341 static int genmii_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
350 ctl
= sungem_phy_read(phy
, MII_BMCR
);
351 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_ANENABLE
);
353 /* First reset the PHY */
354 sungem_phy_write(phy
, MII_BMCR
, ctl
| BMCR_RESET
);
356 /* Select speed & duplex */
361 ctl
|= BMCR_SPEED100
;
367 if (fd
== DUPLEX_FULL
)
368 ctl
|= BMCR_FULLDPLX
;
369 sungem_phy_write(phy
, MII_BMCR
, ctl
);
374 static int genmii_poll_link(struct mii_phy
*phy
)
378 (void)sungem_phy_read(phy
, MII_BMSR
);
379 status
= sungem_phy_read(phy
, MII_BMSR
);
380 if ((status
& BMSR_LSTATUS
) == 0)
382 if (phy
->autoneg
&& !(status
& BMSR_ANEGCOMPLETE
))
387 static int genmii_read_link(struct mii_phy
*phy
)
392 lpa
= sungem_phy_read(phy
, MII_LPA
);
394 if (lpa
& (LPA_10FULL
| LPA_100FULL
))
395 phy
->duplex
= DUPLEX_FULL
;
397 phy
->duplex
= DUPLEX_HALF
;
398 if (lpa
& (LPA_100FULL
| LPA_100HALF
))
399 phy
->speed
= SPEED_100
;
401 phy
->speed
= SPEED_10
;
404 /* On non-aneg, we assume what we put in BMCR is the speed,
405 * though magic-aneg shouldn't prevent this case from occurring
411 static int generic_suspend(struct mii_phy
* phy
)
413 sungem_phy_write(phy
, MII_BMCR
, BMCR_PDOWN
);
418 static int bcm5421_init(struct mii_phy
* phy
)
423 id
= (sungem_phy_read(phy
, MII_PHYSID1
) << 16 | sungem_phy_read(phy
, MII_PHYSID2
));
425 /* Revision 0 of 5421 needs some fixups */
426 if (id
== 0x002060e0) {
427 /* This is borrowed from MacOS
429 sungem_phy_write(phy
, 0x18, 0x1007);
430 data
= sungem_phy_read(phy
, 0x18);
431 sungem_phy_write(phy
, 0x18, data
| 0x0400);
432 sungem_phy_write(phy
, 0x18, 0x0007);
433 data
= sungem_phy_read(phy
, 0x18);
434 sungem_phy_write(phy
, 0x18, data
| 0x0800);
435 sungem_phy_write(phy
, 0x17, 0x000a);
436 data
= sungem_phy_read(phy
, 0x15);
437 sungem_phy_write(phy
, 0x15, data
| 0x0200);
440 /* Pick up some init code from OF for K2 version */
441 if ((id
& 0xfffffff0) == 0x002062e0) {
442 sungem_phy_write(phy
, 4, 0x01e1);
443 sungem_phy_write(phy
, 9, 0x0300);
446 /* Check if we can enable automatic low power */
447 #ifdef CONFIG_PPC_PMAC
448 if (phy
->platform_data
) {
449 struct device_node
*np
= of_get_parent(phy
->platform_data
);
450 int can_low_power
= 1;
451 if (np
== NULL
|| of_get_property(np
, "no-autolowpower", NULL
))
455 /* Enable automatic low-power */
456 sungem_phy_write(phy
, 0x1c, 0x9002);
457 sungem_phy_write(phy
, 0x1c, 0xa821);
458 sungem_phy_write(phy
, 0x1c, 0x941d);
461 #endif /* CONFIG_PPC_PMAC */
466 static int bcm54xx_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
471 phy
->speed
= SPEED_10
;
472 phy
->duplex
= DUPLEX_HALF
;
474 phy
->advertising
= advertise
;
476 /* Setup standard advertise */
477 adv
= sungem_phy_read(phy
, MII_ADVERTISE
);
478 adv
&= ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
479 if (advertise
& ADVERTISED_10baseT_Half
)
480 adv
|= ADVERTISE_10HALF
;
481 if (advertise
& ADVERTISED_10baseT_Full
)
482 adv
|= ADVERTISE_10FULL
;
483 if (advertise
& ADVERTISED_100baseT_Half
)
484 adv
|= ADVERTISE_100HALF
;
485 if (advertise
& ADVERTISED_100baseT_Full
)
486 adv
|= ADVERTISE_100FULL
;
487 if (advertise
& ADVERTISED_Pause
)
488 adv
|= ADVERTISE_PAUSE_CAP
;
489 if (advertise
& ADVERTISED_Asym_Pause
)
490 adv
|= ADVERTISE_PAUSE_ASYM
;
491 sungem_phy_write(phy
, MII_ADVERTISE
, adv
);
493 /* Setup 1000BT advertise */
494 adv
= sungem_phy_read(phy
, MII_1000BASETCONTROL
);
495 adv
&= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP
|MII_1000BASETCONTROL_HALFDUPLEXCAP
);
496 if (advertise
& SUPPORTED_1000baseT_Half
)
497 adv
|= MII_1000BASETCONTROL_HALFDUPLEXCAP
;
498 if (advertise
& SUPPORTED_1000baseT_Full
)
499 adv
|= MII_1000BASETCONTROL_FULLDUPLEXCAP
;
500 sungem_phy_write(phy
, MII_1000BASETCONTROL
, adv
);
502 /* Start/Restart aneg */
503 ctl
= sungem_phy_read(phy
, MII_BMCR
);
504 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
505 sungem_phy_write(phy
, MII_BMCR
, ctl
);
510 static int bcm54xx_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
519 ctl
= sungem_phy_read(phy
, MII_BMCR
);
520 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_SPD2
|BMCR_ANENABLE
);
522 /* First reset the PHY */
523 sungem_phy_write(phy
, MII_BMCR
, ctl
| BMCR_RESET
);
525 /* Select speed & duplex */
530 ctl
|= BMCR_SPEED100
;
535 if (fd
== DUPLEX_FULL
)
536 ctl
|= BMCR_FULLDPLX
;
538 // XXX Should we set the sungem to GII now on 1000BT ?
540 sungem_phy_write(phy
, MII_BMCR
, ctl
);
545 static int bcm54xx_read_link(struct mii_phy
*phy
)
551 val
= sungem_phy_read(phy
, MII_BCM5400_AUXSTATUS
);
552 link_mode
= ((val
& MII_BCM5400_AUXSTATUS_LINKMODE_MASK
) >>
553 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT
);
554 phy
->duplex
= phy_BCM5400_link_table
[link_mode
][0] ?
555 DUPLEX_FULL
: DUPLEX_HALF
;
556 phy
->speed
= phy_BCM5400_link_table
[link_mode
][2] ?
558 (phy_BCM5400_link_table
[link_mode
][1] ?
559 SPEED_100
: SPEED_10
);
560 val
= sungem_phy_read(phy
, MII_LPA
);
561 phy
->pause
= (phy
->duplex
== DUPLEX_FULL
) &&
562 ((val
& LPA_PAUSE
) != 0);
564 /* On non-aneg, we assume what we put in BMCR is the speed,
565 * though magic-aneg shouldn't prevent this case from occurring
571 static int marvell88e1111_init(struct mii_phy
* phy
)
575 /* magic init sequence for rev 0 */
576 rev
= sungem_phy_read(phy
, MII_PHYSID2
) & 0x000f;
578 sungem_phy_write(phy
, 0x1d, 0x000a);
579 sungem_phy_write(phy
, 0x1e, 0x0821);
581 sungem_phy_write(phy
, 0x1d, 0x0006);
582 sungem_phy_write(phy
, 0x1e, 0x8600);
584 sungem_phy_write(phy
, 0x1d, 0x000b);
585 sungem_phy_write(phy
, 0x1e, 0x0100);
587 sungem_phy_write(phy
, 0x1d, 0x0004);
588 sungem_phy_write(phy
, 0x1e, 0x4850);
593 #define BCM5421_MODE_MASK (1 << 5)
595 static int bcm5421_poll_link(struct mii_phy
* phy
)
600 /* find out in what mode we are */
601 sungem_phy_write(phy
, MII_NCONFIG
, 0x1000);
602 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
604 mode
= (phy_reg
& BCM5421_MODE_MASK
) >> 5;
606 if ( mode
== BCM54XX_COPPER
)
607 return genmii_poll_link(phy
);
609 /* try to find out whether we have a link */
610 sungem_phy_write(phy
, MII_NCONFIG
, 0x2000);
611 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
613 if (phy_reg
& 0x0020)
619 static int bcm5421_read_link(struct mii_phy
* phy
)
624 /* find out in what mode we are */
625 sungem_phy_write(phy
, MII_NCONFIG
, 0x1000);
626 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
628 mode
= (phy_reg
& BCM5421_MODE_MASK
) >> 5;
630 if ( mode
== BCM54XX_COPPER
)
631 return bcm54xx_read_link(phy
);
633 phy
->speed
= SPEED_1000
;
635 /* find out whether we are running half- or full duplex */
636 sungem_phy_write(phy
, MII_NCONFIG
, 0x2000);
637 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
639 if ( (phy_reg
& 0x0080) >> 7)
640 phy
->duplex
|= DUPLEX_HALF
;
642 phy
->duplex
|= DUPLEX_FULL
;
647 static int bcm5421_enable_fiber(struct mii_phy
* phy
, int autoneg
)
649 /* enable fiber mode */
650 sungem_phy_write(phy
, MII_NCONFIG
, 0x9020);
651 /* LEDs active in both modes, autosense prio = fiber */
652 sungem_phy_write(phy
, MII_NCONFIG
, 0x945f);
655 /* switch off fibre autoneg */
656 sungem_phy_write(phy
, MII_NCONFIG
, 0xfc01);
657 sungem_phy_write(phy
, 0x0b, 0x0004);
660 phy
->autoneg
= autoneg
;
665 #define BCM5461_FIBER_LINK (1 << 2)
666 #define BCM5461_MODE_MASK (3 << 1)
668 static int bcm5461_poll_link(struct mii_phy
* phy
)
673 /* find out in what mode we are */
674 sungem_phy_write(phy
, MII_NCONFIG
, 0x7c00);
675 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
677 mode
= (phy_reg
& BCM5461_MODE_MASK
) >> 1;
679 if ( mode
== BCM54XX_COPPER
)
680 return genmii_poll_link(phy
);
682 /* find out whether we have a link */
683 sungem_phy_write(phy
, MII_NCONFIG
, 0x7000);
684 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
686 if (phy_reg
& BCM5461_FIBER_LINK
)
692 #define BCM5461_FIBER_DUPLEX (1 << 3)
694 static int bcm5461_read_link(struct mii_phy
* phy
)
699 /* find out in what mode we are */
700 sungem_phy_write(phy
, MII_NCONFIG
, 0x7c00);
701 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
703 mode
= (phy_reg
& BCM5461_MODE_MASK
) >> 1;
705 if ( mode
== BCM54XX_COPPER
) {
706 return bcm54xx_read_link(phy
);
709 phy
->speed
= SPEED_1000
;
711 /* find out whether we are running half- or full duplex */
712 sungem_phy_write(phy
, MII_NCONFIG
, 0x7000);
713 phy_reg
= sungem_phy_read(phy
, MII_NCONFIG
);
715 if (phy_reg
& BCM5461_FIBER_DUPLEX
)
716 phy
->duplex
|= DUPLEX_FULL
;
718 phy
->duplex
|= DUPLEX_HALF
;
723 static int bcm5461_enable_fiber(struct mii_phy
* phy
, int autoneg
)
725 /* select fiber mode, enable 1000 base-X registers */
726 sungem_phy_write(phy
, MII_NCONFIG
, 0xfc0b);
729 /* enable fiber with no autonegotiation */
730 sungem_phy_write(phy
, MII_ADVERTISE
, 0x01e0);
731 sungem_phy_write(phy
, MII_BMCR
, 0x1140);
733 /* enable fiber with autonegotiation */
734 sungem_phy_write(phy
, MII_BMCR
, 0x0140);
737 phy
->autoneg
= autoneg
;
742 static int marvell_setup_aneg(struct mii_phy
*phy
, u32 advertise
)
747 phy
->speed
= SPEED_10
;
748 phy
->duplex
= DUPLEX_HALF
;
750 phy
->advertising
= advertise
;
752 /* Setup standard advertise */
753 adv
= sungem_phy_read(phy
, MII_ADVERTISE
);
754 adv
&= ~(ADVERTISE_ALL
| ADVERTISE_100BASE4
);
755 if (advertise
& ADVERTISED_10baseT_Half
)
756 adv
|= ADVERTISE_10HALF
;
757 if (advertise
& ADVERTISED_10baseT_Full
)
758 adv
|= ADVERTISE_10FULL
;
759 if (advertise
& ADVERTISED_100baseT_Half
)
760 adv
|= ADVERTISE_100HALF
;
761 if (advertise
& ADVERTISED_100baseT_Full
)
762 adv
|= ADVERTISE_100FULL
;
763 if (advertise
& ADVERTISED_Pause
)
764 adv
|= ADVERTISE_PAUSE_CAP
;
765 if (advertise
& ADVERTISED_Asym_Pause
)
766 adv
|= ADVERTISE_PAUSE_ASYM
;
767 sungem_phy_write(phy
, MII_ADVERTISE
, adv
);
769 /* Setup 1000BT advertise & enable crossover detect
770 * XXX How do we advertise 1000BT ? Darwin source is
771 * confusing here, they read from specific control and
772 * write to control... Someone has specs for those
775 adv
= sungem_phy_read(phy
, MII_M1011_PHY_SPEC_CONTROL
);
776 adv
|= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX
;
777 adv
&= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP
|
778 MII_1000BASETCONTROL_HALFDUPLEXCAP
);
779 if (advertise
& SUPPORTED_1000baseT_Half
)
780 adv
|= MII_1000BASETCONTROL_HALFDUPLEXCAP
;
781 if (advertise
& SUPPORTED_1000baseT_Full
)
782 adv
|= MII_1000BASETCONTROL_FULLDUPLEXCAP
;
783 sungem_phy_write(phy
, MII_1000BASETCONTROL
, adv
);
785 /* Start/Restart aneg */
786 ctl
= sungem_phy_read(phy
, MII_BMCR
);
787 ctl
|= (BMCR_ANENABLE
| BMCR_ANRESTART
);
788 sungem_phy_write(phy
, MII_BMCR
, ctl
);
793 static int marvell_setup_forced(struct mii_phy
*phy
, int speed
, int fd
)
802 ctl
= sungem_phy_read(phy
, MII_BMCR
);
803 ctl
&= ~(BMCR_FULLDPLX
|BMCR_SPEED100
|BMCR_SPD2
|BMCR_ANENABLE
);
806 /* Select speed & duplex */
811 ctl
|= BMCR_SPEED100
;
813 /* I'm not sure about the one below, again, Darwin source is
814 * quite confusing and I lack chip specs
819 if (fd
== DUPLEX_FULL
)
820 ctl
|= BMCR_FULLDPLX
;
822 /* Disable crossover. Again, the way Apple does it is strange,
823 * though I don't assume they are wrong ;)
825 ctl2
= sungem_phy_read(phy
, MII_M1011_PHY_SPEC_CONTROL
);
826 ctl2
&= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX
|
827 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX
|
828 MII_1000BASETCONTROL_FULLDUPLEXCAP
|
829 MII_1000BASETCONTROL_HALFDUPLEXCAP
);
830 if (speed
== SPEED_1000
)
831 ctl2
|= (fd
== DUPLEX_FULL
) ?
832 MII_1000BASETCONTROL_FULLDUPLEXCAP
:
833 MII_1000BASETCONTROL_HALFDUPLEXCAP
;
834 sungem_phy_write(phy
, MII_1000BASETCONTROL
, ctl2
);
836 // XXX Should we set the sungem to GII now on 1000BT ?
838 sungem_phy_write(phy
, MII_BMCR
, ctl
);
843 static int marvell_read_link(struct mii_phy
*phy
)
848 status
= sungem_phy_read(phy
, MII_M1011_PHY_SPEC_STATUS
);
849 if ((status
& MII_M1011_PHY_SPEC_STATUS_RESOLVED
) == 0)
851 if (status
& MII_M1011_PHY_SPEC_STATUS_1000
)
852 phy
->speed
= SPEED_1000
;
853 else if (status
& MII_M1011_PHY_SPEC_STATUS_100
)
854 phy
->speed
= SPEED_100
;
856 phy
->speed
= SPEED_10
;
857 if (status
& MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX
)
858 phy
->duplex
= DUPLEX_FULL
;
860 phy
->duplex
= DUPLEX_HALF
;
861 pmask
= MII_M1011_PHY_SPEC_STATUS_TX_PAUSE
|
862 MII_M1011_PHY_SPEC_STATUS_RX_PAUSE
;
863 phy
->pause
= (status
& pmask
) == pmask
;
865 /* On non-aneg, we assume what we put in BMCR is the speed,
866 * though magic-aneg shouldn't prevent this case from occurring
872 #define MII_BASIC_FEATURES \
873 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
874 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
875 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
878 /* On gigabit capable PHYs, we advertise Pause support but not asym pause
879 * support for now as I'm not sure it's supported and Darwin doesn't do
880 * it neither. --BenH.
882 #define MII_GBIT_FEATURES \
883 (MII_BASIC_FEATURES | \
884 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
886 /* Broadcom BCM 5201 */
887 static const struct mii_phy_ops bcm5201_phy_ops
= {
888 .init
= bcm5201_init
,
889 .suspend
= bcm5201_suspend
,
890 .setup_aneg
= genmii_setup_aneg
,
891 .setup_forced
= genmii_setup_forced
,
892 .poll_link
= genmii_poll_link
,
893 .read_link
= genmii_read_link
,
896 static const struct mii_phy_def bcm5201_phy_def
= {
897 .phy_id
= 0x00406210,
898 .phy_id_mask
= 0xfffffff0,
900 .features
= MII_BASIC_FEATURES
,
902 .ops
= &bcm5201_phy_ops
905 /* Broadcom BCM 5221 */
906 static const struct mii_phy_ops bcm5221_phy_ops
= {
907 .suspend
= bcm5221_suspend
,
908 .init
= bcm5221_init
,
909 .setup_aneg
= genmii_setup_aneg
,
910 .setup_forced
= genmii_setup_forced
,
911 .poll_link
= genmii_poll_link
,
912 .read_link
= genmii_read_link
,
915 static const struct mii_phy_def bcm5221_phy_def
= {
916 .phy_id
= 0x004061e0,
917 .phy_id_mask
= 0xfffffff0,
919 .features
= MII_BASIC_FEATURES
,
921 .ops
= &bcm5221_phy_ops
924 /* Broadcom BCM 5241 */
925 static const struct mii_phy_ops bcm5241_phy_ops
= {
926 .suspend
= bcm5241_suspend
,
927 .init
= bcm5241_init
,
928 .setup_aneg
= genmii_setup_aneg
,
929 .setup_forced
= genmii_setup_forced
,
930 .poll_link
= genmii_poll_link
,
931 .read_link
= genmii_read_link
,
934 static const struct mii_phy_def bcm5241_phy_def
= {
935 .phy_id
= 0x0143bc30,
936 .phy_id_mask
= 0xfffffff0,
938 .features
= MII_BASIC_FEATURES
,
940 .ops
= &bcm5241_phy_ops
943 /* Broadcom BCM 5400 */
944 static const struct mii_phy_ops bcm5400_phy_ops
= {
945 .init
= bcm5400_init
,
946 .suspend
= bcm5400_suspend
,
947 .setup_aneg
= bcm54xx_setup_aneg
,
948 .setup_forced
= bcm54xx_setup_forced
,
949 .poll_link
= genmii_poll_link
,
950 .read_link
= bcm54xx_read_link
,
953 static const struct mii_phy_def bcm5400_phy_def
= {
954 .phy_id
= 0x00206040,
955 .phy_id_mask
= 0xfffffff0,
957 .features
= MII_GBIT_FEATURES
,
959 .ops
= &bcm5400_phy_ops
962 /* Broadcom BCM 5401 */
963 static const struct mii_phy_ops bcm5401_phy_ops
= {
964 .init
= bcm5401_init
,
965 .suspend
= bcm5401_suspend
,
966 .setup_aneg
= bcm54xx_setup_aneg
,
967 .setup_forced
= bcm54xx_setup_forced
,
968 .poll_link
= genmii_poll_link
,
969 .read_link
= bcm54xx_read_link
,
972 static const struct mii_phy_def bcm5401_phy_def
= {
973 .phy_id
= 0x00206050,
974 .phy_id_mask
= 0xfffffff0,
976 .features
= MII_GBIT_FEATURES
,
978 .ops
= &bcm5401_phy_ops
981 /* Broadcom BCM 5411 */
982 static const struct mii_phy_ops bcm5411_phy_ops
= {
983 .init
= bcm5411_init
,
984 .suspend
= generic_suspend
,
985 .setup_aneg
= bcm54xx_setup_aneg
,
986 .setup_forced
= bcm54xx_setup_forced
,
987 .poll_link
= genmii_poll_link
,
988 .read_link
= bcm54xx_read_link
,
991 static const struct mii_phy_def bcm5411_phy_def
= {
992 .phy_id
= 0x00206070,
993 .phy_id_mask
= 0xfffffff0,
995 .features
= MII_GBIT_FEATURES
,
997 .ops
= &bcm5411_phy_ops
1000 /* Broadcom BCM 5421 */
1001 static const struct mii_phy_ops bcm5421_phy_ops
= {
1002 .init
= bcm5421_init
,
1003 .suspend
= generic_suspend
,
1004 .setup_aneg
= bcm54xx_setup_aneg
,
1005 .setup_forced
= bcm54xx_setup_forced
,
1006 .poll_link
= bcm5421_poll_link
,
1007 .read_link
= bcm5421_read_link
,
1008 .enable_fiber
= bcm5421_enable_fiber
,
1011 static const struct mii_phy_def bcm5421_phy_def
= {
1012 .phy_id
= 0x002060e0,
1013 .phy_id_mask
= 0xfffffff0,
1015 .features
= MII_GBIT_FEATURES
,
1017 .ops
= &bcm5421_phy_ops
1020 /* Broadcom BCM 5421 built-in K2 */
1021 static const struct mii_phy_ops bcm5421k2_phy_ops
= {
1022 .init
= bcm5421_init
,
1023 .suspend
= generic_suspend
,
1024 .setup_aneg
= bcm54xx_setup_aneg
,
1025 .setup_forced
= bcm54xx_setup_forced
,
1026 .poll_link
= genmii_poll_link
,
1027 .read_link
= bcm54xx_read_link
,
1030 static const struct mii_phy_def bcm5421k2_phy_def
= {
1031 .phy_id
= 0x002062e0,
1032 .phy_id_mask
= 0xfffffff0,
1033 .name
= "BCM5421-K2",
1034 .features
= MII_GBIT_FEATURES
,
1036 .ops
= &bcm5421k2_phy_ops
1039 static const struct mii_phy_ops bcm5461_phy_ops
= {
1040 .init
= bcm5421_init
,
1041 .suspend
= generic_suspend
,
1042 .setup_aneg
= bcm54xx_setup_aneg
,
1043 .setup_forced
= bcm54xx_setup_forced
,
1044 .poll_link
= bcm5461_poll_link
,
1045 .read_link
= bcm5461_read_link
,
1046 .enable_fiber
= bcm5461_enable_fiber
,
1049 static const struct mii_phy_def bcm5461_phy_def
= {
1050 .phy_id
= 0x002060c0,
1051 .phy_id_mask
= 0xfffffff0,
1053 .features
= MII_GBIT_FEATURES
,
1055 .ops
= &bcm5461_phy_ops
1058 /* Broadcom BCM 5462 built-in Vesta */
1059 static const struct mii_phy_ops bcm5462V_phy_ops
= {
1060 .init
= bcm5421_init
,
1061 .suspend
= generic_suspend
,
1062 .setup_aneg
= bcm54xx_setup_aneg
,
1063 .setup_forced
= bcm54xx_setup_forced
,
1064 .poll_link
= genmii_poll_link
,
1065 .read_link
= bcm54xx_read_link
,
1068 static const struct mii_phy_def bcm5462V_phy_def
= {
1069 .phy_id
= 0x002060d0,
1070 .phy_id_mask
= 0xfffffff0,
1071 .name
= "BCM5462-Vesta",
1072 .features
= MII_GBIT_FEATURES
,
1074 .ops
= &bcm5462V_phy_ops
1077 /* Marvell 88E1101 amd 88E1111 */
1078 static const struct mii_phy_ops marvell88e1101_phy_ops
= {
1079 .suspend
= generic_suspend
,
1080 .setup_aneg
= marvell_setup_aneg
,
1081 .setup_forced
= marvell_setup_forced
,
1082 .poll_link
= genmii_poll_link
,
1083 .read_link
= marvell_read_link
1086 static const struct mii_phy_ops marvell88e1111_phy_ops
= {
1087 .init
= marvell88e1111_init
,
1088 .suspend
= generic_suspend
,
1089 .setup_aneg
= marvell_setup_aneg
,
1090 .setup_forced
= marvell_setup_forced
,
1091 .poll_link
= genmii_poll_link
,
1092 .read_link
= marvell_read_link
1095 /* two revs in darwin for the 88e1101 ... I could use a datasheet
1096 * to get the proper names...
1098 static const struct mii_phy_def marvell88e1101v1_phy_def
= {
1099 .phy_id
= 0x01410c20,
1100 .phy_id_mask
= 0xfffffff0,
1101 .name
= "Marvell 88E1101v1",
1102 .features
= MII_GBIT_FEATURES
,
1104 .ops
= &marvell88e1101_phy_ops
1107 static const 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
1116 static const struct mii_phy_def marvell88e1111_phy_def
= {
1117 .phy_id
= 0x01410cc0,
1118 .phy_id_mask
= 0xfffffff0,
1119 .name
= "Marvell 88E1111",
1120 .features
= MII_GBIT_FEATURES
,
1122 .ops
= &marvell88e1111_phy_ops
1125 /* Generic implementation for most 10/100 PHYs */
1126 static const struct mii_phy_ops generic_phy_ops
= {
1127 .setup_aneg
= genmii_setup_aneg
,
1128 .setup_forced
= genmii_setup_forced
,
1129 .poll_link
= genmii_poll_link
,
1130 .read_link
= genmii_read_link
1133 static const struct mii_phy_def genmii_phy_def
= {
1134 .phy_id
= 0x00000000,
1135 .phy_id_mask
= 0x00000000,
1136 .name
= "Generic MII",
1137 .features
= MII_BASIC_FEATURES
,
1139 .ops
= &generic_phy_ops
1142 static const struct mii_phy_def
*mii_phy_table
[] = {
1153 &marvell88e1101v1_phy_def
,
1154 &marvell88e1101v2_phy_def
,
1155 &marvell88e1111_phy_def
,
1160 int sungem_phy_probe(struct mii_phy
*phy
, int mii_id
)
1162 const struct mii_phy_def
*def
;
1167 /* We do not reset the mii_phy structure as the driver
1168 * may re-probe the PHY regulary
1170 phy
->mii_id
= mii_id
;
1172 /* Take PHY out of isloate mode and reset it. */
1173 rc
= reset_one_mii_phy(phy
, mii_id
);
1177 /* Read ID and find matching entry */
1178 id
= (sungem_phy_read(phy
, MII_PHYSID1
) << 16 | sungem_phy_read(phy
, MII_PHYSID2
));
1179 printk(KERN_DEBUG KBUILD_MODNAME
": " "PHY ID: %x, addr: %x\n",
1181 for (i
=0; (def
= mii_phy_table
[i
]) != NULL
; i
++)
1182 if ((id
& def
->phy_id_mask
) == def
->phy_id
)
1184 /* Should never be NULL (we have a generic entry), but... */
1195 phy
->advertising
= 0;
1199 EXPORT_SYMBOL(sungem_phy_probe
);
1200 MODULE_DESCRIPTION("PHY drivers for the sungem Ethernet MAC driver");
1201 MODULE_LICENSE("GPL");