Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / common / boot / grub / netboot / 3c509.c
blob604a6862b192bab6870de6b9ba1e1fae0a0c2a8c
1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
4 Author: Martin Renters.
5 Date: Mar 22 1995
7 This code is based heavily on David Greenman's if_ed.c driver and
8 Andres Vega Garcia's if_ep.c driver.
10 Copyright (C) 1993-1994, David Greenman, Martin Renters.
11 Copyright (C) 1993-1995, Andres Vega Garcia.
12 Copyright (C) 1995, Serge Babkin.
13 This software may be used, modified, copied, distributed, and sold, in
14 both source and binary form provided that the above copyright and these
15 terms are retained. Under no circumstances are the authors responsible for
16 the proper functioning of this software, nor do the authors assume any
17 responsibility for damages incurred with its use.
19 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
21 $Id$
23 ***************************************************************************/
25 /* #define EDEBUG */
27 #include "etherboot.h"
28 #include "nic.h"
29 #include "cards.h"
30 #include "timer.h"
31 #include "3c509.h"
33 #define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
35 static unsigned short eth_nic_base;
36 static enum { none, bnc, utp } connector = none; /* for 3C509 */
38 #ifdef INCLUDE_3C529
40 * This table and several other pieces of the MCA support
41 * code were shamelessly borrowed from the Linux kernel source.
43 * MCA support added by Adam Fritzler (mid@auk.cx)
46 struct el3_mca_adapters_struct {
47 const char *name;
48 int id;
50 static struct el3_mca_adapters_struct el3_mca_adapters[] = {
51 { "3Com 3c529 EtherLink III (10base2)", 0x627c },
52 { "3Com 3c529 EtherLink III (10baseT)", 0x627d },
53 { "3Com 3c529 EtherLink III (test mode)", 0x62db },
54 { "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 },
55 { "3Com 3c529 EtherLink III (TP)", 0x62f7 },
56 { NULL, 0 },
58 #endif
60 /**************************************************************************
61 ETH_RESET - Reset adapter
62 ***************************************************************************/
63 static void t509_reset(struct nic *nic)
65 int i;
67 /***********************************************************
68 Reset 3Com 509 card
69 *************************************************************/
71 /* stop card */
72 outw(RX_DISABLE, BASE + EP_COMMAND);
73 outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
74 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
76 outw(TX_DISABLE, BASE + EP_COMMAND);
77 outw(STOP_TRANSCEIVER, BASE + EP_COMMAND);
78 udelay(1000);
79 outw(RX_RESET, BASE + EP_COMMAND);
80 outw(TX_RESET, BASE + EP_COMMAND);
81 outw(C_INTR_LATCH, BASE + EP_COMMAND);
82 outw(SET_RD_0_MASK, BASE + EP_COMMAND);
83 outw(SET_INTR_MASK, BASE + EP_COMMAND);
84 outw(SET_RX_FILTER, BASE + EP_COMMAND);
87 * initialize card
89 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
92 GO_WINDOW(0);
94 /* Disable the card */
95 outw(0, BASE + EP_W0_CONFIG_CTRL);
97 /* Configure IRQ to none */
98 outw(SET_IRQ(0), BASE + EP_W0_RESOURCE_CFG);
100 /* Enable the card */
101 outw(ENABLE_DRQ_IRQ, BASE + EP_W0_CONFIG_CTRL);
103 GO_WINDOW(2);
105 /* Reload the ether_addr. */
106 for (i = 0; i < ETH_ALEN; i++)
107 outb(nic->node_addr[i], BASE + EP_W2_ADDR_0 + i);
109 outw(RX_RESET, BASE + EP_COMMAND);
110 outw(TX_RESET, BASE + EP_COMMAND);
112 /* Window 1 is operating window */
113 GO_WINDOW(1);
114 for (i = 0; i < 31; i++)
115 inb(BASE + EP_W1_TX_STATUS);
117 /* get rid of stray intr's */
118 outw(ACK_INTR | 0xff, BASE + EP_COMMAND);
120 outw(SET_RD_0_MASK | S_5_INTS, BASE + EP_COMMAND);
122 outw(SET_INTR_MASK, BASE + EP_COMMAND);
124 outw(SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST, BASE + EP_COMMAND);
126 /* configure BNC */
127 if (connector == bnc) {
128 outw(START_TRANSCEIVER, BASE + EP_COMMAND);
129 udelay(1000);
131 /* configure UTP */
132 else if (connector == utp) {
133 GO_WINDOW(4);
134 outw(ENABLE_UTP, BASE + EP_W4_MEDIA_TYPE);
135 sleep(2); /* Give time for media to negotiate */
136 GO_WINDOW(1);
139 /* start transceiver and receiver */
140 outw(RX_ENABLE, BASE + EP_COMMAND);
141 outw(TX_ENABLE, BASE + EP_COMMAND);
143 /* set early threshold for minimal packet length */
144 outw(SET_RX_EARLY_THRESH | ETH_ZLEN, BASE + EP_COMMAND);
145 outw(SET_TX_START_THRESH | 16, BASE + EP_COMMAND);
148 /**************************************************************************
149 ETH_TRANSMIT - Transmit a frame
150 ***************************************************************************/
151 static char padmap[] = {
152 0, 3, 2, 1};
154 static void t509_transmit(
155 struct nic *nic,
156 const char *d, /* Destination */
157 unsigned int t, /* Type */
158 unsigned int s, /* size */
159 const char *p) /* Packet */
161 register unsigned int len;
162 int pad;
163 int status;
165 #ifdef EDEBUG
166 printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
167 #endif
169 /* swap bytes of type */
170 t= htons(t);
172 len=s+ETH_HLEN; /* actual length of packet */
173 pad = padmap[len & 3];
176 * The 3c509 automatically pads short packets to minimum ethernet length,
177 * but we drop packets that are too large. Perhaps we should truncate
178 * them instead?
180 if (len + pad > ETH_FRAME_LEN) {
181 return;
184 /* drop acknowledgements */
185 while ((status=inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
186 if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
187 outw(TX_RESET, BASE + EP_COMMAND);
188 outw(TX_ENABLE, BASE + EP_COMMAND);
190 outb(0x0, BASE + EP_W1_TX_STATUS);
193 while (inw(BASE + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
194 ; /* no room in FIFO */
196 outw(len, BASE + EP_W1_TX_PIO_WR_1);
197 outw(0x0, BASE + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */
199 /* write packet */
200 outsw(BASE + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
201 outsw(BASE + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
202 outw(t, BASE + EP_W1_TX_PIO_WR_1);
203 outsw(BASE + EP_W1_TX_PIO_WR_1, p, s / 2);
204 if (s & 1)
205 outb(*(p+s - 1), BASE + EP_W1_TX_PIO_WR_1);
207 while (pad--)
208 outb(0, BASE + EP_W1_TX_PIO_WR_1); /* Padding */
210 /* wait for Tx complete */
211 while((inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
215 /**************************************************************************
216 ETH_POLL - Wait for a frame
217 ***************************************************************************/
218 static int t509_poll(struct nic *nic)
220 /* common variables */
221 unsigned short type = 0; /* used by EDEBUG */
222 /* variables for 3C509 */
223 short status, cst;
224 register short rx_fifo;
226 cst=inw(BASE + EP_STATUS);
228 #ifdef EDEBUG
229 if(cst & 0x1FFF)
230 printf("-%hX-",cst);
231 #endif
233 if( (cst & S_RX_COMPLETE)==0 ) {
234 /* acknowledge everything */
235 outw(ACK_INTR| (cst & S_5_INTS), BASE + EP_COMMAND);
236 outw(C_INTR_LATCH, BASE + EP_COMMAND);
238 return 0;
241 status = inw(BASE + EP_W1_RX_STATUS);
242 #ifdef EDEBUG
243 printf("*%hX*",status);
244 #endif
246 if (status & ERR_RX) {
247 outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
248 return 0;
251 rx_fifo = status & RX_BYTES_MASK;
252 if (rx_fifo==0)
253 return 0;
255 /* read packet */
256 #ifdef EDEBUG
257 printf("[l=%d",rx_fifo);
258 #endif
259 insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
260 if(rx_fifo & 1)
261 nic->packet[rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
262 nic->packetlen=rx_fifo;
264 while(1) {
265 status = inw(BASE + EP_W1_RX_STATUS);
266 #ifdef EDEBUG
267 printf("*%hX*",status);
268 #endif
269 rx_fifo = status & RX_BYTES_MASK;
270 if(rx_fifo>0) {
271 insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
272 if(rx_fifo & 1)
273 nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
274 nic->packetlen+=rx_fifo;
275 #ifdef EDEBUG
276 printf("+%d",rx_fifo);
277 #endif
279 if(( status & RX_INCOMPLETE )==0) {
280 #ifdef EDEBUG
281 printf("=%d",nic->packetlen);
282 #endif
283 break;
285 udelay(1000); /* if incomplete wait 1 ms */
287 /* acknowledge reception of packet */
288 outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
289 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
291 #ifdef EDEBUG
292 type = (nic->packet[12]<<8) | nic->packet[13];
293 if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
294 nic->packet[5] == 0xFF*ETH_ALEN)
295 printf(",t=%hX,b]",type);
296 else
297 printf(",t=%hX]",type);
298 #endif
299 return (1);
302 /*************************************************************************
303 3Com 509 - specific routines
304 **************************************************************************/
306 static int
307 eeprom_rdy(void)
309 int i;
311 for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++);
312 if (i >= MAX_EEPROMBUSY) {
313 /* printf("3c509: eeprom failed to come ready.\n"); */
314 printf("3c509: eeprom busy.\n"); /* memory in EPROM is tight */
315 return (0);
317 return (1);
321 * get_e: gets a 16 bits word from the EEPROM. we must have set the window
322 * before
324 static int
325 get_e(int offset)
327 if (!eeprom_rdy())
328 return (0xffff);
329 outw(EEPROM_CMD_RD | offset, IS_BASE + EP_W0_EEPROM_COMMAND);
330 if (!eeprom_rdy())
331 return (0xffff);
332 return (inw(IS_BASE + EP_W0_EEPROM_DATA));
335 static int
336 send_ID_sequence(int port)
338 int cx, al;
340 for (al = 0xff, cx = 0; cx < 255; cx++) {
341 outb(al, port);
342 al <<= 1;
343 if (al & 0x100)
344 al ^= 0xcf;
346 return (1);
351 * We get eeprom data from the id_port given an offset into the eeprom.
352 * Basically; after the ID_sequence is sent to all of the cards; they enter
353 * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
354 * the eeprom data. We then read the port 16 times and with every read; the
355 * cards check for contention (ie: if one card writes a 0 bit and another
356 * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
357 * compares the data on the bus; if there is a difference then that card goes
358 * into ID_WAIT state again). In the meantime; one bit of data is returned in
359 * the AX register which is conveniently returned to us by inb(). Hence; we
360 * read 16 times getting one bit of data with each read.
362 static int
363 get_eeprom_data(int id_port, int offset)
365 int i, data = 0;
366 outb(0x80 + offset, id_port);
367 /* Do we really need this wait? Won't be noticeable anyway */
368 udelay(10000);
369 for (i = 0; i < 16; i++)
370 data = (data << 1) | (inw(id_port) & 1);
371 return (data);
374 static void t509_disable(struct nic *nic)
376 outb(0xc0, EP_ID_PORT);
379 /**************************************************************************
380 ETH_PROBE - Look for an adapter
381 ***************************************************************************/
382 #ifdef INCLUDE_3C529
383 struct nic *t529_probe(struct nic *nic, unsigned short *probe_addrs)
384 #else
385 struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs)
386 #endif
388 /* common variables */
389 int i;
390 int failcount;
392 #ifdef INCLUDE_3C529
393 struct el3_mca_adapters_struct *mcafound = NULL;
394 int mca_pos4 = 0, mca_pos5 = 0, mca_irq = 0;
395 #endif
397 t509_disable(nic); /* in case board was active */
398 /* note that nic is not used */
399 for (failcount = 0; failcount < 4000; failcount++) {
400 int data, j, io_base, id_port;
401 unsigned short k;
402 int ep_current_tag;
403 short *p;
404 #ifdef INCLUDE_3C529
405 int curboard;
406 #endif
408 id_port = EP_ID_PORT;
409 ep_current_tag = EP_LAST_TAG + 1;
411 /*********************************************************
412 Search for 3Com 509 card
413 ***********************************************************/
414 #ifdef INCLUDE_3C529
416 * XXX: We should really check to make sure we have an MCA
417 * bus controller before going ahead with this...
419 * For now, we avoid any hassle by making it a compile
420 * time option.
423 printf("\nWarning: Assuming presence of MCA bus\n");
425 /* Make sure motherboard setup is off */
426 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
428 /* Cycle through slots */
429 for(curboard=0; curboard<MCA_MAX_SLOT_NR; curboard++) {
430 int boardid;
431 int curcard;
433 outb_p(0x8|(curboard&0xf), MCA_ADAPTER_SETUP_REG);
435 boardid = inb_p(MCA_POS_REG(0));
436 boardid += inb_p(MCA_POS_REG(1)) << 8;
438 curcard = 0;
439 while (el3_mca_adapters[curcard].name) {
440 if (el3_mca_adapters[curcard].id == boardid) {
441 mcafound = &el3_mca_adapters[curcard];
443 mca_pos4 = inb_p(MCA_POS_REG(4));
444 mca_pos5 = inb_p(MCA_POS_REG(5));
446 goto donewithdetect;
448 else
449 curcard++;
453 donewithdetect:
454 /* Kill all setup modes */
455 outb_p(0, MCA_ADAPTER_SETUP_REG);
457 if (mcafound) {
458 eth_nic_base = ((short)((mca_pos4&0xfc)|0x02)) << 8;
459 mca_irq = mca_pos5 & 0x0f;
460 ep_current_tag--;
462 else
463 printf("MCA Card not found\n");
464 #endif
465 /* Look for the EISA boards, leave them activated */
466 /* search for the first card, ignore all others */
467 for(j = 1; j < 16; j++) {
468 io_base = (j * EP_EISA_START) | EP_EISA_W0;
469 if (inw(io_base + EP_W0_MFG_ID) != MFG_ID)
470 continue;
472 /* we must have found 0x1f if the board is EISA configurated */
473 if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f)
474 continue;
476 /* Reset and Enable the card */
477 outb(W0_P4_CMD_RESET_ADAPTER, io_base + EP_W0_CONFIG_CTRL);
478 udelay(1000); /* Must wait 800 µs, be conservative */
479 outb(W0_P4_CMD_ENABLE_ADAPTER, io_base + EP_W0_CONFIG_CTRL);
482 * Once activated, all the registers are mapped in the range
483 * x000 - x00F, where x is the slot number.
485 eth_nic_base = j * EP_EISA_START;
486 break;
488 ep_current_tag--;
490 /* Look for the ISA boards. Init and leave them actived */
491 /* search for the first card, ignore all others */
492 outb(0xc0, id_port); /* Global reset */
493 udelay(1000); /* wait 1 ms */
494 for (i = 0; i < EP_MAX_BOARDS; i++) {
495 outb(0, id_port);
496 outb(0, id_port);
497 send_ID_sequence(id_port);
499 data = get_eeprom_data(id_port, EEPROM_MFG_ID);
500 if (data != MFG_ID)
501 break;
503 /* resolve contention using the Ethernet address */
504 for (j = 0; j < 3; j++)
505 data = get_eeprom_data(id_port, j);
507 eth_nic_base =
508 (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
509 outb(ep_current_tag, id_port); /* tags board */
510 outb(ACTIVATE_ADAPTER_TO_CONFIG, id_port);
511 ep_current_tag--;
512 break;
515 if (i >= EP_MAX_BOARDS)
516 goto no3c509;
519 * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
520 * 0x9[0-f]50
522 GO_WINDOW(0);
523 k = get_e(EEPROM_PROD_ID);
524 #ifdef INCLUDE_3C529
526 * On MCA, the PROD_ID matches the MCA card ID (POS0+POS1)
528 if (mcafound) {
529 if (mcafound->id != k) {
530 printf("MCA: PROD_ID in EEPROM does not match MCA card ID! (%hX != %hX)\n", k, mcafound->id);
531 goto no3c509;
533 } else { /* for ISA/EISA */
534 if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
535 goto no3c509;
537 #else
538 if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
539 goto no3c509;
540 #endif
542 #ifdef INCLUDE_3C529
543 if (mcafound) {
544 printf("%s board found on MCA at %#hx IRQ %d -",
545 mcafound->name, eth_nic_base, mca_irq);
546 } else {
547 #endif
548 if(eth_nic_base >= EP_EISA_START)
549 printf("3C5x9 board on EISA at %#hx - ",eth_nic_base);
550 else
551 printf("3C5x9 board on ISA at %#hx - ",eth_nic_base);
552 #ifdef INCLUDE_3C529
554 #endif
556 /* test for presence of connectors */
557 i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
558 j = (inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
560 switch(j) {
561 case 0:
562 if (i & IS_UTP) {
563 printf("10baseT\n");
564 connector = utp;
566 else {
567 printf("10baseT not present\n");
568 goto no3c509;
570 break;
571 case 1:
572 if (i & IS_AUI)
573 printf("10base5\n");
574 else {
575 printf("10base5 not present\n");
576 goto no3c509;
578 break;
579 case 3:
580 if (i & IS_BNC) {
581 printf("10base2\n");
582 connector = bnc;
584 else {
585 printf("10base2 not present\n");
586 goto no3c509;
588 break;
589 default:
590 printf("unknown connector\n");
591 goto no3c509;
594 * Read the station address from the eeprom
596 p = (unsigned short *) nic->node_addr;
597 for (i = 0; i < ETH_ALEN / 2; i++) {
598 GO_WINDOW(0);
599 p[i] = htons(get_e(i));
600 GO_WINDOW(2);
601 outw(ntohs(p[i]), BASE + EP_W2_ADDR_0 + (i * 2));
603 printf("Ethernet address: %!\n", nic->node_addr);
604 t509_reset(nic);
605 nic->reset = t509_reset;
606 nic->poll = t509_poll;
607 nic->transmit = t509_transmit;
608 nic->disable = t509_disable;
609 return nic;
610 no3c509:
611 printf("(probe fail)");
613 return 0;
617 * Local variables:
618 * c-basic-offset: 8
619 * End: