Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub / netboot / natsemi.c
blob56ff42dc4792dd5db4662b9fe8e962e6a7b620f9
1 /* -*- Mode:C; c-basic-offset:4; -*- */
3 /*
4 natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
6 Copyright (C) 2001 Entity Cyber, Inc.
8 This development of this Etherboot driver was funded by
10 Sicom Systems: http://www.sicompos.com/
12 Author: Marty Connor (mdc@thinguin.org)
13 Adapted from a Linux driver which was written by Donald Becker
15 This software may be used and distributed according to the terms
16 of the GNU Public License (GPL), incorporated herein by reference.
18 Original Copyright Notice:
20 Written/copyright 1999-2001 by Donald Becker.
22 This software may be used and distributed according to the terms of
23 the GNU General Public License (GPL), incorporated herein by reference.
24 Drivers based on or derived from this code fall under the GPL and must
25 retain the authorship, copyright and license notice. This file is not
26 a complete program and may only be used when the entire operating
27 system is licensed under the GPL. License for under other terms may be
28 available. Contact the original author for details.
30 The original author may be reached as becker@scyld.com, or at
31 Scyld Computing Corporation
32 410 Severn Ave., Suite 210
33 Annapolis MD 21403
35 Support information and updates available at
36 http://www.scyld.com/network/netsemi.html
38 References:
40 http://www.scyld.com/expert/100mbps.html
41 http://www.scyld.com/expert/NWay.html
42 Datasheet is available from:
43 http://www.national.com/pf/DP/DP83815.html
47 /* Revision History */
50 29 May 2001 mdc 1.0
51 Initial Release. Tested with Netgear FA311 and FA312 boards
52 */\f
53 /* Includes */
55 #include "etherboot.h"
56 #include "nic.h"
57 #include "pci.h"
58 #include "cards.h"
60 /* defines */
62 #define OWN 0x80000000
63 #define DSIZE 0x00000FFF
64 #define CRC_SIZE 4
66 /* Time in ticks before concluding the transmitter is hung. */
67 #define TX_TIMEOUT (4*TICKS_PER_SEC)
69 #define TX_BUF_SIZE 1536
70 #define RX_BUF_SIZE 1536
72 #define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
74 typedef unsigned char u8;
75 typedef signed char s8;
76 typedef unsigned short u16;
77 typedef signed short s16;
78 typedef unsigned int u32;
79 typedef signed int s32;
81 /* helpful macroes if on a big_endian machine for changing byte order.
82 not strictly needed on Intel */
83 #define le16_to_cpu(val) (val)
84 #define cpu_to_le32(val) (val)
85 #define get_unaligned(ptr) (*(ptr))
86 #define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
87 #define get_u16(ptr) (*(u16 *)(ptr))
88 #define virt_to_bus(x) ((unsigned long)x)
89 #define virt_to_le32desc(addr) virt_to_bus(addr)
91 enum pcistuff {
92 PCI_USES_IO = 0x01,
93 PCI_USES_MEM = 0x02,
94 PCI_USES_MASTER = 0x04,
95 PCI_ADDR0 = 0x08,
96 PCI_ADDR1 = 0x10,
99 /* MMIO operations required */
100 #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
102 /* Offsets to the device registers.
103 Unlike software-only systems, device drivers interact with complex hardware.
104 It's not useful to define symbolic names for every register bit in the
105 device.
107 enum register_offsets {
108 ChipCmd = 0x00,
109 ChipConfig = 0x04,
110 EECtrl = 0x08,
111 PCIBusCfg = 0x0C,
112 IntrStatus = 0x10,
113 IntrMask = 0x14,
114 IntrEnable = 0x18,
115 TxRingPtr = 0x20,
116 TxConfig = 0x24,
117 RxRingPtr = 0x30,
118 RxConfig = 0x34,
119 ClkRun = 0x3C,
120 WOLCmd = 0x40,
121 PauseCmd = 0x44,
122 RxFilterAddr = 0x48,
123 RxFilterData = 0x4C,
124 BootRomAddr = 0x50,
125 BootRomData = 0x54,
126 SiliconRev = 0x58,
127 StatsCtrl = 0x5C,
128 StatsData = 0x60,
129 RxPktErrs = 0x60,
130 RxMissed = 0x68,
131 RxCRCErrs = 0x64,
132 PCIPM = 0x44,
133 PhyStatus = 0xC0,
134 MIntrCtrl = 0xC4,
135 MIntrStatus = 0xC8,
137 /* These are from the spec, around page 78... on a separate table. */
138 PGSEL = 0xCC,
139 PMDCSR = 0xE4,
140 TSTDAT = 0xFC,
141 DSPCFG = 0xF4,
142 SDCFG = 0x8C
145 /* Bit in ChipCmd. */
146 enum ChipCmdBits {
147 ChipReset = 0x100,
148 RxReset = 0x20,
149 TxReset = 0x10,
150 RxOff = 0x08,
151 RxOn = 0x04,
152 TxOff = 0x02,
153 TxOn = 0x01
156 /* Bits in the RxMode register. */
157 enum rx_mode_bits {
158 AcceptErr = 0x20,
159 AcceptRunt = 0x10,
160 AcceptBroadcast = 0xC0000000,
161 AcceptMulticast = 0x00200000,
162 AcceptAllMulticast = 0x20000000,
163 AcceptAllPhys = 0x10000000,
164 AcceptMyPhys = 0x08000000
167 typedef struct _BufferDesc {
168 u32 link;
169 volatile u32 cmdsts;
170 u32 bufptr;
171 u32 software_use;
172 } BufferDesc;
174 /* Bits in network_desc.status */
175 enum desc_status_bits {
176 DescOwn = 0x80000000,
177 DescMore = 0x40000000,
178 DescIntr = 0x20000000,
179 DescNoCRC = 0x10000000,
180 DescPktOK = 0x08000000,
181 RxTooLong = 0x00400000
184 /* Globals */
186 static int natsemi_debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
188 const char *nic_name;
190 static u32 SavedClkRun;
193 static unsigned short vendor, dev_id;
194 static unsigned long ioaddr;
196 static unsigned int cur_rx;
198 static unsigned int advertising;
200 static unsigned int rx_config;
201 static unsigned int tx_config;
203 /* Note: transmit and receive buffers and descriptors must be
204 longword aligned
207 static BufferDesc txd __attribute__ ((aligned(4)));
208 static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4)));
210 #ifdef USE_LOWMEM_BUFFER
211 #define txb ((char *)0x10000 - TX_BUF_SIZE)
212 #define rxb ((char *)0x10000 - NUM_RX_DESC*RX_BUF_SIZE - TX_BUF_SIZE)
213 #else
214 static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
215 static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE] __attribute__ ((aligned(4)));
216 #endif
218 /* Function Prototypes */
220 struct nic *natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci);
221 static int eeprom_read(long addr, int location);
222 static int mdio_read(int phy_id, int location);
223 static void natsemi_init(struct nic *nic);
224 static void natsemi_reset(struct nic *nic);
225 static void natsemi_init_rxfilter(struct nic *nic);
226 static void natsemi_init_txd(struct nic *nic);
227 static void natsemi_init_rxd(struct nic *nic);
228 static void natsemi_set_rx_mode(struct nic *nic);
229 static void natsemi_check_duplex(struct nic *nic);
230 static void natsemi_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);
231 static int natsemi_poll(struct nic *nic);
232 static void natsemi_disable(struct nic *nic);
235 * Function: natsemi_probe
237 * Description: Retrieves the MAC address of the card, and sets up some
238 * globals required by other routines, and initializes the NIC, making it
239 * ready to send and receive packets.
241 * Side effects:
242 * leaves the ioaddress of the natsemi chip in the variable ioaddr.
243 * leaves the natsemi initialized, and ready to recieve packets.
245 * Returns: struct nic *: pointer to NIC data structure
248 struct nic *
249 natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
251 int i;
252 int prev_eedata;
253 u32 tmp;
255 if (io_addrs == 0 || *io_addrs == 0)
256 return NULL;
258 /* initialize some commonly used globals */
260 ioaddr = *io_addrs & ~3;
261 vendor = pci->vendor;
262 dev_id = pci->dev_id;
263 nic_name = pci->name;
265 adjust_pci_device(pci);
267 /* natsemi has a non-standard PM control register
268 * in PCI config space. Some boards apparently need
269 * to be brought to D0 in this manner.
271 pcibios_read_config_dword(pci->bus, pci->devfn, PCIPM, &tmp);
272 if (tmp & (0x03|0x100)) {
273 /* D0 state, disable PME assertion */
274 u32 newtmp = tmp & ~(0x03|0x100);
275 pcibios_write_config_dword(pci->bus, pci->devfn, PCIPM, newtmp);
278 /* get MAC address */
280 prev_eedata = eeprom_read(ioaddr, 6);
281 for (i = 0; i < 3; i++) {
282 int eedata = eeprom_read(ioaddr, i + 7);
283 nic->node_addr[i*2] = (eedata << 1) + (prev_eedata >> 15);
284 nic->node_addr[i*2+1] = eedata >> 7;
285 prev_eedata = eedata;
288 printf("\nnatsemi_probe: MAC addr %! at ioaddr %#hX\n",
289 nic->node_addr, ioaddr);
290 printf("natsemi_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id);
292 /* Reset the chip to erase any previous misconfiguration. */
293 outl(ChipReset, ioaddr + ChipCmd);
295 advertising = mdio_read(1, 4);
297 u32 chip_config = inl(ioaddr + ChipConfig);
298 printf("%s: Transceiver default autoneg. %s "
299 "10%s %s duplex.\n",
300 nic_name,
301 chip_config & 0x2000 ? "enabled, advertise" : "disabled, force",
302 chip_config & 0x4000 ? "0" : "",
303 chip_config & 0x8000 ? "full" : "half");
305 printf("%s: Transceiver status %hX advertising %hX\n",
306 nic_name, (int)inl(ioaddr + 0x84), advertising);
308 /* Disable PME:
309 * The PME bit is initialized from the EEPROM contents.
310 * PCI cards probably have PME disabled, but motherboard
311 * implementations may have PME set to enable WakeOnLan.
312 * With PME set the chip will scan incoming packets but
313 * nothing will be written to memory. */
314 SavedClkRun = inl(ioaddr + ClkRun);
315 outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
317 /* initialize device */
318 natsemi_init(nic);
320 nic->reset = natsemi_init;
321 nic->poll = natsemi_poll;
322 nic->transmit = natsemi_transmit;
323 nic->disable = natsemi_disable;
325 return nic;
328 /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
329 The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses.
332 /* Delay between EEPROM clock transitions.
333 No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
334 a delay. */
335 #define eeprom_delay(ee_addr) inl(ee_addr)
337 enum EEPROM_Ctrl_Bits {
338 EE_ShiftClk = 0x04,
339 EE_DataIn = 0x01,
340 EE_ChipSelect = 0x08,
341 EE_DataOut = 0x02
344 #define EE_Write0 (EE_ChipSelect)
345 #define EE_Write1 (EE_ChipSelect | EE_DataIn)
347 /* The EEPROM commands include the alway-set leading bit. */
348 enum EEPROM_Cmds {
349 EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
352 static int eeprom_read(long addr, int location)
354 int i;
355 int retval = 0;
356 int ee_addr = addr + EECtrl;
357 int read_cmd = location | EE_ReadCmd;
358 outl(EE_Write0, ee_addr);
360 /* Shift the read command bits out. */
361 for (i = 10; i >= 0; i--) {
362 short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
363 outl(dataval, ee_addr);
364 eeprom_delay(ee_addr);
365 outl(dataval | EE_ShiftClk, ee_addr);
366 eeprom_delay(ee_addr);
368 outl(EE_ChipSelect, ee_addr);
369 eeprom_delay(ee_addr);
371 for (i = 0; i < 16; i++) {
372 outl(EE_ChipSelect | EE_ShiftClk, ee_addr);
373 eeprom_delay(ee_addr);
374 retval |= (inl(ee_addr) & EE_DataOut) ? 1 << i : 0;
375 outl(EE_ChipSelect, ee_addr);
376 eeprom_delay(ee_addr);
379 /* Terminate the EEPROM access. */
380 outl(EE_Write0, ee_addr);
381 outl(0, ee_addr);
383 return retval;
386 /* MII transceiver control section.
387 The 83815 series has an internal transceiver, and we present the
388 management registers as if they were MII connected. */
390 static int mdio_read(int phy_id, int location)
392 if (phy_id == 1 && location < 32)
393 return inl(ioaddr + 0x80 + (location<<2)) & 0xffff;
394 else
395 return 0xffff;
398 /* Function: natsemi_init
400 * Description: resets the ethernet controller chip and configures
401 * registers and data structures required for sending and receiving packets.
403 * Arguments: struct nic *nic: NIC data structure
405 * returns: void.
408 static void
409 natsemi_init(struct nic *nic)
411 natsemi_reset(nic);
413 /* Disable PME:
414 * The PME bit is initialized from the EEPROM contents.
415 * PCI cards probably have PME disabled, but motherboard
416 * implementations may have PME set to enable WakeOnLan.
417 * With PME set the chip will scan incoming packets but
418 * nothing will be written to memory. */
419 outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
421 natsemi_init_rxfilter(nic);
423 natsemi_init_txd(nic);
424 natsemi_init_rxd(nic);
426 /* Initialize other registers. */
427 /* Configure the PCI bus bursts and FIFO thresholds. */
428 /* Configure for standard, in-spec Ethernet. */
429 if (inl(ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */
430 tx_config = 0xD0801002;
431 rx_config = 0x10000020;
432 } else {
433 tx_config = 0x10801002;
434 rx_config = 0x0020;
436 outl(tx_config, ioaddr + TxConfig);
437 outl(rx_config, ioaddr + RxConfig);
439 natsemi_check_duplex(nic);
440 natsemi_set_rx_mode(nic);
442 outl(RxOn, ioaddr + ChipCmd);
446 * Function: natsemi_reset
448 * Description: soft resets the controller chip
450 * Arguments: struct nic *nic: NIC data structure
452 * Returns: void.
454 static void
455 natsemi_reset(struct nic *nic)
457 outl(ChipReset, ioaddr + ChipCmd);
459 /* On page 78 of the spec, they recommend some settings for "optimum
460 performance" to be done in sequence. These settings optimize some
461 of the 100Mbit autodetection circuitry. Also, we only want to do
462 this for rev C of the chip.
464 if (inl(ioaddr + SiliconRev) == 0x302) {
465 outw(0x0001, ioaddr + PGSEL);
466 outw(0x189C, ioaddr + PMDCSR);
467 outw(0x0000, ioaddr + TSTDAT);
468 outw(0x5040, ioaddr + DSPCFG);
469 outw(0x008C, ioaddr + SDCFG);
471 /* Disable interrupts using the mask. */
472 outl(0, ioaddr + IntrMask);
473 outl(0, ioaddr + IntrEnable);
476 /* Function: natsemi_init_rxfilter
478 * Description: sets receive filter address to our MAC address
480 * Arguments: struct nic *nic: NIC data structure
482 * returns: void.
485 static void
486 natsemi_init_rxfilter(struct nic *nic)
488 int i;
490 for (i = 0; i < ETH_ALEN; i += 2) {
491 outl(i, ioaddr + RxFilterAddr);
492 outw(nic->node_addr[i] + (nic->node_addr[i+1] << 8), ioaddr + RxFilterData);
497 * Function: natsemi_init_txd
499 * Description: initializes the Tx descriptor
501 * Arguments: struct nic *nic: NIC data structure
503 * returns: void.
506 static void
507 natsemi_init_txd(struct nic *nic)
509 txd.link = (u32) 0;
510 txd.cmdsts = (u32) 0;
511 txd.bufptr = (u32) &txb[0];
513 /* load Transmit Descriptor Register */
514 outl((u32) &txd, ioaddr + TxRingPtr);
515 if (natsemi_debug > 1)
516 printf("natsemi_init_txd: TX descriptor register loaded with: %X\n",
517 inl(ioaddr + TxRingPtr));
520 /* Function: natsemi_init_rxd
522 * Description: initializes the Rx descriptor ring
524 * Arguments: struct nic *nic: NIC data structure
526 * Returns: void.
529 static void
530 natsemi_init_rxd(struct nic *nic)
532 int i;
534 cur_rx = 0;
536 /* init RX descriptor */
537 for (i = 0; i < NUM_RX_DESC; i++) {
538 rxd[i].link = (i+1 < NUM_RX_DESC) ? (u32) &rxd[i+1] : (u32) &rxd[0];
539 rxd[i].cmdsts = (u32) RX_BUF_SIZE;
540 rxd[i].bufptr = (u32) &rxb[i*RX_BUF_SIZE];
541 if (natsemi_debug > 1)
542 printf("natsemi_init_rxd: rxd[%d]=%X link=%X cmdsts=%X bufptr=%X\n",
543 i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr);
546 /* load Receive Descriptor Register */
547 outl((u32) &rxd[0], ioaddr + RxRingPtr);
549 if (natsemi_debug > 1)
550 printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n",
551 inl(ioaddr + RxRingPtr));
554 /* Function: natsemi_set_rx_mode
556 * Description:
557 * sets the receive mode to accept all broadcast packets and packets
558 * with our MAC address, and reject all multicast packets.
560 * Arguments: struct nic *nic: NIC data structure
562 * Returns: void.
565 static void natsemi_set_rx_mode(struct nic *nic)
567 u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
569 outl(rx_mode, ioaddr + RxFilterAddr);
572 static void natsemi_check_duplex(struct nic *nic)
574 int duplex = inl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
576 if (natsemi_debug)
577 printf("%s: Setting %s-duplex based on negotiated link"
578 " capability.\n", nic_name,
579 duplex ? "full" : "half");
580 if (duplex) {
581 rx_config |= 0x10000000;
582 tx_config |= 0xC0000000;
583 } else {
584 rx_config &= ~0x10000000;
585 tx_config &= ~0xC0000000;
587 outl(tx_config, ioaddr + TxConfig);
588 outl(rx_config, ioaddr + RxConfig);
591 /* Function: natsemi_transmit
593 * Description: transmits a packet and waits for completion or timeout.
595 * Arguments: char d[6]: destination ethernet address.
596 * unsigned short t: ethernet protocol type.
597 * unsigned short s: size of the data-part of the packet.
598 * char *p: the data for the packet.
600 * Returns: void.
603 static void
604 natsemi_transmit(struct nic *nic,
605 const char *d, /* Destination */
606 unsigned int t, /* Type */
607 unsigned int s, /* size */
608 const char *p) /* Packet */
610 u32 status, to, nstype;
611 u32 tx_status;
613 /* Stop the transmitter */
614 outl(TxOff, ioaddr + ChipCmd);
616 /* load Transmit Descriptor Register */
617 outl((u32) &txd, ioaddr + TxRingPtr);
618 if (natsemi_debug > 1)
619 printf("natsemi_transmit: TX descriptor register loaded with: %X\n",
620 inl(ioaddr + TxRingPtr));
622 memcpy(txb, d, ETH_ALEN);
623 memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
624 nstype = htons(t);
625 memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
626 memcpy(txb + ETH_HLEN, p, s);
628 s += ETH_HLEN;
629 s &= DSIZE;
631 if (natsemi_debug > 1)
632 printf("natsemi_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
634 /* pad to minimum packet size */
635 while (s < ETH_ZLEN)
636 txb[s++] = '\0';
638 /* set the transmit buffer descriptor and enable Transmit State Machine */
639 txd.bufptr = (u32) &txb[0];
640 txd.cmdsts = (u32) OWN | s;
642 /* restart the transmitter */
643 outl(TxOn, ioaddr + ChipCmd);
645 if (natsemi_debug > 1)
646 printf("natsemi_transmit: Queued Tx packet size %d.\n", (int) s);
648 to = currticks() + TX_TIMEOUT;
650 while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to))
651 /* wait */ ;
653 if (currticks() >= to) {
654 printf("natsemi_transmit: TX Timeout! Tx status %X.\n", tx_status);
657 if (!(tx_status & 0x08000000)) {
658 printf("natsemi_transmit: Transmit error, Tx status %X.\n", tx_status);
662 /* Function: natsemi_poll
664 * Description: checks for a received packet and returns it if found.
666 * Arguments: struct nic *nic: NIC data structure
668 * Returns: 1 if packet was received.
669 * 0 if no packet was received.
671 * Side effects:
672 * Returns (copies) the packet to the array nic->packet.
673 * Returns the length of the packet in nic->packetlen.
676 static int
677 natsemi_poll(struct nic *nic)
679 u32 rx_status = rxd[cur_rx].cmdsts;
680 int retstat = 0;
682 if (natsemi_debug > 2)
683 printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status);
685 if (!(rx_status & OWN))
686 return retstat;
688 if (natsemi_debug > 1)
689 printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n",
690 cur_rx, rx_status);
692 nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
694 if ((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) {
695 /* corrupted packet received */
696 printf("natsemi_poll: Corrupted packet received, buffer status = %X\n",
697 rx_status);
698 retstat = 0;
699 } else {
700 /* give packet to higher level routine */
701 memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
702 retstat = 1;
705 /* return the descriptor and buffer to receive ring */
706 rxd[cur_rx].cmdsts = RX_BUF_SIZE;
707 rxd[cur_rx].bufptr = (u32) &rxb[cur_rx*RX_BUF_SIZE];
709 if (++cur_rx == NUM_RX_DESC)
710 cur_rx = 0;
712 /* re-enable the potentially idle receive state machine */
713 outl(RxOn, ioaddr + ChipCmd);
715 return retstat;
718 /* Function: natsemi_disable
720 * Description: Turns off interrupts and stops Tx and Rx engines
722 * Arguments: struct nic *nic: NIC data structure
724 * Returns: void.
727 static void
728 natsemi_disable(struct nic *nic)
730 /* Disable interrupts using the mask. */
731 outl(0, ioaddr + IntrMask);
732 outl(0, ioaddr + IntrEnable);
734 /* Stop the chip's Tx and Rx processes. */
735 outl(RxOff | TxOff, ioaddr + ChipCmd);
737 /* Restore PME enable bit */
738 outl(SavedClkRun, ioaddr + ClkRun);