3.1.7 branch.
[minix.git] / drivers / dp8390 / rtl8029.c
blobb3b47e37b37075f29f560b13d9871f901a8cb9a1
1 /*
2 rtl8029.c
4 Initialization of PCI DP8390-based ethernet cards
6 Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
7 */
9 #include <minix/drivers.h>
11 #include <stdlib.h>
12 #include <sys/types.h>
13 #include <net/gen/ether.h>
14 #include <net/gen/eth_io.h>
15 #include <machine/pci.h>
17 #include "assert.h"
19 #include "local.h"
20 #include "dp8390.h"
21 #include "rtl8029.h"
23 #if ENABLE_PCI
25 PRIVATE struct pcitab
27 u16_t vid;
28 u16_t did;
29 int checkclass;
30 } pcitab[]=
32 { 0x10ec, 0x8029, 0 }, /* Realtek RTL8029 */
34 { 0x0000, 0x0000, 0 }
37 _PROTOTYPE( static void rtl_init, (struct dpeth *dep) );
38 #if 0
39 _PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a) );
40 _PROTOTYPE( static void ee_wen, (dpeth_t *dep) );
41 _PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, u16_t w) );
42 _PROTOTYPE( static void ee_wds, (dpeth_t *dep) );
43 #endif
45 PUBLIC int rtl_probe(dep, skip)
46 struct dpeth *dep;
47 int skip;
49 int i, r, devind, just_one;
50 u16_t vid, did;
51 u32_t bar;
52 u8_t ilr;
53 char *dname;
55 pci_init();
57 if ((dep->de_pcibus | dep->de_pcidev | dep->de_pcifunc) != 0)
59 /* Look for specific PCI device */
60 r= pci_find_dev(dep->de_pcibus, dep->de_pcidev,
61 dep->de_pcifunc, &devind);
62 if (r == 0)
64 printf("%s: no PCI found at %d.%d.%d\n",
65 dep->de_name, dep->de_pcibus,
66 dep->de_pcidev, dep->de_pcifunc);
67 return 0;
69 pci_ids(devind, &vid, &did);
70 just_one= TRUE;
72 else
74 r= pci_first_dev(&devind, &vid, &did);
75 if (r == 0)
76 return 0;
77 just_one= FALSE;
80 for(;;)
82 for (i= 0; pcitab[i].vid != 0 || pcitab[i].did != 0; i++)
84 if (pcitab[i].vid != vid)
85 continue;
86 if (pcitab[i].did != did)
87 continue;
88 if (pcitab[i].checkclass) {
89 panic("rtl_probe: class check not implemented");
91 break;
93 if (pcitab[i].vid != 0 || pcitab[i].did != 0) {
94 if (just_one || !skip)
95 break;
96 skip--;
99 if (just_one)
101 printf(
102 "%s: wrong PCI device (%04X/%04X) found at %d.%d.%d\n",
103 dep->de_name, vid, did,
104 dep->de_pcibus,
105 dep->de_pcidev, dep->de_pcifunc);
106 return 0;
109 r= pci_next_dev(&devind, &vid, &did);
110 if (!r)
111 return 0;
114 dname= pci_dev_name(vid, did);
115 if (!dname)
116 dname= "unknown device";
117 printf("%s: %s (%04X/%04X) at %s\n",
118 dep->de_name, dname, vid, did, pci_slot_name(devind));
119 if(pci_reserve_ok(devind) != OK)
120 return 0;
121 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
122 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
124 if (bar < 0x400)
125 panic("base address is not properly configured");
127 dep->de_base_port= bar;
129 ilr= pci_attr_r8(devind, PCI_ILR);
130 dep->de_irq= ilr;
131 if (debug)
133 printf("%s: using I/O address 0x%lx, IRQ %d\n",
134 dep->de_name, (unsigned long)bar, ilr);
136 dep->de_initf= rtl_init;
138 return TRUE;
141 static void rtl_init(dep)
142 dpeth_t *dep;
144 u8_t reg_a, reg_b, cr, config0, config2, config3;
145 int i;
147 #if DEBUG
148 printf("rtl_init called\n");
149 #endif
150 ne_init(dep);
152 /* ID */
153 outb_reg0(dep, DP_CR, CR_PS_P0);
154 reg_a = inb_reg0(dep, DP_DUM1);
155 reg_b = inb_reg0(dep, DP_DUM2);
157 #if DEBUG
158 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
159 #endif
161 outb_reg0(dep, DP_CR, CR_PS_P3);
162 config0 = inb_reg3(dep, 3);
163 config2 = inb_reg3(dep, 5);
164 config3 = inb_reg3(dep, 6);
165 outb_reg0(dep, DP_CR, CR_PS_P0);
167 #if DEBUG
168 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
169 config0, config2, config3);
170 #endif
172 if (getenv("RTL8029FD"))
174 printf("rtl_init: setting full-duplex mode\n");
175 outb_reg0(dep, DP_CR, CR_PS_P3);
177 cr= inb_reg3(dep, 1);
178 outb_reg3(dep, 1, cr | 0xc0);
180 outb_reg3(dep, 6, config3 | 0x40);
181 config3 = inb_reg3(dep, 6);
183 config2= inb_reg3(dep, 5);
184 outb_reg3(dep, 5, config2 | 0x20);
185 config2= inb_reg3(dep, 5);
187 outb_reg3(dep, 1, cr);
189 outb_reg0(dep, DP_CR, CR_PS_P0);
191 #if DEBUG
192 printf("rtl_init: config 2 = %x\n", config2);
193 printf("rtl_init: config 3 = %x\n", config3);
194 #endif
197 #if DEBUG
198 for (i= 0; i<64; i++)
199 printf("%x ", get_ee_word(dep, i));
200 printf("\n");
201 #endif
203 #if 0
204 if (getenv("RTL8029MN"))
206 ee_wen(dep);
208 set_ee_word(dep, 0x78/2, 0x10ec);
209 set_ee_word(dep, 0x7A/2, 0x8029);
210 set_ee_word(dep, 0x7C/2, 0x10ec);
211 set_ee_word(dep, 0x7E/2, 0x8029);
213 ee_wds(dep);
215 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
216 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
217 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
218 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
221 if (getenv("RTL8029XXX"))
223 ee_wen(dep);
225 set_ee_word(dep, 0x76/2, 0x8029);
227 ee_wds(dep);
229 assert(get_ee_word(dep, 0x76/2) == 0x8029);
231 #endif
234 #if 0
235 static u16_t get_ee_word(dep, a)
236 dpeth_t *dep;
237 int a;
239 int b, i, cmd;
240 u16_t w;
242 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
244 /* Switch to 9346 mode and enable CS */
245 outb_reg3(dep, 1, 0x80 | 0x8);
247 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
248 for (i= 8; i >= 0; i--)
250 b= (cmd & (1 << i));
251 b= (b ? 2 : 0);
253 /* Cmd goes out on the rising edge of the clock */
254 outb_reg3(dep, 1, 0x80 | 0x8 | b);
255 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
257 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
259 w= 0;
260 for (i= 0; i<16; i++)
262 w <<= 1;
264 /* Data is shifted out on the rising edge. Read at the
265 * falling edge.
267 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
268 outb_reg3(dep, 1, 0x80 | 0x8 | b);
269 b= inb_reg3(dep, 1);
270 w |= (b & 1);
273 outb_reg3(dep, 1, 0x80); /* drop CS */
274 outb_reg3(dep, 1, 0x00); /* back to normal */
275 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
277 return w;
280 static void ee_wen(dep)
281 dpeth_t *dep;
283 int b, i, cmd;
285 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
287 /* Switch to 9346 mode and enable CS */
288 outb_reg3(dep, 1, 0x80 | 0x8);
290 cmd= 0x130; /* 1 0 0 1 1 x x x x */
291 for (i= 8; i >= 0; i--)
293 b= (cmd & (1 << i));
294 b= (b ? 2 : 0);
296 /* Cmd goes out on the rising edge of the clock */
297 outb_reg3(dep, 1, 0x80 | 0x8 | b);
298 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
300 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
301 outb_reg3(dep, 1, 0x80); /* Drop CS */
302 micro_delay(1); /* Is this required? */
305 static void set_ee_word(dep, a, w)
306 dpeth_t *dep;
307 int a;
308 u16_t w;
310 int b, i, cmd;
312 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
314 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
315 for (i= 8; i >= 0; i--)
317 b= (cmd & (1 << i));
318 b= (b ? 2 : 0);
320 /* Cmd goes out on the rising edge of the clock */
321 outb_reg3(dep, 1, 0x80 | 0x8 | b);
322 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
324 for (i= 15; i >= 0; i--)
326 b= (w & (1 << i));
327 b= (b ? 2 : 0);
329 /* Cmd goes out on the rising edge of the clock */
330 outb_reg3(dep, 1, 0x80 | 0x8 | b);
331 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
333 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
334 outb_reg3(dep, 1, 0x80); /* Drop CS */
335 micro_delay(1); /* Is this required? */
336 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
337 for (i= 0; i<10000; i++)
339 if (inb_reg3(dep, 1) & 1)
340 break;
341 micro_delay(1);
343 if (!(inb_reg3(dep, 1) & 1))
344 panic("set_ee_word: device remains busy");
347 static void ee_wds(dep)
348 dpeth_t *dep;
350 int b, i, cmd;
352 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
354 /* Switch to 9346 mode and enable CS */
355 outb_reg3(dep, 1, 0x80 | 0x8);
357 cmd= 0x100; /* 1 0 0 0 0 x x x x */
358 for (i= 8; i >= 0; i--)
360 b= (cmd & (1 << i));
361 b= (b ? 2 : 0);
363 /* Cmd goes out on the rising edge of the clock */
364 outb_reg3(dep, 1, 0x80 | 0x8 | b);
365 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
367 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
368 outb_reg3(dep, 1, 0x80); /* Drop CS */
369 outb_reg3(dep, 1, 0x00); /* back to normal */
370 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
372 #endif
374 #endif /* ENABLE_PCI */
377 * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $