2 #error multicast support is not yet implemented
4 /* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
6 Permission is granted to distribute the enclosed cs89x0.[ch] driver
7 only in conjunction with the Etherboot package. The code is
8 ordinarily distributed under the GPL.
10 Russ Nelson, January 2000
14 Thu Dec 6 22:40:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
16 * disabled all "advanced" features; this should make the code more reliable
18 * reorganized the reset function
20 * always reset the address port, so that autoprobing will continue working
22 * some cosmetic changes
26 Thu Dec 5 21:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
28 * tested the code against a CS8900 card
30 * lots of minor bug fixes and adjustments
32 * this is the first release, that actually works! it still requires some
33 changes in order to be more tolerant to different environments
37 Fri Nov 22 23:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
39 * read the manuals for the CS89x0 chipsets and took note of all the
40 changes that will be neccessary in order to adapt Russel Nelson's code
41 to the requirements of a BOOT-Prom
45 Thu Nov 19 22:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
47 * Synched with Russel Nelson's current code (v1.00)
51 Thu Nov 12 18:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
53 * Cleaned up some of the code and tried to optimize the code size.
57 Sun Nov 10 16:30:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
59 * First experimental release. This code compiles fine, but I
60 have no way of testing whether it actually works.
62 * I did not (yet) bother to make the code 16bit aware, so for
63 the time being, it will only work for Etherboot/32.
69 #include "etherboot.h"
75 static unsigned short eth_nic_base;
76 static unsigned long eth_mem_start;
77 static unsigned short eth_irqno;
78 static unsigned short eth_cs_type; /* one of: CS8900, CS8920, CS8920M */
79 static unsigned short eth_auto_neg_cnf;
80 static unsigned short eth_adapter_cnf;
81 static unsigned short eth_linectl;
83 /*************************************************************************
84 CS89x0 - specific routines
85 **************************************************************************/
87 static inline int readreg(int portno)
89 outw(portno, eth_nic_base + ADD_PORT);
90 return inw(eth_nic_base + DATA_PORT);
93 static inline void writereg(int portno, int value)
95 outw(portno, eth_nic_base + ADD_PORT);
96 outw(value, eth_nic_base + DATA_PORT);
100 /*************************************************************************
102 **************************************************************************/
104 static int wait_eeprom_ready(void)
106 unsigned long tmo = currticks() + 4*TICKS_PER_SEC;
108 /* check to see if the EEPROM is ready, a timeout is used -
109 just in case EEPROM is ready when SI_BUSY in the
110 PP_SelfST is clear */
111 while(readreg(PP_SelfST) & SI_BUSY) {
112 if (currticks() >= tmo)
117 static int get_eeprom_data(int off, int len, unsigned short *buffer)
122 printf("\ncs: EEPROM data from %hX for %hX:",off,len);
124 for (i = 0; i < len; i++) {
125 if (wait_eeprom_ready() < 0)
127 /* Now send the EEPROM read command and EEPROM location
129 writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD);
130 if (wait_eeprom_ready() < 0)
132 buffer[i] = readreg(PP_EEData);
136 printf("%hX ", buffer[i]);
146 static int get_eeprom_chksum(int off __unused, int len, unsigned short *buffer)
151 for (i = 0; i < len; i++)
159 /*************************************************************************
160 Activate all of the available media and probe for network
161 **************************************************************************/
163 static void clrline(void)
168 for (i = 79; i--; ) putchar(' ');
173 static void control_dc_dc(int on_not_off)
175 unsigned int selfcontrol;
176 unsigned long tmo = currticks() + TICKS_PER_SEC;
178 /* control the DC to DC convertor in the SelfControl register. */
179 selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
180 if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
183 selfcontrol &= ~HCB1;
184 writereg(PP_SelfCTL, selfcontrol);
186 /* Wait for the DC/DC converter to power up - 1000ms */
187 while (currticks() < tmo);
192 static int detect_tp(void)
196 /* Turn on the chip auto detection of 10BT/ AUI */
198 clrline(); printf("attempting %s:","TP");
200 /* If connected to another full duplex capable 10-Base-T card
201 the link pulses seem to be lost when the auto detect bit in
202 the LineCTL is set. To overcome this the auto detect bit
203 will be cleared whilst testing the 10-Base-T interface.
204 This would not be necessary for the sparrow chip but is
205 simpler to do it anyway. */
206 writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY);
209 /* Delay for the hardware to work out if the TP cable is
211 for (tmo = currticks() + 4; currticks() < tmo; );
213 if ((readreg(PP_LineST) & LINK_OK) == 0)
216 if (eth_cs_type != CS8900) {
218 writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK);
220 if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
221 printf(" negotiating duplex... ");
222 while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) {
223 if (currticks() - tmo > 40*TICKS_PER_SEC) {
229 if (readreg(PP_AutoNegST) & FDX_ACTIVE)
230 printf("using full duplex");
232 printf("using half duplex");
235 return A_CNF_MEDIA_10B_T;
238 /* send a test packet - return true if carrier bits are ok */
239 static int send_test_pkt(struct nic *nic)
241 static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
242 0, 46, /*A 46 in network order */
243 0, 0, /*DSAP=0 & SSAP=0 fields */
244 0xf3,0 /*Control (Test Req+P bit set)*/ };
247 writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON);
249 memcpy(testpacket, nic->node_addr, ETH_ALEN);
250 memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN);
252 outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
253 outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT);
255 /* Test to see if the chip has allocated memory for the packet */
256 for (tmo = currticks() + 2;
257 (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; )
258 if (currticks() >= tmo)
261 /* Write the contents of the packet */
262 outsw(eth_nic_base + TX_FRAME_PORT, testpacket,
265 printf(" sending test packet ");
266 /* wait a couple of timer ticks for packet to be received */
267 for (tmo = currticks() + 2; currticks() < tmo; );
269 if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
278 static int detect_aui(struct nic *nic)
280 clrline(); printf("attempting %s:","AUI");
283 writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
285 if (send_test_pkt(nic)) {
286 return A_CNF_MEDIA_AUI; }
291 static int detect_bnc(struct nic *nic)
293 clrline(); printf("attempting %s:","BNC");
296 writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
298 if (send_test_pkt(nic)) {
299 return A_CNF_MEDIA_10B_2; }
304 /**************************************************************************
305 ETH_RESET - Reset adapter
306 ***************************************************************************/
308 static void cs89x0_reset(struct nic *nic)
311 unsigned long reset_tmo;
313 writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET);
315 /* wait for two ticks; that is 2*55ms */
316 for (reset_tmo = currticks() + 2; currticks() < reset_tmo; );
318 if (eth_cs_type != CS8900) {
319 /* Hardware problem requires PNP registers to be reconfigured
321 if (eth_irqno != 0xFFFF) {
322 outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT);
323 outb(eth_irqno, eth_nic_base + DATA_PORT);
324 outb(0, eth_nic_base + DATA_PORT + 1); }
327 outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT);
328 outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT);
329 outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } }
331 /* Wait until the chip is reset */
332 for (reset_tmo = currticks() + 2;
333 (readreg(PP_SelfST) & INIT_DONE) == 0 &&
334 currticks() < reset_tmo; );
336 /* disable interrupts and memory accesses */
337 writereg(PP_BusCTL, 0);
339 /* set the ethernet address */
340 for (i=0; i < ETH_ALEN/2; i++)
342 nic->node_addr[i*2] |
343 (nic->node_addr[i*2+1] << 8));
345 /* receive only error free packets addressed to this card */
346 writereg(PP_RxCTL, DEF_RX_ACCEPT);
348 /* do not generate any interrupts on receive operations */
349 writereg(PP_RxCFG, 0);
351 /* do not generate any interrupts on transmit operations */
352 writereg(PP_TxCFG, 0);
354 /* do not generate any interrupts on buffer operations */
355 writereg(PP_BufCFG, 0);
357 /* reset address port, so that autoprobing will keep working */
358 outw(PP_ChipID, eth_nic_base + ADD_PORT);
363 /**************************************************************************
364 ETH_TRANSMIT - Transmit a frame
365 ***************************************************************************/
367 static void cs89x0_transmit(
369 const char *d, /* Destination */
370 unsigned int t, /* Type */
371 unsigned int s, /* size */
372 const char *p) /* Packet */
377 /* does this size have to be rounded??? please,
378 somebody have a look in the specs */
379 if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN)
383 /* initiate a transmit sequence */
384 outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
385 outw(sr, eth_nic_base + TX_LEN_PORT);
387 /* Test to see if the chip has allocated memory for the packet */
388 if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) {
389 /* Oops... this should not happen! */
390 printf("cs: unable to send packet; retrying...\n");
391 for (tmo = currticks() + 5*TICKS_PER_SEC; currticks() < tmo; );
395 /* Write the contents of the packet */
396 outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2);
397 outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr,
399 outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
400 outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
401 for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0;
402 outw(0, eth_nic_base + TX_FRAME_PORT));
404 /* wait for transfer to succeed */
405 for (tmo = currticks()+5*TICKS_PER_SEC;
406 (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;)
408 if ((s & TX_SEND_OK_BITS) != TX_OK) {
409 printf("\ntransmission error %#hX\n", s);
415 /**************************************************************************
416 ETH_POLL - Wait for a frame
417 ***************************************************************************/
419 static int cs89x0_poll(struct nic *nic, int retrieve)
423 status = readreg(PP_RxEvent);
425 if ((status & RX_OK) == 0)
428 if ( ! retrieve ) return 1;
430 status = inw(eth_nic_base + RX_FRAME_PORT);
431 nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT);
432 insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1);
433 if (nic->packetlen & 1)
434 nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT);
438 static void cs89x0_irq(struct nic *nic __unused, irq_action_t action __unused)
450 static struct nic_operations cs89x0_operations = {
451 .connect = dummy_connect,
453 .transmit = cs89x0_transmit,
457 /**************************************************************************
458 ETH_PROBE - Look for an adapter
459 ***************************************************************************/
461 static int cs89x0_probe_addr ( isa_probe_addr_t ioaddr ) {
462 /* if they give us an odd I/O address, then do ONE write to
463 the address port, to get it back to address zero, where we
464 expect to find the EISA signature word. */
467 if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
469 outw(PP_ChipID, ioaddr + ADD_PORT);
472 if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
478 static int cs89x0_probe ( struct nic *nic, struct isa_device *isa ) {
480 unsigned rev_type = 0, isa_cnf, cs_revision;
481 unsigned short eeprom_buff[CHKSUM_LEN];
483 isa_fill_nic ( nic, isa );
484 nic->ioaddr &= ~1; /* LSB = 1 indicates a more aggressive probe */
486 eth_nic_base = nic->ioaddr;
488 /* get the chip type */
489 rev_type = readreg(PRODUCT_ID_ADD);
490 eth_cs_type = rev_type &~ REVISON_BITS;
491 cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
493 printf("\ncs: cs89%c0%s rev %c, base %#hX",
494 eth_cs_type==CS8900?'0':'2',
495 eth_cs_type==CS8920M?"M":"",
499 /* First check to see if an EEPROM is attached*/
500 if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) {
501 printf("\ncs: no EEPROM...\n");
502 outw(PP_ChipID, eth_nic_base + ADD_PORT);
504 } else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN,
506 printf("\ncs: EEPROM read failed...\n");
507 outw(PP_ChipID, eth_nic_base + ADD_PORT);
509 } else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN,
511 printf("\ncs: EEPROM checksum bad...\n");
512 outw(PP_ChipID, eth_nic_base + ADD_PORT);
516 /* get transmission control word but keep the
517 autonegotiation bits */
518 eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
519 /* Store adapter configuration */
520 eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
521 /* Store ISA configuration */
522 isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2];
524 /* store the initial memory base address */
525 eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
527 printf("%s%s%s, addr ",
528 (eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"",
529 (eth_adapter_cnf & A_CNF_AUI)?", AUI":"",
530 (eth_adapter_cnf & A_CNF_10B_2)?", BNC":"");
532 /* If this is a CS8900 then no pnp soft */
533 if (eth_cs_type != CS8900 &&
534 /* Check if the ISA IRQ has been set */
535 (i = readreg(PP_CS8920_ISAINT) & 0xff,
536 (i != 0 && i < CS8920_NO_INTS)))
539 i = isa_cnf & INT_NO_MASK;
540 if (eth_cs_type == CS8900) {
541 /* the table that follows is dependent
542 upon how you wired up your cs8900
543 in your system. The table is the
544 same as the cs8900 engineering demo
545 board. irq_map also depends on the
546 contents of the table. Also see
547 write_irq, which is the reverse
548 mapping of the table below. */
549 if (i < 4) i = "\012\013\014\005"[i];
550 else printf("\ncs: BUG: isa_config is %d\n", i); }
553 /* Retrieve and print the ethernet address. */
554 for (i=0; i<ETH_ALEN; i++) {
555 nic->node_addr[i] = ((unsigned char *)eeprom_buff)[i];
557 printf("%!\n", nic->node_addr);
560 /* Retrieve and print the ethernet address. */
562 unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
563 memcpy(nic->node_addr, MAC_HW_ADDR, 6);
565 printf("\n%!\n", nic->node_addr);
567 eth_adapter_cnf = A_CNF_10B_T | A_CNF_MEDIA_10B_T;
568 eth_auto_neg_cnf = EE_AUTO_NEG_ENABLE | IMM_BIT;
571 /* Set the LineCTL quintuplet based on adapter
572 configuration read from EEPROM */
573 if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) &&
574 (eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH))
575 eth_linectl = LOW_RX_SQUELCH;
579 /* check to make sure that they have the "right"
580 hardware available */
581 switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
582 case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T;
584 case A_CNF_MEDIA_AUI: result = eth_adapter_cnf & A_CNF_AUI;
586 case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2;
588 default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI |
592 printf("cs: EEPROM is configured for unavailable media\n");
594 writereg(PP_LineCTL, readreg(PP_LineCTL) &
595 ~(SERIAL_TX_ON | SERIAL_RX_ON));
596 outw(PP_ChipID, eth_nic_base + ADD_PORT);
600 /* Initialize the card for probing of the attached media */
603 /* set the hardware to the configured choice */
604 switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
605 case A_CNF_MEDIA_10B_T:
606 result = detect_tp();
609 printf("10Base-T (RJ-45%s",
610 ") has no cable\n"); }
611 /* check "ignore missing media" bit */
612 if (eth_auto_neg_cnf & IMM_BIT)
613 /* Yes! I don't care if I see a link pulse */
614 result = A_CNF_MEDIA_10B_T;
616 case A_CNF_MEDIA_AUI:
617 result = detect_aui(nic);
620 printf("10Base-5 (AUI%s",
621 ") has no cable\n"); }
622 /* check "ignore missing media" bit */
623 if (eth_auto_neg_cnf & IMM_BIT)
624 /* Yes! I don't care if I see a carrrier */
625 result = A_CNF_MEDIA_AUI;
627 case A_CNF_MEDIA_10B_2:
628 result = detect_bnc(nic);
631 printf("10Base-2 (BNC%s",
632 ") has no cable\n"); }
633 /* check "ignore missing media" bit */
634 if (eth_auto_neg_cnf & IMM_BIT)
635 /* Yes! I don't care if I can xmit a packet */
636 result = A_CNF_MEDIA_10B_2;
638 case A_CNF_MEDIA_AUTO:
639 writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET);
640 if (eth_adapter_cnf & A_CNF_10B_T)
641 if ((result = detect_tp()) != 0)
643 if (eth_adapter_cnf & A_CNF_AUI)
644 if ((result = detect_aui(nic)) != 0)
646 if (eth_adapter_cnf & A_CNF_10B_2)
647 if ((result = detect_bnc(nic)) != 0)
649 clrline(); printf("no media detected\n");
654 case 0: printf("no network cable attached to configured media\n");
656 case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\n");
658 case A_CNF_MEDIA_AUI: printf("using 10Base-5 (AUI)\n");
660 case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\n");
664 /* Turn on both receive and transmit operations */
665 writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON |
671 writereg(PP_LineCTL, readreg(PP_LineCTL) &
672 ~(SERIAL_TX_ON | SERIAL_RX_ON));
673 outw(PP_ChipID, eth_nic_base + ADD_PORT);
677 nic->nic_op = &cs89x0_operations;
681 static void cs89x0_disable ( struct nic *nic,
682 struct isa_device *isa __unused ) {
686 static isa_probe_addr_t cs89x0_probe_addrs[] = {
688 /* use "conservative" default values for autoprobing */
689 0x300, 0x320, 0x340, 0x200, 0x220, 0x240,
690 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
691 /* if that did not work, then be more aggressive */
692 0x301, 0x321, 0x341, 0x201, 0x221, 0x241,
693 0x261, 0x281, 0x2a1, 0x2c1, 0x2e1,
699 ISA_DRIVER ( cs89x0_driver, cs89x0_probe_addrs, cs89x0_probe_addr,
700 ISAPNP_VENDOR('C','S','C'), 0x0007 );
702 DRIVER ( "cs89x0", nic_driver, isa_driver, cs89x0_driver,
703 cs89x0_probe, cs89x0_disable );
705 ISA_ROM ( "cs89x0", "Crystal Semiconductor CS89x0" );