Hi Andy, > Extends the mii_dev structure to participate in a full-blown MDIO and > PHY driver scheme. The mii_dev structure and miiphy calls are modified > in such a way to allow the original mii command and miiphy > infrastructure to work as before, but also to support a new set of APIs > which allow (among other things) sharing of PHY driver code and 10G support > > The mii command will continue to support normal PHY management functions > (Clause 22 of 802.3), but will not be changed to support 10G > (Clause 45). > > The basic design is similar to PHY Lib from Linux, but simplified for > U-Boot's network and driver infrastructure. > > We now have MDIO drivers and PHY drivers > > An MDIO driver provides: > read > write > reset > > A PHY driver provides: > (optionally): probe > config - initial setup, starting of auto-negotiation > startup - waiting for AN, and reading link state > shutdown - any cleanup needed > > The ethernet drivers interact with the PHY Lib using these functions: > phy_connect() > phy_config() > phy_startup() > phy_shutdown() > > Each PHY driver can be configured separately, or all at once using > phylib_all_drivers.h (added in the patch which adds the drivers) > > Signed-off-by: Andy Fleming <aflem...@freescale.com>
Looks really good - a few comments: [...] > diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c > new file mode 100644 > index 0000000..ca35404 > --- /dev/null > +++ b/drivers/net/phy/phy.c > @@ -0,0 +1,705 @@ > +/* > + * Generic PHY Management code > + * > + * This software may be used and distributed according to the > + * terms of the GNU Public License, Version 2, incorporated > + * herein by reference. > + * > + * Copyright 2011 Freescale Semiconductor, Inc. > + * author Andy Fleming > + * > + * Based loosely off of Linux's PHY Lib According to http://www.denx.de/wiki/U-Boot/Patches new files need GPLv2+ headers and if I check Linux, I see GPLv2+ in drivers/net/phy/phy.c (and other people have contributed under this), so please change accrodingly. > +/** > + * genphy_update_link - update link status in @phydev > + * @phydev: target phy_device struct > + * > + * Description: Update the value in phydev->link to reflect the > + * current link value. In order to do this, we need to read > + * the status register twice, keeping the second value. > + */ > +int genphy_update_link(struct phy_device *phydev) > +{ > + unsigned int mii_reg; > + > + /* > + * Wait if the link is up, and autonegotiation is in progress > + * (ie - we're capable and it's not done) > + */ > + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); > + > + /* > + * If we already saw the link up, and it hasn't gone down, then > + * we don't need to wait for autoneg again > + */ > + if (phydev->link && mii_reg & BMSR_LSTATUS) > + return 0; > + > + if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) { > + int i = 0; > + > + printf("%s Waiting for PHY auto negotiation to complete", > + phydev->dev->name); > + while (!(mii_reg & BMSR_ANEGCOMPLETE)) { > + /* > + * Timeout reached ? > + */ > + if (i > 5000) { > + printf(" TIMEOUT !\n"); > + phydev->link = 0; > + return 0; > + } > + > + if (ctrlc()) { > + puts("user interrupt!\n"); > + phydev->link = 0; > + return -EINTR; > + } > + > + if ((i++ % 500) == 0) > + printf("."); > + > + udelay(1000); /* 1 ms */ > + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); > + } > + printf(" done\n"); > + phydev->link = 1; > + udelay(500000); /* another 500 ms (results in faster booting) */ I don't understand this, why does sleeping half a second speed up booting? A comment would be in order here. > + } else { > + /* Read the link a second time to clear the latched state */ > + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); > + > + if (mii_reg & BMSR_LSTATUS) > + phydev->link = 1; > + else > + phydev->link = 0; > + } > + > + return 0; > +} [...] > +struct phy_driver *get_phy_driver(struct phy_device *phydev, > + phy_interface_t interface) > +{ > + struct list_head *entry; > + int phy_id = phydev->phy_id; > + struct phy_driver *drv = NULL; > + > + list_for_each(entry, &phy_drivers) { > + drv = list_entry(entry, struct phy_driver, list); > + if ((drv->uid & drv->mask) == (phy_id & drv->mask)) > + return drv; > + } > + > + /* If we made it here, there's no driver for this PHY */ > + if (interface == PHY_INTERFACE_MODE_XGMII) > + return &gen10g_driver; > + else > + return &genphy_driver; > +} Maybe output a warning when the generic driver is used? From what I see later we should get a message from phy_connect, correct? If this is the case, then disregard this comment ;) Apart from these minor things, the code looks really good. I'm looking forward to seeing this merged, thanks a lot! Detlev -- Als ich entführt wurde, begannen meine Eltern aktiv zu werden. Sie vermieteten mein Zimmer. -- Woody Allen -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-40 Fax: (+49)-8142-66989-80 Email: d...@denx.de _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot