xref: /aosp_15_r20/external/coreboot/src/drivers/net/ne2k.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2 ETHERBOOT -  BOOTP/TFTP Bootstrap Program
3 
4 Author: Martin Renters
5   Date: May/94
6 
7  This code is based heavily on David Greenman's if_ed.c driver
8 
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.
15 
16 Multicast support added by Timothy Legge ([email protected]) 09/28/2003
17 Relocation support added by Ken Yap ([email protected]) 28/12/02
18 3c503 support added by Bill Paul ([email protected]) on 11/15/94
19 SMC8416 support added by Bill Paul ([email protected]) on 12/25/94
20 3c503 PIO support added by Jim Hague ([email protected]) on 2/17/98
21 RX overrun by Klaus Espenlaub ([email protected]) 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 ([email protected]) on 4/3/02
24   based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
25 
26 (C) Rudolf Marek <[email protected]> Simplify for RTL8029, Add coreboot glue logic
27 
28 */
29 
30 #include <arch/io.h>
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>
36 
37 #include "ns8390.h"
38 
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)
45 
46 #define MEM_SIZE MEM_32768
47 #define TX_START 64
48 #define RX_START (64 + D8390_TXBUF_SIZE)
49 
get_count(unsigned int eth_nic_base)50 static unsigned int get_count(unsigned int eth_nic_base)
51 {
52 	unsigned int ret;
53 	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
54 	     eth_nic_base + D8390_P0_COMMAND);
55 
56 	ret = inb(eth_nic_base + 8 + 0) | (inb(eth_nic_base + 8 + 1) << 8);
57 
58 	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
59 	     eth_nic_base + D8390_P0_COMMAND);
60 	return ret;
61 }
62 
set_count(unsigned int eth_nic_base,unsigned int what)63 static void set_count(unsigned int eth_nic_base, unsigned int what)
64 {
65 	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
66 	     eth_nic_base + D8390_P0_COMMAND);
67 
68 	outb(what & 0xff,eth_nic_base + 8);
69 	outb((what >> 8) & 0xff,eth_nic_base + 8 + 1);
70 
71 	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
72 	     eth_nic_base + D8390_P0_COMMAND);
73 }
74 
eth_pio_write(unsigned char * src,unsigned int dst,unsigned int cnt,unsigned int eth_nic_base)75 static void eth_pio_write(unsigned char *src, unsigned int dst, unsigned int cnt,
76 				unsigned int eth_nic_base)
77 {
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);
85 
86 	while (cnt--) {
87 		outb(*(src++), eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
88 	}
89 	/*
90 	#warning "Add timeout"
91 	*/
92 	/* wait for operation finish */
93 	while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) != D8390_ISR_RDC)
94 		;
95 }
96 
ne2k_append_data(unsigned char * d,int len,unsigned int base)97 void ne2k_append_data(unsigned char *d, int len, unsigned int base)
98 {
99 	eth_pio_write(d, (TX_START << 8) + 42 + get_count(base), len, base);
100 	set_count(base, get_count(base)+len);
101 }
102 
str2ip(const char * str,unsigned char * ip)103 static void str2ip(const char *str, unsigned char *ip)
104 {
105 	unsigned char c, i = 0;
106 	int acc = 0;
107 
108 	do {
109 		c = str[i];
110 		if ((c >= '0') && (c <= '9')) {
111 			acc *= 10;
112 			acc += (c - '0');
113 		} else {
114 			*ip++ = acc;
115 			acc = 0;
116 		}
117 		i++;
118 	} while (c != '\0');
119 }
120 
str2mac(const char * str,unsigned char * mac)121 static void str2mac(const char *str, unsigned char *mac)
122 {
123 	unsigned char c, i = 0;
124 	int acc = 0;
125 
126 	do {
127 		c = str[i];
128 		if ((c >= '0') && (c <= '9')) {
129 			acc *= 16;
130 			acc += (c - '0');
131 		} else if ((c >= 'a') && (c <= 'f')) {
132 			acc *= 16;
133 			acc += ((c - 'a') + 10);
134 		} else if ((c >= 'A') && (c <= 'F')) {
135 			acc *= 16;
136 			acc += ((c - 'A') + 10);
137 		} else {
138 			*mac++ = acc;
139 			acc = 0;
140 		}
141 
142 		i++;
143 	} while (c != '\0');
144 }
145 
ns8390_tx_header(unsigned int eth_nic_base,int pktlen)146 static void ns8390_tx_header(unsigned int eth_nic_base, int pktlen)
147 {
148 	unsigned short chksum;
149 	unsigned char hdr[] = {
150 		/* ETHERNET HDR */
151 		/* destination macaddr */
152 		0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
153 		/* source mac */
154 		0x02, 0x00, 0x00, 0xC0, 0xFF, 0xEE,
155 		/* ethtype (IP) */
156 		0x08, 0x00,
157 
158 		/* IP HDR */
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,
164 
165 		/* UDP HDR */
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,
169 	};
170 
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]);
174 
175 	/* zero checksum */
176 	hdr[24] = 0;
177 	hdr[25] = 0;
178 
179 	/* update IP packet len */
180 	hdr[16] = ((28 + pktlen) >> 8) & 0xff;
181 	hdr[17] = (28 + pktlen) & 0xff;
182 
183 	/* update UDP len */
184 	hdr[38] = (8 + pktlen) >> 8;
185 	hdr[39] = 8 + pktlen;
186 
187 	chksum = ipchksum(&hdr[14], 20);
188 
189 	hdr[25] = chksum >> 8;
190 	hdr[24] = chksum;
191 	eth_pio_write(hdr, (TX_START << 8), sizeof(hdr), eth_nic_base);
192 }
193 
ne2k_transmit(unsigned int eth_nic_base)194 void ne2k_transmit(unsigned int eth_nic_base)
195 {
196 	unsigned int pktsize;
197 	unsigned int len = get_count(eth_nic_base);
198 
199 	// so place whole header inside chip buffer
200 	ns8390_tx_header(eth_nic_base, len);
201 
202 	// commit sending now
203 	outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
204 
205 	outb(TX_START, eth_nic_base + D8390_P0_TPSR);
206 
207 	pktsize = 42 + len;
208 	if (pktsize < 64)
209 		pktsize = 64;
210 
211 	outb(pktsize, eth_nic_base + D8390_P0_TBCR0);
212 	outb(pktsize >> 8, eth_nic_base + D8390_P0_TBCR1);
213 
214 	outb(D8390_ISR_PTX, eth_nic_base + D8390_P0_ISR);
215 
216 	outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
217 
218 	/* wait for operation finish */
219 	while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_PTX) != D8390_ISR_PTX)
220 		;
221 
222 	set_count(eth_nic_base, 0);
223 }
224 
ns8390_reset(unsigned int eth_nic_base)225 static void ns8390_reset(unsigned int eth_nic_base)
226 {
227 	int i;
228 
229 	outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
230 	     D8390_COMMAND_STP, eth_nic_base + D8390_P0_COMMAND);
231 
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);
243 
244 	outb(D8390_COMMAND_PS1 |
245 	     D8390_COMMAND_RD2 | D8390_COMMAND_STP,
246 	     eth_nic_base + D8390_P0_COMMAND);
247 
248 	for (i = 0; i < ETH_ALEN; i++)
249 		outb(0x0C, eth_nic_base + D8390_P1_PAR0 + i);
250 
251 	for (i = 0; i < ETH_ALEN; i++)
252 		outb(0xFF, eth_nic_base + D8390_P1_MAR0 + i);
253 
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);
262 }
263 
ne2k_init(unsigned int eth_nic_base)264 int ne2k_init(unsigned int eth_nic_base)
265 {
266 	pci_devfn_t dev;
267 	unsigned char c;
268 
269 	if (!ENV_ROMSTAGE_OR_BEFORE)
270 		return 0;
271 
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)
276 		return 0;
277 
278 	pci_s_write_config32(dev, 0x10, eth_nic_base | 1);
279 	pci_s_write_config8(dev, 0x4, 0x1);
280 
281 	c = inb(eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
282 	outb(c, eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
283 
284 	(void)inb(0x84);
285 
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);
288 
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);
292 
293 	ns8390_reset(eth_nic_base);
294 	return 1;
295 }
296 
read_resources(struct device * dev)297 static void read_resources(struct device *dev)
298 {
299 	struct resource *res;
300 
301 	res = new_resource(dev, PCI_BASE_ADDRESS_0);
302 	res->base = CONFIG_CONSOLE_NE2K_IO_PORT;
303 	res->size = 32;
304 	res->align = 5;
305 	res->gran = 5;
306 	res->limit = res->base + res->size - 1;
307 	res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_STORED |
308 				IORESOURCE_ASSIGNED;
309 }
310 
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,
315 };
316 
317 static const struct pci_driver ne2k_driver __pci_driver = {
318 	.ops    = &ne2k_ops,
319 	.vendor = 0x10ec,
320 	.device = 0x8029,
321 };
322