Blame view

drivers/net/sungem_phy.c 29.8 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  /*
   * PHY drivers for the sungem ethernet driver.
6aa20a223   Jeff Garzik   drivers/net: Trim...
4
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   * This file could be shared with other drivers.
6aa20a223   Jeff Garzik   drivers/net: Trim...
6
   *
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
7
   * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
   *
   * TODO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
   *  - Add support for PHYs that provide an IRQ line
   *  - Eventually moved the entire polling state machine in
   *    there (out of the eth driver), so that it can easily be
   *    skipped on PHYs that implement it in hardware.
   *  - On LXT971 & BCM5201, Apple uses some chip specific regs
   *    to read the link status. Figure out why and if it makes
   *    sense to do the same (magic aneg ?)
   *  - Apple has some additional power management code for some
   *    Broadcom PHYs that they "hide" from the OpenSource version
   *    of darwin, still need to reverse engineer that
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
  
  #include <linux/module.h>
  
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
29
30
  #include <linux/types.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/mii.h>
  #include <linux/ethtool.h>
  #include <linux/delay.h>
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
31
32
33
  #ifdef CONFIG_PPC_PMAC
  #include <asm/prom.h>
  #endif
ef37d38a1   Stephen Rothwell   sungem: sungem_ph...
34
  #include <linux/sungem_phy.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  
  /* Link modes of the BCM5400 PHY */
f71e13096   Arjan van de Ven   Massive net drive...
37
  static const int phy_BCM5400_link_table[8][3] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
  	{ 0, 0, 0 },	/* No link */
  	{ 0, 0, 0 },	/* 10BT Half Duplex */
  	{ 1, 0, 0 },	/* 10BT Full Duplex */
  	{ 0, 1, 0 },	/* 100BT Half Duplex */
  	{ 0, 1, 0 },	/* 100BT Half Duplex */
  	{ 1, 1, 0 },	/* 100BT Full Duplex*/
  	{ 1, 0, 1 },	/* 1000BT */
  	{ 1, 0, 1 },	/* 1000BT */
  };
abc4da450   David S. Miller   sungem: Fix globa...
47
  static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
  {
  	return phy->mdio_read(phy->dev, id, reg);
  }
abc4da450   David S. Miller   sungem: Fix globa...
51
  static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
  {
  	phy->mdio_write(phy->dev, id, reg, val);
  }
abc4da450   David S. Miller   sungem: Fix globa...
55
  static inline int sungem_phy_read(struct mii_phy* phy, int reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
  {
  	return phy->mdio_read(phy->dev, phy->mii_id, reg);
  }
abc4da450   David S. Miller   sungem: Fix globa...
59
  static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
  {
  	phy->mdio_write(phy->dev, phy->mii_id, reg, val);
  }
  
  static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
  {
  	u16 val;
  	int limit = 10000;
6aa20a223   Jeff Garzik   drivers/net: Trim...
68

abc4da450   David S. Miller   sungem: Fix globa...
69
  	val = __sungem_phy_read(phy, phy_id, MII_BMCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  	val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
  	val |= BMCR_RESET;
abc4da450   David S. Miller   sungem: Fix globa...
72
  	__sungem_phy_write(phy, phy_id, MII_BMCR, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  
  	udelay(100);
ff01b9163   Roel Kluin   cassini/sungem: l...
75
  	while (--limit) {
abc4da450   David S. Miller   sungem: Fix globa...
76
  		val = __sungem_phy_read(phy, phy_id, MII_BMCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
  		if ((val & BMCR_RESET) == 0)
  			break;
  		udelay(10);
  	}
  	if ((val & BMCR_ISOLATE) && limit > 0)
abc4da450   David S. Miller   sungem: Fix globa...
82
  		__sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
6aa20a223   Jeff Garzik   drivers/net: Trim...
83

807540baa   Eric Dumazet   drivers/net: retu...
84
  	return limit <= 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
89
  }
  
  static int bcm5201_init(struct mii_phy* phy)
  {
  	u16 data;
abc4da450   David S. Miller   sungem: Fix globa...
90
  	data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
abc4da450   David S. Miller   sungem: Fix globa...
92
  	sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93

abc4da450   David S. Miller   sungem: Fix globa...
94
  	sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
99
100
  
  	return 0;
  }
  
  static int bcm5201_suspend(struct mii_phy* phy)
  {
abc4da450   David S. Miller   sungem: Fix globa...
101
102
  	sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
  	sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
  
  	return 0;
  }
  
  static int bcm5221_init(struct mii_phy* phy)
  {
  	u16 data;
abc4da450   David S. Miller   sungem: Fix globa...
110
111
  	data = sungem_phy_read(phy, MII_BCM5221_TEST);
  	sungem_phy_write(phy, MII_BCM5221_TEST,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
abc4da450   David S. Miller   sungem: Fix globa...
113
114
  	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
  	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  		data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
abc4da450   David S. Miller   sungem: Fix globa...
116
117
  	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
  	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  		data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
abc4da450   David S. Miller   sungem: Fix globa...
119
120
  	data = sungem_phy_read(phy, MII_BCM5221_TEST);
  	sungem_phy_write(phy, MII_BCM5221_TEST,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
  		data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
  
  	return 0;
  }
  
  static int bcm5221_suspend(struct mii_phy* phy)
  {
  	u16 data;
abc4da450   David S. Miller   sungem: Fix globa...
129
130
  	data = sungem_phy_read(phy, MII_BCM5221_TEST);
  	sungem_phy_write(phy, MII_BCM5221_TEST,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
abc4da450   David S. Miller   sungem: Fix globa...
132
133
  	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
  	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
  		  data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
  
  	return 0;
  }
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
138
139
140
  static int bcm5241_init(struct mii_phy* phy)
  {
  	u16 data;
abc4da450   David S. Miller   sungem: Fix globa...
141
142
  	data = sungem_phy_read(phy, MII_BCM5221_TEST);
  	sungem_phy_write(phy, MII_BCM5221_TEST,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
143
  		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
abc4da450   David S. Miller   sungem: Fix globa...
144
145
  	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
  	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
146
  		data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
abc4da450   David S. Miller   sungem: Fix globa...
147
148
  	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
  	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
149
  		data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
abc4da450   David S. Miller   sungem: Fix globa...
150
151
  	data = sungem_phy_read(phy, MII_BCM5221_TEST);
  	sungem_phy_write(phy, MII_BCM5221_TEST,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
152
153
154
155
156
157
158
159
  		data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
  
  	return 0;
  }
  
  static int bcm5241_suspend(struct mii_phy* phy)
  {
  	u16 data;
abc4da450   David S. Miller   sungem: Fix globa...
160
161
  	data = sungem_phy_read(phy, MII_BCM5221_TEST);
  	sungem_phy_write(phy, MII_BCM5221_TEST,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
162
  		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
abc4da450   David S. Miller   sungem: Fix globa...
163
164
  	data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
  	sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
165
166
167
168
  		  data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
  static int bcm5400_init(struct mii_phy* phy)
  {
  	u16 data;
  
  	/* Configure for gigabit full duplex */
abc4da450   David S. Miller   sungem: Fix globa...
174
  	data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
abc4da450   David S. Miller   sungem: Fix globa...
176
  	sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
6aa20a223   Jeff Garzik   drivers/net: Trim...
177

abc4da450   David S. Miller   sungem: Fix globa...
178
  	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
abc4da450   David S. Miller   sungem: Fix globa...
180
  	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
6aa20a223   Jeff Garzik   drivers/net: Trim...
181

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
  	udelay(100);
  
  	/* Reset and configure cascaded 10/100 PHY */
  	(void)reset_one_mii_phy(phy, 0x1f);
6aa20a223   Jeff Garzik   drivers/net: Trim...
186

abc4da450   David S. Miller   sungem: Fix globa...
187
  	data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
abc4da450   David S. Miller   sungem: Fix globa...
189
  	__sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190

abc4da450   David S. Miller   sungem: Fix globa...
191
  	data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
abc4da450   David S. Miller   sungem: Fix globa...
193
  	sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
  
  	return 0;
  }
  
  static int bcm5400_suspend(struct mii_phy* phy)
  {
  #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
abc4da450   David S. Miller   sungem: Fix globa...
201
  	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
  #endif
  	return 0;
  }
  
  static int bcm5401_init(struct mii_phy* phy)
  {
  	u16 data;
  	int rev;
abc4da450   David S. Miller   sungem: Fix globa...
210
  	rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
  	if (rev == 0 || rev == 3) {
  		/* Some revisions of 5401 appear to need this
  		 * initialisation sequence to disable, according
  		 * to OF, "tap power management"
6aa20a223   Jeff Garzik   drivers/net: Trim...
215
  		 *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
221
222
  		 * WARNING ! OF and Darwin don't agree on the
  		 * register addresses. OF seem to interpret the
  		 * register numbers below as decimal
  		 *
  		 * Note: This should (and does) match tg3_init_5401phy_dsp
  		 *       in the tg3.c driver. -DaveM
  		 */
abc4da450   David S. Miller   sungem: Fix globa...
223
224
225
226
227
228
229
230
231
232
233
  		sungem_phy_write(phy, 0x18, 0x0c20);
  		sungem_phy_write(phy, 0x17, 0x0012);
  		sungem_phy_write(phy, 0x15, 0x1804);
  		sungem_phy_write(phy, 0x17, 0x0013);
  		sungem_phy_write(phy, 0x15, 0x1204);
  		sungem_phy_write(phy, 0x17, 0x8006);
  		sungem_phy_write(phy, 0x15, 0x0132);
  		sungem_phy_write(phy, 0x17, 0x8006);
  		sungem_phy_write(phy, 0x15, 0x0232);
  		sungem_phy_write(phy, 0x17, 0x201f);
  		sungem_phy_write(phy, 0x15, 0x0a20);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  	}
6aa20a223   Jeff Garzik   drivers/net: Trim...
235

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  	/* Configure for gigabit full duplex */
abc4da450   David S. Miller   sungem: Fix globa...
237
  	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
abc4da450   David S. Miller   sungem: Fix globa...
239
  	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
244
  
  	udelay(10);
  
  	/* Reset and configure cascaded 10/100 PHY */
  	(void)reset_one_mii_phy(phy, 0x1f);
6aa20a223   Jeff Garzik   drivers/net: Trim...
245

abc4da450   David S. Miller   sungem: Fix globa...
246
  	data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
abc4da450   David S. Miller   sungem: Fix globa...
248
  	__sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
  
  	return 0;
  }
  
  static int bcm5401_suspend(struct mii_phy* phy)
  {
  #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
abc4da450   David S. Miller   sungem: Fix globa...
256
  	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
262
263
264
265
266
267
  #endif
  	return 0;
  }
  
  static int bcm5411_init(struct mii_phy* phy)
  {
  	u16 data;
  
  	/* Here's some more Apple black magic to setup
  	 * some voltage stuffs.
  	 */
abc4da450   David S. Miller   sungem: Fix globa...
268
269
270
  	sungem_phy_write(phy, 0x1c, 0x8c23);
  	sungem_phy_write(phy, 0x1c, 0x8ca3);
  	sungem_phy_write(phy, 0x1c, 0x8c23);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
  
  	/* Here, Apple seems to want to reset it, do
  	 * it as well
  	 */
abc4da450   David S. Miller   sungem: Fix globa...
275
276
  	sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
  	sungem_phy_write(phy, MII_BMCR, 0x1340);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277

abc4da450   David S. Miller   sungem: Fix globa...
278
  	data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
abc4da450   David S. Miller   sungem: Fix globa...
280
  	sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
285
  
  	udelay(10);
  
  	/* Reset and configure cascaded 10/100 PHY */
  	(void)reset_one_mii_phy(phy, 0x1f);
6aa20a223   Jeff Garzik   drivers/net: Trim...
286

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
  	return 0;
  }
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
289
290
291
292
293
294
295
296
297
298
299
  static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
  {
  	u16 ctl, adv;
  
  	phy->autoneg = 1;
  	phy->speed = SPEED_10;
  	phy->duplex = DUPLEX_HALF;
  	phy->pause = 0;
  	phy->advertising = advertise;
  
  	/* Setup standard advertise */
abc4da450   David S. Miller   sungem: Fix globa...
300
  	adv = sungem_phy_read(phy, MII_ADVERTISE);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
301
302
303
304
305
306
307
308
309
  	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  	if (advertise & ADVERTISED_10baseT_Half)
  		adv |= ADVERTISE_10HALF;
  	if (advertise & ADVERTISED_10baseT_Full)
  		adv |= ADVERTISE_10FULL;
  	if (advertise & ADVERTISED_100baseT_Half)
  		adv |= ADVERTISE_100HALF;
  	if (advertise & ADVERTISED_100baseT_Full)
  		adv |= ADVERTISE_100FULL;
abc4da450   David S. Miller   sungem: Fix globa...
310
  	sungem_phy_write(phy, MII_ADVERTISE, adv);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
311
312
  
  	/* Start/Restart aneg */
abc4da450   David S. Miller   sungem: Fix globa...
313
  	ctl = sungem_phy_read(phy, MII_BMCR);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
314
  	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
abc4da450   David S. Miller   sungem: Fix globa...
315
  	sungem_phy_write(phy, MII_BMCR, ctl);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
316
317
318
319
320
321
322
323
324
325
326
327
  
  	return 0;
  }
  
  static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
  {
  	u16 ctl;
  
  	phy->autoneg = 0;
  	phy->speed = speed;
  	phy->duplex = fd;
  	phy->pause = 0;
abc4da450   David S. Miller   sungem: Fix globa...
328
  	ctl = sungem_phy_read(phy, MII_BMCR);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
329
330
331
  	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
  
  	/* First reset the PHY */
abc4da450   David S. Miller   sungem: Fix globa...
332
  	sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  
  	/* Select speed & duplex */
  	switch(speed) {
  	case SPEED_10:
  		break;
  	case SPEED_100:
  		ctl |= BMCR_SPEED100;
  		break;
  	case SPEED_1000:
  	default:
  		return -EINVAL;
  	}
  	if (fd == DUPLEX_FULL)
  		ctl |= BMCR_FULLDPLX;
abc4da450   David S. Miller   sungem: Fix globa...
347
  	sungem_phy_write(phy, MII_BMCR, ctl);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
348
349
350
351
352
353
354
  
  	return 0;
  }
  
  static int genmii_poll_link(struct mii_phy *phy)
  {
  	u16 status;
abc4da450   David S. Miller   sungem: Fix globa...
355
356
  	(void)sungem_phy_read(phy, MII_BMSR);
  	status = sungem_phy_read(phy, MII_BMSR);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
357
358
359
360
361
362
363
364
365
366
367
368
  	if ((status & BMSR_LSTATUS) == 0)
  		return 0;
  	if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
  		return 0;
  	return 1;
  }
  
  static int genmii_read_link(struct mii_phy *phy)
  {
  	u16 lpa;
  
  	if (phy->autoneg) {
abc4da450   David S. Miller   sungem: Fix globa...
369
  		lpa = sungem_phy_read(phy, MII_LPA);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  
  		if (lpa & (LPA_10FULL | LPA_100FULL))
  			phy->duplex = DUPLEX_FULL;
  		else
  			phy->duplex = DUPLEX_HALF;
  		if (lpa & (LPA_100FULL | LPA_100HALF))
  			phy->speed = SPEED_100;
  		else
  			phy->speed = SPEED_10;
  		phy->pause = 0;
  	}
  	/* On non-aneg, we assume what we put in BMCR is the speed,
  	 * though magic-aneg shouldn't prevent this case from occurring
  	 */
  
  	 return 0;
  }
d47f3640f   Johannes Berg   [SUNGEM]: Marvell...
387
  static int generic_suspend(struct mii_phy* phy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  {
abc4da450   David S. Miller   sungem: Fix globa...
389
  	sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
394
395
396
  
  	return 0;
  }
  
  static int bcm5421_init(struct mii_phy* phy)
  {
  	u16 data;
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
397
  	unsigned int id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398

abc4da450   David S. Miller   sungem: Fix globa...
399
  	id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
400
401
402
  
  	/* Revision 0 of 5421 needs some fixups */
  	if (id == 0x002060e0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
  		/* This is borrowed from MacOS
  		 */
abc4da450   David S. Miller   sungem: Fix globa...
405
406
407
408
409
410
411
412
413
  		sungem_phy_write(phy, 0x18, 0x1007);
  		data = sungem_phy_read(phy, 0x18);
  		sungem_phy_write(phy, 0x18, data | 0x0400);
  		sungem_phy_write(phy, 0x18, 0x0007);
  		data = sungem_phy_read(phy, 0x18);
  		sungem_phy_write(phy, 0x18, data | 0x0800);
  		sungem_phy_write(phy, 0x17, 0x000a);
  		data = sungem_phy_read(phy, 0x15);
  		sungem_phy_write(phy, 0x15, data | 0x0200);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415

3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
416
417
  	/* Pick up some init code from OF for K2 version */
  	if ((id & 0xfffffff0) == 0x002062e0) {
abc4da450   David S. Miller   sungem: Fix globa...
418
419
  		sungem_phy_write(phy, 4, 0x01e1);
  		sungem_phy_write(phy, 9, 0x0300);
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
420
421
422
423
424
425
426
  	}
  
  	/* Check if we can enable automatic low power */
  #ifdef CONFIG_PPC_PMAC
  	if (phy->platform_data) {
  		struct device_node *np = of_get_parent(phy->platform_data);
  		int can_low_power = 1;
40cd3a456   Stephen Rothwell   [POWERPC] Rename ...
427
  		if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
428
429
430
  			can_low_power = 0;
  		if (can_low_power) {
  			/* Enable automatic low-power */
abc4da450   David S. Miller   sungem: Fix globa...
431
432
433
  			sungem_phy_write(phy, 0x1c, 0x9002);
  			sungem_phy_write(phy, 0x1c, 0xa821);
  			sungem_phy_write(phy, 0x1c, 0x941d);
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
434
435
436
  		}
  	}
  #endif /* CONFIG_PPC_PMAC */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
442
443
  
  	return 0;
  }
  
  static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
  {
  	u16 ctl, adv;
6aa20a223   Jeff Garzik   drivers/net: Trim...
444

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
  	phy->autoneg = 1;
  	phy->speed = SPEED_10;
  	phy->duplex = DUPLEX_HALF;
  	phy->pause = 0;
  	phy->advertising = advertise;
  
  	/* Setup standard advertise */
abc4da450   David S. Miller   sungem: Fix globa...
452
  	adv = sungem_phy_read(phy, MII_ADVERTISE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
456
457
458
459
460
461
  	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  	if (advertise & ADVERTISED_10baseT_Half)
  		adv |= ADVERTISE_10HALF;
  	if (advertise & ADVERTISED_10baseT_Full)
  		adv |= ADVERTISE_10FULL;
  	if (advertise & ADVERTISED_100baseT_Half)
  		adv |= ADVERTISE_100HALF;
  	if (advertise & ADVERTISED_100baseT_Full)
  		adv |= ADVERTISE_100FULL;
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
462
463
464
465
  	if (advertise & ADVERTISED_Pause)
  		adv |= ADVERTISE_PAUSE_CAP;
  	if (advertise & ADVERTISED_Asym_Pause)
  		adv |= ADVERTISE_PAUSE_ASYM;
abc4da450   David S. Miller   sungem: Fix globa...
466
  	sungem_phy_write(phy, MII_ADVERTISE, adv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
  
  	/* Setup 1000BT advertise */
abc4da450   David S. Miller   sungem: Fix globa...
469
  	adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
  	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
  	if (advertise & SUPPORTED_1000baseT_Half)
  		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
  	if (advertise & SUPPORTED_1000baseT_Full)
  		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
abc4da450   David S. Miller   sungem: Fix globa...
475
  	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  
  	/* Start/Restart aneg */
abc4da450   David S. Miller   sungem: Fix globa...
478
  	ctl = sungem_phy_read(phy, MII_BMCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
abc4da450   David S. Miller   sungem: Fix globa...
480
  	sungem_phy_write(phy, MII_BMCR, ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
486
487
  
  	return 0;
  }
  
  static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
  {
  	u16 ctl;
6aa20a223   Jeff Garzik   drivers/net: Trim...
488

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
491
492
  	phy->autoneg = 0;
  	phy->speed = speed;
  	phy->duplex = fd;
  	phy->pause = 0;
abc4da450   David S. Miller   sungem: Fix globa...
493
  	ctl = sungem_phy_read(phy, MII_BMCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
  	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
  
  	/* First reset the PHY */
abc4da450   David S. Miller   sungem: Fix globa...
497
  	sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  
  	/* Select speed & duplex */
  	switch(speed) {
  	case SPEED_10:
  		break;
  	case SPEED_100:
  		ctl |= BMCR_SPEED100;
  		break;
  	case SPEED_1000:
  		ctl |= BMCR_SPD2;
  	}
  	if (fd == DUPLEX_FULL)
  		ctl |= BMCR_FULLDPLX;
  
  	// XXX Should we set the sungem to GII now on 1000BT ?
6aa20a223   Jeff Garzik   drivers/net: Trim...
513

abc4da450   David S. Miller   sungem: Fix globa...
514
  	sungem_phy_write(phy, MII_BMCR, ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
  
  	return 0;
  }
  
  static int bcm54xx_read_link(struct mii_phy *phy)
  {
6aa20a223   Jeff Garzik   drivers/net: Trim...
521
  	int link_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	u16 val;
6aa20a223   Jeff Garzik   drivers/net: Trim...
523

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  	if (phy->autoneg) {
abc4da450   David S. Miller   sungem: Fix globa...
525
  	    	val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
  		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
  			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
528
529
  		phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
  			DUPLEX_FULL : DUPLEX_HALF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
  		phy->speed = phy_BCM5400_link_table[link_mode][2] ?
  				SPEED_1000 :
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
532
533
  				(phy_BCM5400_link_table[link_mode][1] ?
  				 SPEED_100 : SPEED_10);
abc4da450   David S. Miller   sungem: Fix globa...
534
  		val = sungem_phy_read(phy, MII_LPA);
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
535
536
  		phy->pause = (phy->duplex == DUPLEX_FULL) &&
  			((val & LPA_PAUSE) != 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
542
543
  	}
  	/* On non-aneg, we assume what we put in BMCR is the speed,
  	 * though magic-aneg shouldn't prevent this case from occurring
  	 */
  
  	return 0;
  }
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
544
545
546
547
548
  static int marvell88e1111_init(struct mii_phy* phy)
  {
  	u16 rev;
  
  	/* magic init sequence for rev 0 */
abc4da450   David S. Miller   sungem: Fix globa...
549
  	rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
550
  	if (rev == 0) {
abc4da450   David S. Miller   sungem: Fix globa...
551
552
  		sungem_phy_write(phy, 0x1d, 0x000a);
  		sungem_phy_write(phy, 0x1e, 0x0821);
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
553

abc4da450   David S. Miller   sungem: Fix globa...
554
555
  		sungem_phy_write(phy, 0x1d, 0x0006);
  		sungem_phy_write(phy, 0x1e, 0x8600);
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
556

abc4da450   David S. Miller   sungem: Fix globa...
557
558
  		sungem_phy_write(phy, 0x1d, 0x000b);
  		sungem_phy_write(phy, 0x1e, 0x0100);
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
559

abc4da450   David S. Miller   sungem: Fix globa...
560
561
  		sungem_phy_write(phy, 0x1d, 0x0004);
  		sungem_phy_write(phy, 0x1e, 0x4850);
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
562
563
564
  	}
  	return 0;
  }
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
565
566
567
568
569
570
571
572
  #define BCM5421_MODE_MASK	(1 << 5)
  
  static int bcm5421_poll_link(struct mii_phy* phy)
  {
  	u32 phy_reg;
  	int mode;
  
  	/* find out in what mode we are */
abc4da450   David S. Miller   sungem: Fix globa...
573
574
  	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
575
576
577
578
579
  
  	mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
  
  	if ( mode == BCM54XX_COPPER)
  		return genmii_poll_link(phy);
48fc7f7e7   Adam Buchbinder   Fix misspellings ...
580
  	/* try to find out whether we have a link */
abc4da450   David S. Miller   sungem: Fix globa...
581
582
  	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
583
584
585
586
587
588
589
590
591
592
593
594
595
  
  	if (phy_reg & 0x0020)
  		return 0;
  	else
  		return 1;
  }
  
  static int bcm5421_read_link(struct mii_phy* phy)
  {
  	u32 phy_reg;
  	int mode;
  
  	/* find out in what mode we are */
abc4da450   David S. Miller   sungem: Fix globa...
596
597
  	sungem_phy_write(phy, MII_NCONFIG, 0x1000);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
598
599
600
601
602
603
604
  
  	mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
  
  	if ( mode == BCM54XX_COPPER)
  		return bcm54xx_read_link(phy);
  
  	phy->speed = SPEED_1000;
48fc7f7e7   Adam Buchbinder   Fix misspellings ...
605
  	/* find out whether we are running half- or full duplex */
abc4da450   David S. Miller   sungem: Fix globa...
606
607
  	sungem_phy_write(phy, MII_NCONFIG, 0x2000);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
608
609
610
611
612
613
614
615
616
617
618
619
  
  	if ( (phy_reg & 0x0080) >> 7)
  		phy->duplex |=  DUPLEX_HALF;
  	else
  		phy->duplex |=  DUPLEX_FULL;
  
  	return 0;
  }
  
  static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
  {
  	/* enable fiber mode */
abc4da450   David S. Miller   sungem: Fix globa...
620
  	sungem_phy_write(phy, MII_NCONFIG, 0x9020);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
621
  	/* LEDs active in both modes, autosense prio = fiber */
abc4da450   David S. Miller   sungem: Fix globa...
622
  	sungem_phy_write(phy, MII_NCONFIG, 0x945f);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
623
624
625
  
  	if (!autoneg) {
  		/* switch off fibre autoneg */
abc4da450   David S. Miller   sungem: Fix globa...
626
627
  		sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
  		sungem_phy_write(phy, 0x0b, 0x0004);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
  	}
  
  	phy->autoneg = autoneg;
  
  	return 0;
  }
  
  #define BCM5461_FIBER_LINK	(1 << 2)
  #define BCM5461_MODE_MASK	(3 << 1)
  
  static int bcm5461_poll_link(struct mii_phy* phy)
  {
  	u32 phy_reg;
  	int mode;
  
  	/* find out in what mode we are */
abc4da450   David S. Miller   sungem: Fix globa...
644
645
  	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
646
647
648
649
650
  
  	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
  
  	if ( mode == BCM54XX_COPPER)
  		return genmii_poll_link(phy);
48fc7f7e7   Adam Buchbinder   Fix misspellings ...
651
  	/* find out whether we have a link */
abc4da450   David S. Miller   sungem: Fix globa...
652
653
  	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  
  	if (phy_reg & BCM5461_FIBER_LINK)
  		return 1;
  	else
  		return 0;
  }
  
  #define BCM5461_FIBER_DUPLEX	(1 << 3)
  
  static int bcm5461_read_link(struct mii_phy* phy)
  {
  	u32 phy_reg;
  	int mode;
  
  	/* find out in what mode we are */
abc4da450   David S. Miller   sungem: Fix globa...
669
670
  	sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
671
672
673
674
675
676
677
678
  
  	mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
  
  	if ( mode == BCM54XX_COPPER) {
  		return bcm54xx_read_link(phy);
  	}
  
  	phy->speed = SPEED_1000;
48fc7f7e7   Adam Buchbinder   Fix misspellings ...
679
  	/* find out whether we are running half- or full duplex */
abc4da450   David S. Miller   sungem: Fix globa...
680
681
  	sungem_phy_write(phy, MII_NCONFIG, 0x7000);
  	phy_reg = sungem_phy_read(phy, MII_NCONFIG);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
682
683
684
685
686
687
688
689
690
691
692
693
  
  	if (phy_reg & BCM5461_FIBER_DUPLEX)
  		phy->duplex |=  DUPLEX_FULL;
  	else
  		phy->duplex |=  DUPLEX_HALF;
  
  	return 0;
  }
  
  static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
  {
  	/* select fiber mode, enable 1000 base-X registers */
abc4da450   David S. Miller   sungem: Fix globa...
694
  	sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
695
696
697
  
  	if (autoneg) {
  		/* enable fiber with no autonegotiation */
abc4da450   David S. Miller   sungem: Fix globa...
698
699
  		sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
  		sungem_phy_write(phy, MII_BMCR, 0x1140);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
700
701
  	} else {
  		/* enable fiber with autonegotiation */
abc4da450   David S. Miller   sungem: Fix globa...
702
  		sungem_phy_write(phy, MII_BMCR, 0x0140);
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
703
704
705
706
707
708
  	}
  
  	phy->autoneg = autoneg;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
  static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
  {
  	u16 ctl, adv;
6aa20a223   Jeff Garzik   drivers/net: Trim...
712

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
718
719
  	phy->autoneg = 1;
  	phy->speed = SPEED_10;
  	phy->duplex = DUPLEX_HALF;
  	phy->pause = 0;
  	phy->advertising = advertise;
  
  	/* Setup standard advertise */
abc4da450   David S. Miller   sungem: Fix globa...
720
  	adv = sungem_phy_read(phy, MII_ADVERTISE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
726
727
728
729
  	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  	if (advertise & ADVERTISED_10baseT_Half)
  		adv |= ADVERTISE_10HALF;
  	if (advertise & ADVERTISED_10baseT_Full)
  		adv |= ADVERTISE_10FULL;
  	if (advertise & ADVERTISED_100baseT_Half)
  		adv |= ADVERTISE_100HALF;
  	if (advertise & ADVERTISED_100baseT_Full)
  		adv |= ADVERTISE_100FULL;
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
730
731
732
733
  	if (advertise & ADVERTISED_Pause)
  		adv |= ADVERTISE_PAUSE_CAP;
  	if (advertise & ADVERTISED_Asym_Pause)
  		adv |= ADVERTISE_PAUSE_ASYM;
abc4da450   David S. Miller   sungem: Fix globa...
734
  	sungem_phy_write(phy, MII_ADVERTISE, adv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
739
740
741
  
  	/* Setup 1000BT advertise & enable crossover detect
  	 * XXX How do we advertise 1000BT ? Darwin source is
  	 * confusing here, they read from specific control and
  	 * write to control... Someone has specs for those
  	 * beasts ?
  	 */
abc4da450   David S. Miller   sungem: Fix globa...
742
  	adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
747
748
749
  	adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
  	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
  			MII_1000BASETCONTROL_HALFDUPLEXCAP);
  	if (advertise & SUPPORTED_1000baseT_Half)
  		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
  	if (advertise & SUPPORTED_1000baseT_Full)
  		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
abc4da450   David S. Miller   sungem: Fix globa...
750
  	sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
  
  	/* Start/Restart aneg */
abc4da450   David S. Miller   sungem: Fix globa...
753
  	ctl = sungem_phy_read(phy, MII_BMCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
abc4da450   David S. Miller   sungem: Fix globa...
755
  	sungem_phy_write(phy, MII_BMCR, ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
758
759
760
761
762
  
  	return 0;
  }
  
  static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
  {
  	u16 ctl, ctl2;
6aa20a223   Jeff Garzik   drivers/net: Trim...
763

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
767
  	phy->autoneg = 0;
  	phy->speed = speed;
  	phy->duplex = fd;
  	phy->pause = 0;
abc4da450   David S. Miller   sungem: Fix globa...
768
  	ctl = sungem_phy_read(phy, MII_BMCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
  	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
  	ctl |= BMCR_RESET;
  
  	/* Select speed & duplex */
  	switch(speed) {
  	case SPEED_10:
  		break;
  	case SPEED_100:
  		ctl |= BMCR_SPEED100;
  		break;
  	/* I'm not sure about the one below, again, Darwin source is
  	 * quite confusing and I lack chip specs
  	 */
  	case SPEED_1000:
  		ctl |= BMCR_SPD2;
  	}
  	if (fd == DUPLEX_FULL)
  		ctl |= BMCR_FULLDPLX;
  
  	/* Disable crossover. Again, the way Apple does it is strange,
  	 * though I don't assume they are wrong ;)
  	 */
abc4da450   David S. Miller   sungem: Fix globa...
791
  	ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
798
799
  	ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
  		MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
  		MII_1000BASETCONTROL_FULLDUPLEXCAP |
  		MII_1000BASETCONTROL_HALFDUPLEXCAP);
  	if (speed == SPEED_1000)
  		ctl2 |= (fd == DUPLEX_FULL) ?
  			MII_1000BASETCONTROL_FULLDUPLEXCAP :
  			MII_1000BASETCONTROL_HALFDUPLEXCAP;
abc4da450   David S. Miller   sungem: Fix globa...
800
  	sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
  
  	// XXX Should we set the sungem to GII now on 1000BT ?
6aa20a223   Jeff Garzik   drivers/net: Trim...
803

abc4da450   David S. Miller   sungem: Fix globa...
804
  	sungem_phy_write(phy, MII_BMCR, ctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
807
808
809
810
  
  	return 0;
  }
  
  static int marvell_read_link(struct mii_phy *phy)
  {
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
811
  	u16 status, pmask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
813
  
  	if (phy->autoneg) {
abc4da450   David S. Miller   sungem: Fix globa...
814
  		status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
819
820
821
822
823
824
825
826
  		if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
  			return -EAGAIN;
  		if (status & MII_M1011_PHY_SPEC_STATUS_1000)
  			phy->speed = SPEED_1000;
  		else if (status & MII_M1011_PHY_SPEC_STATUS_100)
  			phy->speed = SPEED_100;
  		else
  			phy->speed = SPEED_10;
  		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
  			phy->duplex = DUPLEX_FULL;
  		else
  			phy->duplex = DUPLEX_HALF;
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
827
828
829
  		pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
  			MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
  		phy->pause = (status & pmask) == pmask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
831
832
833
834
835
836
  	}
  	/* On non-aneg, we assume what we put in BMCR is the speed,
  	 * though magic-aneg shouldn't prevent this case from occurring
  	 */
  
  	return 0;
  }
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
837
838
839
840
841
842
843
844
845
846
847
848
849
  #define MII_BASIC_FEATURES \
  	(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |	\
  	 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |	\
  	 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |	\
  	 SUPPORTED_Pause)
  
  /* On gigabit capable PHYs, we advertise Pause support but not asym pause
   * support for now as I'm not sure it's supported and Darwin doesn't do
   * it neither. --BenH.
   */
  #define MII_GBIT_FEATURES \
  	(MII_BASIC_FEATURES |	\
  	 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
  
  /* Broadcom BCM 5201 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
852
  static const struct mii_phy_ops bcm5201_phy_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  	.init		= bcm5201_init,
  	.suspend	= bcm5201_suspend,
  	.setup_aneg	= genmii_setup_aneg,
  	.setup_forced	= genmii_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= genmii_read_link,
  };
  
  static struct mii_phy_def bcm5201_phy_def = {
  	.phy_id		= 0x00406210,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5201",
  	.features	= MII_BASIC_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5201_phy_ops
  };
  
  /* Broadcom BCM 5221 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
871
  static const struct mii_phy_ops bcm5221_phy_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
  	.suspend	= bcm5221_suspend,
  	.init		= bcm5221_init,
  	.setup_aneg	= genmii_setup_aneg,
  	.setup_forced	= genmii_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= genmii_read_link,
  };
  
  static struct mii_phy_def bcm5221_phy_def = {
  	.phy_id		= 0x004061e0,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5221",
  	.features	= MII_BASIC_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5221_phy_ops
  };
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
888
  /* Broadcom BCM 5241 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
889
  static const struct mii_phy_ops bcm5241_phy_ops = {
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
  	.suspend	= bcm5241_suspend,
  	.init		= bcm5241_init,
  	.setup_aneg	= genmii_setup_aneg,
  	.setup_forced	= genmii_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= genmii_read_link,
  };
  static struct mii_phy_def bcm5241_phy_def = {
  	.phy_id		= 0x0143bc30,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5241",
  	.features	= MII_BASIC_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5241_phy_ops
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  /* Broadcom BCM 5400 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
906
  static const struct mii_phy_ops bcm5400_phy_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
  	.init		= bcm5400_init,
  	.suspend	= bcm5400_suspend,
  	.setup_aneg	= bcm54xx_setup_aneg,
  	.setup_forced	= bcm54xx_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= bcm54xx_read_link,
  };
  
  static struct mii_phy_def bcm5400_phy_def = {
  	.phy_id		= 0x00206040,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5400",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5400_phy_ops
  };
  
  /* Broadcom BCM 5401 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
925
  static const struct mii_phy_ops bcm5401_phy_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
  	.init		= bcm5401_init,
  	.suspend	= bcm5401_suspend,
  	.setup_aneg	= bcm54xx_setup_aneg,
  	.setup_forced	= bcm54xx_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= bcm54xx_read_link,
  };
  
  static struct mii_phy_def bcm5401_phy_def = {
  	.phy_id		= 0x00206050,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5401",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5401_phy_ops
  };
  
  /* Broadcom BCM 5411 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
944
  static const struct mii_phy_ops bcm5411_phy_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  	.init		= bcm5411_init,
d47f3640f   Johannes Berg   [SUNGEM]: Marvell...
946
  	.suspend	= generic_suspend,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
  	.setup_aneg	= bcm54xx_setup_aneg,
  	.setup_forced	= bcm54xx_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= bcm54xx_read_link,
  };
  
  static struct mii_phy_def bcm5411_phy_def = {
  	.phy_id		= 0x00206070,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5411",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5411_phy_ops
  };
  
  /* Broadcom BCM 5421 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
963
  static const struct mii_phy_ops bcm5421_phy_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  	.init		= bcm5421_init,
d47f3640f   Johannes Berg   [SUNGEM]: Marvell...
965
  	.suspend	= generic_suspend,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
  	.setup_aneg	= bcm54xx_setup_aneg,
  	.setup_forced	= bcm54xx_setup_forced,
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
968
969
  	.poll_link	= bcm5421_poll_link,
  	.read_link	= bcm5421_read_link,
8ec934596   Jens Osterkamp   spidernet: enable...
970
  	.enable_fiber   = bcm5421_enable_fiber,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
972
973
974
975
976
977
978
979
980
981
982
  };
  
  static struct mii_phy_def bcm5421_phy_def = {
  	.phy_id		= 0x002060e0,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5421",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5421_phy_ops
  };
  
  /* Broadcom BCM 5421 built-in K2 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
983
  static const struct mii_phy_ops bcm5421k2_phy_ops = {
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
984
  	.init		= bcm5421_init,
d47f3640f   Johannes Berg   [SUNGEM]: Marvell...
985
  	.suspend	= generic_suspend,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
988
989
990
991
992
993
994
995
996
997
998
999
  	.setup_aneg	= bcm54xx_setup_aneg,
  	.setup_forced	= bcm54xx_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= bcm54xx_read_link,
  };
  
  static struct mii_phy_def bcm5421k2_phy_def = {
  	.phy_id		= 0x002062e0,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5421-K2",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5421k2_phy_ops
  };
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
1000
  static const struct mii_phy_ops bcm5461_phy_ops = {
8ec934596   Jens Osterkamp   spidernet: enable...
1001
1002
1003
1004
  	.init		= bcm5421_init,
  	.suspend	= generic_suspend,
  	.setup_aneg	= bcm54xx_setup_aneg,
  	.setup_forced	= bcm54xx_setup_forced,
eb5b5b2ff   Jens Osterkamp   sungem_phy: suppo...
1005
1006
  	.poll_link	= bcm5461_poll_link,
  	.read_link	= bcm5461_read_link,
8ec934596   Jens Osterkamp   spidernet: enable...
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  	.enable_fiber   = bcm5461_enable_fiber,
  };
  
  static struct mii_phy_def bcm5461_phy_def = {
  	.phy_id		= 0x002060c0,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5461",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5461_phy_ops
  };
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
1018
  /* Broadcom BCM 5462 built-in Vesta */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
1019
  static const struct mii_phy_ops bcm5462V_phy_ops = {
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
1020
  	.init		= bcm5421_init,
d47f3640f   Johannes Berg   [SUNGEM]: Marvell...
1021
  	.suspend	= generic_suspend,
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
  	.setup_aneg	= bcm54xx_setup_aneg,
  	.setup_forced	= bcm54xx_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= bcm54xx_read_link,
  };
  
  static struct mii_phy_def bcm5462V_phy_def = {
  	.phy_id		= 0x002060d0,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "BCM5462-Vesta",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &bcm5462V_phy_ops
  };
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
1036
  /* Marvell 88E1101 amd 88E1111 */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
1037
  static const struct mii_phy_ops marvell88e1101_phy_ops = {
d47f3640f   Johannes Berg   [SUNGEM]: Marvell...
1038
  	.suspend	= generic_suspend,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
1041
1042
1043
  	.setup_aneg	= marvell_setup_aneg,
  	.setup_forced	= marvell_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= marvell_read_link
  };
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
1044
  static const struct mii_phy_ops marvell88e1111_phy_ops = {
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  	.init		= marvell88e1111_init,
  	.suspend	= generic_suspend,
  	.setup_aneg	= marvell_setup_aneg,
  	.setup_forced	= marvell_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= marvell_read_link
  };
  
  /* two revs in darwin for the 88e1101 ... I could use a datasheet
   * to get the proper names...
   */
  static struct mii_phy_def marvell88e1101v1_phy_def = {
  	.phy_id		= 0x01410c20,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "Marvell 88E1101v1",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &marvell88e1101_phy_ops
  };
  static struct mii_phy_def marvell88e1101v2_phy_def = {
  	.phy_id		= 0x01410c60,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "Marvell 88E1101v2",
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
  	.ops		= &marvell88e1101_phy_ops
  };
  static struct mii_phy_def marvell88e1111_phy_def = {
  	.phy_id		= 0x01410cc0,
  	.phy_id_mask	= 0xfffffff0,
  	.name		= "Marvell 88E1111",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
1077
  	.features	= MII_GBIT_FEATURES,
  	.magic_aneg	= 1,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
1078
  	.ops		= &marvell88e1111_phy_ops
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
1081
  };
  
  /* Generic implementation for most 10/100 PHYs */
7cb6e01de   Bhumika Goyal   drivers/net/sunge...
1082
  static const struct mii_phy_ops generic_phy_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  	.setup_aneg	= genmii_setup_aneg,
  	.setup_forced	= genmii_setup_forced,
  	.poll_link	= genmii_poll_link,
  	.read_link	= genmii_read_link
  };
  
  static struct mii_phy_def genmii_phy_def = {
  	.phy_id		= 0x00000000,
  	.phy_id_mask	= 0x00000000,
  	.name		= "Generic MII",
  	.features	= MII_BASIC_FEATURES,
  	.magic_aneg	= 0,
  	.ops		= &generic_phy_ops
  };
  
  static struct mii_phy_def* mii_phy_table[] = {
  	&bcm5201_phy_def,
  	&bcm5221_phy_def,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
1101
  	&bcm5241_phy_def,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
1104
1105
1106
  	&bcm5400_phy_def,
  	&bcm5401_phy_def,
  	&bcm5411_phy_def,
  	&bcm5421_phy_def,
  	&bcm5421k2_phy_def,
8ec934596   Jens Osterkamp   spidernet: enable...
1107
  	&bcm5461_phy_def,
3c326fe9c   Benjamin Herrenschmidt   [PATCH] ppc64: Ad...
1108
  	&bcm5462V_phy_def,
63ea998a2   Benjamin Herrenschmidt   [SUNGEM]: PHY upd...
1109
1110
1111
  	&marvell88e1101v1_phy_def,
  	&marvell88e1101v2_phy_def,
  	&marvell88e1111_phy_def,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
  	&genmii_phy_def,
  	NULL
  };
19e2f6fe9   David S. Miller   net: Fix sungem_p...
1115
  int sungem_phy_probe(struct mii_phy *phy, int mii_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  {
  	int rc;
  	u32 id;
  	struct mii_phy_def* def;
  	int i;
  
  	/* We do not reset the mii_phy structure as the driver
  	 * may re-probe the PHY regulary
  	 */
  	phy->mii_id = mii_id;
6aa20a223   Jeff Garzik   drivers/net: Trim...
1126

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
1129
1130
  	/* Take PHY out of isloate mode and reset it. */
  	rc = reset_one_mii_phy(phy, mii_id);
  	if (rc)
  		goto fail;
6aa20a223   Jeff Garzik   drivers/net: Trim...
1131
  	/* Read ID and find matching entry */
abc4da450   David S. Miller   sungem: Fix globa...
1132
  	id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
c6c759884   Joe Perches   drivers/net/sunge...
1133
1134
1135
  	printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x
  ",
  	       id, mii_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
1138
1139
1140
1141
1142
1143
  	for (i=0; (def = mii_phy_table[i]) != NULL; i++)
  		if ((id & def->phy_id_mask) == def->phy_id)
  			break;
  	/* Should never be NULL (we have a generic entry), but... */
  	if (def == NULL)
  		goto fail;
  
  	phy->def = def;
6aa20a223   Jeff Garzik   drivers/net: Trim...
1144

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
1146
1147
1148
1149
1150
1151
1152
  	return 0;
  fail:
  	phy->speed = 0;
  	phy->duplex = 0;
  	phy->pause = 0;
  	phy->advertising = 0;
  	return -ENODEV;
  }
19e2f6fe9   David S. Miller   net: Fix sungem_p...
1153
  EXPORT_SYMBOL(sungem_phy_probe);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
  MODULE_LICENSE("GPL");