]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - cpu/mpc5xxx/fec.c
Add support for canmb board
[karo-tx-uboot.git] / cpu / mpc5xxx / fec.c
index 16ca0a9d20d8cd29db4bdb82f4cd881ba31a0d0f..064cee555c12eeadbc24c723741d8d4dc7987e6d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2003
+ * (C) Copyright 2003-2005
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  *
  * This file is based on mpc4200fec.c,
@@ -17,7 +17,7 @@
 /* #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);
@@ -35,6 +35,33 @@ typedef struct {
     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)
 {
@@ -88,7 +115,7 @@ static void mpc5xxx_fec_tbd_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
@@ -114,7 +141,7 @@ static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, FEC_RBD * pRbd)
 /********************************************************************/
 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",
@@ -208,9 +235,9 @@ static void mpc5xxx_fec_set_hwaddr(mpc5xxx_fec_priv *fec, char *mac)
 /********************************************************************/
 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");
@@ -222,17 +249,6 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
        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)
         */
@@ -258,21 +274,13 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
                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 */
        }
 
        /*
@@ -346,10 +354,78 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
        /*
         * 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) {
                /*
@@ -386,7 +462,9 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
                        /*
                         * 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);
@@ -421,7 +499,9 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
 #endif
                        } while (!(phyStatus & 0x0004));        /* !link up */
 
+#if (DEBUG & 0x2)
                        printf ("done.\n");
+#endif
                } else {        /* MII100 */
                        /*
                         * Set the auto-negotiation advertisement register bits
@@ -453,7 +533,7 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
 #endif
                                        return -1;
                                }
-                       } while ((phyStatus & 0x0020) != 0x0020);
+                       } while (!(phyStatus & 0x0004));
 
 #if (DEBUG & 0x2)
                        printf("PHY auto neg complete! \n");
@@ -462,36 +542,17 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
 
        }
 
-       /*
-        * 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;
 }
 
 /********************************************************************/
@@ -504,22 +565,10 @@ static void mpc5xxx_fec_halt(struct eth_device *dev)
        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
         */
@@ -582,7 +631,7 @@ static void mpc5xxx_fec_halt(struct eth_device *dev)
 
 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)
@@ -606,7 +655,7 @@ static void tfifo_print(mpc5xxx_fec_priv *fec)
 
 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)
@@ -639,7 +688,7 @@ static int mpc5xxx_fec_send(struct eth_device *dev, volatile void *eth_data,
         * 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);
@@ -730,7 +779,7 @@ static int mpc5xxx_fec_recv(struct eth_device *dev)
         * 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;
@@ -809,15 +858,29 @@ int mpc5xxx_fec_initialize(bd_t * bis)
 {
        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;
@@ -830,6 +893,22 @@ int mpc5xxx_fec_initialize(bd_t * bis)
        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;
 }
 
@@ -945,4 +1024,4 @@ static uint32 local_crc32(char *string, unsigned int crc_value, int len)
 }
 #endif /* DEBUG */
 
-#endif /* CONFIG_MPC5XXX_FEC */
+#endif /* CONFIG_MPC5xxx_FEC */