drivers: media: arducam_64mp: Add V4L2_CID_LINK_FREQ control
[platform/kernel/linux-rpi.git] / drivers / net / sungem_phy.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * PHY drivers for the sungem ethernet driver.
4  *
5  * This file could be shared with other drivers.
6  *
7  * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
8  *
9  * TODO:
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
23 #include <linux/module.h>
24
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>
32 #include <linux/of.h>
33 #include <linux/sungem_phy.h>
34
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 */
45 };
46
47 static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
48 {
49         return phy->mdio_read(phy->dev, id, reg);
50 }
51
52 static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
53 {
54         phy->mdio_write(phy->dev, id, reg, val);
55 }
56
57 static inline int sungem_phy_read(struct mii_phy* phy, int reg)
58 {
59         return phy->mdio_read(phy->dev, phy->mii_id, reg);
60 }
61
62 static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
63 {
64         phy->mdio_write(phy->dev, phy->mii_id, reg, val);
65 }
66
67 static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
68 {
69         u16 val;
70         int limit = 10000;
71
72         val = __sungem_phy_read(phy, phy_id, MII_BMCR);
73         val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
74         val |= BMCR_RESET;
75         __sungem_phy_write(phy, phy_id, MII_BMCR, val);
76
77         udelay(100);
78
79         while (--limit) {
80                 val = __sungem_phy_read(phy, phy_id, MII_BMCR);
81                 if ((val & BMCR_RESET) == 0)
82                         break;
83                 udelay(10);
84         }
85         if ((val & BMCR_ISOLATE) && limit > 0)
86                 __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
87
88         return limit <= 0;
89 }
90
91 static int bcm5201_init(struct mii_phy* phy)
92 {
93         u16 data;
94
95         data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
96         data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
97         sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
98
99         sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
100
101         return 0;
102 }
103
104 static int bcm5201_suspend(struct mii_phy* phy)
105 {
106         sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
107         sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
108
109         return 0;
110 }
111
112 static int bcm5221_init(struct mii_phy* phy)
113 {
114         u16 data;
115
116         data = sungem_phy_read(phy, MII_BCM5221_TEST);
117         sungem_phy_write(phy, MII_BCM5221_TEST,
118                 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
119
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);
123
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);
127
128         data = sungem_phy_read(phy, MII_BCM5221_TEST);
129         sungem_phy_write(phy, MII_BCM5221_TEST,
130                 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
131
132         return 0;
133 }
134
135 static int bcm5221_suspend(struct mii_phy* phy)
136 {
137         u16 data;
138
139         data = sungem_phy_read(phy, MII_BCM5221_TEST);
140         sungem_phy_write(phy, MII_BCM5221_TEST,
141                 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
142
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);
146
147         return 0;
148 }
149
150 static int bcm5241_init(struct mii_phy* phy)
151 {
152         u16 data;
153
154         data = sungem_phy_read(phy, MII_BCM5221_TEST);
155         sungem_phy_write(phy, MII_BCM5221_TEST,
156                 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
157
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);
161
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);
165
166         data = sungem_phy_read(phy, MII_BCM5221_TEST);
167         sungem_phy_write(phy, MII_BCM5221_TEST,
168                 data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
169
170         return 0;
171 }
172
173 static int bcm5241_suspend(struct mii_phy* phy)
174 {
175         u16 data;
176
177         data = sungem_phy_read(phy, MII_BCM5221_TEST);
178         sungem_phy_write(phy, MII_BCM5221_TEST,
179                 data | MII_BCM5221_TEST_ENABLE_SHADOWS);
180
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);
184
185         return 0;
186 }
187
188 static int bcm5400_init(struct mii_phy* phy)
189 {
190         u16 data;
191
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);
196
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);
200
201         udelay(100);
202
203         /* Reset and configure cascaded 10/100 PHY */
204         (void)reset_one_mii_phy(phy, 0x1f);
205
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);
209
210         data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
211         data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
212         sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
213
214         return 0;
215 }
216
217 static int bcm5400_suspend(struct mii_phy* phy)
218 {
219 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
220         sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
221 #endif
222         return 0;
223 }
224
225 static int bcm5401_init(struct mii_phy* phy)
226 {
227         u16 data;
228         int rev;
229
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"
235                  *
236                  * WARNING ! OF and Darwin don't agree on the
237                  * register addresses. OF seem to interpret the
238                  * register numbers below as decimal
239                  *
240                  * Note: This should (and does) match tg3_init_5401phy_dsp
241                  *       in the tg3.c driver. -DaveM
242                  */
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);
254         }
255
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);
260
261         udelay(10);
262
263         /* Reset and configure cascaded 10/100 PHY */
264         (void)reset_one_mii_phy(phy, 0x1f);
265
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);
269
270         return 0;
271 }
272
273 static int bcm5401_suspend(struct mii_phy* phy)
274 {
275 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
276         sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
277 #endif
278         return 0;
279 }
280
281 static int bcm5411_init(struct mii_phy* phy)
282 {
283         u16 data;
284
285         /* Here's some more Apple black magic to setup
286          * some voltage stuffs.
287          */
288         sungem_phy_write(phy, 0x1c, 0x8c23);
289         sungem_phy_write(phy, 0x1c, 0x8ca3);
290         sungem_phy_write(phy, 0x1c, 0x8c23);
291
292         /* Here, Apple seems to want to reset it, do
293          * it as well
294          */
295         sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
296         sungem_phy_write(phy, MII_BMCR, 0x1340);
297
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);
301
302         udelay(10);
303
304         /* Reset and configure cascaded 10/100 PHY */
305         (void)reset_one_mii_phy(phy, 0x1f);
306
307         return 0;
308 }
309
310 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
311 {
312         u16 ctl, adv;
313
314         phy->autoneg = 1;
315         phy->speed = SPEED_10;
316         phy->duplex = DUPLEX_HALF;
317         phy->pause = 0;
318         phy->advertising = advertise;
319
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);
332
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);
337
338         return 0;
339 }
340
341 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
342 {
343         u16 ctl;
344
345         phy->autoneg = 0;
346         phy->speed = speed;
347         phy->duplex = fd;
348         phy->pause = 0;
349
350         ctl = sungem_phy_read(phy, MII_BMCR);
351         ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
352
353         /* First reset the PHY */
354         sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
355
356         /* Select speed & duplex */
357         switch(speed) {
358         case SPEED_10:
359                 break;
360         case SPEED_100:
361                 ctl |= BMCR_SPEED100;
362                 break;
363         case SPEED_1000:
364         default:
365                 return -EINVAL;
366         }
367         if (fd == DUPLEX_FULL)
368                 ctl |= BMCR_FULLDPLX;
369         sungem_phy_write(phy, MII_BMCR, ctl);
370
371         return 0;
372 }
373
374 static int genmii_poll_link(struct mii_phy *phy)
375 {
376         u16 status;
377
378         (void)sungem_phy_read(phy, MII_BMSR);
379         status = sungem_phy_read(phy, MII_BMSR);
380         if ((status & BMSR_LSTATUS) == 0)
381                 return 0;
382         if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
383                 return 0;
384         return 1;
385 }
386
387 static int genmii_read_link(struct mii_phy *phy)
388 {
389         u16 lpa;
390
391         if (phy->autoneg) {
392                 lpa = sungem_phy_read(phy, MII_LPA);
393
394                 if (lpa & (LPA_10FULL | LPA_100FULL))
395                         phy->duplex = DUPLEX_FULL;
396                 else
397                         phy->duplex = DUPLEX_HALF;
398                 if (lpa & (LPA_100FULL | LPA_100HALF))
399                         phy->speed = SPEED_100;
400                 else
401                         phy->speed = SPEED_10;
402                 phy->pause = 0;
403         }
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
406          */
407
408         return 0;
409 }
410
411 static int generic_suspend(struct mii_phy* phy)
412 {
413         sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
414
415         return 0;
416 }
417
418 static int bcm5421_init(struct mii_phy* phy)
419 {
420         u16 data;
421         unsigned int id;
422
423         id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
424
425         /* Revision 0 of 5421 needs some fixups */
426         if (id == 0x002060e0) {
427                 /* This is borrowed from MacOS
428                  */
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);
438         }
439
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);
444         }
445
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))
452                         can_low_power = 0;
453                 of_node_put(np);
454                 if (can_low_power) {
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);
459                 }
460         }
461 #endif /* CONFIG_PPC_PMAC */
462
463         return 0;
464 }
465
466 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
467 {
468         u16 ctl, adv;
469
470         phy->autoneg = 1;
471         phy->speed = SPEED_10;
472         phy->duplex = DUPLEX_HALF;
473         phy->pause = 0;
474         phy->advertising = advertise;
475
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);
492
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);
501
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);
506
507         return 0;
508 }
509
510 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
511 {
512         u16 ctl;
513
514         phy->autoneg = 0;
515         phy->speed = speed;
516         phy->duplex = fd;
517         phy->pause = 0;
518
519         ctl = sungem_phy_read(phy, MII_BMCR);
520         ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
521
522         /* First reset the PHY */
523         sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
524
525         /* Select speed & duplex */
526         switch(speed) {
527         case SPEED_10:
528                 break;
529         case SPEED_100:
530                 ctl |= BMCR_SPEED100;
531                 break;
532         case SPEED_1000:
533                 ctl |= BMCR_SPD2;
534         }
535         if (fd == DUPLEX_FULL)
536                 ctl |= BMCR_FULLDPLX;
537
538         // XXX Should we set the sungem to GII now on 1000BT ?
539
540         sungem_phy_write(phy, MII_BMCR, ctl);
541
542         return 0;
543 }
544
545 static int bcm54xx_read_link(struct mii_phy *phy)
546 {
547         int link_mode;
548         u16 val;
549
550         if (phy->autoneg) {
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] ?
557                                 SPEED_1000 :
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);
563         }
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
566          */
567
568         return 0;
569 }
570
571 static int marvell88e1111_init(struct mii_phy* phy)
572 {
573         u16 rev;
574
575         /* magic init sequence for rev 0 */
576         rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
577         if (rev == 0) {
578                 sungem_phy_write(phy, 0x1d, 0x000a);
579                 sungem_phy_write(phy, 0x1e, 0x0821);
580
581                 sungem_phy_write(phy, 0x1d, 0x0006);
582                 sungem_phy_write(phy, 0x1e, 0x8600);
583
584                 sungem_phy_write(phy, 0x1d, 0x000b);
585                 sungem_phy_write(phy, 0x1e, 0x0100);
586
587                 sungem_phy_write(phy, 0x1d, 0x0004);
588                 sungem_phy_write(phy, 0x1e, 0x4850);
589         }
590         return 0;
591 }
592
593 #define BCM5421_MODE_MASK       (1 << 5)
594
595 static int bcm5421_poll_link(struct mii_phy* phy)
596 {
597         u32 phy_reg;
598         int mode;
599
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);
603
604         mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
605
606         if ( mode == BCM54XX_COPPER)
607                 return genmii_poll_link(phy);
608
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);
612
613         if (phy_reg & 0x0020)
614                 return 0;
615         else
616                 return 1;
617 }
618
619 static int bcm5421_read_link(struct mii_phy* phy)
620 {
621         u32 phy_reg;
622         int mode;
623
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);
627
628         mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
629
630         if ( mode == BCM54XX_COPPER)
631                 return bcm54xx_read_link(phy);
632
633         phy->speed = SPEED_1000;
634
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);
638
639         if ( (phy_reg & 0x0080) >> 7)
640                 phy->duplex |=  DUPLEX_HALF;
641         else
642                 phy->duplex |=  DUPLEX_FULL;
643
644         return 0;
645 }
646
647 static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
648 {
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);
653
654         if (!autoneg) {
655                 /* switch off fibre autoneg */
656                 sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
657                 sungem_phy_write(phy, 0x0b, 0x0004);
658         }
659
660         phy->autoneg = autoneg;
661
662         return 0;
663 }
664
665 #define BCM5461_FIBER_LINK      (1 << 2)
666 #define BCM5461_MODE_MASK       (3 << 1)
667
668 static int bcm5461_poll_link(struct mii_phy* phy)
669 {
670         u32 phy_reg;
671         int mode;
672
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);
676
677         mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
678
679         if ( mode == BCM54XX_COPPER)
680                 return genmii_poll_link(phy);
681
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);
685
686         if (phy_reg & BCM5461_FIBER_LINK)
687                 return 1;
688         else
689                 return 0;
690 }
691
692 #define BCM5461_FIBER_DUPLEX    (1 << 3)
693
694 static int bcm5461_read_link(struct mii_phy* phy)
695 {
696         u32 phy_reg;
697         int mode;
698
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);
702
703         mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
704
705         if ( mode == BCM54XX_COPPER) {
706                 return bcm54xx_read_link(phy);
707         }
708
709         phy->speed = SPEED_1000;
710
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);
714
715         if (phy_reg & BCM5461_FIBER_DUPLEX)
716                 phy->duplex |=  DUPLEX_FULL;
717         else
718                 phy->duplex |=  DUPLEX_HALF;
719
720         return 0;
721 }
722
723 static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
724 {
725         /* select fiber mode, enable 1000 base-X registers */
726         sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
727
728         if (autoneg) {
729                 /* enable fiber with no autonegotiation */
730                 sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
731                 sungem_phy_write(phy, MII_BMCR, 0x1140);
732         } else {
733                 /* enable fiber with autonegotiation */
734                 sungem_phy_write(phy, MII_BMCR, 0x0140);
735         }
736
737         phy->autoneg = autoneg;
738
739         return 0;
740 }
741
742 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
743 {
744         u16 ctl, adv;
745
746         phy->autoneg = 1;
747         phy->speed = SPEED_10;
748         phy->duplex = DUPLEX_HALF;
749         phy->pause = 0;
750         phy->advertising = advertise;
751
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);
768
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
773          * beasts ?
774          */
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);
784
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);
789
790         return 0;
791 }
792
793 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
794 {
795         u16 ctl, ctl2;
796
797         phy->autoneg = 0;
798         phy->speed = speed;
799         phy->duplex = fd;
800         phy->pause = 0;
801
802         ctl = sungem_phy_read(phy, MII_BMCR);
803         ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
804         ctl |= BMCR_RESET;
805
806         /* Select speed & duplex */
807         switch(speed) {
808         case SPEED_10:
809                 break;
810         case SPEED_100:
811                 ctl |= BMCR_SPEED100;
812                 break;
813         /* I'm not sure about the one below, again, Darwin source is
814          * quite confusing and I lack chip specs
815          */
816         case SPEED_1000:
817                 ctl |= BMCR_SPD2;
818         }
819         if (fd == DUPLEX_FULL)
820                 ctl |= BMCR_FULLDPLX;
821
822         /* Disable crossover. Again, the way Apple does it is strange,
823          * though I don't assume they are wrong ;)
824          */
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);
835
836         // XXX Should we set the sungem to GII now on 1000BT ?
837
838         sungem_phy_write(phy, MII_BMCR, ctl);
839
840         return 0;
841 }
842
843 static int marvell_read_link(struct mii_phy *phy)
844 {
845         u16 status, pmask;
846
847         if (phy->autoneg) {
848                 status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
849                 if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
850                         return -EAGAIN;
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;
855                 else
856                         phy->speed = SPEED_10;
857                 if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
858                         phy->duplex = DUPLEX_FULL;
859                 else
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;
864         }
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
867          */
868
869         return 0;
870 }
871
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 |     \
876          SUPPORTED_Pause)
877
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.
881  */
882 #define MII_GBIT_FEATURES \
883         (MII_BASIC_FEATURES |   \
884          SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
885
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,
894 };
895
896 static struct mii_phy_def bcm5201_phy_def = {
897         .phy_id         = 0x00406210,
898         .phy_id_mask    = 0xfffffff0,
899         .name           = "BCM5201",
900         .features       = MII_BASIC_FEATURES,
901         .magic_aneg     = 1,
902         .ops            = &bcm5201_phy_ops
903 };
904
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,
913 };
914
915 static struct mii_phy_def bcm5221_phy_def = {
916         .phy_id         = 0x004061e0,
917         .phy_id_mask    = 0xfffffff0,
918         .name           = "BCM5221",
919         .features       = MII_BASIC_FEATURES,
920         .magic_aneg     = 1,
921         .ops            = &bcm5221_phy_ops
922 };
923
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,
932 };
933 static struct mii_phy_def bcm5241_phy_def = {
934         .phy_id         = 0x0143bc30,
935         .phy_id_mask    = 0xfffffff0,
936         .name           = "BCM5241",
937         .features       = MII_BASIC_FEATURES,
938         .magic_aneg     = 1,
939         .ops            = &bcm5241_phy_ops
940 };
941
942 /* Broadcom BCM 5400 */
943 static const struct mii_phy_ops bcm5400_phy_ops = {
944         .init           = bcm5400_init,
945         .suspend        = bcm5400_suspend,
946         .setup_aneg     = bcm54xx_setup_aneg,
947         .setup_forced   = bcm54xx_setup_forced,
948         .poll_link      = genmii_poll_link,
949         .read_link      = bcm54xx_read_link,
950 };
951
952 static struct mii_phy_def bcm5400_phy_def = {
953         .phy_id         = 0x00206040,
954         .phy_id_mask    = 0xfffffff0,
955         .name           = "BCM5400",
956         .features       = MII_GBIT_FEATURES,
957         .magic_aneg     = 1,
958         .ops            = &bcm5400_phy_ops
959 };
960
961 /* Broadcom BCM 5401 */
962 static const struct mii_phy_ops bcm5401_phy_ops = {
963         .init           = bcm5401_init,
964         .suspend        = bcm5401_suspend,
965         .setup_aneg     = bcm54xx_setup_aneg,
966         .setup_forced   = bcm54xx_setup_forced,
967         .poll_link      = genmii_poll_link,
968         .read_link      = bcm54xx_read_link,
969 };
970
971 static struct mii_phy_def bcm5401_phy_def = {
972         .phy_id         = 0x00206050,
973         .phy_id_mask    = 0xfffffff0,
974         .name           = "BCM5401",
975         .features       = MII_GBIT_FEATURES,
976         .magic_aneg     = 1,
977         .ops            = &bcm5401_phy_ops
978 };
979
980 /* Broadcom BCM 5411 */
981 static const struct mii_phy_ops bcm5411_phy_ops = {
982         .init           = bcm5411_init,
983         .suspend        = generic_suspend,
984         .setup_aneg     = bcm54xx_setup_aneg,
985         .setup_forced   = bcm54xx_setup_forced,
986         .poll_link      = genmii_poll_link,
987         .read_link      = bcm54xx_read_link,
988 };
989
990 static struct mii_phy_def bcm5411_phy_def = {
991         .phy_id         = 0x00206070,
992         .phy_id_mask    = 0xfffffff0,
993         .name           = "BCM5411",
994         .features       = MII_GBIT_FEATURES,
995         .magic_aneg     = 1,
996         .ops            = &bcm5411_phy_ops
997 };
998
999 /* Broadcom BCM 5421 */
1000 static const struct mii_phy_ops bcm5421_phy_ops = {
1001         .init           = bcm5421_init,
1002         .suspend        = generic_suspend,
1003         .setup_aneg     = bcm54xx_setup_aneg,
1004         .setup_forced   = bcm54xx_setup_forced,
1005         .poll_link      = bcm5421_poll_link,
1006         .read_link      = bcm5421_read_link,
1007         .enable_fiber   = bcm5421_enable_fiber,
1008 };
1009
1010 static struct mii_phy_def bcm5421_phy_def = {
1011         .phy_id         = 0x002060e0,
1012         .phy_id_mask    = 0xfffffff0,
1013         .name           = "BCM5421",
1014         .features       = MII_GBIT_FEATURES,
1015         .magic_aneg     = 1,
1016         .ops            = &bcm5421_phy_ops
1017 };
1018
1019 /* Broadcom BCM 5421 built-in K2 */
1020 static const struct mii_phy_ops bcm5421k2_phy_ops = {
1021         .init           = bcm5421_init,
1022         .suspend        = generic_suspend,
1023         .setup_aneg     = bcm54xx_setup_aneg,
1024         .setup_forced   = bcm54xx_setup_forced,
1025         .poll_link      = genmii_poll_link,
1026         .read_link      = bcm54xx_read_link,
1027 };
1028
1029 static struct mii_phy_def bcm5421k2_phy_def = {
1030         .phy_id         = 0x002062e0,
1031         .phy_id_mask    = 0xfffffff0,
1032         .name           = "BCM5421-K2",
1033         .features       = MII_GBIT_FEATURES,
1034         .magic_aneg     = 1,
1035         .ops            = &bcm5421k2_phy_ops
1036 };
1037
1038 static const struct mii_phy_ops bcm5461_phy_ops = {
1039         .init           = bcm5421_init,
1040         .suspend        = generic_suspend,
1041         .setup_aneg     = bcm54xx_setup_aneg,
1042         .setup_forced   = bcm54xx_setup_forced,
1043         .poll_link      = bcm5461_poll_link,
1044         .read_link      = bcm5461_read_link,
1045         .enable_fiber   = bcm5461_enable_fiber,
1046 };
1047
1048 static struct mii_phy_def bcm5461_phy_def = {
1049         .phy_id         = 0x002060c0,
1050         .phy_id_mask    = 0xfffffff0,
1051         .name           = "BCM5461",
1052         .features       = MII_GBIT_FEATURES,
1053         .magic_aneg     = 1,
1054         .ops            = &bcm5461_phy_ops
1055 };
1056
1057 /* Broadcom BCM 5462 built-in Vesta */
1058 static const struct mii_phy_ops bcm5462V_phy_ops = {
1059         .init           = bcm5421_init,
1060         .suspend        = generic_suspend,
1061         .setup_aneg     = bcm54xx_setup_aneg,
1062         .setup_forced   = bcm54xx_setup_forced,
1063         .poll_link      = genmii_poll_link,
1064         .read_link      = bcm54xx_read_link,
1065 };
1066
1067 static struct mii_phy_def bcm5462V_phy_def = {
1068         .phy_id         = 0x002060d0,
1069         .phy_id_mask    = 0xfffffff0,
1070         .name           = "BCM5462-Vesta",
1071         .features       = MII_GBIT_FEATURES,
1072         .magic_aneg     = 1,
1073         .ops            = &bcm5462V_phy_ops
1074 };
1075
1076 /* Marvell 88E1101 amd 88E1111 */
1077 static const struct mii_phy_ops marvell88e1101_phy_ops = {
1078         .suspend        = generic_suspend,
1079         .setup_aneg     = marvell_setup_aneg,
1080         .setup_forced   = marvell_setup_forced,
1081         .poll_link      = genmii_poll_link,
1082         .read_link      = marvell_read_link
1083 };
1084
1085 static const struct mii_phy_ops marvell88e1111_phy_ops = {
1086         .init           = marvell88e1111_init,
1087         .suspend        = generic_suspend,
1088         .setup_aneg     = marvell_setup_aneg,
1089         .setup_forced   = marvell_setup_forced,
1090         .poll_link      = genmii_poll_link,
1091         .read_link      = marvell_read_link
1092 };
1093
1094 /* two revs in darwin for the 88e1101 ... I could use a datasheet
1095  * to get the proper names...
1096  */
1097 static struct mii_phy_def marvell88e1101v1_phy_def = {
1098         .phy_id         = 0x01410c20,
1099         .phy_id_mask    = 0xfffffff0,
1100         .name           = "Marvell 88E1101v1",
1101         .features       = MII_GBIT_FEATURES,
1102         .magic_aneg     = 1,
1103         .ops            = &marvell88e1101_phy_ops
1104 };
1105 static struct mii_phy_def marvell88e1101v2_phy_def = {
1106         .phy_id         = 0x01410c60,
1107         .phy_id_mask    = 0xfffffff0,
1108         .name           = "Marvell 88E1101v2",
1109         .features       = MII_GBIT_FEATURES,
1110         .magic_aneg     = 1,
1111         .ops            = &marvell88e1101_phy_ops
1112 };
1113 static struct mii_phy_def marvell88e1111_phy_def = {
1114         .phy_id         = 0x01410cc0,
1115         .phy_id_mask    = 0xfffffff0,
1116         .name           = "Marvell 88E1111",
1117         .features       = MII_GBIT_FEATURES,
1118         .magic_aneg     = 1,
1119         .ops            = &marvell88e1111_phy_ops
1120 };
1121
1122 /* Generic implementation for most 10/100 PHYs */
1123 static const struct mii_phy_ops generic_phy_ops = {
1124         .setup_aneg     = genmii_setup_aneg,
1125         .setup_forced   = genmii_setup_forced,
1126         .poll_link      = genmii_poll_link,
1127         .read_link      = genmii_read_link
1128 };
1129
1130 static struct mii_phy_def genmii_phy_def = {
1131         .phy_id         = 0x00000000,
1132         .phy_id_mask    = 0x00000000,
1133         .name           = "Generic MII",
1134         .features       = MII_BASIC_FEATURES,
1135         .magic_aneg     = 0,
1136         .ops            = &generic_phy_ops
1137 };
1138
1139 static struct mii_phy_def* mii_phy_table[] = {
1140         &bcm5201_phy_def,
1141         &bcm5221_phy_def,
1142         &bcm5241_phy_def,
1143         &bcm5400_phy_def,
1144         &bcm5401_phy_def,
1145         &bcm5411_phy_def,
1146         &bcm5421_phy_def,
1147         &bcm5421k2_phy_def,
1148         &bcm5461_phy_def,
1149         &bcm5462V_phy_def,
1150         &marvell88e1101v1_phy_def,
1151         &marvell88e1101v2_phy_def,
1152         &marvell88e1111_phy_def,
1153         &genmii_phy_def,
1154         NULL
1155 };
1156
1157 int sungem_phy_probe(struct mii_phy *phy, int mii_id)
1158 {
1159         int rc;
1160         u32 id;
1161         struct mii_phy_def* def;
1162         int i;
1163
1164         /* We do not reset the mii_phy structure as the driver
1165          * may re-probe the PHY regulary
1166          */
1167         phy->mii_id = mii_id;
1168
1169         /* Take PHY out of isloate mode and reset it. */
1170         rc = reset_one_mii_phy(phy, mii_id);
1171         if (rc)
1172                 goto fail;
1173
1174         /* Read ID and find matching entry */
1175         id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
1176         printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
1177                id, mii_id);
1178         for (i=0; (def = mii_phy_table[i]) != NULL; i++)
1179                 if ((id & def->phy_id_mask) == def->phy_id)
1180                         break;
1181         /* Should never be NULL (we have a generic entry), but... */
1182         if (def == NULL)
1183                 goto fail;
1184
1185         phy->def = def;
1186
1187         return 0;
1188 fail:
1189         phy->speed = 0;
1190         phy->duplex = 0;
1191         phy->pause = 0;
1192         phy->advertising = 0;
1193         return -ENODEV;
1194 }
1195
1196 EXPORT_SYMBOL(sungem_phy_probe);
1197 MODULE_LICENSE("GPL");