xref: /minix3/minix/drivers/net/dp8390/rtl8029.c (revision 3913e49004e638c0cef3eacd49d32f7ec05ff084)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc rtl8029.c
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc Initialization of PCI DP8390-based ethernet cards
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc Created:	April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
7433d6423SLionel Sambuc */
8433d6423SLionel Sambuc 
9433d6423SLionel Sambuc #include <minix/drivers.h>
10*3913e490SDavid van Moolenbroek #include <minix/netdriver.h>
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include <stdlib.h>
13433d6423SLionel Sambuc #include <sys/types.h>
14433d6423SLionel Sambuc #include <net/gen/ether.h>
15433d6423SLionel Sambuc #include <net/gen/eth_io.h>
16433d6423SLionel Sambuc #include <machine/pci.h>
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc #include "assert.h"
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc #include "local.h"
21433d6423SLionel Sambuc #include "dp8390.h"
22433d6423SLionel Sambuc #include "rtl8029.h"
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc static void rtl_init(struct dpeth *dep);
25433d6423SLionel Sambuc #if 0
26433d6423SLionel Sambuc static u16_t get_ee_word(dpeth_t *dep, int a);
27433d6423SLionel Sambuc static void ee_wen(dpeth_t *dep);
28433d6423SLionel Sambuc static void set_ee_word(dpeth_t *dep, int a, u16_t w);
29433d6423SLionel Sambuc static void ee_wds(dpeth_t *dep);
30433d6423SLionel Sambuc #endif
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc int rtl_probe(dep, skip)
33433d6423SLionel Sambuc struct dpeth *dep;
34433d6423SLionel Sambuc int skip;
35433d6423SLionel Sambuc {
36433d6423SLionel Sambuc 	int r, devind;
37433d6423SLionel Sambuc 	u16_t vid, did;
38433d6423SLionel Sambuc 	u32_t bar;
39433d6423SLionel Sambuc 	u8_t ilr;
40433d6423SLionel Sambuc 	char *dname;
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc 	pci_init();
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc 	r= pci_first_dev(&devind, &vid, &did);
45433d6423SLionel Sambuc 	if (r == 0)
46433d6423SLionel Sambuc 		return 0;
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc 	while (skip--)
49433d6423SLionel Sambuc 	{
50433d6423SLionel Sambuc 		r= pci_next_dev(&devind, &vid, &did);
51433d6423SLionel Sambuc 		if (!r)
52433d6423SLionel Sambuc 			return 0;
53433d6423SLionel Sambuc 	}
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc 	dname= pci_dev_name(vid, did);
56433d6423SLionel Sambuc 	if (!dname)
57433d6423SLionel Sambuc 		dname= "unknown device";
58433d6423SLionel Sambuc 	printf("%s: %s (%04X/%04X) at %s\n",
59433d6423SLionel Sambuc 		dep->de_name, dname, vid, did, pci_slot_name(devind));
60433d6423SLionel Sambuc         if(pci_reserve_ok(devind) != OK)
61433d6423SLionel Sambuc                return 0;
62433d6423SLionel Sambuc 	/* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
63433d6423SLionel Sambuc 	bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc 	if (bar < 0x400)
66433d6423SLionel Sambuc 		panic("base address is not properly configured");
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc 	dep->de_base_port= bar;
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc 	ilr= pci_attr_r8(devind, PCI_ILR);
71433d6423SLionel Sambuc 	dep->de_irq= ilr;
72433d6423SLionel Sambuc 	if (debug)
73433d6423SLionel Sambuc 	{
74433d6423SLionel Sambuc 		printf("%s: using I/O address 0x%lx, IRQ %d\n",
75433d6423SLionel Sambuc 			dep->de_name, (unsigned long)bar, ilr);
76433d6423SLionel Sambuc 	}
77433d6423SLionel Sambuc 	dep->de_initf= rtl_init;
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc 	return TRUE;
80433d6423SLionel Sambuc }
81433d6423SLionel Sambuc 
82433d6423SLionel Sambuc static void rtl_init(dep)
83433d6423SLionel Sambuc dpeth_t *dep;
84433d6423SLionel Sambuc {
85433d6423SLionel Sambuc 	u8_t reg_a, reg_b, cr, config0, config2, config3;
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc #if DEBUG
88433d6423SLionel Sambuc 	printf("rtl_init called\n");
89433d6423SLionel Sambuc #endif
90433d6423SLionel Sambuc 	ne_init(dep);
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc 	/* ID */
93433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P0);
94433d6423SLionel Sambuc 	reg_a = inb_reg0(dep, DP_DUM1);
95433d6423SLionel Sambuc 	reg_b = inb_reg0(dep, DP_DUM2);
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc #if DEBUG
98433d6423SLionel Sambuc 	printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
99433d6423SLionel Sambuc #endif
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P3);
102433d6423SLionel Sambuc 	config0 = inb_reg3(dep, 3);
103433d6423SLionel Sambuc 	config2 = inb_reg3(dep, 5);
104433d6423SLionel Sambuc 	config3 = inb_reg3(dep, 6);
105433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P0);
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc #if DEBUG
108433d6423SLionel Sambuc 	printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
109433d6423SLionel Sambuc 		config0, config2, config3);
110433d6423SLionel Sambuc #endif
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc 	if (getenv("RTL8029FD"))
113433d6423SLionel Sambuc 	{
114433d6423SLionel Sambuc 		printf("rtl_init: setting full-duplex mode\n");
115433d6423SLionel Sambuc 		outb_reg0(dep, DP_CR, CR_PS_P3);
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc 		cr= inb_reg3(dep, 1);
118433d6423SLionel Sambuc 		outb_reg3(dep, 1, cr | 0xc0);
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc 		outb_reg3(dep, 6, config3 | 0x40);
121433d6423SLionel Sambuc 		config3 = inb_reg3(dep, 6);
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 		config2= inb_reg3(dep, 5);
124433d6423SLionel Sambuc 		outb_reg3(dep, 5, config2 | 0x20);
125433d6423SLionel Sambuc 		config2= inb_reg3(dep, 5);
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc 		outb_reg3(dep, 1, cr);
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc 		outb_reg0(dep, DP_CR, CR_PS_P0);
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc #if DEBUG
132433d6423SLionel Sambuc 		printf("rtl_init: config 2 = %x\n", config2);
133433d6423SLionel Sambuc 		printf("rtl_init: config 3 = %x\n", config3);
134433d6423SLionel Sambuc #endif
135433d6423SLionel Sambuc 	}
136433d6423SLionel Sambuc 
137433d6423SLionel Sambuc #if 0
138433d6423SLionel Sambuc 	for (i= 0; i<64; i++)
139433d6423SLionel Sambuc 		printf("%x ", get_ee_word(dep, i));
140433d6423SLionel Sambuc 	printf("\n");
141433d6423SLionel Sambuc #endif
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc #if 0
144433d6423SLionel Sambuc 	if (getenv("RTL8029MN"))
145433d6423SLionel Sambuc 	{
146433d6423SLionel Sambuc 		ee_wen(dep);
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 		set_ee_word(dep, 0x78/2, 0x10ec);
149433d6423SLionel Sambuc 		set_ee_word(dep, 0x7A/2, 0x8029);
150433d6423SLionel Sambuc 		set_ee_word(dep, 0x7C/2, 0x10ec);
151433d6423SLionel Sambuc 		set_ee_word(dep, 0x7E/2, 0x8029);
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc 		ee_wds(dep);
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc 		assert(get_ee_word(dep, 0x78/2) == 0x10ec);
156433d6423SLionel Sambuc 		assert(get_ee_word(dep, 0x7A/2) == 0x8029);
157433d6423SLionel Sambuc 		assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
158433d6423SLionel Sambuc 		assert(get_ee_word(dep, 0x7E/2) == 0x8029);
159433d6423SLionel Sambuc 	}
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc 	if (getenv("RTL8029XXX"))
162433d6423SLionel Sambuc 	{
163433d6423SLionel Sambuc 		ee_wen(dep);
164433d6423SLionel Sambuc 
165433d6423SLionel Sambuc 		set_ee_word(dep, 0x76/2, 0x8029);
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc 		ee_wds(dep);
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 		assert(get_ee_word(dep, 0x76/2) == 0x8029);
170433d6423SLionel Sambuc 	}
171433d6423SLionel Sambuc #endif
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc #if 0
175433d6423SLionel Sambuc static u16_t get_ee_word(dep, a)
176433d6423SLionel Sambuc dpeth_t *dep;
177433d6423SLionel Sambuc int a;
178433d6423SLionel Sambuc {
179433d6423SLionel Sambuc 	int b, i, cmd;
180433d6423SLionel Sambuc 	u16_t w;
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P3);	/* Bank 3 */
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc 	/* Switch to 9346 mode and enable CS */
185433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc 	cmd= 0x180 | (a & 0x3f);	/* 1 1 0 a5 a4 a3 a2 a1 a0 */
188433d6423SLionel Sambuc 	for (i= 8; i >= 0; i--)
189433d6423SLionel Sambuc 	{
190433d6423SLionel Sambuc 		b= (cmd & (1 << i));
191433d6423SLionel Sambuc 		b= (b ? 2 : 0);
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc 		/* Cmd goes out on the rising edge of the clock */
194433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | b);
195433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
196433d6423SLionel Sambuc 	}
197433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);	/* End of cmd */
198433d6423SLionel Sambuc 
199433d6423SLionel Sambuc 	w= 0;
200433d6423SLionel Sambuc 	for (i= 0; i<16; i++)
201433d6423SLionel Sambuc 	{
202433d6423SLionel Sambuc 		w <<= 1;
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc 		/* Data is shifted out on the rising edge. Read at the
205433d6423SLionel Sambuc 		 * falling edge.
206433d6423SLionel Sambuc 		 */
207433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
208433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | b);
209433d6423SLionel Sambuc 		b= inb_reg3(dep, 1);
210433d6423SLionel Sambuc 		w |= (b & 1);
211433d6423SLionel Sambuc 	}
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80);		/* drop CS */
214433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x00);		/* back to normal */
215433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P0);	/* back to bank 0 */
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc 	return w;
218433d6423SLionel Sambuc }
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc static void ee_wen(dep)
221433d6423SLionel Sambuc dpeth_t *dep;
222433d6423SLionel Sambuc {
223433d6423SLionel Sambuc 	int b, i, cmd;
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P3);	/* Bank 3 */
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc 	/* Switch to 9346 mode and enable CS */
228433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);
229433d6423SLionel Sambuc 
230433d6423SLionel Sambuc 	cmd= 0x130;		/* 1 0 0 1 1 x x x x */
231433d6423SLionel Sambuc 	for (i= 8; i >= 0; i--)
232433d6423SLionel Sambuc 	{
233433d6423SLionel Sambuc 		b= (cmd & (1 << i));
234433d6423SLionel Sambuc 		b= (b ? 2 : 0);
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc 		/* Cmd goes out on the rising edge of the clock */
237433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | b);
238433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
239433d6423SLionel Sambuc 	}
240433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);	/* End of cmd */
241433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80);	/* Drop CS */
242433d6423SLionel Sambuc 	micro_delay(1);			/* Is this required? */
243433d6423SLionel Sambuc }
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc static void set_ee_word(dep, a, w)
246433d6423SLionel Sambuc dpeth_t *dep;
247433d6423SLionel Sambuc int a;
248433d6423SLionel Sambuc u16_t w;
249433d6423SLionel Sambuc {
250433d6423SLionel Sambuc 	int b, i, cmd;
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);		/* Set CS */
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc 	cmd= 0x140 | (a & 0x3f);		/* 1 0 1 a5 a4 a3 a2 a1 a0 */
255433d6423SLionel Sambuc 	for (i= 8; i >= 0; i--)
256433d6423SLionel Sambuc 	{
257433d6423SLionel Sambuc 		b= (cmd & (1 << i));
258433d6423SLionel Sambuc 		b= (b ? 2 : 0);
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc 		/* Cmd goes out on the rising edge of the clock */
261433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | b);
262433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
263433d6423SLionel Sambuc 	}
264433d6423SLionel Sambuc 	for (i= 15; i >= 0; i--)
265433d6423SLionel Sambuc 	{
266433d6423SLionel Sambuc 		b= (w & (1 << i));
267433d6423SLionel Sambuc 		b= (b ? 2 : 0);
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 		/* Cmd goes out on the rising edge of the clock */
270433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | b);
271433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
272433d6423SLionel Sambuc 	}
273433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);	/* End of data */
274433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80);	/* Drop CS */
275433d6423SLionel Sambuc 	micro_delay(1);			/* Is this required? */
276433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);		/* Set CS */
277433d6423SLionel Sambuc 	for (i= 0; i<10000; i++)
278433d6423SLionel Sambuc 	{
279433d6423SLionel Sambuc 		if (inb_reg3(dep, 1) & 1)
280433d6423SLionel Sambuc 			break;
281433d6423SLionel Sambuc 		micro_delay(1);
282433d6423SLionel Sambuc 	}
283433d6423SLionel Sambuc 	if (!(inb_reg3(dep, 1) & 1))
284433d6423SLionel Sambuc 		panic("set_ee_word: device remains busy");
285433d6423SLionel Sambuc }
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc static void ee_wds(dep)
288433d6423SLionel Sambuc dpeth_t *dep;
289433d6423SLionel Sambuc {
290433d6423SLionel Sambuc 	int b, i, cmd;
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P3);	/* Bank 3 */
293433d6423SLionel Sambuc 
294433d6423SLionel Sambuc 	/* Switch to 9346 mode and enable CS */
295433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);
296433d6423SLionel Sambuc 
297433d6423SLionel Sambuc 	cmd= 0x100;		/* 1 0 0 0 0 x x x x */
298433d6423SLionel Sambuc 	for (i= 8; i >= 0; i--)
299433d6423SLionel Sambuc 	{
300433d6423SLionel Sambuc 		b= (cmd & (1 << i));
301433d6423SLionel Sambuc 		b= (b ? 2 : 0);
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc 		/* Cmd goes out on the rising edge of the clock */
304433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | b);
305433d6423SLionel Sambuc 		outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
306433d6423SLionel Sambuc 	}
307433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80 | 0x8);	/* End of cmd */
308433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x80);	/* Drop CS */
309433d6423SLionel Sambuc 	outb_reg3(dep, 1, 0x00);		/* back to normal */
310433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P0);	/* back to bank 0 */
311433d6423SLionel Sambuc }
312433d6423SLionel Sambuc #endif
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc /*
315433d6423SLionel Sambuc  * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $
316433d6423SLionel Sambuc  */
317