use the override options if specified
[AROS.git] / arch / all-pc / boot / grub / netboot / cs89x0.c
blob9f964811d95398a4e64d3414db9c4d903d19cd0b
1 /* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
2 /*
3 Permission is granted to distribute the enclosed cs89x0.[ch] driver
4 only in conjunction with the Etherboot package. The code is
5 ordinarily distributed under the GPL.
7 Russ Nelson, January 2000
9 ChangeLog:
11 Thu Dec 6 22:40:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
13 * disabled all "advanced" features; this should make the code more reliable
15 * reorganized the reset function
17 * always reset the address port, so that autoprobing will continue working
19 * some cosmetic changes
21 * 2.5
23 Thu Dec 5 21:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
25 * tested the code against a CS8900 card
27 * lots of minor bug fixes and adjustments
29 * this is the first release, that actually works! it still requires some
30 changes in order to be more tolerant to different environments
32 * 4
34 Fri Nov 22 23:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
36 * read the manuals for the CS89x0 chipsets and took note of all the
37 changes that will be neccessary in order to adapt Russel Nelson's code
38 to the requirements of a BOOT-Prom
40 * 6
42 Thu Nov 19 22:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
44 * Synched with Russel Nelson's current code (v1.00)
46 * 2
48 Thu Nov 12 18:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
50 * Cleaned up some of the code and tried to optimize the code size.
52 * 1.5
54 Sun Nov 10 16:30:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
56 * First experimental release. This code compiles fine, but I
57 have no way of testing whether it actually works.
59 * I did not (yet) bother to make the code 16bit aware, so for
60 the time being, it will only work for Etherboot/32.
62 * 12
66 #include "etherboot.h"
67 #include "nic.h"
68 #include "cards.h"
69 #include "cs89x0.h"
71 static unsigned short eth_nic_base;
72 static unsigned long eth_mem_start;
73 static unsigned short eth_irq;
74 static unsigned short eth_cs_type; /* one of: CS8900, CS8920, CS8920M */
75 static unsigned short eth_auto_neg_cnf;
76 static unsigned short eth_adapter_cnf;
77 static unsigned short eth_linectl;
79 /*************************************************************************
80 CS89x0 - specific routines
81 **************************************************************************/
83 static inline int readreg(int portno)
85 outw(portno, eth_nic_base + ADD_PORT);
86 return inw(eth_nic_base + DATA_PORT);
89 static inline void writereg(int portno, int value)
91 outw(portno, eth_nic_base + ADD_PORT);
92 outw(value, eth_nic_base + DATA_PORT);
93 return;
96 /*************************************************************************
97 EEPROM access
98 **************************************************************************/
100 static int wait_eeprom_ready(void)
102 unsigned long tmo = currticks() + 4*TICKS_PER_SEC;
104 /* check to see if the EEPROM is ready, a timeout is used -
105 just in case EEPROM is ready when SI_BUSY in the
106 PP_SelfST is clear */
107 while(readreg(PP_SelfST) & SI_BUSY) {
108 if (currticks() >= tmo)
109 return -1; }
110 return 0;
113 static int get_eeprom_data(int off, int len, unsigned short *buffer)
115 int i;
117 #ifdef EDEBUG
118 printf("\ncs: EEPROM data from %hX for %hX:",off,len);
119 #endif
120 for (i = 0; i < len; i++) {
121 if (wait_eeprom_ready() < 0)
122 return -1;
123 /* Now send the EEPROM read command and EEPROM location
124 to read */
125 writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD);
126 if (wait_eeprom_ready() < 0)
127 return -1;
128 buffer[i] = readreg(PP_EEData);
129 #ifdef EDEBUG
130 if (!(i%10))
131 printf("\ncs: ");
132 printf("%hX ", buffer[i]);
133 #endif
135 #ifdef EDEBUG
136 putchar('\n');
137 #endif
139 return(0);
142 static int get_eeprom_chksum(int off, int len, unsigned short *buffer)
144 int i, cksum;
146 cksum = 0;
147 for (i = 0; i < len; i++)
148 cksum += buffer[i];
149 cksum &= 0xffff;
150 if (cksum == 0)
151 return 0;
152 return -1;
155 /*************************************************************************
156 Activate all of the available media and probe for network
157 **************************************************************************/
159 static void clrline(void)
161 int i;
163 putchar('\r');
164 for (i = 79; i--; ) putchar(' ');
165 printf("\rcs: ");
166 return;
169 static void control_dc_dc(int on_not_off)
171 unsigned int selfcontrol;
172 unsigned long tmo = currticks() + TICKS_PER_SEC;
174 /* control the DC to DC convertor in the SelfControl register. */
175 selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
176 if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
177 selfcontrol |= HCB1;
178 else
179 selfcontrol &= ~HCB1;
180 writereg(PP_SelfCTL, selfcontrol);
182 /* Wait for the DC/DC converter to power up - 1000ms */
183 while (currticks() < tmo);
185 return;
188 static int detect_tp(void)
190 unsigned long tmo;
192 /* Turn on the chip auto detection of 10BT/ AUI */
194 clrline(); printf("attempting %s:","TP");
196 /* If connected to another full duplex capable 10-Base-T card
197 the link pulses seem to be lost when the auto detect bit in
198 the LineCTL is set. To overcome this the auto detect bit
199 will be cleared whilst testing the 10-Base-T interface.
200 This would not be necessary for the sparrow chip but is
201 simpler to do it anyway. */
202 writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY);
203 control_dc_dc(0);
205 /* Delay for the hardware to work out if the TP cable is
206 present - 150ms */
207 for (tmo = currticks() + 4; currticks() < tmo; );
209 if ((readreg(PP_LineST) & LINK_OK) == 0)
210 return 0;
212 if (eth_cs_type != CS8900) {
214 writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK);
216 if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
217 printf(" negotiating duplex... ");
218 while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) {
219 if (currticks() - tmo > 40*TICKS_PER_SEC) {
220 printf("time out ");
221 break;
225 if (readreg(PP_AutoNegST) & FDX_ACTIVE)
226 printf("using full duplex");
227 else
228 printf("using half duplex");
231 return A_CNF_MEDIA_10B_T;
234 /* send a test packet - return true if carrier bits are ok */
235 static int send_test_pkt(struct nic *nic)
237 static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
238 0, 46, /*A 46 in network order */
239 0, 0, /*DSAP=0 & SSAP=0 fields */
240 0xf3,0 /*Control (Test Req+P bit set)*/ };
241 unsigned long tmo;
243 writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON);
245 memcpy(testpacket, nic->node_addr, ETH_ALEN);
246 memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN);
248 outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
249 outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT);
251 /* Test to see if the chip has allocated memory for the packet */
252 for (tmo = currticks() + 2;
253 (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; )
254 if (currticks() >= tmo)
255 return(0);
257 /* Write the contents of the packet */
258 outsw(eth_nic_base + TX_FRAME_PORT, testpacket,
259 (ETH_ZLEN+1)>>1);
261 printf(" sending test packet ");
262 /* wait a couple of timer ticks for packet to be received */
263 for (tmo = currticks() + 2; currticks() < tmo; );
265 if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
266 printf("succeeded");
267 return 1;
269 printf("failed");
270 return 0;
274 static int detect_aui(struct nic *nic)
276 clrline(); printf("attempting %s:","AUI");
277 control_dc_dc(0);
279 writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
281 if (send_test_pkt(nic)) {
282 return A_CNF_MEDIA_AUI; }
283 else
284 return 0;
287 static int detect_bnc(struct nic *nic)
289 clrline(); printf("attempting %s:","BNC");
290 control_dc_dc(1);
292 writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
294 if (send_test_pkt(nic)) {
295 return A_CNF_MEDIA_10B_2; }
296 else
297 return 0;
300 /**************************************************************************
301 ETH_RESET - Reset adapter
302 ***************************************************************************/
304 static void cs89x0_reset(struct nic *nic)
306 int i;
307 unsigned long reset_tmo;
309 writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET);
311 /* wait for two ticks; that is 2*55ms */
312 for (reset_tmo = currticks() + 2; currticks() < reset_tmo; );
314 if (eth_cs_type != CS8900) {
315 /* Hardware problem requires PNP registers to be reconfigured
316 after a reset */
317 if (eth_irq != 0xFFFF) {
318 outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT);
319 outb(eth_irq, eth_nic_base + DATA_PORT);
320 outb(0, eth_nic_base + DATA_PORT + 1); }
322 if (eth_mem_start) {
323 outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT);
324 outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT);
325 outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } }
327 /* Wait until the chip is reset */
328 for (reset_tmo = currticks() + 2;
329 (readreg(PP_SelfST) & INIT_DONE) == 0 &&
330 currticks() < reset_tmo; );
332 /* disable interrupts and memory accesses */
333 writereg(PP_BusCTL, 0);
335 /* set the ethernet address */
336 for (i=0; i < ETH_ALEN/2; i++)
337 writereg(PP_IA+i*2,
338 nic->node_addr[i*2] |
339 (nic->node_addr[i*2+1] << 8));
341 /* receive only error free packets addressed to this card */
342 writereg(PP_RxCTL, DEF_RX_ACCEPT);
344 /* do not generate any interrupts on receive operations */
345 writereg(PP_RxCFG, 0);
347 /* do not generate any interrupts on transmit operations */
348 writereg(PP_TxCFG, 0);
350 /* do not generate any interrupts on buffer operations */
351 writereg(PP_BufCFG, 0);
353 /* reset address port, so that autoprobing will keep working */
354 outw(PP_ChipID, eth_nic_base + ADD_PORT);
356 return;
359 /**************************************************************************
360 ETH_TRANSMIT - Transmit a frame
361 ***************************************************************************/
363 static void cs89x0_transmit(
364 struct nic *nic,
365 const char *d, /* Destination */
366 unsigned int t, /* Type */
367 unsigned int s, /* size */
368 const char *p) /* Packet */
370 unsigned long tmo;
371 int sr;
373 /* does this size have to be rounded??? please,
374 somebody have a look in the specs */
375 if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN)
376 sr = ETH_ZLEN;
378 retry:
379 /* initiate a transmit sequence */
380 outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
381 outw(sr, eth_nic_base + TX_LEN_PORT);
383 /* Test to see if the chip has allocated memory for the packet */
384 if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) {
385 /* Oops... this should not happen! */
386 printf("cs: unable to send packet; retrying...\n");
387 for (tmo = currticks() + 5*TICKS_PER_SEC; currticks() < tmo; );
388 cs89x0_reset(nic);
389 goto retry; }
391 /* Write the contents of the packet */
392 outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2);
393 outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr,
394 ETH_ALEN/2);
395 outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
396 outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
397 for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0;
398 outw(0, eth_nic_base + TX_FRAME_PORT));
400 /* wait for transfer to succeed */
401 for (tmo = currticks()+5*TICKS_PER_SEC;
402 (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;)
403 /* nothing */ ;
404 if ((s & TX_SEND_OK_BITS) != TX_OK) {
405 printf("\ntransmission error %#hX\n", s);
408 return;
411 /**************************************************************************
412 ETH_POLL - Wait for a frame
413 ***************************************************************************/
415 static int cs89x0_poll(struct nic *nic)
417 int status;
419 status = readreg(PP_RxEvent);
421 if ((status & RX_OK) == 0)
422 return(0);
424 status = inw(eth_nic_base + RX_FRAME_PORT);
425 nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT);
426 insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1);
427 if (nic->packetlen & 1)
428 nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT);
429 return 1;
432 static void cs89x0_disable(struct nic *nic)
434 cs89x0_reset(nic);
437 /**************************************************************************
438 ETH_PROBE - Look for an adapter
439 ***************************************************************************/
441 struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs)
443 static const unsigned int netcard_portlist[] = {
444 #ifdef CS_SCAN
445 CS_SCAN,
446 #else /* use "conservative" default values for autoprobing */
447 0x300,0x320,0x340,0x200,0x220,0x240,
448 0x260,0x280,0x2a0,0x2c0,0x2e0,
449 /* if that did not work, then be more aggressive */
450 0x301,0x321,0x341,0x201,0x221,0x241,
451 0x261,0x281,0x2a1,0x2c1,0x2e1,
452 #endif
455 int i, result = -1;
456 unsigned rev_type = 0, ioaddr, ioidx, isa_cnf, cs_revision;
457 unsigned short eeprom_buff[CHKSUM_LEN];
460 for (ioidx = 0; (ioaddr=netcard_portlist[ioidx++]) != 0; ) {
461 /* if they give us an odd I/O address, then do ONE write to
462 the address port, to get it back to address zero, where we
463 expect to find the EISA signature word. */
464 if (ioaddr & 1) {
465 ioaddr &= ~1;
466 if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
467 continue;
468 outw(PP_ChipID, ioaddr + ADD_PORT);
471 if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
472 continue;
473 eth_nic_base = ioaddr;
475 /* get the chip type */
476 rev_type = readreg(PRODUCT_ID_ADD);
477 eth_cs_type = rev_type &~ REVISON_BITS;
478 cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
480 printf("\ncs: cs89%c0%s rev %c, base %#hX",
481 eth_cs_type==CS8900?'0':'2',
482 eth_cs_type==CS8920M?"M":"",
483 cs_revision,
484 eth_nic_base);
486 /* First check to see if an EEPROM is attached*/
487 if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) {
488 printf("\ncs: no EEPROM...\n");
489 outw(PP_ChipID, eth_nic_base + ADD_PORT);
490 continue; }
491 else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN,
492 eeprom_buff) < 0) {
493 printf("\ncs: EEPROM read failed...\n");
494 outw(PP_ChipID, eth_nic_base + ADD_PORT);
495 continue; }
496 else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN,
497 eeprom_buff) < 0) {
498 printf("\ncs: EEPROM checksum bad...\n");
499 outw(PP_ChipID, eth_nic_base + ADD_PORT);
500 continue; }
502 /* get transmission control word but keep the
503 autonegotiation bits */
504 eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
505 /* Store adapter configuration */
506 eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
507 /* Store ISA configuration */
508 isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2];
510 /* store the initial memory base address */
511 eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
513 printf("%s%s%s, addr ",
514 (eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"",
515 (eth_adapter_cnf & A_CNF_AUI)?", AUI":"",
516 (eth_adapter_cnf & A_CNF_10B_2)?", BNC":"");
518 /* If this is a CS8900 then no pnp soft */
519 if (eth_cs_type != CS8900 &&
520 /* Check if the ISA IRQ has been set */
521 (i = readreg(PP_CS8920_ISAINT) & 0xff,
522 (i != 0 && i < CS8920_NO_INTS)))
523 eth_irq = i;
524 else {
525 i = isa_cnf & INT_NO_MASK;
526 if (eth_cs_type == CS8900) {
527 /* the table that follows is dependent
528 upon how you wired up your cs8900
529 in your system. The table is the
530 same as the cs8900 engineering demo
531 board. irq_map also depends on the
532 contents of the table. Also see
533 write_irq, which is the reverse
534 mapping of the table below. */
535 if (i < 4) i = "\012\013\014\005"[i];
536 else printf("\ncs: BUG: isa_config is %d\n", i); }
537 eth_irq = i; }
539 /* Retrieve and print the ethernet address. */
540 for (i=0; i<ETH_ALEN; i++) {
541 nic->node_addr[i] = ((unsigned char *)eeprom_buff)[i];
543 printf("%!\n", nic->node_addr);
545 /* Set the LineCTL quintuplet based on adapter
546 configuration read from EEPROM */
547 if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) &&
548 (eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH))
549 eth_linectl = LOW_RX_SQUELCH;
550 else
551 eth_linectl = 0;
553 /* check to make sure that they have the "right"
554 hardware available */
555 switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
556 case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T;
557 break;
558 case A_CNF_MEDIA_AUI: result = eth_adapter_cnf & A_CNF_AUI;
559 break;
560 case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2;
561 break;
562 default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI |
563 A_CNF_10B_2);
565 if (!result) {
566 printf("cs: EEPROM is configured for unavailable media\n");
567 error:
568 writereg(PP_LineCTL, readreg(PP_LineCTL) &
569 ~(SERIAL_TX_ON | SERIAL_RX_ON));
570 outw(PP_ChipID, eth_nic_base + ADD_PORT);
571 continue;
574 /* Initialize the card for probing of the attached media */
575 cs89x0_reset(nic);
577 /* set the hardware to the configured choice */
578 switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
579 case A_CNF_MEDIA_10B_T:
580 result = detect_tp();
581 if (!result) {
582 clrline();
583 printf("10Base-T (RJ-45%s",
584 ") has no cable\n"); }
585 /* check "ignore missing media" bit */
586 if (eth_auto_neg_cnf & IMM_BIT)
587 /* Yes! I don't care if I see a link pulse */
588 result = A_CNF_MEDIA_10B_T;
589 break;
590 case A_CNF_MEDIA_AUI:
591 result = detect_aui(nic);
592 if (!result) {
593 clrline();
594 printf("10Base-5 (AUI%s",
595 ") has no cable\n"); }
596 /* check "ignore missing media" bit */
597 if (eth_auto_neg_cnf & IMM_BIT)
598 /* Yes! I don't care if I see a carrrier */
599 result = A_CNF_MEDIA_AUI;
600 break;
601 case A_CNF_MEDIA_10B_2:
602 result = detect_bnc(nic);
603 if (!result) {
604 clrline();
605 printf("10Base-2 (BNC%s",
606 ") has no cable\n"); }
607 /* check "ignore missing media" bit */
608 if (eth_auto_neg_cnf & IMM_BIT)
609 /* Yes! I don't care if I can xmit a packet */
610 result = A_CNF_MEDIA_10B_2;
611 break;
612 case A_CNF_MEDIA_AUTO:
613 writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET);
614 if (eth_adapter_cnf & A_CNF_10B_T)
615 if ((result = detect_tp()) != 0)
616 break;
617 if (eth_adapter_cnf & A_CNF_AUI)
618 if ((result = detect_aui(nic)) != 0)
619 break;
620 if (eth_adapter_cnf & A_CNF_10B_2)
621 if ((result = detect_bnc(nic)) != 0)
622 break;
623 clrline(); printf("no media detected\n");
624 goto error;
626 clrline();
627 switch(result) {
628 case 0: printf("no network cable attached to configured media\n");
629 goto error;
630 case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\n");
631 break;
632 case A_CNF_MEDIA_AUI: printf("using 10Base-5 (AUI)\n");
633 break;
634 case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\n");
635 break;
638 /* Turn on both receive and transmit operations */
639 writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON |
640 SERIAL_TX_ON);
642 break;
645 if (ioaddr == 0)
646 return (0);
647 nic->reset = cs89x0_reset;
648 nic->poll = cs89x0_poll;
649 nic->transmit = cs89x0_transmit;
650 nic->disable = cs89x0_disable;
651 return (nic);
655 * Local variables:
656 * c-basic-offset: 8
657 * End: