[go: nahoru, domu]

1/*
2 * PHY drivers for the sungem ethernet driver.
3 *
4 * This file could be shared with other drivers.
5 *
6 * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
7 *
8 * TODO:
9 *  - Add support for PHYs that provide an IRQ line
10 *  - Eventually moved the entire polling state machine in
11 *    there (out of the eth driver), so that it can easily be
12 *    skipped on PHYs that implement it in hardware.
13 *  - On LXT971 & BCM5201, Apple uses some chip specific regs
14 *    to read the link status. Figure out why and if it makes
15 *    sense to do the same (magic aneg ?)
16 *  - Apple has some additional power management code for some
17 *    Broadcom PHYs that they "hide" from the OpenSource version
18 *    of darwin, still need to reverse engineer that
19 */
20
21
22#include <linux/module.h>
23
24#include <linux/kernel.h>
25#include <linux/types.h>
26#include <linux/netdevice.h>
27#include <linux/etherdevice.h>
28#include <linux/mii.h>
29#include <linux/ethtool.h>
30#include <linux/delay.h>
31
32#ifdef CONFIG_PPC_PMAC
33#include <asm/prom.h>
34#endif
35
36#include <linux/sungem_phy.h>
37
38/* Link modes of the BCM5400 PHY */
39static const int phy_BCM5400_link_table[8][3] = {
40	{ 0, 0, 0 },	/* No link */
41	{ 0, 0, 0 },	/* 10BT Half Duplex */
42	{ 1, 0, 0 },	/* 10BT Full Duplex */
43	{ 0, 1, 0 },	/* 100BT Half Duplex */
44	{ 0, 1, 0 },	/* 100BT Half Duplex */
45	{ 1, 1, 0 },	/* 100BT Full Duplex*/
46	{ 1, 0, 1 },	/* 1000BT */
47	{ 1, 0, 1 },	/* 1000BT */
48};
49
50static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
51{
52	return phy->mdio_read(phy->dev, id, reg);
53}
54
55static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
56{
57	phy->mdio_write(phy->dev, id, reg, val);
58}
59
60static inline int sungem_phy_read(struct mii_phy* phy, int reg)
61{
62	return phy->mdio_read(phy->dev, phy->mii_id, reg);
63}
64
65static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
66{
67	phy->mdio_write(phy->dev, phy->mii_id, reg, val);
68}
69
70static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
71{
72	u16 val;
73	int limit = 10000;
74
75	val = __sungem_phy_read(phy, phy_id, MII_BMCR);
76	val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
77	val |= BMCR_RESET;
78	__sungem_phy_write(phy, phy_id, MII_BMCR, val);
79
80	udelay(100);
81
82	while (--limit) {
83		val = __sungem_phy_read(phy, phy_id, MII_BMCR);
84		if ((val & BMCR_RESET) == 0)
85			break;
86		udelay(10);
87	}
88	if ((val & BMCR_ISOLATE) && limit > 0)
89		__sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
90
91	return limit <= 0;
92}
93
94static int bcm5201_init(struct mii_phy* phy)
95{
96	u16 data;
97
98	data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
99	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
100	sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
101
102	sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
103
104	return 0;
105}
106
107static int bcm5201_suspend(struct mii_phy* phy)
108{
109	sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
110	sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
111
112	return 0;
113}
114
115static int bcm5221_init(struct mii_phy* phy)
116{
117	u16 data;
118
119	data = sungem_phy_read(phy, MII_BCM5221_TEST);
120	sungem_phy_write(phy, MII_BCM5221_TEST,
121		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
122
123	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
124	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
125		data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
126
127	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
128	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
129		data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
130
131	data = sungem_phy_read(phy, MII_BCM5221_TEST);
132	sungem_phy_write(phy, MII_BCM5221_TEST,
133		data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
134
135	return 0;
136}
137
138static int bcm5221_suspend(struct mii_phy* phy)
139{
140	u16 data;
141
142	data = sungem_phy_read(phy, MII_BCM5221_TEST);
143	sungem_phy_write(phy, MII_BCM5221_TEST,
144		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
145
146	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
147	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
148		  data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
149
150	return 0;
151}
152
153static int bcm5241_init(struct mii_phy* phy)
154{
155	u16 data;
156
157	data = sungem_phy_read(phy, MII_BCM5221_TEST);
158	sungem_phy_write(phy, MII_BCM5221_TEST,
159		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
160
161	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
162	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
163		data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
164
165	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
166	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
167		data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
168
169	data = sungem_phy_read(phy, MII_BCM5221_TEST);
170	sungem_phy_write(phy, MII_BCM5221_TEST,
171		data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
172
173	return 0;
174}
175
176static int bcm5241_suspend(struct mii_phy* phy)
177{
178	u16 data;
179
180	data = sungem_phy_read(phy, MII_BCM5221_TEST);
181	sungem_phy_write(phy, MII_BCM5221_TEST,
182		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
183
184	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
185	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
186		  data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
187
188	return 0;
189}
190
191static int bcm5400_init(struct mii_phy* phy)
192{
193	u16 data;
194
195	/* Configure for gigabit full duplex */
196	data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
197	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
198	sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
199
200	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
201	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
202	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
203
204	udelay(100);
205
206	/* Reset and configure cascaded 10/100 PHY */
207	(void)reset_one_mii_phy(phy, 0x1f);
208
209	data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
210	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
211	__sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
212
213	data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
214	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
215	sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
216
217	return 0;
218}
219
220static int bcm5400_suspend(struct mii_phy* phy)
221{
222#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
223	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
224#endif
225	return 0;
226}
227
228static int bcm5401_init(struct mii_phy* phy)
229{
230	u16 data;
231	int rev;
232
233	rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
234	if (rev == 0 || rev == 3) {
235		/* Some revisions of 5401 appear to need this
236		 * initialisation sequence to disable, according
237		 * to OF, "tap power management"
238		 *
239		 * WARNING ! OF and Darwin don't agree on the
240		 * register addresses. OF seem to interpret the
241		 * register numbers below as decimal
242		 *
243		 * Note: This should (and does) match tg3_init_5401phy_dsp
244		 *       in the tg3.c driver. -DaveM
245		 */
246		sungem_phy_write(phy, 0x18, 0x0c20);
247		sungem_phy_write(phy, 0x17, 0x0012);
248		sungem_phy_write(phy, 0x15, 0x1804);
249		sungem_phy_write(phy, 0x17, 0x0013);
250		sungem_phy_write(phy, 0x15, 0x1204);
251		sungem_phy_write(phy, 0x17, 0x8006);
252		sungem_phy_write(phy, 0x15, 0x0132);
253		sungem_phy_write(phy, 0x17, 0x8006);
254		sungem_phy_write(phy, 0x15, 0x0232);
255		sungem_phy_write(phy, 0x17, 0x201f);
256		sungem_phy_write(phy, 0x15, 0x0a20);
257	}
258
259	/* Configure for gigabit full duplex */
260	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
261	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
262	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
263
264	udelay(10);
265
266	/* Reset and configure cascaded 10/100 PHY */
267	(void)reset_one_mii_phy(phy, 0x1f);
268
269	data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
270	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
271	__sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
272
273	return 0;
274}
275
276static int bcm5401_suspend(struct mii_phy* phy)
277{
278#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
279	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
280#endif
281	return 0;
282}
283
284static int bcm5411_init(struct mii_phy* phy)
285{
286	u16 data;
287
288	/* Here's some more Apple black magic to setup
289	 * some voltage stuffs.
290	 */
291	sungem_phy_write(phy, 0x1c, 0x8c23);
292	sungem_phy_write(phy, 0x1c, 0x8ca3);
293	sungem_phy_write(phy, 0x1c, 0x8c23);
294
295	/* Here, Apple seems to want to reset it, do
296	 * it as well
297	 */
298	sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
299	sungem_phy_write(phy, MII_BMCR, 0x1340);
300
301	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
302	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
303	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
304
305	udelay(10);
306
307	/* Reset and configure cascaded 10/100 PHY */
308	(void)reset_one_mii_phy(phy, 0x1f);
309
310	return 0;
311}
312
313static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
314{
315	u16 ctl, adv;
316
317	phy->autoneg = 1;
318	phy->speed = SPEED_10;
319	phy->duplex = DUPLEX_HALF;
320	phy->pause = 0;
321	phy->advertising = advertise;
322
323	/* Setup standard advertise */
324	adv = sungem_phy_read(phy, MII_ADVERTISE);
325	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
326	if (advertise & ADVERTISED_10baseT_Half)
327		adv |= ADVERTISE_10HALF;
328	if (advertise & ADVERTISED_10baseT_Full)
329		adv |= ADVERTISE_10FULL;
330	if (advertise & ADVERTISED_100baseT_Half)
331		adv |= ADVERTISE_100HALF;
332	if (advertise & ADVERTISED_100baseT_Full)
333		adv |= ADVERTISE_100FULL;
334	sungem_phy_write(phy, MII_ADVERTISE, adv);
335
336	/* Start/Restart aneg */
337	ctl = sungem_phy_read(phy, MII_BMCR);
338	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
339	sungem_phy_write(phy, MII_BMCR, ctl);
340
341	return 0;
342}
343
344static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
345{
346	u16 ctl;
347
348	phy->autoneg = 0;
349	phy->speed = speed;
350	phy->duplex = fd;
351	phy->pause = 0;
352
353	ctl = sungem_phy_read(phy, MII_BMCR);
354	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
355
356	/* First reset the PHY */
357	sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
358
359	/* Select speed & duplex */
360	switch(speed) {
361	case SPEED_10:
362		break;
363	case SPEED_100:
364		ctl |= BMCR_SPEED100;
365		break;
366	case SPEED_1000:
367	default:
368		return -EINVAL;
369	}
370	if (fd == DUPLEX_FULL)
371		ctl |= BMCR_FULLDPLX;
372	sungem_phy_write(phy, MII_BMCR, ctl);
373
374	return 0;
375}
376
377static int genmii_poll_link(struct mii_phy *phy)
378{
379	u16 status;
380
381	(void)sungem_phy_read(phy, MII_BMSR);
382	status = sungem_phy_read(phy, MII_BMSR);
383	if ((status & BMSR_LSTATUS) == 0)
384		return 0;
385	if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
386		return 0;
387	return 1;
388}
389
390static int genmii_read_link(struct mii_phy *phy)
391{
392	u16 lpa;
393
394	if (phy->autoneg) {
395		lpa = sungem_phy_read(phy, MII_LPA);
396
397		if (lpa & (LPA_10FULL | LPA_100FULL))
398			phy->duplex = DUPLEX_FULL;
399		else
400			phy->duplex = DUPLEX_HALF;
401		if (lpa & (LPA_100FULL | LPA_100HALF))
402			phy->speed = SPEED_100;
403		else
404			phy->speed = SPEED_10;
405		phy->pause = 0;
406	}
407	/* On non-aneg, we assume what we put in BMCR is the speed,
408	 * though magic-aneg shouldn't prevent this case from occurring
409	 */
410
411	 return 0;
412}
413
414static int generic_suspend(struct mii_phy* phy)
415{
416	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
417
418	return 0;
419}
420
421static int bcm5421_init(struct mii_phy* phy)
422{
423	u16 data;
424	unsigned int id;
425
426	id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
427
428	/* Revision 0 of 5421 needs some fixups */
429	if (id == 0x002060e0) {
430		/* This is borrowed from MacOS
431		 */
432		sungem_phy_write(phy, 0x18, 0x1007);
433		data = sungem_phy_read(phy, 0x18);
434		sungem_phy_write(phy, 0x18, data | 0x0400);
435		sungem_phy_write(phy, 0x18, 0x0007);
436		data = sungem_phy_read(phy, 0x18);
437		sungem_phy_write(phy, 0x18, data | 0x0800);
438		sungem_phy_write(phy, 0x17, 0x000a);
439		data = sungem_phy_read(phy, 0x15);
440		sungem_phy_write(phy, 0x15, data | 0x0200);
441	}
442
443	/* Pick up some init code from OF for K2 version */
444	if ((id & 0xfffffff0) == 0x002062e0) {
445		sungem_phy_write(phy, 4, 0x01e1);
446		sungem_phy_write(phy, 9, 0x0300);
447	}
448
449	/* Check if we can enable automatic low power */
450#ifdef CONFIG_PPC_PMAC
451	if (phy->platform_data) {
452		struct device_node *np = of_get_parent(phy->platform_data);
453		int can_low_power = 1;
454		if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
455			can_low_power = 0;
456		if (can_low_power) {
457			/* Enable automatic low-power */
458			sungem_phy_write(phy, 0x1c, 0x9002);
459			sungem_phy_write(phy, 0x1c, 0xa821);
460			sungem_phy_write(phy, 0x1c, 0x941d);
461		}
462	}
463#endif /* CONFIG_PPC_PMAC */
464
465	return 0;
466}
467
468static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
469{
470	u16 ctl, adv;
471
472	phy->autoneg = 1;
473	phy->speed = SPEED_10;
474	phy->duplex = DUPLEX_HALF;
475	phy->pause = 0;
476	phy->advertising = advertise;
477
478	/* Setup standard advertise */
479	adv = sungem_phy_read(phy, MII_ADVERTISE);
480	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
481	if (advertise & ADVERTISED_10baseT_Half)
482		adv |= ADVERTISE_10HALF;
483	if (advertise & ADVERTISED_10baseT_Full)
484		adv |= ADVERTISE_10FULL;
485	if (advertise & ADVERTISED_100baseT_Half)
486		adv |= ADVERTISE_100HALF;
487	if (advertise & ADVERTISED_100baseT_Full)
488		adv |= ADVERTISE_100FULL;
489	if (advertise & ADVERTISED_Pause)
490		adv |= ADVERTISE_PAUSE_CAP;
491	if (advertise & ADVERTISED_Asym_Pause)
492		adv |= ADVERTISE_PAUSE_ASYM;
493	sungem_phy_write(phy, MII_ADVERTISE, adv);
494
495	/* Setup 1000BT advertise */
496	adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
497	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
498	if (advertise & SUPPORTED_1000baseT_Half)
499		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
500	if (advertise & SUPPORTED_1000baseT_Full)
501		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
502	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
503
504	/* Start/Restart aneg */
505	ctl = sungem_phy_read(phy, MII_BMCR);
506	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
507	sungem_phy_write(phy, MII_BMCR, ctl);
508
509	return 0;
510}
511
512static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
513{
514	u16 ctl;
515
516	phy->autoneg = 0;
517	phy->speed = speed;
518	phy->duplex = fd;
519	phy->pause = 0;
520
521	ctl = sungem_phy_read(phy, MII_BMCR);
522	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
523
524	/* First reset the PHY */
525	sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
526
527	/* Select speed & duplex */
528	switch(speed) {
529	case SPEED_10:
530		break;
531	case SPEED_100:
532		ctl |= BMCR_SPEED100;
533		break;
534	case SPEED_1000:
535		ctl |= BMCR_SPD2;
536	}
537	if (fd == DUPLEX_FULL)
538		ctl |= BMCR_FULLDPLX;
539
540	// XXX Should we set the sungem to GII now on 1000BT ?
541
542	sungem_phy_write(phy, MII_BMCR, ctl);
543
544	return 0;
545}
546
547static int bcm54xx_read_link(struct mii_phy *phy)
548{
549	int link_mode;
550	u16 val;
551
552	if (phy->autoneg) {
553	    	val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
554		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
555			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
556		phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
557			DUPLEX_FULL : DUPLEX_HALF;
558		phy->speed = phy_BCM5400_link_table[link_mode][2] ?
559				SPEED_1000 :
560				(phy_BCM5400_link_table[link_mode][1] ?
561				 SPEED_100 : SPEED_10);
562		val = sungem_phy_read(phy, MII_LPA);
563		phy->pause = (phy->duplex == DUPLEX_FULL) &&
564			((val & LPA_PAUSE) != 0);
565	}
566	/* On non-aneg, we assume what we put in BMCR is the speed,
567	 * though magic-aneg shouldn't prevent this case from occurring
568	 */
569
570	return 0;
571}
572
573static int marvell88e1111_init(struct mii_phy* phy)
574{
575	u16 rev;
576
577	/* magic init sequence for rev 0 */
578	rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
579	if (rev == 0) {
580		sungem_phy_write(phy, 0x1d, 0x000a);
581		sungem_phy_write(phy, 0x1e, 0x0821);
582
583		sungem_phy_write(phy, 0x1d, 0x0006);
584		sungem_phy_write(phy, 0x1e, 0x8600);
585
586		sungem_phy_write(phy, 0x1d, 0x000b);
587		sungem_phy_write(phy, 0x1e, 0x0100);
588
589		sungem_phy_write(phy, 0x1d, 0x0004);
590		sungem_phy_write(phy, 0x1e, 0x4850);
591	}
592	return 0;
593}
594
595#define BCM5421_MODE_MASK	(1 << 5)
596
597static int bcm5421_poll_link(struct mii_phy* phy)
598{
599	u32 phy_reg;
600	int mode;
601
602	/* find out in what mode we are */
603	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
604	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
605
606	mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
607
608	if ( mode == BCM54XX_COPPER)
609		return genmii_poll_link(phy);
610
611	/* try to find out whether we have a link */
612	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
613	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
614
615	if (phy_reg & 0x0020)
616		return 0;
617	else
618		return 1;
619}
620
621static int bcm5421_read_link(struct mii_phy* phy)
622{
623	u32 phy_reg;
624	int mode;
625
626	/* find out in what mode we are */
627	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
628	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
629
630	mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
631
632	if ( mode == BCM54XX_COPPER)
633		return bcm54xx_read_link(phy);
634
635	phy->speed = SPEED_1000;
636
637	/* find out whether we are running half- or full duplex */
638	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
639	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
640
641	if ( (phy_reg & 0x0080) >> 7)
642		phy->duplex |=  DUPLEX_HALF;
643	else
644		phy->duplex |=  DUPLEX_FULL;
645
646	return 0;
647}
648
649static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
650{
651	/* enable fiber mode */
652	sungem_phy_write(phy, MII_NCONFIG, 0x9020);
653	/* LEDs active in both modes, autosense prio = fiber */
654	sungem_phy_write(phy, MII_NCONFIG, 0x945f);
655
656	if (!autoneg) {
657		/* switch off fibre autoneg */
658		sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
659		sungem_phy_write(phy, 0x0b, 0x0004);
660	}
661
662	phy->autoneg = autoneg;
663
664	return 0;
665}
666
667#define BCM5461_FIBER_LINK	(1 << 2)
668#define BCM5461_MODE_MASK	(3 << 1)
669
670static int bcm5461_poll_link(struct mii_phy* phy)
671{
672	u32 phy_reg;
673	int mode;
674
675	/* find out in what mode we are */
676	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
677	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
678
679	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
680
681	if ( mode == BCM54XX_COPPER)
682		return genmii_poll_link(phy);
683
684	/* find out whether we have a link */
685	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
686	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
687
688	if (phy_reg & BCM5461_FIBER_LINK)
689		return 1;
690	else
691		return 0;
692}
693
694#define BCM5461_FIBER_DUPLEX	(1 << 3)
695
696static int bcm5461_read_link(struct mii_phy* phy)
697{
698	u32 phy_reg;
699	int mode;
700
701	/* find out in what mode we are */
702	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
703	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
704
705	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
706
707	if ( mode == BCM54XX_COPPER) {
708		return bcm54xx_read_link(phy);
709	}
710
711	phy->speed = SPEED_1000;
712
713	/* find out whether we are running half- or full duplex */
714	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
715	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
716
717	if (phy_reg & BCM5461_FIBER_DUPLEX)
718		phy->duplex |=  DUPLEX_FULL;
719	else
720		phy->duplex |=  DUPLEX_HALF;
721
722	return 0;
723}
724
725static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
726{
727	/* select fiber mode, enable 1000 base-X registers */
728	sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
729
730	if (autoneg) {
731		/* enable fiber with no autonegotiation */
732		sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
733		sungem_phy_write(phy, MII_BMCR, 0x1140);
734	} else {
735		/* enable fiber with autonegotiation */
736		sungem_phy_write(phy, MII_BMCR, 0x0140);
737	}
738
739	phy->autoneg = autoneg;
740
741	return 0;
742}
743
744static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
745{
746	u16 ctl, adv;
747
748	phy->autoneg = 1;
749	phy->speed = SPEED_10;
750	phy->duplex = DUPLEX_HALF;
751	phy->pause = 0;
752	phy->advertising = advertise;
753
754	/* Setup standard advertise */
755	adv = sungem_phy_read(phy, MII_ADVERTISE);
756	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
757	if (advertise & ADVERTISED_10baseT_Half)
758		adv |= ADVERTISE_10HALF;
759	if (advertise & ADVERTISED_10baseT_Full)
760		adv |= ADVERTISE_10FULL;
761	if (advertise & ADVERTISED_100baseT_Half)
762		adv |= ADVERTISE_100HALF;
763	if (advertise & ADVERTISED_100baseT_Full)
764		adv |= ADVERTISE_100FULL;
765	if (advertise & ADVERTISED_Pause)
766		adv |= ADVERTISE_PAUSE_CAP;
767	if (advertise & ADVERTISED_Asym_Pause)
768		adv |= ADVERTISE_PAUSE_ASYM;
769	sungem_phy_write(phy, MII_ADVERTISE, adv);
770
771	/* Setup 1000BT advertise & enable crossover detect
772	 * XXX How do we advertise 1000BT ? Darwin source is
773	 * confusing here, they read from specific control and
774	 * write to control... Someone has specs for those
775	 * beasts ?
776	 */
777	adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
778	adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
779	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
780			MII_1000BASETCONTROL_HALFDUPLEXCAP);
781	if (advertise & SUPPORTED_1000baseT_Half)
782		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
783	if (advertise & SUPPORTED_1000baseT_Full)
784		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
785	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
786
787	/* Start/Restart aneg */
788	ctl = sungem_phy_read(phy, MII_BMCR);
789	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
790	sungem_phy_write(phy, MII_BMCR, ctl);
791
792	return 0;
793}
794
795static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
796{
797	u16 ctl, ctl2;
798
799	phy->autoneg = 0;
800	phy->speed = speed;
801	phy->duplex = fd;
802	phy->pause = 0;
803
804	ctl = sungem_phy_read(phy, MII_BMCR);
805	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
806	ctl |= BMCR_RESET;
807
808	/* Select speed & duplex */
809	switch(speed) {
810	case SPEED_10:
811		break;
812	case SPEED_100:
813		ctl |= BMCR_SPEED100;
814		break;
815	/* I'm not sure about the one below, again, Darwin source is
816	 * quite confusing and I lack chip specs
817	 */
818	case SPEED_1000:
819		ctl |= BMCR_SPD2;
820	}
821	if (fd == DUPLEX_FULL)
822		ctl |= BMCR_FULLDPLX;
823
824	/* Disable crossover. Again, the way Apple does it is strange,
825	 * though I don't assume they are wrong ;)
826	 */
827	ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
828	ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
829		MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
830		MII_1000BASETCONTROL_FULLDUPLEXCAP |
831		MII_1000BASETCONTROL_HALFDUPLEXCAP);
832	if (speed == SPEED_1000)
833		ctl2 |= (fd == DUPLEX_FULL) ?
834			MII_1000BASETCONTROL_FULLDUPLEXCAP :
835			MII_1000BASETCONTROL_HALFDUPLEXCAP;
836	sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
837
838	// XXX Should we set the sungem to GII now on 1000BT ?
839
840	sungem_phy_write(phy, MII_BMCR, ctl);
841
842	return 0;
843}
844
845static int marvell_read_link(struct mii_phy *phy)
846{
847	u16 status, pmask;
848
849	if (phy->autoneg) {
850		status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
851		if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
852			return -EAGAIN;
853		if (status & MII_M1011_PHY_SPEC_STATUS_1000)
854			phy->speed = SPEED_1000;
855		else if (status & MII_M1011_PHY_SPEC_STATUS_100)
856			phy->speed = SPEED_100;
857		else
858			phy->speed = SPEED_10;
859		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
860			phy->duplex = DUPLEX_FULL;
861		else
862			phy->duplex = DUPLEX_HALF;
863		pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
864			MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
865		phy->pause = (status & pmask) == pmask;
866	}
867	/* On non-aneg, we assume what we put in BMCR is the speed,
868	 * though magic-aneg shouldn't prevent this case from occurring
869	 */
870
871	return 0;
872}
873
874#define MII_BASIC_FEATURES \
875	(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |	\
876	 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |	\
877	 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |	\
878	 SUPPORTED_Pause)
879
880/* On gigabit capable PHYs, we advertise Pause support but not asym pause
881 * support for now as I'm not sure it's supported and Darwin doesn't do
882 * it neither. --BenH.
883 */
884#define MII_GBIT_FEATURES \
885	(MII_BASIC_FEATURES |	\
886	 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
887
888/* Broadcom BCM 5201 */
889static struct mii_phy_ops bcm5201_phy_ops = {
890	.init		= bcm5201_init,
891	.suspend	= bcm5201_suspend,
892	.setup_aneg	= genmii_setup_aneg,
893	.setup_forced	= genmii_setup_forced,
894	.poll_link	= genmii_poll_link,
895	.read_link	= genmii_read_link,
896};
897
898static struct mii_phy_def bcm5201_phy_def = {
899	.phy_id		= 0x00406210,
900	.phy_id_mask	= 0xfffffff0,
901	.name		= "BCM5201",
902	.features	= MII_BASIC_FEATURES,
903	.magic_aneg	= 1,
904	.ops		= &bcm5201_phy_ops
905};
906
907/* Broadcom BCM 5221 */
908static struct mii_phy_ops bcm5221_phy_ops = {
909	.suspend	= bcm5221_suspend,
910	.init		= bcm5221_init,
911	.setup_aneg	= genmii_setup_aneg,
912	.setup_forced	= genmii_setup_forced,
913	.poll_link	= genmii_poll_link,
914	.read_link	= genmii_read_link,
915};
916
917static struct mii_phy_def bcm5221_phy_def = {
918	.phy_id		= 0x004061e0,
919	.phy_id_mask	= 0xfffffff0,
920	.name		= "BCM5221",
921	.features	= MII_BASIC_FEATURES,
922	.magic_aneg	= 1,
923	.ops		= &bcm5221_phy_ops
924};
925
926/* Broadcom BCM 5241 */
927static struct mii_phy_ops bcm5241_phy_ops = {
928	.suspend	= bcm5241_suspend,
929	.init		= bcm5241_init,
930	.setup_aneg	= genmii_setup_aneg,
931	.setup_forced	= genmii_setup_forced,
932	.poll_link	= genmii_poll_link,
933	.read_link	= genmii_read_link,
934};
935static struct mii_phy_def bcm5241_phy_def = {
936	.phy_id		= 0x0143bc30,
937	.phy_id_mask	= 0xfffffff0,
938	.name		= "BCM5241",
939	.features	= MII_BASIC_FEATURES,
940	.magic_aneg	= 1,
941	.ops		= &bcm5241_phy_ops
942};
943
944/* Broadcom BCM 5400 */
945static struct mii_phy_ops bcm5400_phy_ops = {
946	.init		= bcm5400_init,
947	.suspend	= bcm5400_suspend,
948	.setup_aneg	= bcm54xx_setup_aneg,
949	.setup_forced	= bcm54xx_setup_forced,
950	.poll_link	= genmii_poll_link,
951	.read_link	= bcm54xx_read_link,
952};
953
954static struct mii_phy_def bcm5400_phy_def = {
955	.phy_id		= 0x00206040,
956	.phy_id_mask	= 0xfffffff0,
957	.name		= "BCM5400",
958	.features	= MII_GBIT_FEATURES,
959	.magic_aneg	= 1,
960	.ops		= &bcm5400_phy_ops
961};
962
963/* Broadcom BCM 5401 */
964static struct mii_phy_ops bcm5401_phy_ops = {
965	.init		= bcm5401_init,
966	.suspend	= bcm5401_suspend,
967	.setup_aneg	= bcm54xx_setup_aneg,
968	.setup_forced	= bcm54xx_setup_forced,
969	.poll_link	= genmii_poll_link,
970	.read_link	= bcm54xx_read_link,
971};
972
973static struct mii_phy_def bcm5401_phy_def = {
974	.phy_id		= 0x00206050,
975	.phy_id_mask	= 0xfffffff0,
976	.name		= "BCM5401",
977	.features	= MII_GBIT_FEATURES,
978	.magic_aneg	= 1,
979	.ops		= &bcm5401_phy_ops
980};
981
982/* Broadcom BCM 5411 */
983static struct mii_phy_ops bcm5411_phy_ops = {
984	.init		= bcm5411_init,
985	.suspend	= generic_suspend,
986	.setup_aneg	= bcm54xx_setup_aneg,
987	.setup_forced	= bcm54xx_setup_forced,
988	.poll_link	= genmii_poll_link,
989	.read_link	= bcm54xx_read_link,
990};
991
992static struct mii_phy_def bcm5411_phy_def = {
993	.phy_id		= 0x00206070,
994	.phy_id_mask	= 0xfffffff0,
995	.name		= "BCM5411",
996	.features	= MII_GBIT_FEATURES,
997	.magic_aneg	= 1,
998	.ops		= &bcm5411_phy_ops
999};
1000
1001/* Broadcom BCM 5421 */
1002static struct mii_phy_ops bcm5421_phy_ops = {
1003	.init		= bcm5421_init,
1004	.suspend	= generic_suspend,
1005	.setup_aneg	= bcm54xx_setup_aneg,
1006	.setup_forced	= bcm54xx_setup_forced,
1007	.poll_link	= bcm5421_poll_link,
1008	.read_link	= bcm5421_read_link,
1009	.enable_fiber   = bcm5421_enable_fiber,
1010};
1011
1012static struct mii_phy_def bcm5421_phy_def = {
1013	.phy_id		= 0x002060e0,
1014	.phy_id_mask	= 0xfffffff0,
1015	.name		= "BCM5421",
1016	.features	= MII_GBIT_FEATURES,
1017	.magic_aneg	= 1,
1018	.ops		= &bcm5421_phy_ops
1019};
1020
1021/* Broadcom BCM 5421 built-in K2 */
1022static struct mii_phy_ops bcm5421k2_phy_ops = {
1023	.init		= bcm5421_init,
1024	.suspend	= generic_suspend,
1025	.setup_aneg	= bcm54xx_setup_aneg,
1026	.setup_forced	= bcm54xx_setup_forced,
1027	.poll_link	= genmii_poll_link,
1028	.read_link	= bcm54xx_read_link,
1029};
1030
1031static struct mii_phy_def bcm5421k2_phy_def = {
1032	.phy_id		= 0x002062e0,
1033	.phy_id_mask	= 0xfffffff0,
1034	.name		= "BCM5421-K2",
1035	.features	= MII_GBIT_FEATURES,
1036	.magic_aneg	= 1,
1037	.ops		= &bcm5421k2_phy_ops
1038};
1039
1040static struct mii_phy_ops bcm5461_phy_ops = {
1041	.init		= bcm5421_init,
1042	.suspend	= generic_suspend,
1043	.setup_aneg	= bcm54xx_setup_aneg,
1044	.setup_forced	= bcm54xx_setup_forced,
1045	.poll_link	= bcm5461_poll_link,
1046	.read_link	= bcm5461_read_link,
1047	.enable_fiber   = bcm5461_enable_fiber,
1048};
1049
1050static struct mii_phy_def bcm5461_phy_def = {
1051	.phy_id		= 0x002060c0,
1052	.phy_id_mask	= 0xfffffff0,
1053	.name		= "BCM5461",
1054	.features	= MII_GBIT_FEATURES,
1055	.magic_aneg	= 1,
1056	.ops		= &bcm5461_phy_ops
1057};
1058
1059/* Broadcom BCM 5462 built-in Vesta */
1060static struct mii_phy_ops bcm5462V_phy_ops = {
1061	.init		= bcm5421_init,
1062	.suspend	= generic_suspend,
1063	.setup_aneg	= bcm54xx_setup_aneg,
1064	.setup_forced	= bcm54xx_setup_forced,
1065	.poll_link	= genmii_poll_link,
1066	.read_link	= bcm54xx_read_link,
1067};
1068
1069static struct mii_phy_def bcm5462V_phy_def = {
1070	.phy_id		= 0x002060d0,
1071	.phy_id_mask	= 0xfffffff0,
1072	.name		= "BCM5462-Vesta",
1073	.features	= MII_GBIT_FEATURES,
1074	.magic_aneg	= 1,
1075	.ops		= &bcm5462V_phy_ops
1076};
1077
1078/* Marvell 88E1101 amd 88E1111 */
1079static struct mii_phy_ops marvell88e1101_phy_ops = {
1080	.suspend	= generic_suspend,
1081	.setup_aneg	= marvell_setup_aneg,
1082	.setup_forced	= marvell_setup_forced,
1083	.poll_link	= genmii_poll_link,
1084	.read_link	= marvell_read_link
1085};
1086
1087static struct mii_phy_ops marvell88e1111_phy_ops = {
1088	.init		= marvell88e1111_init,
1089	.suspend	= generic_suspend,
1090	.setup_aneg	= marvell_setup_aneg,
1091	.setup_forced	= marvell_setup_forced,
1092	.poll_link	= genmii_poll_link,
1093	.read_link	= marvell_read_link
1094};
1095
1096/* two revs in darwin for the 88e1101 ... I could use a datasheet
1097 * to get the proper names...
1098 */
1099static struct mii_phy_def marvell88e1101v1_phy_def = {
1100	.phy_id		= 0x01410c20,
1101	.phy_id_mask	= 0xfffffff0,
1102	.name		= "Marvell 88E1101v1",
1103	.features	= MII_GBIT_FEATURES,
1104	.magic_aneg	= 1,
1105	.ops		= &marvell88e1101_phy_ops
1106};
1107static struct mii_phy_def marvell88e1101v2_phy_def = {
1108	.phy_id		= 0x01410c60,
1109	.phy_id_mask	= 0xfffffff0,
1110	.name		= "Marvell 88E1101v2",
1111	.features	= MII_GBIT_FEATURES,
1112	.magic_aneg	= 1,
1113	.ops		= &marvell88e1101_phy_ops
1114};
1115static struct mii_phy_def marvell88e1111_phy_def = {
1116	.phy_id		= 0x01410cc0,
1117	.phy_id_mask	= 0xfffffff0,
1118	.name		= "Marvell 88E1111",
1119	.features	= MII_GBIT_FEATURES,
1120	.magic_aneg	= 1,
1121	.ops		= &marvell88e1111_phy_ops
1122};
1123
1124/* Generic implementation for most 10/100 PHYs */
1125static struct mii_phy_ops generic_phy_ops = {
1126	.setup_aneg	= genmii_setup_aneg,
1127	.setup_forced	= genmii_setup_forced,
1128	.poll_link	= genmii_poll_link,
1129	.read_link	= genmii_read_link
1130};
1131
1132static struct mii_phy_def genmii_phy_def = {
1133	.phy_id		= 0x00000000,
1134	.phy_id_mask	= 0x00000000,
1135	.name		= "Generic MII",
1136	.features	= MII_BASIC_FEATURES,
1137	.magic_aneg	= 0,
1138	.ops		= &generic_phy_ops
1139};
1140
1141static struct mii_phy_def* mii_phy_table[] = {
1142	&bcm5201_phy_def,
1143	&bcm5221_phy_def,
1144	&bcm5241_phy_def,
1145	&bcm5400_phy_def,
1146	&bcm5401_phy_def,
1147	&bcm5411_phy_def,
1148	&bcm5421_phy_def,
1149	&bcm5421k2_phy_def,
1150	&bcm5461_phy_def,
1151	&bcm5462V_phy_def,
1152	&marvell88e1101v1_phy_def,
1153	&marvell88e1101v2_phy_def,
1154	&marvell88e1111_phy_def,
1155	&genmii_phy_def,
1156	NULL
1157};
1158
1159int sungem_phy_probe(struct mii_phy *phy, int mii_id)
1160{
1161	int rc;
1162	u32 id;
1163	struct mii_phy_def* def;
1164	int i;
1165
1166	/* We do not reset the mii_phy structure as the driver
1167	 * may re-probe the PHY regulary
1168	 */
1169	phy->mii_id = mii_id;
1170
1171	/* Take PHY out of isloate mode and reset it. */
1172	rc = reset_one_mii_phy(phy, mii_id);
1173	if (rc)
1174		goto fail;
1175
1176	/* Read ID and find matching entry */
1177	id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
1178	printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
1179	       id, mii_id);
1180	for (i=0; (def = mii_phy_table[i]) != NULL; i++)
1181		if ((id & def->phy_id_mask) == def->phy_id)
1182			break;
1183	/* Should never be NULL (we have a generic entry), but... */
1184	if (def == NULL)
1185		goto fail;
1186
1187	phy->def = def;
1188
1189	return 0;
1190fail:
1191	phy->speed = 0;
1192	phy->duplex = 0;
1193	phy->pause = 0;
1194	phy->advertising = 0;
1195	return -ENODEV;
1196}
1197
1198EXPORT_SYMBOL(sungem_phy_probe);
1199MODULE_LICENSE("GPL");
1200