blob: 3a23f4db9ae65926d612056db728f3349261ab92 [file] [log] [blame]
wdenkac6dbb82003-03-26 11:42:53 +00001/*
2 * INCA-IP internal switch ethernet driver.
3 *
4 * (C) Copyright 2003
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
71typedef struct
72{
73 union
74 {
75 struct
76 {
77 volatile u32 HOLD :1;
78 volatile u32 ICpt :1;
79 volatile u32 IEop :1;
80 volatile u32 offset :3;
81 volatile u32 reserved0 :4;
82 volatile u32 NFB :22;
83 }field;
84
85 volatile u32 word;
86 }params;
87
88 volatile u32 nextRxDescPtr;
89
90 volatile u32 RxDataPtr;
91
92 union
93 {
94 struct
95 {
96 volatile u32 C :1;
97 volatile u32 Sop :1;
98 volatile u32 Eop :1;
99 volatile u32 reserved3 :12;
100 volatile u32 NBT :17;
101 }field;
102
103 volatile u32 word;
104 }status;
105
106} inca_rx_descriptor_t;
107
108
109typedef struct
110{
111 union
112 {
113 struct
114 {
115 volatile u32 HOLD :1;
116 volatile u32 Eop :1;
117 volatile u32 Sop :1;
118 volatile u32 ICpt :1;
119 volatile u32 IEop :1;
120 volatile u32 reserved0 :5;
121 volatile u32 NBA :22;
122 }field;
123
124 volatile u32 word;
125 }params;
126
127 volatile u32 nextTxDescPtr;
128
129 volatile u32 TxDataPtr;
130
131 volatile u32 C :1;
132 volatile u32 reserved3 :31;
133
134} inca_tx_descriptor_t;
135
136
137static inca_rx_descriptor_t rx_ring[NUM_RX_DESC] __attribute__ ((aligned(16)));
138static inca_tx_descriptor_t tx_ring[NUM_TX_DESC] __attribute__ ((aligned(16)));
139
140static int tx_new, rx_new, tx_hold, rx_hold;
141static int tx_old_hold = -1;
142static int initialized = 0;
143
144
145static int inca_switch_init(struct eth_device *dev, bd_t * bis);
146static int inca_switch_send(struct eth_device *dev, volatile void *packet,
147 int length);
148static int inca_switch_recv(struct eth_device *dev);
149static void inca_switch_halt(struct eth_device *dev);
150static void inca_init_switch_chip(void);
151static void inca_dma_init(void);
152
153
154
155int inca_switch_initialize(bd_t * bis)
156{
157 struct eth_device *dev;
158
159#if 0
160 printf("Entered inca_switch_initialize()\n");
161#endif
162
163 if (!(dev = (struct eth_device *) malloc (sizeof *dev)))
164 {
165 printf("Failed to allocate memory\n");
166 return 0;
167 }
168 memset(dev, 0, sizeof(*dev));
169
170 inca_dma_init();
171
172 inca_init_switch_chip();
173
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;
179
180 eth_register(dev);
181
182#if 0
183 printf("Leaving inca_switch_initialize()\n");
184#endif
185
186 return 1;
187}
188
189
190static int inca_switch_init(struct eth_device *dev, bd_t * bis)
191{
192 int i;
193 u32 v, regValue;
194 u16 wTmp;
195
196#if 0
197 printf("Entering inca_switch_init()\n");
198#endif
199
200 /* Set MAC address.
201 */
202 wTmp = (u16)dev->enetaddr[0];
203 regValue = (wTmp << 8) | dev->enetaddr[1];
204
205 SW_WRITE_REG(INCA_IP_Switch_PMAC_SA1, regValue);
206
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];
212
213 SW_WRITE_REG(INCA_IP_Switch_PMAC_SA2, regValue);
214
215 /* Initialize the descriptor rings.
216 */
217 for (i = 0; i < NUM_RX_DESC; i++)
218 {
219 inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]);
220 memset(rx_desc, 0, sizeof(rx_ring[i]));
221
222 /* Set maximum size of receive buffer.
223 */
224 rx_desc->params.field.NFB = PKTSIZE_ALIGN;
225
226 /* Set the offset of the receive buffer. Zero means
227 * that the offset mechanism is not used.
228 */
229 rx_desc->params.field.offset = 0;
230
231 /* Check if it is the last descriptor.
232 */
233 if (i == (NUM_RX_DESC - 1))
234 {
235 /* Let the last descriptor point to the first
236 * one.
237 */
238 rx_desc->nextRxDescPtr = KSEG1ADDR((u32)rx_ring);
239 }
240 else
241 {
242 /* Set the address of the next descriptor.
243 */
244 rx_desc->nextRxDescPtr = (u32)KSEG1ADDR(&rx_ring[i+1]);
245 }
246
247 rx_desc->RxDataPtr = (u32)KSEG1ADDR(NetRxPackets[i]);
248 }
249
250#if 0
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]);
253#endif
254
255 for (i = 0; i < NUM_TX_DESC; i++)
256 {
257 inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[i]);
258
259 memset(tx_desc, 0, sizeof(tx_ring[i]));
260
261 tx_desc->params.word = 0;
262 tx_desc->params.field.HOLD = 1;
263 tx_desc->C = 1;
264
265 /* Check if it is the last descriptor.
266 */
267 if (i == (NUM_TX_DESC - 1))
268 {
269 /* Let the last descriptor point to the
270 * first one.
271 */
272 tx_desc->nextTxDescPtr = KSEG1ADDR((u32)tx_ring);
273 }
274 else
275 {
276 /* Set the address of the next descriptor.
277 */
278 tx_desc->nextTxDescPtr = (u32)KSEG1ADDR(&tx_ring[i+1]);
279 }
280 }
281
282 /* Initialize RxDMA.
283 */
284 DMA_READ_REG(INCA_IP_DMA_DMA_RXISR, v);
285#if 0
286 printf("RX status = 0x%08X\n", v);
287#endif
288
289 /* Writing to the FRDA of CHANNEL.
290 */
291 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring);
292
293 /* Writing to the COMMAND REG.
294 */
295 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0,
296 INCA_IP_DMA_DMA_RXCCR0_INIT);
297
298 /* Initialize TxDMA.
299 */
300 DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v);
301#if 0
302 printf("TX status = 0x%08X\n", v);
303#endif
304
305 /* Writing to the FRDA of CHANNEL.
306 */
307 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXFRDA0, (u32)tx_ring);
308
309 tx_new = rx_new = 0;
310
311 tx_hold = NUM_TX_DESC - 1;
312 rx_hold = NUM_RX_DESC - 1;
313
314#if 0
315 rx_ring[rx_hold].params.field.HOLD = 1;
316#endif
317 /* enable spanning tree forwarding, enable the CPU port */
318 /* ST_PT:
319 CPS (CPU port status) 0x3 (forwarding)
320 LPS (LAN port status) 0x3 (forwarding)
321 PPS (PC port status) 0x3 (forwarding)
322 */
323 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0x3f);
324
325#if 0
326 printf("Leaving inca_switch_init()\n");
327#endif
328
329 return 0;
330}
331
332
333static int inca_switch_send(struct eth_device *dev, volatile void *packet,
334 int length)
335{
336 int i;
337 int res = -1;
338 u32 command;
339 u32 regValue;
340 inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[tx_new]);
341
342#if 0
343 printf("Entered inca_switch_send()\n");
344#endif
345
346 if (length <= 0)
347 {
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 {
354 if (i >= TOUT_LOOP)
355 {
356 printf("%s: tx error buffer not ready\n", dev->name);
357 goto Done;
358 }
359 }
360
361 if (tx_old_hold >= 0)
362 {
363 KSEG1ADDR(&tx_ring[tx_old_hold])->params.field.HOLD = 1;
364 }
365 tx_old_hold = tx_hold;
366
367 tx_desc->params.word =
368 (INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD);
369
370 tx_desc->C = 0;
371 tx_desc->TxDataPtr = (u32)packet;
372 tx_desc->params.field.NBA = length;
373
374 KSEG1ADDR(&tx_ring[tx_hold])->params.field.HOLD = 0;
375
376 tx_hold = tx_new;
377 tx_new = (tx_new + 1) % NUM_TX_DESC;
378
379
380 if (! initialized)
381 {
382 command = INCA_IP_DMA_DMA_TXCCR0_INIT;
383 initialized = 1;
384 }
385 else
386 {
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; KSEG1ADDR(&tx_ring[tx_hold])->C == 0; i++)
399 {
400 if (i >= TOUT_LOOP)
401 {
402 printf("%s: tx buffer not ready\n", dev->name);
403 goto Done;
404 }
405 }
406#endif
407 res = length;
408Done:
409#if 0
410 printf("Leaving inca_switch_send()\n");
411#endif
412 return res;
413}
414
415
416static int inca_switch_recv(struct eth_device *dev)
417{
418 int length = 0;
419 inca_rx_descriptor_t * rx_desc;
420
421#if 0
422 printf("Entered inca_switch_recv()\n");
423#endif
424
425 for (;;)
426 {
427 rx_desc = KSEG1ADDR(&rx_ring[rx_new]);
428
429 if (rx_desc->status.field.C == 0)
430 {
431 break;
432 }
433
434#if 0
435 rx_ring[rx_new].params.field.HOLD = 1;
436#endif
437
438 if (! rx_desc->status.field.Eop)
439 {
440 printf("Partly received packet!!!\n");
441 break;
442 }
443
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);
447#if 0
448{
449 int i;
450 for (i=0;i<length - 4;i++) {
451 if (i % 16 == 0) printf("\n%04x: ", i);
452 printf("%02X ", NetRxPackets[rx_new][i]);
453 }
454 printf("\n");
455}
456#endif
457
458 if (length)
459 {
460#if 0
461 printf("Received %d bytes\n", length);
462#endif
463 NetReceive((void*)KSEG1ADDR(NetRxPackets[rx_new]),
464 length - 4);
465 }
466 else
467 {
468#if 1
469 printf("Zero length!!!\n");
470#endif
471 }
472
473
474 KSEG1ADDR(&rx_ring[rx_hold])->params.field.HOLD = 0;
475
476 rx_hold = rx_new;
477
478 rx_new = (rx_new + 1) % NUM_RX_DESC;
479 }
480
481#if 0
482 printf("Leaving inca_switch_recv()\n");
483#endif
484
485 return length;
486}
487
488
489static void inca_switch_halt(struct eth_device *dev)
490{
491#if 0
492 printf("Entered inca_switch_halt()\n");
493#endif
494
495#if 1
496 initialized = 0;
497#endif
498#if 1
499 /* Disable forwarding to the CPU port.
500 */
501 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
502
503 /* Close RxDMA channel.
504 */
505 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF);
506
507 /* Close TxDMA channel.
508 */
509 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, INCA_IP_DMA_DMA_TXCCR0_OFF);
510
511
512#endif
513#if 0
514 printf("Leaving inca_switch_halt()\n");
515#endif
516}
517
518
519static void inca_init_switch_chip(void)
520{
521 u32 regValue;
522
523 /* To workaround a problem with collision counter
524 * (see Errata sheet).
525 */
526 SW_WRITE_REG(INCA_IP_Switch_PC_TX_CTL, 0x00000001);
527 SW_WRITE_REG(INCA_IP_Switch_LAN_TX_CTL, 0x00000001);
528
529#if 1
530 /* init MDIO configuration:
531 MDS (Poll speed): 0x01 (4ms)
532 PHY_LAN_ADDR: 0x06
533 PHY_PC_ADDR: 0x05
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)
538 */
539 SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50);
540
541 /* init PHY:
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)
550 */
551 SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff);
552
553 /* MDIO_ACC:
554 RA (Request/Ack) 0x01 (Request)
555 RW (Read/Write) 0x01 (Write)
556 PHY_ADDR 0x05 (PC)
557 REG_ADDR 0x00 (PHY_BCR: basic control register)
558 PHY_DATA 0x8000
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
568 */
569 SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0a08000);
570
571 /* MDIO_ACC:
572 RA (Request/Ack) 0x01 (Request)
573 RW (Read/Write) 0x01 (Write)
574 PHY_ADDR 0x06 (LAN)
575 REG_ADDR 0x00 (PHY_BCR: basic control register)
576 PHY_DATA 0x8000
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
586 */
587 SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, 0xc0c08000);
588#endif
589
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.
593 */
594 SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf);
595
596 SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue);
597
598 /* CRC GEN is enabled.
599 */
600 regValue |= 0x00000200;
601 SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue);
602
603 /* ADD TAG is disabled.
604 */
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);
608}
609
610
611static void inca_dma_init(void)
612{
613 /* Switch off all DMA channels.
614 */
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);
617
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);
621
622 /* Setup TX channel polling time.
623 */
624 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME);
625
626 /* Setup RX channel polling time.
627 */
628 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME);
629
630 /* ERRATA: write reset value into the DMA RX IMR register.
631 */
632 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF);
633
634 /* Just in case: disable all transmit interrupts also.
635 */
636 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXIMR, 0xFFFFFFFF);
637
638 DMA_WRITE_REG(INCA_IP_DMA_DMA_TXISR, 0xFFFFFFFF);
639 DMA_WRITE_REG(INCA_IP_DMA_DMA_RXISR, 0xFFFFFFFF);
640}
641
642#endif
643
644 /* End of file.
645 */
646