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