Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f93ea3bf authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'fec-fix-refclk-enable-for-SMSC-LAN8710-20'



Richard Leitner says:

====================
net: fec: fix refclk enable for SMSC LAN8710/20

This patch series fixes the use of the SMSC LAN8710/20 with a Freescale ETH
when the refclk is generated by the FSL.

This patchset depends on the "phylib: Add device reset GPIO support" patch
submitted by Geert Uytterhoeven/Sergei Shtylyov, which was merged to
net-next as commit bafbdd52 ("phylib: Add device reset GPIO support").

Changes v5:
	- fix reset delay calculation (max_t instead of min_t)

Changes v4:
	- simplify dts parsing
	- simplify reset delay evaluation and execution
	- fec: ensure to only reset once during fec_enet_open()
	- remove dependency notes from commit message
	- add reviews and acks

Changes v3:
	- use phylib to hard-reset the PHY
	- implement reset delays in phylib
	- add new phylib API & flag (PHY_RST_AFTER_CLK_EN) to determine if
	  a PHY is affected

Changes v2:
	- simplify and fix fec_reset_phy function to support multiple calls
	- include: linux: phy: harmonize phy_id{,_mask} type
	- reset the phy instead of not turning the clock on and off
	  (which would have caused a power consumption regression)
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9cca5d2f 1b0a83ac
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -55,6 +55,12 @@ Optional Properties:

- reset-gpios: The GPIO phandle and specifier for the PHY reset signal.

- reset-delay-us: Delay after the reset was asserted in microseconds.
  If this property is missing the delay will be skipped.

- reset-post-delay-us: Delay after the reset was deasserted in microseconds.
  If this property is missing the delay will be skipped.

Example:

ethernet-phy@0 {
@@ -62,4 +68,8 @@ ethernet-phy@0 {
	interrupt-parent = <&PIC>;
	interrupts = <35 IRQ_TYPE_EDGE_RISING>;
	reg = <0>;

	reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
	reset-delay-us = <1000>;
	reset-post-delay-us = <2000>;
};
+20 −0
Original line number Diff line number Diff line
@@ -1862,6 +1862,8 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
		ret = clk_prepare_enable(fep->clk_ref);
		if (ret)
			goto failed_clk_ref;

		phy_reset_after_clk_enable(ndev->phydev);
	} else {
		clk_disable_unprepare(fep->clk_ahb);
		clk_disable_unprepare(fep->clk_enet_out);
@@ -2834,6 +2836,7 @@ fec_enet_open(struct net_device *ndev)
{
	struct fec_enet_private *fep = netdev_priv(ndev);
	int ret;
	bool reset_again;

	ret = pm_runtime_get_sync(&fep->pdev->dev);
	if (ret < 0)
@@ -2844,6 +2847,17 @@ fec_enet_open(struct net_device *ndev)
	if (ret)
		goto clk_enable;

	/* During the first fec_enet_open call the PHY isn't probed at this
	 * point. Therefore the phy_reset_after_clk_enable() call within
	 * fec_enet_clk_enable() fails. As we need this reset in order to be
	 * sure the PHY is working correctly we check if we need to reset again
	 * later when the PHY is probed
	 */
	if (ndev->phydev && ndev->phydev->drv)
		reset_again = false;
	else
		reset_again = true;

	/* I should reset the ring buffers here, but I don't yet know
	 * a simple way to do that.
	 */
@@ -2860,6 +2874,12 @@ fec_enet_open(struct net_device *ndev)
	if (ret)
		goto err_enet_mii_probe;

	/* Call phy_reset_after_clk_enable() again if it failed during
	 * phy_reset_after_clk_enable() before because the PHY wasn't probed.
	 */
	if (reset_again)
		phy_reset_after_clk_enable(ndev->phydev);

	if (fep->quirks & FEC_QUIRK_ERR006687)
		imx6q_cpuidle_fec_irqs_used();

+11 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/delay.h>

void mdio_device_free(struct mdio_device *mdiodev)
{
@@ -118,8 +119,16 @@ EXPORT_SYMBOL(mdio_device_remove);

void mdio_device_reset(struct mdio_device *mdiodev, int value)
{
	if (mdiodev->reset)
	unsigned int d;

	if (!mdiodev->reset)
		return;

	gpiod_set_value(mdiodev->reset, value);

	d = value ? mdiodev->reset_delay : mdiodev->reset_post_delay;
	if (d)
		usleep_range(d, d + max_t(unsigned int, d / 10, 100));
}
EXPORT_SYMBOL(mdio_device_reset);

+24 −0
Original line number Diff line number Diff line
@@ -1218,6 +1218,30 @@ int phy_loopback(struct phy_device *phydev, bool enable)
}
EXPORT_SYMBOL(phy_loopback);

/**
 * phy_reset_after_clk_enable - perform a PHY reset if needed
 * @phydev: target phy_device struct
 *
 * Description: Some PHYs are known to need a reset after their refclk was
 *   enabled. This function evaluates the flags and perform the reset if it's
 *   needed. Returns < 0 on error, 0 if the phy wasn't reset and 1 if the phy
 *   was reset.
 */
int phy_reset_after_clk_enable(struct phy_device *phydev)
{
	if (!phydev || !phydev->drv)
		return -ENODEV;

	if (phydev->drv->flags & PHY_RST_AFTER_CLK_EN) {
		phy_device_reset(phydev, 1);
		phy_device_reset(phydev, 0);
		return 1;
	}

	return 0;
}
EXPORT_SYMBOL(phy_reset_after_clk_enable);

/* Generic PHY support and helper functions */

/**
+1 −1
Original line number Diff line number Diff line
@@ -312,7 +312,7 @@ static struct phy_driver smsc_phy_driver[] = {
	.name		= "SMSC LAN8710/LAN8720",

	.features	= PHY_BASIC_FEATURES,
	.flags		= PHY_HAS_INTERRUPT,
	.flags		= PHY_HAS_INTERRUPT | PHY_RST_AFTER_CLK_EN,

	.probe		= smsc_phy_probe,

Loading