static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev, struct ethtool_tunable *tuna, const void *data) { u8 count = *(u8 *)data; int ret; switch (tuna->id) { case ETHTOOL_PHY_DOWNSHIFT: ret = bcm_phy_downshift_set(phydev, count); break; default: return -EOPNOTSUPP; } if (ret) return ret; /* Disable EEE advertisment since this prevents the PHY * from successfully linking up, trigger auto-negotiation restart * to let the MAC decide what to do. */ ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE); if (ret) return ret; return genphy_restart_aneg(phydev); }
static int ar8031_config(struct phy_device *phydev) { if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, AR803x_DEBUG_REG_5); phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, AR803x_RGMII_TX_CLK_DLY); } if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_ADDR_REG, AR803x_DEBUG_REG_0); phy_write(phydev, MDIO_DEVAD_NONE, AR803x_PHY_DEBUG_DATA_REG, AR803x_RGMII_RX_CLK_DLY); } phydev->supported = phydev->drv->features; genphy_config_aneg(phydev); genphy_restart_aneg(phydev); return 0; }
static int ksz9021_config(struct phy_device *phydev) { unsigned ctrl1000 = 0; const unsigned master = CTRL1000_PREFER_MASTER | CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG; unsigned features = phydev->drv->features; int ret; ret = ksz9021_of_config(phydev); if (ret) return ret; if (env_get("disable_giga")) features &= ~(SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); /* force master mode for 1000BaseT due to chip errata */ if (features & SUPPORTED_1000baseT_Half) ctrl1000 |= ADVERTISE_1000HALF | master; if (features & SUPPORTED_1000baseT_Full) ctrl1000 |= ADVERTISE_1000FULL | master; phydev->advertising = features; phydev->supported = features; phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000); genphy_config_aneg(phydev); genphy_restart_aneg(phydev); return 0; }
/* This function is provided to cope with the possible failures of this phy * during aneg process. When aneg fails, the PHY reports that aneg is done * but the value found in MII_LPA is wrong: * - Early failures: MII_LPA is just 0x0001. if MII_EXPANSION reports that * the link partner (LP) supports aneg but the LP never acked our base * code word, it is likely that we never sent it to begin with. * - Late failures: MII_LPA is filled with a value which seems to make sense * but it actually is not what the LP is advertising. It seems that we * can detect this using a magic bit in the WOL bank (reg 12 - bit 12). * If this particular bit is not set when aneg is reported being done, * it means MII_LPA is likely to be wrong. * * In both case, forcing a restart of the aneg process solve the problem. * When this failure happens, the first retry is usually successful but, * in some cases, it may take up to 6 retries to get a decent result */ static int meson_gxl_read_status(struct phy_device *phydev) { int ret, wol, lpa, exp; if (phydev->autoneg == AUTONEG_ENABLE) { ret = genphy_aneg_done(phydev); if (ret < 0) return ret; else if (!ret) goto read_status_continue; /* Aneg is done, let's check everything is fine */ wol = meson_gxl_read_reg(phydev, BANK_WOL, LPI_STATUS); if (wol < 0) return wol; lpa = phy_read(phydev, MII_LPA); if (lpa < 0) return lpa; exp = phy_read(phydev, MII_EXPANSION); if (exp < 0) return exp; if (!(wol & LPI_STATUS_RSV12) || ((exp & EXPANSION_NWAY) && !(lpa & LPA_LPACK))) { /* Looks like aneg failed after all */ phydev_dbg(phydev, "LPA corruption - aneg restart\n"); return genphy_restart_aneg(phydev); } } read_status_continue: return genphy_read_status(phydev); }
static int ksz9031_center_flp_timing(struct phy_device *phydev) { /* Center KSZ9031RNX FLP timing at 16ms. */ phy_write_mmd_indirect(phydev, MII_KSZ9031RN_FLP_BURST_TX_HI, 0, 0x0006); phy_write_mmd_indirect(phydev, MII_KSZ9031RN_FLP_BURST_TX_LO, 0, 0x1a80); return genphy_restart_aneg(phydev); }
static int dsa_slave_nway_reset(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) return genphy_restart_aneg(p->phy); return -EOPNOTSUPP; }
/** * hns_nic_nway_reset - nway reset * @dev: net device * * Return 0 on success, negative on failure */ static int hns_nic_nway_reset(struct net_device *netdev) { int ret = 0; struct phy_device *phy = netdev->phydev; if (netif_running(netdev)) { if (phy) ret = genphy_restart_aneg(phy); } return ret; }
static int fe_nway_reset(struct net_device *dev) { struct fe_priv *priv = netdev_priv(dev); if (!priv->phy_dev) goto out_nway_reset; return genphy_restart_aneg(priv->phy_dev); out_nway_reset: return -EOPNOTSUPP; }
/** * hns_nic_nway_reset - nway reset * @dev: net device * * Return 0 on success, negative on failure */ static int hns_nic_nway_reset(struct net_device *netdev) { int ret = 0; struct phy_device *phy = netdev->phydev; if (netif_running(netdev)) { /* if autoneg is disabled, don't restart auto-negotiation */ if (phy && phy->autoneg == AUTONEG_ENABLE) ret = genphy_restart_aneg(phy); } return ret; }
static int hns3_nway_reset(struct net_device *netdev) { struct phy_device *phy = netdev->phydev; if (!netif_running(netdev)) return 0; /* Only support nway_reset for netdev with phy attached for now */ if (!phy) return -EOPNOTSUPP; if (phy->autoneg != AUTONEG_ENABLE) return -EINVAL; return genphy_restart_aneg(phy); }
/** * genphy_config_aneg - 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. */ int genphy_config_aneg(struct phy_device *phydev) { int err = 0; if (AUTONEG_ENABLE == phydev->autoneg) { err = genphy_config_advert(phydev); if (err < 0) return err; err = genphy_restart_aneg(phydev); } else err = genphy_setup_forced(phydev); return err; }
static int ksz9031_config(struct phy_device *phydev) { int ret; ret = ksz9031_of_config(phydev); if (ret) return ret; ret = ksz9031_center_flp_timing(phydev); if (ret) return ret; /* add an option to disable the gigabit feature of this PHY */ if (env_get("disable_giga")) { unsigned features; unsigned bmcr; /* disable speed 1000 in features supported by the PHY */ features = phydev->drv->features; features &= ~(SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full); phydev->advertising = phydev->supported = features; /* disable speed 1000 in Basic Control Register */ bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); bmcr &= ~(1 << 6); phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr); /* disable speed 1000 in 1000Base-T Control Register */ phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, 0); /* start autoneg */ genphy_config_aneg(phydev); genphy_restart_aneg(phydev); return 0; } return genphy_config(phydev); }
/** * @brief Set driver specific flags * @param[in] pointer to struct net_device. * @param[in] flags to set. */ static int32_t nss_gmac_set_priv_flags(struct net_device *netdev, u32 flags) { struct nss_gmac_dev *gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); struct phy_device *phydev = gmacdev->phydev; uint32_t changed = flags ^ gmacdev->drv_flags; if (changed & NSS_GMAC_PRIV_FLAG(LINKPOLL)) { if (!test_bit(__NSS_GMAC_LINKPOLL, &gmacdev->flags)) { /* * Platform has disabled Link polling. Do not enable * link polling via driver specific flags. This conditon * is typically true for GMACs connected to a switch. */ return -EOPNOTSUPP; } if (IS_ERR(phydev)) return -EINVAL; if (flags & NSS_GMAC_PRIV_FLAG(LINKPOLL)) { gmacdev->drv_flags |= NSS_GMAC_PRIV_FLAG(LINKPOLL); if (phydev->autoneg == AUTONEG_ENABLE) genphy_restart_aneg(phydev); } else { gmacdev->drv_flags &= ~NSS_GMAC_PRIV_FLAG(LINKPOLL); } } else if (changed & NSS_GMAC_PRIV_FLAG(TSMODE)) { if (flags & NSS_GMAC_PRIV_FLAG(TSMODE)) { gmacdev->drv_flags |= NSS_GMAC_PRIV_FLAG(TSMODE); } else { gmacdev->drv_flags &= ~NSS_GMAC_PRIV_FLAG(TSMODE); } } return 0; }
static int ar8035_config(struct phy_device *phydev) { int regval; phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007); phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016); phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007); regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018)); phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e); phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100)); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { /* select debug reg 5 */ phy_write(phydev, MDIO_DEVAD_NONE, 0x1D, 0x5); /* enable tx delay */ phy_write(phydev, MDIO_DEVAD_NONE, 0x1E, 0x0100); } if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) { /* select debug reg 0 */ phy_write(phydev, MDIO_DEVAD_NONE, 0x1D, 0x0); /* enable rx delay */ phy_write(phydev, MDIO_DEVAD_NONE, 0x1E, 0x8000); } phydev->supported = phydev->drv->features; genphy_config_aneg(phydev); genphy_restart_aneg(phydev); return 0; }
/** * @brief Restart autonegotiation * @param[in] pointer to struct net_device. */ static int nss_gmac_nway_reset(struct net_device *netdev) { struct nss_gmac_dev *gmacdev = NULL; gmacdev = (struct nss_gmac_dev *)netdev_priv(netdev); BUG_ON(gmacdev == NULL); if (!netif_running(netdev)) return -EAGAIN; /* * If the link polling for this GMAC is disabled, we probably * do not have a PHY attached. */ if (!test_bit(__NSS_GMAC_LINKPOLL, &gmacdev->flags)) return -EINVAL; if (!test_bit(__NSS_GMAC_AUTONEG, &gmacdev->flags)) return -EINVAL; genphy_restart_aneg(gmacdev->phydev); return 0; }
/* Marvell 88E1111S */ static int m88e1111s_config(struct phy_device *phydev) { int reg; if (phy_interface_is_rgmii(phydev)) { reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)) { reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { reg &= ~MIIM_88E1111_TX_DELAY; reg |= MIIM_88E1111_RX_DELAY; } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { reg &= ~MIIM_88E1111_RX_DELAY; reg |= MIIM_88E1111_TX_DELAY; } phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); if (reg & MIIM_88E1111_HWCFG_FIBER_COPPER_RES) reg |= MIIM_88E1111_HWCFG_MODE_FIBER_RGMII; else reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RGMII; phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); } if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); } if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); reg |= (MIIM_88E1111_RX_DELAY | MIIM_88E1111_TX_DELAY); phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR, reg); reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | MIIM_88E1111_HWCFG_FIBER_COPPER_RES); reg |= 0x7 | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); /* soft reset */ phy_reset(phydev); reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK | MIIM_88E1111_HWCFG_FIBER_COPPER_RES); reg |= MIIM_88E1111_HWCFG_MODE_COPPER_RTBI | MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); } /* soft reset */ phy_reset(phydev); genphy_config_aneg(phydev); genphy_restart_aneg(phydev); return 0; }
static int m88e1518_config(struct phy_device *phydev) { u16 reg; /* * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512 * /88E1514 Rev A0, Errata Section 3.1 */ /* EEE initialization */ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff); phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B); phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144); phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28); phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146); phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233); phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D); phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C); phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159); phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); /* SGMII-to-Copper mode initialization */ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { /* Select page 18 */ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 18); /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL, 0, 3, MIIM_88E151x_MODE_SGMII); /* PHY reset is necessary after changing MODE[2:0] */ m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL, MIIM_88E151x_RESET_OFFS, 1, 1); /* Reset page selection */ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0); udelay(100); } if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); reg &= ~(MIIM_88E1111_HWCFG_MODE_MASK); reg |= MIIM_88E1111_HWCFG_MODE_SGMII_NO_CLK; reg |= MIIM_88E1111_HWCFG_FIBER_COPPER_AUTO; phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR, reg); } if (phy_interface_is_rgmii(phydev)) { phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 2); reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR); reg &= ~MIIM_88E151x_RGMII_RXTX_DELAY; if (phydev->interface == PHY_INTERFACE_MODE_RGMII || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) reg |= MIIM_88E151x_RGMII_RXTX_DELAY; else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) reg |= MIIM_88E151x_RGMII_RX_DELAY; else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) reg |= MIIM_88E151x_RGMII_TX_DELAY; phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E151x_PHY_MSCR, reg); phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, 0); } /* soft reset */ phy_reset(phydev); genphy_config_aneg(phydev); genphy_restart_aneg(phydev); return 0; }