Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[cascardo/linux.git] / drivers / net / ethernet / freescale / fec_main.c
index fea0f33..01f7e81 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>
 
@@ -111,7 +112,13 @@ static struct platform_device_id fec_devtype[] = {
                                FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
                                FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
                                FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
-                               FEC_QUIRK_HAS_RACC,
+                               FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE,
+       }, {
+               .name = "imx6ul-fec",
+               .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+                               FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+                               FEC_QUIRK_HAS_VLAN | FEC_QUIRK_BUG_CAPTURE |
+                               FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE,
        }, {
                /* sentinel */
        }
@@ -125,6 +132,7 @@ enum imx_fec_type {
        IMX6Q_FEC,
        MVF600_FEC,
        IMX6SX_FEC,
+       IMX6UL_FEC,
 };
 
 static const struct of_device_id fec_dt_ids[] = {
@@ -134,6 +142,7 @@ static const struct of_device_id fec_dt_ids[] = {
        { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
        { .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
        { .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
+       { .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -2358,9 +2367,6 @@ static void fec_enet_itr_coal_set(struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        int rx_itr, tx_itr;
 
-       if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
-               return;
-
        /* Must be greater than zero to avoid unpredictable behavior */
        if (!fep->rx_time_itr || !fep->rx_pkts_itr ||
            !fep->tx_time_itr || !fep->tx_pkts_itr)
@@ -2383,10 +2389,12 @@ static void fec_enet_itr_coal_set(struct net_device *ndev)
 
        writel(tx_itr, fep->hwp + FEC_TXIC0);
        writel(rx_itr, fep->hwp + FEC_RXIC0);
-       writel(tx_itr, fep->hwp + FEC_TXIC1);
-       writel(rx_itr, fep->hwp + FEC_RXIC1);
-       writel(tx_itr, fep->hwp + FEC_TXIC2);
-       writel(rx_itr, fep->hwp + FEC_RXIC2);
+       if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+               writel(tx_itr, fep->hwp + FEC_TXIC1);
+               writel(rx_itr, fep->hwp + FEC_RXIC1);
+               writel(tx_itr, fep->hwp + FEC_TXIC2);
+               writel(rx_itr, fep->hwp + FEC_RXIC2);
+       }
 }
 
 static int
@@ -2394,7 +2402,7 @@ fec_enet_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
 
-       if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
+       if (!(fep->quirks & FEC_QUIRK_HAS_COALESCE))
                return -EOPNOTSUPP;
 
        ec->rx_coalesce_usecs = fep->rx_time_itr;
@@ -2412,7 +2420,7 @@ fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
        struct fec_enet_private *fep = netdev_priv(ndev);
        unsigned int cycle;
 
-       if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
+       if (!(fep->quirks & FEC_QUIRK_HAS_COALESCE))
                return -EOPNOTSUPP;
 
        if (ec->rx_max_coalesced_frames > 255) {
@@ -2818,6 +2826,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);
@@ -2853,6 +2864,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);
@@ -3191,7 +3205,12 @@ static void fec_reset_phy(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
                return;
        }
-       msleep(msec);
+
+       if (msec > 20)
+               msleep(msec);
+       else
+               usleep_range(msec * 1000, msec * 1000 + 1000);
+
        gpio_set_value_cansleep(phy_reset, !active_high);
 }
 #else /* CONFIG_OF */
@@ -3292,6 +3311,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;