Commit 6985157c authored by David S. Miller's avatar David S. Miller

Merge branch 'gmii2rgmii-loopback'

Gerhard Engleder says:

====================
Add Xilinx GMII2RGMII loopback support

The Xilinx GMII2RGMII driver overrides PHY driver functions in order to
configure the device according to the link speed of the PHY attached to
it. This is implemented for a normal link but not for loopback.

Andrew told me to use phy_loopback and this changes make phy_loopback
work in combination with Xilinx GMII2RGMII.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 600003a3 ceaeaafc
......@@ -233,11 +233,9 @@ static DEFINE_MUTEX(phy_fixup_lock);
static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
{
struct device_driver *drv = phydev->mdio.dev.driver;
struct phy_driver *phydrv = to_phy_driver(drv);
struct net_device *netdev = phydev->attached_dev;
if (!drv || !phydrv->suspend)
if (!phydev->drv->suspend)
return false;
/* PHY not attached? May suspend if the PHY has not already been
......@@ -1821,11 +1819,10 @@ EXPORT_SYMBOL(phy_resume);
int phy_loopback(struct phy_device *phydev, bool enable)
{
struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
int ret = 0;
if (!phydrv)
return -ENODEV;
if (!phydev->drv)
return -EIO;
mutex_lock(&phydev->lock);
......@@ -1839,8 +1836,8 @@ int phy_loopback(struct phy_device *phydev, bool enable)
goto out;
}
if (phydrv->set_loopback)
ret = phydrv->set_loopback(phydev, enable);
if (phydev->drv->set_loopback)
ret = phydev->drv->set_loopback(phydev, enable);
else
ret = genphy_loopback(phydev, enable);
......
......@@ -27,12 +27,28 @@ struct gmii2rgmii {
struct mdio_device *mdio;
};
static int xgmiitorgmii_read_status(struct phy_device *phydev)
static void xgmiitorgmii_configure(struct gmii2rgmii *priv, int speed)
{
struct gmii2rgmii *priv = mdiodev_get_drvdata(&phydev->mdio);
struct mii_bus *bus = priv->mdio->bus;
int addr = priv->mdio->addr;
u16 val = 0;
u16 val;
val = mdiobus_read(bus, addr, XILINX_GMII2RGMII_REG);
val &= ~XILINX_GMII2RGMII_SPEED_MASK;
if (speed == SPEED_1000)
val |= BMCR_SPEED1000;
else if (speed == SPEED_100)
val |= BMCR_SPEED100;
else
val |= BMCR_SPEED10;
mdiobus_write(bus, addr, XILINX_GMII2RGMII_REG, val);
}
static int xgmiitorgmii_read_status(struct phy_device *phydev)
{
struct gmii2rgmii *priv = mdiodev_get_drvdata(&phydev->mdio);
int err;
if (priv->phy_drv->read_status)
......@@ -42,17 +58,24 @@ static int xgmiitorgmii_read_status(struct phy_device *phydev)
if (err < 0)
return err;
val = mdiobus_read(bus, addr, XILINX_GMII2RGMII_REG);
val &= ~XILINX_GMII2RGMII_SPEED_MASK;
xgmiitorgmii_configure(priv, phydev->speed);
if (phydev->speed == SPEED_1000)
val |= BMCR_SPEED1000;
else if (phydev->speed == SPEED_100)
val |= BMCR_SPEED100;
return 0;
}
static int xgmiitorgmii_set_loopback(struct phy_device *phydev, bool enable)
{
struct gmii2rgmii *priv = mdiodev_get_drvdata(&phydev->mdio);
int err;
if (priv->phy_drv->set_loopback)
err = priv->phy_drv->set_loopback(phydev, enable);
else
val |= BMCR_SPEED10;
err = genphy_loopback(phydev, enable);
if (err < 0)
return err;
mdiobus_write(bus, addr, XILINX_GMII2RGMII_REG, val);
xgmiitorgmii_configure(priv, phydev->speed);
return 0;
}
......@@ -90,6 +113,7 @@ static int xgmiitorgmii_probe(struct mdio_device *mdiodev)
memcpy(&priv->conv_phy_drv, priv->phy_dev->drv,
sizeof(struct phy_driver));
priv->conv_phy_drv.read_status = xgmiitorgmii_read_status;
priv->conv_phy_drv.set_loopback = xgmiitorgmii_set_loopback;
mdiodev_set_drvdata(&priv->phy_dev->mdio, priv);
priv->phy_dev->drv = &priv->conv_phy_drv;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment