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

Merge branch 'stmmac-clocks'



Joakim Zhang says:

====================
net: stmmac: implement clocks management

This patch set tries to implement clocks management, and takes i.MX platform as an example.

---
ChangeLogs:
V1->V2:
	* change to pm runtime mechanism.
	* rename function: _enable() -> _config()
	* take MDIO bus into account, it needs clocks when interface
	is closed.
	* reverse Christmass tree.
V2->V3:
	* slightly simple the code according to Andrew's suggesstion
	and also add tag: Reviewed-by: Andrew Lunn <andrew@lunn.ch>
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 91de5ac9 8f2f8376
Loading
Loading
Loading
Loading
+36 −24
Original line number Original line Diff line number Diff line
@@ -90,47 +90,52 @@ imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
	return ret;
	return ret;
}
}


static int imx_dwmac_init(struct platform_device *pdev, void *priv)
static int imx_dwmac_clks_config(void *priv, bool enabled)
{
{
	struct plat_stmmacenet_data *plat_dat;
	struct imx_priv_data *dwmac = priv;
	struct imx_priv_data *dwmac = priv;
	int ret;
	int ret = 0;

	plat_dat = dwmac->plat_dat;


	if (enabled) {
		ret = clk_prepare_enable(dwmac->clk_mem);
		ret = clk_prepare_enable(dwmac->clk_mem);
		if (ret) {
		if (ret) {
		dev_err(&pdev->dev, "mem clock enable failed\n");
			dev_err(dwmac->dev, "mem clock enable failed\n");
			return ret;
			return ret;
		}
		}


		ret = clk_prepare_enable(dwmac->clk_tx);
		ret = clk_prepare_enable(dwmac->clk_tx);
		if (ret) {
		if (ret) {
		dev_err(&pdev->dev, "tx clock enable failed\n");
			dev_err(dwmac->dev, "tx clock enable failed\n");
		goto clk_tx_en_failed;
			clk_disable_unprepare(dwmac->clk_mem);
			return ret;
		}
	} else {
		clk_disable_unprepare(dwmac->clk_tx);
		clk_disable_unprepare(dwmac->clk_mem);
	}

	return ret;
}
}


static int imx_dwmac_init(struct platform_device *pdev, void *priv)
{
	struct plat_stmmacenet_data *plat_dat;
	struct imx_priv_data *dwmac = priv;
	int ret;

	plat_dat = dwmac->plat_dat;

	if (dwmac->ops->set_intf_mode) {
	if (dwmac->ops->set_intf_mode) {
		ret = dwmac->ops->set_intf_mode(plat_dat);
		ret = dwmac->ops->set_intf_mode(plat_dat);
		if (ret)
		if (ret)
			goto intf_mode_failed;
			return ret;
	}
	}


	return 0;
	return 0;

intf_mode_failed:
	clk_disable_unprepare(dwmac->clk_tx);
clk_tx_en_failed:
	clk_disable_unprepare(dwmac->clk_mem);
	return ret;
}
}


static void imx_dwmac_exit(struct platform_device *pdev, void *priv)
static void imx_dwmac_exit(struct platform_device *pdev, void *priv)
{
{
	struct imx_priv_data *dwmac = priv;
	/* nothing to do now */

	clk_disable_unprepare(dwmac->clk_tx);
	clk_disable_unprepare(dwmac->clk_mem);
}
}


static void imx_dwmac_fix_speed(void *priv, unsigned int speed)
static void imx_dwmac_fix_speed(void *priv, unsigned int speed)
@@ -249,10 +254,15 @@ static int imx_dwmac_probe(struct platform_device *pdev)
	plat_dat->addr64 = dwmac->ops->addr_width;
	plat_dat->addr64 = dwmac->ops->addr_width;
	plat_dat->init = imx_dwmac_init;
	plat_dat->init = imx_dwmac_init;
	plat_dat->exit = imx_dwmac_exit;
	plat_dat->exit = imx_dwmac_exit;
	plat_dat->clks_config = imx_dwmac_clks_config;
	plat_dat->fix_mac_speed = imx_dwmac_fix_speed;
	plat_dat->fix_mac_speed = imx_dwmac_fix_speed;
	plat_dat->bsp_priv = dwmac;
	plat_dat->bsp_priv = dwmac;
	dwmac->plat_dat = plat_dat;
	dwmac->plat_dat = plat_dat;


	ret = imx_dwmac_clks_config(dwmac, true);
	if (ret)
		goto err_clks_config;

	ret = imx_dwmac_init(pdev, dwmac);
	ret = imx_dwmac_init(pdev, dwmac);
	if (ret)
	if (ret)
		goto err_dwmac_init;
		goto err_dwmac_init;
@@ -263,9 +273,11 @@ static int imx_dwmac_probe(struct platform_device *pdev)


	return 0;
	return 0;


err_dwmac_init:
err_drv_probe:
err_drv_probe:
	imx_dwmac_exit(pdev, plat_dat->bsp_priv);
	imx_dwmac_exit(pdev, plat_dat->bsp_priv);
err_dwmac_init:
	imx_dwmac_clks_config(dwmac, false);
err_clks_config:
err_parse_dt:
err_parse_dt:
err_match_data:
err_match_data:
	stmmac_remove_config_dt(pdev, plat_dat);
	stmmac_remove_config_dt(pdev, plat_dat);
+1 −0
Original line number Original line Diff line number Diff line
@@ -272,6 +272,7 @@ void stmmac_disable_eee_mode(struct stmmac_priv *priv);
bool stmmac_eee_init(struct stmmac_priv *priv);
bool stmmac_eee_init(struct stmmac_priv *priv);
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);


#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
void stmmac_selftest_run(struct net_device *dev,
void stmmac_selftest_run(struct net_device *dev,
+76 −9
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/if_vlan.h>
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/prefetch.h>
#include <linux/prefetch.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/consumer.h>
#ifdef CONFIG_DEBUG_FS
#ifdef CONFIG_DEBUG_FS
@@ -113,6 +114,38 @@ static void stmmac_exit_fs(struct net_device *dev);


#define STMMAC_COAL_TIMER(x) (ns_to_ktime((x) * NSEC_PER_USEC))
#define STMMAC_COAL_TIMER(x) (ns_to_ktime((x) * NSEC_PER_USEC))


int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled)
{
	int ret = 0;

	if (enabled) {
		ret = clk_prepare_enable(priv->plat->stmmac_clk);
		if (ret)
			return ret;
		ret = clk_prepare_enable(priv->plat->pclk);
		if (ret) {
			clk_disable_unprepare(priv->plat->stmmac_clk);
			return ret;
		}
		if (priv->plat->clks_config) {
			ret = priv->plat->clks_config(priv->plat->bsp_priv, enabled);
			if (ret) {
				clk_disable_unprepare(priv->plat->stmmac_clk);
				clk_disable_unprepare(priv->plat->pclk);
				return ret;
			}
		}
	} else {
		clk_disable_unprepare(priv->plat->stmmac_clk);
		clk_disable_unprepare(priv->plat->pclk);
		if (priv->plat->clks_config)
			priv->plat->clks_config(priv->plat->bsp_priv, enabled);
	}

	return ret;
}
EXPORT_SYMBOL_GPL(stmmac_bus_clks_config);

/**
/**
 * stmmac_verify_args - verify the driver parameters.
 * stmmac_verify_args - verify the driver parameters.
 * Description: it checks the driver parameters and set a default in case of
 * Description: it checks the driver parameters and set a default in case of
@@ -2896,6 +2929,12 @@ static int stmmac_open(struct net_device *dev)
	u32 chan;
	u32 chan;
	int ret;
	int ret;


	ret = pm_runtime_get_sync(priv->device);
	if (ret < 0) {
		pm_runtime_put_noidle(priv->device);
		return ret;
	}

	if (priv->hw->pcs != STMMAC_PCS_TBI &&
	if (priv->hw->pcs != STMMAC_PCS_TBI &&
	    priv->hw->pcs != STMMAC_PCS_RTBI &&
	    priv->hw->pcs != STMMAC_PCS_RTBI &&
	    priv->hw->xpcs_args.an_mode != DW_AN_C73) {
	    priv->hw->xpcs_args.an_mode != DW_AN_C73) {
@@ -2904,7 +2943,7 @@ static int stmmac_open(struct net_device *dev)
			netdev_err(priv->dev,
			netdev_err(priv->dev,
				   "%s: Cannot attach to PHY (error: %d)\n",
				   "%s: Cannot attach to PHY (error: %d)\n",
				   __func__, ret);
				   __func__, ret);
			return ret;
			goto init_phy_error;
		}
		}
	}
	}


@@ -3020,6 +3059,8 @@ static int stmmac_open(struct net_device *dev)
	free_dma_desc_resources(priv);
	free_dma_desc_resources(priv);
dma_desc_error:
dma_desc_error:
	phylink_disconnect_phy(priv->phylink);
	phylink_disconnect_phy(priv->phylink);
init_phy_error:
	pm_runtime_put(priv->device);
	return ret;
	return ret;
}
}


@@ -3070,6 +3111,8 @@ static int stmmac_release(struct net_device *dev)


	stmmac_release_ptp(priv);
	stmmac_release_ptp(priv);


	pm_runtime_put(priv->device);

	return 0;
	return 0;
}
}


@@ -4706,6 +4749,12 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
	bool is_double = false;
	bool is_double = false;
	int ret;
	int ret;


	ret = pm_runtime_get_sync(priv->device);
	if (ret < 0) {
		pm_runtime_put_noidle(priv->device);
		return ret;
	}

	if (be16_to_cpu(proto) == ETH_P_8021AD)
	if (be16_to_cpu(proto) == ETH_P_8021AD)
		is_double = true;
		is_double = true;


@@ -4739,10 +4788,15 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
	if (priv->hw->num_vlan) {
	if (priv->hw->num_vlan) {
		ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
		ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
		if (ret)
		if (ret)
			return ret;
			goto del_vlan_error;
	}
	}


	return stmmac_vlan_update(priv, is_double);
	ret = stmmac_vlan_update(priv, is_double);

del_vlan_error:
	pm_runtime_put(priv->device);

	return ret;
}
}


static const struct net_device_ops stmmac_netdev_ops = {
static const struct net_device_ops stmmac_netdev_ops = {
@@ -5181,6 +5235,10 @@ int stmmac_dvr_probe(struct device *device,


	stmmac_check_pcs_mode(priv);
	stmmac_check_pcs_mode(priv);


	pm_runtime_get_noresume(device);
	pm_runtime_set_active(device);
	pm_runtime_enable(device);

	if (priv->hw->pcs != STMMAC_PCS_TBI &&
	if (priv->hw->pcs != STMMAC_PCS_TBI &&
	    priv->hw->pcs != STMMAC_PCS_RTBI) {
	    priv->hw->pcs != STMMAC_PCS_RTBI) {
		/* MDIO bus Registration */
		/* MDIO bus Registration */
@@ -5218,6 +5276,11 @@ int stmmac_dvr_probe(struct device *device,
	stmmac_init_fs(ndev);
	stmmac_init_fs(ndev);
#endif
#endif


	/* Let pm_runtime_put() disable the clocks.
	 * If CONFIG_PM is not enabled, the clocks will stay powered.
	 */
	pm_runtime_put(device);

	return ret;
	return ret;


error_serdes_powerup:
error_serdes_powerup:
@@ -5232,6 +5295,7 @@ int stmmac_dvr_probe(struct device *device,
	stmmac_napi_del(ndev);
	stmmac_napi_del(ndev);
error_hw_init:
error_hw_init:
	destroy_workqueue(priv->wq);
	destroy_workqueue(priv->wq);
	stmmac_bus_clks_config(priv, false);


	return ret;
	return ret;
}
}
@@ -5267,8 +5331,8 @@ int stmmac_dvr_remove(struct device *dev)
	phylink_destroy(priv->phylink);
	phylink_destroy(priv->phylink);
	if (priv->plat->stmmac_rst)
	if (priv->plat->stmmac_rst)
		reset_control_assert(priv->plat->stmmac_rst);
		reset_control_assert(priv->plat->stmmac_rst);
	clk_disable_unprepare(priv->plat->pclk);
	pm_runtime_put(dev);
	clk_disable_unprepare(priv->plat->stmmac_clk);
	pm_runtime_disable(dev);
	if (priv->hw->pcs != STMMAC_PCS_TBI &&
	if (priv->hw->pcs != STMMAC_PCS_TBI &&
	    priv->hw->pcs != STMMAC_PCS_RTBI)
	    priv->hw->pcs != STMMAC_PCS_RTBI)
		stmmac_mdio_unregister(ndev);
		stmmac_mdio_unregister(ndev);
@@ -5291,6 +5355,7 @@ int stmmac_suspend(struct device *dev)
	struct net_device *ndev = dev_get_drvdata(dev);
	struct net_device *ndev = dev_get_drvdata(dev);
	struct stmmac_priv *priv = netdev_priv(ndev);
	struct stmmac_priv *priv = netdev_priv(ndev);
	u32 chan;
	u32 chan;
	int ret;


	if (!ndev || !netif_running(ndev))
	if (!ndev || !netif_running(ndev))
		return 0;
		return 0;
@@ -5334,8 +5399,9 @@ int stmmac_suspend(struct device *dev)
		pinctrl_pm_select_sleep_state(priv->device);
		pinctrl_pm_select_sleep_state(priv->device);
		/* Disable clock in case of PWM is off */
		/* Disable clock in case of PWM is off */
		clk_disable_unprepare(priv->plat->clk_ptp_ref);
		clk_disable_unprepare(priv->plat->clk_ptp_ref);
		clk_disable_unprepare(priv->plat->pclk);
		ret = pm_runtime_force_suspend(dev);
		clk_disable_unprepare(priv->plat->stmmac_clk);
		if (ret)
			return ret;
	}
	}
	mutex_unlock(&priv->lock);
	mutex_unlock(&priv->lock);


@@ -5401,8 +5467,9 @@ int stmmac_resume(struct device *dev)
	} else {
	} else {
		pinctrl_pm_select_default_state(priv->device);
		pinctrl_pm_select_default_state(priv->device);
		/* enable the clk previously disabled */
		/* enable the clk previously disabled */
		clk_prepare_enable(priv->plat->stmmac_clk);
		ret = pm_runtime_force_resume(dev);
		clk_prepare_enable(priv->plat->pclk);
		if (ret)
			return ret;
		if (priv->plat->clk_ptp_ref)
		if (priv->plat->clk_ptp_ref)
			clk_prepare_enable(priv->plat->clk_ptp_ref);
			clk_prepare_enable(priv->plat->clk_ptp_ref);
		/* reset the phy so that it's ready */
		/* reset the phy so that it's ready */
+85 −26
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/iopoll.h>
#include <linux/iopoll.h>
#include <linux/mii.h>
#include <linux/mii.h>
#include <linux/of_mdio.h>
#include <linux/of_mdio.h>
#include <linux/pm_runtime.h>
#include <linux/phy.h>
#include <linux/phy.h>
#include <linux/property.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/slab.h>
@@ -87,21 +88,29 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
	u32 tmp, addr, value = MII_XGMAC_BUSY;
	u32 tmp, addr, value = MII_XGMAC_BUSY;
	int ret;
	int ret;


	ret = pm_runtime_get_sync(priv->device);
	if (ret < 0) {
		pm_runtime_put_noidle(priv->device);
		return ret;
	}

	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		return -EBUSY;
		ret = -EBUSY;
		goto err_disable_clks;
	}


	if (phyreg & MII_ADDR_C45) {
	if (phyreg & MII_ADDR_C45) {
		phyreg &= ~MII_ADDR_C45;
		phyreg &= ~MII_ADDR_C45;


		ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
		ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
		if (ret)
		if (ret)
			return ret;
			goto err_disable_clks;
	} else {
	} else {
		ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
		ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
		if (ret)
		if (ret)
			return ret;
			goto err_disable_clks;


		value |= MII_XGMAC_SADDR;
		value |= MII_XGMAC_SADDR;
	}
	}
@@ -112,8 +121,10 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)


	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		return -EBUSY;
		ret = -EBUSY;
		goto err_disable_clks;
	}


	/* Set the MII address register to read */
	/* Set the MII address register to read */
	writel(addr, priv->ioaddr + mii_address);
	writel(addr, priv->ioaddr + mii_address);
@@ -121,11 +132,18 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)


	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		return -EBUSY;
		ret = -EBUSY;
		goto err_disable_clks;
	}


	/* Read the data from the MII data register */
	/* Read the data from the MII data register */
	return readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
	ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);

err_disable_clks:
	pm_runtime_put(priv->device);

	return ret;
}
}


static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
@@ -138,21 +156,29 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
	u32 addr, tmp, value = MII_XGMAC_BUSY;
	u32 addr, tmp, value = MII_XGMAC_BUSY;
	int ret;
	int ret;


	ret = pm_runtime_get_sync(priv->device);
	if (ret < 0) {
		pm_runtime_put_noidle(priv->device);
		return ret;
	}

	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		return -EBUSY;
		ret = -EBUSY;
		goto err_disable_clks;
	}


	if (phyreg & MII_ADDR_C45) {
	if (phyreg & MII_ADDR_C45) {
		phyreg &= ~MII_ADDR_C45;
		phyreg &= ~MII_ADDR_C45;


		ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
		ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
		if (ret)
		if (ret)
			return ret;
			goto err_disable_clks;
	} else {
	} else {
		ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
		ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
		if (ret)
		if (ret)
			return ret;
			goto err_disable_clks;


		value |= MII_XGMAC_SADDR;
		value |= MII_XGMAC_SADDR;
	}
	}
@@ -164,16 +190,23 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,


	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
			       !(tmp & MII_XGMAC_BUSY), 100, 10000))
			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
		return -EBUSY;
		ret = -EBUSY;
		goto err_disable_clks;
	}


	/* Set the MII address register to write */
	/* Set the MII address register to write */
	writel(addr, priv->ioaddr + mii_address);
	writel(addr, priv->ioaddr + mii_address);
	writel(value, priv->ioaddr + mii_data);
	writel(value, priv->ioaddr + mii_data);


	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	return readl_poll_timeout(priv->ioaddr + mii_data, tmp,
	ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
				 !(tmp & MII_XGMAC_BUSY), 100, 10000);
				 !(tmp & MII_XGMAC_BUSY), 100, 10000);

err_disable_clks:
	pm_runtime_put(priv->device);

	return ret;
}
}


/**
/**
@@ -196,6 +229,12 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
	int data = 0;
	int data = 0;
	u32 v;
	u32 v;


	data = pm_runtime_get_sync(priv->device);
	if (data < 0) {
		pm_runtime_put_noidle(priv->device);
		return data;
	}

	value |= (phyaddr << priv->hw->mii.addr_shift)
	value |= (phyaddr << priv->hw->mii.addr_shift)
		& priv->hw->mii.addr_mask;
		& priv->hw->mii.addr_mask;
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
@@ -216,19 +255,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
	}
	}


	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
			       100, 10000))
			       100, 10000)) {
		return -EBUSY;
		data = -EBUSY;
		goto err_disable_clks;
	}


	writel(data, priv->ioaddr + mii_data);
	writel(data, priv->ioaddr + mii_data);
	writel(value, priv->ioaddr + mii_address);
	writel(value, priv->ioaddr + mii_address);


	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
			       100, 10000))
			       100, 10000)) {
		return -EBUSY;
		data = -EBUSY;
		goto err_disable_clks;
	}


	/* Read the data from the MII data register */
	/* Read the data from the MII data register */
	data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
	data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;


err_disable_clks:
	pm_runtime_put(priv->device);

	return data;
	return data;
}
}


@@ -247,10 +293,16 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
	struct stmmac_priv *priv = netdev_priv(ndev);
	struct stmmac_priv *priv = netdev_priv(ndev);
	unsigned int mii_address = priv->hw->mii.addr;
	unsigned int mii_address = priv->hw->mii.addr;
	unsigned int mii_data = priv->hw->mii.data;
	unsigned int mii_data = priv->hw->mii.data;
	int ret, data = phydata;
	u32 value = MII_BUSY;
	u32 value = MII_BUSY;
	int data = phydata;
	u32 v;
	u32 v;


	ret = pm_runtime_get_sync(priv->device);
	if (ret < 0) {
		pm_runtime_put_noidle(priv->device);
		return ret;
	}

	value |= (phyaddr << priv->hw->mii.addr_shift)
	value |= (phyaddr << priv->hw->mii.addr_shift)
		& priv->hw->mii.addr_mask;
		& priv->hw->mii.addr_mask;
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
@@ -275,16 +327,23 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,


	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
			       100, 10000))
			       100, 10000)) {
		return -EBUSY;
		ret = -EBUSY;
		goto err_disable_clks;
	}


	/* Set the MII address register to write */
	/* Set the MII address register to write */
	writel(data, priv->ioaddr + mii_data);
	writel(data, priv->ioaddr + mii_data);
	writel(value, priv->ioaddr + mii_address);
	writel(value, priv->ioaddr + mii_address);


	/* Wait until any existing MII operation is complete */
	/* Wait until any existing MII operation is complete */
	return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
	ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
				 100, 10000);
				 100, 10000);

err_disable_clks:
	pm_runtime_put(priv->device);

	return ret;
}
}


/**
/**
+22 −2
Original line number Original line Diff line number Diff line
@@ -744,10 +744,30 @@ static int stmmac_pltfr_resume(struct device *dev)


	return stmmac_resume(dev);
	return stmmac_resume(dev);
}
}

static int stmmac_runtime_suspend(struct device *dev)
{
	struct net_device *ndev = dev_get_drvdata(dev);
	struct stmmac_priv *priv = netdev_priv(ndev);

	stmmac_bus_clks_config(priv, false);

	return 0;
}

static int stmmac_runtime_resume(struct device *dev)
{
	struct net_device *ndev = dev_get_drvdata(dev);
	struct stmmac_priv *priv = netdev_priv(ndev);

	return stmmac_bus_clks_config(priv, true);
}
#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM_SLEEP */


SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
const struct dev_pm_ops stmmac_pltfr_pm_ops = {
				       stmmac_pltfr_resume);
	SET_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_suspend, stmmac_pltfr_resume)
	SET_RUNTIME_PM_OPS(stmmac_runtime_suspend, stmmac_runtime_resume, NULL)
};
EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);


MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
Loading