#include "sdma.h"
#include "fec.h"
-#define DEBUG 0x8
+/* #define DEBUG 0x28 */
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
- defined(CONFIG_MPC5XXX_FEC)
+ defined(CONFIG_MPC5xxx_FEC)
#if (DEBUG & 0x60)
static void tfifo_print(mpc5xxx_fec_priv *fec);
static uint32 local_crc32(char *string, unsigned int crc_value, int len);
#endif
+typedef struct {
+ uint8 data[1500]; /* actual data */
+ int length; /* actual length */
+ int used; /* buffer in use or not */
+ uint8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
+} NBUF;
+
+/********************************************************************/
+#if (DEBUG & 0x2)
+static void mpc5xxx_fec_phydump (void)
+{
+ uint16 phyStatus, i;
+ uint8 phyAddr = CONFIG_PHY_ADDR;
+ uint8 reg_mask[] = {
+#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */
+ /* regs to print: 0...7, 16...19, 21, 23, 24 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+#else
+ /* regs to print: 0...8, 16...20 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#endif
+ };
+
+ for (i = 0; i < 32; i++) {
+ if (reg_mask[i]) {
+ miiphy_read(phyAddr, i, &phyStatus);
+ printf("Mii reg %d: 0x%04x\n", i, phyStatus);
+ }
+ }
+}
+#endif
+
/********************************************************************/
static int mpc5xxx_fec_rbd_init(mpc5xxx_fec_priv *fec)
{
int ix;
char *data;
+ static int once = 0;
- /*
- * the receive ring is located right after the transmit one
- */
for (ix = 0; ix < FEC_RBD_NUM; ix++) {
- data = (char *)malloc(FEC_MAX_PKT_SIZE);
- if (data == NULL) {
- printf ("RBD INIT FAILED\n");
- return -1;
+ if (!once) {
+ data = (char *)malloc(FEC_MAX_PKT_SIZE);
+ if (data == NULL) {
+ printf ("RBD INIT FAILED\n");
+ return -1;
+ }
+ fec->rbdBase[ix].dataPointer = (uint32)data;
}
fec->rbdBase[ix].status = FEC_RBD_EMPTY;
fec->rbdBase[ix].dataLength = 0;
- fec->rbdBase[ix].dataPointer = (uint32)data;
}
+ once ++;
/*
* have the last RBD to close the ring
}
/********************************************************************/
-static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, FEC_RBD * pRbd)
+static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, volatile FEC_RBD * pRbd)
{
/*
* Reset buffer descriptor as empty
/********************************************************************/
static void mpc5xxx_fec_tbd_scrub(mpc5xxx_fec_priv *fec)
{
- FEC_TBD *pUsedTbd;
+ volatile FEC_TBD *pUsedTbd;
#if (DEBUG & 0x1)
printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
/********************************************************************/
static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
{
+ DECLARE_GLOBAL_DATA_PTR;
mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
- const uint8 phyAddr = 0; /* Only one PHY */
#if (DEBUG & 0x1)
printf ("mpc5xxx_fec_init... Begin\n");
mpc5xxx_fec_rbd_init(fec);
mpc5xxx_fec_tbd_init(fec);
- /*
- * Initialize GPIO pins
- */
- if (fec->xcv_type == SEVENWIRE) {
- /* 10MBit with 7-wire operation */
- *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000;
- } else {
- /* 100MBit with MD operation */
- *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000;
- }
-
/*
* Clear FEC-Lite interrupt event register(IEVENT)
*/
fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */
}
- if (fec->xcv_type == SEVENWIRE) {
- /*
- * Set FEC-Lite transmit control register(X_CNTRL):
- */
- /*fec->eth->x_cntrl = 0x00000002; */ /* half-duplex, heartbeat */
- fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
- } else {
- /*fec->eth->x_cntrl = 0x00000006; */ /* full-duplex, heartbeat */
- fec->eth->x_cntrl = 0x00000004; /* full-duplex, heartbeat disabled */
-
+ fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
+ if (fec->xcv_type != SEVENWIRE) {
/*
- * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(25Mhz)
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
* and do not drop the Preamble.
*/
- fec->eth->mii_speed = (0x5 << 1); /* No MII for 7-wire mode */
+ fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
}
/*
SDMA_CLEAR_IEVENT(FEC_RECV_TASK_NO);
/*
- * Set SmartDMA intMask register to enable SmartDMA task interrupts
+ * Initialize SmartDMA parameters stored in SRAM
*/
- SDMA_INT_ENABLE(FEC_RECV_TASK_NO);
+ *(volatile int *)FEC_TBD_BASE = (int)fec->tbdBase;
+ *(volatile int *)FEC_RBD_BASE = (int)fec->rbdBase;
+ *(volatile int *)FEC_TBD_NEXT = (int)fec->tbdBase;
+ *(volatile int *)FEC_RBD_NEXT = (int)fec->rbdBase;
/*
- * Initialize SmartDMA parameters stored in SRAM
+ * Enable FEC-Lite controller
+ */
+ fec->eth->ecntrl |= 0x00000006;
+
+#if (DEBUG & 0x2)
+ if (fec->xcv_type != SEVENWIRE)
+ mpc5xxx_fec_phydump ();
+#endif
+
+ /*
+ * Enable SmartDMA receive task
*/
- *(int *)FEC_TBD_BASE = (int)fec->tbdBase;
- *(int *)FEC_RBD_BASE = (int)fec->rbdBase;
- *(int *)FEC_TBD_NEXT = (int)fec->tbdBase;
- *(int *)FEC_RBD_NEXT = (int)fec->rbdBase;
+ SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
+
+#if (DEBUG & 0x1)
+ printf("mpc5xxx_fec_init... Done \n");
+#endif
+
+ return 1;
+}
+
+/********************************************************************/
+static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
+ const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */
+
+#if (DEBUG & 0x1)
+ printf ("mpc5xxx_fec_init_phy... Begin\n");
+#endif
+
+ /*
+ * Initialize GPIO pins
+ */
+ if (fec->xcv_type == SEVENWIRE) {
+ /* 10MBit with 7-wire operation */
+#if defined(CONFIG_TOTAL5200)
+ /* 7-wire and USB2 on Ethernet */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00030000;
+#else /* !CONFIG_TOTAL5200 */
+ /* 7-wire only */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000;
+#endif /* CONFIG_TOTAL5200 */
+ } else {
+ /* 100MBit with MD operation */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000;
+ }
+
+ /*
+ * Clear FEC-Lite interrupt event register(IEVENT)
+ */
+ fec->eth->ievent = 0xffffffff;
+
+ /*
+ * Set interrupt mask register
+ */
+ fec->eth->imask = 0x00000000;
+
+ if (fec->xcv_type != SEVENWIRE) {
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
+ * and do not drop the Preamble.
+ */
+ fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
+ }
if (fec->xcv_type != SEVENWIRE) {
/*
/*
* Force 10Base-T, FDX operation
*/
+#if (DEBUG & 0x2)
printf("Forcing 10 Mbps ethernet link... ");
+#endif
miiphy_read(phyAddr, 0x1, &phyStatus);
/*
miiphy_write(fec, phyAddr, 0x0, 0x0100);
#endif
} while (!(phyStatus & 0x0004)); /* !link up */
+#if (DEBUG & 0x2)
printf ("done.\n");
+#endif
} else { /* MII100 */
/*
* Set the auto-negotiation advertisement register bits
#endif
return -1;
}
- } while ((phyStatus & 0x0020) != 0x0020);
+ } while (!(phyStatus & 0x0004));
#if (DEBUG & 0x2)
printf("PHY auto neg complete! \n");
}
- /*
- * Enable FEC-Lite controller
- */
- fec->eth->ecntrl |= 0x00000006;
-
- if (fec->xcv_type != SEVENWIRE) {
#if (DEBUG & 0x2)
- uint16 phyStatus, i;
- uint8 phyAddr = 0;
-
- for (i = 0; i < 9; i++) {
- miiphy_read(phyAddr, i, &phyStatus);
- printf("Mii reg %d: 0x%04x\n", i, phyStatus);
- }
- for (i = 16; i < 21; i++) {
- miiphy_read(phyAddr, i, &phyStatus);
- printf("Mii reg %d: 0x%04x\n", i, phyStatus);
- }
+ if (fec->xcv_type != SEVENWIRE)
+ mpc5xxx_fec_phydump ();
#endif
- }
- /*
- * Enable SmartDMA receive task
- */
- SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
+
#if (DEBUG & 0x1)
- printf("mpc5xxx_fec_init... Done \n");
+ printf("mpc5xxx_fec_init_phy... Done \n");
#endif
- return 0;
+ return 1;
}
/********************************************************************/
static void mpc5xxx_fec_halt(struct eth_device *dev)
{
- mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
+#if defined(CONFIG_MPC5200)
struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
+#endif
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
int counter = 0xffff;
#if (DEBUG & 0x2)
- if (fec->xcv_type != SEVENWIRE) {
- uint16 phyStatus, i;
- uint8 phyAddr = 0;
-
- for (i = 0; i < 9; i++) {
- miiphy_read(phyAddr, i, &phyStatus);
- printf("Mii reg %d: 0x%04x\n", i, phyStatus);
- }
- for (i = 16; i < 21; i++) {
- miiphy_read(phyAddr, i, &phyStatus);
- printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
- }
- }
+ if (fec->xcv_type != SEVENWIRE)
+ mpc5xxx_fec_phydump ();
#endif
-
/*
* mask FEC chip interrupts
*/
*/
while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ;
- SDMA_INT_DISABLE (FEC_RECV_TASK_NO);
-
/*
* Disable SmartDMA tasks
*/
static void tfifo_print(mpc5xxx_fec_priv *fec)
{
- uint16 phyAddr = 0;
+ uint16 phyAddr = CONFIG_PHY_ADDR;
uint16 phyStatus;
if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
static void rfifo_print(mpc5xxx_fec_priv *fec)
{
- uint16 phyAddr = 0;
+ uint16 phyAddr = CONFIG_PHY_ADDR;
uint16 phyStatus;
if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
* 6-byte Ethernet addresses.
*/
mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
- FEC_TBD *pTbd;
+ volatile FEC_TBD *pTbd;
#if (DEBUG & 0x20)
printf("tbd status: 0x%04x\n", fec->tbdBase[0].status);
pTbd = &fec->tbdBase[fec->tbdIndex];
pTbd->dataLength = data_length;
pTbd->dataPointer = (uint32)eth_data;
- pTbd->status |= FEC_TBD_READY;
+ pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
#if (DEBUG & 0x100)
* This command pulls one frame from the card
*/
mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
- FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
+ volatile FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
unsigned long ievent;
- int frame_length;
- char *frame;
+ int frame_length, len = 0;
+ NBUF *frame;
+ char buff[FEC_MAX_PKT_SIZE];
#if (DEBUG & 0x1)
printf ("mpc5xxx_fec_recv %d Start...\n", fec->rbdIndex);
}
}
- /*
- * Do we have data in Rx FIFO?
- */
- if ((pRbd->status & FEC_RBD_EMPTY) || !(pRbd->status & FEC_RBD_LAST)){
- return 0;
- }
+ if (!(pRbd->status & FEC_RBD_EMPTY)) {
+ if ((pRbd->status & FEC_RBD_LAST) && !(pRbd->status & FEC_RBD_ERR) &&
+ ((pRbd->dataLength - 4) > 14)) {
- /*
- * Pass the packet up only if reception was Ok
- */
- if ((pRbd->dataLength <= 14) || (pRbd->status & FEC_RBD_ERR)) {
- mpc5xxx_fec_rbd_clean(fec, pRbd);
-#if (DEBUG & 0x8)
- printf( "X0" );
+ /*
+ * Get buffer address and size
+ */
+ frame = (NBUF *)pRbd->dataPointer;
+ frame_length = pRbd->dataLength - 4;
+
+#if (DEBUG & 0x20)
+ {
+ int i;
+ printf("recv data hdr:");
+ for (i = 0; i < 14; i++)
+ printf("%x ", *(frame->head + i));
+ printf("\n");
+ }
#endif
- return 0;
+ /*
+ * Fill the buffer and pass it to upper layers
+ */
+ memcpy(buff, frame->head, 14);
+ memcpy(buff + 14, frame->data, frame_length);
+ NetReceive(buff, frame_length);
+ len = frame_length;
+ }
+ /*
+ * Reset buffer descriptor as empty
+ */
+ mpc5xxx_fec_rbd_clean(fec, pRbd);
}
-
- /*
- * Get buffer address and size
- */
- frame = (char *)pRbd->dataPointer;
- frame_length = pRbd->dataLength;
-
- /*
- * Pass the buffer to upper layers
- */
- NetReceive(frame, frame_length);
-
- /*
- * Reset buffer descriptor as empty
- */
- mpc5xxx_fec_rbd_clean(fec, pRbd);
-
- return frame_length;
+ SDMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
+ return len;
}
{
mpc5xxx_fec_priv *fec;
struct eth_device *dev;
+ char *tmp, *end;
+ char env_enetaddr[6];
+ int i;
fec = (mpc5xxx_fec_priv *)malloc(sizeof(*fec));
dev = (struct eth_device *)malloc(sizeof(*dev));
+ memset(dev, 0, sizeof *dev);
fec->eth = (ethernet_regs *)MPC5XXX_FEC;
fec->tbdBase = (FEC_TBD *)FEC_BD_BASE;
fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD));
-#ifdef CONFIG_ICECUBE
+#if defined(CONFIG_ICECUBE) || defined(CONFIG_PM520) || \
+ defined(CONFIG_TOP5200) || defined(CONFIG_TQM5200) || \
+ defined(CONFIG_INKA4X0)
+# ifndef CONFIG_FEC_10MBIT
fec->xcv_type = MII100;
+# else
+ fec->xcv_type = MII10;
+# endif
+#elif defined(CONFIG_TOTAL5200)
+ fec->xcv_type = SEVENWIRE;
+#else
+#error fec->xcv_type not initialized.
#endif
dev->priv = (void *)fec;
dev->send = mpc5xxx_fec_send;
dev->recv = mpc5xxx_fec_recv;
+ sprintf(dev->name, "FEC ETHERNET");
eth_register(dev);
+ /*
+ * Try to set the mac address now. The fec mac address is
+ * a garbage after reset. When not using fec for booting
+ * the Linux fec driver will try to work with this garbage.
+ */
+ tmp = getenv("ethaddr");
+ if (tmp) {
+ for (i=0; i<6; i++) {
+ env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+ if (tmp)
+ tmp = (*end) ? end+1 : end;
+ }
+ mpc5xxx_fec_set_hwaddr(fec, env_enetaddr);
+ }
+
+ mpc5xxx_fec_init_phy(dev, bis);
return 1;
}
}
#endif /* DEBUG */
-#endif /* CONFIG_MPC5XXX_FEC */
+#endif /* CONFIG_MPC5xxx_FEC */