net: phy: mscc: timestamping and PHC support
[platform/kernel/linux-starfive.git] / drivers / net / phy / mscc / mscc_main.c
index 5ddc44f..2a70829 100644 (file)
@@ -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);
@@ -1299,10 +1299,26 @@ static void vsc8584_get_base_addr(struct phy_device *phydev)
        __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
        mutex_unlock(&phydev->mdio.bus->mdio_lock);
 
-       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;
 }
@@ -1418,6 +1434,10 @@ static int vsc8584_config_init(struct phy_device *phydev)
        if (ret)
                return ret;
 
+       ret = vsc8584_ptp_init(phydev);
+       if (ret)
+               goto err;
+
        phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
 
        val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
@@ -1455,12 +1475,20 @@ err:
 
 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);
 
@@ -1900,6 +1928,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 +2028,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 +2042,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 +2054,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 +2443,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,
 }
 
 };