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, volatile 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#if 0
 295        printf("RX status = 0x%08X\n", v);
 296#endif
 297
 298        /* Writing to the FRDA of CHANNEL.
 299         */
 300        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring);
 301
 302        /* Writing to the COMMAND REG.
 303         */
 304        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_INIT);
 305
 306        /* Initialize TxDMA.
 307         */
 308        DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v);
 309#if 0
 310        printf("TX status = 0x%08X\n", v);
 311#endif
 312
 313        /* Writing to the FRDA of CHANNEL.
 314         */
 315        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXFRDA0, (u32)tx_ring);
 316
 317        tx_new = rx_new = 0;
 318
 319        tx_hold = NUM_TX_DESC - 1;
 320        rx_hold = NUM_RX_DESC - 1;
 321
 322#if 0
 323        rx_ring[rx_hold].params.field.HOLD = 1;
 324#endif
 325        /* enable spanning tree forwarding, enable the CPU port */
 326        /* ST_PT:
 327         *      CPS (CPU port status)   0x3 (forwarding)
 328         *      LPS (LAN port status)   0x3 (forwarding)
 329         *      PPS (PC port status)    0x3 (forwarding)
 330         */
 331        SW_WRITE_REG(INCA_IP_Switch_ST_PT,0x3f);
 332
 333#if 0
 334        printf("Leaving inca_switch_init()\n");
 335#endif
 336
 337        return 0;
 338}
 339
 340
 341static int inca_switch_send(struct eth_device *dev, volatile void *packet, int length)
 342{
 343        int                    i;
 344        int                    res      = -1;
 345        u32                    command;
 346        u32                    regValue;
 347        inca_tx_descriptor_t * tx_desc  = (inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_new]);
 348
 349#if 0
 350        printf("Entered inca_switch_send()\n");
 351#endif
 352
 353        if (length <= 0) {
 354                printf ("%s: bad packet size: %d\n", dev->name, length);
 355                goto Done;
 356        }
 357
 358        for(i = 0; tx_desc->C == 0; i++) {
 359                if (i >= TOUT_LOOP) {
 360                        printf("%s: tx error buffer not ready\n", dev->name);
 361                        goto Done;
 362                }
 363        }
 364
 365        if (tx_old_hold >= 0) {
 366                ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_old_hold]))->params.field.HOLD = 1;
 367        }
 368        tx_old_hold = tx_hold;
 369
 370        tx_desc->params.word =
 371                        (INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD);
 372
 373        tx_desc->C = 0;
 374        tx_desc->TxDataPtr = (u32)packet;
 375        tx_desc->params.field.NBA = length;
 376
 377        ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_hold]))->params.field.HOLD = 0;
 378
 379        tx_hold = tx_new;
 380        tx_new  = (tx_new + 1) % NUM_TX_DESC;
 381
 382
 383        if (! initialized) {
 384                command = INCA_IP_DMA_DMA_TXCCR0_INIT;
 385                initialized = 1;
 386        } else {
 387                command = INCA_IP_DMA_DMA_TXCCR0_HR;
 388        }
 389
 390        DMA_READ_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
 391        regValue |= command;
 392#if 0
 393        printf("regValue = 0x%x\n", regValue);
 394#endif
 395        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
 396
 397#if 1
 398        for(i = 0; ((inca_tx_descriptor_t *)CKSEG1ADDR(&tx_ring[tx_hold]))->C == 0; i++) {
 399                if (i >= TOUT_LOOP) {
 400                        printf("%s: tx buffer not ready\n", dev->name);
 401                        goto Done;
 402                }
 403        }
 404#endif
 405        res = length;
 406Done:
 407#if 0
 408        printf("Leaving inca_switch_send()\n");
 409#endif
 410        return res;
 411}
 412
 413
 414static int inca_switch_recv(struct eth_device *dev)
 415{
 416        int                    length  = 0;
 417        inca_rx_descriptor_t * rx_desc;
 418
 419#if 0
 420        printf("Entered inca_switch_recv()\n");
 421#endif
 422
 423        for (;;) {
 424                rx_desc = (inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[rx_new]);
 425
 426                if (rx_desc->status.field.C == 0) {
 427                        break;
 428                }
 429
 430#if 0
 431                rx_ring[rx_new].params.field.HOLD = 1;
 432#endif
 433
 434                if (! rx_desc->status.field.Eop) {
 435                        printf("Partly received packet!!!\n");
 436                        break;
 437                }
 438
 439                length = rx_desc->status.field.NBT;
 440                rx_desc->status.word &=
 441                         ~(INCA_DMA_RX_EOP | INCA_DMA_RX_SOP | INCA_DMA_RX_C);
 442#if 0
 443{
 444  int i;
 445  for (i=0;i<length - 4;i++) {
 446    if (i % 16 == 0) printf("\n%04x: ", i);
 447    printf("%02X ", NetRxPackets[rx_new][i]);
 448  }
 449  printf("\n");
 450}
 451#endif
 452
 453                if (length) {
 454#if 0
 455                        printf("Received %d bytes\n", length);
 456#endif
 457                        NetReceive((void*)CKSEG1ADDR(NetRxPackets[rx_new]), length - 4);
 458                } else {
 459#if 1
 460                        printf("Zero length!!!\n");
 461#endif
 462                }
 463
 464
 465                ((inca_rx_descriptor_t *)CKSEG1ADDR(&rx_ring[rx_hold]))->params.field.HOLD = 0;
 466
 467                rx_hold = rx_new;
 468
 469                rx_new = (rx_new + 1) % NUM_RX_DESC;
 470        }
 471
 472#if 0
 473        printf("Leaving inca_switch_recv()\n");
 474#endif
 475
 476        return length;
 477}
 478
 479
 480static void inca_switch_halt(struct eth_device *dev)
 481{
 482#if 0
 483        printf("Entered inca_switch_halt()\n");
 484#endif
 485
 486#if 1
 487        initialized = 0;
 488#endif
 489#if 1
 490        /* Disable forwarding to the CPU port.
 491         */
 492        SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
 493
 494        /* Close RxDMA channel.
 495         */
 496        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
 497
 498        /* Close TxDMA channel.
 499         */
 500        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_TXCCR0_OFF);
 501
 502
 503#endif
 504#if 0
 505        printf("Leaving inca_switch_halt()\n");
 506#endif
 507}
 508
 509
 510static void inca_init_switch_chip(void)
 511{
 512        u32 regValue;
 513
 514        /* To workaround a problem with collision counter
 515         * (see Errata sheet).
 516         */
 517        SW_WRITE_REG(INCA_IP_Switch_PC_TX_CTL, 0x00000001);
 518        SW_WRITE_REG(INCA_IP_Switch_LAN_TX_CTL, 0x00000001);
 519
 520#if 1
 521        /* init MDIO configuration:
 522         *      MDS (Poll speed):       0x01 (4ms)
 523         *      PHY_LAN_ADDR:           0x06
 524         *      PHY_PC_ADDR:            0x05
 525         *      UEP (Use External PHY): 0x00 (Internal PHY is used)
 526         *      PS (Port Select):       0x00 (PT/UMM for LAN)
 527         *      PT (PHY Test):          0x00 (no test mode)
 528         *      UMM (Use MDIO Mode):    0x00 (state machine is disabled)
 529         */
 530        SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50);
 531
 532        /* init PHY:
 533         *      SL (Auto Neg. Speed for LAN)
 534         *      SP (Auto Neg. Speed for PC)
 535         *      LL (Link Status for LAN)
 536         *      LP (Link Status for PC)
 537         *      DL (Duplex Status for LAN)
 538         *      DP (Duplex Status for PC)
 539         *      PL (Auto Neg. Pause Status for LAN)
 540         *      PP (Auto Neg. Pause Status for PC)
 541         */
 542        SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff);
 543
 544        /* MDIO_ACC:
 545         *      RA (Request/Ack)  0x01 (Request)
 546         *      RW (Read/Write)   0x01 (Write)
 547         *      PHY_ADDR          0x05 (PC)
 548         *      REG_ADDR          0x00 (PHY_BCR: basic control register)
 549         *      PHY_DATA          0x8000
 550         *                    Reset                   - software reset
 551         *                    LB (loop back)          - normal
 552         *                    SS (speed select)       - 10 Mbit/s
 553         *                    ANE (auto neg. enable)  - enable
 554         *                    PD (power down)         - normal
 555         *                    ISO (isolate)           - normal
 556         *                    RAN (restart auto neg.) - normal
 557         *                    DM (duplex mode)        - half duplex
 558         *                    CT (collision test)     - enable
 559         */
 560        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0a09000);
 561
 562        /* MDIO_ACC:
 563         *      RA (Request/Ack)  0x01 (Request)
 564         *      RW (Read/Write)   0x01 (Write)
 565         *      PHY_ADDR          0x06 (LAN)
 566         *      REG_ADDR          0x00 (PHY_BCR: basic control register)
 567         *      PHY_DATA          0x8000
 568         *                    Reset                   - software reset
 569         *                    LB (loop back)          - normal
 570         *                    SS (speed select)       - 10 Mbit/s
 571         *                    ANE (auto neg. enable)  - enable
 572         *                    PD (power down)         - normal
 573         *                    ISO (isolate)           - normal
 574         *                    RAN (restart auto neg.) - normal
 575         *                    DM (duplex mode)        - half duplex
 576         *                    CT (collision test)     - enable
 577         */
 578        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0c09000);
 579
 580#endif
 581
 582        /* Make sure the CPU port is disabled for now. We
 583         * don't want packets to get stacked for us until
 584         * we enable DMA and are prepared to receive them.
 585         */
 586        SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
 587
 588        SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue);
 589
 590        /* CRC GEN is enabled.
 591         */
 592        regValue |= 0x00000200;
 593        SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue);
 594
 595        /* ADD TAG is disabled.
 596         */
 597        SW_READ_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
 598        regValue &= ~0x00000002;
 599        SW_WRITE_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
 600}
 601
 602
 603static void inca_dma_init(void)
 604{
 605        /* Switch off all DMA channels.
 606         */
 607        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
 608        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR1, INCA_IP_DMA_DMA_RXCCR1_OFF);
 609
 610        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
 611        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR1, INCA_IP_DMA_DMA_TXCCR1_OFF);
 612        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR2, INCA_IP_DMA_DMA_TXCCR2_OFF);
 613
 614        /* Setup TX channel polling time.
 615         */
 616        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME);
 617
 618        /* Setup RX channel polling time.
 619         */
 620        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME);
 621
 622        /* ERRATA: write reset value into the DMA RX IMR register.
 623         */
 624        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF);
 625
 626        /* Just in case: disable all transmit interrupts also.
 627         */
 628        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXIMR, 0xFFFFFFFF);
 629
 630        DMA_WRITE_REG(INCA_IP_DMA_DMA_TXISR, 0xFFFFFFFF);
 631        DMA_WRITE_REG(INCA_IP_DMA_DMA_RXISR, 0xFFFFFFFF);
 632}
 633
 634#if defined(CONFIG_INCA_IP_SWITCH_AMDIX)
 635static int inca_amdix(void)
 636{
 637        u32 phyReg1 = 0;
 638        u32 phyReg4 = 0;
 639        u32 phyReg5 = 0;
 640        u32 phyReg6 = 0;
 641        u32 phyReg31 = 0;
 642        u32 regEphy = 0;
 643        int mdi_flag;
 644        int retries;
 645
 646        /* Setup GPIO pins.
 647         */
 648        *INCA_IP_AUTO_MDIX_LAN_PORTS_DIR    |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 649        *INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 650
 651#if 0
 652        /* Wait for signal.
 653         */
 654        retries = WAIT_SIGNAL_RETRIES;
 655        while (--retries) {
 656                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 657                                (0x1 << 31) |   /* RA           */
 658                                (0x0 << 30) |   /* Read         */
 659                                (0x6 << 21) |   /* LAN          */
 660                                (17  << 16));   /* PHY_MCSR     */
 661                do {
 662                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
 663                } while (phyReg1 & (1 << 31));
 664
 665                if (phyReg1 & (1 << 1)) {
 666                        /* Signal detected */
 667                        break;
 668                }
 669        }
 670
 671        if (!retries)
 672                goto Fail;
 673#endif
 674
 675        /* Set MDI mode.
 676         */
 677        *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 678        mdi_flag = 1;
 679
 680        /* Wait for link.
 681         */
 682        retries = WAIT_LINK_RETRIES;
 683        while (--retries) {
 684                udelay(LINK_RETRY_DELAY * 1000);
 685                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 686                                (0x1 << 31) |   /* RA           */
 687                                (0x0 << 30) |   /* Read         */
 688                                (0x6 << 21) |   /* LAN          */
 689                                (1   << 16));   /* PHY_BSR      */
 690                do {
 691                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
 692                } while (phyReg1 & (1 << 31));
 693
 694                if (phyReg1 & (1 << 2)) {
 695                        /* Link is up */
 696                        break;
 697                } else if (mdi_flag) {
 698                        /* Set MDIX mode */
 699                        *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 700                        mdi_flag = 0;
 701                } else {
 702                        /* Set MDI mode */
 703                        *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX);
 704                        mdi_flag = 1;
 705                }
 706        }
 707
 708        if (!retries) {
 709                goto Fail;
 710        } else {
 711                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 712                                (0x1 << 31) |   /* RA           */
 713                                (0x0 << 30) |   /* Read         */
 714                                (0x6 << 21) |   /* LAN          */
 715                                (1   << 16));   /* PHY_BSR      */
 716                do {
 717                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg1);
 718                } while (phyReg1 & (1 << 31));
 719
 720                /* Auto-negotiation / Parallel detection complete
 721                 */
 722                if (phyReg1 & (1 << 5)) {
 723                        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 724                                (0x1 << 31) |   /* RA           */
 725                                (0x0 << 30) |   /* Read         */
 726                                (0x6 << 21) |   /* LAN          */
 727                                (31  << 16));   /* PHY_SCSR     */
 728                        do {
 729                                SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg31);
 730                        } while (phyReg31 & (1 << 31));
 731
 732                        switch ((phyReg31 >> 2) & 0x7) {
 733                        case INCA_SWITCH_PHY_SPEED_10H:
 734                                /* 10Base-T Half-duplex */
 735                                regEphy = 0;
 736                                break;
 737                        case INCA_SWITCH_PHY_SPEED_10F:
 738                                /* 10Base-T Full-duplex */
 739                                regEphy = INCA_IP_Switch_EPHY_DL;
 740                                break;
 741                        case INCA_SWITCH_PHY_SPEED_100H:
 742                                /* 100Base-TX Half-duplex */
 743                                regEphy = INCA_IP_Switch_EPHY_SL;
 744                                break;
 745                        case INCA_SWITCH_PHY_SPEED_100F:
 746                                /* 100Base-TX Full-duplex */
 747                                regEphy = INCA_IP_Switch_EPHY_SL | INCA_IP_Switch_EPHY_DL;
 748                                break;
 749                        }
 750
 751                        /* In case of Auto-negotiation,
 752                         * update the negotiated PAUSE support status
 753                         */
 754                        if (phyReg1 & (1 << 3)) {
 755                                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 756                                        (0x1 << 31) |   /* RA           */
 757                                        (0x0 << 30) |   /* Read         */
 758                                        (0x6 << 21) |   /* LAN          */
 759                                        (6   << 16));   /* PHY_ANER     */
 760                                do {
 761                                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg6);
 762                                } while (phyReg6 & (1 << 31));
 763
 764                                /* We are Autoneg-able.
 765                                 * Is Link partner also able to autoneg?
 766                                 */
 767                                if (phyReg6 & (1 << 0)) {
 768                                        SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 769                                                (0x1 << 31) |   /* RA           */
 770                                                (0x0 << 30) |   /* Read         */
 771                                                (0x6 << 21) |   /* LAN          */
 772                                                (4   << 16));   /* PHY_ANAR     */
 773                                        do {
 774                                                SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg4);
 775                                        } while (phyReg4 & (1 << 31));
 776
 777                                        /* We advertise PAUSE capab.
 778                                         * Does link partner also advertise it?
 779                                         */
 780                                        if (phyReg4 & (1 << 10)) {
 781                                                SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC,
 782                                                        (0x1 << 31) |   /* RA           */
 783                                                        (0x0 << 30) |   /* Read         */
 784                                                        (0x6 << 21) |   /* LAN          */
 785                                                        (5   << 16));   /* PHY_ANLPAR   */
 786                                                do {
 787                                                        SW_READ_REG(INCA_IP_Switch_MDIO_ACC, phyReg5);
 788                                                } while (phyReg5 & (1 << 31));
 789
 790                                                /* Link partner is PAUSE capab.
 791                                                 */
 792                                                if (phyReg5 & (1 << 10)) {
 793                                                        regEphy |= INCA_IP_Switch_EPHY_PL;
 794                                                }
 795                                        }
 796                                }
 797
 798                        }
 799
 800                        /* Link is up */
 801                        regEphy |= INCA_IP_Switch_EPHY_LL;
 802
 803                        SW_WRITE_REG(INCA_IP_Switch_EPHY, regEphy);
 804                }
 805        }
 806
 807        return 0;
 808
 809Fail:
 810        printf("No Link on LAN port\n");
 811        return -1;
 812}
 813#endif /* CONFIG_INCA_IP_SWITCH_AMDIX */
 814