[U-Boot] [PATCH 4/7] Create PHY Lib for U-Boot
Detlev Zundel
dzu at denx.de
Wed Mar 30 13:47:00 CEST 2011
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 <afleming at 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: dzu at denx.de
More information about the U-Boot
mailing list