Browse Source

ipq806x: update stmmac to the version from linux 4.3

Signed-off-by: Felix Fietkau <[email protected]>

SVN-Revision: 47593
Felix Fietkau 10 years ago
parent
commit
3789b1f5a0
17 changed files with 6664 additions and 1621 deletions
  1. 9 3
      target/linux/ipq806x/config-3.18
  2. 10 1
      target/linux/ipq806x/config-4.1
  3. 0 105
      target/linux/ipq806x/patches-3.18/701-stmmac-add-phy-handle-support-to-the-platform-layer.patch
  4. 4258 0
      target/linux/ipq806x/patches-3.18/701-stmmac_update_to_4.3.patch
  5. 0 65
      target/linux/ipq806x/patches-3.18/702-stmmac-move-error-path-at-the-end-of-stmmac_probe_co.patch
  6. 0 64
      target/linux/ipq806x/patches-3.18/703-stmmac-add-fixed-link-device-tree-support.patch
  7. 0 427
      target/linux/ipq806x/patches-3.18/704-stmmac-add-ipq806x-glue-layer.patch
  8. 0 52
      target/linux/ipq806x/patches-3.18/705-net-stmmac-ipq806x-document-device-tree-bindings.patch
  9. 0 171
      target/linux/ipq806x/patches-3.18/706-net-stmmac-create-one-debugfs-dir-per-net-device.patch
  10. 16 20
      target/linux/ipq806x/patches-3.18/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch
  11. 0 105
      target/linux/ipq806x/patches-4.1/701-stmmac-add-phy-handle-support-to-the-platform-layer.patch
  12. 2355 0
      target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch
  13. 0 65
      target/linux/ipq806x/patches-4.1/702-stmmac-move-error-path-at-the-end-of-stmmac_probe_co.patch
  14. 0 64
      target/linux/ipq806x/patches-4.1/703-stmmac-add-fixed-link-device-tree-support.patch
  15. 0 407
      target/linux/ipq806x/patches-4.1/704-stmmac-add-ipq806x-glue-layer.patch
  16. 0 52
      target/linux/ipq806x/patches-4.1/705-net-stmmac-ipq806x-document-device-tree-bindings.patch
  17. 16 20
      target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch

+ 9 - 3
target/linux/ipq806x/config-3.18

@@ -106,8 +106,10 @@ CONFIG_CRC32_SLICEBY8=y
 CONFIG_CROSS_MEMORY_ATTACH=y
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_RNG2=y
 # CONFIG_CRYPTO_SHA1_ARM_NEON is not set
 # CONFIG_CRYPTO_SHA512_ARM_NEON is not set
+CONFIG_CRYPTO_WORKQUEUE=y
 CONFIG_CRYPTO_XZ=y
 CONFIG_DCACHE_WORD_ACCESS=y
 CONFIG_DEBUG_BUGVERBOSE=y
@@ -123,7 +125,14 @@ CONFIG_DMA_ENGINE=y
 CONFIG_DMA_OF=y
 CONFIG_DMA_VIRTUAL_CHANNELS=y
 CONFIG_DTC=y
+# CONFIG_DWMAC_GENERIC is not set
 CONFIG_DWMAC_IPQ806X=y
+# CONFIG_DWMAC_LPC18XX is not set
+# CONFIG_DWMAC_MESON is not set
+# CONFIG_DWMAC_ROCKCHIP is not set
+# CONFIG_DWMAC_SOCFPGA is not set
+# CONFIG_DWMAC_STI is not set
+# CONFIG_DWMAC_SUNXI is not set
 # CONFIG_DW_DMAC_CORE is not set
 # CONFIG_DW_DMAC_PCI is not set
 CONFIG_DYNAMIC_DEBUG=y
@@ -234,7 +243,6 @@ CONFIG_KRAITCC=y
 CONFIG_KRAIT_CLOCKS=y
 CONFIG_KRAIT_L2_ACCESSORS=y
 # CONFIG_LEDS_REGULATOR is not set
-CONFIG_LEDS_TRIGGER_IDE_DISK=y
 CONFIG_LIBFDT=y
 CONFIG_LOCKUP_DETECTOR=y
 CONFIG_LZO_COMPRESS=y
@@ -387,8 +395,6 @@ CONFIG_SPI_MASTER=y
 CONFIG_SPI_QUP=y
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB=y
-# CONFIG_STMMAC_DA is not set
-CONFIG_STMMAC_DEBUG_FS=y
 CONFIG_STMMAC_ETH=y
 CONFIG_STMMAC_PLATFORM=y
 CONFIG_STOP_MACHINE=y

+ 10 - 1
target/linux/ipq806x/config-4.1

@@ -112,6 +112,8 @@ CONFIG_CRC32_SLICEBY8=y
 CONFIG_CROSS_MEMORY_ATTACH=y
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
 CONFIG_CRYPTO_XZ=y
 CONFIG_DCACHE_WORD_ACCESS=y
 CONFIG_DEBUG_BUGVERBOSE=y
@@ -127,6 +129,14 @@ CONFIG_DMA_ENGINE=y
 CONFIG_DMA_OF=y
 CONFIG_DMA_VIRTUAL_CHANNELS=y
 CONFIG_DTC=y
+# CONFIG_DWMAC_GENERIC is not set
+CONFIG_DWMAC_IPQ806X=y
+# CONFIG_DWMAC_LPC18XX is not set
+# CONFIG_DWMAC_MESON is not set
+# CONFIG_DWMAC_ROCKCHIP is not set
+# CONFIG_DWMAC_SOCFPGA is not set
+# CONFIG_DWMAC_STI is not set
+# CONFIG_DWMAC_SUNXI is not set
 # CONFIG_DW_DMAC_PCI is not set
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_ETHERNET_PACKET_MANGLE=y
@@ -241,7 +251,6 @@ CONFIG_KPSS_XCC=y
 CONFIG_KRAITCC=y
 CONFIG_KRAIT_CLOCKS=y
 CONFIG_KRAIT_L2_ACCESSORS=y
-CONFIG_LEDS_TRIGGER_IDE_DISK=y
 CONFIG_LIBFDT=y
 CONFIG_LOCKUP_DETECTOR=y
 CONFIG_LOCK_SPIN_ON_OWNER=y

+ 0 - 105
target/linux/ipq806x/patches-3.18/701-stmmac-add-phy-handle-support-to-the-platform-layer.patch

@@ -1,105 +0,0 @@
-From 4f09499bc1d9bb095caccbcd73ff951ee631e521 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 15:42:40 -0700
-Subject: [PATCH 1/8] stmmac: add phy-handle support to the platform layer
-
-On stmmac driver, PHY specification in device-tree was done using the
-non-standard property "snps,phy-addr". Specifying a PHY on a different
-MDIO bus that the one within the stmmac controller doesn't seem to be
-possible when device-tree is used.
-
-This change adds support for the phy-handle property, as specified in
-Documentation/devicetree/bindings/net/ethernet.txt.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 28 ++++++++++++++--------
- .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |  6 ++++-
- include/linux/stmmac.h                             |  1 +
- 3 files changed, 24 insertions(+), 11 deletions(-)
-
---- 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)
- 
-@@ -818,18 +819,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);
--
--	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);
-+	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);
- 
--	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(phydev)) {
- 		pr_err("%s: Could not attach to PHY\n", dev->name);
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -27,6 +27,7 @@
- #include <linux/of.h>
- #include <linux/of_net.h>
- #include <linux/of_device.h>
-+#include <linux/of_mdio.h>
- #include "stmmac.h"
- 
- static const struct of_device_id stmmac_dt_ids[] = {
-@@ -155,13 +156,16 @@ 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);
-+
- 	/* "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 =
---- 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;

+ 4258 - 0
target/linux/ipq806x/patches-3.18/701-stmmac_update_to_4.3.patch

@@ -0,0 +1,4258 @@
+--- 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;
+@@ -114,32 +115,12 @@ struct plat_stmmacenet_data {
+ 	int maxmtu;
+ 	int multicast_filter_bins;
+ 	int unicast_filter_entries;
++	int tx_fifo_size;
++	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
+--- 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
+@@ -14,21 +14,54 @@ config STMMAC_ETH
+ if STMMAC_ETH
+ 
+ config STMMAC_PLATFORM
+-	bool "STMMAC Platform bus support"
++	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 device driver. This is the driver used
+-	  on many embedded STM platforms based on ARM and SuperH
+-	  processors.
++	  This selects the platform specific bus support for the stmmac driver.
++	  This is the driver used on several SoCs:
++	  STi, Allwinner, Amlogic Meson, Altera SOCFPGA.
++
+ 	  If you have a controller with this interface, say Y or M here.
+ 
+ 	  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
+-	bool "Amlogic Meson dwmac support"
+-	depends on STMMAC_PLATFORM && ARCH_MESON
++	tristate "Amlogic Meson dwmac support"
++	default ARCH_MESON
++	depends on OF
+ 	help
+ 	  Support for Ethernet controller on Amlogic Meson SoCs.
+ 
+@@ -36,9 +69,22 @@ config DWMAC_MESON
+ 	  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
+-	bool "SOCFPGA dwmac support"
+-	depends on STMMAC_PLATFORM && MFD_SYSCON && (ARCH_SOCFPGA || COMPILE_TEST)
++	tristate "SOCFPGA dwmac support"
++	default ARCH_SOCFPGA
++	depends on OF
++	select MFD_SYSCON
+ 	help
+ 	  Support for ethernet controller on Altera SOCFPGA
+ 
+@@ -46,21 +92,11 @@ config DWMAC_SOCFPGA
+ 	  for the stmmac device driver. This driver is used for
+ 	  arria5 and cyclone5 FPGA SoCs.
+ 
+-config DWMAC_SUNXI
+-	bool "Allwinner GMAC support"
+-	depends on STMMAC_PLATFORM && ARCH_SUNXI
+-	default y
+-	---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.
+-
+ config DWMAC_STI
+-	bool "STi GMAC support"
+-	depends on STMMAC_PLATFORM && ARCH_STI
+-	default y
++	tristate "STi GMAC support"
++	default ARCH_STI
++	depends on OF
++	select MFD_SYSCON
+ 	---help---
+ 	  Support for ethernet controller on STi SOCs.
+ 
+@@ -68,8 +104,20 @@ config DWMAC_STI
+ 	  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
+-	bool "STMMAC PCI bus support"
++	tristate "STMMAC PCI bus support"
+ 	depends on STMMAC_ETH && PCI
+ 	---help---
+ 	  This is to select the Synopsys DWMAC available on PCI devices,
+@@ -79,22 +127,4 @@ config STMMAC_PCI
+ 	  D1215994A VIRTEX FPGA board.
+ 
+ 	  If unsure, say N.
+-
+-config STMMAC_DEBUG_FS
+-	bool "Enable monitoring via sysFS "
+-	default n
+-	depends on STMMAC_ETH && DEBUG_FS
+-	---help---
+-	  The stmmac entry in /sys reports DMA TX/RX rings
+-	  or (if supported) the HW cap register.
+-
+-config STMMAC_DA
+-	bool "STMMAC DMA arbitration scheme"
+-	default n
+-	---help---
+-	  Selecting this option, rx has priority over Tx (only for Giga
+-	  Ethernet device).
+-	  By default, the DMA arbitration scheme is based on Round-robin
+-	  (rx:tx priority is 1:1).
+-
+ endif
+--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
+@@ -1,11 +1,20 @@
+ obj-$(CONFIG_STMMAC_ETH) += stmmac.o
+-stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
+-stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
+-stmmac-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
+-stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
+-stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o
+-stmmac-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
+ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
+-	      chain_mode.o dwmac_lib.o dwmac1000_core.o  dwmac1000_dma.o \
+-	      dwmac100_core.o dwmac100_dma.o enh_desc.o  norm_desc.o \
++	      chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o	\
++	      dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o	\
+ 	      mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
++
++# 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
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -44,6 +44,7 @@
+ #undef FRAME_FILTER_DEBUG
+ /* #define FRAME_FILTER_DEBUG */
+ 
++/* Extra statistic and debug information exposed by ethtool */
+ struct stmmac_extra_stats {
+ 	/* Transmit errors */
+ 	unsigned long tx_underflow ____cacheline_aligned;
+@@ -149,7 +150,7 @@ struct stmmac_extra_stats {
+ #define	MAC_CSR_H_FRQ_MASK	0x20
+ 
+ #define HASH_TABLE_SIZE 64
+-#define PAUSE_TIME 0x200
++#define PAUSE_TIME 0xffff
+ 
+ /* Flow Control defines */
+ #define FLOW_OFF	0
+@@ -220,6 +221,7 @@ enum dma_irq_status {
+ 	handle_tx = 0x8,
+ };
+ 
++/* EEE and LPI defines */
+ #define	CORE_IRQ_TX_PATH_IN_LPI_MODE	(1 << 0)
+ #define	CORE_IRQ_TX_PATH_EXIT_LPI_MODE	(1 << 1)
+ #define	CORE_IRQ_RX_PATH_IN_LPI_MODE	(1 << 2)
+@@ -229,6 +231,7 @@ enum dma_irq_status {
+ #define	CORE_PCS_LINK_STATUS		(1 << 6)
+ #define	CORE_RGMII_IRQ			(1 << 7)
+ 
++/* Physical Coding Sublayer */
+ struct rgmii_adv {
+ 	unsigned int pause;
+ 	unsigned int duplex;
+@@ -294,6 +297,7 @@ struct dma_features {
+ 
+ #define JUMBO_LEN		9000
+ 
++/* Descriptors helpers */
+ struct stmmac_desc_ops {
+ 	/* DMA RX descriptor ring initialization */
+ 	void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode,
+@@ -341,6 +345,10 @@ struct stmmac_desc_ops {
+ 	int (*get_rx_timestamp_status) (void *desc, u32 ats);
+ };
+ 
++extern const struct stmmac_desc_ops enh_desc_ops;
++extern const struct stmmac_desc_ops ndesc_ops;
++
++/* Specific DMA helpers */
+ struct stmmac_dma_ops {
+ 	/* DMA core initialization */
+ 	int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
+@@ -349,7 +357,8 @@ struct stmmac_dma_ops {
+ 	void (*dump_regs) (void __iomem *ioaddr);
+ 	/* Set tx/rx threshold in the csr6 register
+ 	 * An invalid value enables the store-and-forward mode */
+-	void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode);
++	void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
++			 int rxfifosz);
+ 	/* To track extra statistic (if supported) */
+ 	void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
+ 				   void __iomem *ioaddr);
+@@ -370,6 +379,7 @@ struct stmmac_dma_ops {
+ 
+ struct mac_device_info;
+ 
++/* Helpers to program the MAC core */
+ struct stmmac_ops {
+ 	/* MAC core initialization */
+ 	void (*core_init)(struct mac_device_info *hw, int mtu);
+@@ -400,6 +410,7 @@ struct stmmac_ops {
+ 	void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv);
+ };
+ 
++/* PTP and HW Timer helpers */
+ struct stmmac_hwtimestamp {
+ 	void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
+ 	void (*config_sub_second_increment) (void __iomem *ioaddr);
+@@ -410,6 +421,8 @@ struct stmmac_hwtimestamp {
+ 	 u64(*get_systime) (void __iomem *ioaddr);
+ };
+ 
++extern const struct stmmac_hwtimestamp stmmac_ptp;
++
+ struct mac_link {
+ 	int port;
+ 	int duplex;
+@@ -421,6 +434,7 @@ struct mii_regs {
+ 	unsigned int data;	/* MII Data */
+ };
+ 
++/* Helpers to manage the descriptors for chain and ring modes */
+ struct stmmac_mode_ops {
+ 	void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
+ 		      unsigned int extend_desc);
+--- /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 <[email protected]>
++ *
++ * 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 <[email protected]>");
++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 <[email protected]>
++ *
++ * 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 <[email protected]>");
++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,9 +15,12 @@
+ #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>
+ 
++#include "stmmac_platform.h"
++
+ #define ETHMAC_SPEED_100	BIT(1)
+ 
+ struct meson_dwmac {
+@@ -44,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 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 <[email protected]>");
++MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -0,0 +1,626 @@
++/**
++ * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
++ *
++ * Copyright (C) 2014 Chen-Zhi (Roger Chen)
++ *
++ * Chen-Zhi (Roger Chen)  <[email protected]>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that 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.
++ */
++
++#include <linux/stmmac.h>
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#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;
++
++	struct clk *clk_mac;
++	struct clk *gmac_clkin;
++	struct clk *mac_clk_rx;
++	struct clk *mac_clk_tx;
++	struct clk *clk_mac_ref;
++	struct clk *clk_mac_refout;
++	struct clk *aclk_mac;
++	struct clk *pclk_mac;
++
++	int tx_delay;
++	int rx_delay;
++
++	struct regmap *grf;
++};
++
++#define HIWORD_UPDATE(val, mask, shift) \
++		((val) << (shift) | (mask) << ((shift) + 16))
++
++#define GRF_BIT(nr)	(BIT(nr) | BIT(nr+16))
++#define GRF_CLR_BIT(nr)	(BIT(nr+16))
++
++#define RK3288_GRF_SOC_CON1	0x0248
++#define RK3288_GRF_SOC_CON3	0x0250
++
++/*RK3288_GRF_SOC_CON1*/
++#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 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 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, "Missing rockchip,grf property\n");
++		return;
++	}
++
++	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
++		     RK3288_GMAC_PHY_INTF_SEL_RGMII |
++		     RK3288_GMAC_RMII_MODE_CLR);
++	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
++		     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 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, "Missing rockchip,grf property\n");
++		return;
++	}
++
++	regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
++		     RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE);
++}
++
++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, "Missing rockchip,grf property\n");
++		return;
++	}
++
++	if (speed == 10)
++		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,
++			     RK3288_GMAC_CLK_25M);
++	else if (speed == 1000)
++		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 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, "Missing rockchip,grf property\n");
++		return;
++	}
++
++	if (speed == 10) {
++		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
++			     RK3288_GMAC_RMII_CLK_2_5M |
++			     RK3288_GMAC_SPEED_10M);
++	} else if (speed == 100) {
++		regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
++			     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;
++
++	bsp_priv->clk_enabled = false;
++
++	bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx");
++	if (IS_ERR(bsp_priv->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, "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, "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, "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, "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, "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, "cannot get clock %s\n",
++					"clk_mac_refout");
++		}
++	}
++
++	if (bsp_priv->clock_input) {
++		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);
++	}
++
++	return 0;
++}
++
++static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
++{
++	int phy_iface = phy_iface = bsp_priv->phy_iface;
++
++	if (enable) {
++		if (!bsp_priv->clk_enabled) {
++			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
++				if (!IS_ERR(bsp_priv->mac_clk_rx))
++					clk_prepare_enable(
++						bsp_priv->mac_clk_rx);
++
++				if (!IS_ERR(bsp_priv->clk_mac_ref))
++					clk_prepare_enable(
++						bsp_priv->clk_mac_ref);
++
++				if (!IS_ERR(bsp_priv->clk_mac_refout))
++					clk_prepare_enable(
++						bsp_priv->clk_mac_refout);
++			}
++
++			if (!IS_ERR(bsp_priv->aclk_mac))
++				clk_prepare_enable(bsp_priv->aclk_mac);
++
++			if (!IS_ERR(bsp_priv->pclk_mac))
++				clk_prepare_enable(bsp_priv->pclk_mac);
++
++			if (!IS_ERR(bsp_priv->mac_clk_tx))
++				clk_prepare_enable(bsp_priv->mac_clk_tx);
++
++			/**
++			 * if (!IS_ERR(bsp_priv->clk_mac))
++			 *	clk_prepare_enable(bsp_priv->clk_mac);
++			 */
++			mdelay(5);
++			bsp_priv->clk_enabled = true;
++		}
++	} else {
++		if (bsp_priv->clk_enabled) {
++			if (phy_iface == PHY_INTERFACE_MODE_RMII) {
++				if (!IS_ERR(bsp_priv->mac_clk_rx))
++					clk_disable_unprepare(
++						bsp_priv->mac_clk_rx);
++
++				if (!IS_ERR(bsp_priv->clk_mac_ref))
++					clk_disable_unprepare(
++						bsp_priv->clk_mac_ref);
++
++				if (!IS_ERR(bsp_priv->clk_mac_refout))
++					clk_disable_unprepare(
++						bsp_priv->clk_mac_refout);
++			}
++
++			if (!IS_ERR(bsp_priv->aclk_mac))
++				clk_disable_unprepare(bsp_priv->aclk_mac);
++
++			if (!IS_ERR(bsp_priv->pclk_mac))
++				clk_disable_unprepare(bsp_priv->pclk_mac);
++
++			if (!IS_ERR(bsp_priv->mac_clk_tx))
++				clk_disable_unprepare(bsp_priv->mac_clk_tx);
++			/**
++			 * if (!IS_ERR(bsp_priv->clk_mac))
++			 *	clk_disable_unprepare(bsp_priv->clk_mac);
++			 */
++			bsp_priv->clk_enabled = false;
++		}
++	}
++
++	return 0;
++}
++
++static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
++{
++	struct regulator *ldo = bsp_priv->regulator;
++	int ret;
++	struct device *dev = &bsp_priv->pdev->dev;
++
++	if (!ldo) {
++		dev_err(dev, "no regulator found\n");
++		return -1;
++	}
++
++	if (enable) {
++		ret = regulator_enable(ldo);
++		if (ret)
++			dev_err(dev, "fail to enable phy-supply\n");
++	} else {
++		ret = regulator_disable(ldo);
++		if (ret)
++			dev_err(dev, "fail to disable phy-supply\n");
++	}
++
++	return 0;
++}
++
++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;
++	int ret;
++	const char *strings = NULL;
++	int value;
++
++	bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
++	if (!bsp_priv)
++		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)) {
++		if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) {
++			dev_err(dev, "phy regulator is not available yet, deferred probing\n");
++			return ERR_PTR(-EPROBE_DEFER);
++		}
++		dev_err(dev, "no regulator found\n");
++		bsp_priv->regulator = NULL;
++	}
++
++	ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
++	if (ret) {
++		dev_err(dev, "Can not read property: clock_in_out.\n");
++		bsp_priv->clock_input = true;
++	} else {
++		dev_info(dev, "clock input or output? (%s).\n",
++			 strings);
++		if (!strcmp(strings, "input"))
++			bsp_priv->clock_input = true;
++		else
++			bsp_priv->clock_input = false;
++	}
++
++	ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
++	if (ret) {
++		bsp_priv->tx_delay = 0x30;
++		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, "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, "Can not read property: rx_delay.");
++		dev_err(dev, "set rx_delay to 0x%x\n",
++			bsp_priv->rx_delay);
++	} else {
++		dev_info(dev, "RX delay(0x%x).\n", value);
++		bsp_priv->rx_delay = value;
++	}
++
++	bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
++							"rockchip,grf");
++	bsp_priv->pdev = pdev;
++
++	/*rmii or rgmii*/
++	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
++		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, "init for RMII\n");
++		bsp_priv->ops->set_to_rmii(bsp_priv);
++	} else {
++		dev_err(dev, "NO interface defined!\n");
++	}
++
++	gmac_clk_init(bsp_priv);
++
++	return bsp_priv;
++}
++
++static int rk_gmac_init(struct platform_device *pdev, void *priv)
++{
++	struct rk_priv_data *bsp_priv = priv;
++	int ret;
++
++	ret = phy_power_on(bsp_priv, true);
++	if (ret)
++		return ret;
++
++	ret = gmac_clk_enable(bsp_priv, true);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static void rk_gmac_exit(struct platform_device *pdev, void *priv)
++{
++	struct rk_priv_data *gmac = priv;
++
++	phy_power_on(gmac, false);
++	gmac_clk_enable(gmac, false);
++}
++
++static void rk_fix_speed(void *priv, unsigned int speed)
++{
++	struct rk_priv_data *bsp_priv = priv;
++	struct device *dev = &bsp_priv->pdev->dev;
++
++	if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
++		bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
++	else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
++		bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
++	else
++		dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
++}
++
++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) <[email protected]>");
++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
+@@ -23,7 +23,9 @@
+ #include <linux/regmap.h>
+ #include <linux/reset.h>
+ #include <linux/stmmac.h>
++
+ #include "stmmac.h"
++#include "stmmac_platform.h"
+ 
+ #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
+ #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
+@@ -89,7 +91,9 @@ static int socfpga_dwmac_parse_data(stru
+ 						  STMMAC_RESOURCE_NAME);
+ 	if (IS_ERR(dwmac->stmmac_rst)) {
+ 		dev_info(dev, "Could not get reset control!\n");
+-		return -EINVAL;
++		if (PTR_ERR(dwmac->stmmac_rst) == -EPROBE_DEFER)
++			return -EPROBE_DEFER;
++		dwmac->stmmac_rst = NULL;
+ 	}
+ 
+ 	dwmac->interface = of_get_phy_mode(np);
+@@ -171,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;
+@@ -253,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
+@@ -1,4 +1,4 @@
+-/**
++/*
+  * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer
+  *
+  * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
+@@ -17,11 +17,15 @@
+ #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"
++
+ #define DWMAC_125MHZ	125000000
+ #define DWMAC_50MHZ	50000000
+ #define DWMAC_25MHZ	25000000
+@@ -35,9 +39,8 @@
+ #define IS_PHY_IF_MODE_GBIT(iface)	(IS_PHY_IF_MODE_RGMII(iface) || \
+ 					 iface == PHY_INTERFACE_MODE_GMII)
+ 
+-/* STiH4xx register definitions (STiH415/STiH416/STiH407/STiH410 families) */
+-
+-/**
++/* STiH4xx register definitions (STiH415/STiH416/STiH407/STiH410 families)
++ *
+  * Below table summarizes the clock requirement and clock sources for
+  * supported phy interface modes with link speeds.
+  * ________________________________________________
+@@ -76,9 +79,7 @@
+ #define STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK	BIT(7)
+ #define STIH4XX_ETH_SEL_TXCLK_NOT_CLK125	BIT(6)
+ 
+-/* STiD127 register definitions */
+-
+-/**
++/* STiD127 register definitions
+  *-----------------------
+  * src	 |BIT(6)| BIT(7)|
+  *-----------------------
+@@ -104,13 +105,13 @@
+ #define EN_MASK		GENMASK(1, 1)
+ #define EN		BIT(1)
+ 
+-/**
++/*
+  * 3 bits [4:2]
+  *	000-GMII/MII
+  *	001-RGMII
+  *	010-SGMII
+  *	100-RMII
+-*/
++ */
+ #define MII_PHY_SEL_MASK	GENMASK(4, 2)
+ #define ETH_PHY_SEL_RMII	BIT(4)
+ #define ETH_PHY_SEL_SGMII	BIT(3)
+@@ -123,11 +124,16 @@ struct sti_dwmac {
+ 	bool ext_phyclk;	/* Clock from external PHY */
+ 	u32 tx_retime_src;	/* TXCLK Retiming*/
+ 	struct clk *clk;	/* PHY clock */
+-	int ctrl_reg;		/* GMAC glue-logic control register */
++	u32 ctrl_reg;		/* GMAC glue-logic control register */
+ 	int clk_sel_reg;	/* GMAC ext clk selection register */
+ 	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[] = {
+@@ -222,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;
+@@ -241,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;
+ }
+@@ -286,11 +273,6 @@ static int sti_dwmac_parse_data(struct s
+ 	if (!np)
+ 		return -EINVAL;
+ 
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf");
+-	if (!res)
+-		return -ENODATA;
+-	dwmac->ctrl_reg = res->start;
+-
+ 	/* clk selection from extra syscfg register */
+ 	dwmac->clk_sel_reg = -ENXIO;
+ 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf");
+@@ -301,6 +283,12 @@ static int sti_dwmac_parse_data(struct s
+ 	if (IS_ERR(regmap))
+ 		return PTR_ERR(regmap);
+ 
++	err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->ctrl_reg);
++	if (err) {
++		dev_err(dev, "Can't get sysconfig ctrl offset (%d)\n", err);
++		return err;
++	}
++
+ 	dwmac->dev = dev;
+ 	dwmac->interface = of_get_phy_mode(np);
+ 	dwmac->regmap = regmap;
+@@ -310,16 +298,16 @@ static int sti_dwmac_parse_data(struct s
+ 
+ 	if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
+ 		const char *rs;
+-		dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
+ 
+ 		err = of_property_read_string(np, "st,tx-retime-src", &rs);
+-		if (err < 0)
++		if (err < 0) {
+ 			dev_warn(dev, "Use internal clock source\n");
+-
+-		if (!strcasecmp(rs, "clk_125"))
++			dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
++		} else if (!strcasecmp(rs, "clk_125")) {
+ 			dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
+-		else if (!strcasecmp(rs, "txclk"))
++		} else if (!strcasecmp(rs, "txclk")) {
+ 			dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
++		}
+ 
+ 		dwmac->speed = SPEED_1000;
+ 	}
+@@ -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,
+ };
+ 
+-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 sti_dwmac_of_data stid127_dwmac_data = {
++	.fix_retime_src = stid127_fix_retime_src,
+ };
++
++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 <[email protected]>");
++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
+@@ -1,4 +1,4 @@
+-/**
++/*
+  * dwmac-sunxi.c - Allwinner sunxi DWMAC specific glue layer
+  *
+  * Copyright (C) 2013 Chen-Yu Tsai
+@@ -18,10 +18,14 @@
+ 
+ #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>
+ 
++#include "stmmac_platform.h"
++
+ struct sunxi_priv_data {
+ 	int interface;
+ 	int clk_enabled;
+@@ -29,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
+ 
+@@ -128,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 <[email protected]>");
++MODULE_DESCRIPTION("Allwinner sunxi DWMAC specific glue layer");
++MODULE_LICENSE("GPL");
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+@@ -172,6 +172,7 @@ enum inter_frame_gap {
+ /* GMAC FLOW CTRL defines */
+ #define GMAC_FLOW_CTRL_PT_MASK	0xffff0000	/* Pause Time Mask */
+ #define GMAC_FLOW_CTRL_PT_SHIFT	16
++#define GMAC_FLOW_CTRL_UP	0x00000008	/* Unicast pause frame enable */
+ #define GMAC_FLOW_CTRL_RFE	0x00000004	/* Rx Flow Control Enable */
+ #define GMAC_FLOW_CTRL_TFE	0x00000002	/* Tx Flow Control Enable */
+ #define GMAC_FLOW_CTRL_FCB_BPA	0x00000001	/* Flow Control Busy ... */
+@@ -246,6 +247,56 @@ enum ttc_control {
+ #define DMA_CONTROL_FEF		0x00000080
+ #define DMA_CONTROL_FUF		0x00000040
+ 
++/* Receive flow control activation field
++ * RFA field in DMA control register, bits 23,10:9
++ */
++#define DMA_CONTROL_RFA_MASK	0x00800600
++
++/* Receive flow control deactivation field
++ * RFD field in DMA control register, bits 22,12:11
++ */
++#define DMA_CONTROL_RFD_MASK	0x00401800
++
++/* RFD and RFA fields are encoded as follows
++ *
++ *   Bit Field
++ *   0,00 - Full minus 1KB (only valid when rxfifo >= 4KB and EFC enabled)
++ *   0,01 - Full minus 2KB (only valid when rxfifo >= 4KB and EFC enabled)
++ *   0,10 - Full minus 3KB (only valid when rxfifo >= 4KB and EFC enabled)
++ *   0,11 - Full minus 4KB (only valid when rxfifo > 4KB and EFC enabled)
++ *   1,00 - Full minus 5KB (only valid when rxfifo > 8KB and EFC enabled)
++ *   1,01 - Full minus 6KB (only valid when rxfifo > 8KB and EFC enabled)
++ *   1,10 - Full minus 7KB (only valid when rxfifo > 8KB and EFC enabled)
++ *   1,11 - Reserved
++ *
++ * RFD should always be > RFA for a given FIFO size. RFD == RFA may work,
++ * but packet throughput performance may not be as expected.
++ *
++ * Be sure that bit 3 in GMAC Register 6 is set for Unicast Pause frame
++ * detection (IEEE Specification Requirement, Annex 31B, 31B.1, Pause
++ * Description).
++ *
++ * Be sure that DZPA (bit 7 in Flow Control Register, GMAC Register 6),
++ * is set to 0. This allows pause frames with a quanta of 0 to be sent
++ * as an XOFF message to the link peer.
++ */
++
++#define RFA_FULL_MINUS_1K	0x00000000
++#define RFA_FULL_MINUS_2K	0x00000200
++#define RFA_FULL_MINUS_3K	0x00000400
++#define RFA_FULL_MINUS_4K	0x00000600
++#define RFA_FULL_MINUS_5K	0x00800000
++#define RFA_FULL_MINUS_6K	0x00800200
++#define RFA_FULL_MINUS_7K	0x00800400
++
++#define RFD_FULL_MINUS_1K	0x00000000
++#define RFD_FULL_MINUS_2K	0x00000800
++#define RFD_FULL_MINUS_3K	0x00001000
++#define RFD_FULL_MINUS_4K	0x00001800
++#define RFD_FULL_MINUS_5K	0x00400000
++#define RFD_FULL_MINUS_6K	0x00400800
++#define RFD_FULL_MINUS_7K	0x00401000
++
+ enum rtc_control {
+ 	DMA_CONTROL_RTC_64 = 0x00000000,
+ 	DMA_CONTROL_RTC_32 = 0x00000008,
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+@@ -201,7 +201,10 @@ static void dwmac1000_flow_ctrl(struct m
+ 				unsigned int fc, unsigned int pause_time)
+ {
+ 	void __iomem *ioaddr = hw->pcsr;
+-	unsigned int flow = 0;
++	/* Set flow such that DZPQ in Mac Register 6 is 0,
++	 * and unicast pause detect is enabled.
++	 */
++	unsigned int flow = GMAC_FLOW_CTRL_UP;
+ 
+ 	pr_debug("GMAC Flow-Control:\n");
+ 	if (fc & FLOW_RX) {
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+@@ -70,10 +70,6 @@ static int dwmac1000_dma_init(void __iom
+ 	if (mb)
+ 		value |= DMA_BUS_MODE_MB;
+ 
+-#ifdef CONFIG_STMMAC_DA
+-	value |= DMA_BUS_MODE_DA;	/* Rx has priority over tx */
+-#endif
+-
+ 	if (atds)
+ 		value |= DMA_BUS_MODE_ATDS;
+ 
+@@ -110,8 +106,29 @@ static int dwmac1000_dma_init(void __iom
+ 	return 0;
+ }
+ 
++static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
++{
++	csr6 &= ~DMA_CONTROL_RFA_MASK;
++	csr6 &= ~DMA_CONTROL_RFD_MASK;
++
++	/* Leave flow control disabled if receive fifo size is less than
++	 * 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
++	 * and send XON when 2K less than full.
++	 */
++	if (rxfifosz < 4096) {
++		csr6 &= ~DMA_CONTROL_EFC;
++		pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
++			 rxfifosz);
++	} else {
++		csr6 |= DMA_CONTROL_EFC;
++		csr6 |= RFA_FULL_MINUS_1K;
++		csr6 |= RFD_FULL_MINUS_2K;
++	}
++	return csr6;
++}
++
+ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
+-					 int rxmode)
++					 int rxmode, int rxfifosz)
+ {
+ 	u32 csr6 = readl(ioaddr + DMA_CONTROL);
+ 
+@@ -157,6 +174,9 @@ static void dwmac1000_dma_operation_mode
+ 			csr6 |= DMA_CONTROL_RTC_128;
+ 	}
+ 
++	/* Configure flow control based on rx fifo size */
++	csr6 = dwmac1000_configure_fc(csr6, rxfifosz);
++
+ 	writel(csr6, ioaddr + DMA_CONTROL);
+ }
+ 
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+@@ -72,7 +72,7 @@ static int dwmac100_dma_init(void __iome
+  * control register.
+  */
+ static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode,
+-					int rxmode)
++					int rxmode, int rxfifosz)
+ {
+ 	u32 csr6 = readl(ioaddr + DMA_CONTROL);
+ 
+--- 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;
+@@ -97,6 +105,7 @@ struct stmmac_priv {
+ 	int wolopts;
+ 	int wol_irq;
+ 	struct clk *stmmac_clk;
++	struct clk *pclk;
+ 	struct reset_control *stmmac_rst;
+ 	int clk_csr;
+ 	struct timer_list eee_ctrl_timer;
+@@ -116,97 +125,28 @@ struct stmmac_priv {
+ 	int use_riwt;
+ 	int irq_wake;
+ 	spinlock_t ptp_lock;
++
++#ifdef CONFIG_DEBUG_FS
++	struct dentry *dbgfs_dir;
++	struct dentry *dbgfs_rings_status;
++	struct dentry *dbgfs_dma_cap;
++#endif
+ };
+ 
+ int stmmac_mdio_unregister(struct net_device *ndev);
+ int stmmac_mdio_register(struct net_device *ndev);
+ int stmmac_mdio_reset(struct mii_bus *mii);
+ void stmmac_set_ethtool_ops(struct net_device *netdev);
+-extern const struct stmmac_desc_ops enh_desc_ops;
+-extern const struct stmmac_desc_ops ndesc_ops;
+-extern const struct stmmac_hwtimestamp stmmac_ptp;
++
+ int stmmac_ptp_register(struct stmmac_priv *priv);
+ void stmmac_ptp_unregister(struct stmmac_priv *priv);
+ 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);
+ 
+-#ifdef CONFIG_STMMAC_PLATFORM
+-#ifdef CONFIG_DWMAC_MESON
+-extern const struct stmmac_of_data meson6_dwmac_data;
+-#endif
+-#ifdef CONFIG_DWMAC_SUNXI
+-extern const struct stmmac_of_data sun7i_gmac_data;
+-#endif
+-#ifdef CONFIG_DWMAC_STI
+-extern const struct stmmac_of_data stih4xx_dwmac_data;
+-extern const struct stmmac_of_data stid127_dwmac_data;
+-#endif
+-#ifdef CONFIG_DWMAC_SOCFPGA
+-extern const struct stmmac_of_data socfpga_gmac_data;
+-#endif
+-extern struct platform_driver stmmac_pltfr_driver;
+-static inline int stmmac_register_platform(void)
+-{
+-	int err;
+-
+-	err = platform_driver_register(&stmmac_pltfr_driver);
+-	if (err)
+-		pr_err("stmmac: failed to register the platform driver\n");
+-
+-	return err;
+-}
+-
+-static inline void stmmac_unregister_platform(void)
+-{
+-	platform_driver_unregister(&stmmac_pltfr_driver);
+-}
+-#else
+-static inline int stmmac_register_platform(void)
+-{
+-	pr_debug("stmmac: do not register the platf driver\n");
+-
+-	return 0;
+-}
+-
+-static inline void stmmac_unregister_platform(void)
+-{
+-}
+-#endif /* CONFIG_STMMAC_PLATFORM */
+-
+-#ifdef CONFIG_STMMAC_PCI
+-extern struct pci_driver stmmac_pci_driver;
+-static inline int stmmac_register_pci(void)
+-{
+-	int err;
+-
+-	err = pci_register_driver(&stmmac_pci_driver);
+-	if (err)
+-		pr_err("stmmac: failed to register the PCI driver\n");
+-
+-	return err;
+-}
+-
+-static inline void stmmac_unregister_pci(void)
+-{
+-	pci_unregister_driver(&stmmac_pci_driver);
+-}
+-#else
+-static inline int stmmac_register_pci(void)
+-{
+-	pr_debug("stmmac: do not register the PCI driver\n");
+-
+-	return 0;
+-}
+-
+-static inline void stmmac_unregister_pci(void)
+-{
+-}
+-#endif /* CONFIG_STMMAC_PCI */
+-
+ #endif /* __STMMAC_H__ */
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+@@ -696,7 +696,7 @@ static int stmmac_set_coalesce(struct ne
+ 	    (ec->tx_max_coalesced_frames == 0))
+ 		return -EINVAL;
+ 
+-	if ((ec->tx_coalesce_usecs > STMMAC_COAL_TX_TIMER) ||
++	if ((ec->tx_coalesce_usecs > STMMAC_MAX_COAL_TX_TICK) ||
+ 	    (ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES))
+ 		return -EINVAL;
+ 
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -44,14 +44,15 @@
+ #include <linux/slab.h>
+ #include <linux/prefetch.h>
+ #include <linux/pinctrl/consumer.h>
+-#ifdef CONFIG_STMMAC_DEBUG_FS
++#ifdef CONFIG_DEBUG_FS
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
+-#endif /* CONFIG_STMMAC_DEBUG_FS */
++#endif /* CONFIG_DEBUG_FS */
+ #include <linux/net_tstamp.h>
+ #include "stmmac_ptp.h"
+ #include "stmmac.h"
+ #include <linux/reset.h>
++#include <linux/of_mdio.h>
+ 
+ #define STMMAC_ALIGN(x)	L1_CACHE_ALIGN(x)
+ 
+@@ -116,17 +117,17 @@ MODULE_PARM_DESC(chain_mode, "To use cha
+ 
+ static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+ 
+-#ifdef CONFIG_STMMAC_DEBUG_FS
++#ifdef CONFIG_DEBUG_FS
+ static int stmmac_init_fs(struct net_device *dev);
+-static void stmmac_exit_fs(void);
++static void stmmac_exit_fs(struct net_device *dev);
+ #endif
+ 
+ #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+ 
+ /**
+  * stmmac_verify_args - verify the driver parameters.
+- * Description: it verifies if some wrong parameter is passed to the driver.
+- * Note that wrong parameters are replaced with the default values.
++ * Description: it checks the driver parameters and set a default in case of
++ * errors.
+  */
+ static void stmmac_verify_args(void)
+ {
+@@ -191,14 +192,8 @@ static void stmmac_clk_csr_set(struct st
+ 
+ static void print_pkt(unsigned char *buf, int len)
+ {
+-	int j;
+-	pr_debug("len = %d byte, buf addr: 0x%p", len, buf);
+-	for (j = 0; j < len; j++) {
+-		if ((j % 16) == 0)
+-			pr_debug("\n %03x:", j);
+-		pr_debug(" %02x", buf[j]);
+-	}
+-	pr_debug("\n");
++	pr_debug("len = %d byte, buf addr: 0x%p\n", len, buf);
++	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
+ }
+ 
+ /* minimum number of free TX descriptors required to wake up TX process */
+@@ -210,7 +205,7 @@ static inline u32 stmmac_tx_avail(struct
+ }
+ 
+ /**
+- * stmmac_hw_fix_mac_speed: callback for speed selection
++ * stmmac_hw_fix_mac_speed - callback for speed selection
+  * @priv: driver private structure
+  * Description: on some platforms (e.g. ST), some HW system configuraton
+  * registers have to be set according to the link speed negotiated.
+@@ -224,9 +219,10 @@ static inline void stmmac_hw_fix_mac_spe
+ }
+ 
+ /**
+- * stmmac_enable_eee_mode: Check and enter in LPI mode
++ * stmmac_enable_eee_mode - check and enter in LPI mode
+  * @priv: driver private structure
+- * Description: this function is to verify and enter in LPI mode for EEE.
++ * Description: this function is to verify and enter in LPI mode in case of
++ * EEE.
+  */
+ static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
+ {
+@@ -237,7 +233,7 @@ static void stmmac_enable_eee_mode(struc
+ }
+ 
+ /**
+- * stmmac_disable_eee_mode: disable/exit from EEE
++ * stmmac_disable_eee_mode - disable and exit from LPI mode
+  * @priv: driver private structure
+  * Description: this function is to exit and disable EEE in case of
+  * LPI state is true. This is called by the xmit.
+@@ -250,7 +246,7 @@ void stmmac_disable_eee_mode(struct stmm
+ }
+ 
+ /**
+- * stmmac_eee_ctrl_timer: EEE TX SW timer.
++ * stmmac_eee_ctrl_timer - EEE TX SW timer.
+  * @arg : data hook
+  * Description:
+  *  if there is no data transfer and if we are not in LPI state,
+@@ -265,13 +261,12 @@ static void stmmac_eee_ctrl_timer(unsign
+ }
+ 
+ /**
+- * stmmac_eee_init: init EEE
++ * stmmac_eee_init - init EEE
+  * @priv: driver private structure
+  * Description:
+- *  If the EEE support has been enabled while configuring the driver,
+- *  if the GMAC actually supports the EEE (from the HW cap reg) and the
+- *  phy can also manage EEE, so enable the LPI state and start the timer
+- *  to verify if the tx path can enter in LPI state.
++ *  if the GMAC supports the EEE (from the HW cap reg) and the phy device
++ *  can also manage EEE, this function enable the LPI state and start related
++ *  timer.
+  */
+ bool stmmac_eee_init(struct stmmac_priv *priv)
+ {
+@@ -316,11 +311,11 @@ bool stmmac_eee_init(struct stmmac_priv
+ 		spin_lock_irqsave(&priv->lock, flags);
+ 		if (!priv->eee_active) {
+ 			priv->eee_active = 1;
+-			init_timer(&priv->eee_ctrl_timer);
+-			priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
+-			priv->eee_ctrl_timer.data = (unsigned long)priv;
+-			priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer);
+-			add_timer(&priv->eee_ctrl_timer);
++			setup_timer(&priv->eee_ctrl_timer,
++				    stmmac_eee_ctrl_timer,
++				    (unsigned long)priv);
++			mod_timer(&priv->eee_ctrl_timer,
++				  STMMAC_LPI_T(eee_timer));
+ 
+ 			priv->hw->mac->set_eee_timer(priv->hw,
+ 						     STMMAC_DEFAULT_LIT_LS,
+@@ -338,7 +333,7 @@ out:
+ 	return ret;
+ }
+ 
+-/* stmmac_get_tx_hwtstamp: get HW TX timestamps
++/* stmmac_get_tx_hwtstamp - get HW TX timestamps
+  * @priv: driver private structure
+  * @entry : descriptor index to be used.
+  * @skb : the socket buffer
+@@ -380,7 +375,7 @@ static void stmmac_get_tx_hwtstamp(struc
+ 	return;
+ }
+ 
+-/* stmmac_get_rx_hwtstamp: get HW RX timestamps
++/* stmmac_get_rx_hwtstamp - get HW RX timestamps
+  * @priv: driver private structure
+  * @entry : descriptor index to be used.
+  * @skb : the socket buffer
+@@ -615,7 +610,7 @@ static int stmmac_hwtstamp_ioctl(struct
+ 		 * where, freq_div_ratio = clk_ptp_ref_i/50MHz
+ 		 * hence, addend = ((2^32) * 50MHz)/clk_ptp_ref_i;
+ 		 * NOTE: clk_ptp_ref_i should be >= 50MHz to
+-		 *       achive 20ns accuracy.
++		 *       achieve 20ns accuracy.
+ 		 *
+ 		 * 2^x * y == (y << x), hence
+ 		 * 2^32 * 50000000 ==> (50000000 << 32)
+@@ -636,11 +631,11 @@ static int stmmac_hwtstamp_ioctl(struct
+ }
+ 
+ /**
+- * stmmac_init_ptp: init PTP
++ * stmmac_init_ptp - init PTP
+  * @priv: driver private structure
+- * Description: this is to verify if the HW supports the PTPv1 or v2.
++ * Description: this is to verify if the HW supports the PTPv1 or PTPv2.
+  * This is done by looking at the HW cap. register.
+- * Also it registers the ptp driver.
++ * This function also registers the ptp driver.
+  */
+ static int stmmac_init_ptp(struct stmmac_priv *priv)
+ {
+@@ -682,9 +677,13 @@ static void stmmac_release_ptp(struct st
+ }
+ 
+ /**
+- * stmmac_adjust_link
++ * stmmac_adjust_link - adjusts the link parameters
+  * @dev: net device structure
+- * Description: it adjusts the link parameters.
++ * Description: this is the helper called by the physical abstraction layer
++ * drivers to communicate the phy link status. According the speed and duplex
++ * this driver can invoke registered glue-logic as well.
++ * It also invoke the eee initialization because it could happen when switch
++ * on different networks (that are eee capable).
+  */
+ static void stmmac_adjust_link(struct net_device *dev)
+ {
+@@ -774,7 +773,7 @@ static void stmmac_adjust_link(struct ne
+ }
+ 
+ /**
+- * stmmac_check_pcs_mode: verify if RGMII/SGMII is supported
++ * stmmac_check_pcs_mode - verify if RGMII/SGMII is supported
+  * @priv: driver private structure
+  * Description: this is to verify if the HW supports the PCS.
+  * Physical Coding Sublayer (PCS) interface that can be used when the MAC is
+@@ -818,21 +817,31 @@ 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(phydev)) {
++	if (IS_ERR_OR_NULL(phydev)) {
+ 		pr_err("%s: Could not attach to PHY\n", dev->name);
++		if (!phydev)
++			return -ENODEV;
++
+ 		return PTR_ERR(phydev);
+ 	}
+ 
+@@ -850,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;
+ 	}
+@@ -863,7 +872,7 @@ static int stmmac_init_phy(struct net_de
+ }
+ 
+ /**
+- * stmmac_display_ring: display ring
++ * stmmac_display_ring - display ring
+  * @head: pointer to the head of the ring passed.
+  * @size: size of the ring.
+  * @extend_desc: to verify if extended descriptors are used.
+@@ -931,7 +940,7 @@ static int stmmac_set_bfsize(int mtu, in
+ }
+ 
+ /**
+- * stmmac_clear_descriptors: clear descriptors
++ * stmmac_clear_descriptors - clear descriptors
+  * @priv: driver private structure
+  * Description: this function is called to clear the tx and rx descriptors
+  * in case of both basic and extended descriptors are used.
+@@ -963,18 +972,25 @@ static void stmmac_clear_descriptors(str
+ 						     (i == txsize - 1));
+ }
+ 
++/**
++ * stmmac_init_rx_buffers - init the RX descriptor buffer.
++ * @priv: driver private structure
++ * @p: descriptor pointer
++ * @i: descriptor index
++ * @flags: gfp flag.
++ * Description: this function is called to allocate a receive buffer, perform
++ * the DMA mapping and init the descriptor.
++ */
+ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
+ 				  int i, gfp_t flags)
+ {
+ 	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,
+@@ -1007,7 +1023,8 @@ static void stmmac_free_rx_buffers(struc
+ /**
+  * init_dma_desc_rings - init the RX/TX descriptor rings
+  * @dev: net device structure
+- * Description:  this function initializes the DMA RX/TX descriptors
++ * @flags: gfp flag.
++ * Description: this function initializes the DMA RX/TX descriptors
+  * and allocates the socket buffers. It suppors the chained and ring
+  * modes.
+  */
+@@ -1089,6 +1106,7 @@ static int init_dma_desc_rings(struct ne
+ 
+ 	priv->dirty_tx = 0;
+ 	priv->cur_tx = 0;
++	netdev_reset_queue(priv->dev);
+ 
+ 	stmmac_clear_descriptors(priv);
+ 
+@@ -1144,6 +1162,14 @@ static void dma_free_tx_skbufs(struct st
+ 	}
+ }
+ 
++/**
++ * alloc_dma_desc_resources - alloc TX/RX resources.
++ * @priv: private structure
++ * Description: according to which descriptor can be used (extend or basic)
++ * this function allocates the resources for TX and RX paths. In case of
++ * reception, for example, it pre-allocated the RX socket buffer in order to
++ * allow zero-copy mechanism.
++ */
+ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
+ {
+ 	unsigned int txsize = priv->dma_tx_size;
+@@ -1255,13 +1281,15 @@ static void free_dma_desc_resources(stru
+ /**
+  *  stmmac_dma_operation_mode - HW DMA operation mode
+  *  @priv: driver private structure
+- *  Description: it sets the DMA operation mode: tx/rx DMA thresholds
+- *  or Store-And-Forward capability.
++ *  Description: it is used for configuring the DMA operation mode register in
++ *  order to program the tx/rx DMA thresholds or Store-And-Forward mode.
+  */
+ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
+ {
++	int rxfifosz = priv->plat->rx_fifo_size;
++
+ 	if (priv->plat->force_thresh_dma_mode)
+-		priv->hw->dma->dma_mode(priv->ioaddr, tc, tc);
++		priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, rxfifosz);
+ 	else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
+ 		/*
+ 		 * In case of GMAC, SF mode can be enabled
+@@ -1270,20 +1298,23 @@ static void stmmac_dma_operation_mode(st
+ 		 * 2) There is no bugged Jumbo frame support
+ 		 *    that needs to not insert csum in the TDES.
+ 		 */
+-		priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE);
+-		tc = SF_DMA_MODE;
++		priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE,
++					rxfifosz);
++		priv->xstats.threshold = SF_DMA_MODE;
+ 	} else
+-		priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
++		priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE,
++					rxfifosz);
+ }
+ 
+ /**
+- * stmmac_tx_clean:
++ * stmmac_tx_clean - to manage the transmission completion
+  * @priv: driver private structure
+- * Description: it reclaims resources after transmission completes.
++ * Description: it reclaims the transmit resources after transmission completes.
+  */
+ static void stmmac_tx_clean(struct stmmac_priv *priv)
+ {
+ 	unsigned int txsize = priv->dma_tx_size;
++	unsigned int bytes_compl = 0, pkts_compl = 0;
+ 
+ 	spin_lock(&priv->tx_lock);
+ 
+@@ -1340,6 +1371,8 @@ static void stmmac_tx_clean(struct stmma
+ 		priv->hw->mode->clean_desc3(priv, p);
+ 
+ 		if (likely(skb != NULL)) {
++			pkts_compl++;
++			bytes_compl += skb->len;
+ 			dev_consume_skb_any(skb);
+ 			priv->tx_skbuff[entry] = NULL;
+ 		}
+@@ -1348,6 +1381,9 @@ static void stmmac_tx_clean(struct stmma
+ 
+ 		priv->dirty_tx++;
+ 	}
++
++	netdev_completed_queue(priv->dev, pkts_compl, bytes_compl);
++
+ 	if (unlikely(netif_queue_stopped(priv->dev) &&
+ 		     stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
+ 		netif_tx_lock(priv->dev);
+@@ -1378,10 +1414,10 @@ static inline void stmmac_disable_dma_ir
+ }
+ 
+ /**
+- * stmmac_tx_err: irq tx error mng function
++ * stmmac_tx_err - to manage the tx error
+  * @priv: driver private structure
+  * Description: it cleans the descriptors and restarts the transmission
+- * in case of errors.
++ * in case of transmission errors.
+  */
+ static void stmmac_tx_err(struct stmmac_priv *priv)
+ {
+@@ -1402,6 +1438,7 @@ static void stmmac_tx_err(struct stmmac_
+ 						     (i == txsize - 1));
+ 	priv->dirty_tx = 0;
+ 	priv->cur_tx = 0;
++	netdev_reset_queue(priv->dev);
+ 	priv->hw->dma->start_tx(priv->ioaddr);
+ 
+ 	priv->dev->stats.tx_errors++;
+@@ -1409,16 +1446,16 @@ static void stmmac_tx_err(struct stmmac_
+ }
+ 
+ /**
+- * stmmac_dma_interrupt: DMA ISR
++ * stmmac_dma_interrupt - DMA ISR
+  * @priv: driver private structure
+  * Description: this is the DMA ISR. It is called by the main ISR.
+- * It calls the dwmac dma routine to understand which type of interrupt
+- * happened. In case of there is a Normal interrupt and either TX or RX
+- * interrupt happened so the NAPI is scheduled.
++ * It calls the dwmac dma routine and schedule poll method in case of some
++ * work can be done.
+  */
+ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
+ {
+ 	int status;
++	int rxfifosz = priv->plat->rx_fifo_size;
+ 
+ 	status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
+ 	if (likely((status & handle_rx)) || (status & handle_tx)) {
+@@ -1429,9 +1466,15 @@ static void stmmac_dma_interrupt(struct
+ 	}
+ 	if (unlikely(status & tx_hard_error_bump_tc)) {
+ 		/* Try to bump up the dma threshold on this failure */
+-		if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
++		if (unlikely(priv->xstats.threshold != SF_DMA_MODE) &&
++		    (tc <= 256)) {
+ 			tc += 64;
+-			priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
++			if (priv->plat->force_thresh_dma_mode)
++				priv->hw->dma->dma_mode(priv->ioaddr, tc, tc,
++							rxfifosz);
++			else
++				priv->hw->dma->dma_mode(priv->ioaddr, tc,
++							SF_DMA_MODE, rxfifosz);
+ 			priv->xstats.threshold = tc;
+ 		}
+ 	} else if (unlikely(status == tx_hard_error))
+@@ -1457,6 +1500,12 @@ static void stmmac_mmc_setup(struct stmm
+ 		pr_info(" No MAC Management Counters available\n");
+ }
+ 
++/**
++ * stmmac_get_synopsys_id - return the SYINID.
++ * @priv: driver private structure
++ * Description: this simple function is to decode and return the SYINID
++ * starting from the HW core register.
++ */
+ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
+ {
+ 	u32 hwid = priv->hw->synopsys_uid;
+@@ -1475,11 +1524,11 @@ static u32 stmmac_get_synopsys_id(struct
+ }
+ 
+ /**
+- * stmmac_selec_desc_mode: to select among: normal/alternate/extend descriptors
++ * stmmac_selec_desc_mode - to select among: normal/alternate/extend descriptors
+  * @priv: driver private structure
+  * Description: select the Enhanced/Alternate or Normal descriptors.
+- * In case of Enhanced/Alternate, it looks at the extended descriptors are
+- * supported by the HW cap. register.
++ * In case of Enhanced/Alternate, it checks if the extended descriptors are
++ * supported by the HW capability register.
+  */
+ static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
+ {
+@@ -1501,7 +1550,7 @@ static void stmmac_selec_desc_mode(struc
+ }
+ 
+ /**
+- * stmmac_get_hw_features: get MAC capabilities from the HW cap. register.
++ * stmmac_get_hw_features - get MAC capabilities from the HW cap. register.
+  * @priv: driver private structure
+  * Description:
+  *  new GMAC chip generations have a new register to indicate the
+@@ -1559,7 +1608,7 @@ static int stmmac_get_hw_features(struct
+ }
+ 
+ /**
+- * stmmac_check_ether_addr: check if the MAC addr is valid
++ * stmmac_check_ether_addr - check if the MAC addr is valid
+  * @priv: driver private structure
+  * Description:
+  * it is to verify if the MAC address is valid, in case of failures it
+@@ -1578,7 +1627,7 @@ static void stmmac_check_ether_addr(stru
+ }
+ 
+ /**
+- * stmmac_init_dma_engine: DMA init.
++ * stmmac_init_dma_engine - DMA init.
+  * @priv: driver private structure
+  * Description:
+  * It inits the DMA invoking the specific MAC/GMAC callback.
+@@ -1607,7 +1656,7 @@ static int stmmac_init_dma_engine(struct
+ }
+ 
+ /**
+- * stmmac_tx_timer: mitigation sw timer for tx.
++ * stmmac_tx_timer - mitigation sw timer for tx.
+  * @data: data pointer
+  * Description:
+  * This is the timer handler to directly invoke the stmmac_tx_clean.
+@@ -1620,7 +1669,7 @@ static void stmmac_tx_timer(unsigned lon
+ }
+ 
+ /**
+- * stmmac_init_tx_coalesce: init tx mitigation options.
++ * stmmac_init_tx_coalesce - init tx mitigation options.
+  * @priv: driver private structure
+  * Description:
+  * This inits the transmit coalesce parameters: i.e. timer rate,
+@@ -1639,15 +1688,18 @@ static void stmmac_init_tx_coalesce(stru
+ }
+ 
+ /**
+- * stmmac_hw_setup: setup mac in a usable state.
++ * stmmac_hw_setup - setup mac in a usable state.
+  *  @dev : pointer to the device structure.
+  *  Description:
+- *  This function sets up the ip in a usable state.
++ *  this is the main function to setup the HW in a usable state because the
++ *  dma engine is reset, the core registers are configured (e.g. AXI,
++ *  Checksum features, timers). The DMA is ready to start receiving and
++ *  transmitting.
+  *  Return value:
+  *  0 on success and an appropriate (-)ve integer as defined in errno.h
+  *  file on failure.
+  */
+-static int stmmac_hw_setup(struct net_device *dev)
++static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
+ {
+ 	struct stmmac_priv *priv = netdev_priv(dev);
+ 	int ret;
+@@ -1684,11 +1736,13 @@ static int stmmac_hw_setup(struct net_de
+ 
+ 	stmmac_mmc_setup(priv);
+ 
+-	ret = stmmac_init_ptp(priv);
+-	if (ret && ret != -EOPNOTSUPP)
+-		pr_warn("%s: failed PTP initialisation\n", __func__);
++	if (init_ptp) {
++		ret = stmmac_init_ptp(priv);
++		if (ret && ret != -EOPNOTSUPP)
++			pr_warn("%s: failed PTP initialisation\n", __func__);
++	}
+ 
+-#ifdef CONFIG_STMMAC_DEBUG_FS
++#ifdef CONFIG_DEBUG_FS
+ 	ret = stmmac_init_fs(dev);
+ 	if (ret < 0)
+ 		pr_warn("%s: failed debugFS registration\n", __func__);
+@@ -1763,7 +1817,7 @@ static int stmmac_open(struct net_device
+ 		goto init_error;
+ 	}
+ 
+-	ret = stmmac_hw_setup(dev);
++	ret = stmmac_hw_setup(dev, true);
+ 	if (ret < 0) {
+ 		pr_err("%s: Hw setup failed\n", __func__);
+ 		goto init_error;
+@@ -1870,8 +1924,8 @@ static int stmmac_release(struct net_dev
+ 
+ 	netif_carrier_off(dev);
+ 
+-#ifdef CONFIG_STMMAC_DEBUG_FS
+-	stmmac_exit_fs();
++#ifdef CONFIG_DEBUG_FS
++	stmmac_exit_fs(dev);
+ #endif
+ 
+ 	stmmac_release_ptp(priv);
+@@ -1880,7 +1934,7 @@ static int stmmac_release(struct net_dev
+ }
+ 
+ /**
+- *  stmmac_xmit: Tx entry point of the driver
++ *  stmmac_xmit - Tx entry point of the driver
+  *  @skb : the socket buffer
+  *  @dev : device pointer
+  *  Description : this is the tx entry point of the driver.
+@@ -2024,6 +2078,7 @@ static netdev_tx_t stmmac_xmit(struct sk
+ 	if (!priv->hwts_tx_en)
+ 		skb_tx_timestamp(skb);
+ 
++	netdev_sent_queue(dev, skb->len);
+ 	priv->hw->dma->enable_dma_transmission(priv->ioaddr);
+ 
+ 	spin_unlock(&priv->tx_lock);
+@@ -2055,7 +2110,7 @@ static void stmmac_rx_vlan(struct net_de
+ 
+ 
+ /**
+- * stmmac_rx_refill: refill used skb preallocated buffers
++ * stmmac_rx_refill - refill used skb preallocated buffers
+  * @priv: driver private structure
+  * Description : this is to reallocate the skb for the reception process
+  * that is based on zero-copy.
+@@ -2106,7 +2161,7 @@ static inline void stmmac_rx_refill(stru
+ }
+ 
+ /**
+- * stmmac_rx_refill: refill used skb preallocated buffers
++ * stmmac_rx - manage the receive process
+  * @priv: driver private structure
+  * @limit: napi bugget.
+  * Description :  this the function called by the napi poll method.
+@@ -2375,8 +2430,11 @@ static int stmmac_set_features(struct ne
+  *  @irq: interrupt number.
+  *  @dev_id: to pass the net device pointer.
+  *  Description: this is the main driver interrupt service routine.
+- *  It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI
+- *  interrupts.
++ *  It can call:
++ *  o DMA service routine (to manage incoming frame reception and transmission
++ *    status)
++ *  o Core interrupts to manage: remote wake-up, management counter, LPI
++ *    interrupts.
+  */
+ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+ {
+@@ -2457,10 +2515,8 @@ static int stmmac_ioctl(struct net_devic
+ 	return ret;
+ }
+ 
+-#ifdef CONFIG_STMMAC_DEBUG_FS
++#ifdef CONFIG_DEBUG_FS
+ static struct dentry *stmmac_fs_dir;
+-static struct dentry *stmmac_rings_status;
+-static struct dentry *stmmac_dma_cap;
+ 
+ static void sysfs_display_ring(void *head, int size, int extend_desc,
+ 			       struct seq_file *seq)
+@@ -2599,36 +2655,39 @@ static const struct file_operations stmm
+ 
+ static int stmmac_init_fs(struct net_device *dev)
+ {
+-	/* Create debugfs entries */
+-	stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
++	struct stmmac_priv *priv = netdev_priv(dev);
+ 
+-	if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
+-		pr_err("ERROR %s, debugfs create directory failed\n",
+-		       STMMAC_RESOURCE_NAME);
++	/* Create per netdev entries */
++	priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir);
++
++	if (!priv->dbgfs_dir || IS_ERR(priv->dbgfs_dir)) {
++		pr_err("ERROR %s/%s, debugfs create directory failed\n",
++		       STMMAC_RESOURCE_NAME, dev->name);
+ 
+ 		return -ENOMEM;
+ 	}
+ 
+ 	/* Entry to report DMA RX/TX rings */
+-	stmmac_rings_status = debugfs_create_file("descriptors_status",
+-						  S_IRUGO, stmmac_fs_dir, dev,
+-						  &stmmac_rings_status_fops);
++	priv->dbgfs_rings_status =
++		debugfs_create_file("descriptors_status", S_IRUGO,
++				    priv->dbgfs_dir, dev,
++				    &stmmac_rings_status_fops);
+ 
+-	if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) {
++	if (!priv->dbgfs_rings_status || IS_ERR(priv->dbgfs_rings_status)) {
+ 		pr_info("ERROR creating stmmac ring debugfs file\n");
+-		debugfs_remove(stmmac_fs_dir);
++		debugfs_remove_recursive(priv->dbgfs_dir);
+ 
+ 		return -ENOMEM;
+ 	}
+ 
+ 	/* Entry to report the DMA HW features */
+-	stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir,
+-					     dev, &stmmac_dma_cap_fops);
++	priv->dbgfs_dma_cap = debugfs_create_file("dma_cap", S_IRUGO,
++					    priv->dbgfs_dir,
++					    dev, &stmmac_dma_cap_fops);
+ 
+-	if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) {
++	if (!priv->dbgfs_dma_cap || IS_ERR(priv->dbgfs_dma_cap)) {
+ 		pr_info("ERROR creating stmmac MMC debugfs file\n");
+-		debugfs_remove(stmmac_rings_status);
+-		debugfs_remove(stmmac_fs_dir);
++		debugfs_remove_recursive(priv->dbgfs_dir);
+ 
+ 		return -ENOMEM;
+ 	}
+@@ -2636,13 +2695,13 @@ static int stmmac_init_fs(struct net_dev
+ 	return 0;
+ }
+ 
+-static void stmmac_exit_fs(void)
++static void stmmac_exit_fs(struct net_device *dev)
+ {
+-	debugfs_remove(stmmac_rings_status);
+-	debugfs_remove(stmmac_dma_cap);
+-	debugfs_remove(stmmac_fs_dir);
++	struct stmmac_priv *priv = netdev_priv(dev);
++
++	debugfs_remove_recursive(priv->dbgfs_dir);
+ }
+-#endif /* CONFIG_STMMAC_DEBUG_FS */
++#endif /* CONFIG_DEBUG_FS */
+ 
+ static const struct net_device_ops stmmac_netdev_ops = {
+ 	.ndo_open = stmmac_open,
+@@ -2663,11 +2722,10 @@ static const struct net_device_ops stmma
+ /**
+  *  stmmac_hw_init - Init the MAC device
+  *  @priv: driver private structure
+- *  Description: this function detects which MAC device
+- *  (GMAC/MAC10-100) has to attached, checks the HW capability
+- *  (if supported) and sets the driver's features (for example
+- *  to use the ring or chaine mode or support the normal/enh
+- *  descriptor structure).
++ *  Description: this function is to configure the MAC device according to
++ *  some platform parameters or the HW capability register. It prepares the
++ *  driver to use either ring or chain modes and to setup either enhanced or
++ *  normal descriptors.
+  */
+ static int stmmac_hw_init(struct stmmac_priv *priv)
+ {
+@@ -2714,7 +2772,11 @@ static int stmmac_hw_init(struct stmmac_
+ 		priv->plat->enh_desc = priv->dma_cap.enh_desc;
+ 		priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up;
+ 
+-		priv->plat->tx_coe = priv->dma_cap.tx_coe;
++		/* TXCOE doesn't work in thresh DMA mode */
++		if (priv->plat->force_thresh_dma_mode)
++			priv->plat->tx_coe = 0;
++		else
++			priv->plat->tx_coe = priv->dma_cap.tx_coe;
+ 
+ 		if (priv->dma_cap.rx_coe_type2)
+ 			priv->plat->rx_coe = STMMAC_RX_COE_TYPE2;
+@@ -2747,13 +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:
++ * 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;
+@@ -2761,7 +2825,7 @@ struct stmmac_priv *stmmac_dvr_probe(str
+ 
+ 	ndev = alloc_etherdev(sizeof(struct stmmac_priv));
+ 	if (!ndev)
+-		return NULL;
++		return -ENOMEM;
+ 
+ 	SET_NETDEV_DEV(ndev, device);
+ 
+@@ -2772,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();
+@@ -2800,6 +2873,16 @@ struct stmmac_priv *stmmac_dvr_probe(str
+ 	}
+ 	clk_prepare_enable(priv->stmmac_clk);
+ 
++	priv->pclk = devm_clk_get(priv->device, "pclk");
++	if (IS_ERR(priv->pclk)) {
++		if (PTR_ERR(priv->pclk) == -EPROBE_DEFER) {
++			ret = -EPROBE_DEFER;
++			goto error_pclk_get;
++		}
++		priv->pclk = NULL;
++	}
++	clk_prepare_enable(priv->pclk);
++
+ 	priv->stmmac_rst = devm_reset_control_get(priv->device,
+ 						  STMMAC_RESOURCE_NAME);
+ 	if (IS_ERR(priv->stmmac_rst)) {
+@@ -2878,19 +2961,22 @@ struct stmmac_priv *stmmac_dvr_probe(str
+ 		}
+ 	}
+ 
+-	return priv;
++	return 0;
+ 
+ error_mdio_register:
+ 	unregister_netdev(ndev);
+ error_netdev_register:
+ 	netif_napi_del(&priv->napi);
+ error_hw_init:
++	clk_disable_unprepare(priv->pclk);
++error_pclk_get:
+ 	clk_disable_unprepare(priv->stmmac_clk);
+ error_clk_get:
+ 	free_netdev(ndev);
+ 
+-	return ERR_PTR(ret);
++	return ret;
+ }
++EXPORT_SYMBOL_GPL(stmmac_dvr_probe);
+ 
+ /**
+  * stmmac_dvr_remove
+@@ -2908,20 +2994,28 @@ int stmmac_dvr_remove(struct net_device
+ 	priv->hw->dma->stop_tx(priv->ioaddr);
+ 
+ 	stmmac_set_mac(priv->ioaddr, false);
+-	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
+-	    priv->pcs != STMMAC_PCS_RTBI)
+-		stmmac_mdio_unregister(ndev);
+ 	netif_carrier_off(ndev);
+ 	unregister_netdev(ndev);
+ 	if (priv->stmmac_rst)
+ 		reset_control_assert(priv->stmmac_rst);
++	clk_disable_unprepare(priv->pclk);
+ 	clk_disable_unprepare(priv->stmmac_clk);
++	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
++	    priv->pcs != STMMAC_PCS_RTBI)
++		stmmac_mdio_unregister(ndev);
+ 	free_netdev(ndev);
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(stmmac_dvr_remove);
+ 
+-#ifdef CONFIG_PM
++/**
++ * stmmac_suspend - suspend callback
++ * @ndev: net device pointer
++ * Description: this is the function to suspend the device and it is called
++ * by the platform driver to stop the network queue, release the resources,
++ * program the PMT register (for WoL), clean and release driver resources.
++ */
+ int stmmac_suspend(struct net_device *ndev)
+ {
+ 	struct stmmac_priv *priv = netdev_priv(ndev);
+@@ -2954,6 +3048,7 @@ int stmmac_suspend(struct net_device *nd
+ 		stmmac_set_mac(priv->ioaddr, false);
+ 		pinctrl_pm_select_sleep_state(priv->device);
+ 		/* Disable clock in case of PWM is off */
++		clk_disable(priv->pclk);
+ 		clk_disable(priv->stmmac_clk);
+ 	}
+ 	spin_unlock_irqrestore(&priv->lock, flags);
+@@ -2963,7 +3058,14 @@ int stmmac_suspend(struct net_device *nd
+ 	priv->oldduplex = -1;
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(stmmac_suspend);
+ 
++/**
++ * stmmac_resume - resume callback
++ * @ndev: net device pointer
++ * Description: when resume this function is invoked to setup the DMA and CORE
++ * in a usable state.
++ */
+ int stmmac_resume(struct net_device *ndev)
+ {
+ 	struct stmmac_priv *priv = netdev_priv(ndev);
+@@ -2987,6 +3089,7 @@ int stmmac_resume(struct net_device *nde
+ 		pinctrl_pm_select_default_state(priv->device);
+ 		/* enable the clk prevously disabled */
+ 		clk_enable(priv->stmmac_clk);
++		clk_enable(priv->pclk);
+ 		/* reset the phy so that it's ready */
+ 		if (priv->mii)
+ 			stmmac_mdio_reset(priv->mii);
+@@ -2995,7 +3098,7 @@ int stmmac_resume(struct net_device *nde
+ 	netif_device_attach(ndev);
+ 
+ 	init_dma_desc_rings(ndev, GFP_ATOMIC);
+-	stmmac_hw_setup(ndev);
++	stmmac_hw_setup(ndev, false);
+ 	stmmac_init_tx_coalesce(priv);
+ 
+ 	napi_enable(&priv->napi);
+@@ -3009,37 +3112,7 @@ int stmmac_resume(struct net_device *nde
+ 
+ 	return 0;
+ }
+-#endif /* CONFIG_PM */
+-
+-/* Driver can be configured w/ and w/ both PCI and Platf drivers
+- * depending on the configuration selected.
+- */
+-static int __init stmmac_init(void)
+-{
+-	int ret;
+-
+-	ret = stmmac_register_platform();
+-	if (ret)
+-		goto err;
+-	ret = stmmac_register_pci();
+-	if (ret)
+-		goto err_pci;
+-	return 0;
+-err_pci:
+-	stmmac_unregister_platform();
+-err:
+-	pr_err("stmmac: driver registration failed\n");
+-	return ret;
+-}
+-
+-static void __exit stmmac_exit(void)
+-{
+-	stmmac_unregister_platform();
+-	stmmac_unregister_pci();
+-}
+-
+-module_init(stmmac_init);
+-module_exit(stmmac_exit);
++EXPORT_SYMBOL_GPL(stmmac_resume);
+ 
+ #ifndef MODULE
+ static int __init stmmac_cmdline_opt(char *str)
+@@ -3094,6 +3167,35 @@ err:
+ __setup("stmmaceth=", stmmac_cmdline_opt);
+ #endif /* MODULE */
+ 
++static int __init stmmac_init(void)
++{
++#ifdef CONFIG_DEBUG_FS
++	/* Create debugfs main directory if it doesn't exist yet */
++	if (!stmmac_fs_dir) {
++		stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
++
++		if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
++			pr_err("ERROR %s, debugfs create directory failed\n",
++			       STMMAC_RESOURCE_NAME);
++
++			return -ENOMEM;
++		}
++	}
++#endif
++
++	return 0;
++}
++
++static void __exit stmmac_exit(void)
++{
++#ifdef CONFIG_DEBUG_FS
++	debugfs_remove_recursive(stmmac_fs_dir);
++#endif
++}
++
++module_init(stmmac_init)
++module_exit(stmmac_exit)
++
+ MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver");
+ MODULE_AUTHOR("Giuseppe Cavallaro <[email protected]>");
+ MODULE_LICENSE("GPL");
+--- 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
+@@ -24,38 +24,128 @@
+ *******************************************************************************/
+ 
+ #include <linux/pci.h>
++#include <linux/dmi.h>
++
+ #include "stmmac.h"
+ 
+-static struct plat_stmmacenet_data plat_dat;
+-static struct stmmac_mdio_bus_data mdio_data;
+-static struct stmmac_dma_cfg dma_cfg;
+-
+-static void stmmac_default_data(void)
+-{
+-	memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data));
+-
+-	plat_dat.bus_id = 1;
+-	plat_dat.phy_addr = 0;
+-	plat_dat.interface = PHY_INTERFACE_MODE_GMII;
+-	plat_dat.clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
+-	plat_dat.has_gmac = 1;
+-	plat_dat.force_sf_dma_mode = 1;
+-
+-	mdio_data.phy_reset = NULL;
+-	mdio_data.phy_mask = 0;
+-	plat_dat.mdio_bus_data = &mdio_data;
+-
+-	dma_cfg.pbl = 32;
+-	dma_cfg.burst_len = DMA_AXI_BLEN_256;
+-	plat_dat.dma_cfg = &dma_cfg;
++/*
++ * This struct is used to associate PCI Function of MAC controller on a board,
++ * discovered via DMI, with the address of PHY connected to the MAC. The
++ * negative value of the address means that MAC controller is not connected
++ * with PHY.
++ */
++struct stmmac_pci_dmi_data {
++	const char *name;
++	unsigned int func;
++	int phy_addr;
++};
++
++struct stmmac_pci_info {
++	struct pci_dev *pdev;
++	int (*setup)(struct plat_stmmacenet_data *plat,
++		     struct stmmac_pci_info *info);
++	struct stmmac_pci_dmi_data *dmi;
++};
++
++static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info)
++{
++	const char *name = dmi_get_system_info(DMI_BOARD_NAME);
++	unsigned int func = PCI_FUNC(info->pdev->devfn);
++	struct stmmac_pci_dmi_data *dmi;
++
++	/*
++	 * Galileo boards with old firmware don't support DMI. We always return
++	 * 1 here, so at least first found MAC controller would be probed.
++	 */
++	if (!name)
++		return 1;
++
++	for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) {
++		if (!strcmp(dmi->name, name) && dmi->func == func)
++			return dmi->phy_addr;
++	}
++
++	return -ENODEV;
++}
++
++static void stmmac_default_data(struct plat_stmmacenet_data *plat)
++{
++	plat->bus_id = 1;
++	plat->phy_addr = 0;
++	plat->interface = PHY_INTERFACE_MODE_GMII;
++	plat->clk_csr = 2;	/* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
++	plat->has_gmac = 1;
++	plat->force_sf_dma_mode = 1;
++
++	plat->mdio_bus_data->phy_reset = NULL;
++	plat->mdio_bus_data->phy_mask = 0;
++
++	plat->dma_cfg->pbl = 32;
++	plat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
++
++	/* 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;
++}
++
++static int quark_default_data(struct plat_stmmacenet_data *plat,
++			      struct stmmac_pci_info *info)
++{
++	struct pci_dev *pdev = info->pdev;
++	int ret;
++
++	/*
++	 * Refuse to load the driver and register net device if MAC controller
++	 * does not connect to any PHY interface.
++	 */
++	ret = stmmac_pci_find_phy_addr(info);
++	if (ret < 0)
++		return ret;
++
++	plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
++	plat->phy_addr = ret;
++	plat->interface = PHY_INTERFACE_MODE_RMII;
++	plat->clk_csr = 2;
++	plat->has_gmac = 1;
++	plat->force_sf_dma_mode = 1;
++
++	plat->mdio_bus_data->phy_reset = NULL;
++	plat->mdio_bus_data->phy_mask = 0;
++
++	plat->dma_cfg->pbl = 16;
++	plat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
++	plat->dma_cfg->fixed_burst = 1;
+ 
+ 	/* Set default value for multicast hash bins */
+-	plat_dat.multicast_filter_bins = HASH_TABLE_SIZE;
++	plat->multicast_filter_bins = HASH_TABLE_SIZE;
+ 
+ 	/* Set default value for unicast filter entries */
+-	plat_dat.unicast_filter_entries = 1;
++	plat->unicast_filter_entries = 1;
++
++	return 0;
+ }
+ 
++static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
++	{
++		.name = "Galileo",
++		.func = 6,
++		.phy_addr = 1,
++	},
++	{
++		.name = "GalileoGen2",
++		.func = 6,
++		.phy_addr = 1,
++	},
++	{}
++};
++
++static struct stmmac_pci_info quark_pci_info = {
++	.setup = quark_default_data,
++	.dmi = quark_pci_dmi_data,
++};
++
+ /**
+  * stmmac_pci_probe
+  *
+@@ -71,64 +161,65 @@ static void stmmac_default_data(void)
+ static int stmmac_pci_probe(struct pci_dev *pdev,
+ 			    const struct pci_device_id *id)
+ {
+-	int ret = 0;
+-	void __iomem *addr = NULL;
+-	struct stmmac_priv *priv = NULL;
++	struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
++	struct plat_stmmacenet_data *plat;
++	struct stmmac_resources res;
+ 	int i;
++	int ret;
++
++	plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
++	if (!plat)
++		return -ENOMEM;
++
++	plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
++					   sizeof(*plat->mdio_bus_data),
++					   GFP_KERNEL);
++	if (!plat->mdio_bus_data)
++		return -ENOMEM;
++
++	plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg),
++				     GFP_KERNEL);
++	if (!plat->dma_cfg)
++		return -ENOMEM;
+ 
+ 	/* Enable pci device */
+-	ret = pci_enable_device(pdev);
++	ret = pcim_enable_device(pdev);
+ 	if (ret) {
+-		pr_err("%s : ERROR: failed to enable %s device\n", __func__,
+-		       pci_name(pdev));
++		dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
++			__func__);
+ 		return ret;
+ 	}
+-	if (pci_request_regions(pdev, STMMAC_RESOURCE_NAME)) {
+-		pr_err("%s: ERROR: failed to get PCI region\n", __func__);
+-		ret = -ENODEV;
+-		goto err_out_req_reg_failed;
+-	}
+ 
+ 	/* Get the base address of device */
+-	for (i = 0; i <= 5; i++) {
++	for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
+ 		if (pci_resource_len(pdev, i) == 0)
+ 			continue;
+-		addr = pci_iomap(pdev, i, 0);
+-		if (addr == NULL) {
+-			pr_err("%s: ERROR: cannot map register memory aborting",
+-			       __func__);
+-			ret = -EIO;
+-			goto err_out_map_failed;
+-		}
++		ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev));
++		if (ret)
++			return ret;
+ 		break;
+ 	}
+-	pci_set_master(pdev);
+-
+-	stmmac_default_data();
+ 
+-	priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
+-	if (IS_ERR(priv)) {
+-		pr_err("%s: main driver probe failed", __func__);
+-		ret = PTR_ERR(priv);
+-		goto err_out;
+-	}
+-	priv->dev->irq = pdev->irq;
+-	priv->wol_irq = pdev->irq;
+-
+-	pci_set_drvdata(pdev, priv->dev);
++	pci_set_master(pdev);
+ 
+-	pr_debug("STMMAC platform driver registration completed");
++	if (info) {
++		info->pdev = pdev;
++		if (info->setup) {
++			ret = info->setup(plat, info);
++			if (ret)
++				return ret;
++		}
++	} else
++		stmmac_default_data(plat);
+ 
+-	return 0;
++	pci_enable_msi(pdev);
+ 
+-err_out:
+-	pci_clear_master(pdev);
+-err_out_map_failed:
+-	pci_release_regions(pdev);
+-err_out_req_reg_failed:
+-	pci_disable_device(pdev);
++	memset(&res, 0, sizeof(res));
++	res.addr = pcim_iomap_table(pdev)[i];
++	res.wol_irq = pdev->irq;
++	res.irq = pdev->irq;
+ 
+-	return ret;
++	return stmmac_dvr_probe(&pdev->dev, plat, &res);
+ }
+ 
+ /**
+@@ -141,61 +232,55 @@ err_out_req_reg_failed:
+ static void stmmac_pci_remove(struct pci_dev *pdev)
+ {
+ 	struct net_device *ndev = pci_get_drvdata(pdev);
+-	struct stmmac_priv *priv = netdev_priv(ndev);
+ 
+ 	stmmac_dvr_remove(ndev);
+-
+-	pci_iounmap(pdev, priv->ioaddr);
+-	pci_release_regions(pdev);
+-	pci_disable_device(pdev);
+ }
+ 
+-#ifdef CONFIG_PM
+-static int stmmac_pci_suspend(struct pci_dev *pdev, pm_message_t state)
++#ifdef CONFIG_PM_SLEEP
++static int stmmac_pci_suspend(struct device *dev)
+ {
++	struct pci_dev *pdev = to_pci_dev(dev);
+ 	struct net_device *ndev = pci_get_drvdata(pdev);
+-	int ret;
+-
+-	ret = stmmac_suspend(ndev);
+-	pci_save_state(pdev);
+-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ 
+-	return ret;
++	return stmmac_suspend(ndev);
+ }
+ 
+-static int stmmac_pci_resume(struct pci_dev *pdev)
++static int stmmac_pci_resume(struct device *dev)
+ {
++	struct pci_dev *pdev = to_pci_dev(dev);
+ 	struct net_device *ndev = pci_get_drvdata(pdev);
+ 
+-	pci_set_power_state(pdev, PCI_D0);
+-	pci_restore_state(pdev);
+-
+ 	return stmmac_resume(ndev);
+ }
+ #endif
+ 
++static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume);
++
+ #define STMMAC_VENDOR_ID 0x700
++#define STMMAC_QUARK_ID  0x0937
+ #define STMMAC_DEVICE_ID 0x1108
+ 
+ static const struct pci_device_id stmmac_id_table[] = {
+ 	{PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
+ 	{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
++	{PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info},
+ 	{}
+ };
+ 
+ MODULE_DEVICE_TABLE(pci, stmmac_id_table);
+ 
+-struct pci_driver stmmac_pci_driver = {
++static struct pci_driver stmmac_pci_driver = {
+ 	.name = STMMAC_RESOURCE_NAME,
+ 	.id_table = stmmac_id_table,
+ 	.probe = stmmac_pci_probe,
+ 	.remove = stmmac_pci_remove,
+-#ifdef CONFIG_PM
+-	.suspend = stmmac_pci_suspend,
+-	.resume = stmmac_pci_resume,
+-#endif
++	.driver         = {
++		.pm     = &stmmac_pm_ops,
++	},
+ };
+ 
++module_pci_driver(stmmac_pci_driver);
++
+ MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
+ MODULE_AUTHOR("Rayagond Kokatanur <[email protected]>");
+ MODULE_AUTHOR("Giuseppe Cavallaro <[email protected]>");
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -23,41 +23,23 @@
+ *******************************************************************************/
+ 
+ #include <linux/platform_device.h>
++#include <linux/module.h>
+ #include <linux/io.h>
+ #include <linux/of.h>
+ #include <linux/of_net.h>
+ #include <linux/of_device.h>
+-#include "stmmac.h"
++#include <linux/of_mdio.h>
+ 
+-static const struct of_device_id stmmac_dt_ids[] = {
+-#ifdef CONFIG_DWMAC_MESON
+-	{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
+-#endif
+-#ifdef CONFIG_DWMAC_SUNXI
+-	{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
+-#endif
+-#ifdef CONFIG_DWMAC_STI
+-	{ .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},
+-#endif
+-#ifdef CONFIG_DWMAC_SOCFPGA
+-	{ .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
+-#endif
+-	/* SoC specific glue layers should come before generic bindings */
+-	{ .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);
++#include "stmmac.h"
++#include "stmmac_platform.h"
+ 
+ #ifdef CONFIG_OF
+ 
+-/* This function validates the number of Multicast filtering bins specified
++/**
++ * dwmac1000_validate_mcast_bins - validates the number of Multicast filter bins
++ * @mcast_bins: Multicast filtering bins
++ * Description:
++ * this function validates the number of Multicast filtering bins specified
+  * by the configuration through the device tree. The Synopsys GMAC supports
+  * 64 bins, 128 bins, or 256 bins. "bins" refer to the division of CRC
+  * number space. 64 bins correspond to 6 bits of the CRC, 128 corresponds
+@@ -83,7 +65,11 @@ static int dwmac1000_validate_mcast_bins
+ 	return x;
+ }
+ 
+-/* This function validates the number of Unicast address entries supported
++/**
++ * dwmac1000_validate_ucast_entries - validate the Unicast address entries
++ * @ucast_entries: number of Unicast address entries
++ * Description:
++ * This function validates the number of Unicast address entries supported
+  * by a particular Synopsys 10/100/1000 controller. The Synopsys controller
+  * supports 1, 32, 64, or 128 Unicast filter entries for it's Unicast filter
+  * logic. This function validates a valid, supported configuration is
+@@ -109,37 +95,25 @@ static int dwmac1000_validate_ucast_entr
+ 	return x;
+ }
+ 
+-static int stmmac_probe_config_dt(struct platform_device *pdev,
+-				  struct plat_stmmacenet_data *plat,
+-				  const char **mac)
++/**
++ * stmmac_probe_config_dt - parse device-tree driver parameters
++ * @pdev: platform_device structure
++ * @plat: driver data platform structure
++ * @mac: MAC address to use
++ * Description:
++ * 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.
++ */
++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);
+@@ -155,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 =
+@@ -169,6 +154,10 @@ static int stmmac_probe_config_dt(struct
+ 				     sizeof(struct stmmac_mdio_bus_data),
+ 				     GFP_KERNEL);
+ 
++	of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
++
++	of_property_read_u32(np, "rx-fifo-depth", &plat->rx_fifo_size);
++
+ 	plat->force_sf_dma_mode =
+ 		of_property_read_bool(np, "snps,force_sf_dma_mode");
+ 
+@@ -177,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
+@@ -215,14 +210,19 @@ 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 =
+ 			of_property_read_bool(np, "snps,fixed-burst");
+ 		dma_cfg->mixed_burst =
+ 			of_property_read_bool(np, "snps,mixed-burst");
++		of_property_read_u32(np, "snps,burst_len", &dma_cfg->burst_len);
++		if (dma_cfg->burst_len < 0 || dma_cfg->burst_len > 256)
++			dma_cfg->burst_len = 0;
+ 	}
+ 	plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
+ 	if (plat->force_thresh_dma_mode) {
+@@ -230,123 +230,60 @@ 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
+- * @pdev: platform device pointer
+- * Description: platform_device probe function. It allocates
+- * the necessary resources and invokes the main to init
+- * the net device, register the mdio bus etc.
+- */
+-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;
+-
+-	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;
+-
+-	/* 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);
+-	}
++	memset(stmmac_res, 0, sizeof(*stmmac_res));
+ 
+-	/* Get MAC address if available (DT) */
+-	if (mac)
+-		memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
+-
+-	/* Get the MAC information */
+-	priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
+-	if (priv->dev->irq < 0) {
+-		if (priv->dev->irq != -EPROBE_DEFER) {
+-			netdev_err(priv->dev,
+-				   "MAC IRQ configuration information not found\n");
++	/* Get IRQ information early to have an ability to ask for deferred
++	 * probe if needed before we went too far with resource allocation.
++	 */
++	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 priv->dev->irq;
++		return stmmac_res->irq;
+ 	}
+ 
+-	/*
+-	 * On some platforms e.g. SPEAr the wake up irq differs from the mac irq
++	/* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
+ 	 * The external wake up irq can be passed through the platform code
+ 	 * named as "eth_wake_irq"
+ 	 *
+ 	 * In case the wake up interrupt is not passed from the platform
+ 	 * so the driver will continue to use the mac irq (ndev->irq)
+ 	 */
+-	priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+-	if (priv->wol_irq < 0) {
+-		if (priv->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;
+-		priv->wol_irq = priv->dev->irq;
++		stmmac_res->wol_irq = stmmac_res->irq;
+ 	}
+ 
+-	priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
+-	if (priv->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;
+ 
+-	platform_set_drvdata(pdev, priv->dev);
+-
+-	pr_debug("STMMAC platform driver registration completed");
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
+ 
+-	return 0;
++	return PTR_ERR_OR_ZERO(stmmac_res->addr);
+ }
++EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
+ 
+ /**
+  * stmmac_pltfr_remove
+@@ -354,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);
+@@ -363,13 +300,18 @@ 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
++#ifdef CONFIG_PM_SLEEP
++/**
++ * stmmac_pltfr_suspend
++ * @dev: device pointer
++ * Description: this function is invoked when suspend the driver and it direcly
++ * call the main suspend function and then, if required, on some platform, it
++ * can call an exit helper.
++ */
+ static int stmmac_pltfr_suspend(struct device *dev)
+ {
+ 	int ret;
+@@ -384,6 +326,13 @@ static int stmmac_pltfr_suspend(struct d
+ 	return ret;
+ }
+ 
++/**
++ * stmmac_pltfr_resume
++ * @dev: device pointer
++ * Description: this function is invoked when resume the driver before calling
++ * the main resume function, on some platforms, it can call own init helper
++ * if required.
++ */
+ static int stmmac_pltfr_resume(struct device *dev)
+ {
+ 	struct net_device *ndev = dev_get_drvdata(dev);
+@@ -395,23 +344,12 @@ static int stmmac_pltfr_resume(struct de
+ 
+ 	return stmmac_resume(ndev);
+ }
++#endif /* CONFIG_PM_SLEEP */
+ 
+-#endif /* CONFIG_PM */
+-
+-static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops,
+-			stmmac_pltfr_suspend, stmmac_pltfr_resume);
+-
+-struct platform_driver stmmac_pltfr_driver = {
+-	.probe = stmmac_pltfr_probe,
+-	.remove = stmmac_pltfr_remove,
+-	.driver = {
+-		   .name = STMMAC_RESOURCE_NAME,
+-		   .owner = THIS_MODULE,
+-		   .pm = &stmmac_pltfr_pm_ops,
+-		   .of_match_table = of_match_ptr(stmmac_dt_ids),
+-		   },
+-};
++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 <[email protected]>");
+ MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+@@ -0,0 +1,33 @@
++/*******************************************************************************
++  Copyright (C) 2007-2009  STMicroelectronics Ltd
++
++  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.
++
++  The full GNU General Public License is included in this distribution in
++  the file called "COPYING".
++
++  Author: Giuseppe Cavallaro <[email protected]>
++*******************************************************************************/
++
++#ifndef __STMMAC_PLATFORM_H__
++#define __STMMAC_PLATFORM_H__
++
++#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__ */

+ 0 - 65
target/linux/ipq806x/patches-3.18/702-stmmac-move-error-path-at-the-end-of-stmmac_probe_co.patch

@@ -1,65 +0,0 @@
-From 0149d275415cd1b2382ce94e5eb32641590097d0 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 15:57:12 -0700
-Subject: [PATCH 2/8] stmmac: move error path at the end of
- stmmac_probe_config_dt()
-
-We will want to do additional clean-up on certain errors. Therefore,
-this change moves the error path at the end of the function for better
-code readability.
-
-This patch doesn't change anything functionally.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 22 ++++++++++++++++------
- 1 file changed, 16 insertions(+), 6 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -117,13 +117,18 @@ static int stmmac_probe_config_dt(struct
- 	struct device_node *np = pdev->dev.of_node;
- 	struct stmmac_dma_cfg *dma_cfg;
- 	const struct of_device_id *device;
-+	int ret;
- 
--	if (!np)
--		return -ENODEV;
-+	if (!np) {
-+		ret = -ENODEV;
-+		goto err;
-+	}
- 
- 	device = of_match_device(stmmac_dt_ids, &pdev->dev);
--	if (!device)
--		return -ENODEV;
-+	if (!device) {
-+		ret = -ENODEV;
-+		goto err;
-+	}
- 
- 	if (device->data) {
- 		const struct stmmac_of_data *data = device->data;
-@@ -219,8 +224,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) {
-+			ret = -ENOMEM;
-+			goto err;
-+		}
- 		plat->dma_cfg = dma_cfg;
- 		of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
- 		dma_cfg->fixed_burst =
-@@ -235,6 +242,9 @@ static int stmmac_probe_config_dt(struct
- 	}
- 
- 	return 0;
-+
-+err:
-+	return ret;
- }
- #else
- static int stmmac_probe_config_dt(struct platform_device *pdev,

+ 0 - 64
target/linux/ipq806x/patches-3.18/703-stmmac-add-fixed-link-device-tree-support.patch

@@ -1,64 +0,0 @@
-From 3a95f75867be562cb919ff23a738f70357188fbd Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 16:02:03 -0700
-Subject: [PATCH 3/8] stmmac: add fixed-link device-tree support
-
-In case DT is used, this change adds the ability to the stmmac driver to
-detect a fixed-link PHY, instanciate it, and use it during
-phy_connect().
-
-Fixed link PHYs DT usage is described in:
-Documentation/devicetree/bindings/net/fixed-link.txt
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c     |  2 +-
- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 12 +++++++++++-
- 2 files changed, 12 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -858,7 +858,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;
- 	}
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -164,6 +164,14 @@ static int stmmac_probe_config_dt(struct
- 	/* 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 -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.
- 	 */
-@@ -226,7 +234,7 @@ static int stmmac_probe_config_dt(struct
- 				       GFP_KERNEL);
- 		if (!dma_cfg) {
- 			ret = -ENOMEM;
--			goto err;
-+			goto err2;
- 		}
- 		plat->dma_cfg = dma_cfg;
- 		of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
-@@ -243,6 +251,8 @@ static int stmmac_probe_config_dt(struct
- 
- 	return 0;
- 
-+err2:
-+	of_node_put(np);
- err:
- 	return ret;
- }

+ 0 - 427
target/linux/ipq806x/patches-3.18/704-stmmac-add-ipq806x-glue-layer.patch

@@ -1,427 +0,0 @@
-From 69fb970ad3fe05af7cb99ea78230c69c7ca0d03b Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 16:10:22 -0700
-Subject: [PATCH 4/8] stmmac: add ipq806x glue layer
-
-The ethernet controller available in IPQ806x is a Synopsys DesignWare
-Gigabit MAC IP core, already supported by the stmmac driver.
-
-This glue layer implements some platform specific settings required to
-get the controller working on an IPQ806x based platform.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- drivers/net/ethernet/stmicro/stmmac/Kconfig        |   1 +
- drivers/net/ethernet/stmicro/stmmac/Makefile       |   2 +-
- drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c    | 324 +++++++++++++++++++++
- .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   1 +
- .../net/ethernet/stmicro/stmmac/stmmac_platform.h  |   1 +
- 5 files changed, 328 insertions(+), 1 deletion(-)
- create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c
-
---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
-+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-@@ -16,6 +16,7 @@ if STMMAC_ETH
- config STMMAC_PLATFORM
- 	bool "STMMAC Platform bus support"
- 	depends on STMMAC_ETH
-+	select MFD_SYSCON
- 	default y
- 	---help---
- 	  This selects the platform specific bus support for
-@@ -26,6 +27,15 @@ config STMMAC_PLATFORM
- 
- 	  If unsure, say N.
- 
-+config DWMAC_IPQ806X
-+	bool "QCA IPQ806x dwmac support"
-+	depends on STMMAC_PLATFORM && ARCH_QCOM
-+	help
-+	  Support for Ethernet controller on QCA IPQ806x SoC.
-+
-+	  This selects the QCA IPQ806x SoC glue layer support for
-+	  the stmmac device driver.
-+
- config DWMAC_MESON
- 	bool "Amlogic Meson dwmac support"
- 	depends on STMMAC_PLATFORM && ARCH_MESON
---- a/drivers/net/ethernet/stmicro/stmmac/Makefile
-+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
-@@ -1,6 +1,7 @@
- obj-$(CONFIG_STMMAC_ETH) += stmmac.o
- stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
- stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
-+stmmac-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
- stmmac-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
- stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
- stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -46,6 +46,9 @@ static const struct of_device_id stmmac_
- #ifdef CONFIG_DWMAC_SOCFPGA
- 	{ .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
- #endif
-+#ifdef CONFIG_DWMAC_IPQ806X
-+	{ .compatible = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data },
-+#endif
- 	/* SoC specific glue layers should come before generic bindings */
- 	{ .compatible = "st,spear600-gmac"},
- 	{ .compatible = "snps,dwmac-3.610"},
---- /dev/null
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
-@@ -0,0 +1,343 @@
-+/*
-+ * 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 "stmmac.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)	(1 << 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_setup(struct platform_device *pdev)
-+{
-+	struct device *dev = &pdev->dev;
-+	struct ipq806x_gmac *gmac;
-+	int val;
-+	void *err;
-+
-+	gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
-+	if (!gmac)
-+		return ERR_PTR(-ENOMEM);
-+
-+	gmac->pdev = pdev;
-+
-+	err = ipq806x_gmac_of_parse(gmac);
-+	if (err) {
-+		dev_err(dev, "device tree parsing error\n");
-+		return 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 NULL;
-+	}
-+	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 &= ~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 NULL;
-+	}
-+	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);
-+	}
-+
-+	return gmac;
-+}
-+
-+static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
-+{
-+	struct ipq806x_gmac *gmac = priv;
-+
-+	ipq806x_gmac_set_speed(gmac, speed);
-+}
-+
-+const struct stmmac_of_data ipq806x_gmac_data = {
-+	.has_gmac	= 1,
-+	.setup		= ipq806x_gmac_setup,
-+	.fix_mac_speed	= ipq806x_gmac_fix_mac_speed,
-+};
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-@@ -137,6 +137,9 @@ void stmmac_disable_eee_mode(struct stmm
- bool stmmac_eee_init(struct stmmac_priv *priv);
- 
- #ifdef CONFIG_STMMAC_PLATFORM
-+#ifdef CONFIG_DWMAC_IPQ806X
-+extern const struct stmmac_of_data ipq806x_gmac_data;
-+#endif
- #ifdef CONFIG_DWMAC_MESON
- extern const struct stmmac_of_data meson6_dwmac_data;
- #endif

+ 0 - 52
target/linux/ipq806x/patches-3.18/705-net-stmmac-ipq806x-document-device-tree-bindings.patch

@@ -1,52 +0,0 @@
-From 0f9605d9409b77a89daef91cc68239fc2ff50457 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 16:51:25 -0700
-Subject: [PATCH 5/8] net: stmmac: ipq806x: document device tree bindings
-
-Add the device tree bindings documentation for the QCA IPQ806x
-variant of the Synopsys DesignWare MAC.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- .../devicetree/bindings/net/ipq806x-dwmac.txt      | 35 ++++++++++++++++++++++
- 1 file changed, 35 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/net/ipq806x-dwmac.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/ipq806x-dwmac.txt
-@@ -0,0 +1,35 @@
-+* IPQ806x DWMAC Ethernet controller
-+
-+The device inherits all the properties of the dwmac/stmmac devices
-+described in the file net/stmmac.txt with the following changes.
-+
-+Required properties:
-+
-+- compatible: should be "qcom,ipq806x-gmac" along with "snps,dwmac"
-+	      and any applicable more detailed version number
-+	      described in net/stmmac.txt
-+
-+- qcom,nss-common: should contain a phandle to a syscon device mapping the
-+		   nss-common registers.
-+
-+- qcom,qsgmii-csr: should contain a phandle to a syscon device mapping the
-+		   qsgmii-csr registers.
-+
-+Example:
-+
-+	gmac: ethernet@37000000 {
-+		device_type = "network";
-+		compatible = "qcom,ipq806x-gmac";
-+		reg = <0x37000000 0x200000>;
-+		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
-+		interrupt-names = "macirq";
-+
-+		qcom,nss-common = <&nss_common>;
-+		qcom,qsgmii-csr = <&qsgmii_csr>;
-+
-+		clocks = <&gcc GMAC_CORE1_CLK>;
-+		clock-names = "stmmaceth";
-+
-+		resets = <&gcc GMAC_CORE1_RESET>;
-+		reset-names = "stmmaceth";
-+	};

+ 0 - 171
target/linux/ipq806x/patches-3.18/706-net-stmmac-create-one-debugfs-dir-per-net-device.patch

@@ -1,171 +0,0 @@
-From df944689d491e6af533173bf2ef448c3dd334f15 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Mon, 11 May 2015 15:15:25 -0700
-Subject: [PATCH 6/8] net: stmmac: create one debugfs dir per net-device
-
-stmmac DebugFS entries are currently global to the driver. As a result,
-having more than one stmmac device in the system creates the following
-error:
-* ERROR stmmaceth, debugfs create directory failed
-* stmmac_hw_setup: failed debugFS registration
-
-This also results in being able to access the debugfs information for
-the first registered device only.
-
-This patch changes the debugfs structure to have one sub-directory per
-net-device. Files under "/sys/kernel/debug/stmmaceth" will now show-up
-under /sys/kernel/debug/stmmaceth/ethN/.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- drivers/net/ethernet/stmicro/stmmac/stmmac.h      |  6 ++
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 76 ++++++++++++++++-------
- 2 files changed, 59 insertions(+), 23 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-@@ -116,6 +116,12 @@ struct stmmac_priv {
- 	int use_riwt;
- 	int irq_wake;
- 	spinlock_t ptp_lock;
-+
-+#ifdef CONFIG_DEBUG_FS
-+	struct dentry *dbgfs_dir;
-+	struct dentry *dbgfs_rings_status;
-+	struct dentry *dbgfs_dma_cap;
-+#endif
- };
- 
- int stmmac_mdio_unregister(struct net_device *ndev);
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -119,7 +119,7 @@ static irqreturn_t stmmac_interrupt(int
- 
- #ifdef CONFIG_STMMAC_DEBUG_FS
- static int stmmac_init_fs(struct net_device *dev);
--static void stmmac_exit_fs(void);
-+static void stmmac_exit_fs(struct net_device *dev);
- #endif
- 
- #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
-@@ -1879,7 +1879,7 @@ static int stmmac_release(struct net_dev
- 	netif_carrier_off(dev);
- 
- #ifdef CONFIG_STMMAC_DEBUG_FS
--	stmmac_exit_fs();
-+	stmmac_exit_fs(dev);
- #endif
- 
- 	stmmac_release_ptp(priv);
-@@ -2467,8 +2467,6 @@ static int stmmac_ioctl(struct net_devic
- 
- #ifdef CONFIG_STMMAC_DEBUG_FS
- static struct dentry *stmmac_fs_dir;
--static struct dentry *stmmac_rings_status;
--static struct dentry *stmmac_dma_cap;
- 
- static void sysfs_display_ring(void *head, int size, int extend_desc,
- 			       struct seq_file *seq)
-@@ -2607,36 +2605,39 @@ static const struct file_operations stmm
- 
- static int stmmac_init_fs(struct net_device *dev)
- {
--	/* Create debugfs entries */
--	stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
-+	struct stmmac_priv *priv = netdev_priv(dev);
-+
-+	/* Create per netdev entries */
-+	priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir);
- 
--	if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
--		pr_err("ERROR %s, debugfs create directory failed\n",
--		       STMMAC_RESOURCE_NAME);
-+	if (!priv->dbgfs_dir || IS_ERR(priv->dbgfs_dir)) {
-+		pr_err("ERROR %s/%s, debugfs create directory failed\n",
-+		       STMMAC_RESOURCE_NAME, dev->name);
- 
- 		return -ENOMEM;
- 	}
- 
- 	/* Entry to report DMA RX/TX rings */
--	stmmac_rings_status = debugfs_create_file("descriptors_status",
--						  S_IRUGO, stmmac_fs_dir, dev,
--						  &stmmac_rings_status_fops);
-+	priv->dbgfs_rings_status =
-+		debugfs_create_file("descriptors_status", S_IRUGO,
-+				    priv->dbgfs_dir, dev,
-+				    &stmmac_rings_status_fops);
- 
--	if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) {
-+	if (!priv->dbgfs_rings_status || IS_ERR(priv->dbgfs_rings_status)) {
- 		pr_info("ERROR creating stmmac ring debugfs file\n");
--		debugfs_remove(stmmac_fs_dir);
-+		debugfs_remove_recursive(priv->dbgfs_dir);
- 
- 		return -ENOMEM;
- 	}
- 
- 	/* Entry to report the DMA HW features */
--	stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir,
--					     dev, &stmmac_dma_cap_fops);
-+	priv->dbgfs_dma_cap = debugfs_create_file("dma_cap", S_IRUGO,
-+					    priv->dbgfs_dir,
-+					    dev, &stmmac_dma_cap_fops);
- 
--	if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) {
-+	if (!priv->dbgfs_dma_cap || IS_ERR(priv->dbgfs_dma_cap)) {
- 		pr_info("ERROR creating stmmac MMC debugfs file\n");
--		debugfs_remove(stmmac_rings_status);
--		debugfs_remove(stmmac_fs_dir);
-+		debugfs_remove_recursive(priv->dbgfs_dir);
- 
- 		return -ENOMEM;
- 	}
-@@ -2644,11 +2645,11 @@ static int stmmac_init_fs(struct net_dev
- 	return 0;
- }
- 
--static void stmmac_exit_fs(void)
-+static void stmmac_exit_fs(struct net_device *dev)
- {
--	debugfs_remove(stmmac_rings_status);
--	debugfs_remove(stmmac_dma_cap);
--	debugfs_remove(stmmac_fs_dir);
-+	struct stmmac_priv *priv = netdev_priv(dev);
-+
-+	debugfs_remove_recursive(priv->dbgfs_dir);
- }
- #endif /* CONFIG_STMMAC_DEBUG_FS */
- 
-@@ -3032,6 +3033,21 @@ static int __init stmmac_init(void)
- 	ret = stmmac_register_pci();
- 	if (ret)
- 		goto err_pci;
-+
-+#ifdef CONFIG_STMMAC_DEBUG_FS
-+	/* Create debugfs main directory if it doesn't exist yet */
-+	if (stmmac_fs_dir == NULL) {
-+		stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
-+
-+		if (!stmmac_fs_dir || IS_ERR(stmmac_fs_dir)) {
-+			pr_err("ERROR %s, debugfs create directory failed\n",
-+			       STMMAC_RESOURCE_NAME);
-+
-+			return -ENOMEM;
-+		}
-+	}
-+#endif
-+
- 	return 0;
- err_pci:
- 	stmmac_unregister_platform();
-@@ -3042,6 +3058,9 @@ err:
- 
- static void __exit stmmac_exit(void)
- {
-+#ifdef CONFIG_STMMAC_DEBUG_FS
-+	debugfs_remove_recursive(stmmac_fs_dir);
-+#endif
- 	stmmac_unregister_platform();
- 	stmmac_unregister_pci();
- }

+ 16 - 20
target/linux/ipq806x/patches-3.18/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch

@@ -9,27 +9,23 @@ Subject: [PATCH] stmac: platform: add support for retreiving mac from mtd
 
 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
 +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -284,6 +284,7 @@ static int stmmac_pltfr_probe(struct pla
- 	struct stmmac_priv *priv = NULL;
- 	struct plat_stmmacenet_data *plat_dat = NULL;
- 	const char *mac = NULL;
-+	u8 mtd_mac[ETH_ALEN] = { };
+@@ -116,6 +116,19 @@ stmmac_probe_config_dt(struct platform_d
+ 		return ERR_PTR(-ENOMEM);
  
- 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- 	addr = devm_ioremap_resource(dev, res);
-@@ -313,6 +314,15 @@ static int stmmac_pltfr_probe(struct pla
- 			pr_err("%s: main dt probe failed", __func__);
- 			return ret;
- 		}
+ 	*mac = of_get_mac_address(np);
++	if (!*mac) {
++		u8 mtd_mac[ETH_ALEN];
++		int ret;
 +
-+		if (!mac) {
-+			ret = of_get_mac_address_mtd(dev->of_node, &mtd_mac);
-+			if (ret == -EPROBE_DEFER)
-+				return ret;
++		ret = of_get_mac_address_mtd(np, mtd_mac);
++		if (ret == -EPROBE_DEFER)
++			return ERR_PTR(ret);
 +
-+			if (is_valid_ether_addr(&mtd_mac))
-+				mac = mtd_mac;
-+		}
- 	}
++		if (is_valid_ether_addr(mtd_mac))
++			*mac = devm_kmemdup(&pdev->dev, mtd_mac, ETH_ALEN,
++					    GFP_KERNEL);
++	}
++
+ 	plat->interface = of_get_phy_mode(np);
  
- 	/* Custom setup (if needed) */
+ 	/* Get max speed of operation from device tree */

+ 0 - 105
target/linux/ipq806x/patches-4.1/701-stmmac-add-phy-handle-support-to-the-platform-layer.patch

@@ -1,105 +0,0 @@
-From 4f09499bc1d9bb095caccbcd73ff951ee631e521 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 15:42:40 -0700
-Subject: [PATCH 1/8] stmmac: add phy-handle support to the platform layer
-
-On stmmac driver, PHY specification in device-tree was done using the
-non-standard property "snps,phy-addr". Specifying a PHY on a different
-MDIO bus that the one within the stmmac controller doesn't seem to be
-possible when device-tree is used.
-
-This change adds support for the phy-handle property, as specified in
-Documentation/devicetree/bindings/net/ethernet.txt.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  | 28 ++++++++++++++--------
- .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |  6 ++++-
- include/linux/stmmac.h                             |  1 +
- 3 files changed, 24 insertions(+), 11 deletions(-)
-
---- 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);
--
--	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);
-+	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);
- 
--	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);
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -28,6 +28,7 @@
- #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"
-@@ -168,13 +169,16 @@ 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);
-+
- 	/* "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 =
---- 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;

+ 2355 - 0
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 <[email protected]>
++ *
++ * 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 <[email protected]>");
++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 <[email protected]>
++ *
++ * 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 <[email protected]>");
++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 <[email protected]>");
++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) <[email protected]>");
++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 <[email protected]>");
++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 <[email protected]>");
++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 <[email protected]>");
+ 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

+ 0 - 65
target/linux/ipq806x/patches-4.1/702-stmmac-move-error-path-at-the-end-of-stmmac_probe_co.patch

@@ -1,65 +0,0 @@
-From 0149d275415cd1b2382ce94e5eb32641590097d0 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 15:57:12 -0700
-Subject: [PATCH 2/8] stmmac: move error path at the end of
- stmmac_probe_config_dt()
-
-We will want to do additional clean-up on certain errors. Therefore,
-this change moves the error path at the end of the function for better
-code readability.
-
-This patch doesn't change anything functionally.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- .../net/ethernet/stmicro/stmmac/stmmac_platform.c  | 22 ++++++++++++++++------
- 1 file changed, 16 insertions(+), 6 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -130,13 +130,18 @@ static int stmmac_probe_config_dt(struct
- 	struct device_node *np = pdev->dev.of_node;
- 	struct stmmac_dma_cfg *dma_cfg;
- 	const struct of_device_id *device;
-+	int ret;
- 
--	if (!np)
--		return -ENODEV;
-+	if (!np) {
-+		ret = -ENODEV;
-+		goto err;
-+	}
- 
- 	device = of_match_device(stmmac_dt_ids, &pdev->dev);
--	if (!device)
--		return -ENODEV;
-+	if (!device) {
-+		ret = -ENODEV;
-+		goto err;
-+	}
- 
- 	if (device->data) {
- 		const struct stmmac_of_data *data = device->data;
-@@ -236,8 +241,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) {
-+			ret = -ENOMEM;
-+			goto err;
-+		}
- 		plat->dma_cfg = dma_cfg;
- 		of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
- 		dma_cfg->fixed_burst =
-@@ -255,6 +262,9 @@ static int stmmac_probe_config_dt(struct
- 	}
- 
- 	return 0;
-+
-+err:
-+	return ret;
- }
- #else
- static int stmmac_probe_config_dt(struct platform_device *pdev,

+ 0 - 64
target/linux/ipq806x/patches-4.1/703-stmmac-add-fixed-link-device-tree-support.patch

@@ -1,64 +0,0 @@
-From 3a95f75867be562cb919ff23a738f70357188fbd Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 16:02:03 -0700
-Subject: [PATCH 3/8] stmmac: add fixed-link device-tree support
-
-In case DT is used, this change adds the ability to the stmmac driver to
-detect a fixed-link PHY, instanciate it, and use it during
-phy_connect().
-
-Fixed link PHYs DT usage is described in:
-Documentation/devicetree/bindings/net/fixed-link.txt
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c     |  2 +-
- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 12 +++++++++++-
- 2 files changed, 12 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -859,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;
- 	}
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -177,6 +177,14 @@ static int stmmac_probe_config_dt(struct
- 	/* 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 -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.
- 	 */
-@@ -243,7 +251,7 @@ static int stmmac_probe_config_dt(struct
- 				       GFP_KERNEL);
- 		if (!dma_cfg) {
- 			ret = -ENOMEM;
--			goto err;
-+			goto err2;
- 		}
- 		plat->dma_cfg = dma_cfg;
- 		of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
-@@ -263,6 +271,8 @@ static int stmmac_probe_config_dt(struct
- 
- 	return 0;
- 
-+err2:
-+	of_node_put(np);
- err:
- 	return ret;
- }

+ 0 - 407
target/linux/ipq806x/patches-4.1/704-stmmac-add-ipq806x-glue-layer.patch

@@ -1,407 +0,0 @@
-From 69fb970ad3fe05af7cb99ea78230c69c7ca0d03b Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 16:10:22 -0700
-Subject: [PATCH 4/8] stmmac: add ipq806x glue layer
-
-The ethernet controller available in IPQ806x is a Synopsys DesignWare
-Gigabit MAC IP core, already supported by the stmmac driver.
-
-This glue layer implements some platform specific settings required to
-get the controller working on an IPQ806x based platform.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- drivers/net/ethernet/stmicro/stmmac/Kconfig        |   1 +
- drivers/net/ethernet/stmicro/stmmac/Makefile       |   2 +-
- drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c    | 324 +++++++++++++++++++++
- .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   1 +
- .../net/ethernet/stmicro/stmmac/stmmac_platform.h  |   1 +
- 5 files changed, 328 insertions(+), 1 deletion(-)
- create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c
-
---- 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.
---- a/drivers/net/ethernet/stmicro/stmmac/Makefile
-+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
-@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethto
- 
- 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
-+		       dwmac-sti.o dwmac-socfpga.o dwmac-rk.o dwmac-ipq806x.o
- 
- obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
- stmmac-pci-objs:= stmmac_pci.o
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -43,6 +43,7 @@ static const struct of_device_id stmmac_
- 	{ .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 = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data },
- 	{ .compatible = "st,spear600-gmac"},
- 	{ .compatible = "snps,dwmac-3.610"},
- 	{ .compatible = "snps,dwmac-3.70a"},
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
-@@ -25,5 +25,6 @@ extern const struct stmmac_of_data stih4
- 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;
-+extern const struct stmmac_of_data ipq806x_gmac_data;
- 
- #endif /* __STMMAC_PLATFORM_H__ */
---- /dev/null
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
-@@ -0,0 +1,343 @@
-+/*
-+ * 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 "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)	(1 << 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_setup(struct platform_device *pdev)
-+{
-+	struct device *dev = &pdev->dev;
-+	struct ipq806x_gmac *gmac;
-+	int val;
-+	void *err;
-+
-+	gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
-+	if (!gmac)
-+		return ERR_PTR(-ENOMEM);
-+
-+	gmac->pdev = pdev;
-+
-+	err = ipq806x_gmac_of_parse(gmac);
-+	if (err) {
-+		dev_err(dev, "device tree parsing error\n");
-+		return 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 NULL;
-+	}
-+	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 &= ~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 NULL;
-+	}
-+	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);
-+	}
-+
-+	return gmac;
-+}
-+
-+static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
-+{
-+	struct ipq806x_gmac *gmac = priv;
-+
-+	ipq806x_gmac_set_speed(gmac, speed);
-+}
-+
-+const struct stmmac_of_data ipq806x_gmac_data = {
-+	.has_gmac	= 1,
-+	.setup		= ipq806x_gmac_setup,
-+	.fix_mac_speed	= ipq806x_gmac_fix_mac_speed,
-+};

+ 0 - 52
target/linux/ipq806x/patches-4.1/705-net-stmmac-ipq806x-document-device-tree-bindings.patch

@@ -1,52 +0,0 @@
-From 0f9605d9409b77a89daef91cc68239fc2ff50457 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <[email protected]>
-Date: Fri, 8 May 2015 16:51:25 -0700
-Subject: [PATCH 5/8] net: stmmac: ipq806x: document device tree bindings
-
-Add the device tree bindings documentation for the QCA IPQ806x
-variant of the Synopsys DesignWare MAC.
-
-Signed-off-by: Mathieu Olivari <[email protected]>
----
- .../devicetree/bindings/net/ipq806x-dwmac.txt      | 35 ++++++++++++++++++++++
- 1 file changed, 35 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/net/ipq806x-dwmac.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/ipq806x-dwmac.txt
-@@ -0,0 +1,35 @@
-+* IPQ806x DWMAC Ethernet controller
-+
-+The device inherits all the properties of the dwmac/stmmac devices
-+described in the file net/stmmac.txt with the following changes.
-+
-+Required properties:
-+
-+- compatible: should be "qcom,ipq806x-gmac" along with "snps,dwmac"
-+	      and any applicable more detailed version number
-+	      described in net/stmmac.txt
-+
-+- qcom,nss-common: should contain a phandle to a syscon device mapping the
-+		   nss-common registers.
-+
-+- qcom,qsgmii-csr: should contain a phandle to a syscon device mapping the
-+		   qsgmii-csr registers.
-+
-+Example:
-+
-+	gmac: ethernet@37000000 {
-+		device_type = "network";
-+		compatible = "qcom,ipq806x-gmac";
-+		reg = <0x37000000 0x200000>;
-+		interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
-+		interrupt-names = "macirq";
-+
-+		qcom,nss-common = <&nss_common>;
-+		qcom,qsgmii-csr = <&qsgmii_csr>;
-+
-+		clocks = <&gcc GMAC_CORE1_CLK>;
-+		clock-names = "stmmaceth";
-+
-+		resets = <&gcc GMAC_CORE1_RESET>;
-+		reset-names = "stmmaceth";
-+	};

+ 16 - 20
target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch

@@ -9,27 +9,23 @@ Subject: [PATCH] stmac: platform: add support for retreiving mac from mtd
 
 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
 +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -302,6 +302,7 @@ static int stmmac_pltfr_probe(struct pla
- 	struct stmmac_priv *priv = NULL;
- 	struct plat_stmmacenet_data *plat_dat = NULL;
- 	const char *mac = NULL;
-+	u8 mtd_mac[ETH_ALEN] = { };
- 	int irq, wol_irq, lpi_irq;
+@@ -116,6 +116,19 @@ stmmac_probe_config_dt(struct platform_d
+ 		return ERR_PTR(-ENOMEM);
  
- 	/* Get IRQ information early to have an ability to ask for deferred
-@@ -362,6 +363,15 @@ static int stmmac_pltfr_probe(struct pla
- 			pr_err("%s: main dt probe failed", __func__);
- 			return ret;
- 		}
+ 	*mac = of_get_mac_address(np);
++	if (!*mac) {
++		u8 mtd_mac[ETH_ALEN];
++		int ret;
 +
-+		if (!mac) {
-+			ret = of_get_mac_address_mtd(dev->of_node, &mtd_mac);
-+			if (ret == -EPROBE_DEFER)
-+				return ret;
++		ret = of_get_mac_address_mtd(np, mtd_mac);
++		if (ret == -EPROBE_DEFER)
++			return ERR_PTR(ret);
 +
-+			if (is_valid_ether_addr(&mtd_mac))
-+				mac = mtd_mac;
-+		}
- 	}
++		if (is_valid_ether_addr(mtd_mac))
++			*mac = devm_kmemdup(&pdev->dev, mtd_mac, ETH_ALEN,
++					    GFP_KERNEL);
++	}
++
+ 	plat->interface = of_get_phy_mode(np);
  
- 	/* Custom setup (if needed) */
+ 	/* Get max speed of operation from device tree */