/*
- * (C) Copyright 2003
+ * (C) Copyright 2003-2005
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* This file is based on mpc4200fec.c,
/* #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);
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)
{
}
/********************************************************************/
-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 */
}
/*
/*
* Initialize SmartDMA parameters stored in SRAM
*/
- *(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;
+ *(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;
+
+ /*
+ * Enable FEC-Lite controller
+ */
+ fec->eth->ecntrl |= 0x00000006;
+
+#if (DEBUG & 0x2)
+ 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");
+#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;
}
/********************************************************************/
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
*/
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);
* 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, len = 0;
NBUF *frame;
{
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_CANMB) || defined(CONFIG_ICECUBE) || \
+ defined(CONFIG_INKA4X0) || defined(CONFIG_PM520) || \
+ defined(CONFIG_TOP5200) || defined(CONFIG_TQM5200)
+# 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;
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 */