]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/net/fec_mxc.c
Merge branch 'u-boot/master' into u-boot-arm/master
[karo-tx-uboot.git] / drivers / net / fec_mxc.c
index 913c5617b2069974c5a5cbb71448f6b4d84119ff..e14a3598ca3e91465cafd2d613a84d807ca1ffd1 100644 (file)
@@ -5,20 +5,7 @@
  * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
  * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
@@ -516,9 +503,7 @@ static int fec_open(struct eth_device *edev)
 #ifdef FEC_QUIRK_ENET_MAC
        {
                u32 ecr = readl(&fec->eth->ecntrl) & ~FEC_ECNTRL_SPEED;
-               u32 rcr = (readl(&fec->eth->r_cntrl) &
-                               ~(FEC_RCNTRL_RMII | FEC_RCNTRL_RMII_10T)) |
-                               FEC_RCNTRL_RGMII | FEC_RCNTRL_MII_MODE;
+               u32 rcr = readl(&fec->eth->r_cntrl) & ~FEC_RCNTRL_RMII_10T;
                if (speed == _1000BASET)
                        ecr |= FEC_ECNTRL_SPEED;
                else if (speed != _100BASET)
@@ -562,7 +547,6 @@ static int fec_init(struct eth_device *dev, bd_t* bd)
                }
                memset(fec->tbd_base, 0, size);
                fec_tbd_init(fec);
-               flush_dcache_range((unsigned)fec->tbd_base, size);
        }
 
        /*
@@ -739,6 +723,28 @@ static int fec_send(struct eth_device *dev, void *packet, int length)
        addr = (uint32_t)fec->tbd_base;
        flush_dcache_range(addr, addr + size);
 
+       /*
+        * Below we read the DMA descriptor's last four bytes back from the
+        * DRAM. This is important in order to make sure that all WRITE
+        * operations on the bus that were triggered by previous cache FLUSH
+        * have completed.
+        *
+        * Otherwise, on MX28, it is possible to observe a corruption of the
+        * DMA descriptors. Please refer to schematic "Figure 1-2" in MX28RM
+        * for the bus structure of MX28. The scenario is as follows:
+        *
+        * 1) ARM core triggers a series of WRITEs on the AHB_ARB2 bus going
+        *    to DRAM due to flush_dcache_range()
+        * 2) ARM core writes the FEC registers via AHB_ARB2
+        * 3) FEC DMA starts reading/writing from/to DRAM via AHB_ARB3
+        *
+        * Note that 2) does sometimes finish before 1) due to reordering of
+        * WRITE accesses on the AHB bus, therefore triggering 3) before the
+        * DMA descriptor is fully written into DRAM. This results in occasional
+        * corruption of the DMA descriptor.
+        */
+       readl(addr + size - 4);
+
        /*
         * Enable SmartDMA transmit task
         */
@@ -901,12 +907,16 @@ static void fec_set_dev_name(char *dest, int dev_id)
        sprintf(dest, (dev_id == -1) ? "FEC" : "FEC%i", dev_id);
 }
 
-static int fec_probe(bd_t *bd, int dev_id, int phy_id, uint32_t base_addr)
+#ifdef CONFIG_PHYLIB
+int fec_probe(bd_t *bd, int dev_id, uint32_t base_addr,
+               struct mii_dev *bus, struct phy_device *phydev)
+#else
+static int fec_probe(bd_t *bd, int dev_id, uint32_t base_addr,
+               struct mii_dev *bus, int phy_id)
+#endif
 {
-       struct phy_device *phydev;
        struct eth_device *edev;
        struct fec_priv *fec;
-       struct mii_dev *bus;
        unsigned char ethaddr[6];
        uint32_t start;
        int ret = 0;
@@ -953,69 +963,98 @@ static int fec_probe(bd_t *bd, int dev_id, int phy_id, uint32_t base_addr)
        }
 
        fec_reg_setup(fec);
-
        fec_set_dev_name(edev->name, dev_id);
        fec->dev_id = (dev_id == -1) ? 0 : dev_id;
+       fec->bus = bus;
+       fec_mii_setspeed(bus->priv);
+#ifdef CONFIG_PHYLIB
+       fec->phydev = phydev;
+       phy_connect_dev(phydev, edev);
+       /* Configure phy */
+       phy_config(phydev);
+#else
        fec->phy_id = phy_id;
+#endif
+       eth_register(edev);
+
+       if (fec_get_hwaddr(edev, dev_id, ethaddr) == 0) {
+               debug("got MAC%d address from fuse: %pM\n", dev_id, ethaddr);
+               memcpy(edev->enetaddr, ethaddr, 6);
+       }
+       return ret;
+err3:
+       free(fec);
+err2:
+       free(edev);
+err1:
+       return ret;
+}
+
+struct mii_dev *fec_get_miibus(uint32_t base_addr, int dev_id)
+{
+       struct ethernet_regs *eth = (struct ethernet_regs *)base_addr;
+       struct mii_dev *bus;
+       int ret;
 
        bus = mdio_alloc();
        if (!bus) {
                printf("mdio_alloc failed\n");
-               ret = -ENOMEM;
-               goto err3;
+               return NULL;
        }
        bus->read = fec_phy_read;
        bus->write = fec_phy_write;
+       bus->priv = eth;
        fec_set_dev_name(bus->name, dev_id);
+
+       ret = mdio_register(bus);
+       if (ret) {
+               printf("mdio_register failed\n");
+               free(bus);
+               return NULL;
+       }
+       fec_mii_setspeed(eth);
+       return bus;
+}
+
+int fecmxc_initialize_multi(bd_t *bd, int dev_id, int phy_id, uint32_t addr)
+{
+       uint32_t base_mii;
+       struct mii_dev *bus = NULL;
+#ifdef CONFIG_PHYLIB
+       struct phy_device *phydev = NULL;
+#endif
+       int ret;
+
 #ifdef CONFIG_MX28
        /*
         * The i.MX28 has two ethernet interfaces, but they are not equal.
         * Only the first one can access the MDIO bus.
         */
-       bus->priv = (struct ethernet_regs *)MXS_ENET0_BASE;
+       base_mii = MXS_ENET0_BASE;
 #else
-       bus->priv = fec->eth;
+       base_mii = addr;
 #endif
-       fec_mii_setspeed(bus->priv);
-       ret = mdio_register(bus);
-       if (ret) {
-               printf("mdio_register failed\n");
-               free(bus);
-               ret = -ENOMEM;
-               goto err3;
-       }
-       fec->bus = bus;
-       eth_register(edev);
-
-       if (fec_get_hwaddr(edev, dev_id, ethaddr) == 0) {
-               debug("got MAC%d address from fuse: %pM\n", dev_id, ethaddr);
-               memcpy(edev->enetaddr, ethaddr, 6);
-       }
-       /* Configure phy */
+       debug("eth_init: fec_probe(bd, %i, %i) @ %08x\n", dev_id, phy_id, addr);
+       bus = fec_get_miibus(base_mii, dev_id);
+       if (!bus)
+               return -ENOMEM;
 #ifdef CONFIG_PHYLIB
-       phydev = phy_connect(fec->bus, phy_id, edev, PHY_INTERFACE_MODE_RGMII);
+       phydev = phy_find_by_mask(bus, 1 << phy_id, PHY_INTERFACE_MODE_RGMII);
        if (!phydev) {
                free(bus);
-               ret = -ENOMEM;
-               goto err3;
+               return -ENOMEM;
        }
-       fec->phydev = phydev;
-       phy_config(phydev);
+       ret = fec_probe(bd, dev_id, addr, bus, phydev);
+#else
+       ret = fec_probe(bd, dev_id, addr, bus, phy_id);
 #endif
+       if (ret) {
+#ifdef CONFIG_PHYLIB
+               free(phydev);
+#endif
+               free(bus);
+       }
        return ret;
-
-err3:
-       free(fec);
-err2:
-       free(edev);
-err1:
-       return ret;
-}
-
-int fecmxc_initialize_multi(bd_t *bd, int dev_id, int phy_id, uint32_t addr)
-{
-       debug("eth_init: fec_probe(bd, %i, %i) @ %08x\n", dev_id, phy_id, addr);
-       return fec_probe(bd, dev_id, phy_id, addr);
 }
 
 #ifdef CONFIG_FEC_MXC_PHYADDR