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