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

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
...@@ -90,6 +90,32 @@ imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat) ...@@ -90,6 +90,32 @@ imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
return ret; return ret;
} }
static int imx_dwmac_clks_config(void *priv, bool enabled)
{
struct imx_priv_data *dwmac = priv;
int ret = 0;
if (enabled) {
ret = clk_prepare_enable(dwmac->clk_mem);
if (ret) {
dev_err(dwmac->dev, "mem clock enable failed\n");
return ret;
}
ret = clk_prepare_enable(dwmac->clk_tx);
if (ret) {
dev_err(dwmac->dev, "tx clock enable failed\n");
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) static int imx_dwmac_init(struct platform_device *pdev, void *priv)
{ {
struct plat_stmmacenet_data *plat_dat; struct plat_stmmacenet_data *plat_dat;
...@@ -98,39 +124,18 @@ static int imx_dwmac_init(struct platform_device *pdev, void *priv) ...@@ -98,39 +124,18 @@ static int imx_dwmac_init(struct platform_device *pdev, void *priv)
plat_dat = dwmac->plat_dat; plat_dat = dwmac->plat_dat;
ret = clk_prepare_enable(dwmac->clk_mem);
if (ret) {
dev_err(&pdev->dev, "mem clock enable failed\n");
return ret;
}
ret = clk_prepare_enable(dwmac->clk_tx);
if (ret) {
dev_err(&pdev->dev, "tx clock enable failed\n");
goto clk_tx_en_failed;
}
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) ...@@ -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) ...@@ -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);
......
...@@ -272,6 +272,7 @@ void stmmac_disable_eee_mode(struct stmmac_priv *priv); ...@@ -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,
......
...@@ -28,6 +28,7 @@ ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 */
......
...@@ -15,6 +15,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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;
} }
/** /**
......
...@@ -744,10 +744,30 @@ static int stmmac_pltfr_resume(struct device *dev) ...@@ -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");
......
...@@ -184,6 +184,7 @@ struct plat_stmmacenet_data { ...@@ -184,6 +184,7 @@ struct plat_stmmacenet_data {
int (*init)(struct platform_device *pdev, void *priv); int (*init)(struct platform_device *pdev, void *priv);
void (*exit)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv);
struct mac_device_info *(*setup)(void *priv); struct mac_device_info *(*setup)(void *priv);
int (*clks_config)(void *priv, bool enabled);
void *bsp_priv; void *bsp_priv;
struct clk *stmmac_clk; struct clk *stmmac_clk;
struct clk *pclk; struct clk *pclk;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment