1 | /*
|
---|
2 | rtl8029.c
|
---|
3 |
|
---|
4 | Initialization of PCI DP8390-based ethernet cards
|
---|
5 |
|
---|
6 | Created: 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 |
|
---|
27 | PRIVATE 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 |
|
---|
46 | PUBLIC int rtl_probe(dep)
|
---|
47 | struct 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 |
|
---|
140 | static void rtl_init(dep)
|
---|
141 | dpeth_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 |
|
---|
231 | static u16_t get_ee_word(dep, a)
|
---|
232 | dpeth_t *dep;
|
---|
233 | int 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 |
|
---|
276 | static void ee_wen(dep)
|
---|
277 | dpeth_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 |
|
---|
301 | static void set_ee_word(dep, a, w)
|
---|
302 | dpeth_t *dep;
|
---|
303 | int a;
|
---|
304 | u16_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 |
|
---|
343 | static void ee_wds(dep)
|
---|
344 | dpeth_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 |
|
---|
369 | static 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 | */
|
---|