Commit a29de52b authored by Dan Murphy's avatar Dan Murphy Committed by David S. Miller
Browse files

net: dp83869: Add ability to advertise Fiber connection



Add the ability to advertise the Fiber connection if the strap or the
op-mode is configured for 100Base-FX.

Auto negotiation is not supported on this PHY when in fiber mode.

Signed-off-by: default avatarDan Murphy <dmurphy@ti.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 55f13311
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -52,6 +52,10 @@
					 BMCR_FULLDPLX | \
					 BMCR_SPEED1000)

#define MII_DP83869_FIBER_ADVERTISE    (ADVERTISED_FIBRE | \
					ADVERTISED_Pause | \
					ADVERTISED_Asym_Pause)

/* This is the same bit mask as the BMCR so re-use the BMCR default */
#define DP83869_FX_CTRL_DEFAULT	MII_DP83869_BMCR_DEFAULT

@@ -118,6 +122,28 @@ struct dp83869_private {
	int mode;
};

static int dp83869_read_status(struct phy_device *phydev)
{
	struct dp83869_private *dp83869 = phydev->priv;
	int ret;

	ret = genphy_read_status(phydev);
	if (ret)
		return ret;

	if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
		if (phydev->link) {
			if (dp83869->mode == DP83869_RGMII_100_BASE)
				phydev->speed = SPEED_100;
		} else {
			phydev->speed = SPEED_UNKNOWN;
			phydev->duplex = DUPLEX_UNKNOWN;
		}
	}

	return 0;
}

static int dp83869_ack_interrupt(struct phy_device *phydev)
{
	int err = phy_read(phydev, MII_DP83869_ISR);
@@ -295,6 +321,51 @@ static int dp83869_configure_rgmii(struct phy_device *phydev,
	return ret;
}

static int dp83869_configure_fiber(struct phy_device *phydev,
				   struct dp83869_private *dp83869)
{
	int bmcr;
	int ret;

	/* Only allow advertising what this PHY supports */
	linkmode_and(phydev->advertising, phydev->advertising,
		     phydev->supported);

	linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
	linkmode_set_bit(ADVERTISED_FIBRE, phydev->advertising);

	if (dp83869->mode == DP83869_RGMII_1000_BASE) {
		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
				 phydev->supported);
	} else {
		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
				 phydev->supported);
		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
				 phydev->supported);

		/* Auto neg is not supported in 100base FX mode */
		bmcr = phy_read(phydev, MII_BMCR);
		if (bmcr < 0)
			return bmcr;

		phydev->autoneg = AUTONEG_DISABLE;
		linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
		linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->advertising);

		if (bmcr & BMCR_ANENABLE) {
			ret =  phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
			if (ret < 0)
				return ret;
		}
	}

	/* Update advertising from supported */
	linkmode_or(phydev->advertising, phydev->advertising,
		    phydev->supported);

	return 0;
}

static int dp83869_configure_mode(struct phy_device *phydev,
				  struct dp83869_private *dp83869)
{
@@ -384,6 +455,7 @@ static int dp83869_configure_mode(struct phy_device *phydev,
		break;
	case DP83869_RGMII_1000_BASE:
	case DP83869_RGMII_100_BASE:
		ret = dp83869_configure_fiber(phydev, dp83869);
		break;
	default:
		return -EINVAL;
@@ -494,6 +566,7 @@ static struct phy_driver dp83869_driver[] = {
		/* IRQ related */
		.ack_interrupt	= dp83869_ack_interrupt,
		.config_intr	= dp83869_config_intr,
		.read_status	= dp83869_read_status,

		.suspend	= genphy_suspend,
		.resume		= genphy_resume,