generic: 6.6: backports and add LED support for Aquantia PHYs
authorDaniel Golle <daniel@makrotopia.org>
Fri, 10 May 2024 23:48:57 +0000 (00:48 +0100)
committerDaniel Golle <daniel@makrotopia.org>
Fri, 24 May 2024 17:34:13 +0000 (18:34 +0100)
Backport patch adding support for the AQR114C PHY and add support for
PHY LEDs and polarity setting of Aquantia 3rd and 4th generation PHYs.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
target/linux/generic/hack-6.6/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch
target/linux/generic/hack-6.6/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch
target/linux/generic/pending-6.6/743-net-phy-aquantia-add-support-for-PHY-LEDs.patch [new file with mode: 0644]
target/linux/generic/pending-6.6/999-net-phy-move-LED-polarity-to-phy_init_hw.patch [new file with mode: 0644]

index ff2038d6f7cd4440487aa09e30b577b04b26cb8b..b3fb3c5020c910ea7dc036eb781e95d48be35a8b 100644 (file)
@@ -15,9 +15,9 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
 
 --- a/drivers/net/phy/aquantia/aquantia_main.c
 +++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -102,6 +102,29 @@
- #define AQR107_OP_IN_PROG_SLEEP               1000
- #define AQR107_OP_IN_PROG_TIMEOUT     100000
+@@ -127,6 +127,29 @@ struct aqr107_priv {
+       u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
+ };
  
 +/* registers in MDIO_MMD_VEND1 region */
 +#define AQUANTIA_VND1_GLOBAL_SC                       0x000
@@ -42,9 +42,9 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
 +#define AQUANTIA_VND1_GSYSCFG_5G              3
 +#define AQUANTIA_VND1_GSYSCFG_10G             4
 +
- struct aqr107_hw_stat {
-       const char *name;
-       int reg;
+ static int aqr107_get_sset_count(struct phy_device *phydev)
+ {
+       return AQR107_SGMII_STAT_SZ;
 @@ -233,6 +256,51 @@ static int aqr_config_aneg(struct phy_de
        return genphy_c45_check_and_restart_aneg(phydev, changed);
  }
@@ -97,7 +97,7 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
  static int aqr_config_intr(struct phy_device *phydev)
  {
        bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
-@@ -810,7 +878,7 @@ static struct phy_driver aqr_driver[] =
+@@ -838,7 +906,7 @@ static struct phy_driver aqr_driver[] =
        PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
        .name           = "Aquantia AQR112",
        .probe          = aqr107_probe,
@@ -106,7 +106,7 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
        .config_intr    = aqr_config_intr,
        .handle_interrupt = aqr_handle_interrupt,
        .get_tunable    = aqr107_get_tunable,
-@@ -828,7 +896,7 @@ static struct phy_driver aqr_driver[] =
+@@ -863,7 +931,7 @@ static struct phy_driver aqr_driver[] =
        PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
        .name           = "Aquantia AQR412",
        .probe          = aqr107_probe,
index 4a72b1bd2b2998c5859c221086b74ffdb383aff0..c93a77d6a47e8866d209eea20143579fdea9be09 100644 (file)
@@ -21,9 +21,9 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  
  #define MDIO_PHYXS_VEND_IF_STATUS             0xe812
  #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK   GENMASK(7, 3)
-@@ -992,6 +994,30 @@ static struct phy_driver aqr_driver[] =
-       .get_stats      = aqr107_get_stats,
-       .link_change_notify = aqr107_link_change_notify,
+@@ -1062,6 +1064,30 @@ static struct phy_driver aqr_driver[] =
+       .led_polarity_set = aqr_phy_led_polarity_set,
+ #endif
  },
 +{
 +      PHY_ID_MATCH_MODEL(PHY_ID_AQR112C),
@@ -52,7 +52,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
  };
  
  module_phy_driver(aqr_driver);
-@@ -1012,6 +1038,8 @@ static struct mdio_device_id __maybe_unu
+@@ -1082,6 +1108,8 @@ static struct mdio_device_id __maybe_unu
        { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
        { PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) },
        { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
diff --git a/target/linux/generic/pending-6.6/743-net-phy-aquantia-add-support-for-PHY-LEDs.patch b/target/linux/generic/pending-6.6/743-net-phy-aquantia-add-support-for-PHY-LEDs.patch
new file mode 100644 (file)
index 0000000..ca3a2b5
--- /dev/null
@@ -0,0 +1,368 @@
+From c6a1759365fc35463138a7d9e335ee53f384b8df Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 10 May 2024 02:53:52 +0100
+Subject: [PATCH] net: phy: aquantia: add support for PHY LEDs
+
+Aquantia Ethernet PHYs got 3 LED output pins which are typically used
+to indicate link status and activity.
+Add a minimal LED controller driver supporting the most common uses
+with the 'netdev' trigger as well as software-driven forced control of
+the LEDs.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/net/phy/aquantia/Makefile        |   3 +
+ drivers/net/phy/aquantia/aquantia.h      |  84 +++++++++++++
+ drivers/net/phy/aquantia/aquantia_leds.c | 152 +++++++++++++++++++++++
+ drivers/net/phy/aquantia/aquantia_main.c | 127 +++++++++++++------
+ 4 files changed, 329 insertions(+), 37 deletions(-)
+ create mode 100644 drivers/net/phy/aquantia/aquantia_leds.c
+
+--- a/drivers/net/phy/aquantia/Makefile
++++ b/drivers/net/phy/aquantia/Makefile
+@@ -3,4 +3,7 @@ aquantia-objs                  += aquantia_main.o aquan
+ ifdef CONFIG_HWMON
+ aquantia-objs                 += aquantia_hwmon.o
+ endif
++ifdef CONFIG_PHYLIB_LEDS
++aquantia-objs                 += aquantia_leds.o
++endif
+ obj-$(CONFIG_AQUANTIA_PHY)    += aquantia.o
+--- a/drivers/net/phy/aquantia/aquantia.h
++++ b/drivers/net/phy/aquantia/aquantia.h
+@@ -62,6 +62,26 @@
+ #define VEND1_THERMAL_PROV_LOW_TEMP_FAIL      0xc422
+ #define VEND1_THERMAL_PROV_HIGH_TEMP_WARN     0xc423
+ #define VEND1_THERMAL_PROV_LOW_TEMP_WARN      0xc424
++
++#define AQR_NUM_LEDS                          3
++
++#define VEND1_GLOBAL_LED_PROV                 0xc430
++#define AQR_LED_PROV(x)                               (VEND1_GLOBAL_LED_PROV + x)
++#define VEND1_GLOBAL_LED_PROV_ACT_STRETCH     GENMASK(0, 1)
++#define VEND1_GLOBAL_LED_PROV_TX_ACT          BIT(2)
++#define VEND1_GLOBAL_LED_PROV_RX_ACT          BIT(3)
++#define VEND1_GLOBAL_LED_PROV_LINK_MASK               (GENMASK(15, 14) | GENMASK(8, 5))
++#define VEND1_GLOBAL_LED_PROV_LINK100         BIT(5)
++#define VEND1_GLOBAL_LED_PROV_LINK1000                BIT(6)
++#define VEND1_GLOBAL_LED_PROV_LINK10000               BIT(7)
++#define VEND1_GLOBAL_LED_PROV_FORCE_ON                BIT(8)
++#define VEND1_GLOBAL_LED_PROV_LINK2500                BIT(14)
++#define VEND1_GLOBAL_LED_PROV_LINK5000                BIT(15)
++
++#define VEND1_GLOBAL_LED_DRIVE                        0xc438
++#define VEND1_GLOBAL_LED_DRIVE_VDD            BIT(1)
++#define AQR_LED_DRIVE(x)                      (VEND1_GLOBAL_LED_DRIVE + x)
++
+ #define VEND1_THERMAL_STAT1                   0xc820
+ #define VEND1_THERMAL_STAT2                   0xc821
+ #define VEND1_THERMAL_STAT2_VALID             BIT(0)
+@@ -115,3 +135,23 @@ static inline int aqr_hwmon_probe(struct
+ #endif
+ int aqr_firmware_load(struct phy_device *phydev);
++
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++int aqr_phy_led_blink_set(struct phy_device *phydev, u8 index,
++                       unsigned long *delay_on,
++                       unsigned long *delay_off);
++
++int aqr_phy_led_brightness_set(struct phy_device *phydev,
++                             u8 index, enum led_brightness value);
++
++int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++                              unsigned long rules);
++
++int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++                             unsigned long *rules);
++
++int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++                             unsigned long rules);
++
++int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes);
++#endif
+--- /dev/null
++++ b/drivers/net/phy/aquantia/aquantia_leds.c
+@@ -0,0 +1,140 @@
++// SPDX-License-Identifier: GPL-2.0
++/* LED driver for Aquantia PHY
++ *
++ * Author: Daniel Golle <daniel@makrotopia.org>
++ */
++
++#include <linux/phy.h>
++
++#include "aquantia.h"
++
++int aqr_phy_led_brightness_set(struct phy_device *phydev,
++                             u8 index, enum led_brightness value)
++{
++      if (index > 2)
++              return -EINVAL;
++
++      return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index), VEND1_GLOBAL_LED_PROV_LINK_MASK |
++                                                  VEND1_GLOBAL_LED_PROV_FORCE_ON |
++                                                  VEND1_GLOBAL_LED_PROV_RX_ACT |
++                                                  VEND1_GLOBAL_LED_PROV_TX_ACT,
++                                                  value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0);
++}
++
++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK)        |
++                                               BIT(TRIGGER_NETDEV_LINK_100)    |
++                                               BIT(TRIGGER_NETDEV_LINK_1000)   |
++                                               BIT(TRIGGER_NETDEV_LINK_2500)   |
++                                               BIT(TRIGGER_NETDEV_LINK_5000)   |
++                                               BIT(TRIGGER_NETDEV_LINK_10000)  |
++                                               BIT(TRIGGER_NETDEV_RX)          |
++                                               BIT(TRIGGER_NETDEV_TX));
++
++int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++                              unsigned long rules)
++{
++      if (index >= AQR_NUM_LEDS)
++              return -EINVAL;
++
++      /* All combinations of the supported triggers are allowed */
++      if (rules & ~supported_triggers)
++              return -EOPNOTSUPP;
++
++      return 0;
++}
++
++int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++                             unsigned long *rules)
++{
++      int val;
++
++      if (index >= AQR_NUM_LEDS)
++              return -EINVAL;
++
++      val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index));
++      if (val < 0)
++              return val;
++
++      *rules = 0;
++      if (val & VEND1_GLOBAL_LED_PROV_LINK100)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++      if (val & VEND1_GLOBAL_LED_PROV_LINK1000)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++      if (val & VEND1_GLOBAL_LED_PROV_LINK2500)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
++
++      if (val & VEND1_GLOBAL_LED_PROV_LINK5000)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_5000);
++
++      if (val & VEND1_GLOBAL_LED_PROV_LINK10000)
++              *rules |= BIT(TRIGGER_NETDEV_LINK_10000);
++
++      if (val & VEND1_GLOBAL_LED_PROV_RX_ACT)
++              *rules |= BIT(TRIGGER_NETDEV_RX);
++
++      if (val & VEND1_GLOBAL_LED_PROV_TX_ACT)
++              *rules |= BIT(TRIGGER_NETDEV_TX);
++
++      return 0;
++}
++
++int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++                             unsigned long rules)
++{
++      u16 val = 0;
++
++      if (index >= AQR_NUM_LEDS)
++              return -EINVAL;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++              val |= VEND1_GLOBAL_LED_PROV_LINK100;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++              val |= VEND1_GLOBAL_LED_PROV_LINK1000;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
++              val |= VEND1_GLOBAL_LED_PROV_LINK2500;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))
++              val |= VEND1_GLOBAL_LED_PROV_LINK5000;
++
++      if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))
++              val |= VEND1_GLOBAL_LED_PROV_LINK10000;
++
++      if (rules & BIT(TRIGGER_NETDEV_RX))
++              val |= VEND1_GLOBAL_LED_PROV_RX_ACT;
++
++      if (rules & BIT(TRIGGER_NETDEV_TX))
++              val |= VEND1_GLOBAL_LED_PROV_TX_ACT;
++
++      return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
++                                                  VEND1_GLOBAL_LED_PROV_LINK_MASK |
++                                                  VEND1_GLOBAL_LED_PROV_FORCE_ON |
++                                                  VEND1_GLOBAL_LED_PROV_RX_ACT |
++                                                  VEND1_GLOBAL_LED_PROV_TX_ACT, val);
++}
++
++int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
++{
++      bool active_low = false;
++      u32 mode;
++
++      if (index >= AQR_NUM_LEDS)
++              return -EINVAL;
++
++      for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
++              switch (mode) {
++              case PHY_LED_ACTIVE_LOW:
++                      active_low = true;
++                      break;
++              default:
++              return -EINVAL;
++              }
++      }
++
++      return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
++                            VEND1_GLOBAL_LED_DRIVE_VDD,
++                            active_low ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);
++}
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -740,6 +740,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
+@@ -759,6 +766,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR111),
+@@ -778,6 +792,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0),
+@@ -797,6 +818,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
+@@ -823,6 +851,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
+@@ -841,6 +876,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR113),
+@@ -860,6 +902,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
+@@ -879,6 +928,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR114C),
+@@ -898,6 +954,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ {
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR813),
+@@ -917,6 +980,13 @@ static struct phy_driver aqr_driver[] =
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
++#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
++      .led_brightness_set = aqr_phy_led_brightness_set,
++      .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++      .led_hw_control_set = aqr_phy_led_hw_control_set,
++      .led_hw_control_get = aqr_phy_led_hw_control_get,
++      .led_polarity_set = aqr_phy_led_polarity_set,
++#endif
+ },
+ };
diff --git a/target/linux/generic/pending-6.6/999-net-phy-move-LED-polarity-to-phy_init_hw.patch b/target/linux/generic/pending-6.6/999-net-phy-move-LED-polarity-to-phy_init_hw.patch
new file mode 100644 (file)
index 0000000..22c4776
--- /dev/null
@@ -0,0 +1,100 @@
+From 6e6fff51ae5e54092611d174fa45fa78c237a415 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Tue, 21 May 2024 20:01:46 +0200
+Subject: [PATCH] net: phy: move LED polarity to phy_init_hw
+
+Some PHY reset the polarity on reset and this cause the LED to
+malfunction as LED polarity is configured only when LED is
+registered.
+
+To better handle this, move the LED polarity configuration in
+phy_init_hw to reconfigure it after PHY reset.
+
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+---
+ drivers/net/phy/phy_device.c | 53 +++++++++++++++++++++++++-----------
+ 1 file changed, 37 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1223,6 +1223,37 @@ static int phy_poll_reset(struct phy_dev
+       return 0;
+ }
++static int of_phy_led_init(struct phy_device *phydev)
++{
++      struct phy_led *phyled;
++
++      list_for_each_entry(phyled, &phydev->leds, list) {
++              struct led_classdev *cdev = &phyled->led_cdev;
++              struct device_node *np = cdev->dev->of_node;
++              unsigned long modes = 0;
++              int err;
++
++              if (of_property_read_bool(np, "active-low"))
++                      set_bit(PHY_LED_ACTIVE_LOW, &modes);
++              if (of_property_read_bool(np, "inactive-high-impedance"))
++                      set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
++
++              if (!modes)
++                      continue;
++
++              /* Return error if asked to set polarity modes but not supported */
++              if (!phydev->drv->led_polarity_set)
++                      return -EINVAL;
++
++              err = phydev->drv->led_polarity_set(phydev, phyled->index,
++                                                  modes);
++              if (err)
++                      return err;
++      }
++
++      return 0;
++}
++
+ int phy_init_hw(struct phy_device *phydev)
+ {
+       int ret = 0;
+@@ -1259,6 +1290,12 @@ int phy_init_hw(struct phy_device *phyde
+                       return ret;
+       }
++      if (IS_ENABLED(CONFIG_PHYLIB_LEDS)) {
++              ret = of_phy_led_init(phydev);
++              if (ret < 0)
++                      return ret;
++      }
++
+       return 0;
+ }
+ EXPORT_SYMBOL(phy_init_hw);
+@@ -3204,7 +3241,6 @@ static int of_phy_led(struct phy_device
+       struct device *dev = &phydev->mdio.dev;
+       struct led_init_data init_data = {};
+       struct led_classdev *cdev;
+-      unsigned long modes = 0;
+       struct phy_led *phyled;
+       u32 index;
+       int err;
+@@ -3222,21 +3258,6 @@ static int of_phy_led(struct phy_device
+       if (index > U8_MAX)
+               return -EINVAL;
+-      if (of_property_read_bool(led, "active-low"))
+-              set_bit(PHY_LED_ACTIVE_LOW, &modes);
+-      if (of_property_read_bool(led, "inactive-high-impedance"))
+-              set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
+-
+-      if (modes) {
+-              /* Return error if asked to set polarity modes but not supported */
+-              if (!phydev->drv->led_polarity_set)
+-                      return -EINVAL;
+-
+-              err = phydev->drv->led_polarity_set(phydev, index, modes);
+-              if (err)
+-                      return err;
+-      }
+-
+       phyled->index = index;
+       if (phydev->drv->led_brightness_set)
+               cdev->brightness_set_blocking = phy_led_set_brightness;