]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
net: phy: mediatek: Move LED helper functions into mtk phy lib
authorSkyLake.Huang <skylake.huang@mediatek.com>
Fri, 8 Nov 2024 16:34:52 +0000 (00:34 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 Nov 2024 13:06:04 +0000 (13:06 +0000)
This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's
LED helper functions so that we can use those helper functions in other
MTK's ethernet phy driver.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: SkyLake.Huang <skylake.huang@mediatek.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
MAINTAINERS
drivers/net/phy/mediatek/Kconfig
drivers/net/phy/mediatek/Makefile
drivers/net/phy/mediatek/mtk-ge-soc.c
drivers/net/phy/mediatek/mtk-phy-lib.c [new file with mode: 0644]
drivers/net/phy/mediatek/mtk.h [new file with mode: 0644]

index 16c37c8d7cc142137fd8f11cbe485046d0dfe8e3..675bd38630b736e38c522499d120ca1b6daafabe 100644 (file)
@@ -14440,7 +14440,9 @@ M:      SkyLake Huang <SkyLake.Huang@mediatek.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/phy/mediatek/mtk-ge-soc.c
+F:     drivers/net/phy/mediatek/mtk-phy-lib.c
 F:     drivers/net/phy/mediatek/mtk-ge.c
+F:     drivers/net/phy/mediatek/mtk.h
 F:     drivers/phy/mediatek/phy-mtk-xfi-tphy.c
 
 MEDIATEK I2C CONTROLLER DRIVER
index 112d9c0f219c6471b303cf872d6e2c62798c04d6..19b5d23e7cd0b09649c1dcabe25383954362148f 100644 (file)
@@ -1,4 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
+config MTK_NET_PHYLIB
+       tristate
+
 config MEDIATEK_GE_PHY
        tristate "MediaTek Gigabit Ethernet PHYs"
        help
@@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY
        tristate "MediaTek SoC Ethernet PHYs"
        depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
        depends on NVMEM_MTK_EFUSE
+       select MTK_NET_PHYLIB
        help
          Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
 
index 005bde26c1d72279b4d263f5dfd08213e994e205..814879d0abe5de42e9ac56a6b962443850f76720 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_MTK_NET_PHYLIB)           += mtk-phy-lib.o
 obj-$(CONFIG_MEDIATEK_GE_PHY)          += mtk-ge.o
 obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)      += mtk-ge-soc.o
index a931832b14183e9143f4291e84bf95282cb44965..d3a8b3946056e5dc13f2cff18fac298bbcadcc0d 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/phy.h>
 #include <linux/regmap.h>
 
+#include "mtk.h"
+
 #define MTK_GPHY_ID_MT7981                     0x03a29461
 #define MTK_GPHY_ID_MT7988                     0x03a29481
 
 #define MTK_PHY_DA_TX_R50_PAIR_D               0x540
 
 /* Registers on MDIO_MMD_VEND2 */
-#define MTK_PHY_LED0_ON_CTRL                   0x24
-#define MTK_PHY_LED1_ON_CTRL                   0x26
-#define   MTK_PHY_LED_ON_MASK                  GENMASK(6, 0)
-#define   MTK_PHY_LED_ON_LINK1000              BIT(0)
-#define   MTK_PHY_LED_ON_LINK100               BIT(1)
-#define   MTK_PHY_LED_ON_LINK10                        BIT(2)
-#define   MTK_PHY_LED_ON_LINK                  (MTK_PHY_LED_ON_LINK10 |\
-                                                MTK_PHY_LED_ON_LINK100 |\
-                                                MTK_PHY_LED_ON_LINK1000)
-#define   MTK_PHY_LED_ON_LINKDOWN              BIT(3)
-#define   MTK_PHY_LED_ON_FDX                   BIT(4) /* Full duplex */
-#define   MTK_PHY_LED_ON_HDX                   BIT(5) /* Half duplex */
-#define   MTK_PHY_LED_ON_FORCE_ON              BIT(6)
-#define   MTK_PHY_LED_ON_POLARITY              BIT(14)
-#define   MTK_PHY_LED_ON_ENABLE                        BIT(15)
-
-#define MTK_PHY_LED0_BLINK_CTRL                        0x25
-#define MTK_PHY_LED1_BLINK_CTRL                        0x27
-#define   MTK_PHY_LED_BLINK_1000TX             BIT(0)
-#define   MTK_PHY_LED_BLINK_1000RX             BIT(1)
-#define   MTK_PHY_LED_BLINK_100TX              BIT(2)
-#define   MTK_PHY_LED_BLINK_100RX              BIT(3)
-#define   MTK_PHY_LED_BLINK_10TX               BIT(4)
-#define   MTK_PHY_LED_BLINK_10RX               BIT(5)
-#define   MTK_PHY_LED_BLINK_RX                 (MTK_PHY_LED_BLINK_10RX |\
-                                                MTK_PHY_LED_BLINK_100RX |\
-                                                MTK_PHY_LED_BLINK_1000RX)
-#define   MTK_PHY_LED_BLINK_TX                 (MTK_PHY_LED_BLINK_10TX |\
-                                                MTK_PHY_LED_BLINK_100TX |\
-                                                MTK_PHY_LED_BLINK_1000TX)
-#define   MTK_PHY_LED_BLINK_COLLISION          BIT(6)
-#define   MTK_PHY_LED_BLINK_RX_CRC_ERR         BIT(7)
-#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR                BIT(8)
-#define   MTK_PHY_LED_BLINK_FORCE_BLINK                BIT(9)
-
 #define MTK_PHY_LED1_DEFAULT_POLARITIES                BIT(1)
 
 #define MTK_PHY_RG_BG_RASEL                    0x115
@@ -299,14 +266,6 @@ enum CAL_MODE {
        SW_M
 };
 
-#define MTK_PHY_LED_STATE_FORCE_ON     0
-#define MTK_PHY_LED_STATE_FORCE_BLINK  1
-#define MTK_PHY_LED_STATE_NETDEV       2
-
-struct mtk_socphy_priv {
-       unsigned long           led_state;
-};
-
 struct mtk_socphy_shared {
        u32                     boottrap;
        struct mtk_socphy_priv  priv[4];
@@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct phy_device *phydev)
        return mt798x_phy_calibration(phydev);
 }
 
-static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
-                                   bool on)
-{
-       unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-       struct mtk_socphy_priv *priv = phydev->priv;
-       bool changed;
-
-       if (on)
-               changed = !test_and_set_bit(bit_on, &priv->led_state);
-       else
-               changed = !!test_and_clear_bit(bit_on, &priv->led_state);
-
-       changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
-                                       (index ? 16 : 0), &priv->led_state);
-       if (changed)
-               return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-                                     MTK_PHY_LED1_ON_CTRL :
-                                     MTK_PHY_LED0_ON_CTRL,
-                                     MTK_PHY_LED_ON_MASK,
-                                     on ? MTK_PHY_LED_ON_FORCE_ON : 0);
-       else
-               return 0;
-}
-
-static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
-                                      bool blinking)
-{
-       unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-                                (index ? 16 : 0);
-       struct mtk_socphy_priv *priv = phydev->priv;
-       bool changed;
-
-       if (blinking)
-               changed = !test_and_set_bit(bit_blink, &priv->led_state);
-       else
-               changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
-
-       changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
-                             (index ? 16 : 0), &priv->led_state);
-       if (changed)
-               return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-                                    MTK_PHY_LED1_BLINK_CTRL :
-                                    MTK_PHY_LED0_BLINK_CTRL,
-                                    blinking ?
-                                    MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
-       else
-               return 0;
-}
-
 static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index,
                                    unsigned long *delay_on,
                                    unsigned long *delay_off)
 {
        bool blinking = false;
-       int err = 0;
-
-       if (index > 1)
-               return -EINVAL;
+       int err;
 
-       if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
-               blinking = true;
-               *delay_on = 50;
-               *delay_off = 50;
-       }
+       err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking);
+       if (err < 0)
+               return err;
 
-       err = mt798x_phy_hw_led_blink_set(phydev, index, blinking);
+       err = mtk_phy_hw_led_blink_set(phydev, index, blinking);
        if (err)
                return err;
 
-       return mt798x_phy_hw_led_on_set(phydev, index, false);
+       return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
+                                    false);
 }
 
 static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
@@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set(struct phy_device *phydev,
 {
        int err;
 
-       err = mt798x_phy_hw_led_blink_set(phydev, index, false);
+       err = mtk_phy_hw_led_blink_set(phydev, index, false);
        if (err)
                return err;
 
-       return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF));
+       return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK,
+                                    (value != LED_OFF));
 }
 
 static const unsigned long supported_triggers =
@@ -1269,155 +1176,26 @@ static const unsigned long supported_triggers =
 static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
                                          unsigned long rules)
 {
-       if (index > 1)
-               return -EINVAL;
-
-       /* All combinations of the supported triggers are allowed */
-       if (rules & ~supported_triggers)
-               return -EOPNOTSUPP;
-
-       return 0;
-};
+       return mtk_phy_led_hw_is_supported(phydev, index, rules,
+                                          supported_triggers);
+}
 
 static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
                                         unsigned long *rules)
 {
-       unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
-                                (index ? 16 : 0);
-       unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-       unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
-       struct mtk_socphy_priv *priv = phydev->priv;
-       int on, blink;
-
-       if (index > 1)
-               return -EINVAL;
-
-       on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-                         index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
-
-       if (on < 0)
-               return -EIO;
-
-       blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
-                            index ? MTK_PHY_LED1_BLINK_CTRL :
-                                    MTK_PHY_LED0_BLINK_CTRL);
-       if (blink < 0)
-               return -EIO;
-
-       if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX |
-                  MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
-           (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX)))
-               set_bit(bit_netdev, &priv->led_state);
-       else
-               clear_bit(bit_netdev, &priv->led_state);
-
-       if (on & MTK_PHY_LED_ON_FORCE_ON)
-               set_bit(bit_on, &priv->led_state);
-       else
-               clear_bit(bit_on, &priv->led_state);
-
-       if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
-               set_bit(bit_blink, &priv->led_state);
-       else
-               clear_bit(bit_blink, &priv->led_state);
-
-       if (!rules)
-               return 0;
-
-       if (on & MTK_PHY_LED_ON_LINK)
-               *rules |= BIT(TRIGGER_NETDEV_LINK);
-
-       if (on & MTK_PHY_LED_ON_LINK10)
-               *rules |= BIT(TRIGGER_NETDEV_LINK_10);
-
-       if (on & MTK_PHY_LED_ON_LINK100)
-               *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-
-       if (on & MTK_PHY_LED_ON_LINK1000)
-               *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-
-       if (on & MTK_PHY_LED_ON_FDX)
-               *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
-
-       if (on & MTK_PHY_LED_ON_HDX)
-               *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
-
-       if (blink & MTK_PHY_LED_BLINK_RX)
-               *rules |= BIT(TRIGGER_NETDEV_RX);
-
-       if (blink & MTK_PHY_LED_BLINK_TX)
-               *rules |= BIT(TRIGGER_NETDEV_TX);
-
-       return 0;
+       return mtk_phy_led_hw_ctrl_get(phydev, index, rules,
+                                      MTK_GPHY_LED_ON_SET,
+                                      MTK_GPHY_LED_RX_BLINK_SET,
+                                      MTK_GPHY_LED_TX_BLINK_SET);
 };
 
 static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
                                         unsigned long rules)
 {
-       unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
-       struct mtk_socphy_priv *priv = phydev->priv;
-       u16 on = 0, blink = 0;
-       int ret;
-
-       if (index > 1)
-               return -EINVAL;
-
-       if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
-               on |= MTK_PHY_LED_ON_FDX;
-
-       if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
-               on |= MTK_PHY_LED_ON_HDX;
-
-       if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
-               on |= MTK_PHY_LED_ON_LINK10;
-
-       if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-               on |= MTK_PHY_LED_ON_LINK100;
-
-       if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-               on |= MTK_PHY_LED_ON_LINK1000;
-
-       if (rules & BIT(TRIGGER_NETDEV_RX)) {
-               blink |= (on & MTK_PHY_LED_ON_LINK) ?
-                         (((on & MTK_PHY_LED_ON_LINK10) ?
-                           MTK_PHY_LED_BLINK_10RX : 0) |
-                          ((on & MTK_PHY_LED_ON_LINK100) ?
-                           MTK_PHY_LED_BLINK_100RX : 0) |
-                          ((on & MTK_PHY_LED_ON_LINK1000) ?
-                           MTK_PHY_LED_BLINK_1000RX : 0)) :
-                         MTK_PHY_LED_BLINK_RX;
-       }
-
-       if (rules & BIT(TRIGGER_NETDEV_TX)) {
-               blink |= (on & MTK_PHY_LED_ON_LINK) ?
-                         (((on & MTK_PHY_LED_ON_LINK10) ?
-                           MTK_PHY_LED_BLINK_10TX : 0) |
-                          ((on & MTK_PHY_LED_ON_LINK100) ?
-                           MTK_PHY_LED_BLINK_100TX : 0) |
-                          ((on & MTK_PHY_LED_ON_LINK1000) ?
-                           MTK_PHY_LED_BLINK_1000TX : 0)) :
-                         MTK_PHY_LED_BLINK_TX;
-       }
-
-       if (blink || on)
-               set_bit(bit_netdev, &priv->led_state);
-       else
-               clear_bit(bit_netdev, &priv->led_state);
-
-       ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
-                               MTK_PHY_LED1_ON_CTRL :
-                               MTK_PHY_LED0_ON_CTRL,
-                            MTK_PHY_LED_ON_FDX     |
-                            MTK_PHY_LED_ON_HDX     |
-                            MTK_PHY_LED_ON_LINK,
-                            on);
-
-       if (ret)
-               return ret;
-
-       return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
-                               MTK_PHY_LED1_BLINK_CTRL :
-                               MTK_PHY_LED0_BLINK_CTRL, blink);
+       return mtk_phy_led_hw_ctrl_set(phydev, index, rules,
+                                      MTK_GPHY_LED_ON_SET,
+                                      MTK_GPHY_LED_RX_BLINK_SET,
+                                      MTK_GPHY_LED_TX_BLINK_SET);
 };
 
 static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num)
@@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev)
        return 0;
 }
 
-static void mt798x_phy_leds_state_init(struct phy_device *phydev)
-{
-       int i;
-
-       for (i = 0; i < 2; ++i)
-               mt798x_phy_led_hw_control_get(phydev, i, NULL);
-}
-
 static int mt7988_phy_probe(struct phy_device *phydev)
 {
        struct mtk_socphy_shared *shared;
@@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_device *phydev)
 
        phydev->priv = priv;
 
-       mt798x_phy_leds_state_init(phydev);
+       mtk_phy_leds_state_init(phydev);
 
        err = mt7988_phy_fix_leds_polarities(phydev);
        if (err)
@@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_device *phydev)
 
        phydev->priv = priv;
 
-       mt798x_phy_leds_state_init(phydev);
+       mtk_phy_leds_state_init(phydev);
 
        return mt798x_phy_calibration(phydev);
 }
diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c
new file mode 100644 (file)
index 0000000..34b0957
--- /dev/null
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/phy.h>
+#include <linux/module.h>
+
+#include <linux/netdevice.h>
+
+#include "mtk.h"
+
+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+                               unsigned long rules,
+                               unsigned long supported_triggers)
+{
+       if (index > 1)
+               return -EINVAL;
+
+       /* All combinations of the supported triggers are allowed */
+       if (rules & ~supported_triggers)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported);
+
+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
+                           unsigned long *rules, u16 on_set,
+                           u16 rx_blink_set, u16 tx_blink_set)
+{
+       unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+                                (index ? 16 : 0);
+       unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+       unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+       struct mtk_socphy_priv *priv = phydev->priv;
+       int on, blink;
+
+       if (index > 1)
+               return -EINVAL;
+
+       on = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+                         index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL);
+
+       if (on < 0)
+               return -EIO;
+
+       blink = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+                            index ? MTK_PHY_LED1_BLINK_CTRL :
+                                    MTK_PHY_LED0_BLINK_CTRL);
+       if (blink < 0)
+               return -EIO;
+
+       if ((on & (on_set | MTK_PHY_LED_ON_FDX |
+                  MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) ||
+           (blink & (rx_blink_set | tx_blink_set)))
+               set_bit(bit_netdev, &priv->led_state);
+       else
+               clear_bit(bit_netdev, &priv->led_state);
+
+       if (on & MTK_PHY_LED_ON_FORCE_ON)
+               set_bit(bit_on, &priv->led_state);
+       else
+               clear_bit(bit_on, &priv->led_state);
+
+       if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK)
+               set_bit(bit_blink, &priv->led_state);
+       else
+               clear_bit(bit_blink, &priv->led_state);
+
+       if (!rules)
+               return 0;
+
+       if (on & on_set)
+               *rules |= BIT(TRIGGER_NETDEV_LINK);
+
+       if (on & MTK_PHY_LED_ON_LINK10)
+               *rules |= BIT(TRIGGER_NETDEV_LINK_10);
+
+       if (on & MTK_PHY_LED_ON_LINK100)
+               *rules |= BIT(TRIGGER_NETDEV_LINK_100);
+
+       if (on & MTK_PHY_LED_ON_LINK1000)
+               *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+
+       if (on & MTK_PHY_LED_ON_LINK2500)
+               *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
+
+       if (on & MTK_PHY_LED_ON_FDX)
+               *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+
+       if (on & MTK_PHY_LED_ON_HDX)
+               *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
+
+       if (blink & rx_blink_set)
+               *rules |= BIT(TRIGGER_NETDEV_RX);
+
+       if (blink & tx_blink_set)
+               *rules |= BIT(TRIGGER_NETDEV_TX);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get);
+
+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
+                           unsigned long rules, u16 on_set,
+                           u16 rx_blink_set, u16 tx_blink_set)
+{
+       unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0);
+       struct mtk_socphy_priv *priv = phydev->priv;
+       u16 on = 0, blink = 0;
+       int ret;
+
+       if (index > 1)
+               return -EINVAL;
+
+       if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+               on |= MTK_PHY_LED_ON_FDX;
+
+       if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
+               on |= MTK_PHY_LED_ON_HDX;
+
+       if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
+               on |= MTK_PHY_LED_ON_LINK10;
+
+       if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
+               on |= MTK_PHY_LED_ON_LINK100;
+
+       if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
+               on |= MTK_PHY_LED_ON_LINK1000;
+
+       if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
+               on |= MTK_PHY_LED_ON_LINK2500;
+
+       if (rules & BIT(TRIGGER_NETDEV_RX)) {
+               blink |= (on & on_set) ?
+                         (((on & MTK_PHY_LED_ON_LINK10) ?
+                           MTK_PHY_LED_BLINK_10RX : 0) |
+                          ((on & MTK_PHY_LED_ON_LINK100) ?
+                           MTK_PHY_LED_BLINK_100RX : 0) |
+                          ((on & MTK_PHY_LED_ON_LINK1000) ?
+                           MTK_PHY_LED_BLINK_1000RX : 0) |
+                          ((on & MTK_PHY_LED_ON_LINK2500) ?
+                           MTK_PHY_LED_BLINK_2500RX : 0)) :
+                         rx_blink_set;
+       }
+
+       if (rules & BIT(TRIGGER_NETDEV_TX)) {
+               blink |= (on & on_set) ?
+                         (((on & MTK_PHY_LED_ON_LINK10) ?
+                           MTK_PHY_LED_BLINK_10TX : 0) |
+                          ((on & MTK_PHY_LED_ON_LINK100) ?
+                           MTK_PHY_LED_BLINK_100TX : 0) |
+                          ((on & MTK_PHY_LED_ON_LINK1000) ?
+                           MTK_PHY_LED_BLINK_1000TX : 0) |
+                          ((on & MTK_PHY_LED_ON_LINK2500) ?
+                           MTK_PHY_LED_BLINK_2500TX : 0)) :
+                         tx_blink_set;
+       }
+
+       if (blink || on)
+               set_bit(bit_netdev, &priv->led_state);
+       else
+               clear_bit(bit_netdev, &priv->led_state);
+
+       ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+                            MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL,
+                            MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set,
+                            on);
+
+       if (ret)
+               return ret;
+
+       return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+                            MTK_PHY_LED1_BLINK_CTRL :
+                            MTK_PHY_LED0_BLINK_CTRL, blink);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set);
+
+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
+                           unsigned long *delay_off, bool *blinking)
+{
+       if (index > 1)
+               return -EINVAL;
+
+       if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) {
+               *blinking = true;
+               *delay_on = 50;
+               *delay_off = 50;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg);
+
+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+                         u16 led_on_mask, bool on)
+{
+       unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0);
+       struct mtk_socphy_priv *priv = phydev->priv;
+       bool changed;
+
+       if (on)
+               changed = !test_and_set_bit(bit_on, &priv->led_state);
+       else
+               changed = !!test_and_clear_bit(bit_on, &priv->led_state);
+
+       changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV +
+                                       (index ? 16 : 0), &priv->led_state);
+       if (changed)
+               return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ?
+                                     MTK_PHY_LED1_ON_CTRL :
+                                     MTK_PHY_LED0_ON_CTRL,
+                                     led_on_mask,
+                                     on ? MTK_PHY_LED_ON_FORCE_ON : 0);
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set);
+
+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking)
+{
+       unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK +
+                                (index ? 16 : 0);
+       struct mtk_socphy_priv *priv = phydev->priv;
+       bool changed;
+
+       if (blinking)
+               changed = !test_and_set_bit(bit_blink, &priv->led_state);
+       else
+               changed = !!test_and_clear_bit(bit_blink, &priv->led_state);
+
+       changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV +
+                             (index ? 16 : 0), &priv->led_state);
+       if (changed)
+               return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ?
+                                    MTK_PHY_LED1_BLINK_CTRL :
+                                    MTK_PHY_LED0_BLINK_CTRL,
+                                    blinking ?
+                                    MTK_PHY_LED_BLINK_FORCE_BLINK : 0);
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set);
+
+void mtk_phy_leds_state_init(struct phy_device *phydev)
+{
+       int i;
+
+       for (i = 0; i < 2; ++i)
+               phydev->drv->led_hw_control_get(phydev, i, NULL);
+}
+EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init);
+
+MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common");
+MODULE_AUTHOR("Sky Huang <SkyLake.Huang@mediatek.com>");
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h
new file mode 100644 (file)
index 0000000..9aaff2c
--- /dev/null
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Common definition for Mediatek Ethernet PHYs
+ * Author: SkyLake Huang <SkyLake.Huang@mediatek.com>
+ * Copyright (c) 2024 MediaTek Inc.
+ */
+
+#ifndef _MTK_EPHY_H_
+#define _MTK_EPHY_H_
+
+#define MTK_EXT_PAGE_ACCESS                    0x1f
+
+/* Registers on MDIO_MMD_VEND2 */
+#define MTK_PHY_LED0_ON_CTRL                   0x24
+#define MTK_PHY_LED1_ON_CTRL                   0x26
+#define   MTK_GPHY_LED_ON_MASK                 GENMASK(6, 0)
+#define   MTK_2P5GPHY_LED_ON_MASK              GENMASK(7, 0)
+#define   MTK_PHY_LED_ON_LINK1000              BIT(0)
+#define   MTK_PHY_LED_ON_LINK100               BIT(1)
+#define   MTK_PHY_LED_ON_LINK10                        BIT(2)
+#define   MTK_PHY_LED_ON_LINKDOWN              BIT(3)
+#define   MTK_PHY_LED_ON_FDX                   BIT(4) /* Full duplex */
+#define   MTK_PHY_LED_ON_HDX                   BIT(5) /* Half duplex */
+#define   MTK_PHY_LED_ON_FORCE_ON              BIT(6)
+#define   MTK_PHY_LED_ON_LINK2500              BIT(7)
+#define   MTK_PHY_LED_ON_POLARITY              BIT(14)
+#define   MTK_PHY_LED_ON_ENABLE                        BIT(15)
+
+#define MTK_PHY_LED0_BLINK_CTRL                        0x25
+#define MTK_PHY_LED1_BLINK_CTRL                        0x27
+#define   MTK_PHY_LED_BLINK_1000TX             BIT(0)
+#define   MTK_PHY_LED_BLINK_1000RX             BIT(1)
+#define   MTK_PHY_LED_BLINK_100TX              BIT(2)
+#define   MTK_PHY_LED_BLINK_100RX              BIT(3)
+#define   MTK_PHY_LED_BLINK_10TX               BIT(4)
+#define   MTK_PHY_LED_BLINK_10RX               BIT(5)
+#define   MTK_PHY_LED_BLINK_COLLISION          BIT(6)
+#define   MTK_PHY_LED_BLINK_RX_CRC_ERR         BIT(7)
+#define   MTK_PHY_LED_BLINK_RX_IDLE_ERR                BIT(8)
+#define   MTK_PHY_LED_BLINK_FORCE_BLINK                BIT(9)
+#define   MTK_PHY_LED_BLINK_2500TX             BIT(10)
+#define   MTK_PHY_LED_BLINK_2500RX             BIT(11)
+
+#define MTK_GPHY_LED_ON_SET                    (MTK_PHY_LED_ON_LINK1000 | \
+                                                MTK_PHY_LED_ON_LINK100 | \
+                                                MTK_PHY_LED_ON_LINK10)
+#define MTK_GPHY_LED_RX_BLINK_SET              (MTK_PHY_LED_BLINK_1000RX | \
+                                                MTK_PHY_LED_BLINK_100RX | \
+                                                MTK_PHY_LED_BLINK_10RX)
+#define MTK_GPHY_LED_TX_BLINK_SET              (MTK_PHY_LED_BLINK_1000RX | \
+                                                MTK_PHY_LED_BLINK_100RX | \
+                                                MTK_PHY_LED_BLINK_10RX)
+
+#define MTK_2P5GPHY_LED_ON_SET                 (MTK_PHY_LED_ON_LINK2500 | \
+                                                MTK_GPHY_LED_ON_SET)
+#define MTK_2P5GPHY_LED_RX_BLINK_SET           (MTK_PHY_LED_BLINK_2500RX | \
+                                                MTK_GPHY_LED_RX_BLINK_SET)
+#define MTK_2P5GPHY_LED_TX_BLINK_SET           (MTK_PHY_LED_BLINK_2500RX | \
+                                                MTK_GPHY_LED_TX_BLINK_SET)
+
+#define MTK_PHY_LED_STATE_FORCE_ON     0
+#define MTK_PHY_LED_STATE_FORCE_BLINK  1
+#define MTK_PHY_LED_STATE_NETDEV       2
+
+struct mtk_socphy_priv {
+       unsigned long           led_state;
+};
+
+int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
+                               unsigned long rules,
+                               unsigned long supported_triggers);
+int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index,
+                           unsigned long rules, u16 on_set,
+                           u16 rx_blink_set, u16 tx_blink_set);
+int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
+                           unsigned long *rules, u16 on_set,
+                           u16 rx_blink_set, u16 tx_blink_set);
+int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on,
+                           unsigned long *delay_off, bool *blinking);
+int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index,
+                         u16 led_on_mask, bool on);
+int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index,
+                            bool blinking);
+void mtk_phy_leds_state_init(struct phy_device *phydev);
+
+#endif /* _MTK_EPHY_H_ */