The LCPLL Reset sequence is added to the initialization path of the VSC8574 Family of phy drivers.
The LCPLL Reset sequence is known to reduce hardware inter-op issues when using the QSGMII MAC interface. This patch is submitted to net-next to avoid merging conflicts that may arise if submitted to net. Signed-off-by: Bryan Whitehead <bryan.whiteh...@microchip.com> --- drivers/net/phy/mscc/mscc_main.c | 90 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index a4fbf3a..f2fa221 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -929,6 +929,90 @@ static bool vsc8574_is_serdes_init(struct phy_device *phydev) } /* bus->mdio_lock should be locked when using this function */ +/* Page should already be set to MSCC_PHY_PAGE_EXTENDED_GPIO */ +static int vsc8574_wait_for_micro_complete(struct phy_device *phydev) +{ + u16 timeout = 500; + u16 reg18g = 0; + + reg18g = phy_base_read(phydev, 18); + while (reg18g & 0x8000) { + timeout--; + if (timeout == 0) + return -1; + usleep_range(1000, 2000); + reg18g = phy_base_read(phydev, 18); + } + + return 0; +} + +/* bus->mdio_lock should be locked when using this function */ +static int vsc8574_reset_lcpll(struct phy_device *phydev) +{ + u16 reg_val = 0; + int ret = 0; + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + + /* Read LCPLL config vector into PRAM */ + phy_base_write(phydev, 18, 0x8023); + ret = vsc8574_wait_for_micro_complete(phydev); + if (ret) + goto done; + + /* Set Address to Poke */ + phy_base_write(phydev, 18, 0xd7d5); + ret = vsc8574_wait_for_micro_complete(phydev); + if (ret) + goto done; + + /* Poke to reset PLL Start up State Machine, + * set disable_fsm:bit 119 + */ + phy_base_write(phydev, 18, 0x8d06); + ret = vsc8574_wait_for_micro_complete(phydev); + if (ret) + goto done; + + /* Rewrite PLL config vector */ + phy_base_write(phydev, 18, 0x80c0); + ret = vsc8574_wait_for_micro_complete(phydev); + if (ret) + goto done; + + usleep_range(10000, 20000); + + /* Poke to deassert Reset of PLL State Machine, + * clear disable_fsm:bit 119 + */ + phy_base_write(phydev, 18, 0x8506); + ret = vsc8574_wait_for_micro_complete(phydev); + if (ret) + goto done; + + /* Rewrite PLL config vector */ + phy_base_write(phydev, 18, 0x80c0); + ret = vsc8574_wait_for_micro_complete(phydev); + if (ret) + goto done; + + usleep_range(10000, 20000); + + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_3); + reg_val = phy_base_read(phydev, 20); + reg_val = phy_base_read(phydev, 20); + + usleep_range(110000, 200000); + +done: + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + return ret; +} + +/* bus->mdio_lock should be locked when using this function */ static int vsc8574_config_pre_init(struct phy_device *phydev) { static const struct reg_val pre_init1[] = { @@ -1002,6 +1086,12 @@ static int vsc8574_config_pre_init(struct phy_device *phydev) bool serdes_init; int ret; + ret = vsc8574_reset_lcpll(phydev); + if (ret) { + dev_err(dev, "failed lcpll reset\n"); + return ret; + } + phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); /* all writes below are broadcasted to all PHYs in the same package */ -- 2.7.4