uboot/drivers/net/xilinx_emac.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
   4 * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
   5 * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
   6 * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
   7 * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
   8 * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
   9 * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
  10 * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
  11 * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
  12 * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
  13 * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
  14 * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  15 * FOR A PARTICULAR PURPOSE.
  16 *
  17 * (C) Copyright 2007-2008 Michal Simek
  18 * Michal SIMEK <monstr@monstr.eu>
  19 *
  20 * (c) Copyright 2003 Xilinx Inc.
  21 * All rights reserved.
  22 *
  23 ******************************************************************************/
  24
  25#include <config.h>
  26#include <common.h>
  27#include <net.h>
  28#include <asm/io.h>
  29
  30#include <asm/asm.h>
  31
  32#undef DEBUG
  33
  34typedef struct {
  35        u32 regbaseaddress;     /* Base address of registers */
  36        u32 databaseaddress;    /* Base address of data for FIFOs */
  37} xpacketfifov100b;
  38
  39typedef struct {
  40        u32 baseaddress;        /* Base address (of IPIF) */
  41        u32 isstarted;          /* Device is currently started 0-no, 1-yes */
  42        xpacketfifov100b recvfifo;      /* FIFO used to receive frames */
  43        xpacketfifov100b sendfifo;      /* FIFO used to send frames */
  44} xemac;
  45
  46#define XIIF_V123B_IISR_OFFSET  32UL /* IP interrupt status register */
  47#define XIIF_V123B_RESET_MASK           0xAUL
  48#define XIIF_V123B_RESETR_OFFSET        64UL /* reset register */
  49
  50/* This constant is used with the Reset Register */
  51#define XPF_RESET_FIFO_MASK             0x0000000A
  52#define XPF_COUNT_STATUS_REG_OFFSET     4UL
  53
  54/* These constants are used with the Occupancy/Vacancy Count Register. This
  55 * register also contains FIFO status */
  56#define XPF_COUNT_MASK                  0x0000FFFF
  57#define XPF_DEADLOCK_MASK               0x20000000
  58
  59/* Offset of the MAC registers from the IPIF base address */
  60#define XEM_REG_OFFSET          0x1100UL
  61
  62/*
  63 * Register offsets for the Ethernet MAC. Each register is 32 bits.
  64 */
  65#define XEM_ECR_OFFSET  (XEM_REG_OFFSET + 0x4)  /* MAC Control */
  66#define XEM_SAH_OFFSET  (XEM_REG_OFFSET + 0xC)  /* Station addr, high */
  67#define XEM_SAL_OFFSET  (XEM_REG_OFFSET + 0x10) /* Station addr, low */
  68#define XEM_RPLR_OFFSET (XEM_REG_OFFSET + 0x1C) /* Rx packet length */
  69#define XEM_TPLR_OFFSET (XEM_REG_OFFSET + 0x20) /* Tx packet length */
  70#define XEM_TSR_OFFSET  (XEM_REG_OFFSET + 0x24) /* Tx status */
  71
  72#define XEM_PFIFO_OFFSET        0x2000UL
  73/* Tx registers */
  74#define XEM_PFIFO_TXREG_OFFSET  (XEM_PFIFO_OFFSET + 0x0)
  75/* Rx registers */
  76#define XEM_PFIFO_RXREG_OFFSET  (XEM_PFIFO_OFFSET + 0x10)
  77/* Tx keyhole */
  78#define XEM_PFIFO_TXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x100)
  79/* Rx keyhole */
  80#define XEM_PFIFO_RXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x200)
  81
  82/*
  83 * EMAC Interrupt Registers (Status and Enable) masks. These registers are
  84 * part of the IPIF IP Interrupt registers
  85 */
  86/* A mask for all transmit interrupts, used in polled mode */
  87#define XEM_EIR_XMIT_ALL_MASK   (XEM_EIR_XMIT_DONE_MASK |\
  88                                XEM_EIR_XMIT_ERROR_MASK | \
  89                                XEM_EIR_XMIT_SFIFO_EMPTY_MASK |\
  90                                XEM_EIR_XMIT_LFIFO_FULL_MASK)
  91
  92/* Xmit complete */
  93#define XEM_EIR_XMIT_DONE_MASK          0x00000001UL
  94/* Recv complete */
  95#define XEM_EIR_RECV_DONE_MASK          0x00000002UL
  96/* Xmit error */
  97#define XEM_EIR_XMIT_ERROR_MASK         0x00000004UL
  98/* Recv error */
  99#define XEM_EIR_RECV_ERROR_MASK         0x00000008UL
 100/* Xmit status fifo empty */
 101#define XEM_EIR_XMIT_SFIFO_EMPTY_MASK   0x00000010UL
 102/* Recv length fifo empty */
 103#define XEM_EIR_RECV_LFIFO_EMPTY_MASK   0x00000020UL
 104/* Xmit length fifo full */
 105#define XEM_EIR_XMIT_LFIFO_FULL_MASK    0x00000040UL
 106/* Recv length fifo overrun */
 107#define XEM_EIR_RECV_LFIFO_OVER_MASK    0x00000080UL
 108/* Recv length fifo underrun */
 109#define XEM_EIR_RECV_LFIFO_UNDER_MASK   0x00000100UL
 110/* Xmit status fifo overrun */
 111#define XEM_EIR_XMIT_SFIFO_OVER_MASK    0x00000200UL
 112/* Transmit status fifo underrun */
 113#define XEM_EIR_XMIT_SFIFO_UNDER_MASK   0x00000400UL
 114/* Transmit length fifo overrun */
 115#define XEM_EIR_XMIT_LFIFO_OVER_MASK    0x00000800UL
 116/* Transmit length fifo underrun */
 117#define XEM_EIR_XMIT_LFIFO_UNDER_MASK   0x00001000UL
 118/* Transmit pause pkt received */
 119#define XEM_EIR_XMIT_PAUSE_MASK         0x00002000UL
 120
 121/*
 122 * EMAC Control Register (ECR)
 123 */
 124/* Full duplex mode */
 125#define XEM_ECR_FULL_DUPLEX_MASK        0x80000000UL
 126/* Reset transmitter */
 127#define XEM_ECR_XMIT_RESET_MASK         0x40000000UL
 128/* Enable transmitter */
 129#define XEM_ECR_XMIT_ENABLE_MASK        0x20000000UL
 130/* Reset receiver */
 131#define XEM_ECR_RECV_RESET_MASK         0x10000000UL
 132/* Enable receiver */
 133#define XEM_ECR_RECV_ENABLE_MASK        0x08000000UL
 134/* Enable PHY */
 135#define XEM_ECR_PHY_ENABLE_MASK         0x04000000UL
 136/* Enable xmit pad insert */
 137#define XEM_ECR_XMIT_PAD_ENABLE_MASK    0x02000000UL
 138/* Enable xmit FCS insert */
 139#define XEM_ECR_XMIT_FCS_ENABLE_MASK    0x01000000UL
 140/* Enable unicast addr */
 141#define XEM_ECR_UNICAST_ENABLE_MASK     0x00020000UL
 142/* Enable broadcast addr */
 143#define XEM_ECR_BROAD_ENABLE_MASK       0x00008000UL
 144
 145/*
 146 * Transmit Status Register (TSR)
 147 */
 148/* Transmit excess deferral */
 149#define XEM_TSR_EXCESS_DEFERRAL_MASK    0x80000000UL
 150/* Transmit late collision */
 151#define XEM_TSR_LATE_COLLISION_MASK     0x01000000UL
 152
 153#define ENET_MAX_MTU            PKTSIZE
 154#define ENET_ADDR_LENGTH        6
 155
 156static unsigned int etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
 157
 158static u8 emacaddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 };
 159
 160static xemac emac;
 161
 162void eth_halt(void)
 163{
 164        debug ("eth_halt\n");
 165}
 166
 167int eth_init(bd_t * bis)
 168{
 169        u32 helpreg;
 170        debug ("EMAC Initialization Started\n\r");
 171
 172        if (emac.isstarted) {
 173                puts("Emac is started\n");
 174                return 0;
 175        }
 176
 177        memset (&emac, 0, sizeof (xemac));
 178
 179        emac.baseaddress = XILINX_EMAC_BASEADDR;
 180
 181        /* Setting up FIFOs */
 182        emac.recvfifo.regbaseaddress = emac.baseaddress +
 183                                        XEM_PFIFO_RXREG_OFFSET;
 184        emac.recvfifo.databaseaddress = emac.baseaddress +
 185                                        XEM_PFIFO_RXDATA_OFFSET;
 186        out_be32 (emac.recvfifo.regbaseaddress, XPF_RESET_FIFO_MASK);
 187
 188        emac.sendfifo.regbaseaddress = emac.baseaddress +
 189                                        XEM_PFIFO_TXREG_OFFSET;
 190        emac.sendfifo.databaseaddress = emac.baseaddress +
 191                                        XEM_PFIFO_TXDATA_OFFSET;
 192        out_be32 (emac.sendfifo.regbaseaddress, XPF_RESET_FIFO_MASK);
 193
 194        /* Reset the entire IPIF */
 195        out_be32 (emac.baseaddress + XIIF_V123B_RESETR_OFFSET,
 196                                        XIIF_V123B_RESET_MASK);
 197
 198        /* Stopping EMAC for setting up MAC */
 199        helpreg = in_be32 (emac.baseaddress + XEM_ECR_OFFSET);
 200        helpreg &= ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
 201        out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
 202
 203        if (!getenv("ethaddr")) {
 204                memcpy(bis->bi_enetaddr, emacaddr, ENET_ADDR_LENGTH);
 205        }
 206
 207        /* Set the device station address high and low registers */
 208        helpreg = (bis->bi_enetaddr[0] << 8) | bis->bi_enetaddr[1];
 209        out_be32 (emac.baseaddress + XEM_SAH_OFFSET, helpreg);
 210        helpreg = (bis->bi_enetaddr[2] << 24) | (bis->bi_enetaddr[3] << 16) |
 211                        (bis->bi_enetaddr[4] << 8) | bis->bi_enetaddr[5];
 212        out_be32 (emac.baseaddress + XEM_SAL_OFFSET, helpreg);
 213
 214        helpreg = XEM_ECR_UNICAST_ENABLE_MASK | XEM_ECR_BROAD_ENABLE_MASK |
 215                XEM_ECR_FULL_DUPLEX_MASK | XEM_ECR_XMIT_FCS_ENABLE_MASK |
 216                XEM_ECR_XMIT_PAD_ENABLE_MASK | XEM_ECR_PHY_ENABLE_MASK;
 217        out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
 218
 219        emac.isstarted = 1;
 220
 221        /* Enable the transmitter, and receiver */
 222        helpreg = in_be32 (emac.baseaddress + XEM_ECR_OFFSET);
 223        helpreg &= ~(XEM_ECR_XMIT_RESET_MASK | XEM_ECR_RECV_RESET_MASK);
 224        helpreg |= (XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
 225        out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
 226
 227        printf("EMAC Initialization complete\n\r");
 228        return 0;
 229}
 230
 231int eth_send(volatile void *ptr, int len)
 232{
 233        u32 intrstatus;
 234        u32 xmitstatus;
 235        u32 fifocount;
 236        u32 wordcount;
 237        u32 extrabytecount;
 238        u32 *wordbuffer = (u32 *) ptr;
 239
 240        if (len > ENET_MAX_MTU)
 241                len = ENET_MAX_MTU;
 242
 243        /*
 244         * Check for overruns and underruns for the transmit status and length
 245         * FIFOs and make sure the send packet FIFO is not deadlocked.
 246         * Any of these conditions is bad enough that we do not want to
 247         * continue. The upper layer software should reset the device to resolve
 248         * the error.
 249         */
 250        intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET);
 251        if (intrstatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
 252                        XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
 253                debug ("Transmitting overrun error\n");
 254                return 0;
 255        } else if (intrstatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
 256                        XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
 257                debug ("Transmitting underrun error\n");
 258                return 0;
 259        } else if (in_be32 (emac.sendfifo.regbaseaddress +
 260                        XPF_COUNT_STATUS_REG_OFFSET) & XPF_DEADLOCK_MASK) {
 261                debug ("Transmitting fifo error\n");
 262                return 0;
 263        }
 264
 265        /*
 266         * Before writing to the data FIFO, make sure the length FIFO is not
 267         * full. The data FIFO might not be full yet even though the length FIFO
 268         * is. This avoids an overrun condition on the length FIFO and keeps the
 269         * FIFOs in sync.
 270         *
 271         * Clear the latched LFIFO_FULL bit so next time around the most
 272         * current status is represented
 273         */
 274        if (intrstatus & XEM_EIR_XMIT_LFIFO_FULL_MASK) {
 275                out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
 276                        intrstatus & XEM_EIR_XMIT_LFIFO_FULL_MASK);
 277                debug ("Fifo is full\n");
 278                return 0;
 279        }
 280
 281        /* get the count of how many words may be inserted into the FIFO */
 282        fifocount = in_be32 (emac.sendfifo.regbaseaddress +
 283                                XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK;
 284        wordcount = len >> 2;
 285        extrabytecount = len & 0x3;
 286
 287        if (fifocount < wordcount) {
 288                debug ("Sending packet is larger then size of FIFO\n");
 289                return 0;
 290        }
 291
 292        for (fifocount = 0; fifocount < wordcount; fifocount++) {
 293                out_be32 (emac.sendfifo.databaseaddress, wordbuffer[fifocount]);
 294        }
 295        if (extrabytecount > 0) {
 296                u32 lastword = 0;
 297                u8 *extrabytesbuffer = (u8 *) (wordbuffer + wordcount);
 298
 299                if (extrabytecount == 1) {
 300                        lastword = extrabytesbuffer[0] << 24;
 301                } else if (extrabytecount == 2) {
 302                        lastword = extrabytesbuffer[0] << 24 |
 303                                extrabytesbuffer[1] << 16;
 304                } else if (extrabytecount == 3) {
 305                        lastword = extrabytesbuffer[0] << 24 |
 306                                extrabytesbuffer[1] << 16 |
 307                                extrabytesbuffer[2] << 8;
 308                }
 309                out_be32 (emac.sendfifo.databaseaddress, lastword);
 310        }
 311
 312        /* Loop on the MAC's status to wait for any pause to complete */
 313        intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET);
 314        while ((intrstatus & XEM_EIR_XMIT_PAUSE_MASK) != 0) {
 315                intrstatus = in_be32 ((emac.baseaddress) +
 316                                        XIIF_V123B_IISR_OFFSET);
 317                /* Clear the pause status from the transmit status register */
 318                out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
 319                                intrstatus & XEM_EIR_XMIT_PAUSE_MASK);
 320        }
 321
 322        /*
 323         * Set the MAC's transmit packet length register to tell it to transmit
 324         */
 325        out_be32 (emac.baseaddress + XEM_TPLR_OFFSET, len);
 326
 327        /*
 328         * Loop on the MAC's status to wait for the transmit to complete.
 329         * The transmit status is in the FIFO when the XMIT_DONE bit is set.
 330         */
 331        do {
 332                intrstatus = in_be32 ((emac.baseaddress) +
 333                                                XIIF_V123B_IISR_OFFSET);
 334        }
 335        while ((intrstatus & XEM_EIR_XMIT_DONE_MASK) == 0);
 336
 337        xmitstatus = in_be32 (emac.baseaddress + XEM_TSR_OFFSET);
 338
 339        if (intrstatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
 340                                        XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
 341                debug ("Transmitting overrun error\n");
 342                return 0;
 343        } else if (intrstatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
 344                                        XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
 345                debug ("Transmitting underrun error\n");
 346                return 0;
 347        }
 348
 349        /* Clear the interrupt status register of transmit statuses */
 350        out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
 351                                intrstatus & XEM_EIR_XMIT_ALL_MASK);
 352
 353        /*
 354         * Collision errors are stored in the transmit status register
 355         * instead of the interrupt status register
 356         */
 357        if ((xmitstatus & XEM_TSR_EXCESS_DEFERRAL_MASK) ||
 358                                (xmitstatus & XEM_TSR_LATE_COLLISION_MASK)) {
 359                debug ("Transmitting collision error\n");
 360                return 0;
 361        }
 362        return 1;
 363}
 364
 365int eth_rx(void)
 366{
 367        u32 pktlength;
 368        u32 intrstatus;
 369        u32 fifocount;
 370        u32 wordcount;
 371        u32 extrabytecount;
 372        u32 lastword;
 373        u8 *extrabytesbuffer;
 374
 375        if (in_be32 (emac.recvfifo.regbaseaddress + XPF_COUNT_STATUS_REG_OFFSET)
 376                        & XPF_DEADLOCK_MASK) {
 377                out_be32 (emac.recvfifo.regbaseaddress, XPF_RESET_FIFO_MASK);
 378                debug ("Receiving FIFO deadlock\n");
 379                return 0;
 380        }
 381
 382        /*
 383         * Get the interrupt status to know what happened (whether an error
 384         * occurred and/or whether frames have been received successfully).
 385         * When clearing the intr status register, clear only statuses that
 386         * pertain to receive.
 387         */
 388        intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET);
 389        /*
 390         * Before reading from the length FIFO, make sure the length FIFO is not
 391         * empty. We could cause an underrun error if we try to read from an
 392         * empty FIFO.
 393         */
 394        if (!(intrstatus & XEM_EIR_RECV_DONE_MASK)) {
 395                /* debug ("Receiving FIFO is empty\n"); */
 396                return 0;
 397        }
 398
 399        /*
 400         * Determine, from the MAC, the length of the next packet available
 401         * in the data FIFO (there should be a non-zero length here)
 402         */
 403        pktlength = in_be32 (emac.baseaddress + XEM_RPLR_OFFSET);
 404        if (!pktlength) {
 405                return 0;
 406        }
 407
 408        /*
 409         * Write the RECV_DONE bit in the status register to clear it. This bit
 410         * indicates the RPLR is non-empty, and we know it's set at this point.
 411         * We clear it so that subsequent entry into this routine will reflect
 412         * the current status. This is done because the non-empty bit is latched
 413         * in the IPIF, which means it may indicate a non-empty condition even
 414         * though there is something in the FIFO.
 415         */
 416        out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
 417                                                XEM_EIR_RECV_DONE_MASK);
 418
 419        fifocount = in_be32 (emac.recvfifo.regbaseaddress +
 420                                XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK;
 421
 422        if ((fifocount * 4) < pktlength) {
 423                debug ("Receiving FIFO is smaller than packet size.\n");
 424                return 0;
 425        }
 426
 427        wordcount = pktlength >> 2;
 428        extrabytecount = pktlength & 0x3;
 429
 430        for (fifocount = 0; fifocount < wordcount; fifocount++) {
 431                etherrxbuff[fifocount] =
 432                                in_be32 (emac.recvfifo.databaseaddress);
 433        }
 434
 435        /*
 436         * if there are extra bytes to handle, read the last word from the FIFO
 437         * and insert the extra bytes into the buffer
 438         */
 439        if (extrabytecount > 0) {
 440                extrabytesbuffer = (u8 *) (etherrxbuff + wordcount);
 441
 442                lastword = in_be32 (emac.recvfifo.databaseaddress);
 443
 444                /*
 445                 * one extra byte in the last word, put the byte into the next
 446                 * location of the buffer, bytes in a word of the FIFO are
 447                 * ordered from most significant byte to least
 448                 */
 449                if (extrabytecount == 1) {
 450                        extrabytesbuffer[0] = (u8) (lastword >> 24);
 451                } else if (extrabytecount == 2) {
 452                        extrabytesbuffer[0] = (u8) (lastword >> 24);
 453                        extrabytesbuffer[1] = (u8) (lastword >> 16);
 454                } else if (extrabytecount == 3) {
 455                        extrabytesbuffer[0] = (u8) (lastword >> 24);
 456                        extrabytesbuffer[1] = (u8) (lastword >> 16);
 457                        extrabytesbuffer[2] = (u8) (lastword >> 8);
 458                }
 459        }
 460        NetReceive((uchar *)etherrxbuff, pktlength);
 461        return 1;
 462}
 463