diff options
Diffstat (limited to 'drivers/net/phy/mscc/mscc_main.c')
| -rw-r--r-- | drivers/net/phy/mscc/mscc_main.c | 213 |
1 files changed, 112 insertions, 101 deletions
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index c8aa6d905d8e..6bc7406a1ce7 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -98,7 +98,7 @@ static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = { }, }; -#ifdef CONFIG_OF_MDIO +#if IS_ENABLED(CONFIG_OF_MDIO) static const struct vsc8531_edge_rate_table edge_table[] = { {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} }, {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} }, @@ -382,7 +382,7 @@ out_unlock: mutex_unlock(&phydev->lock); } -#ifdef CONFIG_OF_MDIO +#if IS_ENABLED(CONFIG_OF_MDIO) static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) { u32 vdd, sd; @@ -629,7 +629,7 @@ static int vsc8531_pre_init_seq_set(struct phy_device *phydev) if (rc < 0) return rc; rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_TEST, - MSCC_PHY_TEST_PAGE_8, 0x8000, 0x8000); + MSCC_PHY_TEST_PAGE_8, TR_CLK_DISABLE, TR_CLK_DISABLE); if (rc < 0) return rc; @@ -691,27 +691,23 @@ out_unlock: /* phydev->bus->mdio_lock should be locked when using this function */ static int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val) { - struct vsc8531_private *priv = phydev->priv; - if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) { dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n"); dump_stack(); } - return __mdiobus_write(phydev->mdio.bus, priv->base_addr, regnum, val); + return __phy_package_write(phydev, regnum, val); } /* phydev->bus->mdio_lock should be locked when using this function */ static int phy_base_read(struct phy_device *phydev, u32 regnum) { - struct vsc8531_private *priv = phydev->priv; - if (unlikely(!mutex_is_locked(&phydev->mdio.bus->mdio_lock))) { dev_err(&phydev->mdio.dev, "MDIO bus lock not held!\n"); dump_stack(); } - return __mdiobus_read(phydev->mdio.bus, priv->base_addr, regnum); + return __phy_package_read(phydev, regnum); } /* bus->mdio_lock should be locked when using this function */ @@ -1030,7 +1026,7 @@ static int vsc8574_config_pre_init(struct phy_device *phydev) phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1b20); reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); - reg |= 0x8000; + reg |= TR_CLK_DISABLE; phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR); @@ -1050,7 +1046,7 @@ static int vsc8574_config_pre_init(struct phy_device *phydev) phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST); reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); - reg &= ~0x8000; + reg &= ~TR_CLK_DISABLE; phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); @@ -1200,7 +1196,7 @@ static int vsc8584_config_pre_init(struct phy_device *phydev) phy_base_write(phydev, MSCC_PHY_TEST_PAGE_5, 0x1f20); reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); - reg |= 0x8000; + reg |= TR_CLK_DISABLE; phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR); @@ -1229,7 +1225,7 @@ static int vsc8584_config_pre_init(struct phy_device *phydev) phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TEST); reg = phy_base_read(phydev, MSCC_PHY_TEST_PAGE_8); - reg &= ~0x8000; + reg &= ~TR_CLK_DISABLE; phy_base_write(phydev, MSCC_PHY_TEST_PAGE_8, reg); phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); @@ -1287,67 +1283,55 @@ out: return ret; } -/* Check if one PHY has already done the init of the parts common to all PHYs - * in the Quad PHY package. - */ -static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed) +static void vsc8584_get_base_addr(struct phy_device *phydev) { - struct mdio_device **map = phydev->mdio.bus->mdio_map; - struct vsc8531_private *vsc8531; - struct phy_device *phy; - int i, addr; - - /* VSC8584 is a Quad PHY */ - for (i = 0; i < 4; i++) { - vsc8531 = phydev->priv; + struct vsc8531_private *vsc8531 = phydev->priv; + u16 val, addr; - if (reversed) - addr = vsc8531->base_addr - i; - else - addr = vsc8531->base_addr + i; + phy_lock_mdio_bus(phydev); + __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED); - if (!map[addr]) - continue; + addr = __phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_4); + addr >>= PHY_CNTL_4_ADDR_POS; - phy = container_of(map[addr], struct phy_device, mdio); + val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); - if ((phy->phy_id & phydev->drv->phy_id_mask) != - (phydev->drv->phy_id & phydev->drv->phy_id_mask)) - continue; + __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + phy_unlock_mdio_bus(phydev); - vsc8531 = phy->priv; + /* In the package, there are two pairs of PHYs (PHY0 + PHY2 and + * PHY1 + PHY3). The first PHY of each pair (PHY0 and PHY1) is + * the base PHY for timestamping operations. + */ + vsc8531->ts_base_addr = phydev->mdio.addr; + vsc8531->ts_base_phy = addr; - if (vsc8531 && vsc8531->pkg_init) - return true; + if (val & PHY_ADDR_REVERSED) { + vsc8531->base_addr = phydev->mdio.addr + addr; + if (addr > 1) { + vsc8531->ts_base_addr += 2; + vsc8531->ts_base_phy += 2; + } + } else { + vsc8531->base_addr = phydev->mdio.addr - addr; + if (addr > 1) { + vsc8531->ts_base_addr -= 2; + vsc8531->ts_base_phy -= 2; + } } - return false; + vsc8531->addr = addr; } static int vsc8584_config_init(struct phy_device *phydev) { struct vsc8531_private *vsc8531 = phydev->priv; - u16 addr, val; int ret, i; + u16 val; phydev->mdix_ctrl = ETH_TP_MDI_AUTO; - mutex_lock(&phydev->mdio.bus->mdio_lock); - - __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, - MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED); - addr = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, - MSCC_PHY_EXT_PHY_CNTL_4); - addr >>= PHY_CNTL_4_ADDR_POS; - - val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, - MSCC_PHY_ACTIPHY_CNTL); - if (val & PHY_ADDR_REVERSED) - vsc8531->base_addr = phydev->mdio.addr + addr; - else - vsc8531->base_addr = phydev->mdio.addr - addr; - - vsc8531->addr = addr; + phy_lock_mdio_bus(phydev); /* Some parts of the init sequence are identical for every PHY in the * package. Some parts are modifying the GPIO register bank which is a @@ -1362,7 +1346,7 @@ static int vsc8584_config_init(struct phy_device *phydev) * do the correct init sequence for all PHYs that are package-critical * in this pre-init function. */ - if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) { + if (phy_package_init_once(phydev)) { /* The following switch statement assumes that the lowest * nibble of the phy_id_mask is always 0. This works because * the lowest nibble of the PHY_ID's below are also 0. @@ -1391,10 +1375,10 @@ static int vsc8584_config_init(struct phy_device *phydev) goto err; } - vsc8531->pkg_init = true; - - phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, - MSCC_PHY_PAGE_EXTENDED_GPIO); + ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + if (ret) + goto err; val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK); val &= ~MAC_CFG_MASK; @@ -1413,6 +1397,11 @@ static int vsc8584_config_init(struct phy_device *phydev) if (ret) goto err; + ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STANDARD); + if (ret) + goto err; + if (!phy_interface_is_rgmii(phydev)) { val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT | PROC_CMD_READ_MOD_WRITE_PORT; @@ -1430,7 +1419,8 @@ static int vsc8584_config_init(struct phy_device *phydev) /* Disable SerDes for 100Base-FX */ ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF | - PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE | + PROC_CMD_FIBER_PORT(vsc8531->addr) | + PROC_CMD_FIBER_DISABLE | PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX); if (ret) @@ -1438,19 +1428,22 @@ static int vsc8584_config_init(struct phy_device *phydev) /* Disable SerDes for 1000Base-X */ ret = vsc8584_cmd(phydev, PROC_CMD_FIBER_MEDIA_CONF | - PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE | + PROC_CMD_FIBER_PORT(vsc8531->addr) | + PROC_CMD_FIBER_DISABLE | PROC_CMD_READ_MOD_WRITE_PORT | PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X); if (ret) goto err; - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); ret = vsc8584_macsec_init(phydev); if (ret) return ret; - phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); + ret = vsc8584_ptp_init(phydev); + if (ret) + return ret; val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1); val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK); @@ -1481,18 +1474,26 @@ static int vsc8584_config_init(struct phy_device *phydev) return 0; err: - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } static irqreturn_t vsc8584_handle_interrupt(struct phy_device *phydev) { + irqreturn_t ret; int irq_status; irq_status = phy_read(phydev, MII_VSC85XX_INT_STATUS); - if (irq_status < 0 || !(irq_status & MII_VSC85XX_INT_MASK_MASK)) + if (irq_status < 0) return IRQ_NONE; + /* Timestamping IRQ does not set a bit in the global INT_STATUS, so + * irq_status would be 0. + */ + ret = vsc8584_handle_ts_interrupt(phydev); + if (!(irq_status & MII_VSC85XX_INT_MASK_MASK)) + return ret; + if (irq_status & MII_VSC85XX_INT_MASK_EXT) vsc8584_handle_macsec_interrupt(phydev); @@ -1737,13 +1738,13 @@ static int __phy_write_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb, return 0; } -/* Trigger a read to the spcified MCB */ +/* Trigger a read to the specified MCB */ static int phy_update_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb) { return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_READ); } -/* Trigger a write to the spcified MCB */ +/* Trigger a write to the specified MCB */ static int phy_commit_mcb_s6g(struct phy_device *phydev, u32 reg, u8 mcb) { return __phy_write_mcb_s6g(phydev, reg, mcb, PHY_MCB_S6G_WRITE); @@ -1753,27 +1754,13 @@ static int vsc8514_config_init(struct phy_device *phydev) { struct vsc8531_private *vsc8531 = phydev->priv; unsigned long deadline; - u16 val, addr; int ret, i; + u16 val; u32 reg; phydev->mdix_ctrl = ETH_TP_MDI_AUTO; - mutex_lock(&phydev->mdio.bus->mdio_lock); - - __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED); - - addr = __phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_4); - addr >>= PHY_CNTL_4_ADDR_POS; - - val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); - - if (val & PHY_ADDR_REVERSED) - vsc8531->base_addr = phydev->mdio.addr + addr; - else - vsc8531->base_addr = phydev->mdio.addr - addr; - - vsc8531->addr = addr; + phy_lock_mdio_bus(phydev); /* Some parts of the init sequence are identical for every PHY in the * package. Some parts are modifying the GPIO register bank which is a @@ -1786,20 +1773,24 @@ static int vsc8514_config_init(struct phy_device *phydev) * do the correct init sequence for all PHYs that are package-critical * in this pre-init function. */ - if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) + if (phy_package_init_once(phydev)) vsc8514_config_pre_init(phydev); - vsc8531->pkg_init = true; - - phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, - MSCC_PHY_PAGE_EXTENDED_GPIO); + ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXTENDED_GPIO); + if (ret) + goto err; val = phy_base_read(phydev, MSCC_PHY_MAC_CFG_FASTLINK); val &= ~MAC_CFG_MASK; val |= MAC_CFG_QSGMII; ret = phy_base_write(phydev, MSCC_PHY_MAC_CFG_FASTLINK, val); + if (ret) + goto err; + ret = phy_base_write(phydev, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STANDARD); if (ret) goto err; @@ -1863,14 +1854,14 @@ static int vsc8514_config_init(struct phy_device *phydev) reg = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET, PHY_S6G_PLL_STATUS); if (reg == 0xffffffff) { - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return -EIO; } } while (time_before(jiffies, deadline) && (reg & BIT(12))); if (reg & BIT(12)) { - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return -ETIMEDOUT; } @@ -1890,23 +1881,18 @@ static int vsc8514_config_init(struct phy_device *phydev) reg = vsc85xx_csr_ctrl_phy_read(phydev, PHY_MCB_TARGET, PHY_S6G_IB_STATUS0); if (reg == 0xffffffff) { - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return -EIO; } } while (time_before(jiffies, deadline) && !(reg & BIT(8))); if (!(reg & BIT(8))) { - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return -ETIMEDOUT; } - mutex_unlock(&phydev->mdio.bus->mdio_lock); - - ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); - - if (ret) - return ret; + phy_unlock_mdio_bus(phydev); ret = phy_modify(phydev, MSCC_PHY_EXT_PHY_CNTL_1, MEDIA_OP_MODE_MASK, MEDIA_OP_MODE_COPPER << MEDIA_OP_MODE_POS); @@ -1928,7 +1914,7 @@ static int vsc8514_config_init(struct phy_device *phydev) return ret; err: - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } @@ -1948,6 +1934,7 @@ static int vsc85xx_config_intr(struct phy_device *phydev) if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { vsc8584_config_macsec_intr(phydev); + vsc8584_config_ts_intr(phydev); rc = phy_write(phydev, MII_VSC85XX_INT_MASK, MII_VSC85XX_INT_MASK_MASK); @@ -1996,6 +1983,10 @@ static int vsc8514_probe(struct phy_device *phydev) phydev->priv = vsc8531; + vsc8584_get_base_addr(phydev); + devm_phy_package_join(&phydev->mdio.dev, phydev, + vsc8531->base_addr, 0); + vsc8531->nleds = 4; vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES; vsc8531->hw_stats = vsc85xx_hw_stats; @@ -2021,6 +2012,10 @@ static int vsc8574_probe(struct phy_device *phydev) phydev->priv = vsc8531; + vsc8584_get_base_addr(phydev); + devm_phy_package_join(&phydev->mdio.dev, phydev, + vsc8531->base_addr, 0); + vsc8531->nleds = 4; vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES; vsc8531->hw_stats = vsc8584_hw_stats; @@ -2039,6 +2034,7 @@ static int vsc8584_probe(struct phy_device *phydev) u32 default_mode[4] = {VSC8531_LINK_1000_ACTIVITY, VSC8531_LINK_100_ACTIVITY, VSC8531_LINK_ACTIVITY, VSC8531_DUPLEX_COLLISION}; + int ret; if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) { dev_err(&phydev->mdio.dev, "Only VSC8584 revB is supported.\n"); @@ -2051,6 +2047,10 @@ static int vsc8584_probe(struct phy_device *phydev) phydev->priv = vsc8531; + vsc8584_get_base_addr(phydev); + devm_phy_package_join(&phydev->mdio.dev, phydev, vsc8531->base_addr, + sizeof(struct vsc85xx_shared_private)); + vsc8531->nleds = 4; vsc8531->supp_led_modes = VSC8584_SUPP_LED_MODES; vsc8531->hw_stats = vsc8584_hw_stats; @@ -2060,6 +2060,16 @@ static int vsc8584_probe(struct phy_device *phydev) if (!vsc8531->stats) return -ENOMEM; + if (phy_package_probe_once(phydev)) { + ret = vsc8584_ptp_probe_once(phydev); + if (ret) + return ret; + } + + ret = vsc8584_ptp_probe(phydev); + if (ret) + return ret; + return vsc85xx_dt_led_modes_get(phydev, default_mode); } @@ -2439,6 +2449,7 @@ static struct phy_driver vsc85xx_driver[] = { .get_sset_count = &vsc85xx_get_sset_count, .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, + .link_change_notify = &vsc85xx_link_change_notify, } }; |