source: trunk/minix/drivers/dp8390/rtl8029.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 7.6 KB
Line 
1/*
2rtl8029.c
3
4Initialization of PCI DP8390-based ethernet cards
5
6Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
7*/
8
9#include "../drivers.h"
10
11#include <stdlib.h>
12#include <sys/types.h>
13#include <net/gen/ether.h>
14#include <net/gen/eth_io.h>
15#include <ibm/pci.h>
16
17#include "assert.h"
18
19#include "local.h"
20#include "dp8390.h"
21#include "rtl8029.h"
22
23#if ENABLE_PCI
24
25#define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1)
26
27PRIVATE struct pcitab
28{
29 u16_t vid;
30 u16_t did;
31 int checkclass;
32} pcitab[]=
33{
34 { 0x10ec, 0x8029, 0 }, /* Realtek RTL8029 */
35
36 { 0x0000, 0x0000, 0 }
37};
38
39_PROTOTYPE( static void rtl_init, (struct dpeth *dep) );
40_PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a) );
41_PROTOTYPE( static void ee_wen, (dpeth_t *dep) );
42_PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w) );
43_PROTOTYPE( static void ee_wds, (dpeth_t *dep) );
44_PROTOTYPE( static void micro_delay, (unsigned long usecs) );
45
46PUBLIC int rtl_probe(dep)
47struct dpeth *dep;
48{
49 int i, r, devind, just_one;
50 u16_t vid, did;
51 u32_t bar;
52 u8_t ilr;
53 char *dname;
54
55 pci_init();
56
57 if ((dep->de_pcibus | dep->de_pcidev | dep->de_pcifunc) != 0)
58 {
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)
63 {
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;
68 }
69 pci_ids(devind, &vid, &did);
70 just_one= TRUE;
71 }
72 else
73 {
74 r= pci_first_dev(&devind, &vid, &did);
75 if (r == 0)
76 return 0;
77 just_one= FALSE;
78 }
79
80 for(;;)
81 {
82 for (i= 0; pcitab[i].vid != 0; i++)
83 {
84 if (pcitab[i].vid != vid)
85 continue;
86 if (pcitab[i].did != did)
87 continue;
88 if (pcitab[i].checkclass)
89 {
90 panic("",
91 "rtl_probe: class check not implemented",
92 NO_NUM);
93 }
94 break;
95 }
96 if (pcitab[i].vid != 0)
97 break;
98
99 if (just_one)
100 {
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;
107 }
108
109 r= pci_next_dev(&devind, &vid, &did);
110 if (!r)
111 return 0;
112 }
113
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 pci_reserve(devind);
120 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
121 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
122
123 if (bar < 0x400)
124 panic("", "base address is not properly configured", NO_NUM);
125
126 dep->de_base_port= bar;
127
128 ilr= pci_attr_r8(devind, PCI_ILR);
129 dep->de_irq= ilr;
130 if (debug)
131 {
132 printf("%s: using I/O address 0x%lx, IRQ %d\n",
133 dep->de_name, (unsigned long)bar, ilr);
134 }
135 dep->de_initf= rtl_init;
136
137 return TRUE;
138}
139
140static void rtl_init(dep)
141dpeth_t *dep;
142{
143 u8_t reg_a, reg_b, cr, config0, config2, config3;
144 int i;
145
146#if DEBUG
147 printf("rtl_init called\n");
148#endif
149 ne_init(dep);
150
151 /* ID */
152 outb_reg0(dep, DP_CR, CR_PS_P0);
153 reg_a = inb_reg0(dep, DP_DUM1);
154 reg_b = inb_reg0(dep, DP_DUM2);
155
156#if DEBUG
157 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
158#endif
159
160 outb_reg0(dep, DP_CR, CR_PS_P3);
161 config0 = inb_reg3(dep, 3);
162 config2 = inb_reg3(dep, 5);
163 config3 = inb_reg3(dep, 6);
164 outb_reg0(dep, DP_CR, CR_PS_P0);
165
166#if DEBUG
167 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
168 config0, config2, config3);
169#endif
170
171 if (getenv("RTL8029FD"))
172 {
173 printf("rtl_init: setting full-duplex mode\n");
174 outb_reg0(dep, DP_CR, CR_PS_P3);
175
176 cr= inb_reg3(dep, 1);
177 outb_reg3(dep, 1, cr | 0xc0);
178
179 outb_reg3(dep, 6, config3 | 0x40);
180 config3 = inb_reg3(dep, 6);
181
182 config2= inb_reg3(dep, 5);
183 outb_reg3(dep, 5, config2 | 0x20);
184 config2= inb_reg3(dep, 5);
185
186 outb_reg3(dep, 1, cr);
187
188 outb_reg0(dep, DP_CR, CR_PS_P0);
189
190#if DEBUG
191 printf("rtl_init: config 2 = %x\n", config2);
192 printf("rtl_init: config 3 = %x\n", config3);
193#endif
194 }
195
196#if DEBUG
197 for (i= 0; i<64; i++)
198 printf("%x ", get_ee_word(dep, i));
199 printf("\n");
200#endif
201
202 if (getenv("RTL8029MN"))
203 {
204 ee_wen(dep);
205
206 set_ee_word(dep, 0x78/2, 0x10ec);
207 set_ee_word(dep, 0x7A/2, 0x8029);
208 set_ee_word(dep, 0x7C/2, 0x10ec);
209 set_ee_word(dep, 0x7E/2, 0x8029);
210
211 ee_wds(dep);
212
213 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
214 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
215 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
216 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
217 }
218
219 if (getenv("RTL8029XXX"))
220 {
221 ee_wen(dep);
222
223 set_ee_word(dep, 0x76/2, 0x8029);
224
225 ee_wds(dep);
226
227 assert(get_ee_word(dep, 0x76/2) == 0x8029);
228 }
229}
230
231static u16_t get_ee_word(dep, a)
232dpeth_t *dep;
233int a;
234{
235 int b, i, cmd;
236 u16_t w;
237
238 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
239
240 /* Switch to 9346 mode and enable CS */
241 outb_reg3(dep, 1, 0x80 | 0x8);
242
243 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
244 for (i= 8; i >= 0; i--)
245 {
246 b= (cmd & (1 << i));
247 b= (b ? 2 : 0);
248
249 /* Cmd goes out on the rising edge of the clock */
250 outb_reg3(dep, 1, 0x80 | 0x8 | b);
251 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
252 }
253 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
254
255 w= 0;
256 for (i= 0; i<16; i++)
257 {
258 w <<= 1;
259
260 /* Data is shifted out on the rising edge. Read at the
261 * falling edge.
262 */
263 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
264 outb_reg3(dep, 1, 0x80 | 0x8 | b);
265 b= inb_reg3(dep, 1);
266 w |= (b & 1);
267 }
268
269 outb_reg3(dep, 1, 0x80); /* drop CS */
270 outb_reg3(dep, 1, 0x00); /* back to normal */
271 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
272
273 return w;
274}
275
276static void ee_wen(dep)
277dpeth_t *dep;
278{
279 int b, i, cmd;
280
281 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
282
283 /* Switch to 9346 mode and enable CS */
284 outb_reg3(dep, 1, 0x80 | 0x8);
285
286 cmd= 0x130; /* 1 0 0 1 1 x x x x */
287 for (i= 8; i >= 0; i--)
288 {
289 b= (cmd & (1 << i));
290 b= (b ? 2 : 0);
291
292 /* Cmd goes out on the rising edge of the clock */
293 outb_reg3(dep, 1, 0x80 | 0x8 | b);
294 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
295 }
296 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
297 outb_reg3(dep, 1, 0x80); /* Drop CS */
298 micro_delay(1); /* Is this required? */
299}
300
301static void set_ee_word(dep, a, w)
302dpeth_t *dep;
303int a;
304u16_t w;
305{
306 int b, i, cmd;
307
308 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
309
310 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
311 for (i= 8; i >= 0; i--)
312 {
313 b= (cmd & (1 << i));
314 b= (b ? 2 : 0);
315
316 /* Cmd goes out on the rising edge of the clock */
317 outb_reg3(dep, 1, 0x80 | 0x8 | b);
318 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
319 }
320 for (i= 15; i >= 0; i--)
321 {
322 b= (w & (1 << i));
323 b= (b ? 2 : 0);
324
325 /* Cmd goes out on the rising edge of the clock */
326 outb_reg3(dep, 1, 0x80 | 0x8 | b);
327 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
328 }
329 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
330 outb_reg3(dep, 1, 0x80); /* Drop CS */
331 micro_delay(1); /* Is this required? */
332 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
333 for (i= 0; i<10000; i++)
334 {
335 if (inb_reg3(dep, 1) & 1)
336 break;
337 micro_delay(1);
338 }
339 if (!(inb_reg3(dep, 1) & 1))
340 panic("", "set_ee_word: device remains busy", NO_NUM);
341}
342
343static void ee_wds(dep)
344dpeth_t *dep;
345{
346 int b, i, cmd;
347
348 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
349
350 /* Switch to 9346 mode and enable CS */
351 outb_reg3(dep, 1, 0x80 | 0x8);
352
353 cmd= 0x100; /* 1 0 0 0 0 x x x x */
354 for (i= 8; i >= 0; i--)
355 {
356 b= (cmd & (1 << i));
357 b= (b ? 2 : 0);
358
359 /* Cmd goes out on the rising edge of the clock */
360 outb_reg3(dep, 1, 0x80 | 0x8 | b);
361 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
362 }
363 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
364 outb_reg3(dep, 1, 0x80); /* Drop CS */
365 outb_reg3(dep, 1, 0x00); /* back to normal */
366 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
367}
368
369static void micro_delay(unsigned long usecs)
370{
371 tickdelay(MICROS_TO_TICKS(usecs));
372}
373
374#endif /* ENABLE_PCI */
375
376/*
377 * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $
378 */
Note: See TracBrowser for help on using the repository browser.