]>
Commit | Line | Data |
---|---|---|
983fda83 WD |
1 | /* |
2 | * (C) Copyright 2003 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * This file is based on mpc4200fec.c, | |
6 | * (C) Copyright Motorola, Inc., 2000 | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <mpc8220.h> | |
11 | #include <malloc.h> | |
12 | #include <net.h> | |
13 | #include <miiphy.h> | |
14 | #include "dma.h" | |
15 | #include "fec.h" | |
16 | ||
ba91e26a | 17 | #undef DEBUG |
4431283c | 18 | #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ |
7680c140 | 19 | defined(CONFIG_MPC8220_FEC) |
983fda83 | 20 | |
4431283c | 21 | #if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) |
63ff004c MB |
22 | #error "CONFIG_MII has to be defined!" |
23 | #endif | |
983fda83 | 24 | |
ba91e26a | 25 | #ifdef DEBUG |
63ff004c MB |
26 | static void tfifo_print (char *devname, mpc8220_fec_priv * fec); |
27 | static void rfifo_print (char *devname, mpc8220_fec_priv * fec); | |
983fda83 WD |
28 | #endif /* DEBUG */ |
29 | ||
ba91e26a | 30 | #ifdef DEBUG |
983fda83 WD |
31 | static u32 local_crc32 (char *string, unsigned int crc_value, int len); |
32 | #endif | |
33 | ||
34 | typedef struct { | |
35 | u8 data[1500]; /* actual data */ | |
36 | int length; /* actual length */ | |
37 | int used; /* buffer in use or not */ | |
38 | u8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */ | |
39 | } NBUF; | |
40 | ||
63ff004c MB |
41 | int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal); |
42 | int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data); | |
43 | ||
983fda83 | 44 | /********************************************************************/ |
ba91e26a | 45 | #ifdef DEBUG |
63ff004c | 46 | static void mpc8220_fec_phydump (char *devname) |
983fda83 WD |
47 | { |
48 | u16 phyStatus, i; | |
49 | u8 phyAddr = CONFIG_PHY_ADDR; | |
50 | u8 reg_mask[] = { | |
51 | #if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */ | |
52 | /* regs to print: 0...7, 16...19, 21, 23, 24 */ | |
53 | 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, | |
54 | 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, | |
55 | #else | |
56 | /* regs to print: 0...8, 16...20 */ | |
57 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, | |
58 | 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
59 | #endif | |
60 | }; | |
61 | ||
62 | for (i = 0; i < 32; i++) { | |
63 | if (reg_mask[i]) { | |
63ff004c | 64 | miiphy_read (devname, phyAddr, i, &phyStatus); |
983fda83 WD |
65 | printf ("Mii reg %d: 0x%04x\n", i, phyStatus); |
66 | } | |
67 | } | |
68 | } | |
69 | #endif | |
70 | ||
71 | /********************************************************************/ | |
72 | static int mpc8220_fec_rbd_init (mpc8220_fec_priv * fec) | |
73 | { | |
74 | int ix; | |
75 | char *data; | |
76 | static int once = 0; | |
77 | ||
78 | for (ix = 0; ix < FEC_RBD_NUM; ix++) { | |
79 | if (!once) { | |
80 | data = (char *) malloc (FEC_MAX_PKT_SIZE); | |
81 | if (data == NULL) { | |
82 | printf ("RBD INIT FAILED\n"); | |
83 | return -1; | |
84 | } | |
85 | fec->rbdBase[ix].dataPointer = (u32) data; | |
86 | } | |
87 | fec->rbdBase[ix].status = FEC_RBD_EMPTY; | |
88 | fec->rbdBase[ix].dataLength = 0; | |
89 | } | |
90 | once++; | |
91 | ||
92 | /* | |
93 | * have the last RBD to close the ring | |
94 | */ | |
95 | fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP; | |
96 | fec->rbdIndex = 0; | |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | /********************************************************************/ | |
102 | static void mpc8220_fec_tbd_init (mpc8220_fec_priv * fec) | |
103 | { | |
104 | int ix; | |
105 | ||
106 | for (ix = 0; ix < FEC_TBD_NUM; ix++) { | |
107 | fec->tbdBase[ix].status = 0; | |
108 | } | |
109 | ||
110 | /* | |
111 | * Have the last TBD to close the ring | |
112 | */ | |
113 | fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP; | |
114 | ||
115 | /* | |
116 | * Initialize some indices | |
117 | */ | |
118 | fec->tbdIndex = 0; | |
119 | fec->usedTbdIndex = 0; | |
120 | fec->cleanTbdNum = FEC_TBD_NUM; | |
121 | } | |
122 | ||
123 | /********************************************************************/ | |
124 | static void mpc8220_fec_rbd_clean (mpc8220_fec_priv * fec, FEC_RBD * pRbd) | |
125 | { | |
126 | /* | |
127 | * Reset buffer descriptor as empty | |
128 | */ | |
129 | if ((fec->rbdIndex) == (FEC_RBD_NUM - 1)) | |
130 | pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY); | |
131 | else | |
132 | pRbd->status = FEC_RBD_EMPTY; | |
133 | ||
134 | pRbd->dataLength = 0; | |
135 | ||
136 | /* | |
137 | * Now, we have an empty RxBD, restart the SmartDMA receive task | |
138 | */ | |
139 | DMA_TASK_ENABLE (FEC_RECV_TASK_NO); | |
140 | ||
141 | /* | |
142 | * Increment BD count | |
143 | */ | |
144 | fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM; | |
145 | } | |
146 | ||
147 | /********************************************************************/ | |
148 | static void mpc8220_fec_tbd_scrub (mpc8220_fec_priv * fec) | |
149 | { | |
150 | FEC_TBD *pUsedTbd; | |
151 | ||
ba91e26a | 152 | #ifdef DEBUG |
983fda83 WD |
153 | printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n", |
154 | fec->cleanTbdNum, fec->usedTbdIndex); | |
155 | #endif | |
156 | ||
157 | /* | |
158 | * process all the consumed TBDs | |
159 | */ | |
160 | while (fec->cleanTbdNum < FEC_TBD_NUM) { | |
161 | pUsedTbd = &fec->tbdBase[fec->usedTbdIndex]; | |
162 | if (pUsedTbd->status & FEC_TBD_READY) { | |
ba91e26a | 163 | #ifdef DEBUG |
983fda83 WD |
164 | printf ("Cannot clean TBD %d, in use\n", |
165 | fec->cleanTbdNum); | |
166 | #endif | |
167 | return; | |
168 | } | |
169 | ||
170 | /* | |
171 | * clean this buffer descriptor | |
172 | */ | |
173 | if (fec->usedTbdIndex == (FEC_TBD_NUM - 1)) | |
174 | pUsedTbd->status = FEC_TBD_WRAP; | |
175 | else | |
176 | pUsedTbd->status = 0; | |
177 | ||
178 | /* | |
179 | * update some indeces for a correct handling of the TBD ring | |
180 | */ | |
181 | fec->cleanTbdNum++; | |
182 | fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM; | |
183 | } | |
184 | } | |
185 | ||
186 | /********************************************************************/ | |
187 | static void mpc8220_fec_set_hwaddr (mpc8220_fec_priv * fec, char *mac) | |
188 | { | |
189 | u8 currByte; /* byte for which to compute the CRC */ | |
190 | int byte; /* loop - counter */ | |
191 | int bit; /* loop - counter */ | |
192 | u32 crc = 0xffffffff; /* initial value */ | |
193 | ||
194 | /* | |
195 | * The algorithm used is the following: | |
196 | * we loop on each of the six bytes of the provided address, | |
197 | * and we compute the CRC by left-shifting the previous | |
198 | * value by one position, so that each bit in the current | |
199 | * byte of the address may contribute the calculation. If | |
200 | * the latter and the MSB in the CRC are different, then | |
201 | * the CRC value so computed is also ex-ored with the | |
202 | * "polynomium generator". The current byte of the address | |
203 | * is also shifted right by one bit at each iteration. | |
204 | * This is because the CRC generatore in hardware is implemented | |
205 | * as a shift-register with as many ex-ores as the radixes | |
206 | * in the polynomium. This suggests that we represent the | |
207 | * polynomiumm itself as a 32-bit constant. | |
208 | */ | |
209 | for (byte = 0; byte < 6; byte++) { | |
210 | currByte = mac[byte]; | |
211 | for (bit = 0; bit < 8; bit++) { | |
212 | if ((currByte & 0x01) ^ (crc & 0x01)) { | |
213 | crc >>= 1; | |
214 | crc = crc ^ 0xedb88320; | |
215 | } else { | |
216 | crc >>= 1; | |
217 | } | |
218 | currByte >>= 1; | |
219 | } | |
220 | } | |
221 | ||
222 | crc = crc >> 26; | |
223 | ||
224 | /* | |
225 | * Set individual hash table register | |
226 | */ | |
227 | if (crc >= 32) { | |
228 | fec->eth->iaddr1 = (1 << (crc - 32)); | |
229 | fec->eth->iaddr2 = 0; | |
230 | } else { | |
231 | fec->eth->iaddr1 = 0; | |
232 | fec->eth->iaddr2 = (1 << crc); | |
233 | } | |
234 | ||
235 | /* | |
236 | * Set physical address | |
237 | */ | |
238 | fec->eth->paddr1 = | |
239 | (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3]; | |
240 | fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808; | |
241 | } | |
242 | ||
243 | /********************************************************************/ | |
244 | static int mpc8220_fec_init (struct eth_device *dev, bd_t * bis) | |
245 | { | |
246 | mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; | |
247 | struct mpc8220_dma *dma = (struct mpc8220_dma *) MMAP_DMA; | |
248 | const u8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */ | |
249 | ||
ba91e26a | 250 | #ifdef DEBUG |
983fda83 WD |
251 | printf ("mpc8220_fec_init... Begin\n"); |
252 | #endif | |
253 | ||
254 | /* | |
255 | * Initialize RxBD/TxBD rings | |
256 | */ | |
257 | mpc8220_fec_rbd_init (fec); | |
258 | mpc8220_fec_tbd_init (fec); | |
259 | ||
260 | /* | |
261 | * Set up Pin Muxing for FEC 1 | |
262 | */ | |
263 | *(vu_long *) MMAP_PCFG = 0; | |
264 | *(vu_long *) (MMAP_PCFG + 4) = 0; | |
265 | /* | |
266 | * Clear FEC-Lite interrupt event register(IEVENT) | |
267 | */ | |
268 | fec->eth->ievent = 0xffffffff; | |
269 | ||
270 | /* | |
271 | * Set interrupt mask register | |
272 | */ | |
273 | fec->eth->imask = 0x00000000; | |
274 | ||
275 | /* | |
276 | * Set FEC-Lite receive control register(R_CNTRL): | |
277 | */ | |
278 | if (fec->xcv_type == SEVENWIRE) { | |
279 | /* | |
280 | * Frame length=1518; 7-wire mode | |
281 | */ | |
282 | fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */ | |
283 | } else { | |
284 | /* | |
285 | * Frame length=1518; MII mode; | |
286 | */ | |
287 | fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */ | |
288 | } | |
289 | ||
290 | fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */ | |
291 | if (fec->xcv_type != SEVENWIRE) { | |
292 | /* | |
293 | * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock | |
294 | * and do not drop the Preamble. | |
295 | */ | |
296 | /* tbd - rtm */ | |
297 | /*fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); */ | |
298 | /* No MII for 7-wire mode */ | |
299 | fec->eth->mii_speed = 0x00000030; | |
300 | } | |
301 | ||
302 | /* | |
303 | * Set Opcode/Pause Duration Register | |
304 | */ | |
305 | fec->eth->op_pause = 0x00010020; /*FIXME0xffff0020; */ | |
306 | ||
307 | /* | |
308 | * Set Rx FIFO alarm and granularity value | |
309 | */ | |
310 | fec->eth->rfifo_cntrl = 0x0c000000; | |
311 | fec->eth->rfifo_alarm = 0x0000030c; | |
ba91e26a | 312 | #ifdef DEBUG |
983fda83 WD |
313 | if (fec->eth->rfifo_status & 0x00700000) { |
314 | printf ("mpc8220_fec_init() RFIFO error\n"); | |
315 | } | |
316 | #endif | |
317 | ||
318 | /* | |
319 | * Set Tx FIFO granularity value | |
320 | */ | |
321 | /*fec->eth->tfifo_cntrl = 0x0c000000; */ /*tbd - rtm */ | |
322 | fec->eth->tfifo_cntrl = 0x0e000000; | |
ba91e26a | 323 | #ifdef DEBUG |
983fda83 WD |
324 | printf ("tfifo_status: 0x%08x\n", fec->eth->tfifo_status); |
325 | printf ("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm); | |
326 | #endif | |
327 | ||
328 | /* | |
329 | * Set transmit fifo watermark register(X_WMRK), default = 64 | |
330 | */ | |
331 | fec->eth->tfifo_alarm = 0x00000080; | |
332 | fec->eth->x_wmrk = 0x2; | |
333 | ||
334 | /* | |
335 | * Set individual address filter for unicast address | |
336 | * and set physical address registers. | |
337 | */ | |
77ddac94 | 338 | mpc8220_fec_set_hwaddr (fec, (char *)(dev->enetaddr)); |
983fda83 WD |
339 | |
340 | /* | |
341 | * Set multicast address filter | |
342 | */ | |
343 | fec->eth->gaddr1 = 0x00000000; | |
344 | fec->eth->gaddr2 = 0x00000000; | |
345 | ||
346 | /* | |
347 | * Turn ON cheater FSM: ???? | |
348 | */ | |
349 | fec->eth->xmit_fsm = 0x03000000; | |
350 | ||
351 | #if 1 | |
352 | /*#if defined(CONFIG_MPC5200)*/ | |
353 | /* | |
354 | * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't | |
355 | * work w/ the current receive task. | |
356 | */ | |
357 | dma->PtdCntrl |= 0x00000001; | |
358 | #endif | |
359 | ||
360 | /* | |
361 | * Set priority of different initiators | |
362 | */ | |
363 | dma->IPR0 = 7; /* always */ | |
364 | dma->IPR3 = 6; /* Eth RX */ | |
365 | dma->IPR4 = 5; /* Eth Tx */ | |
366 | ||
367 | /* | |
368 | * Clear SmartDMA task interrupt pending bits | |
369 | */ | |
370 | DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO); | |
371 | ||
372 | /* | |
373 | * Initialize SmartDMA parameters stored in SRAM | |
374 | */ | |
375 | *(int *) FEC_TBD_BASE = (int) fec->tbdBase; | |
376 | *(int *) FEC_RBD_BASE = (int) fec->rbdBase; | |
377 | *(int *) FEC_TBD_NEXT = (int) fec->tbdBase; | |
378 | *(int *) FEC_RBD_NEXT = (int) fec->rbdBase; | |
379 | ||
380 | if (fec->xcv_type != SEVENWIRE) { | |
381 | /* | |
382 | * Initialize PHY(LXT971A): | |
383 | * | |
384 | * Generally, on power up, the LXT971A reads its configuration | |
385 | * pins to check for forced operation, If not cofigured for | |
386 | * forced operation, it uses auto-negotiation/parallel detection | |
387 | * to automatically determine line operating conditions. | |
388 | * If the PHY device on the other side of the link supports | |
389 | * auto-negotiation, the LXT971A auto-negotiates with it | |
390 | * using Fast Link Pulse(FLP) Bursts. If the PHY partner does not | |
391 | * support auto-negotiation, the LXT971A automatically detects | |
392 | * the presence of either link pulses(10Mbps PHY) or Idle | |
393 | * symbols(100Mbps) and sets its operating conditions accordingly. | |
394 | * | |
395 | * When auto-negotiation is controlled by software, the following | |
396 | * steps are recommended. | |
397 | * | |
398 | * Note: | |
399 | * The physical address is dependent on hardware configuration. | |
400 | * | |
401 | */ | |
402 | int timeout = 1; | |
403 | u16 phyStatus; | |
404 | ||
405 | /* | |
406 | * Reset PHY, then delay 300ns | |
407 | */ | |
63ff004c | 408 | miiphy_write (dev->name, phyAddr, 0x0, 0x8000); |
983fda83 WD |
409 | udelay (1000); |
410 | ||
411 | if (fec->xcv_type == MII10) { | |
412 | /* | |
413 | * Force 10Base-T, FDX operation | |
414 | */ | |
ba91e26a | 415 | #ifdef DEBUG |
983fda83 WD |
416 | printf ("Forcing 10 Mbps ethernet link... "); |
417 | #endif | |
63ff004c | 418 | miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); |
983fda83 WD |
419 | /* |
420 | miiphy_write(fec, phyAddr, 0x0, 0x0100); | |
421 | */ | |
63ff004c | 422 | miiphy_write (dev->name, phyAddr, 0x0, 0x0180); |
983fda83 WD |
423 | |
424 | timeout = 20; | |
425 | do { /* wait for link status to go down */ | |
426 | udelay (10000); | |
427 | if ((timeout--) == 0) { | |
ba91e26a | 428 | #ifdef DEBUG |
983fda83 WD |
429 | printf ("hmmm, should not have waited..."); |
430 | #endif | |
431 | break; | |
432 | } | |
63ff004c | 433 | miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); |
ba91e26a | 434 | #ifdef DEBUG |
983fda83 WD |
435 | printf ("="); |
436 | #endif | |
437 | } while ((phyStatus & 0x0004)); /* !link up */ | |
438 | ||
439 | timeout = 1000; | |
440 | do { /* wait for link status to come back up */ | |
441 | udelay (10000); | |
442 | if ((timeout--) == 0) { | |
443 | printf ("failed. Link is down.\n"); | |
444 | break; | |
445 | } | |
63ff004c | 446 | miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); |
ba91e26a | 447 | #ifdef DEBUG |
983fda83 WD |
448 | printf ("+"); |
449 | #endif | |
450 | } while (!(phyStatus & 0x0004)); /* !link up */ | |
451 | ||
ba91e26a | 452 | #ifdef DEBUG |
983fda83 WD |
453 | printf ("done.\n"); |
454 | #endif | |
455 | } else { /* MII100 */ | |
456 | /* | |
457 | * Set the auto-negotiation advertisement register bits | |
458 | */ | |
63ff004c | 459 | miiphy_write (dev->name, phyAddr, 0x4, 0x01e1); |
983fda83 WD |
460 | |
461 | /* | |
462 | * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation | |
463 | */ | |
63ff004c | 464 | miiphy_write (dev->name, phyAddr, 0x0, 0x1200); |
983fda83 WD |
465 | |
466 | /* | |
467 | * Wait for AN completion | |
468 | */ | |
469 | timeout = 5000; | |
470 | do { | |
471 | udelay (1000); | |
472 | ||
473 | if ((timeout--) == 0) { | |
ba91e26a | 474 | #ifdef DEBUG |
983fda83 WD |
475 | printf ("PHY auto neg 0 failed...\n"); |
476 | #endif | |
477 | return -1; | |
478 | } | |
479 | ||
63ff004c | 480 | if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) != |
983fda83 | 481 | 0) { |
ba91e26a | 482 | #ifdef DEBUG |
983fda83 WD |
483 | printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus); |
484 | #endif | |
485 | return -1; | |
486 | } | |
487 | } while (!(phyStatus & 0x0004)); | |
488 | ||
ba91e26a | 489 | #ifdef DEBUG |
983fda83 WD |
490 | printf ("PHY auto neg complete! \n"); |
491 | #endif | |
492 | } | |
493 | ||
494 | } | |
495 | ||
496 | /* | |
497 | * Enable FEC-Lite controller | |
498 | */ | |
499 | fec->eth->ecntrl |= 0x00000006; | |
500 | ||
ba91e26a | 501 | #ifdef DEBUG |
983fda83 | 502 | if (fec->xcv_type != SEVENWIRE) |
63ff004c | 503 | mpc8220_fec_phydump (dev->name); |
983fda83 WD |
504 | #endif |
505 | ||
506 | /* | |
507 | * Enable SmartDMA receive task | |
508 | */ | |
509 | DMA_TASK_ENABLE (FEC_RECV_TASK_NO); | |
510 | ||
ba91e26a | 511 | #ifdef DEBUG |
983fda83 WD |
512 | printf ("mpc8220_fec_init... Done \n"); |
513 | #endif | |
514 | ||
515 | return 1; | |
516 | } | |
517 | ||
518 | /********************************************************************/ | |
519 | static void mpc8220_fec_halt (struct eth_device *dev) | |
520 | { | |
521 | mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; | |
522 | int counter = 0xffff; | |
523 | ||
ba91e26a | 524 | #ifdef DEBUG |
983fda83 | 525 | if (fec->xcv_type != SEVENWIRE) |
63ff004c | 526 | mpc8220_fec_phydump (dev->name); |
983fda83 WD |
527 | #endif |
528 | ||
529 | /* | |
530 | * mask FEC chip interrupts | |
531 | */ | |
532 | fec->eth->imask = 0; | |
533 | ||
534 | /* | |
535 | * issue graceful stop command to the FEC transmitter if necessary | |
536 | */ | |
537 | fec->eth->x_cntrl |= 0x00000001; | |
538 | ||
539 | /* | |
540 | * wait for graceful stop to register | |
541 | */ | |
542 | while ((counter--) && (!(fec->eth->ievent & 0x10000000))); | |
543 | ||
544 | /* | |
545 | * Disable SmartDMA tasks | |
546 | */ | |
547 | DMA_TASK_DISABLE (FEC_XMIT_TASK_NO); | |
548 | DMA_TASK_DISABLE (FEC_RECV_TASK_NO); | |
549 | ||
550 | /* | |
551 | * Disable the Ethernet Controller | |
552 | */ | |
553 | fec->eth->ecntrl &= 0xfffffffd; | |
554 | ||
555 | /* | |
556 | * Clear FIFO status registers | |
557 | */ | |
558 | fec->eth->rfifo_status &= 0x00700000; | |
559 | fec->eth->tfifo_status &= 0x00700000; | |
560 | ||
561 | fec->eth->reset_cntrl = 0x01000000; | |
562 | ||
563 | /* | |
564 | * Issue a reset command to the FEC chip | |
565 | */ | |
566 | fec->eth->ecntrl |= 0x1; | |
567 | ||
568 | /* | |
569 | * wait at least 16 clock cycles | |
570 | */ | |
571 | udelay (10); | |
572 | ||
ba91e26a | 573 | #ifdef DEBUG |
983fda83 WD |
574 | printf ("Ethernet task stopped\n"); |
575 | #endif | |
576 | } | |
577 | ||
ba91e26a | 578 | #ifdef DEBUG |
983fda83 WD |
579 | /********************************************************************/ |
580 | ||
63ff004c | 581 | static void tfifo_print (char *devname, mpc8220_fec_priv * fec) |
983fda83 WD |
582 | { |
583 | u16 phyAddr = CONFIG_PHY_ADDR; | |
584 | u16 phyStatus; | |
585 | ||
586 | if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr) | |
587 | || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) { | |
588 | ||
63ff004c | 589 | miiphy_read (devname, phyAddr, 0x1, &phyStatus); |
983fda83 WD |
590 | printf ("\nphyStatus: 0x%04x\n", phyStatus); |
591 | printf ("ecntrl: 0x%08x\n", fec->eth->ecntrl); | |
592 | printf ("ievent: 0x%08x\n", fec->eth->ievent); | |
593 | printf ("x_status: 0x%08x\n", fec->eth->x_status); | |
594 | printf ("tfifo: status 0x%08x\n", fec->eth->tfifo_status); | |
595 | ||
596 | printf (" control 0x%08x\n", fec->eth->tfifo_cntrl); | |
597 | printf (" lrfp 0x%08x\n", fec->eth->tfifo_lrf_ptr); | |
598 | printf (" lwfp 0x%08x\n", fec->eth->tfifo_lwf_ptr); | |
599 | printf (" alarm 0x%08x\n", fec->eth->tfifo_alarm); | |
600 | printf (" readptr 0x%08x\n", fec->eth->tfifo_rdptr); | |
601 | printf (" writptr 0x%08x\n", fec->eth->tfifo_wrptr); | |
602 | } | |
603 | } | |
604 | ||
63ff004c | 605 | static void rfifo_print (char *devname, mpc8220_fec_priv * fec) |
983fda83 WD |
606 | { |
607 | u16 phyAddr = CONFIG_PHY_ADDR; | |
608 | u16 phyStatus; | |
609 | ||
610 | if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr) | |
611 | || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) { | |
612 | ||
63ff004c | 613 | miiphy_read (devname, phyAddr, 0x1, &phyStatus); |
983fda83 WD |
614 | printf ("\nphyStatus: 0x%04x\n", phyStatus); |
615 | printf ("ecntrl: 0x%08x\n", fec->eth->ecntrl); | |
616 | printf ("ievent: 0x%08x\n", fec->eth->ievent); | |
617 | printf ("x_status: 0x%08x\n", fec->eth->x_status); | |
618 | printf ("rfifo: status 0x%08x\n", fec->eth->rfifo_status); | |
619 | ||
620 | printf (" control 0x%08x\n", fec->eth->rfifo_cntrl); | |
621 | printf (" lrfp 0x%08x\n", fec->eth->rfifo_lrf_ptr); | |
622 | printf (" lwfp 0x%08x\n", fec->eth->rfifo_lwf_ptr); | |
623 | printf (" alarm 0x%08x\n", fec->eth->rfifo_alarm); | |
624 | printf (" readptr 0x%08x\n", fec->eth->rfifo_rdptr); | |
625 | printf (" writptr 0x%08x\n", fec->eth->rfifo_wrptr); | |
626 | } | |
627 | } | |
628 | #endif /* DEBUG */ | |
629 | ||
630 | /********************************************************************/ | |
631 | ||
632 | static int mpc8220_fec_send (struct eth_device *dev, volatile void *eth_data, | |
633 | int data_length) | |
634 | { | |
635 | /* | |
636 | * This routine transmits one frame. This routine only accepts | |
637 | * 6-byte Ethernet addresses. | |
638 | */ | |
639 | mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; | |
640 | FEC_TBD *pTbd; | |
641 | ||
ba91e26a | 642 | #ifdef DEBUG |
983fda83 | 643 | printf ("tbd status: 0x%04x\n", fec->tbdBase[0].status); |
63ff004c | 644 | tfifo_print (dev->name, fec); |
983fda83 WD |
645 | #endif |
646 | ||
647 | /* | |
648 | * Clear Tx BD ring at first | |
649 | */ | |
650 | mpc8220_fec_tbd_scrub (fec); | |
651 | ||
652 | /* | |
653 | * Check for valid length of data. | |
654 | */ | |
655 | if ((data_length > 1500) || (data_length <= 0)) { | |
656 | return -1; | |
657 | } | |
658 | ||
659 | /* | |
660 | * Check the number of vacant TxBDs. | |
661 | */ | |
662 | if (fec->cleanTbdNum < 1) { | |
ba91e26a | 663 | #ifdef DEBUG |
983fda83 WD |
664 | printf ("No available TxBDs ...\n"); |
665 | #endif | |
666 | return -1; | |
667 | } | |
668 | ||
669 | /* | |
670 | * Get the first TxBD to send the mac header | |
671 | */ | |
672 | pTbd = &fec->tbdBase[fec->tbdIndex]; | |
673 | pTbd->dataLength = data_length; | |
674 | pTbd->dataPointer = (u32) eth_data; | |
675 | pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY; | |
676 | fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM; | |
677 | ||
ba91e26a | 678 | #ifdef DEBUG |
983fda83 WD |
679 | printf ("DMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex); |
680 | #endif | |
681 | ||
682 | /* | |
683 | * Kick the MII i/f | |
684 | */ | |
685 | if (fec->xcv_type != SEVENWIRE) { | |
686 | u16 phyStatus; | |
687 | ||
63ff004c | 688 | miiphy_read (dev->name, 0, 0x1, &phyStatus); |
983fda83 WD |
689 | } |
690 | ||
691 | /* | |
692 | * Enable SmartDMA transmit task | |
693 | */ | |
694 | ||
ba91e26a | 695 | #ifdef DEBUG |
63ff004c | 696 | tfifo_print (dev->name, fec); |
983fda83 WD |
697 | #endif |
698 | ||
699 | DMA_TASK_ENABLE (FEC_XMIT_TASK_NO); | |
700 | ||
ba91e26a | 701 | #ifdef DEBUG |
63ff004c | 702 | tfifo_print (dev->name, fec); |
983fda83 WD |
703 | #endif |
704 | ||
ba91e26a | 705 | #ifdef DEBUG |
983fda83 WD |
706 | printf ("+"); |
707 | #endif | |
708 | ||
709 | fec->cleanTbdNum -= 1; | |
710 | ||
ba91e26a | 711 | #ifdef DEBUG |
983fda83 WD |
712 | printf ("smartDMA ethernet Tx task enabled\n"); |
713 | #endif | |
714 | /* | |
715 | * wait until frame is sent . | |
716 | */ | |
717 | while (pTbd->status & FEC_TBD_READY) { | |
718 | udelay (10); | |
ba91e26a | 719 | #ifdef DEBUG |
983fda83 WD |
720 | printf ("TDB status = %04x\n", pTbd->status); |
721 | #endif | |
722 | } | |
723 | ||
724 | return 0; | |
725 | } | |
726 | ||
727 | ||
728 | /********************************************************************/ | |
729 | static int mpc8220_fec_recv (struct eth_device *dev) | |
730 | { | |
731 | /* | |
732 | * This command pulls one frame from the card | |
733 | */ | |
734 | mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; | |
735 | FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex]; | |
736 | unsigned long ievent; | |
737 | int frame_length, len = 0; | |
738 | NBUF *frame; | |
739 | ||
ba91e26a | 740 | #ifdef DEBUG |
983fda83 | 741 | printf ("mpc8220_fec_recv %d Start...\n", fec->rbdIndex); |
983fda83 WD |
742 | printf ("-"); |
743 | #endif | |
744 | ||
745 | /* | |
746 | * Check if any critical events have happened | |
747 | */ | |
748 | ievent = fec->eth->ievent; | |
749 | fec->eth->ievent = ievent; | |
750 | if (ievent & 0x20060000) { | |
751 | /* BABT, Rx/Tx FIFO errors */ | |
752 | mpc8220_fec_halt (dev); | |
753 | mpc8220_fec_init (dev, NULL); | |
754 | return 0; | |
755 | } | |
756 | if (ievent & 0x80000000) { | |
757 | /* Heartbeat error */ | |
758 | fec->eth->x_cntrl |= 0x00000001; | |
759 | } | |
760 | if (ievent & 0x10000000) { | |
761 | /* Graceful stop complete */ | |
762 | if (fec->eth->x_cntrl & 0x00000001) { | |
763 | mpc8220_fec_halt (dev); | |
764 | fec->eth->x_cntrl &= ~0x00000001; | |
765 | mpc8220_fec_init (dev, NULL); | |
766 | } | |
767 | } | |
768 | ||
769 | if (!(pRbd->status & FEC_RBD_EMPTY)) { | |
770 | if ((pRbd->status & FEC_RBD_LAST) | |
771 | && !(pRbd->status & FEC_RBD_ERR) | |
772 | && ((pRbd->dataLength - 4) > 14)) { | |
773 | ||
774 | /* | |
775 | * Get buffer address and size | |
776 | */ | |
777 | frame = (NBUF *) pRbd->dataPointer; | |
778 | frame_length = pRbd->dataLength - 4; | |
779 | ||
780 | #if (0) | |
781 | { | |
782 | int i; | |
783 | ||
784 | printf ("recv data hdr:"); | |
785 | for (i = 0; i < 14; i++) | |
786 | printf ("%x ", *(frame->head + i)); | |
787 | printf ("\n"); | |
788 | } | |
789 | #endif | |
790 | /* | |
791 | * Fill the buffer and pass it to upper layers | |
792 | */ | |
793 | /* memcpy(buff, frame->head, 14); | |
794 | memcpy(buff + 14, frame->data, frame_length);*/ | |
795 | NetReceive ((volatile uchar *) pRbd->dataPointer, | |
796 | frame_length); | |
797 | len = frame_length; | |
798 | } | |
799 | /* | |
800 | * Reset buffer descriptor as empty | |
801 | */ | |
802 | mpc8220_fec_rbd_clean (fec, pRbd); | |
803 | } | |
804 | DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO); | |
805 | return len; | |
806 | } | |
807 | ||
808 | ||
809 | /********************************************************************/ | |
810 | int mpc8220_fec_initialize (bd_t * bis) | |
811 | { | |
812 | mpc8220_fec_priv *fec; | |
813 | ||
e2ffd59b | 814 | #ifdef CONFIG_HAS_ETH1 |
983fda83 WD |
815 | mpc8220_fec_priv *fec2; |
816 | #endif | |
817 | struct eth_device *dev; | |
818 | char *tmp, *end; | |
819 | char env_enetaddr[6]; | |
820 | ||
e2ffd59b | 821 | #ifdef CONFIG_HAS_ETH1 |
983fda83 WD |
822 | char env_enet1addr[6]; |
823 | #endif | |
824 | int i; | |
825 | ||
826 | fec = (mpc8220_fec_priv *) malloc (sizeof (*fec)); | |
827 | dev = (struct eth_device *) malloc (sizeof (*dev)); | |
828 | memset (dev, 0, sizeof *dev); | |
829 | ||
830 | fec->eth = (ethernet_regs *) MMAP_FEC1; | |
e2ffd59b | 831 | #ifdef CONFIG_HAS_ETH1 |
983fda83 WD |
832 | fec2 = (mpc8220_fec_priv *) malloc (sizeof (*fec)); |
833 | fec2->eth = (ethernet_regs *) MMAP_FEC2; | |
834 | #endif | |
835 | fec->tbdBase = (FEC_TBD *) FEC_BD_BASE; | |
836 | fec->rbdBase = | |
837 | (FEC_RBD *) (FEC_BD_BASE + FEC_TBD_NUM * sizeof (FEC_TBD)); | |
838 | fec->xcv_type = MII100; | |
839 | ||
840 | dev->priv = (void *) fec; | |
841 | dev->iobase = MMAP_FEC1; | |
842 | dev->init = mpc8220_fec_init; | |
843 | dev->halt = mpc8220_fec_halt; | |
844 | dev->send = mpc8220_fec_send; | |
845 | dev->recv = mpc8220_fec_recv; | |
846 | ||
847 | sprintf (dev->name, "FEC ETHERNET"); | |
848 | eth_register (dev); | |
849 | ||
4431283c | 850 | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) |
63ff004c MB |
851 | miiphy_register (dev->name, |
852 | fec8220_miiphy_read, fec8220_miiphy_write); | |
853 | #endif | |
854 | ||
983fda83 WD |
855 | /* |
856 | * Try to set the mac address now. The fec mac address is | |
857 | * a garbage after reset. When not using fec for booting | |
858 | * the Linux fec driver will try to work with this garbage. | |
859 | */ | |
860 | tmp = getenv ("ethaddr"); | |
861 | if (tmp) { | |
862 | for (i = 0; i < 6; i++) { | |
863 | env_enetaddr[i] = | |
864 | tmp ? simple_strtoul (tmp, &end, 16) : 0; | |
865 | if (tmp) | |
866 | tmp = (*end) ? end + 1 : end; | |
867 | } | |
868 | mpc8220_fec_set_hwaddr (fec, env_enetaddr); | |
869 | } | |
e2ffd59b | 870 | #ifdef CONFIG_HAS_ETH1 |
983fda83 WD |
871 | tmp = getenv ("eth1addr"); |
872 | if (tmp) { | |
873 | for (i = 0; i < 6; i++) { | |
874 | env_enet1addr[i] = | |
875 | tmp ? simple_strtoul (tmp, &end, 16) : 0; | |
876 | if (tmp) | |
877 | tmp = (*end) ? end + 1 : end; | |
878 | } | |
879 | mpc8220_fec_set_hwaddr (fec2, env_enet1addr); | |
880 | } | |
881 | #endif | |
882 | ||
883 | return 1; | |
884 | } | |
885 | ||
886 | /* MII-interface related functions */ | |
887 | /********************************************************************/ | |
63ff004c | 888 | int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal) |
983fda83 WD |
889 | { |
890 | ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1; | |
891 | u32 reg; /* convenient holder for the PHY register */ | |
892 | u32 phy; /* convenient holder for the PHY */ | |
893 | int timeout = 0xffff; | |
894 | ||
895 | /* | |
896 | * reading from any PHY's register is done by properly | |
897 | * programming the FEC's MII data register. | |
898 | */ | |
899 | reg = regAddr << FEC_MII_DATA_RA_SHIFT; | |
900 | phy = phyAddr << FEC_MII_DATA_PA_SHIFT; | |
901 | ||
902 | eth->mii_data = | |
903 | (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | |
904 | | reg); | |
905 | ||
906 | /* | |
907 | * wait for the related interrupt | |
908 | */ | |
909 | while ((timeout--) && (!(eth->ievent & 0x00800000))); | |
910 | ||
911 | if (timeout == 0) { | |
ba91e26a | 912 | #ifdef DEBUG |
983fda83 WD |
913 | printf ("Read MDIO failed...\n"); |
914 | #endif | |
915 | return -1; | |
916 | } | |
917 | ||
918 | /* | |
919 | * clear mii interrupt bit | |
920 | */ | |
921 | eth->ievent = 0x00800000; | |
922 | ||
923 | /* | |
924 | * it's now safe to read the PHY's register | |
925 | */ | |
926 | *retVal = (u16) eth->mii_data; | |
927 | ||
928 | return 0; | |
929 | } | |
930 | ||
931 | /********************************************************************/ | |
63ff004c | 932 | int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data) |
983fda83 WD |
933 | { |
934 | ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1; | |
935 | u32 reg; /* convenient holder for the PHY register */ | |
936 | u32 phy; /* convenient holder for the PHY */ | |
937 | int timeout = 0xffff; | |
938 | ||
939 | reg = regAddr << FEC_MII_DATA_RA_SHIFT; | |
940 | phy = phyAddr << FEC_MII_DATA_PA_SHIFT; | |
941 | ||
942 | eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | | |
943 | FEC_MII_DATA_TA | phy | reg | data); | |
944 | ||
945 | /* | |
946 | * wait for the MII interrupt | |
947 | */ | |
948 | while ((timeout--) && (!(eth->ievent & 0x00800000))); | |
949 | ||
950 | if (timeout == 0) { | |
ba91e26a | 951 | #ifdef DEBUG |
983fda83 WD |
952 | printf ("Write MDIO failed...\n"); |
953 | #endif | |
954 | return -1; | |
955 | } | |
956 | ||
957 | /* | |
958 | * clear MII interrupt bit | |
959 | */ | |
960 | eth->ievent = 0x00800000; | |
961 | ||
962 | return 0; | |
963 | } | |
964 | ||
ba91e26a | 965 | #ifdef DEBUG |
983fda83 WD |
966 | static u32 local_crc32 (char *string, unsigned int crc_value, int len) |
967 | { | |
968 | int i; | |
969 | char c; | |
970 | unsigned int crc, count; | |
971 | ||
972 | /* | |
973 | * crc32 algorithm | |
974 | */ | |
975 | /* | |
976 | * crc = 0xffffffff; * The initialized value should be 0xffffffff | |
977 | */ | |
978 | crc = crc_value; | |
979 | ||
980 | for (i = len; --i >= 0;) { | |
981 | c = *string++; | |
982 | for (count = 0; count < 8; count++) { | |
983 | if ((c & 0x01) ^ (crc & 0x01)) { | |
984 | crc >>= 1; | |
985 | crc = crc ^ 0xedb88320; | |
986 | } else { | |
987 | crc >>= 1; | |
988 | } | |
989 | c >>= 1; | |
990 | } | |
991 | } | |
992 | ||
993 | /* | |
994 | * In big endian system, do byte swaping for crc value | |
995 | */ | |
996 | return crc; | |
997 | } | |
998 | #endif /* DEBUG */ | |
999 | ||
1000 | #endif /* CONFIG_MPC8220_FEC */ |