uboot/drivers/net/3c589.c
<<
>>
Prefs
   1/*------------------------------------------------------------------------
   2 . 3c589.c
   3 . This is a driver for 3Com's 3C589 (Etherlink III) PCMCIA Ethernet device.
   4 .
   5 . (C) Copyright 2002
   6 . Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   7 . Rolf Offermanns <rof@sysgo.de>
   8 .
   9 . This program is free software; you can redistribute it and/or modify
  10 . it under the terms of the GNU General Public License as published by
  11 . the Free Software Foundation; either version 2 of the License, or
  12 . (at your option) any later version.
  13 .
  14 . This program is distributed in the hope that it will be useful,
  15 . but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 . GNU General Public License for more details.
  18 .
  19 . You should have received a copy of the GNU General Public License
  20 . along with this program; if not, write to the Free Software
  21 . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22 .
  23 ----------------------------------------------------------------------------*/
  24
  25#include <common.h>
  26#include <command.h>
  27#include <net.h>
  28
  29#include "3c589.h"
  30
  31
  32/* Use power-down feature of the chip */
  33#define POWER_DOWN      0
  34
  35#define NO_AUTOPROBE
  36
  37static const char version[] =
  38        "Your ad here! :P\n";
  39
  40
  41#undef EL_DEBUG
  42
  43typedef unsigned char byte;
  44typedef unsigned short word;
  45typedef unsigned long int dword;
  46/*------------------------------------------------------------------------
  47 .
  48 . Configuration options, for the experienced user to change.
  49 .
  50 -------------------------------------------------------------------------*/
  51
  52/*
  53 . Wait time for memory to be free.  This probably shouldn't be
  54 . tuned that much, as waiting for this means nothing else happens
  55 . in the system
  56*/
  57#define MEMORY_WAIT_TIME 16
  58
  59
  60#if (EL_DEBUG > 2 )
  61#define PRINTK3(args...) printf(args)
  62#else
  63#define PRINTK3(args...)
  64#endif
  65
  66#if EL_DEBUG > 1
  67#define PRINTK2(args...) printf(args)
  68#else
  69#define PRINTK2(args...)
  70#endif
  71
  72#ifdef EL_DEBUG
  73#define PRINTK(args...) printf(args)
  74#else
  75#define PRINTK(args...)
  76#endif
  77
  78#define outb(args...)   mmio_outb(args)
  79#define mmio_outb(value, addr)  (*((volatile byte *)(addr)) = value)
  80
  81#define inb(args...)    mmio_inb(args)
  82#define mmio_inb(addr) (*((volatile byte *)(addr)))
  83
  84#define outw(args...)   mmio_outw(args)
  85#define mmio_outw(value, addr)  (*((volatile word *)(addr)) = value)
  86
  87#define inw(args...)    mmio_inw(args)
  88#define mmio_inw(addr) (*((volatile word *)(addr)))
  89
  90#define outsw(args...)  mmio_outsw(args)
  91#define mmio_outsw(r,b,l)       ({      int __i; \
  92                                        word *__b2; \
  93                                        __b2 = (word *) b; \
  94                                        for (__i = 0; __i < l; __i++) { \
  95                                            mmio_outw( *(__b2 + __i), r); \
  96                                        } \
  97                                })
  98
  99#define insw(args...)   mmio_insw(args)
 100#define mmio_insw(r,b,l)        ({      int __i ;  \
 101                                        word *__b2;  \
 102                                        __b2 = (word *) b;  \
 103                                        for (__i = 0; __i < l; __i++) {  \
 104                                          *(__b2 + __i) = mmio_inw(r);  \
 105                                          mmio_inw(0);  \
 106                                        };  \
 107                                })
 108
 109/*------------------------------------------------------------------------
 110 .
 111 . The internal workings of the driver.  If you are changing anything
 112 . here with the 3Com stuff, you should have the datasheet and know
 113 . what you are doing.
 114 .
 115 -------------------------------------------------------------------------*/
 116#define EL_BASE_ADDR    0x20000000
 117
 118
 119/* Offsets from base I/O address. */
 120#define EL3_DATA        0x00
 121#define EL3_TIMER       0x0a
 122#define EL3_CMD         0x0e
 123#define EL3_STATUS      0x0e
 124
 125#define EEPROM_READ     0x0080
 126
 127#define EL3WINDOW(win_num) mmio_outw(SelectWindow + (win_num), EL_BASE_ADDR + EL3_CMD)
 128
 129/* The top five bits written to EL3_CMD are a command, the lower
 130   11 bits are the parameter, if applicable. */
 131enum c509cmd {
 132    TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
 133    RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
 134    TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
 135    FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
 136    SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
 137    SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
 138    StatsDisable = 22<<11, StopCoax = 23<<11,
 139};
 140
 141enum c509status {
 142    IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
 143    TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
 144    IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000
 145};
 146
 147/* The SetRxFilter command accepts the following classes: */
 148enum RxFilter {
 149    RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
 150};
 151
 152/* Register window 1 offsets, the window used in normal operation. */
 153#define TX_FIFO         0x00
 154#define RX_FIFO         0x00
 155#define RX_STATUS       0x08
 156#define TX_STATUS       0x0B
 157#define TX_FREE         0x0C    /* Remaining free bytes in Tx buffer. */
 158
 159
 160/*
 161  Read a word from the EEPROM using the regular EEPROM access register.
 162  Assume that we are in register window zero.
 163*/
 164static word read_eeprom(dword ioaddr, int index)
 165{
 166    int i;
 167    outw(EEPROM_READ + index, ioaddr + 0xa);
 168    /* Reading the eeprom takes 162 us */
 169    for (i = 1620; i >= 0; i--)
 170        if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
 171            break;
 172    return inw(ioaddr + 0xc);
 173}
 174
 175static void el_get_mac_addr( unsigned char *mac_addr )
 176{
 177        int i;
 178        union
 179        {
 180                word w;
 181                unsigned char b[2];
 182        } wrd;
 183        unsigned char old_window = inw( EL_BASE_ADDR + EL3_STATUS ) >> 13;
 184        GO_WINDOW(0);
 185        VX_BUSY_WAIT;
 186        for (i = 0; i < 3; i++)
 187        {
 188                wrd.w = read_eeprom(EL_BASE_ADDR, 0xa+i);
 189#ifdef __BIG_ENDIAN
 190                mac_addr[2*i]   = wrd.b[0];
 191                mac_addr[2*i+1] = wrd.b[1];
 192#else
 193                mac_addr[2*i]   = wrd.b[1];
 194                mac_addr[2*i+1] = wrd.b[0];
 195#endif
 196        }
 197        GO_WINDOW(old_window);
 198        VX_BUSY_WAIT;
 199}
 200
 201
 202#if EL_DEBUG > 1
 203static void print_packet( byte * buf, int length )
 204{
 205        int i;
 206        int remainder;
 207        int lines;
 208
 209        PRINTK2("Packet of length %d \n", length );
 210
 211        lines = length / 16;
 212        remainder = length % 16;
 213
 214        for ( i = 0; i < lines ; i ++ ) {
 215                int cur;
 216
 217                for ( cur = 0; cur < 8; cur ++ ) {
 218                        byte a, b;
 219
 220                        a = *(buf ++ );
 221                        b = *(buf ++ );
 222                        PRINTK2("%02x%02x ", a, b );
 223                }
 224                PRINTK2("\n");
 225        }
 226        for ( i = 0; i < remainder/2 ; i++ ) {
 227                byte a, b;
 228
 229                a = *(buf ++ );
 230                b = *(buf ++ );
 231                PRINTK2("%02x%02x ", a, b );
 232        }
 233        PRINTK2("\n");
 234}
 235#endif /* EL_DEBUG > 1 */
 236
 237
 238/**************************************************************************
 239ETH_RESET - Reset adapter
 240***************************************************************************/
 241static void el_reset(bd_t *bd)
 242{
 243        /***********************************************************
 244                        Reset 3Com 595 card
 245        *************************************************************/
 246        /* QUICK HACK
 247         * - adjust timing for 3c589
 248         * - enable io for PCMCIA */
 249        outw(0x0004, 0xa0000018);
 250        udelay(100);
 251        outw(0x0041, 0x28010000);
 252        udelay(100);
 253
 254        /* issue global reset */
 255        outw(GLOBAL_RESET, BASE + VX_COMMAND);
 256
 257        /* must wait for at least 1ms */
 258        udelay(100000000);
 259
 260        /* set mac addr */
 261        {
 262                uchar mac_addr[6];
 263                int i;
 264
 265                if (!eth_getenv_enetaddr("ethaddr", mac_addr)) {
 266                        el_get_mac_addr(mac_addr);
 267                        eth_setenv_enetaddr("ethaddr", mac_addr);
 268                }
 269
 270                GO_WINDOW(2);
 271                VX_BUSY_WAIT;
 272
 273                printf("3C589 MAC Addr.: ");
 274                for (i = 0; i < 6; i++)
 275                {
 276                        printf("%02x", mac_addr[i]);
 277                        outb(mac_addr[i], BASE + VX_W2_ADDR_0 + i);
 278                        VX_BUSY_WAIT;
 279                }
 280                printf("\n\n");
 281        }
 282
 283        /* set RX filter */
 284        outw(SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST, BASE + VX_COMMAND);
 285        VX_BUSY_WAIT;
 286
 287
 288        /* set irq mask and read_zero */
 289        outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
 290                S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
 291        VX_BUSY_WAIT;
 292
 293        outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
 294                S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
 295        VX_BUSY_WAIT;
 296
 297        /* enable TP Linkbeat */
 298        GO_WINDOW(4);
 299        VX_BUSY_WAIT;
 300
 301        outw( ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
 302        VX_BUSY_WAIT;
 303
 304
 305/*
 306 * Attempt to get rid of any stray interrupts that occured during
 307 * configuration.  On the i386 this isn't possible because one may
 308 * already be queued.  However, a single stray interrupt is
 309 * unimportant.
 310 */
 311
 312        outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
 313        VX_BUSY_WAIT;
 314
 315        /* enable TX and RX */
 316        outw( RX_ENABLE, BASE + VX_COMMAND );
 317        VX_BUSY_WAIT;
 318
 319        outw( TX_ENABLE, BASE + VX_COMMAND );
 320        VX_BUSY_WAIT;
 321
 322
 323        /* print the diag. regs. */
 324        PRINTK2("Diag. Regs\n");
 325        PRINTK2("--> MEDIA_TYPE:   %04x\n", inw(BASE + VX_W4_MEDIA_TYPE));
 326        PRINTK2("--> NET_DIAG:     %04x\n", inw(BASE + VX_W4_NET_DIAG));
 327        PRINTK2("--> FIFO_DIAG:    %04x\n", inw(BASE + VX_W4_FIFO_DIAG));
 328        PRINTK2("--> CTRLR_STATUS: %04x\n", inw(BASE + VX_W4_CTRLR_STATUS));
 329        PRINTK2("\n\n");
 330
 331        /* enter working mode */
 332        GO_WINDOW(1);
 333        VX_BUSY_WAIT;
 334
 335        /* wait for another 1ms */
 336        udelay(100000000);
 337}
 338
 339
 340/*-----------------------------------------------------------------
 341 .
 342 .  The driver can be entered at any of the following entry points.
 343 .
 344 .------------------------------------------------------------------  */
 345
 346extern int eth_init(bd_t *bd);
 347extern void eth_halt(void);
 348extern int eth_rx(void);
 349extern int eth_send(volatile void *packet, int length);
 350
 351
 352/*
 353 ------------------------------------------------------------
 354 .
 355 . Internal routines
 356 .
 357 ------------------------------------------------------------
 358*/
 359
 360int eth_init(bd_t *bd)
 361{
 362        el_reset(bd);
 363        return 0;
 364}
 365
 366void eth_halt() {
 367        return;
 368}
 369
 370#define EDEBUG 1
 371
 372
 373/**************************************************************************
 374ETH_POLL - Wait for a frame
 375***************************************************************************/
 376
 377int eth_rx()
 378{
 379        word status, rx_status, packet_size;
 380
 381        VX_BUSY_WAIT;
 382
 383        status = inw( BASE + VX_STATUS );
 384
 385        if ( (status & S_RX_COMPLETE) == 0 ) return 0; /* nothing to do */
 386
 387        /* Packet waiting -> check RX_STATUS */
 388        rx_status = inw( BASE + VX_W1_RX_STATUS );
 389
 390        if ( rx_status & ERR_RX )
 391        {
 392                /* error in packet -> discard */
 393                PRINTK("[ERROR] Invalid packet -> discarding\n");
 394                PRINTK("-- error code 0x%02x\n", rx_status & ERR_MASK);
 395                PRINTK("-- rx bytes 0x%04d\n", rx_status & ((1<<11) - 1));
 396                PRINTK("[ERROR] Invalid packet -> discarding\n");
 397                outw( RX_DISCARD_TOP_PACK, BASE + VX_COMMAND );
 398                return 0;
 399        }
 400
 401        /* correct pack. waiting in fifo */
 402        packet_size = rx_status & RX_BYTES_MASK;
 403
 404        PRINTK("Correct packet waiting in fifo, size: %d\n", packet_size);
 405
 406        {
 407                volatile word *packet_start = (word *)(BASE + VX_W1_RX_PIO_RD_1);
 408                word *RcvBuffer = (word *)(NetRxPackets[0]);
 409                int wcount = 0;
 410
 411                for (wcount = 0; wcount < (packet_size >> 1); wcount++)
 412                {
 413                        *RcvBuffer++ = *(packet_start);
 414                }
 415
 416                /* handle odd packets */
 417                if ( packet_size & 1 )
 418                {
 419                        *RcvBuffer++ = *(packet_start);
 420                }
 421        }
 422
 423        /* fifo should now be empty (besides the padding bytes) */
 424        if ( ((*((word *)(BASE + VX_W1_RX_STATUS))) & RX_BYTES_MASK) > 3 )
 425        {
 426                PRINTK("[ERROR] Fifo not empty after packet read (remaining pkts: %d)\n",
 427                        (((*(word *)(BASE + VX_W1_RX_STATUS))) & RX_BYTES_MASK));
 428        }
 429
 430        /* discard packet */
 431        *((word *)(BASE + VX_COMMAND)) = RX_DISCARD_TOP_PACK;
 432
 433        /* Pass Packets to upper Layer */
 434        NetReceive(NetRxPackets[0], packet_size);
 435        return packet_size;
 436}
 437
 438
 439/**************************************************************************
 440ETH_TRANSMIT - Transmit a frame
 441***************************************************************************/
 442static char padmap[] = {
 443        0, 3, 2, 1};
 444
 445
 446int eth_send(volatile void *packet, int length) {
 447        int pad;
 448        int status;
 449        volatile word *buf = (word *)packet;
 450        int dummy = 0;
 451
 452        /* padding stuff */
 453        pad = padmap[length & 3];
 454
 455        PRINTK("eth_send(), length: %d\n", length);
 456        /* drop acknowledgements */
 457        while(( status=inb(EL_BASE_ADDR + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
 458                if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
 459                        outw(TX_RESET, EL_BASE_ADDR + VX_COMMAND);
 460                        outw(TX_ENABLE, EL_BASE_ADDR + VX_COMMAND);
 461                        PRINTK("Bad status, resetting and reenabling transmitter\n");
 462                }
 463
 464                outb(0x0, EL_BASE_ADDR + VX_W1_TX_STATUS);
 465        }
 466
 467
 468        while (inw(EL_BASE_ADDR + VX_W1_FREE_TX) < length + pad + 4) {
 469                /* no room in FIFO */
 470                if (dummy == 0)
 471                {
 472                        PRINTK("No room in FIFO, waiting...\n");
 473                        dummy++;
 474                }
 475
 476        }
 477
 478        PRINTK("    ---> FIFO ready\n");
 479
 480
 481        outw(length, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
 482
 483        /* Second dword meaningless */
 484        outw(0x0, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
 485
 486#if EL_DEBUG > 1
 487        print_packet((byte *)buf, length);
 488#endif
 489
 490        /* write packet */
 491        {
 492                unsigned int i, totw;
 493
 494                totw = ((length + 1) >> 1);
 495                PRINTK("Buffer: (totw = %d)\n", totw);
 496                for (i = 0; i < totw; i++) {
 497                        outw( *(buf+i), EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
 498                        udelay(10);
 499                }
 500                if(totw & 1)
 501                {       /* pad to double word length */
 502                        outw( 0, EL_BASE_ADDR + VX_W1_TX_PIO_WR_1);
 503                        udelay(10);
 504                }
 505                PRINTK("\n\n");
 506        }
 507
 508        /* wait for Tx complete */
 509        PRINTK("Waiting for Tx to complete...\n");
 510        while(((status = inw(EL_BASE_ADDR + VX_STATUS)) & S_COMMAND_IN_PROGRESS) != 0)
 511        {
 512                udelay(10);
 513        }
 514        PRINTK("   ---> Tx completed, status = 0x%04x\n", status);
 515
 516        return length;
 517}
 518