Marvell phy: add configuration of autonegociation for fiber link.
To be correctly initilized, the fiber interface needs to be configured via autonegociation registers which use some customs options or registers. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Charles-Antoine Couret <charles-antoine.couret@nexvision.fr> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2170fef78a
commit
78301ebe9b
|
@ -493,15 +493,122 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
|
||||||
return m88e1121_config_aneg(phydev);
|
return m88e1121_config_aneg(phydev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ethtool_adv_to_fiber_adv_t
|
||||||
|
* @ethadv: the ethtool advertisement settings
|
||||||
|
*
|
||||||
|
* A small helper function that translates ethtool advertisement
|
||||||
|
* settings to phy autonegotiation advertisements for the
|
||||||
|
* MII_ADV register for fiber link.
|
||||||
|
*/
|
||||||
|
static inline u32 ethtool_adv_to_fiber_adv_t(u32 ethadv)
|
||||||
|
{
|
||||||
|
u32 result = 0;
|
||||||
|
|
||||||
|
if (ethadv & ADVERTISED_1000baseT_Half)
|
||||||
|
result |= ADVERTISE_FIBER_1000HALF;
|
||||||
|
if (ethadv & ADVERTISED_1000baseT_Full)
|
||||||
|
result |= ADVERTISE_FIBER_1000FULL;
|
||||||
|
|
||||||
|
if ((ethadv & ADVERTISE_PAUSE_ASYM) && (ethadv & ADVERTISE_PAUSE_CAP))
|
||||||
|
result |= LPA_PAUSE_ASYM_FIBER;
|
||||||
|
else if (ethadv & ADVERTISE_PAUSE_CAP)
|
||||||
|
result |= (ADVERTISE_PAUSE_FIBER
|
||||||
|
& (~ADVERTISE_PAUSE_ASYM_FIBER));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* marvell_config_aneg_fiber - restart auto-negotiation or write BMCR
|
||||||
|
* @phydev: target phy_device struct
|
||||||
|
*
|
||||||
|
* Description: If auto-negotiation is enabled, we configure the
|
||||||
|
* advertising, and then restart auto-negotiation. If it is not
|
||||||
|
* enabled, then we write the BMCR. Adapted for fiber link in
|
||||||
|
* some Marvell's devices.
|
||||||
|
*/
|
||||||
|
static int marvell_config_aneg_fiber(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int changed = 0;
|
||||||
|
int err;
|
||||||
|
int adv, oldadv;
|
||||||
|
u32 advertise;
|
||||||
|
|
||||||
|
if (phydev->autoneg != AUTONEG_ENABLE)
|
||||||
|
return genphy_setup_forced(phydev);
|
||||||
|
|
||||||
|
/* Only allow advertising what this PHY supports */
|
||||||
|
phydev->advertising &= phydev->supported;
|
||||||
|
advertise = phydev->advertising;
|
||||||
|
|
||||||
|
/* Setup fiber advertisement */
|
||||||
|
adv = phy_read(phydev, MII_ADVERTISE);
|
||||||
|
if (adv < 0)
|
||||||
|
return adv;
|
||||||
|
|
||||||
|
oldadv = adv;
|
||||||
|
adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL
|
||||||
|
| LPA_PAUSE_FIBER);
|
||||||
|
adv |= ethtool_adv_to_fiber_adv_t(advertise);
|
||||||
|
|
||||||
|
if (adv != oldadv) {
|
||||||
|
err = phy_write(phydev, MII_ADVERTISE, adv);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed == 0) {
|
||||||
|
/* Advertisement hasn't changed, but maybe aneg was never on to
|
||||||
|
* begin with? Or maybe phy was isolated?
|
||||||
|
*/
|
||||||
|
int ctl = phy_read(phydev, MII_BMCR);
|
||||||
|
|
||||||
|
if (ctl < 0)
|
||||||
|
return ctl;
|
||||||
|
|
||||||
|
if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
|
||||||
|
changed = 1; /* do restart aneg */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only restart aneg if we are advertising something different
|
||||||
|
* than we were before.
|
||||||
|
*/
|
||||||
|
if (changed > 0)
|
||||||
|
changed = genphy_restart_aneg(phydev);
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
static int m88e1510_config_aneg(struct phy_device *phydev)
|
static int m88e1510_config_aneg(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
|
||||||
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Configure the copper link first */
|
||||||
err = m88e1318_config_aneg(phydev);
|
err = m88e1318_config_aneg(phydev);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
goto error;
|
||||||
|
|
||||||
return 0;
|
/* Then the fiber link */
|
||||||
|
err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER);
|
||||||
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
err = marvell_config_aneg_fiber(phydev);
|
||||||
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
|
||||||
|
|
||||||
|
error:
|
||||||
|
phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int marvell_config_init(struct phy_device *phydev)
|
static int marvell_config_init(struct phy_device *phydev)
|
||||||
|
|
Loading…
Reference in a new issue