summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/mscc/mscc_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/mscc/mscc_main.c')
-rw-r--r--drivers/net/phy/mscc/mscc_main.c111
1 files changed, 79 insertions, 32 deletions
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 5ddc44f87eaf..a4fbf3a4fa97 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -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;
@@ -1026,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);
@@ -1046,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);
@@ -1196,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);
@@ -1225,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);
@@ -1288,7 +1288,7 @@ static void vsc8584_get_base_addr(struct phy_device *phydev)
struct vsc8531_private *vsc8531 = phydev->priv;
u16 val, addr;
- mutex_lock(&phydev->mdio.bus->mdio_lock);
+ phy_lock_mdio_bus(phydev);
__phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED);
addr = __phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_4);
@@ -1297,12 +1297,28 @@ static void vsc8584_get_base_addr(struct phy_device *phydev)
val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
__phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
- mutex_unlock(&phydev->mdio.bus->mdio_lock);
+ phy_unlock_mdio_bus(phydev);
- if (val & PHY_ADDR_REVERSED)
+ /* 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 (val & PHY_ADDR_REVERSED) {
vsc8531->base_addr = phydev->mdio.addr + addr;
- else
+ 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;
+ }
+ }
vsc8531->addr = addr;
}
@@ -1315,7 +1331,7 @@ static int vsc8584_config_init(struct phy_device *phydev)
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
- mutex_lock(&phydev->mdio.bus->mdio_lock);
+ 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
@@ -1359,8 +1375,10 @@ static int vsc8584_config_init(struct phy_device *phydev)
goto err;
}
- 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;
@@ -1379,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;
@@ -1412,13 +1435,15 @@ static int vsc8584_config_init(struct phy_device *phydev)
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);
@@ -1449,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);
@@ -1727,7 +1760,7 @@ static int vsc8514_config_init(struct phy_device *phydev)
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
- mutex_lock(&phydev->mdio.bus->mdio_lock);
+ 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
@@ -1743,15 +1776,21 @@ static int vsc8514_config_init(struct phy_device *phydev)
if (phy_package_init_once(phydev))
vsc8514_config_pre_init(phydev);
- 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;
@@ -1815,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;
}
@@ -1842,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);
@@ -1880,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;
}
@@ -1900,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);
@@ -1999,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");
@@ -2012,8 +2048,8 @@ 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, 0);
+ 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;
@@ -2024,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);
}
@@ -2403,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,
}
};