[PATCH 1/2] net: phy: Factor out PHY GPIO reset code

Pull the PHY GPIO reset code into separate function, since this is and will be reused multiple times. Set up default reset assert and deassert timing to generous 20ms and 1ms for maximum compatibility in case those DT properties are missing.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Joe Hershberger joe.hershberger@ni.com Cc: Marek Vasut marek.vasut+renesas@mailbox.org Cc: Michal Simek michal.simek@amd.com Cc: Nishanth Menon nm@ti.com Cc: Ramon Fried rfried.dev@gmail.com --- drivers/net/phy/ethernet_id.c | 37 ++++----------------------- drivers/net/phy/phy.c | 47 +++++++++++++++++++++++++++++++++++ include/phy.h | 9 +++++++ 3 files changed, 61 insertions(+), 32 deletions(-)
diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c index 877a51c3d00..0beafaae46a 100644 --- a/drivers/net/phy/ethernet_id.c +++ b/drivers/net/phy/ethernet_id.c @@ -18,12 +18,11 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, { struct phy_device *phydev; struct ofnode_phandle_args phandle_args; - struct gpio_desc gpio; const char *node_name; struct udevice *pdev; - ofnode node; - u32 id, assert, deassert; u16 vendor, device; + ofnode node; + u32 id; int ret;
if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, @@ -41,35 +40,9 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, return NULL; }
- if (!IS_ENABLED(CONFIG_DM_ETH_PHY)) { - ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio, - GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); - if (!ret) { - assert = ofnode_read_u32_default(node, - "reset-assert-us", 0); - deassert = ofnode_read_u32_default(node, - "reset-deassert-us", - 0); - ret = dm_gpio_set_value(&gpio, 1); - if (ret) { - dev_err(dev, - "Failed assert gpio, err: %d\n", ret); - return NULL; - } - - udelay(assert); - - ret = dm_gpio_set_value(&gpio, 0); - if (ret) { - dev_err(dev, - "Failed deassert gpio, err: %d\n", - ret); - return NULL; - } - - udelay(deassert); - } - } + ret = phy_gpio_reset(dev); + if (ret) + return NULL;
id = vendor << 16 | device; phydev = phy_device_create(bus, phyaddr, id, false); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index ae21acb059b..3d69c2c4d28 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -18,6 +18,8 @@ #include <phy.h> #include <errno.h> #include <asm/global_data.h> +#include <asm/gpio.h> +#include <dm/device_compat.h> #include <dm/of_extra.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -799,6 +801,51 @@ int miiphy_reset(const char *devname, unsigned char addr) return phy_reset(phydev); }
+int phy_gpio_reset(struct udevice *dev) +{ + struct ofnode_phandle_args phandle_args; + struct gpio_desc gpio; + u32 assert, deassert; + ofnode node; + int ret; + + ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, + &phandle_args); + /* No PHY handle is OK */ + if (ret) + return 0; + + node = phandle_args.node; + if (!ofnode_valid(node)) + return -EINVAL; + + ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio, + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); + /* No PHY reset GPIO is OK */ + if (ret) + return 0; + + assert = ofnode_read_u32_default(node, "reset-assert-us", 20000); + deassert = ofnode_read_u32_default(node, "reset-deassert-us", 1000); + ret = dm_gpio_set_value(&gpio, 1); + if (ret) { + dev_err(dev, "Failed assert gpio, err: %d\n", ret); + return ret; + } + + udelay(assert); + + ret = dm_gpio_set_value(&gpio, 0); + if (ret) { + dev_err(dev, "Failed deassert gpio, err: %d\n", ret); + return ret; + } + + udelay(deassert); + + return 0; +} + struct phy_device *phy_find_by_mask(struct mii_dev *bus, uint phy_mask) { /* Reset the bus */ diff --git a/include/phy.h b/include/phy.h index f023a3c2685..6fe397be1fe 100644 --- a/include/phy.h +++ b/include/phy.h @@ -188,6 +188,15 @@ int phy_init(void); */ int phy_reset(struct phy_device *phydev);
+/** + * phy_gpio_reset() - Resets the specified PHY using GPIO reset + * Toggles the optional PHY reset GPIO + * + * @dev: PHY udevice to reset + * @return: 0 if OK, -ve on error + */ +int phy_gpio_reset(struct udevice *dev); + /** * phy_find_by_mask() - Searches for a PHY on the specified MDIO bus * The function checks the PHY addresses flagged in phy_mask and returns a

In case the PHY DT node describes GPIO reset and no other method of detecting the PHY succeeded, release the PHY from reset using its reset GPIO before reading out the PHY IDs as a last resort. This way there is slightly better chance of successful PHY ID readout.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- Cc: Joe Hershberger joe.hershberger@ni.com Cc: Marek Vasut marek.vasut+renesas@mailbox.org Cc: Michal Simek michal.simek@amd.com Cc: Nishanth Menon nm@ti.com Cc: Ramon Fried rfried.dev@gmail.com --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3d69c2c4d28..373006f8206 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -969,7 +969,7 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr, phydev = phy_connect_gmii2rgmii(bus, dev); #endif
- if (!phydev) + if (!phydev && !phy_gpio_reset(dev)) phydev = phy_find_by_mask(bus, mask);
if (phydev)

On Tue, Jun 20, 2023 at 1:46 AM Marek Vasut marek.vasut+renesas@mailbox.org wrote:
In case the PHY DT node describes GPIO reset and no other method of detecting the PHY succeeded, release the PHY from reset using its reset GPIO before reading out the PHY IDs as a last resort. This way there is slightly better chance of successful PHY ID readout.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Joe Hershberger joe.hershberger@ni.com Cc: Marek Vasut marek.vasut+renesas@mailbox.org Cc: Michal Simek michal.simek@amd.com Cc: Nishanth Menon nm@ti.com Cc: Ramon Fried rfried.dev@gmail.com
drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3d69c2c4d28..373006f8206 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -969,7 +969,7 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr, phydev = phy_connect_gmii2rgmii(bus, dev); #endif
if (!phydev)
if (!phydev && !phy_gpio_reset(dev)) phydev = phy_find_by_mask(bus, mask); if (phydev)
-- 2.39.2
Reviewed-by: Ramon Fried rfried.dev@gmail.com

On Tue, Jun 20, 2023 at 1:46 AM Marek Vasut marek.vasut+renesas@mailbox.org wrote:
Pull the PHY GPIO reset code into separate function, since this is and will be reused multiple times. Set up default reset assert and deassert timing to generous 20ms and 1ms for maximum compatibility in case those DT properties are missing.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Cc: Joe Hershberger joe.hershberger@ni.com Cc: Marek Vasut marek.vasut+renesas@mailbox.org Cc: Michal Simek michal.simek@amd.com Cc: Nishanth Menon nm@ti.com Cc: Ramon Fried rfried.dev@gmail.com
drivers/net/phy/ethernet_id.c | 37 ++++----------------------- drivers/net/phy/phy.c | 47 +++++++++++++++++++++++++++++++++++ include/phy.h | 9 +++++++ 3 files changed, 61 insertions(+), 32 deletions(-)
diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c index 877a51c3d00..0beafaae46a 100644 --- a/drivers/net/phy/ethernet_id.c +++ b/drivers/net/phy/ethernet_id.c @@ -18,12 +18,11 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, { struct phy_device *phydev; struct ofnode_phandle_args phandle_args;
struct gpio_desc gpio; const char *node_name; struct udevice *pdev;
ofnode node;
u32 id, assert, deassert; u16 vendor, device;
ofnode node;
u32 id; int ret; if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
@@ -41,35 +40,9 @@ struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev, return NULL; }
if (!IS_ENABLED(CONFIG_DM_ETH_PHY)) {
ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio,
GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
if (!ret) {
assert = ofnode_read_u32_default(node,
"reset-assert-us", 0);
deassert = ofnode_read_u32_default(node,
"reset-deassert-us",
0);
ret = dm_gpio_set_value(&gpio, 1);
if (ret) {
dev_err(dev,
"Failed assert gpio, err: %d\n", ret);
return NULL;
}
udelay(assert);
ret = dm_gpio_set_value(&gpio, 0);
if (ret) {
dev_err(dev,
"Failed deassert gpio, err: %d\n",
ret);
return NULL;
}
udelay(deassert);
}
}
ret = phy_gpio_reset(dev);
if (ret)
return NULL; id = vendor << 16 | device; phydev = phy_device_create(bus, phyaddr, id, false);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index ae21acb059b..3d69c2c4d28 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -18,6 +18,8 @@ #include <phy.h> #include <errno.h> #include <asm/global_data.h> +#include <asm/gpio.h> +#include <dm/device_compat.h> #include <dm/of_extra.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -799,6 +801,51 @@ int miiphy_reset(const char *devname, unsigned char addr) return phy_reset(phydev); }
+int phy_gpio_reset(struct udevice *dev) +{
struct ofnode_phandle_args phandle_args;
struct gpio_desc gpio;
u32 assert, deassert;
ofnode node;
int ret;
ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
&phandle_args);
/* No PHY handle is OK */
if (ret)
return 0;
node = phandle_args.node;
if (!ofnode_valid(node))
return -EINVAL;
ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio,
GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
/* No PHY reset GPIO is OK */
if (ret)
return 0;
assert = ofnode_read_u32_default(node, "reset-assert-us", 20000);
deassert = ofnode_read_u32_default(node, "reset-deassert-us", 1000);
ret = dm_gpio_set_value(&gpio, 1);
if (ret) {
dev_err(dev, "Failed assert gpio, err: %d\n", ret);
return ret;
}
udelay(assert);
ret = dm_gpio_set_value(&gpio, 0);
if (ret) {
dev_err(dev, "Failed deassert gpio, err: %d\n", ret);
return ret;
}
udelay(deassert);
return 0;
+}
struct phy_device *phy_find_by_mask(struct mii_dev *bus, uint phy_mask) { /* Reset the bus */ diff --git a/include/phy.h b/include/phy.h index f023a3c2685..6fe397be1fe 100644 --- a/include/phy.h +++ b/include/phy.h @@ -188,6 +188,15 @@ int phy_init(void); */ int phy_reset(struct phy_device *phydev);
+/**
- phy_gpio_reset() - Resets the specified PHY using GPIO reset
- Toggles the optional PHY reset GPIO
- @dev: PHY udevice to reset
- @return: 0 if OK, -ve on error
- */
+int phy_gpio_reset(struct udevice *dev);
/**
- phy_find_by_mask() - Searches for a PHY on the specified MDIO bus
- The function checks the PHY addresses flagged in phy_mask and returns a
-- 2.39.2
Reviewed-by: Ramon Fried rfried.dev@gmail.com

On Tue, Jun 20, 2023 at 12:45:54AM +0200, Marek Vasut wrote:
Pull the PHY GPIO reset code into separate function, since this is and will be reused multiple times. Set up default reset assert and deassert timing to generous 20ms and 1ms for maximum compatibility in case those DT properties are missing.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org Reviewed-by: Ramon Fried rfried.dev@gmail.com
Cc: Joe Hershberger joe.hershberger@ni.com Cc: Marek Vasut marek.vasut+renesas@mailbox.org Cc: Michal Simek michal.simek@amd.com Cc: Nishanth Menon nm@ti.com Cc: Ramon Fried rfried.dev@gmail.com
drivers/net/phy/ethernet_id.c | 37 ++++----------------------- drivers/net/phy/phy.c | 47 +++++++++++++++++++++++++++++++++++ include/phy.h | 9 +++++++ 3 files changed, 61 insertions(+), 32 deletions(-)
This introduces a fail to build on am335x_evm (and others) as before thee code was guarded by CONFIG_DM_ETH_PHY (which I haven't seen how then leads to DM_GPIO/SPL_DM_GPIO/etc being set) and now does not.
participants (3)
-
Marek Vasut
-
Ramon Fried
-
Tom Rini