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