c29dea86587581af85cae5a8fa09e2a479802358
[people/xl0/gpxe.git] / src / drivers / net / 3c509.c
1 /*
2  * Split out into 3c509.c and 3c5x9.c, to make it possible to build a
3  * 3c529 module without including ISA, ISAPnP and EISA code.
4  *
5  */
6
7 #include "isa.h"
8 #include "io.h"
9 #include "timer.h"
10 #include "string.h"
11 #include "console.h"
12 #include "3c509.h"
13
14 /*
15  * 3c509 cards have their own method of contention resolution; this
16  * effectively defines another bus type.
17  *
18  */
19
20 /*
21  * A physical t509 device
22  *
23  */
24 struct t509_device {
25         char *magic; /* must be first */
26         uint16_t id_port;
27         uint16_t ioaddr;
28         unsigned char current_tag;
29 };
30
31 /*
32  * A t509 driver
33  *
34  */
35 struct t509_driver {
36         const char *name;
37 };
38
39 /*
40  * Ensure that there is sufficient space in the shared dev_bus
41  * structure for a struct pci_device.
42  *
43  */
44 DEV_BUS( struct t509_device, t509_dev );
45 static char t509_magic[0]; /* guaranteed unique symbol */
46
47 /*
48  * Find a port that can be used for contention select
49  *
50  * Called only once, so inlined for efficiency.
51  *
52  */
53 static inline int find_id_port ( struct t509_device *t509 ) {
54         for ( t509->id_port = EP_ID_PORT_START ;
55               t509->id_port < EP_ID_PORT_END ;
56               t509->id_port += EP_ID_PORT_INC ) {
57                 outb ( 0x00, t509->id_port );
58                 outb ( 0xff, t509->id_port );
59                 if ( inb ( t509->id_port ) & 0x01 ) {
60                         /* Found a suitable port */
61                         return 1;
62                 }
63         }
64         /* No id port available */
65         return 0;
66 }
67
68 /*
69  * Send ID sequence to the ID port
70  *
71  * Called only once, so inlined for efficiency.
72  *
73  */
74 static inline void send_id_sequence ( struct t509_device *t509 ) {
75         unsigned short lrs_state, i;
76
77         outb ( 0x00, t509->id_port );
78         outb ( 0x00, t509->id_port );
79         lrs_state = 0xff;
80         for ( i = 0; i < 255; i++ ) {
81                 outb ( lrs_state, t509->id_port );
82                 lrs_state <<= 1;
83                 lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
84         }
85 }
86
87 /*
88  * We get eeprom data from the id_port given an offset into the eeprom.
89  * Basically; after the ID_sequence is sent to all of the cards; they enter
90  * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
91  * the eeprom data.  We then read the port 16 times and with every read; the
92  * cards check for contention (ie: if one card writes a 0 bit and another
93  * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
94  * compares the data on the bus; if there is a difference then that card goes
95  * into ID_WAIT state again). In the meantime; one bit of data is returned in
96  * the AX register which is conveniently returned to us by inb().  Hence; we
97  * read 16 times getting one bit of data with each read.
98  */
99 static uint16_t id_read_eeprom ( struct t509_device *t509, int offset ) {
100         int i, data = 0;
101
102         outb ( 0x80 + offset, t509->id_port );
103         /* Do we really need this wait? Won't be noticeable anyway */
104         udelay(10000);
105
106         for ( i = 0; i < 16; i++ ) {
107                 data = ( data << 1 ) | ( inw ( t509->id_port ) & 1 );
108         }
109         return data;
110 }
111
112 /*
113  * Find the next t509 device
114  *
115  * Called only once, so inlined for efficiency.
116  *
117  */
118 static inline int fill_t509_device ( struct t509_device *t509 ) {
119         int i;
120         uint16_t iobase;
121
122         /*
123          * We need an ID port, if we don't already have one.
124          *
125          */
126         if ( ! t509->id_port ) {
127                 if ( ! find_id_port ( t509 ) ) {
128                         DBG ( "No ID port available for contention select\n" );
129                         return 0;
130                 }
131                 DBG ( "T509 scan using ID port at %hx\n", t509->id_port );
132         }
133
134         /* 
135          * If this is the start of the scan, clear all tag registers.
136          * Otherwise, tell already-found NICs not to respond.
137          *
138          */
139         if ( t509->current_tag == 0 ) {
140                 outb ( 0xd0, t509->id_port );
141         } else {
142                 outb ( 0xd8, t509->id_port ) ;
143         }
144
145         /* Send the ID sequence */
146         send_id_sequence ( t509 );
147
148         /* Check the manufacturer ID */
149         if ( id_read_eeprom ( t509, EEPROM_MFG_ID ) != MFG_ID ) {
150                 /* No more t509 devices */
151                 return 0;
152         }
153
154         /* Do contention select by reading the MAC address */
155         for ( i = 0 ; i < 3 ; i++ ) {
156                 id_read_eeprom ( t509, i );
157         }
158
159         /* By now, only one device will be left active.  Get its I/O
160          * address, tag and activate the adaptor.  Tagging will
161          * prevent it taking part in the next scan, enabling us to see
162          * the next device.
163          */
164         iobase = id_read_eeprom ( t509, EEPROM_ADDR_CFG );
165         t509->ioaddr = 0x200 + ( ( iobase & 0x1f ) << 4 );
166         outb ( ++t509->current_tag, t509->id_port ); /* tag */
167         outb ( ( 0xe0 | iobase ), t509->id_port ); /* activate */
168
169         DBG ( "T509 found at %hx (tagged as %hhx)\n", t509->ioaddr,
170               t509->current_tag );
171
172         return 1;
173 }
174
175 /*
176  * Find a t509 device matching the specified driver.  ("Matching the
177  * specified driver" is, in this case, a no-op, but we want to
178  * preserve the common bus API).
179  *
180  * Called only once, so inlined for efficiency.
181  *
182  */
183 static inline int find_t509_device ( struct t509_device *t509,
184                                      struct t509_driver *driver __unused ) {
185
186         /* Initialise struct t509 if it's the first time it's been used. */
187         if ( t509->magic != t509_magic ) {
188                 memset ( t509, 0, sizeof ( *t509 ) );
189                 t509->magic = t509_magic;
190         }
191
192         /* Find the next t509 device */
193         if ( ! fill_t509_device ( t509 ) )
194                 return 0;
195         
196         return 1;
197 }
198
199 /*
200  * Find the next T509 device that can be used to boot using the
201  * specified driver.
202  *
203  */
204 int find_t509_boot_device ( struct dev *dev, struct t509_driver *driver ) {
205         struct t509_device *t509 = ( struct t509_device * )dev->bus;
206
207         if ( ! find_t509_device ( t509, driver ) )
208                 return 0;
209
210         dev->name = driver->name;
211         dev->devid.bus_type = ISA_BUS_TYPE;
212         dev->devid.vendor_id = MFG_ID;
213         dev->devid.device_id = PROD_ID;
214         return 1;
215 }
216
217 /*
218  * The ISA probe function
219  *
220  */
221 static int el3_t509_probe ( struct dev *dev, struct t509_device *t509 ) {
222         struct nic *nic = nic_device ( dev );
223         
224         nic->ioaddr = t509->ioaddr;
225         nic->irqno = 0;
226         printf ( "3c509 board on ISA at %#hx - ", nic->ioaddr );
227
228         /* Hand off to generic t5x9 probe routine */
229         return t5x9_probe ( nic, ISA_PROD_ID ( PROD_ID ), ISA_PROD_ID_MASK );
230 }
231
232 static struct t509_driver el3_t509_driver = { "3c509 (ISA)" };
233
234 BOOT_DRIVER ( "3c509", find_t509_boot_device, el3_t509_driver,
235               el3_t509_probe );
236
237 ISA_ROM ( "3c509","3c509" );