2 * INCA-IP internal switch ethernet driver.
5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7 * See file CREDITS for list of people who contributed to this
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.
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.
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,
29 #if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \
30 && defined(CONFIG_INCA_IP_SWITCH)
34 #include <asm/inca-ip.h>
35 #include <asm/addrspace.h>
38 #define NUM_RX_DESC PKTBUFSRX
40 #define TOUT_LOOP 1000000
43 #define DELAY udelay(10000)
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;\
50 *((volatile u32*)reg) = (u32)value;
52 #define SW_READ_REG(reg, value) \
53 value = (u32)*((volatile u32*)reg);\
55 value = (u32)*((volatile u32*)reg);
57 #define INCA_DMA_TX_POLLING_TIME 0x07
58 #define INCA_DMA_RX_POLLING_TIME 0x07
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
66 #define INCA_DMA_RX_C 0x80000000
67 #define INCA_DMA_RX_SOP 0x40000000
68 #define INCA_DMA_RX_EOP 0x20000000
80 volatile u32 offset :3;
81 volatile u32 reserved0 :4;
88 volatile u32 nextRxDescPtr;
90 volatile u32 RxDataPtr;
99 volatile u32 reserved3 :12;
100 volatile u32 NBT :17;
106 } inca_rx_descriptor_t;
115 volatile u32 HOLD :1;
118 volatile u32 ICpt :1;
119 volatile u32 IEop :1;
120 volatile u32 reserved0 :5;
121 volatile u32 NBA :22;
127 volatile u32 nextTxDescPtr;
129 volatile u32 TxDataPtr;
132 volatile u32 reserved3 :31;
134 } inca_tx_descriptor_t;
137 static inca_rx_descriptor_t rx_ring[NUM_RX_DESC] __attribute__ ((aligned(16)));
138 static inca_tx_descriptor_t tx_ring[NUM_TX_DESC] __attribute__ ((aligned(16)));
140 static int tx_new, rx_new, tx_hold, rx_hold;
141 static int tx_old_hold = -1;
142 static int initialized = 0;
145 static int inca_switch_init(struct eth_device *dev, bd_t * bis);
146 static int inca_switch_send(struct eth_device *dev, volatile void *packet,
148 static int inca_switch_recv(struct eth_device *dev);
149 static void inca_switch_halt(struct eth_device *dev);
150 static void inca_init_switch_chip(void);
151 static void inca_dma_init(void);
154 int inca_switch_initialize(bd_t * bis)
156 struct eth_device *dev;
159 printf("Entered inca_switch_initialize()\n");
162 if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
164 printf("Failed to allocate memory\n");
167 memset(dev, 0, sizeof(*dev));
171 inca_init_switch_chip();
173 sprintf(dev->name, "INCA-IP Switch");
174 dev->init = inca_switch_init;
175 dev->halt = inca_switch_halt;
176 dev->send = inca_switch_send;
177 dev->recv = inca_switch_recv;
182 printf("Leaving inca_switch_initialize()\n");
189 static int inca_switch_init(struct eth_device *dev, bd_t * bis)
196 printf("Entering inca_switch_init()\n");
201 wTmp = (u16)dev->enetaddr[0];
202 regValue = (wTmp << 8) | dev->enetaddr[1];
204 SW_WRITE_REG(INCA_IP_Switch_PMAC_SA1, regValue);
206 wTmp = (u16)dev->enetaddr[2];
207 regValue = (wTmp << 8) | dev->enetaddr[3];
208 regValue = regValue << 16;
209 wTmp = (u16)dev->enetaddr[4];
210 regValue |= (wTmp<<8) | dev->enetaddr[5];
212 SW_WRITE_REG(INCA_IP_Switch_PMAC_SA2, regValue);
214 /* Initialize the descriptor rings.
216 for (i = 0; i < NUM_RX_DESC; i++)
218 inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]);
219 memset(rx_desc, 0, sizeof(rx_ring[i]));
221 /* Set maximum size of receive buffer.
223 rx_desc->params.field.NFB = PKTSIZE_ALIGN;
225 /* Set the offset of the receive buffer. Zero means
226 * that the offset mechanism is not used.
228 rx_desc->params.field.offset = 0;
230 /* Check if it is the last descriptor.
232 if (i == (NUM_RX_DESC - 1))
234 /* Let the last descriptor point to the first
237 rx_desc->nextRxDescPtr = KSEG1ADDR((u32)rx_ring);
241 /* Set the address of the next descriptor.
243 rx_desc->nextRxDescPtr = (u32)KSEG1ADDR(&rx_ring[i+1]);
246 rx_desc->RxDataPtr = (u32)KSEG1ADDR(NetRxPackets[i]);
250 printf("rx_ring = 0x%08X 0x%08X\n", (u32)rx_ring, (u32)&rx_ring[0]);
251 printf("tx_ring = 0x%08X 0x%08X\n", (u32)tx_ring, (u32)&tx_ring[0]);
254 for (i = 0; i < NUM_TX_DESC; i++)
256 inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[i]);
258 memset(tx_desc, 0, sizeof(tx_ring[i]));
260 tx_desc->params.word = 0;
261 tx_desc->params.field.HOLD = 1;
264 /* Check if it is the last descriptor.
266 if (i == (NUM_TX_DESC - 1))
268 /* Let the last descriptor point to the
271 tx_desc->nextTxDescPtr = KSEG1ADDR((u32)tx_ring);
275 /* Set the address of the next descriptor.
277 tx_desc->nextTxDescPtr = (u32)KSEG1ADDR(&tx_ring[i+1]);
283 DMA_READ_REG(INCA_IP_DMA_DMA_RXISR, v);
285 printf("RX status = 0x%08X\n", v);
288 /* Writing to the FRDA of CHANNEL.
290 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring);
292 /* Writing to the COMMAND REG.
294 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0,
295 INCA_IP_DMA_DMA_RXCCR0_INIT);
299 DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v);
301 printf("TX status = 0x%08X\n", v);
304 /* Writing to the FRDA of CHANNEL.
306 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXFRDA0, (u32)tx_ring);
310 tx_hold = NUM_TX_DESC - 1;
311 rx_hold = NUM_RX_DESC - 1;
314 rx_ring[rx_hold].params.field.HOLD = 1;
316 /* enable spanning tree forwarding, enable the CPU port */
318 CPS (CPU port status) 0x3 (forwarding)
319 LPS (LAN port status) 0x3 (forwarding)
320 PPS (PC port status) 0x3 (forwarding)
322 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0x3f);
325 printf("Leaving inca_switch_init()\n");
332 static int inca_switch_send(struct eth_device *dev, volatile void *packet,
339 inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[tx_new]);
342 printf("Entered inca_switch_send()\n");
347 printf ("%s: bad packet size: %d\n", dev->name, length);
351 for(i = 0; tx_desc->C == 0; i++)
355 printf("%s: tx error buffer not ready\n", dev->name);
360 if (tx_old_hold >= 0)
362 KSEG1ADDR(&tx_ring[tx_old_hold])->params.field.HOLD = 1;
364 tx_old_hold = tx_hold;
366 tx_desc->params.word =
367 (INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD);
370 tx_desc->TxDataPtr = (u32)packet;
371 tx_desc->params.field.NBA = length;
373 KSEG1ADDR(&tx_ring[tx_hold])->params.field.HOLD = 0;
376 tx_new = (tx_new + 1) % NUM_TX_DESC;
381 command = INCA_IP_DMA_DMA_TXCCR0_INIT;
386 command = INCA_IP_DMA_DMA_TXCCR0_HR;
389 DMA_READ_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
392 printf("regValue = 0x%x\n", regValue);
394 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
397 for(i = 0; KSEG1ADDR(&tx_ring[tx_hold])->C == 0; i++)
401 printf("%s: tx buffer not ready\n", dev->name);
409 printf("Leaving inca_switch_send()\n");
415 static int inca_switch_recv(struct eth_device *dev)
418 inca_rx_descriptor_t * rx_desc;
421 printf("Entered inca_switch_recv()\n");
426 rx_desc = KSEG1ADDR(&rx_ring[rx_new]);
428 if (rx_desc->status.field.C == 0)
434 rx_ring[rx_new].params.field.HOLD = 1;
437 if (! rx_desc->status.field.Eop)
439 printf("Partly received packet!!!\n");
443 length = rx_desc->status.field.NBT;
444 rx_desc->status.word &=
445 ~(INCA_DMA_RX_EOP | INCA_DMA_RX_SOP | INCA_DMA_RX_C);
449 for (i=0;i<length - 4;i++) {
450 if (i % 16 == 0) printf("\n%04x: ", i);
451 printf("%02X ", NetRxPackets[rx_new][i]);
460 printf("Received %d bytes\n", length);
462 NetReceive((void*)KSEG1ADDR(NetRxPackets[rx_new]),
468 printf("Zero length!!!\n");
473 KSEG1ADDR(&rx_ring[rx_hold])->params.field.HOLD = 0;
477 rx_new = (rx_new + 1) % NUM_RX_DESC;
481 printf("Leaving inca_switch_recv()\n");
488 static void inca_switch_halt(struct eth_device *dev)
491 printf("Entered inca_switch_halt()\n");
498 /* Disable forwarding to the CPU port.
500 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
502 /* Close RxDMA channel.
504 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
506 /* Close TxDMA channel.
508 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_TXCCR0_OFF);
513 printf("Leaving inca_switch_halt()\n");
518 static void inca_init_switch_chip(void)
522 /* To workaround a problem with collision counter
523 * (see Errata sheet).
525 SW_WRITE_REG(INCA_IP_Switch_PC_TX_CTL, 0x00000001);
526 SW_WRITE_REG(INCA_IP_Switch_LAN_TX_CTL, 0x00000001);
529 /* init MDIO configuration:
530 MDS (Poll speed): 0x01 (4ms)
533 UEP (Use External PHY): 0x00 (Internal PHY is used)
534 PS (Port Select): 0x00 (PT/UMM for LAN)
535 PT (PHY Test): 0x00 (no test mode)
536 UMM (Use MDIO Mode): 0x00 (state machine is disabled)
538 SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50);
541 SL (Auto Neg. Speed for LAN)
542 SP (Auto Neg. Speed for PC)
543 LL (Link Status for LAN)
544 LP (Link Status for PC)
545 DL (Duplex Status for LAN)
546 DP (Duplex Status for PC)
547 PL (Auto Neg. Pause Status for LAN)
548 PP (Auto Neg. Pause Status for PC)
550 SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff);
553 RA (Request/Ack) 0x01 (Request)
554 RW (Read/Write) 0x01 (Write)
556 REG_ADDR 0x00 (PHY_BCR: basic control register)
558 Reset - software reset
559 LB (loop back) - normal
560 SS (speed select) - 10 Mbit/s
561 ANE (auto neg. enable) - disable
562 PD (power down) - normal
563 ISO (isolate) - normal
564 RAN (restart auto neg.) - normal
565 DM (duplex mode) - half duplex
566 CT (collision test) - enable
568 SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0a08000);
571 RA (Request/Ack) 0x01 (Request)
572 RW (Read/Write) 0x01 (Write)
574 REG_ADDR 0x00 (PHY_BCR: basic control register)
576 Reset - software reset
577 LB (loop back) - normal
578 SS (speed select) - 10 Mbit/s
579 ANE (auto neg. enable) - disable
580 PD (power down) - normal
581 ISO (isolate) - normal
582 RAN (restart auto neg.) - normal
583 DM (duplex mode) - half duplex
584 CT (collision test) - enable
586 SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0c08000);
589 /* Make sure the CPU port is disabled for now. We
590 * don't want packets to get stacked for us until
591 * we enable DMA and are prepared to receive them.
593 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
595 SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue);
597 /* CRC GEN is enabled.
599 regValue |= 0x00000200;
600 SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue);
602 /* ADD TAG is disabled.
604 SW_READ_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
605 regValue &= ~0x00000002;
606 SW_WRITE_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
610 static void inca_dma_init(void)
612 /* Switch off all DMA channels.
614 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
615 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR1, INCA_IP_DMA_DMA_RXCCR1_OFF);
617 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
618 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR1, INCA_IP_DMA_DMA_TXCCR1_OFF);
619 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR2, INCA_IP_DMA_DMA_TXCCR2_OFF);
621 /* Setup TX channel polling time.
623 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME);
625 /* Setup RX channel polling time.
627 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME);
629 /* ERRATA: write reset value into the DMA RX IMR register.
631 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF);
633 /* Just in case: disable all transmit interrupts also.
635 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXIMR, 0xFFFFFFFF);
637 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXISR, 0xFFFFFFFF);
638 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXISR, 0xFFFFFFFF);