• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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