From f2c6f8711c3866caafee997cfa60af4f38879be0 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Wed, 25 Jun 2025 00:45:11 +0200
Subject: [PATCH 1/2] net: phy: add PHY_DETACH_NO_HW_RESET PHY flag

Some PHY require a firmware to correctly work and such firmware might
get reset when the GPIO reset is assert.

This is the case for the Aeonsemi PHY where when the PHY is torn down,
phy_detach() is called that assert the GPIO reset pin resetting the
firmware.

To handle this introduce a flag, PHY_DETACH_NO_HW_RESET that instruct
phy_detach() to skip asserting the GPIO reset on detaching the PHY.

The PHY is still reset in all other case where it's removed or the PHY
fails to probe.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
 drivers/net/phy/as21xxx.c    | 10 ++++++++++
 drivers/net/phy/phy_device.c |  3 ++-
 include/linux/phy.h          |  1 +
 3 files changed, 13 insertions(+), 1 deletion(-)

--- a/drivers/net/phy/as21xxx.c
+++ b/drivers/net/phy/as21xxx.c
@@ -965,6 +965,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1),
@@ -977,6 +978,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1),
@@ -989,6 +991,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1),
@@ -1001,6 +1004,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1),
@@ -1013,6 +1017,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1),
@@ -1025,6 +1030,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1),
@@ -1037,6 +1043,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1),
@@ -1049,6 +1056,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1),
@@ -1061,6 +1069,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 	{
 		PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1),
@@ -1073,6 +1082,7 @@ static struct phy_driver as21xxx_drivers
 		.led_hw_control_set = as21xxx_led_hw_control_set,
 		.led_hw_control_get = as21xxx_led_hw_control_get,
 		.led_polarity_set = as21xxx_led_polarity_set,
+		.flags = PHY_DETACH_NO_RESET,
 	},
 };
 module_phy_driver(as21xxx_drivers);
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2074,7 +2074,8 @@ void phy_detach(struct phy_device *phyde
 		device_release_driver(&phydev->mdio.dev);
 
 	/* Assert the reset signal */
-	phy_device_reset(phydev, 1);
+	if (!phydev->drv || !(phydev->drv->flags & PHY_DETACH_NO_HW_RESET))
+		phy_device_reset(phydev, 1);
 
 	/*
 	 * The phydev might go away on the put_device() below, so avoid
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -90,6 +90,7 @@ extern const int phy_10gbit_features_arr
 #define PHY_RST_AFTER_CLK_EN	0x00000002
 #define PHY_POLL_CABLE_TEST	0x00000004
 #define PHY_ALWAYS_CALL_SUSPEND	0x00000008
+#define PHY_DETACH_NO_HW_RESET	0x00000010
 #define MDIO_DEVICE_IS_PHY	0x80000000
 
 /**
