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 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 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 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 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 ***************************************************************************/ 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 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 ***************************************************************************/ 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 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 ***************************************************************************/ 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