2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
7 This code is based heavily on David Greenman's if_ed.c driver
9 Copyright (C) 1993-1994, David Greenman, Martin Renters.
10 This software may be used, modified, copied, distributed, and sold, in
11 both source and binary form provided that the above copyright and these
12 terms are retained. Under no circumstances are the authors responsible for
13 the proper functioning of this software, nor do the authors assume any
14 responsibility for damages incurred with its use.
16 Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
17 Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
18 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
19 SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
20 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
21 RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
22 parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
23 SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
24 based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
26 (C) Rudolf Marek <r.marek@assembler.cz> Simplify for RTL8029, Add coreboot glue logic
30 #define ETH_ALEN 6 /* Size of Ethernet address */
31 #define ETH_HLEN 14 /* Size of ethernet header */
32 #define ETH_ZLEN 60 /* Minimum packet */
33 #define ETH_FRAME_LEN 1514 /* Maximum packet */
34 #define ETH_DATA_ALIGN 2 /* Amount needed to align the data after an ethernet header */
35 #define ETH_MAX_MTU (ETH_FRAME_LEN-ETH_HLEN)
38 #include <ip_checksum.h>
39 #include <console/ne2k.h>
41 //#include <arch/romcc_io.h>
43 #define MEM_SIZE MEM_32768
45 #define RX_START (64 + D8390_TXBUF_SIZE)
47 static unsigned int get_count(unsigned int eth_nic_base
)
50 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS1
,
51 eth_nic_base
+ D8390_P0_COMMAND
);
53 ret
= inb(eth_nic_base
+ 8 + 0) | (inb(eth_nic_base
+ 8 + 1) << 8);
55 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS0
,
56 eth_nic_base
+ D8390_P0_COMMAND
);
60 static void set_count(unsigned int eth_nic_base
, unsigned int what
)
62 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS1
,
63 eth_nic_base
+ D8390_P0_COMMAND
);
65 outb(what
& 0xff,eth_nic_base
+ 8);
66 outb((what
>> 8) & 0xff,eth_nic_base
+ 8 + 1);
68 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS0
,
69 eth_nic_base
+ D8390_P0_COMMAND
);
72 static void eth_pio_write(unsigned char *src
, unsigned int dst
, unsigned int cnt
,
73 unsigned int eth_nic_base
)
75 outb(D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
76 outb(D8390_ISR_RDC
, eth_nic_base
+ D8390_P0_ISR
);
77 outb(cnt
, eth_nic_base
+ D8390_P0_RBCR0
);
78 outb(cnt
>> 8, eth_nic_base
+ D8390_P0_RBCR1
);
79 outb(dst
, eth_nic_base
+ D8390_P0_RSAR0
);
80 outb(dst
>> 8, eth_nic_base
+ D8390_P0_RSAR1
);
81 outb(D8390_COMMAND_RD1
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
84 outb(*(src
++), eth_nic_base
+ NE_ASIC_OFFSET
+ NE_DATA
);
87 #warning "Add timeout"
89 /* wait for operation finish */
90 while ((inb(eth_nic_base
+ D8390_P0_ISR
) & D8390_ISR_RDC
) != D8390_ISR_RDC
)
94 void ne2k_append_data(unsigned char *d
, int len
, unsigned int base
)
96 eth_pio_write(d
, (TX_START
<< 8) + 42 + get_count(base
), len
, base
);
97 set_count(base
, get_count(base
)+len
);
102 void eth_pio_write_byte(int data
, unsigned short dst
, unsigned int eth_nic_base
)
104 outb(D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
105 outb(D8390_ISR_RDC
, eth_nic_base
+ D8390_P0_ISR
);
106 outb(1, eth_nic_base
+ D8390_P0_RBCR0
);
107 outb(0, eth_nic_base
+ D8390_P0_RBCR1
);
108 outb(dst
, eth_nic_base
+ D8390_P0_RSAR0
);
109 outb(dst
>> 8, eth_nic_base
+ D8390_P0_RSAR1
);
110 outb(D8390_COMMAND_RD1
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
111 outb(data
, eth_nic_base
+ NE_ASIC_OFFSET
+ NE_DATA
);
113 while ((inb(eth_nic_base
+ D8390_P0_ISR
) & D8390_ISR_RDC
) != D8390_ISR_RDC
)
117 void ne2k_append_data_byte(int d
, unsigned int base
)
119 eth_pio_write_byte(d
, (TX_START
<< 8) + 42 + get_count(base
), base
);
120 set_count(base
, get_count(base
)+1);
123 static unsigned char eth_pio_read_byte(unsigned int src
,
124 unsigned int eth_nic_base
)
126 outb(D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
127 outb(0, eth_nic_base
+ D8390_P0_RBCR0
);
128 outb(1, eth_nic_base
+ D8390_P0_RBCR1
);
129 outb(src
, eth_nic_base
+ D8390_P0_RSAR0
);
130 outb(src
>> 8, eth_nic_base
+ D8390_P0_RSAR1
);
131 outb(D8390_COMMAND_RD0
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
132 return inb(eth_nic_base
+ NE_ASIC_OFFSET
+ NE_DATA
);
136 /* varition of compute_ip_checksum which works on SRAM */
137 unsigned long compute_ip_checksum_from_sram(unsigned short offset
, unsigned short length
,
138 unsigned int eth_nic_base
)
142 /* In the most straight forward way possible,
143 * compute an ip style checksum.
146 for(i
= 0; i
< length
; i
++) {
148 v
= eth_pio_read_byte((TX_START
<< 8)+i
+offset
, eth_nic_base
);
152 /* Add the new value */
154 /* Wrap around the carry */
156 sum
= (sum
+ (sum
>> 16)) & 0xFFFF;
159 return (~((sum
& 0xff) | (((sum
>> 8) & 0xff) << 8) )) & 0xffff;
163 static void str2ip_load(const char *str
, unsigned short offset
, unsigned int eth_nic_base
)
165 static void str2ip(const char *str
, unsigned char *ip
)
168 unsigned char c
, i
= 0;
173 if ((c
>= '0') && (c
<= '9')) {
178 eth_pio_write_byte(acc
, (TX_START
<< 8)+offset
, eth_nic_base
);
190 static void str2mac_load(const char *str
, unsigned short offset
, unsigned int eth_nic_base
)
192 static void str2mac(const char *str
, unsigned char *mac
)
195 unsigned char c
, i
= 0;
201 if ((c
>= '0') && (c
<= '9')) {
204 } else if ((c
>= 'a') && (c
<= 'f')) {
206 acc
+= ((c
- 'a') + 10) ;
207 } else if ((c
>= 'A') && (c
<= 'F')) {
209 acc
+= ((c
- 'A') + 10) ;
212 eth_pio_write_byte(acc
, ((TX_START
<< 8)+offset
), eth_nic_base
);
226 static void ns8390_tx_header(unsigned int eth_nic_base
, int pktlen
) {
227 unsigned short chksum
;
228 unsigned char hdr
[] = {
230 static const unsigned char hdr
[] = {
236 // destination macaddr
237 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
239 0x02, 0x00, 0x00, 0xC0, 0xFF, 0xEE,
245 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
246 /* TTL, proto (UDP), chksum_hi, chksum_lo, IP0, IP1, IP2, IP3, */
247 0x40, 0x11, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x1,
248 /* IP0, IP1, IP2, IP3 */
249 0xff, 0xff, 0xff, 0xff,
253 /* SRC PORT DST PORT (2bytes each), ulen, uchksum (must be zero or correct */
254 0x1a, 0x0b, 0x1a, 0x0a, 0x00, 0x9, 0x00, 0x00,
258 str2mac(CONFIG_CONSOLE_NE2K_DST_MAC
, &hdr
[0]);
259 str2ip(CONFIG_CONSOLE_NE2K_DST_IP
, &hdr
[30]);
260 str2ip(CONFIG_CONSOLE_NE2K_SRC_IP
, &hdr
[26]);
266 /* update IP packet len */
267 hdr
[16] = ((28 + pktlen
) >> 8) & 0xff;
268 hdr
[17] = (28 + pktlen
) & 0xff;
271 hdr
[38] = (8 + pktlen
) >> 8;
272 hdr
[39] = 8 + pktlen
;
274 chksum
= compute_ip_checksum(&hdr
[14], 20);
276 hdr
[25] = chksum
>> 8;
278 eth_pio_write(hdr
, (TX_START
<< 8), sizeof(hdr
), eth_nic_base
);
285 static void ns8390_tx_header(unsigned int eth_nic_base
, int pktlen
)
287 unsigned short chksum
;
289 eth_pio_write(hdr
, (TX_START
<< 8), sizeof(hdr
), eth_nic_base
);
291 str2mac_load(CONFIG_CONSOLE_NE2K_DST_MAC
, 0, eth_nic_base
);
293 str2ip_load(CONFIG_CONSOLE_NE2K_DST_IP
, 30, eth_nic_base
);
294 str2ip_load(CONFIG_CONSOLE_NE2K_SRC_IP
, 26, eth_nic_base
);
296 eth_pio_write_byte(0, (TX_START
<< 8)+24, eth_nic_base
);
297 eth_pio_write_byte(0, (TX_START
<< 8)+25, eth_nic_base
);
299 /* update IP packet len */
300 eth_pio_write_byte(((28 + pktlen
) >> 8) & 0xff, (TX_START
<< 8)+16, eth_nic_base
);
301 eth_pio_write_byte( (28 + pktlen
) & 0xff, (TX_START
<< 8)+17, eth_nic_base
);
304 eth_pio_write_byte((8 + pktlen
) >> 8, (TX_START
<< 8)+38, eth_nic_base
);
305 eth_pio_write_byte( 8 + pktlen
, (TX_START
<< 8)+39, eth_nic_base
);
307 chksum
= compute_ip_checksum_from_sram(14, 20, eth_nic_base
);
309 eth_pio_write_byte(chksum
, (TX_START
<< 8)+24, eth_nic_base
);
310 eth_pio_write_byte(chksum
>> 8, (TX_START
<< 8)+25, eth_nic_base
);
315 void ne2k_transmit(unsigned int eth_nic_base
) {
316 unsigned int pktsize
;
317 unsigned int len
= get_count(eth_nic_base
);
319 // so place whole header inside chip buffer
320 ns8390_tx_header(eth_nic_base
, len
);
322 // commit sending now
323 outb(D8390_COMMAND_PS0
| D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
325 outb(TX_START
, eth_nic_base
+ D8390_P0_TPSR
);
331 outb(pktsize
, eth_nic_base
+ D8390_P0_TBCR0
);
332 outb(pktsize
>> 8, eth_nic_base
+ D8390_P0_TBCR1
);
334 outb(D8390_ISR_PTX
, eth_nic_base
+ D8390_P0_ISR
);
336 outb(D8390_COMMAND_PS0
| D8390_COMMAND_TXP
| D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
338 /* wait for operation finish */
339 while ((inb(eth_nic_base
+ D8390_P0_ISR
) & D8390_ISR_PTX
) != D8390_ISR_PTX
) ;
341 set_count(eth_nic_base
, 0);
346 #include <arch/romcc_io.h>
348 static void ns8390_reset(unsigned int eth_nic_base
)
352 outb(D8390_COMMAND_PS0
| D8390_COMMAND_RD2
|
353 D8390_COMMAND_STP
, eth_nic_base
+ D8390_P0_COMMAND
);
355 outb(0x48, eth_nic_base
+ D8390_P0_DCR
);
356 outb(0, eth_nic_base
+ D8390_P0_RBCR0
);
357 outb(0, eth_nic_base
+ D8390_P0_RBCR1
);
358 outb(0x20, eth_nic_base
+ D8390_P0_RCR
);
359 outb(2, eth_nic_base
+ D8390_P0_TCR
);
360 outb(TX_START
, eth_nic_base
+ D8390_P0_TPSR
);
361 outb(RX_START
, eth_nic_base
+ D8390_P0_PSTART
);
362 outb(MEM_SIZE
, eth_nic_base
+ D8390_P0_PSTOP
);
363 outb(MEM_SIZE
- 1, eth_nic_base
+ D8390_P0_BOUND
);
364 outb(0xFF, eth_nic_base
+ D8390_P0_ISR
);
365 outb(0, eth_nic_base
+ D8390_P0_IMR
);
367 outb(D8390_COMMAND_PS1
|
368 D8390_COMMAND_RD2
| D8390_COMMAND_STP
,
369 eth_nic_base
+ D8390_P0_COMMAND
);
371 for (i
= 0; i
< ETH_ALEN
; i
++)
372 outb(0x0C, eth_nic_base
+ D8390_P1_PAR0
+ i
);
374 for (i
= 0; i
< ETH_ALEN
; i
++)
375 outb(0xFF, eth_nic_base
+ D8390_P1_MAR0
+ i
);
377 outb(RX_START
, eth_nic_base
+ D8390_P1_CURR
);
378 outb(D8390_COMMAND_PS0
|
379 D8390_COMMAND_RD2
| D8390_COMMAND_STA
,
380 eth_nic_base
+ D8390_P0_COMMAND
);
381 outb(0xFF, eth_nic_base
+ D8390_P0_ISR
);
382 outb(0, eth_nic_base
+ D8390_P0_TCR
);
383 outb(4, eth_nic_base
+ D8390_P0_RCR
);
384 set_count(eth_nic_base
, 0);
388 int ne2k_init(unsigned int eth_nic_base
) {
393 /* Power management controller */
394 dev
= pci_locate_device(PCI_ID(0x10ec,
397 if (dev
== PCI_DEV_INVALID
)
400 pci_write_config32(dev
, 0x10, eth_nic_base
| 1 );
401 pci_write_config8(dev
, 0x4, 0x1);
403 c
= inb(eth_nic_base
+ NE_ASIC_OFFSET
+ NE_RESET
);
404 outb(c
, eth_nic_base
+ NE_ASIC_OFFSET
+ NE_RESET
);
408 outb(D8390_COMMAND_STP
| D8390_COMMAND_RD2
, eth_nic_base
+ D8390_P0_COMMAND
);
409 outb(D8390_RCR_MON
, eth_nic_base
+ D8390_P0_RCR
);
411 outb(D8390_DCR_FT1
| D8390_DCR_LS
, eth_nic_base
+ D8390_P0_DCR
);
412 outb(MEM_8192
, eth_nic_base
+ D8390_P0_PSTART
);
413 outb(MEM_16384
, eth_nic_base
+ D8390_P0_PSTOP
);
415 ns8390_reset(eth_nic_base
);
426 #include <console/console.h>
427 #include <device/device.h>
428 #include <device/pci.h>
429 #include <device/pci_ids.h>
430 #include <device/pci_ops.h>
432 static void read_resources(struct device
*dev
)
434 struct resource
*res
;
436 res
= new_resource(dev
, PCI_BASE_ADDRESS_0
);
437 res
->base
= CONFIG_CONSOLE_NE2K_IO_PORT
;
441 res
->limit
= res
->base
+ res
->size
- 1;
442 res
->flags
= IORESOURCE_IO
| IORESOURCE_FIXED
| IORESOURCE_STORED
|
448 static struct device_operations si_sata_ops
= {
449 .read_resources
= read_resources
,
450 .set_resources
= pci_dev_set_resources
,
451 .enable_resources
= pci_dev_enable_resources
,
456 static const struct pci_driver si_sata_driver __pci_driver
= {