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
31static unsigned short vendor, dev_id;
32static unsigned short ioaddr;
33static unsigned int *membase;
34static 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 */
40static struct txdesc txd;
41
42/* receive descriptor(s) and buffer(s) */
43#define NRXD 4
44static struct rxdesc rxd[NRXD];
45static 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
50static unsigned char rxb[NRXD * BUFLEN];
51static unsigned char txb[BUFLEN];
52#endif
53
54static unsigned char ehdr[ETH_HLEN];    /* buffer for ethernet header */
55
56enum 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
71static 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
80static 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
89static 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
109static 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/**************************************************************************
156ETH_RESET - Reset adapter
157***************************************************************************/
158static 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
250st 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/**************************************************************************
262ETH_TRANSMIT - Transmit a frame
263***************************************************************************/
264static const char padmap[] = {
265        0, 3, 2, 1};
266
267static 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/**************************************************************************
310ETH_POLL - Wait for a frame
311***************************************************************************/
312static 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
333static void tulip_disable(struct nic *nic)
334{
335	/* nothing for the moment */
336}
337
338/**************************************************************************
339ETH_PROBE - Look for an adapter
340***************************************************************************/
341struct 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