1 /*
2 Etherboot DEC Tulip driver
3 adapted by Ken Yap from
4
5 FreeBSD netboot DEC 21143 driver
6
7 Author: David Sharp
8 date: Nov/98
9
10 Known to work on DEC DE500 using 21143-PC chipset.
11 Even on cards with the same chipset there can be
12 incompatablity problems with the way media selection
13 and status LED settings are done. See comments below.
14
15 Some code fragments were taken from verious places,
16 Ken Yap's etherboot, FreeBSD's if_de.c, and various
17 Linux related files. DEC's manuals for the 21143 and
18 SROM format were very helpful. The Linux de driver
19 development page has a number of links to useful
20 related information. Have a look at:
21 ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html
22
23 */
24
25 #include "etherboot.h"
26 #include "nic.h"
27 #include "pci.h"
28 #include "cards.h"
29 #include "otulip.h"
30
31 static unsigned short vendor, dev_id;
32 static unsigned short ioaddr;
33 static unsigned int *membase;
34 static unsigned char srom[1024];
35
36 #define BUFLEN 1536 /* must be longword divisable */
37 /* buffers must be longword aligned */
38
39 /* transmit descriptor and buffer */
40 static struct txdesc txd;
41
42 /* receive descriptor(s) and buffer(s) */
43 #define NRXD 4
44 static struct rxdesc rxd[NRXD];
45 static int rxd_tail = 0;
46 #ifdef USE_LOWMEM_BUFFER
47 #define rxb ((char *)0x10000 - NRXD * BUFLEN)
48 #define txb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN)
49 #else
50 static unsigned char rxb[NRXD * BUFLEN];
51 static unsigned char txb[BUFLEN];
52 #endif
53
54 static unsigned char ehdr[ETH_HLEN]; /* buffer for ethernet header */
55
56 enum tulip_offsets {
57 CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
58 CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
59 CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
60
61
62 /***************************************************************************/
63 /* 21143 specific stuff */
64 /***************************************************************************/
65
66 /* XXX assume 33MHz PCI bus, this is not very accurate and should be
67 used only with gross over estimations of required delay times unless
68 you tune UADJUST to your specific processor and I/O subsystem */
69
70 #define UADJUST 870
udelay(unsigned long usec)71 static void udelay(unsigned long usec) {
72 unsigned long i;
73 for (i=((usec*UADJUST)/33)+1; i>0; i--) (void) TULIP_CSR_READ(csr_0);
74 }
75
76 /* The following srom related code was taken from FreeBSD's if_de.c */
77 /* with minor alterations to make it work here. the Linux code is */
78 /* better but this was easier to use */
79
delay_300ns(void)80 static void delay_300ns(void)
81 {
82 int idx;
83 for (idx = (300 / 33) + 1; idx > 0; idx--)
84 (void) TULIP_CSR_READ(csr_busmode);
85 }
86
87 #define EMIT do { TULIP_CSR_WRITE(csr_srom_mii, csr); delay_300ns(); } while (0)
88
srom_idle(void)89 static void srom_idle(void)
90 {
91 unsigned bit, csr;
92
93 csr = SROMSEL ; EMIT;
94 csr = SROMSEL | SROMRD; EMIT;
95 csr ^= SROMCS; EMIT;
96 csr ^= SROMCLKON; EMIT;
97 /*
98 * Write 25 cycles of 0 which will force the SROM to be idle.
99 */
100 for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
101 csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
102 csr ^= SROMCLKON; EMIT; /* clock high; data valid */
103 }
104 csr ^= SROMCLKOFF; EMIT;
105 csr ^= SROMCS; EMIT;
106 csr = 0; EMIT;
107 }
108
srom_read(void)109 static void srom_read(void)
110 {
111 unsigned idx;
112 const unsigned bitwidth = SROM_BITWIDTH;
113 const unsigned cmdmask = (SROMCMD_RD << bitwidth);
114 const unsigned msb = 1 << (bitwidth + 3 - 1);
115 unsigned lastidx = (1 << bitwidth) - 1;
116
117 srom_idle();
118
119 for (idx = 0; idx <= lastidx; idx++) {
120 unsigned lastbit, data, bits, bit, csr;
121 csr = SROMSEL ; EMIT;
122 csr = SROMSEL | SROMRD; EMIT;
123 csr ^= SROMCSON; EMIT;
124 csr ^= SROMCLKON; EMIT;
125
126 lastbit = 0;
127 for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1)
128 {
129 const unsigned thisbit = bits & msb;
130 csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
131 if (thisbit != lastbit) {
132 csr ^= SROMDOUT; EMIT; /* clock low; invert data */
133 } else {
134 EMIT;
135 }
136 csr ^= SROMCLKON; EMIT; /* clock high; data valid */
137 lastbit = thisbit;
138 }
139 csr ^= SROMCLKOFF; EMIT;
140
141 for (data = 0, bits = 0; bits < 16; bits++) {
142 data <<= 1;
143 csr ^= SROMCLKON; EMIT; /* clock high; data valid */
144 data |= TULIP_CSR_READ(csr_srom_mii) & SROMDIN ? 1 : 0;
145 csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
146 }
147 srom[idx*2] = data & 0xFF;
148 srom[idx*2+1] = data >> 8;
149 csr = SROMSEL | SROMRD; EMIT;
150 csr = 0; EMIT;
151 }
152 srom_idle();
153 }
154
155 /**************************************************************************
156 ETH_RESET - Reset adapter
157 ***************************************************************************/
tulip_reset(struct nic * nic)158 static void tulip_reset(struct nic *nic)
159 {
160 int x,cnt=2;
161
162 outl(0x00000001, ioaddr + CSR0);
163 udelay(1000);
164 /* turn off reset and set cache align=16lword, burst=unlimit */
165 outl(0x01A08000, ioaddr + CSR0);
166
167 /* for some reason the media selection does not take
168 the first time se it is repeated. */
169
170 while(cnt--) {
171 /* stop TX,RX processes */
172 if (cnt == 1)
173 outl(0x32404000, ioaddr + CSR6);
174 else
175 outl(0x32000040, ioaddr + CSR6);
176
177 /* XXX - media selection is vendor specific and hard coded right
178 here. This should be fixed to use the hints in the SROM and
179 allow media selection by the user at runtime. MII support
180 should also be added. Support for chips other than the
181 21143 should be added here as well */
182
183 /* start set to 10Mbps half-duplex */
184
185 /* setup SIA */
186 outl(0x0, ioaddr + CSR13); /* reset SIA */
187 outl(0x7f3f, ioaddr + CSR14);
188 outl(0x8000008, ioaddr + CSR15);
189 outl(0x0, ioaddr + CSR13);
190 outl(0x1, ioaddr + CSR13);
191 outl(0x2404000, ioaddr + CSR6);
192
193 /* initalize GP */
194 outl(0x8af0008, ioaddr + CSR15);
195 outl(0x50008, ioaddr + CSR15);
196
197 /* end set to 10Mbps half-duplex */
198
199 if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) {
200 /* do stuff for MX98715 */
201 outl(0x01a80000, ioaddr + CSR6);
202 outl(0xFFFFFFFF, ioaddr + CSR14);
203 outl(0x00001000, ioaddr + CSR12);
204 }
205
206 outl(0x0, ioaddr + CSR7); /* disable interrupts */
207
208 /* construct setup packet which is used by the 21143 to
209 program its CAM to recognize interesting MAC addresses */
210
211 memset(&txd, 0, sizeof(struct txdesc));
212 txd.buf1addr = &txb[0];
213 txd.buf2addr = &txb[0]; /* just in case */
214 txd.buf1sz = 192; /* setup packet must be 192 bytes */
215 txd.buf2sz = 0;
216 txd.control = 0x020; /* setup packet */
217 txd.status = 0x80000000; /* give ownership to 21143 */
218
219 /* construct perfect filter frame */
220 /* with mac address as first match */
221 /* and broadcast address for all others */
222
223 for(x=0;x<192;x++) txb[x] = 0xff;
224 txb[0] = nic->node_addr[0];
225 txb[1] = nic->node_addr[1];
226 txb[4] = nic->node_addr[2];
227 txb[5] = nic->node_addr[3];
228 txb[8] = nic->node_addr[4];
229 txb[9] = nic->node_addr[5];
230 outl((unsigned long)&txd, ioaddr + CSR4); /* set xmit buf */
231 outl(0x2406000, ioaddr + CSR6); /* start transmiter */
232
233 udelay(50000); /* wait for the setup packet to be processed */
234
235 }
236
237 /* setup receive descriptor */
238 {
239 int x;
240 for(x=0;x<NRXD;x++) {
241 memset(&rxd[x], 0, sizeof(struct rxdesc));
242 rxd[x].buf1addr = &rxb[x * BUFLEN];
243 rxd[x].buf2addr = 0; /* not used */
244 rxd[x].buf1sz = BUFLEN;
245 rxd[x].buf2sz = 0; /* not used */
246 rxd[x].control = 0x0;
247 rxd[x].status = 0x80000000; /* give ownership it to 21143 */
248 }
249 rxd[NRXD - 1].control = 0x008; /* Set Receive end of ring on la
250 st descriptor */
251 rxd_tail = 0;
252 }
253
254 /* tell DC211XX where to find rx descriptor list */
255 outl((unsigned long)&rxd[0], ioaddr + CSR3);
256 /* start the receiver */
257 outl(0x2406002, ioaddr + CSR6);
258
259 }
260
261 /**************************************************************************
262 ETH_TRANSMIT - Transmit a frame
263 ***************************************************************************/
264 static const char padmap[] = {
265 0, 3, 2, 1};
266
tulip_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)267 static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
268 {
269 unsigned long time;
270
271 /* setup ethernet header */
272
273 memcpy(ehdr, d, ETH_ALEN);
274 memcpy(&ehdr[ETH_ALEN], nic->node_addr, ETH_ALEN);
275 ehdr[ETH_ALEN*2] = (t >> 8) & 0xff;
276 ehdr[ETH_ALEN*2+1] = t & 0xff;
277
278 /* setup the transmit descriptor */
279
280 memset(&txd, 0, sizeof(struct txdesc));
281
282 txd.buf1addr = &ehdr[0]; /* ethernet header */
283 txd.buf1sz = ETH_HLEN;
284
285 txd.buf2addr = p; /* packet to transmit */
286 txd.buf2sz = s;
287
288 txd.control = 0x188; /* LS+FS+TER */
289
290 txd.status = 0x80000000; /* give it to 21143 */
291
292 outl(inl(ioaddr + CSR6) & ~0x00004000, ioaddr + CSR6);
293 outl((unsigned long)&txd, ioaddr + CSR4);
294 outl(inl(ioaddr + CSR6) | 0x00004000, ioaddr + CSR6);
295
296 /* Wait for transmit to complete before returning. not well tested.
297
298 time = currticks();
299 while(txd.status & 0x80000000) {
300 if (currticks() - time > 20) {
301 printf("transmit timeout.\n");
302 break;
303 }
304 }
305 */
306
307 }
308
309 /**************************************************************************
310 ETH_POLL - Wait for a frame
311 ***************************************************************************/
tulip_poll(struct nic * nic)312 static int tulip_poll(struct nic *nic)
313 {
314 if (rxd[rxd_tail].status & 0x80000000) return 0;
315
316 nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16;
317
318 /* copy packet to working buffer */
319 /* XXX - this copy could be avoided with a little more work
320 but for now we are content with it because the optimised
321 memcpy(, , ) is quite fast */
322
323 memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen);
324
325 /* return the descriptor and buffer to recieve ring */
326 rxd[rxd_tail].status = 0x80000000;
327 rxd_tail++;
328 if (rxd_tail == NRXD) rxd_tail = 0;
329
330 return 1;
331 }
332
tulip_disable(struct nic * nic)333 static void tulip_disable(struct nic *nic)
334 {
335 /* nothing for the moment */
336 }
337
338 /**************************************************************************
339 ETH_PROBE - Look for an adapter
340 ***************************************************************************/
otulip_probe(struct nic * nic,unsigned short * io_addrs,struct pci_device * pci)341 struct nic *otulip_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
342 {
343 int i;
344
345 if (io_addrs == 0 || *io_addrs == 0)
346 return (0);
347 vendor = pci->vendor;
348 dev_id = pci->dev_id;
349 ioaddr = *io_addrs;
350 membase = (unsigned int *)pci->membase;
351
352 /* wakeup chip */
353 pcibios_write_config_dword(pci->bus,pci->devfn,0x40,0x00000000);
354
355 /* Stop the chip's Tx and Rx processes. */
356 /* outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); */
357 /* Clear the missed-packet counter. */
358 /* (volatile int)inl(ioaddr + CSR8); */
359
360 srom_read();
361
362 for (i=0; i < ETH_ALEN; i++)
363 nic->node_addr[i] = srom[20+i];
364
365 printf("Tulip %! at ioaddr %#hX\n", nic->node_addr, ioaddr);
366
367 tulip_reset(nic);
368
369 nic->reset = tulip_reset;
370 nic->poll = tulip_poll;
371 nic->transmit = tulip_transmit;
372 nic->disable = tulip_disable;
373 return nic;
374 }
375