xref: /openbmc/linux/drivers/net/sungem_phy.c (revision ebbbe23f)
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 
__sungem_phy_read(struct mii_phy * phy,int id,int reg)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 
__sungem_phy_write(struct mii_phy * phy,int id,int reg,int val)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 
sungem_phy_read(struct mii_phy * phy,int reg)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 
sungem_phy_write(struct mii_phy * phy,int reg,int val)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 
reset_one_mii_phy(struct mii_phy * phy,int phy_id)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 
bcm5201_init(struct mii_phy * phy)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 
bcm5201_suspend(struct mii_phy * phy)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 
bcm5221_init(struct mii_phy * phy)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 
bcm5221_suspend(struct mii_phy * phy)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 
bcm5241_init(struct mii_phy * phy)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 
bcm5241_suspend(struct mii_phy * phy)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 
bcm5400_init(struct mii_phy * phy)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 
bcm5400_suspend(struct mii_phy * phy)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 
bcm5401_init(struct mii_phy * phy)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 
bcm5401_suspend(struct mii_phy * phy)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 
bcm5411_init(struct mii_phy * phy)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 
genmii_setup_aneg(struct mii_phy * phy,u32 advertise)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 
genmii_setup_forced(struct mii_phy * phy,int speed,int fd)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 
genmii_poll_link(struct mii_phy * phy)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 
genmii_read_link(struct mii_phy * phy)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 
generic_suspend(struct mii_phy * phy)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 
bcm5421_init(struct mii_phy * phy)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 
bcm54xx_setup_aneg(struct mii_phy * phy,u32 advertise)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 
bcm54xx_setup_forced(struct mii_phy * phy,int speed,int fd)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 
bcm54xx_read_link(struct mii_phy * phy)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 
marvell88e1111_init(struct mii_phy * phy)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 
bcm5421_poll_link(struct mii_phy * phy)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 
bcm5421_read_link(struct mii_phy * phy)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 
bcm5421_enable_fiber(struct mii_phy * phy,int autoneg)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 
bcm5461_poll_link(struct mii_phy * phy)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 
bcm5461_read_link(struct mii_phy * phy)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 
bcm5461_enable_fiber(struct mii_phy * phy,int autoneg)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 
marvell_setup_aneg(struct mii_phy * phy,u32 advertise)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 
marvell_setup_forced(struct mii_phy * phy,int speed,int fd)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 
marvell_read_link(struct mii_phy * phy)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 
sungem_phy_probe(struct mii_phy * phy,int mii_id)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");
1198