Thread (14 messages) 14 messages, 3 authors, 2020-03-18

RE: [EXT] [PATCH 1/4] net: fec: set GPR bit on suspend by DT connfiguration.

From: Andy Duan <hidden>
Date: 2020-03-18 06:26:28
Also in: lkml, netdev

From: Martin Fuzzey <redacted> Sent: Wednesday, March 18, 2020 12:50 AM
quoted hunk ↗ jump to hunk
On some SoCs, such as the i.MX6, it is necessary to set a bit in the SoC level
GPR register before suspending for wake on lan to work.

The fec platform callback sleep_mode_enable was intended to allow this but
the platform implementation was NAK'd back in 2015 [1]

This means that, currently, wake on lan is broken on mainline for the i.MX6 at
least.

So implement the required bit setting in the fec driver by itself by adding a
new optional DT property indicating the register and bit to set.

[1]
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.s
pinics.net%2Flists%2Fnetdev%2Fmsg310922.html&amp;data=02%7C01%7Cf
ugang.duan%40nxp.com%7Ca9e64936ec9f45edc57108d7ca9340dd%7C686e
a1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637200606109625887&am
p;sdata=%2Bg4NIxZRwNY331k9cq5s6OIm22qD5qstiDIVlSQiL8E%3D&amp;res
erved=0

Signed-off-by: Martin Fuzzey <redacted>
---
 drivers/net/ethernet/freescale/fec.h      |  7 +++
 drivers/net/ethernet/freescale/fec_main.c | 72
++++++++++++++++++++++++++++---
 2 files changed, 72 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h
b/drivers/net/ethernet/freescale/fec.h
index f79e57f..d89568f 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -488,6 +488,12 @@ struct fec_enet_priv_rx_q {
        struct  sk_buff *rx_skbuff[RX_RING_SIZE];  };

+struct fec_stop_mode_gpr {
+       struct regmap *gpr;
+       u8 reg;
+       u8 bit;
+};
+
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
  * tx_bd_base always point to the base of the buffer descriptors.  The
  * cur_rx and cur_tx point to the currently available buffer.
@@ -562,6 +568,7 @@ struct fec_enet_private {
        int hwts_tx_en;
        struct delayed_work time_keep;
        struct regulator *reg_phy;
+       struct fec_stop_mode_gpr stop_gpr;

        unsigned int tx_align;
        unsigned int rx_align;
diff --git a/drivers/net/ethernet/freescale/fec_main.c
b/drivers/net/ethernet/freescale/fec_main.c
index 23c5fef..3c78124 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -62,6 +62,8 @@
 #include <linux/if_vlan.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/prefetch.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include <soc/imx/cpuidle.h>

 #include <asm/cacheflush.h>
@@ -1092,11 +1094,28 @@ static void fec_enet_reset_skb(struct
net_device *ndev)

 }

+static void fec_enet_stop_mode(struct fec_enet_private *fep, bool
+enabled) {
+       struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
+       struct fec_stop_mode_gpr *stop_gpr = &fep->stop_gpr;
+
+       if (stop_gpr->gpr) {
+               if (enabled)
+                       regmap_update_bits(stop_gpr->gpr,
stop_gpr->reg,
+                                          BIT(stop_gpr->bit),
+                                          BIT(stop_gpr->bit));
+               else
+                       regmap_update_bits(stop_gpr->gpr,
stop_gpr->reg,
+                                          BIT(stop_gpr->bit), 0);
+       } else if (pdata && pdata->sleep_mode_enable) {
+               pdata->sleep_mode_enable(enabled);
+       }
+}
+
 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;
@@ -1125,9 +1144,7 @@ static void fec_enet_reset_skb(struct net_device
*ndev)
                val = readl(fep->hwp + FEC_ECNTRL);
                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);
@@ -3397,6 +3414,43 @@ static int fec_enet_get_irq_cnt(struct
platform_device *pdev)
        return irq_cnt;
 }

+static int fec_enet_of_parse_stop_mode(struct fec_enet_private *fep,
+                                      struct device_node *np) {
+       static const char prop[] = "fsl,stop-mode";
+       struct of_phandle_args args;
+       int ret;
+
+       ret = of_parse_phandle_with_fixed_args(np, prop, 2, 0, &args);
To save memory:

		 ret = of_parse_phandle_with_fixed_args(np, "fsl,stop-mode", 2, 0, &args);
quoted hunk ↗ jump to hunk
+       if (ret == -ENOENT)
+               return 0;
+       if (ret)
+               return ret;
+
+       if (args.args_count != 2) {
+               dev_err(&fep->pdev->dev,
+                       "Bad %s args want gpr offset, bit\n", prop);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       fep->stop_gpr.gpr = syscon_node_to_regmap(args.np);
+       if (IS_ERR(fep->stop_gpr.gpr)) {
+               dev_err(&fep->pdev->dev, "could not find gpr regmap\n");
+               ret = PTR_ERR(fep->stop_gpr.gpr);
+               fep->stop_gpr.gpr = NULL;
+               goto out;
+       }
+
+       fep->stop_gpr.reg = args.args[0];
+       fep->stop_gpr.bit = args.args[1];
+
+out:
+       of_node_put(args.np);
+
+       return ret;
+}
+
 static int
 fec_probe(struct platform_device *pdev)  { @@ -3463,6 +3517,10 @@
static int fec_enet_get_irq_cnt(struct platform_device *pdev)
        if (of_get_property(np, "fsl,magic-packet", NULL))
                fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;

+       ret = fec_enet_of_parse_stop_mode(fep, np);
+       if (ret)
+               goto failed_stop_mode;
+
        phy_node = of_parse_phandle(np, "phy-handle", 0);
        if (!phy_node && of_phy_is_fixed_link(np)) {
                ret = of_phy_register_fixed_link(np); @@ -3631,6
+3689,7 @@ static int fec_enet_get_irq_cnt(struct platform_device *pdev)
        if (of_phy_is_fixed_link(np))
                of_phy_deregister_fixed_link(np);
        of_node_put(phy_node);
+failed_stop_mode:
 failed_phy:
        dev_id--;
 failed_ioremap:
@@ -3708,7 +3767,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;
@@ -3726,8 +3784,8 @@ static int __maybe_unused fec_resume(struct
device *dev)
                        goto failed_clk;
                }
                if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
-                       if (pdata && pdata->sleep_mode_enable)
-                               pdata->sleep_mode_enable(false);
+                       fec_enet_stop_mode(fep, false);
+
                        val = readl(fep->hwp + FEC_ECNTRL);
                        val &= ~(FEC_ECR_MAGICEN |
FEC_ECR_SLEEP);
                        writel(val, fep->hwp + FEC_ECNTRL);
--
1.9.1
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help