make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / net / sungem_phy.c
1 /*
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
35 #include "sungem_phy.h"
36
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 */
47 };
48
49 static inline int __phy_read(struct mii_phy* phy, int id, int reg)
50 {
51         return phy->mdio_read(phy->dev, id, reg);
52 }
53
54 static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
55 {
56         phy->mdio_write(phy->dev, id, reg, val);
57 }
58
59 static inline int phy_read(struct mii_phy* phy, int reg)
60 {
61         return phy->mdio_read(phy->dev, phy->mii_id, reg);
62 }
63
64 static inline void phy_write(struct mii_phy* phy, int reg, int val)
65 {
66         phy->mdio_write(phy->dev, phy->mii_id, reg, val);
67 }
68
69 static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
70 {
71         u16 val;
72         int limit = 10000;
73         
74         val = __phy_read(phy, phy_id, MII_BMCR);
75         val &= ~BMCR_ISOLATE;
76         val |= BMCR_RESET;
77         __phy_write(phy, phy_id, MII_BMCR, val);
78
79         udelay(100);
80
81         while (limit--) {
82                 val = __phy_read(phy, phy_id, MII_BMCR);
83                 if ((val & BMCR_RESET) == 0)
84                         break;
85                 udelay(10);
86         }
87         if ((val & BMCR_ISOLATE) && limit > 0)
88                 __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
89         
90         return (limit <= 0);
91 }
92
93 static int bcm5201_init(struct mii_phy* phy)
94 {
95         u16 data;
96
97         data = phy_read(phy, MII_BCM5201_MULTIPHY);
98         data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
99         phy_write(phy, MII_BCM5201_MULTIPHY, data);
100
101         return 0;
102 }
103
104 static int bcm5201_suspend(struct mii_phy* phy, int wol_options)
105 {
106         if (!wol_options)
107                 phy_write(phy, MII_BCM5201_INTERRUPT, 0);
108
109         /* Here's a strange hack used by both MacOS 9 and X */
110         phy_write(phy, MII_LPA, phy_read(phy, MII_LPA));
111         
112         if (!wol_options) {
113 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
114                 u16 val = phy_read(phy, MII_BCM5201_AUXMODE2)
115                 phy_write(phy, MII_BCM5201_AUXMODE2,
116                           val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
117 #endif                  
118                 phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
119         }
120
121         return 0;
122 }
123
124 static int bcm5400_init(struct mii_phy* phy)
125 {
126         u16 data;
127
128         /* Configure for gigabit full duplex */
129         data = phy_read(phy, MII_BCM5400_AUXCONTROL);
130         data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
131         phy_write(phy, MII_BCM5400_AUXCONTROL, data);
132         
133         data = phy_read(phy, MII_BCM5400_GB_CONTROL);
134         data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
135         phy_write(phy, MII_BCM5400_GB_CONTROL, data);
136         
137         mdelay(10);
138
139         /* Reset and configure cascaded 10/100 PHY */
140         (void)reset_one_mii_phy(phy, 0x1f);
141         
142         data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
143         data |= MII_BCM5201_MULTIPHY_SERIALMODE;
144         __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
145
146         data = phy_read(phy, MII_BCM5400_AUXCONTROL);
147         data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
148         phy_write(phy, MII_BCM5400_AUXCONTROL, data);
149
150         return 0;
151 }
152
153 static int bcm5400_suspend(struct mii_phy* phy, int wol_options)
154 {
155 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
156         phy_write(phy, MII_BMCR, BMCR_PDOWN);
157 #endif
158         return 0;
159 }
160
161 static int bcm5401_init(struct mii_phy* phy)
162 {
163         u16 data;
164         int rev;
165
166         rev = phy_read(phy, MII_PHYSID2) & 0x000f;
167         if (rev == 0 || rev == 3) {
168                 /* Some revisions of 5401 appear to need this
169                  * initialisation sequence to disable, according
170                  * to OF, "tap power management"
171                  * 
172                  * WARNING ! OF and Darwin don't agree on the
173                  * register addresses. OF seem to interpret the
174                  * register numbers below as decimal
175                  *
176                  * Note: This should (and does) match tg3_init_5401phy_dsp
177                  *       in the tg3.c driver. -DaveM
178                  */
179                 phy_write(phy, 0x18, 0x0c20);
180                 phy_write(phy, 0x17, 0x0012);
181                 phy_write(phy, 0x15, 0x1804);
182                 phy_write(phy, 0x17, 0x0013);
183                 phy_write(phy, 0x15, 0x1204);
184                 phy_write(phy, 0x17, 0x8006);
185                 phy_write(phy, 0x15, 0x0132);
186                 phy_write(phy, 0x17, 0x8006);
187                 phy_write(phy, 0x15, 0x0232);
188                 phy_write(phy, 0x17, 0x201f);
189                 phy_write(phy, 0x15, 0x0a20);
190         }
191         
192         /* Configure for gigabit full duplex */
193         data = phy_read(phy, MII_BCM5400_GB_CONTROL);
194         data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
195         phy_write(phy, MII_BCM5400_GB_CONTROL, data);
196
197         mdelay(10);
198
199         /* Reset and configure cascaded 10/100 PHY */
200         (void)reset_one_mii_phy(phy, 0x1f);
201         
202         data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
203         data |= MII_BCM5201_MULTIPHY_SERIALMODE;
204         __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
205
206         return 0;
207 }
208
209 static int bcm5401_suspend(struct mii_phy* phy, int wol_options)
210 {
211 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
212         phy_write(phy, MII_BMCR, BMCR_PDOWN);
213 #endif
214         return 0;
215 }
216
217 static int bcm5411_init(struct mii_phy* phy)
218 {
219         u16 data;
220
221         /* Here's some more Apple black magic to setup
222          * some voltage stuffs.
223          */
224         phy_write(phy, 0x1c, 0x8c23);
225         phy_write(phy, 0x1c, 0x8ca3);
226         phy_write(phy, 0x1c, 0x8c23);
227
228         /* Here, Apple seems to want to reset it, do
229          * it as well
230          */
231         phy_write(phy, MII_BMCR, BMCR_RESET);
232         phy_write(phy, MII_BMCR, 0x1340);
233
234         data = phy_read(phy, MII_BCM5400_GB_CONTROL);
235         data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
236         phy_write(phy, MII_BCM5400_GB_CONTROL, data);
237
238         mdelay(10);
239
240         /* Reset and configure cascaded 10/100 PHY */
241         (void)reset_one_mii_phy(phy, 0x1f);
242         
243         return 0;
244 }
245
246 static int bcm5411_suspend(struct mii_phy* phy, int wol_options)
247 {
248         phy_write(phy, MII_BMCR, BMCR_PDOWN);
249
250         return 0;
251 }
252
253 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
254 {
255         u16 ctl, adv;
256         
257         phy->autoneg = 1;
258         phy->speed = SPEED_10;
259         phy->duplex = DUPLEX_HALF;
260         phy->pause = 0;
261         phy->advertising = advertise;
262
263         /* Setup standard advertise */
264         adv = phy_read(phy, MII_ADVERTISE);
265         adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
266         if (advertise & ADVERTISED_10baseT_Half)
267                 adv |= ADVERTISE_10HALF;
268         if (advertise & ADVERTISED_10baseT_Full)
269                 adv |= ADVERTISE_10FULL;
270         if (advertise & ADVERTISED_100baseT_Half)
271                 adv |= ADVERTISE_100HALF;
272         if (advertise & ADVERTISED_100baseT_Full)
273                 adv |= ADVERTISE_100FULL;
274         phy_write(phy, MII_ADVERTISE, adv);
275
276         /* Setup 1000BT advertise */
277         adv = phy_read(phy, MII_1000BASETCONTROL);
278         adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
279         if (advertise & SUPPORTED_1000baseT_Half)
280                 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
281         if (advertise & SUPPORTED_1000baseT_Full)
282                 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
283         phy_write(phy, MII_1000BASETCONTROL, adv);
284
285         /* Start/Restart aneg */
286         ctl = phy_read(phy, MII_BMCR);
287         ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
288         phy_write(phy, MII_BMCR, ctl);
289
290         return 0;
291 }
292
293 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
294 {
295         u16 ctl;
296         
297         phy->autoneg = 0;
298         phy->speed = speed;
299         phy->duplex = fd;
300         phy->pause = 0;
301
302         ctl = phy_read(phy, MII_BMCR);
303         ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
304
305         /* First reset the PHY */
306         phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
307
308         /* Select speed & duplex */
309         switch(speed) {
310         case SPEED_10:
311                 break;
312         case SPEED_100:
313                 ctl |= BMCR_SPEED100;
314                 break;
315         case SPEED_1000:
316                 ctl |= BMCR_SPD2;
317         }
318         if (fd == DUPLEX_FULL)
319                 ctl |= BMCR_FULLDPLX;
320
321         // XXX Should we set the sungem to GII now on 1000BT ?
322         
323         phy_write(phy, MII_BMCR, ctl);
324
325         return 0;
326 }
327
328 static int bcm54xx_read_link(struct mii_phy *phy)
329 {
330         int link_mode;  
331         u16 val;
332         
333         if (phy->autoneg) {
334                 val = phy_read(phy, MII_BCM5400_AUXSTATUS);
335                 link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
336                              MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
337                 phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
338                 phy->speed = phy_BCM5400_link_table[link_mode][2] ?
339                                 SPEED_1000 :
340                                 (phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
341                 val = phy_read(phy, MII_LPA);
342                 phy->pause = ((val & LPA_PAUSE) != 0);
343         }
344         /* On non-aneg, we assume what we put in BMCR is the speed,
345          * though magic-aneg shouldn't prevent this case from occurring
346          */
347
348         return 0;
349 }
350
351 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
352 {
353         u16 ctl, adv;
354         
355         phy->autoneg = 1;
356         phy->speed = SPEED_10;
357         phy->duplex = DUPLEX_HALF;
358         phy->pause = 0;
359         phy->advertising = advertise;
360
361         /* Setup standard advertise */
362         adv = phy_read(phy, MII_ADVERTISE);
363         adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
364         if (advertise & ADVERTISED_10baseT_Half)
365                 adv |= ADVERTISE_10HALF;
366         if (advertise & ADVERTISED_10baseT_Full)
367                 adv |= ADVERTISE_10FULL;
368         if (advertise & ADVERTISED_100baseT_Half)
369                 adv |= ADVERTISE_100HALF;
370         if (advertise & ADVERTISED_100baseT_Full)
371                 adv |= ADVERTISE_100FULL;
372         phy_write(phy, MII_ADVERTISE, adv);
373
374         /* Setup 1000BT advertise & enable crossover detect
375          * XXX How do we advertise 1000BT ? Darwin source is
376          * confusing here, they read from specific control and
377          * write to control... Someone has specs for those
378          * beasts ?
379          */
380         adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
381         adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
382         adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
383                         MII_1000BASETCONTROL_HALFDUPLEXCAP);
384         if (advertise & SUPPORTED_1000baseT_Half)
385                 adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
386         if (advertise & SUPPORTED_1000baseT_Full)
387                 adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
388         phy_write(phy, MII_1000BASETCONTROL, adv);
389
390         /* Start/Restart aneg */
391         ctl = phy_read(phy, MII_BMCR);
392         ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
393         phy_write(phy, MII_BMCR, ctl);
394
395         return 0;
396 }
397
398 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
399 {
400         u16 ctl, ctl2;
401         
402         phy->autoneg = 0;
403         phy->speed = speed;
404         phy->duplex = fd;
405         phy->pause = 0;
406
407         ctl = phy_read(phy, MII_BMCR);
408         ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
409         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         /* I'm not sure about the one below, again, Darwin source is
419          * quite confusing and I lack chip specs
420          */
421         case SPEED_1000:
422                 ctl |= BMCR_SPD2;
423         }
424         if (fd == DUPLEX_FULL)
425                 ctl |= BMCR_FULLDPLX;
426
427         /* Disable crossover. Again, the way Apple does it is strange,
428          * though I don't assume they are wrong ;)
429          */
430         ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
431         ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
432                 MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
433                 MII_1000BASETCONTROL_FULLDUPLEXCAP |
434                 MII_1000BASETCONTROL_HALFDUPLEXCAP);
435         if (speed == SPEED_1000)
436                 ctl2 |= (fd == DUPLEX_FULL) ?
437                         MII_1000BASETCONTROL_FULLDUPLEXCAP :
438                         MII_1000BASETCONTROL_HALFDUPLEXCAP;
439         phy_write(phy, MII_1000BASETCONTROL, ctl2);
440
441         // XXX Should we set the sungem to GII now on 1000BT ?
442         
443         phy_write(phy, MII_BMCR, ctl);
444
445         return 0;
446 }
447
448 static int marvell_read_link(struct mii_phy *phy)
449 {
450         u16 status;
451
452         if (phy->autoneg) {
453                 status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
454                 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
455                         return -EAGAIN;
456                 if (status & MII_M1011_PHY_SPEC_STATUS_1000)
457                         phy->speed = SPEED_1000;
458                 else if (status & MII_M1011_PHY_SPEC_STATUS_100)
459                         phy->speed = SPEED_100;
460                 else
461                         phy->speed = SPEED_10;
462                 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
463                         phy->duplex = DUPLEX_FULL;
464                 else
465                         phy->duplex = DUPLEX_HALF;
466                 phy->pause = 0; /* XXX Check against spec ! */
467         }
468         /* On non-aneg, we assume what we put in BMCR is the speed,
469          * though magic-aneg shouldn't prevent this case from occurring
470          */
471
472         return 0;
473 }
474
475 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
476 {
477         u16 ctl, adv;
478         
479         phy->autoneg = 1;
480         phy->speed = SPEED_10;
481         phy->duplex = DUPLEX_HALF;
482         phy->pause = 0;
483         phy->advertising = advertise;
484
485         /* Setup standard advertise */
486         adv = phy_read(phy, MII_ADVERTISE);
487         adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
488         if (advertise & ADVERTISED_10baseT_Half)
489                 adv |= ADVERTISE_10HALF;
490         if (advertise & ADVERTISED_10baseT_Full)
491                 adv |= ADVERTISE_10FULL;
492         if (advertise & ADVERTISED_100baseT_Half)
493                 adv |= ADVERTISE_100HALF;
494         if (advertise & ADVERTISED_100baseT_Full)
495                 adv |= ADVERTISE_100FULL;
496         phy_write(phy, MII_ADVERTISE, adv);
497
498         /* Start/Restart aneg */
499         ctl = phy_read(phy, MII_BMCR);
500         ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
501         phy_write(phy, MII_BMCR, ctl);
502
503         return 0;
504 }
505
506 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
507 {
508         u16 ctl;
509         
510         phy->autoneg = 0;
511         phy->speed = speed;
512         phy->duplex = fd;
513         phy->pause = 0;
514
515         ctl = phy_read(phy, MII_BMCR);
516         ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
517
518         /* First reset the PHY */
519         phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
520
521         /* Select speed & duplex */
522         switch(speed) {
523         case SPEED_10:
524                 break;
525         case SPEED_100:
526                 ctl |= BMCR_SPEED100;
527                 break;
528         case SPEED_1000:
529         default:
530                 return -EINVAL;
531         }
532         if (fd == DUPLEX_FULL)
533                 ctl |= BMCR_FULLDPLX;
534         phy_write(phy, MII_BMCR, ctl);
535
536         return 0;
537 }
538
539 static int genmii_poll_link(struct mii_phy *phy)
540 {
541         u16 status;
542         
543         (void)phy_read(phy, MII_BMSR);
544         status = phy_read(phy, MII_BMSR);
545         if ((status & BMSR_LSTATUS) == 0)
546                 return 0;
547         if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
548                 return 0;
549         return 1;
550 }
551
552 static int genmii_read_link(struct mii_phy *phy)
553 {
554         u16 lpa;
555
556         if (phy->autoneg) {
557                 lpa = phy_read(phy, MII_LPA);
558
559                 if (lpa & (LPA_10FULL | LPA_100FULL))
560                         phy->duplex = DUPLEX_FULL;
561                 else
562                         phy->duplex = DUPLEX_HALF;
563                 if (lpa & (LPA_100FULL | LPA_100HALF))
564                         phy->speed = SPEED_100;
565                 else
566                         phy->speed = SPEED_10;
567                 phy->pause = 0;
568         }
569         /* On non-aneg, we assume what we put in BMCR is the speed,
570          * though magic-aneg shouldn't prevent this case from occurring
571          */
572
573          return 0;
574 }
575
576
577 #define MII_BASIC_FEATURES      (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
578                                  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
579                                  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
580 #define MII_GBIT_FEATURES       (MII_BASIC_FEATURES | \
581                                  SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
582
583 /* Broadcom BCM 5201 */
584 static struct mii_phy_ops bcm5201_phy_ops = {
585         init:           bcm5201_init,
586         suspend:        bcm5201_suspend,
587         setup_aneg:     genmii_setup_aneg,
588         setup_forced:   genmii_setup_forced,
589         poll_link:      genmii_poll_link,
590         read_link:      genmii_read_link,
591 };
592
593 static struct mii_phy_def bcm5201_phy_def = {
594         phy_id:         0x00406210,
595         phy_id_mask:    0xfffffff0,
596         name:           "BCM5201",
597         features:       MII_BASIC_FEATURES,
598         magic_aneg:     0,
599         ops:            &bcm5201_phy_ops
600 };
601
602 /* Broadcom BCM 5221 */
603 static struct mii_phy_ops bcm5221_phy_ops = {
604         suspend:        bcm5201_suspend,
605         setup_aneg:     genmii_setup_aneg,
606         setup_forced:   genmii_setup_forced,
607         poll_link:      genmii_poll_link,
608         read_link:      genmii_read_link,
609 };
610
611 static struct mii_phy_def bcm5221_phy_def = {
612         phy_id:         0x004061e0,
613         phy_id_mask:    0xfffffff0,
614         name:           "BCM5221",
615         features:       MII_BASIC_FEATURES,
616         magic_aneg:     0,
617         ops:            &bcm5221_phy_ops
618 };
619
620 /* Broadcom BCM 5400 */
621 static struct mii_phy_ops bcm5400_phy_ops = {
622         init:           bcm5400_init,
623         suspend:        bcm5400_suspend,
624         setup_aneg:     bcm54xx_setup_aneg,
625         setup_forced:   bcm54xx_setup_forced,
626         poll_link:      genmii_poll_link,
627         read_link:      bcm54xx_read_link,
628 };
629
630 static struct mii_phy_def bcm5400_phy_def = {
631         phy_id:         0x00206040,
632         phy_id_mask:    0xfffffff0,
633         name:           "BCM5400",
634         features:       MII_GBIT_FEATURES,
635         magic_aneg:     1,
636         ops:            &bcm5400_phy_ops
637 };
638
639 /* Broadcom BCM 5401 */
640 static struct mii_phy_ops bcm5401_phy_ops = {
641         init:           bcm5401_init,
642         suspend:        bcm5401_suspend,
643         setup_aneg:     bcm54xx_setup_aneg,
644         setup_forced:   bcm54xx_setup_forced,
645         poll_link:      genmii_poll_link,
646         read_link:      bcm54xx_read_link,
647 };
648
649 static struct mii_phy_def bcm5401_phy_def = {
650         phy_id:         0x00206050,
651         phy_id_mask:    0xfffffff0,
652         name:           "BCM5401",
653         features:       MII_GBIT_FEATURES,
654         magic_aneg:     1,
655         ops:            &bcm5401_phy_ops
656 };
657
658 /* Broadcom BCM 5411 */
659 static struct mii_phy_ops bcm5411_phy_ops = {
660         init:           bcm5411_init,
661         suspend:        bcm5411_suspend,
662         setup_aneg:     bcm54xx_setup_aneg,
663         setup_forced:   bcm54xx_setup_forced,
664         poll_link:      genmii_poll_link,
665         read_link:      bcm54xx_read_link,
666 };
667
668 static struct mii_phy_def bcm5411_phy_def = {
669         phy_id:         0x00206070,
670         phy_id_mask:    0xfffffff0,
671         name:           "BCM5411",
672         features:       MII_GBIT_FEATURES,
673         magic_aneg:     1,
674         ops:            &bcm5411_phy_ops
675 };
676
677 /* Broadcom BCM 5421 */
678 static struct mii_phy_ops bcm5421_phy_ops = {
679         suspend:        bcm5411_suspend,
680         setup_aneg:     bcm54xx_setup_aneg,
681         setup_forced:   bcm54xx_setup_forced,
682         poll_link:      genmii_poll_link,
683         read_link:      bcm54xx_read_link,
684 };
685
686 static struct mii_phy_def bcm5421_phy_def = {
687         phy_id:         0x002060e0,
688         phy_id_mask:    0xfffffff0,
689         name:           "BCM5421",
690         features:       MII_GBIT_FEATURES,
691         magic_aneg:     1,
692         ops:            &bcm5421_phy_ops
693 };
694
695 /* Marvell 88E1101 (Apple seem to deal with 2 different revs,
696  * I masked out the 8 last bits to get both, but some specs
697  * would be useful here) --BenH.
698  */
699 static struct mii_phy_ops marvell_phy_ops = {
700         setup_aneg:     marvell_setup_aneg,
701         setup_forced:   marvell_setup_forced,
702         poll_link:      genmii_poll_link,
703         read_link:      marvell_read_link
704 };
705
706 static struct mii_phy_def marvell_phy_def = {
707         phy_id:         0x01410c00,
708         phy_id_mask:    0xffffff00,
709         name:           "Marvell 88E1101",
710         features:       MII_GBIT_FEATURES,
711         magic_aneg:     1,
712         ops:            &marvell_phy_ops
713 };
714
715 /* Generic implementation for most 10/100 PHYs */
716 static struct mii_phy_ops generic_phy_ops = {
717         setup_aneg:     genmii_setup_aneg,
718         setup_forced:   genmii_setup_forced,
719         poll_link:      genmii_poll_link,
720         read_link:      genmii_read_link
721 };
722
723 static struct mii_phy_def genmii_phy_def = {
724         phy_id:         0x00000000,
725         phy_id_mask:    0x00000000,
726         name:           "Generic MII",
727         features:       MII_BASIC_FEATURES,
728         magic_aneg:     0,
729         ops:            &generic_phy_ops
730 };
731
732 static struct mii_phy_def* mii_phy_table[] = {
733         &bcm5201_phy_def,
734         &bcm5221_phy_def,
735         &bcm5400_phy_def,
736         &bcm5401_phy_def,
737         &bcm5411_phy_def,
738         &bcm5421_phy_def,
739         &marvell_phy_def,
740         &genmii_phy_def,
741         NULL
742 };
743
744 int mii_phy_probe(struct mii_phy *phy, int mii_id)
745 {
746         int rc;
747         u32 id;
748         struct mii_phy_def* def;
749         int i;
750         
751         phy->autoneg = 0;
752         phy->advertising = 0;
753         phy->mii_id = mii_id;
754         phy->speed = 0;
755         phy->duplex = 0;
756         phy->pause = 0;
757         
758         /* Take PHY out of isloate mode and reset it. */
759         rc = reset_one_mii_phy(phy, mii_id);
760         if (rc)
761                 return -ENODEV;
762
763         /* Read ID and find matching entry */   
764         id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2))
765                                 & 0xfffffff0;
766         for (i=0; (def = mii_phy_table[i]) != NULL; i++)
767                 if ((id & def->phy_id_mask) == def->phy_id)
768                         break;
769         /* Should never be NULL (we have a generic entry), but... */
770         if (def == NULL)
771                 return -ENODEV;
772
773         phy->def = def;
774
775         /* Setup default advertising */
776         phy->advertising = def->features;
777
778         return 0;
779 }
780
781 EXPORT_SYMBOL(mii_phy_probe);
782 MODULE_LICENSE("GPL");
783