uboot/drivers/net/inca-ip_sw.c
<<
>>
Prefs
   1/*
   2 * INCA-IP internal switch ethernet driver.
   3 *
   4 * (C) Copyright 2003-2004
   5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   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
  27#include <common.h>
  28
  29#include <malloc.h>
  30#include <net.h>
  31#include <netdev.h>
  32#include <asm/inca-ip.h>
  33#include <asm/addrspace.h>
  34
  35
  36#define NUM_RX_DESC     PKTBUFSRX
  37#define NUM_TX_DESC     3
  38#define TOUT_LOOP       1000000
  39
  40
  41#define DELAY   udelay(10000)
  42  /* Sometimes the store word instruction hangs while writing to one
  43   * of the Switch registers. Moving the instruction into a separate
  44   * function somehow makes the problem go away.
  45   */
  46static void SWORD(volatile u32 * reg, u32 value)
  47{
  48        *reg = value;
  49}
  50
  51#define DMA_WRITE_REG(reg, value) *((volatile u32 *)reg) = (u32)value;
  52#define DMA_READ_REG(reg, value)    value = (u32)*((volatile u32*)reg)
  53#define SW_WRITE_REG(reg, value)   \
  54        SWORD(reg, value);\
  55        DELAY;\
  56        SWORD(reg, value);
  57
  58#define SW_READ_REG(reg, value)    \
  59        value = (u32)*((volatile u32*)reg);\
  60        DELAY;\
  61        value = (u32)*((volatile u32*)reg);
  62
  63#define INCA_DMA_TX_POLLING_TIME        0x07
  64#define INCA_DMA_RX_POLLING_TIME        0x07
  65
  66#define INCA_DMA_TX_HOLD                0x80000000
  67#define INCA_DMA_TX_EOP                 0x40000000
  68#define INCA_DMA_TX_SOP                 0x20000000
  69#define INCA_DMA_TX_ICPT                0x10000000
  70#define INCA_DMA_TX_IEOP                0x08000000
  71
  72#define INCA_DMA_RX_C                   0x80000000
  73#define INCA_DMA_RX_SOP                 0x40000000
  74#define INCA_DMA_RX_EOP                 0x20000000
  75
  76#define INCA_SWITCH_PHY_SPEED_10H       0x1
  77#define INCA_SWITCH_PHY_SPEED_10F       0x5
  78#define INCA_SWITCH_PHY_SPEED_100H      0x2
  79#define INCA_SWITCH_PHY_SPEED_100F      0x6
  80
  81/************************ Auto MDIX settings ************************/
  82#define INCA_IP_AUTO_MDIX_LAN_PORTS_DIR         INCA_IP_Ports_P1_DIR
  83#define INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL      INCA_IP_Ports_P1_ALTSEL
  84#define INCA_IP_AUTO_MDIX_LAN_PORTS_OUT         INCA_IP_Ports_P1_OUT
  85#define INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX     16
  86
  87#define WAIT_SIGNAL_RETRIES                     100
  88#define WAIT_LINK_RETRIES                       100
  89#define LINK_RETRY_DELAY                        2000  /* ms */
  90/********************************************************************/
  91
  92typedef struct
  93{
  94        union {
  95                struct {
  96                        volatile u32 HOLD               :1;
  97                        volatile u32 ICpt               :1;
  98                        volatile u32 IEop               :1;
  99                        volatile u32 offset             :3;
 100                        volatile u32 reserved0          :4;
 101                        volatile u32 NFB                :22;
 102                }field;
 103
 104                volatile u32 word;
 105        }params;
 106
 107        volatile u32 nextRxDescPtr;
 108
 109        volatile u32 RxDataPtr;
 110
 111        union {
 112                struct {
 113                        volatile u32 C                  :1;
 114                        volatile u32 Sop                :1;
 115                        volatile u32 Eop                :1;
 116                        volatile u32 reserved3          :12;
 117                        volatile u32 NBT                :17;
 118                }field;
 119
 120                volatile u32 word;
 121        }status;
 122
 123} inca_rx_descriptor_t;
 124
 125
 126typedef struct
 127{
 128        union {
 129                struct {
 130                        volatile u32 HOLD               :1;
 131                        volatile u32 Eop                :1;
 132                        volatile u32 Sop                :1;
 133                        volatile u32 ICpt               :1;
 134                        volatile u32 IEop               :1;
 135                        volatile u32 reserved0          :5;
 136                        volatile u32 NBA                :22;
 137                }field;
 138
 139                volatile u32 word;
 140        }params;
 141
 142        volatile u32 nextTxDescPtr;
 143
 144        volatile u32 TxDataPtr;
 145
 146        volatile u32 C                  :1;
 147        volatile u32 reserved3          :31;
 148
 149} inca_tx_descriptor_t;
 150
 151
 152static inca_rx_descriptor_t rx_ring[NUM_RX_DESC] __attribute__ ((aligned(16)));
 153static inca_tx_descriptor_t tx_ring[NUM_TX_DESC] __attribute__ ((aligned(16)));
 154
 155static int tx_new, rx_new, tx_hold, rx_hold;
 156static int tx_old_hold = -1;
 157static int initialized  = 0;
 158
 159
 160static int inca_switch_init(struct eth_device *dev, bd_t * bis);
 161static int inca_switch_send(struct eth_device *dev, void *packet, int length);
 162static int inca_switch_recv(struct eth_device *dev);
 163static void inca_switch_halt(struct eth_device *dev);
 164static void inca_init_switch_chip(void);
 165static void inca_dma_init(void);
 166static int inca_amdix(void);
 167
 168
 169int inca_switch_initialize(bd_t * bis)
 170{
 171        struct eth_device *dev;
 172
 173#if 0
 174        printf("Entered inca_switch_initialize()\n");
 175#endif
 176
 177        if (!(dev = (struct eth_device *) malloc (sizeof *dev))) {
 178                printf("Failed to allocate memory\n");
 179                return 0;
 180        }
 181        memset(dev, 0, sizeof(*dev));
 182
 183        inca_dma_init();
 184
 185        inca_init_switch_chip();
 186
 187#if defined(CONFIG_INCA_IP_SWITCH_AMDIX)
 188        inca_amdix();
 189#endif
 190
 191        sprintf(dev->name, "INCA-IP Switch");
 192        dev->init = inca_switch_init;
 193        dev->halt = inca_switch_halt;
 194        dev->send = inca_switch_send;
 195        dev->recv = inca_switch_recv;
 196
 197        eth_register(dev);
 198
 199#if 0
 200        printf("Leaving inca_switch_initialize()\n");
 201#endif
 202
 203        return 0;
 204}
 205
 206
 207static int inca_switch_init(struct eth_device *dev, bd_t * bis)
 208{
 209        int i;
 210        u32 v, regValue;
 211        u16 wTmp;
 212
 213#if 0
 214        printf("Entering inca_switch_init()\n");
 215#endif
 216
 217        /* Set MAC address.
 218         */
 219        wTmp = (u16)dev->enetaddr[0];
 220        regValue = (wTmp << 8) | dev->enetaddr[1];
 221
 222        SW_WRITE_REG(INCA_IP_Switch_PMAC_SA1, regValue);
 223
 224        wTmp = (u16)dev->enetaddr[2];
 225        regValue = (wTmp << 8) | dev->enetaddr[3];
 226        regValue = regValue << 16;
 227        wTmp = (u16)dev->enetaddr[4];
 228        regValue |= (wTmp<<8) | dev->enetaddr[5];
 229
 230        SW_WRITE_REG(INCA_IP_Switch_PMAC_SA2, regValue);
 231
 232        /* Initialize the descriptor rings.
 233         */
 234        for (i = 0; i < NUM_RX_DESC; i++) {
 235                inca_rx_descriptor_t * rx_desc = (inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[i]);
 236                memset(rx_desc, 0, sizeof(rx_ring[i]));
 237
 238                /* Set maximum size of receive buffer.
 239                 */
 240                rx_desc->params.field.NFB = PKTSIZE_ALIGN;
 241
 242                /* Set the offset of the receive buffer. Zero means
 243                 * that the offset mechanism is not used.
 244                 */
 245                rx_desc->params.field.offset = 0;
 246
 247                /* Check if it is the last descriptor.
 248                 */
 249                if (i == (NUM_RX_DESC - 1)) {
 250                        /* Let the last descriptor point to the first
 251                         * one.
 252                         */
 253                        rx_desc->nextRxDescPtr = (u32)CKSEG1ADDR(rx_ring);
 254                } else {
 255                        /* Set the address of the next descriptor.
 256                         */
 257                        rx_desc->nextRxDescPtr = (u32)CKSEG1ADDR(&rx_ring[i+1]);
 258                }
 259
 260                rx_desc->RxDataPtr = (u32)CKSEG1ADDR(NetRxPackets[i]);
 261        }
 262
 263#if 0
 264        printf("rx_ring = 0x%08X 0x%08X\n", (u32)rx_ring, (u32)&rx_ring[0]);
 265        printf("tx_ring = 0x%08X 0x%08X\n", (u32)tx_ring, (u32)&tx_ring[0]);
 266#endif
 267
 268        for (i = 0; i < NUM_TX_DESC; i++) {
 269                inca_tx_descriptor_t * tx_desc = (inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[i]);
 270
 271                memset(tx_desc, 0, sizeof(tx_ring[i]));
 272
 273                tx_desc->params.word       = 0;
 274                tx_desc->params.field.HOLD = 1;
 275                tx_desc->C                 = 1;
 276
 277                        /* Check if it is the last descriptor.
 278                         */
 279                if (i == (NUM_TX_DESC - 1)) {
 280                                /* Let the last descriptor point to the
 281                                 * first one.
 282                                 */
 283                        tx_desc->nextTxDescPtr = (u32)CKSEG1ADDR(tx_ring);
 284                } else {
 285                                /* Set the address of the next descriptor.
 286                                 */
 287                        tx_desc->nextTxDescPtr = (u32)CKSEG1ADDR(&tx_ring[i+1]);
 288                }
 289        }
 290
 291        /* Initialize RxDMA.
 292         */
 293        DMA_READ_REG(INCA_IP_DMA_DMA_RXISR, v);
 294        debug("RX status = 0x%08X\n", v);
 295
 296        /* Writing to the FRDA of CHANNEL.
 297         */
 298        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring);
 299
 300        /* Writing to the COMMAND REG.
 301         */
 302        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_INIT);
 303
 304        /* Initialize TxDMA.
 305         */
 306        DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v);
 307        debug("TX status = 0x%08X\n", v);
 308
 309        /* Writing to the FRDA of CHANNEL.
 310         */
 311        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXFRDA0, (u32)tx_ring);
 312
 313        tx_new = rx_new = 0;
 314
 315        tx_hold = NUM_TX_DESC - 1;
 316        rx_hold = NUM_RX_DESC - 1;
 317
 318#if 0
 319        rx_ring[rx_hold].params.field.HOLD = 1;
 320#endif
 321        /* enable spanning tree forwarding, enable the CPU port */
 322        /* ST_PT:
 323         *      CPS (CPU port status)   0x3 (forwarding)
 324         *      LPS (LAN port status)   0x3 (forwarding)
 325         *      PPS (PC port status)    0x3 (forwarding)
 326         */
 327        SW_WRITE_REG(INCA_IP_Switch_ST_PT,0x3f);
 328
 329#if 0
 330        printf("Leaving inca_switch_init()\n");
 331#endif
 332
 333        return 0;
 334}
 335
 336
 337static int inca_switch_send(struct eth_device *dev, void *packet, int length)
 338{
 339        int                    i;
 340        int                    res      = -1;
 341        u32                    command;
 342        u32                    regValue;
 343        inca_tx_descriptor_t * tx_desc  = (inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_new]);
 344
 345#if 0
 346        printf("Entered inca_switch_send()\n");
 347#endif
 348
 349        if (length <= 0) {
 350                printf ("%s: bad packet size: %d\n", dev->name, length);
 351                goto Done;
 352        }
 353
 354        for(i = 0; tx_desc->C == 0; i++) {
 355                if (i >= TOUT_LOOP) {
 356                        printf("%s: tx error buffer not ready\n", dev->name);
 357                        goto Done;
 358                }
 359        }
 360
 361        if (tx_old_hold >= 0) {
 362                ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_old_hold]))->params.field.HOLD = 1;
 363        }
 364        tx_old_hold = tx_hold;
 365
 366        tx_desc->params.word =
 367                        (INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD);
 368
 369        tx_desc->C = 0;
 370        tx_desc->TxDataPtr = (u32)packet;
 371        tx_desc->params.field.NBA = length;
 372
 373        ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_hold]))->params.field.HOLD = 0;
 374
 375        tx_hold = tx_new;
 376        tx_new  = (tx_new + 1) % NUM_TX_DESC;
 377
 378
 379        if (! initialized) {
 380                command = INCA_IP_DMA_DMA_TXCCR0_INIT;
 381                initialized = 1;
 382        } else {
 383                command = INCA_IP_DMA_DMA_TXCCR0_HR;
 384        }
 385
 386        DMA_READ_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
 387        regValue |= command;
 388#if 0
 389        printf("regValue = 0x%x\n", regValue);
 390#endif
 391        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
 392
 393#if 1
 394        for(i = 0; ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_hold]))->C == 0; i++) {
 395                if (i >= TOUT_LOOP) {
 396                        printf("%s: tx buffer not ready\n", dev->name);
 397                        goto Done;
 398                }
 399        }
 400#endif
 401        res = length;
 402Done:
 403#if 0
 404        printf("Leaving inca_switch_send()\n");
 405#endif
 406        return res;
 407}
 408
 409
 410static int inca_switch_recv(struct eth_device *dev)
 411{
 412        int                    length  = 0;
 413        inca_rx_descriptor_t * rx_desc;
 414
 415#if 0
 416        printf("Entered inca_switch_recv()\n");
 417#endif
 418
 419        for (;;) {
 420                rx_desc = (inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[rx_new]);
 421
 422                if (rx_desc->status.field.C == 0) {
 423                        break;
 424                }
 425
 426#if 0
 427                rx_ring[rx_new].params.field.HOLD = 1;
 428#endif
 429
 430                if (! rx_desc->status.field.Eop) {
 431                        printf("Partly received packet!!!\n");
 432                        break;
 433                }
 434
 435                length = rx_desc->status.field.NBT;
 436                rx_desc->status.word &=
 437                         ~(INCA_DMA_RX_EOP | INCA_DMA_RX_SOP | INCA_DMA_RX_C);
 438#if 0
 439{
 440  int i;
 441  for (i=0;i<length - 4;i++) {
 442    if (i % 16 == 0) printf("\n%04x: ", i);
 443    printf("%02X ", NetRxPackets[rx_new][i]);
 444  }
 445  printf("\n");
 446}
 447#endif
 448
 449                if (length) {
 450#if 0
 451                        printf("Received %d bytes\n", length);
 452#endif
 453                        NetReceive((void*)CKSEG1ADDR(NetRxPackets[rx_new]), length - 4);
 454                } else {
 455#if 1
 456                        printf("Zero length!!!\n");
 457#endif
 458                }
 459
 460
 461                ((inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[rx_hold]))->params.field.HOLD = 0;
 462
 463                rx_hold = rx_new;
 464
 465                rx_new = (rx_new + 1) % NUM_RX_DESC;
 466        }
 467
 468#if 0
 469        printf("Leaving inca_switch_recv()\n");
 470#endif
 471
 472        return length;
 473}
 474
 475
 476static void inca_switch_halt(struct eth_device *dev)
 477{
 478#if 0
 479        printf("Entered inca_switch_halt()\n");
 480#endif
 481
 482#if 1
 483        initialized = 0;
 484#endif
 485#if 1
 486        /* Disable forwarding to the CPU port.
 487         */
 488        SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
 489
 490        /* Close RxDMA channel.
 491         */
 492        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
 493
 494        /* Close TxDMA channel.
 495         */
 496        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_TXCCR0_OFF);
 497
 498
 499#endif
 500#if 0
 501        printf("Leaving inca_switch_halt()\n");
 502#endif
 503}
 504
 505
 506static void inca_init_switch_chip(void)
 507{
 508        u32 regValue;
 509
 510        /* To workaround a problem with collision counter
 511         * (see Errata sheet).
 512         */
 513        SW_WRITE_REG(INCA_IP_Switch_PC_TX_CTL, 0x00000001);
 514        SW_WRITE_REG(INCA_IP_Switch_LAN_TX_CTL, 0x00000001);
 515
 516#if 1
 517        /* init MDIO configuration:
 518         *      MDS (Poll speed):       0x01 (4ms)
 519         *      PHY_LAN_ADDR:           0x06
 520         *      PHY_PC_ADDR:            0x05
 521         *      UEP (Use External PHY): 0x00 (Internal PHY is used)
 522         *      PS (Port Select):       0x00 (PT/UMM for LAN)
 523         *      PT (PHY Test):          0x00 (no test mode)
 524         *      UMM (Use MDIO Mode):    0x00 (state machine is disabled)
 525         */
 526        SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50);
 527
 528        /* init PHY:
 529         *      SL (Auto Neg. Speed for LAN)
 530         *      SP (Auto Neg. Speed for PC)
 531         *      LL (Link Status for LAN)
 532         *      LP (Link Status for PC)
 533         *      DL (Duplex Status for LAN)
 534         *      DP (Duplex Status for PC)
 535         *      PL (Auto Neg. Pause Status for LAN)
 536         *      PP (Auto Neg. Pause Status for PC)
 537         */
 538        SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff);
 539
 540        /* MDIO_ACC:
 541         *      RA (Request/Ack)  0x01 (Request)
 542         *      RW (Read/Write)   0x01 (Write)
 543         *      PHY_ADDR          0x05 (PC)
 544         *      REG_ADDR          0x00 (PHY_BCR: basic control register)
 545         *      PHY_DATA          0x8000
 546         *                    Reset                   - software reset
 547         *                    LB (loop back)          - normal
 548         *                    SS (speed select)       - 10 Mbit/s
 549         *                    ANE (auto neg. enable)  - enable
 550         *                    PD (power down)         - normal
 551         *                    ISO (isolate)           - normal
 552         *                    RAN (restart auto neg.) - normal
 553         *                    DM (duplex mode)        - half duplex
 554         *                    CT (collision test)     - enable
 555         */
 556        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0a09000);
 557
 558        /* MDIO_ACC:
 559         *      RA (Request/Ack)  0x01 (Request)
 560         *      RW (Read/Write)   0x01 (Write)
 561         *      PHY_ADDR          0x06 (LAN)
 562         *      REG_ADDR          0x00 (PHY_BCR: basic control register)
 563         *      PHY_DATA          0x8000
 564         *                    Reset                   - software reset
 565         *                    LB (loop back)          - normal
 566         *                    SS (speed select)       - 10 Mbit/s
 567         *                    ANE (auto neg. enable)  - enable
 568         *                    PD (power down)         - normal
 569         *                    ISO (isolate)           - normal
 570         *                    RAN (restart auto neg.) - normal
 571         *                    DM (duplex mode)        - half duplex
 572         *                    CT (collision test)     - enable
 573         */
 574        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0c09000);
 575
 576#endif
 577
 578        /* Make sure the CPU port is disabled for now. We
 579         * don't want packets to get stacked for us until
 580         * we enable DMA and are prepared to receive them.
 581         */
 582        SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
 583
 584        SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue);
 585
 586        /* CRC GEN is enabled.
 587         */
 588        regValue |= 0x00000200;
 589        SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue);
 590
 591        /* ADD TAG is disabled.
 592         */
 593        SW_READ_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
 594        regValue &= ~0x00000002;
 595        SW_WRITE_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
 596}
 597
 598
 599static void inca_dma_init(void)
 600{
 601        /* Switch off all DMA channels.
 602         */
 603        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
 604        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR1, INCA_IP_DMA_DMA_RXCCR1_OFF);
 605
 606        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
 607        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR1, INCA_IP_DMA_DMA_TXCCR1_OFF);
 608        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR2, INCA_IP_DMA_DMA_TXCCR2_OFF);
 609
 610        /* Setup TX channel polling time.
 611         */
 612        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME);
 613
 614        /* Setup RX channel polling time.
 615         */
 616        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME);
 617
 618        /* ERRATA: write reset value into the DMA RX IMR register.
 619         */
 620        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF);
 621
 622        /* Just in case: disable all transmit interrupts also.
 623         */
 624        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXIMR, 0xFFFFFFFF);
 625
 626        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXISR, 0xFFFFFFFF);
 627        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXISR, 0xFFFFFFFF);
 628}
 629
 630#if defined(CONFIG_INCA_IP_SWITCH_AMDIX)
 631static int inca_amdix(void)
 632{
 633        u32 phyReg1 = 0;
 634        u32 phyReg4 = 0;
 635        u32 phyReg5 = 0;
 636        u32 phyReg6 = 0;
 637        u32 phyReg31 = 0;
 638        u32 regEphy = 0;
 639        int mdi_flag;
 640        int retries;
 641
 642        /* Setup GPIO pins.
 643         */
 644        *INCA_IP_AUTO_MDIX_LAN_PORTS_DIR    |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 645        *INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 646
 647#if 0
 648        /* Wait for signal.
 649         */
 650        retries = WAIT_SIGNAL_RETRIES;
 651        while (--retries) {
 652                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 653                                (0x1 << 31) |   /* RA           */
 654                                (0x0 << 30) |   /* Read         */
 655                                (0x6 << 21) |   /* LAN          */
 656                                (17  << 16));   /* PHY_MCSR     */
 657                do {
 658                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
 659                } while (phyReg1 & (1 << 31));
 660
 661                if (phyReg1 & (1 << 1)) {
 662                        /* Signal detected */
 663                        break;
 664                }
 665        }
 666
 667        if (!retries)
 668                goto Fail;
 669#endif
 670
 671        /* Set MDI mode.
 672         */
 673        *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 674        mdi_flag = 1;
 675
 676        /* Wait for link.
 677         */
 678        retries = WAIT_LINK_RETRIES;
 679        while (--retries) {
 680                udelay(LINK_RETRY_DELAY * 1000);
 681                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 682                                (0x1 << 31) |   /* RA           */
 683                                (0x0 << 30) |   /* Read         */
 684                                (0x6 << 21) |   /* LAN          */
 685                                (1   << 16));   /* PHY_BSR      */
 686                do {
 687                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
 688                } while (phyReg1 & (1 << 31));
 689
 690                if (phyReg1 & (1 << 2)) {
 691                        /* Link is up */
 692                        break;
 693                } else if (mdi_flag) {
 694                        /* Set MDIX mode */
 695                        *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 696                        mdi_flag = 0;
 697                } else {
 698                        /* Set MDI mode */
 699                        *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 700                        mdi_flag = 1;
 701                }
 702        }
 703
 704        if (!retries) {
 705                goto Fail;
 706        } else {
 707                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 708                                (0x1 << 31) |   /* RA           */
 709                                (0x0 << 30) |   /* Read         */
 710                                (0x6 << 21) |   /* LAN          */
 711                                (1   << 16));   /* PHY_BSR      */
 712                do {
 713                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
 714                } while (phyReg1 & (1 << 31));
 715
 716                /* Auto-negotiation / Parallel detection complete
 717                 */
 718                if (phyReg1 & (1 << 5)) {
 719                        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 720                                (0x1 << 31) |   /* RA           */
 721                                (0x0 << 30) |   /* Read         */
 722                                (0x6 << 21) |   /* LAN          */
 723                                (31  << 16));   /* PHY_SCSR     */
 724                        do {
 725                                SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg31);
 726                        } while (phyReg31 & (1 << 31));
 727
 728                        switch ((phyReg31 >> 2) & 0x7) {
 729                        case INCA_SWITCH_PHY_SPEED_10H:
 730                                /* 10Base-T Half-duplex */
 731                                regEphy = 0;
 732                                break;
 733                        case INCA_SWITCH_PHY_SPEED_10F:
 734                                /* 10Base-T Full-duplex */
 735                                regEphy = INCA_IP_Switch_EPHY_DL;
 736                                break;
 737                        case INCA_SWITCH_PHY_SPEED_100H:
 738                                /* 100Base-TX Half-duplex */
 739                                regEphy = INCA_IP_Switch_EPHY_SL;
 740                                break;
 741                        case INCA_SWITCH_PHY_SPEED_100F:
 742                                /* 100Base-TX Full-duplex */
 743                                regEphy = INCA_IP_Switch_EPHY_SL | INCA_IP_Switch_EPHY_DL;
 744                                break;
 745                        }
 746
 747                        /* In case of Auto-negotiation,
 748                         * update the negotiated PAUSE support status
 749                         */
 750                        if (phyReg1 & (1 << 3)) {
 751                                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 752                                        (0x1 << 31) |   /* RA           */
 753                                        (0x0 << 30) |   /* Read         */
 754                                        (0x6 << 21) |   /* LAN          */
 755                                        (6   << 16));   /* MII_EXPANSION        */
 756                                do {
 757                                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg6);
 758                                } while (phyReg6 & (1 << 31));
 759
 760                                /* We are Autoneg-able.
 761                                 * Is Link partner also able to autoneg?
 762                                 */
 763                                if (phyReg6 & (1 << 0)) {
 764                                        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 765                                                (0x1 << 31) |   /* RA           */
 766                                                (0x0 << 30) |   /* Read         */
 767                                                (0x6 << 21) |   /* LAN          */
 768                                                (4   << 16));   /* MII_ADVERTISE        */
 769                                        do {
 770                                                SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg4);
 771                                        } while (phyReg4 & (1 << 31));
 772
 773                                        /* We advertise PAUSE capab.
 774                                         * Does link partner also advertise it?
 775                                         */
 776                                        if (phyReg4 & (1 << 10)) {
 777                                                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 778                                                        (0x1 << 31) |   /* RA           */
 779                                                        (0x0 << 30) |   /* Read         */
 780                                                        (0x6 << 21) |   /* LAN          */
 781                                                        (5   << 16));   /* MII_LPA      */
 782                                                do {
 783                                                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg5);
 784                                                } while (phyReg5 & (1 << 31));
 785
 786                                                /* Link partner is PAUSE capab.
 787                                                 */
 788                                                if (phyReg5 & (1 << 10)) {
 789                                                        regEphy |= INCA_IP_Switch_EPHY_PL;
 790                                                }
 791                                        }
 792                                }
 793
 794                        }
 795
 796                        /* Link is up */
 797                        regEphy |= INCA_IP_Switch_EPHY_LL;
 798
 799                        SW_WRITE_REG(INCA_IP_Switch_EPHY, regEphy);
 800                }
 801        }
 802
 803        return 0;
 804
 805Fail:
 806        printf("No Link on LAN port\n");
 807        return -1;
 808}
 809#endif /* CONFIG_INCA_IP_SWITCH_AMDIX */
 810