MLK-10939-01 net: fec: add stop mode support for dts register set

The current driver support stop mode by calling machine api.
The patch add dts support to set gpr register for stop request.

After magic pattern comming during system suspend status, system will
be waked up, and irq handler will be running, there have enet register
access. Since all clocks are disabled in suspend, and clocks are enabled
after resume function. But irq handler run before resume function.

For imx7d chip, access register need some clocks enabled, otherwise system
hang. So the patch also disable wake up irq in the suspend, after resume
back enable the irq, which can avoid system hang issue.

Signed-off-by: Fugang Duan <B38611@freescale.com>
(cherry pick and merge from commit: 8da4f80af0913781a4f9d50917c1dd66180e519d)
This commit is contained in:
Fugang Duan
2015-05-20 18:36:19 +08:00
committed by Leonard Crestez
parent fc014617ae
commit 19b76fd012
3 changed files with 90 additions and 16 deletions

View File

@ -30,6 +30,9 @@ Optional properties:
- fsl,err006687-workaround-present: If present indicates that the system has
the hardware workaround for ERR006687 applied and does not need a software
workaround.
- fsl,wakeup_irq : The property define the wakeup irq index in enet irq source.
- stop-mode : If present, indicates soc need to set gpr bit to request stop
mode.
Optional subnodes:
- mdio : specifies the mdio bus in the FEC, used as a container for phy nodes

View File

@ -471,6 +471,12 @@ struct bufdesc_prop {
unsigned char dsize_log2;
};
struct fec_enet_stop_mode {
struct regmap *gpr;
u8 req_gpr;
u8 req_bit;
};
struct fec_enet_priv_tx_q {
struct bufdesc_prop bd;
unsigned char *tx_bounce[TX_RING_SIZE];
@ -545,6 +551,7 @@ struct fec_enet_private {
bool bufdesc_ex;
int pause_flag;
int wol_flag;
int wake_irq;
u32 quirks;
struct napi_struct napi;
@ -589,6 +596,8 @@ struct fec_enet_private {
unsigned int next_counter;
u64 ethtool_stats[0];
struct fec_enet_stop_mode gpr;
};
void fec_ptp_init(struct platform_device *pdev);

View File

@ -61,6 +61,8 @@
#include <linux/pinctrl/consumer.h>
#include <linux/prefetch.h>
#include <soc/imx/cpuidle.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <asm/cacheflush.h>
@ -1079,11 +1081,30 @@ fec_restart(struct net_device *ndev)
}
static int fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled)
{
struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
if (fep->gpr.gpr) {
if (enabled)
regmap_update_bits(fep->gpr.gpr, fep->gpr.req_gpr,
1 << fep->gpr.req_bit,
1 << fep->gpr.req_bit);
else
regmap_update_bits(fep->gpr.gpr, fep->gpr.req_gpr,
1 << fep->gpr.req_bit,
0);
} else if (pdata && pdata->sleep_mode_enable) {
pdata->sleep_mode_enable(enabled);
}
return 0;
}
static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
u32 val;
@ -1113,8 +1134,7 @@ fec_stop(struct net_device *ndev)
val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
writel(val, fep->hwp + FEC_ECNTRL);
if (pdata && pdata->sleep_mode_enable)
pdata->sleep_mode_enable(true);
fec_enet_stop_mode(fep, true);
}
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
@ -2578,15 +2598,10 @@ fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
return -EINVAL;
device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
if (device_may_wakeup(&ndev->dev)) {
if (device_may_wakeup(&ndev->dev))
fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
if (fep->irq[0] > 0)
enable_irq_wake(fep->irq[0]);
} else {
else
fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
if (fep->irq[0] > 0)
disable_irq_wake(fep->irq[0]);
}
return 0;
}
@ -3368,6 +3383,41 @@ fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
}
static void fec_enet_of_parse_stop_mode(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node;
struct fec_enet_private *fep = netdev_priv(dev);
struct device_node *node;
phandle phandle;
u32 out_val[3];
int ret;
ret = of_property_read_u32_array(np, "stop-mode", out_val, 3);
if (ret) {
dev_dbg(&pdev->dev, "no stop-mode property\n");
return;
}
phandle = *out_val;
node = of_find_node_by_phandle(phandle);
if (!node) {
dev_dbg(&pdev->dev, "could not find gpr node by phandle\n");
return;
}
fep->gpr.gpr = syscon_node_to_regmap(node);
if (IS_ERR(fep->gpr.gpr)) {
dev_dbg(&pdev->dev, "could not find gpr regmap\n");
return;
}
of_node_put(node);
fep->gpr.req_gpr = out_val[1];
fep->gpr.req_bit = out_val[2];
}
static int
fec_probe(struct platform_device *pdev)
{
@ -3430,6 +3480,8 @@ fec_probe(struct platform_device *pdev)
!of_property_read_bool(np, "fsl,err006687-workaround-present"))
fep->quirks |= FEC_QUIRK_ERR006687;
fec_enet_of_parse_stop_mode(pdev);
if (of_get_property(np, "fsl,magic-packet", NULL))
fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
@ -3541,6 +3593,12 @@ fec_probe(struct platform_device *pdev)
fep->irq[i] = irq;
}
ret = of_property_read_u32(np, "fsl,wakeup_irq", &irq);
if (!ret && irq < FEC_IRQ_NUM)
fep->wake_irq = fep->irq[irq];
else
fep->wake_irq = fep->irq[0];
init_completion(&fep->mdio_done);
ret = fec_enet_mii_init(pdev);
if (ret)
@ -3628,10 +3686,13 @@ static int __maybe_unused fec_suspend(struct device *dev)
netif_device_detach(ndev);
netif_tx_unlock_bh(ndev);
fec_stop(ndev);
fec_enet_clk_enable(ndev, false);
if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
} else {
disable_irq(fep->wake_irq);
enable_irq_wake(fep->wake_irq);
}
fec_enet_clk_enable(ndev, false);
} else if (fep->mii_bus_share && !ndev->phydev) {
fec_enet_clk_enable(ndev, false);
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
@ -3654,7 +3715,6 @@ static int __maybe_unused fec_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
int ret;
int val;
@ -3671,9 +3731,11 @@ static int __maybe_unused fec_resume(struct device *dev)
rtnl_unlock();
goto failed_clk;
}
if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
if (pdata && pdata->sleep_mode_enable)
pdata->sleep_mode_enable(false);
disable_irq_wake(fep->wake_irq);
fec_enet_stop_mode(fep, false);
enable_irq(fep->wake_irq);
val = readl(fep->hwp + FEC_ECNTRL);
val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
writel(val, fep->hwp + FEC_ECNTRL);