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
31 #include <commonlib/bsd/ipchksum.h>
32 #include <console/ne2k.h>
33 #include <device/device.h>
34 #include <device/pci.h>
35 #include <device/pci_ops.h>
39 #define ETH_ALEN 6 /* Size of Ethernet address */
40 #define ETH_HLEN 14 /* Size of ethernet header */
41 #define ETH_ZLEN 60 /* Minimum packet */
42 #define ETH_FRAME_LEN 1514 /* Maximum packet */
43 #define ETH_DATA_ALIGN 2 /* Amount needed to align the data after an ethernet header */
44 #define ETH_MAX_MTU (ETH_FRAME_LEN-ETH_HLEN)
46 #define MEM_SIZE MEM_32768
48 #define RX_START (64 + D8390_TXBUF_SIZE)
50 static unsigned int get_count(unsigned int eth_nic_base
)
53 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS1
,
54 eth_nic_base
+ D8390_P0_COMMAND
);
56 ret
= inb(eth_nic_base
+ 8 + 0) | (inb(eth_nic_base
+ 8 + 1) << 8);
58 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS0
,
59 eth_nic_base
+ D8390_P0_COMMAND
);
63 static void set_count(unsigned int eth_nic_base
, unsigned int what
)
65 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS1
,
66 eth_nic_base
+ D8390_P0_COMMAND
);
68 outb(what
& 0xff,eth_nic_base
+ 8);
69 outb((what
>> 8) & 0xff,eth_nic_base
+ 8 + 1);
71 outb(D8390_COMMAND_RD2
+ D8390_COMMAND_PS0
,
72 eth_nic_base
+ D8390_P0_COMMAND
);
75 static void eth_pio_write(unsigned char *src
, unsigned int dst
, unsigned int cnt
,
76 unsigned int eth_nic_base
)
78 outb(D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
79 outb(D8390_ISR_RDC
, eth_nic_base
+ D8390_P0_ISR
);
80 outb(cnt
, eth_nic_base
+ D8390_P0_RBCR0
);
81 outb(cnt
>> 8, eth_nic_base
+ D8390_P0_RBCR1
);
82 outb(dst
, eth_nic_base
+ D8390_P0_RSAR0
);
83 outb(dst
>> 8, eth_nic_base
+ D8390_P0_RSAR1
);
84 outb(D8390_COMMAND_RD1
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
87 outb(*(src
++), eth_nic_base
+ NE_ASIC_OFFSET
+ NE_DATA
);
90 #warning "Add timeout"
92 /* wait for operation finish */
93 while ((inb(eth_nic_base
+ D8390_P0_ISR
) & D8390_ISR_RDC
) != D8390_ISR_RDC
)
97 void ne2k_append_data(unsigned char *d
, int len
, unsigned int base
)
99 eth_pio_write(d
, (TX_START
<< 8) + 42 + get_count(base
), len
, base
);
100 set_count(base
, get_count(base
)+len
);
103 static void str2ip(const char *str
, unsigned char *ip
)
105 unsigned char c
, i
= 0;
110 if ((c
>= '0') && (c
<= '9')) {
121 static void str2mac(const char *str
, unsigned char *mac
)
123 unsigned char c
, i
= 0;
128 if ((c
>= '0') && (c
<= '9')) {
131 } else if ((c
>= 'a') && (c
<= 'f')) {
133 acc
+= ((c
- 'a') + 10);
134 } else if ((c
>= 'A') && (c
<= 'F')) {
136 acc
+= ((c
- 'A') + 10);
146 static void ns8390_tx_header(unsigned int eth_nic_base
, int pktlen
)
148 unsigned short chksum
;
149 unsigned char hdr
[] = {
151 /* destination macaddr */
152 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
154 0x02, 0x00, 0x00, 0xC0, 0xFF, 0xEE,
159 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
160 /* TTL, proto (UDP), chksum_hi, chksum_lo, IP0, IP1, IP2, IP3, */
161 0x40, 0x11, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x1,
162 /* IP0, IP1, IP2, IP3 */
163 0xff, 0xff, 0xff, 0xff,
166 /* SRC PORT DST PORT (2 bytes each),
167 * ulen, uchksum (must be zero or correct */
168 0x1a, 0x0b, 0x1a, 0x0a, 0x00, 0x9, 0x00, 0x00,
171 str2mac(CONFIG_CONSOLE_NE2K_DST_MAC
, &hdr
[0]);
172 str2ip(CONFIG_CONSOLE_NE2K_DST_IP
, &hdr
[30]);
173 str2ip(CONFIG_CONSOLE_NE2K_SRC_IP
, &hdr
[26]);
179 /* update IP packet len */
180 hdr
[16] = ((28 + pktlen
) >> 8) & 0xff;
181 hdr
[17] = (28 + pktlen
) & 0xff;
184 hdr
[38] = (8 + pktlen
) >> 8;
185 hdr
[39] = 8 + pktlen
;
187 chksum
= ipchksum(&hdr
[14], 20);
189 hdr
[25] = chksum
>> 8;
191 eth_pio_write(hdr
, (TX_START
<< 8), sizeof(hdr
), eth_nic_base
);
194 void ne2k_transmit(unsigned int eth_nic_base
)
196 unsigned int pktsize
;
197 unsigned int len
= get_count(eth_nic_base
);
199 // so place whole header inside chip buffer
200 ns8390_tx_header(eth_nic_base
, len
);
202 // commit sending now
203 outb(D8390_COMMAND_PS0
| D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
205 outb(TX_START
, eth_nic_base
+ D8390_P0_TPSR
);
211 outb(pktsize
, eth_nic_base
+ D8390_P0_TBCR0
);
212 outb(pktsize
>> 8, eth_nic_base
+ D8390_P0_TBCR1
);
214 outb(D8390_ISR_PTX
, eth_nic_base
+ D8390_P0_ISR
);
216 outb(D8390_COMMAND_PS0
| D8390_COMMAND_TXP
| D8390_COMMAND_RD2
| D8390_COMMAND_STA
, eth_nic_base
+ D8390_P0_COMMAND
);
218 /* wait for operation finish */
219 while ((inb(eth_nic_base
+ D8390_P0_ISR
) & D8390_ISR_PTX
) != D8390_ISR_PTX
)
222 set_count(eth_nic_base
, 0);
225 static void ns8390_reset(unsigned int eth_nic_base
)
229 outb(D8390_COMMAND_PS0
| D8390_COMMAND_RD2
|
230 D8390_COMMAND_STP
, eth_nic_base
+ D8390_P0_COMMAND
);
232 outb(0x48, eth_nic_base
+ D8390_P0_DCR
);
233 outb(0, eth_nic_base
+ D8390_P0_RBCR0
);
234 outb(0, eth_nic_base
+ D8390_P0_RBCR1
);
235 outb(0x20, eth_nic_base
+ D8390_P0_RCR
);
236 outb(2, eth_nic_base
+ D8390_P0_TCR
);
237 outb(TX_START
, eth_nic_base
+ D8390_P0_TPSR
);
238 outb(RX_START
, eth_nic_base
+ D8390_P0_PSTART
);
239 outb(MEM_SIZE
, eth_nic_base
+ D8390_P0_PSTOP
);
240 outb(MEM_SIZE
- 1, eth_nic_base
+ D8390_P0_BOUND
);
241 outb(0xFF, eth_nic_base
+ D8390_P0_ISR
);
242 outb(0, eth_nic_base
+ D8390_P0_IMR
);
244 outb(D8390_COMMAND_PS1
|
245 D8390_COMMAND_RD2
| D8390_COMMAND_STP
,
246 eth_nic_base
+ D8390_P0_COMMAND
);
248 for (i
= 0; i
< ETH_ALEN
; i
++)
249 outb(0x0C, eth_nic_base
+ D8390_P1_PAR0
+ i
);
251 for (i
= 0; i
< ETH_ALEN
; i
++)
252 outb(0xFF, eth_nic_base
+ D8390_P1_MAR0
+ i
);
254 outb(RX_START
, eth_nic_base
+ D8390_P1_CURR
);
255 outb(D8390_COMMAND_PS0
|
256 D8390_COMMAND_RD2
| D8390_COMMAND_STA
,
257 eth_nic_base
+ D8390_P0_COMMAND
);
258 outb(0xFF, eth_nic_base
+ D8390_P0_ISR
);
259 outb(0, eth_nic_base
+ D8390_P0_TCR
);
260 outb(4, eth_nic_base
+ D8390_P0_RCR
);
261 set_count(eth_nic_base
, 0);
264 int ne2k_init(unsigned int eth_nic_base
)
269 if (!ENV_ROMSTAGE_OR_BEFORE
)
272 /* For this to work, mainboard code must have configured
273 PCI bridges prior to calling console_init(). */
274 dev
= pci_locate_device(PCI_ID(0x10ec, 0x8029), 0);
275 if (dev
== PCI_DEV_INVALID
)
278 pci_s_write_config32(dev
, 0x10, eth_nic_base
| 1);
279 pci_s_write_config8(dev
, 0x4, 0x1);
281 c
= inb(eth_nic_base
+ NE_ASIC_OFFSET
+ NE_RESET
);
282 outb(c
, eth_nic_base
+ NE_ASIC_OFFSET
+ NE_RESET
);
286 outb(D8390_COMMAND_STP
| D8390_COMMAND_RD2
, eth_nic_base
+ D8390_P0_COMMAND
);
287 outb(D8390_RCR_MON
, eth_nic_base
+ D8390_P0_RCR
);
289 outb(D8390_DCR_FT1
| D8390_DCR_LS
, eth_nic_base
+ D8390_P0_DCR
);
290 outb(MEM_8192
, eth_nic_base
+ D8390_P0_PSTART
);
291 outb(MEM_16384
, eth_nic_base
+ D8390_P0_PSTOP
);
293 ns8390_reset(eth_nic_base
);
297 static void read_resources(struct device
*dev
)
299 struct resource
*res
;
301 res
= new_resource(dev
, PCI_BASE_ADDRESS_0
);
302 res
->base
= CONFIG_CONSOLE_NE2K_IO_PORT
;
306 res
->limit
= res
->base
+ res
->size
- 1;
307 res
->flags
= IORESOURCE_IO
| IORESOURCE_FIXED
| IORESOURCE_STORED
|
311 static struct device_operations ne2k_ops
= {
312 .read_resources
= read_resources
,
313 .set_resources
= pci_dev_set_resources
,
314 .enable_resources
= pci_dev_enable_resources
,
317 static const struct pci_driver ne2k_driver __pci_driver
= {