]>
Commit | Line | Data |
---|---|---|
ac6dbb85 WD |
1 | /* |
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) \ | |
8bde7f77 WD |
48 | *((volatile u32*)reg) = (u32)value;\ |
49 | DELAY;\ | |
50 | *((volatile u32*)reg) = (u32)value; | |
ac6dbb85 WD |
51 | |
52 | #define SW_READ_REG(reg, value) \ | |
8bde7f77 WD |
53 | value = (u32)*((volatile u32*)reg);\ |
54 | DELAY;\ | |
55 | value = (u32)*((volatile u32*)reg); | |
ac6dbb85 WD |
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 | ||
cf56e110 WD |
70 | /************************ Auto MDIX settings ************************/ |
71 | #define INCA_IP_AUTO_MDIX_LAN_PORTS_DIR INCA_IP_Ports_P1_DIR | |
3c74e32a | 72 | #define INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL INCA_IP_Ports_P1_ALTSEL |
cf56e110 WD |
73 | #define INCA_IP_AUTO_MDIX_LAN_PORTS_OUT INCA_IP_Ports_P1_OUT |
74 | #define INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX 16 | |
75 | ||
76 | #define WAIT_SIGNAL_RETRIES 100 | |
77 | #define WAIT_LINK_RETRIES 100 | |
78 | #define LINK_RETRY_DELAY 300 /* ms */ | |
79 | /********************************************************************/ | |
ac6dbb85 WD |
80 | |
81 | typedef struct | |
82 | { | |
e0ac62d7 WD |
83 | union { |
84 | struct { | |
ac6dbb85 WD |
85 | volatile u32 HOLD :1; |
86 | volatile u32 ICpt :1; | |
87 | volatile u32 IEop :1; | |
88 | volatile u32 offset :3; | |
89 | volatile u32 reserved0 :4; | |
90 | volatile u32 NFB :22; | |
91 | }field; | |
92 | ||
93 | volatile u32 word; | |
94 | }params; | |
95 | ||
96 | volatile u32 nextRxDescPtr; | |
97 | ||
98 | volatile u32 RxDataPtr; | |
99 | ||
e0ac62d7 WD |
100 | union { |
101 | struct { | |
ac6dbb85 WD |
102 | volatile u32 C :1; |
103 | volatile u32 Sop :1; | |
104 | volatile u32 Eop :1; | |
105 | volatile u32 reserved3 :12; | |
106 | volatile u32 NBT :17; | |
107 | }field; | |
108 | ||
109 | volatile u32 word; | |
110 | }status; | |
111 | ||
112 | } inca_rx_descriptor_t; | |
113 | ||
114 | ||
115 | typedef struct | |
116 | { | |
e0ac62d7 WD |
117 | union { |
118 | struct { | |
ac6dbb85 WD |
119 | volatile u32 HOLD :1; |
120 | volatile u32 Eop :1; | |
121 | volatile u32 Sop :1; | |
122 | volatile u32 ICpt :1; | |
123 | volatile u32 IEop :1; | |
124 | volatile u32 reserved0 :5; | |
125 | volatile u32 NBA :22; | |
126 | }field; | |
127 | ||
128 | volatile u32 word; | |
129 | }params; | |
130 | ||
131 | volatile u32 nextTxDescPtr; | |
132 | ||
133 | volatile u32 TxDataPtr; | |
134 | ||
135 | volatile u32 C :1; | |
136 | volatile u32 reserved3 :31; | |
137 | ||
138 | } inca_tx_descriptor_t; | |
139 | ||
140 | ||
141 | static inca_rx_descriptor_t rx_ring[NUM_RX_DESC] __attribute__ ((aligned(16))); | |
142 | static inca_tx_descriptor_t tx_ring[NUM_TX_DESC] __attribute__ ((aligned(16))); | |
143 | ||
144 | static int tx_new, rx_new, tx_hold, rx_hold; | |
145 | static int tx_old_hold = -1; | |
146 | static int initialized = 0; | |
147 | ||
148 | ||
149 | static int inca_switch_init(struct eth_device *dev, bd_t * bis); | |
150 | static int inca_switch_send(struct eth_device *dev, volatile void *packet, | |
151 | int length); | |
152 | static int inca_switch_recv(struct eth_device *dev); | |
153 | static void inca_switch_halt(struct eth_device *dev); | |
154 | static void inca_init_switch_chip(void); | |
155 | static void inca_dma_init(void); | |
cf56e110 | 156 | static int inca_amdix(void); |
ac6dbb85 WD |
157 | |
158 | ||
ac6dbb85 WD |
159 | int inca_switch_initialize(bd_t * bis) |
160 | { | |
161 | struct eth_device *dev; | |
162 | ||
163 | #if 0 | |
164 | printf("Entered inca_switch_initialize()\n"); | |
165 | #endif | |
166 | ||
e0ac62d7 | 167 | if (!(dev = (struct eth_device *) malloc (sizeof *dev))) { |
ac6dbb85 WD |
168 | printf("Failed to allocate memory\n"); |
169 | return 0; | |
170 | } | |
171 | memset(dev, 0, sizeof(*dev)); | |
172 | ||
173 | inca_dma_init(); | |
174 | ||
175 | inca_init_switch_chip(); | |
3c74e32a | 176 | |
0c852a28 | 177 | #if defined(CONFIG_INCA_IP_SWITCH_AMDIX) |
cf56e110 | 178 | inca_amdix(); |
0c852a28 | 179 | #endif |
ac6dbb85 WD |
180 | |
181 | sprintf(dev->name, "INCA-IP Switch"); | |
182 | dev->init = inca_switch_init; | |
183 | dev->halt = inca_switch_halt; | |
184 | dev->send = inca_switch_send; | |
185 | dev->recv = inca_switch_recv; | |
186 | ||
187 | eth_register(dev); | |
188 | ||
189 | #if 0 | |
190 | printf("Leaving inca_switch_initialize()\n"); | |
191 | #endif | |
192 | ||
193 | return 1; | |
194 | } | |
195 | ||
196 | ||
197 | static int inca_switch_init(struct eth_device *dev, bd_t * bis) | |
198 | { | |
199 | int i; | |
200 | u32 v, regValue; | |
201 | u16 wTmp; | |
202 | ||
203 | #if 0 | |
204 | printf("Entering inca_switch_init()\n"); | |
205 | #endif | |
206 | ||
e0ac62d7 WD |
207 | /* Set MAC address. |
208 | */ | |
ac6dbb85 WD |
209 | wTmp = (u16)dev->enetaddr[0]; |
210 | regValue = (wTmp << 8) | dev->enetaddr[1]; | |
211 | ||
212 | SW_WRITE_REG(INCA_IP_Switch_PMAC_SA1, regValue); | |
213 | ||
214 | wTmp = (u16)dev->enetaddr[2]; | |
215 | regValue = (wTmp << 8) | dev->enetaddr[3]; | |
216 | regValue = regValue << 16; | |
217 | wTmp = (u16)dev->enetaddr[4]; | |
218 | regValue |= (wTmp<<8) | dev->enetaddr[5]; | |
219 | ||
220 | SW_WRITE_REG(INCA_IP_Switch_PMAC_SA2, regValue); | |
221 | ||
e0ac62d7 WD |
222 | /* Initialize the descriptor rings. |
223 | */ | |
ac6dbb85 WD |
224 | for (i = 0; i < NUM_RX_DESC; i++) |
225 | { | |
226 | inca_rx_descriptor_t * rx_desc = KSEG1ADDR(&rx_ring[i]); | |
227 | memset(rx_desc, 0, sizeof(rx_ring[i])); | |
228 | ||
e0ac62d7 WD |
229 | /* Set maximum size of receive buffer. |
230 | */ | |
ac6dbb85 WD |
231 | rx_desc->params.field.NFB = PKTSIZE_ALIGN; |
232 | ||
e0ac62d7 WD |
233 | /* Set the offset of the receive buffer. Zero means |
234 | * that the offset mechanism is not used. | |
235 | */ | |
ac6dbb85 WD |
236 | rx_desc->params.field.offset = 0; |
237 | ||
238 | /* Check if it is the last descriptor. | |
239 | */ | |
e0ac62d7 WD |
240 | if (i == (NUM_RX_DESC - 1)) { |
241 | /* Let the last descriptor point to the first | |
242 | * one. | |
243 | */ | |
ac6dbb85 | 244 | rx_desc->nextRxDescPtr = KSEG1ADDR((u32)rx_ring); |
e0ac62d7 WD |
245 | } else { |
246 | /* Set the address of the next descriptor. | |
247 | */ | |
ac6dbb85 WD |
248 | rx_desc->nextRxDescPtr = (u32)KSEG1ADDR(&rx_ring[i+1]); |
249 | } | |
250 | ||
251 | rx_desc->RxDataPtr = (u32)KSEG1ADDR(NetRxPackets[i]); | |
252 | } | |
253 | ||
254 | #if 0 | |
255 | printf("rx_ring = 0x%08X 0x%08X\n", (u32)rx_ring, (u32)&rx_ring[0]); | |
256 | printf("tx_ring = 0x%08X 0x%08X\n", (u32)tx_ring, (u32)&tx_ring[0]); | |
257 | #endif | |
258 | ||
e0ac62d7 | 259 | for (i = 0; i < NUM_TX_DESC; i++) { |
ac6dbb85 WD |
260 | inca_tx_descriptor_t * tx_desc = KSEG1ADDR(&tx_ring[i]); |
261 | ||
262 | memset(tx_desc, 0, sizeof(tx_ring[i])); | |
263 | ||
264 | tx_desc->params.word = 0; | |
265 | tx_desc->params.field.HOLD = 1; | |
266 | tx_desc->C = 1; | |
267 | ||
268 | /* Check if it is the last descriptor. | |
269 | */ | |
e0ac62d7 | 270 | if (i == (NUM_TX_DESC - 1)) { |
ac6dbb85 WD |
271 | /* Let the last descriptor point to the |
272 | * first one. | |
273 | */ | |
274 | tx_desc->nextTxDescPtr = KSEG1ADDR((u32)tx_ring); | |
e0ac62d7 | 275 | } else { |
ac6dbb85 WD |
276 | /* Set the address of the next descriptor. |
277 | */ | |
278 | tx_desc->nextTxDescPtr = (u32)KSEG1ADDR(&tx_ring[i+1]); | |
279 | } | |
280 | } | |
281 | ||
e0ac62d7 WD |
282 | /* Initialize RxDMA. |
283 | */ | |
ac6dbb85 WD |
284 | DMA_READ_REG(INCA_IP_DMA_DMA_RXISR, v); |
285 | #if 0 | |
286 | printf("RX status = 0x%08X\n", v); | |
287 | #endif | |
288 | ||
e0ac62d7 WD |
289 | /* Writing to the FRDA of CHANNEL. |
290 | */ | |
ac6dbb85 WD |
291 | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXFRDA0, (u32)rx_ring); |
292 | ||
e0ac62d7 WD |
293 | /* Writing to the COMMAND REG. |
294 | */ | |
ac6dbb85 | 295 | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, |
8bde7f77 | 296 | INCA_IP_DMA_DMA_RXCCR0_INIT); |
ac6dbb85 | 297 | |
e0ac62d7 WD |
298 | /* Initialize TxDMA. |
299 | */ | |
ac6dbb85 WD |
300 | DMA_READ_REG(INCA_IP_DMA_DMA_TXISR, v); |
301 | #if 0 | |
302 | printf("TX status = 0x%08X\n", v); | |
303 | #endif | |
304 | ||
e0ac62d7 WD |
305 | /* Writing to the FRDA of CHANNEL. |
306 | */ | |
ac6dbb85 WD |
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 | |
e0ac62d7 WD |
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 | */ | |
ac6dbb85 WD |
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 | ||
333 | static 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 | ||
e0ac62d7 | 346 | if (length <= 0) { |
ac6dbb85 WD |
347 | printf ("%s: bad packet size: %d\n", dev->name, length); |
348 | goto Done; | |
349 | } | |
8bde7f77 | 350 | |
e0ac62d7 WD |
351 | for(i = 0; tx_desc->C == 0; i++) { |
352 | if (i >= TOUT_LOOP) { | |
ac6dbb85 WD |
353 | printf("%s: tx error buffer not ready\n", dev->name); |
354 | goto Done; | |
355 | } | |
356 | } | |
357 | ||
e0ac62d7 | 358 | if (tx_old_hold >= 0) { |
ac6dbb85 WD |
359 | KSEG1ADDR(&tx_ring[tx_old_hold])->params.field.HOLD = 1; |
360 | } | |
361 | tx_old_hold = tx_hold; | |
362 | ||
363 | tx_desc->params.word = | |
8bde7f77 | 364 | (INCA_DMA_TX_SOP | INCA_DMA_TX_EOP | INCA_DMA_TX_HOLD); |
ac6dbb85 WD |
365 | |
366 | tx_desc->C = 0; | |
367 | tx_desc->TxDataPtr = (u32)packet; | |
368 | tx_desc->params.field.NBA = length; | |
369 | ||
370 | KSEG1ADDR(&tx_ring[tx_hold])->params.field.HOLD = 0; | |
371 | ||
372 | tx_hold = tx_new; | |
373 | tx_new = (tx_new + 1) % NUM_TX_DESC; | |
374 | ||
375 | ||
e0ac62d7 | 376 | if (! initialized) { |
ac6dbb85 WD |
377 | command = INCA_IP_DMA_DMA_TXCCR0_INIT; |
378 | initialized = 1; | |
e0ac62d7 | 379 | } else { |
ac6dbb85 WD |
380 | command = INCA_IP_DMA_DMA_TXCCR0_HR; |
381 | } | |
8bde7f77 | 382 | |
ac6dbb85 WD |
383 | DMA_READ_REG(INCA_IP_DMA_DMA_TXCCR0, regValue); |
384 | regValue |= command; | |
385 | #if 0 | |
386 | printf("regValue = 0x%x\n", regValue); | |
387 | #endif | |
388 | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXCCR0, regValue); | |
389 | ||
390 | #if 1 | |
e0ac62d7 WD |
391 | for(i = 0; KSEG1ADDR(&tx_ring[tx_hold])->C == 0; i++) { |
392 | if (i >= TOUT_LOOP) { | |
ac6dbb85 WD |
393 | printf("%s: tx buffer not ready\n", dev->name); |
394 | goto Done; | |
395 | } | |
396 | } | |
397 | #endif | |
398 | res = length; | |
399 | Done: | |
400 | #if 0 | |
401 | printf("Leaving inca_switch_send()\n"); | |
402 | #endif | |
403 | return res; | |
404 | } | |
405 | ||
406 | ||
407 | static int inca_switch_recv(struct eth_device *dev) | |
408 | { | |
409 | int length = 0; | |
410 | inca_rx_descriptor_t * rx_desc; | |
411 | ||
412 | #if 0 | |
413 | printf("Entered inca_switch_recv()\n"); | |
414 | #endif | |
415 | ||
e0ac62d7 | 416 | for (;;) { |
ac6dbb85 WD |
417 | rx_desc = KSEG1ADDR(&rx_ring[rx_new]); |
418 | ||
e0ac62d7 | 419 | if (rx_desc->status.field.C == 0) { |
ac6dbb85 WD |
420 | break; |
421 | } | |
422 | ||
423 | #if 0 | |
424 | rx_ring[rx_new].params.field.HOLD = 1; | |
425 | #endif | |
426 | ||
e0ac62d7 | 427 | if (! rx_desc->status.field.Eop) { |
ac6dbb85 WD |
428 | printf("Partly received packet!!!\n"); |
429 | break; | |
430 | } | |
431 | ||
432 | length = rx_desc->status.field.NBT; | |
433 | rx_desc->status.word &= | |
8bde7f77 | 434 | ~(INCA_DMA_RX_EOP | INCA_DMA_RX_SOP | INCA_DMA_RX_C); |
ac6dbb85 WD |
435 | #if 0 |
436 | { | |
437 | int i; | |
438 | for (i=0;i<length - 4;i++) { | |
439 | if (i % 16 == 0) printf("\n%04x: ", i); | |
440 | printf("%02X ", NetRxPackets[rx_new][i]); | |
441 | } | |
442 | printf("\n"); | |
443 | } | |
444 | #endif | |
445 | ||
e0ac62d7 | 446 | if (length) { |
ac6dbb85 WD |
447 | #if 0 |
448 | printf("Received %d bytes\n", length); | |
449 | #endif | |
450 | NetReceive((void*)KSEG1ADDR(NetRxPackets[rx_new]), | |
8bde7f77 | 451 | length - 4); |
e0ac62d7 | 452 | } else { |
ac6dbb85 WD |
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 | |
e0ac62d7 WD |
484 | /* Disable forwarding to the CPU port. |
485 | */ | |
ac6dbb85 WD |
486 | SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf); |
487 | ||
e0ac62d7 WD |
488 | /* Close RxDMA channel. |
489 | */ | |
ac6dbb85 WD |
490 | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXCCR0, INCA_IP_DMA_DMA_RXCCR0_OFF); |
491 | ||
e0ac62d7 WD |
492 | /* Close TxDMA channel. |
493 | */ | |
ac6dbb85 WD |
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 | ||
e0ac62d7 WD |
508 | /* To workaround a problem with collision counter |
509 | * (see Errata sheet). | |
510 | */ | |
ac6dbb85 WD |
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 | |
e0ac62d7 WD |
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 | */ | |
ac6dbb85 WD |
524 | SW_WRITE_REG(INCA_IP_Switch_MDIO_CFG, 0x4c50); |
525 | ||
e0ac62d7 WD |
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 | */ | |
ac6dbb85 WD |
536 | SW_WRITE_REG (INCA_IP_Switch_EPHY, 0xff); |
537 | ||
e0ac62d7 WD |
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 | ||
ac6dbb85 WD |
574 | #endif |
575 | ||
e0ac62d7 WD |
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 | */ | |
ac6dbb85 WD |
580 | SW_WRITE_REG(INCA_IP_Switch_ST_PT,0xf); |
581 | ||
582 | SW_READ_REG(INCA_IP_Switch_ARL_CTL, regValue); | |
583 | ||
e0ac62d7 WD |
584 | /* CRC GEN is enabled. |
585 | */ | |
ac6dbb85 WD |
586 | regValue |= 0x00000200; |
587 | SW_WRITE_REG(INCA_IP_Switch_ARL_CTL, regValue); | |
588 | ||
e0ac62d7 WD |
589 | /* ADD TAG is disabled. |
590 | */ | |
ac6dbb85 WD |
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 | { | |
e0ac62d7 WD |
599 | /* Switch off all DMA channels. |
600 | */ | |
ac6dbb85 WD |
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 | ||
e0ac62d7 WD |
608 | /* Setup TX channel polling time. |
609 | */ | |
ac6dbb85 WD |
610 | DMA_WRITE_REG(INCA_IP_DMA_DMA_TXPOLL, INCA_DMA_TX_POLLING_TIME); |
611 | ||
e0ac62d7 WD |
612 | /* Setup RX channel polling time. |
613 | */ | |
ac6dbb85 WD |
614 | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXPOLL, INCA_DMA_RX_POLLING_TIME); |
615 | ||
e0ac62d7 WD |
616 | /* ERRATA: write reset value into the DMA RX IMR register. |
617 | */ | |
ac6dbb85 WD |
618 | DMA_WRITE_REG(INCA_IP_DMA_DMA_RXIMR, 0xFFFFFFFF); |
619 | ||
e0ac62d7 WD |
620 | /* Just in case: disable all transmit interrupts also. |
621 | */ | |
ac6dbb85 WD |
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 | ||
0c852a28 | 628 | #if defined(CONFIG_INCA_IP_SWITCH_AMDIX) |
cf56e110 WD |
629 | static int inca_amdix(void) |
630 | { | |
631 | u32 regValue = 0; | |
632 | int mdi_flag; | |
633 | int retries; | |
634 | ||
635 | /* Setup GPIO pins. | |
636 | */ | |
637 | *INCA_IP_AUTO_MDIX_LAN_PORTS_DIR |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | |
638 | *INCA_IP_AUTO_MDIX_LAN_PORTS_ALTSEL |= (1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | |
639 | ||
640 | /* Wait for signal. | |
641 | */ | |
642 | retries = WAIT_SIGNAL_RETRIES; | |
643 | while (--retries) | |
644 | { | |
645 | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | |
646 | (0x1 << 31) | /* RA */ | |
647 | (0x0 << 30) | /* Read */ | |
648 | (0x6 << 21) | /* LAN */ | |
649 | (17 << 16)); /* PHY_MCSR */ | |
650 | do | |
651 | { | |
652 | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, regValue); | |
653 | } | |
654 | while (regValue & (1 << 31)); | |
655 | ||
656 | if (regValue & (1 << 1)) | |
657 | { | |
658 | /* Signal detected */ | |
659 | break; | |
660 | } | |
661 | } | |
662 | ||
663 | if (!retries) | |
664 | return -1; | |
665 | ||
666 | /* Set MDI mode. | |
667 | */ | |
668 | *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | |
669 | mdi_flag = 1; | |
670 | ||
671 | /* Wait for link. | |
672 | */ | |
673 | retries = WAIT_LINK_RETRIES; | |
674 | while (--retries) | |
675 | { | |
676 | udelay(LINK_RETRY_DELAY * 1000); | |
677 | SW_WRITE_REG(INCA_IP_Switch_MDIO_ACC, | |
678 | (0x1 << 31) | /* RA */ | |
679 | (0x0 << 30) | /* Read */ | |
680 | (0x6 << 21) | /* LAN */ | |
681 | (1 << 16)); /* PHY_BSR */ | |
682 | do | |
683 | { | |
684 | SW_READ_REG(INCA_IP_Switch_MDIO_ACC, regValue); | |
685 | } | |
686 | while (regValue & (1 << 31)); | |
687 | ||
688 | if (regValue & (1 << 2)) | |
689 | { | |
690 | /* Link is up */ | |
691 | break; | |
692 | } | |
693 | else if (mdi_flag) | |
694 | { | |
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 | } | |
699 | else | |
700 | { | |
701 | /* Set MDI mode */ | |
702 | *INCA_IP_AUTO_MDIX_LAN_PORTS_OUT &= ~(1 << INCA_IP_AUTO_MDIX_LAN_GPIO_PIN_RXTX); | |
703 | mdi_flag = 1; | |
704 | } | |
705 | } | |
706 | ||
707 | if (!retries) | |
708 | return -1; | |
709 | ||
710 | return 0; | |
711 | } | |
0c852a28 | 712 | #endif /* CONFIG_INCA_IP_SWITCH_AMDIX */ |
cf56e110 | 713 | |
ac6dbb85 | 714 | #endif |