1/**************************************************************************
2*
3*    mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip.
4*    Written 2004-2004 by Erdem Güven <zuencap@yahoo.com>
5*
6*    This program is free software; you can redistribute it and/or modify
7*    it under the terms of the GNU General Public License as published by
8*    the Free Software Foundation; either version 2 of the License, or
9*    (at your option) any later version.
10*
11*    This program is distributed in the hope that it will be useful,
12*    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*    GNU General Public License for more details.
15*
16*    You should have received a copy of the GNU General Public License
17*    along with this program; if not, write to the Free Software
18*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*
20*    Portions of this code based on:
21*               fealnx.c: A Linux device driver for the mtd80x Ethernet chip
22*               Written 1998-2000 by Donald Becker
23*
24***************************************************************************/
25
26FILE_LICENCE ( GPL2_OR_LATER );
27
28/* to get some global routines like printf */
29#include "etherboot.h"
30/* to get the interface to the body of the program */
31#include "nic.h"
32/* to get the PCI support functions, if this is a PCI NIC */
33#include <gpxe/pci.h>
34#include <gpxe/ethernet.h>
35#include <mii.h>
36
37/* Condensed operations for readability. */
38#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
39#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
40#define get_unaligned(ptr) (*(ptr))
41
42
43/* Operational parameters that are set at compile time. */
44
45/* Keep the ring sizes a power of two for compile efficiency.           */
46/* The compiler will convert <unsigned>'%'<2^N> into a bit mask.        */
47/* Making the Tx ring too large decreases the effectiveness of channel  */
48/* bonding and packet priority.                                         */
49/* There are no ill effects from too-large receive rings.               */
50#define TX_RING_SIZE 2
51#define TX_QUEUE_LEN 10 /* Limit ring entries actually used.  */
52#define RX_RING_SIZE 4
53
54/* Operational parameters that usually are not changed. */
55/* Time in jiffies before concluding the transmitter is hung. */
56#define HZ 100
57#define TX_TIME_OUT   (6*HZ)
58
59/* Allocation size of Rx buffers with normal sized Ethernet frames.
60   Do not change this value without good reason.  This is not a limit,
61   but a way to keep a consistent allocation size among drivers.
62 */
63#define PKT_BUF_SZ 1536
64
65/* for different PHY */
66enum phy_type_flags {
67    MysonPHY = 1,
68    AhdocPHY = 2,
69    SeeqPHY = 3,
70    MarvellPHY = 4,
71    Myson981 = 5,
72    LevelOnePHY = 6,
73    OtherPHY = 10,
74};
75
76/* A chip capabilities table*/
77enum chip_capability_flags {
78    HAS_MII_XCVR,
79    HAS_CHIP_XCVR,
80};
81
82#if 0 /* not used */
83static
84struct chip_info
85{
86    u16 dev_id;
87    int flag;
88}
89mtd80x_chips[] = {
90                     {0x0800, HAS_MII_XCVR},
91                     {0x0803, HAS_CHIP_XCVR},
92                     {0x0891, HAS_MII_XCVR}
93                 };
94static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info );
95#endif
96
97/* Offsets to the Command and Status Registers. */
98enum mtd_offsets {
99    PAR0 = 0x0,        /* physical address 0-3 */
100    PAR1 = 0x04,        /* physical address 4-5 */
101    MAR0 = 0x08,        /* multicast address 0-3 */
102    MAR1 = 0x0C,        /* multicast address 4-7 */
103    FAR0 = 0x10,        /* flow-control address 0-3 */
104    FAR1 = 0x14,        /* flow-control address 4-5 */
105    TCRRCR = 0x18,        /* receive & transmit configuration */
106    BCR = 0x1C,        /* bus command */
107    TXPDR = 0x20,        /* transmit polling demand */
108    RXPDR = 0x24,        /* receive polling demand */
109    RXCWP = 0x28,        /* receive current word pointer */
110    TXLBA = 0x2C,        /* transmit list base address */
111    RXLBA = 0x30,        /* receive list base address */
112    ISR = 0x34,        /* interrupt status */
113    IMR = 0x38,        /* interrupt mask */
114    FTH = 0x3C,        /* flow control high/low threshold */
115    MANAGEMENT = 0x40,    /* bootrom/eeprom and mii management */
116    TALLY = 0x44,        /* tally counters for crc and mpa */
117    TSR = 0x48,        /* tally counter for transmit status */
118    BMCRSR = 0x4c,        /* basic mode control and status */
119    PHYIDENTIFIER = 0x50,    /* phy identifier */
120    ANARANLPAR = 0x54,    /* auto-negotiation advertisement and link
121                                                       partner ability */
122    ANEROCR = 0x58,        /* auto-negotiation expansion and pci conf. */
123    BPREMRPSR = 0x5c,    /* bypass & receive error mask and phy status */
124};
125
126/* Bits in the interrupt status/enable registers. */
127/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
128enum intr_status_bits {
129    RFCON = 0x00020000, /* receive flow control xon packet */
130    RFCOFF = 0x00010000, /* receive flow control xoff packet */
131    LSCStatus = 0x00008000, /* link status change */
132    ANCStatus = 0x00004000, /* autonegotiation completed */
133    FBE = 0x00002000, /* fatal bus error */
134    FBEMask = 0x00001800, /* mask bit12-11 */
135    ParityErr = 0x00000000, /* parity error */
136    TargetErr = 0x00001000, /* target abort */
137    MasterErr = 0x00000800, /* master error */
138    TUNF = 0x00000400, /* transmit underflow */
139    ROVF = 0x00000200, /* receive overflow */
140    ETI = 0x00000100, /* transmit early int */
141    ERI = 0x00000080, /* receive early int */
142    CNTOVF = 0x00000040, /* counter overflow */
143    RBU = 0x00000020, /* receive buffer unavailable */
144    TBU = 0x00000010, /* transmit buffer unavilable */
145    TI = 0x00000008, /* transmit interrupt */
146    RI = 0x00000004, /* receive interrupt */
147    RxErr = 0x00000002, /* receive error */
148};
149
150/* Bits in the NetworkConfig register. */
151enum rx_mode_bits {
152    RxModeMask   = 0xe0,
153    AcceptAllPhys = 0x80,        /* promiscuous mode */
154    AcceptBroadcast = 0x40,        /* accept broadcast */
155    AcceptMulticast = 0x20,        /* accept mutlicast */
156    AcceptRunt   = 0x08,        /* receive runt pkt */
157    ALP          = 0x04,        /* receive long pkt */
158    AcceptErr    = 0x02,        /* receive error pkt */
159
160    AcceptMyPhys = 0x00000000,
161    RxEnable     = 0x00000001,
162    RxFlowCtrl   = 0x00002000,
163    TxEnable     = 0x00040000,
164    TxModeFDX    = 0x00100000,
165    TxThreshold  = 0x00e00000,
166
167    PS1000       = 0x00010000,
168    PS10         = 0x00080000,
169    FD           = 0x00100000,
170};
171
172/* Bits in network_desc.status */
173enum rx_desc_status_bits {
174    RXOWN = 0x80000000, /* own bit */
175    FLNGMASK = 0x0fff0000, /* frame length */
176    FLNGShift = 16,
177    MARSTATUS = 0x00004000, /* multicast address received */
178    BARSTATUS = 0x00002000, /* broadcast address received */
179    PHYSTATUS = 0x00001000, /* physical address received */
180    RXFSD = 0x00000800, /* first descriptor */
181    RXLSD = 0x00000400, /* last descriptor */
182    ErrorSummary = 0x80, /* error summary */
183    RUNT = 0x40,  /* runt packet received */
184    LONG = 0x20,  /* long packet received */
185    FAE = 0x10,  /* frame align error */
186    CRC = 0x08,  /* crc error */
187    RXER = 0x04,  /* receive error */
188};
189
190enum rx_desc_control_bits {
191    RXIC = 0x00800000, /* interrupt control */
192    RBSShift = 0,
193};
194
195enum tx_desc_status_bits {
196    TXOWN = 0x80000000, /* own bit */
197    JABTO = 0x00004000, /* jabber timeout */
198    CSL = 0x00002000, /* carrier sense lost */
199    LC = 0x00001000, /* late collision */
200    EC = 0x00000800, /* excessive collision */
201    UDF = 0x00000400, /* fifo underflow */
202    DFR = 0x00000200, /* deferred */
203    HF = 0x00000100, /* heartbeat fail */
204    NCRMask = 0x000000ff, /* collision retry count */
205    NCRShift = 0,
206};
207
208enum tx_desc_control_bits {
209    TXIC = 0x80000000, /* interrupt control */
210    ETIControl = 0x40000000, /* early transmit interrupt */
211    TXLD = 0x20000000, /* last descriptor */
212    TXFD = 0x10000000, /* first descriptor */
213    CRCEnable = 0x08000000, /* crc control */
214    PADEnable = 0x04000000, /* padding control */
215    RetryTxLC = 0x02000000, /* retry late collision */
216    PKTSMask = 0x3ff800, /* packet size bit21-11 */
217    PKTSShift = 11,
218    TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */
219    TBSShift = 0,
220};
221
222/* BootROM/EEPROM/MII Management Register */
223#define MASK_MIIR_MII_READ       0x00000000
224#define MASK_MIIR_MII_WRITE      0x00000008
225#define MASK_MIIR_MII_MDO        0x00000004
226#define MASK_MIIR_MII_MDI        0x00000002
227#define MASK_MIIR_MII_MDC        0x00000001
228
229/* ST+OP+PHYAD+REGAD+TA */
230#define OP_READ             0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */
231#define OP_WRITE            0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */
232
233/* ------------------------------------------------------------------------- */
234/*      Constants for Myson PHY                                              */
235/* ------------------------------------------------------------------------- */
236#define MysonPHYID      0xd0000302
237/* 89-7-27 add, (begin) */
238#define MysonPHYID0     0x0302
239#define StatusRegister  18
240#define SPEED100        0x0400 // bit10
241#define FULLMODE        0x0800 // bit11
242/* 89-7-27 add, (end) */
243
244/* ------------------------------------------------------------------------- */
245/*      Constants for Seeq 80225 PHY                                         */
246/* ------------------------------------------------------------------------- */
247#define SeeqPHYID0      0x0016
248
249#define MIIRegister18   18
250#define SPD_DET_100     0x80
251#define DPLX_DET_FULL   0x40
252
253/* ------------------------------------------------------------------------- */
254/*      Constants for Ahdoc 101 PHY                                          */
255/* ------------------------------------------------------------------------- */
256#define AhdocPHYID0     0x0022
257
258#define DiagnosticReg   18
259#define DPLX_FULL       0x0800
260#define Speed_100       0x0400
261
262/* 89/6/13 add, */
263/* -------------------------------------------------------------------------- */
264/*      Constants                                                             */
265/* -------------------------------------------------------------------------- */
266#define MarvellPHYID0           0x0141
267#define LevelOnePHYID0  0x0013
268
269#define MII1000BaseTControlReg  9
270#define MII1000BaseTStatusReg   10
271#define SpecificReg  17
272
273/* for 1000BaseT Control Register */
274#define PHYAbletoPerform1000FullDuplex  0x0200
275#define PHYAbletoPerform1000HalfDuplex  0x0100
276#define PHY1000AbilityMask              0x300
277
278// for phy specific status register, marvell phy.
279#define SpeedMask       0x0c000
280#define Speed_1000M     0x08000
281#define Speed_100M      0x4000
282#define Speed_10M       0
283#define Full_Duplex     0x2000
284
285// 89/12/29 add, for phy specific status register, levelone phy, (begin)
286#define LXT1000_100M    0x08000
287#define LXT1000_1000M   0x0c000
288#define LXT1000_Full    0x200
289// 89/12/29 add, for phy specific status register, levelone phy, (end)
290
291#if 0
292/* for 3-in-1 case */
293#define PS10            0x00080000
294#define FD              0x00100000
295#define PS1000          0x00010000
296#endif
297
298/* for PHY */
299#define LinkIsUp        0x0004
300#define LinkIsUp2 0x00040000
301
302/* Create a static buffer of size PKT_BUF_SZ for each
303RX and TX Descriptor.  All descriptors point to a
304part of this buffer */
305struct {
306	u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8)));
307	u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8)));
308} mtd80x_bufs __shared;
309#define txb mtd80x_bufs.txb
310#define rxb mtd80x_bufs.rxb
311
312/* The Tulip Rx and Tx buffer descriptors. */
313struct mtd_desc
314{
315    s32 status;
316    s32 control;
317    u32 buffer;
318    u32 next_desc;
319    struct mtd_desc *next_desc_logical;
320    u8* skbuff;
321    u32 reserved1;
322    u32 reserved2;
323};
324
325struct mtd_private
326{
327    struct mtd_desc rx_ring[RX_RING_SIZE];
328    struct mtd_desc tx_ring[TX_RING_SIZE];
329
330    /* Frequently used values: keep some adjacent for cache effect. */
331    int flags;
332    struct pci_dev *pci_dev;
333    unsigned long crvalue;
334    unsigned long bcrvalue;
335    /*unsigned long imrvalue;*/
336    struct mtd_desc *cur_rx;
337    struct mtd_desc *lack_rxbuf;
338    int really_rx_count;
339    struct mtd_desc *cur_tx;
340    struct mtd_desc *cur_tx_copy;
341    int really_tx_count;
342    int free_tx_count;
343    unsigned int rx_buf_sz; /* Based on MTU+slack. */
344
345    /* These values are keep track of the transceiver/media in use. */
346    unsigned int linkok;
347    unsigned int line_speed;
348    unsigned int duplexmode;
349    unsigned int default_port:
350    4; /* Last dev->if_port value. */
351    unsigned int PHYType;
352
353    /* MII transceiver section. */
354    int mii_cnt;  /* MII device addresses. */
355    unsigned char phys[1]; /* MII device addresses. */
356
357    /*other*/
358    const char *nic_name;
359    int ioaddr;
360    u16 dev_id;
361};
362
363static struct mtd_private mtdx;
364
365static int mdio_read(struct nic * , int phy_id, int location);
366static void getlinktype(struct nic * );
367static void getlinkstatus(struct nic * );
368static void set_rx_mode(struct nic *);
369
370/**************************************************************************
371 *  init_ring - setup the tx and rx descriptors
372 *************************************************************************/
373static void init_ring(struct nic *nic __unused)
374{
375    int i;
376
377    mtdx.cur_rx = &mtdx.rx_ring[0];
378
379    mtdx.rx_buf_sz = PKT_BUF_SZ;
380    /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/
381
382    /* Initialize all Rx descriptors. */
383    /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
384    for (i = 0; i < RX_RING_SIZE; i++)
385    {
386        mtdx.rx_ring[i].status = RXOWN;
387        mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift;
388        mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]);
389        mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1];
390        mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
391        mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ];
392    }
393    /* Mark the last entry as wrapping the ring. */
394    mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]);
395    mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0];
396
397    /* We only use one transmit buffer, but two
398     * descriptors so transmit engines have somewhere
399     * to point should they feel the need */
400    mtdx.tx_ring[0].status = 0x00000000;
401    mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]);
402    mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]);
403
404    /* This descriptor is never used */
405    mtdx.tx_ring[1].status = 0x00000000;
406    mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */
407    mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]);
408
409    return;
410}
411
412/**************************************************************************
413RESET - Reset Adapter
414***************************************************************************/
415static void mtd_reset( struct nic *nic )
416{
417    /* Reset the chip to erase previous misconfiguration. */
418    outl(0x00000001, mtdx.ioaddr + BCR);
419
420    init_ring(nic);
421
422    outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA);
423    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
424
425    /* Initialize other registers. */
426    /* Configure the PCI bus bursts and FIFO thresholds. */
427    mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */
428    mtdx.crvalue = 0xa00; /* rx 128 burst length */
429
430	if ( mtdx.dev_id == 0x891 ) {
431		mtdx.bcrvalue |= 0x200;	/* set PROG bit */
432		mtdx.crvalue |= 0x02000000;	/* set enhanced bit */
433	}
434
435    outl( mtdx.bcrvalue, mtdx.ioaddr + BCR);
436
437    /* Restart Rx engine if stopped. */
438    outl(0, mtdx.ioaddr + RXPDR);
439
440    getlinkstatus(nic);
441    if (mtdx.linkok)
442    {
443        static const char* texts[]={"half","full","10","100","1000"};
444        getlinktype(nic);
445        DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] );
446    } else
447    {
448        DBG ( "No link!!!\n" );
449    }
450
451    mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold;
452    set_rx_mode(nic);
453
454    /* Clear interrupts by setting the interrupt mask. */
455    outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR);
456    outl( 0, mtdx.ioaddr + IMR);
457}
458
459/**************************************************************************
460POLL - Wait for a frame
461***************************************************************************/
462static int mtd_poll(struct nic *nic, __unused int retrieve)
463{
464    s32 rx_status = mtdx.cur_rx->status;
465    int retval = 0;
466
467    if( ( rx_status & RXOWN ) != 0 )
468    {
469        return 0;
470    }
471
472    if (rx_status & ErrorSummary)
473    { /* there was a fatal error */
474        printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n",
475                mtdx.nic_name, (unsigned int) rx_status,
476                (rx_status & (LONG | RUNT)) ? "length_error ":"",
477                (rx_status & RXER) ? "frame_error ":"",
478                (rx_status & CRC) ? "crc_error ":"" );
479        retval = 0;
480    } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) )
481    {
482        /* this pkt is too long, over one rx buffer */
483        printf("Pkt is too long, over one rx buffer.\n");
484        retval = 0;
485    } else
486    { /* this received pkt is ok */
487        /* Omit the four octet CRC from the length. */
488        short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4;
489
490        DBG ( " netdev_rx() normal Rx pkt length %d"
491 	      " status %x.\n", pkt_len, (unsigned int) rx_status );
492
493        nic->packetlen = pkt_len;
494        memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len);
495
496        retval = 1;
497    }
498
499    while( ( mtdx.cur_rx->status & RXOWN ) == 0 )
500    {
501        mtdx.cur_rx->status = RXOWN;
502        mtdx.cur_rx = mtdx.cur_rx->next_desc_logical;
503    }
504
505    /* Restart Rx engine if stopped. */
506    outl(0, mtdx.ioaddr + RXPDR);
507
508    return retval;
509}
510
511/**************************************************************************
512TRANSMIT - Transmit a frame
513***************************************************************************/
514static void mtd_transmit(
515    struct nic *nic,
516    const char *dest,            /* Destination */
517    unsigned int type,            /* Type */
518    unsigned int size,            /* size */
519    const char *data)            /* Packet */
520{
521    u32 to;
522    u32 tx_status;
523    unsigned int nstype = htons ( type );
524
525    memcpy( txb, dest, ETH_ALEN );
526    memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN );
527    memcpy( txb + 2 * ETH_ALEN, &nstype, 2 );
528    memcpy( txb + ETH_HLEN, data, size );
529
530    size += ETH_HLEN;
531    size &= 0x0FFF;
532    while( size < ETH_ZLEN )
533    {
534        txb[size++] = '\0';
535    }
536
537    mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable;
538    mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */
539    mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */
540    mtdx.tx_ring[0].status = TXOWN;
541
542    /* Point to transmit descriptor */
543    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
544    /* Enable Tx */
545    outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR);
546    /* Wake the potentially-idle transmit channel. */
547    outl(0, mtdx.ioaddr + TXPDR);
548
549    to = currticks() + TX_TIME_OUT;
550    while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to));
551
552    /* Disable Tx */
553    outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR);
554
555    tx_status = mtdx.tx_ring[0].status;
556    if (currticks() >= to){
557        DBG ( "TX Time Out" );
558    } else if( tx_status & (CSL | LC | EC | UDF | HF)){
559        printf( "Transmit error: %8.8x %s %s %s %s %s\n",
560                (unsigned int) tx_status,
561                tx_status & EC ? "abort" : "",
562                tx_status & CSL ? "carrier" : "",
563                tx_status & LC ? "late" : "",
564                tx_status & UDF ? "fifo" : "",
565                tx_status & HF ? "heartbeat" : "" );
566    }
567
568    /*hex_dump( txb, size );*/
569    /*pause();*/
570
571    DBG ( "TRANSMIT\n" );
572}
573
574/**************************************************************************
575DISABLE - Turn off ethernet interface
576***************************************************************************/
577static void mtd_disable ( struct nic *nic ) {
578
579    /* Disable Tx Rx*/
580    outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR );
581
582    /* Reset the chip to erase previous misconfiguration. */
583    mtd_reset(nic);
584
585    DBG ( "DISABLE\n" );
586}
587
588static struct nic_operations mtd_operations = {
589	.connect	= dummy_connect,
590	.poll		= mtd_poll,
591	.transmit	= mtd_transmit,
592	.irq		= dummy_irq,
593
594};
595
596static struct pci_device_id mtd80x_nics[] = {
597        PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800", 0),
598        PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0),
599        PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0),
600};
601
602PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS );
603
604/**************************************************************************
605PROBE - Look for an adapter, this routine's visible to the outside
606***************************************************************************/
607
608static int mtd_probe ( struct nic *nic, struct pci_device *pci ) {
609
610    int i;
611
612    if (pci->ioaddr == 0)
613	    return 0;
614
615    adjust_pci_device(pci);
616
617    nic->ioaddr = pci->ioaddr;
618    nic->irqno = 0;
619
620    mtdx.nic_name = pci->driver_name;
621    mtdx.dev_id = pci->device;
622    mtdx.ioaddr = nic->ioaddr;
623
624    /* read ethernet id */
625    for (i = 0; i < 6; ++i)
626    {
627        nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i);
628    }
629
630    if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0)
631    {
632        return 0;
633    }
634
635    DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) );
636
637    /* Reset the chip to erase previous misconfiguration. */
638    outl(0x00000001, mtdx.ioaddr + BCR);
639
640    /* find the connected MII xcvrs */
641
642    if( mtdx.dev_id != 0x803 )
643    {
644        int phy, phy_idx = 0;
645
646        for (phy = 1; phy < 32 && phy_idx < 1; phy++) {
647            int mii_status = mdio_read(nic, phy, 1);
648
649            if (mii_status != 0xffff && mii_status != 0x0000) {
650                mtdx.phys[phy_idx] = phy;
651
652                DBG ( "%s: MII PHY found at address %d, status "
653		      "0x%4.4x.\n", mtdx.nic_name, phy, mii_status );
654                /* get phy type */
655                {
656                    unsigned int data;
657
658                    data = mdio_read(nic, mtdx.phys[phy_idx], 2);
659                    if (data == SeeqPHYID0)
660                        mtdx.PHYType = SeeqPHY;
661                    else if (data == AhdocPHYID0)
662                        mtdx.PHYType = AhdocPHY;
663                    else if (data == MarvellPHYID0)
664                        mtdx.PHYType = MarvellPHY;
665                    else if (data == MysonPHYID0)
666                        mtdx.PHYType = Myson981;
667                    else if (data == LevelOnePHYID0)
668                        mtdx.PHYType = LevelOnePHY;
669                    else
670                        mtdx.PHYType = OtherPHY;
671                }
672                phy_idx++;
673            }
674        }
675
676        mtdx.mii_cnt = phy_idx;
677        if (phy_idx == 0) {
678            printf("%s: MII PHY not found -- this device may "
679                   "not operate correctly.\n", mtdx.nic_name);
680        }
681    } else {
682        mtdx.phys[0] = 32;
683        /* get phy type */
684        if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) {
685            mtdx.PHYType = MysonPHY;
686            DBG ( "MysonPHY\n" );
687        } else {
688            mtdx.PHYType = OtherPHY;
689            DBG ( "OtherPHY\n" );
690        }
691    }
692
693    getlinkstatus(nic);
694    if( !mtdx.linkok )
695    {
696        printf("No link!!!\n");
697        return 0;
698    }
699
700    mtd_reset( nic );
701
702    /* point to NIC specific routines */
703    nic->nic_op	= &mtd_operations;
704    return 1;
705}
706
707
708/**************************************************************************/
709static void set_rx_mode(struct nic *nic __unused)
710{
711    u32 mc_filter[2];                       /* Multicast hash filter */
712    u32 rx_mode;
713
714    /* Too many to match, or accept all multicasts. */
715    mc_filter[1] = mc_filter[0] = ~0;
716    rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
717
718    outl(mc_filter[0], mtdx.ioaddr + MAR0);
719    outl(mc_filter[1], mtdx.ioaddr + MAR1);
720
721    mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode;
722    outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR);
723}
724/**************************************************************************/
725static unsigned int m80x_read_tick(void)
726/* function: Reads the Timer tick count register which decrements by 2 from  */
727/*           65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */
728/*           count represents 838 nsec's.                                    */
729/* input   : none.                                                           */
730/* output  : none.                                                           */
731{
732    unsigned char tmp;
733    int value;
734
735    outb((char) 0x06, 0x43); // Command 8254 to latch T0's count
736
737    // now read the count.
738    tmp = (unsigned char) inb(0x40);
739    value = ((int) tmp) << 8;
740    tmp = (unsigned char) inb(0x40);
741    value |= (((int) tmp) & 0xff);
742    return (value);
743}
744
745static void m80x_delay(unsigned int interval)
746/* function: to wait for a specified time.                                   */
747/* input   : interval ... the specified time.                                */
748/* output  : none.                                                           */
749{
750    unsigned int interval1, interval2, i = 0;
751
752    interval1 = m80x_read_tick(); // get initial value
753    do
754    {
755        interval2 = m80x_read_tick();
756        if (interval1 < interval2)
757            interval1 += 65536;
758        ++i;
759    } while (((interval1 - interval2) < (u16) interval) && (i < 65535));
760}
761
762
763static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
764{
765    u32 miir;
766    int i;
767    unsigned int mask, data;
768
769    /* enable MII output */
770    miir = (u32) inl(miiport);
771    miir &= 0xfffffff0;
772
773    miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;
774
775    /* send 32 1's preamble */
776    for (i = 0; i < 32; i++) {
777        /* low MDC; MDO is already high (miir) */
778        miir &= ~MASK_MIIR_MII_MDC;
779        outl(miir, miiport);
780
781        /* high MDC */
782        miir |= MASK_MIIR_MII_MDC;
783        outl(miir, miiport);
784    }
785
786    /* calculate ST+OP+PHYAD+REGAD+TA */
787    data = opcode | (phyad << 7) | (regad << 2);
788
789    /* sent out */
790    mask = 0x8000;
791    while (mask) {
792        /* low MDC, prepare MDO */
793        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
794        if (mask & data)
795            miir |= MASK_MIIR_MII_MDO;
796
797        outl(miir, miiport);
798        /* high MDC */
799        miir |= MASK_MIIR_MII_MDC;
800        outl(miir, miiport);
801        m80x_delay(30);
802
803        /* next */
804        mask >>= 1;
805        if (mask == 0x2 && opcode == OP_READ)
806            miir &= ~MASK_MIIR_MII_WRITE;
807    }
808    return miir;
809}
810
811static int mdio_read(struct nic *nic __unused, int phyad, int regad)
812{
813    long miiport = mtdx.ioaddr + MANAGEMENT;
814    u32 miir;
815    unsigned int mask, data;
816
817    miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad);
818
819    /* read data */
820    mask = 0x8000;
821    data = 0;
822    while (mask)
823    {
824        /* low MDC */
825        miir &= ~MASK_MIIR_MII_MDC;
826        outl(miir, miiport);
827
828        /* read MDI */
829        miir = inl(miiport);
830        if (miir & MASK_MIIR_MII_MDI)
831            data |= mask;
832
833        /* high MDC, and wait */
834        miir |= MASK_MIIR_MII_MDC;
835        outl(miir, miiport);
836        m80x_delay((int) 30);
837
838        /* next */
839        mask >>= 1;
840    }
841
842    /* low MDC */
843    miir &= ~MASK_MIIR_MII_MDC;
844    outl(miir, miiport);
845
846    return data & 0xffff;
847}
848
849#if 0 /* not used */
850static void mdio_write(struct nic *nic __unused, int phyad, int regad,
851		       int data)
852{
853    long miiport = mtdx.ioaddr + MANAGEMENT;
854    u32 miir;
855    unsigned int mask;
856
857    miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad);
858
859    /* write data */
860    mask = 0x8000;
861    while (mask)
862    {
863        /* low MDC, prepare MDO */
864        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
865        if (mask & data)
866            miir |= MASK_MIIR_MII_MDO;
867        outl(miir, miiport);
868
869        /* high MDC */
870        miir |= MASK_MIIR_MII_MDC;
871        outl(miir, miiport);
872
873        /* next */
874        mask >>= 1;
875    }
876
877    /* low MDC */
878    miir &= ~MASK_MIIR_MII_MDC;
879    outl(miir, miiport);
880
881    return;
882}
883#endif
884
885static void getlinkstatus(struct nic *nic)
886/* function: Routine will read MII Status Register to get link status.       */
887/* input   : dev... pointer to the adapter block.                            */
888/* output  : none.                                                           */
889{
890    unsigned int i, DelayTime = 0x1000;
891
892    mtdx.linkok = 0;
893
894    if (mtdx.PHYType == MysonPHY)
895    {
896        for (i = 0; i < DelayTime; ++i) {
897            if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) {
898                mtdx.linkok = 1;
899                return;
900            }
901            // delay
902            m80x_delay(100);
903        }
904    } else
905    {
906        for (i = 0; i < DelayTime; ++i) {
907            if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) {
908                mtdx.linkok = 1;
909                return;
910            }
911            // delay
912            m80x_delay(100);
913        }
914    }
915}
916
917
918static void getlinktype(struct nic *dev)
919{
920    if (mtdx.PHYType == MysonPHY)
921    { /* 3-in-1 case */
922        if (inl(mtdx.ioaddr + TCRRCR) & FD)
923            mtdx.duplexmode = 2; /* full duplex */
924        else
925            mtdx.duplexmode = 1; /* half duplex */
926        if (inl(mtdx.ioaddr + TCRRCR) & PS10)
927            mtdx.line_speed = 1; /* 10M */
928        else
929            mtdx.line_speed = 2; /* 100M */
930    } else
931    {
932        if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */
933            unsigned int data;
934
935            data = mdio_read(dev, mtdx.phys[0], MIIRegister18);
936            if (data & SPD_DET_100)
937                mtdx.line_speed = 2; /* 100M */
938            else
939                mtdx.line_speed = 1; /* 10M */
940            if (data & DPLX_DET_FULL)
941                mtdx.duplexmode = 2; /* full duplex mode */
942            else
943                mtdx.duplexmode = 1; /* half duplex mode */
944        } else if (mtdx.PHYType == AhdocPHY) {
945            unsigned int data;
946
947            data = mdio_read(dev, mtdx.phys[0], DiagnosticReg);
948            if (data & Speed_100)
949                mtdx.line_speed = 2; /* 100M */
950            else
951                mtdx.line_speed = 1; /* 10M */
952            if (data & DPLX_FULL)
953                mtdx.duplexmode = 2; /* full duplex mode */
954            else
955                mtdx.duplexmode = 1; /* half duplex mode */
956        }
957        /* 89/6/13 add, (begin) */
958        else if (mtdx.PHYType == MarvellPHY) {
959            unsigned int data;
960
961            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
962            if (data & Full_Duplex)
963                mtdx.duplexmode = 2; /* full duplex mode */
964            else
965                mtdx.duplexmode = 1; /* half duplex mode */
966            data &= SpeedMask;
967            if (data == Speed_1000M)
968                mtdx.line_speed = 3; /* 1000M */
969            else if (data == Speed_100M)
970                mtdx.line_speed = 2; /* 100M */
971            else
972                mtdx.line_speed = 1; /* 10M */
973        }
974        /* 89/6/13 add, (end) */
975        /* 89/7/27 add, (begin) */
976        else if (mtdx.PHYType == Myson981) {
977            unsigned int data;
978
979            data = mdio_read(dev, mtdx.phys[0], StatusRegister);
980
981            if (data & SPEED100)
982                mtdx.line_speed = 2;
983            else
984                mtdx.line_speed = 1;
985
986            if (data & FULLMODE)
987                mtdx.duplexmode = 2;
988            else
989                mtdx.duplexmode = 1;
990        }
991        /* 89/7/27 add, (end) */
992        /* 89/12/29 add */
993        else if (mtdx.PHYType == LevelOnePHY) {
994            unsigned int data;
995
996            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
997            if (data & LXT1000_Full)
998                mtdx.duplexmode = 2; /* full duplex mode */
999            else
1000                mtdx.duplexmode = 1; /* half duplex mode */
1001            data &= SpeedMask;
1002            if (data == LXT1000_1000M)
1003                mtdx.line_speed = 3; /* 1000M */
1004            else if (data == LXT1000_100M)
1005                mtdx.line_speed = 2; /* 100M */
1006            else
1007                mtdx.line_speed = 1; /* 10M */
1008        }
1009        // chage crvalue
1010        // mtdx.crvalue&=(~PS10)&(~FD);
1011        mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000);
1012        if (mtdx.line_speed == 1)
1013            mtdx.crvalue |= PS10;
1014        else if (mtdx.line_speed == 3)
1015            mtdx.crvalue |= PS1000;
1016        if (mtdx.duplexmode == 2)
1017            mtdx.crvalue |= FD;
1018    }
1019}
1020
1021DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver,
1022	 mtd_probe, mtd_disable );
1023