From 61be0bf5cbaf9a30dc42c807ca118519e4d3bea1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Aug 2020 09:32:18 +0100 Subject: net: phy: marvell10g: select host interface configuration Select the host interface configuration according to the capabilities of the host; this allows the kernel to support SFP modules using the 88x3310. Signed-off-by: Russell King --- drivers/net/phy/marvell10g.c | 62 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index f233d09160dc..f45d1d752a1c 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -95,8 +95,8 @@ enum { MV_V2_PORT_CTRL = 0xf001, MV_V2_PORT_CTRL_SWRST = BIT(15), MV_V2_PORT_CTRL_PWRDOWN = BIT(11), - MV_V2_PORT_MAC_TYPE_MASK = 0x7, - MV_V2_PORT_MAC_TYPE_RATE_MATCH = 0x6, + MV_V2_PORT_CTRL_MACTYPE_MASK = 0x7, + MV_V2_PORT_CTRL_MACTYPE_RATE_MATCH = 0x6, /* Temperature control/read registers (88X3310 only) */ MV_V2_TEMP_CTRL = 0xf08a, MV_V2_TEMP_CTRL_MASK = 0xc000, @@ -590,19 +590,44 @@ static bool mv3310_has_pma_ngbaset_quirk(struct phy_device *phydev) MV_PHY_ALASKA_NBT_QUIRK_MASK) == MV_PHY_ALASKA_NBT_QUIRK_REV; } +static int mv3310_select_mode(struct phy_device *phydev, + unsigned long *host_interfaces) +{ + int mac_type = -1; + + if (test_bit(PHY_INTERFACE_MODE_USXGMII, host_interfaces)) + mac_type = 7; + else if (test_bit(PHY_INTERFACE_MODE_SGMII, host_interfaces) && + test_bit(PHY_INTERFACE_MODE_10GBASER, host_interfaces)) + mac_type = 4; + else if (test_bit(PHY_INTERFACE_MODE_SGMII, host_interfaces) && + test_bit(PHY_INTERFACE_MODE_RXAUI, host_interfaces)) + mac_type = 0; + else if (test_bit(PHY_INTERFACE_MODE_10GBASER, host_interfaces)) + mac_type = 6; + else if (test_bit(PHY_INTERFACE_MODE_RXAUI, host_interfaces)) + mac_type = 2; + else if (test_bit(PHY_INTERFACE_MODE_SGMII, host_interfaces)) + mac_type = 4; + + return mac_type; +} + static int mv3310_config_init(struct phy_device *phydev) { struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); - int err; - int val; + int val, ret, err, mac_type = -1; /* Check that the PHY interface type is compatible */ - if (phydev->interface != PHY_INTERFACE_MODE_SGMII && - phydev->interface != PHY_INTERFACE_MODE_2500BASEX && - phydev->interface != PHY_INTERFACE_MODE_XAUI && - phydev->interface != PHY_INTERFACE_MODE_RXAUI && - phydev->interface != PHY_INTERFACE_MODE_10GBASER) + if (!phy_interface_empty(phydev->host_interfaces)) { + mac_type = mv3310_select_mode(phydev, phydev->host_interfaces); + } else if (phydev->interface != PHY_INTERFACE_MODE_SGMII && + phydev->interface != PHY_INTERFACE_MODE_2500BASEX && + phydev->interface != PHY_INTERFACE_MODE_XAUI && + phydev->interface != PHY_INTERFACE_MODE_RXAUI && + phydev->interface != PHY_INTERFACE_MODE_10GBASER) { return -ENODEV; + } phydev->mdix_ctrl = ETH_TP_MDI_AUTO; @@ -611,11 +636,26 @@ static int mv3310_config_init(struct phy_device *phydev) if (err) return err; + if (mac_type != -1) { + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, + MV_V2_PORT_CTRL, + MV_V2_PORT_CTRL_MACTYPE_MASK, + mac_type); + if (ret > 0) + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, + MV_V2_PORT_CTRL, + MV_V2_PORT_CTRL_SWRST, + MV_V2_PORT_CTRL_SWRST); + + if (ret < 0) + return ret; + } + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); if (val < 0) return val; - priv->rate_match = ((val & MV_V2_PORT_MAC_TYPE_MASK) == - MV_V2_PORT_MAC_TYPE_RATE_MATCH); + priv->rate_match = ((val & MV_V2_PORT_CTRL_MACTYPE_MASK) == + MV_V2_PORT_CTRL_MACTYPE_RATE_MATCH); /* Enable EDPD mode - saving 600mW */ err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); -- cgit