]>
Commit | Line | Data |
---|---|---|
8993e54b RJ |
1 | /* |
2 | * (C) Copyright 2003-2007 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * Derived from the MPC8xx FEC driver. | |
6 | * Adapted for MPC512x by Grzegorz Bernacki <gjb@semihalf.com> | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <mpc512x.h> | |
11 | #include <malloc.h> | |
12 | #include <net.h> | |
a0aad08f | 13 | #include <netdev.h> |
8993e54b | 14 | #include <miiphy.h> |
6b5049d0 | 15 | #include "mpc512x_fec.h" |
8993e54b RJ |
16 | |
17 | DECLARE_GLOBAL_DATA_PTR; | |
18 | ||
19 | #define DEBUG 0 | |
20 | ||
afaac86f | 21 | #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ |
8993e54b RJ |
22 | defined(CONFIG_MPC512x_FEC) |
23 | ||
afaac86f | 24 | #if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) |
8993e54b RJ |
25 | #error "CONFIG_MII has to be defined!" |
26 | #endif | |
27 | ||
28 | #if (DEBUG & 0x40) | |
29 | static uint32 local_crc32(char *string, unsigned int crc_value, int len); | |
30 | #endif | |
31 | ||
32 | int fec512x_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal); | |
33 | int fec512x_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data); | |
34 | int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis); | |
35 | ||
7a888d6b | 36 | static uchar rx_buff[FEC_BUFFER_SIZE]; |
08e2e5fc GB |
37 | static int rx_buff_idx = 0; |
38 | ||
8993e54b RJ |
39 | /********************************************************************/ |
40 | #if (DEBUG & 0x2) | |
41 | static void mpc512x_fec_phydump (char *devname) | |
42 | { | |
43 | uint16 phyStatus, i; | |
44 | uint8 phyAddr = CONFIG_PHY_ADDR; | |
45 | uint8 reg_mask[] = { | |
46 | /* regs to print: 0...8, 21,27,31 */ | |
47 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, | |
48 | 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, | |
49 | }; | |
50 | ||
51 | for (i = 0; i < 32; i++) { | |
52 | if (reg_mask[i]) { | |
53 | miiphy_read (devname, phyAddr, i, &phyStatus); | |
54 | printf ("Mii reg %d: 0x%04x\n", i, phyStatus); | |
55 | } | |
56 | } | |
57 | } | |
58 | #endif | |
59 | ||
60 | /********************************************************************/ | |
61 | static int mpc512x_fec_bd_init (mpc512x_fec_priv *fec) | |
62 | { | |
63 | int ix; | |
64 | ||
65 | /* | |
66 | * Receive BDs init | |
67 | */ | |
68 | for (ix = 0; ix < FEC_RBD_NUM; ix++) { | |
69 | fec->bdBase->rbd[ix].dataPointer = (uint32)&fec->bdBase->recv_frames[ix]; | |
70 | fec->bdBase->rbd[ix].status = FEC_RBD_EMPTY; | |
71 | fec->bdBase->rbd[ix].dataLength = 0; | |
72 | } | |
73 | ||
74 | /* | |
75 | * have the last RBD to close the ring | |
76 | */ | |
77 | fec->bdBase->rbd[ix - 1].status |= FEC_RBD_WRAP; | |
78 | fec->rbdIndex = 0; | |
79 | ||
80 | /* | |
81 | * Trasmit BDs init | |
82 | */ | |
83 | for (ix = 0; ix < FEC_TBD_NUM; ix++) { | |
b1b54e35 WD |
84 | fec->bdBase->tbd[ix].status = 0; |
85 | } | |
8993e54b | 86 | |
b1b54e35 WD |
87 | /* |
88 | * Have the last TBD to close the ring | |
89 | */ | |
90 | fec->bdBase->tbd[ix - 1].status |= FEC_TBD_WRAP; | |
8993e54b | 91 | |
b1b54e35 WD |
92 | /* |
93 | * Initialize some indices | |
94 | */ | |
95 | fec->tbdIndex = 0; | |
96 | fec->usedTbdIndex = 0; | |
97 | fec->cleanTbdNum = FEC_TBD_NUM; | |
8993e54b RJ |
98 | |
99 | return 0; | |
100 | } | |
101 | ||
102 | /********************************************************************/ | |
103 | static void mpc512x_fec_rbd_clean (mpc512x_fec_priv *fec, volatile FEC_RBD * pRbd) | |
104 | { | |
105 | /* | |
106 | * Reset buffer descriptor as empty | |
107 | */ | |
108 | if ((fec->rbdIndex) == (FEC_RBD_NUM - 1)) | |
109 | pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY); | |
110 | else | |
111 | pRbd->status = FEC_RBD_EMPTY; | |
112 | ||
113 | pRbd->dataLength = 0; | |
114 | ||
115 | /* | |
116 | * Increment BD count | |
117 | */ | |
118 | fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM; | |
119 | ||
120 | /* | |
121 | * Now, we have an empty RxBD, notify FEC | |
122 | */ | |
123 | fec->eth->r_des_active = 0x01000000; /* Descriptor polling active */ | |
124 | } | |
125 | ||
126 | /********************************************************************/ | |
127 | static void mpc512x_fec_tbd_scrub (mpc512x_fec_priv *fec) | |
128 | { | |
129 | volatile FEC_TBD *pUsedTbd; | |
130 | ||
131 | #if (DEBUG & 0x1) | |
132 | printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n", | |
133 | fec->cleanTbdNum, fec->usedTbdIndex); | |
134 | #endif | |
135 | ||
136 | /* | |
137 | * process all the consumed TBDs | |
138 | */ | |
139 | while (fec->cleanTbdNum < FEC_TBD_NUM) { | |
140 | pUsedTbd = &fec->bdBase->tbd[fec->usedTbdIndex]; | |
141 | if (pUsedTbd->status & FEC_TBD_READY) { | |
142 | #if (DEBUG & 0x20) | |
143 | printf ("Cannot clean TBD %d, in use\n", fec->usedTbdIndex); | |
144 | #endif | |
145 | return; | |
146 | } | |
147 | ||
148 | /* | |
149 | * clean this buffer descriptor | |
150 | */ | |
151 | if (fec->usedTbdIndex == (FEC_TBD_NUM - 1)) | |
152 | pUsedTbd->status = FEC_TBD_WRAP; | |
153 | else | |
154 | pUsedTbd->status = 0; | |
155 | ||
156 | /* | |
157 | * update some indeces for a correct handling of the TBD ring | |
158 | */ | |
159 | fec->cleanTbdNum++; | |
160 | fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM; | |
161 | } | |
162 | } | |
163 | ||
164 | /********************************************************************/ | |
165 | static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, char *mac) | |
166 | { | |
167 | uint8 currByte; /* byte for which to compute the CRC */ | |
168 | int byte; /* loop - counter */ | |
169 | int bit; /* loop - counter */ | |
170 | uint32 crc = 0xffffffff; /* initial value */ | |
171 | ||
172 | /* | |
173 | * The algorithm used is the following: | |
174 | * we loop on each of the six bytes of the provided address, | |
175 | * and we compute the CRC by left-shifting the previous | |
176 | * value by one position, so that each bit in the current | |
177 | * byte of the address may contribute the calculation. If | |
178 | * the latter and the MSB in the CRC are different, then | |
179 | * the CRC value so computed is also ex-ored with the | |
180 | * "polynomium generator". The current byte of the address | |
181 | * is also shifted right by one bit at each iteration. | |
182 | * This is because the CRC generatore in hardware is implemented | |
183 | * as a shift-register with as many ex-ores as the radixes | |
184 | * in the polynomium. This suggests that we represent the | |
185 | * polynomiumm itself as a 32-bit constant. | |
186 | */ | |
187 | for (byte = 0; byte < 6; byte++) { | |
188 | currByte = mac[byte]; | |
189 | for (bit = 0; bit < 8; bit++) { | |
190 | if ((currByte & 0x01) ^ (crc & 0x01)) { | |
191 | crc >>= 1; | |
192 | crc = crc ^ 0xedb88320; | |
193 | } else { | |
194 | crc >>= 1; | |
195 | } | |
196 | currByte >>= 1; | |
197 | } | |
198 | } | |
199 | ||
200 | crc = crc >> 26; | |
201 | ||
202 | /* | |
203 | * Set individual hash table register | |
204 | */ | |
205 | if (crc >= 32) { | |
206 | fec->eth->iaddr1 = (1 << (crc - 32)); | |
207 | fec->eth->iaddr2 = 0; | |
208 | } else { | |
209 | fec->eth->iaddr1 = 0; | |
210 | fec->eth->iaddr2 = (1 << crc); | |
211 | } | |
212 | ||
213 | /* | |
214 | * Set physical address | |
215 | */ | |
216 | fec->eth->paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3]; | |
217 | fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808; | |
218 | } | |
219 | ||
220 | /********************************************************************/ | |
221 | static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis) | |
222 | { | |
223 | mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; | |
224 | ||
225 | #if (DEBUG & 0x1) | |
226 | printf ("mpc512x_fec_init... Begin\n"); | |
227 | #endif | |
228 | ||
229 | /* Set interrupt mask register */ | |
230 | fec->eth->imask = 0x00000000; | |
231 | ||
232 | /* Clear FEC-Lite interrupt event register(IEVENT) */ | |
233 | fec->eth->ievent = 0xffffffff; | |
234 | ||
235 | /* Set transmit fifo watermark register(X_WMRK), default = 64 */ | |
236 | fec->eth->x_wmrk = 0x0; | |
237 | ||
238 | /* Set Opcode/Pause Duration Register */ | |
239 | fec->eth->op_pause = 0x00010020; | |
240 | ||
7a888d6b GB |
241 | /* Frame length=1522; MII mode */ |
242 | fec->eth->r_cntrl = (FEC_MAX_FRAME_LEN << 16) | 0x24; | |
8993e54b RJ |
243 | |
244 | /* Half-duplex, heartbeat disabled */ | |
b1b54e35 | 245 | fec->eth->x_cntrl = 0x00000000; |
8993e54b RJ |
246 | |
247 | /* Enable MIB counters */ | |
248 | fec->eth->mib_control = 0x0; | |
249 | ||
250 | /* Setup recv fifo start and buff size */ | |
251 | fec->eth->r_fstart = 0x500; | |
7a888d6b | 252 | fec->eth->r_buff_size = FEC_BUFFER_SIZE; |
8993e54b RJ |
253 | |
254 | /* Setup BD base addresses */ | |
255 | fec->eth->r_des_start = (uint32)fec->bdBase->rbd; | |
256 | fec->eth->x_des_start = (uint32)fec->bdBase->tbd; | |
257 | ||
258 | /* DMA Control */ | |
259 | fec->eth->dma_control = 0xc0000000; | |
260 | ||
261 | /* Enable FEC */ | |
262 | fec->eth->ecntrl |= 0x00000006; | |
263 | ||
264 | /* Initilize addresses and status words of BDs */ | |
265 | mpc512x_fec_bd_init (fec); | |
266 | ||
b1b54e35 | 267 | /* Descriptor polling active */ |
8993e54b RJ |
268 | fec->eth->r_des_active = 0x01000000; |
269 | ||
270 | #if (DEBUG & 0x1) | |
271 | printf("mpc512x_fec_init... Done \n"); | |
272 | #endif | |
273 | return 1; | |
274 | } | |
275 | ||
276 | /********************************************************************/ | |
277 | int mpc512x_fec_init_phy (struct eth_device *dev, bd_t * bis) | |
278 | { | |
279 | mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; | |
280 | const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */ | |
281 | int timeout = 1; | |
282 | uint16 phyStatus; | |
283 | ||
284 | #if (DEBUG & 0x1) | |
285 | printf ("mpc512x_fec_init_phy... Begin\n"); | |
286 | #endif | |
287 | ||
288 | /* | |
289 | * Clear FEC-Lite interrupt event register(IEVENT) | |
290 | */ | |
291 | fec->eth->ievent = 0xffffffff; | |
292 | ||
293 | /* | |
294 | * Set interrupt mask register | |
295 | */ | |
296 | fec->eth->imask = 0x00000000; | |
297 | ||
298 | if (fec->xcv_type != SEVENWIRE) { | |
299 | /* | |
300 | * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock | |
301 | * and do not drop the Preamble. | |
302 | */ | |
5d49e0e1 | 303 | fec->eth->mii_speed = (((gd->ips_clk / 1000000) / 5) + 1) << 1; |
8993e54b RJ |
304 | |
305 | /* | |
306 | * Reset PHY, then delay 300ns | |
307 | */ | |
308 | miiphy_write (dev->name, phyAddr, 0x0, 0x8000); | |
309 | udelay (1000); | |
310 | ||
311 | if (fec->xcv_type == MII10) { | |
312 | /* | |
313 | * Force 10Base-T, FDX operation | |
314 | */ | |
315 | #if (DEBUG & 0x2) | |
316 | printf ("Forcing 10 Mbps ethernet link... "); | |
317 | #endif | |
318 | miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); | |
b1b54e35 | 319 | |
8993e54b RJ |
320 | miiphy_write (dev->name, phyAddr, 0x0, 0x0180); |
321 | ||
322 | timeout = 20; | |
323 | do { /* wait for link status to go down */ | |
324 | udelay (10000); | |
325 | if ((timeout--) == 0) { | |
326 | #if (DEBUG & 0x2) | |
327 | printf ("hmmm, should not have waited..."); | |
328 | #endif | |
329 | break; | |
330 | } | |
331 | miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); | |
332 | #if (DEBUG & 0x2) | |
333 | printf ("="); | |
334 | #endif | |
335 | } while ((phyStatus & 0x0004)); /* !link up */ | |
336 | ||
337 | timeout = 1000; | |
338 | do { /* wait for link status to come back up */ | |
339 | udelay (10000); | |
340 | if ((timeout--) == 0) { | |
341 | printf ("failed. Link is down.\n"); | |
342 | break; | |
343 | } | |
344 | miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); | |
345 | #if (DEBUG & 0x2) | |
346 | printf ("+"); | |
347 | #endif | |
348 | } while (!(phyStatus & 0x0004)); /* !link up */ | |
349 | ||
350 | #if (DEBUG & 0x2) | |
351 | printf ("done.\n"); | |
352 | #endif | |
b1b54e35 | 353 | } else { /* MII100 */ |
8993e54b RJ |
354 | /* |
355 | * Set the auto-negotiation advertisement register bits | |
356 | */ | |
357 | miiphy_write (dev->name, phyAddr, 0x4, 0x01e1); | |
358 | ||
359 | /* | |
360 | * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation | |
361 | */ | |
362 | miiphy_write (dev->name, phyAddr, 0x0, 0x1200); | |
363 | ||
364 | /* | |
365 | * Wait for AN completion | |
366 | */ | |
7238ada3 | 367 | timeout = 2500; |
8993e54b RJ |
368 | do { |
369 | udelay (1000); | |
370 | ||
371 | if ((timeout--) == 0) { | |
372 | #if (DEBUG & 0x2) | |
373 | printf ("PHY auto neg 0 failed...\n"); | |
374 | #endif | |
375 | return -1; | |
376 | } | |
377 | ||
378 | if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) != 0) { | |
379 | #if (DEBUG & 0x2) | |
380 | printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus); | |
381 | #endif | |
382 | return -1; | |
383 | } | |
384 | } while (!(phyStatus & 0x0004)); | |
385 | ||
386 | #if (DEBUG & 0x2) | |
387 | printf ("PHY auto neg complete! \n"); | |
388 | #endif | |
389 | } | |
390 | } | |
391 | ||
392 | #if (DEBUG & 0x2) | |
393 | if (fec->xcv_type != SEVENWIRE) | |
394 | mpc512x_fec_phydump (dev->name); | |
395 | #endif | |
396 | ||
397 | #if (DEBUG & 0x1) | |
398 | printf ("mpc512x_fec_init_phy... Done \n"); | |
399 | #endif | |
400 | return 1; | |
401 | } | |
402 | ||
403 | /********************************************************************/ | |
404 | static void mpc512x_fec_halt (struct eth_device *dev) | |
405 | { | |
406 | mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; | |
407 | int counter = 0xffff; | |
408 | ||
409 | #if (DEBUG & 0x2) | |
410 | if (fec->xcv_type != SEVENWIRE) | |
411 | mpc512x_fec_phydump (dev->name); | |
412 | #endif | |
413 | ||
414 | /* | |
415 | * mask FEC chip interrupts | |
416 | */ | |
417 | fec->eth->imask = 0; | |
418 | ||
419 | /* | |
420 | * issue graceful stop command to the FEC transmitter if necessary | |
421 | */ | |
422 | fec->eth->x_cntrl |= 0x00000001; | |
423 | ||
424 | /* | |
425 | * wait for graceful stop to register | |
426 | */ | |
427 | while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ; | |
428 | ||
429 | /* | |
430 | * Disable the Ethernet Controller | |
431 | */ | |
432 | fec->eth->ecntrl &= 0xfffffffd; | |
433 | ||
434 | /* | |
435 | * Issue a reset command to the FEC chip | |
436 | */ | |
437 | fec->eth->ecntrl |= 0x1; | |
438 | ||
439 | /* | |
440 | * wait at least 16 clock cycles | |
441 | */ | |
442 | udelay (10); | |
443 | #if (DEBUG & 0x3) | |
444 | printf ("Ethernet task stopped\n"); | |
445 | #endif | |
446 | } | |
447 | ||
448 | /********************************************************************/ | |
449 | ||
450 | static int mpc512x_fec_send (struct eth_device *dev, volatile void *eth_data, | |
451 | int data_length) | |
452 | { | |
453 | /* | |
454 | * This routine transmits one frame. This routine only accepts | |
455 | * 6-byte Ethernet addresses. | |
456 | */ | |
457 | mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; | |
458 | volatile FEC_TBD *pTbd; | |
459 | ||
460 | #if (DEBUG & 0x20) | |
461 | printf("tbd status: 0x%04x\n", fec->tbdBase[fec->tbdIndex].status); | |
462 | #endif | |
463 | ||
464 | /* | |
465 | * Clear Tx BD ring at first | |
466 | */ | |
467 | mpc512x_fec_tbd_scrub (fec); | |
468 | ||
469 | /* | |
470 | * Check for valid length of data. | |
471 | */ | |
472 | if ((data_length > 1500) || (data_length <= 0)) { | |
473 | return -1; | |
474 | } | |
475 | ||
476 | /* | |
477 | * Check the number of vacant TxBDs. | |
478 | */ | |
479 | if (fec->cleanTbdNum < 1) { | |
480 | #if (DEBUG & 0x20) | |
481 | printf ("No available TxBDs ...\n"); | |
482 | #endif | |
483 | return -1; | |
484 | } | |
485 | ||
486 | /* | |
487 | * Get the first TxBD to send the mac header | |
488 | */ | |
489 | pTbd = &fec->bdBase->tbd[fec->tbdIndex]; | |
490 | pTbd->dataLength = data_length; | |
491 | pTbd->dataPointer = (uint32)eth_data; | |
492 | pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY; | |
493 | fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM; | |
b1b54e35 | 494 | |
8993e54b RJ |
495 | /* Activate transmit Buffer Descriptor polling */ |
496 | fec->eth->x_des_active = 0x01000000; /* Descriptor polling active */ | |
497 | ||
498 | #if (DEBUG & 0x8) | |
499 | printf ( "+" ); | |
500 | #endif | |
501 | ||
502 | fec->cleanTbdNum -= 1; | |
503 | ||
504 | /* | |
505 | * wait until frame is sent . | |
506 | */ | |
507 | while (pTbd->status & FEC_TBD_READY) { | |
508 | udelay (10); | |
509 | #if (DEBUG & 0x8) | |
510 | printf ("TDB status = %04x\n", pTbd->status); | |
511 | #endif | |
512 | } | |
513 | ||
514 | return 0; | |
515 | } | |
516 | ||
517 | ||
518 | /********************************************************************/ | |
519 | static int mpc512x_fec_recv (struct eth_device *dev) | |
520 | { | |
521 | /* | |
522 | * This command pulls one frame from the card | |
523 | */ | |
524 | mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; | |
525 | volatile FEC_RBD *pRbd = &fec->bdBase->rbd[fec->rbdIndex]; | |
526 | unsigned long ievent; | |
08e2e5fc | 527 | int frame_length = 0; |
8993e54b RJ |
528 | |
529 | #if (DEBUG & 0x1) | |
530 | printf ("mpc512x_fec_recv %d Start...\n", fec->rbdIndex); | |
531 | #endif | |
532 | #if (DEBUG & 0x8) | |
533 | printf( "-" ); | |
534 | #endif | |
b1b54e35 | 535 | |
8993e54b RJ |
536 | /* |
537 | * Check if any critical events have happened | |
538 | */ | |
539 | ievent = fec->eth->ievent; | |
540 | fec->eth->ievent = ievent; | |
541 | if (ievent & 0x20060000) { | |
542 | /* BABT, Rx/Tx FIFO errors */ | |
543 | mpc512x_fec_halt (dev); | |
544 | mpc512x_fec_init (dev, NULL); | |
545 | return 0; | |
546 | } | |
547 | if (ievent & 0x80000000) { | |
548 | /* Heartbeat error */ | |
549 | fec->eth->x_cntrl |= 0x00000001; | |
550 | } | |
551 | if (ievent & 0x10000000) { | |
552 | /* Graceful stop complete */ | |
553 | if (fec->eth->x_cntrl & 0x00000001) { | |
554 | mpc512x_fec_halt (dev); | |
555 | fec->eth->x_cntrl &= ~0x00000001; | |
556 | mpc512x_fec_init (dev, NULL); | |
557 | } | |
558 | } | |
559 | ||
560 | if (!(pRbd->status & FEC_RBD_EMPTY)) { | |
08e2e5fc | 561 | if (!(pRbd->status & FEC_RBD_ERR) && |
8993e54b | 562 | ((pRbd->dataLength - 4) > 14)) { |
b1b54e35 | 563 | |
8993e54b RJ |
564 | /* |
565 | * Get buffer size | |
566 | */ | |
08e2e5fc GB |
567 | if (pRbd->status & FEC_RBD_LAST) |
568 | frame_length = pRbd->dataLength - 4; | |
569 | else | |
570 | frame_length = pRbd->dataLength; | |
8993e54b RJ |
571 | #if (DEBUG & 0x20) |
572 | { | |
573 | int i; | |
08e2e5fc GB |
574 | printf ("recv data length 0x%08x data hdr: ", |
575 | pRbd->dataLength); | |
8993e54b RJ |
576 | for (i = 0; i < 14; i++) |
577 | printf ("%x ", *((uint8*)pRbd->dataPointer + i)); | |
578 | printf("\n"); | |
579 | } | |
580 | #endif | |
8993e54b RJ |
581 | /* |
582 | * Fill the buffer and pass it to upper layers | |
583 | */ | |
08e2e5fc GB |
584 | memcpy (&rx_buff[rx_buff_idx], (void*)pRbd->dataPointer, |
585 | frame_length - rx_buff_idx); | |
586 | rx_buff_idx = frame_length; | |
587 | ||
588 | if (pRbd->status & FEC_RBD_LAST) { | |
589 | NetReceive ((uchar*)rx_buff, frame_length); | |
590 | rx_buff_idx = 0; | |
591 | } | |
8993e54b RJ |
592 | } |
593 | ||
594 | /* | |
595 | * Reset buffer descriptor as empty | |
596 | */ | |
597 | mpc512x_fec_rbd_clean (fec, pRbd); | |
598 | } | |
599 | ||
600 | /* Try to fill Buffer Descriptors */ | |
601 | fec->eth->r_des_active = 0x01000000; /* Descriptor polling active */ | |
08e2e5fc | 602 | return frame_length; |
8993e54b RJ |
603 | } |
604 | ||
605 | /********************************************************************/ | |
606 | int mpc512x_fec_initialize (bd_t * bis) | |
607 | { | |
8993e54b RJ |
608 | mpc512x_fec_priv *fec; |
609 | struct eth_device *dev; | |
610 | int i; | |
611 | char *tmp, *end, env_enetaddr[6]; | |
8993e54b RJ |
612 | void * bd; |
613 | ||
614 | fec = (mpc512x_fec_priv *) malloc (sizeof(*fec)); | |
615 | dev = (struct eth_device *) malloc (sizeof(*dev)); | |
616 | memset (dev, 0, sizeof *dev); | |
617 | ||
618 | fec->eth = (ethernet_regs *) MPC512X_FEC; | |
619 | ||
620 | # ifndef CONFIG_FEC_10MBIT | |
621 | fec->xcv_type = MII100; | |
622 | # else | |
623 | fec->xcv_type = MII10; | |
624 | # endif | |
625 | dev->priv = (void *)fec; | |
626 | dev->iobase = MPC512X_FEC; | |
627 | dev->init = mpc512x_fec_init; | |
628 | dev->halt = mpc512x_fec_halt; | |
629 | dev->send = mpc512x_fec_send; | |
630 | dev->recv = mpc512x_fec_recv; | |
631 | ||
632 | sprintf (dev->name, "FEC ETHERNET"); | |
633 | eth_register (dev); | |
634 | ||
afaac86f | 635 | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) |
8993e54b RJ |
636 | miiphy_register (dev->name, |
637 | fec512x_miiphy_read, fec512x_miiphy_write); | |
638 | #endif | |
639 | ||
8993e54b RJ |
640 | /* Clean up space FEC's MIB and FIFO RAM ...*/ |
641 | memset ((void *) MPC512X_FEC + 0x200, 0x00, 0x400); | |
b1b54e35 WD |
642 | |
643 | /* | |
8993e54b | 644 | * Malloc space for BDs (must be quad word-aligned) |
b1b54e35 | 645 | * this pointer is lost, so cannot be freed |
8993e54b RJ |
646 | */ |
647 | bd = malloc (sizeof(mpc512x_buff_descs) + 0x1f); | |
b1b54e35 | 648 | fec->bdBase = (mpc512x_buff_descs*)((uint32)bd & 0xfffffff0); |
8993e54b RJ |
649 | memset ((void *) bd, 0x00, sizeof(mpc512x_buff_descs) + 0x1f); |
650 | ||
651 | /* | |
652 | * Set interrupt mask register | |
653 | */ | |
654 | fec->eth->imask = 0x00000000; | |
655 | ||
656 | /* | |
657 | * Clear FEC-Lite interrupt event register(IEVENT) | |
658 | */ | |
659 | fec->eth->ievent = 0xffffffff; | |
660 | ||
661 | /* | |
662 | * Try to set the mac address now. The fec mac address is | |
663 | * a garbage after reset. When not using fec for booting | |
664 | * the Linux fec driver will try to work with this garbage. | |
665 | */ | |
666 | tmp = getenv ("ethaddr"); | |
667 | if (tmp) { | |
668 | for (i=0; i<6; i++) { | |
669 | env_enetaddr[i] = tmp ? simple_strtoul (tmp, &end, 16) : 0; | |
670 | if (tmp) | |
671 | tmp = (*end) ? end+1 : end; | |
672 | } | |
673 | mpc512x_fec_set_hwaddr (fec, env_enetaddr); | |
674 | fec->eth->gaddr1 = 0x00000000; | |
675 | fec->eth->gaddr2 = 0x00000000; | |
676 | } | |
677 | ||
678 | mpc512x_fec_init_phy (dev, bis); | |
679 | ||
680 | return 1; | |
681 | } | |
682 | ||
683 | /* MII-interface related functions */ | |
684 | /********************************************************************/ | |
685 | int fec512x_miiphy_read (char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal) | |
686 | { | |
687 | ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC; | |
688 | uint32 reg; /* convenient holder for the PHY register */ | |
689 | uint32 phy; /* convenient holder for the PHY */ | |
690 | int timeout = 0xffff; | |
691 | ||
692 | /* | |
693 | * reading from any PHY's register is done by properly | |
694 | * programming the FEC's MII data register. | |
695 | */ | |
696 | reg = regAddr << FEC_MII_DATA_RA_SHIFT; | |
697 | phy = phyAddr << FEC_MII_DATA_PA_SHIFT; | |
698 | ||
699 | eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg); | |
700 | ||
701 | /* | |
702 | * wait for the related interrupt | |
703 | */ | |
704 | while ((timeout--) && (!(eth->ievent & 0x00800000))) ; | |
705 | ||
706 | if (timeout == 0) { | |
707 | #if (DEBUG & 0x2) | |
708 | printf ("Read MDIO failed...\n"); | |
709 | #endif | |
710 | return -1; | |
711 | } | |
712 | ||
713 | /* | |
714 | * clear mii interrupt bit | |
715 | */ | |
716 | eth->ievent = 0x00800000; | |
717 | ||
718 | /* | |
719 | * it's now safe to read the PHY's register | |
720 | */ | |
721 | *retVal = (uint16) eth->mii_data; | |
722 | ||
723 | return 0; | |
724 | } | |
725 | ||
726 | /********************************************************************/ | |
727 | int fec512x_miiphy_write (char *devname, uint8 phyAddr, uint8 regAddr, uint16 data) | |
728 | { | |
729 | ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC; | |
730 | uint32 reg; /* convenient holder for the PHY register */ | |
731 | uint32 phy; /* convenient holder for the PHY */ | |
732 | int timeout = 0xffff; | |
733 | ||
734 | reg = regAddr << FEC_MII_DATA_RA_SHIFT; | |
735 | phy = phyAddr << FEC_MII_DATA_PA_SHIFT; | |
736 | ||
737 | eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | | |
738 | FEC_MII_DATA_TA | phy | reg | data); | |
739 | ||
740 | /* | |
741 | * wait for the MII interrupt | |
742 | */ | |
743 | while ((timeout--) && (!(eth->ievent & 0x00800000))) ; | |
744 | ||
745 | if (timeout == 0) { | |
746 | #if (DEBUG & 0x2) | |
747 | printf ("Write MDIO failed...\n"); | |
748 | #endif | |
749 | return -1; | |
750 | } | |
751 | ||
752 | /* | |
753 | * clear MII interrupt bit | |
754 | */ | |
755 | eth->ievent = 0x00800000; | |
756 | ||
757 | return 0; | |
758 | } | |
759 | ||
760 | #if (DEBUG & 0x40) | |
761 | static uint32 local_crc32 (char *string, unsigned int crc_value, int len) | |
762 | { | |
763 | int i; | |
764 | char c; | |
765 | unsigned int crc, count; | |
766 | ||
767 | /* | |
768 | * crc32 algorithm | |
769 | */ | |
770 | /* | |
771 | * crc = 0xffffffff; * The initialized value should be 0xffffffff | |
772 | */ | |
773 | crc = crc_value; | |
774 | ||
775 | for (i = len; --i >= 0;) { | |
776 | c = *string++; | |
777 | for (count = 0; count < 8; count++) { | |
778 | if ((c & 0x01) ^ (crc & 0x01)) { | |
779 | crc >>= 1; | |
780 | crc = crc ^ 0xedb88320; | |
781 | } else { | |
782 | crc >>= 1; | |
783 | } | |
784 | c >>= 1; | |
785 | } | |
786 | } | |
787 | ||
788 | /* | |
789 | * In big endian system, do byte swaping for crc value | |
790 | */ | |
791 | /**/ return crc; | |
792 | } | |
793 | #endif /* DEBUG */ | |
794 | ||
795 | #endif /* CONFIG_MPC512x_FEC */ |