blob: 9282b4b0c0229e0f86b6f779c02d52189e34f8e8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * PHY drivers for the sungem ethernet driver.
3 *
4 * This file could be shared with other drivers.
5 *
6 * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
7 *
8 * TODO:
9 * - Implement WOL
10 * - Add support for PHYs that provide an IRQ line
11 * - Eventually moved the entire polling state machine in
12 * there (out of the eth driver), so that it can easily be
13 * skipped on PHYs that implement it in hardware.
14 * - On LXT971 & BCM5201, Apple uses some chip specific regs
15 * to read the link status. Figure out why and if it makes
16 * sense to do the same (magic aneg ?)
17 * - Apple has some additional power management code for some
18 * Broadcom PHYs that they "hide" from the OpenSource version
19 * of darwin, still need to reverse engineer that
20 */
21
22#include <linux/config.h>
23
24#include <linux/module.h>
25
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>
34
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -070035#ifdef CONFIG_PPC_PMAC
36#include <asm/prom.h>
37#endif
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "sungem_phy.h"
40
41/* Link modes of the BCM5400 PHY */
Arjan van de Venf71e1302006-03-03 21:33:57 -050042static const int phy_BCM5400_link_table[8][3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 { 0, 0, 0 }, /* No link */
44 { 0, 0, 0 }, /* 10BT Half Duplex */
45 { 1, 0, 0 }, /* 10BT Full Duplex */
46 { 0, 1, 0 }, /* 100BT Half Duplex */
47 { 0, 1, 0 }, /* 100BT Half Duplex */
48 { 1, 1, 0 }, /* 100BT Full Duplex*/
49 { 1, 0, 1 }, /* 1000BT */
50 { 1, 0, 1 }, /* 1000BT */
51};
52
53static inline int __phy_read(struct mii_phy* phy, int id, int reg)
54{
55 return phy->mdio_read(phy->dev, id, reg);
56}
57
58static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
59{
60 phy->mdio_write(phy->dev, id, reg, val);
61}
62
63static inline int phy_read(struct mii_phy* phy, int reg)
64{
65 return phy->mdio_read(phy->dev, phy->mii_id, reg);
66}
67
68static inline void phy_write(struct mii_phy* phy, int reg, int val)
69{
70 phy->mdio_write(phy->dev, phy->mii_id, reg, val);
71}
72
73static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
74{
75 u16 val;
76 int limit = 10000;
77
78 val = __phy_read(phy, phy_id, MII_BMCR);
79 val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
80 val |= BMCR_RESET;
81 __phy_write(phy, phy_id, MII_BMCR, val);
82
83 udelay(100);
84
85 while (limit--) {
86 val = __phy_read(phy, phy_id, MII_BMCR);
87 if ((val & BMCR_RESET) == 0)
88 break;
89 udelay(10);
90 }
91 if ((val & BMCR_ISOLATE) && limit > 0)
92 __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
93
94 return (limit <= 0);
95}
96
97static int bcm5201_init(struct mii_phy* phy)
98{
99 u16 data;
100
101 data = phy_read(phy, MII_BCM5201_MULTIPHY);
102 data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
103 phy_write(phy, MII_BCM5201_MULTIPHY, data);
104
105 phy_write(phy, MII_BCM5201_INTERRUPT, 0);
106
107 return 0;
108}
109
110static int bcm5201_suspend(struct mii_phy* phy)
111{
112 phy_write(phy, MII_BCM5201_INTERRUPT, 0);
113 phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
114
115 return 0;
116}
117
118static int bcm5221_init(struct mii_phy* phy)
119{
120 u16 data;
121
122 data = phy_read(phy, MII_BCM5221_TEST);
123 phy_write(phy, MII_BCM5221_TEST,
124 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
125
126 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
127 phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
128 data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
129
130 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
131 phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
132 data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
133
134 data = phy_read(phy, MII_BCM5221_TEST);
135 phy_write(phy, MII_BCM5221_TEST,
136 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
137
138 return 0;
139}
140
141static int bcm5221_suspend(struct mii_phy* phy)
142{
143 u16 data;
144
145 data = phy_read(phy, MII_BCM5221_TEST);
146 phy_write(phy, MII_BCM5221_TEST,
147 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
148
149 data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
150 phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
151 data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
152
153 return 0;
154}
155
156static int bcm5400_init(struct mii_phy* phy)
157{
158 u16 data;
159
160 /* Configure for gigabit full duplex */
161 data = phy_read(phy, MII_BCM5400_AUXCONTROL);
162 data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
163 phy_write(phy, MII_BCM5400_AUXCONTROL, data);
164
165 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
166 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
167 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
168
169 udelay(100);
170
171 /* Reset and configure cascaded 10/100 PHY */
172 (void)reset_one_mii_phy(phy, 0x1f);
173
174 data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
175 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
176 __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
177
178 data = phy_read(phy, MII_BCM5400_AUXCONTROL);
179 data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
180 phy_write(phy, MII_BCM5400_AUXCONTROL, data);
181
182 return 0;
183}
184
185static int bcm5400_suspend(struct mii_phy* phy)
186{
187#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
188 phy_write(phy, MII_BMCR, BMCR_PDOWN);
189#endif
190 return 0;
191}
192
193static int bcm5401_init(struct mii_phy* phy)
194{
195 u16 data;
196 int rev;
197
198 rev = phy_read(phy, MII_PHYSID2) & 0x000f;
199 if (rev == 0 || rev == 3) {
200 /* Some revisions of 5401 appear to need this
201 * initialisation sequence to disable, according
202 * to OF, "tap power management"
203 *
204 * WARNING ! OF and Darwin don't agree on the
205 * register addresses. OF seem to interpret the
206 * register numbers below as decimal
207 *
208 * Note: This should (and does) match tg3_init_5401phy_dsp
209 * in the tg3.c driver. -DaveM
210 */
211 phy_write(phy, 0x18, 0x0c20);
212 phy_write(phy, 0x17, 0x0012);
213 phy_write(phy, 0x15, 0x1804);
214 phy_write(phy, 0x17, 0x0013);
215 phy_write(phy, 0x15, 0x1204);
216 phy_write(phy, 0x17, 0x8006);
217 phy_write(phy, 0x15, 0x0132);
218 phy_write(phy, 0x17, 0x8006);
219 phy_write(phy, 0x15, 0x0232);
220 phy_write(phy, 0x17, 0x201f);
221 phy_write(phy, 0x15, 0x0a20);
222 }
223
224 /* Configure for gigabit full duplex */
225 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
226 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
227 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
228
229 udelay(10);
230
231 /* Reset and configure cascaded 10/100 PHY */
232 (void)reset_one_mii_phy(phy, 0x1f);
233
234 data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
235 data |= MII_BCM5201_MULTIPHY_SERIALMODE;
236 __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
237
238 return 0;
239}
240
241static int bcm5401_suspend(struct mii_phy* phy)
242{
243#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
244 phy_write(phy, MII_BMCR, BMCR_PDOWN);
245#endif
246 return 0;
247}
248
249static int bcm5411_init(struct mii_phy* phy)
250{
251 u16 data;
252
253 /* Here's some more Apple black magic to setup
254 * some voltage stuffs.
255 */
256 phy_write(phy, 0x1c, 0x8c23);
257 phy_write(phy, 0x1c, 0x8ca3);
258 phy_write(phy, 0x1c, 0x8c23);
259
260 /* Here, Apple seems to want to reset it, do
261 * it as well
262 */
263 phy_write(phy, MII_BMCR, BMCR_RESET);
264 phy_write(phy, MII_BMCR, 0x1340);
265
266 data = phy_read(phy, MII_BCM5400_GB_CONTROL);
267 data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
268 phy_write(phy, MII_BCM5400_GB_CONTROL, data);
269
270 udelay(10);
271
272 /* Reset and configure cascaded 10/100 PHY */
273 (void)reset_one_mii_phy(phy, 0x1f);
274
275 return 0;
276}
277
Johannes Bergd47f3642006-04-19 15:42:28 -0700278static int generic_suspend(struct mii_phy* phy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
280 phy_write(phy, MII_BMCR, BMCR_PDOWN);
281
282 return 0;
283}
284
285static int bcm5421_init(struct mii_phy* phy)
286{
287 u16 data;
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -0700288 unsigned int id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -0700290 id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
291
292 /* Revision 0 of 5421 needs some fixups */
293 if (id == 0x002060e0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 /* This is borrowed from MacOS
295 */
296 phy_write(phy, 0x18, 0x1007);
297 data = phy_read(phy, 0x18);
298 phy_write(phy, 0x18, data | 0x0400);
299 phy_write(phy, 0x18, 0x0007);
300 data = phy_read(phy, 0x18);
301 phy_write(phy, 0x18, data | 0x0800);
302 phy_write(phy, 0x17, 0x000a);
303 data = phy_read(phy, 0x15);
304 phy_write(phy, 0x15, data | 0x0200);
305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -0700307 /* Pick up some init code from OF for K2 version */
308 if ((id & 0xfffffff0) == 0x002062e0) {
309 phy_write(phy, 4, 0x01e1);
310 phy_write(phy, 9, 0x0300);
311 }
312
313 /* Check if we can enable automatic low power */
314#ifdef CONFIG_PPC_PMAC
315 if (phy->platform_data) {
316 struct device_node *np = of_get_parent(phy->platform_data);
317 int can_low_power = 1;
318 if (np == NULL || get_property(np, "no-autolowpower", NULL))
319 can_low_power = 0;
320 if (can_low_power) {
321 /* Enable automatic low-power */
322 phy_write(phy, 0x1c, 0x9002);
323 phy_write(phy, 0x1c, 0xa821);
324 phy_write(phy, 0x1c, 0x941d);
325 }
326 }
327#endif /* CONFIG_PPC_PMAC */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 return 0;
330}
331
Jens Osterkamp8ec93452006-05-04 05:59:41 -0400332static int bcm5421_enable_fiber(struct mii_phy* phy)
333{
334 /* enable fiber mode */
335 phy_write(phy, MII_NCONFIG, 0x9020);
336 /* LEDs active in both modes, autosense prio = fiber */
337 phy_write(phy, MII_NCONFIG, 0x945f);
338
339 /* switch off fibre autoneg */
340 phy_write(phy, MII_NCONFIG, 0xfc01);
341 phy_write(phy, 0x0b, 0x0004);
342
343 return 0;
344}
345
346static int bcm5461_enable_fiber(struct mii_phy* phy)
347{
Jens Osterkamp48cf2702006-05-24 23:33:11 +0200348 phy_write(phy, MII_NCONFIG, 0xfc0c);
349 phy_write(phy, MII_BMCR, 0x4140);
350 phy_write(phy, MII_NCONFIG, 0xfc0b);
Jens Osterkamp8ec93452006-05-04 05:59:41 -0400351 phy_write(phy, MII_BMCR, 0x0140);
352
353 return 0;
354}
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
357{
358 u16 ctl, adv;
359
360 phy->autoneg = 1;
361 phy->speed = SPEED_10;
362 phy->duplex = DUPLEX_HALF;
363 phy->pause = 0;
364 phy->advertising = advertise;
365
366 /* Setup standard advertise */
367 adv = phy_read(phy, MII_ADVERTISE);
368 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
369 if (advertise & ADVERTISED_10baseT_Half)
370 adv |= ADVERTISE_10HALF;
371 if (advertise & ADVERTISED_10baseT_Full)
372 adv |= ADVERTISE_10FULL;
373 if (advertise & ADVERTISED_100baseT_Half)
374 adv |= ADVERTISE_100HALF;
375 if (advertise & ADVERTISED_100baseT_Full)
376 adv |= ADVERTISE_100FULL;
377 phy_write(phy, MII_ADVERTISE, adv);
378
379 /* Setup 1000BT advertise */
380 adv = phy_read(phy, MII_1000BASETCONTROL);
381 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
382 if (advertise & SUPPORTED_1000baseT_Half)
383 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
384 if (advertise & SUPPORTED_1000baseT_Full)
385 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
386 phy_write(phy, MII_1000BASETCONTROL, adv);
387
388 /* Start/Restart aneg */
389 ctl = phy_read(phy, MII_BMCR);
390 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
391 phy_write(phy, MII_BMCR, ctl);
392
393 return 0;
394}
395
396static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
397{
398 u16 ctl;
399
400 phy->autoneg = 0;
401 phy->speed = speed;
402 phy->duplex = fd;
403 phy->pause = 0;
404
405 ctl = phy_read(phy, MII_BMCR);
406 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
407
408 /* First reset the PHY */
409 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
410
411 /* Select speed & duplex */
412 switch(speed) {
413 case SPEED_10:
414 break;
415 case SPEED_100:
416 ctl |= BMCR_SPEED100;
417 break;
418 case SPEED_1000:
419 ctl |= BMCR_SPD2;
420 }
421 if (fd == DUPLEX_FULL)
422 ctl |= BMCR_FULLDPLX;
423
424 // XXX Should we set the sungem to GII now on 1000BT ?
425
426 phy_write(phy, MII_BMCR, ctl);
427
428 return 0;
429}
430
431static int bcm54xx_read_link(struct mii_phy *phy)
432{
433 int link_mode;
434 u16 val;
435
436 if (phy->autoneg) {
437 val = phy_read(phy, MII_BCM5400_AUXSTATUS);
438 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
439 MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
440 phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
441 phy->speed = phy_BCM5400_link_table[link_mode][2] ?
442 SPEED_1000 :
443 (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
444 val = phy_read(phy, MII_LPA);
445 phy->pause = ((val & LPA_PAUSE) != 0);
446 }
447 /* On non-aneg, we assume what we put in BMCR is the speed,
448 * though magic-aneg shouldn't prevent this case from occurring
449 */
450
451 return 0;
452}
453
454static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
455{
456 u16 ctl, adv;
457
458 phy->autoneg = 1;
459 phy->speed = SPEED_10;
460 phy->duplex = DUPLEX_HALF;
461 phy->pause = 0;
462 phy->advertising = advertise;
463
464 /* Setup standard advertise */
465 adv = phy_read(phy, MII_ADVERTISE);
466 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
467 if (advertise & ADVERTISED_10baseT_Half)
468 adv |= ADVERTISE_10HALF;
469 if (advertise & ADVERTISED_10baseT_Full)
470 adv |= ADVERTISE_10FULL;
471 if (advertise & ADVERTISED_100baseT_Half)
472 adv |= ADVERTISE_100HALF;
473 if (advertise & ADVERTISED_100baseT_Full)
474 adv |= ADVERTISE_100FULL;
475 phy_write(phy, MII_ADVERTISE, adv);
476
477 /* Setup 1000BT advertise & enable crossover detect
478 * XXX How do we advertise 1000BT ? Darwin source is
479 * confusing here, they read from specific control and
480 * write to control... Someone has specs for those
481 * beasts ?
482 */
483 adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
484 adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
485 adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
486 MII_1000BASETCONTROL_HALFDUPLEXCAP);
487 if (advertise & SUPPORTED_1000baseT_Half)
488 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
489 if (advertise & SUPPORTED_1000baseT_Full)
490 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
491 phy_write(phy, MII_1000BASETCONTROL, adv);
492
493 /* Start/Restart aneg */
494 ctl = phy_read(phy, MII_BMCR);
495 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
496 phy_write(phy, MII_BMCR, ctl);
497
498 return 0;
499}
500
501static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
502{
503 u16 ctl, ctl2;
504
505 phy->autoneg = 0;
506 phy->speed = speed;
507 phy->duplex = fd;
508 phy->pause = 0;
509
510 ctl = phy_read(phy, MII_BMCR);
511 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
512 ctl |= BMCR_RESET;
513
514 /* Select speed & duplex */
515 switch(speed) {
516 case SPEED_10:
517 break;
518 case SPEED_100:
519 ctl |= BMCR_SPEED100;
520 break;
521 /* I'm not sure about the one below, again, Darwin source is
522 * quite confusing and I lack chip specs
523 */
524 case SPEED_1000:
525 ctl |= BMCR_SPD2;
526 }
527 if (fd == DUPLEX_FULL)
528 ctl |= BMCR_FULLDPLX;
529
530 /* Disable crossover. Again, the way Apple does it is strange,
531 * though I don't assume they are wrong ;)
532 */
533 ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
534 ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
535 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
536 MII_1000BASETCONTROL_FULLDUPLEXCAP |
537 MII_1000BASETCONTROL_HALFDUPLEXCAP);
538 if (speed == SPEED_1000)
539 ctl2 |= (fd == DUPLEX_FULL) ?
540 MII_1000BASETCONTROL_FULLDUPLEXCAP :
541 MII_1000BASETCONTROL_HALFDUPLEXCAP;
542 phy_write(phy, MII_1000BASETCONTROL, ctl2);
543
544 // XXX Should we set the sungem to GII now on 1000BT ?
545
546 phy_write(phy, MII_BMCR, ctl);
547
548 return 0;
549}
550
551static int marvell_read_link(struct mii_phy *phy)
552{
553 u16 status;
554
555 if (phy->autoneg) {
556 status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
557 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
558 return -EAGAIN;
559 if (status & MII_M1011_PHY_SPEC_STATUS_1000)
560 phy->speed = SPEED_1000;
561 else if (status & MII_M1011_PHY_SPEC_STATUS_100)
562 phy->speed = SPEED_100;
563 else
564 phy->speed = SPEED_10;
565 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
566 phy->duplex = DUPLEX_FULL;
567 else
568 phy->duplex = DUPLEX_HALF;
569 phy->pause = 0; /* XXX Check against spec ! */
570 }
571 /* On non-aneg, we assume what we put in BMCR is the speed,
572 * though magic-aneg shouldn't prevent this case from occurring
573 */
574
575 return 0;
576}
577
578static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
579{
580 u16 ctl, adv;
581
582 phy->autoneg = 1;
583 phy->speed = SPEED_10;
584 phy->duplex = DUPLEX_HALF;
585 phy->pause = 0;
586 phy->advertising = advertise;
587
588 /* Setup standard advertise */
589 adv = phy_read(phy, MII_ADVERTISE);
590 adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
591 if (advertise & ADVERTISED_10baseT_Half)
592 adv |= ADVERTISE_10HALF;
593 if (advertise & ADVERTISED_10baseT_Full)
594 adv |= ADVERTISE_10FULL;
595 if (advertise & ADVERTISED_100baseT_Half)
596 adv |= ADVERTISE_100HALF;
597 if (advertise & ADVERTISED_100baseT_Full)
598 adv |= ADVERTISE_100FULL;
599 phy_write(phy, MII_ADVERTISE, adv);
600
601 /* Start/Restart aneg */
602 ctl = phy_read(phy, MII_BMCR);
603 ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
604 phy_write(phy, MII_BMCR, ctl);
605
606 return 0;
607}
608
609static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
610{
611 u16 ctl;
612
613 phy->autoneg = 0;
614 phy->speed = speed;
615 phy->duplex = fd;
616 phy->pause = 0;
617
618 ctl = phy_read(phy, MII_BMCR);
619 ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
620
621 /* First reset the PHY */
622 phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
623
624 /* Select speed & duplex */
625 switch(speed) {
626 case SPEED_10:
627 break;
628 case SPEED_100:
629 ctl |= BMCR_SPEED100;
630 break;
631 case SPEED_1000:
632 default:
633 return -EINVAL;
634 }
635 if (fd == DUPLEX_FULL)
636 ctl |= BMCR_FULLDPLX;
637 phy_write(phy, MII_BMCR, ctl);
638
639 return 0;
640}
641
642static int genmii_poll_link(struct mii_phy *phy)
643{
644 u16 status;
645
646 (void)phy_read(phy, MII_BMSR);
647 status = phy_read(phy, MII_BMSR);
648 if ((status & BMSR_LSTATUS) == 0)
649 return 0;
650 if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
651 return 0;
652 return 1;
653}
654
655static int genmii_read_link(struct mii_phy *phy)
656{
657 u16 lpa;
658
659 if (phy->autoneg) {
660 lpa = phy_read(phy, MII_LPA);
661
662 if (lpa & (LPA_10FULL | LPA_100FULL))
663 phy->duplex = DUPLEX_FULL;
664 else
665 phy->duplex = DUPLEX_HALF;
666 if (lpa & (LPA_100FULL | LPA_100HALF))
667 phy->speed = SPEED_100;
668 else
669 phy->speed = SPEED_10;
670 phy->pause = 0;
671 }
672 /* On non-aneg, we assume what we put in BMCR is the speed,
673 * though magic-aneg shouldn't prevent this case from occurring
674 */
675
676 return 0;
677}
678
679
680#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
681 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
682 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
683#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
684 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
685
686/* Broadcom BCM 5201 */
687static struct mii_phy_ops bcm5201_phy_ops = {
688 .init = bcm5201_init,
689 .suspend = bcm5201_suspend,
690 .setup_aneg = genmii_setup_aneg,
691 .setup_forced = genmii_setup_forced,
692 .poll_link = genmii_poll_link,
693 .read_link = genmii_read_link,
694};
695
696static struct mii_phy_def bcm5201_phy_def = {
697 .phy_id = 0x00406210,
698 .phy_id_mask = 0xfffffff0,
699 .name = "BCM5201",
700 .features = MII_BASIC_FEATURES,
701 .magic_aneg = 1,
702 .ops = &bcm5201_phy_ops
703};
704
705/* Broadcom BCM 5221 */
706static struct mii_phy_ops bcm5221_phy_ops = {
707 .suspend = bcm5221_suspend,
708 .init = bcm5221_init,
709 .setup_aneg = genmii_setup_aneg,
710 .setup_forced = genmii_setup_forced,
711 .poll_link = genmii_poll_link,
712 .read_link = genmii_read_link,
713};
714
715static struct mii_phy_def bcm5221_phy_def = {
716 .phy_id = 0x004061e0,
717 .phy_id_mask = 0xfffffff0,
718 .name = "BCM5221",
719 .features = MII_BASIC_FEATURES,
720 .magic_aneg = 1,
721 .ops = &bcm5221_phy_ops
722};
723
724/* Broadcom BCM 5400 */
725static struct mii_phy_ops bcm5400_phy_ops = {
726 .init = bcm5400_init,
727 .suspend = bcm5400_suspend,
728 .setup_aneg = bcm54xx_setup_aneg,
729 .setup_forced = bcm54xx_setup_forced,
730 .poll_link = genmii_poll_link,
731 .read_link = bcm54xx_read_link,
732};
733
734static struct mii_phy_def bcm5400_phy_def = {
735 .phy_id = 0x00206040,
736 .phy_id_mask = 0xfffffff0,
737 .name = "BCM5400",
738 .features = MII_GBIT_FEATURES,
739 .magic_aneg = 1,
740 .ops = &bcm5400_phy_ops
741};
742
743/* Broadcom BCM 5401 */
744static struct mii_phy_ops bcm5401_phy_ops = {
745 .init = bcm5401_init,
746 .suspend = bcm5401_suspend,
747 .setup_aneg = bcm54xx_setup_aneg,
748 .setup_forced = bcm54xx_setup_forced,
749 .poll_link = genmii_poll_link,
750 .read_link = bcm54xx_read_link,
751};
752
753static struct mii_phy_def bcm5401_phy_def = {
754 .phy_id = 0x00206050,
755 .phy_id_mask = 0xfffffff0,
756 .name = "BCM5401",
757 .features = MII_GBIT_FEATURES,
758 .magic_aneg = 1,
759 .ops = &bcm5401_phy_ops
760};
761
762/* Broadcom BCM 5411 */
763static struct mii_phy_ops bcm5411_phy_ops = {
764 .init = bcm5411_init,
Johannes Bergd47f3642006-04-19 15:42:28 -0700765 .suspend = generic_suspend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 .setup_aneg = bcm54xx_setup_aneg,
767 .setup_forced = bcm54xx_setup_forced,
768 .poll_link = genmii_poll_link,
769 .read_link = bcm54xx_read_link,
770};
771
772static struct mii_phy_def bcm5411_phy_def = {
773 .phy_id = 0x00206070,
774 .phy_id_mask = 0xfffffff0,
775 .name = "BCM5411",
776 .features = MII_GBIT_FEATURES,
777 .magic_aneg = 1,
778 .ops = &bcm5411_phy_ops
779};
780
781/* Broadcom BCM 5421 */
782static struct mii_phy_ops bcm5421_phy_ops = {
783 .init = bcm5421_init,
Johannes Bergd47f3642006-04-19 15:42:28 -0700784 .suspend = generic_suspend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 .setup_aneg = bcm54xx_setup_aneg,
786 .setup_forced = bcm54xx_setup_forced,
787 .poll_link = genmii_poll_link,
788 .read_link = bcm54xx_read_link,
Jens Osterkamp8ec93452006-05-04 05:59:41 -0400789 .enable_fiber = bcm5421_enable_fiber,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790};
791
792static struct mii_phy_def bcm5421_phy_def = {
793 .phy_id = 0x002060e0,
794 .phy_id_mask = 0xfffffff0,
795 .name = "BCM5421",
796 .features = MII_GBIT_FEATURES,
797 .magic_aneg = 1,
798 .ops = &bcm5421_phy_ops
799};
800
801/* Broadcom BCM 5421 built-in K2 */
802static struct mii_phy_ops bcm5421k2_phy_ops = {
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -0700803 .init = bcm5421_init,
Johannes Bergd47f3642006-04-19 15:42:28 -0700804 .suspend = generic_suspend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 .setup_aneg = bcm54xx_setup_aneg,
806 .setup_forced = bcm54xx_setup_forced,
807 .poll_link = genmii_poll_link,
808 .read_link = bcm54xx_read_link,
809};
810
811static struct mii_phy_def bcm5421k2_phy_def = {
812 .phy_id = 0x002062e0,
813 .phy_id_mask = 0xfffffff0,
814 .name = "BCM5421-K2",
815 .features = MII_GBIT_FEATURES,
816 .magic_aneg = 1,
817 .ops = &bcm5421k2_phy_ops
818};
819
Jens Osterkamp8ec93452006-05-04 05:59:41 -0400820static struct mii_phy_ops bcm5461_phy_ops = {
821 .init = bcm5421_init,
822 .suspend = generic_suspend,
823 .setup_aneg = bcm54xx_setup_aneg,
824 .setup_forced = bcm54xx_setup_forced,
825 .poll_link = genmii_poll_link,
826 .read_link = bcm54xx_read_link,
827 .enable_fiber = bcm5461_enable_fiber,
828};
829
830static struct mii_phy_def bcm5461_phy_def = {
831 .phy_id = 0x002060c0,
832 .phy_id_mask = 0xfffffff0,
833 .name = "BCM5461",
834 .features = MII_GBIT_FEATURES,
835 .magic_aneg = 1,
836 .ops = &bcm5461_phy_ops
837};
838
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -0700839/* Broadcom BCM 5462 built-in Vesta */
840static struct mii_phy_ops bcm5462V_phy_ops = {
841 .init = bcm5421_init,
Johannes Bergd47f3642006-04-19 15:42:28 -0700842 .suspend = generic_suspend,
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -0700843 .setup_aneg = bcm54xx_setup_aneg,
844 .setup_forced = bcm54xx_setup_forced,
845 .poll_link = genmii_poll_link,
846 .read_link = bcm54xx_read_link,
847};
848
849static struct mii_phy_def bcm5462V_phy_def = {
850 .phy_id = 0x002060d0,
851 .phy_id_mask = 0xfffffff0,
852 .name = "BCM5462-Vesta",
853 .features = MII_GBIT_FEATURES,
854 .magic_aneg = 1,
855 .ops = &bcm5462V_phy_ops
856};
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858/* Marvell 88E1101 (Apple seem to deal with 2 different revs,
859 * I masked out the 8 last bits to get both, but some specs
860 * would be useful here) --BenH.
861 */
862static struct mii_phy_ops marvell_phy_ops = {
Johannes Bergd47f3642006-04-19 15:42:28 -0700863 .suspend = generic_suspend,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 .setup_aneg = marvell_setup_aneg,
865 .setup_forced = marvell_setup_forced,
866 .poll_link = genmii_poll_link,
867 .read_link = marvell_read_link
868};
869
870static struct mii_phy_def marvell_phy_def = {
871 .phy_id = 0x01410c00,
872 .phy_id_mask = 0xffffff00,
873 .name = "Marvell 88E1101",
874 .features = MII_GBIT_FEATURES,
875 .magic_aneg = 1,
876 .ops = &marvell_phy_ops
877};
878
879/* Generic implementation for most 10/100 PHYs */
880static struct mii_phy_ops generic_phy_ops = {
881 .setup_aneg = genmii_setup_aneg,
882 .setup_forced = genmii_setup_forced,
883 .poll_link = genmii_poll_link,
884 .read_link = genmii_read_link
885};
886
887static struct mii_phy_def genmii_phy_def = {
888 .phy_id = 0x00000000,
889 .phy_id_mask = 0x00000000,
890 .name = "Generic MII",
891 .features = MII_BASIC_FEATURES,
892 .magic_aneg = 0,
893 .ops = &generic_phy_ops
894};
895
896static struct mii_phy_def* mii_phy_table[] = {
897 &bcm5201_phy_def,
898 &bcm5221_phy_def,
899 &bcm5400_phy_def,
900 &bcm5401_phy_def,
901 &bcm5411_phy_def,
902 &bcm5421_phy_def,
903 &bcm5421k2_phy_def,
Jens Osterkamp8ec93452006-05-04 05:59:41 -0400904 &bcm5461_phy_def,
Benjamin Herrenschmidt3c326fe2005-07-07 17:56:09 -0700905 &bcm5462V_phy_def,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 &marvell_phy_def,
907 &genmii_phy_def,
908 NULL
909};
910
911int mii_phy_probe(struct mii_phy *phy, int mii_id)
912{
913 int rc;
914 u32 id;
915 struct mii_phy_def* def;
916 int i;
917
918 /* We do not reset the mii_phy structure as the driver
919 * may re-probe the PHY regulary
920 */
921 phy->mii_id = mii_id;
922
923 /* Take PHY out of isloate mode and reset it. */
924 rc = reset_one_mii_phy(phy, mii_id);
925 if (rc)
926 goto fail;
927
928 /* Read ID and find matching entry */
929 id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
930 printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
931 for (i=0; (def = mii_phy_table[i]) != NULL; i++)
932 if ((id & def->phy_id_mask) == def->phy_id)
933 break;
934 /* Should never be NULL (we have a generic entry), but... */
935 if (def == NULL)
936 goto fail;
937
938 phy->def = def;
939
940 return 0;
941fail:
942 phy->speed = 0;
943 phy->duplex = 0;
944 phy->pause = 0;
945 phy->advertising = 0;
946 return -ENODEV;
947}
948
949EXPORT_SYMBOL(mii_phy_probe);
950MODULE_LICENSE("GPL");
951