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);
155 int inca_switch_initialize(bd_t * bis)
157 struct eth_device *dev;
160 printf("Entered inca_switch_initialize()\n");
163 if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
165 printf("Failed to allocate memory\n");
168 memset(dev, 0, sizeof(*dev));
172 inca_init_switch_chip();
174 sprintf(dev->name, "INCA-IP Switch");
175 dev->init = inca_switch_init;
176 dev->halt = inca_switch_halt;
177 dev->send = inca_switch_send;
178 dev->recv = inca_switch_recv;
183 printf("Leaving inca_switch_initialize()\n");
190 static int inca_switch_init(struct eth_device *dev, bd_t * bis)
197 printf("Entering inca_switch_init()\n");
202 wTmp = (u16)dev->enetaddr[0];
203 regValue = (wTmp << 8) | dev->enetaddr[1];
205 SW_WRITE_REG(INCA_IP_Switch_PMAC_SA1, regValue);
207 wTmp = (u16)dev->enetaddr[2];
208 regValue = (wTmp << 8) | dev->enetaddr[3];
209 regValue = regValue << 16;
210 wTmp = (u16)dev->enetaddr[4];
211 regValue |= (wTmp<<8) | dev->enetaddr[5];
213 SW_WRITE_REG(INCA_IP_Switch_PMAC_SA2, regValue);
215 /* Initialize the descriptor rings.
217 for (i = 0; i < NUM_RX_DESC; i++)
219 inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]);
220 memset(rx_desc, 0, sizeof(rx_ring[i]));
222 /* Set maximum size of receive buffer.
224 rx_desc->params.field.NFB = PKTSIZE_ALIGN;
226 /* Set the offset of the receive buffer. Zero means
227 * that the offset mechanism is not used.
229 rx_desc->params.field.offset = 0;
231 /* Check if it is the last descriptor.
233 if (i == (NUM_RX_DESC - 1))
235 /* Let the last descriptor point to the first
238 rx_desc->nextRxDescPtr = KSEG1ADDR((u32)rx_ring);
242 /* Set the address of the next descriptor.
244 rx_desc->nextRxDescPtr = (u32)KSEG1ADDR(&rx_ring[i+1]);
247 rx_desc->RxDataPtr = (u32)KSEG1ADDR(NetRxPackets[i]);
251 printf("rx_ring = 0x%08X 0x%08X\n", (u32)rx_ring, (u32)&rx_ring[0]);
252 printf("tx_ring = 0x%08X 0x%08X\n", (u32)tx_ring, (u32)&tx_ring[0]);
255 for (i = 0; i < NUM_TX_DESC; i++)
257 inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[i]);
259 memset(tx_desc, 0, sizeof(tx_ring[i]));
261 tx_desc->params.word = 0;
262 tx_desc->params.field.HOLD = 1;
265 /* Check if it is the last descriptor.
267 if (i == (NUM_TX_DESC - 1))
269 /* Let the last descriptor point to the
272 tx_desc->nextTxDescPtr = KSEG1ADDR((u32)tx_ring);
276 /* Set the address of the next descriptor.
278 tx_desc->nextTxDescPtr = (u32)KSEG1ADDR(&tx_ring[i+1]);
284 DMA_READ_REG(INCA_IP_DMA_DMA_RXISR, v);
286 printf("RX status = 0x%08X\n", v);
289 /* Writing to the FRDA of CHANNEL.
291 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring);
293 /* Writing to the COMMAND REG.
295 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0,
296 INCA_IP_DMA_DMA_RXCCR0_INIT);
300 DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v);
302 printf("TX status = 0x%08X\n", v);
305 /* Writing to the FRDA of CHANNEL.
307 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXFRDA0, (u32)tx_ring);
311 tx_hold = NUM_TX_DESC - 1;
312 rx_hold = NUM_RX_DESC - 1;
315 rx_ring[rx_hold].params.field.HOLD = 1;
317 /* enable spanning tree forwarding, enable the CPU port */
319 CPS (CPU port status) 0x3 (forwarding)
320 LPS (LAN port status) 0x3 (forwarding)
321 PPS (PC port status) 0x3 (forwarding)
323 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0x3f);
326 printf("Leaving inca_switch_init()\n");
333 static int inca_switch_send(struct eth_device *dev, volatile void *packet,
340 inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[tx_new]);
343 printf("Entered inca_switch_send()\n");
348 printf ("%s: bad packet size: %d\n", dev->name, length);
352 for(i = 0; tx_desc->C == 0; i++)
356 printf("%s: tx error buffer not ready\n", dev->name);
361 if (tx_old_hold >= 0)
363 KSEG1ADDR(&tx_ring[tx_old_hold])->params.field.HOLD = 1;
365 tx_old_hold = tx_hold;
367 tx_desc->params.word =
368 (INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD);
371 tx_desc->TxDataPtr = (u32)packet;
372 tx_desc->params.field.NBA = length;
374 KSEG1ADDR(&tx_ring[tx_hold])->params.field.HOLD = 0;
377 tx_new = (tx_new + 1) % NUM_TX_DESC;
382 command = INCA_IP_DMA_DMA_TXCCR0_INIT;
387 command = INCA_IP_DMA_DMA_TXCCR0_HR;
390 DMA_READ_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
393 printf("regValue = 0x%x\n", regValue);
395 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue);
398 for(i = 0; KSEG1ADDR(&tx_ring[tx_hold])->C == 0; i++)
402 printf("%s: tx buffer not ready\n", dev->name);
410 printf("Leaving inca_switch_send()\n");
416 static int inca_switch_recv(struct eth_device *dev)
419 inca_rx_descriptor_t * rx_desc;
422 printf("Entered inca_switch_recv()\n");
427 rx_desc = KSEG1ADDR(&rx_ring[rx_new]);
429 if (rx_desc->status.field.C == 0)
435 rx_ring[rx_new].params.field.HOLD = 1;
438 if (! rx_desc->status.field.Eop)
440 printf("Partly received packet!!!\n");
444 length = rx_desc->status.field.NBT;
445 rx_desc->status.word &=
446 ~(INCA_DMA_RX_EOP | INCA_DMA_RX_SOP | INCA_DMA_RX_C);
450 for (i=0;i<length - 4;i++) {
451 if (i % 16 == 0) printf("\n%04x: ", i);
452 printf("%02X ", NetRxPackets[rx_new][i]);
461 printf("Received %d bytes\n", length);
463 NetReceive((void*)KSEG1ADDR(NetRxPackets[rx_new]),
469 printf("Zero length!!!\n");
474 KSEG1ADDR(&rx_ring[rx_hold])->params.field.HOLD = 0;
478 rx_new = (rx_new + 1) % NUM_RX_DESC;
482 printf("Leaving inca_switch_recv()\n");
489 static void inca_switch_halt(struct eth_device *dev)
492 printf("Entered inca_switch_halt()\n");
499 /* Disable forwarding to the CPU port.
501 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
503 /* Close RxDMA channel.
505 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
507 /* Close TxDMA channel.
509 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_TXCCR0_OFF);
514 printf("Leaving inca_switch_halt()\n");
519 static void inca_init_switch_chip(void)
523 /* To workaround a problem with collision counter
524 * (see Errata sheet).
526 SW_WRITE_REG(INCA_IP_Switch_PC_TX_CTL, 0x00000001);
527 SW_WRITE_REG(INCA_IP_Switch_LAN_TX_CTL, 0x00000001);
530 /* init MDIO configuration:
531 MDS (Poll speed): 0x01 (4ms)
534 UEP (Use External PHY): 0x00 (Internal PHY is used)
535 PS (Port Select): 0x00 (PT/UMM for LAN)
536 PT (PHY Test): 0x00 (no test mode)
537 UMM (Use MDIO Mode): 0x00 (state machine is disabled)
539 SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50);
542 SL (Auto Neg. Speed for LAN)
543 SP (Auto Neg. Speed for PC)
544 LL (Link Status for LAN)
545 LP (Link Status for PC)
546 DL (Duplex Status for LAN)
547 DP (Duplex Status for PC)
548 PL (Auto Neg. Pause Status for LAN)
549 PP (Auto Neg. Pause Status for PC)
551 SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff);
554 RA (Request/Ack) 0x01 (Request)
555 RW (Read/Write) 0x01 (Write)
557 REG_ADDR 0x00 (PHY_BCR: basic control register)
559 Reset - software reset
560 LB (loop back) - normal
561 SS (speed select) - 10 Mbit/s
562 ANE (auto neg. enable) - disable
563 PD (power down) - normal
564 ISO (isolate) - normal
565 RAN (restart auto neg.) - normal
566 DM (duplex mode) - half duplex
567 CT (collision test) - enable
569 SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0a08000);
572 RA (Request/Ack) 0x01 (Request)
573 RW (Read/Write) 0x01 (Write)
575 REG_ADDR 0x00 (PHY_BCR: basic control register)
577 Reset - software reset
578 LB (loop back) - normal
579 SS (speed select) - 10 Mbit/s
580 ANE (auto neg. enable) - disable
581 PD (power down) - normal
582 ISO (isolate) - normal
583 RAN (restart auto neg.) - normal
584 DM (duplex mode) - half duplex
585 CT (collision test) - enable
587 SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0c08000);
590 /* Make sure the CPU port is disabled for now. We
591 * don't want packets to get stacked for us until
592 * we enable DMA and are prepared to receive them.
594 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
596 SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue);
598 /* CRC GEN is enabled.
600 regValue |= 0x00000200;
601 SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue);
603 /* ADD TAG is disabled.
605 SW_READ_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
606 regValue &= ~0x00000002;
607 SW_WRITE_REG(INCA_IP_Switch_PMAC_HD_CTL, regValue);
611 static void inca_dma_init(void)
613 /* Switch off all DMA channels.
615 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
616 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR1, INCA_IP_DMA_DMA_RXCCR1_OFF);
618 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
619 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR1, INCA_IP_DMA_DMA_TXCCR1_OFF);
620 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR2, INCA_IP_DMA_DMA_TXCCR2_OFF);
622 /* Setup TX channel polling time.
624 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME);
626 /* Setup RX channel polling time.
628 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME);
630 /* ERRATA: write reset value into the DMA RX IMR register.
632 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF);
634 /* Just in case: disable all transmit interrupts also.
636 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXIMR, 0xFFFFFFFF);
638 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXISR, 0xFFFFFFFF);
639 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXISR, 0xFFFFFFFF);