1*58a2b000SEvgeniy Ivanov /* $NetBSD: 3c509.c,v 1.10 2008/12/14 18:46:33 christos Exp $ */
2*58a2b000SEvgeniy Ivanov
3*58a2b000SEvgeniy Ivanov /* stripped down from freebsd:sys/i386/netboot/3c509.c */
4*58a2b000SEvgeniy Ivanov
5*58a2b000SEvgeniy Ivanov /**************************************************************************
6*58a2b000SEvgeniy Ivanov NETBOOT - BOOTP/TFTP Bootstrap Program
7*58a2b000SEvgeniy Ivanov
8*58a2b000SEvgeniy Ivanov Author: Martin Renters.
9*58a2b000SEvgeniy Ivanov Date: Mar 22 1995
10*58a2b000SEvgeniy Ivanov
11*58a2b000SEvgeniy Ivanov This code is based heavily on David Greenman's if_ed.c driver and
12*58a2b000SEvgeniy Ivanov Andres Vega Garcia's if_ep.c driver.
13*58a2b000SEvgeniy Ivanov
14*58a2b000SEvgeniy Ivanov Copyright (C) 1993-1994, David Greenman, Martin Renters.
15*58a2b000SEvgeniy Ivanov Copyright (C) 1993-1995, Andres Vega Garcia.
16*58a2b000SEvgeniy Ivanov Copyright (C) 1995, Serge Babkin.
17*58a2b000SEvgeniy Ivanov This software may be used, modified, copied, distributed, and sold, in
18*58a2b000SEvgeniy Ivanov both source and binary form provided that the above copyright and these
19*58a2b000SEvgeniy Ivanov terms are retained. Under no circumstances are the authors responsible for
20*58a2b000SEvgeniy Ivanov the proper functioning of this software, nor do the authors assume any
21*58a2b000SEvgeniy Ivanov responsibility for damages incurred with its use.
22*58a2b000SEvgeniy Ivanov
23*58a2b000SEvgeniy Ivanov 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
24*58a2b000SEvgeniy Ivanov
25*58a2b000SEvgeniy Ivanov 3c509.c,v 1.2 1995/05/30 07:58:52 rgrimes Exp
26*58a2b000SEvgeniy Ivanov
27*58a2b000SEvgeniy Ivanov ***************************************************************************/
28*58a2b000SEvgeniy Ivanov
29*58a2b000SEvgeniy Ivanov #include <sys/types.h>
30*58a2b000SEvgeniy Ivanov #include <machine/pio.h>
31*58a2b000SEvgeniy Ivanov
32*58a2b000SEvgeniy Ivanov #include <lib/libsa/stand.h>
33*58a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
34*58a2b000SEvgeniy Ivanov
35*58a2b000SEvgeniy Ivanov #include <libi386.h>
36*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE
37*58a2b000SEvgeniy Ivanov #include <bootinfo.h>
38*58a2b000SEvgeniy Ivanov #endif
39*58a2b000SEvgeniy Ivanov
40*58a2b000SEvgeniy Ivanov #include "etherdrv.h"
41*58a2b000SEvgeniy Ivanov #include "3c509.h"
42*58a2b000SEvgeniy Ivanov
43*58a2b000SEvgeniy Ivanov unsigned ether_medium;
44*58a2b000SEvgeniy Ivanov unsigned short eth_base;
45*58a2b000SEvgeniy Ivanov
46*58a2b000SEvgeniy Ivanov extern void epreset(void);
47*58a2b000SEvgeniy Ivanov extern int ep_get_e(int);
48*58a2b000SEvgeniy Ivanov
49*58a2b000SEvgeniy Ivanov static int send_ID_sequence(int);
50*58a2b000SEvgeniy Ivanov static int get_eeprom_data(int, int);
51*58a2b000SEvgeniy Ivanov
52*58a2b000SEvgeniy Ivanov u_char eth_myaddr[6];
53*58a2b000SEvgeniy Ivanov
54*58a2b000SEvgeniy Ivanov static struct mtabentry {
55*58a2b000SEvgeniy Ivanov int address_cfg; /* configured connector */
56*58a2b000SEvgeniy Ivanov int config_bit; /* connector present */
57*58a2b000SEvgeniy Ivanov char *name;
58*58a2b000SEvgeniy Ivanov } mediatab[] = { /* indexed by media type - etherdrv.h */
59*58a2b000SEvgeniy Ivanov {3, IS_BNC, "BNC"},
60*58a2b000SEvgeniy Ivanov {0, IS_UTP, "UTP"},
61*58a2b000SEvgeniy Ivanov {1, IS_AUI, "AUI"},
62*58a2b000SEvgeniy Ivanov };
63*58a2b000SEvgeniy Ivanov
64*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE
65*58a2b000SEvgeniy Ivanov static struct btinfo_netif bi_netif;
66*58a2b000SEvgeniy Ivanov #endif
67*58a2b000SEvgeniy Ivanov
68*58a2b000SEvgeniy Ivanov #ifndef _STANDALONE
69*58a2b000SEvgeniy Ivanov extern int mapio(void);
70*58a2b000SEvgeniy Ivanov #endif
71*58a2b000SEvgeniy Ivanov
72*58a2b000SEvgeniy Ivanov /**************************************************************************
73*58a2b000SEvgeniy Ivanov ETH_PROBE - Look for an adapter
74*58a2b000SEvgeniy Ivanov ***************************************************************************/
75*58a2b000SEvgeniy Ivanov int
EtherInit(unsigned char * myadr)76*58a2b000SEvgeniy Ivanov EtherInit(unsigned char *myadr)
77*58a2b000SEvgeniy Ivanov {
78*58a2b000SEvgeniy Ivanov /* common variables */
79*58a2b000SEvgeniy Ivanov int i;
80*58a2b000SEvgeniy Ivanov /* variables for 3C509 */
81*58a2b000SEvgeniy Ivanov int data, j, id_port = EP_ID_PORT;
82*58a2b000SEvgeniy Ivanov u_short k;
83*58a2b000SEvgeniy Ivanov /* int ep_current_tag = EP_LAST_TAG + 1; */
84*58a2b000SEvgeniy Ivanov u_short *p;
85*58a2b000SEvgeniy Ivanov struct mtabentry *m;
86*58a2b000SEvgeniy Ivanov
87*58a2b000SEvgeniy Ivanov #ifndef _STANDALONE
88*58a2b000SEvgeniy Ivanov if (mapio()) {
89*58a2b000SEvgeniy Ivanov printf("no IO access\n");
90*58a2b000SEvgeniy Ivanov return 0;
91*58a2b000SEvgeniy Ivanov }
92*58a2b000SEvgeniy Ivanov #endif
93*58a2b000SEvgeniy Ivanov
94*58a2b000SEvgeniy Ivanov /*********************************************************
95*58a2b000SEvgeniy Ivanov Search for 3Com 509 card
96*58a2b000SEvgeniy Ivanov ***********************************************************/
97*58a2b000SEvgeniy Ivanov /*
98*58a2b000SEvgeniy Ivanov ep_current_tag--;
99*58a2b000SEvgeniy Ivanov */
100*58a2b000SEvgeniy Ivanov
101*58a2b000SEvgeniy Ivanov /* Look for the ISA boards. Init and leave them actived */
102*58a2b000SEvgeniy Ivanov /* search for the first card, ignore all others */
103*58a2b000SEvgeniy Ivanov outb(id_port, 0xc0); /* Global reset */
104*58a2b000SEvgeniy Ivanov delay(1000);
105*58a2b000SEvgeniy Ivanov /*
106*58a2b000SEvgeniy Ivanov for (i = 0; i < EP_MAX_BOARDS; i++) {
107*58a2b000SEvgeniy Ivanov */
108*58a2b000SEvgeniy Ivanov outb(id_port, 0);
109*58a2b000SEvgeniy Ivanov outb(id_port, 0);
110*58a2b000SEvgeniy Ivanov send_ID_sequence(id_port);
111*58a2b000SEvgeniy Ivanov
112*58a2b000SEvgeniy Ivanov data = get_eeprom_data(id_port, EEPROM_MFG_ID);
113*58a2b000SEvgeniy Ivanov if (data != MFG_ID)
114*58a2b000SEvgeniy Ivanov return 0;
115*58a2b000SEvgeniy Ivanov
116*58a2b000SEvgeniy Ivanov /* resolve contention using the Ethernet address */
117*58a2b000SEvgeniy Ivanov for (j = 0; j < 3; j++)
118*58a2b000SEvgeniy Ivanov data = get_eeprom_data(id_port, j);
119*58a2b000SEvgeniy Ivanov
120*58a2b000SEvgeniy Ivanov eth_base =
121*58a2b000SEvgeniy Ivanov (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
122*58a2b000SEvgeniy Ivanov outb(id_port, EP_LAST_TAG); /* tags board */
123*58a2b000SEvgeniy Ivanov outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
124*58a2b000SEvgeniy Ivanov /*
125*58a2b000SEvgeniy Ivanov ep_current_tag--;
126*58a2b000SEvgeniy Ivanov break;
127*58a2b000SEvgeniy Ivanov }
128*58a2b000SEvgeniy Ivanov
129*58a2b000SEvgeniy Ivanov if (i == EP_MAX_BOARDS)
130*58a2b000SEvgeniy Ivanov return 0;
131*58a2b000SEvgeniy Ivanov */
132*58a2b000SEvgeniy Ivanov
133*58a2b000SEvgeniy Ivanov /*
134*58a2b000SEvgeniy Ivanov * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
135*58a2b000SEvgeniy Ivanov * 0x9[0-f]50
136*58a2b000SEvgeniy Ivanov */
137*58a2b000SEvgeniy Ivanov GO_WINDOW(0);
138*58a2b000SEvgeniy Ivanov k = (u_int)ep_get_e(EEPROM_PROD_ID);
139*58a2b000SEvgeniy Ivanov if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
140*58a2b000SEvgeniy Ivanov return 0;
141*58a2b000SEvgeniy Ivanov
142*58a2b000SEvgeniy Ivanov printf("3C5x9 board on ISA at 0x%x - ", eth_base);
143*58a2b000SEvgeniy Ivanov
144*58a2b000SEvgeniy Ivanov /* test for presence of connectors */
145*58a2b000SEvgeniy Ivanov i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
146*58a2b000SEvgeniy Ivanov j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14;
147*58a2b000SEvgeniy Ivanov
148*58a2b000SEvgeniy Ivanov for (ether_medium = 0, m = mediatab;
149*58a2b000SEvgeniy Ivanov ether_medium < sizeof(mediatab) / sizeof(mediatab[0]);
150*58a2b000SEvgeniy Ivanov ether_medium++, m++) {
151*58a2b000SEvgeniy Ivanov if (j == m->address_cfg) {
152*58a2b000SEvgeniy Ivanov if (!(i & m->config_bit)) {
153*58a2b000SEvgeniy Ivanov printf("%s not present\n", m->name);
154*58a2b000SEvgeniy Ivanov return 0;
155*58a2b000SEvgeniy Ivanov }
156*58a2b000SEvgeniy Ivanov printf("using %s\n", m->name);
157*58a2b000SEvgeniy Ivanov goto ok;
158*58a2b000SEvgeniy Ivanov }
159*58a2b000SEvgeniy Ivanov }
160*58a2b000SEvgeniy Ivanov printf("unknown connector\n");
161*58a2b000SEvgeniy Ivanov return 0;
162*58a2b000SEvgeniy Ivanov
163*58a2b000SEvgeniy Ivanov ok:
164*58a2b000SEvgeniy Ivanov /*
165*58a2b000SEvgeniy Ivanov * Read the station address from the eeprom
166*58a2b000SEvgeniy Ivanov */
167*58a2b000SEvgeniy Ivanov p = (u_short *) eth_myaddr;
168*58a2b000SEvgeniy Ivanov for (i = 0; i < 3; i++) {
169*58a2b000SEvgeniy Ivanov u_short help;
170*58a2b000SEvgeniy Ivanov GO_WINDOW(0);
171*58a2b000SEvgeniy Ivanov help = ep_get_e(i);
172*58a2b000SEvgeniy Ivanov p[i] = ((help & 0xff) << 8) | ((help & 0xff00) >> 8);
173*58a2b000SEvgeniy Ivanov GO_WINDOW(2);
174*58a2b000SEvgeniy Ivanov outw(BASE + EP_W2_ADDR_0 + (i * 2), help);
175*58a2b000SEvgeniy Ivanov }
176*58a2b000SEvgeniy Ivanov for (i = 0; i < 6; i++)
177*58a2b000SEvgeniy Ivanov myadr[i] = eth_myaddr[i];
178*58a2b000SEvgeniy Ivanov
179*58a2b000SEvgeniy Ivanov epreset();
180*58a2b000SEvgeniy Ivanov
181*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE
182*58a2b000SEvgeniy Ivanov strncpy(bi_netif.ifname, "ep", sizeof(bi_netif.ifname));
183*58a2b000SEvgeniy Ivanov bi_netif.bus = BI_BUS_ISA;
184*58a2b000SEvgeniy Ivanov bi_netif.addr.iobase = eth_base;
185*58a2b000SEvgeniy Ivanov
186*58a2b000SEvgeniy Ivanov BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
187*58a2b000SEvgeniy Ivanov #endif
188*58a2b000SEvgeniy Ivanov
189*58a2b000SEvgeniy Ivanov return 1;
190*58a2b000SEvgeniy Ivanov }
191*58a2b000SEvgeniy Ivanov
192*58a2b000SEvgeniy Ivanov static int
send_ID_sequence(int port)193*58a2b000SEvgeniy Ivanov send_ID_sequence(int port)
194*58a2b000SEvgeniy Ivanov {
195*58a2b000SEvgeniy Ivanov int cx, al;
196*58a2b000SEvgeniy Ivanov
197*58a2b000SEvgeniy Ivanov for (al = 0xff, cx = 0; cx < 255; cx++) {
198*58a2b000SEvgeniy Ivanov outb(port, al);
199*58a2b000SEvgeniy Ivanov al <<= 1;
200*58a2b000SEvgeniy Ivanov if (al & 0x100)
201*58a2b000SEvgeniy Ivanov al ^= 0xcf;
202*58a2b000SEvgeniy Ivanov }
203*58a2b000SEvgeniy Ivanov return 1;
204*58a2b000SEvgeniy Ivanov }
205*58a2b000SEvgeniy Ivanov
206*58a2b000SEvgeniy Ivanov /*
207*58a2b000SEvgeniy Ivanov * We get eeprom data from the id_port given an offset into the eeprom.
208*58a2b000SEvgeniy Ivanov * Basically; after the ID_sequence is sent to all of the cards; they enter
209*58a2b000SEvgeniy Ivanov * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
210*58a2b000SEvgeniy Ivanov * the eeprom data. We then read the port 16 times and with every read; the
211*58a2b000SEvgeniy Ivanov * cards check for contention (ie: if one card writes a 0 bit and another
212*58a2b000SEvgeniy Ivanov * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
213*58a2b000SEvgeniy Ivanov * compares the data on the bus; if there is a difference then that card goes
214*58a2b000SEvgeniy Ivanov * into ID_WAIT state again). In the meantime; one bit of data is returned in
215*58a2b000SEvgeniy Ivanov * the AX register which is conveniently returned to us by inb(). Hence; we
216*58a2b000SEvgeniy Ivanov * read 16 times getting one bit of data with each read.
217*58a2b000SEvgeniy Ivanov */
218*58a2b000SEvgeniy Ivanov static int
get_eeprom_data(int id_port,int offset)219*58a2b000SEvgeniy Ivanov get_eeprom_data(int id_port, int offset)
220*58a2b000SEvgeniy Ivanov {
221*58a2b000SEvgeniy Ivanov int i, data = 0;
222*58a2b000SEvgeniy Ivanov outb(id_port, 0x80 + offset);
223*58a2b000SEvgeniy Ivanov delay(1000);
224*58a2b000SEvgeniy Ivanov for (i = 0; i < 16; i++)
225*58a2b000SEvgeniy Ivanov data = (data << 1) | (inw(id_port) & 1);
226*58a2b000SEvgeniy Ivanov return data;
227*58a2b000SEvgeniy Ivanov }
228