xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/dec/tulip/media.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun 	drivers/net/ethernet/dec/tulip/media.c
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun 	Copyright 2000,2001  The Linux Kernel Team
5*4882a593Smuzhiyun 	Written/copyright 1994-2001 by Donald Becker.
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun 	This software may be used and distributed according to the terms
8*4882a593Smuzhiyun 	of the GNU General Public License, incorporated herein by reference.
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun 	Please submit bugs to http://bugzilla.kernel.org/ .
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/mii.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/pci.h>
17*4882a593Smuzhiyun #include "tulip.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
21*4882a593Smuzhiyun    met by back-to-back PCI I/O cycles, but we insert a delay to avoid
22*4882a593Smuzhiyun    "overclocking" issues or future 66Mhz PCI. */
23*4882a593Smuzhiyun #define mdio_delay() ioread32(mdio_addr)
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* Read and write the MII registers using software-generated serial
26*4882a593Smuzhiyun    MDIO protocol.  It is just different enough from the EEPROM protocol
27*4882a593Smuzhiyun    to not share code.  The maxium data clock rate is 2.5 Mhz. */
28*4882a593Smuzhiyun #define MDIO_SHIFT_CLK		0x10000
29*4882a593Smuzhiyun #define MDIO_DATA_WRITE0	0x00000
30*4882a593Smuzhiyun #define MDIO_DATA_WRITE1	0x20000
31*4882a593Smuzhiyun #define MDIO_ENB		0x00000 /* Ignore the 0x02000 databook setting. */
32*4882a593Smuzhiyun #define MDIO_ENB_IN		0x40000
33*4882a593Smuzhiyun #define MDIO_DATA_READ		0x80000
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static const unsigned char comet_miireg2offset[32] = {
36*4882a593Smuzhiyun 	0xB4, 0xB8, 0xBC, 0xC0,  0xC4, 0xC8, 0xCC, 0,  0,0,0,0,  0,0,0,0,
37*4882a593Smuzhiyun 	0,0xD0,0,0,  0,0,0,0,  0,0,0,0, 0, 0xD4, 0xD8, 0xDC, };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* MII transceiver control section.
41*4882a593Smuzhiyun    Read and write the MII registers using software-generated serial
42*4882a593Smuzhiyun    MDIO protocol.
43*4882a593Smuzhiyun    See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
44*4882a593Smuzhiyun    or DP83840A data sheet for more details.
45*4882a593Smuzhiyun    */
46*4882a593Smuzhiyun 
tulip_mdio_read(struct net_device * dev,int phy_id,int location)47*4882a593Smuzhiyun int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	struct tulip_private *tp = netdev_priv(dev);
50*4882a593Smuzhiyun 	int i;
51*4882a593Smuzhiyun 	int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location;
52*4882a593Smuzhiyun 	int retval = 0;
53*4882a593Smuzhiyun 	void __iomem *ioaddr = tp->base_addr;
54*4882a593Smuzhiyun 	void __iomem *mdio_addr = ioaddr + CSR9;
55*4882a593Smuzhiyun 	unsigned long flags;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	if (location & ~0x1f)
58*4882a593Smuzhiyun 		return 0xffff;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	if (tp->chip_id == COMET  &&  phy_id == 30) {
61*4882a593Smuzhiyun 		if (comet_miireg2offset[location])
62*4882a593Smuzhiyun 			return ioread32(ioaddr + comet_miireg2offset[location]);
63*4882a593Smuzhiyun 		return 0xffff;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	spin_lock_irqsave(&tp->mii_lock, flags);
67*4882a593Smuzhiyun 	if (tp->chip_id == LC82C168) {
68*4882a593Smuzhiyun 		iowrite32(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
69*4882a593Smuzhiyun 		ioread32(ioaddr + 0xA0);
70*4882a593Smuzhiyun 		ioread32(ioaddr + 0xA0);
71*4882a593Smuzhiyun 		for (i = 1000; i >= 0; --i) {
72*4882a593Smuzhiyun 			barrier();
73*4882a593Smuzhiyun 			if ( ! ((retval = ioread32(ioaddr + 0xA0)) & 0x80000000))
74*4882a593Smuzhiyun 				break;
75*4882a593Smuzhiyun 		}
76*4882a593Smuzhiyun 		spin_unlock_irqrestore(&tp->mii_lock, flags);
77*4882a593Smuzhiyun 		return retval & 0xffff;
78*4882a593Smuzhiyun 	}
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	/* Establish sync by sending at least 32 logic ones. */
81*4882a593Smuzhiyun 	for (i = 32; i >= 0; i--) {
82*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
83*4882a593Smuzhiyun 		mdio_delay();
84*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
85*4882a593Smuzhiyun 		mdio_delay();
86*4882a593Smuzhiyun 	}
87*4882a593Smuzhiyun 	/* Shift the read command bits out. */
88*4882a593Smuzhiyun 	for (i = 15; i >= 0; i--) {
89*4882a593Smuzhiyun 		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | dataval, mdio_addr);
92*4882a593Smuzhiyun 		mdio_delay();
93*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
94*4882a593Smuzhiyun 		mdio_delay();
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 	/* Read the two transition, 16 data, and wire-idle bits. */
97*4882a593Smuzhiyun 	for (i = 19; i > 0; i--) {
98*4882a593Smuzhiyun 		iowrite32(MDIO_ENB_IN, mdio_addr);
99*4882a593Smuzhiyun 		mdio_delay();
100*4882a593Smuzhiyun 		retval = (retval << 1) | ((ioread32(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
101*4882a593Smuzhiyun 		iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
102*4882a593Smuzhiyun 		mdio_delay();
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	spin_unlock_irqrestore(&tp->mii_lock, flags);
106*4882a593Smuzhiyun 	return (retval>>1) & 0xffff;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
tulip_mdio_write(struct net_device * dev,int phy_id,int location,int val)109*4882a593Smuzhiyun void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct tulip_private *tp = netdev_priv(dev);
112*4882a593Smuzhiyun 	int i;
113*4882a593Smuzhiyun 	int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff);
114*4882a593Smuzhiyun 	void __iomem *ioaddr = tp->base_addr;
115*4882a593Smuzhiyun 	void __iomem *mdio_addr = ioaddr + CSR9;
116*4882a593Smuzhiyun 	unsigned long flags;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (location & ~0x1f)
119*4882a593Smuzhiyun 		return;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	if (tp->chip_id == COMET && phy_id == 30) {
122*4882a593Smuzhiyun 		if (comet_miireg2offset[location])
123*4882a593Smuzhiyun 			iowrite32(val, ioaddr + comet_miireg2offset[location]);
124*4882a593Smuzhiyun 		return;
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	spin_lock_irqsave(&tp->mii_lock, flags);
128*4882a593Smuzhiyun 	if (tp->chip_id == LC82C168) {
129*4882a593Smuzhiyun 		iowrite32(cmd, ioaddr + 0xA0);
130*4882a593Smuzhiyun 		for (i = 1000; i >= 0; --i) {
131*4882a593Smuzhiyun 			barrier();
132*4882a593Smuzhiyun 			if ( ! (ioread32(ioaddr + 0xA0) & 0x80000000))
133*4882a593Smuzhiyun 				break;
134*4882a593Smuzhiyun 		}
135*4882a593Smuzhiyun 		spin_unlock_irqrestore(&tp->mii_lock, flags);
136*4882a593Smuzhiyun 		return;
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	/* Establish sync by sending 32 logic ones. */
140*4882a593Smuzhiyun 	for (i = 32; i >= 0; i--) {
141*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
142*4882a593Smuzhiyun 		mdio_delay();
143*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
144*4882a593Smuzhiyun 		mdio_delay();
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 	/* Shift the command bits out. */
147*4882a593Smuzhiyun 	for (i = 31; i >= 0; i--) {
148*4882a593Smuzhiyun 		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
149*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | dataval, mdio_addr);
150*4882a593Smuzhiyun 		mdio_delay();
151*4882a593Smuzhiyun 		iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
152*4882a593Smuzhiyun 		mdio_delay();
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun 	/* Clear out extra bits. */
155*4882a593Smuzhiyun 	for (i = 2; i > 0; i--) {
156*4882a593Smuzhiyun 		iowrite32(MDIO_ENB_IN, mdio_addr);
157*4882a593Smuzhiyun 		mdio_delay();
158*4882a593Smuzhiyun 		iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
159*4882a593Smuzhiyun 		mdio_delay();
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	spin_unlock_irqrestore(&tp->mii_lock, flags);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun /* Set up the transceiver control registers for the selected media type. */
tulip_select_media(struct net_device * dev,int startup)167*4882a593Smuzhiyun void tulip_select_media(struct net_device *dev, int startup)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	struct tulip_private *tp = netdev_priv(dev);
170*4882a593Smuzhiyun 	void __iomem *ioaddr = tp->base_addr;
171*4882a593Smuzhiyun 	struct mediatable *mtable = tp->mtable;
172*4882a593Smuzhiyun 	u32 new_csr6;
173*4882a593Smuzhiyun 	int i;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (mtable) {
176*4882a593Smuzhiyun 		struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
177*4882a593Smuzhiyun 		unsigned char *p = mleaf->leafdata;
178*4882a593Smuzhiyun 		switch (mleaf->type) {
179*4882a593Smuzhiyun 		case 0:					/* 21140 non-MII xcvr. */
180*4882a593Smuzhiyun 			if (tulip_debug > 1)
181*4882a593Smuzhiyun 				netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n",
182*4882a593Smuzhiyun 					   p[1]);
183*4882a593Smuzhiyun 			dev->if_port = p[0];
184*4882a593Smuzhiyun 			if (startup)
185*4882a593Smuzhiyun 				iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
186*4882a593Smuzhiyun 			iowrite32(p[1], ioaddr + CSR12);
187*4882a593Smuzhiyun 			new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
188*4882a593Smuzhiyun 			break;
189*4882a593Smuzhiyun 		case 2: case 4: {
190*4882a593Smuzhiyun 			u16 setup[5];
191*4882a593Smuzhiyun 			u32 csr13val, csr14val, csr15dir, csr15val;
192*4882a593Smuzhiyun 			for (i = 0; i < 5; i++)
193*4882a593Smuzhiyun 				setup[i] = get_u16(&p[i*2 + 1]);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 			dev->if_port = p[0] & MEDIA_MASK;
196*4882a593Smuzhiyun 			if (tulip_media_cap[dev->if_port] & MediaAlwaysFD)
197*4882a593Smuzhiyun 				tp->full_duplex = 1;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 			if (startup && mtable->has_reset) {
200*4882a593Smuzhiyun 				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
201*4882a593Smuzhiyun 				unsigned char *rst = rleaf->leafdata;
202*4882a593Smuzhiyun 				if (tulip_debug > 1)
203*4882a593Smuzhiyun 					netdev_dbg(dev, "Resetting the transceiver\n");
204*4882a593Smuzhiyun 				for (i = 0; i < rst[0]; i++)
205*4882a593Smuzhiyun 					iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
206*4882a593Smuzhiyun 			}
207*4882a593Smuzhiyun 			if (tulip_debug > 1)
208*4882a593Smuzhiyun 				netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n",
209*4882a593Smuzhiyun 					   medianame[dev->if_port],
210*4882a593Smuzhiyun 					   setup[0], setup[1]);
211*4882a593Smuzhiyun 			if (p[0] & 0x40) {	/* SIA (CSR13-15) setup values are provided. */
212*4882a593Smuzhiyun 				csr13val = setup[0];
213*4882a593Smuzhiyun 				csr14val = setup[1];
214*4882a593Smuzhiyun 				csr15dir = (setup[3]<<16) | setup[2];
215*4882a593Smuzhiyun 				csr15val = (setup[4]<<16) | setup[2];
216*4882a593Smuzhiyun 				iowrite32(0, ioaddr + CSR13);
217*4882a593Smuzhiyun 				iowrite32(csr14val, ioaddr + CSR14);
218*4882a593Smuzhiyun 				iowrite32(csr15dir, ioaddr + CSR15);	/* Direction */
219*4882a593Smuzhiyun 				iowrite32(csr15val, ioaddr + CSR15);	/* Data */
220*4882a593Smuzhiyun 				iowrite32(csr13val, ioaddr + CSR13);
221*4882a593Smuzhiyun 			} else {
222*4882a593Smuzhiyun 				csr13val = 1;
223*4882a593Smuzhiyun 				csr14val = 0;
224*4882a593Smuzhiyun 				csr15dir = (setup[0]<<16) | 0x0008;
225*4882a593Smuzhiyun 				csr15val = (setup[1]<<16) | 0x0008;
226*4882a593Smuzhiyun 				if (dev->if_port <= 4)
227*4882a593Smuzhiyun 					csr14val = t21142_csr14[dev->if_port];
228*4882a593Smuzhiyun 				if (startup) {
229*4882a593Smuzhiyun 					iowrite32(0, ioaddr + CSR13);
230*4882a593Smuzhiyun 					iowrite32(csr14val, ioaddr + CSR14);
231*4882a593Smuzhiyun 				}
232*4882a593Smuzhiyun 				iowrite32(csr15dir, ioaddr + CSR15);	/* Direction */
233*4882a593Smuzhiyun 				iowrite32(csr15val, ioaddr + CSR15);	/* Data */
234*4882a593Smuzhiyun 				if (startup) iowrite32(csr13val, ioaddr + CSR13);
235*4882a593Smuzhiyun 			}
236*4882a593Smuzhiyun 			if (tulip_debug > 1)
237*4882a593Smuzhiyun 				netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n",
238*4882a593Smuzhiyun 					   csr15dir, csr15val);
239*4882a593Smuzhiyun 			if (mleaf->type == 4)
240*4882a593Smuzhiyun 				new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
241*4882a593Smuzhiyun 			else
242*4882a593Smuzhiyun 				new_csr6 = 0x82420000;
243*4882a593Smuzhiyun 			break;
244*4882a593Smuzhiyun 		}
245*4882a593Smuzhiyun 		case 1: case 3: {
246*4882a593Smuzhiyun 			int phy_num = p[0];
247*4882a593Smuzhiyun 			int init_length = p[1];
248*4882a593Smuzhiyun 			u16 *misc_info, tmp_info;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 			dev->if_port = 11;
251*4882a593Smuzhiyun 			new_csr6 = 0x020E0000;
252*4882a593Smuzhiyun 			if (mleaf->type == 3) {	/* 21142 */
253*4882a593Smuzhiyun 				u16 *init_sequence = (u16*)(p+2);
254*4882a593Smuzhiyun 				u16 *reset_sequence = &((u16*)(p+3))[init_length];
255*4882a593Smuzhiyun 				int reset_length = p[2 + init_length*2];
256*4882a593Smuzhiyun 				misc_info = reset_sequence + reset_length;
257*4882a593Smuzhiyun 				if (startup) {
258*4882a593Smuzhiyun 					int timeout = 10;	/* max 1 ms */
259*4882a593Smuzhiyun 					for (i = 0; i < reset_length; i++)
260*4882a593Smuzhiyun 						iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 					/* flush posted writes */
263*4882a593Smuzhiyun 					ioread32(ioaddr + CSR15);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 					/* Sect 3.10.3 in DP83840A.pdf (p39) */
266*4882a593Smuzhiyun 					udelay(500);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 					/* Section 4.2 in DP83840A.pdf (p43) */
269*4882a593Smuzhiyun 					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
270*4882a593Smuzhiyun 					while (timeout-- &&
271*4882a593Smuzhiyun 						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
272*4882a593Smuzhiyun 						udelay(100);
273*4882a593Smuzhiyun 				}
274*4882a593Smuzhiyun 				for (i = 0; i < init_length; i++)
275*4882a593Smuzhiyun 					iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 				ioread32(ioaddr + CSR15);	/* flush posted writes */
278*4882a593Smuzhiyun 			} else {
279*4882a593Smuzhiyun 				u8 *init_sequence = p + 2;
280*4882a593Smuzhiyun 				u8 *reset_sequence = p + 3 + init_length;
281*4882a593Smuzhiyun 				int reset_length = p[2 + init_length];
282*4882a593Smuzhiyun 				misc_info = (u16*)(reset_sequence + reset_length);
283*4882a593Smuzhiyun 				if (startup) {
284*4882a593Smuzhiyun 					int timeout = 10;	/* max 1 ms */
285*4882a593Smuzhiyun 					iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
286*4882a593Smuzhiyun 					for (i = 0; i < reset_length; i++)
287*4882a593Smuzhiyun 						iowrite32(reset_sequence[i], ioaddr + CSR12);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 					/* flush posted writes */
290*4882a593Smuzhiyun 					ioread32(ioaddr + CSR12);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 					/* Sect 3.10.3 in DP83840A.pdf (p39) */
293*4882a593Smuzhiyun 					udelay(500);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 					/* Section 4.2 in DP83840A.pdf (p43) */
296*4882a593Smuzhiyun 					/* and IEEE 802.3 "22.2.4.1.1 Reset" */
297*4882a593Smuzhiyun 					while (timeout-- &&
298*4882a593Smuzhiyun 						(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
299*4882a593Smuzhiyun 						udelay(100);
300*4882a593Smuzhiyun 				}
301*4882a593Smuzhiyun 				for (i = 0; i < init_length; i++)
302*4882a593Smuzhiyun 					iowrite32(init_sequence[i], ioaddr + CSR12);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 				ioread32(ioaddr + CSR12);	/* flush posted writes */
305*4882a593Smuzhiyun 			}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 			tmp_info = get_u16(&misc_info[1]);
308*4882a593Smuzhiyun 			if (tmp_info)
309*4882a593Smuzhiyun 				tp->advertising[phy_num] = tmp_info | 1;
310*4882a593Smuzhiyun 			if (tmp_info && startup < 2) {
311*4882a593Smuzhiyun 				if (tp->mii_advertise == 0)
312*4882a593Smuzhiyun 					tp->mii_advertise = tp->advertising[phy_num];
313*4882a593Smuzhiyun 				if (tulip_debug > 1)
314*4882a593Smuzhiyun 					netdev_dbg(dev, " Advertising %04x on MII %d\n",
315*4882a593Smuzhiyun 						   tp->mii_advertise,
316*4882a593Smuzhiyun 						   tp->phys[phy_num]);
317*4882a593Smuzhiyun 				tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
318*4882a593Smuzhiyun 			}
319*4882a593Smuzhiyun 			break;
320*4882a593Smuzhiyun 		}
321*4882a593Smuzhiyun 		case 5: case 6: {
322*4882a593Smuzhiyun 			new_csr6 = 0; /* FIXME */
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 			if (startup && mtable->has_reset) {
325*4882a593Smuzhiyun 				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
326*4882a593Smuzhiyun 				unsigned char *rst = rleaf->leafdata;
327*4882a593Smuzhiyun 				if (tulip_debug > 1)
328*4882a593Smuzhiyun 					netdev_dbg(dev, "Resetting the transceiver\n");
329*4882a593Smuzhiyun 				for (i = 0; i < rst[0]; i++)
330*4882a593Smuzhiyun 					iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
331*4882a593Smuzhiyun 			}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 			break;
334*4882a593Smuzhiyun 		}
335*4882a593Smuzhiyun 		default:
336*4882a593Smuzhiyun 			netdev_dbg(dev, " Invalid media table selection %d\n",
337*4882a593Smuzhiyun 				   mleaf->type);
338*4882a593Smuzhiyun 			new_csr6 = 0x020E0000;
339*4882a593Smuzhiyun 		}
340*4882a593Smuzhiyun 		if (tulip_debug > 1)
341*4882a593Smuzhiyun 			netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n",
342*4882a593Smuzhiyun 				   medianame[dev->if_port],
343*4882a593Smuzhiyun 				   ioread32(ioaddr + CSR12) & 0xff);
344*4882a593Smuzhiyun 	} else if (tp->chip_id == LC82C168) {
345*4882a593Smuzhiyun 		if (startup && ! tp->medialock)
346*4882a593Smuzhiyun 			dev->if_port = tp->mii_cnt ? 11 : 0;
347*4882a593Smuzhiyun 		if (tulip_debug > 1)
348*4882a593Smuzhiyun 			netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n",
349*4882a593Smuzhiyun 				   ioread32(ioaddr + 0xB8),
350*4882a593Smuzhiyun 				   medianame[dev->if_port]);
351*4882a593Smuzhiyun 		if (tp->mii_cnt) {
352*4882a593Smuzhiyun 			new_csr6 = 0x810C0000;
353*4882a593Smuzhiyun 			iowrite32(0x0001, ioaddr + CSR15);
354*4882a593Smuzhiyun 			iowrite32(0x0201B07A, ioaddr + 0xB8);
355*4882a593Smuzhiyun 		} else if (startup) {
356*4882a593Smuzhiyun 			/* Start with 10mbps to do autonegotiation. */
357*4882a593Smuzhiyun 			iowrite32(0x32, ioaddr + CSR12);
358*4882a593Smuzhiyun 			new_csr6 = 0x00420000;
359*4882a593Smuzhiyun 			iowrite32(0x0001B078, ioaddr + 0xB8);
360*4882a593Smuzhiyun 			iowrite32(0x0201B078, ioaddr + 0xB8);
361*4882a593Smuzhiyun 		} else if (dev->if_port == 3  ||  dev->if_port == 5) {
362*4882a593Smuzhiyun 			iowrite32(0x33, ioaddr + CSR12);
363*4882a593Smuzhiyun 			new_csr6 = 0x01860000;
364*4882a593Smuzhiyun 			/* Trigger autonegotiation. */
365*4882a593Smuzhiyun 			iowrite32(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
366*4882a593Smuzhiyun 		} else {
367*4882a593Smuzhiyun 			iowrite32(0x32, ioaddr + CSR12);
368*4882a593Smuzhiyun 			new_csr6 = 0x00420000;
369*4882a593Smuzhiyun 			iowrite32(0x1F078, ioaddr + 0xB8);
370*4882a593Smuzhiyun 		}
371*4882a593Smuzhiyun 	} else {					/* Unknown chip type with no media table. */
372*4882a593Smuzhiyun 		if (tp->default_port == 0)
373*4882a593Smuzhiyun 			dev->if_port = tp->mii_cnt ? 11 : 3;
374*4882a593Smuzhiyun 		if (tulip_media_cap[dev->if_port] & MediaIsMII) {
375*4882a593Smuzhiyun 			new_csr6 = 0x020E0000;
376*4882a593Smuzhiyun 		} else if (tulip_media_cap[dev->if_port] & MediaIsFx) {
377*4882a593Smuzhiyun 			new_csr6 = 0x02860000;
378*4882a593Smuzhiyun 		} else
379*4882a593Smuzhiyun 			new_csr6 = 0x03860000;
380*4882a593Smuzhiyun 		if (tulip_debug > 1)
381*4882a593Smuzhiyun 			netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n",
382*4882a593Smuzhiyun 				   medianame[dev->if_port],
383*4882a593Smuzhiyun 				   ioread32(ioaddr + CSR12));
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	mdelay(1);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun /*
392*4882a593Smuzhiyun   Check the MII negotiated duplex and change the CSR6 setting if
393*4882a593Smuzhiyun   required.
394*4882a593Smuzhiyun   Return 0 if everything is OK.
395*4882a593Smuzhiyun   Return < 0 if the transceiver is missing or has no link beat.
396*4882a593Smuzhiyun   */
tulip_check_duplex(struct net_device * dev)397*4882a593Smuzhiyun int tulip_check_duplex(struct net_device *dev)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	struct tulip_private *tp = netdev_priv(dev);
400*4882a593Smuzhiyun 	unsigned int bmsr, lpa, negotiated, new_csr6;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
403*4882a593Smuzhiyun 	lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA);
404*4882a593Smuzhiyun 	if (tulip_debug > 1)
405*4882a593Smuzhiyun 		dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n",
406*4882a593Smuzhiyun 			 bmsr, lpa);
407*4882a593Smuzhiyun 	if (bmsr == 0xffff)
408*4882a593Smuzhiyun 		return -2;
409*4882a593Smuzhiyun 	if ((bmsr & BMSR_LSTATUS) == 0) {
410*4882a593Smuzhiyun 		int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
411*4882a593Smuzhiyun 		if ((new_bmsr & BMSR_LSTATUS) == 0) {
412*4882a593Smuzhiyun 			if (tulip_debug  > 1)
413*4882a593Smuzhiyun 				dev_info(&dev->dev,
414*4882a593Smuzhiyun 					 "No link beat on the MII interface, status %04x\n",
415*4882a593Smuzhiyun 					 new_bmsr);
416*4882a593Smuzhiyun 			return -1;
417*4882a593Smuzhiyun 		}
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun 	negotiated = lpa & tp->advertising[0];
420*4882a593Smuzhiyun 	tp->full_duplex = mii_duplex(tp->full_duplex_lock, negotiated);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	new_csr6 = tp->csr6;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	if (negotiated & LPA_100) new_csr6 &= ~TxThreshold;
425*4882a593Smuzhiyun 	else			  new_csr6 |= TxThreshold;
426*4882a593Smuzhiyun 	if (tp->full_duplex) new_csr6 |= FullDuplex;
427*4882a593Smuzhiyun 	else		     new_csr6 &= ~FullDuplex;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	if (new_csr6 != tp->csr6) {
430*4882a593Smuzhiyun 		tp->csr6 = new_csr6;
431*4882a593Smuzhiyun 		tulip_restart_rxtx(tp);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 		if (tulip_debug > 0)
434*4882a593Smuzhiyun 			dev_info(&dev->dev,
435*4882a593Smuzhiyun 				 "Setting %s-duplex based on MII#%d link partner capability of %04x\n",
436*4882a593Smuzhiyun 				 tp->full_duplex ? "full" : "half",
437*4882a593Smuzhiyun 				 tp->phys[0], lpa);
438*4882a593Smuzhiyun 		return 1;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	return 0;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
tulip_find_mii(struct net_device * dev,int board_idx)444*4882a593Smuzhiyun void tulip_find_mii(struct net_device *dev, int board_idx)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	struct tulip_private *tp = netdev_priv(dev);
447*4882a593Smuzhiyun 	int phyn, phy_idx = 0;
448*4882a593Smuzhiyun 	int mii_reg0;
449*4882a593Smuzhiyun 	int mii_advert;
450*4882a593Smuzhiyun 	unsigned int to_advert, new_bmcr, ane_switch;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	/* Find the connected MII xcvrs.
453*4882a593Smuzhiyun 	   Doing this in open() would allow detecting external xcvrs later,
454*4882a593Smuzhiyun 	   but takes much time. */
455*4882a593Smuzhiyun 	for (phyn = 1; phyn <= 32 && phy_idx < ARRAY_SIZE(tp->phys); phyn++) {
456*4882a593Smuzhiyun 		int phy = phyn & 0x1f;
457*4882a593Smuzhiyun 		int mii_status = tulip_mdio_read (dev, phy, MII_BMSR);
458*4882a593Smuzhiyun 		if ((mii_status & 0x8301) == 0x8001 ||
459*4882a593Smuzhiyun 		    ((mii_status & BMSR_100BASE4) == 0 &&
460*4882a593Smuzhiyun 		     (mii_status & 0x7800) != 0)) {
461*4882a593Smuzhiyun 			/* preserve Becker logic, gain indentation level */
462*4882a593Smuzhiyun 		} else {
463*4882a593Smuzhiyun 			continue;
464*4882a593Smuzhiyun 		}
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 		mii_reg0 = tulip_mdio_read (dev, phy, MII_BMCR);
467*4882a593Smuzhiyun 		mii_advert = tulip_mdio_read (dev, phy, MII_ADVERTISE);
468*4882a593Smuzhiyun 		ane_switch = 0;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		/* if not advertising at all, gen an
471*4882a593Smuzhiyun 		 * advertising value from the capability
472*4882a593Smuzhiyun 		 * bits in BMSR
473*4882a593Smuzhiyun 		 */
474*4882a593Smuzhiyun 		if ((mii_advert & ADVERTISE_ALL) == 0) {
475*4882a593Smuzhiyun 			unsigned int tmpadv = tulip_mdio_read (dev, phy, MII_BMSR);
476*4882a593Smuzhiyun 			mii_advert = ((tmpadv >> 6) & 0x3e0) | 1;
477*4882a593Smuzhiyun 		}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 		if (tp->mii_advertise) {
480*4882a593Smuzhiyun 			tp->advertising[phy_idx] =
481*4882a593Smuzhiyun 			to_advert = tp->mii_advertise;
482*4882a593Smuzhiyun 		} else if (tp->advertising[phy_idx]) {
483*4882a593Smuzhiyun 			to_advert = tp->advertising[phy_idx];
484*4882a593Smuzhiyun 		} else {
485*4882a593Smuzhiyun 			tp->advertising[phy_idx] =
486*4882a593Smuzhiyun 			tp->mii_advertise =
487*4882a593Smuzhiyun 			to_advert = mii_advert;
488*4882a593Smuzhiyun 		}
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 		tp->phys[phy_idx++] = phy;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 		pr_info("tulip%d:  MII transceiver #%d config %04x status %04x advertising %04x\n",
493*4882a593Smuzhiyun 			board_idx, phy, mii_reg0, mii_status, mii_advert);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 		/* Fixup for DLink with miswired PHY. */
496*4882a593Smuzhiyun 		if (mii_advert != to_advert) {
497*4882a593Smuzhiyun 			pr_debug("tulip%d:  Advertising %04x on PHY %d, previously advertising %04x\n",
498*4882a593Smuzhiyun 				 board_idx, to_advert, phy, mii_advert);
499*4882a593Smuzhiyun 			tulip_mdio_write (dev, phy, 4, to_advert);
500*4882a593Smuzhiyun 		}
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 		/* Enable autonegotiation: some boards default to off. */
503*4882a593Smuzhiyun 		if (tp->default_port == 0) {
504*4882a593Smuzhiyun 			new_bmcr = mii_reg0 | BMCR_ANENABLE;
505*4882a593Smuzhiyun 			if (new_bmcr != mii_reg0) {
506*4882a593Smuzhiyun 				new_bmcr |= BMCR_ANRESTART;
507*4882a593Smuzhiyun 				ane_switch = 1;
508*4882a593Smuzhiyun 			}
509*4882a593Smuzhiyun 		}
510*4882a593Smuzhiyun 		/* ...or disable nway, if forcing media */
511*4882a593Smuzhiyun 		else {
512*4882a593Smuzhiyun 			new_bmcr = mii_reg0 & ~BMCR_ANENABLE;
513*4882a593Smuzhiyun 			if (new_bmcr != mii_reg0)
514*4882a593Smuzhiyun 				ane_switch = 1;
515*4882a593Smuzhiyun 		}
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 		/* clear out bits we never want at this point */
518*4882a593Smuzhiyun 		new_bmcr &= ~(BMCR_CTST | BMCR_FULLDPLX | BMCR_ISOLATE |
519*4882a593Smuzhiyun 			      BMCR_PDOWN | BMCR_SPEED100 | BMCR_LOOPBACK |
520*4882a593Smuzhiyun 			      BMCR_RESET);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 		if (tp->full_duplex)
523*4882a593Smuzhiyun 			new_bmcr |= BMCR_FULLDPLX;
524*4882a593Smuzhiyun 		if (tulip_media_cap[tp->default_port] & MediaIs100)
525*4882a593Smuzhiyun 			new_bmcr |= BMCR_SPEED100;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 		if (new_bmcr != mii_reg0) {
528*4882a593Smuzhiyun 			/* some phys need the ANE switch to
529*4882a593Smuzhiyun 			 * happen before forced media settings
530*4882a593Smuzhiyun 			 * will "take."  However, we write the
531*4882a593Smuzhiyun 			 * same value twice in order not to
532*4882a593Smuzhiyun 			 * confuse the sane phys.
533*4882a593Smuzhiyun 			 */
534*4882a593Smuzhiyun 			if (ane_switch) {
535*4882a593Smuzhiyun 				tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
536*4882a593Smuzhiyun 				udelay (10);
537*4882a593Smuzhiyun 			}
538*4882a593Smuzhiyun 			tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
539*4882a593Smuzhiyun 		}
540*4882a593Smuzhiyun 	}
541*4882a593Smuzhiyun 	tp->mii_cnt = phy_idx;
542*4882a593Smuzhiyun 	if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
543*4882a593Smuzhiyun 		pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n",
544*4882a593Smuzhiyun 			board_idx);
545*4882a593Smuzhiyun 		tp->phys[0] = 1;
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun }
548