summaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2015-11-22 19:06:51 +0000
committerFelix Fietkau <nbd@openwrt.org>2015-11-22 19:06:51 +0000
commit3789b1f5a0760bce2f56993685a3f7e7202d41d0 (patch)
tree5fa9d37601b64b81ca4fce683b6cd8bc58b44843 /target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch
parentb1a91ca57fc9bbdb648e77790a0812fd9bd96373 (diff)
downloadmaster-31e0f0ae-3789b1f5a0760bce2f56993685a3f7e7202d41d0.tar.gz
master-31e0f0ae-3789b1f5a0760bce2f56993685a3f7e7202d41d0.tar.bz2
master-31e0f0ae-3789b1f5a0760bce2f56993685a3f7e7202d41d0.zip
ipq806x: update stmmac to the version from linux 4.3
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 47593
Diffstat (limited to 'target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch')
-rw-r--r--target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch2355
1 files changed, 2355 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch b/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch
new file mode 100644
index 0000000000..22450d4bbe
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch
@@ -0,0 +1,2355 @@
+--- a/drivers/net/ethernet/stmicro/Kconfig
++++ b/drivers/net/ethernet/stmicro/Kconfig
+@@ -7,9 +7,7 @@ config NET_VENDOR_STMICRO
+ default y
+ depends on HAS_IOMEM
+ ---help---
+- If you have a network (Ethernet) card belonging to this class, say Y
+- and read the Ethernet-HOWTO, available from
+- <http://www.tldp.org/docs.html#howto>.
++ If you have a network (Ethernet) card belonging to this class, say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
+@@ -16,6 +16,7 @@ if STMMAC_ETH
+ config STMMAC_PLATFORM
+ tristate "STMMAC Platform bus support"
+ depends on STMMAC_ETH
++ select MFD_SYSCON
+ default y
+ ---help---
+ This selects the platform specific bus support for the stmmac driver.
+@@ -26,6 +27,95 @@ config STMMAC_PLATFORM
+
+ If unsure, say N.
+
++if STMMAC_PLATFORM
++
++config DWMAC_GENERIC
++ tristate "Generic driver for DWMAC"
++ default STMMAC_PLATFORM
++ ---help---
++ Generic DWMAC driver for platforms that don't require any
++ platform specific code to function or is using platform
++ data for setup.
++
++config DWMAC_IPQ806X
++ tristate "QCA IPQ806x DWMAC support"
++ default ARCH_QCOM
++ depends on OF
++ select MFD_SYSCON
++ help
++ Support for QCA IPQ806X DWMAC Ethernet.
++
++ This selects the IPQ806x SoC glue layer support for the stmmac
++ device driver. This driver does not use any of the hardware
++ acceleration features available on this SoC. Network devices
++ will behave like standard non-accelerated ethernet interfaces.
++
++config DWMAC_LPC18XX
++ tristate "NXP LPC18xx/43xx DWMAC support"
++ default ARCH_LPC18XX
++ depends on OF
++ select MFD_SYSCON
++ ---help---
++ Support for NXP LPC18xx/43xx DWMAC Ethernet.
++
++config DWMAC_MESON
++ tristate "Amlogic Meson dwmac support"
++ default ARCH_MESON
++ depends on OF
++ help
++ Support for Ethernet controller on Amlogic Meson SoCs.
++
++ This selects the Amlogic Meson SoC glue layer support for
++ the stmmac device driver. This driver is used for Meson6 and
++ Meson8 SoCs.
++
++config DWMAC_ROCKCHIP
++ tristate "Rockchip dwmac support"
++ default ARCH_ROCKCHIP
++ depends on OF
++ select MFD_SYSCON
++ help
++ Support for Ethernet controller on Rockchip RK3288 SoC.
++
++ This selects the Rockchip RK3288 SoC glue layer support for
++ the stmmac device driver.
++
++config DWMAC_SOCFPGA
++ tristate "SOCFPGA dwmac support"
++ default ARCH_SOCFPGA
++ depends on OF
++ select MFD_SYSCON
++ help
++ Support for ethernet controller on Altera SOCFPGA
++
++ This selects the Altera SOCFPGA SoC glue layer support
++ for the stmmac device driver. This driver is used for
++ arria5 and cyclone5 FPGA SoCs.
++
++config DWMAC_STI
++ tristate "STi GMAC support"
++ default ARCH_STI
++ depends on OF
++ select MFD_SYSCON
++ ---help---
++ Support for ethernet controller on STi SOCs.
++
++ This selects STi SoC glue layer support for the stmmac
++ device driver. This driver is used on for the STi series
++ SOCs GMAC ethernet controller.
++
++config DWMAC_SUNXI
++ tristate "Allwinner GMAC support"
++ default ARCH_SUNXI
++ depends on OF
++ ---help---
++ Support for Allwinner A20/A31 GMAC ethernet controllers.
++
++ This selects Allwinner SoC glue layer support for the
++ stmmac device driver. This driver is used for A20/A31
++ GMAC ethernet controller.
++endif
++
+ config STMMAC_PCI
+ tristate "STMMAC PCI bus support"
+ depends on STMMAC_ETH && PCI
+--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
+@@ -4,9 +4,17 @@ stmmac-objs:= stmmac_main.o stmmac_ethto
+ dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
+ mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
+
+-obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
+-stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \
+- dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
++# Ordering matters. Generic driver must be last.
++obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
++obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
++obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
++obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
++obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
++obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
++obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
++obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
++obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
++stmmac-platform-objs:= stmmac_platform.o
+
+ obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
+ stmmac-pci-objs:= stmmac_pci.o
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
+@@ -0,0 +1,81 @@
++/*
++ * Generic DWMAC platform driver
++ *
++ * Copyright (C) 2007-2011 STMicroelectronics Ltd
++ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++
++#include "stmmac.h"
++#include "stmmac_platform.h"
++
++static int dwmac_generic_probe(struct platform_device *pdev)
++{
++ struct plat_stmmacenet_data *plat_dat;
++ struct stmmac_resources stmmac_res;
++ int ret;
++
++ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (ret)
++ return ret;
++
++ if (pdev->dev.of_node) {
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat)) {
++ dev_err(&pdev->dev, "dt configuration failed\n");
++ return PTR_ERR(plat_dat);
++ }
++ } else {
++ plat_dat = dev_get_platdata(&pdev->dev);
++ if (!plat_dat) {
++ dev_err(&pdev->dev, "no platform data provided\n");
++ return -EINVAL;
++ }
++
++ /* Set default value for multicast hash bins */
++ plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
++
++ /* Set default value for unicast filter entries */
++ plat_dat->unicast_filter_entries = 1;
++ }
++
++ /* Custom initialisation (if needed) */
++ if (plat_dat->init) {
++ ret = plat_dat->init(pdev, plat_dat->bsp_priv);
++ if (ret)
++ return ret;
++ }
++
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++}
++
++static const struct of_device_id dwmac_generic_match[] = {
++ { .compatible = "st,spear600-gmac"},
++ { .compatible = "snps,dwmac-3.610"},
++ { .compatible = "snps,dwmac-3.70a"},
++ { .compatible = "snps,dwmac-3.710"},
++ { .compatible = "snps,dwmac"},
++ { }
++};
++MODULE_DEVICE_TABLE(of, dwmac_generic_match);
++
++static struct platform_driver dwmac_generic_driver = {
++ .probe = dwmac_generic_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = STMMAC_RESOURCE_NAME,
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = of_match_ptr(dwmac_generic_match),
++ },
++};
++module_platform_driver(dwmac_generic_driver);
++
++MODULE_DESCRIPTION("Generic dwmac driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+@@ -0,0 +1,373 @@
++/*
++ * Qualcomm Atheros IPQ806x GMAC glue layer
++ *
++ * Copyright (C) 2015 The Linux Foundation
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/phy.h>
++#include <linux/regmap.h>
++#include <linux/clk.h>
++#include <linux/reset.h>
++#include <linux/of_net.h>
++#include <linux/mfd/syscon.h>
++#include <linux/stmmac.h>
++#include <linux/of_mdio.h>
++#include <linux/module.h>
++
++#include "stmmac_platform.h"
++
++#define NSS_COMMON_CLK_GATE 0x8
++#define NSS_COMMON_CLK_GATE_PTP_EN(x) BIT(0x10 + x)
++#define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x) BIT(0x9 + (x * 2))
++#define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x) BIT(0x8 + (x * 2))
++#define NSS_COMMON_CLK_GATE_GMII_RX_EN(x) BIT(0x4 + x)
++#define NSS_COMMON_CLK_GATE_GMII_TX_EN(x) BIT(0x0 + x)
++
++#define NSS_COMMON_CLK_DIV0 0xC
++#define NSS_COMMON_CLK_DIV_OFFSET(x) (x * 8)
++#define NSS_COMMON_CLK_DIV_MASK 0x7f
++
++#define NSS_COMMON_CLK_SRC_CTRL 0x14
++#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (x)
++/* Mode is coded on 1 bit but is different depending on the MAC ID:
++ * MAC0: QSGMII=0 RGMII=1
++ * MAC1: QSGMII=0 SGMII=0 RGMII=1
++ * MAC2 & MAC3: QSGMII=0 SGMII=1
++ */
++#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1
++#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0)
++
++#define NSS_COMMON_MACSEC_CTL 0x28
++#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x)
++
++#define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4))
++#define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19)
++#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16)
++#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8
++#define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0
++#define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f
++
++#define NSS_COMMON_CLK_DIV_RGMII_1000 1
++#define NSS_COMMON_CLK_DIV_RGMII_100 9
++#define NSS_COMMON_CLK_DIV_RGMII_10 99
++#define NSS_COMMON_CLK_DIV_SGMII_1000 0
++#define NSS_COMMON_CLK_DIV_SGMII_100 4
++#define NSS_COMMON_CLK_DIV_SGMII_10 49
++
++#define QSGMII_PCS_MODE_CTL 0x68
++#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7)
++
++#define QSGMII_PCS_CAL_LCKDT_CTL 0x120
++#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19)
++
++/* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */
++#define QSGMII_PHY_SGMII_CTL(x) ((x == 1) ? 0x134 : \
++ (0x13c + (4 * (x - 2))))
++#define QSGMII_PHY_CDR_EN BIT(0)
++#define QSGMII_PHY_RX_FRONT_EN BIT(1)
++#define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2)
++#define QSGMII_PHY_TX_DRIVER_EN BIT(3)
++#define QSGMII_PHY_QSGMII_EN BIT(7)
++#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12
++#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7
++#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18
++#define QSGMII_PHY_RX_DC_BIAS_MASK 0x3
++#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20
++#define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3
++#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22
++#define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3
++#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28
++#define QSGMII_PHY_TX_DRV_AMP_MASK 0xf
++
++struct ipq806x_gmac {
++ struct platform_device *pdev;
++ struct regmap *nss_common;
++ struct regmap *qsgmii_csr;
++ uint32_t id;
++ struct clk *core_clk;
++ phy_interface_t phy_mode;
++};
++
++static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed)
++{
++ struct device *dev = &gmac->pdev->dev;
++ int div;
++
++ switch (speed) {
++ case SPEED_1000:
++ div = NSS_COMMON_CLK_DIV_SGMII_1000;
++ break;
++
++ case SPEED_100:
++ div = NSS_COMMON_CLK_DIV_SGMII_100;
++ break;
++
++ case SPEED_10:
++ div = NSS_COMMON_CLK_DIV_SGMII_10;
++ break;
++
++ default:
++ dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed);
++ return -EINVAL;
++ }
++
++ return div;
++}
++
++static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed)
++{
++ struct device *dev = &gmac->pdev->dev;
++ int div;
++
++ switch (speed) {
++ case SPEED_1000:
++ div = NSS_COMMON_CLK_DIV_RGMII_1000;
++ break;
++
++ case SPEED_100:
++ div = NSS_COMMON_CLK_DIV_RGMII_100;
++ break;
++
++ case SPEED_10:
++ div = NSS_COMMON_CLK_DIV_RGMII_10;
++ break;
++
++ default:
++ dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed);
++ return -EINVAL;
++ }
++
++ return div;
++}
++
++static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed)
++{
++ uint32_t clk_bits, val;
++ int div;
++
++ switch (gmac->phy_mode) {
++ case PHY_INTERFACE_MODE_RGMII:
++ div = get_clk_div_rgmii(gmac, speed);
++ clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
++ NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
++ break;
++
++ case PHY_INTERFACE_MODE_SGMII:
++ div = get_clk_div_sgmii(gmac, speed);
++ clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
++ NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
++ break;
++
++ default:
++ dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n",
++ phy_modes(gmac->phy_mode));
++ return -EINVAL;
++ }
++
++ /* Disable the clocks */
++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
++ val &= ~clk_bits;
++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
++
++ /* Set the divider */
++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val);
++ val &= ~(NSS_COMMON_CLK_DIV_MASK
++ << NSS_COMMON_CLK_DIV_OFFSET(gmac->id));
++ val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id);
++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val);
++
++ /* Enable the clock back */
++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
++ val |= clk_bits;
++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
++
++ return 0;
++}
++
++static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
++{
++ struct device *dev = &gmac->pdev->dev;
++
++ gmac->phy_mode = of_get_phy_mode(dev->of_node);
++ if (gmac->phy_mode < 0) {
++ dev_err(dev, "missing phy mode property\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) {
++ dev_err(dev, "missing qcom id property\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ /* The GMACs are called 1 to 4 in the documentation, but to simplify the
++ * code and keep it consistent with the Linux convention, we'll number
++ * them from 0 to 3 here.
++ */
++ if (gmac->id < 0 || gmac->id > 3) {
++ dev_err(dev, "invalid gmac id\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ gmac->core_clk = devm_clk_get(dev, "stmmaceth");
++ if (IS_ERR(gmac->core_clk)) {
++ dev_err(dev, "missing stmmaceth clk property\n");
++ return gmac->core_clk;
++ }
++ clk_set_rate(gmac->core_clk, 266000000);
++
++ /* Setup the register map for the nss common registers */
++ gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node,
++ "qcom,nss-common");
++ if (IS_ERR(gmac->nss_common)) {
++ dev_err(dev, "missing nss-common node\n");
++ return gmac->nss_common;
++ }
++
++ /* Setup the register map for the qsgmii csr registers */
++ gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node,
++ "qcom,qsgmii-csr");
++ if (IS_ERR(gmac->qsgmii_csr)) {
++ dev_err(dev, "missing qsgmii-csr node\n");
++ return gmac->qsgmii_csr;
++ }
++
++ return NULL;
++}
++
++static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
++{
++ struct ipq806x_gmac *gmac = priv;
++
++ ipq806x_gmac_set_speed(gmac, speed);
++}
++
++static int ipq806x_gmac_probe(struct platform_device *pdev)
++{
++ struct plat_stmmacenet_data *plat_dat;
++ struct stmmac_resources stmmac_res;
++ struct device *dev = &pdev->dev;
++ struct ipq806x_gmac *gmac;
++ int val;
++ void *err;
++
++ val = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (val)
++ return val;
++
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat))
++ return PTR_ERR(plat_dat);
++
++ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
++ if (!gmac)
++ return -ENOMEM;
++
++ gmac->pdev = pdev;
++
++ err = ipq806x_gmac_of_parse(gmac);
++ if (IS_ERR(err)) {
++ dev_err(dev, "device tree parsing error\n");
++ return PTR_ERR(err);
++ }
++
++ regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
++ QSGMII_PCS_CAL_LCKDT_CTL_RST);
++
++ /* Inter frame gap is set to 12 */
++ val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET |
++ 12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET;
++ /* We also initiate an AXI low power exit request */
++ val |= NSS_COMMON_GMAC_CTL_CSYS_REQ;
++ switch (gmac->phy_mode) {
++ case PHY_INTERFACE_MODE_RGMII:
++ val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
++ break;
++ case PHY_INTERFACE_MODE_SGMII:
++ val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
++ break;
++ default:
++ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
++ phy_modes(gmac->phy_mode));
++ return -EINVAL;
++ }
++ regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
++
++ /* Configure the clock src according to the mode */
++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
++ val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id));
++ switch (gmac->phy_mode) {
++ case PHY_INTERFACE_MODE_RGMII:
++ val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
++ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
++ break;
++ case PHY_INTERFACE_MODE_SGMII:
++ val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) <<
++ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
++ break;
++ default:
++ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
++ phy_modes(gmac->phy_mode));
++ return -EINVAL;
++ }
++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
++
++ /* Enable PTP clock */
++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
++ val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
++
++ if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
++ regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
++ QSGMII_PHY_CDR_EN |
++ QSGMII_PHY_RX_FRONT_EN |
++ QSGMII_PHY_RX_SIGNAL_DETECT_EN |
++ QSGMII_PHY_TX_DRIVER_EN |
++ QSGMII_PHY_QSGMII_EN |
++ 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
++ 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET |
++ 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
++ 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
++ 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET);
++ }
++
++ plat_dat->has_gmac = true;
++ plat_dat->bsp_priv = gmac;
++ plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed;
++
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++}
++
++static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
++ { .compatible = "qcom,ipq806x-gmac" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match);
++
++static struct platform_driver ipq806x_gmac_dwmac_driver = {
++ .probe = ipq806x_gmac_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = "ipq806x-gmac-dwmac",
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = ipq806x_gmac_dwmac_match,
++ },
++};
++module_platform_driver(ipq806x_gmac_dwmac_driver);
++
++MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
++MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer");
++MODULE_LICENSE("Dual BSD/GPL");
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
+@@ -0,0 +1,86 @@
++/*
++ * DWMAC glue for NXP LPC18xx/LPC43xx Ethernet
++ *
++ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_net.h>
++#include <linux/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/stmmac.h>
++
++#include "stmmac_platform.h"
++
++/* Register defines for CREG syscon */
++#define LPC18XX_CREG_CREG6 0x12c
++# define LPC18XX_CREG_CREG6_ETHMODE_MASK 0x7
++# define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0
++# define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4
++
++static int lpc18xx_dwmac_probe(struct platform_device *pdev)
++{
++ struct plat_stmmacenet_data *plat_dat;
++ struct stmmac_resources stmmac_res;
++ struct regmap *reg;
++ u8 ethmode;
++ int ret;
++
++ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (ret)
++ return ret;
++
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat))
++ return PTR_ERR(plat_dat);
++
++ plat_dat->has_gmac = true;
++
++ reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
++ if (IS_ERR(reg)) {
++ dev_err(&pdev->dev, "syscon lookup failed\n");
++ return PTR_ERR(reg);
++ }
++
++ if (plat_dat->interface == PHY_INTERFACE_MODE_MII) {
++ ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII;
++ } else if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) {
++ ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
++ } else {
++ dev_err(&pdev->dev, "Only MII and RMII mode supported\n");
++ return -EINVAL;
++ }
++
++ regmap_update_bits(reg, LPC18XX_CREG_CREG6,
++ LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode);
++
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++}
++
++static const struct of_device_id lpc18xx_dwmac_match[] = {
++ { .compatible = "nxp,lpc1850-dwmac" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match);
++
++static struct platform_driver lpc18xx_dwmac_driver = {
++ .probe = lpc18xx_dwmac_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = "lpc18xx-dwmac",
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = lpc18xx_dwmac_match,
++ },
++};
++module_platform_driver(lpc18xx_dwmac_driver);
++
++MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
++MODULE_DESCRIPTION("DWMAC glue for LPC18xx/43xx Ethernet");
++MODULE_LICENSE("GPL v2");
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+@@ -15,6 +15,7 @@
+ #include <linux/ethtool.h>
+ #include <linux/io.h>
+ #include <linux/ioport.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/stmmac.h>
+
+@@ -46,24 +47,54 @@ static void meson6_dwmac_fix_mac_speed(v
+ writel(val, dwmac->reg);
+ }
+
+-static void *meson6_dwmac_setup(struct platform_device *pdev)
++static int meson6_dwmac_probe(struct platform_device *pdev)
+ {
++ struct plat_stmmacenet_data *plat_dat;
++ struct stmmac_resources stmmac_res;
+ struct meson_dwmac *dwmac;
+ struct resource *res;
++ int ret;
++
++ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (ret)
++ return ret;
++
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat))
++ return PTR_ERR(plat_dat);
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+- return ERR_PTR(-ENOMEM);
++ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dwmac->reg))
+- return ERR_CAST(dwmac->reg);
++ return PTR_ERR(dwmac->reg);
++
++ plat_dat->bsp_priv = dwmac;
++ plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
+
+- return dwmac;
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ }
+
+-const struct stmmac_of_data meson6_dwmac_data = {
+- .setup = meson6_dwmac_setup,
+- .fix_mac_speed = meson6_dwmac_fix_mac_speed,
++static const struct of_device_id meson6_dwmac_match[] = {
++ { .compatible = "amlogic,meson6-dwmac" },
++ { }
+ };
++MODULE_DEVICE_TABLE(of, meson6_dwmac_match);
++
++static struct platform_driver meson6_dwmac_driver = {
++ .probe = meson6_dwmac_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = "meson6-dwmac",
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = meson6_dwmac_match,
++ },
++};
++module_platform_driver(meson6_dwmac_driver);
++
++MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
++MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer");
++MODULE_LICENSE("GPL v2");
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -22,17 +22,31 @@
+ #include <linux/phy.h>
+ #include <linux/of_net.h>
+ #include <linux/gpio.h>
++#include <linux/module.h>
+ #include <linux/of_gpio.h>
+ #include <linux/of_device.h>
++#include <linux/platform_device.h>
+ #include <linux/regulator/consumer.h>
+ #include <linux/delay.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/regmap.h>
+
++#include "stmmac_platform.h"
++
++struct rk_priv_data;
++struct rk_gmac_ops {
++ void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
++ int tx_delay, int rx_delay);
++ void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
++ void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
++ void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
++};
++
+ struct rk_priv_data {
+ struct platform_device *pdev;
+ int phy_iface;
+ struct regulator *regulator;
++ const struct rk_gmac_ops *ops;
+
+ bool clk_enabled;
+ bool clock_input;
+@@ -60,103 +74,228 @@ struct rk_priv_data {
+
+ #define RK3288_GRF_SOC_CON1 0x0248
+ #define RK3288_GRF_SOC_CON3 0x0250
+-#define RK3288_GRF_GPIO3D_E 0x01ec
+-#define RK3288_GRF_GPIO4A_E 0x01f0
+-#define RK3288_GRF_GPIO4B_E 0x01f4
+
+ /*RK3288_GRF_SOC_CON1*/
+-#define GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8))
+-#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8))
+-#define GMAC_FLOW_CTRL GRF_BIT(9)
+-#define GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
+-#define GMAC_SPEED_10M GRF_CLR_BIT(10)
+-#define GMAC_SPEED_100M GRF_BIT(10)
+-#define GMAC_RMII_CLK_25M GRF_BIT(11)
+-#define GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
+-#define GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
+-#define GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
+-#define GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
+-#define GMAC_RMII_MODE GRF_BIT(14)
+-#define GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
++#define RK3288_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | \
++ GRF_CLR_BIT(8))
++#define RK3288_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | \
++ GRF_BIT(8))
++#define RK3288_GMAC_FLOW_CTRL GRF_BIT(9)
++#define RK3288_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
++#define RK3288_GMAC_SPEED_10M GRF_CLR_BIT(10)
++#define RK3288_GMAC_SPEED_100M GRF_BIT(10)
++#define RK3288_GMAC_RMII_CLK_25M GRF_BIT(11)
++#define RK3288_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
++#define RK3288_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
++#define RK3288_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
++#define RK3288_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
++#define RK3288_GMAC_RMII_MODE GRF_BIT(14)
++#define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
+
+ /*RK3288_GRF_SOC_CON3*/
+-#define GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
+-#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
+-#define GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+-#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+-#define GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
+-#define GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
++#define RK3288_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
++#define RK3288_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
++#define RK3288_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
++#define RK3288_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
++#define RK3288_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
++#define RK3288_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+-static void set_to_rgmii(struct rk_priv_data *bsp_priv,
+- int tx_delay, int rx_delay)
++static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
++ int tx_delay, int rx_delay)
+ {
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+- GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR);
++ RK3288_GMAC_PHY_INTF_SEL_RGMII |
++ RK3288_GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+- GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE |
+- GMAC_CLK_RX_DL_CFG(rx_delay) |
+- GMAC_CLK_TX_DL_CFG(tx_delay));
++ RK3288_GMAC_RXCLK_DLY_ENABLE |
++ RK3288_GMAC_TXCLK_DLY_ENABLE |
++ RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
++ RK3288_GMAC_CLK_TX_DL_CFG(tx_delay));
+ }
+
+-static void set_to_rmii(struct rk_priv_data *bsp_priv)
++static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
+ {
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+- GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE);
++ RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE);
+ }
+
+-static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
++static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+ {
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10)
+- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
++ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
++ RK3288_GMAC_CLK_2_5M);
+ else if (speed == 100)
+- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
++ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
++ RK3288_GMAC_CLK_25M);
+ else if (speed == 1000)
+- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
++ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
++ RK3288_GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+ }
+
+-static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
++static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+ {
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ dev_err(dev, "Missing rockchip,grf property\n");
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+- GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M);
++ RK3288_GMAC_RMII_CLK_2_5M |
++ RK3288_GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+- GMAC_RMII_CLK_25M | GMAC_SPEED_100M);
++ RK3288_GMAC_RMII_CLK_25M |
++ RK3288_GMAC_SPEED_100M);
++ } else {
++ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
++ }
++}
++
++static const struct rk_gmac_ops rk3288_ops = {
++ .set_to_rgmii = rk3288_set_to_rgmii,
++ .set_to_rmii = rk3288_set_to_rmii,
++ .set_rgmii_speed = rk3288_set_rgmii_speed,
++ .set_rmii_speed = rk3288_set_rmii_speed,
++};
++
++#define RK3368_GRF_SOC_CON15 0x043c
++#define RK3368_GRF_SOC_CON16 0x0440
++
++/* RK3368_GRF_SOC_CON15 */
++#define RK3368_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
++ GRF_CLR_BIT(11))
++#define RK3368_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
++ GRF_BIT(11))
++#define RK3368_GMAC_FLOW_CTRL GRF_BIT(8)
++#define RK3368_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
++#define RK3368_GMAC_SPEED_10M GRF_CLR_BIT(7)
++#define RK3368_GMAC_SPEED_100M GRF_BIT(7)
++#define RK3368_GMAC_RMII_CLK_25M GRF_BIT(3)
++#define RK3368_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
++#define RK3368_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
++#define RK3368_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
++#define RK3368_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
++#define RK3368_GMAC_RMII_MODE GRF_BIT(6)
++#define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
++
++/* RK3368_GRF_SOC_CON16 */
++#define RK3368_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
++#define RK3368_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
++#define RK3368_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
++#define RK3368_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
++#define RK3368_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
++#define RK3368_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
++
++static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
++ int tx_delay, int rx_delay)
++{
++ struct device *dev = &bsp_priv->pdev->dev;
++
++ if (IS_ERR(bsp_priv->grf)) {
++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ return;
++ }
++
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
++ RK3368_GMAC_PHY_INTF_SEL_RGMII |
++ RK3368_GMAC_RMII_MODE_CLR);
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16,
++ RK3368_GMAC_RXCLK_DLY_ENABLE |
++ RK3368_GMAC_TXCLK_DLY_ENABLE |
++ RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
++ RK3368_GMAC_CLK_TX_DL_CFG(tx_delay));
++}
++
++static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
++{
++ struct device *dev = &bsp_priv->pdev->dev;
++
++ if (IS_ERR(bsp_priv->grf)) {
++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ return;
++ }
++
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
++ RK3368_GMAC_PHY_INTF_SEL_RMII | RK3368_GMAC_RMII_MODE);
++}
++
++static void rk3368_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
++{
++ struct device *dev = &bsp_priv->pdev->dev;
++
++ if (IS_ERR(bsp_priv->grf)) {
++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ return;
++ }
++
++ if (speed == 10)
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
++ RK3368_GMAC_CLK_2_5M);
++ else if (speed == 100)
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
++ RK3368_GMAC_CLK_25M);
++ else if (speed == 1000)
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
++ RK3368_GMAC_CLK_125M);
++ else
++ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
++}
++
++static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
++{
++ struct device *dev = &bsp_priv->pdev->dev;
++
++ if (IS_ERR(bsp_priv->grf)) {
++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
++ return;
++ }
++
++ if (speed == 10) {
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
++ RK3368_GMAC_RMII_CLK_2_5M |
++ RK3368_GMAC_SPEED_10M);
++ } else if (speed == 100) {
++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
++ RK3368_GMAC_RMII_CLK_25M |
++ RK3368_GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+ }
+
++static const struct rk_gmac_ops rk3368_ops = {
++ .set_to_rgmii = rk3368_set_to_rgmii,
++ .set_to_rmii = rk3368_set_to_rmii,
++ .set_rgmii_speed = rk3368_set_rgmii_speed,
++ .set_rmii_speed = rk3368_set_rmii_speed,
++};
++
+ static int gmac_clk_init(struct rk_priv_data *bsp_priv)
+ {
+ struct device *dev = &bsp_priv->pdev->dev;
+@@ -165,46 +304,46 @@ static int gmac_clk_init(struct rk_priv_
+
+ bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx");
+ if (IS_ERR(bsp_priv->mac_clk_rx))
+- dev_err(dev, "%s: cannot get clock %s\n",
+- __func__, "mac_clk_rx");
++ dev_err(dev, "cannot get clock %s\n",
++ "mac_clk_rx");
+
+ bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx");
+ if (IS_ERR(bsp_priv->mac_clk_tx))
+- dev_err(dev, "%s: cannot get clock %s\n",
+- __func__, "mac_clk_tx");
++ dev_err(dev, "cannot get clock %s\n",
++ "mac_clk_tx");
+
+ bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac");
+ if (IS_ERR(bsp_priv->aclk_mac))
+- dev_err(dev, "%s: cannot get clock %s\n",
+- __func__, "aclk_mac");
++ dev_err(dev, "cannot get clock %s\n",
++ "aclk_mac");
+
+ bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac");
+ if (IS_ERR(bsp_priv->pclk_mac))
+- dev_err(dev, "%s: cannot get clock %s\n",
+- __func__, "pclk_mac");
++ dev_err(dev, "cannot get clock %s\n",
++ "pclk_mac");
+
+ bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth");
+ if (IS_ERR(bsp_priv->clk_mac))
+- dev_err(dev, "%s: cannot get clock %s\n",
+- __func__, "stmmaceth");
++ dev_err(dev, "cannot get clock %s\n",
++ "stmmaceth");
+
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+ bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref");
+ if (IS_ERR(bsp_priv->clk_mac_ref))
+- dev_err(dev, "%s: cannot get clock %s\n",
+- __func__, "clk_mac_ref");
++ dev_err(dev, "cannot get clock %s\n",
++ "clk_mac_ref");
+
+ if (!bsp_priv->clock_input) {
+ bsp_priv->clk_mac_refout =
+ devm_clk_get(dev, "clk_mac_refout");
+ if (IS_ERR(bsp_priv->clk_mac_refout))
+- dev_err(dev, "%s: cannot get clock %s\n",
+- __func__, "clk_mac_refout");
++ dev_err(dev, "cannot get clock %s\n",
++ "clk_mac_refout");
+ }
+ }
+
+ if (bsp_priv->clock_input) {
+- dev_info(dev, "%s: clock input from PHY\n", __func__);
++ dev_info(dev, "clock input from PHY\n");
+ } else {
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+ clk_set_rate(bsp_priv->clk_mac, 50000000);
+@@ -291,26 +430,25 @@ static int phy_power_on(struct rk_priv_d
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (!ldo) {
+- dev_err(dev, "%s: no regulator found\n", __func__);
++ dev_err(dev, "no regulator found\n");
+ return -1;
+ }
+
+ if (enable) {
+ ret = regulator_enable(ldo);
+ if (ret)
+- dev_err(dev, "%s: fail to enable phy-supply\n",
+- __func__);
++ dev_err(dev, "fail to enable phy-supply\n");
+ } else {
+ ret = regulator_disable(ldo);
+ if (ret)
+- dev_err(dev, "%s: fail to disable phy-supply\n",
+- __func__);
++ dev_err(dev, "fail to disable phy-supply\n");
+ }
+
+ return 0;
+ }
+
+-static void *rk_gmac_setup(struct platform_device *pdev)
++static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
++ const struct rk_gmac_ops *ops)
+ {
+ struct rk_priv_data *bsp_priv;
+ struct device *dev = &pdev->dev;
+@@ -323,6 +461,7 @@ static void *rk_gmac_setup(struct platfo
+ return ERR_PTR(-ENOMEM);
+
+ bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
++ bsp_priv->ops = ops;
+
+ bsp_priv->regulator = devm_regulator_get_optional(dev, "phy");
+ if (IS_ERR(bsp_priv->regulator)) {
+@@ -336,12 +475,11 @@ static void *rk_gmac_setup(struct platfo
+
+ ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
+ if (ret) {
+- dev_err(dev, "%s: Can not read property: clock_in_out.\n",
+- __func__);
++ dev_err(dev, "Can not read property: clock_in_out.\n");
+ bsp_priv->clock_input = true;
+ } else {
+- dev_info(dev, "%s: clock input or output? (%s).\n",
+- __func__, strings);
++ dev_info(dev, "clock input or output? (%s).\n",
++ strings);
+ if (!strcmp(strings, "input"))
+ bsp_priv->clock_input = true;
+ else
+@@ -351,22 +489,22 @@ static void *rk_gmac_setup(struct platfo
+ ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
+ if (ret) {
+ bsp_priv->tx_delay = 0x30;
+- dev_err(dev, "%s: Can not read property: tx_delay.", __func__);
+- dev_err(dev, "%s: set tx_delay to 0x%x\n",
+- __func__, bsp_priv->tx_delay);
++ dev_err(dev, "Can not read property: tx_delay.");
++ dev_err(dev, "set tx_delay to 0x%x\n",
++ bsp_priv->tx_delay);
+ } else {
+- dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value);
++ dev_info(dev, "TX delay(0x%x).\n", value);
+ bsp_priv->tx_delay = value;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
+ if (ret) {
+ bsp_priv->rx_delay = 0x10;
+- dev_err(dev, "%s: Can not read property: rx_delay.", __func__);
+- dev_err(dev, "%s: set rx_delay to 0x%x\n",
+- __func__, bsp_priv->rx_delay);
++ dev_err(dev, "Can not read property: rx_delay.");
++ dev_err(dev, "set rx_delay to 0x%x\n",
++ bsp_priv->rx_delay);
+ } else {
+- dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value);
++ dev_info(dev, "RX delay(0x%x).\n", value);
+ bsp_priv->rx_delay = value;
+ }
+
+@@ -376,13 +514,14 @@ static void *rk_gmac_setup(struct platfo
+
+ /*rmii or rgmii*/
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
+- dev_info(dev, "%s: init for RGMII\n", __func__);
+- set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
++ dev_info(dev, "init for RGMII\n");
++ bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay,
++ bsp_priv->rx_delay);
+ } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+- dev_info(dev, "%s: init for RMII\n", __func__);
+- set_to_rmii(bsp_priv);
++ dev_info(dev, "init for RMII\n");
++ bsp_priv->ops->set_to_rmii(bsp_priv);
+ } else {
+- dev_err(dev, "%s: NO interface defined!\n", __func__);
++ dev_err(dev, "NO interface defined!\n");
+ }
+
+ gmac_clk_init(bsp_priv);
+@@ -420,17 +559,68 @@ static void rk_fix_speed(void *priv, uns
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
+- set_rgmii_speed(bsp_priv, speed);
++ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
+ else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+- set_rmii_speed(bsp_priv, speed);
++ bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
+ else
+ dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
+ }
+
+-const struct stmmac_of_data rk3288_gmac_data = {
+- .has_gmac = 1,
+- .fix_mac_speed = rk_fix_speed,
+- .setup = rk_gmac_setup,
+- .init = rk_gmac_init,
+- .exit = rk_gmac_exit,
++static int rk_gmac_probe(struct platform_device *pdev)
++{
++ struct plat_stmmacenet_data *plat_dat;
++ struct stmmac_resources stmmac_res;
++ const struct rk_gmac_ops *data;
++ int ret;
++
++ data = of_device_get_match_data(&pdev->dev);
++ if (!data) {
++ dev_err(&pdev->dev, "no of match data provided\n");
++ return -EINVAL;
++ }
++
++ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (ret)
++ return ret;
++
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat))
++ return PTR_ERR(plat_dat);
++
++ plat_dat->has_gmac = true;
++ plat_dat->init = rk_gmac_init;
++ plat_dat->exit = rk_gmac_exit;
++ plat_dat->fix_mac_speed = rk_fix_speed;
++
++ plat_dat->bsp_priv = rk_gmac_setup(pdev, data);
++ if (IS_ERR(plat_dat->bsp_priv))
++ return PTR_ERR(plat_dat->bsp_priv);
++
++ ret = rk_gmac_init(pdev, plat_dat->bsp_priv);
++ if (ret)
++ return ret;
++
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++}
++
++static const struct of_device_id rk_gmac_dwmac_match[] = {
++ { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
++ { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
++ { }
+ };
++MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
++
++static struct platform_driver rk_gmac_dwmac_driver = {
++ .probe = rk_gmac_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = "rk_gmac-dwmac",
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = rk_gmac_dwmac_match,
++ },
++};
++module_platform_driver(rk_gmac_dwmac_driver);
++
++MODULE_AUTHOR("Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>");
++MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer");
++MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+@@ -175,31 +175,6 @@ static int socfpga_dwmac_setup(struct so
+ return 0;
+ }
+
+-static void *socfpga_dwmac_probe(struct platform_device *pdev)
+-{
+- struct device *dev = &pdev->dev;
+- int ret;
+- struct socfpga_dwmac *dwmac;
+-
+- dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
+- if (!dwmac)
+- return ERR_PTR(-ENOMEM);
+-
+- ret = socfpga_dwmac_parse_data(dwmac, dev);
+- if (ret) {
+- dev_err(dev, "Unable to parse OF data\n");
+- return ERR_PTR(ret);
+- }
+-
+- ret = socfpga_dwmac_setup(dwmac);
+- if (ret) {
+- dev_err(dev, "couldn't setup SoC glue (%d)\n", ret);
+- return ERR_PTR(ret);
+- }
+-
+- return dwmac;
+-}
+-
+ static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv)
+ {
+ struct socfpga_dwmac *dwmac = priv;
+@@ -257,9 +232,65 @@ static int socfpga_dwmac_init(struct pla
+ return ret;
+ }
+
+-const struct stmmac_of_data socfpga_gmac_data = {
+- .setup = socfpga_dwmac_probe,
+- .init = socfpga_dwmac_init,
+- .exit = socfpga_dwmac_exit,
+- .fix_mac_speed = socfpga_dwmac_fix_mac_speed,
++static int socfpga_dwmac_probe(struct platform_device *pdev)
++{
++ struct plat_stmmacenet_data *plat_dat;
++ struct stmmac_resources stmmac_res;
++ struct device *dev = &pdev->dev;
++ int ret;
++ struct socfpga_dwmac *dwmac;
++
++ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (ret)
++ return ret;
++
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat))
++ return PTR_ERR(plat_dat);
++
++ dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
++ if (!dwmac)
++ return -ENOMEM;
++
++ ret = socfpga_dwmac_parse_data(dwmac, dev);
++ if (ret) {
++ dev_err(dev, "Unable to parse OF data\n");
++ return ret;
++ }
++
++ ret = socfpga_dwmac_setup(dwmac);
++ if (ret) {
++ dev_err(dev, "couldn't setup SoC glue (%d)\n", ret);
++ return ret;
++ }
++
++ plat_dat->bsp_priv = dwmac;
++ plat_dat->init = socfpga_dwmac_init;
++ plat_dat->exit = socfpga_dwmac_exit;
++ plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
++
++ ret = socfpga_dwmac_init(pdev, plat_dat->bsp_priv);
++ if (ret)
++ return ret;
++
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++}
++
++static const struct of_device_id socfpga_dwmac_match[] = {
++ { .compatible = "altr,socfpga-stmmac" },
++ { }
+ };
++MODULE_DEVICE_TABLE(of, socfpga_dwmac_match);
++
++static struct platform_driver socfpga_dwmac_driver = {
++ .probe = socfpga_dwmac_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = "socfpga-dwmac",
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = socfpga_dwmac_match,
++ },
++};
++module_platform_driver(socfpga_dwmac_driver);
++
++MODULE_LICENSE("GPL v2");
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+@@ -17,9 +17,11 @@
+ #include <linux/stmmac.h>
+ #include <linux/phy.h>
+ #include <linux/mfd/syscon.h>
++#include <linux/module.h>
+ #include <linux/regmap.h>
+ #include <linux/clk.h>
+ #include <linux/of.h>
++#include <linux/of_device.h>
+ #include <linux/of_net.h>
+
+ #include "stmmac_platform.h"
+@@ -127,6 +129,11 @@ struct sti_dwmac {
+ struct device *dev;
+ struct regmap *regmap;
+ u32 speed;
++ void (*fix_retime_src)(void *priv, unsigned int speed);
++};
++
++struct sti_dwmac_of_data {
++ void (*fix_retime_src)(void *priv, unsigned int speed);
+ };
+
+ static u32 phy_intf_sels[] = {
+@@ -221,8 +228,9 @@ static void stid127_fix_retime_src(void
+ regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val);
+ }
+
+-static void sti_dwmac_ctrl_init(struct sti_dwmac *dwmac)
++static int sti_dwmac_init(struct platform_device *pdev, void *priv)
+ {
++ struct sti_dwmac *dwmac = priv;
+ struct regmap *regmap = dwmac->regmap;
+ int iface = dwmac->interface;
+ struct device *dev = dwmac->dev;
+@@ -240,28 +248,8 @@ static void sti_dwmac_ctrl_init(struct s
+
+ val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
+ regmap_update_bits(regmap, reg, ENMII_MASK, val);
+-}
+-
+-static int stix4xx_init(struct platform_device *pdev, void *priv)
+-{
+- struct sti_dwmac *dwmac = priv;
+- u32 spd = dwmac->speed;
+
+- sti_dwmac_ctrl_init(dwmac);
+-
+- stih4xx_fix_retime_src(priv, spd);
+-
+- return 0;
+-}
+-
+-static int stid127_init(struct platform_device *pdev, void *priv)
+-{
+- struct sti_dwmac *dwmac = priv;
+- u32 spd = dwmac->speed;
+-
+- sti_dwmac_ctrl_init(dwmac);
+-
+- stid127_fix_retime_src(priv, spd);
++ dwmac->fix_retime_src(priv, dwmac->speed);
+
+ return 0;
+ }
+@@ -333,34 +321,80 @@ static int sti_dwmac_parse_data(struct s
+ return 0;
+ }
+
+-static void *sti_dwmac_setup(struct platform_device *pdev)
++static int sti_dwmac_probe(struct platform_device *pdev)
+ {
++ struct plat_stmmacenet_data *plat_dat;
++ const struct sti_dwmac_of_data *data;
++ struct stmmac_resources stmmac_res;
+ struct sti_dwmac *dwmac;
+ int ret;
+
++ data = of_device_get_match_data(&pdev->dev);
++ if (!data) {
++ dev_err(&pdev->dev, "No OF match data provided\n");
++ return -EINVAL;
++ }
++
++ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (ret)
++ return ret;
++
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat))
++ return PTR_ERR(plat_dat);
++
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+- return ERR_PTR(-ENOMEM);
++ return -ENOMEM;
+
+ ret = sti_dwmac_parse_data(dwmac, pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to parse OF data\n");
+- return ERR_PTR(ret);
++ return ret;
+ }
+
+- return dwmac;
++ dwmac->fix_retime_src = data->fix_retime_src;
++
++ plat_dat->bsp_priv = dwmac;
++ plat_dat->init = sti_dwmac_init;
++ plat_dat->exit = sti_dwmac_exit;
++ plat_dat->fix_mac_speed = data->fix_retime_src;
++
++ ret = sti_dwmac_init(pdev, plat_dat->bsp_priv);
++ if (ret)
++ return ret;
++
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ }
+
+-const struct stmmac_of_data stih4xx_dwmac_data = {
+- .fix_mac_speed = stih4xx_fix_retime_src,
+- .setup = sti_dwmac_setup,
+- .init = stix4xx_init,
+- .exit = sti_dwmac_exit,
++static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
++ .fix_retime_src = stih4xx_fix_retime_src,
++};
++
++static const struct sti_dwmac_of_data stid127_dwmac_data = {
++ .fix_retime_src = stid127_fix_retime_src,
+ };
+
+-const struct stmmac_of_data stid127_dwmac_data = {
+- .fix_mac_speed = stid127_fix_retime_src,
+- .setup = sti_dwmac_setup,
+- .init = stid127_init,
+- .exit = sti_dwmac_exit,
++static const struct of_device_id sti_dwmac_match[] = {
++ { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
++ { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
++ { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
++ { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
++ { }
+ };
++MODULE_DEVICE_TABLE(of, sti_dwmac_match);
++
++static struct platform_driver sti_dwmac_driver = {
++ .probe = sti_dwmac_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = "sti-dwmac",
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = sti_dwmac_match,
++ },
++};
++module_platform_driver(sti_dwmac_driver);
++
++MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics DWMAC Specific Glue layer");
++MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+@@ -18,7 +18,9 @@
+
+ #include <linux/stmmac.h>
+ #include <linux/clk.h>
++#include <linux/module.h>
+ #include <linux/phy.h>
++#include <linux/platform_device.h>
+ #include <linux/of_net.h>
+ #include <linux/regulator/consumer.h>
+
+@@ -31,35 +33,6 @@ struct sunxi_priv_data {
+ struct regulator *regulator;
+ };
+
+-static void *sun7i_gmac_setup(struct platform_device *pdev)
+-{
+- struct sunxi_priv_data *gmac;
+- struct device *dev = &pdev->dev;
+-
+- gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
+- if (!gmac)
+- return ERR_PTR(-ENOMEM);
+-
+- gmac->interface = of_get_phy_mode(dev->of_node);
+-
+- gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
+- if (IS_ERR(gmac->tx_clk)) {
+- dev_err(dev, "could not get tx clock\n");
+- return gmac->tx_clk;
+- }
+-
+- /* Optional regulator for PHY */
+- gmac->regulator = devm_regulator_get_optional(dev, "phy");
+- if (IS_ERR(gmac->regulator)) {
+- if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
+- return ERR_PTR(-EPROBE_DEFER);
+- dev_info(dev, "no regulator found\n");
+- gmac->regulator = NULL;
+- }
+-
+- return gmac;
+-}
+-
+ #define SUN7I_GMAC_GMII_RGMII_RATE 125000000
+ #define SUN7I_GMAC_MII_RATE 25000000
+
+@@ -130,13 +103,76 @@ static void sun7i_fix_speed(void *priv,
+ }
+ }
+
+-/* of_data specifying hardware features and callbacks.
+- * hardware features were copied from Allwinner drivers. */
+-const struct stmmac_of_data sun7i_gmac_data = {
+- .has_gmac = 1,
+- .tx_coe = 1,
+- .fix_mac_speed = sun7i_fix_speed,
+- .setup = sun7i_gmac_setup,
+- .init = sun7i_gmac_init,
+- .exit = sun7i_gmac_exit,
++static int sun7i_gmac_probe(struct platform_device *pdev)
++{
++ struct plat_stmmacenet_data *plat_dat;
++ struct stmmac_resources stmmac_res;
++ struct sunxi_priv_data *gmac;
++ struct device *dev = &pdev->dev;
++ int ret;
++
++ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
++ if (ret)
++ return ret;
++
++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++ if (IS_ERR(plat_dat))
++ return PTR_ERR(plat_dat);
++
++ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
++ if (!gmac)
++ return -ENOMEM;
++
++ gmac->interface = of_get_phy_mode(dev->of_node);
++
++ gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
++ if (IS_ERR(gmac->tx_clk)) {
++ dev_err(dev, "could not get tx clock\n");
++ return PTR_ERR(gmac->tx_clk);
++ }
++
++ /* Optional regulator for PHY */
++ gmac->regulator = devm_regulator_get_optional(dev, "phy");
++ if (IS_ERR(gmac->regulator)) {
++ if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ dev_info(dev, "no regulator found\n");
++ gmac->regulator = NULL;
++ }
++
++ /* platform data specifying hardware features and callbacks.
++ * hardware features were copied from Allwinner drivers. */
++ plat_dat->tx_coe = 1;
++ plat_dat->has_gmac = true;
++ plat_dat->bsp_priv = gmac;
++ plat_dat->init = sun7i_gmac_init;
++ plat_dat->exit = sun7i_gmac_exit;
++ plat_dat->fix_mac_speed = sun7i_fix_speed;
++
++ ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv);
++ if (ret)
++ return ret;
++
++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++}
++
++static const struct of_device_id sun7i_dwmac_match[] = {
++ { .compatible = "allwinner,sun7i-a20-gmac" },
++ { }
+ };
++MODULE_DEVICE_TABLE(of, sun7i_dwmac_match);
++
++static struct platform_driver sun7i_dwmac_driver = {
++ .probe = sun7i_gmac_probe,
++ .remove = stmmac_pltfr_remove,
++ .driver = {
++ .name = "sun7i-dwmac",
++ .pm = &stmmac_pltfr_pm_ops,
++ .of_match_table = sun7i_dwmac_match,
++ },
++};
++module_platform_driver(sun7i_dwmac_driver);
++
++MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
++MODULE_DESCRIPTION("Allwinner sunxi DWMAC specific glue layer");
++MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+@@ -73,7 +73,7 @@
+ #define MMC_RX_OCTETCOUNT_G 0x00000188
+ #define MMC_RX_BROADCASTFRAME_G 0x0000018c
+ #define MMC_RX_MULTICASTFRAME_G 0x00000190
+-#define MMC_RX_CRC_ERRROR 0x00000194
++#define MMC_RX_CRC_ERROR 0x00000194
+ #define MMC_RX_ALIGN_ERROR 0x00000198
+ #define MMC_RX_RUN_ERROR 0x0000019C
+ #define MMC_RX_JABBER_ERROR 0x000001A0
+@@ -196,7 +196,7 @@ void dwmac_mmc_read(void __iomem *ioaddr
+ mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G);
+ mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G);
+ mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G);
+- mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERRROR);
++ mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERROR);
+ mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR);
+ mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR);
+ mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR);
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -34,6 +34,14 @@
+ #include <linux/ptp_clock_kernel.h>
+ #include <linux/reset.h>
+
++struct stmmac_resources {
++ void __iomem *addr;
++ const char *mac;
++ int wol_irq;
++ int lpi_irq;
++ int irq;
++};
++
+ struct stmmac_tx_info {
+ dma_addr_t buf;
+ bool map_as_page;
+@@ -135,9 +143,9 @@ void stmmac_ptp_unregister(struct stmmac
+ int stmmac_resume(struct net_device *ndev);
+ int stmmac_suspend(struct net_device *ndev);
+ int stmmac_dvr_remove(struct net_device *ndev);
+-struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+- struct plat_stmmacenet_data *plat_dat,
+- void __iomem *addr);
++int stmmac_dvr_probe(struct device *device,
++ struct plat_stmmacenet_data *plat_dat,
++ struct stmmac_resources *res);
+ void stmmac_disable_eee_mode(struct stmmac_priv *priv);
+ bool stmmac_eee_init(struct stmmac_priv *priv);
+
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -52,6 +52,7 @@
+ #include "stmmac_ptp.h"
+ #include "stmmac.h"
+ #include <linux/reset.h>
++#include <linux/of_mdio.h>
+
+ #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
+
+@@ -816,18 +817,25 @@ static int stmmac_init_phy(struct net_de
+ priv->speed = 0;
+ priv->oldduplex = -1;
+
+- if (priv->plat->phy_bus_name)
+- snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
+- priv->plat->phy_bus_name, priv->plat->bus_id);
+- else
+- snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
+- priv->plat->bus_id);
++ if (priv->plat->phy_node) {
++ phydev = of_phy_connect(dev, priv->plat->phy_node,
++ &stmmac_adjust_link, 0, interface);
++ } else {
++ if (priv->plat->phy_bus_name)
++ snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
++ priv->plat->phy_bus_name, priv->plat->bus_id);
++ else
++ snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
++ priv->plat->bus_id);
+
+- snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+- priv->plat->phy_addr);
+- pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt);
++ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
++ priv->plat->phy_addr);
++ pr_debug("stmmac_init_phy: trying to attach to %s\n",
++ phy_id_fmt);
+
+- phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface);
++ phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
++ interface);
++ }
+
+ if (IS_ERR_OR_NULL(phydev)) {
+ pr_err("%s: Could not attach to PHY\n", dev->name);
+@@ -851,7 +859,7 @@ static int stmmac_init_phy(struct net_de
+ * device as well.
+ * Note: phydev->phy_id is the result of reading the UID PHY registers.
+ */
+- if (phydev->phy_id == 0) {
++ if (!priv->plat->phy_node && phydev->phy_id == 0) {
+ phy_disconnect(phydev);
+ return -ENODEV;
+ }
+@@ -978,13 +986,11 @@ static int stmmac_init_rx_buffers(struct
+ {
+ struct sk_buff *skb;
+
+- skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
+- flags);
++ skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);
+ if (!skb) {
+ pr_err("%s: Rx init fails; skb is NULL\n", __func__);
+ return -ENOMEM;
+ }
+- skb_reserve(skb, NET_IP_ALIGN);
+ priv->rx_skbuff[i] = skb;
+ priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
+ priv->dma_buf_sz,
+@@ -2803,16 +2809,15 @@ static int stmmac_hw_init(struct stmmac_
+ * stmmac_dvr_probe
+ * @device: device pointer
+ * @plat_dat: platform data pointer
+- * @addr: iobase memory address
++ * @res: stmmac resource pointer
+ * Description: this is the main probe function used to
+ * call the alloc_etherdev, allocate the priv structure.
+ * Return:
+- * on success the new private structure is returned, otherwise the error
+- * pointer.
++ * returns 0 on success, otherwise errno.
+ */
+-struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+- struct plat_stmmacenet_data *plat_dat,
+- void __iomem *addr)
++int stmmac_dvr_probe(struct device *device,
++ struct plat_stmmacenet_data *plat_dat,
++ struct stmmac_resources *res)
+ {
+ int ret = 0;
+ struct net_device *ndev = NULL;
+@@ -2820,7 +2825,7 @@ struct stmmac_priv *stmmac_dvr_probe(str
+
+ ndev = alloc_etherdev(sizeof(struct stmmac_priv));
+ if (!ndev)
+- return ERR_PTR(-ENOMEM);
++ return -ENOMEM;
+
+ SET_NETDEV_DEV(ndev, device);
+
+@@ -2831,8 +2836,17 @@ struct stmmac_priv *stmmac_dvr_probe(str
+ stmmac_set_ethtool_ops(ndev);
+ priv->pause = pause;
+ priv->plat = plat_dat;
+- priv->ioaddr = addr;
+- priv->dev->base_addr = (unsigned long)addr;
++ priv->ioaddr = res->addr;
++ priv->dev->base_addr = (unsigned long)res->addr;
++
++ priv->dev->irq = res->irq;
++ priv->wol_irq = res->wol_irq;
++ priv->lpi_irq = res->lpi_irq;
++
++ if (res->mac)
++ memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
++
++ dev_set_drvdata(device, priv->dev);
+
+ /* Verify driver arguments */
+ stmmac_verify_args();
+@@ -2947,7 +2961,7 @@ struct stmmac_priv *stmmac_dvr_probe(str
+ }
+ }
+
+- return priv;
++ return 0;
+
+ error_mdio_register:
+ unregister_netdev(ndev);
+@@ -2960,7 +2974,7 @@ error_pclk_get:
+ error_clk_get:
+ free_netdev(ndev);
+
+- return ERR_PTR(ret);
++ return ret;
+ }
+ EXPORT_SYMBOL_GPL(stmmac_dvr_probe);
+
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+@@ -161,11 +161,16 @@ int stmmac_mdio_reset(struct mii_bus *bu
+
+ if (!gpio_request(reset_gpio, "mdio-reset")) {
+ gpio_direction_output(reset_gpio, active_low ? 1 : 0);
+- udelay(data->delays[0]);
++ if (data->delays[0])
++ msleep(DIV_ROUND_UP(data->delays[0], 1000));
++
+ gpio_set_value(reset_gpio, active_low ? 0 : 1);
+- udelay(data->delays[1]);
++ if (data->delays[1])
++ msleep(DIV_ROUND_UP(data->delays[1], 1000));
++
+ gpio_set_value(reset_gpio, active_low ? 1 : 0);
+- udelay(data->delays[2]);
++ if (data->delays[2])
++ msleep(DIV_ROUND_UP(data->delays[2], 1000));
+ }
+ }
+ #endif
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -163,7 +163,7 @@ static int stmmac_pci_probe(struct pci_d
+ {
+ struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
+ struct plat_stmmacenet_data *plat;
+- struct stmmac_priv *priv;
++ struct stmmac_resources res;
+ int i;
+ int ret;
+
+@@ -214,19 +214,12 @@ static int stmmac_pci_probe(struct pci_d
+
+ pci_enable_msi(pdev);
+
+- priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]);
+- if (IS_ERR(priv)) {
+- dev_err(&pdev->dev, "%s: main driver probe failed\n", __func__);
+- return PTR_ERR(priv);
+- }
+- priv->dev->irq = pdev->irq;
+- priv->wol_irq = pdev->irq;
+-
+- pci_set_drvdata(pdev, priv->dev);
+-
+- dev_dbg(&pdev->dev, "STMMAC PCI driver registration completed\n");
++ memset(&res, 0, sizeof(res));
++ res.addr = pcim_iomap_table(pdev)[i];
++ res.wol_irq = pdev->irq;
++ res.irq = pdev->irq;
+
+- return 0;
++ return stmmac_dvr_probe(&pdev->dev, plat, &res);
+ }
+
+ /**
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -28,29 +28,11 @@
+ #include <linux/of.h>
+ #include <linux/of_net.h>
+ #include <linux/of_device.h>
++#include <linux/of_mdio.h>
+
+ #include "stmmac.h"
+ #include "stmmac_platform.h"
+
+-static const struct of_device_id stmmac_dt_ids[] = {
+- /* SoC specific glue layers should come before generic bindings */
+- { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data},
+- { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
+- { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
+- { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
+- { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
+- { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
+- { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
+- { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
+- { .compatible = "st,spear600-gmac"},
+- { .compatible = "snps,dwmac-3.610"},
+- { .compatible = "snps,dwmac-3.70a"},
+- { .compatible = "snps,dwmac-3.710"},
+- { .compatible = "snps,dwmac"},
+- { /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
+-
+ #ifdef CONFIG_OF
+
+ /**
+@@ -122,37 +104,16 @@ static int dwmac1000_validate_ucast_entr
+ * this function is to read the driver parameters from device-tree and
+ * set some private fields that will be used by the main at runtime.
+ */
+-static int stmmac_probe_config_dt(struct platform_device *pdev,
+- struct plat_stmmacenet_data *plat,
+- const char **mac)
++struct plat_stmmacenet_data *
++stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+ {
+ struct device_node *np = pdev->dev.of_node;
++ struct plat_stmmacenet_data *plat;
+ struct stmmac_dma_cfg *dma_cfg;
+- const struct of_device_id *device;
+-
+- if (!np)
+- return -ENODEV;
+
+- device = of_match_device(stmmac_dt_ids, &pdev->dev);
+- if (!device)
+- return -ENODEV;
+-
+- if (device->data) {
+- const struct stmmac_of_data *data = device->data;
+- plat->has_gmac = data->has_gmac;
+- plat->enh_desc = data->enh_desc;
+- plat->tx_coe = data->tx_coe;
+- plat->rx_coe = data->rx_coe;
+- plat->bugged_jumbo = data->bugged_jumbo;
+- plat->pmt = data->pmt;
+- plat->riwt_off = data->riwt_off;
+- plat->fix_mac_speed = data->fix_mac_speed;
+- plat->bus_setup = data->bus_setup;
+- plat->setup = data->setup;
+- plat->free = data->free;
+- plat->init = data->init;
+- plat->exit = data->exit;
+- }
++ plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
++ if (!plat)
++ return ERR_PTR(-ENOMEM);
+
+ *mac = of_get_mac_address(np);
+ plat->interface = of_get_phy_mode(np);
+@@ -168,13 +129,24 @@ static int stmmac_probe_config_dt(struct
+ /* Default to phy auto-detection */
+ plat->phy_addr = -1;
+
++ /* If we find a phy-handle property, use it as the PHY */
++ plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
++
++ /* If phy-handle is not specified, check if we have a fixed-phy */
++ if (!plat->phy_node && of_phy_is_fixed_link(np)) {
++ if ((of_phy_register_fixed_link(np) < 0))
++ return ERR_PTR(-ENODEV);
++
++ plat->phy_node = of_node_get(np);
++ }
++
+ /* "snps,phy-addr" is not a standard property. Mark it as deprecated
+ * and warn of its use. Remove this when phy node support is added.
+ */
+ if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
+ dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
+
+- if (plat->phy_bus_name)
++ if (plat->phy_node || plat->phy_bus_name)
+ plat->mdio_bus_data = NULL;
+ else
+ plat->mdio_bus_data =
+@@ -194,6 +166,12 @@ static int stmmac_probe_config_dt(struct
+ */
+ plat->maxmtu = JUMBO_LEN;
+
++ /* Set default value for multicast hash bins */
++ plat->multicast_filter_bins = HASH_TABLE_SIZE;
++
++ /* Set default value for unicast filter entries */
++ plat->unicast_filter_entries = 1;
++
+ /*
+ * Currently only the properties needed on SPEAr600
+ * are provided. All other properties should be added
+@@ -232,8 +210,10 @@ static int stmmac_probe_config_dt(struct
+ if (of_find_property(np, "snps,pbl", NULL)) {
+ dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
+ GFP_KERNEL);
+- if (!dma_cfg)
+- return -ENOMEM;
++ if (!dma_cfg) {
++ of_node_put(np);
++ return ERR_PTR(-ENOMEM);
++ }
+ plat->dma_cfg = dma_cfg;
+ of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+ dma_cfg->fixed_burst =
+@@ -250,45 +230,34 @@ static int stmmac_probe_config_dt(struct
+ pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
+ }
+
+- return 0;
++ return plat;
+ }
+ #else
+-static int stmmac_probe_config_dt(struct platform_device *pdev,
+- struct plat_stmmacenet_data *plat,
+- const char **mac)
++struct plat_stmmacenet_data *
++stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+ {
+- return -ENOSYS;
++ return ERR_PTR(-ENOSYS);
+ }
+ #endif /* CONFIG_OF */
++EXPORT_SYMBOL_GPL(stmmac_probe_config_dt);
+
+-/**
+- * stmmac_pltfr_probe - platform driver probe.
+- * @pdev: platform device pointer
+- * Description: platform_device probe function. It is to allocate
+- * the necessary platform resources, invoke custom helper (if required) and
+- * invoke the main probe function.
+- */
+-static int stmmac_pltfr_probe(struct platform_device *pdev)
++int stmmac_get_platform_resources(struct platform_device *pdev,
++ struct stmmac_resources *stmmac_res)
+ {
+- int ret = 0;
+ struct resource *res;
+- struct device *dev = &pdev->dev;
+- void __iomem *addr = NULL;
+- struct stmmac_priv *priv = NULL;
+- struct plat_stmmacenet_data *plat_dat = NULL;
+- const char *mac = NULL;
+- int irq, wol_irq, lpi_irq;
++
++ memset(stmmac_res, 0, sizeof(*stmmac_res));
+
+ /* Get IRQ information early to have an ability to ask for deferred
+ * probe if needed before we went too far with resource allocation.
+ */
+- irq = platform_get_irq_byname(pdev, "macirq");
+- if (irq < 0) {
+- if (irq != -EPROBE_DEFER) {
+- dev_err(dev,
++ stmmac_res->irq = platform_get_irq_byname(pdev, "macirq");
++ if (stmmac_res->irq < 0) {
++ if (stmmac_res->irq != -EPROBE_DEFER) {
++ dev_err(&pdev->dev,
+ "MAC IRQ configuration information not found\n");
+ }
+- return irq;
++ return stmmac_res->irq;
+ }
+
+ /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
+@@ -298,82 +267,23 @@ static int stmmac_pltfr_probe(struct pla
+ * In case the wake up interrupt is not passed from the platform
+ * so the driver will continue to use the mac irq (ndev->irq)
+ */
+- wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+- if (wol_irq < 0) {
+- if (wol_irq == -EPROBE_DEFER)
++ stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
++ if (stmmac_res->wol_irq < 0) {
++ if (stmmac_res->wol_irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+- wol_irq = irq;
++ stmmac_res->wol_irq = stmmac_res->irq;
+ }
+
+- lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
+- if (lpi_irq == -EPROBE_DEFER)
++ stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
++ if (stmmac_res->lpi_irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- addr = devm_ioremap_resource(dev, res);
+- if (IS_ERR(addr))
+- return PTR_ERR(addr);
+-
+- plat_dat = dev_get_platdata(&pdev->dev);
+-
+- if (!plat_dat)
+- plat_dat = devm_kzalloc(&pdev->dev,
+- sizeof(struct plat_stmmacenet_data),
+- GFP_KERNEL);
+- if (!plat_dat) {
+- pr_err("%s: ERROR: no memory", __func__);
+- return -ENOMEM;
+- }
+-
+- /* Set default value for multicast hash bins */
+- plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
++ stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
+
+- /* Set default value for unicast filter entries */
+- plat_dat->unicast_filter_entries = 1;
+-
+- if (pdev->dev.of_node) {
+- ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
+- if (ret) {
+- pr_err("%s: main dt probe failed", __func__);
+- return ret;
+- }
+- }
+-
+- /* Custom setup (if needed) */
+- if (plat_dat->setup) {
+- plat_dat->bsp_priv = plat_dat->setup(pdev);
+- if (IS_ERR(plat_dat->bsp_priv))
+- return PTR_ERR(plat_dat->bsp_priv);
+- }
+-
+- /* Custom initialisation (if needed)*/
+- if (plat_dat->init) {
+- ret = plat_dat->init(pdev, plat_dat->bsp_priv);
+- if (unlikely(ret))
+- return ret;
+- }
+-
+- priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
+- if (IS_ERR(priv)) {
+- pr_err("%s: main driver probe failed", __func__);
+- return PTR_ERR(priv);
+- }
+-
+- /* Copy IRQ values to priv structure which is now avaialble */
+- priv->dev->irq = irq;
+- priv->wol_irq = wol_irq;
+- priv->lpi_irq = lpi_irq;
+-
+- /* Get MAC address if available (DT) */
+- if (mac)
+- memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
+-
+- platform_set_drvdata(pdev, priv->dev);
+-
+- pr_debug("STMMAC platform driver registration completed");
+-
+- return 0;
++ return PTR_ERR_OR_ZERO(stmmac_res->addr);
+ }
++EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
+
+ /**
+ * stmmac_pltfr_remove
+@@ -381,7 +291,7 @@ static int stmmac_pltfr_probe(struct pla
+ * Description: this function calls the main to free the net resources
+ * and calls the platforms hook and release the resources (e.g. mem).
+ */
+-static int stmmac_pltfr_remove(struct platform_device *pdev)
++int stmmac_pltfr_remove(struct platform_device *pdev)
+ {
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct stmmac_priv *priv = netdev_priv(ndev);
+@@ -390,11 +300,9 @@ static int stmmac_pltfr_remove(struct pl
+ if (priv->plat->exit)
+ priv->plat->exit(pdev, priv->plat->bsp_priv);
+
+- if (priv->plat->free)
+- priv->plat->free(pdev, priv->plat->bsp_priv);
+-
+ return ret;
+ }
++EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
+
+ #ifdef CONFIG_PM_SLEEP
+ /**
+@@ -438,21 +346,10 @@ static int stmmac_pltfr_resume(struct de
+ }
+ #endif /* CONFIG_PM_SLEEP */
+
+-static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops,
+- stmmac_pltfr_suspend, stmmac_pltfr_resume);
+-
+-static struct platform_driver stmmac_pltfr_driver = {
+- .probe = stmmac_pltfr_probe,
+- .remove = stmmac_pltfr_remove,
+- .driver = {
+- .name = STMMAC_RESOURCE_NAME,
+- .pm = &stmmac_pltfr_pm_ops,
+- .of_match_table = of_match_ptr(stmmac_dt_ids),
+- },
+-};
+-
+-module_platform_driver(stmmac_pltfr_driver);
++SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
++ stmmac_pltfr_resume);
++EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
+
+-MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
++MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
+ MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+ MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+@@ -19,11 +19,15 @@
+ #ifndef __STMMAC_PLATFORM_H__
+ #define __STMMAC_PLATFORM_H__
+
+-extern const struct stmmac_of_data meson6_dwmac_data;
+-extern const struct stmmac_of_data sun7i_gmac_data;
+-extern const struct stmmac_of_data stih4xx_dwmac_data;
+-extern const struct stmmac_of_data stid127_dwmac_data;
+-extern const struct stmmac_of_data socfpga_gmac_data;
+-extern const struct stmmac_of_data rk3288_gmac_data;
++#include "stmmac.h"
++
++struct plat_stmmacenet_data *
++stmmac_probe_config_dt(struct platform_device *pdev, const char **mac);
++
++int stmmac_get_platform_resources(struct platform_device *pdev,
++ struct stmmac_resources *stmmac_res);
++
++int stmmac_pltfr_remove(struct platform_device *pdev);
++extern const struct dev_pm_ops stmmac_pltfr_pm_ops;
+
+ #endif /* __STMMAC_PLATFORM_H__ */
+--- a/include/linux/stmmac.h
++++ b/include/linux/stmmac.h
+@@ -99,6 +99,7 @@ struct plat_stmmacenet_data {
+ int phy_addr;
+ int interface;
+ struct stmmac_mdio_bus_data *mdio_bus_data;
++ struct device_node *phy_node;
+ struct stmmac_dma_cfg *dma_cfg;
+ int clk_csr;
+ int has_gmac;
+@@ -118,30 +119,8 @@ struct plat_stmmacenet_data {
+ int rx_fifo_size;
+ void (*fix_mac_speed)(void *priv, unsigned int speed);
+ void (*bus_setup)(void __iomem *ioaddr);
+- void *(*setup)(struct platform_device *pdev);
+- void (*free)(struct platform_device *pdev, void *priv);
+ int (*init)(struct platform_device *pdev, void *priv);
+ void (*exit)(struct platform_device *pdev, void *priv);
+- void *custom_cfg;
+- void *custom_data;
+ void *bsp_priv;
+ };
+-
+-/* of_data for SoC glue layer device tree bindings */
+-
+-struct stmmac_of_data {
+- int has_gmac;
+- int enh_desc;
+- int tx_coe;
+- int rx_coe;
+- int bugged_jumbo;
+- int pmt;
+- int riwt_off;
+- void (*fix_mac_speed)(void *priv, unsigned int speed);
+- void (*bus_setup)(void __iomem *ioaddr);
+- void *(*setup)(struct platform_device *pdev);
+- void (*free)(struct platform_device *pdev, void *priv);
+- int (*init)(struct platform_device *pdev, void *priv);
+- void (*exit)(struct platform_device *pdev, void *priv);
+-};
+ #endif