7c6947777b997de9a2639b728b092b0335633969
[people/xl0/gpxe-arm.git] / src / drivers / net / smc9000.c
1 #ifdef ALLMULTI
2 #error multicast support is not yet implemented
3 #endif
4  /*------------------------------------------------------------------------
5  * smc9000.c
6  * This is a Etherboot driver for SMC's 9000 series of Ethernet cards.
7  *
8  * Copyright (C) 1998 Daniel Engström <daniel.engstrom@riksnett.no>
9  * Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman
10  * Copyright (C) 1996 by Erik Stahlman <eric@vt.edu>
11  *
12  * This software may be used and distributed according to the terms
13  * of the GNU Public License, incorporated herein by reference.
14  *
15  * "Features" of the SMC chip:
16  *   4608 byte packet memory. ( for the 91C92/4.  Others have more )
17  *   EEPROM for configuration
18  *   AUI/TP selection
19  *
20  * Authors
21  *      Erik Stahlman                           <erik@vt.edu>
22  *      Daniel Engström                         <daniel.engstrom@riksnett.no>
23  *
24  * History
25  * 98-09-25              Daniel Engström Etherboot driver crated from Eric's
26  *                                       Linux driver.
27  *
28  *---------------------------------------------------------------------------*/
29 #define LINUX_OUT_MACROS 1
30 #define SMC9000_DEBUG    0
31
32 #include "etherboot.h"
33 #include "nic.h"
34 #include "isa.h"
35 #include "smc9000.h"
36
37 # define _outb outb
38 # define _outw outw
39
40 static const char       smc9000_version[] = "Version 0.99 98-09-30";
41 static const char       *interfaces[ 2 ] = { "TP", "AUI" };
42 static const char       *chip_ids[ 15 ] =  {
43    NULL, NULL, NULL,
44    /* 3 */ "SMC91C90/91C92",
45    /* 4 */ "SMC91C94",
46    /* 5 */ "SMC91C95",
47    NULL,
48    /* 7 */ "SMC91C100",
49    /* 8 */ "SMC91C100FD",
50    NULL, NULL, NULL,
51    NULL, NULL, NULL
52 };
53 static const char      smc91c96_id[] = "SMC91C96";
54
55 /*
56  * Function: smc_reset( int ioaddr )
57  * Purpose:
58  *      This sets the SMC91xx chip to its normal state, hopefully from whatever
59  *      mess that any other DOS driver has put it in.
60  *
61  * Maybe I should reset more registers to defaults in here?  SOFTRESET  should
62  * do that for me.
63  *
64  * Method:
65  *      1.  send a SOFT RESET
66  *      2.  wait for it to finish
67  *      3.  reset the memory management unit
68  *      4.  clear all interrupts
69  *
70 */
71 static void smc_reset(int ioaddr)
72 {
73    /* This resets the registers mostly to defaults, but doesn't
74     * affect EEPROM.  That seems unnecessary */
75    SMC_SELECT_BANK(ioaddr, 0);
76    _outw( RCR_SOFTRESET, ioaddr + RCR );
77
78    /* this should pause enough for the chip to be happy */
79    SMC_DELAY(ioaddr);
80
81    /* Set the transmit and receive configuration registers to
82     * default values */
83    _outw(RCR_CLEAR, ioaddr + RCR);
84    _outw(TCR_CLEAR, ioaddr + TCR);
85
86    /* Reset the MMU */
87    SMC_SELECT_BANK(ioaddr, 2);
88    _outw( MC_RESET, ioaddr + MMU_CMD );
89
90    /* Note:  It doesn't seem that waiting for the MMU busy is needed here,
91     * but this is a place where future chipsets _COULD_ break.  Be wary
92     * of issuing another MMU command right after this */
93    _outb(0, ioaddr + INT_MASK);
94 }
95
96
97 /*----------------------------------------------------------------------
98  * Function: smc9000_probe_addr( int ioaddr )
99  *
100  * Purpose:
101  *      Tests to see if a given ioaddr points to an SMC9xxx chip.
102  *      Returns a 1 on success
103  *
104  * Algorithm:
105  *      (1) see if the high byte of BANK_SELECT is 0x33
106  *      (2) compare the ioaddr with the base register's address
107  *      (3) see if I recognize the chip ID in the appropriate register
108  *
109  * ---------------------------------------------------------------------
110  */
111 static int smc9000_probe_addr( isa_probe_addr_t ioaddr )
112 {
113    word bank;
114    word revision_register;
115    word base_address_register;
116
117    /* First, see if the high byte is 0x33 */
118    bank = inw(ioaddr + BANK_SELECT);
119    if ((bank & 0xFF00) != 0x3300) {
120       return 0;
121    }
122    /* The above MIGHT indicate a device, but I need to write to further
123     *   test this.  */
124    _outw(0x0, ioaddr + BANK_SELECT);
125    bank = inw(ioaddr + BANK_SELECT);
126    if ((bank & 0xFF00) != 0x3300) {
127       return 0;
128    }
129
130    /* well, we've already written once, so hopefully another time won't
131     *  hurt.  This time, I need to switch the bank register to bank 1,
132     *  so I can access the base address register */
133    SMC_SELECT_BANK(ioaddr, 1);
134    base_address_register = inw(ioaddr + BASE);
135
136    if (ioaddr != (base_address_register >> 3 & 0x3E0))  {
137       DBG("SMC9000: IOADDR %hX doesn't match configuration (%hX)."
138           "Probably not a SMC chip\n",
139           ioaddr, base_address_register >> 3 & 0x3E0);
140       /* well, the base address register didn't match.  Must not have
141        * been a SMC chip after all. */
142       return 0;
143    }
144
145
146    /* check if the revision register is something that I recognize.
147     * These might need to be added to later, as future revisions
148     * could be added.  */
149    SMC_SELECT_BANK(ioaddr, 3);
150    revision_register  = inw(ioaddr + REVISION);
151    if (!chip_ids[(revision_register >> 4) & 0xF]) {
152       /* I don't recognize this chip, so... */
153       DBG( "SMC9000: IO %hX: Unrecognized revision register:"
154            " %hX, Contact author.\n", ioaddr, revision_register );
155       return 0;
156    }
157
158    /* at this point I'll assume that the chip is an SMC9xxx.
159     * It might be prudent to check a listing of MAC addresses
160     * against the hardware address, or do some other tests. */
161    return 1;
162 }
163
164
165 /**************************************************************************
166  * ETH_TRANSMIT - Transmit a frame
167  ***************************************************************************/
168 static void smc9000_transmit(
169         struct nic *nic,
170         const char *d,                  /* Destination */
171         unsigned int t,                 /* Type */
172         unsigned int s,                 /* size */
173         const char *p)                  /* Packet */
174 {
175    word length; /* real, length incl. header */
176    word numPages;
177    unsigned long time_out;
178    byte packet_no;
179    word status;
180    int i;
181
182    /* We dont pad here since we can have the hardware doing it for us */
183    length = (s + ETH_HLEN + 1)&~1;
184
185    /* convert to MMU pages */
186    numPages = length / 256;
187
188    if (numPages > 7 ) {
189       DBG("SMC9000: Far too big packet error. \n");
190       return;
191    }
192
193    /* dont try more than, say 30 times */
194    for (i=0;i<30;i++) {
195       /* now, try to allocate the memory */
196       SMC_SELECT_BANK(nic->ioaddr, 2);
197       _outw(MC_ALLOC | numPages, nic->ioaddr + MMU_CMD);
198
199       status = 0;
200       /* wait for the memory allocation to finnish */
201       for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) {
202          status = inb(nic->ioaddr + INTERRUPT);
203          if ( status & IM_ALLOC_INT ) {
204             /* acknowledge the interrupt */
205             _outb(IM_ALLOC_INT, nic->ioaddr + INTERRUPT);
206             break;
207          }
208       }
209
210       if ((status & IM_ALLOC_INT) != 0 ) {
211          /* We've got the memory */
212          break;
213       } else {
214          printf("SMC9000: Memory allocation timed out, resetting MMU.\n");
215          _outw(MC_RESET, nic->ioaddr + MMU_CMD);
216       }
217    }
218
219    /* If I get here, I _know_ there is a packet slot waiting for me */
220    packet_no = inb(nic->ioaddr + PNR_ARR + 1);
221    if (packet_no & 0x80) {
222       /* or isn't there?  BAD CHIP! */
223       printf("SMC9000: Memory allocation failed. \n");
224       return;
225    }
226
227    /* we have a packet address, so tell the card to use it */
228    _outb(packet_no, nic->ioaddr + PNR_ARR);
229
230    /* point to the beginning of the packet */
231    _outw(PTR_AUTOINC, nic->ioaddr + POINTER);
232
233 #if     SMC9000_DEBUG > 2
234    printf("Trying to xmit packet of length %hX\n", length );
235 #endif
236
237    /* send the packet length ( +6 for status, length and ctl byte )
238     * and the status word ( set to zeros ) */
239    _outw(0, nic->ioaddr + DATA_1 );
240
241    /* send the packet length ( +6 for status words, length, and ctl) */
242    _outb((length+6) & 0xFF,  nic->ioaddr + DATA_1);
243    _outb((length+6) >> 8 ,   nic->ioaddr + DATA_1);
244
245    /* Write the contents of the packet */
246
247    /* The ethernet header first... */
248    outsw(nic->ioaddr + DATA_1, d, ETH_ALEN >> 1);
249    outsw(nic->ioaddr + DATA_1, nic->node_addr, ETH_ALEN >> 1);
250    _outw(htons(t), nic->ioaddr + DATA_1);
251
252    /* ... the data ... */
253    outsw(nic->ioaddr + DATA_1 , p, s >> 1);
254
255    /* ... and the last byte, if there is one.   */
256    if ((s & 1) == 0) {
257       _outw(0, nic->ioaddr + DATA_1);
258    } else {
259       _outb(p[s-1], nic->ioaddr + DATA_1);
260       _outb(0x20, nic->ioaddr + DATA_1);
261    }
262
263    /* and let the chipset deal with it */
264    _outw(MC_ENQUEUE , nic->ioaddr + MMU_CMD);
265
266    status = 0; time_out = currticks() + 5*TICKS_PER_SEC;
267    do {
268       status = inb(nic->ioaddr + INTERRUPT);
269
270       if ((status & IM_TX_INT ) != 0) {
271          word tx_status;
272
273          /* ack interrupt */
274          _outb(IM_TX_INT, nic->ioaddr + INTERRUPT);
275
276          packet_no = inw(nic->ioaddr + FIFO_PORTS);
277          packet_no &= 0x7F;
278
279          /* select this as the packet to read from */
280          _outb( packet_no, nic->ioaddr + PNR_ARR );
281
282          /* read the first word from this packet */
283          _outw( PTR_AUTOINC | PTR_READ, nic->ioaddr + POINTER );
284
285          tx_status = inw( nic->ioaddr + DATA_1 );
286
287          if (0 == (tx_status & TS_SUCCESS)) {
288             DBG("SMC9000: TX FAIL STATUS: %hX \n", tx_status);
289             /* re-enable transmit */
290             SMC_SELECT_BANK(nic->ioaddr, 0);
291             _outw(inw(nic->ioaddr + TCR ) | TCR_ENABLE, nic->ioaddr + TCR );
292          }
293
294          /* kill the packet */
295          SMC_SELECT_BANK(nic->ioaddr, 2);
296          _outw(MC_FREEPKT, nic->ioaddr + MMU_CMD);
297
298          return;
299       }
300    }while(currticks() < time_out);
301
302    printf("SMC9000: TX timed out, resetting board\n");
303    smc_reset(nic->ioaddr);
304    return;
305 }
306
307 /**************************************************************************
308  * ETH_POLL - Wait for a frame
309  ***************************************************************************/
310 static int smc9000_poll(struct nic *nic, int retrieve)
311 {
312    SMC_SELECT_BANK(nic->ioaddr, 2);
313    if (inw(nic->ioaddr + FIFO_PORTS) & FP_RXEMPTY)
314      return 0;
315    
316    if ( ! retrieve ) return 1;
317
318    /*  start reading from the start of the packet */
319    _outw(PTR_READ | PTR_RCV | PTR_AUTOINC, nic->ioaddr + POINTER);
320
321    /* First read the status and check that we're ok */
322    if (!(inw(nic->ioaddr + DATA_1) & RS_ERRORS)) {
323       /* Next: read the packet length and mask off the top bits */
324       nic->packetlen = (inw(nic->ioaddr + DATA_1) & 0x07ff);
325
326       /* the packet length includes the 3 extra words */
327       nic->packetlen -= 6;
328 #if     SMC9000_DEBUG > 2
329       printf(" Reading %d words (and %d byte(s))\n",
330                (nic->packetlen >> 1), nic->packetlen & 1);
331 #endif
332       /* read the packet (and the last "extra" word) */
333       insw(nic->ioaddr + DATA_1, nic->packet, (nic->packetlen+2) >> 1);
334       /* is there an odd last byte ? */
335       if (nic->packet[nic->packetlen+1] & 0x20)
336          nic->packetlen++;
337
338       /*  error or good, tell the card to get rid of this packet */
339       _outw(MC_RELEASE, nic->ioaddr + MMU_CMD);
340       return 1;
341    }
342
343    printf("SMC9000: RX error\n");
344    /*  error or good, tell the card to get rid of this packet */
345    _outw(MC_RELEASE, nic->ioaddr + MMU_CMD);
346    return 0;
347 }
348
349 static void smc9000_disable ( struct nic *nic, struct isa_device *isa __unused ) {
350    nic_disable ( nic );
351    smc_reset(nic->ioaddr);
352
353    /* no more interrupts for me */
354    SMC_SELECT_BANK(nic->ioaddr, 2);
355    _outb( 0, nic->ioaddr + INT_MASK);
356
357    /* and tell the card to stay away from that nasty outside world */
358    SMC_SELECT_BANK(nic->ioaddr, 0);
359    _outb( RCR_CLEAR, nic->ioaddr + RCR );
360    _outb( TCR_CLEAR, nic->ioaddr + TCR );
361 }
362
363 static void smc9000_irq(struct nic *nic __unused, irq_action_t action __unused)
364 {
365   switch ( action ) {
366   case DISABLE :
367     break;
368   case ENABLE :
369     break;
370   case FORCE :
371     break;
372   }
373 }
374
375 static struct nic_operations smc9000_operations = {
376         .connect        = dummy_connect,
377         .poll           = smc9000_poll,
378         .transmit       = smc9000_transmit,
379         .irq            = smc9000_irq,
380
381 };
382
383 /**************************************************************************
384  * ETH_PROBE - Look for an adapter
385  ***************************************************************************/
386
387 static int smc9000_probe ( struct nic *nic, struct isa_device *isa ) {
388
389    unsigned short   revision;
390    int              memory;
391    int              media;
392    const char *     version_string;
393    const char *     if_string;
394    int              i;
395
396    nic->irqno  = 0;
397    isa_fill_nic ( nic, isa );
398    nic->ioaddr = isa->ioaddr;
399
400    /*
401     * Get the MAC address ( bank 1, regs 4 - 9 )
402     */
403    SMC_SELECT_BANK(nic->ioaddr, 1);
404    for ( i = 0; i < 6; i += 2 ) {
405       word address;
406
407       address = inw(nic->ioaddr + ADDR0 + i);
408       nic->node_addr[i+1] = address >> 8;
409       nic->node_addr[i] = address & 0xFF;
410    }
411
412    /* get the memory information */
413    SMC_SELECT_BANK(nic->ioaddr, 0);
414    memory = ( inw(nic->ioaddr + MCR) >> 9 )  & 0x7;  /* multiplier */
415    memory *= 256 * (inw(nic->ioaddr + MIR) & 0xFF);
416
417    /*
418     * Now, I want to find out more about the chip.  This is sort of
419     * redundant, but it's cleaner to have it in both, rather than having
420     * one VERY long probe procedure.
421     */
422    SMC_SELECT_BANK(nic->ioaddr, 3);
423    revision  = inw(nic->ioaddr + REVISION);
424    version_string = chip_ids[(revision >> 4) & 0xF];
425
426    if (((revision & 0xF0) >> 4 == CHIP_9196) &&
427        ((revision & 0x0F) >= REV_9196)) {
428       /* This is a 91c96. 'c96 has the same chip id as 'c94 (4) but
429        * a revision starting at 6 */
430       version_string = smc91c96_id;
431    }
432
433    if ( !version_string ) {
434       /* I shouldn't get here because this call was done before.... */
435       return 0;
436    }
437
438    /* is it using AUI or 10BaseT ? */
439    SMC_SELECT_BANK(nic->ioaddr, 1);
440    if (inw(nic->ioaddr + CONFIG) & CFG_AUI_SELECT)
441      media = 2;
442    else
443      media = 1;
444
445    if_string = interfaces[media - 1];
446
447    /* now, reset the chip, and put it into a known state */
448    smc_reset(nic->ioaddr);
449
450    printf("SMC9000 %s\n", smc9000_version);
451    DBG("Copyright (C) 1998 Daniel Engstr\x94m\n");
452    DBG("Copyright (C) 1996 Eric Stahlman\n");
453
454    printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n",
455           version_string, revision & 0xF,
456           nic->ioaddr, if_string, memory );
457    /*
458     * Print the Ethernet address
459     */
460    printf("Ethernet MAC address: %!\n", nic->node_addr);
461
462    SMC_SELECT_BANK(nic->ioaddr, 0);
463
464    /* see the header file for options in TCR/RCR NORMAL*/
465    _outw(TCR_NORMAL, nic->ioaddr + TCR);
466    _outw(RCR_NORMAL, nic->ioaddr + RCR);
467
468    /* Select which interface to use */
469    SMC_SELECT_BANK(nic->ioaddr, 1);
470    if ( media == 1 ) {
471       _outw( inw( nic->ioaddr + CONFIG ) & ~CFG_AUI_SELECT,
472            nic->ioaddr + CONFIG );
473    }
474    else if ( media == 2 ) {
475       _outw( inw( nic->ioaddr + CONFIG ) | CFG_AUI_SELECT,
476            nic->ioaddr + CONFIG );
477    }
478
479    nic->nic_op  = &smc9000_operations;
480    return 1;
481 }
482
483 /*
484  * The SMC9000 can be at any of the following port addresses.  To
485  * change for a slightly different card, you can add it to the array.
486  *
487  */
488 static isa_probe_addr_t smc9000_probe_addrs[] = {
489    0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
490    0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0,
491 };
492
493 ISA_DRIVER ( smc9000_driver, smc9000_probe_addrs, smc9000_probe_addr,
494                      GENERIC_ISAPNP_VENDOR, 0x8228 );
495
496 DRIVER ( "SMC9000", nic_driver, isa_driver, smc9000_driver,
497          smc9000_probe, smc9000_disable );
498
499 ISA_ROM ( "smc9000", "SMC9000" );
500
501 /*
502  * Local variables:
503  *  c-basic-offset: 3
504  * End:
505  */