2 #error multicast support is not yet implemented
6 Per an email message from Russ Nelson <nelson@crynwr.com> on
7 18 March 2008 this file is now licensed under GPL Version 2.
9 From: Russ Nelson <nelson@crynwr.com>
10 Date: Tue, 18 Mar 2008 12:42:00 -0400
11 Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
13 As copyright holder, if I say it doesn't conflict with the GPL,
14 then it doesn't conflict with the GPL.
16 However, there's no point in causing people's brains to overheat,
17 so yes, I grant permission for the code to be relicensed under the
18 GPLv2. Please make sure that this change in licensing makes its
23 /* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
25 Permission is granted to distribute the enclosed cs89x0.[ch] driver
26 only in conjunction with the Etherboot package. The code is
27 ordinarily distributed under the GPL.
29 Russ Nelson, January 2000
33 Thu Dec 6 22:40:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
35 * disabled all "advanced" features; this should make the code more reliable
37 * reorganized the reset function
39 * always reset the address port, so that autoprobing will continue working
41 * some cosmetic changes
45 Thu Dec 5 21:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
47 * tested the code against a CS8900 card
49 * lots of minor bug fixes and adjustments
51 * this is the first release, that actually works! it still requires some
52 changes in order to be more tolerant to different environments
56 Fri Nov 22 23:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
58 * read the manuals for the CS89x0 chipsets and took note of all the
59 changes that will be neccessary in order to adapt Russel Nelson's code
60 to the requirements of a BOOT-Prom
64 Thu Nov 19 22:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
66 * Synched with Russel Nelson's current code (v1.00)
70 Thu Nov 12 18:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
72 * Cleaned up some of the code and tried to optimize the code size.
76 Sun Nov 10 16:30:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
78 * First experimental release. This code compiles fine, but I
79 have no way of testing whether it actually works.
81 * I did not (yet) bother to make the code 16bit aware, so for
82 the time being, it will only work for Etherboot/32.
89 #include <gpxe/ethernet.h>
90 #include "etherboot.h"
96 static unsigned short eth_nic_base
;
97 static unsigned long eth_mem_start
;
98 static unsigned short eth_irqno
;
99 static unsigned short eth_cs_type
; /* one of: CS8900, CS8920, CS8920M */
100 static unsigned short eth_auto_neg_cnf
;
101 static unsigned short eth_adapter_cnf
;
102 static unsigned short eth_linectl
;
104 /*************************************************************************
105 CS89x0 - specific routines
106 **************************************************************************/
108 static inline int readreg(int portno
)
110 outw(portno
, eth_nic_base
+ ADD_PORT
);
111 return inw(eth_nic_base
+ DATA_PORT
);
114 static inline void writereg(int portno
, int value
)
116 outw(portno
, eth_nic_base
+ ADD_PORT
);
117 outw(value
, eth_nic_base
+ DATA_PORT
);
121 /*************************************************************************
123 **************************************************************************/
125 static int wait_eeprom_ready(void)
127 unsigned long tmo
= currticks() + 4*TICKS_PER_SEC
;
129 /* check to see if the EEPROM is ready, a timeout is used -
130 just in case EEPROM is ready when SI_BUSY in the
131 PP_SelfST is clear */
132 while(readreg(PP_SelfST
) & SI_BUSY
) {
133 if (currticks() >= tmo
)
138 static int get_eeprom_data(int off
, int len
, unsigned short *buffer
)
143 printf("\ncs: EEPROM data from %hX for %hX:",off
,len
);
145 for (i
= 0; i
< len
; i
++) {
146 if (wait_eeprom_ready() < 0)
148 /* Now send the EEPROM read command and EEPROM location
150 writereg(PP_EECMD
, (off
+ i
) | EEPROM_READ_CMD
);
151 if (wait_eeprom_ready() < 0)
153 buffer
[i
] = readreg(PP_EEData
);
157 printf("%hX ", buffer
[i
]);
167 static int get_eeprom_chksum(int off __unused
, int len
, unsigned short *buffer
)
172 for (i
= 0; i
< len
; i
++)
180 /*************************************************************************
181 Activate all of the available media and probe for network
182 **************************************************************************/
184 static void clrline(void)
189 for (i
= 79; i
--; ) putchar(' ');
194 static void control_dc_dc(int on_not_off
)
196 unsigned int selfcontrol
;
197 unsigned long tmo
= currticks() + TICKS_PER_SEC
;
199 /* control the DC to DC convertor in the SelfControl register. */
200 selfcontrol
= HCB1_ENBL
; /* Enable the HCB1 bit as an output */
201 if (((eth_adapter_cnf
& A_CNF_DC_DC_POLARITY
) != 0) ^ on_not_off
)
204 selfcontrol
&= ~HCB1
;
205 writereg(PP_SelfCTL
, selfcontrol
);
207 /* Wait for the DC/DC converter to power up - 1000ms */
208 while (currticks() < tmo
);
213 static int detect_tp(void)
217 /* Turn on the chip auto detection of 10BT/ AUI */
219 clrline(); printf("attempting %s:","TP");
221 /* If connected to another full duplex capable 10-Base-T card
222 the link pulses seem to be lost when the auto detect bit in
223 the LineCTL is set. To overcome this the auto detect bit
224 will be cleared whilst testing the 10-Base-T interface.
225 This would not be necessary for the sparrow chip but is
226 simpler to do it anyway. */
227 writereg(PP_LineCTL
, eth_linectl
&~ AUI_ONLY
);
230 /* Delay for the hardware to work out if the TP cable is
232 for (tmo
= currticks() + 4; currticks() < tmo
; );
234 if ((readreg(PP_LineST
) & LINK_OK
) == 0)
237 if (eth_cs_type
!= CS8900
) {
239 writereg(PP_AutoNegCTL
, eth_auto_neg_cnf
& AUTO_NEG_MASK
);
241 if ((eth_auto_neg_cnf
& AUTO_NEG_BITS
) == AUTO_NEG_ENABLE
) {
242 printf(" negotiating duplex... ");
243 while (readreg(PP_AutoNegST
) & AUTO_NEG_BUSY
) {
244 if (currticks() - tmo
> 40*TICKS_PER_SEC
) {
250 if (readreg(PP_AutoNegST
) & FDX_ACTIVE
)
251 printf("using full duplex");
253 printf("using half duplex");
256 return A_CNF_MEDIA_10B_T
;
259 /* send a test packet - return true if carrier bits are ok */
260 static int send_test_pkt(struct nic
*nic
)
262 static unsigned char testpacket
[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
263 0, 46, /*A 46 in network order */
264 0, 0, /*DSAP=0 & SSAP=0 fields */
265 0xf3,0 /*Control (Test Req+P bit set)*/ };
268 writereg(PP_LineCTL
, readreg(PP_LineCTL
) | SERIAL_TX_ON
);
270 memcpy(testpacket
, nic
->node_addr
, ETH_ALEN
);
271 memcpy(testpacket
+ETH_ALEN
, nic
->node_addr
, ETH_ALEN
);
273 outw(TX_AFTER_ALL
, eth_nic_base
+ TX_CMD_PORT
);
274 outw(ETH_ZLEN
, eth_nic_base
+ TX_LEN_PORT
);
276 /* Test to see if the chip has allocated memory for the packet */
277 for (tmo
= currticks() + 2;
278 (readreg(PP_BusST
) & READY_FOR_TX_NOW
) == 0; )
279 if (currticks() >= tmo
)
282 /* Write the contents of the packet */
283 outsw(eth_nic_base
+ TX_FRAME_PORT
, testpacket
,
286 printf(" sending test packet ");
287 /* wait a couple of timer ticks for packet to be received */
288 for (tmo
= currticks() + 2; currticks() < tmo
; );
290 if ((readreg(PP_TxEvent
) & TX_SEND_OK_BITS
) == TX_OK
) {
299 static int detect_aui(struct nic
*nic
)
301 clrline(); printf("attempting %s:","AUI");
304 writereg(PP_LineCTL
, (eth_linectl
& ~AUTO_AUI_10BASET
) | AUI_ONLY
);
306 if (send_test_pkt(nic
)) {
307 return A_CNF_MEDIA_AUI
; }
312 static int detect_bnc(struct nic
*nic
)
314 clrline(); printf("attempting %s:","BNC");
317 writereg(PP_LineCTL
, (eth_linectl
& ~AUTO_AUI_10BASET
) | AUI_ONLY
);
319 if (send_test_pkt(nic
)) {
320 return A_CNF_MEDIA_10B_2
; }
325 /**************************************************************************
326 ETH_RESET - Reset adapter
327 ***************************************************************************/
329 static void cs89x0_reset(struct nic
*nic
)
332 unsigned long reset_tmo
;
334 writereg(PP_SelfCTL
, readreg(PP_SelfCTL
) | POWER_ON_RESET
);
336 /* wait for two ticks; that is 2*55ms */
337 for (reset_tmo
= currticks() + 2; currticks() < reset_tmo
; );
339 if (eth_cs_type
!= CS8900
) {
340 /* Hardware problem requires PNP registers to be reconfigured
342 if (eth_irqno
!= 0xFFFF) {
343 outw(PP_CS8920_ISAINT
, eth_nic_base
+ ADD_PORT
);
344 outb(eth_irqno
, eth_nic_base
+ DATA_PORT
);
345 outb(0, eth_nic_base
+ DATA_PORT
+ 1); }
348 outw(PP_CS8920_ISAMemB
, eth_nic_base
+ ADD_PORT
);
349 outb((eth_mem_start
>> 8) & 0xff, eth_nic_base
+ DATA_PORT
);
350 outb((eth_mem_start
>> 24) & 0xff, eth_nic_base
+ DATA_PORT
+ 1); } }
352 /* Wait until the chip is reset */
353 for (reset_tmo
= currticks() + 2;
354 (readreg(PP_SelfST
) & INIT_DONE
) == 0 &&
355 currticks() < reset_tmo
; );
357 /* disable interrupts and memory accesses */
358 writereg(PP_BusCTL
, 0);
360 /* set the ethernet address */
361 for (i
=0; i
< ETH_ALEN
/2; i
++)
363 nic
->node_addr
[i
*2] |
364 (nic
->node_addr
[i
*2+1] << 8));
366 /* receive only error free packets addressed to this card */
367 writereg(PP_RxCTL
, DEF_RX_ACCEPT
);
369 /* do not generate any interrupts on receive operations */
370 writereg(PP_RxCFG
, 0);
372 /* do not generate any interrupts on transmit operations */
373 writereg(PP_TxCFG
, 0);
375 /* do not generate any interrupts on buffer operations */
376 writereg(PP_BufCFG
, 0);
378 /* reset address port, so that autoprobing will keep working */
379 outw(PP_ChipID
, eth_nic_base
+ ADD_PORT
);
384 /**************************************************************************
385 ETH_TRANSMIT - Transmit a frame
386 ***************************************************************************/
388 static void cs89x0_transmit(
390 const char *d
, /* Destination */
391 unsigned int t
, /* Type */
392 unsigned int s
, /* size */
393 const char *p
) /* Packet */
398 /* does this size have to be rounded??? please,
399 somebody have a look in the specs */
400 if ((sr
= ((s
+ ETH_HLEN
+ 1)&~1)) < ETH_ZLEN
)
404 /* initiate a transmit sequence */
405 outw(TX_AFTER_ALL
, eth_nic_base
+ TX_CMD_PORT
);
406 outw(sr
, eth_nic_base
+ TX_LEN_PORT
);
408 /* Test to see if the chip has allocated memory for the packet */
409 if ((readreg(PP_BusST
) & READY_FOR_TX_NOW
) == 0) {
410 /* Oops... this should not happen! */
411 printf("cs: unable to send packet; retrying...\n");
412 for (tmo
= currticks() + 5*TICKS_PER_SEC
; currticks() < tmo
; );
416 /* Write the contents of the packet */
417 outsw(eth_nic_base
+ TX_FRAME_PORT
, d
, ETH_ALEN
/2);
418 outsw(eth_nic_base
+ TX_FRAME_PORT
, nic
->node_addr
,
420 outw(((t
>> 8)&0xFF)|(t
<< 8), eth_nic_base
+ TX_FRAME_PORT
);
421 outsw(eth_nic_base
+ TX_FRAME_PORT
, p
, (s
+1)/2);
422 for (sr
= sr
/2 - (s
+1)/2 - ETH_ALEN
- 1; sr
-- > 0;
423 outw(0, eth_nic_base
+ TX_FRAME_PORT
));
425 /* wait for transfer to succeed */
426 for (tmo
= currticks()+5*TICKS_PER_SEC
;
427 (s
= readreg(PP_TxEvent
)&~0x1F) == 0 && currticks() < tmo
;)
429 if ((s
& TX_SEND_OK_BITS
) != TX_OK
) {
430 printf("\ntransmission error %#hX\n", s
);
436 /**************************************************************************
437 ETH_POLL - Wait for a frame
438 ***************************************************************************/
440 static int cs89x0_poll(struct nic
*nic
, int retrieve
)
444 status
= readreg(PP_RxEvent
);
446 if ((status
& RX_OK
) == 0)
449 if ( ! retrieve
) return 1;
451 status
= inw(eth_nic_base
+ RX_FRAME_PORT
);
452 nic
->packetlen
= inw(eth_nic_base
+ RX_FRAME_PORT
);
453 insw(eth_nic_base
+ RX_FRAME_PORT
, nic
->packet
, nic
->packetlen
>> 1);
454 if (nic
->packetlen
& 1)
455 nic
->packet
[nic
->packetlen
-1] = inw(eth_nic_base
+ RX_FRAME_PORT
);
459 static void cs89x0_irq(struct nic
*nic __unused
, irq_action_t action __unused
)
471 static struct nic_operations cs89x0_operations
= {
472 .connect
= dummy_connect
,
474 .transmit
= cs89x0_transmit
,
478 /**************************************************************************
479 ETH_PROBE - Look for an adapter
480 ***************************************************************************/
482 static int cs89x0_probe_addr ( isa_probe_addr_t ioaddr
) {
483 /* if they give us an odd I/O address, then do ONE write to
484 the address port, to get it back to address zero, where we
485 expect to find the EISA signature word. */
488 if ((inw(ioaddr
+ ADD_PORT
) & ADD_MASK
) != ADD_SIG
)
490 outw(PP_ChipID
, ioaddr
+ ADD_PORT
);
493 if (inw(ioaddr
+ DATA_PORT
) != CHIP_EISA_ID_SIG
)
499 static int cs89x0_probe ( struct nic
*nic
, struct isa_device
*isa __unused
) {
501 unsigned rev_type
= 0, isa_cnf
, cs_revision
;
502 unsigned short eeprom_buff
[CHKSUM_LEN
];
504 nic
->ioaddr
&= ~1; /* LSB = 1 indicates a more aggressive probe */
505 eth_nic_base
= nic
->ioaddr
;
507 /* get the chip type */
508 rev_type
= readreg(PRODUCT_ID_ADD
);
509 eth_cs_type
= rev_type
&~ REVISON_BITS
;
510 cs_revision
= ((rev_type
& REVISON_BITS
) >> 8) + 'A';
512 printf("\ncs: cs89%c0%s rev %c, base %#hX",
513 eth_cs_type
==CS8900
?'0':'2',
514 eth_cs_type
==CS8920M
?"M":"",
518 /* First check to see if an EEPROM is attached*/
519 if ((readreg(PP_SelfST
) & EEPROM_PRESENT
) == 0) {
520 printf("\ncs: no EEPROM...\n");
521 outw(PP_ChipID
, eth_nic_base
+ ADD_PORT
);
523 } else if (get_eeprom_data(START_EEPROM_DATA
,CHKSUM_LEN
,
525 printf("\ncs: EEPROM read failed...\n");
526 outw(PP_ChipID
, eth_nic_base
+ ADD_PORT
);
528 } else if (get_eeprom_chksum(START_EEPROM_DATA
,CHKSUM_LEN
,
530 printf("\ncs: EEPROM checksum bad...\n");
531 outw(PP_ChipID
, eth_nic_base
+ ADD_PORT
);
535 /* get transmission control word but keep the
536 autonegotiation bits */
537 eth_auto_neg_cnf
= eeprom_buff
[AUTO_NEG_CNF_OFFSET
/2];
538 /* Store adapter configuration */
539 eth_adapter_cnf
= eeprom_buff
[ADAPTER_CNF_OFFSET
/2];
540 /* Store ISA configuration */
541 isa_cnf
= eeprom_buff
[ISA_CNF_OFFSET
/2];
543 /* store the initial memory base address */
544 eth_mem_start
= eeprom_buff
[PACKET_PAGE_OFFSET
/2] << 8;
546 printf("%s%s%s, addr ",
547 (eth_adapter_cnf
& A_CNF_10B_T
)?", RJ-45":"",
548 (eth_adapter_cnf
& A_CNF_AUI
)?", AUI":"",
549 (eth_adapter_cnf
& A_CNF_10B_2
)?", BNC":"");
551 /* If this is a CS8900 then no pnp soft */
552 if (eth_cs_type
!= CS8900
&&
553 /* Check if the ISA IRQ has been set */
554 (i
= readreg(PP_CS8920_ISAINT
) & 0xff,
555 (i
!= 0 && i
< CS8920_NO_INTS
)))
558 i
= isa_cnf
& INT_NO_MASK
;
559 if (eth_cs_type
== CS8900
) {
560 /* the table that follows is dependent
561 upon how you wired up your cs8900
562 in your system. The table is the
563 same as the cs8900 engineering demo
564 board. irq_map also depends on the
565 contents of the table. Also see
566 write_irq, which is the reverse
567 mapping of the table below. */
568 if (i
< 4) i
= "\012\013\014\005"[i
];
569 else printf("\ncs: BUG: isa_config is %d\n", i
); }
572 nic
->irqno
= eth_irqno
;
574 /* Retrieve and print the ethernet address. */
575 for (i
=0; i
<ETH_ALEN
; i
++) {
576 nic
->node_addr
[i
] = ((unsigned char *)eeprom_buff
)[i
];
579 DBG ( "%s\n", eth_ntoa ( nic
->node_addr
) );
583 /* Retrieve and print the ethernet address. */
585 unsigned char MAC_HW_ADDR
[6]={MAC_HW_ADDR_DRV
};
586 memcpy(nic
->node_addr
, MAC_HW_ADDR
, 6);
589 DBG ( "%s\n", eth_ntoa ( nic
->node_addr
) );
591 eth_adapter_cnf
= A_CNF_10B_T
| A_CNF_MEDIA_10B_T
;
592 eth_auto_neg_cnf
= EE_AUTO_NEG_ENABLE
| IMM_BIT
;
595 /* Set the LineCTL quintuplet based on adapter
596 configuration read from EEPROM */
597 if ((eth_adapter_cnf
& A_CNF_EXTND_10B_2
) &&
598 (eth_adapter_cnf
& A_CNF_LOW_RX_SQUELCH
))
599 eth_linectl
= LOW_RX_SQUELCH
;
603 /* check to make sure that they have the "right"
604 hardware available */
605 switch(eth_adapter_cnf
& A_CNF_MEDIA_TYPE
) {
606 case A_CNF_MEDIA_10B_T
: result
= eth_adapter_cnf
& A_CNF_10B_T
;
608 case A_CNF_MEDIA_AUI
: result
= eth_adapter_cnf
& A_CNF_AUI
;
610 case A_CNF_MEDIA_10B_2
: result
= eth_adapter_cnf
& A_CNF_10B_2
;
612 default: result
= eth_adapter_cnf
& (A_CNF_10B_T
| A_CNF_AUI
|
616 printf("cs: EEPROM is configured for unavailable media\n");
618 writereg(PP_LineCTL
, readreg(PP_LineCTL
) &
619 ~(SERIAL_TX_ON
| SERIAL_RX_ON
));
620 outw(PP_ChipID
, eth_nic_base
+ ADD_PORT
);
624 /* Initialize the card for probing of the attached media */
627 /* set the hardware to the configured choice */
628 switch(eth_adapter_cnf
& A_CNF_MEDIA_TYPE
) {
629 case A_CNF_MEDIA_10B_T
:
630 result
= detect_tp();
633 printf("10Base-T (RJ-45%s",
634 ") has no cable\n"); }
635 /* check "ignore missing media" bit */
636 if (eth_auto_neg_cnf
& IMM_BIT
)
637 /* Yes! I don't care if I see a link pulse */
638 result
= A_CNF_MEDIA_10B_T
;
640 case A_CNF_MEDIA_AUI
:
641 result
= detect_aui(nic
);
644 printf("10Base-5 (AUI%s",
645 ") has no cable\n"); }
646 /* check "ignore missing media" bit */
647 if (eth_auto_neg_cnf
& IMM_BIT
)
648 /* Yes! I don't care if I see a carrrier */
649 result
= A_CNF_MEDIA_AUI
;
651 case A_CNF_MEDIA_10B_2
:
652 result
= detect_bnc(nic
);
655 printf("10Base-2 (BNC%s",
656 ") has no cable\n"); }
657 /* check "ignore missing media" bit */
658 if (eth_auto_neg_cnf
& IMM_BIT
)
659 /* Yes! I don't care if I can xmit a packet */
660 result
= A_CNF_MEDIA_10B_2
;
662 case A_CNF_MEDIA_AUTO
:
663 writereg(PP_LineCTL
, eth_linectl
| AUTO_AUI_10BASET
);
664 if (eth_adapter_cnf
& A_CNF_10B_T
)
665 if ((result
= detect_tp()) != 0)
667 if (eth_adapter_cnf
& A_CNF_AUI
)
668 if ((result
= detect_aui(nic
)) != 0)
670 if (eth_adapter_cnf
& A_CNF_10B_2
)
671 if ((result
= detect_bnc(nic
)) != 0)
673 clrline(); printf("no media detected\n");
678 case 0: printf("no network cable attached to configured media\n");
680 case A_CNF_MEDIA_10B_T
: printf("using 10Base-T (RJ-45)\n");
682 case A_CNF_MEDIA_AUI
: printf("using 10Base-5 (AUI)\n");
684 case A_CNF_MEDIA_10B_2
: printf("using 10Base-2 (BNC)\n");
688 /* Turn on both receive and transmit operations */
689 writereg(PP_LineCTL
, readreg(PP_LineCTL
) | SERIAL_RX_ON
|
695 writereg(PP_LineCTL
, readreg(PP_LineCTL
) &
696 ~(SERIAL_TX_ON
| SERIAL_RX_ON
));
697 outw(PP_ChipID
, eth_nic_base
+ ADD_PORT
);
701 nic
->nic_op
= &cs89x0_operations
;
705 static void cs89x0_disable ( struct nic
*nic
,
706 struct isa_device
*isa __unused
) {
710 static isa_probe_addr_t cs89x0_probe_addrs
[] = {
712 /* use "conservative" default values for autoprobing */
713 0x300, 0x320, 0x340, 0x200, 0x220, 0x240,
714 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
715 /* if that did not work, then be more aggressive */
716 0x301, 0x321, 0x341, 0x201, 0x221, 0x241,
717 0x261, 0x281, 0x2a1, 0x2c1, 0x2e1,
723 ISA_DRIVER ( cs89x0_driver
, cs89x0_probe_addrs
, cs89x0_probe_addr
,
724 ISAPNP_VENDOR('C','S','C'), 0x0007 );
726 DRIVER ( "cs89x0", nic_driver
, isa_driver
, cs89x0_driver
,
727 cs89x0_probe
, cs89x0_disable
);
729 ISA_ROM ( "cs89x0", "Crystal Semiconductor CS89x0" );