/* Enable ffe zero detection for Vitesse interoperability */
bcm_phy_write_misc(phydev, 0x26, 0x2, 0x0015);
bcm_phy_r_rc_cal_reset(phydev);
return 0;
}
staticint bcm7xxx_28nm_config_init(struct phy_device *phydev)
{
u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
u8 count; int ret = 0;
/* Newer devices have moved the revision information back into a * standard location in MII_PHYS_ID[23]
*/ if (rev == 0)
rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
/* Dummy read to a register to workaround an issue upon reset where the * internal inverter may not allow the first MDIO transaction to pass * the MDIO management controller and make us return 0xffff for such * reads.
*/
phy_read(phydev, MII_BMSR);
switch (rev) { case 0xa0: case 0xb0:
ret = bcm_phy_28nm_a0b0_afe_config_init(phydev); break; case 0xd0:
ret = bcm7xxx_28nm_d0_afe_config_init(phydev); break; case 0xe0: case 0xf0: /* Rev G0 introduces a roll over */ case 0x10:
ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev); break; case 0x01:
ret = bcm7xxx_28nm_a0_patch_afe_config_init(phydev); break; default: break;
}
if (ret) return ret;
ret = bcm_phy_enable_jumbo(phydev); if (ret) return ret;
ret = bcm_phy_downshift_get(phydev, &count); if (ret) return ret;
/* Only enable EEE if Wirespeed/downshift is disabled */
ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE); if (ret) return ret;
return bcm_phy_enable_apd(phydev, true);
}
staticint bcm7xxx_28nm_resume(struct phy_device *phydev)
{ int ret;
/* Re-apply workarounds coming out suspend/resume */
ret = bcm7xxx_28nm_config_init(phydev); if (ret) return ret;
/* 28nm Gigabit PHYs come out of reset without any half-duplex * or "hub" compliant advertised mode, fix that. This does not * cause any problems with the PHY library since genphy_config_aneg() * gracefully handles auto-negotiated and forced modes.
*/ return genphy_config_aneg(phydev);
}
staticint __phy_set_clr_bits(struct phy_device *dev, int location, int set_mask, int clr_mask)
{ int v, ret;
v = __phy_read(dev, location); if (v < 0) return v;
v &= ~clr_mask;
v |= set_mask;
ret = __phy_write(dev, location, v); if (ret < 0) return ret;
return v;
}
staticint phy_set_clr_bits(struct phy_device *dev, int location, int set_mask, int clr_mask)
{ int ret;
mutex_lock(&dev->mdio.bus->mdio_lock);
ret = __phy_set_clr_bits(dev, location, set_mask, clr_mask);
mutex_unlock(&dev->mdio.bus->mdio_lock);
return ret;
}
staticint bcm7xxx_28nm_ephy_01_afe_config_init(struct phy_device *phydev)
{ int ret;
/* set shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
MII_BCM7XXX_SHD_MODE_2, 0); if (ret < 0) return ret;
/* Set current trim values INT_trim = -1, Ext_trim =0 */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_BIAS_TRIM, 0x3BE0); if (ret < 0) goto reset_shadow_mode;
/* Cal reset */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_TL4); if (ret < 0) goto reset_shadow_mode;
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MII_BCM7XXX_TL4_RST_MSK, 0); if (ret < 0) goto reset_shadow_mode;
/* Cal reset disable */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_TL4); if (ret < 0) goto reset_shadow_mode;
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
0, MII_BCM7XXX_TL4_RST_MSK); if (ret < 0) goto reset_shadow_mode;
reset_shadow_mode: /* reset shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
MII_BCM7XXX_SHD_MODE_2); if (ret < 0) return ret;
return 0;
}
/* The 28nm EPHY does not support Clause 45 (MMD) used by bcm-phy-lib */ staticint bcm7xxx_28nm_ephy_apd_enable(struct phy_device *phydev)
{ int ret;
/* set shadow mode 1 */
ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST,
MII_BRCM_FET_BT_SRE, 0); if (ret < 0) return ret;
/* Enable auto-power down */
ret = phy_set_clr_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
MII_BRCM_FET_SHDW_AS2_APDE, 0); if (ret < 0) return ret;
/* reset shadow mode 1 */
ret = phy_set_clr_bits(phydev, MII_BRCM_FET_BRCMTEST, 0,
MII_BRCM_FET_BT_SRE); if (ret < 0) return ret;
return 0;
}
staticint bcm7xxx_28nm_ephy_eee_enable(struct phy_device *phydev)
{ int ret;
/* set shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
MII_BCM7XXX_SHD_MODE_2, 0); if (ret < 0) return ret;
/* Advertise supported modes */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_AN_EEE_ADV); if (ret < 0) goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MDIO_EEE_100TX); if (ret < 0) goto reset_shadow_mode;
/* Restore Defaults */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_PCS_CTRL_2); if (ret < 0) goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MII_BCM7XXX_PCS_CTRL_2_DEF); if (ret < 0) goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_EEE_THRESH); if (ret < 0) goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
MII_BCM7XXX_EEE_THRESH_DEF); if (ret < 0) goto reset_shadow_mode;
/* Enable EEE autonegotiation */
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_ADDR_CTRL,
MII_BCM7XXX_SHD_3_AN_STAT); if (ret < 0) goto reset_shadow_mode;
ret = phy_write(phydev, MII_BCM7XXX_SHD_2_CTRL_STAT,
(MII_BCM7XXX_AN_NULL_MSG_EN | MII_BCM7XXX_AN_EEE_EN)); if (ret < 0) goto reset_shadow_mode;
reset_shadow_mode: /* reset shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0,
MII_BCM7XXX_SHD_MODE_2); if (ret < 0) return ret;
/* Dummy read to a register to workaround a possible issue upon reset * where the internal inverter may not allow the first MDIO transaction * to pass the MDIO management controller and make us return 0xffff for * such reads.
*/
phy_read(phydev, MII_BMSR);
/* Apply AFE software work-around if necessary */ if (rev == 0x01) {
ret = bcm7xxx_28nm_ephy_01_afe_config_init(phydev); if (ret) return ret;
}
ret = bcm7xxx_28nm_ephy_eee_enable(phydev); if (ret) return ret;
/* reset shadow mode 2 */
ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2); if (ret < 0) return ret;
return 0;
}
/* Workaround for putting the PHY in IDDQ mode, required * for all BCM7XXX 40nm and 65nm PHYs
*/ staticint bcm7xxx_suspend(struct phy_device *phydev)
{ int ret; staticconststruct bcm7xxx_regs { int reg;
u16 value;
} bcm7xxx_suspend_cfg[] = {
{ MII_BCM7XXX_TEST, 0x008b },
{ MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
{ MII_BCM7XXX_100TX_DISC, 0x7000 },
{ MII_BCM7XXX_TEST, 0x000f },
{ MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
{ MII_BCM7XXX_TEST, 0x000b },
}; unsignedint i;
for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
ret = phy_write(phydev,
bcm7xxx_suspend_cfg[i].reg,
bcm7xxx_suspend_cfg[i].value); if (ret) return 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 advertisement 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;
staticint bcm7xxx_28nm_probe(struct phy_device *phydev)
{ struct bcm7xxx_phy_priv *priv; struct clk *clk; int ret = 0;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
phydev->priv = priv;
priv->stats = devm_kcalloc(&phydev->mdio.dev,
bcm_phy_get_sset_count(phydev), sizeof(u64),
GFP_KERNEL); if (!priv->stats) return -ENOMEM;
clk = devm_clk_get_optional_enabled(&phydev->mdio.dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk);
/* Dummy read to a register to workaround an issue upon reset where the * internal inverter may not allow the first MDIO transaction to pass * the MDIO management controller and make us return 0xffff for such * reads. This is needed to ensure that any subsequent reads to the * PHY will succeed.
*/
phy_read(phydev, MII_BMSR);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.