]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/net/designware.c
net: dm9000: random mac address support
[karo-tx-uboot.git] / drivers / net / designware.c
index 9b17db41f60b24353eb02d842a3907a7828e86c9..22155b4d949f76587570cbf93001370fc0d7619f 100644 (file)
@@ -2,23 +2,7 @@
  * (C) Copyright 2010
  * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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+
  */
 
 /*
@@ -28,6 +12,7 @@
 #include <common.h>
 #include <miiphy.h>
 #include <malloc.h>
+#include <linux/compiler.h>
 #include <linux/err.h>
 #include <asm/io.h>
 #include "designware.h"
@@ -111,8 +96,10 @@ static int mac_reset(struct eth_device *dev)
        ulong start;
        int timeout = CONFIG_MACRESET_TIMEOUT;
 
-       writel(DMAMAC_SRST, &dma_p->busmode);
-       writel(MII_PORTSELECT, &mac_p->conf);
+       writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
+
+       if (priv->interface != PHY_INTERFACE_MODE_RGMII)
+               writel(MII_PORTSELECT, &mac_p->conf);
 
        start = get_timer(0);
        while (get_timer(start) < timeout) {
@@ -153,6 +140,13 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
        if (priv->phy_configured != 1)
                configure_phy(dev);
 
+       /* Print link status only once */
+       if (!priv->link_printed) {
+               printf("ENET Speed is %d Mbps - %s duplex connection\n",
+                      priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
+               priv->link_printed = 1;
+       }
+
        /* Reset ethernet hardware */
        if (mac_reset(dev) < 0)
                return -1;
@@ -163,15 +157,22 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
        writel(FIXEDBURST | PRIORXTX_41 | BURST_16,
                        &dma_p->busmode);
 
-       writel(FLUSHTXFIFO | readl(&dma_p->opmode), &dma_p->opmode);
-       writel(STOREFORWARD | TXSECONDFRAME, &dma_p->opmode);
+       writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD |
+               TXSECONDFRAME, &dma_p->opmode);
 
        conf = FRAMEBURSTENABLE | DISABLERXOWN;
 
-       if (priv->speed != SPEED_1000M)
+       if (priv->speed != 1000)
                conf |= MII_PORTSELECT;
 
-       if (priv->duplex == FULL_DUPLEX)
+       if ((priv->interface != PHY_INTERFACE_MODE_MII) &&
+               (priv->interface != PHY_INTERFACE_MODE_GMII)) {
+
+               if (priv->speed == 100)
+                       conf |= FES_100;
+       }
+
+       if (priv->duplex == FULL)
                conf |= FULLDPLXMODE;
 
        writel(conf, &mac_p->conf);
@@ -389,6 +390,16 @@ static int dw_reset_phy(struct eth_device *dev)
        return 0;
 }
 
+/*
+ * Add weak default function for board specific PHY configuration
+ */
+int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr,
+               int (*mii_write)(struct eth_device *, u8, u8, u16),
+               int dw_reset_phy(struct eth_device *))
+{
+       return 0;
+}
+
 static int configure_phy(struct eth_device *dev)
 {
        struct dw_eth_dev *priv = dev->priv;
@@ -398,9 +409,6 @@ static int configure_phy(struct eth_device *dev)
        u16 bmsr;
        u32 timeout;
        ulong start;
-       u16 anlpar, btsr;
-#else
-       u16 ctrl;
 #endif
 
 #if defined(CONFIG_DW_SEARCH_PHY)
@@ -412,6 +420,16 @@ static int configure_phy(struct eth_device *dev)
 #else
        phy_addr = priv->address;
 #endif
+
+       /*
+        * Some boards need board specific PHY initialization. This is
+        * after the main driver init code but before the auto negotiation
+        * is run.
+        */
+       if (designware_board_phy_init(dev, phy_addr,
+                                     eth_mdio_write, dw_reset_phy) < 0)
+               return -1;
+
        if (dw_reset_phy(dev) < 0)
                return -1;
 
@@ -437,72 +455,32 @@ static int configure_phy(struct eth_device *dev)
 #if defined(CONFIG_DW_AUTONEG)
        timeout = CONFIG_AUTONEG_TIMEOUT;
        start = get_timer(0);
-
+       puts("Waiting for PHY auto negotiation to complete");
        while (get_timer(start) < timeout) {
                eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr);
-               if (bmsr & BMSR_ANEGCOMPLETE)
+               if (bmsr & BMSR_ANEGCOMPLETE) {
+                       priv->phy_configured = 1;
                        break;
-
-               /* Try again after 10usec */
-               udelay(10);
-       };
-
-       eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar);
-       eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr);
-
-       if (bmsr & BMSR_ANEGCOMPLETE) {
-               if (btsr & PHY_1000BTSR_1000FD) {
-                       priv->speed = SPEED_1000M;
-                       bmcr |= BMCR_SPEED1000;
-                       priv->duplex = FULL_DUPLEX;
-                       bmcr |= BMCR_FULLDPLX;
-               } else if (btsr & PHY_1000BTSR_1000HD) {
-                       priv->speed = SPEED_1000M;
-                       bmcr |= BMCR_SPEED1000;
-                       priv->duplex = HALF_DUPLEX;
-                       bmcr &= ~BMCR_FULLDPLX;
-               } else if (anlpar & LPA_100FULL) {
-                       priv->speed = SPEED_100M;
-                       bmcr |= BMCR_SPEED100;
-                       priv->duplex = FULL_DUPLEX;
-                       bmcr |= BMCR_FULLDPLX;
-               } else if (anlpar & LPA_100HALF) {
-                       priv->speed = SPEED_100M;
-                       bmcr |= BMCR_SPEED100;
-                       priv->duplex = HALF_DUPLEX;
-                       bmcr &= ~BMCR_FULLDPLX;
-               } else if (anlpar & LPA_10FULL) {
-                       priv->speed = SPEED_10M;
-                       bmcr &= ~BMCR_SPEED100;
-                       priv->duplex = FULL_DUPLEX;
-                       bmcr |= BMCR_FULLDPLX;
-               } else {
-                               priv->speed = SPEED_10M;
-                               bmcr &= ~BMCR_SPEED100;
-                               priv->duplex = HALF_DUPLEX;
-                               bmcr &= ~BMCR_FULLDPLX;
                }
-               if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0)
-                       return -1;
-       } else
-               return -1;
-#else
-       if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0)
-               return -1;
 
-       if (ctrl & BMCR_FULLDPLX)
-               priv->duplex = FULL_DUPLEX;
-       else
-               priv->duplex = HALF_DUPLEX;
+               /* Print dot all 1s to show progress */
+               if ((get_timer(start) % 1000) == 0)
+                       putc('.');
 
-       if (ctrl & BMCR_SPEED1000)
-               priv->speed = SPEED_1000M;
-       else if (ctrl & BMCR_SPEED100)
-               priv->speed = SPEED_100M;
+               /* Try again after 1msec */
+               udelay(1000);
+       };
+
+       if (!(bmsr & BMSR_ANEGCOMPLETE))
+               puts(" TIMEOUT!\n");
        else
-               priv->speed = SPEED_10M;
-#endif
+               puts(" done\n");
+#else
        priv->phy_configured = 1;
+#endif
+
+       priv->speed = miiphy_speed(dev->name, phy_addr);
+       priv->duplex = miiphy_duplex(dev->name, phy_addr);
 
        return 0;
 }
@@ -531,7 +509,7 @@ static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val)
 }
 #endif
 
-int designware_initialize(u32 id, ulong base_addr, u32 phy_addr)
+int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface)
 {
        struct eth_device *dev;
        struct dw_eth_dev *priv;
@@ -565,11 +543,7 @@ int designware_initialize(u32 id, ulong base_addr, u32 phy_addr)
                        DW_DMA_BASE_OFFSET);
        priv->address = phy_addr;
        priv->phy_configured = 0;
-
-       if (mac_reset(dev) < 0)
-               return -1;
-
-       configure_phy(dev);
+       priv->interface = interface;
 
        dev->init = dw_eth_init;
        dev->send = dw_eth_send;