Add new ec subdir for Embedded Controllers and common ACPI EC support
[coreboot.git] / src / lib / ne2k.c
blobabc97082be3abb78610bb3e9b83ebd2d614441dd
1 /*
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
4 Author: Martin Renters
5 Date: May/94
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)
37 #include "ns8390.h"
38 #include <ip_checksum.h>
39 #include <console/ne2k.h>
40 #include <arch/io.h>
41 //#include <arch/romcc_io.h>
43 #define MEM_SIZE MEM_32768
44 #define TX_START 64
45 #define RX_START (64 + D8390_TXBUF_SIZE)
47 static unsigned int get_count(unsigned int eth_nic_base)
49 unsigned int ret;
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);
57 return ret;
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);
83 while (cnt--) {
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);
100 #ifdef __ROMCC__
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)
140 unsigned long sum;
141 unsigned long i;
142 /* In the most straight forward way possible,
143 * compute an ip style checksum.
145 sum = 0;
146 for(i = 0; i < length; i++) {
147 unsigned long v;
148 v = eth_pio_read_byte((TX_START << 8)+i+offset, eth_nic_base);
149 if (i & 1) {
150 v <<= 8;
152 /* Add the new value */
153 sum += v;
154 /* Wrap around the carry */
155 if (sum > 0xFFFF) {
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)
164 #else
165 static void str2ip(const char *str, unsigned char *ip)
166 #endif
168 unsigned char c, i = 0;
169 int acc = 0;
171 do {
172 c = str[i];
173 if ((c >= '0') && (c <= '9')) {
174 acc *= 10;
175 acc += (c - '0');
176 } else {
177 #ifdef __ROMCC__
178 eth_pio_write_byte(acc, (TX_START << 8)+offset, eth_nic_base);
179 offset++;
180 #else
181 *ip++ = acc;
182 #endif
183 acc = 0;
185 i++;
186 } while (c != '\0');
189 #ifdef __ROMCC__
190 static void str2mac_load(const char *str, unsigned short offset, unsigned int eth_nic_base)
191 #else
192 static void str2mac(const char *str, unsigned char *mac)
193 #endif
195 unsigned char c, i = 0;
196 int acc = 0;
198 do {
200 c = str[i];
201 if ((c >= '0') && (c <= '9')) {
202 acc *= 16;
203 acc += (c - '0');
204 } else if ((c >= 'a') && (c <= 'f')) {
205 acc *= 16;
206 acc += ((c - 'a') + 10) ;
207 } else if ((c >= 'A') && (c <= 'F')) {
208 acc *= 16;
209 acc += ((c - 'A') + 10) ;
210 } else {
211 #ifdef __ROMCC__
212 eth_pio_write_byte(acc, ((TX_START << 8)+offset), eth_nic_base);
213 offset++;
214 #else
215 *mac++ = acc;
216 #endif
217 acc = 0;
220 i++;
221 } while (c != '\0');
225 #ifndef __ROMCC__
226 static void ns8390_tx_header(unsigned int eth_nic_base, int pktlen) {
227 unsigned short chksum;
228 unsigned char hdr[] = {
229 #else
230 static const unsigned char hdr[] = {
231 #endif
233 * ETHERNET HDR
236 // destination macaddr
237 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
238 /* source mac */
239 0x02, 0x00, 0x00, 0xC0, 0xFF, 0xEE,
240 /* ethtype (IP) */
241 0x08, 0x00,
243 * IP HDR
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,
251 * UDP HDR
253 /* SRC PORT DST PORT (2bytes each), ulen, uchksum (must be zero or correct */
254 0x1a, 0x0b, 0x1a, 0x0a, 0x00, 0x9, 0x00, 0x00,
257 #ifndef __ROMCC__
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]);
262 /* zero checksum */
263 hdr[24] = 0;
264 hdr[25] = 0;
266 /* update IP packet len */
267 hdr[16] = ((28 + pktlen) >> 8) & 0xff;
268 hdr[17] = (28 + pktlen) & 0xff;
270 /* update UDP len */
271 hdr[38] = (8 + pktlen) >> 8;
272 hdr[39] = 8 + pktlen;
274 chksum = compute_ip_checksum(&hdr[14], 20);
276 hdr[25] = chksum >> 8;
277 hdr[24] = chksum;
278 eth_pio_write(hdr, (TX_START << 8), sizeof(hdr), eth_nic_base);
282 #else
284 /* ROMCC madness */
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);
295 /* zero checksum */
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);
303 /* update UDP len */
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);
313 #endif
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);
327 pktsize = 42 + len;
328 if (pktsize < 64)
329 pktsize = 64;
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);
344 #ifdef __PRE_RAM__
346 #include <arch/romcc_io.h>
348 static void ns8390_reset(unsigned int eth_nic_base)
350 int i;
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) {
390 device_t dev;
391 unsigned char c;
393 /* Power management controller */
394 dev = pci_locate_device(PCI_ID(0x10ec,
395 0x8029), 0);
397 if (dev == PCI_DEV_INVALID)
398 return 0;
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);
406 (void) inb(0x84);
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);
416 return 1;
419 #else
421 #include <delay.h>
422 #include <stdlib.h>
423 #include <string.h>
424 #include <arch/io.h>
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;
438 res->size = 32;
439 res->align = 5;
440 res->gran = 5;
441 res->limit = res->base + res->size - 1;
442 res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_STORED |
443 IORESOURCE_ASSIGNED;
444 return;
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,
452 .init = 0,
453 .scan_bus = 0,
456 static const struct pci_driver si_sata_driver __pci_driver = {
457 .ops = &si_sata_ops,
458 .vendor = 0x10ec,
459 .device = 0x8029,
462 #endif