uboot/drivers/net/xilinx_emaclite.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007-2009 Michal Simek
   3 * (C) Copyright 2003 Xilinx Inc.
   4 *
   5 * Michal SIMEK <monstr@monstr.eu>
   6 *
   7 * See file CREDITS for list of people who contributed to this
   8 * project.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License as
  12 * published by the Free Software Foundation; either version 2 of
  13 * the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23 * MA 02111-1307 USA
  24 */
  25
  26#include <common.h>
  27#include <net.h>
  28#include <config.h>
  29#include <malloc.h>
  30#include <asm/io.h>
  31
  32#undef DEBUG
  33
  34#define ENET_MAX_MTU            PKTSIZE
  35#define ENET_MAX_MTU_ALIGNED    PKTSIZE_ALIGN
  36#define ENET_ADDR_LENGTH        6
  37
  38/* EmacLite constants */
  39#define XEL_BUFFER_OFFSET       0x0800  /* Next buffer's offset */
  40#define XEL_TPLR_OFFSET         0x07F4  /* Tx packet length */
  41#define XEL_TSR_OFFSET          0x07FC  /* Tx status */
  42#define XEL_RSR_OFFSET          0x17FC  /* Rx status */
  43#define XEL_RXBUFF_OFFSET       0x1000  /* Receive Buffer */
  44
  45/* Xmit complete */
  46#define XEL_TSR_XMIT_BUSY_MASK          0x00000001UL
  47/* Xmit interrupt enable bit */
  48#define XEL_TSR_XMIT_IE_MASK            0x00000008UL
  49/* Buffer is active, SW bit only */
  50#define XEL_TSR_XMIT_ACTIVE_MASK        0x80000000UL
  51/* Program the MAC address */
  52#define XEL_TSR_PROGRAM_MASK            0x00000002UL
  53/* define for programming the MAC address into the EMAC Lite */
  54#define XEL_TSR_PROG_MAC_ADDR   (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK)
  55
  56/* Transmit packet length upper byte */
  57#define XEL_TPLR_LENGTH_MASK_HI         0x0000FF00UL
  58/* Transmit packet length lower byte */
  59#define XEL_TPLR_LENGTH_MASK_LO         0x000000FFUL
  60
  61/* Recv complete */
  62#define XEL_RSR_RECV_DONE_MASK          0x00000001UL
  63/* Recv interrupt enable bit */
  64#define XEL_RSR_RECV_IE_MASK            0x00000008UL
  65
  66typedef struct {
  67        u32 baseaddress;        /* Base address for device (IPIF) */
  68        u32 nexttxbuffertouse;  /* Next TX buffer to write to */
  69        u32 nextrxbuffertouse;  /* Next RX buffer to read from */
  70        uchar deviceid;         /* Unique ID of device - for future */
  71} xemaclite;
  72
  73static xemaclite emaclite;
  74
  75static u32 etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
  76
  77static void xemaclite_alignedread (u32 *srcptr, void *destptr, u32 bytecount)
  78{
  79        u32 i;
  80        u32 alignbuffer;
  81        u32 *to32ptr;
  82        u32 *from32ptr;
  83        u8 *to8ptr;
  84        u8 *from8ptr;
  85
  86        from32ptr = (u32 *) srcptr;
  87
  88        /* Word aligned buffer, no correction needed. */
  89        to32ptr = (u32 *) destptr;
  90        while (bytecount > 3) {
  91                *to32ptr++ = *from32ptr++;
  92                bytecount -= 4;
  93        }
  94        to8ptr = (u8 *) to32ptr;
  95
  96        alignbuffer = *from32ptr++;
  97        from8ptr = (u8 *) & alignbuffer;
  98
  99        for (i = 0; i < bytecount; i++) {
 100                *to8ptr++ = *from8ptr++;
 101        }
 102}
 103
 104static void xemaclite_alignedwrite (void *srcptr, u32 destptr, u32 bytecount)
 105{
 106        u32 i;
 107        u32 alignbuffer;
 108        u32 *to32ptr = (u32 *) destptr;
 109        u32 *from32ptr;
 110        u8 *to8ptr;
 111        u8 *from8ptr;
 112
 113        from32ptr = (u32 *) srcptr;
 114        while (bytecount > 3) {
 115
 116                *to32ptr++ = *from32ptr++;
 117                bytecount -= 4;
 118        }
 119
 120        alignbuffer = 0;
 121        to8ptr = (u8 *) & alignbuffer;
 122        from8ptr = (u8 *) from32ptr;
 123
 124        for (i = 0; i < bytecount; i++) {
 125                *to8ptr++ = *from8ptr++;
 126        }
 127
 128        *to32ptr++ = alignbuffer;
 129}
 130
 131static void emaclite_halt(struct eth_device *dev)
 132{
 133        debug ("eth_halt\n");
 134}
 135
 136static int emaclite_init(struct eth_device *dev, bd_t *bis)
 137{
 138        debug ("EmacLite Initialization Started\n");
 139        memset (&emaclite, 0, sizeof (xemaclite));
 140        emaclite.baseaddress = dev->iobase;
 141
 142/*
 143 * TX - TX_PING & TX_PONG initialization
 144 */
 145        /* Restart PING TX */
 146        out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0);
 147        /* Copy MAC address */
 148        xemaclite_alignedwrite (dev->enetaddr,
 149                emaclite.baseaddress, ENET_ADDR_LENGTH);
 150        /* Set the length */
 151        out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
 152        /* Update the MAC address in the EMAC Lite */
 153        out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR);
 154        /* Wait for EMAC Lite to finish with the MAC address update */
 155        while ((in_be32 (emaclite.baseaddress + XEL_TSR_OFFSET) &
 156                XEL_TSR_PROG_MAC_ADDR) != 0) ;
 157
 158#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
 159        /* The same operation with PONG TX */
 160        out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0);
 161        xemaclite_alignedwrite (dev->enetaddr, emaclite.baseaddress +
 162                XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH);
 163        out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
 164        out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET,
 165                XEL_TSR_PROG_MAC_ADDR);
 166        while ((in_be32 (emaclite.baseaddress + XEL_TSR_OFFSET +
 167                XEL_BUFFER_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0) ;
 168#endif
 169
 170/*
 171 * RX - RX_PING & RX_PONG initialization
 172 */
 173        /* Write out the value to flush the RX buffer */
 174        out_be32 (emaclite.baseaddress + XEL_RSR_OFFSET, XEL_RSR_RECV_IE_MASK);
 175#ifdef CONFIG_XILINX_EMACLITE_RX_PING_PONG
 176        out_be32 (emaclite.baseaddress + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET,
 177                XEL_RSR_RECV_IE_MASK);
 178#endif
 179
 180        debug ("EmacLite Initialization complete\n");
 181        return 0;
 182}
 183
 184static int xemaclite_txbufferavailable (xemaclite *instanceptr)
 185{
 186        u32 reg;
 187        u32 txpingbusy;
 188        u32 txpongbusy;
 189        /*
 190         * Read the other buffer register
 191         * and determine if the other buffer is available
 192         */
 193        reg = in_be32 (instanceptr->baseaddress +
 194                        instanceptr->nexttxbuffertouse + 0);
 195        txpingbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
 196                        XEL_TSR_XMIT_BUSY_MASK);
 197
 198        reg = in_be32 (instanceptr->baseaddress +
 199                        (instanceptr->nexttxbuffertouse ^ XEL_TSR_OFFSET) + 0);
 200        txpongbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) ==
 201                        XEL_TSR_XMIT_BUSY_MASK);
 202
 203        return (!(txpingbusy && txpongbusy));
 204}
 205
 206static int emaclite_send (struct eth_device *dev, volatile void *ptr, int len)
 207{
 208        u32 reg;
 209        u32 baseaddress;
 210
 211        u32 maxtry = 1000;
 212
 213        if (len > ENET_MAX_MTU)
 214                len = ENET_MAX_MTU;
 215
 216        while (!xemaclite_txbufferavailable (&emaclite) && maxtry) {
 217                udelay (10);
 218                maxtry--;
 219        }
 220
 221        if (!maxtry) {
 222                printf ("Error: Timeout waiting for ethernet TX buffer\n");
 223                /* Restart PING TX */
 224                out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0);
 225#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
 226                out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET +
 227                XEL_BUFFER_OFFSET, 0);
 228#endif
 229                return 0;
 230        }
 231
 232        /* Determine the expected TX buffer address */
 233        baseaddress = (emaclite.baseaddress + emaclite.nexttxbuffertouse);
 234
 235        /* Determine if the expected buffer address is empty */
 236        reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
 237        if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
 238                && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
 239                        & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
 240
 241#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
 242                emaclite.nexttxbuffertouse ^= XEL_BUFFER_OFFSET;
 243#endif
 244                debug ("Send packet from 0x%x\n", baseaddress);
 245                /* Write the frame to the buffer */
 246                xemaclite_alignedwrite ((void *) ptr, baseaddress, len);
 247                out_be32 (baseaddress + XEL_TPLR_OFFSET,(len &
 248                        (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
 249                reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
 250                reg |= XEL_TSR_XMIT_BUSY_MASK;
 251                if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) {
 252                        reg |= XEL_TSR_XMIT_ACTIVE_MASK;
 253                }
 254                out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
 255                return 1;
 256        }
 257#ifdef CONFIG_XILINX_EMACLITE_TX_PING_PONG
 258        /* Switch to second buffer */
 259        baseaddress ^= XEL_BUFFER_OFFSET;
 260        /* Determine if the expected buffer address is empty */
 261        reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
 262        if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0)
 263                && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET)
 264                        & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
 265                debug ("Send packet from 0x%x\n", baseaddress);
 266                /* Write the frame to the buffer */
 267                xemaclite_alignedwrite ((void *) ptr, baseaddress, len);
 268                out_be32 (baseaddress + XEL_TPLR_OFFSET,(len &
 269                        (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
 270                reg = in_be32 (baseaddress + XEL_TSR_OFFSET);
 271                reg |= XEL_TSR_XMIT_BUSY_MASK;
 272                if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) {
 273                        reg |= XEL_TSR_XMIT_ACTIVE_MASK;
 274                }
 275                out_be32 (baseaddress + XEL_TSR_OFFSET, reg);
 276                return 1;
 277        }
 278#endif
 279        puts ("Error while sending frame\n");
 280        return 0;
 281}
 282
 283static int emaclite_recv(struct eth_device *dev)
 284{
 285        u32 length;
 286        u32 reg;
 287        u32 baseaddress;
 288
 289        baseaddress = emaclite.baseaddress + emaclite.nextrxbuffertouse;
 290        reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
 291        debug ("Testing data at address 0x%x\n", baseaddress);
 292        if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
 293#ifdef CONFIG_XILINX_EMACLITE_RX_PING_PONG
 294                emaclite.nextrxbuffertouse ^= XEL_BUFFER_OFFSET;
 295#endif
 296        } else {
 297#ifndef CONFIG_XILINX_EMACLITE_RX_PING_PONG
 298                debug ("No data was available - address 0x%x\n", baseaddress);
 299                return 0;
 300#else
 301                baseaddress ^= XEL_BUFFER_OFFSET;
 302                reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
 303                if ((reg & XEL_RSR_RECV_DONE_MASK) !=
 304                                        XEL_RSR_RECV_DONE_MASK) {
 305                        debug ("No data was available - address 0x%x\n",
 306                                        baseaddress);
 307                        return 0;
 308                }
 309#endif
 310        }
 311        /* Get the length of the frame that arrived */
 312        switch(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0xC))) &
 313                        0xFFFF0000 ) >> 16) {
 314                case 0x806:
 315                        length = 42 + 20; /* FIXME size of ARP */
 316                        debug ("ARP Packet\n");
 317                        break;
 318                case 0x800:
 319                        length = 14 + 14 +
 320                        (((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0x10))) &
 321                        0xFFFF0000) >> 16); /* FIXME size of IP packet */
 322                        debug ("IP Packet\n");
 323                        break;
 324                default:
 325                        debug ("Other Packet\n");
 326                        length = ENET_MAX_MTU;
 327                        break;
 328        }
 329
 330        xemaclite_alignedread ((u32 *) (baseaddress + XEL_RXBUFF_OFFSET),
 331                        etherrxbuff, length);
 332
 333        /* Acknowledge the frame */
 334        reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
 335        reg &= ~XEL_RSR_RECV_DONE_MASK;
 336        out_be32 (baseaddress + XEL_RSR_OFFSET, reg);
 337
 338        debug ("Packet receive from 0x%x, length %dB\n", baseaddress, length);
 339        NetReceive ((uchar *) etherrxbuff, length);
 340        return 1;
 341
 342}
 343
 344int xilinx_emaclite_initialize (bd_t *bis, int base_addr)
 345{
 346        struct eth_device *dev;
 347
 348        dev = malloc(sizeof(*dev));
 349        if (dev == NULL)
 350                hang();
 351
 352        memset(dev, 0, sizeof(*dev));
 353        sprintf(dev->name, "Xilinx_Emaclite");
 354
 355        dev->iobase = base_addr;
 356        dev->priv = 0;
 357        dev->init = emaclite_init;
 358        dev->halt = emaclite_halt;
 359        dev->send = emaclite_send;
 360        dev->recv = emaclite_recv;
 361
 362        eth_register(dev);
 363
 364        return 0;
 365}
 366