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 <minix/drivers.h>
10 #include <minix/netdriver.h>
11
12 #include <stdlib.h>
13 #include <sys/types.h>
14 #include <machine/pci.h>
15
16 #include "assert.h"
17
18 #include "local.h"
19 #include "dp8390.h"
20 #include "rtl8029.h"
21
22 static void rtl_init(struct dpeth *dep);
23 #if 0
24 static u16_t get_ee_word(dpeth_t *dep, int a);
25 static void ee_wen(dpeth_t *dep);
26 static void set_ee_word(dpeth_t *dep, int a, u16_t w);
27 static void ee_wds(dpeth_t *dep);
28 #endif
29
rtl_probe(dep,skip)30 int rtl_probe(dep, skip)
31 struct dpeth *dep;
32 int skip;
33 {
34 int r, devind;
35 u16_t vid, did;
36 u32_t bar;
37 u8_t ilr;
38 const char *dname;
39
40 pci_init();
41
42 r= pci_first_dev(&devind, &vid, &did);
43 if (r == 0)
44 return 0;
45
46 while (skip--)
47 {
48 r= pci_next_dev(&devind, &vid, &did);
49 if (!r)
50 return 0;
51 }
52
53 dname= pci_dev_name(vid, did);
54 if (!dname)
55 dname= "unknown device";
56 printf("%s: %s (%04X/%04X) at %s\n",
57 netdriver_name(), dname, vid, did, pci_slot_name(devind));
58 if(pci_reserve_ok(devind) != OK)
59 return 0;
60 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
61 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
62
63 if (bar < 0x400)
64 panic("base address is not properly configured");
65
66 dep->de_base_port= bar;
67
68 ilr= pci_attr_r8(devind, PCI_ILR);
69 dep->de_irq= ilr;
70 if (debug)
71 {
72 printf("%s: using I/O address 0x%lx, IRQ %d\n",
73 netdriver_name(), (unsigned long)bar, ilr);
74 }
75 dep->de_initf= rtl_init;
76
77 return TRUE;
78 }
79
rtl_init(dep)80 static void rtl_init(dep)
81 dpeth_t *dep;
82 {
83 u8_t reg_a, reg_b, cr, config0, config2, config3;
84
85 #if DEBUG
86 printf("rtl_init called\n");
87 #endif
88 ne_init(dep);
89
90 /* ID */
91 outb_reg0(dep, DP_CR, CR_PS_P0);
92 reg_a = inb_reg0(dep, DP_DUM1);
93 reg_b = inb_reg0(dep, DP_DUM2);
94
95 #if DEBUG
96 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
97 #endif
98
99 outb_reg0(dep, DP_CR, CR_PS_P3);
100 config0 = inb_reg3(dep, 3);
101 config2 = inb_reg3(dep, 5);
102 config3 = inb_reg3(dep, 6);
103 outb_reg0(dep, DP_CR, CR_PS_P0);
104
105 #if DEBUG
106 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
107 config0, config2, config3);
108 #endif
109
110 if (getenv("RTL8029FD"))
111 {
112 printf("rtl_init: setting full-duplex mode\n");
113 outb_reg0(dep, DP_CR, CR_PS_P3);
114
115 cr= inb_reg3(dep, 1);
116 outb_reg3(dep, 1, cr | 0xc0);
117
118 outb_reg3(dep, 6, config3 | 0x40);
119 config3 = inb_reg3(dep, 6);
120
121 config2= inb_reg3(dep, 5);
122 outb_reg3(dep, 5, config2 | 0x20);
123 config2= inb_reg3(dep, 5);
124
125 outb_reg3(dep, 1, cr);
126
127 outb_reg0(dep, DP_CR, CR_PS_P0);
128
129 #if DEBUG
130 printf("rtl_init: config 2 = %x\n", config2);
131 printf("rtl_init: config 3 = %x\n", config3);
132 #endif
133 }
134
135 #if 0
136 for (i= 0; i<64; i++)
137 printf("%x ", get_ee_word(dep, i));
138 printf("\n");
139 #endif
140
141 #if 0
142 if (getenv("RTL8029MN"))
143 {
144 ee_wen(dep);
145
146 set_ee_word(dep, 0x78/2, 0x10ec);
147 set_ee_word(dep, 0x7A/2, 0x8029);
148 set_ee_word(dep, 0x7C/2, 0x10ec);
149 set_ee_word(dep, 0x7E/2, 0x8029);
150
151 ee_wds(dep);
152
153 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
154 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
155 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
156 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
157 }
158
159 if (getenv("RTL8029XXX"))
160 {
161 ee_wen(dep);
162
163 set_ee_word(dep, 0x76/2, 0x8029);
164
165 ee_wds(dep);
166
167 assert(get_ee_word(dep, 0x76/2) == 0x8029);
168 }
169 #endif
170 }
171
172 #if 0
173 static u16_t get_ee_word(dep, a)
174 dpeth_t *dep;
175 int a;
176 {
177 int b, i, cmd;
178 u16_t w;
179
180 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
181
182 /* Switch to 9346 mode and enable CS */
183 outb_reg3(dep, 1, 0x80 | 0x8);
184
185 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
186 for (i= 8; i >= 0; i--)
187 {
188 b= (cmd & (1 << i));
189 b= (b ? 2 : 0);
190
191 /* Cmd goes out on the rising edge of the clock */
192 outb_reg3(dep, 1, 0x80 | 0x8 | b);
193 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
194 }
195 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
196
197 w= 0;
198 for (i= 0; i<16; i++)
199 {
200 w <<= 1;
201
202 /* Data is shifted out on the rising edge. Read at the
203 * falling edge.
204 */
205 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
206 outb_reg3(dep, 1, 0x80 | 0x8 | b);
207 b= inb_reg3(dep, 1);
208 w |= (b & 1);
209 }
210
211 outb_reg3(dep, 1, 0x80); /* drop CS */
212 outb_reg3(dep, 1, 0x00); /* back to normal */
213 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
214
215 return w;
216 }
217
218 static void ee_wen(dep)
219 dpeth_t *dep;
220 {
221 int b, i, cmd;
222
223 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
224
225 /* Switch to 9346 mode and enable CS */
226 outb_reg3(dep, 1, 0x80 | 0x8);
227
228 cmd= 0x130; /* 1 0 0 1 1 x x x x */
229 for (i= 8; i >= 0; i--)
230 {
231 b= (cmd & (1 << i));
232 b= (b ? 2 : 0);
233
234 /* Cmd goes out on the rising edge of the clock */
235 outb_reg3(dep, 1, 0x80 | 0x8 | b);
236 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
237 }
238 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
239 outb_reg3(dep, 1, 0x80); /* Drop CS */
240 micro_delay(1); /* Is this required? */
241 }
242
243 static void set_ee_word(dep, a, w)
244 dpeth_t *dep;
245 int a;
246 u16_t w;
247 {
248 int b, i, cmd;
249
250 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
251
252 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
253 for (i= 8; i >= 0; i--)
254 {
255 b= (cmd & (1 << i));
256 b= (b ? 2 : 0);
257
258 /* Cmd goes out on the rising edge of the clock */
259 outb_reg3(dep, 1, 0x80 | 0x8 | b);
260 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
261 }
262 for (i= 15; i >= 0; i--)
263 {
264 b= (w & (1 << i));
265 b= (b ? 2 : 0);
266
267 /* Cmd goes out on the rising edge of the clock */
268 outb_reg3(dep, 1, 0x80 | 0x8 | b);
269 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
270 }
271 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
272 outb_reg3(dep, 1, 0x80); /* Drop CS */
273 micro_delay(1); /* Is this required? */
274 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
275 for (i= 0; i<10000; i++)
276 {
277 if (inb_reg3(dep, 1) & 1)
278 break;
279 micro_delay(1);
280 }
281 if (!(inb_reg3(dep, 1) & 1))
282 panic("set_ee_word: device remains busy");
283 }
284
285 static void ee_wds(dep)
286 dpeth_t *dep;
287 {
288 int b, i, cmd;
289
290 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
291
292 /* Switch to 9346 mode and enable CS */
293 outb_reg3(dep, 1, 0x80 | 0x8);
294
295 cmd= 0x100; /* 1 0 0 0 0 x x x x */
296 for (i= 8; i >= 0; i--)
297 {
298 b= (cmd & (1 << i));
299 b= (b ? 2 : 0);
300
301 /* Cmd goes out on the rising edge of the clock */
302 outb_reg3(dep, 1, 0x80 | 0x8 | b);
303 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
304 }
305 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
306 outb_reg3(dep, 1, 0x80); /* Drop CS */
307 outb_reg3(dep, 1, 0x00); /* back to normal */
308 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
309 }
310 #endif
311
312 /*
313 * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $
314 */
315