Merge branch 'master' of git://git.denx.de/u-boot-mpc85xx
[oweals/u-boot.git] / drivers / net / phy / phy.c
index df7e9450c2614a4040ced79d12d0e21238e5f689..80bdfb6d9d5dc535ca6e89f7aa7ecaf597eb7189 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <config.h>
 #include <common.h>
+#include <console.h>
+#include <dm.h>
 #include <malloc.h>
 #include <net.h>
 #include <command.h>
@@ -20,6 +22,8 @@
 #include <linux/err.h>
 #include <linux/compiler.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /* Generic PHY support and helper functions */
 
 /**
 static int genphy_config_advert(struct phy_device *phydev)
 {
        u32 advertise;
-       int oldadv, adv;
+       int oldadv, adv, bmsr;
        int err, changed = 0;
 
-       /* Only allow advertising what
-        * this PHY supports */
+       /* Only allow advertising what this PHY supports */
        phydev->advertising &= phydev->supported;
        advertise = phydev->advertising;
 
        /* Setup standard advertisement */
-       oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+       adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+       oldadv = adv;
 
        if (adv < 0)
                return adv;
@@ -75,29 +79,40 @@ static int genphy_config_advert(struct phy_device *phydev)
                changed = 1;
        }
 
+       bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+       if (bmsr < 0)
+               return bmsr;
+
+       /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+        * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+        * logical 1.
+        */
+       if (!(bmsr & BMSR_ESTATEN))
+               return changed;
+
        /* Configure gigabit if it's supported */
-       if (phydev->supported & (SUPPORTED_1000baseT_Half |
-                               SUPPORTED_1000baseT_Full)) {
-               oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+       adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+       oldadv = adv;
 
-               if (adv < 0)
-                       return adv;
+       if (adv < 0)
+               return adv;
 
-               adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+       adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+
+       if (phydev->supported & (SUPPORTED_1000baseT_Half |
+                               SUPPORTED_1000baseT_Full)) {
                if (advertise & SUPPORTED_1000baseT_Half)
                        adv |= ADVERTISE_1000HALF;
                if (advertise & SUPPORTED_1000baseT_Full)
                        adv |= ADVERTISE_1000FULL;
+       }
 
-               if (adv != oldadv) {
-                       err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
-                                       adv);
+       if (adv != oldadv)
+               changed = 1;
 
-                       if (err < 0)
-                               return err;
-                       changed = 1;
-               }
-       }
+       err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
+       if (err < 0)
+               return err;
 
        return changed;
 }
@@ -113,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev)
 static int genphy_setup_forced(struct phy_device *phydev)
 {
        int err;
-       int ctl = 0;
+       int ctl = BMCR_ANRESTART;
 
        phydev->pause = phydev->asym_pause = 0;
 
@@ -220,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev)
        if (phydev->link && mii_reg & BMSR_LSTATUS)
                return 0;
 
-       if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+       if ((phydev->autoneg == AUTONEG_ENABLE) &&
+           !(mii_reg & BMSR_ANEGCOMPLETE)) {
                int i = 0;
 
                printf("%s Waiting for PHY auto negotiation to complete",
@@ -232,7 +248,7 @@ int genphy_update_link(struct phy_device *phydev)
                        if (i > PHY_ANEG_TIMEOUT) {
                                printf(" TIMEOUT !\n");
                                phydev->link = 0;
-                               return 0;
+                               return -ETIMEDOUT;
                        }
 
                        if (ctrlc()) {
@@ -276,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev)
        int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
 
        /* We're using autonegotiation */
-       if (phydev->supported & SUPPORTED_Autoneg) {
+       if (phydev->autoneg == AUTONEG_ENABLE) {
                u32 lpa = 0;
                int gblpa = 0;
                u32 estatus = 0;
@@ -367,8 +383,6 @@ int genphy_config(struct phy_device *phydev)
        int val;
        u32 features;
 
-       /* For now, I'll claim that the generic driver supports
-        * all possible port types */
        features = (SUPPORTED_TP | SUPPORTED_MII
                        | SUPPORTED_AUI | SUPPORTED_FIBRE |
                        SUPPORTED_BNC);
@@ -407,8 +421,8 @@ int genphy_config(struct phy_device *phydev)
                        features |= SUPPORTED_1000baseX_Half;
        }
 
-       phydev->supported = features;
-       phydev->advertising = features;
+       phydev->supported &= features;
+       phydev->advertising &= features;
 
        genphy_config_aneg(phydev);
 
@@ -417,10 +431,13 @@ int genphy_config(struct phy_device *phydev)
 
 int genphy_startup(struct phy_device *phydev)
 {
-       genphy_update_link(phydev);
-       genphy_parse_link(phydev);
+       int ret;
 
-       return 0;
+       ret = genphy_update_link(phydev);
+       if (ret)
+               return ret;
+
+       return genphy_parse_link(phydev);
 }
 
 int genphy_shutdown(struct phy_device *phydev)
@@ -432,7 +449,9 @@ static struct phy_driver genphy_driver = {
        .uid            = 0xffffffff,
        .mask           = 0xffffffff,
        .name           = "Generic PHY",
-       .features       = 0,
+       .features       = PHY_GBIT_FEATURES | SUPPORTED_MII |
+                         SUPPORTED_AUI | SUPPORTED_FIBRE |
+                         SUPPORTED_BNC,
        .config         = genphy_config,
        .startup        = genphy_startup,
        .shutdown       = genphy_shutdown,
@@ -442,6 +461,9 @@ static LIST_HEAD(phy_drivers);
 
 int phy_init(void)
 {
+#ifdef CONFIG_MV88E61XX_SWITCH
+       phy_mv88e61xx_init();
+#endif
 #ifdef CONFIG_PHY_AQUANTIA
        phy_aquantia_init();
 #endif
@@ -481,9 +503,15 @@ int phy_init(void)
 #ifdef CONFIG_PHY_TERANETICS
        phy_teranetics_init();
 #endif
+#ifdef CONFIG_PHY_TI
+       phy_ti_init();
+#endif
 #ifdef CONFIG_PHY_VITESSE
        phy_vitesse_init();
 #endif
+#ifdef CONFIG_PHY_XILINX
+       phy_xilinx_init();
+#endif
 
        return 0;
 }
@@ -493,6 +521,44 @@ int phy_register(struct phy_driver *drv)
        INIT_LIST_HEAD(&drv->list);
        list_add_tail(&drv->list, &phy_drivers);
 
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+       if (drv->probe)
+               drv->probe += gd->reloc_off;
+       if (drv->config)
+               drv->config += gd->reloc_off;
+       if (drv->startup)
+               drv->startup += gd->reloc_off;
+       if (drv->shutdown)
+               drv->shutdown += gd->reloc_off;
+       if (drv->readext)
+               drv->readext += gd->reloc_off;
+       if (drv->writeext)
+               drv->writeext += gd->reloc_off;
+#endif
+       return 0;
+}
+
+int phy_set_supported(struct phy_device *phydev, u32 max_speed)
+{
+       /* The default values for phydev->supported are provided by the PHY
+        * driver "features" member, we want to reset to sane defaults first
+        * before supporting higher speeds.
+        */
+       phydev->supported &= PHY_DEFAULT_FEATURES;
+
+       switch (max_speed) {
+       default:
+               return -ENOTSUPP;
+       case SPEED_1000:
+               phydev->supported |= PHY_1000BT_FEATURES;
+               /* fall through */
+       case SPEED_100:
+               phydev->supported |= PHY_100BT_FEATURES;
+               /* fall through */
+       case SPEED_10:
+               phydev->supported |= PHY_10BT_FEATURES;
+       }
+
        return 0;
 }
 
@@ -537,7 +603,7 @@ static struct phy_driver *get_phy_driver(struct phy_device *phydev,
 }
 
 static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
-                                           int phy_id,
+                                           u32 phy_id,
                                            phy_interface_t interface)
 {
        struct phy_device *dev;
@@ -554,7 +620,7 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
        memset(dev, 0, sizeof(*dev));
 
        dev->duplex = -1;
-       dev->link = 1;
+       dev->link = 0;
        dev->interface = interface;
 
        dev->autoneg = AUTONEG_ENABLE;
@@ -581,7 +647,7 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
  * Description: Reads the ID registers of the PHY at @addr on the
  *   @bus, stores it in @phy_id and returns zero on success.
  */
-static int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
+int __weak get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
 {
        int phy_reg;
 
@@ -654,8 +720,16 @@ static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus,
                if (phydev)
                        return phydev;
        }
-       printf("Phy %d not found\n", ffs(phy_mask) - 1);
-       return phy_device_create(bus, ffs(phy_mask) - 1, 0xffffffff, interface);
+
+       debug("\n%s PHY: ", bus->name);
+       while (phy_mask) {
+               int addr = ffs(phy_mask) - 1;
+               debug("%d ", addr);
+               phy_mask &= ~(1 << addr);
+       }
+       debug("not found\n");
+
+       return NULL;
 }
 
 /**
@@ -678,6 +752,9 @@ int phy_reset(struct phy_device *phydev)
        int timeout = 500;
        int devad = MDIO_DEVAD_NONE;
 
+       if (phydev->flags & PHY_FLAG_BROKEN_RESET)
+               return 0;
+
 #ifdef CONFIG_PHYLIB_10G
        /* If it's 10G, we need to issue reset through one of the MMDs */
        if (is_10g_interface(phydev->interface)) {
@@ -688,15 +765,7 @@ int phy_reset(struct phy_device *phydev)
        }
 #endif
 
-       reg = phy_read(phydev, devad, MII_BMCR);
-       if (reg < 0) {
-               debug("PHY status read failed\n");
-               return -1;
-       }
-
-       reg |= BMCR_RESET;
-
-       if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
+       if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
                debug("PHY reset failed\n");
                return -1;
        }
@@ -709,6 +778,7 @@ int phy_reset(struct phy_device *phydev)
         * auto-clearing).  This should happen within 0.5 seconds per the
         * IEEE spec.
         */
+       reg = phy_read(phydev, devad, MII_BMCR);
        while ((reg & BMCR_RESET) && timeout--) {
                reg = phy_read(phydev, devad, MII_BMCR);
 
@@ -746,19 +816,25 @@ struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask,
                phy_interface_t interface)
 {
        /* Reset the bus */
-       if (bus->reset)
+       if (bus->reset) {
                bus->reset(bus);
 
-       /* Wait 15ms to make sure the PHY has come out of hard reset */
-       udelay(15000);
+               /* Wait 15ms to make sure the PHY has come out of hard reset */
+               udelay(15000);
+       }
+
        return get_phy_device_by_mask(bus, phy_mask, interface);
 }
 
+#ifdef CONFIG_DM_ETH
+void phy_connect_dev(struct phy_device *phydev, struct udevice *dev)
+#else
 void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
+#endif
 {
        /* Soft Reset the PHY */
        phy_reset(phydev);
-       if (phydev->dev) {
+       if (phydev->dev && phydev->dev != dev) {
                printf("%s:%d is connected to %s.  Reconnecting to %s\n",
                                phydev->bus->name, phydev->addr,
                                phydev->dev->name, dev->name);
@@ -767,8 +843,13 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev)
        debug("%s connected to %s\n", dev->name, phydev->drv->name);
 }
 
+#ifdef CONFIG_DM_ETH
+struct phy_device *phy_connect(struct mii_dev *bus, int addr,
+               struct udevice *dev, phy_interface_t interface)
+#else
 struct phy_device *phy_connect(struct mii_dev *bus, int addr,
                struct eth_device *dev, phy_interface_t interface)
+#endif
 {
        struct phy_device *phydev;
 
@@ -801,9 +882,7 @@ __weak int board_phy_config(struct phy_device *phydev)
 int phy_config(struct phy_device *phydev)
 {
        /* Invoke an optional board-specific helper */
-       board_phy_config(phydev);
-
-       return 0;
+       return board_phy_config(phydev);
 }
 
 int phy_shutdown(struct phy_device *phydev)
@@ -813,3 +892,15 @@ int phy_shutdown(struct phy_device *phydev)
 
        return 0;
 }
+
+int phy_get_interface_by_name(const char *str)
+{
+       int i;
+
+       for (i = 0; i < PHY_INTERFACE_MODE_COUNT; i++) {
+               if (!strcmp(str, phy_interface_strings[i]))
+                       return i;
+       }
+
+       return -1;
+}