uboot/drivers/net/bfin_mac.c
<<
>>
Prefs
   1/*
   2 * Driver for Blackfin On-Chip MAC device
   3 *
   4 * Copyright (c) 2005-2008 Analog Device, Inc.
   5 *
   6 * Licensed under the GPL-2 or later.
   7 */
   8
   9#include <common.h>
  10#include <config.h>
  11#include <net.h>
  12#include <netdev.h>
  13#include <command.h>
  14#include <malloc.h>
  15#include <miiphy.h>
  16#include <linux/mii.h>
  17
  18#include <asm/blackfin.h>
  19#include <asm/portmux.h>
  20#include <asm/mach-common/bits/dma.h>
  21#include <asm/mach-common/bits/emac.h>
  22#include <asm/mach-common/bits/pll.h>
  23
  24#include "bfin_mac.h"
  25
  26#ifndef CONFIG_PHY_ADDR
  27# define CONFIG_PHY_ADDR 1
  28#endif
  29#ifndef CONFIG_PHY_CLOCK_FREQ
  30# define CONFIG_PHY_CLOCK_FREQ 2500000
  31#endif
  32
  33#ifdef CONFIG_POST
  34#include <post.h>
  35#endif
  36
  37#define RXBUF_BASE_ADDR         0xFF900000
  38#define TXBUF_BASE_ADDR         0xFF800000
  39#define TX_BUF_CNT              1
  40
  41#define TOUT_LOOP               1000000
  42
  43static ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT];
  44static ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX];
  45static u16 txIdx;               /* index of the current RX buffer */
  46static u16 rxIdx;               /* index of the current TX buffer */
  47
  48/* DMAx_CONFIG values at DMA Restart */
  49static const union {
  50        u16 data;
  51        ADI_DMA_CONFIG_REG reg;
  52} txdmacfg = {
  53        .reg = {
  54                .b_DMA_EN  = 1, /* enabled */
  55                .b_WNR     = 0, /* read from memory */
  56                .b_WDSIZE  = 2, /* wordsize is 32 bits */
  57                .b_DMA2D   = 0,
  58                .b_RESTART = 0,
  59                .b_DI_SEL  = 0,
  60                .b_DI_EN   = 0, /* no interrupt */
  61                .b_NDSIZE  = 5, /* 5 half words is desc size */
  62                .b_FLOW    = 7  /* large desc flow */
  63        },
  64};
  65
  66static int bfin_miiphy_wait(void)
  67{
  68        /* poll the STABUSY bit */
  69        while (bfin_read_EMAC_STAADD() & STABUSY)
  70                continue;
  71        return 0;
  72}
  73
  74static int bfin_miiphy_read(const char *devname, uchar addr, uchar reg, ushort *val)
  75{
  76        if (bfin_miiphy_wait())
  77                return 1;
  78        bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY);
  79        if (bfin_miiphy_wait())
  80                return 1;
  81        *val = bfin_read_EMAC_STADAT();
  82        return 0;
  83}
  84
  85static int bfin_miiphy_write(const char *devname, uchar addr, uchar reg, ushort val)
  86{
  87        if (bfin_miiphy_wait())
  88                return 1;
  89        bfin_write_EMAC_STADAT(val);
  90        bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STAOP | STABUSY);
  91        return 0;
  92}
  93
  94int bfin_EMAC_initialize(bd_t *bis)
  95{
  96        struct eth_device *dev;
  97        dev = malloc(sizeof(*dev));
  98        if (dev == NULL)
  99                hang();
 100
 101        memset(dev, 0, sizeof(*dev));
 102        strcpy(dev->name, "bfin_mac");
 103
 104        dev->iobase = 0;
 105        dev->priv = 0;
 106        dev->init = bfin_EMAC_init;
 107        dev->halt = bfin_EMAC_halt;
 108        dev->send = bfin_EMAC_send;
 109        dev->recv = bfin_EMAC_recv;
 110        dev->write_hwaddr = bfin_EMAC_setup_addr;
 111
 112        eth_register(dev);
 113
 114#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 115        miiphy_register(dev->name, bfin_miiphy_read, bfin_miiphy_write);
 116#endif
 117
 118        return 0;
 119}
 120
 121static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet,
 122                          int length)
 123{
 124        int i;
 125        int result = 0;
 126        unsigned int *buf;
 127        buf = (unsigned int *)packet;
 128
 129        if (length <= 0) {
 130                printf("Ethernet: bad packet size: %d\n", length);
 131                goto out;
 132        }
 133
 134        if (bfin_read_DMA2_IRQ_STATUS() & DMA_ERR) {
 135                printf("Ethernet: tx DMA error\n");
 136                goto out;
 137        }
 138
 139        for (i = 0; (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN); ++i) {
 140                if (i > TOUT_LOOP) {
 141                        puts("Ethernet: tx time out\n");
 142                        goto out;
 143                }
 144        }
 145        txbuf[txIdx]->FrmData->NoBytes = length;
 146        memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length);
 147        txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData;
 148        bfin_write_DMA2_NEXT_DESC_PTR(txbuf[txIdx]->Dma);
 149        bfin_write_DMA2_CONFIG(txdmacfg.data);
 150        bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
 151
 152        for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) {
 153                if (i > TOUT_LOOP) {
 154                        puts("Ethernet: tx error\n");
 155                        goto out;
 156                }
 157        }
 158        result = txbuf[txIdx]->StatusWord;
 159        txbuf[txIdx]->StatusWord = 0;
 160        if ((txIdx + 1) >= TX_BUF_CNT)
 161                txIdx = 0;
 162        else
 163                txIdx++;
 164 out:
 165        debug("BFIN EMAC send: length = %d\n", length);
 166        return result;
 167}
 168
 169static int bfin_EMAC_recv(struct eth_device *dev)
 170{
 171        int length = 0;
 172
 173        for (;;) {
 174                if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) {
 175                        length = -1;
 176                        break;
 177                }
 178                if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) {
 179                        printf("Ethernet: rx dma overrun\n");
 180                        break;
 181                }
 182                if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) {
 183                        printf("Ethernet: rx error\n");
 184                        break;
 185                }
 186                length = rxbuf[rxIdx]->StatusWord & 0x000007FF;
 187                if (length <= 4) {
 188                        printf("Ethernet: bad frame\n");
 189                        break;
 190                }
 191
 192                debug("%s: len = %d\n", __func__, length - 4);
 193
 194                NetRxPackets[rxIdx] =
 195                    (volatile uchar *)(rxbuf[rxIdx]->FrmData->Dest);
 196                NetReceive(NetRxPackets[rxIdx], length - 4);
 197                bfin_write_DMA1_IRQ_STATUS(DMA_DONE | DMA_ERR);
 198                rxbuf[rxIdx]->StatusWord = 0x00000000;
 199                if ((rxIdx + 1) >= PKTBUFSRX)
 200                        rxIdx = 0;
 201                else
 202                        rxIdx++;
 203        }
 204
 205        return length;
 206}
 207
 208/**************************************************************
 209 *
 210 * Ethernet Initialization Routine
 211 *
 212 *************************************************************/
 213
 214/* MDC = SCLK / MDC_freq / 2 - 1 */
 215#define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1)
 216
 217#ifndef CONFIG_BFIN_MAC_PINS
 218# ifdef CONFIG_RMII
 219#  define CONFIG_BFIN_MAC_PINS P_RMII0
 220# else
 221#  define CONFIG_BFIN_MAC_PINS P_MII0
 222# endif
 223#endif
 224
 225static int bfin_miiphy_init(struct eth_device *dev, int *opmode)
 226{
 227        const unsigned short pins[] = CONFIG_BFIN_MAC_PINS;
 228        u16 phydat;
 229        size_t count;
 230
 231        /* Enable PHY output */
 232        bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE);
 233
 234        /* Set all the pins to peripheral mode */
 235        peripheral_request_list(pins, "bfin_mac");
 236
 237        /* Odd word alignment for Receive Frame DMA word */
 238        /* Configure checksum support and rcve frame word alignment */
 239        bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(CONFIG_PHY_CLOCK_FREQ)));
 240
 241        /* turn on auto-negotiation and wait for link to come up */
 242        bfin_miiphy_write(dev->name, CONFIG_PHY_ADDR, MII_BMCR, BMCR_ANENABLE);
 243        count = 0;
 244        while (1) {
 245                ++count;
 246                if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_BMSR, &phydat))
 247                        return -1;
 248                if (phydat & BMSR_LSTATUS)
 249                        break;
 250                if (count > 30000) {
 251                        printf("%s: link down, check cable\n", dev->name);
 252                        return -1;
 253                }
 254                udelay(100);
 255        }
 256
 257        /* see what kind of link we have */
 258        if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_LPA, &phydat))
 259                return -1;
 260        if (phydat & LPA_DUPLEX)
 261                *opmode = FDMODE;
 262        else
 263                *opmode = 0;
 264
 265        bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
 266
 267        /* Initialize the TX DMA channel registers */
 268        bfin_write_DMA2_X_COUNT(0);
 269        bfin_write_DMA2_X_MODIFY(4);
 270        bfin_write_DMA2_Y_COUNT(0);
 271        bfin_write_DMA2_Y_MODIFY(0);
 272
 273        /* Initialize the RX DMA channel registers */
 274        bfin_write_DMA1_X_COUNT(0);
 275        bfin_write_DMA1_X_MODIFY(4);
 276        bfin_write_DMA1_Y_COUNT(0);
 277        bfin_write_DMA1_Y_MODIFY(0);
 278
 279        return 0;
 280}
 281
 282static int bfin_EMAC_setup_addr(struct eth_device *dev)
 283{
 284        bfin_write_EMAC_ADDRLO(
 285                dev->enetaddr[0] |
 286                dev->enetaddr[1] << 8 |
 287                dev->enetaddr[2] << 16 |
 288                dev->enetaddr[3] << 24
 289        );
 290        bfin_write_EMAC_ADDRHI(
 291                dev->enetaddr[4] |
 292                dev->enetaddr[5] << 8
 293        );
 294        return 0;
 295}
 296
 297static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)
 298{
 299        u32 opmode;
 300        int dat;
 301        int i;
 302        debug("Eth_init: ......\n");
 303
 304        txIdx = 0;
 305        rxIdx = 0;
 306
 307        /* Initialize System Register */
 308        if (bfin_miiphy_init(dev, &dat) < 0)
 309                return -1;
 310
 311        /* Initialize EMAC address */
 312        bfin_EMAC_setup_addr(dev);
 313
 314        /* Initialize TX and RX buffer */
 315        for (i = 0; i < PKTBUFSRX; i++) {
 316                rxbuf[i] = SetupRxBuffer(i);
 317                if (i > 0) {
 318                        rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = rxbuf[i]->Dma;
 319                        if (i == (PKTBUFSRX - 1))
 320                                rxbuf[i]->Dma[1].NEXT_DESC_PTR = rxbuf[0]->Dma;
 321                }
 322        }
 323        for (i = 0; i < TX_BUF_CNT; i++) {
 324                txbuf[i] = SetupTxBuffer(i);
 325                if (i > 0) {
 326                        txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = txbuf[i]->Dma;
 327                        if (i == (TX_BUF_CNT - 1))
 328                                txbuf[i]->Dma[1].NEXT_DESC_PTR = txbuf[0]->Dma;
 329                }
 330        }
 331
 332        /* Set RX DMA */
 333        bfin_write_DMA1_NEXT_DESC_PTR(rxbuf[0]->Dma);
 334        bfin_write_DMA1_CONFIG(rxbuf[0]->Dma[0].CONFIG_DATA);
 335
 336        /* Wait MII done */
 337        bfin_miiphy_wait();
 338
 339        /* We enable only RX here */
 340        /* ASTP   : Enable Automatic Pad Stripping
 341           PR     : Promiscuous Mode for test
 342           PSF    : Receive frames with total length less than 64 bytes.
 343           FDMODE : Full Duplex Mode
 344           LB     : Internal Loopback for test
 345           RE     : Receiver Enable */
 346        if (dat == FDMODE)
 347                opmode = ASTP | FDMODE | PSF;
 348        else
 349                opmode = ASTP | PSF;
 350        opmode |= RE;
 351#ifdef CONFIG_RMII
 352        opmode |= TE | RMII;
 353#endif
 354        /* Turn on the EMAC */
 355        bfin_write_EMAC_OPMODE(opmode);
 356        return 0;
 357}
 358
 359static void bfin_EMAC_halt(struct eth_device *dev)
 360{
 361        debug("Eth_halt: ......\n");
 362        /* Turn off the EMAC */
 363        bfin_write_EMAC_OPMODE(0);
 364        /* Turn off the EMAC RX DMA */
 365        bfin_write_DMA1_CONFIG(0);
 366        bfin_write_DMA2_CONFIG(0);
 367}
 368
 369ADI_ETHER_BUFFER *SetupRxBuffer(int no)
 370{
 371        ADI_ETHER_FRAME_BUFFER *frmbuf;
 372        ADI_ETHER_BUFFER *buf;
 373        int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2;   /* ensure a multi. of 4 */
 374        int total_size = nobytes_buffer + RECV_BUFSIZE;
 375
 376        buf = (void *) (RXBUF_BASE_ADDR + no * total_size);
 377        frmbuf = (void *) (RXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
 378
 379        memset(buf, 0x00, nobytes_buffer);
 380        buf->FrmData = frmbuf;
 381        memset(frmbuf, 0xfe, RECV_BUFSIZE);
 382
 383        /* set up first desc to point to receive frame buffer */
 384        buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
 385        buf->Dma[0].START_ADDR = (u32) buf->FrmData;
 386        buf->Dma[0].CONFIG.b_DMA_EN = 1;        /* enabled */
 387        buf->Dma[0].CONFIG.b_WNR = 1;   /* Write to memory */
 388        buf->Dma[0].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
 389        buf->Dma[0].CONFIG.b_NDSIZE = 5;        /* 5 half words is desc size. */
 390        buf->Dma[0].CONFIG.b_FLOW = 7;  /* large desc flow */
 391
 392        /* set up second desc to point to status word */
 393        buf->Dma[1].NEXT_DESC_PTR = buf->Dma;
 394        buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum;
 395        buf->Dma[1].CONFIG.b_DMA_EN = 1;        /* enabled */
 396        buf->Dma[1].CONFIG.b_WNR = 1;   /* Write to memory */
 397        buf->Dma[1].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
 398        buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
 399        buf->Dma[1].CONFIG.b_NDSIZE = 5;        /* must be 0 when FLOW is 0 */
 400        buf->Dma[1].CONFIG.b_FLOW = 7;  /* stop */
 401
 402        return buf;
 403}
 404
 405ADI_ETHER_BUFFER *SetupTxBuffer(int no)
 406{
 407        ADI_ETHER_FRAME_BUFFER *frmbuf;
 408        ADI_ETHER_BUFFER *buf;
 409        int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2;   /* ensure a multi. of 4 */
 410        int total_size = nobytes_buffer + RECV_BUFSIZE;
 411
 412        buf = (void *) (TXBUF_BASE_ADDR + no * total_size);
 413        frmbuf = (void *) (TXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
 414
 415        memset(buf, 0x00, nobytes_buffer);
 416        buf->FrmData = frmbuf;
 417        memset(frmbuf, 0x00, RECV_BUFSIZE);
 418
 419        /* set up first desc to point to receive frame buffer */
 420        buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
 421        buf->Dma[0].START_ADDR = (u32) buf->FrmData;
 422        buf->Dma[0].CONFIG.b_DMA_EN = 1;        /* enabled */
 423        buf->Dma[0].CONFIG.b_WNR = 0;   /* Read to memory */
 424        buf->Dma[0].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
 425        buf->Dma[0].CONFIG.b_NDSIZE = 5;        /* 5 half words is desc size. */
 426        buf->Dma[0].CONFIG.b_FLOW = 7;  /* large desc flow */
 427
 428        /* set up second desc to point to status word */
 429        buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
 430        buf->Dma[1].START_ADDR = (u32) & buf->StatusWord;
 431        buf->Dma[1].CONFIG.b_DMA_EN = 1;        /* enabled */
 432        buf->Dma[1].CONFIG.b_WNR = 1;   /* Write to memory */
 433        buf->Dma[1].CONFIG.b_WDSIZE = 2;        /* wordsize is 32 bits */
 434        buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
 435        buf->Dma[1].CONFIG.b_NDSIZE = 0;        /* must be 0 when FLOW is 0 */
 436        buf->Dma[1].CONFIG.b_FLOW = 0;  /* stop */
 437
 438        return buf;
 439}
 440
 441#if defined(CONFIG_POST) && defined(CONFIG_SYS_POST_ETHER)
 442int ether_post_test(int flags)
 443{
 444        uchar buf[64];
 445        int i, value = 0;
 446        int length;
 447        uint addr;
 448
 449        printf("\n--------");
 450        bfin_EMAC_init(NULL, NULL);
 451        /* construct the package */
 452        addr = bfin_read_EMAC_ADDRLO();
 453        buf[0] = buf[6] = addr;
 454        buf[1] = buf[7] = addr >> 8;
 455        buf[2] = buf[8] = addr >> 16;
 456        buf[3] = buf[9] = addr >> 24;
 457        addr = bfin_read_EMAC_ADDRHI();
 458        buf[4] = buf[10] = addr;
 459        buf[5] = buf[11] = addr >> 8;
 460        buf[12] = 0x08;         /* Type: ARP */
 461        buf[13] = 0x06;
 462        buf[14] = 0x00;         /* Hardware type: Ethernet */
 463        buf[15] = 0x01;
 464        buf[16] = 0x08;         /* Protocal type: IP */
 465        buf[17] = 0x00;
 466        buf[18] = 0x06;         /* Hardware size    */
 467        buf[19] = 0x04;         /* Protocol size    */
 468        buf[20] = 0x00;         /* Opcode: request  */
 469        buf[21] = 0x01;
 470
 471        for (i = 0; i < 42; i++)
 472                buf[i + 22] = i;
 473        printf("--------Send 64 bytes......\n");
 474        bfin_EMAC_send(NULL, (volatile void *)buf, 64);
 475        for (i = 0; i < 100; i++) {
 476                udelay(10000);
 477                if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) {
 478                        value = 1;
 479                        break;
 480                }
 481        }
 482        if (value == 0) {
 483                printf("--------EMAC can't receive any data\n");
 484                eth_halt();
 485                return -1;
 486        }
 487        length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4;
 488        for (i = 0; i < length; i++) {
 489                if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) {
 490                        printf("--------EMAC receive error data!\n");
 491                        eth_halt();
 492                        return -1;
 493                }
 494        }
 495        printf("--------receive %d bytes, matched\n", length);
 496        bfin_EMAC_halt(NULL);
 497        return 0;
 498}
 499#endif
 500