blob: f8618b1726e6761597fa326ed3fe7d674fe9603f [file] [log] [blame]
wdenk945af8d2003-07-16 21:53:01 +00001/*
wdenk5e5f9ed2005-04-13 23:15:10 +00002 * (C) Copyright 2003-2005
wdenk945af8d2003-07-16 21:53:01 +00003 * 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 <mpc5xxx.h>
Ben Warren80b00af2008-08-28 23:58:29 -070011#include <mpc5xxx_sdma.h>
wdenk945af8d2003-07-16 21:53:01 +000012#include <malloc.h>
13#include <net.h>
Ben Warrene1d74802008-08-31 10:39:12 -070014#include <netdev.h>
wdenk945af8d2003-07-16 21:53:01 +000015#include <miiphy.h>
Ben Warren80b00af2008-08-28 23:58:29 -070016#include "mpc5xxx_fec.h"
wdenk945af8d2003-07-16 21:53:01 +000017
Wolfgang Denkd87080b2006-03-31 18:32:53 +020018DECLARE_GLOBAL_DATA_PTR;
19
wdenk77846742003-07-26 08:08:08 +000020/* #define DEBUG 0x28 */
wdenk945af8d2003-07-16 21:53:01 +000021
Jon Loeliger44312832007-07-09 19:06:00 -050022#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
wdenkcbd8a352004-02-24 02:00:03 +000023 defined(CONFIG_MPC5xxx_FEC)
wdenk945af8d2003-07-16 21:53:01 +000024
Jon Loeliger44312832007-07-09 19:06:00 -050025#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
Marian Balakowicz63ff0042005-10-28 22:30:33 +020026#error "CONFIG_MII has to be defined!"
27#endif
28
wdenk945af8d2003-07-16 21:53:01 +000029#if (DEBUG & 0x60)
Marian Balakowicz63ff0042005-10-28 22:30:33 +020030static void tfifo_print(char *devname, mpc5xxx_fec_priv *fec);
31static void rfifo_print(char *devname, mpc5xxx_fec_priv *fec);
wdenk945af8d2003-07-16 21:53:01 +000032#endif /* DEBUG */
33
34#if (DEBUG & 0x40)
35static uint32 local_crc32(char *string, unsigned int crc_value, int len);
36#endif
37
wdenk77846742003-07-26 08:08:08 +000038typedef struct {
39 uint8 data[1500]; /* actual data */
40 int length; /* actual length */
41 int used; /* buffer in use or not */
42 uint8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
43} NBUF;
44
Marian Balakowicz63ff0042005-10-28 22:30:33 +020045int fec5xxx_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal);
46int fec5xxx_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data);
47
wdenk945af8d2003-07-16 21:53:01 +000048/********************************************************************/
wdenkd4ca31c2004-01-02 14:00:00 +000049#if (DEBUG & 0x2)
Marian Balakowicz63ff0042005-10-28 22:30:33 +020050static void mpc5xxx_fec_phydump (char *devname)
wdenkd4ca31c2004-01-02 14:00:00 +000051{
52 uint16 phyStatus, i;
53 uint8 phyAddr = CONFIG_PHY_ADDR;
54 uint8 reg_mask[] = {
55#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */
56 /* regs to print: 0...7, 16...19, 21, 23, 24 */
57 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
58 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
59#else
60 /* regs to print: 0...8, 16...20 */
61 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
62 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63#endif
64 };
65
66 for (i = 0; i < 32; i++) {
67 if (reg_mask[i]) {
Marian Balakowicz63ff0042005-10-28 22:30:33 +020068 miiphy_read(devname, phyAddr, i, &phyStatus);
wdenkd4ca31c2004-01-02 14:00:00 +000069 printf("Mii reg %d: 0x%04x\n", i, phyStatus);
70 }
71 }
72}
73#endif
74
75/********************************************************************/
wdenk945af8d2003-07-16 21:53:01 +000076static int mpc5xxx_fec_rbd_init(mpc5xxx_fec_priv *fec)
77{
78 int ix;
79 char *data;
wdenk77846742003-07-26 08:08:08 +000080 static int once = 0;
wdenk945af8d2003-07-16 21:53:01 +000081
wdenk945af8d2003-07-16 21:53:01 +000082 for (ix = 0; ix < FEC_RBD_NUM; ix++) {
wdenk77846742003-07-26 08:08:08 +000083 if (!once) {
84 data = (char *)malloc(FEC_MAX_PKT_SIZE);
85 if (data == NULL) {
86 printf ("RBD INIT FAILED\n");
87 return -1;
88 }
89 fec->rbdBase[ix].dataPointer = (uint32)data;
wdenk945af8d2003-07-16 21:53:01 +000090 }
91 fec->rbdBase[ix].status = FEC_RBD_EMPTY;
92 fec->rbdBase[ix].dataLength = 0;
wdenk945af8d2003-07-16 21:53:01 +000093 }
wdenk77846742003-07-26 08:08:08 +000094 once ++;
wdenk945af8d2003-07-16 21:53:01 +000095
96 /*
97 * have the last RBD to close the ring
98 */
99 fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP;
100 fec->rbdIndex = 0;
101
102 return 0;
103}
104
105/********************************************************************/
106static void mpc5xxx_fec_tbd_init(mpc5xxx_fec_priv *fec)
107{
108 int ix;
109
110 for (ix = 0; ix < FEC_TBD_NUM; ix++) {
111 fec->tbdBase[ix].status = 0;
112 }
113
114 /*
115 * Have the last TBD to close the ring
116 */
117 fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP;
118
119 /*
120 * Initialize some indices
121 */
122 fec->tbdIndex = 0;
123 fec->usedTbdIndex = 0;
124 fec->cleanTbdNum = FEC_TBD_NUM;
125}
126
127/********************************************************************/
wdenk151ab832005-02-24 22:44:16 +0000128static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, volatile FEC_RBD * pRbd)
wdenk945af8d2003-07-16 21:53:01 +0000129{
130 /*
131 * Reset buffer descriptor as empty
132 */
133 if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
134 pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
135 else
136 pRbd->status = FEC_RBD_EMPTY;
137
138 pRbd->dataLength = 0;
139
140 /*
141 * Now, we have an empty RxBD, restart the SmartDMA receive task
142 */
143 SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
144
145 /*
146 * Increment BD count
147 */
148 fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
149}
150
151/********************************************************************/
152static void mpc5xxx_fec_tbd_scrub(mpc5xxx_fec_priv *fec)
153{
wdenk151ab832005-02-24 22:44:16 +0000154 volatile FEC_TBD *pUsedTbd;
wdenk945af8d2003-07-16 21:53:01 +0000155
156#if (DEBUG & 0x1)
157 printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
158 fec->cleanTbdNum, fec->usedTbdIndex);
159#endif
160
161 /*
162 * process all the consumed TBDs
163 */
164 while (fec->cleanTbdNum < FEC_TBD_NUM) {
165 pUsedTbd = &fec->tbdBase[fec->usedTbdIndex];
166 if (pUsedTbd->status & FEC_TBD_READY) {
167#if (DEBUG & 0x20)
168 printf("Cannot clean TBD %d, in use\n", fec->cleanTbdNum);
169#endif
170 return;
171 }
172
173 /*
174 * clean this buffer descriptor
175 */
176 if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
177 pUsedTbd->status = FEC_TBD_WRAP;
178 else
179 pUsedTbd->status = 0;
180
181 /*
182 * update some indeces for a correct handling of the TBD ring
183 */
184 fec->cleanTbdNum++;
185 fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
186 }
187}
188
189/********************************************************************/
190static void mpc5xxx_fec_set_hwaddr(mpc5xxx_fec_priv *fec, char *mac)
191{
192 uint8 currByte; /* byte for which to compute the CRC */
193 int byte; /* loop - counter */
194 int bit; /* loop - counter */
195 uint32 crc = 0xffffffff; /* initial value */
196
197 /*
198 * The algorithm used is the following:
199 * we loop on each of the six bytes of the provided address,
200 * and we compute the CRC by left-shifting the previous
201 * value by one position, so that each bit in the current
202 * byte of the address may contribute the calculation. If
203 * the latter and the MSB in the CRC are different, then
204 * the CRC value so computed is also ex-ored with the
205 * "polynomium generator". The current byte of the address
206 * is also shifted right by one bit at each iteration.
207 * This is because the CRC generatore in hardware is implemented
208 * as a shift-register with as many ex-ores as the radixes
209 * in the polynomium. This suggests that we represent the
210 * polynomiumm itself as a 32-bit constant.
211 */
212 for (byte = 0; byte < 6; byte++) {
213 currByte = mac[byte];
214 for (bit = 0; bit < 8; bit++) {
215 if ((currByte & 0x01) ^ (crc & 0x01)) {
216 crc >>= 1;
217 crc = crc ^ 0xedb88320;
218 } else {
219 crc >>= 1;
220 }
221 currByte >>= 1;
222 }
223 }
224
225 crc = crc >> 26;
226
227 /*
228 * Set individual hash table register
229 */
230 if (crc >= 32) {
231 fec->eth->iaddr1 = (1 << (crc - 32));
232 fec->eth->iaddr2 = 0;
233 } else {
234 fec->eth->iaddr1 = 0;
235 fec->eth->iaddr2 = (1 << crc);
236 }
237
238 /*
239 * Set physical address
240 */
241 fec->eth->paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
242 fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
243}
244
245/********************************************************************/
246static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
247{
248 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
249 struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
wdenk945af8d2003-07-16 21:53:01 +0000250
251#if (DEBUG & 0x1)
252 printf ("mpc5xxx_fec_init... Begin\n");
253#endif
254
255 /*
256 * Initialize RxBD/TxBD rings
257 */
258 mpc5xxx_fec_rbd_init(fec);
259 mpc5xxx_fec_tbd_init(fec);
260
261 /*
wdenk945af8d2003-07-16 21:53:01 +0000262 * Clear FEC-Lite interrupt event register(IEVENT)
263 */
264 fec->eth->ievent = 0xffffffff;
265
266 /*
267 * Set interrupt mask register
268 */
269 fec->eth->imask = 0x00000000;
270
271 /*
272 * Set FEC-Lite receive control register(R_CNTRL):
273 */
274 if (fec->xcv_type == SEVENWIRE) {
275 /*
276 * Frame length=1518; 7-wire mode
277 */
278 fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */
279 } else {
280 /*
281 * Frame length=1518; MII mode;
282 */
283 fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */
284 }
285
wdenk7e780362004-04-08 22:31:29 +0000286 fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
287 if (fec->xcv_type != SEVENWIRE) {
wdenk945af8d2003-07-16 21:53:01 +0000288 /*
wdenk7152b1d2003-09-05 23:19:14 +0000289 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
wdenk945af8d2003-07-16 21:53:01 +0000290 * and do not drop the Preamble.
291 */
Heiko Schocher6341d9d2008-01-11 15:15:14 +0100292 fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
wdenk945af8d2003-07-16 21:53:01 +0000293 }
294
295 /*
296 * Set Opcode/Pause Duration Register
297 */
Heiko Schocher6341d9d2008-01-11 15:15:14 +0100298 fec->eth->op_pause = 0x00010020; /*FIXME 0xffff0020; */
wdenk945af8d2003-07-16 21:53:01 +0000299
300 /*
301 * Set Rx FIFO alarm and granularity value
302 */
Wolfgang Denkc44ffb92005-09-04 23:19:41 +0200303 fec->eth->rfifo_cntrl = 0x0c000000
304 | (fec->eth->rfifo_cntrl & ~0x0f000000);
wdenk945af8d2003-07-16 21:53:01 +0000305 fec->eth->rfifo_alarm = 0x0000030c;
306#if (DEBUG & 0x22)
307 if (fec->eth->rfifo_status & 0x00700000 ) {
308 printf("mpc5xxx_fec_init() RFIFO error\n");
309 }
310#endif
311
312 /*
313 * Set Tx FIFO granularity value
314 */
Wolfgang Denkc44ffb92005-09-04 23:19:41 +0200315 fec->eth->tfifo_cntrl = 0x0c000000
316 | (fec->eth->tfifo_cntrl & ~0x0f000000);
wdenk945af8d2003-07-16 21:53:01 +0000317#if (DEBUG & 0x2)
318 printf("tfifo_status: 0x%08x\n", fec->eth->tfifo_status);
319 printf("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm);
320#endif
321
322 /*
323 * Set transmit fifo watermark register(X_WMRK), default = 64
324 */
325 fec->eth->tfifo_alarm = 0x00000080;
326 fec->eth->x_wmrk = 0x2;
327
328 /*
329 * Set individual address filter for unicast address
330 * and set physical address registers.
331 */
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200332 mpc5xxx_fec_set_hwaddr(fec, (char *)dev->enetaddr);
wdenk945af8d2003-07-16 21:53:01 +0000333
334 /*
335 * Set multicast address filter
336 */
337 fec->eth->gaddr1 = 0x00000000;
338 fec->eth->gaddr2 = 0x00000000;
339
340 /*
341 * Turn ON cheater FSM: ????
342 */
343 fec->eth->xmit_fsm = 0x03000000;
344
345#if defined(CONFIG_MPC5200)
346 /*
347 * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't
348 * work w/ the current receive task.
349 */
350 sdma->PtdCntrl |= 0x00000001;
351#endif
352
353 /*
354 * Set priority of different initiators
355 */
356 sdma->IPR0 = 7; /* always */
357 sdma->IPR3 = 6; /* Eth RX */
358 sdma->IPR4 = 5; /* Eth Tx */
359
360 /*
361 * Clear SmartDMA task interrupt pending bits
362 */
363 SDMA_CLEAR_IEVENT(FEC_RECV_TASK_NO);
364
365 /*
wdenk945af8d2003-07-16 21:53:01 +0000366 * Initialize SmartDMA parameters stored in SRAM
367 */
wdenk151ab832005-02-24 22:44:16 +0000368 *(volatile int *)FEC_TBD_BASE = (int)fec->tbdBase;
369 *(volatile int *)FEC_RBD_BASE = (int)fec->rbdBase;
370 *(volatile int *)FEC_TBD_NEXT = (int)fec->tbdBase;
371 *(volatile int *)FEC_RBD_NEXT = (int)fec->rbdBase;
wdenk945af8d2003-07-16 21:53:01 +0000372
wdenk6c1362c2004-05-12 22:18:31 +0000373 /*
374 * Enable FEC-Lite controller
375 */
376 fec->eth->ecntrl |= 0x00000006;
377
378#if (DEBUG & 0x2)
379 if (fec->xcv_type != SEVENWIRE)
Heiko Schocher6dedf3d2006-12-21 16:14:48 +0100380 mpc5xxx_fec_phydump (dev->name);
wdenk6c1362c2004-05-12 22:18:31 +0000381#endif
382
383 /*
384 * Enable SmartDMA receive task
385 */
386 SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
387
388#if (DEBUG & 0x1)
389 printf("mpc5xxx_fec_init... Done \n");
390#endif
391
392 return 1;
393}
394
395/********************************************************************/
396static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis)
397{
wdenk6c1362c2004-05-12 22:18:31 +0000398 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
399 const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */
400
401#if (DEBUG & 0x1)
402 printf ("mpc5xxx_fec_init_phy... Begin\n");
403#endif
404
405 /*
406 * Initialize GPIO pins
407 */
408 if (fec->xcv_type == SEVENWIRE) {
409 /* 10MBit with 7-wire operation */
wdenk6c7a1402004-07-11 19:17:20 +0000410#if defined(CONFIG_TOTAL5200)
411 /* 7-wire and USB2 on Ethernet */
412 *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00030000;
413#else /* !CONFIG_TOTAL5200 */
414 /* 7-wire only */
wdenk6c1362c2004-05-12 22:18:31 +0000415 *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000;
wdenk6c7a1402004-07-11 19:17:20 +0000416#endif /* CONFIG_TOTAL5200 */
wdenk6c1362c2004-05-12 22:18:31 +0000417 } else {
418 /* 100MBit with MD operation */
419 *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000;
420 }
421
422 /*
423 * Clear FEC-Lite interrupt event register(IEVENT)
424 */
425 fec->eth->ievent = 0xffffffff;
426
427 /*
428 * Set interrupt mask register
429 */
430 fec->eth->imask = 0x00000000;
431
Bartlomiej Sieka008861a2007-05-07 22:36:15 +0200432/*
433 * In original Promess-provided code PHY initialization is disabled with the
434 * following comment: "Phy initialization is DISABLED for now. There was a
435 * problem with running 100 Mbps on PRO board". Thus we temporarily disable
436 * PHY initialization for the Motion-PRO board, until a proper fix is found.
437 */
438
wdenk6c1362c2004-05-12 22:18:31 +0000439 if (fec->xcv_type != SEVENWIRE) {
440 /*
441 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
442 * and do not drop the Preamble.
443 */
444 fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
445 }
446
wdenk945af8d2003-07-16 21:53:01 +0000447 if (fec->xcv_type != SEVENWIRE) {
448 /*
449 * Initialize PHY(LXT971A):
450 *
451 * Generally, on power up, the LXT971A reads its configuration
452 * pins to check for forced operation, If not cofigured for
453 * forced operation, it uses auto-negotiation/parallel detection
454 * to automatically determine line operating conditions.
455 * If the PHY device on the other side of the link supports
456 * auto-negotiation, the LXT971A auto-negotiates with it
457 * using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
458 * support auto-negotiation, the LXT971A automatically detects
459 * the presence of either link pulses(10Mbps PHY) or Idle
460 * symbols(100Mbps) and sets its operating conditions accordingly.
461 *
462 * When auto-negotiation is controlled by software, the following
463 * steps are recommended.
464 *
465 * Note:
466 * The physical address is dependent on hardware configuration.
467 *
468 */
469 int timeout = 1;
470 uint16 phyStatus;
471
472 /*
473 * Reset PHY, then delay 300ns
474 */
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200475 miiphy_write(dev->name, phyAddr, 0x0, 0x8000);
wdenk945af8d2003-07-16 21:53:01 +0000476 udelay(1000);
477
Heiko Schocher258c37b2008-08-21 20:44:49 +0200478#if defined(CONFIG_UC101) || defined(CONFIG_MUCMC52)
479 /* Set the LED configuration Register for the UC101
480 and MUCMC52 Board */
Heiko Schocher37403002007-04-14 05:26:48 +0200481 miiphy_write(dev->name, phyAddr, 0x14, 0x4122);
482#endif
wdenk945af8d2003-07-16 21:53:01 +0000483 if (fec->xcv_type == MII10) {
484 /*
485 * Force 10Base-T, FDX operation
486 */
wdenka57106f2003-09-16 17:29:31 +0000487#if (DEBUG & 0x2)
wdenk945af8d2003-07-16 21:53:01 +0000488 printf("Forcing 10 Mbps ethernet link... ");
wdenka57106f2003-09-16 17:29:31 +0000489#endif
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200490 miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
wdenk945af8d2003-07-16 21:53:01 +0000491 /*
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200492 miiphy_write(dev->name, fec, phyAddr, 0x0, 0x0100);
wdenk945af8d2003-07-16 21:53:01 +0000493 */
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200494 miiphy_write(dev->name, phyAddr, 0x0, 0x0180);
wdenk945af8d2003-07-16 21:53:01 +0000495
496 timeout = 20;
497 do { /* wait for link status to go down */
498 udelay(10000);
499 if ((timeout--) == 0) {
500#if (DEBUG & 0x2)
501 printf("hmmm, should not have waited...");
502#endif
503 break;
504 }
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200505 miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
wdenk945af8d2003-07-16 21:53:01 +0000506#if (DEBUG & 0x2)
507 printf("=");
508#endif
509 } while ((phyStatus & 0x0004)); /* !link up */
510
511 timeout = 1000;
512 do { /* wait for link status to come back up */
513 udelay(10000);
514 if ((timeout--) == 0) {
515 printf("failed. Link is down.\n");
516 break;
517 }
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200518 miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
wdenk945af8d2003-07-16 21:53:01 +0000519#if (DEBUG & 0x2)
520 printf("+");
521#endif
522 } while (!(phyStatus & 0x0004)); /* !link up */
523
dzuab209d52003-09-30 14:08:43 +0000524#if (DEBUG & 0x2)
wdenk945af8d2003-07-16 21:53:01 +0000525 printf ("done.\n");
dzuab209d52003-09-30 14:08:43 +0000526#endif
wdenk945af8d2003-07-16 21:53:01 +0000527 } else { /* MII100 */
528 /*
529 * Set the auto-negotiation advertisement register bits
530 */
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200531 miiphy_write(dev->name, phyAddr, 0x4, 0x01e1);
wdenk945af8d2003-07-16 21:53:01 +0000532
533 /*
534 * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
535 */
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200536 miiphy_write(dev->name, phyAddr, 0x0, 0x1200);
wdenk945af8d2003-07-16 21:53:01 +0000537
538 /*
539 * Wait for AN completion
540 */
541 timeout = 5000;
542 do {
543 udelay(1000);
544
545 if ((timeout--) == 0) {
546#if (DEBUG & 0x2)
547 printf("PHY auto neg 0 failed...\n");
548#endif
549 return -1;
550 }
551
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200552 if (miiphy_read(dev->name, phyAddr, 0x1, &phyStatus) != 0) {
wdenk945af8d2003-07-16 21:53:01 +0000553#if (DEBUG & 0x2)
554 printf("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
555#endif
556 return -1;
557 }
wdenk7e780362004-04-08 22:31:29 +0000558 } while (!(phyStatus & 0x0004));
wdenk945af8d2003-07-16 21:53:01 +0000559
560#if (DEBUG & 0x2)
561 printf("PHY auto neg complete! \n");
562#endif
563 }
564
565 }
566
wdenk945af8d2003-07-16 21:53:01 +0000567#if (DEBUG & 0x2)
wdenkd4ca31c2004-01-02 14:00:00 +0000568 if (fec->xcv_type != SEVENWIRE)
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200569 mpc5xxx_fec_phydump (dev->name);
wdenk945af8d2003-07-16 21:53:01 +0000570#endif
wdenkd4ca31c2004-01-02 14:00:00 +0000571
wdenk945af8d2003-07-16 21:53:01 +0000572
573#if (DEBUG & 0x1)
wdenk6c1362c2004-05-12 22:18:31 +0000574 printf("mpc5xxx_fec_init_phy... Done \n");
wdenk945af8d2003-07-16 21:53:01 +0000575#endif
576
wdenk013dc8d2003-08-07 14:52:18 +0000577 return 1;
wdenk945af8d2003-07-16 21:53:01 +0000578}
579
580/********************************************************************/
581static void mpc5xxx_fec_halt(struct eth_device *dev)
582{
wdenk77846742003-07-26 08:08:08 +0000583#if defined(CONFIG_MPC5200)
wdenk945af8d2003-07-16 21:53:01 +0000584 struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
wdenk77846742003-07-26 08:08:08 +0000585#endif
586 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
wdenk945af8d2003-07-16 21:53:01 +0000587 int counter = 0xffff;
588
589#if (DEBUG & 0x2)
wdenkd4ca31c2004-01-02 14:00:00 +0000590 if (fec->xcv_type != SEVENWIRE)
Heiko Schocher6dedf3d2006-12-21 16:14:48 +0100591 mpc5xxx_fec_phydump (dev->name);
wdenk945af8d2003-07-16 21:53:01 +0000592#endif
593
wdenk945af8d2003-07-16 21:53:01 +0000594 /*
595 * mask FEC chip interrupts
596 */
597 fec->eth->imask = 0;
598
599 /*
600 * issue graceful stop command to the FEC transmitter if necessary
601 */
602 fec->eth->x_cntrl |= 0x00000001;
603
604 /*
605 * wait for graceful stop to register
606 */
607 while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ;
608
wdenk945af8d2003-07-16 21:53:01 +0000609 /*
610 * Disable SmartDMA tasks
611 */
612 SDMA_TASK_DISABLE (FEC_XMIT_TASK_NO);
613 SDMA_TASK_DISABLE (FEC_RECV_TASK_NO);
614
615#if defined(CONFIG_MPC5200)
616 /*
617 * Turn on COMM bus prefetch in the MGT5200 BestComm after we're
618 * done. It doesn't work w/ the current receive task.
619 */
620 sdma->PtdCntrl &= ~0x00000001;
621#endif
622
623 /*
624 * Disable the Ethernet Controller
625 */
626 fec->eth->ecntrl &= 0xfffffffd;
627
628 /*
629 * Clear FIFO status registers
630 */
631 fec->eth->rfifo_status &= 0x00700000;
632 fec->eth->tfifo_status &= 0x00700000;
633
634 fec->eth->reset_cntrl = 0x01000000;
635
636 /*
637 * Issue a reset command to the FEC chip
638 */
639 fec->eth->ecntrl |= 0x1;
640
641 /*
642 * wait at least 16 clock cycles
643 */
644 udelay(10);
645
646#if (DEBUG & 0x3)
647 printf("Ethernet task stopped\n");
648#endif
649}
650
651#if (DEBUG & 0x60)
652/********************************************************************/
653
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200654static void tfifo_print(char *devname, mpc5xxx_fec_priv *fec)
wdenk945af8d2003-07-16 21:53:01 +0000655{
wdenkd4ca31c2004-01-02 14:00:00 +0000656 uint16 phyAddr = CONFIG_PHY_ADDR;
wdenk945af8d2003-07-16 21:53:01 +0000657 uint16 phyStatus;
658
659 if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
660 || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) {
661
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200662 miiphy_read(devname, phyAddr, 0x1, &phyStatus);
wdenk945af8d2003-07-16 21:53:01 +0000663 printf("\nphyStatus: 0x%04x\n", phyStatus);
664 printf("ecntrl: 0x%08x\n", fec->eth->ecntrl);
665 printf("ievent: 0x%08x\n", fec->eth->ievent);
666 printf("x_status: 0x%08x\n", fec->eth->x_status);
667 printf("tfifo: status 0x%08x\n", fec->eth->tfifo_status);
668
669 printf(" control 0x%08x\n", fec->eth->tfifo_cntrl);
670 printf(" lrfp 0x%08x\n", fec->eth->tfifo_lrf_ptr);
671 printf(" lwfp 0x%08x\n", fec->eth->tfifo_lwf_ptr);
672 printf(" alarm 0x%08x\n", fec->eth->tfifo_alarm);
673 printf(" readptr 0x%08x\n", fec->eth->tfifo_rdptr);
674 printf(" writptr 0x%08x\n", fec->eth->tfifo_wrptr);
675 }
676}
677
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200678static void rfifo_print(char *devname, mpc5xxx_fec_priv *fec)
wdenk945af8d2003-07-16 21:53:01 +0000679{
wdenkd4ca31c2004-01-02 14:00:00 +0000680 uint16 phyAddr = CONFIG_PHY_ADDR;
wdenk945af8d2003-07-16 21:53:01 +0000681 uint16 phyStatus;
682
683 if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
684 || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) {
685
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200686 miiphy_read(devname, phyAddr, 0x1, &phyStatus);
wdenk945af8d2003-07-16 21:53:01 +0000687 printf("\nphyStatus: 0x%04x\n", phyStatus);
688 printf("ecntrl: 0x%08x\n", fec->eth->ecntrl);
689 printf("ievent: 0x%08x\n", fec->eth->ievent);
690 printf("x_status: 0x%08x\n", fec->eth->x_status);
691 printf("rfifo: status 0x%08x\n", fec->eth->rfifo_status);
692
693 printf(" control 0x%08x\n", fec->eth->rfifo_cntrl);
694 printf(" lrfp 0x%08x\n", fec->eth->rfifo_lrf_ptr);
695 printf(" lwfp 0x%08x\n", fec->eth->rfifo_lwf_ptr);
696 printf(" alarm 0x%08x\n", fec->eth->rfifo_alarm);
697 printf(" readptr 0x%08x\n", fec->eth->rfifo_rdptr);
698 printf(" writptr 0x%08x\n", fec->eth->rfifo_wrptr);
699 }
700}
701#endif /* DEBUG */
702
703/********************************************************************/
704
705static int mpc5xxx_fec_send(struct eth_device *dev, volatile void *eth_data,
706 int data_length)
707{
708 /*
709 * This routine transmits one frame. This routine only accepts
710 * 6-byte Ethernet addresses.
711 */
712 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
wdenk151ab832005-02-24 22:44:16 +0000713 volatile FEC_TBD *pTbd;
wdenk945af8d2003-07-16 21:53:01 +0000714
715#if (DEBUG & 0x20)
716 printf("tbd status: 0x%04x\n", fec->tbdBase[0].status);
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200717 tfifo_print(dev->name, fec);
wdenk945af8d2003-07-16 21:53:01 +0000718#endif
719
720 /*
721 * Clear Tx BD ring at first
722 */
723 mpc5xxx_fec_tbd_scrub(fec);
724
725 /*
726 * Check for valid length of data.
727 */
728 if ((data_length > 1500) || (data_length <= 0)) {
729 return -1;
730 }
731
732 /*
733 * Check the number of vacant TxBDs.
734 */
735 if (fec->cleanTbdNum < 1) {
736#if (DEBUG & 0x20)
737 printf("No available TxBDs ...\n");
738#endif
739 return -1;
740 }
741
742 /*
743 * Get the first TxBD to send the mac header
744 */
745 pTbd = &fec->tbdBase[fec->tbdIndex];
746 pTbd->dataLength = data_length;
747 pTbd->dataPointer = (uint32)eth_data;
wdenk77846742003-07-26 08:08:08 +0000748 pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
wdenk945af8d2003-07-16 21:53:01 +0000749 fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
750
751#if (DEBUG & 0x100)
752 printf("SDMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex);
753#endif
754
755 /*
756 * Kick the MII i/f
757 */
758 if (fec->xcv_type != SEVENWIRE) {
759 uint16 phyStatus;
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200760 miiphy_read(dev->name, 0, 0x1, &phyStatus);
wdenk945af8d2003-07-16 21:53:01 +0000761 }
762
763 /*
764 * Enable SmartDMA transmit task
765 */
766
767#if (DEBUG & 0x20)
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200768 tfifo_print(dev->name, fec);
wdenk945af8d2003-07-16 21:53:01 +0000769#endif
770 SDMA_TASK_ENABLE (FEC_XMIT_TASK_NO);
771#if (DEBUG & 0x20)
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200772 tfifo_print(dev->name, fec);
wdenk945af8d2003-07-16 21:53:01 +0000773#endif
774#if (DEBUG & 0x8)
775 printf( "+" );
776#endif
777
778 fec->cleanTbdNum -= 1;
779
780#if (DEBUG & 0x129) && (DEBUG & 0x80000000)
781 printf ("smartDMA ethernet Tx task enabled\n");
782#endif
783 /*
784 * wait until frame is sent .
785 */
786 while (pTbd->status & FEC_TBD_READY) {
787 udelay(10);
788#if (DEBUG & 0x8)
789 printf ("TDB status = %04x\n", pTbd->status);
790#endif
791 }
792
793 return 0;
794}
795
796
797/********************************************************************/
798static int mpc5xxx_fec_recv(struct eth_device *dev)
799{
800 /*
801 * This command pulls one frame from the card
802 */
803 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
wdenk151ab832005-02-24 22:44:16 +0000804 volatile FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
wdenk945af8d2003-07-16 21:53:01 +0000805 unsigned long ievent;
wdenk77846742003-07-26 08:08:08 +0000806 int frame_length, len = 0;
807 NBUF *frame;
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200808 uchar buff[FEC_MAX_PKT_SIZE];
wdenk945af8d2003-07-16 21:53:01 +0000809
810#if (DEBUG & 0x1)
811 printf ("mpc5xxx_fec_recv %d Start...\n", fec->rbdIndex);
812#endif
813#if (DEBUG & 0x8)
814 printf( "-" );
815#endif
816
817 /*
818 * Check if any critical events have happened
819 */
820 ievent = fec->eth->ievent;
821 fec->eth->ievent = ievent;
822 if (ievent & 0x20060000) {
823 /* BABT, Rx/Tx FIFO errors */
824 mpc5xxx_fec_halt(dev);
825 mpc5xxx_fec_init(dev, NULL);
826 return 0;
827 }
828 if (ievent & 0x80000000) {
829 /* Heartbeat error */
830 fec->eth->x_cntrl |= 0x00000001;
831 }
832 if (ievent & 0x10000000) {
833 /* Graceful stop complete */
834 if (fec->eth->x_cntrl & 0x00000001) {
835 mpc5xxx_fec_halt(dev);
836 fec->eth->x_cntrl &= ~0x00000001;
837 mpc5xxx_fec_init(dev, NULL);
838 }
839 }
840
wdenk77846742003-07-26 08:08:08 +0000841 if (!(pRbd->status & FEC_RBD_EMPTY)) {
842 if ((pRbd->status & FEC_RBD_LAST) && !(pRbd->status & FEC_RBD_ERR) &&
843 ((pRbd->dataLength - 4) > 14)) {
wdenk945af8d2003-07-16 21:53:01 +0000844
wdenk77846742003-07-26 08:08:08 +0000845 /*
846 * Get buffer address and size
847 */
848 frame = (NBUF *)pRbd->dataPointer;
849 frame_length = pRbd->dataLength - 4;
850
851#if (DEBUG & 0x20)
852 {
853 int i;
854 printf("recv data hdr:");
855 for (i = 0; i < 14; i++)
856 printf("%x ", *(frame->head + i));
857 printf("\n");
858 }
wdenk945af8d2003-07-16 21:53:01 +0000859#endif
wdenk77846742003-07-26 08:08:08 +0000860 /*
861 * Fill the buffer and pass it to upper layers
862 */
863 memcpy(buff, frame->head, 14);
864 memcpy(buff + 14, frame->data, frame_length);
865 NetReceive(buff, frame_length);
866 len = frame_length;
867 }
868 /*
869 * Reset buffer descriptor as empty
870 */
871 mpc5xxx_fec_rbd_clean(fec, pRbd);
wdenk945af8d2003-07-16 21:53:01 +0000872 }
wdenk77846742003-07-26 08:08:08 +0000873 SDMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
874 return len;
wdenk945af8d2003-07-16 21:53:01 +0000875}
876
877
878/********************************************************************/
879int mpc5xxx_fec_initialize(bd_t * bis)
880{
881 mpc5xxx_fec_priv *fec;
882 struct eth_device *dev;
wdenk12f34242003-09-02 22:48:03 +0000883 char *tmp, *end;
884 char env_enetaddr[6];
885 int i;
wdenk945af8d2003-07-16 21:53:01 +0000886
887 fec = (mpc5xxx_fec_priv *)malloc(sizeof(*fec));
888 dev = (struct eth_device *)malloc(sizeof(*dev));
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200889 memset(dev, 0, sizeof *dev);
wdenk945af8d2003-07-16 21:53:01 +0000890
891 fec->eth = (ethernet_regs *)MPC5XXX_FEC;
892 fec->tbdBase = (FEC_TBD *)FEC_BD_BASE;
893 fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD));
Bartlomiej Siekafa1df302007-07-11 20:11:07 +0200894#if defined(CONFIG_CANMB) || \
Bartlomiej Sieka86b116b2007-08-03 12:08:16 +0200895 defined(CONFIG_CM5200) || \
Bartlomiej Siekafa1df302007-07-11 20:11:07 +0200896 defined(CONFIG_HMI1001) || \
897 defined(CONFIG_ICECUBE) || \
898 defined(CONFIG_INKA4X0) || \
899 defined(CONFIG_JUPITER) || \
900 defined(CONFIG_MCC200) || \
901 defined(CONFIG_MOTIONPRO) || \
Heiko Schocher258c37b2008-08-21 20:44:49 +0200902 defined(CONFIG_MUCMC52) || \
Bartlomiej Siekafa1df302007-07-11 20:11:07 +0200903 defined(CONFIG_O2DNT) || \
904 defined(CONFIG_PM520) || \
905 defined(CONFIG_TOP5200) || \
906 defined(CONFIG_TQM5200) || \
907 defined(CONFIG_UC101) || \
Heiko Schocher6341d9d2008-01-11 15:15:14 +0100908 defined(CONFIG_V38B) || \
909 defined(CONFIG_MUNICES)
wdenkefa329c2004-03-23 20:18:25 +0000910# ifndef CONFIG_FEC_10MBIT
wdenk945af8d2003-07-16 21:53:01 +0000911 fec->xcv_type = MII100;
wdenkefa329c2004-03-23 20:18:25 +0000912# else
wdenka57106f2003-09-16 17:29:31 +0000913 fec->xcv_type = MII10;
wdenkefa329c2004-03-23 20:18:25 +0000914# endif
wdenk6c7a1402004-07-11 19:17:20 +0000915#elif defined(CONFIG_TOTAL5200)
916 fec->xcv_type = SEVENWIRE;
wdenka57106f2003-09-16 17:29:31 +0000917#else
918#error fec->xcv_type not initialized.
wdenk945af8d2003-07-16 21:53:01 +0000919#endif
920
921 dev->priv = (void *)fec;
922 dev->iobase = MPC5XXX_FEC;
923 dev->init = mpc5xxx_fec_init;
924 dev->halt = mpc5xxx_fec_halt;
925 dev->send = mpc5xxx_fec_send;
926 dev->recv = mpc5xxx_fec_recv;
927
wdenk77846742003-07-26 08:08:08 +0000928 sprintf(dev->name, "FEC ETHERNET");
wdenk945af8d2003-07-16 21:53:01 +0000929 eth_register(dev);
930
Jon Loeliger44312832007-07-09 19:06:00 -0500931#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200932 miiphy_register (dev->name,
933 fec5xxx_miiphy_read, fec5xxx_miiphy_write);
934#endif
935
wdenk12f34242003-09-02 22:48:03 +0000936 /*
937 * Try to set the mac address now. The fec mac address is
wdenk42d1f032003-10-15 23:53:47 +0000938 * a garbage after reset. When not using fec for booting
wdenk12f34242003-09-02 22:48:03 +0000939 * the Linux fec driver will try to work with this garbage.
940 */
941 tmp = getenv("ethaddr");
942 if (tmp) {
943 for (i=0; i<6; i++) {
944 env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
945 if (tmp)
946 tmp = (*end) ? end+1 : end;
947 }
948 mpc5xxx_fec_set_hwaddr(fec, env_enetaddr);
949 }
950
wdenk6c1362c2004-05-12 22:18:31 +0000951 mpc5xxx_fec_init_phy(dev, bis);
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200952
wdenk945af8d2003-07-16 21:53:01 +0000953 return 1;
954}
955
956/* MII-interface related functions */
957/********************************************************************/
Marian Balakowicz63ff0042005-10-28 22:30:33 +0200958int fec5xxx_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal)
wdenk945af8d2003-07-16 21:53:01 +0000959{
960 ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
961 uint32 reg; /* convenient holder for the PHY register */
962 uint32 phy; /* convenient holder for the PHY */
963 int timeout = 0xffff;
964
965 /*
966 * reading from any PHY's register is done by properly
967 * programming the FEC's MII data register.
968 */
969 reg = regAddr << FEC_MII_DATA_RA_SHIFT;
970 phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
971
972 eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg);
973
974 /*
975 * wait for the related interrupt
976 */
977 while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
978
979 if (timeout == 0) {
980#if (DEBUG & 0x2)
981 printf ("Read MDIO failed...\n");
982#endif
983 return -1;
984 }
985
986 /*
987 * clear mii interrupt bit
988 */
989 eth->ievent = 0x00800000;
990
991 /*
992 * it's now safe to read the PHY's register
993 */
994 *retVal = (uint16) eth->mii_data;
995
996 return 0;
997}
998
999/********************************************************************/
Marian Balakowicz63ff0042005-10-28 22:30:33 +02001000int fec5xxx_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data)
wdenk945af8d2003-07-16 21:53:01 +00001001{
1002 ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
1003 uint32 reg; /* convenient holder for the PHY register */
1004 uint32 phy; /* convenient holder for the PHY */
1005 int timeout = 0xffff;
1006
1007 reg = regAddr << FEC_MII_DATA_RA_SHIFT;
1008 phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
1009
1010 eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
1011 FEC_MII_DATA_TA | phy | reg | data);
1012
1013 /*
1014 * wait for the MII interrupt
1015 */
1016 while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
1017
1018 if (timeout == 0) {
1019#if (DEBUG & 0x2)
1020 printf ("Write MDIO failed...\n");
1021#endif
1022 return -1;
1023 }
1024
1025 /*
1026 * clear MII interrupt bit
1027 */
1028 eth->ievent = 0x00800000;
1029
1030 return 0;
1031}
1032
1033#if (DEBUG & 0x40)
1034static uint32 local_crc32(char *string, unsigned int crc_value, int len)
1035{
1036 int i;
1037 char c;
1038 unsigned int crc, count;
1039
1040 /*
1041 * crc32 algorithm
1042 */
1043 /*
1044 * crc = 0xffffffff; * The initialized value should be 0xffffffff
1045 */
1046 crc = crc_value;
1047
1048 for (i = len; --i >= 0;) {
1049 c = *string++;
1050 for (count = 0; count < 8; count++) {
1051 if ((c & 0x01) ^ (crc & 0x01)) {
1052 crc >>= 1;
1053 crc = crc ^ 0xedb88320;
1054 } else {
1055 crc >>= 1;
1056 }
1057 c >>= 1;
1058 }
1059 }
1060
1061 /*
1062 * In big endian system, do byte swaping for crc value
1063 */
1064 /**/ return crc;
1065}
1066#endif /* DEBUG */
1067
wdenkcbd8a352004-02-24 02:00:03 +00001068#endif /* CONFIG_MPC5xxx_FEC */