xref: /openbmc/linux/drivers/net/sungem_phy.c (revision d3741027)
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 		if (can_low_power) {
454 			/* Enable automatic low-power */
455 			sungem_phy_write(phy, 0x1c, 0x9002);
456 			sungem_phy_write(phy, 0x1c, 0xa821);
457 			sungem_phy_write(phy, 0x1c, 0x941d);
458 		}
459 	}
460 #endif /* CONFIG_PPC_PMAC */
461 
462 	return 0;
463 }
464 
465 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
466 {
467 	u16 ctl, adv;
468 
469 	phy->autoneg = 1;
470 	phy->speed = SPEED_10;
471 	phy->duplex = DUPLEX_HALF;
472 	phy->pause = 0;
473 	phy->advertising = advertise;
474 
475 	/* Setup standard advertise */
476 	adv = sungem_phy_read(phy, MII_ADVERTISE);
477 	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
478 	if (advertise & ADVERTISED_10baseT_Half)
479 		adv |= ADVERTISE_10HALF;
480 	if (advertise & ADVERTISED_10baseT_Full)
481 		adv |= ADVERTISE_10FULL;
482 	if (advertise & ADVERTISED_100baseT_Half)
483 		adv |= ADVERTISE_100HALF;
484 	if (advertise & ADVERTISED_100baseT_Full)
485 		adv |= ADVERTISE_100FULL;
486 	if (advertise & ADVERTISED_Pause)
487 		adv |= ADVERTISE_PAUSE_CAP;
488 	if (advertise & ADVERTISED_Asym_Pause)
489 		adv |= ADVERTISE_PAUSE_ASYM;
490 	sungem_phy_write(phy, MII_ADVERTISE, adv);
491 
492 	/* Setup 1000BT advertise */
493 	adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
494 	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
495 	if (advertise & SUPPORTED_1000baseT_Half)
496 		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
497 	if (advertise & SUPPORTED_1000baseT_Full)
498 		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
499 	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
500 
501 	/* Start/Restart aneg */
502 	ctl = sungem_phy_read(phy, MII_BMCR);
503 	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
504 	sungem_phy_write(phy, MII_BMCR, ctl);
505 
506 	return 0;
507 }
508 
509 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
510 {
511 	u16 ctl;
512 
513 	phy->autoneg = 0;
514 	phy->speed = speed;
515 	phy->duplex = fd;
516 	phy->pause = 0;
517 
518 	ctl = sungem_phy_read(phy, MII_BMCR);
519 	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
520 
521 	/* First reset the PHY */
522 	sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
523 
524 	/* Select speed & duplex */
525 	switch(speed) {
526 	case SPEED_10:
527 		break;
528 	case SPEED_100:
529 		ctl |= BMCR_SPEED100;
530 		break;
531 	case SPEED_1000:
532 		ctl |= BMCR_SPD2;
533 	}
534 	if (fd == DUPLEX_FULL)
535 		ctl |= BMCR_FULLDPLX;
536 
537 	// XXX Should we set the sungem to GII now on 1000BT ?
538 
539 	sungem_phy_write(phy, MII_BMCR, ctl);
540 
541 	return 0;
542 }
543 
544 static int bcm54xx_read_link(struct mii_phy *phy)
545 {
546 	int link_mode;
547 	u16 val;
548 
549 	if (phy->autoneg) {
550 	    	val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
551 		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
552 			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
553 		phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
554 			DUPLEX_FULL : DUPLEX_HALF;
555 		phy->speed = phy_BCM5400_link_table[link_mode][2] ?
556 				SPEED_1000 :
557 				(phy_BCM5400_link_table[link_mode][1] ?
558 				 SPEED_100 : SPEED_10);
559 		val = sungem_phy_read(phy, MII_LPA);
560 		phy->pause = (phy->duplex == DUPLEX_FULL) &&
561 			((val & LPA_PAUSE) != 0);
562 	}
563 	/* On non-aneg, we assume what we put in BMCR is the speed,
564 	 * though magic-aneg shouldn't prevent this case from occurring
565 	 */
566 
567 	return 0;
568 }
569 
570 static int marvell88e1111_init(struct mii_phy* phy)
571 {
572 	u16 rev;
573 
574 	/* magic init sequence for rev 0 */
575 	rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
576 	if (rev == 0) {
577 		sungem_phy_write(phy, 0x1d, 0x000a);
578 		sungem_phy_write(phy, 0x1e, 0x0821);
579 
580 		sungem_phy_write(phy, 0x1d, 0x0006);
581 		sungem_phy_write(phy, 0x1e, 0x8600);
582 
583 		sungem_phy_write(phy, 0x1d, 0x000b);
584 		sungem_phy_write(phy, 0x1e, 0x0100);
585 
586 		sungem_phy_write(phy, 0x1d, 0x0004);
587 		sungem_phy_write(phy, 0x1e, 0x4850);
588 	}
589 	return 0;
590 }
591 
592 #define BCM5421_MODE_MASK	(1 << 5)
593 
594 static int bcm5421_poll_link(struct mii_phy* phy)
595 {
596 	u32 phy_reg;
597 	int mode;
598 
599 	/* find out in what mode we are */
600 	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
601 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
602 
603 	mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
604 
605 	if ( mode == BCM54XX_COPPER)
606 		return genmii_poll_link(phy);
607 
608 	/* try to find out whether we have a link */
609 	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
610 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
611 
612 	if (phy_reg & 0x0020)
613 		return 0;
614 	else
615 		return 1;
616 }
617 
618 static int bcm5421_read_link(struct mii_phy* phy)
619 {
620 	u32 phy_reg;
621 	int mode;
622 
623 	/* find out in what mode we are */
624 	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
625 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
626 
627 	mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
628 
629 	if ( mode == BCM54XX_COPPER)
630 		return bcm54xx_read_link(phy);
631 
632 	phy->speed = SPEED_1000;
633 
634 	/* find out whether we are running half- or full duplex */
635 	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
636 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
637 
638 	if ( (phy_reg & 0x0080) >> 7)
639 		phy->duplex |=  DUPLEX_HALF;
640 	else
641 		phy->duplex |=  DUPLEX_FULL;
642 
643 	return 0;
644 }
645 
646 static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
647 {
648 	/* enable fiber mode */
649 	sungem_phy_write(phy, MII_NCONFIG, 0x9020);
650 	/* LEDs active in both modes, autosense prio = fiber */
651 	sungem_phy_write(phy, MII_NCONFIG, 0x945f);
652 
653 	if (!autoneg) {
654 		/* switch off fibre autoneg */
655 		sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
656 		sungem_phy_write(phy, 0x0b, 0x0004);
657 	}
658 
659 	phy->autoneg = autoneg;
660 
661 	return 0;
662 }
663 
664 #define BCM5461_FIBER_LINK	(1 << 2)
665 #define BCM5461_MODE_MASK	(3 << 1)
666 
667 static int bcm5461_poll_link(struct mii_phy* phy)
668 {
669 	u32 phy_reg;
670 	int mode;
671 
672 	/* find out in what mode we are */
673 	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
674 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
675 
676 	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
677 
678 	if ( mode == BCM54XX_COPPER)
679 		return genmii_poll_link(phy);
680 
681 	/* find out whether we have a link */
682 	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
683 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
684 
685 	if (phy_reg & BCM5461_FIBER_LINK)
686 		return 1;
687 	else
688 		return 0;
689 }
690 
691 #define BCM5461_FIBER_DUPLEX	(1 << 3)
692 
693 static int bcm5461_read_link(struct mii_phy* phy)
694 {
695 	u32 phy_reg;
696 	int mode;
697 
698 	/* find out in what mode we are */
699 	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
700 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
701 
702 	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
703 
704 	if ( mode == BCM54XX_COPPER) {
705 		return bcm54xx_read_link(phy);
706 	}
707 
708 	phy->speed = SPEED_1000;
709 
710 	/* find out whether we are running half- or full duplex */
711 	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
712 	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
713 
714 	if (phy_reg & BCM5461_FIBER_DUPLEX)
715 		phy->duplex |=  DUPLEX_FULL;
716 	else
717 		phy->duplex |=  DUPLEX_HALF;
718 
719 	return 0;
720 }
721 
722 static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
723 {
724 	/* select fiber mode, enable 1000 base-X registers */
725 	sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
726 
727 	if (autoneg) {
728 		/* enable fiber with no autonegotiation */
729 		sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
730 		sungem_phy_write(phy, MII_BMCR, 0x1140);
731 	} else {
732 		/* enable fiber with autonegotiation */
733 		sungem_phy_write(phy, MII_BMCR, 0x0140);
734 	}
735 
736 	phy->autoneg = autoneg;
737 
738 	return 0;
739 }
740 
741 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
742 {
743 	u16 ctl, adv;
744 
745 	phy->autoneg = 1;
746 	phy->speed = SPEED_10;
747 	phy->duplex = DUPLEX_HALF;
748 	phy->pause = 0;
749 	phy->advertising = advertise;
750 
751 	/* Setup standard advertise */
752 	adv = sungem_phy_read(phy, MII_ADVERTISE);
753 	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
754 	if (advertise & ADVERTISED_10baseT_Half)
755 		adv |= ADVERTISE_10HALF;
756 	if (advertise & ADVERTISED_10baseT_Full)
757 		adv |= ADVERTISE_10FULL;
758 	if (advertise & ADVERTISED_100baseT_Half)
759 		adv |= ADVERTISE_100HALF;
760 	if (advertise & ADVERTISED_100baseT_Full)
761 		adv |= ADVERTISE_100FULL;
762 	if (advertise & ADVERTISED_Pause)
763 		adv |= ADVERTISE_PAUSE_CAP;
764 	if (advertise & ADVERTISED_Asym_Pause)
765 		adv |= ADVERTISE_PAUSE_ASYM;
766 	sungem_phy_write(phy, MII_ADVERTISE, adv);
767 
768 	/* Setup 1000BT advertise & enable crossover detect
769 	 * XXX How do we advertise 1000BT ? Darwin source is
770 	 * confusing here, they read from specific control and
771 	 * write to control... Someone has specs for those
772 	 * beasts ?
773 	 */
774 	adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
775 	adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
776 	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
777 			MII_1000BASETCONTROL_HALFDUPLEXCAP);
778 	if (advertise & SUPPORTED_1000baseT_Half)
779 		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
780 	if (advertise & SUPPORTED_1000baseT_Full)
781 		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
782 	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
783 
784 	/* Start/Restart aneg */
785 	ctl = sungem_phy_read(phy, MII_BMCR);
786 	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
787 	sungem_phy_write(phy, MII_BMCR, ctl);
788 
789 	return 0;
790 }
791 
792 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
793 {
794 	u16 ctl, ctl2;
795 
796 	phy->autoneg = 0;
797 	phy->speed = speed;
798 	phy->duplex = fd;
799 	phy->pause = 0;
800 
801 	ctl = sungem_phy_read(phy, MII_BMCR);
802 	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
803 	ctl |= BMCR_RESET;
804 
805 	/* Select speed & duplex */
806 	switch(speed) {
807 	case SPEED_10:
808 		break;
809 	case SPEED_100:
810 		ctl |= BMCR_SPEED100;
811 		break;
812 	/* I'm not sure about the one below, again, Darwin source is
813 	 * quite confusing and I lack chip specs
814 	 */
815 	case SPEED_1000:
816 		ctl |= BMCR_SPD2;
817 	}
818 	if (fd == DUPLEX_FULL)
819 		ctl |= BMCR_FULLDPLX;
820 
821 	/* Disable crossover. Again, the way Apple does it is strange,
822 	 * though I don't assume they are wrong ;)
823 	 */
824 	ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
825 	ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
826 		MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
827 		MII_1000BASETCONTROL_FULLDUPLEXCAP |
828 		MII_1000BASETCONTROL_HALFDUPLEXCAP);
829 	if (speed == SPEED_1000)
830 		ctl2 |= (fd == DUPLEX_FULL) ?
831 			MII_1000BASETCONTROL_FULLDUPLEXCAP :
832 			MII_1000BASETCONTROL_HALFDUPLEXCAP;
833 	sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
834 
835 	// XXX Should we set the sungem to GII now on 1000BT ?
836 
837 	sungem_phy_write(phy, MII_BMCR, ctl);
838 
839 	return 0;
840 }
841 
842 static int marvell_read_link(struct mii_phy *phy)
843 {
844 	u16 status, pmask;
845 
846 	if (phy->autoneg) {
847 		status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
848 		if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
849 			return -EAGAIN;
850 		if (status & MII_M1011_PHY_SPEC_STATUS_1000)
851 			phy->speed = SPEED_1000;
852 		else if (status & MII_M1011_PHY_SPEC_STATUS_100)
853 			phy->speed = SPEED_100;
854 		else
855 			phy->speed = SPEED_10;
856 		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
857 			phy->duplex = DUPLEX_FULL;
858 		else
859 			phy->duplex = DUPLEX_HALF;
860 		pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
861 			MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
862 		phy->pause = (status & pmask) == pmask;
863 	}
864 	/* On non-aneg, we assume what we put in BMCR is the speed,
865 	 * though magic-aneg shouldn't prevent this case from occurring
866 	 */
867 
868 	return 0;
869 }
870 
871 #define MII_BASIC_FEATURES \
872 	(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |	\
873 	 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |	\
874 	 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |	\
875 	 SUPPORTED_Pause)
876 
877 /* On gigabit capable PHYs, we advertise Pause support but not asym pause
878  * support for now as I'm not sure it's supported and Darwin doesn't do
879  * it neither. --BenH.
880  */
881 #define MII_GBIT_FEATURES \
882 	(MII_BASIC_FEATURES |	\
883 	 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
884 
885 /* Broadcom BCM 5201 */
886 static const struct mii_phy_ops bcm5201_phy_ops = {
887 	.init		= bcm5201_init,
888 	.suspend	= bcm5201_suspend,
889 	.setup_aneg	= genmii_setup_aneg,
890 	.setup_forced	= genmii_setup_forced,
891 	.poll_link	= genmii_poll_link,
892 	.read_link	= genmii_read_link,
893 };
894 
895 static struct mii_phy_def bcm5201_phy_def = {
896 	.phy_id		= 0x00406210,
897 	.phy_id_mask	= 0xfffffff0,
898 	.name		= "BCM5201",
899 	.features	= MII_BASIC_FEATURES,
900 	.magic_aneg	= 1,
901 	.ops		= &bcm5201_phy_ops
902 };
903 
904 /* Broadcom BCM 5221 */
905 static const struct mii_phy_ops bcm5221_phy_ops = {
906 	.suspend	= bcm5221_suspend,
907 	.init		= bcm5221_init,
908 	.setup_aneg	= genmii_setup_aneg,
909 	.setup_forced	= genmii_setup_forced,
910 	.poll_link	= genmii_poll_link,
911 	.read_link	= genmii_read_link,
912 };
913 
914 static struct mii_phy_def bcm5221_phy_def = {
915 	.phy_id		= 0x004061e0,
916 	.phy_id_mask	= 0xfffffff0,
917 	.name		= "BCM5221",
918 	.features	= MII_BASIC_FEATURES,
919 	.magic_aneg	= 1,
920 	.ops		= &bcm5221_phy_ops
921 };
922 
923 /* Broadcom BCM 5241 */
924 static const struct mii_phy_ops bcm5241_phy_ops = {
925 	.suspend	= bcm5241_suspend,
926 	.init		= bcm5241_init,
927 	.setup_aneg	= genmii_setup_aneg,
928 	.setup_forced	= genmii_setup_forced,
929 	.poll_link	= genmii_poll_link,
930 	.read_link	= genmii_read_link,
931 };
932 static struct mii_phy_def bcm5241_phy_def = {
933 	.phy_id		= 0x0143bc30,
934 	.phy_id_mask	= 0xfffffff0,
935 	.name		= "BCM5241",
936 	.features	= MII_BASIC_FEATURES,
937 	.magic_aneg	= 1,
938 	.ops		= &bcm5241_phy_ops
939 };
940 
941 /* Broadcom BCM 5400 */
942 static const struct mii_phy_ops bcm5400_phy_ops = {
943 	.init		= bcm5400_init,
944 	.suspend	= bcm5400_suspend,
945 	.setup_aneg	= bcm54xx_setup_aneg,
946 	.setup_forced	= bcm54xx_setup_forced,
947 	.poll_link	= genmii_poll_link,
948 	.read_link	= bcm54xx_read_link,
949 };
950 
951 static struct mii_phy_def bcm5400_phy_def = {
952 	.phy_id		= 0x00206040,
953 	.phy_id_mask	= 0xfffffff0,
954 	.name		= "BCM5400",
955 	.features	= MII_GBIT_FEATURES,
956 	.magic_aneg	= 1,
957 	.ops		= &bcm5400_phy_ops
958 };
959 
960 /* Broadcom BCM 5401 */
961 static const struct mii_phy_ops bcm5401_phy_ops = {
962 	.init		= bcm5401_init,
963 	.suspend	= bcm5401_suspend,
964 	.setup_aneg	= bcm54xx_setup_aneg,
965 	.setup_forced	= bcm54xx_setup_forced,
966 	.poll_link	= genmii_poll_link,
967 	.read_link	= bcm54xx_read_link,
968 };
969 
970 static struct mii_phy_def bcm5401_phy_def = {
971 	.phy_id		= 0x00206050,
972 	.phy_id_mask	= 0xfffffff0,
973 	.name		= "BCM5401",
974 	.features	= MII_GBIT_FEATURES,
975 	.magic_aneg	= 1,
976 	.ops		= &bcm5401_phy_ops
977 };
978 
979 /* Broadcom BCM 5411 */
980 static const struct mii_phy_ops bcm5411_phy_ops = {
981 	.init		= bcm5411_init,
982 	.suspend	= generic_suspend,
983 	.setup_aneg	= bcm54xx_setup_aneg,
984 	.setup_forced	= bcm54xx_setup_forced,
985 	.poll_link	= genmii_poll_link,
986 	.read_link	= bcm54xx_read_link,
987 };
988 
989 static struct mii_phy_def bcm5411_phy_def = {
990 	.phy_id		= 0x00206070,
991 	.phy_id_mask	= 0xfffffff0,
992 	.name		= "BCM5411",
993 	.features	= MII_GBIT_FEATURES,
994 	.magic_aneg	= 1,
995 	.ops		= &bcm5411_phy_ops
996 };
997 
998 /* Broadcom BCM 5421 */
999 static const struct mii_phy_ops bcm5421_phy_ops = {
1000 	.init		= bcm5421_init,
1001 	.suspend	= generic_suspend,
1002 	.setup_aneg	= bcm54xx_setup_aneg,
1003 	.setup_forced	= bcm54xx_setup_forced,
1004 	.poll_link	= bcm5421_poll_link,
1005 	.read_link	= bcm5421_read_link,
1006 	.enable_fiber   = bcm5421_enable_fiber,
1007 };
1008 
1009 static struct mii_phy_def bcm5421_phy_def = {
1010 	.phy_id		= 0x002060e0,
1011 	.phy_id_mask	= 0xfffffff0,
1012 	.name		= "BCM5421",
1013 	.features	= MII_GBIT_FEATURES,
1014 	.magic_aneg	= 1,
1015 	.ops		= &bcm5421_phy_ops
1016 };
1017 
1018 /* Broadcom BCM 5421 built-in K2 */
1019 static const struct mii_phy_ops bcm5421k2_phy_ops = {
1020 	.init		= bcm5421_init,
1021 	.suspend	= generic_suspend,
1022 	.setup_aneg	= bcm54xx_setup_aneg,
1023 	.setup_forced	= bcm54xx_setup_forced,
1024 	.poll_link	= genmii_poll_link,
1025 	.read_link	= bcm54xx_read_link,
1026 };
1027 
1028 static struct mii_phy_def bcm5421k2_phy_def = {
1029 	.phy_id		= 0x002062e0,
1030 	.phy_id_mask	= 0xfffffff0,
1031 	.name		= "BCM5421-K2",
1032 	.features	= MII_GBIT_FEATURES,
1033 	.magic_aneg	= 1,
1034 	.ops		= &bcm5421k2_phy_ops
1035 };
1036 
1037 static const struct mii_phy_ops bcm5461_phy_ops = {
1038 	.init		= bcm5421_init,
1039 	.suspend	= generic_suspend,
1040 	.setup_aneg	= bcm54xx_setup_aneg,
1041 	.setup_forced	= bcm54xx_setup_forced,
1042 	.poll_link	= bcm5461_poll_link,
1043 	.read_link	= bcm5461_read_link,
1044 	.enable_fiber   = bcm5461_enable_fiber,
1045 };
1046 
1047 static struct mii_phy_def bcm5461_phy_def = {
1048 	.phy_id		= 0x002060c0,
1049 	.phy_id_mask	= 0xfffffff0,
1050 	.name		= "BCM5461",
1051 	.features	= MII_GBIT_FEATURES,
1052 	.magic_aneg	= 1,
1053 	.ops		= &bcm5461_phy_ops
1054 };
1055 
1056 /* Broadcom BCM 5462 built-in Vesta */
1057 static const struct mii_phy_ops bcm5462V_phy_ops = {
1058 	.init		= bcm5421_init,
1059 	.suspend	= generic_suspend,
1060 	.setup_aneg	= bcm54xx_setup_aneg,
1061 	.setup_forced	= bcm54xx_setup_forced,
1062 	.poll_link	= genmii_poll_link,
1063 	.read_link	= bcm54xx_read_link,
1064 };
1065 
1066 static struct mii_phy_def bcm5462V_phy_def = {
1067 	.phy_id		= 0x002060d0,
1068 	.phy_id_mask	= 0xfffffff0,
1069 	.name		= "BCM5462-Vesta",
1070 	.features	= MII_GBIT_FEATURES,
1071 	.magic_aneg	= 1,
1072 	.ops		= &bcm5462V_phy_ops
1073 };
1074 
1075 /* Marvell 88E1101 amd 88E1111 */
1076 static const struct mii_phy_ops marvell88e1101_phy_ops = {
1077 	.suspend	= generic_suspend,
1078 	.setup_aneg	= marvell_setup_aneg,
1079 	.setup_forced	= marvell_setup_forced,
1080 	.poll_link	= genmii_poll_link,
1081 	.read_link	= marvell_read_link
1082 };
1083 
1084 static const struct mii_phy_ops marvell88e1111_phy_ops = {
1085 	.init		= marvell88e1111_init,
1086 	.suspend	= generic_suspend,
1087 	.setup_aneg	= marvell_setup_aneg,
1088 	.setup_forced	= marvell_setup_forced,
1089 	.poll_link	= genmii_poll_link,
1090 	.read_link	= marvell_read_link
1091 };
1092 
1093 /* two revs in darwin for the 88e1101 ... I could use a datasheet
1094  * to get the proper names...
1095  */
1096 static struct mii_phy_def marvell88e1101v1_phy_def = {
1097 	.phy_id		= 0x01410c20,
1098 	.phy_id_mask	= 0xfffffff0,
1099 	.name		= "Marvell 88E1101v1",
1100 	.features	= MII_GBIT_FEATURES,
1101 	.magic_aneg	= 1,
1102 	.ops		= &marvell88e1101_phy_ops
1103 };
1104 static struct mii_phy_def marvell88e1101v2_phy_def = {
1105 	.phy_id		= 0x01410c60,
1106 	.phy_id_mask	= 0xfffffff0,
1107 	.name		= "Marvell 88E1101v2",
1108 	.features	= MII_GBIT_FEATURES,
1109 	.magic_aneg	= 1,
1110 	.ops		= &marvell88e1101_phy_ops
1111 };
1112 static struct mii_phy_def marvell88e1111_phy_def = {
1113 	.phy_id		= 0x01410cc0,
1114 	.phy_id_mask	= 0xfffffff0,
1115 	.name		= "Marvell 88E1111",
1116 	.features	= MII_GBIT_FEATURES,
1117 	.magic_aneg	= 1,
1118 	.ops		= &marvell88e1111_phy_ops
1119 };
1120 
1121 /* Generic implementation for most 10/100 PHYs */
1122 static const struct mii_phy_ops generic_phy_ops = {
1123 	.setup_aneg	= genmii_setup_aneg,
1124 	.setup_forced	= genmii_setup_forced,
1125 	.poll_link	= genmii_poll_link,
1126 	.read_link	= genmii_read_link
1127 };
1128 
1129 static struct mii_phy_def genmii_phy_def = {
1130 	.phy_id		= 0x00000000,
1131 	.phy_id_mask	= 0x00000000,
1132 	.name		= "Generic MII",
1133 	.features	= MII_BASIC_FEATURES,
1134 	.magic_aneg	= 0,
1135 	.ops		= &generic_phy_ops
1136 };
1137 
1138 static struct mii_phy_def* mii_phy_table[] = {
1139 	&bcm5201_phy_def,
1140 	&bcm5221_phy_def,
1141 	&bcm5241_phy_def,
1142 	&bcm5400_phy_def,
1143 	&bcm5401_phy_def,
1144 	&bcm5411_phy_def,
1145 	&bcm5421_phy_def,
1146 	&bcm5421k2_phy_def,
1147 	&bcm5461_phy_def,
1148 	&bcm5462V_phy_def,
1149 	&marvell88e1101v1_phy_def,
1150 	&marvell88e1101v2_phy_def,
1151 	&marvell88e1111_phy_def,
1152 	&genmii_phy_def,
1153 	NULL
1154 };
1155 
1156 int sungem_phy_probe(struct mii_phy *phy, int mii_id)
1157 {
1158 	int rc;
1159 	u32 id;
1160 	struct mii_phy_def* def;
1161 	int i;
1162 
1163 	/* We do not reset the mii_phy structure as the driver
1164 	 * may re-probe the PHY regulary
1165 	 */
1166 	phy->mii_id = mii_id;
1167 
1168 	/* Take PHY out of isloate mode and reset it. */
1169 	rc = reset_one_mii_phy(phy, mii_id);
1170 	if (rc)
1171 		goto fail;
1172 
1173 	/* Read ID and find matching entry */
1174 	id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
1175 	printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
1176 	       id, mii_id);
1177 	for (i=0; (def = mii_phy_table[i]) != NULL; i++)
1178 		if ((id & def->phy_id_mask) == def->phy_id)
1179 			break;
1180 	/* Should never be NULL (we have a generic entry), but... */
1181 	if (def == NULL)
1182 		goto fail;
1183 
1184 	phy->def = def;
1185 
1186 	return 0;
1187 fail:
1188 	phy->speed = 0;
1189 	phy->duplex = 0;
1190 	phy->pause = 0;
1191 	phy->advertising = 0;
1192 	return -ENODEV;
1193 }
1194 
1195 EXPORT_SYMBOL(sungem_phy_probe);
1196 MODULE_LICENSE("GPL");
1197