ARM: imx6: disable deeper idle states when FEC is active w/o HW workaround
authorLucas Stach <l.stach@pengutronix.de>
Fri, 3 Jun 2016 16:31:19 +0000 (18:31 +0200)
committerShawn Guo <shawnguo@kernel.org>
Sun, 12 Jun 2016 11:48:08 +0000 (19:48 +0800)
The i.MX6 Q/DL has an erratum (ERR006687) that prevents the FEC from
waking the CPUs when they are in wait(unclocked) state. As the hardware
workaround isn't applicable to all boards, disable the deeper idle state
when the workaround isn't present and the FEC is in use.

This allows to safely run a kernel with CPUidle enabled on all i.MX6
boards.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Acked-by: David S. Miller <davem@davemloft.net> (for network changes)
Signed-off-by: Shawn Guo <shawnguo@kernel.org>
Documentation/devicetree/bindings/net/fsl-fec.txt
arch/arm/mach-imx/cpuidle-imx6q.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
include/soc/imx/cpuidle.h [new file with mode: 0644]

index b037a9d78d931312f9f950db4e358c8e86a5c86b..a1e3693cca1601e47096dc2edc2a9580b8b0569a 100644 (file)
@@ -27,6 +27,9 @@ Optional properties:
   number to 1.
 - fsl,magic-packet : If present, indicates that the hardware supports waking
   up via magic packet.
+- fsl,err006687-workaround-present: If present indicates that the system has
+  the hardware workaround for ERR006687 applied and does not need a software
+  workaround.
 
 Optional subnodes:
 - mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
index 353bb8774112d8068a072d0afe8f8f32a61683ae..c3cc8ca8d2ff04927db736ecb46e601cc85901db 100644 (file)
@@ -62,6 +62,22 @@ static struct cpuidle_driver imx6q_cpuidle_driver = {
        .safe_state_index = 0,
 };
 
+/*
+ * i.MX6 Q/DL has an erratum (ERR006687) that prevents the FEC from waking the
+ * CPUs when they are in wait(unclocked) state. As the hardware workaround isn't
+ * applicable to all boards, disable the deeper idle state when the workaround
+ * isn't present and the FEC is in use.
+ */
+void imx6q_cpuidle_fec_irqs_used(void)
+{
+       imx6q_cpuidle_driver.states[1].disabled = true;
+}
+
+void imx6q_cpuidle_fec_irqs_unused(void)
+{
+       imx6q_cpuidle_driver.states[1].disabled = false;
+}
+
 int __init imx6q_cpuidle_init(void)
 {
        /* Set INT_MEM_CLK_LPM bit to get a reliable WAIT mode support */
index f58f9ea51639ca9ab60018a34a1df2ffe3fd3d40..dc71a88e9c558c57dc544f4547a11a9d7c10d234 100644 (file)
@@ -442,6 +442,8 @@ struct bufdesc_ex {
 #define FEC_QUIRK_SINGLE_MDIO          (1 << 11)
 /* Controller supports RACC register */
 #define FEC_QUIRK_HAS_RACC             (1 << 12)
+/* Interrupt doesn't wake CPU from deep idle */
+#define FEC_QUIRK_ERR006687            (1 << 13)
 
 struct bufdesc_prop {
        int qid;
index ca2cccc594fdc240d4951cd8deb0b6232aa80c2f..8c2110b616847383b364563d2c8fb4a54189c0a5 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/if_vlan.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/prefetch.h>
+#include <soc/imx/cpuidle.h>
 
 #include <asm/cacheflush.h>
 
@@ -2820,6 +2821,9 @@ fec_enet_open(struct net_device *ndev)
        if (ret)
                goto err_enet_mii_probe;
 
+       if (fep->quirks & FEC_QUIRK_ERR006687)
+               imx6q_cpuidle_fec_irqs_used();
+
        napi_enable(&fep->napi);
        phy_start(ndev->phydev);
        netif_tx_start_all_queues(ndev);
@@ -2855,6 +2859,9 @@ fec_enet_close(struct net_device *ndev)
 
        phy_disconnect(ndev->phydev);
 
+       if (fep->quirks & FEC_QUIRK_ERR006687)
+               imx6q_cpuidle_fec_irqs_unused();
+
        fec_enet_clk_enable(ndev, false);
        pinctrl_pm_select_sleep_state(&fep->pdev->dev);
        pm_runtime_mark_last_busy(&fep->pdev->dev);
@@ -3294,6 +3301,11 @@ fec_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ndev);
 
+       if ((of_machine_is_compatible("fsl,imx6q") ||
+            of_machine_is_compatible("fsl,imx6dl")) &&
+           !of_property_read_bool(np, "fsl,err006687-workaround-present"))
+               fep->quirks |= FEC_QUIRK_ERR006687;
+
        if (of_get_property(np, "fsl,magic-packet", NULL))
                fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
 
diff --git a/include/soc/imx/cpuidle.h b/include/soc/imx/cpuidle.h
new file mode 100644 (file)
index 0000000..986a482
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 Pengutronix, <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __SOC_IMX_CPUIDLE_H__
+#define __SOC_IMX_CPUIDLE_H__
+
+#if defined(CONFIG_CPU_IDLE) && defined(CONFIG_SOC_IMX6Q)
+void imx6q_cpuidle_fec_irqs_used(void);
+void imx6q_cpuidle_fec_irqs_unused(void);
+#else
+void imx6q_cpuidle_fec_irqs_used(void) { }
+void imx6q_cpuidle_fec_irqs_unused(void) { }
+#endif
+
+#endif /* __SOC_IMX_CPUIDLE_H__ */