From 89a9f6eee64e54ce282584cfc7bedcdd944f7c4b Mon Sep 17 00:00:00 2001 From: Pavan Kumar Ramayanam Date: Tue, 12 Nov 2019 18:15:16 +0530 Subject: [PATCH 4103/4736] modifying link and led state with respect to cable connection Enable Marvell PHY 10G linkup on Bilby. The current 10G linkup happens only in backplane mode, meaning there will be no sideband to talk to the external PHY connected onboard. So, when the driver reads the port property as BACKPLANE, technically we are not supposed to go and read what is the external PHY connected through MDIO. This changes are only a workaround to read the external phy through MDIO in backplane mode. --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 30 ++++++-- drivers/net/phy/marvell10g.c | 80 ++++++++++++++++++++- 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 9cddcc8433e1..a6fb6754984f 100755 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -156,6 +156,11 @@ /* RRC frequency during link status check */ #define XGBE_RRC_FREQUENCY 10 +/* Enable Marvell PHY writes by forcing the MDIO connections */ +static int force_mdio_mv_bp_con = 1; +module_param(force_mdio_mv_bp_con, uint, 0644); +MODULE_PARM_DESC(force_mdio_mv_bp_con, + " Enable Marvell PHY writes by forcing the MDIO connections"); enum xgbe_port_mode { XGBE_PORT_MODE_RSVD = 0, XGBE_PORT_MODE_BACKPLANE, @@ -985,8 +990,15 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) pdata->an_again = 0; /* Check for the use of an external PHY */ - if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE) - return 0; + if (phy_data->phydev_mode == XGBE_MDIO_MODE_NONE) { + if(force_mdio_mv_bp_con) { + phy_data->phydev_mode = XGBE_MDIO_MODE_CL45; + phy_data->conn_type = XGBE_CONN_TYPE_MDIO; + netif_dbg(pdata, drv, pdata->netdev, "*** DEBUG: %s - bypass phydev_mode check\n", __func__); + } else { + return 0; + } + } /* For SFP, only use an external PHY if available */ if ((phy_data->port_mode == XGBE_PORT_MODE_SFP) && @@ -1011,7 +1023,7 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) return -ENODEV; } netif_dbg(pdata, drv, pdata->netdev, "external PHY id is %#010x\n", - phydev->phy_id); + (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45) ? phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] : phydev->phy_id); /*TODO: If c45, add request_module based on one of the MMD ids? */ @@ -1034,6 +1046,14 @@ static int xgbe_phy_find_phy_device(struct xgbe_prv_data *pdata) xgbe_phy_external_phy_quirks(pdata); + if(force_mdio_mv_bp_con) { + phy_data->phydev_mode = XGBE_MDIO_MODE_NONE; + phy_data->conn_type = XGBE_CONN_TYPE_BACKPLANE; + netif_dbg(pdata, drv, pdata->netdev, "phy_dev removed!\n"); + xgbe_phy_free_phy_device(pdata); + return 0; + } + ethtool_convert_link_mode_to_legacy_u32(&advertising, lks->link_modes.advertising); phydev->advertising &= advertising; @@ -2551,8 +2571,10 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) return 0; if ((pdata->phy.autoneg == AUTONEG_ENABLE) && - !phy_aneg_done(phy_data->phydev)) + !phy_aneg_done(phy_data->phydev)) { + netif_dbg(pdata, drv, pdata->netdev,"%s Ext phy AN not complete!\n", __func__); return 0; + } if (!phy_data->phydev->link) return 0; diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index f77a2d9e7f9d..080272a3d2b6 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -25,6 +25,7 @@ #include #include #include +#include enum { MV_PCS_BASE_T = 0x0000, @@ -48,7 +49,12 @@ enum { MV_V2_TEMP_CTRL_MASK = 0xc000, MV_V2_TEMP_CTRL_SAMPLE = 0x0000, MV_V2_TEMP_CTRL_DISABLE = 0xc000, + MV_V2_MODE_CFG = 0xf000, + MV_V2_PORT_CTRL = 0xf001, + MV_V2_LED0_CTRL = 0xf020, MV_V2_TEMP = 0xf08c, + MV_V2_HOST_KR_ENABLE = 0xf084, + MV_V2_HOST_KR_TUNE = 0xf07c, MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */ }; @@ -75,7 +81,7 @@ static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg, return ret < 0 ? ret : 1; } -#ifdef CONFIG_HWMON +#ifdef CONFIG_HWMON_MV static umode_t mv3310_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -249,6 +255,77 @@ static int mv3310_resume(struct phy_device *phydev) return mv3310_hwmon_config(phydev, true); } + +/* Some PHYs within the Alaska family like 88x3310 has problems with the + * KR Auto-negotiation. marvell datasheet for 88x3310 section 6.2.11 says that + * KR auto-negotitaion can be enabled to adapt to the incoming SERDES by writing + * to autoneg registers and the PMA/PMD registers + */ +static int mv3310_amd_quirk(struct phy_device *phydev) +{ + int reg=0, count=0; + int version, subversion; + + version = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0xC011); + subversion = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0xC012); + dev_dbg(&phydev->mdio.dev,"%s: Marvell FW Version: %x.%x \n", __func__, version, subversion); + + if(subversion != 0x400) + return 0; + + reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_ENABLE); + reg |= 0x8000; + phy_write_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_ENABLE, reg); + + reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_TUNE); + reg = (reg & ~0x8000) | 0x4000; + phy_write_mmd(phydev, MDIO_MMD_PHYXS, MV_V2_HOST_KR_TUNE, reg); + + if((reg & BIT(8)) && (reg & BIT(11))) { + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R); + /* disable BASE-R */ + phy_write_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R, reg); + } else { + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R); + /* enable BASE-R for KR initiation */ + reg |= 0x1000; + phy_write_mmd(phydev, MDIO_MMD_AN, MV_PCS_BASE_R, reg); + } + + /* down the port if no link */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_MODE_CFG); + reg &= 0xFFF7; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_MODE_CFG, reg); + + /* reset port to effect above change */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); + reg |= 0x8000; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, reg); + + /* wait till reset complete */ + count = 50; + do { + msleep(10); + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL); + } while ((reg & 0x8000) && --count); + + if(reg & 0x8000){ + dev_warn(&phydev->mdio.dev,"%s: Port Reset taking long time\n", __func__); + return -ETIMEDOUT; + } + + /* LED0 Amber light On-Off settings [1:0]=01 */ + reg = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED0_CTRL); + if((reg & 0x3) != 0x1) { + reg &= 0xFFFC; + reg |= 0x1; + phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_LED0_CTRL, reg); + } + + dev_dbg(&phydev->mdio.dev,"%s: quirk applied\n", __func__); + return 0; +} + static int mv3310_config_init(struct phy_device *phydev) { __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, }; @@ -274,6 +351,7 @@ static int mv3310_config_init(struct phy_device *phydev) __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported); } + mv3310_amd_quirk(phydev); val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2); if (val < 0) return val; -- 2.17.1