sunxi: backport the stmmac driver from kernel 4.13
authorHauke Mehrtens <hauke@hauke-m.de>
Thu, 21 Sep 2017 20:10:08 +0000 (22:10 +0200)
committerHauke Mehrtens <hauke@hauke-m.de>
Sun, 1 Oct 2017 11:00:16 +0000 (13:00 +0200)
This adds support for the GMAC which is use in the A64 and other
Allwinner chips by backporting the changes from the kernel versions
4.13.

Some commits are not backported which are adding support for newly
introduced APIs which are not available in kernel 4.9.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/sunxi/config-4.9
target/linux/sunxi/cortexa53/config-default
target/linux/sunxi/cortexa7/config-default
target/linux/sunxi/patches-4.9/0050-stmmac-form-4-10.patch [new file with mode: 0644]
target/linux/sunxi/patches-4.9/0051-stmmac-form-4-11.patch [new file with mode: 0644]
target/linux/sunxi/patches-4.9/0052-stmmac-form-4-12.patch [new file with mode: 0644]
target/linux/sunxi/patches-4.9/0053-stmmac-form-4-13.patch [new file with mode: 0644]

index 45677f9..e961c8a 100644 (file)
@@ -146,7 +146,9 @@ CONFIG_DMA_VIRTUAL_CHANNELS=y
 CONFIG_DNOTIFY=y
 CONFIG_DTC=y
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_DWMAC_DWC_QOS_ETH is not set
 CONFIG_DWMAC_GENERIC=y
+# CONFIG_DWMAC_SUN8I is not set
 CONFIG_DWMAC_SUNXI=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_EDAC_ATOMIC_SCRUB=y
index 58ac214..527a6f6 100644 (file)
@@ -43,6 +43,7 @@ CONFIG_COMMON_CLK_XGENE=y
 # CONFIG_COMPAT is not set
 # CONFIG_DEBUG_ALIGN_RODATA is not set
 CONFIG_DEBUG_RODATA=y
+CONFIG_DWMAC_SUN8I=y
 CONFIG_FRAME_POINTER=y
 # CONFIG_FSL_ERRATUM_A008585 is not set
 CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
index aabfa5a..fe974c1 100644 (file)
@@ -1,3 +1,4 @@
+CONFIG_DWMAC_SUN8I=y
 # CONFIG_MACH_SUN4I is not set
 # CONFIG_MACH_SUN5I is not set
 # CONFIG_PINCTRL_GR8 is not set
diff --git a/target/linux/sunxi/patches-4.9/0050-stmmac-form-4-10.patch b/target/linux/sunxi/patches-4.9/0050-stmmac-form-4-10.patch
new file mode 100644 (file)
index 0000000..b88c19e
--- /dev/null
@@ -0,0 +1,3497 @@
+--- a/Documentation/devicetree/bindings/net/stmmac.txt
++++ b/Documentation/devicetree/bindings/net/stmmac.txt
+@@ -1,7 +1,7 @@
+ * STMicroelectronics 10/100/1000 Ethernet driver (GMAC)
+ Required properties:
+-- compatible: Should be "snps,dwmac-<ip_version>" "snps,dwmac"
++- compatible: Should be "snps,dwmac-<ip_version>", "snps,dwmac"
+       For backwards compatibility: "st,spear600-gmac" is also supported.
+ - reg: Address and length of the register set for the device
+ - interrupt-parent: Should be the phandle for the interrupt controller
+@@ -34,7 +34,13 @@ Optional properties:
+   platforms.
+ - tx-fifo-depth: See ethernet.txt file in the same directory
+ - rx-fifo-depth: See ethernet.txt file in the same directory
+-- snps,pbl            Programmable Burst Length
++- snps,pbl            Programmable Burst Length (tx and rx)
++- snps,txpbl          Tx Programmable Burst Length. Only for GMAC and newer.
++                      If set, DMA tx will use this value rather than snps,pbl.
++- snps,rxpbl          Rx Programmable Burst Length. Only for GMAC and newer.
++                      If set, DMA rx will use this value rather than snps,pbl.
++- snps,no-pbl-x8      Don't multiply the pbl/txpbl/rxpbl values by 8.
++                      For core rev < 3.50, don't multiply the values by 4.
+ - snps,aal            Address-Aligned Beats
+ - snps,fixed-burst    Program the DMA to use the fixed burst mode
+ - snps,mixed-burst    Program the DMA to use the mixed burst mode
+@@ -50,6 +56,8 @@ Optional properties:
+ - snps,ps-speed: port selection speed that can be passed to the core when
+                PCS is supported. For example, this is used in case of SGMII
+                and MAC2MAC connection.
++- snps,tso: this enables the TSO feature otherwise it will be managed by
++               MAC HW capability register. Only for GMAC4 and newer.
+ - AXI BUS Mode parameters: below the list of all the parameters to program the
+                          AXI register inside the DMA module:
+       - snps,lpi_en: enable Low Power Interface
+@@ -62,8 +70,6 @@ Optional properties:
+       - snps,fb: fixed-burst
+       - snps,mb: mixed-burst
+       - snps,rb: rebuild INCRx Burst
+-      - snps,tso: this enables the TSO feature otherwise it will be managed by
+-          MAC HW capability register.
+ - mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
+ Examples:
+--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
+@@ -69,6 +69,17 @@ config DWMAC_MESON
+         the stmmac device driver. This driver is used for Meson6,
+         Meson8, Meson8b and GXBB SoCs.
++config DWMAC_OXNAS
++      tristate "Oxford Semiconductor OXNAS dwmac support"
++      default ARCH_OXNAS
++      depends on OF && COMMON_CLK && (ARCH_OXNAS || COMPILE_TEST)
++      select MFD_SYSCON
++      help
++        Support for Ethernet controller on Oxford Semiconductor OXNAS SoCs.
++
++        This selects the Oxford Semiconductor OXNASSoC glue layer support for
++        the stmmac device driver. This driver is used for OX820.
++
+ config DWMAC_ROCKCHIP
+       tristate "Rockchip dwmac support"
+       default ARCH_ROCKCHIP
+--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_STMMAC_PLATFORM)        += stmmac-
+ obj-$(CONFIG_DWMAC_IPQ806X)   += dwmac-ipq806x.o
+ obj-$(CONFIG_DWMAC_LPC18XX)   += dwmac-lpc18xx.o
+ obj-$(CONFIG_DWMAC_MESON)     += dwmac-meson.o dwmac-meson8b.o
++obj-$(CONFIG_DWMAC_OXNAS)     += dwmac-oxnas.o
+ obj-$(CONFIG_DWMAC_ROCKCHIP)  += dwmac-rk.o
+ obj-$(CONFIG_DWMAC_SOCFPGA)   += dwmac-altr-socfpga.o
+ obj-$(CONFIG_DWMAC_STI)               += dwmac-sti.o
+--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
++++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+@@ -34,7 +34,7 @@ static int stmmac_jumbo_frm(void *p, str
+       unsigned int entry = priv->cur_tx;
+       struct dma_desc *desc = priv->dma_tx + entry;
+       unsigned int nopaged_len = skb_headlen(skb);
+-      unsigned int bmax;
++      unsigned int bmax, des2;
+       unsigned int i = 1, len;
+       if (priv->plat->enh_desc)
+@@ -44,11 +44,12 @@ static int stmmac_jumbo_frm(void *p, str
+       len = nopaged_len - bmax;
+-      desc->des2 = dma_map_single(priv->device, skb->data,
+-                                  bmax, DMA_TO_DEVICE);
+-      if (dma_mapping_error(priv->device, desc->des2))
++      des2 = dma_map_single(priv->device, skb->data,
++                            bmax, DMA_TO_DEVICE);
++      desc->des2 = cpu_to_le32(des2);
++      if (dma_mapping_error(priv->device, des2))
+               return -1;
+-      priv->tx_skbuff_dma[entry].buf = desc->des2;
++      priv->tx_skbuff_dma[entry].buf = des2;
+       priv->tx_skbuff_dma[entry].len = bmax;
+       /* do not close the descriptor and do not set own bit */
+       priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
+@@ -60,12 +61,13 @@ static int stmmac_jumbo_frm(void *p, str
+               desc = priv->dma_tx + entry;
+               if (len > bmax) {
+-                      desc->des2 = dma_map_single(priv->device,
+-                                                  (skb->data + bmax * i),
+-                                                  bmax, DMA_TO_DEVICE);
+-                      if (dma_mapping_error(priv->device, desc->des2))
++                      des2 = dma_map_single(priv->device,
++                                            (skb->data + bmax * i),
++                                            bmax, DMA_TO_DEVICE);
++                      desc->des2 = cpu_to_le32(des2);
++                      if (dma_mapping_error(priv->device, des2))
+                               return -1;
+-                      priv->tx_skbuff_dma[entry].buf = desc->des2;
++                      priv->tx_skbuff_dma[entry].buf = des2;
+                       priv->tx_skbuff_dma[entry].len = bmax;
+                       priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
+                                                       STMMAC_CHAIN_MODE, 1,
+@@ -73,12 +75,13 @@ static int stmmac_jumbo_frm(void *p, str
+                       len -= bmax;
+                       i++;
+               } else {
+-                      desc->des2 = dma_map_single(priv->device,
+-                                                  (skb->data + bmax * i), len,
+-                                                  DMA_TO_DEVICE);
+-                      if (dma_mapping_error(priv->device, desc->des2))
++                      des2 = dma_map_single(priv->device,
++                                            (skb->data + bmax * i), len,
++                                            DMA_TO_DEVICE);
++                      desc->des2 = cpu_to_le32(des2);
++                      if (dma_mapping_error(priv->device, des2))
+                               return -1;
+-                      priv->tx_skbuff_dma[entry].buf = desc->des2;
++                      priv->tx_skbuff_dma[entry].buf = des2;
+                       priv->tx_skbuff_dma[entry].len = len;
+                       /* last descriptor can be set now */
+                       priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
+@@ -119,19 +122,19 @@ static void stmmac_init_dma_chain(void *
+               struct dma_extended_desc *p = (struct dma_extended_desc *)des;
+               for (i = 0; i < (size - 1); i++) {
+                       dma_phy += sizeof(struct dma_extended_desc);
+-                      p->basic.des3 = (unsigned int)dma_phy;
++                      p->basic.des3 = cpu_to_le32((unsigned int)dma_phy);
+                       p++;
+               }
+-              p->basic.des3 = (unsigned int)phy_addr;
++              p->basic.des3 = cpu_to_le32((unsigned int)phy_addr);
+       } else {
+               struct dma_desc *p = (struct dma_desc *)des;
+               for (i = 0; i < (size - 1); i++) {
+                       dma_phy += sizeof(struct dma_desc);
+-                      p->des3 = (unsigned int)dma_phy;
++                      p->des3 = cpu_to_le32((unsigned int)dma_phy);
+                       p++;
+               }
+-              p->des3 = (unsigned int)phy_addr;
++              p->des3 = cpu_to_le32((unsigned int)phy_addr);
+       }
+ }
+@@ -144,10 +147,10 @@ static void stmmac_refill_desc3(void *pr
+                * 1588-2002 time stamping is enabled, hence reinitialize it
+                * to keep explicit chaining in the descriptor.
+                */
+-              p->des3 = (unsigned int)(priv->dma_rx_phy +
+-                                       (((priv->dirty_rx) + 1) %
+-                                        DMA_RX_SIZE) *
+-                                       sizeof(struct dma_desc));
++              p->des3 = cpu_to_le32((unsigned int)(priv->dma_rx_phy +
++                                    (((priv->dirty_rx) + 1) %
++                                     DMA_RX_SIZE) *
++                                    sizeof(struct dma_desc)));
+ }
+ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
+@@ -161,9 +164,9 @@ static void stmmac_clean_desc3(void *pri
+                * 1588-2002 time stamping is enabled, hence reinitialize it
+                * to keep explicit chaining in the descriptor.
+                */
+-              p->des3 = (unsigned int)((priv->dma_tx_phy +
+-                                        ((priv->dirty_tx + 1) % DMA_TX_SIZE))
+-                                        * sizeof(struct dma_desc));
++              p->des3 = cpu_to_le32((unsigned int)((priv->dma_tx_phy +
++                                    ((priv->dirty_tx + 1) % DMA_TX_SIZE))
++                                    * sizeof(struct dma_desc)));
+ }
+ const struct stmmac_mode_ops chain_mode_ops = {
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -44,6 +44,7 @@
+ #define       DWMAC_CORE_4_00 0x40
+ #define STMMAC_CHAN0  0       /* Always supported and default for all chips */
++/* These need to be power of two, and >= 4 */
+ #define DMA_TX_SIZE 512
+ #define DMA_RX_SIZE 512
+ #define STMMAC_GET_ENTRY(x, size)     ((x + 1) & (size - 1))
+@@ -411,8 +412,8 @@ extern const struct stmmac_desc_ops ndes
+ struct stmmac_dma_ops {
+       /* DMA core initialization */
+       int (*reset)(void __iomem *ioaddr);
+-      void (*init)(void __iomem *ioaddr, int pbl, int fb, int mb,
+-                   int aal, u32 dma_tx, u32 dma_rx, int atds);
++      void (*init)(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg,
++                   u32 dma_tx, u32 dma_rx, int atds);
+       /* Configure the AXI Bus Mode Register */
+       void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
+       /* Dump DMA registers */
+@@ -506,6 +507,12 @@ struct mac_link {
+ struct mii_regs {
+       unsigned int addr;      /* MII Address */
+       unsigned int data;      /* MII Data */
++      unsigned int addr_shift;        /* MII address shift */
++      unsigned int reg_shift;         /* MII reg shift */
++      unsigned int addr_mask;         /* MII address mask */
++      unsigned int reg_mask;          /* MII reg mask */
++      unsigned int clk_csr_shift;
++      unsigned int clk_csr_mask;
+ };
+ /* Helpers to manage the descriptors for chain and ring modes */
+--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
++++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
+@@ -87,7 +87,7 @@
+ #define       TDES0_ERROR_SUMMARY             BIT(15)
+ #define       TDES0_IP_HEADER_ERROR           BIT(16)
+ #define       TDES0_TIME_STAMP_STATUS         BIT(17)
+-#define       TDES0_OWN                       BIT(31)
++#define       TDES0_OWN                       ((u32)BIT(31))  /* silence sparse */
+ /* TDES1 */
+ #define       TDES1_BUFFER1_SIZE_MASK         GENMASK(10, 0)
+ #define       TDES1_BUFFER2_SIZE_MASK         GENMASK(21, 11)
+@@ -130,7 +130,7 @@
+ #define       ETDES0_FIRST_SEGMENT            BIT(28)
+ #define       ETDES0_LAST_SEGMENT             BIT(29)
+ #define       ETDES0_INTERRUPT                BIT(30)
+-#define       ETDES0_OWN                      BIT(31)
++#define       ETDES0_OWN                      ((u32)BIT(31))  /* silence sparse */
+ /* TDES1 */
+ #define       ETDES1_BUFFER1_SIZE_MASK        GENMASK(12, 0)
+ #define       ETDES1_BUFFER2_SIZE_MASK        GENMASK(28, 16)
+@@ -170,19 +170,19 @@
+ /* Basic descriptor structure for normal and alternate descriptors */
+ struct dma_desc {
+-      unsigned int des0;
+-      unsigned int des1;
+-      unsigned int des2;
+-      unsigned int des3;
++      __le32 des0;
++      __le32 des1;
++      __le32 des2;
++      __le32 des3;
+ };
+ /* Extended descriptor structure (e.g. >= databook 3.50a) */
+ struct dma_extended_desc {
+       struct dma_desc basic;  /* Basic descriptors */
+-      unsigned int des4;      /* Extended Status */
+-      unsigned int des5;      /* Reserved */
+-      unsigned int des6;      /* Tx/Rx Timestamp Low */
+-      unsigned int des7;      /* Tx/Rx Timestamp High */
++      __le32 des4;    /* Extended Status */
++      __le32 des5;    /* Reserved */
++      __le32 des6;    /* Tx/Rx Timestamp Low */
++      __le32 des7;    /* Tx/Rx Timestamp High */
+ };
+ /* Transmit checksum insertion control */
+--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
++++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+@@ -35,47 +35,50 @@
+ /* Enhanced descriptors */
+ static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
+ {
+-      p->des1 |= ((BUF_SIZE_8KiB - 1) << ERDES1_BUFFER2_SIZE_SHIFT)
+-                 & ERDES1_BUFFER2_SIZE_MASK;
++      p->des1 |= cpu_to_le32(((BUF_SIZE_8KiB - 1)
++                      << ERDES1_BUFFER2_SIZE_SHIFT)
++                 & ERDES1_BUFFER2_SIZE_MASK);
+       if (end)
+-              p->des1 |= ERDES1_END_RING;
++              p->des1 |= cpu_to_le32(ERDES1_END_RING);
+ }
+ static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int end)
+ {
+       if (end)
+-              p->des0 |= ETDES0_END_RING;
++              p->des0 |= cpu_to_le32(ETDES0_END_RING);
+       else
+-              p->des0 &= ~ETDES0_END_RING;
++              p->des0 &= cpu_to_le32(~ETDES0_END_RING);
+ }
+ static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
+ {
+       if (unlikely(len > BUF_SIZE_4KiB)) {
+-              p->des1 |= (((len - BUF_SIZE_4KiB) << ETDES1_BUFFER2_SIZE_SHIFT)
++              p->des1 |= cpu_to_le32((((len - BUF_SIZE_4KiB)
++                                      << ETDES1_BUFFER2_SIZE_SHIFT)
+                           & ETDES1_BUFFER2_SIZE_MASK) | (BUF_SIZE_4KiB
+-                          & ETDES1_BUFFER1_SIZE_MASK);
++                          & ETDES1_BUFFER1_SIZE_MASK));
+       } else
+-              p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
++              p->des1 |= cpu_to_le32((len & ETDES1_BUFFER1_SIZE_MASK));
+ }
+ /* Normal descriptors */
+ static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
+ {
+-      p->des1 |= ((BUF_SIZE_2KiB - 1) << RDES1_BUFFER2_SIZE_SHIFT)
+-                  & RDES1_BUFFER2_SIZE_MASK;
++      p->des1 |= cpu_to_le32(((BUF_SIZE_2KiB - 1)
++                              << RDES1_BUFFER2_SIZE_SHIFT)
++                  & RDES1_BUFFER2_SIZE_MASK);
+       if (end)
+-              p->des1 |= RDES1_END_RING;
++              p->des1 |= cpu_to_le32(RDES1_END_RING);
+ }
+ static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int end)
+ {
+       if (end)
+-              p->des1 |= TDES1_END_RING;
++              p->des1 |= cpu_to_le32(TDES1_END_RING);
+       else
+-              p->des1 &= ~TDES1_END_RING;
++              p->des1 &= cpu_to_le32(~TDES1_END_RING);
+ }
+ static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
+@@ -83,10 +86,11 @@ static inline void norm_set_tx_desc_len_
+       if (unlikely(len > BUF_SIZE_2KiB)) {
+               unsigned int buffer1 = (BUF_SIZE_2KiB - 1)
+                                       & TDES1_BUFFER1_SIZE_MASK;
+-              p->des1 |= ((((len - buffer1) << TDES1_BUFFER2_SIZE_SHIFT)
+-                          & TDES1_BUFFER2_SIZE_MASK) | buffer1);
++              p->des1 |= cpu_to_le32((((len - buffer1)
++                                      << TDES1_BUFFER2_SIZE_SHIFT)
++                              & TDES1_BUFFER2_SIZE_MASK) | buffer1);
+       } else
+-              p->des1 |= (len & TDES1_BUFFER1_SIZE_MASK);
++              p->des1 |= cpu_to_le32((len & TDES1_BUFFER1_SIZE_MASK));
+ }
+ /* Specific functions used for Chain mode */
+@@ -94,32 +98,32 @@ static inline void norm_set_tx_desc_len_
+ /* Enhanced descriptors */
+ static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p)
+ {
+-      p->des1 |= ERDES1_SECOND_ADDRESS_CHAINED;
++      p->des1 |= cpu_to_le32(ERDES1_SECOND_ADDRESS_CHAINED);
+ }
+ static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p)
+ {
+-      p->des0 |= ETDES0_SECOND_ADDRESS_CHAINED;
++      p->des0 |= cpu_to_le32(ETDES0_SECOND_ADDRESS_CHAINED);
+ }
+ static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
+ {
+-      p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
++      p->des1 |= cpu_to_le32(len & ETDES1_BUFFER1_SIZE_MASK);
+ }
+ /* Normal descriptors */
+ static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
+ {
+-      p->des1 |= RDES1_SECOND_ADDRESS_CHAINED;
++      p->des1 |= cpu_to_le32(RDES1_SECOND_ADDRESS_CHAINED);
+ }
+ static inline void ndesc_tx_set_on_chain(struct dma_desc *p)
+ {
+-      p->des1 |= TDES1_SECOND_ADDRESS_CHAINED;
++      p->des1 |= cpu_to_le32(TDES1_SECOND_ADDRESS_CHAINED);
+ }
+ static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
+ {
+-      p->des1 |= len & TDES1_BUFFER1_SIZE_MASK;
++      p->des1 |= cpu_to_le32(len & TDES1_BUFFER1_SIZE_MASK);
+ }
+ #endif /* __DESC_COM_H__ */
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
+@@ -71,9 +71,12 @@ err_remove_config_dt:
+ static const struct of_device_id dwmac_generic_match[] = {
+       { .compatible = "st,spear600-gmac"},
++      { .compatible = "snps,dwmac-3.50a"},
+       { .compatible = "snps,dwmac-3.610"},
+       { .compatible = "snps,dwmac-3.70a"},
+       { .compatible = "snps,dwmac-3.710"},
++      { .compatible = "snps,dwmac-4.00"},
++      { .compatible = "snps,dwmac-4.10a"},
+       { .compatible = "snps,dwmac"},
+       { }
+ };
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c
+@@ -0,0 +1,194 @@
++/*
++ * Oxford Semiconductor OXNAS DWMAC glue layer
++ *
++ * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
++ * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org>
++ * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/mfd/syscon.h>
++#include <linux/stmmac.h>
++
++#include "stmmac_platform.h"
++
++/* System Control regmap offsets */
++#define OXNAS_DWMAC_CTRL_REGOFFSET    0x78
++#define OXNAS_DWMAC_DELAY_REGOFFSET   0x100
++
++/* Control Register */
++#define DWMAC_CKEN_RX_IN        14
++#define DWMAC_CKEN_RXN_OUT      13
++#define DWMAC_CKEN_RX_OUT       12
++#define DWMAC_CKEN_TX_IN        10
++#define DWMAC_CKEN_TXN_OUT      9
++#define DWMAC_CKEN_TX_OUT       8
++#define DWMAC_RX_SOURCE         7
++#define DWMAC_TX_SOURCE         6
++#define DWMAC_LOW_TX_SOURCE     4
++#define DWMAC_AUTO_TX_SOURCE    3
++#define DWMAC_RGMII             2
++#define DWMAC_SIMPLE_MUX        1
++#define DWMAC_CKEN_GTX          0
++
++/* Delay register */
++#define DWMAC_TX_VARDELAY_SHIFT               0
++#define DWMAC_TXN_VARDELAY_SHIFT      8
++#define DWMAC_RX_VARDELAY_SHIFT               16
++#define DWMAC_RXN_VARDELAY_SHIFT      24
++#define DWMAC_TX_VARDELAY(d)          ((d) << DWMAC_TX_VARDELAY_SHIFT)
++#define DWMAC_TXN_VARDELAY(d)         ((d) << DWMAC_TXN_VARDELAY_SHIFT)
++#define DWMAC_RX_VARDELAY(d)          ((d) << DWMAC_RX_VARDELAY_SHIFT)
++#define DWMAC_RXN_VARDELAY(d)         ((d) << DWMAC_RXN_VARDELAY_SHIFT)
++
++struct oxnas_dwmac {
++      struct device   *dev;
++      struct clk      *clk;
++      struct regmap   *regmap;
++};
++
++static int oxnas_dwmac_init(struct platform_device *pdev, void *priv)
++{
++      struct oxnas_dwmac *dwmac = priv;
++      unsigned int value;
++      int ret;
++
++      /* Reset HW here before changing the glue configuration */
++      ret = device_reset(dwmac->dev);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(dwmac->clk);
++      if (ret)
++              return ret;
++
++      ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
++      if (ret < 0) {
++              clk_disable_unprepare(dwmac->clk);
++              return ret;
++      }
++
++      /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
++      value |= BIT(DWMAC_CKEN_GTX)            |
++               /* Use simple mux for 25/125 Mhz clock switching */
++               BIT(DWMAC_SIMPLE_MUX)          |
++               /* set auto switch tx clock source */
++               BIT(DWMAC_AUTO_TX_SOURCE)      |
++               /* enable tx & rx vardelay */
++               BIT(DWMAC_CKEN_TX_OUT)         |
++               BIT(DWMAC_CKEN_TXN_OUT)        |
++               BIT(DWMAC_CKEN_TX_IN)          |
++               BIT(DWMAC_CKEN_RX_OUT)         |
++               BIT(DWMAC_CKEN_RXN_OUT)        |
++               BIT(DWMAC_CKEN_RX_IN);
++      regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
++
++      /* set tx & rx vardelay */
++      value = DWMAC_TX_VARDELAY(4)    |
++              DWMAC_TXN_VARDELAY(2)   |
++              DWMAC_RX_VARDELAY(10)   |
++              DWMAC_RXN_VARDELAY(8);
++      regmap_write(dwmac->regmap, OXNAS_DWMAC_DELAY_REGOFFSET, value);
++
++      return 0;
++}
++
++static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv)
++{
++      struct oxnas_dwmac *dwmac = priv;
++
++      clk_disable_unprepare(dwmac->clk);
++}
++
++static int oxnas_dwmac_probe(struct platform_device *pdev)
++{
++      struct plat_stmmacenet_data *plat_dat;
++      struct stmmac_resources stmmac_res;
++      struct oxnas_dwmac *dwmac;
++      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) {
++              ret = -ENOMEM;
++              goto err_remove_config_dt;
++      }
++
++      dwmac->dev = &pdev->dev;
++      plat_dat->bsp_priv = dwmac;
++      plat_dat->init = oxnas_dwmac_init;
++      plat_dat->exit = oxnas_dwmac_exit;
++
++      dwmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
++                                                      "oxsemi,sys-ctrl");
++      if (IS_ERR(dwmac->regmap)) {
++              dev_err(&pdev->dev, "failed to have sysctrl regmap\n");
++              ret = PTR_ERR(dwmac->regmap);
++              goto err_remove_config_dt;
++      }
++
++      dwmac->clk = devm_clk_get(&pdev->dev, "gmac");
++      if (IS_ERR(dwmac->clk)) {
++              ret = PTR_ERR(dwmac->clk);
++              goto err_remove_config_dt;
++      }
++
++      ret = oxnas_dwmac_init(pdev, plat_dat->bsp_priv);
++      if (ret)
++              goto err_remove_config_dt;
++
++      ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++      if (ret)
++              goto err_dwmac_exit;
++
++
++      return 0;
++
++err_dwmac_exit:
++      oxnas_dwmac_exit(pdev, plat_dat->bsp_priv);
++err_remove_config_dt:
++      stmmac_remove_config_dt(pdev, plat_dat);
++
++      return ret;
++}
++
++static const struct of_device_id oxnas_dwmac_match[] = {
++      { .compatible = "oxsemi,ox820-dwmac" },
++      { }
++};
++MODULE_DEVICE_TABLE(of, oxnas_dwmac_match);
++
++static struct platform_driver oxnas_dwmac_driver = {
++      .probe  = oxnas_dwmac_probe,
++      .remove = stmmac_pltfr_remove,
++      .driver = {
++              .name           = "oxnas-dwmac",
++              .pm             = &stmmac_pltfr_pm_ops,
++              .of_match_table = oxnas_dwmac_match,
++      },
++};
++module_platform_driver(oxnas_dwmac_driver);
++
++MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
++MODULE_DESCRIPTION("Oxford Semiconductor OXNAS 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
+@@ -864,6 +864,10 @@ static int rk_gmac_powerup(struct rk_pri
+       int ret;
+       struct device *dev = &bsp_priv->pdev->dev;
++      ret = gmac_clk_enable(bsp_priv, true);
++      if (ret)
++              return ret;
++
+       /*rmii or rgmii*/
+       if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
+               dev_info(dev, "init for RGMII\n");
+@@ -880,10 +884,6 @@ static int rk_gmac_powerup(struct rk_pri
+       if (ret)
+               return ret;
+-      ret = gmac_clk_enable(bsp_priv, true);
+-      if (ret)
+-              return ret;
+-
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+@@ -901,44 +901,6 @@ static void rk_gmac_powerdown(struct rk_
+       gmac_clk_enable(gmac, false);
+ }
+-static int rk_gmac_init(struct platform_device *pdev, void *priv)
+-{
+-      struct rk_priv_data *bsp_priv = priv;
+-
+-      return rk_gmac_powerup(bsp_priv);
+-}
+-
+-static void rk_gmac_exit(struct platform_device *pdev, void *priv)
+-{
+-      struct rk_priv_data *bsp_priv = priv;
+-
+-      rk_gmac_powerdown(bsp_priv);
+-}
+-
+-static void rk_gmac_suspend(struct platform_device *pdev, void *priv)
+-{
+-      struct rk_priv_data *bsp_priv = priv;
+-
+-      /* Keep the PHY up if we use Wake-on-Lan. */
+-      if (device_may_wakeup(&pdev->dev))
+-              return;
+-
+-      rk_gmac_powerdown(bsp_priv);
+-      bsp_priv->suspended = true;
+-}
+-
+-static void rk_gmac_resume(struct platform_device *pdev, void *priv)
+-{
+-      struct rk_priv_data *bsp_priv = priv;
+-
+-      /* The PHY was up for Wake-on-Lan. */
+-      if (!bsp_priv->suspended)
+-              return;
+-
+-      rk_gmac_powerup(bsp_priv);
+-      bsp_priv->suspended = false;
+-}
+-
+ static void rk_fix_speed(void *priv, unsigned int speed)
+ {
+       struct rk_priv_data *bsp_priv = priv;
+@@ -974,11 +936,7 @@ static int rk_gmac_probe(struct platform
+               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->suspend = rk_gmac_suspend;
+-      plat_dat->resume = rk_gmac_resume;
+       plat_dat->bsp_priv = rk_gmac_setup(pdev, data);
+       if (IS_ERR(plat_dat->bsp_priv)) {
+@@ -986,24 +944,65 @@ static int rk_gmac_probe(struct platform
+               goto err_remove_config_dt;
+       }
+-      ret = rk_gmac_init(pdev, plat_dat->bsp_priv);
++      ret = rk_gmac_powerup(plat_dat->bsp_priv);
+       if (ret)
+               goto err_remove_config_dt;
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+-              goto err_gmac_exit;
++              goto err_gmac_powerdown;
+       return 0;
+-err_gmac_exit:
+-      rk_gmac_exit(pdev, plat_dat->bsp_priv);
++err_gmac_powerdown:
++      rk_gmac_powerdown(plat_dat->bsp_priv);
+ err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
+       return ret;
+ }
++static int rk_gmac_remove(struct platform_device *pdev)
++{
++      struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(&pdev->dev);
++      int ret = stmmac_dvr_remove(&pdev->dev);
++
++      rk_gmac_powerdown(bsp_priv);
++
++      return ret;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int rk_gmac_suspend(struct device *dev)
++{
++      struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev);
++      int ret = stmmac_suspend(dev);
++
++      /* Keep the PHY up if we use Wake-on-Lan. */
++      if (!device_may_wakeup(dev)) {
++              rk_gmac_powerdown(bsp_priv);
++              bsp_priv->suspended = true;
++      }
++
++      return ret;
++}
++
++static int rk_gmac_resume(struct device *dev)
++{
++      struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev);
++
++      /* The PHY was up for Wake-on-Lan. */
++      if (bsp_priv->suspended) {
++              rk_gmac_powerup(bsp_priv);
++              bsp_priv->suspended = false;
++      }
++
++      return stmmac_resume(dev);
++}
++#endif /* CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(rk_gmac_pm_ops, rk_gmac_suspend, rk_gmac_resume);
++
+ static const struct of_device_id rk_gmac_dwmac_match[] = {
+       { .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
+       { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
+@@ -1016,10 +1015,10 @@ MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_ma
+ static struct platform_driver rk_gmac_dwmac_driver = {
+       .probe  = rk_gmac_probe,
+-      .remove = stmmac_pltfr_remove,
++      .remove = rk_gmac_remove,
+       .driver = {
+               .name           = "rk_gmac-dwmac",
+-              .pm             = &stmmac_pltfr_pm_ops,
++              .pm             = &rk_gmac_pm_ops,
+               .of_match_table = rk_gmac_dwmac_match,
+       },
+ };
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+@@ -380,8 +380,8 @@ static int socfpga_dwmac_resume(struct d
+        * control register 0, and can be modified by the phy driver
+        * framework.
+        */
+-      if (priv->phydev)
+-              phy_resume(priv->phydev);
++      if (ndev->phydev)
++              phy_resume(ndev->phydev);
+       return stmmac_resume(dev);
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+@@ -126,8 +126,8 @@ struct sti_dwmac {
+       struct clk *clk;        /* PHY clock */
+       u32 ctrl_reg;           /* GMAC glue-logic control register */
+       int clk_sel_reg;        /* GMAC ext clk selection register */
+-      struct device *dev;
+       struct regmap *regmap;
++      bool gmac_en;
+       u32 speed;
+       void (*fix_retime_src)(void *priv, unsigned int speed);
+ };
+@@ -191,7 +191,7 @@ static void stih4xx_fix_retime_src(void
+               }
+       }
+-      if (src == TX_RETIME_SRC_CLKGEN && dwmac->clk && freq)
++      if (src == TX_RETIME_SRC_CLKGEN && freq)
+               clk_set_rate(dwmac->clk, freq);
+       regmap_update_bits(dwmac->regmap, reg, STIH4XX_RETIME_SRC_MASK,
+@@ -222,26 +222,20 @@ static void stid127_fix_retime_src(void
+                       freq = DWMAC_2_5MHZ;
+       }
+-      if (dwmac->clk && freq)
++      if (freq)
+               clk_set_rate(dwmac->clk, freq);
+       regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val);
+ }
+-static int sti_dwmac_init(struct platform_device *pdev, void *priv)
++static int sti_dwmac_set_mode(struct sti_dwmac *dwmac)
+ {
+-      struct sti_dwmac *dwmac = priv;
+       struct regmap *regmap = dwmac->regmap;
+       int iface = dwmac->interface;
+-      struct device *dev = dwmac->dev;
+-      struct device_node *np = dev->of_node;
+       u32 reg = dwmac->ctrl_reg;
+       u32 val;
+-      if (dwmac->clk)
+-              clk_prepare_enable(dwmac->clk);
+-
+-      if (of_property_read_bool(np, "st,gmac_en"))
++      if (dwmac->gmac_en)
+               regmap_update_bits(regmap, reg, EN_MASK, EN);
+       regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]);
+@@ -249,18 +243,11 @@ static int sti_dwmac_init(struct platfor
+       val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
+       regmap_update_bits(regmap, reg, ENMII_MASK, val);
+-      dwmac->fix_retime_src(priv, dwmac->speed);
++      dwmac->fix_retime_src(dwmac, dwmac->speed);
+       return 0;
+ }
+-static void sti_dwmac_exit(struct platform_device *pdev, void *priv)
+-{
+-      struct sti_dwmac *dwmac = priv;
+-
+-      if (dwmac->clk)
+-              clk_disable_unprepare(dwmac->clk);
+-}
+ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
+                               struct platform_device *pdev)
+ {
+@@ -270,9 +257,6 @@ static int sti_dwmac_parse_data(struct s
+       struct regmap *regmap;
+       int err;
+-      if (!np)
+-              return -EINVAL;
+-
+       /* clk selection from extra syscfg register */
+       dwmac->clk_sel_reg = -ENXIO;
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf");
+@@ -289,9 +273,9 @@ static int sti_dwmac_parse_data(struct s
+               return err;
+       }
+-      dwmac->dev = dev;
+       dwmac->interface = of_get_phy_mode(np);
+       dwmac->regmap = regmap;
++      dwmac->gmac_en = of_property_read_bool(np, "st,gmac_en");
+       dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk");
+       dwmac->tx_retime_src = TX_RETIME_SRC_NA;
+       dwmac->speed = SPEED_100;
+@@ -359,28 +343,65 @@ static int sti_dwmac_probe(struct platfo
+       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);
++      ret = clk_prepare_enable(dwmac->clk);
+       if (ret)
+               goto err_remove_config_dt;
++      ret = sti_dwmac_set_mode(dwmac);
++      if (ret)
++              goto disable_clk;
++
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+-              goto err_dwmac_exit;
++              goto disable_clk;
+       return 0;
+-err_dwmac_exit:
+-      sti_dwmac_exit(pdev, plat_dat->bsp_priv);
++disable_clk:
++      clk_disable_unprepare(dwmac->clk);
+ err_remove_config_dt:
+       stmmac_remove_config_dt(pdev, plat_dat);
+       return ret;
+ }
++static int sti_dwmac_remove(struct platform_device *pdev)
++{
++      struct sti_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
++      int ret = stmmac_dvr_remove(&pdev->dev);
++
++      clk_disable_unprepare(dwmac->clk);
++
++      return ret;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int sti_dwmac_suspend(struct device *dev)
++{
++      struct sti_dwmac *dwmac = get_stmmac_bsp_priv(dev);
++      int ret = stmmac_suspend(dev);
++
++      clk_disable_unprepare(dwmac->clk);
++
++      return ret;
++}
++
++static int sti_dwmac_resume(struct device *dev)
++{
++      struct sti_dwmac *dwmac = get_stmmac_bsp_priv(dev);
++
++      clk_prepare_enable(dwmac->clk);
++      sti_dwmac_set_mode(dwmac);
++
++      return stmmac_resume(dev);
++}
++#endif /* CONFIG_PM_SLEEP */
++
++static SIMPLE_DEV_PM_OPS(sti_dwmac_pm_ops, sti_dwmac_suspend,
++                                         sti_dwmac_resume);
++
+ static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
+       .fix_retime_src = stih4xx_fix_retime_src,
+ };
+@@ -400,10 +421,10 @@ MODULE_DEVICE_TABLE(of, sti_dwmac_match)
+ static struct platform_driver sti_dwmac_driver = {
+       .probe  = sti_dwmac_probe,
+-      .remove = stmmac_pltfr_remove,
++      .remove = sti_dwmac_remove,
+       .driver = {
+               .name           = "sti-dwmac",
+-              .pm             = &stmmac_pltfr_pm_ops,
++              .pm             = &sti_dwmac_pm_ops,
+               .of_match_table = sti_dwmac_match,
+       },
+ };
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+@@ -225,7 +225,7 @@ enum rx_tx_priority_ratio {
+ #define DMA_BUS_MODE_FB               0x00010000      /* Fixed burst */
+ #define DMA_BUS_MODE_MB               0x04000000      /* Mixed burst */
+-#define DMA_BUS_MODE_RPBL_MASK        0x003e0000      /* Rx-Programmable Burst Len */
++#define DMA_BUS_MODE_RPBL_MASK        0x007e0000      /* Rx-Programmable Burst Len */
+ #define DMA_BUS_MODE_RPBL_SHIFT       17
+ #define DMA_BUS_MODE_USP      0x00800000
+ #define DMA_BUS_MODE_MAXPBL   0x01000000
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+@@ -538,6 +538,12 @@ struct mac_device_info *dwmac1000_setup(
+       mac->link.speed = GMAC_CONTROL_FES;
+       mac->mii.addr = GMAC_MII_ADDR;
+       mac->mii.data = GMAC_MII_DATA;
++      mac->mii.addr_shift = 11;
++      mac->mii.addr_mask = 0x0000F800;
++      mac->mii.reg_shift = 6;
++      mac->mii.reg_mask = 0x000007C0;
++      mac->mii.clk_csr_shift = 2;
++      mac->mii.clk_csr_mask = GENMASK(5, 2);
+       /* Get and dump the chip ID */
+       *synopsys_id = stmmac_get_synopsys_id(hwid);
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+@@ -84,37 +84,39 @@ static void dwmac1000_dma_axi(void __iom
+       writel(value, ioaddr + DMA_AXI_BUS_MODE);
+ }
+-static void dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+-                             int aal, u32 dma_tx, u32 dma_rx, int atds)
++static void dwmac1000_dma_init(void __iomem *ioaddr,
++                             struct stmmac_dma_cfg *dma_cfg,
++                             u32 dma_tx, u32 dma_rx, int atds)
+ {
+       u32 value = readl(ioaddr + DMA_BUS_MODE);
++      int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
++      int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
+       /*
+        * Set the DMA PBL (Programmable Burst Length) mode.
+        *
+        * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
+        * post 3.5 mode bit acts as 8*PBL.
+-       *
+-       * This configuration doesn't take care about the Separate PBL
+-       * so only the bits: 13-8 are programmed with the PBL passed from the
+-       * platform.
+        */
+-      value |= DMA_BUS_MODE_MAXPBL;
+-      value &= ~DMA_BUS_MODE_PBL_MASK;
+-      value |= (pbl << DMA_BUS_MODE_PBL_SHIFT);
++      if (dma_cfg->pblx8)
++              value |= DMA_BUS_MODE_MAXPBL;
++      value |= DMA_BUS_MODE_USP;
++      value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
++      value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
++      value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
+       /* Set the Fixed burst mode */
+-      if (fb)
++      if (dma_cfg->fixed_burst)
+               value |= DMA_BUS_MODE_FB;
+       /* Mixed Burst has no effect when fb is set */
+-      if (mb)
++      if (dma_cfg->mixed_burst)
+               value |= DMA_BUS_MODE_MB;
+       if (atds)
+               value |= DMA_BUS_MODE_ATDS;
+-      if (aal)
++      if (dma_cfg->aal)
+               value |= DMA_BUS_MODE_AAL;
+       writel(value, ioaddr + DMA_BUS_MODE);
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+@@ -192,6 +192,13 @@ struct mac_device_info *dwmac100_setup(v
+       mac->link.speed = 0;
+       mac->mii.addr = MAC_MII_ADDR;
+       mac->mii.data = MAC_MII_DATA;
++      mac->mii.addr_shift = 11;
++      mac->mii.addr_mask = 0x0000F800;
++      mac->mii.reg_shift = 6;
++      mac->mii.reg_mask = 0x000007C0;
++      mac->mii.clk_csr_shift = 2;
++      mac->mii.clk_csr_mask = GENMASK(5, 2);
++
+       /* Synopsys Id is not available on old chips */
+       *synopsys_id = 0;
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+@@ -32,11 +32,12 @@
+ #include "dwmac100.h"
+ #include "dwmac_dma.h"
+-static void dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+-                            int aal, u32 dma_tx, u32 dma_rx, int atds)
++static void dwmac100_dma_init(void __iomem *ioaddr,
++                            struct stmmac_dma_cfg *dma_cfg,
++                            u32 dma_tx, u32 dma_rx, int atds)
+ {
+       /* Enable Application Access by writing to DMA CSR0 */
+-      writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
++      writel(DMA_BUS_MODE_DEFAULT | (dma_cfg->pbl << DMA_BUS_MODE_PBL_SHIFT),
+              ioaddr + DMA_BUS_MODE);
+       /* Mask interrupts by writing to CSR7 */
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+@@ -155,8 +155,11 @@ enum power_event {
+ #define MTL_CHAN_RX_DEBUG(x)          (MTL_CHANX_BASE_ADDR(x) + 0x38)
+ #define MTL_OP_MODE_RSF                       BIT(5)
++#define MTL_OP_MODE_TXQEN             BIT(3)
+ #define MTL_OP_MODE_TSF                       BIT(1)
++#define MTL_OP_MODE_TQS_MASK          GENMASK(24, 16)
++
+ #define MTL_OP_MODE_TTC_MASK          0x70
+ #define MTL_OP_MODE_TTC_SHIFT         4
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+@@ -430,6 +430,12 @@ struct mac_device_info *dwmac4_setup(voi
+       mac->link.speed = GMAC_CONFIG_FES;
+       mac->mii.addr = GMAC_MDIO_ADDR;
+       mac->mii.data = GMAC_MDIO_DATA;
++      mac->mii.addr_shift = 21;
++      mac->mii.addr_mask = GENMASK(25, 21);
++      mac->mii.reg_shift = 16;
++      mac->mii.reg_mask = GENMASK(20, 16);
++      mac->mii.clk_csr_shift = 8;
++      mac->mii.clk_csr_mask = GENMASK(11, 8);
+       /* Get and dump the chip ID */
+       *synopsys_id = stmmac_get_synopsys_id(hwid);
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+@@ -23,7 +23,7 @@ static int dwmac4_wrback_get_tx_status(v
+       unsigned int tdes3;
+       int ret = tx_done;
+-      tdes3 = p->des3;
++      tdes3 = le32_to_cpu(p->des3);
+       /* Get tx owner first */
+       if (unlikely(tdes3 & TDES3_OWN))
+@@ -77,9 +77,9 @@ static int dwmac4_wrback_get_rx_status(v
+                                      struct dma_desc *p)
+ {
+       struct net_device_stats *stats = (struct net_device_stats *)data;
+-      unsigned int rdes1 = p->des1;
+-      unsigned int rdes2 = p->des2;
+-      unsigned int rdes3 = p->des3;
++      unsigned int rdes1 = le32_to_cpu(p->des1);
++      unsigned int rdes2 = le32_to_cpu(p->des2);
++      unsigned int rdes3 = le32_to_cpu(p->des3);
+       int message_type;
+       int ret = good_frame;
+@@ -176,47 +176,48 @@ static int dwmac4_wrback_get_rx_status(v
+ static int dwmac4_rd_get_tx_len(struct dma_desc *p)
+ {
+-      return (p->des2 & TDES2_BUFFER1_SIZE_MASK);
++      return (le32_to_cpu(p->des2) & TDES2_BUFFER1_SIZE_MASK);
+ }
+ static int dwmac4_get_tx_owner(struct dma_desc *p)
+ {
+-      return (p->des3 & TDES3_OWN) >> TDES3_OWN_SHIFT;
++      return (le32_to_cpu(p->des3) & TDES3_OWN) >> TDES3_OWN_SHIFT;
+ }
+ static void dwmac4_set_tx_owner(struct dma_desc *p)
+ {
+-      p->des3 |= TDES3_OWN;
++      p->des3 |= cpu_to_le32(TDES3_OWN);
+ }
+ static void dwmac4_set_rx_owner(struct dma_desc *p)
+ {
+-      p->des3 |= RDES3_OWN;
++      p->des3 |= cpu_to_le32(RDES3_OWN);
+ }
+ static int dwmac4_get_tx_ls(struct dma_desc *p)
+ {
+-      return (p->des3 & TDES3_LAST_DESCRIPTOR) >> TDES3_LAST_DESCRIPTOR_SHIFT;
++      return (le32_to_cpu(p->des3) & TDES3_LAST_DESCRIPTOR)
++              >> TDES3_LAST_DESCRIPTOR_SHIFT;
+ }
+ static int dwmac4_wrback_get_rx_frame_len(struct dma_desc *p, int rx_coe)
+ {
+-      return (p->des3 & RDES3_PACKET_SIZE_MASK);
++      return (le32_to_cpu(p->des3) & RDES3_PACKET_SIZE_MASK);
+ }
+ static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p)
+ {
+-      p->des2 |= TDES2_TIMESTAMP_ENABLE;
++      p->des2 |= cpu_to_le32(TDES2_TIMESTAMP_ENABLE);
+ }
+ static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p)
+ {
+       /* Context type from W/B descriptor must be zero */
+-      if (p->des3 & TDES3_CONTEXT_TYPE)
++      if (le32_to_cpu(p->des3) & TDES3_CONTEXT_TYPE)
+               return -EINVAL;
+       /* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
+-      if (p->des3 & TDES3_TIMESTAMP_STATUS)
++      if (le32_to_cpu(p->des3) & TDES3_TIMESTAMP_STATUS)
+               return 0;
+       return 1;
+@@ -227,9 +228,9 @@ static inline u64 dwmac4_get_timestamp(v
+       struct dma_desc *p = (struct dma_desc *)desc;
+       u64 ns;
+-      ns = p->des0;
++      ns = le32_to_cpu(p->des0);
+       /* convert high/sec time stamp value to nanosecond */
+-      ns += p->des1 * 1000000000ULL;
++      ns += le32_to_cpu(p->des1) * 1000000000ULL;
+       return ns;
+ }
+@@ -264,7 +265,7 @@ static int dwmac4_wrback_get_rx_timestam
+       /* Get the status from normal w/b descriptor */
+       if (likely(p->des3 & TDES3_RS1V)) {
+-              if (likely(p->des1 & RDES1_TIMESTAMP_AVAILABLE)) {
++              if (likely(le32_to_cpu(p->des1) & RDES1_TIMESTAMP_AVAILABLE)) {
+                       int i = 0;
+                       /* Check if timestamp is OK from context descriptor */
+@@ -287,10 +288,10 @@ exit:
+ static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
+                                  int mode, int end)
+ {
+-      p->des3 = RDES3_OWN | RDES3_BUFFER1_VALID_ADDR;
++      p->des3 = cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR);
+       if (!disable_rx_ic)
+-              p->des3 |= RDES3_INT_ON_COMPLETION_EN;
++              p->des3 |= cpu_to_le32(RDES3_INT_ON_COMPLETION_EN);
+ }
+ static void dwmac4_rd_init_tx_desc(struct dma_desc *p, int mode, int end)
+@@ -305,9 +306,9 @@ static void dwmac4_rd_prepare_tx_desc(st
+                                     bool csum_flag, int mode, bool tx_own,
+                                     bool ls)
+ {
+-      unsigned int tdes3 = p->des3;
++      unsigned int tdes3 = le32_to_cpu(p->des3);
+-      p->des2 |= (len & TDES2_BUFFER1_SIZE_MASK);
++      p->des2 |= cpu_to_le32(len & TDES2_BUFFER1_SIZE_MASK);
+       if (is_fs)
+               tdes3 |= TDES3_FIRST_DESCRIPTOR;
+@@ -333,9 +334,9 @@ static void dwmac4_rd_prepare_tx_desc(st
+                * descriptors for the same frame has to be set before, to
+                * avoid race condition.
+                */
+-              wmb();
++              dma_wmb();
+-      p->des3 = tdes3;
++      p->des3 = cpu_to_le32(tdes3);
+ }
+ static void dwmac4_rd_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
+@@ -343,14 +344,14 @@ static void dwmac4_rd_prepare_tso_tx_des
+                                         bool ls, unsigned int tcphdrlen,
+                                         unsigned int tcppayloadlen)
+ {
+-      unsigned int tdes3 = p->des3;
++      unsigned int tdes3 = le32_to_cpu(p->des3);
+       if (len1)
+-              p->des2 |= (len1 & TDES2_BUFFER1_SIZE_MASK);
++              p->des2 |= cpu_to_le32((len1 & TDES2_BUFFER1_SIZE_MASK));
+       if (len2)
+-              p->des2 |= (len2 << TDES2_BUFFER2_SIZE_MASK_SHIFT)
+-                          & TDES2_BUFFER2_SIZE_MASK;
++              p->des2 |= cpu_to_le32((len2 << TDES2_BUFFER2_SIZE_MASK_SHIFT)
++                          & TDES2_BUFFER2_SIZE_MASK);
+       if (is_fs) {
+               tdes3 |= TDES3_FIRST_DESCRIPTOR |
+@@ -376,9 +377,9 @@ static void dwmac4_rd_prepare_tso_tx_des
+                * descriptors for the same frame has to be set before, to
+                * avoid race condition.
+                */
+-              wmb();
++              dma_wmb();
+-      p->des3 = tdes3;
++      p->des3 = cpu_to_le32(tdes3);
+ }
+ static void dwmac4_release_tx_desc(struct dma_desc *p, int mode)
+@@ -389,7 +390,7 @@ static void dwmac4_release_tx_desc(struc
+ static void dwmac4_rd_set_tx_ic(struct dma_desc *p)
+ {
+-      p->des2 |= TDES2_INTERRUPT_ON_COMPLETION;
++      p->des2 |= cpu_to_le32(TDES2_INTERRUPT_ON_COMPLETION);
+ }
+ static void dwmac4_display_ring(void *head, unsigned int size, bool rx)
+@@ -402,7 +403,8 @@ static void dwmac4_display_ring(void *he
+       for (i = 0; i < size; i++) {
+               pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+                       i, (unsigned int)virt_to_phys(p),
+-                      p->des0, p->des1, p->des2, p->des3);
++                      le32_to_cpu(p->des0), le32_to_cpu(p->des1),
++                      le32_to_cpu(p->des2), le32_to_cpu(p->des3));
+               p++;
+       }
+ }
+@@ -411,8 +413,8 @@ static void dwmac4_set_mss_ctxt(struct d
+ {
+       p->des0 = 0;
+       p->des1 = 0;
+-      p->des2 = mss;
+-      p->des3 = TDES3_CONTEXT_TYPE | TDES3_CTXT_TCMSSV;
++      p->des2 = cpu_to_le32(mss);
++      p->des3 = cpu_to_le32(TDES3_CONTEXT_TYPE | TDES3_CTXT_TCMSSV);
+ }
+ const struct stmmac_desc_ops dwmac4_desc_ops = {
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+@@ -71,25 +71,29 @@ static void dwmac4_dma_axi(void __iomem
+       writel(value, ioaddr + DMA_SYS_BUS_MODE);
+ }
+-static void dwmac4_dma_init_channel(void __iomem *ioaddr, int pbl,
++static void dwmac4_dma_init_channel(void __iomem *ioaddr,
++                                  struct stmmac_dma_cfg *dma_cfg,
+                                   u32 dma_tx_phy, u32 dma_rx_phy,
+                                   u32 channel)
+ {
+       u32 value;
++      int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
++      int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
+       /* set PBL for each channels. Currently we affect same configuration
+        * on each channel
+        */
+       value = readl(ioaddr + DMA_CHAN_CONTROL(channel));
+-      value = value | DMA_BUS_MODE_PBL;
++      if (dma_cfg->pblx8)
++              value = value | DMA_BUS_MODE_PBL;
+       writel(value, ioaddr + DMA_CHAN_CONTROL(channel));
+       value = readl(ioaddr + DMA_CHAN_TX_CONTROL(channel));
+-      value = value | (pbl << DMA_BUS_MODE_PBL_SHIFT);
++      value = value | (txpbl << DMA_BUS_MODE_PBL_SHIFT);
+       writel(value, ioaddr + DMA_CHAN_TX_CONTROL(channel));
+       value = readl(ioaddr + DMA_CHAN_RX_CONTROL(channel));
+-      value = value | (pbl << DMA_BUS_MODE_RPBL_SHIFT);
++      value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
+       writel(value, ioaddr + DMA_CHAN_RX_CONTROL(channel));
+       /* Mask interrupts by writing to CSR7 */
+@@ -99,27 +103,28 @@ static void dwmac4_dma_init_channel(void
+       writel(dma_rx_phy, ioaddr + DMA_CHAN_RX_BASE_ADDR(channel));
+ }
+-static void dwmac4_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+-                          int aal, u32 dma_tx, u32 dma_rx, int atds)
++static void dwmac4_dma_init(void __iomem *ioaddr,
++                          struct stmmac_dma_cfg *dma_cfg,
++                          u32 dma_tx, u32 dma_rx, int atds)
+ {
+       u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
+       int i;
+       /* Set the Fixed burst mode */
+-      if (fb)
++      if (dma_cfg->fixed_burst)
+               value |= DMA_SYS_BUS_FB;
+       /* Mixed Burst has no effect when fb is set */
+-      if (mb)
++      if (dma_cfg->mixed_burst)
+               value |= DMA_SYS_BUS_MB;
+-      if (aal)
++      if (dma_cfg->aal)
+               value |= DMA_SYS_BUS_AAL;
+       writel(value, ioaddr + DMA_SYS_BUS_MODE);
+       for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
+-              dwmac4_dma_init_channel(ioaddr, pbl, dma_tx, dma_rx, i);
++              dwmac4_dma_init_channel(ioaddr, dma_cfg, dma_tx, dma_rx, i);
+ }
+ static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel)
+@@ -215,7 +220,17 @@ static void dwmac4_dma_chan_op_mode(void
+               else
+                       mtl_tx_op |= MTL_OP_MODE_TTC_512;
+       }
+-
++      /* For an IP with DWC_EQOS_NUM_TXQ == 1, the fields TXQEN and TQS are RO
++       * with reset values: TXQEN on, TQS == DWC_EQOS_TXFIFO_SIZE.
++       * For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
++       * with reset values: TXQEN off, TQS 256 bytes.
++       *
++       * Write the bits in both cases, since it will have no effect when RO.
++       * For DWC_EQOS_NUM_TXQ > 1, the top bits in MTL_OP_MODE_TQS_MASK might
++       * be RO, however, writing the whole TQS field will result in a value
++       * equal to DWC_EQOS_TXFIFO_SIZE, just like for DWC_EQOS_NUM_TXQ == 1.
++       */
++      mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
+       writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
+       mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel));
+--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
++++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+@@ -30,7 +30,7 @@ static int enh_desc_get_tx_status(void *
+                                 struct dma_desc *p, void __iomem *ioaddr)
+ {
+       struct net_device_stats *stats = (struct net_device_stats *)data;
+-      unsigned int tdes0 = p->des0;
++      unsigned int tdes0 = le32_to_cpu(p->des0);
+       int ret = tx_done;
+       /* Get tx owner first */
+@@ -95,7 +95,7 @@ static int enh_desc_get_tx_status(void *
+ static int enh_desc_get_tx_len(struct dma_desc *p)
+ {
+-      return (p->des1 & ETDES1_BUFFER1_SIZE_MASK);
++      return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
+ }
+ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
+@@ -134,8 +134,8 @@ static int enh_desc_coe_rdes0(int ipc_er
+ static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
+                                   struct dma_extended_desc *p)
+ {
+-      unsigned int rdes0 = p->basic.des0;
+-      unsigned int rdes4 = p->des4;
++      unsigned int rdes0 = le32_to_cpu(p->basic.des0);
++      unsigned int rdes4 = le32_to_cpu(p->des4);
+       if (unlikely(rdes0 & ERDES0_RX_MAC_ADDR)) {
+               int message_type = (rdes4 & ERDES4_MSG_TYPE_MASK) >> 8;
+@@ -199,7 +199,7 @@ static int enh_desc_get_rx_status(void *
+                                 struct dma_desc *p)
+ {
+       struct net_device_stats *stats = (struct net_device_stats *)data;
+-      unsigned int rdes0 = p->des0;
++      unsigned int rdes0 = le32_to_cpu(p->des0);
+       int ret = good_frame;
+       if (unlikely(rdes0 & RDES0_OWN))
+@@ -265,8 +265,8 @@ static int enh_desc_get_rx_status(void *
+ static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
+                                 int mode, int end)
+ {
+-      p->des0 |= RDES0_OWN;
+-      p->des1 |= ((BUF_SIZE_8KiB - 1) & ERDES1_BUFFER1_SIZE_MASK);
++      p->des0 |= cpu_to_le32(RDES0_OWN);
++      p->des1 |= cpu_to_le32((BUF_SIZE_8KiB - 1) & ERDES1_BUFFER1_SIZE_MASK);
+       if (mode == STMMAC_CHAIN_MODE)
+               ehn_desc_rx_set_on_chain(p);
+@@ -274,12 +274,12 @@ static void enh_desc_init_rx_desc(struct
+               ehn_desc_rx_set_on_ring(p, end);
+       if (disable_rx_ic)
+-              p->des1 |= ERDES1_DISABLE_IC;
++              p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);
+ }
+ static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
+ {
+-      p->des0 &= ~ETDES0_OWN;
++      p->des0 &= cpu_to_le32(~ETDES0_OWN);
+       if (mode == STMMAC_CHAIN_MODE)
+               enh_desc_end_tx_desc_on_chain(p);
+       else
+@@ -288,27 +288,27 @@ static void enh_desc_init_tx_desc(struct
+ static int enh_desc_get_tx_owner(struct dma_desc *p)
+ {
+-      return (p->des0 & ETDES0_OWN) >> 31;
++      return (le32_to_cpu(p->des0) & ETDES0_OWN) >> 31;
+ }
+ static void enh_desc_set_tx_owner(struct dma_desc *p)
+ {
+-      p->des0 |= ETDES0_OWN;
++      p->des0 |= cpu_to_le32(ETDES0_OWN);
+ }
+ static void enh_desc_set_rx_owner(struct dma_desc *p)
+ {
+-      p->des0 |= RDES0_OWN;
++      p->des0 |= cpu_to_le32(RDES0_OWN);
+ }
+ static int enh_desc_get_tx_ls(struct dma_desc *p)
+ {
+-      return (p->des0 & ETDES0_LAST_SEGMENT) >> 29;
++      return (le32_to_cpu(p->des0) & ETDES0_LAST_SEGMENT) >> 29;
+ }
+ static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
+ {
+-      int ter = (p->des0 & ETDES0_END_RING) >> 21;
++      int ter = (le32_to_cpu(p->des0) & ETDES0_END_RING) >> 21;
+       memset(p, 0, offsetof(struct dma_desc, des2));
+       if (mode == STMMAC_CHAIN_MODE)
+@@ -321,7 +321,7 @@ static void enh_desc_prepare_tx_desc(str
+                                    bool csum_flag, int mode, bool tx_own,
+                                    bool ls)
+ {
+-      unsigned int tdes0 = p->des0;
++      unsigned int tdes0 = le32_to_cpu(p->des0);
+       if (mode == STMMAC_CHAIN_MODE)
+               enh_set_tx_desc_len_on_chain(p, len);
+@@ -350,14 +350,14 @@ static void enh_desc_prepare_tx_desc(str
+                * descriptors for the same frame has to be set before, to
+                * avoid race condition.
+                */
+-              wmb();
++              dma_wmb();
+-      p->des0 = tdes0;
++      p->des0 = cpu_to_le32(tdes0);
+ }
+ static void enh_desc_set_tx_ic(struct dma_desc *p)
+ {
+-      p->des0 |= ETDES0_INTERRUPT;
++      p->des0 |= cpu_to_le32(ETDES0_INTERRUPT);
+ }
+ static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
+@@ -372,18 +372,18 @@ static int enh_desc_get_rx_frame_len(str
+       if (rx_coe_type == STMMAC_RX_COE_TYPE1)
+               csum = 2;
+-      return (((p->des0 & RDES0_FRAME_LEN_MASK) >> RDES0_FRAME_LEN_SHIFT) -
+-              csum);
++      return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
++                              >> RDES0_FRAME_LEN_SHIFT) - csum);
+ }
+ static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
+ {
+-      p->des0 |= ETDES0_TIME_STAMP_ENABLE;
++      p->des0 |= cpu_to_le32(ETDES0_TIME_STAMP_ENABLE);
+ }
+ static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
+ {
+-      return (p->des0 & ETDES0_TIME_STAMP_STATUS) >> 17;
++      return (le32_to_cpu(p->des0) & ETDES0_TIME_STAMP_STATUS) >> 17;
+ }
+ static u64 enh_desc_get_timestamp(void *desc, u32 ats)
+@@ -392,13 +392,13 @@ static u64 enh_desc_get_timestamp(void *
+       if (ats) {
+               struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
+-              ns = p->des6;
++              ns = le32_to_cpu(p->des6);
+               /* convert high/sec time stamp value to nanosecond */
+-              ns += p->des7 * 1000000000ULL;
++              ns += le32_to_cpu(p->des7) * 1000000000ULL;
+       } else {
+               struct dma_desc *p = (struct dma_desc *)desc;
+-              ns = p->des2;
+-              ns += p->des3 * 1000000000ULL;
++              ns = le32_to_cpu(p->des2);
++              ns += le32_to_cpu(p->des3) * 1000000000ULL;
+       }
+       return ns;
+@@ -408,10 +408,11 @@ static int enh_desc_get_rx_timestamp_sta
+ {
+       if (ats) {
+               struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
+-              return (p->basic.des0 & RDES0_IPC_CSUM_ERROR) >> 7;
++              return (le32_to_cpu(p->basic.des0) & RDES0_IPC_CSUM_ERROR) >> 7;
+       } else {
+               struct dma_desc *p = (struct dma_desc *)desc;
+-              if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
++              if ((le32_to_cpu(p->des2) == 0xffffffff) &&
++                  (le32_to_cpu(p->des3) == 0xffffffff))
+                       /* timestamp is corrupted, hence don't store it */
+                       return 0;
+               else
+--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
++++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+@@ -30,8 +30,8 @@ static int ndesc_get_tx_status(void *dat
+                              struct dma_desc *p, void __iomem *ioaddr)
+ {
+       struct net_device_stats *stats = (struct net_device_stats *)data;
+-      unsigned int tdes0 = p->des0;
+-      unsigned int tdes1 = p->des1;
++      unsigned int tdes0 = le32_to_cpu(p->des0);
++      unsigned int tdes1 = le32_to_cpu(p->des1);
+       int ret = tx_done;
+       /* Get tx owner first */
+@@ -77,7 +77,7 @@ static int ndesc_get_tx_status(void *dat
+ static int ndesc_get_tx_len(struct dma_desc *p)
+ {
+-      return (p->des1 & RDES1_BUFFER1_SIZE_MASK);
++      return (le32_to_cpu(p->des1) & RDES1_BUFFER1_SIZE_MASK);
+ }
+ /* This function verifies if each incoming frame has some errors
+@@ -88,7 +88,7 @@ static int ndesc_get_rx_status(void *dat
+                              struct dma_desc *p)
+ {
+       int ret = good_frame;
+-      unsigned int rdes0 = p->des0;
++      unsigned int rdes0 = le32_to_cpu(p->des0);
+       struct net_device_stats *stats = (struct net_device_stats *)data;
+       if (unlikely(rdes0 & RDES0_OWN))
+@@ -141,8 +141,8 @@ static int ndesc_get_rx_status(void *dat
+ static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
+                              int end)
+ {
+-      p->des0 |= RDES0_OWN;
+-      p->des1 |= (BUF_SIZE_2KiB - 1) & RDES1_BUFFER1_SIZE_MASK;
++      p->des0 |= cpu_to_le32(RDES0_OWN);
++      p->des1 |= cpu_to_le32((BUF_SIZE_2KiB - 1) & RDES1_BUFFER1_SIZE_MASK);
+       if (mode == STMMAC_CHAIN_MODE)
+               ndesc_rx_set_on_chain(p, end);
+@@ -150,12 +150,12 @@ static void ndesc_init_rx_desc(struct dm
+               ndesc_rx_set_on_ring(p, end);
+       if (disable_rx_ic)
+-              p->des1 |= RDES1_DISABLE_IC;
++              p->des1 |= cpu_to_le32(RDES1_DISABLE_IC);
+ }
+ static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
+ {
+-      p->des0 &= ~TDES0_OWN;
++      p->des0 &= cpu_to_le32(~TDES0_OWN);
+       if (mode == STMMAC_CHAIN_MODE)
+               ndesc_tx_set_on_chain(p);
+       else
+@@ -164,27 +164,27 @@ static void ndesc_init_tx_desc(struct dm
+ static int ndesc_get_tx_owner(struct dma_desc *p)
+ {
+-      return (p->des0 & TDES0_OWN) >> 31;
++      return (le32_to_cpu(p->des0) & TDES0_OWN) >> 31;
+ }
+ static void ndesc_set_tx_owner(struct dma_desc *p)
+ {
+-      p->des0 |= TDES0_OWN;
++      p->des0 |= cpu_to_le32(TDES0_OWN);
+ }
+ static void ndesc_set_rx_owner(struct dma_desc *p)
+ {
+-      p->des0 |= RDES0_OWN;
++      p->des0 |= cpu_to_le32(RDES0_OWN);
+ }
+ static int ndesc_get_tx_ls(struct dma_desc *p)
+ {
+-      return (p->des1 & TDES1_LAST_SEGMENT) >> 30;
++      return (le32_to_cpu(p->des1) & TDES1_LAST_SEGMENT) >> 30;
+ }
+ static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
+ {
+-      int ter = (p->des1 & TDES1_END_RING) >> 25;
++      int ter = (le32_to_cpu(p->des1) & TDES1_END_RING) >> 25;
+       memset(p, 0, offsetof(struct dma_desc, des2));
+       if (mode == STMMAC_CHAIN_MODE)
+@@ -197,7 +197,7 @@ static void ndesc_prepare_tx_desc(struct
+                                 bool csum_flag, int mode, bool tx_own,
+                                 bool ls)
+ {
+-      unsigned int tdes1 = p->des1;
++      unsigned int tdes1 = le32_to_cpu(p->des1);
+       if (is_fs)
+               tdes1 |= TDES1_FIRST_SEGMENT;
+@@ -212,7 +212,7 @@ static void ndesc_prepare_tx_desc(struct
+       if (ls)
+               tdes1 |= TDES1_LAST_SEGMENT;
+-      p->des1 = tdes1;
++      p->des1 = cpu_to_le32(tdes1);
+       if (mode == STMMAC_CHAIN_MODE)
+               norm_set_tx_desc_len_on_chain(p, len);
+@@ -220,12 +220,12 @@ static void ndesc_prepare_tx_desc(struct
+               norm_set_tx_desc_len_on_ring(p, len);
+       if (tx_own)
+-              p->des0 |= TDES0_OWN;
++              p->des0 |= cpu_to_le32(TDES0_OWN);
+ }
+ static void ndesc_set_tx_ic(struct dma_desc *p)
+ {
+-      p->des1 |= TDES1_INTERRUPT;
++      p->des1 |= cpu_to_le32(TDES1_INTERRUPT);
+ }
+ static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
+@@ -241,19 +241,20 @@ static int ndesc_get_rx_frame_len(struct
+       if (rx_coe_type == STMMAC_RX_COE_TYPE1)
+               csum = 2;
+-      return (((p->des0 & RDES0_FRAME_LEN_MASK) >> RDES0_FRAME_LEN_SHIFT) -
++      return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
++                              >> RDES0_FRAME_LEN_SHIFT) -
+               csum);
+ }
+ static void ndesc_enable_tx_timestamp(struct dma_desc *p)
+ {
+-      p->des1 |= TDES1_TIME_STAMP_ENABLE;
++      p->des1 |= cpu_to_le32(TDES1_TIME_STAMP_ENABLE);
+ }
+ static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
+ {
+-      return (p->des0 & TDES0_TIME_STAMP_STATUS) >> 17;
++      return (le32_to_cpu(p->des0) & TDES0_TIME_STAMP_STATUS) >> 17;
+ }
+ static u64 ndesc_get_timestamp(void *desc, u32 ats)
+@@ -261,9 +262,9 @@ static u64 ndesc_get_timestamp(void *des
+       struct dma_desc *p = (struct dma_desc *)desc;
+       u64 ns;
+-      ns = p->des2;
++      ns = le32_to_cpu(p->des2);
+       /* convert high/sec time stamp value to nanosecond */
+-      ns += p->des3 * 1000000000ULL;
++      ns += le32_to_cpu(p->des3) * 1000000000ULL;
+       return ns;
+ }
+@@ -272,7 +273,8 @@ static int ndesc_get_rx_timestamp_status
+ {
+       struct dma_desc *p = (struct dma_desc *)desc;
+-      if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
++      if ((le32_to_cpu(p->des2) == 0xffffffff) &&
++          (le32_to_cpu(p->des3) == 0xffffffff))
+               /* timestamp is corrupted, hence don't store it */
+               return 0;
+       else
+--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
++++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+@@ -34,7 +34,7 @@ static int stmmac_jumbo_frm(void *p, str
+       unsigned int entry = priv->cur_tx;
+       struct dma_desc *desc;
+       unsigned int nopaged_len = skb_headlen(skb);
+-      unsigned int bmax, len;
++      unsigned int bmax, len, des2;
+       if (priv->extend_desc)
+               desc = (struct dma_desc *)(priv->dma_etx + entry);
+@@ -50,16 +50,17 @@ static int stmmac_jumbo_frm(void *p, str
+       if (nopaged_len > BUF_SIZE_8KiB) {
+-              desc->des2 = dma_map_single(priv->device, skb->data,
+-                                          bmax, DMA_TO_DEVICE);
+-              if (dma_mapping_error(priv->device, desc->des2))
++              des2 = dma_map_single(priv->device, skb->data, bmax,
++                                    DMA_TO_DEVICE);
++              desc->des2 = cpu_to_le32(des2);
++              if (dma_mapping_error(priv->device, des2))
+                       return -1;
+-              priv->tx_skbuff_dma[entry].buf = desc->des2;
++              priv->tx_skbuff_dma[entry].buf = des2;
+               priv->tx_skbuff_dma[entry].len = bmax;
+               priv->tx_skbuff_dma[entry].is_jumbo = true;
+-              desc->des3 = desc->des2 + BUF_SIZE_4KiB;
++              desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
+               priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
+                                               STMMAC_RING_MODE, 0, false);
+               priv->tx_skbuff[entry] = NULL;
+@@ -70,26 +71,28 @@ static int stmmac_jumbo_frm(void *p, str
+               else
+                       desc = priv->dma_tx + entry;
+-              desc->des2 = dma_map_single(priv->device, skb->data + bmax,
+-                                          len, DMA_TO_DEVICE);
+-              if (dma_mapping_error(priv->device, desc->des2))
++              des2 = dma_map_single(priv->device, skb->data + bmax, len,
++                                    DMA_TO_DEVICE);
++              desc->des2 = cpu_to_le32(des2);
++              if (dma_mapping_error(priv->device, des2))
+                       return -1;
+-              priv->tx_skbuff_dma[entry].buf = desc->des2;
++              priv->tx_skbuff_dma[entry].buf = des2;
+               priv->tx_skbuff_dma[entry].len = len;
+               priv->tx_skbuff_dma[entry].is_jumbo = true;
+-              desc->des3 = desc->des2 + BUF_SIZE_4KiB;
++              desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
+               priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
+                                               STMMAC_RING_MODE, 1, true);
+       } else {
+-              desc->des2 = dma_map_single(priv->device, skb->data,
+-                                          nopaged_len, DMA_TO_DEVICE);
+-              if (dma_mapping_error(priv->device, desc->des2))
++              des2 = dma_map_single(priv->device, skb->data,
++                                    nopaged_len, DMA_TO_DEVICE);
++              desc->des2 = cpu_to_le32(des2);
++              if (dma_mapping_error(priv->device, des2))
+                       return -1;
+-              priv->tx_skbuff_dma[entry].buf = desc->des2;
++              priv->tx_skbuff_dma[entry].buf = des2;
+               priv->tx_skbuff_dma[entry].len = nopaged_len;
+               priv->tx_skbuff_dma[entry].is_jumbo = true;
+-              desc->des3 = desc->des2 + BUF_SIZE_4KiB;
++              desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
+               priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
+                                               STMMAC_RING_MODE, 0, true);
+       }
+@@ -115,13 +118,13 @@ static void stmmac_refill_desc3(void *pr
+       /* Fill DES3 in case of RING mode */
+       if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+-              p->des3 = p->des2 + BUF_SIZE_8KiB;
++              p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB);
+ }
+ /* In ring mode we need to fill the desc3 because it is used as buffer */
+ static void stmmac_init_desc3(struct dma_desc *p)
+ {
+-      p->des3 = p->des2 + BUF_SIZE_8KiB;
++      p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB);
+ }
+ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -64,7 +64,6 @@ struct stmmac_priv {
+       dma_addr_t dma_tx_phy;
+       int tx_coalesce;
+       int hwts_tx_en;
+-      spinlock_t tx_lock;
+       bool tx_path_in_lpi_mode;
+       struct timer_list txtimer;
+       bool tso;
+@@ -90,7 +89,6 @@ struct stmmac_priv {
+       struct mac_device_info *hw;
+       spinlock_t lock;
+-      struct phy_device *phydev ____cacheline_aligned_in_smp;
+       int oldlink;
+       int speed;
+       int oldduplex;
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+@@ -263,7 +263,7 @@ static void stmmac_ethtool_getdrvinfo(st
+ {
+       struct stmmac_priv *priv = netdev_priv(dev);
+-      if (priv->plat->has_gmac)
++      if (priv->plat->has_gmac || priv->plat->has_gmac4)
+               strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver));
+       else
+               strlcpy(info->driver, MAC100_ETHTOOL_NAME,
+@@ -272,25 +272,26 @@ static void stmmac_ethtool_getdrvinfo(st
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+ }
+-static int stmmac_ethtool_getsettings(struct net_device *dev,
+-                                    struct ethtool_cmd *cmd)
++static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
++                                           struct ethtool_link_ksettings *cmd)
+ {
+       struct stmmac_priv *priv = netdev_priv(dev);
+-      struct phy_device *phy = priv->phydev;
++      struct phy_device *phy = dev->phydev;
+       int rc;
+       if (priv->hw->pcs & STMMAC_PCS_RGMII ||
+           priv->hw->pcs & STMMAC_PCS_SGMII) {
+               struct rgmii_adv adv;
++              u32 supported, advertising, lp_advertising;
+               if (!priv->xstats.pcs_link) {
+-                      ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+-                      cmd->duplex = DUPLEX_UNKNOWN;
++                      cmd->base.speed = SPEED_UNKNOWN;
++                      cmd->base.duplex = DUPLEX_UNKNOWN;
+                       return 0;
+               }
+-              cmd->duplex = priv->xstats.pcs_duplex;
++              cmd->base.duplex = priv->xstats.pcs_duplex;
+-              ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
++              cmd->base.speed = priv->xstats.pcs_speed;
+               /* Get and convert ADV/LP_ADV from the HW AN registers */
+               if (!priv->hw->mac->pcs_get_adv_lp)
+@@ -300,45 +301,59 @@ static int stmmac_ethtool_getsettings(st
+               /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
++              ethtool_convert_link_mode_to_legacy_u32(
++                      &supported, cmd->link_modes.supported);
++              ethtool_convert_link_mode_to_legacy_u32(
++                      &advertising, cmd->link_modes.advertising);
++              ethtool_convert_link_mode_to_legacy_u32(
++                      &lp_advertising, cmd->link_modes.lp_advertising);
++
+               if (adv.pause & STMMAC_PCS_PAUSE)
+-                      cmd->advertising |= ADVERTISED_Pause;
++                      advertising |= ADVERTISED_Pause;
+               if (adv.pause & STMMAC_PCS_ASYM_PAUSE)
+-                      cmd->advertising |= ADVERTISED_Asym_Pause;
++                      advertising |= ADVERTISED_Asym_Pause;
+               if (adv.lp_pause & STMMAC_PCS_PAUSE)
+-                      cmd->lp_advertising |= ADVERTISED_Pause;
++                      lp_advertising |= ADVERTISED_Pause;
+               if (adv.lp_pause & STMMAC_PCS_ASYM_PAUSE)
+-                      cmd->lp_advertising |= ADVERTISED_Asym_Pause;
++                      lp_advertising |= ADVERTISED_Asym_Pause;
+               /* Reg49[3] always set because ANE is always supported */
+-              cmd->autoneg = ADVERTISED_Autoneg;
+-              cmd->supported |= SUPPORTED_Autoneg;
+-              cmd->advertising |= ADVERTISED_Autoneg;
+-              cmd->lp_advertising |= ADVERTISED_Autoneg;
++              cmd->base.autoneg = ADVERTISED_Autoneg;
++              supported |= SUPPORTED_Autoneg;
++              advertising |= ADVERTISED_Autoneg;
++              lp_advertising |= ADVERTISED_Autoneg;
+               if (adv.duplex) {
+-                      cmd->supported |= (SUPPORTED_1000baseT_Full |
+-                                         SUPPORTED_100baseT_Full |
+-                                         SUPPORTED_10baseT_Full);
+-                      cmd->advertising |= (ADVERTISED_1000baseT_Full |
+-                                           ADVERTISED_100baseT_Full |
+-                                           ADVERTISED_10baseT_Full);
++                      supported |= (SUPPORTED_1000baseT_Full |
++                                    SUPPORTED_100baseT_Full |
++                                    SUPPORTED_10baseT_Full);
++                      advertising |= (ADVERTISED_1000baseT_Full |
++                                      ADVERTISED_100baseT_Full |
++                                      ADVERTISED_10baseT_Full);
+               } else {
+-                      cmd->supported |= (SUPPORTED_1000baseT_Half |
+-                                         SUPPORTED_100baseT_Half |
+-                                         SUPPORTED_10baseT_Half);
+-                      cmd->advertising |= (ADVERTISED_1000baseT_Half |
+-                                           ADVERTISED_100baseT_Half |
+-                                           ADVERTISED_10baseT_Half);
++                      supported |= (SUPPORTED_1000baseT_Half |
++                                    SUPPORTED_100baseT_Half |
++                                    SUPPORTED_10baseT_Half);
++                      advertising |= (ADVERTISED_1000baseT_Half |
++                                      ADVERTISED_100baseT_Half |
++                                      ADVERTISED_10baseT_Half);
+               }
+               if (adv.lp_duplex)
+-                      cmd->lp_advertising |= (ADVERTISED_1000baseT_Full |
+-                                              ADVERTISED_100baseT_Full |
+-                                              ADVERTISED_10baseT_Full);
++                      lp_advertising |= (ADVERTISED_1000baseT_Full |
++                                         ADVERTISED_100baseT_Full |
++                                         ADVERTISED_10baseT_Full);
+               else
+-                      cmd->lp_advertising |= (ADVERTISED_1000baseT_Half |
+-                                              ADVERTISED_100baseT_Half |
+-                                              ADVERTISED_10baseT_Half);
+-              cmd->port = PORT_OTHER;
++                      lp_advertising |= (ADVERTISED_1000baseT_Half |
++                                         ADVERTISED_100baseT_Half |
++                                         ADVERTISED_10baseT_Half);
++              cmd->base.port = PORT_OTHER;
++
++              ethtool_convert_legacy_u32_to_link_mode(
++                      cmd->link_modes.supported, supported);
++              ethtool_convert_legacy_u32_to_link_mode(
++                      cmd->link_modes.advertising, advertising);
++              ethtool_convert_legacy_u32_to_link_mode(
++                      cmd->link_modes.lp_advertising, lp_advertising);
+               return 0;
+       }
+@@ -353,16 +368,16 @@ static int stmmac_ethtool_getsettings(st
+               "link speed / duplex setting\n", dev->name);
+               return -EBUSY;
+       }
+-      cmd->transceiver = XCVR_INTERNAL;
+-      rc = phy_ethtool_gset(phy, cmd);
++      rc = phy_ethtool_ksettings_get(phy, cmd);
+       return rc;
+ }
+-static int stmmac_ethtool_setsettings(struct net_device *dev,
+-                                    struct ethtool_cmd *cmd)
++static int
++stmmac_ethtool_set_link_ksettings(struct net_device *dev,
++                                const struct ethtool_link_ksettings *cmd)
+ {
+       struct stmmac_priv *priv = netdev_priv(dev);
+-      struct phy_device *phy = priv->phydev;
++      struct phy_device *phy = dev->phydev;
+       int rc;
+       if (priv->hw->pcs & STMMAC_PCS_RGMII ||
+@@ -370,7 +385,7 @@ static int stmmac_ethtool_setsettings(st
+               u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
+               /* Only support ANE */
+-              if (cmd->autoneg != AUTONEG_ENABLE)
++              if (cmd->base.autoneg != AUTONEG_ENABLE)
+                       return -EINVAL;
+               mask &= (ADVERTISED_1000baseT_Half |
+@@ -391,9 +406,7 @@ static int stmmac_ethtool_setsettings(st
+               return 0;
+       }
+-      spin_lock(&priv->lock);
+-      rc = phy_ethtool_sset(phy, cmd);
+-      spin_unlock(&priv->lock);
++      rc = phy_ethtool_ksettings_set(phy, cmd);
+       return rc;
+ }
+@@ -433,7 +446,7 @@ static void stmmac_ethtool_gregs(struct
+       memset(reg_space, 0x0, REG_SPACE_SIZE);
+-      if (!priv->plat->has_gmac) {
++      if (!(priv->plat->has_gmac || priv->plat->has_gmac4)) {
+               /* MAC registers */
+               for (i = 0; i < 12; i++)
+                       reg_space[i] = readl(priv->ioaddr + (i * 4));
+@@ -471,12 +484,12 @@ stmmac_get_pauseparam(struct net_device
+               if (!adv_lp.pause)
+                       return;
+       } else {
+-              if (!(priv->phydev->supported & SUPPORTED_Pause) ||
+-                  !(priv->phydev->supported & SUPPORTED_Asym_Pause))
++              if (!(netdev->phydev->supported & SUPPORTED_Pause) ||
++                  !(netdev->phydev->supported & SUPPORTED_Asym_Pause))
+                       return;
+       }
+-      pause->autoneg = priv->phydev->autoneg;
++      pause->autoneg = netdev->phydev->autoneg;
+       if (priv->flow_ctrl & FLOW_RX)
+               pause->rx_pause = 1;
+@@ -490,7 +503,7 @@ stmmac_set_pauseparam(struct net_device
+                     struct ethtool_pauseparam *pause)
+ {
+       struct stmmac_priv *priv = netdev_priv(netdev);
+-      struct phy_device *phy = priv->phydev;
++      struct phy_device *phy = netdev->phydev;
+       int new_pause = FLOW_OFF;
+       if (priv->hw->pcs && priv->hw->mac->pcs_get_adv_lp) {
+@@ -550,7 +563,7 @@ static void stmmac_get_ethtool_stats(str
+                       }
+               }
+               if (priv->eee_enabled) {
+-                      int val = phy_get_eee_err(priv->phydev);
++                      int val = phy_get_eee_err(dev->phydev);
+                       if (val)
+                               priv->xstats.phy_eee_wakeup_error_n = val;
+               }
+@@ -669,7 +682,7 @@ static int stmmac_ethtool_op_get_eee(str
+       edata->eee_active = priv->eee_active;
+       edata->tx_lpi_timer = priv->tx_lpi_timer;
+-      return phy_ethtool_get_eee(priv->phydev, edata);
++      return phy_ethtool_get_eee(dev->phydev, edata);
+ }
+ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
+@@ -694,7 +707,7 @@ static int stmmac_ethtool_op_set_eee(str
+               priv->tx_lpi_timer = edata->tx_lpi_timer;
+       }
+-      return phy_ethtool_set_eee(priv->phydev, edata);
++      return phy_ethtool_set_eee(dev->phydev, edata);
+ }
+ static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv)
+@@ -853,8 +866,6 @@ static int stmmac_set_tunable(struct net
+ static const struct ethtool_ops stmmac_ethtool_ops = {
+       .begin = stmmac_check_if_running,
+       .get_drvinfo = stmmac_ethtool_getdrvinfo,
+-      .get_settings = stmmac_ethtool_getsettings,
+-      .set_settings = stmmac_ethtool_setsettings,
+       .get_msglevel = stmmac_ethtool_getmsglevel,
+       .set_msglevel = stmmac_ethtool_setmsglevel,
+       .get_regs = stmmac_ethtool_gregs,
+@@ -874,6 +885,8 @@ static const struct ethtool_ops stmmac_e
+       .set_coalesce = stmmac_set_coalesce,
+       .get_tunable = stmmac_get_tunable,
+       .set_tunable = stmmac_set_tunable,
++      .get_link_ksettings = stmmac_ethtool_get_link_ksettings,
++      .set_link_ksettings = stmmac_ethtool_set_link_ksettings,
+ };
+ void stmmac_set_ethtool_ops(struct net_device *netdev)
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -105,8 +105,8 @@ module_param(eee_timer, int, S_IRUGO | S
+ MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
+ #define STMMAC_LPI_T(x) (jiffies + msecs_to_jiffies(x))
+-/* By default the driver will use the ring mode to manage tx and rx descriptors
+- * but passing this value so user can force to use the chain instead of the ring
++/* By default the driver will use the ring mode to manage tx and rx descriptors,
++ * but allow user to force to use the chain instead of the ring
+  */
+ static unsigned int chain_mode;
+ module_param(chain_mode, int, S_IRUGO);
+@@ -221,7 +221,8 @@ static inline u32 stmmac_rx_dirty(struct
+  */
+ static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
+ {
+-      struct phy_device *phydev = priv->phydev;
++      struct net_device *ndev = priv->dev;
++      struct phy_device *phydev = ndev->phydev;
+       if (likely(priv->plat->fix_mac_speed))
+               priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed);
+@@ -279,6 +280,7 @@ static void stmmac_eee_ctrl_timer(unsign
+  */
+ bool stmmac_eee_init(struct stmmac_priv *priv)
+ {
++      struct net_device *ndev = priv->dev;
+       unsigned long flags;
+       bool ret = false;
+@@ -295,7 +297,7 @@ bool stmmac_eee_init(struct stmmac_priv
+               int tx_lpi_timer = priv->tx_lpi_timer;
+               /* Check if the PHY supports EEE */
+-              if (phy_init_eee(priv->phydev, 1)) {
++              if (phy_init_eee(ndev->phydev, 1)) {
+                       /* To manage at run-time if the EEE cannot be supported
+                        * anymore (for example because the lp caps have been
+                        * changed).
+@@ -303,7 +305,7 @@ bool stmmac_eee_init(struct stmmac_priv
+                        */
+                       spin_lock_irqsave(&priv->lock, flags);
+                       if (priv->eee_active) {
+-                              pr_debug("stmmac: disable EEE\n");
++                              netdev_dbg(priv->dev, "disable EEE\n");
+                               del_timer_sync(&priv->eee_ctrl_timer);
+                               priv->hw->mac->set_eee_timer(priv->hw, 0,
+                                                            tx_lpi_timer);
+@@ -327,12 +329,12 @@ bool stmmac_eee_init(struct stmmac_priv
+                                                    tx_lpi_timer);
+               }
+               /* Set HW EEE according to the speed */
+-              priv->hw->mac->set_eee_pls(priv->hw, priv->phydev->link);
++              priv->hw->mac->set_eee_pls(priv->hw, ndev->phydev->link);
+               ret = true;
+               spin_unlock_irqrestore(&priv->lock, flags);
+-              pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
++              netdev_dbg(priv->dev, "Energy-Efficient Ethernet initialized\n");
+       }
+ out:
+       return ret;
+@@ -450,8 +452,8 @@ static int stmmac_hwtstamp_ioctl(struct
+                          sizeof(struct hwtstamp_config)))
+               return -EFAULT;
+-      pr_debug("%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
+-               __func__, config.flags, config.tx_type, config.rx_filter);
++      netdev_dbg(priv->dev, "%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
++                 __func__, config.flags, config.tx_type, config.rx_filter);
+       /* reserved for future extensions */
+       if (config.flags)
+@@ -697,7 +699,7 @@ static void stmmac_release_ptp(struct st
+ static void stmmac_adjust_link(struct net_device *dev)
+ {
+       struct stmmac_priv *priv = netdev_priv(dev);
+-      struct phy_device *phydev = priv->phydev;
++      struct phy_device *phydev = dev->phydev;
+       unsigned long flags;
+       int new_state = 0;
+       unsigned int fc = priv->flow_ctrl, pause_time = priv->pause;
+@@ -750,9 +752,9 @@ static void stmmac_adjust_link(struct ne
+                               stmmac_hw_fix_mac_speed(priv);
+                               break;
+                       default:
+-                              if (netif_msg_link(priv))
+-                                      pr_warn("%s: Speed (%d) not 10/100\n",
+-                                              dev->name, phydev->speed);
++                              netif_warn(priv, link, priv->dev,
++                                         "Speed (%d) not 10/100\n",
++                                         phydev->speed);
+                               break;
+                       }
+@@ -805,10 +807,10 @@ static void stmmac_check_pcs_mode(struct
+                   (interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+                   (interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+                   (interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
+-                      pr_debug("STMMAC: PCS RGMII support enable\n");
++                      netdev_dbg(priv->dev, "PCS RGMII support enabled\n");
+                       priv->hw->pcs = STMMAC_PCS_RGMII;
+               } else if (interface == PHY_INTERFACE_MODE_SGMII) {
+-                      pr_debug("STMMAC: PCS SGMII support enable\n");
++                      netdev_dbg(priv->dev, "PCS SGMII support enabled\n");
+                       priv->hw->pcs = STMMAC_PCS_SGMII;
+               }
+       }
+@@ -843,15 +845,15 @@ static int stmmac_init_phy(struct net_de
+               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);
++              netdev_dbg(priv->dev, "%s: trying to attach to %s\n", __func__,
++                         phy_id_fmt);
+               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);
++              netdev_err(priv->dev, "Could not attach to PHY\n");
+               if (!phydev)
+                       return -ENODEV;
+@@ -884,10 +886,8 @@ static int stmmac_init_phy(struct net_de
+       if (phydev->is_pseudo_fixed_link)
+               phydev->irq = PHY_POLL;
+-      pr_debug("stmmac_init_phy:  %s: attached to PHY (UID 0x%x)"
+-               " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
+-
+-      priv->phydev = phydev;
++      netdev_dbg(priv->dev, "%s: attached to PHY (UID 0x%x) Link = %d\n",
++                 __func__, phydev->phy_id, phydev->link);
+       return 0;
+ }
+@@ -973,7 +973,8 @@ static int stmmac_init_rx_buffers(struct
+       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__);
++              netdev_err(priv->dev,
++                         "%s: Rx init fails; skb is NULL\n", __func__);
+               return -ENOMEM;
+       }
+       priv->rx_skbuff[i] = skb;
+@@ -981,15 +982,15 @@ static int stmmac_init_rx_buffers(struct
+                                               priv->dma_buf_sz,
+                                               DMA_FROM_DEVICE);
+       if (dma_mapping_error(priv->device, priv->rx_skbuff_dma[i])) {
+-              pr_err("%s: DMA mapping error\n", __func__);
++              netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+               dev_kfree_skb_any(skb);
+               return -EINVAL;
+       }
+       if (priv->synopsys_id >= DWMAC_CORE_4_00)
+-              p->des0 = priv->rx_skbuff_dma[i];
++              p->des0 = cpu_to_le32(priv->rx_skbuff_dma[i]);
+       else
+-              p->des2 = priv->rx_skbuff_dma[i];
++              p->des2 = cpu_to_le32(priv->rx_skbuff_dma[i]);
+       if ((priv->hw->mode->init_desc3) &&
+           (priv->dma_buf_sz == BUF_SIZE_16KiB))
+@@ -1031,13 +1032,14 @@ static int init_dma_desc_rings(struct ne
+       priv->dma_buf_sz = bfsize;
+-      if (netif_msg_probe(priv)) {
+-              pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__,
+-                       (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy);
++      netif_dbg(priv, probe, priv->dev,
++                "(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n",
++                __func__, (u32)priv->dma_rx_phy, (u32)priv->dma_tx_phy);
++
++      /* RX INITIALIZATION */
++      netif_dbg(priv, probe, priv->dev,
++                "SKB addresses:\nskb\t\tskb data\tdma data\n");
+-              /* RX INITIALIZATION */
+-              pr_debug("\tSKB addresses:\nskb\t\tskb data\tdma data\n");
+-      }
+       for (i = 0; i < DMA_RX_SIZE; i++) {
+               struct dma_desc *p;
+               if (priv->extend_desc)
+@@ -1049,10 +1051,9 @@ static int init_dma_desc_rings(struct ne
+               if (ret)
+                       goto err_init_rx_buffers;
+-              if (netif_msg_probe(priv))
+-                      pr_debug("[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
+-                               priv->rx_skbuff[i]->data,
+-                               (unsigned int)priv->rx_skbuff_dma[i]);
++              netif_dbg(priv, probe, priv->dev, "[%p]\t[%p]\t[%x]\n",
++                        priv->rx_skbuff[i], priv->rx_skbuff[i]->data,
++                        (unsigned int)priv->rx_skbuff_dma[i]);
+       }
+       priv->cur_rx = 0;
+       priv->dirty_rx = (unsigned int)(i - DMA_RX_SIZE);
+@@ -1307,7 +1308,7 @@ static void stmmac_tx_clean(struct stmma
+       unsigned int bytes_compl = 0, pkts_compl = 0;
+       unsigned int entry = priv->dirty_tx;
+-      spin_lock(&priv->tx_lock);
++      netif_tx_lock(priv->dev);
+       priv->xstats.tx_clean++;
+@@ -1378,22 +1379,17 @@ static void stmmac_tx_clean(struct stmma
+       netdev_completed_queue(priv->dev, pkts_compl, bytes_compl);
+       if (unlikely(netif_queue_stopped(priv->dev) &&
+-                   stmmac_tx_avail(priv) > STMMAC_TX_THRESH)) {
+-              netif_tx_lock(priv->dev);
+-              if (netif_queue_stopped(priv->dev) &&
+-                  stmmac_tx_avail(priv) > STMMAC_TX_THRESH) {
+-                      if (netif_msg_tx_done(priv))
+-                              pr_debug("%s: restart transmit\n", __func__);
+-                      netif_wake_queue(priv->dev);
+-              }
+-              netif_tx_unlock(priv->dev);
++          stmmac_tx_avail(priv) > STMMAC_TX_THRESH)) {
++              netif_dbg(priv, tx_done, priv->dev,
++                        "%s: restart transmit\n", __func__);
++              netif_wake_queue(priv->dev);
+       }
+       if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
+               stmmac_enable_eee_mode(priv);
+               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
+       }
+-      spin_unlock(&priv->tx_lock);
++      netif_tx_unlock(priv->dev);
+ }
+ static inline void stmmac_enable_dma_irq(struct stmmac_priv *priv)
+@@ -1497,7 +1493,7 @@ static void stmmac_mmc_setup(struct stmm
+               dwmac_mmc_ctrl(priv->mmcaddr, mode);
+               memset(&priv->mmc, 0, sizeof(struct stmmac_counters));
+       } else
+-              pr_info(" No MAC Management Counters available\n");
++              netdev_info(priv->dev, "No MAC Management Counters available\n");
+ }
+ /**
+@@ -1510,18 +1506,18 @@ static void stmmac_mmc_setup(struct stmm
+ static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
+ {
+       if (priv->plat->enh_desc) {
+-              pr_info(" Enhanced/Alternate descriptors\n");
++              dev_info(priv->device, "Enhanced/Alternate descriptors\n");
+               /* GMAC older than 3.50 has no extended descriptors */
+               if (priv->synopsys_id >= DWMAC_CORE_3_50) {
+-                      pr_info("\tEnabled extended descriptors\n");
++                      dev_info(priv->device, "Enabled extended descriptors\n");
+                       priv->extend_desc = 1;
+               } else
+-                      pr_warn("Extended descriptors not supported\n");
++                      dev_warn(priv->device, "Extended descriptors not supported\n");
+               priv->hw->desc = &enh_desc_ops;
+       } else {
+-              pr_info(" Normal descriptors\n");
++              dev_info(priv->device, "Normal descriptors\n");
+               priv->hw->desc = &ndesc_ops;
+       }
+ }
+@@ -1562,8 +1558,8 @@ static void stmmac_check_ether_addr(stru
+                                            priv->dev->dev_addr, 0);
+               if (!is_valid_ether_addr(priv->dev->dev_addr))
+                       eth_hw_addr_random(priv->dev);
+-              pr_info("%s: device MAC address %pM\n", priv->dev->name,
+-                      priv->dev->dev_addr);
++              netdev_info(priv->dev, "device MAC address %pM\n",
++                          priv->dev->dev_addr);
+       }
+ }
+@@ -1577,16 +1573,12 @@ static void stmmac_check_ether_addr(stru
+  */
+ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
+ {
+-      int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, aal = 0;
+-      int mixed_burst = 0;
+       int atds = 0;
+       int ret = 0;
+-      if (priv->plat->dma_cfg) {
+-              pbl = priv->plat->dma_cfg->pbl;
+-              fixed_burst = priv->plat->dma_cfg->fixed_burst;
+-              mixed_burst = priv->plat->dma_cfg->mixed_burst;
+-              aal = priv->plat->dma_cfg->aal;
++      if (!priv->plat->dma_cfg || !priv->plat->dma_cfg->pbl) {
++              dev_err(priv->device, "Invalid DMA configuration\n");
++              return -EINVAL;
+       }
+       if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE))
+@@ -1598,8 +1590,8 @@ static int stmmac_init_dma_engine(struct
+               return ret;
+       }
+-      priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
+-                          aal, priv->dma_tx_phy, priv->dma_rx_phy, atds);
++      priv->hw->dma->init(priv->ioaddr, priv->plat->dma_cfg,
++                          priv->dma_tx_phy, priv->dma_rx_phy, atds);
+       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
+               priv->rx_tail_addr = priv->dma_rx_phy +
+@@ -1671,7 +1663,8 @@ static int stmmac_hw_setup(struct net_de
+       /* DMA initialization and SW reset */
+       ret = stmmac_init_dma_engine(priv);
+       if (ret < 0) {
+-              pr_err("%s: DMA engine initialization failed\n", __func__);
++              netdev_err(priv->dev, "%s: DMA engine initialization failed\n",
++                         __func__);
+               return ret;
+       }
+@@ -1700,7 +1693,7 @@ static int stmmac_hw_setup(struct net_de
+       ret = priv->hw->mac->rx_ipc(priv->hw);
+       if (!ret) {
+-              pr_warn(" RX IPC Checksum Offload disabled\n");
++              netdev_warn(priv->dev, "RX IPC Checksum Offload disabled\n");
+               priv->plat->rx_coe = STMMAC_RX_COE_NONE;
+               priv->hw->rx_csum = 0;
+       }
+@@ -1725,10 +1718,11 @@ static int stmmac_hw_setup(struct net_de
+ #ifdef CONFIG_DEBUG_FS
+       ret = stmmac_init_fs(dev);
+       if (ret < 0)
+-              pr_warn("%s: failed debugFS registration\n", __func__);
++              netdev_warn(priv->dev, "%s: failed debugFS registration\n",
++                          __func__);
+ #endif
+       /* Start the ball rolling... */
+-      pr_debug("%s: DMA RX/TX processes started...\n", dev->name);
++      netdev_dbg(priv->dev, "DMA RX/TX processes started...\n");
+       priv->hw->dma->start_tx(priv->ioaddr);
+       priv->hw->dma->start_rx(priv->ioaddr);
+@@ -1783,8 +1777,9 @@ static int stmmac_open(struct net_device
+           priv->hw->pcs != STMMAC_PCS_RTBI) {
+               ret = stmmac_init_phy(dev);
+               if (ret) {
+-                      pr_err("%s: Cannot attach to PHY (error: %d)\n",
+-                             __func__, ret);
++                      netdev_err(priv->dev,
++                                 "%s: Cannot attach to PHY (error: %d)\n",
++                                 __func__, ret);
+                       return ret;
+               }
+       }
+@@ -1798,33 +1793,36 @@ static int stmmac_open(struct net_device
+       ret = alloc_dma_desc_resources(priv);
+       if (ret < 0) {
+-              pr_err("%s: DMA descriptors allocation failed\n", __func__);
++              netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n",
++                         __func__);
+               goto dma_desc_error;
+       }
+       ret = init_dma_desc_rings(dev, GFP_KERNEL);
+       if (ret < 0) {
+-              pr_err("%s: DMA descriptors initialization failed\n", __func__);
++              netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n",
++                         __func__);
+               goto init_error;
+       }
+       ret = stmmac_hw_setup(dev, true);
+       if (ret < 0) {
+-              pr_err("%s: Hw setup failed\n", __func__);
++              netdev_err(priv->dev, "%s: Hw setup failed\n", __func__);
+               goto init_error;
+       }
+       stmmac_init_tx_coalesce(priv);
+-      if (priv->phydev)
+-              phy_start(priv->phydev);
++      if (dev->phydev)
++              phy_start(dev->phydev);
+       /* Request the IRQ lines */
+       ret = request_irq(dev->irq, stmmac_interrupt,
+                         IRQF_SHARED, dev->name, dev);
+       if (unlikely(ret < 0)) {
+-              pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",
+-                     __func__, dev->irq, ret);
++              netdev_err(priv->dev,
++                         "%s: ERROR: allocating the IRQ %d (error: %d)\n",
++                         __func__, dev->irq, ret);
+               goto init_error;
+       }
+@@ -1833,8 +1831,9 @@ static int stmmac_open(struct net_device
+               ret = request_irq(priv->wol_irq, stmmac_interrupt,
+                                 IRQF_SHARED, dev->name, dev);
+               if (unlikely(ret < 0)) {
+-                      pr_err("%s: ERROR: allocating the WoL IRQ %d (%d)\n",
+-                             __func__, priv->wol_irq, ret);
++                      netdev_err(priv->dev,
++                                 "%s: ERROR: allocating the WoL IRQ %d (%d)\n",
++                                 __func__, priv->wol_irq, ret);
+                       goto wolirq_error;
+               }
+       }
+@@ -1844,8 +1843,9 @@ static int stmmac_open(struct net_device
+               ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED,
+                                 dev->name, dev);
+               if (unlikely(ret < 0)) {
+-                      pr_err("%s: ERROR: allocating the LPI IRQ %d (%d)\n",
+-                             __func__, priv->lpi_irq, ret);
++                      netdev_err(priv->dev,
++                                 "%s: ERROR: allocating the LPI IRQ %d (%d)\n",
++                                 __func__, priv->lpi_irq, ret);
+                       goto lpiirq_error;
+               }
+       }
+@@ -1864,8 +1864,8 @@ wolirq_error:
+ init_error:
+       free_dma_desc_resources(priv);
+ dma_desc_error:
+-      if (priv->phydev)
+-              phy_disconnect(priv->phydev);
++      if (dev->phydev)
++              phy_disconnect(dev->phydev);
+       return ret;
+ }
+@@ -1884,10 +1884,9 @@ static int stmmac_release(struct net_dev
+               del_timer_sync(&priv->eee_ctrl_timer);
+       /* Stop and disconnect the PHY */
+-      if (priv->phydev) {
+-              phy_stop(priv->phydev);
+-              phy_disconnect(priv->phydev);
+-              priv->phydev = NULL;
++      if (dev->phydev) {
++              phy_stop(dev->phydev);
++              phy_disconnect(dev->phydev);
+       }
+       netif_stop_queue(dev);
+@@ -1947,13 +1946,13 @@ static void stmmac_tso_allocator(struct
+               priv->cur_tx = STMMAC_GET_ENTRY(priv->cur_tx, DMA_TX_SIZE);
+               desc = priv->dma_tx + priv->cur_tx;
+-              desc->des0 = des + (total_len - tmp_len);
++              desc->des0 = cpu_to_le32(des + (total_len - tmp_len));
+               buff_size = tmp_len >= TSO_MAX_BUFF_SIZE ?
+                           TSO_MAX_BUFF_SIZE : tmp_len;
+               priv->hw->desc->prepare_tso_tx_desc(desc, 0, buff_size,
+                       0, 1,
+-                      (last_segment) && (tmp_len <= TSO_MAX_BUFF_SIZE),
++                      (last_segment) && (buff_size < TSO_MAX_BUFF_SIZE),
+                       0, 0);
+               tmp_len -= TSO_MAX_BUFF_SIZE;
+@@ -1998,8 +1997,6 @@ static netdev_tx_t stmmac_tso_xmit(struc
+       u8 proto_hdr_len;
+       int i;
+-      spin_lock(&priv->tx_lock);
+-
+       /* Compute header lengths */
+       proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+@@ -2009,9 +2006,10 @@ static netdev_tx_t stmmac_tso_xmit(struc
+               if (!netif_queue_stopped(dev)) {
+                       netif_stop_queue(dev);
+                       /* This is a hard error, log it. */
+-                      pr_err("%s: Tx Ring full when queue awake\n", __func__);
++                      netdev_err(priv->dev,
++                                 "%s: Tx Ring full when queue awake\n",
++                                 __func__);
+               }
+-              spin_unlock(&priv->tx_lock);
+               return NETDEV_TX_BUSY;
+       }
+@@ -2049,11 +2047,11 @@ static netdev_tx_t stmmac_tso_xmit(struc
+       priv->tx_skbuff_dma[first_entry].len = skb_headlen(skb);
+       priv->tx_skbuff[first_entry] = skb;
+-      first->des0 = des;
++      first->des0 = cpu_to_le32(des);
+       /* Fill start of payload in buff2 of first descriptor */
+       if (pay_len)
+-              first->des1 =  des + proto_hdr_len;
++              first->des1 = cpu_to_le32(des + proto_hdr_len);
+       /* If needed take extra descriptors to fill the remaining payload */
+       tmp_pay_len = pay_len - TSO_MAX_BUFF_SIZE;
+@@ -2082,8 +2080,8 @@ static netdev_tx_t stmmac_tso_xmit(struc
+       priv->cur_tx = STMMAC_GET_ENTRY(priv->cur_tx, DMA_TX_SIZE);
+       if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
+-              if (netif_msg_hw(priv))
+-                      pr_debug("%s: stop transmitted packets\n", __func__);
++              netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
++                        __func__);
+               netif_stop_queue(dev);
+       }
+@@ -2127,7 +2125,7 @@ static netdev_tx_t stmmac_tso_xmit(struc
+        * descriptor and then barrier is needed to make sure that
+        * all is coherent before granting the DMA engine.
+        */
+-      smp_wmb();
++      dma_wmb();
+       if (netif_msg_pktdata(priv)) {
+               pr_info("%s: curr=%d dirty=%d f=%d, e=%d, f_p=%p, nfrags %d\n",
+@@ -2146,11 +2144,9 @@ static netdev_tx_t stmmac_tso_xmit(struc
+       priv->hw->dma->set_tx_tail_ptr(priv->ioaddr, priv->tx_tail_addr,
+                                      STMMAC_CHAN0);
+-      spin_unlock(&priv->tx_lock);
+       return NETDEV_TX_OK;
+ dma_map_err:
+-      spin_unlock(&priv->tx_lock);
+       dev_err(priv->device, "Tx dma map failed\n");
+       dev_kfree_skb(skb);
+       priv->dev->stats.tx_dropped++;
+@@ -2182,14 +2178,13 @@ static netdev_tx_t stmmac_xmit(struct sk
+                       return stmmac_tso_xmit(skb, dev);
+       }
+-      spin_lock(&priv->tx_lock);
+-
+       if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
+-              spin_unlock(&priv->tx_lock);
+               if (!netif_queue_stopped(dev)) {
+                       netif_stop_queue(dev);
+                       /* This is a hard error, log it. */
+-                      pr_err("%s: Tx Ring full when queue awake\n", __func__);
++                      netdev_err(priv->dev,
++                                 "%s: Tx Ring full when queue awake\n",
++                                 __func__);
+               }
+               return NETDEV_TX_BUSY;
+       }
+@@ -2242,13 +2237,11 @@ static netdev_tx_t stmmac_xmit(struct sk
+               priv->tx_skbuff[entry] = NULL;
+-              if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00)) {
+-                      desc->des0 = des;
+-                      priv->tx_skbuff_dma[entry].buf = desc->des0;
+-              } else {
+-                      desc->des2 = des;
+-                      priv->tx_skbuff_dma[entry].buf = desc->des2;
+-              }
++              priv->tx_skbuff_dma[entry].buf = des;
++              if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
++                      desc->des0 = cpu_to_le32(des);
++              else
++                      desc->des2 = cpu_to_le32(des);
+               priv->tx_skbuff_dma[entry].map_as_page = true;
+               priv->tx_skbuff_dma[entry].len = len;
+@@ -2266,9 +2259,10 @@ static netdev_tx_t stmmac_xmit(struct sk
+       if (netif_msg_pktdata(priv)) {
+               void *tx_head;
+-              pr_debug("%s: curr=%d dirty=%d f=%d, e=%d, first=%p, nfrags=%d",
+-                       __func__, priv->cur_tx, priv->dirty_tx, first_entry,
+-                       entry, first, nfrags);
++              netdev_dbg(priv->dev,
++                         "%s: curr=%d dirty=%d f=%d, e=%d, first=%p, nfrags=%d",
++                         __func__, priv->cur_tx, priv->dirty_tx, first_entry,
++                         entry, first, nfrags);
+               if (priv->extend_desc)
+                       tx_head = (void *)priv->dma_etx;
+@@ -2277,13 +2271,13 @@ static netdev_tx_t stmmac_xmit(struct sk
+               priv->hw->desc->display_ring(tx_head, DMA_TX_SIZE, false);
+-              pr_debug(">>> frame to be transmitted: ");
++              netdev_dbg(priv->dev, ">>> frame to be transmitted: ");
+               print_pkt(skb->data, skb->len);
+       }
+       if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
+-              if (netif_msg_hw(priv))
+-                      pr_debug("%s: stop transmitted packets\n", __func__);
++              netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
++                        __func__);
+               netif_stop_queue(dev);
+       }
+@@ -2319,13 +2313,11 @@ static netdev_tx_t stmmac_xmit(struct sk
+               if (dma_mapping_error(priv->device, des))
+                       goto dma_map_err;
+-              if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00)) {
+-                      first->des0 = des;
+-                      priv->tx_skbuff_dma[first_entry].buf = first->des0;
+-              } else {
+-                      first->des2 = des;
+-                      priv->tx_skbuff_dma[first_entry].buf = first->des2;
+-              }
++              priv->tx_skbuff_dma[first_entry].buf = des;
++              if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
++                      first->des0 = cpu_to_le32(des);
++              else
++                      first->des2 = cpu_to_le32(des);
+               priv->tx_skbuff_dma[first_entry].len = nopaged_len;
+               priv->tx_skbuff_dma[first_entry].last_segment = last_segment;
+@@ -2346,7 +2338,7 @@ static netdev_tx_t stmmac_xmit(struct sk
+                * descriptor and then barrier is needed to make sure that
+                * all is coherent before granting the DMA engine.
+                */
+-              smp_wmb();
++              dma_wmb();
+       }
+       netdev_sent_queue(dev, skb->len);
+@@ -2357,12 +2349,10 @@ static netdev_tx_t stmmac_xmit(struct sk
+               priv->hw->dma->set_tx_tail_ptr(priv->ioaddr, priv->tx_tail_addr,
+                                              STMMAC_CHAN0);
+-      spin_unlock(&priv->tx_lock);
+       return NETDEV_TX_OK;
+ dma_map_err:
+-      spin_unlock(&priv->tx_lock);
+-      dev_err(priv->device, "Tx dma map failed\n");
++      netdev_err(priv->dev, "Tx DMA map failed\n");
+       dev_kfree_skb(skb);
+       priv->dev->stats.tx_dropped++;
+       return NETDEV_TX_OK;
+@@ -2433,16 +2423,16 @@ static inline void stmmac_rx_refill(stru
+                                          DMA_FROM_DEVICE);
+                       if (dma_mapping_error(priv->device,
+                                             priv->rx_skbuff_dma[entry])) {
+-                              dev_err(priv->device, "Rx dma map failed\n");
++                              netdev_err(priv->dev, "Rx DMA map failed\n");
+                               dev_kfree_skb(skb);
+                               break;
+                       }
+                       if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00)) {
+-                              p->des0 = priv->rx_skbuff_dma[entry];
++                              p->des0 = cpu_to_le32(priv->rx_skbuff_dma[entry]);
+                               p->des1 = 0;
+                       } else {
+-                              p->des2 = priv->rx_skbuff_dma[entry];
++                              p->des2 = cpu_to_le32(priv->rx_skbuff_dma[entry]);
+                       }
+                       if (priv->hw->mode->refill_desc3)
+                               priv->hw->mode->refill_desc3(priv, p);
+@@ -2450,17 +2440,17 @@ static inline void stmmac_rx_refill(stru
+                       if (priv->rx_zeroc_thresh > 0)
+                               priv->rx_zeroc_thresh--;
+-                      if (netif_msg_rx_status(priv))
+-                              pr_debug("\trefill entry #%d\n", entry);
++                      netif_dbg(priv, rx_status, priv->dev,
++                                "refill entry #%d\n", entry);
+               }
+-              wmb();
++              dma_wmb();
+               if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
+                       priv->hw->desc->init_rx_desc(p, priv->use_riwt, 0, 0);
+               else
+                       priv->hw->desc->set_rx_owner(p);
+-              wmb();
++              dma_wmb();
+               entry = STMMAC_GET_ENTRY(entry, DMA_RX_SIZE);
+       }
+@@ -2484,7 +2474,7 @@ static int stmmac_rx(struct stmmac_priv
+       if (netif_msg_rx_status(priv)) {
+               void *rx_head;
+-              pr_info(">>>>>> %s: descriptor ring:\n", __func__);
++              netdev_dbg(priv->dev, "%s: descriptor ring:\n", __func__);
+               if (priv->extend_desc)
+                       rx_head = (void *)priv->dma_erx;
+               else
+@@ -2546,9 +2536,9 @@ static int stmmac_rx(struct stmmac_priv
+                       unsigned int des;
+                       if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
+-                              des = p->des0;
++                              des = le32_to_cpu(p->des0);
+                       else
+-                              des = p->des2;
++                              des = le32_to_cpu(p->des2);
+                       frame_len = priv->hw->desc->get_rx_frame_len(p, coe);
+@@ -2557,9 +2547,9 @@ static int stmmac_rx(struct stmmac_priv
+                        *  ignored
+                        */
+                       if (frame_len > priv->dma_buf_sz) {
+-                              pr_err("%s: len %d larger than size (%d)\n",
+-                                     priv->dev->name, frame_len,
+-                                     priv->dma_buf_sz);
++                              netdev_err(priv->dev,
++                                         "len %d larger than size (%d)\n",
++                                         frame_len, priv->dma_buf_sz);
+                               priv->dev->stats.rx_length_errors++;
+                               break;
+                       }
+@@ -2571,11 +2561,11 @@ static int stmmac_rx(struct stmmac_priv
+                               frame_len -= ETH_FCS_LEN;
+                       if (netif_msg_rx_status(priv)) {
+-                              pr_info("\tdesc: %p [entry %d] buff=0x%x\n",
+-                                      p, entry, des);
++                              netdev_dbg(priv->dev, "\tdesc: %p [entry %d] buff=0x%x\n",
++                                         p, entry, des);
+                               if (frame_len > ETH_FRAME_LEN)
+-                                      pr_debug("\tframe size %d, COE: %d\n",
+-                                               frame_len, status);
++                                      netdev_dbg(priv->dev, "frame size %d, COE: %d\n",
++                                                 frame_len, status);
+                       }
+                       /* The zero-copy is always used for all the sizes
+@@ -2612,8 +2602,9 @@ static int stmmac_rx(struct stmmac_priv
+                       } else {
+                               skb = priv->rx_skbuff[entry];
+                               if (unlikely(!skb)) {
+-                                      pr_err("%s: Inconsistent Rx chain\n",
+-                                             priv->dev->name);
++                                      netdev_err(priv->dev,
++                                                 "%s: Inconsistent Rx chain\n",
++                                                 priv->dev->name);
+                                       priv->dev->stats.rx_dropped++;
+                                       break;
+                               }
+@@ -2629,7 +2620,8 @@ static int stmmac_rx(struct stmmac_priv
+                       }
+                       if (netif_msg_pktdata(priv)) {
+-                              pr_debug("frame received (%dbytes)", frame_len);
++                              netdev_dbg(priv->dev, "frame received (%dbytes)",
++                                         frame_len);
+                               print_pkt(skb->data, frame_len);
+                       }
+@@ -2732,7 +2724,7 @@ static int stmmac_change_mtu(struct net_
+       int max_mtu;
+       if (netif_running(dev)) {
+-              pr_err("%s: must be stopped to change its MTU\n", dev->name);
++              netdev_err(priv->dev, "must be stopped to change its MTU\n");
+               return -EBUSY;
+       }
+@@ -2824,7 +2816,7 @@ static irqreturn_t stmmac_interrupt(int
+               pm_wakeup_event(priv->device, 0);
+       if (unlikely(!dev)) {
+-              pr_err("%s: invalid dev pointer\n", __func__);
++              netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
+               return IRQ_NONE;
+       }
+@@ -2882,7 +2874,6 @@ static void stmmac_poll_controller(struc
+  */
+ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ {
+-      struct stmmac_priv *priv = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+       if (!netif_running(dev))
+@@ -2892,9 +2883,9 @@ static int stmmac_ioctl(struct net_devic
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+-              if (!priv->phydev)
++              if (!dev->phydev)
+                       return -EINVAL;
+-              ret = phy_mii_ioctl(priv->phydev, rq, cmd);
++              ret = phy_mii_ioctl(dev->phydev, rq, cmd);
+               break;
+       case SIOCSHWTSTAMP:
+               ret = stmmac_hwtstamp_ioctl(dev, rq);
+@@ -2922,14 +2913,17 @@ static void sysfs_display_ring(void *hea
+                       x = *(u64 *) ep;
+                       seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+                                  i, (unsigned int)virt_to_phys(ep),
+-                                 ep->basic.des0, ep->basic.des1,
+-                                 ep->basic.des2, ep->basic.des3);
++                                 le32_to_cpu(ep->basic.des0),
++                                 le32_to_cpu(ep->basic.des1),
++                                 le32_to_cpu(ep->basic.des2),
++                                 le32_to_cpu(ep->basic.des3));
+                       ep++;
+               } else {
+                       x = *(u64 *) p;
+                       seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+                                  i, (unsigned int)virt_to_phys(ep),
+-                                 p->des0, p->des1, p->des2, p->des3);
++                                 le32_to_cpu(p->des0), le32_to_cpu(p->des1),
++                                 le32_to_cpu(p->des2), le32_to_cpu(p->des3));
+                       p++;
+               }
+               seq_printf(seq, "\n");
+@@ -2961,6 +2955,8 @@ static int stmmac_sysfs_ring_open(struct
+       return single_open(file, stmmac_sysfs_ring_read, inode->i_private);
+ }
++/* Debugfs files, should appear in /sys/kernel/debug/stmmaceth/eth0 */
++
+ static const struct file_operations stmmac_rings_status_fops = {
+       .owner = THIS_MODULE,
+       .open = stmmac_sysfs_ring_open,
+@@ -2983,11 +2979,11 @@ static int stmmac_sysfs_dma_cap_read(str
+       seq_printf(seq, "\tDMA HW features\n");
+       seq_printf(seq, "==============================\n");
+-      seq_printf(seq, "\t10/100 Mbps %s\n",
++      seq_printf(seq, "\t10/100 Mbps: %s\n",
+                  (priv->dma_cap.mbps_10_100) ? "Y" : "N");
+-      seq_printf(seq, "\t1000 Mbps %s\n",
++      seq_printf(seq, "\t1000 Mbps: %s\n",
+                  (priv->dma_cap.mbps_1000) ? "Y" : "N");
+-      seq_printf(seq, "\tHalf duple %s\n",
++      seq_printf(seq, "\tHalf duplex: %s\n",
+                  (priv->dma_cap.half_duplex) ? "Y" : "N");
+       seq_printf(seq, "\tHash Filter: %s\n",
+                  (priv->dma_cap.hash_filter) ? "Y" : "N");
+@@ -3005,9 +3001,9 @@ static int stmmac_sysfs_dma_cap_read(str
+                  (priv->dma_cap.rmon) ? "Y" : "N");
+       seq_printf(seq, "\tIEEE 1588-2002 Time Stamp: %s\n",
+                  (priv->dma_cap.time_stamp) ? "Y" : "N");
+-      seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp:%s\n",
++      seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp: %s\n",
+                  (priv->dma_cap.atime_stamp) ? "Y" : "N");
+-      seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE) %s\n",
++      seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE): %s\n",
+                  (priv->dma_cap.eee) ? "Y" : "N");
+       seq_printf(seq, "\tAV features: %s\n", (priv->dma_cap.av) ? "Y" : "N");
+       seq_printf(seq, "\tChecksum Offload in TX: %s\n",
+@@ -3054,8 +3050,7 @@ static int stmmac_init_fs(struct net_dev
+       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);
++              netdev_err(priv->dev, "ERROR failed to create debugfs directory\n");
+               return -ENOMEM;
+       }
+@@ -3067,7 +3062,7 @@ static int stmmac_init_fs(struct net_dev
+                                   &stmmac_rings_status_fops);
+       if (!priv->dbgfs_rings_status || IS_ERR(priv->dbgfs_rings_status)) {
+-              pr_info("ERROR creating stmmac ring debugfs file\n");
++              netdev_err(priv->dev, "ERROR creating stmmac ring debugfs file\n");
+               debugfs_remove_recursive(priv->dbgfs_dir);
+               return -ENOMEM;
+@@ -3079,7 +3074,7 @@ static int stmmac_init_fs(struct net_dev
+                                           dev, &stmmac_dma_cap_fops);
+       if (!priv->dbgfs_dma_cap || IS_ERR(priv->dbgfs_dma_cap)) {
+-              pr_info("ERROR creating stmmac MMC debugfs file\n");
++              netdev_err(priv->dev, "ERROR creating stmmac MMC debugfs file\n");
+               debugfs_remove_recursive(priv->dbgfs_dir);
+               return -ENOMEM;
+@@ -3151,11 +3146,11 @@ static int stmmac_hw_init(struct stmmac_
+       } else {
+               if (chain_mode) {
+                       priv->hw->mode = &chain_mode_ops;
+-                      pr_info(" Chain mode enabled\n");
++                      dev_info(priv->device, "Chain mode enabled\n");
+                       priv->mode = STMMAC_CHAIN_MODE;
+               } else {
+                       priv->hw->mode = &ring_mode_ops;
+-                      pr_info(" Ring mode enabled\n");
++                      dev_info(priv->device, "Ring mode enabled\n");
+                       priv->mode = STMMAC_RING_MODE;
+               }
+       }
+@@ -3163,7 +3158,7 @@ static int stmmac_hw_init(struct stmmac_
+       /* Get the HW capability (new GMAC newer than 3.50a) */
+       priv->hw_cap_support = stmmac_get_hw_features(priv);
+       if (priv->hw_cap_support) {
+-              pr_info(" DMA HW capability register supported");
++              dev_info(priv->device, "DMA HW capability register supported\n");
+               /* We can override some gmac/dma configuration fields: e.g.
+                * enh_desc, tx_coe (e.g. that are passed through the
+@@ -3188,8 +3183,9 @@ static int stmmac_hw_init(struct stmmac_
+               else if (priv->dma_cap.rx_coe_type1)
+                       priv->plat->rx_coe = STMMAC_RX_COE_TYPE1;
+-      } else
+-              pr_info(" No HW DMA feature register supported");
++      } else {
++              dev_info(priv->device, "No HW DMA feature register supported\n");
++      }
+       /* To use alternate (extended), normal or GMAC4 descriptor structures */
+       if (priv->synopsys_id >= DWMAC_CORE_4_00)
+@@ -3199,20 +3195,20 @@ static int stmmac_hw_init(struct stmmac_
+       if (priv->plat->rx_coe) {
+               priv->hw->rx_csum = priv->plat->rx_coe;
+-              pr_info(" RX Checksum Offload Engine supported\n");
++              dev_info(priv->device, "RX Checksum Offload Engine supported\n");
+               if (priv->synopsys_id < DWMAC_CORE_4_00)
+-                      pr_info("\tCOE Type %d\n", priv->hw->rx_csum);
++                      dev_info(priv->device, "COE Type %d\n", priv->hw->rx_csum);
+       }
+       if (priv->plat->tx_coe)
+-              pr_info(" TX Checksum insertion supported\n");
++              dev_info(priv->device, "TX Checksum insertion supported\n");
+       if (priv->plat->pmt) {
+-              pr_info(" Wake-Up On Lan supported\n");
++              dev_info(priv->device, "Wake-Up On Lan supported\n");
+               device_set_wakeup_capable(priv->device, 1);
+       }
+       if (priv->dma_cap.tsoen)
+-              pr_info(" TSO supported\n");
++              dev_info(priv->device, "TSO supported\n");
+       return 0;
+ }
+@@ -3271,8 +3267,8 @@ int stmmac_dvr_probe(struct device *devi
+       priv->stmmac_clk = devm_clk_get(priv->device, STMMAC_RESOURCE_NAME);
+       if (IS_ERR(priv->stmmac_clk)) {
+-              dev_warn(priv->device, "%s: warning: cannot get CSR clock\n",
+-                       __func__);
++              netdev_warn(priv->dev, "%s: warning: cannot get CSR clock\n",
++                          __func__);
+               /* If failed to obtain stmmac_clk and specific clk_csr value
+                * is NOT passed from the platform, probe fail.
+                */
+@@ -3321,7 +3317,7 @@ int stmmac_dvr_probe(struct device *devi
+       if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {
+               ndev->hw_features |= NETIF_F_TSO;
+               priv->tso = true;
+-              pr_info(" TSO feature enabled\n");
++              dev_info(priv->device, "TSO feature enabled\n");
+       }
+       ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
+       ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
+@@ -3341,13 +3337,13 @@ int stmmac_dvr_probe(struct device *devi
+        */
+       if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) {
+               priv->use_riwt = 1;
+-              pr_info(" Enable RX Mitigation via HW Watchdog Timer\n");
++              dev_info(priv->device,
++                       "Enable RX Mitigation via HW Watchdog Timer\n");
+       }
+       netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);
+       spin_lock_init(&priv->lock);
+-      spin_lock_init(&priv->tx_lock);
+       /* If a specific clk_csr value is passed from the platform
+        * this means that the CSR Clock Range selection cannot be
+@@ -3368,15 +3364,17 @@ int stmmac_dvr_probe(struct device *devi
+               /* MDIO bus Registration */
+               ret = stmmac_mdio_register(ndev);
+               if (ret < 0) {
+-                      pr_debug("%s: MDIO bus (id: %d) registration failed",
+-                               __func__, priv->plat->bus_id);
+-                      goto error_napi_register;
++                      dev_err(priv->device,
++                              "%s: MDIO bus (id: %d) registration failed",
++                              __func__, priv->plat->bus_id);
++                      goto error_mdio_register;
+               }
+       }
+       ret = register_netdev(ndev);
+       if (ret) {
+-              pr_err("%s: ERROR %i registering the device\n", __func__, ret);
++              dev_err(priv->device, "%s: ERROR %i registering the device\n",
++                      __func__, ret);
+               goto error_netdev_register;
+       }
+@@ -3387,7 +3385,7 @@ error_netdev_register:
+           priv->hw->pcs != STMMAC_PCS_TBI &&
+           priv->hw->pcs != STMMAC_PCS_RTBI)
+               stmmac_mdio_unregister(ndev);
+-error_napi_register:
++error_mdio_register:
+       netif_napi_del(&priv->napi);
+ error_hw_init:
+       clk_disable_unprepare(priv->pclk);
+@@ -3411,7 +3409,7 @@ int stmmac_dvr_remove(struct device *dev
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct stmmac_priv *priv = netdev_priv(ndev);
+-      pr_info("%s:\n\tremoving driver", __func__);
++      netdev_info(priv->dev, "%s: removing driver", __func__);
+       priv->hw->dma->stop_rx(priv->ioaddr);
+       priv->hw->dma->stop_tx(priv->ioaddr);
+@@ -3449,8 +3447,8 @@ int stmmac_suspend(struct device *dev)
+       if (!ndev || !netif_running(ndev))
+               return 0;
+-      if (priv->phydev)
+-              phy_stop(priv->phydev);
++      if (ndev->phydev)
++              phy_stop(ndev->phydev);
+       spin_lock_irqsave(&priv->lock, flags);
+@@ -3544,8 +3542,8 @@ int stmmac_resume(struct device *dev)
+       spin_unlock_irqrestore(&priv->lock, flags);
+-      if (priv->phydev)
+-              phy_start(priv->phydev);
++      if (ndev->phydev)
++              phy_start(ndev->phydev);
+       return 0;
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+@@ -42,13 +42,6 @@
+ #define MII_GMAC4_WRITE                       (1 << MII_GMAC4_GOC_SHIFT)
+ #define MII_GMAC4_READ                        (3 << MII_GMAC4_GOC_SHIFT)
+-#define MII_PHY_ADDR_GMAC4_SHIFT      21
+-#define MII_PHY_ADDR_GMAC4_MASK               GENMASK(25, 21)
+-#define MII_PHY_REG_GMAC4_SHIFT               16
+-#define MII_PHY_REG_GMAC4_MASK                GENMASK(20, 16)
+-#define MII_CSR_CLK_GMAC4_SHIFT               8
+-#define MII_CSR_CLK_GMAC4_MASK                GENMASK(11, 8)
+-
+ static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr)
+ {
+       unsigned long curr;
+@@ -68,8 +61,8 @@ static int stmmac_mdio_busy_wait(void __
+ /**
+  * stmmac_mdio_read
+  * @bus: points to the mii_bus structure
+- * @phyaddr: MII addr reg bits 15-11
+- * @phyreg: MII addr reg bits 10-6
++ * @phyaddr: MII addr
++ * @phyreg: MII reg
+  * Description: it reads data from the MII register from within the phy device.
+  * For the 7111 GMAC, we must set the bit 0 in the MII address register while
+  * accessing the PHY registers.
+@@ -83,14 +76,20 @@ static int stmmac_mdio_read(struct mii_b
+       unsigned int mii_data = priv->hw->mii.data;
+       int data;
+-      u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
+-                      ((phyreg << 6) & (0x000007C0)));
+-      regValue |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
++      u32 value = MII_BUSY;
++
++      value |= (phyaddr << priv->hw->mii.addr_shift)
++              & priv->hw->mii.addr_mask;
++      value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
++      value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
++              & priv->hw->mii.clk_csr_mask;
++      if (priv->plat->has_gmac4)
++              value |= MII_GMAC4_READ;
+       if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+               return -EBUSY;
+-      writel(regValue, priv->ioaddr + mii_address);
++      writel(value, priv->ioaddr + mii_address);
+       if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+               return -EBUSY;
+@@ -104,8 +103,8 @@ static int stmmac_mdio_read(struct mii_b
+ /**
+  * stmmac_mdio_write
+  * @bus: points to the mii_bus structure
+- * @phyaddr: MII addr reg bits 15-11
+- * @phyreg: MII addr reg bits 10-6
++ * @phyaddr: MII addr
++ * @phyreg: MII reg
+  * @phydata: phy data
+  * Description: it writes the data into the MII register from within the device.
+  */
+@@ -117,85 +116,18 @@ static int stmmac_mdio_write(struct mii_
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
+-      u16 value =
+-          (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
+-          | MII_WRITE;
+-
+-      value |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
+-
+-      /* Wait until any existing MII operation is complete */
+-      if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+-              return -EBUSY;
+-
+-      /* Set the MII address register to write */
+-      writel(phydata, priv->ioaddr + mii_data);
+-      writel(value, priv->ioaddr + mii_address);
+-
+-      /* Wait until any existing MII operation is complete */
+-      return stmmac_mdio_busy_wait(priv->ioaddr, mii_address);
+-}
+-
+-/**
+- * stmmac_mdio_read_gmac4
+- * @bus: points to the mii_bus structure
+- * @phyaddr: MII addr reg bits 25-21
+- * @phyreg: MII addr reg bits 20-16
+- * Description: it reads data from the MII register of GMAC4 from within
+- * the phy device.
+- */
+-static int stmmac_mdio_read_gmac4(struct mii_bus *bus, int phyaddr, int phyreg)
+-{
+-      struct net_device *ndev = bus->priv;
+-      struct stmmac_priv *priv = netdev_priv(ndev);
+-      unsigned int mii_address = priv->hw->mii.addr;
+-      unsigned int mii_data = priv->hw->mii.data;
+-      int data;
+-      u32 value = (((phyaddr << MII_PHY_ADDR_GMAC4_SHIFT) &
+-                   (MII_PHY_ADDR_GMAC4_MASK)) |
+-                   ((phyreg << MII_PHY_REG_GMAC4_SHIFT) &
+-                   (MII_PHY_REG_GMAC4_MASK))) | MII_GMAC4_READ;
+-
+-      value |= MII_BUSY | ((priv->clk_csr & MII_CSR_CLK_GMAC4_MASK)
+-               << MII_CSR_CLK_GMAC4_SHIFT);
+-
+-      if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+-              return -EBUSY;
+-
+-      writel(value, priv->ioaddr + mii_address);
+-
+-      if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+-              return -EBUSY;
+-
+-      /* Read the data from the MII data register */
+-      data = (int)readl(priv->ioaddr + mii_data);
+-
+-      return data;
+-}
+-
+-/**
+- * stmmac_mdio_write_gmac4
+- * @bus: points to the mii_bus structure
+- * @phyaddr: MII addr reg bits 25-21
+- * @phyreg: MII addr reg bits 20-16
+- * @phydata: phy data
+- * Description: it writes the data into the MII register of GMAC4 from within
+- * the device.
+- */
+-static int stmmac_mdio_write_gmac4(struct mii_bus *bus, int phyaddr, int phyreg,
+-                                 u16 phydata)
+-{
+-      struct net_device *ndev = bus->priv;
+-      struct stmmac_priv *priv = netdev_priv(ndev);
+-      unsigned int mii_address = priv->hw->mii.addr;
+-      unsigned int mii_data = priv->hw->mii.data;
+-
+-      u32 value = (((phyaddr << MII_PHY_ADDR_GMAC4_SHIFT) &
+-                   (MII_PHY_ADDR_GMAC4_MASK)) |
+-                   ((phyreg << MII_PHY_REG_GMAC4_SHIFT) &
+-                   (MII_PHY_REG_GMAC4_MASK))) | MII_GMAC4_WRITE;
++      u32 value = MII_BUSY;
+-      value |= MII_BUSY | ((priv->clk_csr & MII_CSR_CLK_GMAC4_MASK)
+-               << MII_CSR_CLK_GMAC4_SHIFT);
++      value |= (phyaddr << priv->hw->mii.addr_shift)
++              & priv->hw->mii.addr_mask;
++      value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
++
++      value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
++              & priv->hw->mii.clk_csr_mask;
++      if (priv->plat->has_gmac4)
++              value |= MII_GMAC4_WRITE;
++      else
++              value |= MII_WRITE;
+       /* Wait until any existing MII operation is complete */
+       if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+@@ -260,7 +192,7 @@ int stmmac_mdio_reset(struct mii_bus *bu
+ #endif
+       if (data->phy_reset) {
+-              pr_debug("stmmac_mdio_reset: calling phy_reset\n");
++              netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n");
+               data->phy_reset(priv->plat->bsp_priv);
+       }
+@@ -305,13 +237,8 @@ int stmmac_mdio_register(struct net_devi
+ #endif
+       new_bus->name = "stmmac";
+-      if (priv->plat->has_gmac4) {
+-              new_bus->read = &stmmac_mdio_read_gmac4;
+-              new_bus->write = &stmmac_mdio_write_gmac4;
+-      } else {
+-              new_bus->read = &stmmac_mdio_read;
+-              new_bus->write = &stmmac_mdio_write;
+-      }
++      new_bus->read = &stmmac_mdio_read;
++      new_bus->write = &stmmac_mdio_write;
+       new_bus->reset = &stmmac_mdio_reset;
+       snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+@@ -325,7 +252,7 @@ int stmmac_mdio_register(struct net_devi
+       else
+               err = mdiobus_register(new_bus);
+       if (err != 0) {
+-              pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);
++              netdev_err(ndev, "Cannot register the MDIO bus\n");
+               goto bus_register_fail;
+       }
+@@ -372,16 +299,16 @@ int stmmac_mdio_register(struct net_devi
+                               irq_str = irq_num;
+                               break;
+                       }
+-                      pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
+-                              ndev->name, phydev->phy_id, addr,
+-                              irq_str, phydev_name(phydev),
+-                              act ? " active" : "");
++                      netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
++                                  phydev->phy_id, addr,
++                                  irq_str, phydev_name(phydev),
++                                  act ? " active" : "");
+                       found = 1;
+               }
+       }
+       if (!found && !mdio_node) {
+-              pr_warn("%s: No PHY found\n", ndev->name);
++              netdev_warn(ndev, "No PHY found\n");
+               mdiobus_unregister(new_bus);
+               mdiobus_free(new_bus);
+               return -ENODEV;
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -81,6 +81,7 @@ static void stmmac_default_data(struct p
+       plat->mdio_bus_data->phy_mask = 0;
+       plat->dma_cfg->pbl = 32;
++      plat->dma_cfg->pblx8 = true;
+       /* TODO: AXI */
+       /* Set default value for multicast hash bins */
+@@ -88,6 +89,9 @@ static void stmmac_default_data(struct p
+       /* Set default value for unicast filter entries */
+       plat->unicast_filter_entries = 1;
++
++      /* Set the maxmtu to a default of JUMBO_LEN */
++      plat->maxmtu = JUMBO_LEN;
+ }
+ static int quark_default_data(struct plat_stmmacenet_data *plat,
+@@ -115,6 +119,7 @@ static int quark_default_data(struct pla
+       plat->mdio_bus_data->phy_mask = 0;
+       plat->dma_cfg->pbl = 16;
++      plat->dma_cfg->pblx8 = true;
+       plat->dma_cfg->fixed_burst = 1;
+       /* AXI (TODO) */
+@@ -124,6 +129,9 @@ static int quark_default_data(struct pla
+       /* Set default value for unicast filter entries */
+       plat->unicast_filter_entries = 1;
++      /* Set the maxmtu to a default of JUMBO_LEN */
++      plat->maxmtu = JUMBO_LEN;
++
+       return 0;
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -292,6 +292,7 @@ stmmac_probe_config_dt(struct platform_d
+       if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
+           of_device_is_compatible(np, "snps,dwmac-4.10a")) {
+               plat->has_gmac4 = 1;
++              plat->has_gmac = 0;
+               plat->pmt = 1;
+               plat->tso_en = of_property_read_bool(np, "snps,tso");
+       }
+@@ -303,21 +304,25 @@ stmmac_probe_config_dt(struct platform_d
+               plat->force_sf_dma_mode = 1;
+       }
+-      if (of_find_property(np, "snps,pbl", NULL)) {
+-              dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
+-                                     GFP_KERNEL);
+-              if (!dma_cfg) {
+-                      stmmac_remove_config_dt(pdev, plat);
+-                      return ERR_PTR(-ENOMEM);
+-              }
+-              plat->dma_cfg = dma_cfg;
+-              of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+-              dma_cfg->aal = of_property_read_bool(np, "snps,aal");
+-              dma_cfg->fixed_burst =
+-                      of_property_read_bool(np, "snps,fixed-burst");
+-              dma_cfg->mixed_burst =
+-                      of_property_read_bool(np, "snps,mixed-burst");
+-      }
++      dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
++                             GFP_KERNEL);
++      if (!dma_cfg) {
++              stmmac_remove_config_dt(pdev, plat);
++              return ERR_PTR(-ENOMEM);
++      }
++      plat->dma_cfg = dma_cfg;
++
++      of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
++      if (!dma_cfg->pbl)
++              dma_cfg->pbl = DEFAULT_DMA_PBL;
++      of_property_read_u32(np, "snps,txpbl", &dma_cfg->txpbl);
++      of_property_read_u32(np, "snps,rxpbl", &dma_cfg->rxpbl);
++      dma_cfg->pblx8 = !of_property_read_bool(np, "snps,no-pbl-x8");
++
++      dma_cfg->aal = of_property_read_bool(np, "snps,aal");
++      dma_cfg->fixed_burst = of_property_read_bool(np, "snps,fixed-burst");
++      dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
++
+       plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
+       if (plat->force_thresh_dma_mode) {
+               plat->force_sf_dma_mode = 0;
+@@ -445,9 +450,7 @@ static int stmmac_pltfr_suspend(struct d
+       struct platform_device *pdev = to_platform_device(dev);
+       ret = stmmac_suspend(dev);
+-      if (priv->plat->suspend)
+-              priv->plat->suspend(pdev, priv->plat->bsp_priv);
+-      else if (priv->plat->exit)
++      if (priv->plat->exit)
+               priv->plat->exit(pdev, priv->plat->bsp_priv);
+       return ret;
+@@ -466,9 +469,7 @@ static int stmmac_pltfr_resume(struct de
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       struct platform_device *pdev = to_platform_device(dev);
+-      if (priv->plat->resume)
+-              priv->plat->resume(pdev, priv->plat->bsp_priv);
+-      else if (priv->plat->init)
++      if (priv->plat->init)
+               priv->plat->init(pdev, priv->plat->bsp_priv);
+       return stmmac_resume(dev);
+--- a/include/linux/stmmac.h
++++ b/include/linux/stmmac.h
+@@ -88,6 +88,9 @@ struct stmmac_mdio_bus_data {
+ struct stmmac_dma_cfg {
+       int pbl;
++      int txpbl;
++      int rxpbl;
++      bool pblx8;
+       int fixed_burst;
+       int mixed_burst;
+       bool aal;
+@@ -135,8 +138,6 @@ struct plat_stmmacenet_data {
+       void (*bus_setup)(void __iomem *ioaddr);
+       int (*init)(struct platform_device *pdev, void *priv);
+       void (*exit)(struct platform_device *pdev, void *priv);
+-      void (*suspend)(struct platform_device *pdev, void *priv);
+-      void (*resume)(struct platform_device *pdev, void *priv);
+       void *bsp_priv;
+       struct stmmac_axi *axi;
+       int has_gmac4;
diff --git a/target/linux/sunxi/patches-4.9/0051-stmmac-form-4-11.patch b/target/linux/sunxi/patches-4.9/0051-stmmac-form-4-11.patch
new file mode 100644 (file)
index 0000000..f3b4262
--- /dev/null
@@ -0,0 +1,2305 @@
+--- a/Documentation/devicetree/bindings/net/stmmac.txt
++++ b/Documentation/devicetree/bindings/net/stmmac.txt
+@@ -49,6 +49,8 @@ Optional properties:
+ - snps,force_sf_dma_mode      Force DMA to use the Store and Forward
+                               mode for both tx and rx. This flag is
+                               ignored if force_thresh_dma_mode is set.
++- snps,en-tx-lpi-clockgating  Enable gating of the MAC TX clock during
++                              TX low-power mode
+ - snps,multicast-filter-bins: Number of multicast filter hash bins
+                               supported by this device instance
+ - snps,perfect-filter-entries:        Number of perfect filter entries supported
+@@ -65,7 +67,6 @@ Optional properties:
+       - snps,wr_osr_lmt: max write outstanding req. limit
+       - snps,rd_osr_lmt: max read outstanding req. limit
+       - snps,kbbe: do not cross 1KiB boundary.
+-      - snps,axi_all: align address
+       - snps,blen: this is a vector of supported burst length.
+       - snps,fb: fixed-burst
+       - snps,mb: mixed-burst
+--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
+@@ -1,5 +1,5 @@
+ config STMMAC_ETH
+-      tristate "STMicroelectronics 10/100/1000 Ethernet driver"
++      tristate "STMicroelectronics 10/100/1000/EQOS Ethernet driver"
+       depends on HAS_IOMEM && HAS_DMA
+       select MII
+       select PHYLIB
+@@ -7,9 +7,8 @@ config STMMAC_ETH
+       select PTP_1588_CLOCK
+       select RESET_CONTROLLER
+       ---help---
+-        This is the driver for the Ethernet IPs are built around a
+-        Synopsys IP Core and only tested on the STMicroelectronics
+-        platforms.
++        This is the driver for the Ethernet IPs built around a
++        Synopsys IP Core.
+ if STMMAC_ETH
+@@ -29,6 +28,15 @@ config STMMAC_PLATFORM
+ if STMMAC_PLATFORM
++config DWMAC_DWC_QOS_ETH
++      tristate "Support for snps,dwc-qos-ethernet.txt DT binding."
++      select PHYLIB
++      select CRC32
++      select MII
++      depends on OF && HAS_DMA
++      help
++        Support for chips using the snps,dwc-qos-ethernet.txt DT binding.
++
+ config DWMAC_GENERIC
+       tristate "Generic driver for DWMAC"
+       default STMMAC_PLATFORM
+@@ -143,11 +151,11 @@ config STMMAC_PCI
+       tristate "STMMAC PCI bus support"
+       depends on STMMAC_ETH && PCI
+       ---help---
+-        This is to select the Synopsys DWMAC available on PCI devices,
+-        if you have a controller with this interface, say Y or M here.
++        This selects the platform specific bus support for the stmmac driver.
++        This driver was tested on XLINX XC2V3000 FF1152AMT0221
++        D1215994A VIRTEX FPGA board and SNPS QoS IPK Prototyping Kit.
+-        This PCI support is tested on XLINX XC2V3000 FF1152AMT0221
+-        D1215994A VIRTEX FPGA board.
++        If you have a controller with this interface, say Y or M here.
+         If unsure, say N.
+ endif
+--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
+@@ -16,6 +16,7 @@ obj-$(CONFIG_DWMAC_SOCFPGA)  += dwmac-alt
+ obj-$(CONFIG_DWMAC_STI)               += dwmac-sti.o
+ obj-$(CONFIG_DWMAC_STM32)     += dwmac-stm32.o
+ obj-$(CONFIG_DWMAC_SUNXI)     += dwmac-sunxi.o
++obj-$(CONFIG_DWMAC_DWC_QOS_ETH)       += dwmac-dwc-qos-eth.o
+ obj-$(CONFIG_DWMAC_GENERIC)   += dwmac-generic.o
+ stmmac-platform-objs:= stmmac_platform.o
+ dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o
+--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
++++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+@@ -16,10 +16,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -71,7 +67,7 @@ struct stmmac_extra_stats {
+       unsigned long overflow_error;
+       unsigned long ipc_csum_error;
+       unsigned long rx_collision;
+-      unsigned long rx_crc;
++      unsigned long rx_crc_errors;
+       unsigned long dribbling_bit;
+       unsigned long rx_length;
+       unsigned long rx_mii;
+@@ -323,6 +319,9 @@ struct dma_features {
+       /* TX and RX number of channels */
+       unsigned int number_rx_channel;
+       unsigned int number_tx_channel;
++      /* TX and RX number of queues */
++      unsigned int number_rx_queues;
++      unsigned int number_tx_queues;
+       /* Alternate (enhanced) DESC mode */
+       unsigned int enh_desc;
+ };
+@@ -340,7 +339,7 @@ struct dma_features {
+ /* Common MAC defines */
+ #define MAC_CTRL_REG          0x00000000      /* MAC Control */
+ #define MAC_ENABLE_TX         0x00000008      /* Transmitter Enable */
+-#define MAC_RNABLE_RX         0x00000004      /* Receiver Enable */
++#define MAC_ENABLE_RX         0x00000004      /* Receiver Enable */
+ /* Default LPI timers */
+ #define STMMAC_DEFAULT_LIT_LS 0x3E8
+@@ -417,7 +416,7 @@ struct stmmac_dma_ops {
+       /* Configure the AXI Bus Mode Register */
+       void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
+       /* Dump DMA registers */
+-      void (*dump_regs) (void __iomem *ioaddr);
++      void (*dump_regs)(void __iomem *ioaddr, u32 *reg_space);
+       /* 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,
+@@ -454,8 +453,10 @@ struct stmmac_ops {
+       void (*core_init)(struct mac_device_info *hw, int mtu);
+       /* Enable and verify that the IPC module is supported */
+       int (*rx_ipc)(struct mac_device_info *hw);
++      /* Enable RX Queues */
++      void (*rx_queue_enable)(struct mac_device_info *hw, u32 queue);
+       /* Dump MAC registers */
+-      void (*dump_regs)(struct mac_device_info *hw);
++      void (*dump_regs)(struct mac_device_info *hw, u32 *reg_space);
+       /* Handle extra events on specific interrupts hw dependent */
+       int (*host_irq_status)(struct mac_device_info *hw,
+                              struct stmmac_extra_stats *x);
+@@ -471,7 +472,8 @@ struct stmmac_ops {
+                             unsigned int reg_n);
+       void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
+                             unsigned int reg_n);
+-      void (*set_eee_mode)(struct mac_device_info *hw);
++      void (*set_eee_mode)(struct mac_device_info *hw,
++                           bool en_tx_lpi_clockgating);
+       void (*reset_eee_mode)(struct mac_device_info *hw);
+       void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
+       void (*set_eee_pls)(struct mac_device_info *hw, int link);
+--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
++++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
+@@ -11,10 +11,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
++++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+@@ -17,10 +17,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
+@@ -0,0 +1,202 @@
++/*
++ * Synopsys DWC Ethernet Quality-of-Service v4.10a linux driver
++ *
++ * Copyright (C) 2016 Joao Pinto <jpinto@synopsys.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/device.h>
++#include <linux/ethtool.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/of_net.h>
++#include <linux/mfd/syscon.h>
++#include <linux/platform_device.h>
++#include <linux/stmmac.h>
++
++#include "stmmac_platform.h"
++
++static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
++                                 struct plat_stmmacenet_data *plat_dat)
++{
++      struct device_node *np = pdev->dev.of_node;
++      u32 burst_map = 0;
++      u32 bit_index = 0;
++      u32 a_index = 0;
++
++      if (!plat_dat->axi) {
++              plat_dat->axi = kzalloc(sizeof(struct stmmac_axi), GFP_KERNEL);
++
++              if (!plat_dat->axi)
++                      return -ENOMEM;
++      }
++
++      plat_dat->axi->axi_lpi_en = of_property_read_bool(np, "snps,en-lpi");
++      if (of_property_read_u32(np, "snps,write-requests",
++                               &plat_dat->axi->axi_wr_osr_lmt)) {
++              /**
++               * Since the register has a reset value of 1, if property
++               * is missing, default to 1.
++               */
++              plat_dat->axi->axi_wr_osr_lmt = 1;
++      } else {
++              /**
++               * If property exists, to keep the behavior from dwc_eth_qos,
++               * subtract one after parsing.
++               */
++              plat_dat->axi->axi_wr_osr_lmt--;
++      }
++
++      if (of_property_read_u32(np, "read,read-requests",
++                               &plat_dat->axi->axi_rd_osr_lmt)) {
++              /**
++               * Since the register has a reset value of 1, if property
++               * is missing, default to 1.
++               */
++              plat_dat->axi->axi_rd_osr_lmt = 1;
++      } else {
++              /**
++               * If property exists, to keep the behavior from dwc_eth_qos,
++               * subtract one after parsing.
++               */
++              plat_dat->axi->axi_rd_osr_lmt--;
++      }
++      of_property_read_u32(np, "snps,burst-map", &burst_map);
++
++      /* converts burst-map bitmask to burst array */
++      for (bit_index = 0; bit_index < 7; bit_index++) {
++              if (burst_map & (1 << bit_index)) {
++                      switch (bit_index) {
++                      case 0:
++                      plat_dat->axi->axi_blen[a_index] = 4; break;
++                      case 1:
++                      plat_dat->axi->axi_blen[a_index] = 8; break;
++                      case 2:
++                      plat_dat->axi->axi_blen[a_index] = 16; break;
++                      case 3:
++                      plat_dat->axi->axi_blen[a_index] = 32; break;
++                      case 4:
++                      plat_dat->axi->axi_blen[a_index] = 64; break;
++                      case 5:
++                      plat_dat->axi->axi_blen[a_index] = 128; break;
++                      case 6:
++                      plat_dat->axi->axi_blen[a_index] = 256; break;
++                      default:
++                      break;
++                      }
++                      a_index++;
++              }
++      }
++
++      /* dwc-qos needs GMAC4, AAL, TSO and PMT */
++      plat_dat->has_gmac4 = 1;
++      plat_dat->dma_cfg->aal = 1;
++      plat_dat->tso_en = 1;
++      plat_dat->pmt = 1;
++
++      return 0;
++}
++
++static int dwc_eth_dwmac_probe(struct platform_device *pdev)
++{
++      struct plat_stmmacenet_data *plat_dat;
++      struct stmmac_resources stmmac_res;
++      struct resource *res;
++      int ret;
++
++      memset(&stmmac_res, 0, sizeof(struct stmmac_resources));
++
++      /**
++       * Since stmmac_platform supports name IRQ only, basic platform
++       * resource initialization is done in the glue logic.
++       */
++      stmmac_res.irq = platform_get_irq(pdev, 0);
++      if (stmmac_res.irq < 0) {
++              if (stmmac_res.irq != -EPROBE_DEFER)
++                      dev_err(&pdev->dev,
++                              "IRQ configuration information not found\n");
++
++              return stmmac_res.irq;
++      }
++      stmmac_res.wol_irq = stmmac_res.irq;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      stmmac_res.addr = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(stmmac_res.addr))
++              return PTR_ERR(stmmac_res.addr);
++
++      plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
++      if (IS_ERR(plat_dat))
++              return PTR_ERR(plat_dat);
++
++      plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");
++      if (IS_ERR(plat_dat->stmmac_clk)) {
++              dev_err(&pdev->dev, "apb_pclk clock not found.\n");
++              ret = PTR_ERR(plat_dat->stmmac_clk);
++              plat_dat->stmmac_clk = NULL;
++              goto err_remove_config_dt;
++      }
++      clk_prepare_enable(plat_dat->stmmac_clk);
++
++      plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");
++      if (IS_ERR(plat_dat->pclk)) {
++              dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
++              ret = PTR_ERR(plat_dat->pclk);
++              plat_dat->pclk = NULL;
++              goto err_out_clk_dis_phy;
++      }
++      clk_prepare_enable(plat_dat->pclk);
++
++      ret = dwc_eth_dwmac_config_dt(pdev, plat_dat);
++      if (ret)
++              goto err_out_clk_dis_aper;
++
++      ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
++      if (ret)
++              goto err_out_clk_dis_aper;
++
++      return 0;
++
++err_out_clk_dis_aper:
++      clk_disable_unprepare(plat_dat->pclk);
++err_out_clk_dis_phy:
++      clk_disable_unprepare(plat_dat->stmmac_clk);
++err_remove_config_dt:
++      stmmac_remove_config_dt(pdev, plat_dat);
++
++      return ret;
++}
++
++static int dwc_eth_dwmac_remove(struct platform_device *pdev)
++{
++      return stmmac_pltfr_remove(pdev);
++}
++
++static const struct of_device_id dwc_eth_dwmac_match[] = {
++      { .compatible = "snps,dwc-qos-ethernet-4.10", },
++      { }
++};
++MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
++
++static struct platform_driver dwc_eth_dwmac_driver = {
++      .probe  = dwc_eth_dwmac_probe,
++      .remove = dwc_eth_dwmac_remove,
++      .driver = {
++              .name           = "dwc-eth-dwmac",
++              .of_match_table = dwc_eth_dwmac_match,
++      },
++};
++module_platform_driver(dwc_eth_dwmac_driver);
++
++MODULE_AUTHOR("Joao Pinto <jpinto@synopsys.com>");
++MODULE_DESCRIPTION("Synopsys DWC Ethernet Quality-of-Service v4.10a driver");
++MODULE_LICENSE("GPL v2");
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
+@@ -35,10 +35,6 @@
+ #define PRG_ETH0_TXDLY_SHIFT          5
+ #define PRG_ETH0_TXDLY_MASK           GENMASK(6, 5)
+-#define PRG_ETH0_TXDLY_OFF            (0x0 << PRG_ETH0_TXDLY_SHIFT)
+-#define PRG_ETH0_TXDLY_QUARTER                (0x1 << PRG_ETH0_TXDLY_SHIFT)
+-#define PRG_ETH0_TXDLY_HALF           (0x2 << PRG_ETH0_TXDLY_SHIFT)
+-#define PRG_ETH0_TXDLY_THREE_QUARTERS (0x3 << PRG_ETH0_TXDLY_SHIFT)
+ /* divider for the result of m250_sel */
+ #define PRG_ETH0_CLK_M250_DIV_SHIFT   7
+@@ -69,6 +65,8 @@ struct meson8b_dwmac {
+       struct clk_divider      m25_div;
+       struct clk              *m25_div_clk;
++
++      u32                     tx_delay_ns;
+ };
+ static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
+@@ -179,11 +177,19 @@ static int meson8b_init_prg_eth(struct m
+ {
+       int ret;
+       unsigned long clk_rate;
++      u8 tx_dly_val = 0;
+       switch (dwmac->phy_mode) {
+       case PHY_INTERFACE_MODE_RGMII:
+-      case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
++              /* TX clock delay in ns = "8ns / 4 * tx_dly_val" (where
++               * 8ns are exactly one cycle of the 125MHz RGMII TX clock):
++               * 0ns = 0x0, 2ns = 0x1, 4ns = 0x2, 6ns = 0x3
++               */
++              tx_dly_val = dwmac->tx_delay_ns >> 1;
++              /* fall through */
++
++      case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               /* Generate a 25MHz clock for the PHY */
+               clk_rate = 25 * 1000 * 1000;
+@@ -196,9 +202,8 @@ static int meson8b_init_prg_eth(struct m
+               meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
+                                       PRG_ETH0_INVERTED_RMII_CLK, 0);
+-              /* TX clock delay - all known boards use a 1/4 cycle delay */
+               meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
+-                                      PRG_ETH0_TXDLY_QUARTER);
++                                      tx_dly_val << PRG_ETH0_TXDLY_SHIFT);
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+@@ -284,6 +289,11 @@ static int meson8b_dwmac_probe(struct pl
+               goto err_remove_config_dt;
+       }
++      /* use 2ns as fallback since this value was previously hardcoded */
++      if (of_property_read_u32(pdev->dev.of_node, "amlogic,tx-delay-ns",
++                               &dwmac->tx_delay_ns))
++              dwmac->tx_delay_ns = 2;
++
+       ret = meson8b_init_clk(dwmac);
+       if (ret)
+               goto err_remove_config_dt;
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -302,6 +302,122 @@ static const struct rk_gmac_ops rk3288_o
+       .set_rmii_speed = rk3288_set_rmii_speed,
+ };
++#define RK3328_GRF_MAC_CON0   0x0900
++#define RK3328_GRF_MAC_CON1   0x0904
++
++/* RK3328_GRF_MAC_CON0 */
++#define RK3328_GMAC_CLK_RX_DL_CFG(val)        HIWORD_UPDATE(val, 0x7F, 7)
++#define RK3328_GMAC_CLK_TX_DL_CFG(val)        HIWORD_UPDATE(val, 0x7F, 0)
++
++/* RK3328_GRF_MAC_CON1 */
++#define RK3328_GMAC_PHY_INTF_SEL_RGMII        \
++              (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6))
++#define RK3328_GMAC_PHY_INTF_SEL_RMII \
++              (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6))
++#define RK3328_GMAC_FLOW_CTRL         GRF_BIT(3)
++#define RK3328_GMAC_FLOW_CTRL_CLR     GRF_CLR_BIT(3)
++#define RK3328_GMAC_SPEED_10M         GRF_CLR_BIT(2)
++#define RK3328_GMAC_SPEED_100M                GRF_BIT(2)
++#define RK3328_GMAC_RMII_CLK_25M      GRF_BIT(7)
++#define RK3328_GMAC_RMII_CLK_2_5M     GRF_CLR_BIT(7)
++#define RK3328_GMAC_CLK_125M          (GRF_CLR_BIT(11) | GRF_CLR_BIT(12))
++#define RK3328_GMAC_CLK_25M           (GRF_BIT(11) | GRF_BIT(12))
++#define RK3328_GMAC_CLK_2_5M          (GRF_CLR_BIT(11) | GRF_BIT(12))
++#define RK3328_GMAC_RMII_MODE         GRF_BIT(9)
++#define RK3328_GMAC_RMII_MODE_CLR     GRF_CLR_BIT(9)
++#define RK3328_GMAC_TXCLK_DLY_ENABLE  GRF_BIT(0)
++#define RK3328_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0)
++#define RK3328_GMAC_RXCLK_DLY_ENABLE  GRF_BIT(1)
++#define RK3328_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(0)
++
++static void rk3328_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, RK3328_GRF_MAC_CON1,
++                   RK3328_GMAC_PHY_INTF_SEL_RGMII |
++                   RK3328_GMAC_RMII_MODE_CLR |
++                   RK3328_GMAC_RXCLK_DLY_ENABLE |
++                   RK3328_GMAC_TXCLK_DLY_ENABLE);
++
++      regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON0,
++                   RK3328_GMAC_CLK_RX_DL_CFG(rx_delay) |
++                   RK3328_GMAC_CLK_TX_DL_CFG(tx_delay));
++}
++
++static void rk3328_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, RK3328_GRF_MAC_CON1,
++                   RK3328_GMAC_PHY_INTF_SEL_RMII |
++                   RK3328_GMAC_RMII_MODE);
++
++      /* set MAC to RMII mode */
++      regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1, GRF_BIT(11));
++}
++
++static void rk3328_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, RK3328_GRF_MAC_CON1,
++                           RK3328_GMAC_CLK_2_5M);
++      else if (speed == 100)
++              regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
++                           RK3328_GMAC_CLK_25M);
++      else if (speed == 1000)
++              regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
++                           RK3328_GMAC_CLK_125M);
++      else
++              dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
++}
++
++static void rk3328_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, RK3328_GRF_MAC_CON1,
++                           RK3328_GMAC_RMII_CLK_2_5M |
++                           RK3328_GMAC_SPEED_10M);
++      else if (speed == 100)
++              regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1,
++                           RK3328_GMAC_RMII_CLK_25M |
++                           RK3328_GMAC_SPEED_100M);
++      else
++              dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
++}
++
++static const struct rk_gmac_ops rk3328_ops = {
++      .set_to_rgmii = rk3328_set_to_rgmii,
++      .set_to_rmii = rk3328_set_to_rmii,
++      .set_rgmii_speed = rk3328_set_rgmii_speed,
++      .set_rmii_speed = rk3328_set_rmii_speed,
++};
++
+ #define RK3366_GRF_SOC_CON6   0x0418
+ #define RK3366_GRF_SOC_CON7   0x041c
+@@ -1006,6 +1122,7 @@ static SIMPLE_DEV_PM_OPS(rk_gmac_pm_ops,
+ static const struct of_device_id rk_gmac_dwmac_match[] = {
+       { .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
+       { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
++      { .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
+       { .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
+       { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
+       { .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+@@ -341,7 +341,7 @@ static int socfpga_dwmac_probe(struct pl
+        * mode. Create a copy of the core reset handle so it can be used by
+        * the driver later.
+        */
+-      dwmac->stmmac_rst = stpriv->stmmac_rst;
++      dwmac->stmmac_rst = stpriv->plat->stmmac_rst;
+       ret = socfpga_dwmac_set_phy_mode(dwmac);
+       if (ret)
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+@@ -10,10 +10,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+@@ -16,10 +16,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -96,17 +92,13 @@ static int dwmac1000_rx_ipc_enable(struc
+       return !!(value & GMAC_CONTROL_IPC);
+ }
+-static void dwmac1000_dump_regs(struct mac_device_info *hw)
++static void dwmac1000_dump_regs(struct mac_device_info *hw, u32 *reg_space)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+       int i;
+-      pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
+-      for (i = 0; i < 55; i++) {
+-              int offset = i * 4;
+-              pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
+-                      offset, readl(ioaddr + offset));
+-      }
++      for (i = 0; i < 55; i++)
++              reg_space[i] = readl(ioaddr + i * 4);
+ }
+ static void dwmac1000_set_umac_addr(struct mac_device_info *hw,
+@@ -347,11 +339,14 @@ static int dwmac1000_irq_status(struct m
+       return ret;
+ }
+-static void dwmac1000_set_eee_mode(struct mac_device_info *hw)
++static void dwmac1000_set_eee_mode(struct mac_device_info *hw,
++                                 bool en_tx_lpi_clockgating)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+       u32 value;
++      /*TODO - en_tx_lpi_clockgating treatment */
++
+       /* Enable the link status receive on RGMII, SGMII ore SMII
+        * receive path and instruct the transmit to enter in LPI
+        * state.
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+@@ -16,10 +16,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -205,18 +201,14 @@ static void dwmac1000_dma_operation_mode
+       writel(csr6, ioaddr + DMA_CONTROL);
+ }
+-static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
++static void dwmac1000_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
+ {
+       int i;
+-      pr_info(" DMA registers\n");
+-      for (i = 0; i < 22; i++) {
+-              if ((i < 9) || (i > 17)) {
+-                      int offset = i * 4;
+-                      pr_err("\t Reg No. %d (offset 0x%x): 0x%08x\n", i,
+-                             (DMA_BUS_MODE + offset),
+-                             readl(ioaddr + DMA_BUS_MODE + offset));
+-              }
+-      }
++
++      for (i = 0; i < 22; i++)
++              if ((i < 9) || (i > 17))
++                      reg_space[DMA_BUS_MODE / 4 + i] =
++                              readl(ioaddr + DMA_BUS_MODE + i * 4);
+ }
+ static void dwmac1000_get_hw_feature(void __iomem *ioaddr,
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+@@ -18,10 +18,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -44,28 +40,18 @@ static void dwmac100_core_init(struct ma
+ #endif
+ }
+-static void dwmac100_dump_mac_regs(struct mac_device_info *hw)
++static void dwmac100_dump_mac_regs(struct mac_device_info *hw, u32 *reg_space)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+-      pr_info("\t----------------------------------------------\n"
+-              "\t  DWMAC 100 CSR (base addr = 0x%p)\n"
+-              "\t----------------------------------------------\n", ioaddr);
+-      pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
+-              readl(ioaddr + MAC_CONTROL));
+-      pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
+-              readl(ioaddr + MAC_ADDR_HIGH));
+-      pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
+-              readl(ioaddr + MAC_ADDR_LOW));
+-      pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
+-              MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
+-      pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
+-              MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
+-      pr_info("\tflow control (offset 0x%x): 0x%08x\n",
+-              MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
+-      pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
+-              readl(ioaddr + MAC_VLAN1));
+-      pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
+-              readl(ioaddr + MAC_VLAN2));
++
++      reg_space[MAC_CONTROL / 4] = readl(ioaddr + MAC_CONTROL);
++      reg_space[MAC_ADDR_HIGH / 4] = readl(ioaddr + MAC_ADDR_HIGH);
++      reg_space[MAC_ADDR_LOW / 4] = readl(ioaddr + MAC_ADDR_LOW);
++      reg_space[MAC_HASH_HIGH / 4] = readl(ioaddr + MAC_HASH_HIGH);
++      reg_space[MAC_HASH_LOW / 4] = readl(ioaddr + MAC_HASH_LOW);
++      reg_space[MAC_FLOW_CTRL / 4] = readl(ioaddr + MAC_FLOW_CTRL);
++      reg_space[MAC_VLAN1 / 4] = readl(ioaddr + MAC_VLAN1);
++      reg_space[MAC_VLAN2 / 4] = readl(ioaddr + MAC_VLAN2);
+ }
+ static int dwmac100_rx_ipc_enable(struct mac_device_info *hw)
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+@@ -18,10 +18,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -70,19 +66,18 @@ static void dwmac100_dma_operation_mode(
+       writel(csr6, ioaddr + DMA_CONTROL);
+ }
+-static void dwmac100_dump_dma_regs(void __iomem *ioaddr)
++static void dwmac100_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
+ {
+       int i;
+-      pr_debug("DWMAC 100 DMA CSR\n");
+       for (i = 0; i < 9; i++)
+-              pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
+-                       (DMA_BUS_MODE + i * 4),
+-                       readl(ioaddr + DMA_BUS_MODE + i * 4));
+-
+-      pr_debug("\tCSR20 (0x%x): 0x%08x, CSR21 (0x%x): 0x%08x\n",
+-               DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR),
+-               DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
++              reg_space[DMA_BUS_MODE / 4 + i] =
++                      readl(ioaddr + DMA_BUS_MODE + i * 4);
++
++      reg_space[DMA_CUR_TX_BUF_ADDR / 4] =
++              readl(ioaddr + DMA_CUR_TX_BUF_ADDR);
++      reg_space[DMA_CUR_RX_BUF_ADDR / 4] =
++              readl(ioaddr + DMA_CUR_RX_BUF_ADDR);
+ }
+ /* DMA controller has two counters to track the number of the missed frames. */
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+@@ -22,6 +22,7 @@
+ #define GMAC_HASH_TAB_32_63           0x00000014
+ #define GMAC_RX_FLOW_CTRL             0x00000090
+ #define GMAC_QX_TX_FLOW_CTRL(x)               (0x70 + x * 4)
++#define GMAC_RXQ_CTRL0                        0x000000a0
+ #define GMAC_INT_STATUS                       0x000000b0
+ #define GMAC_INT_EN                   0x000000b4
+ #define GMAC_PCS_BASE                 0x000000e0
+@@ -44,6 +45,11 @@
+ #define GMAC_MAX_PERFECT_ADDRESSES    128
++/* MAC RX Queue Enable */
++#define GMAC_RX_QUEUE_CLEAR(queue)    ~(GENMASK(1, 0) << ((queue) * 2))
++#define GMAC_RX_AV_QUEUE_ENABLE(queue)        BIT((queue) * 2)
++#define GMAC_RX_DCB_QUEUE_ENABLE(queue)       BIT(((queue) * 2) + 1)
++
+ /* MAC Flow Control RX */
+ #define GMAC_RX_FLOW_CTRL_RFE         BIT(0)
+@@ -84,6 +90,19 @@ enum power_event {
+       power_down = 0x00000001,
+ };
++/* Energy Efficient Ethernet (EEE) for GMAC4
++ *
++ * LPI status, timer and control register offset
++ */
++#define GMAC4_LPI_CTRL_STATUS 0xd0
++#define GMAC4_LPI_TIMER_CTRL  0xd4
++
++/* LPI control and status defines */
++#define GMAC4_LPI_CTRL_STATUS_LPITCSE BIT(21) /* LPI Tx Clock Stop Enable */
++#define GMAC4_LPI_CTRL_STATUS_LPITXA  BIT(19) /* Enable LPI TX Automate */
++#define GMAC4_LPI_CTRL_STATUS_PLS     BIT(17) /* PHY Link Status */
++#define GMAC4_LPI_CTRL_STATUS_LPIEN   BIT(16) /* LPI Enable */
++
+ /* MAC Debug bitmap */
+ #define GMAC_DEBUG_TFCSTS_MASK                GENMASK(18, 17)
+ #define GMAC_DEBUG_TFCSTS_SHIFT               17
+@@ -133,6 +152,8 @@ enum power_event {
+ /* MAC HW features2 bitmap */
+ #define GMAC_HW_FEAT_TXCHCNT          GENMASK(21, 18)
+ #define GMAC_HW_FEAT_RXCHCNT          GENMASK(15, 12)
++#define GMAC_HW_FEAT_TXQCNT           GENMASK(9, 6)
++#define GMAC_HW_FEAT_RXQCNT           GENMASK(3, 0)
+ /* MAC HW ADDR regs */
+ #define GMAC_HI_DCS                   GENMASK(18, 16)
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+@@ -59,19 +59,24 @@ static void dwmac4_core_init(struct mac_
+       writel(value, ioaddr + GMAC_INT_EN);
+ }
+-static void dwmac4_dump_regs(struct mac_device_info *hw)
++static void dwmac4_rx_queue_enable(struct mac_device_info *hw, u32 queue)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+-      int i;
++      u32 value = readl(ioaddr + GMAC_RXQ_CTRL0);
+-      pr_debug("\tDWMAC4 regs (base addr = 0x%p)\n", ioaddr);
++      value &= GMAC_RX_QUEUE_CLEAR(queue);
++      value |= GMAC_RX_AV_QUEUE_ENABLE(queue);
+-      for (i = 0; i < GMAC_REG_NUM; i++) {
+-              int offset = i * 4;
++      writel(value, ioaddr + GMAC_RXQ_CTRL0);
++}
+-              pr_debug("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
+-                       offset, readl(ioaddr + offset));
+-      }
++static void dwmac4_dump_regs(struct mac_device_info *hw, u32 *reg_space)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      int i;
++
++      for (i = 0; i < GMAC_REG_NUM; i++)
++              reg_space[i] = readl(ioaddr + i * 4);
+ }
+ static int dwmac4_rx_ipc_enable(struct mac_device_info *hw)
+@@ -126,6 +131,65 @@ static void dwmac4_get_umac_addr(struct
+                                  GMAC_ADDR_LOW(reg_n));
+ }
++static void dwmac4_set_eee_mode(struct mac_device_info *hw,
++                              bool en_tx_lpi_clockgating)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value;
++
++      /* Enable the link status receive on RGMII, SGMII ore SMII
++       * receive path and instruct the transmit to enter in LPI
++       * state.
++       */
++      value = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
++      value |= GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA;
++
++      if (en_tx_lpi_clockgating)
++              value |= GMAC4_LPI_CTRL_STATUS_LPITCSE;
++
++      writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
++}
++
++static void dwmac4_reset_eee_mode(struct mac_device_info *hw)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value;
++
++      value = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
++      value &= ~(GMAC4_LPI_CTRL_STATUS_LPIEN | GMAC4_LPI_CTRL_STATUS_LPITXA);
++      writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
++}
++
++static void dwmac4_set_eee_pls(struct mac_device_info *hw, int link)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value;
++
++      value = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
++
++      if (link)
++              value |= GMAC4_LPI_CTRL_STATUS_PLS;
++      else
++              value &= ~GMAC4_LPI_CTRL_STATUS_PLS;
++
++      writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
++}
++
++static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      int value = ((tw & 0xffff)) | ((ls & 0x3ff) << 16);
++
++      /* Program the timers in the LPI timer control register:
++       * LS: minimum time (ms) for which the link
++       *  status from PHY should be ok before transmitting
++       *  the LPI pattern.
++       * TW: minimum time (us) for which the core waits
++       *  after it has stopped transmitting the LPI pattern.
++       */
++      writel(value, ioaddr + GMAC4_LPI_TIMER_CTRL);
++}
++
+ static void dwmac4_set_filter(struct mac_device_info *hw,
+                             struct net_device *dev)
+ {
+@@ -392,12 +456,17 @@ static void dwmac4_debug(void __iomem *i
+ static const struct stmmac_ops dwmac4_ops = {
+       .core_init = dwmac4_core_init,
+       .rx_ipc = dwmac4_rx_ipc_enable,
++      .rx_queue_enable = dwmac4_rx_queue_enable,
+       .dump_regs = dwmac4_dump_regs,
+       .host_irq_status = dwmac4_irq_status,
+       .flow_ctrl = dwmac4_flow_ctrl,
+       .pmt = dwmac4_pmt,
+       .set_umac_addr = dwmac4_set_umac_addr,
+       .get_umac_addr = dwmac4_get_umac_addr,
++      .set_eee_mode = dwmac4_set_eee_mode,
++      .reset_eee_mode = dwmac4_reset_eee_mode,
++      .set_eee_timer = dwmac4_set_eee_timer,
++      .set_eee_pls = dwmac4_set_eee_pls,
+       .pcs_ctrl_ane = dwmac4_ctrl_ane,
+       .pcs_rane = dwmac4_rane,
+       .pcs_get_adv_lp = dwmac4_get_adv_lp,
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+@@ -103,7 +103,7 @@ static int dwmac4_wrback_get_rx_status(v
+                       x->rx_mii++;
+               if (unlikely(rdes3 & RDES3_CRC_ERROR)) {
+-                      x->rx_crc++;
++                      x->rx_crc_errors++;
+                       stats->rx_crc_errors++;
+               }
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+@@ -127,53 +127,51 @@ static void dwmac4_dma_init(void __iomem
+               dwmac4_dma_init_channel(ioaddr, dma_cfg, dma_tx, dma_rx, i);
+ }
+-static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel)
++static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel,
++                                u32 *reg_space)
+ {
+-      pr_debug(" Channel %d\n", channel);
+-      pr_debug("\tDMA_CHAN_CONTROL, offset: 0x%x, val: 0x%x\n", 0,
+-               readl(ioaddr + DMA_CHAN_CONTROL(channel)));
+-      pr_debug("\tDMA_CHAN_TX_CONTROL, offset: 0x%x, val: 0x%x\n", 0x4,
+-               readl(ioaddr + DMA_CHAN_TX_CONTROL(channel)));
+-      pr_debug("\tDMA_CHAN_RX_CONTROL, offset: 0x%x, val: 0x%x\n", 0x8,
+-               readl(ioaddr + DMA_CHAN_RX_CONTROL(channel)));
+-      pr_debug("\tDMA_CHAN_TX_BASE_ADDR, offset: 0x%x, val: 0x%x\n", 0x14,
+-               readl(ioaddr + DMA_CHAN_TX_BASE_ADDR(channel)));
+-      pr_debug("\tDMA_CHAN_RX_BASE_ADDR, offset: 0x%x, val: 0x%x\n", 0x1c,
+-               readl(ioaddr + DMA_CHAN_RX_BASE_ADDR(channel)));
+-      pr_debug("\tDMA_CHAN_TX_END_ADDR, offset: 0x%x, val: 0x%x\n", 0x20,
+-               readl(ioaddr + DMA_CHAN_TX_END_ADDR(channel)));
+-      pr_debug("\tDMA_CHAN_RX_END_ADDR, offset: 0x%x, val: 0x%x\n", 0x28,
+-               readl(ioaddr + DMA_CHAN_RX_END_ADDR(channel)));
+-      pr_debug("\tDMA_CHAN_TX_RING_LEN, offset: 0x%x, val: 0x%x\n", 0x2c,
+-               readl(ioaddr + DMA_CHAN_TX_RING_LEN(channel)));
+-      pr_debug("\tDMA_CHAN_RX_RING_LEN, offset: 0x%x, val: 0x%x\n", 0x30,
+-               readl(ioaddr + DMA_CHAN_RX_RING_LEN(channel)));
+-      pr_debug("\tDMA_CHAN_INTR_ENA, offset: 0x%x, val: 0x%x\n", 0x34,
+-               readl(ioaddr + DMA_CHAN_INTR_ENA(channel)));
+-      pr_debug("\tDMA_CHAN_RX_WATCHDOG, offset: 0x%x, val: 0x%x\n", 0x38,
+-               readl(ioaddr + DMA_CHAN_RX_WATCHDOG(channel)));
+-      pr_debug("\tDMA_CHAN_SLOT_CTRL_STATUS, offset: 0x%x, val: 0x%x\n", 0x3c,
+-               readl(ioaddr + DMA_CHAN_SLOT_CTRL_STATUS(channel)));
+-      pr_debug("\tDMA_CHAN_CUR_TX_DESC, offset: 0x%x, val: 0x%x\n", 0x44,
+-               readl(ioaddr + DMA_CHAN_CUR_TX_DESC(channel)));
+-      pr_debug("\tDMA_CHAN_CUR_RX_DESC, offset: 0x%x, val: 0x%x\n", 0x4c,
+-               readl(ioaddr + DMA_CHAN_CUR_RX_DESC(channel)));
+-      pr_debug("\tDMA_CHAN_CUR_TX_BUF_ADDR, offset: 0x%x, val: 0x%x\n", 0x54,
+-               readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR(channel)));
+-      pr_debug("\tDMA_CHAN_CUR_RX_BUF_ADDR, offset: 0x%x, val: 0x%x\n", 0x5c,
+-               readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR(channel)));
+-      pr_debug("\tDMA_CHAN_STATUS, offset: 0x%x, val: 0x%x\n", 0x60,
+-               readl(ioaddr + DMA_CHAN_STATUS(channel)));
++      reg_space[DMA_CHAN_CONTROL(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_CONTROL(channel));
++      reg_space[DMA_CHAN_TX_CONTROL(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_TX_CONTROL(channel));
++      reg_space[DMA_CHAN_RX_CONTROL(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_RX_CONTROL(channel));
++      reg_space[DMA_CHAN_TX_BASE_ADDR(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_TX_BASE_ADDR(channel));
++      reg_space[DMA_CHAN_RX_BASE_ADDR(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_RX_BASE_ADDR(channel));
++      reg_space[DMA_CHAN_TX_END_ADDR(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_TX_END_ADDR(channel));
++      reg_space[DMA_CHAN_RX_END_ADDR(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_RX_END_ADDR(channel));
++      reg_space[DMA_CHAN_TX_RING_LEN(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_TX_RING_LEN(channel));
++      reg_space[DMA_CHAN_RX_RING_LEN(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_RX_RING_LEN(channel));
++      reg_space[DMA_CHAN_INTR_ENA(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_INTR_ENA(channel));
++      reg_space[DMA_CHAN_RX_WATCHDOG(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_RX_WATCHDOG(channel));
++      reg_space[DMA_CHAN_SLOT_CTRL_STATUS(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_SLOT_CTRL_STATUS(channel));
++      reg_space[DMA_CHAN_CUR_TX_DESC(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_CUR_TX_DESC(channel));
++      reg_space[DMA_CHAN_CUR_RX_DESC(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_CUR_RX_DESC(channel));
++      reg_space[DMA_CHAN_CUR_TX_BUF_ADDR(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_CUR_TX_BUF_ADDR(channel));
++      reg_space[DMA_CHAN_CUR_RX_BUF_ADDR(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_CUR_RX_BUF_ADDR(channel));
++      reg_space[DMA_CHAN_STATUS(channel) / 4] =
++              readl(ioaddr + DMA_CHAN_STATUS(channel));
+ }
+-static void dwmac4_dump_dma_regs(void __iomem *ioaddr)
++static void dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
+ {
+       int i;
+-      pr_debug(" GMAC4 DMA registers\n");
+-
+       for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
+-              _dwmac4_dump_dma_regs(ioaddr, i);
++              _dwmac4_dump_dma_regs(ioaddr, i, reg_space);
+ }
+ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
+@@ -303,6 +301,11 @@ static void dwmac4_get_hw_feature(void _
+               ((hw_cap & GMAC_HW_FEAT_RXCHCNT) >> 12) + 1;
+       dma_cap->number_tx_channel =
+               ((hw_cap & GMAC_HW_FEAT_TXCHCNT) >> 18) + 1;
++      /* TX and RX number of queues */
++      dma_cap->number_rx_queues =
++              ((hw_cap & GMAC_HW_FEAT_RXQCNT) >> 0) + 1;
++      dma_cap->number_tx_queues =
++              ((hw_cap & GMAC_HW_FEAT_TXQCNT) >> 6) + 1;
+       /* IEEE 1588-2002 */
+       dma_cap->time_stamp = 0;
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+@@ -10,10 +10,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -21,6 +17,7 @@
+ *******************************************************************************/
+ #include <linux/io.h>
++#include <linux/iopoll.h>
+ #include "common.h"
+ #include "dwmac_dma.h"
+@@ -29,19 +26,16 @@
+ int dwmac_dma_reset(void __iomem *ioaddr)
+ {
+       u32 value = readl(ioaddr + DMA_BUS_MODE);
+-      int limit;
++      int err;
+       /* DMA SW reset */
+       value |= DMA_BUS_MODE_SFT_RESET;
+       writel(value, ioaddr + DMA_BUS_MODE);
+-      limit = 10;
+-      while (limit--) {
+-              if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
+-                      break;
+-              mdelay(10);
+-      }
+-      if (limit < 0)
++      err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
++                               !(value & DMA_BUS_MODE_SFT_RESET),
++                               100000, 10000);
++      if (err)
+               return -EBUSY;
+       return 0;
+@@ -102,7 +96,7 @@ static void show_tx_process_state(unsign
+               pr_debug("- TX (Stopped): Reset or Stop command\n");
+               break;
+       case 1:
+-              pr_debug("- TX (Running):Fetching the Tx desc\n");
++              pr_debug("- TX (Running): Fetching the Tx desc\n");
+               break;
+       case 2:
+               pr_debug("- TX (Running): Waiting for end of tx\n");
+@@ -136,7 +130,7 @@ static void show_rx_process_state(unsign
+               pr_debug("- RX (Running): Fetching the Rx desc\n");
+               break;
+       case 2:
+-              pr_debug("- RX (Running):Checking for end of pkt\n");
++              pr_debug("- RX (Running): Checking for end of pkt\n");
+               break;
+       case 3:
+               pr_debug("- RX (Running): Waiting for Rx pkt\n");
+@@ -246,7 +240,7 @@ void stmmac_set_mac_addr(void __iomem *i
+       unsigned long data;
+       data = (addr[5] << 8) | addr[4];
+-      /* For MAC Addr registers se have to set the Address Enable (AE)
++      /* For MAC Addr registers we have to set the Address Enable (AE)
+        * bit that has no effect on the High Reg 0 where the bit 31 (MO)
+        * is RO.
+        */
+@@ -261,9 +255,9 @@ void stmmac_set_mac(void __iomem *ioaddr
+       u32 value = readl(ioaddr + MAC_CTRL_REG);
+       if (enable)
+-              value |= MAC_RNABLE_RX | MAC_ENABLE_TX;
++              value |= MAC_ENABLE_RX | MAC_ENABLE_TX;
+       else
+-              value &= ~(MAC_ENABLE_TX | MAC_RNABLE_RX);
++              value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX);
+       writel(value, ioaddr + MAC_CTRL_REG);
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
++++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -225,7 +221,7 @@ static int enh_desc_get_rx_status(void *
+                       x->rx_mii++;
+               if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
+-                      x->rx_crc++;
++                      x->rx_crc_errors++;
+                       stats->rx_crc_errors++;
+               }
+               ret = discard_frame;
+--- a/drivers/net/ethernet/stmicro/stmmac/mmc.h
++++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
++++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -115,7 +111,7 @@ static int ndesc_get_rx_status(void *dat
+                       stats->collisions++;
+               }
+               if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
+-                      x->rx_crc++;
++                      x->rx_crc_errors++;
+                       stats->rx_crc_errors++;
+               }
+               ret = discard_frame;
+--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
++++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+@@ -16,10 +16,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -10,10 +10,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -106,9 +102,6 @@ struct stmmac_priv {
+       u32 msg_enable;
+       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;
+       int lpi_irq;
+@@ -120,8 +113,6 @@ struct stmmac_priv {
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info ptp_clock_ops;
+       unsigned int default_addend;
+-      struct clk *clk_ptp_ref;
+-      unsigned int clk_ptp_rate;
+       u32 adv_ts;
+       int use_riwt;
+       int irq_wake;
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -65,7 +61,7 @@ static const struct stmmac_stats stmmac_
+       STMMAC_STAT(overflow_error),
+       STMMAC_STAT(ipc_csum_error),
+       STMMAC_STAT(rx_collision),
+-      STMMAC_STAT(rx_crc),
++      STMMAC_STAT(rx_crc_errors),
+       STMMAC_STAT(dribbling_bit),
+       STMMAC_STAT(rx_length),
+       STMMAC_STAT(rx_mii),
+@@ -439,32 +435,14 @@ static int stmmac_ethtool_get_regs_len(s
+ static void stmmac_ethtool_gregs(struct net_device *dev,
+                         struct ethtool_regs *regs, void *space)
+ {
+-      int i;
+       u32 *reg_space = (u32 *) space;
+       struct stmmac_priv *priv = netdev_priv(dev);
+       memset(reg_space, 0x0, REG_SPACE_SIZE);
+-      if (!(priv->plat->has_gmac || priv->plat->has_gmac4)) {
+-              /* MAC registers */
+-              for (i = 0; i < 12; i++)
+-                      reg_space[i] = readl(priv->ioaddr + (i * 4));
+-              /* DMA registers */
+-              for (i = 0; i < 9; i++)
+-                      reg_space[i + 12] =
+-                          readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
+-              reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR);
+-              reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR);
+-      } else {
+-              /* MAC registers */
+-              for (i = 0; i < 55; i++)
+-                      reg_space[i] = readl(priv->ioaddr + (i * 4));
+-              /* DMA registers */
+-              for (i = 0; i < 22; i++)
+-                      reg_space[i + 55] =
+-                          readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
+-      }
++      priv->hw->mac->dump_regs(priv->hw, reg_space);
++      priv->hw->dma->dump_regs(priv->ioaddr, reg_space);
+ }
+ static void
+@@ -712,7 +690,7 @@ static int stmmac_ethtool_op_set_eee(str
+ static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv)
+ {
+-      unsigned long clk = clk_get_rate(priv->stmmac_clk);
++      unsigned long clk = clk_get_rate(priv->plat->stmmac_clk);
+       if (!clk)
+               return 0;
+@@ -722,7 +700,7 @@ static u32 stmmac_usec2riwt(u32 usec, st
+ static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv)
+ {
+-      unsigned long clk = clk_get_rate(priv->stmmac_clk);
++      unsigned long clk = clk_get_rate(priv->plat->stmmac_clk);
+       if (!clk)
+               return 0;
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -13,10 +13,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -158,7 +154,7 @@ static void stmmac_clk_csr_set(struct st
+ {
+       u32 clk_rate;
+-      clk_rate = clk_get_rate(priv->stmmac_clk);
++      clk_rate = clk_get_rate(priv->plat->stmmac_clk);
+       /* Platform provided default clk_csr would be assumed valid
+        * for all other cases except for the below mentioned ones.
+@@ -191,7 +187,7 @@ static void print_pkt(unsigned char *buf
+ static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
+ {
+-      unsigned avail;
++      u32 avail;
+       if (priv->dirty_tx > priv->cur_tx)
+               avail = priv->dirty_tx - priv->cur_tx - 1;
+@@ -203,7 +199,7 @@ static inline u32 stmmac_tx_avail(struct
+ static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv)
+ {
+-      unsigned dirty;
++      u32 dirty;
+       if (priv->dirty_rx <= priv->cur_rx)
+               dirty = priv->cur_rx - priv->dirty_rx;
+@@ -216,7 +212,7 @@ static inline u32 stmmac_rx_dirty(struct
+ /**
+  * stmmac_hw_fix_mac_speed - callback for speed selection
+  * @priv: driver private structure
+- * Description: on some platforms (e.g. ST), some HW system configuraton
++ * Description: on some platforms (e.g. ST), some HW system configuration
+  * registers have to be set according to the link speed negotiated.
+  */
+ static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
+@@ -239,7 +235,8 @@ static void stmmac_enable_eee_mode(struc
+       /* Check and enter in LPI mode */
+       if ((priv->dirty_tx == priv->cur_tx) &&
+           (priv->tx_path_in_lpi_mode == false))
+-              priv->hw->mac->set_eee_mode(priv->hw);
++              priv->hw->mac->set_eee_mode(priv->hw,
++                                          priv->plat->en_tx_lpi_clockgating);
+ }
+ /**
+@@ -415,7 +412,7 @@ static void stmmac_get_rx_hwtstamp(struc
+ /**
+  *  stmmac_hwtstamp_ioctl - control hardware timestamping.
+  *  @dev: device pointer.
+- *  @ifr: An IOCTL specefic structure, that can contain a pointer to
++ *  @ifr: An IOCTL specific structure, that can contain a pointer to
+  *  a proprietary structure used to pass information to the driver.
+  *  Description:
+  *  This function configures the MAC to enable/disable both outgoing(TX)
+@@ -606,7 +603,7 @@ static int stmmac_hwtstamp_ioctl(struct
+               /* program Sub Second Increment reg */
+               sec_inc = priv->hw->ptp->config_sub_second_increment(
+-                      priv->ptpaddr, priv->clk_ptp_rate,
++                      priv->ptpaddr, priv->plat->clk_ptp_rate,
+                       priv->plat->has_gmac4);
+               temp = div_u64(1000000000ULL, sec_inc);
+@@ -616,7 +613,7 @@ static int stmmac_hwtstamp_ioctl(struct
+                * where, freq_div_ratio = 1e9ns/sec_inc
+                */
+               temp = (u64)(temp << 32);
+-              priv->default_addend = div_u64(temp, priv->clk_ptp_rate);
++              priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate);
+               priv->hw->ptp->config_addend(priv->ptpaddr,
+                                            priv->default_addend);
+@@ -644,18 +641,6 @@ static int stmmac_init_ptp(struct stmmac
+       if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
+               return -EOPNOTSUPP;
+-      /* Fall-back to main clock in case of no PTP ref is passed */
+-      priv->clk_ptp_ref = devm_clk_get(priv->device, "clk_ptp_ref");
+-      if (IS_ERR(priv->clk_ptp_ref)) {
+-              priv->clk_ptp_rate = clk_get_rate(priv->stmmac_clk);
+-              priv->clk_ptp_ref = NULL;
+-              netdev_dbg(priv->dev, "PTP uses main clock\n");
+-      } else {
+-              clk_prepare_enable(priv->clk_ptp_ref);
+-              priv->clk_ptp_rate = clk_get_rate(priv->clk_ptp_ref);
+-              netdev_dbg(priv->dev, "PTP rate %d\n", priv->clk_ptp_rate);
+-      }
+-
+       priv->adv_ts = 0;
+       /* Check if adv_ts can be enabled for dwmac 4.x core */
+       if (priv->plat->has_gmac4 && priv->dma_cap.atime_stamp)
+@@ -682,8 +667,8 @@ static int stmmac_init_ptp(struct stmmac
+ static void stmmac_release_ptp(struct stmmac_priv *priv)
+ {
+-      if (priv->clk_ptp_ref)
+-              clk_disable_unprepare(priv->clk_ptp_ref);
++      if (priv->plat->clk_ptp_ref)
++              clk_disable_unprepare(priv->plat->clk_ptp_ref);
+       stmmac_ptp_unregister(priv);
+ }
+@@ -704,7 +689,7 @@ static void stmmac_adjust_link(struct ne
+       int new_state = 0;
+       unsigned int fc = priv->flow_ctrl, pause_time = priv->pause;
+-      if (phydev == NULL)
++      if (!phydev)
+               return;
+       spin_lock_irqsave(&priv->lock, flags);
+@@ -731,33 +716,36 @@ static void stmmac_adjust_link(struct ne
+                       new_state = 1;
+                       switch (phydev->speed) {
+                       case 1000:
+-                              if (likely((priv->plat->has_gmac) ||
+-                                         (priv->plat->has_gmac4)))
++                              if (priv->plat->has_gmac ||
++                                  priv->plat->has_gmac4)
+                                       ctrl &= ~priv->hw->link.port;
+-                              stmmac_hw_fix_mac_speed(priv);
+                               break;
+                       case 100:
++                              if (priv->plat->has_gmac ||
++                                  priv->plat->has_gmac4) {
++                                      ctrl |= priv->hw->link.port;
++                                      ctrl |= priv->hw->link.speed;
++                              } else {
++                                      ctrl &= ~priv->hw->link.port;
++                              }
++                              break;
+                       case 10:
+-                              if (likely((priv->plat->has_gmac) ||
+-                                         (priv->plat->has_gmac4))) {
++                              if (priv->plat->has_gmac ||
++                                  priv->plat->has_gmac4) {
+                                       ctrl |= priv->hw->link.port;
+-                                      if (phydev->speed == SPEED_100) {
+-                                              ctrl |= priv->hw->link.speed;
+-                                      } else {
+-                                              ctrl &= ~(priv->hw->link.speed);
+-                                      }
++                                      ctrl &= ~(priv->hw->link.speed);
+                               } else {
+                                       ctrl &= ~priv->hw->link.port;
+                               }
+-                              stmmac_hw_fix_mac_speed(priv);
+                               break;
+                       default:
+                               netif_warn(priv, link, priv->dev,
+-                                         "Speed (%d) not 10/100\n",
+-                                         phydev->speed);
++                                         "broken speed: %d\n", phydev->speed);
++                              phydev->speed = SPEED_UNKNOWN;
+                               break;
+                       }
+-
++                      if (phydev->speed != SPEED_UNKNOWN)
++                              stmmac_hw_fix_mac_speed(priv);
+                       priv->speed = phydev->speed;
+               }
+@@ -770,8 +758,8 @@ static void stmmac_adjust_link(struct ne
+       } else if (priv->oldlink) {
+               new_state = 1;
+               priv->oldlink = 0;
+-              priv->speed = 0;
+-              priv->oldduplex = -1;
++              priv->speed = SPEED_UNKNOWN;
++              priv->oldduplex = DUPLEX_UNKNOWN;
+       }
+       if (new_state && netif_msg_link(priv))
+@@ -833,8 +821,8 @@ static int stmmac_init_phy(struct net_de
+       int interface = priv->plat->interface;
+       int max_speed = priv->plat->max_speed;
+       priv->oldlink = 0;
+-      priv->speed = 0;
+-      priv->oldduplex = -1;
++      priv->speed = SPEED_UNKNOWN;
++      priv->oldduplex = DUPLEX_UNKNOWN;
+       if (priv->plat->phy_node) {
+               phydev = of_phy_connect(dev, priv->plat->phy_node,
+@@ -886,9 +874,7 @@ static int stmmac_init_phy(struct net_de
+       if (phydev->is_pseudo_fixed_link)
+               phydev->irq = PHY_POLL;
+-      netdev_dbg(priv->dev, "%s: attached to PHY (UID 0x%x) Link = %d\n",
+-                 __func__, phydev->phy_id, phydev->link);
+-
++      phy_attached_info(phydev);
+       return 0;
+ }
+@@ -1014,7 +1000,7 @@ static void stmmac_free_rx_buffers(struc
+  * @dev: net device structure
+  * @flags: gfp flag.
+  * Description: this function initializes the DMA RX/TX descriptors
+- * and allocates the socket buffers. It suppors the chained and ring
++ * and allocates the socket buffers. It supports the chained and ring
+  * modes.
+  */
+ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
+@@ -1127,13 +1113,6 @@ static void dma_free_tx_skbufs(struct st
+       int i;
+       for (i = 0; i < DMA_TX_SIZE; i++) {
+-              struct dma_desc *p;
+-
+-              if (priv->extend_desc)
+-                      p = &((priv->dma_etx + i)->basic);
+-              else
+-                      p = priv->dma_tx + i;
+-
+               if (priv->tx_skbuff_dma[i].buf) {
+                       if (priv->tx_skbuff_dma[i].map_as_page)
+                               dma_unmap_page(priv->device,
+@@ -1147,7 +1126,7 @@ static void dma_free_tx_skbufs(struct st
+                                                DMA_TO_DEVICE);
+               }
+-              if (priv->tx_skbuff[i] != NULL) {
++              if (priv->tx_skbuff[i]) {
+                       dev_kfree_skb_any(priv->tx_skbuff[i]);
+                       priv->tx_skbuff[i] = NULL;
+                       priv->tx_skbuff_dma[i].buf = 0;
+@@ -1271,6 +1250,28 @@ static void free_dma_desc_resources(stru
+ }
+ /**
++ *  stmmac_mac_enable_rx_queues - Enable MAC rx queues
++ *  @priv: driver private structure
++ *  Description: It is used for enabling the rx queues in the MAC
++ */
++static void stmmac_mac_enable_rx_queues(struct stmmac_priv *priv)
++{
++      int rx_count = priv->dma_cap.number_rx_queues;
++      int queue = 0;
++
++      /* If GMAC does not have multiple queues, then this is not necessary*/
++      if (rx_count == 1)
++              return;
++
++      /**
++       *  If the core is synthesized with multiple rx queues / multiple
++       *  dma channels, then rx queues will be disabled by default.
++       *  For now only rx queue 0 is enabled.
++       */
++      priv->hw->mac->rx_queue_enable(priv->hw, queue);
++}
++
++/**
+  *  stmmac_dma_operation_mode - HW DMA operation mode
+  *  @priv: driver private structure
+  *  Description: it is used for configuring the DMA operation mode register in
+@@ -1671,10 +1672,6 @@ static int stmmac_hw_setup(struct net_de
+       /* Copy the MAC addr into the HW  */
+       priv->hw->mac->set_umac_addr(priv->hw, dev->dev_addr, 0);
+-      /* If required, perform hw setup of the bus. */
+-      if (priv->plat->bus_setup)
+-              priv->plat->bus_setup(priv->ioaddr);
+-
+       /* PS and related bits will be programmed according to the speed */
+       if (priv->hw->pcs) {
+               int speed = priv->plat->mac_port_sel_speed;
+@@ -1691,6 +1688,10 @@ static int stmmac_hw_setup(struct net_de
+       /* Initialize the MAC Core */
+       priv->hw->mac->core_init(priv->hw, dev->mtu);
++      /* Initialize MAC RX Queues */
++      if (priv->hw->mac->rx_queue_enable)
++              stmmac_mac_enable_rx_queues(priv);
++
+       ret = priv->hw->mac->rx_ipc(priv->hw);
+       if (!ret) {
+               netdev_warn(priv->dev, "RX IPC Checksum Offload disabled\n");
+@@ -1711,8 +1712,10 @@ static int stmmac_hw_setup(struct net_de
+       if (init_ptp) {
+               ret = stmmac_init_ptp(priv);
+-              if (ret)
+-                      netdev_warn(priv->dev, "fail to init PTP.\n");
++              if (ret == -EOPNOTSUPP)
++                      netdev_warn(priv->dev, "PTP not supported by HW\n");
++              else if (ret)
++                      netdev_warn(priv->dev, "PTP init failed\n");
+       }
+ #ifdef CONFIG_DEBUG_FS
+@@ -1726,11 +1729,6 @@ static int stmmac_hw_setup(struct net_de
+       priv->hw->dma->start_tx(priv->ioaddr);
+       priv->hw->dma->start_rx(priv->ioaddr);
+-      /* Dump DMA/MAC registers */
+-      if (netif_msg_hw(priv)) {
+-              priv->hw->mac->dump_regs(priv->hw);
+-              priv->hw->dma->dump_regs(priv->ioaddr);
+-      }
+       priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
+       if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) {
+@@ -2519,7 +2517,7 @@ static int stmmac_rx(struct stmmac_priv
+               if (unlikely(status == discard_frame)) {
+                       priv->dev->stats.rx_errors++;
+                       if (priv->hwts_rx_en && !priv->extend_desc) {
+-                              /* DESC2 & DESC3 will be overwitten by device
++                              /* DESC2 & DESC3 will be overwritten by device
+                                * with timestamp value, hence reinitialize
+                                * them in stmmac_rx_refill() function so that
+                                * device can reuse it.
+@@ -2542,7 +2540,7 @@ static int stmmac_rx(struct stmmac_priv
+                       frame_len = priv->hw->desc->get_rx_frame_len(p, coe);
+-                      /*  If frame length is greather than skb buffer size
++                      /*  If frame length is greater than skb buffer size
+                        *  (preallocated during init) then the packet is
+                        *  ignored
+                        */
+@@ -2669,7 +2667,7 @@ static int stmmac_poll(struct napi_struc
+       work_done = stmmac_rx(priv, budget);
+       if (work_done < budget) {
+-              napi_complete(napi);
++              napi_complete_done(napi, work_done);
+               stmmac_enable_dma_irq(priv);
+       }
+       return work_done;
+@@ -2762,7 +2760,7 @@ static netdev_features_t stmmac_fix_feat
+       /* Some GMAC devices have a bugged Jumbo frame support that
+        * needs to have the Tx COE disabled for oversized frames
+        * (due to limited buffer sizes). In this case we disable
+-       * the TX csum insertionin the TDES and not use SF.
++       * the TX csum insertion in the TDES and not use SF.
+        */
+       if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))
+               features &= ~NETIF_F_CSUM_MASK;
+@@ -2908,9 +2906,7 @@ static void sysfs_display_ring(void *hea
+       struct dma_desc *p = (struct dma_desc *)head;
+       for (i = 0; i < size; i++) {
+-              u64 x;
+               if (extend_desc) {
+-                      x = *(u64 *) ep;
+                       seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+                                  i, (unsigned int)virt_to_phys(ep),
+                                  le32_to_cpu(ep->basic.des0),
+@@ -2919,7 +2915,6 @@ static void sysfs_display_ring(void *hea
+                                  le32_to_cpu(ep->basic.des3));
+                       ep++;
+               } else {
+-                      x = *(u64 *) p;
+                       seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+                                  i, (unsigned int)virt_to_phys(ep),
+                                  le32_to_cpu(p->des0), le32_to_cpu(p->des1),
+@@ -2989,7 +2984,7 @@ static int stmmac_sysfs_dma_cap_read(str
+                  (priv->dma_cap.hash_filter) ? "Y" : "N");
+       seq_printf(seq, "\tMultiple MAC address registers: %s\n",
+                  (priv->dma_cap.multi_addr) ? "Y" : "N");
+-      seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfatces): %s\n",
++      seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfaces): %s\n",
+                  (priv->dma_cap.pcs) ? "Y" : "N");
+       seq_printf(seq, "\tSMA (MDIO) Interface: %s\n",
+                  (priv->dma_cap.sma_mdio) ? "Y" : "N");
+@@ -3265,44 +3260,8 @@ int stmmac_dvr_probe(struct device *devi
+       if ((phyaddr >= 0) && (phyaddr <= 31))
+               priv->plat->phy_addr = phyaddr;
+-      priv->stmmac_clk = devm_clk_get(priv->device, STMMAC_RESOURCE_NAME);
+-      if (IS_ERR(priv->stmmac_clk)) {
+-              netdev_warn(priv->dev, "%s: warning: cannot get CSR clock\n",
+-                          __func__);
+-              /* If failed to obtain stmmac_clk and specific clk_csr value
+-               * is NOT passed from the platform, probe fail.
+-               */
+-              if (!priv->plat->clk_csr) {
+-                      ret = PTR_ERR(priv->stmmac_clk);
+-                      goto error_clk_get;
+-              } else {
+-                      priv->stmmac_clk = NULL;
+-              }
+-      }
+-      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)) {
+-              if (PTR_ERR(priv->stmmac_rst) == -EPROBE_DEFER) {
+-                      ret = -EPROBE_DEFER;
+-                      goto error_hw_init;
+-              }
+-              dev_info(priv->device, "no reset control found\n");
+-              priv->stmmac_rst = NULL;
+-      }
+-      if (priv->stmmac_rst)
+-              reset_control_deassert(priv->stmmac_rst);
++      if (priv->plat->stmmac_rst)
++              reset_control_deassert(priv->plat->stmmac_rst);
+       /* Init MAC and get the capabilities */
+       ret = stmmac_hw_init(priv);
+@@ -3388,10 +3347,6 @@ error_netdev_register:
+ error_mdio_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 ret;
+@@ -3417,10 +3372,10 @@ int stmmac_dvr_remove(struct device *dev
+       stmmac_set_mac(priv->ioaddr, false);
+       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->plat->stmmac_rst)
++              reset_control_assert(priv->plat->stmmac_rst);
++      clk_disable_unprepare(priv->plat->pclk);
++      clk_disable_unprepare(priv->plat->stmmac_clk);
+       if (priv->hw->pcs != STMMAC_PCS_RGMII &&
+           priv->hw->pcs != STMMAC_PCS_TBI &&
+           priv->hw->pcs != STMMAC_PCS_RTBI)
+@@ -3469,14 +3424,14 @@ int stmmac_suspend(struct device *dev)
+               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);
++              clk_disable(priv->plat->pclk);
++              clk_disable(priv->plat->stmmac_clk);
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->oldlink = 0;
+-      priv->speed = 0;
+-      priv->oldduplex = -1;
++      priv->speed = SPEED_UNKNOWN;
++      priv->oldduplex = DUPLEX_UNKNOWN;
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(stmmac_suspend);
+@@ -3509,9 +3464,9 @@ int stmmac_resume(struct device *dev)
+               priv->irq_wake = 0;
+       } else {
+               pinctrl_pm_select_default_state(priv->device);
+-              /* enable the clk prevously disabled */
+-              clk_enable(priv->stmmac_clk);
+-              clk_enable(priv->pclk);
++              /* enable the clk previously disabled */
++              clk_enable(priv->plat->stmmac_clk);
++              clk_enable(priv->plat->pclk);
+               /* reset the phy so that it's ready */
+               if (priv->mii)
+                       stmmac_mdio_reset(priv->mii);
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+@@ -13,10 +13,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -24,13 +20,14 @@
+   Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *******************************************************************************/
++#include <linux/io.h>
++#include <linux/iopoll.h>
+ #include <linux/mii.h>
+-#include <linux/phy.h>
+-#include <linux/slab.h>
+ #include <linux/of.h>
+ #include <linux/of_gpio.h>
+ #include <linux/of_mdio.h>
+-#include <asm/io.h>
++#include <linux/phy.h>
++#include <linux/slab.h>
+ #include "stmmac.h"
+@@ -42,22 +39,6 @@
+ #define MII_GMAC4_WRITE                       (1 << MII_GMAC4_GOC_SHIFT)
+ #define MII_GMAC4_READ                        (3 << MII_GMAC4_GOC_SHIFT)
+-static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr)
+-{
+-      unsigned long curr;
+-      unsigned long finish = jiffies + 3 * HZ;
+-
+-      do {
+-              curr = jiffies;
+-              if (readl(ioaddr + mii_addr) & MII_BUSY)
+-                      cpu_relax();
+-              else
+-                      return 0;
+-      } while (!time_after_eq(curr, finish));
+-
+-      return -EBUSY;
+-}
+-
+ /**
+  * stmmac_mdio_read
+  * @bus: points to the mii_bus structure
+@@ -74,7 +55,7 @@ static int stmmac_mdio_read(struct mii_b
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
+-
++      u32 v;
+       int data;
+       u32 value = MII_BUSY;
+@@ -86,12 +67,14 @@ static int stmmac_mdio_read(struct mii_b
+       if (priv->plat->has_gmac4)
+               value |= MII_GMAC4_READ;
+-      if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
++      if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
++                             100, 10000))
+               return -EBUSY;
+       writel(value, priv->ioaddr + mii_address);
+-      if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
++      if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
++                             100, 10000))
+               return -EBUSY;
+       /* Read the data from the MII data register */
+@@ -115,7 +98,7 @@ static int stmmac_mdio_write(struct mii_
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
+-
++      u32 v;
+       u32 value = MII_BUSY;
+       value |= (phyaddr << priv->hw->mii.addr_shift)
+@@ -130,7 +113,8 @@ static int stmmac_mdio_write(struct mii_
+               value |= MII_WRITE;
+       /* Wait until any existing MII operation is complete */
+-      if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
++      if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
++                             100, 10000))
+               return -EBUSY;
+       /* Set the MII address register to write */
+@@ -138,7 +122,8 @@ static int stmmac_mdio_write(struct mii_
+       writel(value, priv->ioaddr + mii_address);
+       /* Wait until any existing MII operation is complete */
+-      return stmmac_mdio_busy_wait(priv->ioaddr, mii_address);
++      return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
++                                100, 10000);
+ }
+ /**
+@@ -156,9 +141,9 @@ int stmmac_mdio_reset(struct mii_bus *bu
+ #ifdef CONFIG_OF
+       if (priv->device->of_node) {
+-
+               if (data->reset_gpio < 0) {
+                       struct device_node *np = priv->device->of_node;
++
+                       if (!np)
+                               return 0;
+@@ -198,7 +183,7 @@ int stmmac_mdio_reset(struct mii_bus *bu
+       /* This is a workaround for problems with the STE101P PHY.
+        * It doesn't complete its reset until at least one clock cycle
+-       * on MDC, so perform a dummy mdio read. To be upadted for GMAC4
++       * on MDC, so perform a dummy mdio read. To be updated for GMAC4
+        * if needed.
+        */
+       if (!priv->plat->has_gmac4)
+@@ -225,7 +210,7 @@ int stmmac_mdio_register(struct net_devi
+               return 0;
+       new_bus = mdiobus_alloc();
+-      if (new_bus == NULL)
++      if (!new_bus)
+               return -ENOMEM;
+       if (mdio_bus_data->irqs)
+@@ -262,49 +247,48 @@ int stmmac_mdio_register(struct net_devi
+       found = 0;
+       for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+               struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
+-              if (phydev) {
+-                      int act = 0;
+-                      char irq_num[4];
+-                      char *irq_str;
+-
+-                      /*
+-                       * If an IRQ was provided to be assigned after
+-                       * the bus probe, do it here.
+-                       */
+-                      if ((mdio_bus_data->irqs == NULL) &&
+-                          (mdio_bus_data->probed_phy_irq > 0)) {
+-                              new_bus->irq[addr] =
+-                                      mdio_bus_data->probed_phy_irq;
+-                              phydev->irq = mdio_bus_data->probed_phy_irq;
+-                      }
+-
+-                      /*
+-                       * If we're going to bind the MAC to this PHY bus,
+-                       * and no PHY number was provided to the MAC,
+-                       * use the one probed here.
+-                       */
+-                      if (priv->plat->phy_addr == -1)
+-                              priv->plat->phy_addr = addr;
+-
+-                      act = (priv->plat->phy_addr == addr);
+-                      switch (phydev->irq) {
+-                      case PHY_POLL:
+-                              irq_str = "POLL";
+-                              break;
+-                      case PHY_IGNORE_INTERRUPT:
+-                              irq_str = "IGNORE";
+-                              break;
+-                      default:
+-                              sprintf(irq_num, "%d", phydev->irq);
+-                              irq_str = irq_num;
+-                              break;
+-                      }
+-                      netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
+-                                  phydev->phy_id, addr,
+-                                  irq_str, phydev_name(phydev),
+-                                  act ? " active" : "");
+-                      found = 1;
++              int act = 0;
++              char irq_num[4];
++              char *irq_str;
++
++              if (!phydev)
++                      continue;
++
++              /*
++               * If an IRQ was provided to be assigned after
++               * the bus probe, do it here.
++               */
++              if (!mdio_bus_data->irqs &&
++                  (mdio_bus_data->probed_phy_irq > 0)) {
++                      new_bus->irq[addr] = mdio_bus_data->probed_phy_irq;
++                      phydev->irq = mdio_bus_data->probed_phy_irq;
++              }
++
++              /*
++               * If we're going to bind the MAC to this PHY bus,
++               * and no PHY number was provided to the MAC,
++               * use the one probed here.
++               */
++              if (priv->plat->phy_addr == -1)
++                      priv->plat->phy_addr = addr;
++
++              act = (priv->plat->phy_addr == addr);
++              switch (phydev->irq) {
++              case PHY_POLL:
++                      irq_str = "POLL";
++                      break;
++              case PHY_IGNORE_INTERRUPT:
++                      irq_str = "IGNORE";
++                      break;
++              default:
++                      sprintf(irq_num, "%d", phydev->irq);
++                      irq_str = irq_num;
++                      break;
+               }
++              netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
++                          phydev->phy_id, addr, irq_str, phydev_name(phydev),
++                          act ? " active" : "");
++              found = 1;
+       }
+       if (!found && !mdio_node) {
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+@@ -121,7 +117,6 @@ static struct stmmac_axi *stmmac_axi_set
+       axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
+       axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
+       axi->axi_kbbe = of_property_read_bool(np, "snps,axi_kbbe");
+-      axi->axi_axi_all = of_property_read_bool(np, "snps,axi_all");
+       axi->axi_fb = of_property_read_bool(np, "snps,axi_fb");
+       axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
+       axi->axi_rb =  of_property_read_bool(np, "snps,axi_rb");
+@@ -181,10 +176,19 @@ static int stmmac_dt_phy(struct plat_stm
+               mdio = false;
+       }
+-      /* If snps,dwmac-mdio is passed from DT, always register the MDIO */
+-      for_each_child_of_node(np, plat->mdio_node) {
+-              if (of_device_is_compatible(plat->mdio_node, "snps,dwmac-mdio"))
+-                      break;
++      /* exception for dwmac-dwc-qos-eth glue logic */
++      if (of_device_is_compatible(np, "snps,dwc-qos-ethernet-4.10")) {
++              plat->mdio_node = of_get_child_by_name(np, "mdio");
++      } else {
++              /**
++               * If snps,dwmac-mdio is passed from DT, always register
++               * the MDIO
++               */
++              for_each_child_of_node(np, plat->mdio_node) {
++                      if (of_device_is_compatible(plat->mdio_node,
++                                                  "snps,dwmac-mdio"))
++                              break;
++              }
+       }
+       if (plat->mdio_node) {
+@@ -249,6 +253,9 @@ stmmac_probe_config_dt(struct platform_d
+       plat->force_sf_dma_mode =
+               of_property_read_bool(np, "snps,force_sf_dma_mode");
++      plat->en_tx_lpi_clockgating =
++              of_property_read_bool(np, "snps,en-tx-lpi-clockgating");
++
+       /* Set the maxmtu to a default of JUMBO_LEN in case the
+        * parameter is not present in the device tree.
+        */
+@@ -333,7 +340,54 @@ stmmac_probe_config_dt(struct platform_d
+       plat->axi = stmmac_axi_setup(pdev);
++      /* clock setup */
++      plat->stmmac_clk = devm_clk_get(&pdev->dev,
++                                      STMMAC_RESOURCE_NAME);
++      if (IS_ERR(plat->stmmac_clk)) {
++              dev_warn(&pdev->dev, "Cannot get CSR clock\n");
++              plat->stmmac_clk = NULL;
++      }
++      clk_prepare_enable(plat->stmmac_clk);
++
++      plat->pclk = devm_clk_get(&pdev->dev, "pclk");
++      if (IS_ERR(plat->pclk)) {
++              if (PTR_ERR(plat->pclk) == -EPROBE_DEFER)
++                      goto error_pclk_get;
++
++              plat->pclk = NULL;
++      }
++      clk_prepare_enable(plat->pclk);
++
++      /* Fall-back to main clock in case of no PTP ref is passed */
++      plat->clk_ptp_ref = devm_clk_get(&pdev->dev, "clk_ptp_ref");
++      if (IS_ERR(plat->clk_ptp_ref)) {
++              plat->clk_ptp_rate = clk_get_rate(plat->stmmac_clk);
++              plat->clk_ptp_ref = NULL;
++              dev_warn(&pdev->dev, "PTP uses main clock\n");
++      } else {
++              clk_prepare_enable(plat->clk_ptp_ref);
++              plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref);
++              dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate);
++      }
++
++      plat->stmmac_rst = devm_reset_control_get(&pdev->dev,
++                                                STMMAC_RESOURCE_NAME);
++      if (IS_ERR(plat->stmmac_rst)) {
++              if (PTR_ERR(plat->stmmac_rst) == -EPROBE_DEFER)
++                      goto error_hw_init;
++
++              dev_info(&pdev->dev, "no reset control found\n");
++              plat->stmmac_rst = NULL;
++      }
++
+       return plat;
++
++error_hw_init:
++      clk_disable_unprepare(plat->pclk);
++error_pclk_get:
++      clk_disable_unprepare(plat->stmmac_clk);
++
++      return ERR_PTR(-EPROBE_DEFER);
+ }
+ /**
+@@ -357,7 +411,7 @@ void stmmac_remove_config_dt(struct plat
+ struct plat_stmmacenet_data *
+ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
+ {
+-      return ERR_PTR(-ENOSYS);
++      return ERR_PTR(-EINVAL);
+ }
+ void stmmac_remove_config_dt(struct platform_device *pdev,
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+@@ -12,10 +12,6 @@
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+-  You should have received a copy of the GNU General Public License along with
+-  this program; if not, write to the Free Software Foundation, Inc.,
+-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+-
+   The full GNU General Public License is included in this distribution in
+   the file called "COPYING".
+--- a/include/linux/stmmac.h
++++ b/include/linux/stmmac.h
+@@ -103,7 +103,6 @@ struct stmmac_axi {
+       u32 axi_wr_osr_lmt;
+       u32 axi_rd_osr_lmt;
+       bool axi_kbbe;
+-      bool axi_axi_all;
+       u32 axi_blen[AXI_BLEN];
+       bool axi_fb;
+       bool axi_mb;
+@@ -135,13 +134,18 @@ struct plat_stmmacenet_data {
+       int tx_fifo_size;
+       int rx_fifo_size;
+       void (*fix_mac_speed)(void *priv, unsigned int speed);
+-      void (*bus_setup)(void __iomem *ioaddr);
+       int (*init)(struct platform_device *pdev, void *priv);
+       void (*exit)(struct platform_device *pdev, void *priv);
+       void *bsp_priv;
++      struct clk *stmmac_clk;
++      struct clk *pclk;
++      struct clk *clk_ptp_ref;
++      unsigned int clk_ptp_rate;
++      struct reset_control *stmmac_rst;
+       struct stmmac_axi *axi;
+       int has_gmac4;
+       bool tso_en;
+       int mac_port_sel_speed;
++      bool en_tx_lpi_clockgating;
+ };
+ #endif
diff --git a/target/linux/sunxi/patches-4.9/0052-stmmac-form-4-12.patch b/target/linux/sunxi/patches-4.9/0052-stmmac-form-4-12.patch
new file mode 100644 (file)
index 0000000..285e4d2
--- /dev/null
@@ -0,0 +1,5952 @@
+--- a/Documentation/devicetree/bindings/net/stmmac.txt
++++ b/Documentation/devicetree/bindings/net/stmmac.txt
+@@ -7,9 +7,12 @@ Required properties:
+ - interrupt-parent: Should be the phandle for the interrupt controller
+   that services interrupts for this device
+ - interrupts: Should contain the STMMAC interrupts
+-- interrupt-names: Should contain the interrupt names "macirq"
+-  "eth_wake_irq" if this interrupt is supported in the "interrupts"
+-  property
++- interrupt-names: Should contain a list of interrupt names corresponding to
++      the interrupts in the interrupts property, if available.
++      Valid interrupt names are:
++  - "macirq" (combined signal for various interrupt events)
++  - "eth_wake_irq" (the interrupt to manage the remote wake-up packet detection)
++  - "eth_lpi" (the interrupt that occurs when Tx or Rx enters/exits LPI state)
+ - phy-mode: See ethernet.txt file in the same directory.
+ - snps,reset-gpio     gpio number for phy reset.
+ - snps,reset-active-low boolean flag to indicate if phy reset is active low.
+@@ -28,9 +31,9 @@ Optional properties:
+   clocks may be specified in derived bindings.
+ - clock-names: One name for each entry in the clocks property, the
+   first one should be "stmmaceth" and the second one should be "pclk".
+-- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
+-  available this clock is used for programming the Timestamp Addend Register.
+-  If not passed then the system clock will be used and this is fine on some
++- ptp_ref: this is the PTP reference clock; in case of the PTP is available
++  this clock is used for programming the Timestamp Addend Register. If not
++  passed then the system clock will be used and this is fine on some
+   platforms.
+ - tx-fifo-depth: See ethernet.txt file in the same directory
+ - rx-fifo-depth: See ethernet.txt file in the same directory
+@@ -72,7 +75,45 @@ Optional properties:
+       - snps,mb: mixed-burst
+       - snps,rb: rebuild INCRx Burst
+ - mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
+-
++- Multiple RX Queues parameters: below the list of all the parameters to
++                               configure the multiple RX queues:
++      - snps,rx-queues-to-use: number of RX queues to be used in the driver
++      - Choose one of these RX scheduling algorithms:
++              - snps,rx-sched-sp: Strict priority
++              - snps,rx-sched-wsp: Weighted Strict priority
++      - For each RX queue
++              - Choose one of these modes:
++                      - snps,dcb-algorithm: Queue to be enabled as DCB
++                      - snps,avb-algorithm: Queue to be enabled as AVB
++              - snps,map-to-dma-channel: Channel to map
++              - Specifiy specific packet routing:
++                      - snps,route-avcp: AV Untagged Control packets
++                      - snps,route-ptp: PTP Packets
++                      - snps,route-dcbcp: DCB Control Packets
++                      - snps,route-up: Untagged Packets
++                      - snps,route-multi-broad: Multicast & Broadcast Packets
++              - snps,priority: RX queue priority (Range: 0x0 to 0xF)
++- Multiple TX Queues parameters: below the list of all the parameters to
++                               configure the multiple TX queues:
++      - snps,tx-queues-to-use: number of TX queues to be used in the driver
++      - Choose one of these TX scheduling algorithms:
++              - snps,tx-sched-wrr: Weighted Round Robin
++              - snps,tx-sched-wfq: Weighted Fair Queuing
++              - snps,tx-sched-dwrr: Deficit Weighted Round Robin
++              - snps,tx-sched-sp: Strict priority
++      - For each TX queue
++              - snps,weight: TX queue weight (if using a DCB weight algorithm)
++              - Choose one of these modes:
++                      - snps,dcb-algorithm: TX queue will be working in DCB
++                      - snps,avb-algorithm: TX queue will be working in AVB
++                        [Attention] Queue 0 is reserved for legacy traffic
++                        and so no AVB is available in this queue.
++              - Configure Credit Base Shaper (if AVB Mode selected):
++                      - snps,send_slope: enable Low Power Interface
++                      - snps,idle_slope: unlock on WoL
++                      - snps,high_credit: max write outstanding req. limit
++                      - snps,low_credit: max read outstanding req. limit
++              - snps,priority: TX queue priority (Range: 0x0 to 0xF)
+ Examples:
+       stmmac_axi_setup: stmmac-axi-config {
+@@ -81,12 +122,41 @@ Examples:
+               snps,blen = <256 128 64 32 0 0 0>;
+       };
++      mtl_rx_setup: rx-queues-config {
++              snps,rx-queues-to-use = <1>;
++              snps,rx-sched-sp;
++              queue0 {
++                      snps,dcb-algorithm;
++                      snps,map-to-dma-channel = <0x0>;
++                      snps,priority = <0x0>;
++              };
++      };
++
++      mtl_tx_setup: tx-queues-config {
++              snps,tx-queues-to-use = <2>;
++              snps,tx-sched-wrr;
++              queue0 {
++                      snps,weight = <0x10>;
++                      snps,dcb-algorithm;
++                      snps,priority = <0x0>;
++              };
++
++              queue1 {
++                      snps,avb-algorithm;
++                      snps,send_slope = <0x1000>;
++                      snps,idle_slope = <0x1000>;
++                      snps,high_credit = <0x3E800>;
++                      snps,low_credit = <0xFFC18000>;
++                      snps,priority = <0x1>;
++              };
++      };
++
+       gmac0: ethernet@e0800000 {
+               compatible = "st,spear600-gmac";
+               reg = <0xe0800000 0x8000>;
+               interrupt-parent = <&vic1>;
+-              interrupts = <24 23>;
+-              interrupt-names = "macirq", "eth_wake_irq";
++              interrupts = <24 23 22>;
++              interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+               mac-address = [000000000000]; /* Filled in by U-Boot */
+               max-frame-size = <3800>;
+               phy-mode = "gmii";
+@@ -104,4 +174,6 @@ Examples:
+                       phy1: ethernet-phy@0 {
+                       };
+               };
++              snps,mtl-rx-config = <&mtl_rx_setup>;
++              snps,mtl-tx-config = <&mtl_tx_setup>;
+       };
+--- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
++++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
+@@ -37,6 +37,7 @@
+ #define TSE_PCS_CONTROL_AN_EN_MASK                    BIT(12)
+ #define TSE_PCS_CONTROL_REG                           0x00
+ #define TSE_PCS_CONTROL_RESTART_AN_MASK                       BIT(9)
++#define TSE_PCS_CTRL_AUTONEG_SGMII                    0x1140
+ #define TSE_PCS_IF_MODE_REG                           0x28
+ #define TSE_PCS_LINK_TIMER_0_REG                      0x24
+ #define TSE_PCS_LINK_TIMER_1_REG                      0x26
+@@ -65,6 +66,7 @@
+ #define TSE_PCS_SW_RESET_TIMEOUT                      100
+ #define TSE_PCS_USE_SGMII_AN_MASK                     BIT(1)
+ #define TSE_PCS_USE_SGMII_ENA                         BIT(0)
++#define TSE_PCS_IF_USE_SGMII                          0x03
+ #define SGMII_ADAPTER_CTRL_REG                                0x00
+ #define SGMII_ADAPTER_DISABLE                         0x0001
+@@ -101,7 +103,9 @@ int tse_pcs_init(void __iomem *base, str
+ {
+       int ret = 0;
+-      writew(TSE_PCS_USE_SGMII_ENA, base + TSE_PCS_IF_MODE_REG);
++      writew(TSE_PCS_IF_USE_SGMII, base + TSE_PCS_IF_MODE_REG);
++
++      writew(TSE_PCS_CTRL_AUTONEG_SGMII, base + TSE_PCS_CONTROL_REG);
+       writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG);
+       writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG);
+--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
++++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+@@ -26,12 +26,15 @@
+ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+ {
+-      struct stmmac_priv *priv = (struct stmmac_priv *)p;
+-      unsigned int entry = priv->cur_tx;
+-      struct dma_desc *desc = priv->dma_tx + entry;
++      struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)p;
+       unsigned int nopaged_len = skb_headlen(skb);
++      struct stmmac_priv *priv = tx_q->priv_data;
++      unsigned int entry = tx_q->cur_tx;
+       unsigned int bmax, des2;
+       unsigned int i = 1, len;
++      struct dma_desc *desc;
++
++      desc = tx_q->dma_tx + entry;
+       if (priv->plat->enh_desc)
+               bmax = BUF_SIZE_8KiB;
+@@ -45,16 +48,16 @@ static int stmmac_jumbo_frm(void *p, str
+       desc->des2 = cpu_to_le32(des2);
+       if (dma_mapping_error(priv->device, des2))
+               return -1;
+-      priv->tx_skbuff_dma[entry].buf = des2;
+-      priv->tx_skbuff_dma[entry].len = bmax;
++      tx_q->tx_skbuff_dma[entry].buf = des2;
++      tx_q->tx_skbuff_dma[entry].len = bmax;
+       /* do not close the descriptor and do not set own bit */
+       priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
+-                                      0, false);
++                                      0, false, skb->len);
+       while (len != 0) {
+-              priv->tx_skbuff[entry] = NULL;
++              tx_q->tx_skbuff[entry] = NULL;
+               entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
+-              desc = priv->dma_tx + entry;
++              desc = tx_q->dma_tx + entry;
+               if (len > bmax) {
+                       des2 = dma_map_single(priv->device,
+@@ -63,11 +66,11 @@ static int stmmac_jumbo_frm(void *p, str
+                       desc->des2 = cpu_to_le32(des2);
+                       if (dma_mapping_error(priv->device, des2))
+                               return -1;
+-                      priv->tx_skbuff_dma[entry].buf = des2;
+-                      priv->tx_skbuff_dma[entry].len = bmax;
++                      tx_q->tx_skbuff_dma[entry].buf = des2;
++                      tx_q->tx_skbuff_dma[entry].len = bmax;
+                       priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
+                                                       STMMAC_CHAIN_MODE, 1,
+-                                                      false);
++                                                      false, skb->len);
+                       len -= bmax;
+                       i++;
+               } else {
+@@ -77,17 +80,17 @@ static int stmmac_jumbo_frm(void *p, str
+                       desc->des2 = cpu_to_le32(des2);
+                       if (dma_mapping_error(priv->device, des2))
+                               return -1;
+-                      priv->tx_skbuff_dma[entry].buf = des2;
+-                      priv->tx_skbuff_dma[entry].len = len;
++                      tx_q->tx_skbuff_dma[entry].buf = des2;
++                      tx_q->tx_skbuff_dma[entry].len = len;
+                       /* last descriptor can be set now */
+                       priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
+                                                       STMMAC_CHAIN_MODE, 1,
+-                                                      true);
++                                                      true, skb->len);
+                       len = 0;
+               }
+       }
+-      priv->cur_tx = entry;
++      tx_q->cur_tx = entry;
+       return entry;
+ }
+@@ -136,32 +139,34 @@ static void stmmac_init_dma_chain(void *
+ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
+ {
+-      struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
++      struct stmmac_rx_queue *rx_q = (struct stmmac_rx_queue *)priv_ptr;
++      struct stmmac_priv *priv = rx_q->priv_data;
+       if (priv->hwts_rx_en && !priv->extend_desc)
+               /* NOTE: Device will overwrite des3 with timestamp value if
+                * 1588-2002 time stamping is enabled, hence reinitialize it
+                * to keep explicit chaining in the descriptor.
+                */
+-              p->des3 = cpu_to_le32((unsigned int)(priv->dma_rx_phy +
+-                                    (((priv->dirty_rx) + 1) %
++              p->des3 = cpu_to_le32((unsigned int)(rx_q->dma_rx_phy +
++                                    (((rx_q->dirty_rx) + 1) %
+                                      DMA_RX_SIZE) *
+                                     sizeof(struct dma_desc)));
+ }
+ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
+ {
+-      struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+-      unsigned int entry = priv->dirty_tx;
++      struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)priv_ptr;
++      struct stmmac_priv *priv = tx_q->priv_data;
++      unsigned int entry = tx_q->dirty_tx;
+-      if (priv->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
++      if (tx_q->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
+           priv->hwts_tx_en)
+               /* NOTE: Device will overwrite des3 with timestamp value if
+                * 1588-2002 time stamping is enabled, hence reinitialize it
+                * to keep explicit chaining in the descriptor.
+                */
+-              p->des3 = cpu_to_le32((unsigned int)((priv->dma_tx_phy +
+-                                    ((priv->dirty_tx + 1) % DMA_TX_SIZE))
++              p->des3 = cpu_to_le32((unsigned int)((tx_q->dma_tx_phy +
++                                    ((tx_q->dirty_tx + 1) % DMA_TX_SIZE))
+                                     * sizeof(struct dma_desc)));
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -246,6 +246,15 @@ struct stmmac_extra_stats {
+ #define STMMAC_TX_MAX_FRAMES  256
+ #define STMMAC_TX_FRAMES      64
++/* Packets types */
++enum packets_types {
++      PACKET_AVCPQ = 0x1, /* AV Untagged Control packets */
++      PACKET_PTPQ = 0x2, /* PTP Packets */
++      PACKET_DCBCPQ = 0x3, /* DCB Control Packets */
++      PACKET_UPQ = 0x4, /* Untagged Packets */
++      PACKET_MCBCQ = 0x5, /* Multicast & Broadcast Packets */
++};
++
+ /* Rx IPC status */
+ enum rx_frame_status {
+       good_frame = 0x0,
+@@ -324,6 +333,9 @@ struct dma_features {
+       unsigned int number_tx_queues;
+       /* Alternate (enhanced) DESC mode */
+       unsigned int enh_desc;
++      /* TX and RX FIFO sizes */
++      unsigned int tx_fifo_size;
++      unsigned int rx_fifo_size;
+ };
+ /* GMAC TX FIFO is 8K, Rx FIFO is 16K */
+@@ -361,7 +373,7 @@ struct stmmac_desc_ops {
+       /* Invoked by the xmit function to prepare the tx descriptor */
+       void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
+                                bool csum_flag, int mode, bool tx_own,
+-                               bool ls);
++                               bool ls, unsigned int tot_pkt_len);
+       void (*prepare_tso_tx_desc)(struct dma_desc *p, int is_fs, int len1,
+                                   int len2, bool tx_own, bool ls,
+                                   unsigned int tcphdrlen,
+@@ -413,6 +425,14 @@ struct stmmac_dma_ops {
+       int (*reset)(void __iomem *ioaddr);
+       void (*init)(void __iomem *ioaddr, struct stmmac_dma_cfg *dma_cfg,
+                    u32 dma_tx, u32 dma_rx, int atds);
++      void (*init_chan)(void __iomem *ioaddr,
++                        struct stmmac_dma_cfg *dma_cfg, u32 chan);
++      void (*init_rx_chan)(void __iomem *ioaddr,
++                           struct stmmac_dma_cfg *dma_cfg,
++                           u32 dma_rx_phy, u32 chan);
++      void (*init_tx_chan)(void __iomem *ioaddr,
++                           struct stmmac_dma_cfg *dma_cfg,
++                           u32 dma_tx_phy, u32 chan);
+       /* Configure the AXI Bus Mode Register */
+       void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
+       /* Dump DMA registers */
+@@ -421,25 +441,28 @@ struct stmmac_dma_ops {
+        * An invalid value enables the store-and-forward mode */
+       void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
+                        int rxfifosz);
++      void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
++                          int fifosz);
++      void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel);
+       /* To track extra statistic (if supported) */
+       void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
+                                  void __iomem *ioaddr);
+       void (*enable_dma_transmission) (void __iomem *ioaddr);
+-      void (*enable_dma_irq) (void __iomem *ioaddr);
+-      void (*disable_dma_irq) (void __iomem *ioaddr);
+-      void (*start_tx) (void __iomem *ioaddr);
+-      void (*stop_tx) (void __iomem *ioaddr);
+-      void (*start_rx) (void __iomem *ioaddr);
+-      void (*stop_rx) (void __iomem *ioaddr);
++      void (*enable_dma_irq)(void __iomem *ioaddr, u32 chan);
++      void (*disable_dma_irq)(void __iomem *ioaddr, u32 chan);
++      void (*start_tx)(void __iomem *ioaddr, u32 chan);
++      void (*stop_tx)(void __iomem *ioaddr, u32 chan);
++      void (*start_rx)(void __iomem *ioaddr, u32 chan);
++      void (*stop_rx)(void __iomem *ioaddr, u32 chan);
+       int (*dma_interrupt) (void __iomem *ioaddr,
+-                            struct stmmac_extra_stats *x);
++                            struct stmmac_extra_stats *x, u32 chan);
+       /* If supported then get the optional core features */
+       void (*get_hw_feature)(void __iomem *ioaddr,
+                              struct dma_features *dma_cap);
+       /* Program the HW RX Watchdog */
+-      void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
+-      void (*set_tx_ring_len)(void __iomem *ioaddr, u32 len);
+-      void (*set_rx_ring_len)(void __iomem *ioaddr, u32 len);
++      void (*rx_watchdog)(void __iomem *ioaddr, u32 riwt, u32 number_chan);
++      void (*set_tx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
++      void (*set_rx_ring_len)(void __iomem *ioaddr, u32 len, u32 chan);
+       void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
+       void (*set_tx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
+       void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan);
+@@ -451,20 +474,44 @@ struct mac_device_info;
+ struct stmmac_ops {
+       /* MAC core initialization */
+       void (*core_init)(struct mac_device_info *hw, int mtu);
++      /* Enable the MAC RX/TX */
++      void (*set_mac)(void __iomem *ioaddr, bool enable);
+       /* Enable and verify that the IPC module is supported */
+       int (*rx_ipc)(struct mac_device_info *hw);
+       /* Enable RX Queues */
+-      void (*rx_queue_enable)(struct mac_device_info *hw, u32 queue);
++      void (*rx_queue_enable)(struct mac_device_info *hw, u8 mode, u32 queue);
++      /* RX Queues Priority */
++      void (*rx_queue_prio)(struct mac_device_info *hw, u32 prio, u32 queue);
++      /* TX Queues Priority */
++      void (*tx_queue_prio)(struct mac_device_info *hw, u32 prio, u32 queue);
++      /* RX Queues Routing */
++      void (*rx_queue_routing)(struct mac_device_info *hw, u8 packet,
++                               u32 queue);
++      /* Program RX Algorithms */
++      void (*prog_mtl_rx_algorithms)(struct mac_device_info *hw, u32 rx_alg);
++      /* Program TX Algorithms */
++      void (*prog_mtl_tx_algorithms)(struct mac_device_info *hw, u32 tx_alg);
++      /* Set MTL TX queues weight */
++      void (*set_mtl_tx_queue_weight)(struct mac_device_info *hw,
++                                      u32 weight, u32 queue);
++      /* RX MTL queue to RX dma mapping */
++      void (*map_mtl_to_dma)(struct mac_device_info *hw, u32 queue, u32 chan);
++      /* Configure AV Algorithm */
++      void (*config_cbs)(struct mac_device_info *hw, u32 send_slope,
++                         u32 idle_slope, u32 high_credit, u32 low_credit,
++                         u32 queue);
+       /* Dump MAC registers */
+       void (*dump_regs)(struct mac_device_info *hw, u32 *reg_space);
+       /* Handle extra events on specific interrupts hw dependent */
+       int (*host_irq_status)(struct mac_device_info *hw,
+                              struct stmmac_extra_stats *x);
++      /* Handle MTL interrupts */
++      int (*host_mtl_irq_status)(struct mac_device_info *hw, u32 chan);
+       /* Multicast filter setting */
+       void (*set_filter)(struct mac_device_info *hw, struct net_device *dev);
+       /* Flow control setting */
+       void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex,
+-                        unsigned int fc, unsigned int pause_time);
++                        unsigned int fc, unsigned int pause_time, u32 tx_cnt);
+       /* Set power management mode (e.g. magic frame) */
+       void (*pmt)(struct mac_device_info *hw, unsigned long mode);
+       /* Set/Get Unicast MAC addresses */
+@@ -477,7 +524,8 @@ struct stmmac_ops {
+       void (*reset_eee_mode)(struct mac_device_info *hw);
+       void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
+       void (*set_eee_pls)(struct mac_device_info *hw, int link);
+-      void (*debug)(void __iomem *ioaddr, struct stmmac_extra_stats *x);
++      void (*debug)(void __iomem *ioaddr, struct stmmac_extra_stats *x,
++                    u32 rx_queues, u32 tx_queues);
+       /* PCS calls */
+       void (*pcs_ctrl_ane)(void __iomem *ioaddr, bool ane, bool srgmi_ral,
+                            bool loopback);
+@@ -547,6 +595,11 @@ struct mac_device_info {
+       unsigned int ps;
+ };
++struct stmmac_rx_routing {
++      u32 reg_mask;
++      u32 reg_shift;
++};
++
+ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
+                                       int perfect_uc_entries,
+                                       int *synopsys_id);
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
+@@ -14,16 +14,34 @@
+ #include <linux/clk.h>
+ #include <linux/clk-provider.h>
+ #include <linux/device.h>
++#include <linux/gpio/consumer.h>
+ #include <linux/ethtool.h>
+ #include <linux/io.h>
++#include <linux/iopoll.h>
+ #include <linux/ioport.h>
+ #include <linux/module.h>
++#include <linux/of_device.h>
+ #include <linux/of_net.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/platform_device.h>
++#include <linux/reset.h>
+ #include <linux/stmmac.h>
+ #include "stmmac_platform.h"
++#include "dwmac4.h"
++
++struct tegra_eqos {
++      struct device *dev;
++      void __iomem *regs;
++
++      struct reset_control *rst;
++      struct clk *clk_master;
++      struct clk *clk_slave;
++      struct clk *clk_tx;
++      struct clk *clk_rx;
++
++      struct gpio_desc *reset;
++};
+ static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
+                                  struct plat_stmmacenet_data *plat_dat)
+@@ -106,13 +124,309 @@ static int dwc_eth_dwmac_config_dt(struc
+       return 0;
+ }
++static void *dwc_qos_probe(struct platform_device *pdev,
++                         struct plat_stmmacenet_data *plat_dat,
++                         struct stmmac_resources *stmmac_res)
++{
++      int err;
++
++      plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");
++      if (IS_ERR(plat_dat->stmmac_clk)) {
++              dev_err(&pdev->dev, "apb_pclk clock not found.\n");
++              return ERR_CAST(plat_dat->stmmac_clk);
++      }
++
++      err = clk_prepare_enable(plat_dat->stmmac_clk);
++      if (err < 0) {
++              dev_err(&pdev->dev, "failed to enable apb_pclk clock: %d\n",
++                      err);
++              return ERR_PTR(err);
++      }
++
++      plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");
++      if (IS_ERR(plat_dat->pclk)) {
++              dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
++              err = PTR_ERR(plat_dat->pclk);
++              goto disable;
++      }
++
++      err = clk_prepare_enable(plat_dat->pclk);
++      if (err < 0) {
++              dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n",
++                      err);
++              goto disable;
++      }
++
++      return NULL;
++
++disable:
++      clk_disable_unprepare(plat_dat->stmmac_clk);
++      return ERR_PTR(err);
++}
++
++static int dwc_qos_remove(struct platform_device *pdev)
++{
++      struct net_device *ndev = platform_get_drvdata(pdev);
++      struct stmmac_priv *priv = netdev_priv(ndev);
++
++      clk_disable_unprepare(priv->plat->pclk);
++      clk_disable_unprepare(priv->plat->stmmac_clk);
++
++      return 0;
++}
++
++#define SDMEMCOMPPADCTRL 0x8800
++#define  SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31)
++
++#define AUTO_CAL_CONFIG 0x8804
++#define  AUTO_CAL_CONFIG_START BIT(31)
++#define  AUTO_CAL_CONFIG_ENABLE BIT(29)
++
++#define AUTO_CAL_STATUS 0x880c
++#define  AUTO_CAL_STATUS_ACTIVE BIT(31)
++
++static void tegra_eqos_fix_speed(void *priv, unsigned int speed)
++{
++      struct tegra_eqos *eqos = priv;
++      unsigned long rate = 125000000;
++      bool needs_calibration = false;
++      u32 value;
++      int err;
++
++      switch (speed) {
++      case SPEED_1000:
++              needs_calibration = true;
++              rate = 125000000;
++              break;
++
++      case SPEED_100:
++              needs_calibration = true;
++              rate = 25000000;
++              break;
++
++      case SPEED_10:
++              rate = 2500000;
++              break;
++
++      default:
++              dev_err(eqos->dev, "invalid speed %u\n", speed);
++              break;
++      }
++
++      if (needs_calibration) {
++              /* calibrate */
++              value = readl(eqos->regs + SDMEMCOMPPADCTRL);
++              value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
++              writel(value, eqos->regs + SDMEMCOMPPADCTRL);
++
++              udelay(1);
++
++              value = readl(eqos->regs + AUTO_CAL_CONFIG);
++              value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE;
++              writel(value, eqos->regs + AUTO_CAL_CONFIG);
++
++              err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
++                                              value,
++                                              value & AUTO_CAL_STATUS_ACTIVE,
++                                              1, 10);
++              if (err < 0) {
++                      dev_err(eqos->dev, "calibration did not start\n");
++                      goto failed;
++              }
++
++              err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
++                                              value,
++                                              (value & AUTO_CAL_STATUS_ACTIVE) == 0,
++                                              20, 200);
++              if (err < 0) {
++                      dev_err(eqos->dev, "calibration didn't finish\n");
++                      goto failed;
++              }
++
++      failed:
++              value = readl(eqos->regs + SDMEMCOMPPADCTRL);
++              value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
++              writel(value, eqos->regs + SDMEMCOMPPADCTRL);
++      } else {
++              value = readl(eqos->regs + AUTO_CAL_CONFIG);
++              value &= ~AUTO_CAL_CONFIG_ENABLE;
++              writel(value, eqos->regs + AUTO_CAL_CONFIG);
++      }
++
++      err = clk_set_rate(eqos->clk_tx, rate);
++      if (err < 0)
++              dev_err(eqos->dev, "failed to set TX rate: %d\n", err);
++}
++
++static int tegra_eqos_init(struct platform_device *pdev, void *priv)
++{
++      struct tegra_eqos *eqos = priv;
++      unsigned long rate;
++      u32 value;
++
++      rate = clk_get_rate(eqos->clk_slave);
++
++      value = (rate / 1000000) - 1;
++      writel(value, eqos->regs + GMAC_1US_TIC_COUNTER);
++
++      return 0;
++}
++
++static void *tegra_eqos_probe(struct platform_device *pdev,
++                            struct plat_stmmacenet_data *data,
++                            struct stmmac_resources *res)
++{
++      struct tegra_eqos *eqos;
++      int err;
++
++      eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);
++      if (!eqos) {
++              err = -ENOMEM;
++              goto error;
++      }
++
++      eqos->dev = &pdev->dev;
++      eqos->regs = res->addr;
++
++      eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");
++      if (IS_ERR(eqos->clk_master)) {
++              err = PTR_ERR(eqos->clk_master);
++              goto error;
++      }
++
++      err = clk_prepare_enable(eqos->clk_master);
++      if (err < 0)
++              goto error;
++
++      eqos->clk_slave = devm_clk_get(&pdev->dev, "slave_bus");
++      if (IS_ERR(eqos->clk_slave)) {
++              err = PTR_ERR(eqos->clk_slave);
++              goto disable_master;
++      }
++
++      data->stmmac_clk = eqos->clk_slave;
++
++      err = clk_prepare_enable(eqos->clk_slave);
++      if (err < 0)
++              goto disable_master;
++
++      eqos->clk_rx = devm_clk_get(&pdev->dev, "rx");
++      if (IS_ERR(eqos->clk_rx)) {
++              err = PTR_ERR(eqos->clk_rx);
++              goto disable_slave;
++      }
++
++      err = clk_prepare_enable(eqos->clk_rx);
++      if (err < 0)
++              goto disable_slave;
++
++      eqos->clk_tx = devm_clk_get(&pdev->dev, "tx");
++      if (IS_ERR(eqos->clk_tx)) {
++              err = PTR_ERR(eqos->clk_tx);
++              goto disable_rx;
++      }
++
++      err = clk_prepare_enable(eqos->clk_tx);
++      if (err < 0)
++              goto disable_rx;
++
++      eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);
++      if (IS_ERR(eqos->reset)) {
++              err = PTR_ERR(eqos->reset);
++              goto disable_tx;
++      }
++
++      usleep_range(2000, 4000);
++      gpiod_set_value(eqos->reset, 0);
++
++      eqos->rst = devm_reset_control_get(&pdev->dev, "eqos");
++      if (IS_ERR(eqos->rst)) {
++              err = PTR_ERR(eqos->rst);
++              goto reset_phy;
++      }
++
++      err = reset_control_assert(eqos->rst);
++      if (err < 0)
++              goto reset_phy;
++
++      usleep_range(2000, 4000);
++
++      err = reset_control_deassert(eqos->rst);
++      if (err < 0)
++              goto reset_phy;
++
++      usleep_range(2000, 4000);
++
++      data->fix_mac_speed = tegra_eqos_fix_speed;
++      data->init = tegra_eqos_init;
++      data->bsp_priv = eqos;
++
++      err = tegra_eqos_init(pdev, eqos);
++      if (err < 0)
++              goto reset;
++
++out:
++      return eqos;
++
++reset:
++      reset_control_assert(eqos->rst);
++reset_phy:
++      gpiod_set_value(eqos->reset, 1);
++disable_tx:
++      clk_disable_unprepare(eqos->clk_tx);
++disable_rx:
++      clk_disable_unprepare(eqos->clk_rx);
++disable_slave:
++      clk_disable_unprepare(eqos->clk_slave);
++disable_master:
++      clk_disable_unprepare(eqos->clk_master);
++error:
++      eqos = ERR_PTR(err);
++      goto out;
++}
++
++static int tegra_eqos_remove(struct platform_device *pdev)
++{
++      struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);
++
++      reset_control_assert(eqos->rst);
++      gpiod_set_value(eqos->reset, 1);
++      clk_disable_unprepare(eqos->clk_tx);
++      clk_disable_unprepare(eqos->clk_rx);
++      clk_disable_unprepare(eqos->clk_slave);
++      clk_disable_unprepare(eqos->clk_master);
++
++      return 0;
++}
++
++struct dwc_eth_dwmac_data {
++      void *(*probe)(struct platform_device *pdev,
++                     struct plat_stmmacenet_data *data,
++                     struct stmmac_resources *res);
++      int (*remove)(struct platform_device *pdev);
++};
++
++static const struct dwc_eth_dwmac_data dwc_qos_data = {
++      .probe = dwc_qos_probe,
++      .remove = dwc_qos_remove,
++};
++
++static const struct dwc_eth_dwmac_data tegra_eqos_data = {
++      .probe = tegra_eqos_probe,
++      .remove = tegra_eqos_remove,
++};
++
+ static int dwc_eth_dwmac_probe(struct platform_device *pdev)
+ {
++      const struct dwc_eth_dwmac_data *data;
+       struct plat_stmmacenet_data *plat_dat;
+       struct stmmac_resources stmmac_res;
+       struct resource *res;
++      void *priv;
+       int ret;
++      data = of_device_get_match_data(&pdev->dev);
++
+       memset(&stmmac_res, 0, sizeof(struct stmmac_resources));
+       /**
+@@ -138,39 +452,26 @@ static int dwc_eth_dwmac_probe(struct pl
+       if (IS_ERR(plat_dat))
+               return PTR_ERR(plat_dat);
+-      plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");
+-      if (IS_ERR(plat_dat->stmmac_clk)) {
+-              dev_err(&pdev->dev, "apb_pclk clock not found.\n");
+-              ret = PTR_ERR(plat_dat->stmmac_clk);
+-              plat_dat->stmmac_clk = NULL;
+-              goto err_remove_config_dt;
++      priv = data->probe(pdev, plat_dat, &stmmac_res);
++      if (IS_ERR(priv)) {
++              ret = PTR_ERR(priv);
++              dev_err(&pdev->dev, "failed to probe subdriver: %d\n", ret);
++              goto remove_config;
+       }
+-      clk_prepare_enable(plat_dat->stmmac_clk);
+-
+-      plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");
+-      if (IS_ERR(plat_dat->pclk)) {
+-              dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
+-              ret = PTR_ERR(plat_dat->pclk);
+-              plat_dat->pclk = NULL;
+-              goto err_out_clk_dis_phy;
+-      }
+-      clk_prepare_enable(plat_dat->pclk);
+       ret = dwc_eth_dwmac_config_dt(pdev, plat_dat);
+       if (ret)
+-              goto err_out_clk_dis_aper;
++              goto remove;
+       ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+       if (ret)
+-              goto err_out_clk_dis_aper;
++              goto remove;
+-      return 0;
++      return ret;
+-err_out_clk_dis_aper:
+-      clk_disable_unprepare(plat_dat->pclk);
+-err_out_clk_dis_phy:
+-      clk_disable_unprepare(plat_dat->stmmac_clk);
+-err_remove_config_dt:
++remove:
++      data->remove(pdev);
++remove_config:
+       stmmac_remove_config_dt(pdev, plat_dat);
+       return ret;
+@@ -178,11 +479,29 @@ err_remove_config_dt:
+ static int dwc_eth_dwmac_remove(struct platform_device *pdev)
+ {
+-      return stmmac_pltfr_remove(pdev);
++      struct net_device *ndev = platform_get_drvdata(pdev);
++      struct stmmac_priv *priv = netdev_priv(ndev);
++      const struct dwc_eth_dwmac_data *data;
++      int err;
++
++      data = of_device_get_match_data(&pdev->dev);
++
++      err = stmmac_dvr_remove(&pdev->dev);
++      if (err < 0)
++              dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
++
++      err = data->remove(pdev);
++      if (err < 0)
++              dev_err(&pdev->dev, "failed to remove subdriver: %d\n", err);
++
++      stmmac_remove_config_dt(pdev, priv->plat);
++
++      return err;
+ }
+ static const struct of_device_id dwc_eth_dwmac_match[] = {
+-      { .compatible = "snps,dwc-qos-ethernet-4.10", },
++      { .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
++      { .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data },
+       { }
+ };
+ MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+@@ -74,6 +74,10 @@ struct rk_priv_data {
+ #define GRF_BIT(nr)   (BIT(nr) | BIT(nr+16))
+ #define GRF_CLR_BIT(nr)       (BIT(nr+16))
++#define DELAY_ENABLE(soc, tx, rx) \
++      (((tx) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \
++       ((rx) ? soc##_GMAC_RXCLK_DLY_ENABLE : soc##_GMAC_RXCLK_DLY_DISABLE))
++
+ #define RK3228_GRF_MAC_CON0   0x0900
+ #define RK3228_GRF_MAC_CON1   0x0904
+@@ -115,8 +119,7 @@ static void rk3228_set_to_rgmii(struct r
+       regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1,
+                    RK3228_GMAC_PHY_INTF_SEL_RGMII |
+                    RK3228_GMAC_RMII_MODE_CLR |
+-                   RK3228_GMAC_RXCLK_DLY_ENABLE |
+-                   RK3228_GMAC_TXCLK_DLY_ENABLE);
++                   DELAY_ENABLE(RK3228, tx_delay, rx_delay));
+       regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON0,
+                    RK3228_GMAC_CLK_RX_DL_CFG(rx_delay) |
+@@ -232,8 +235,7 @@ static void rk3288_set_to_rgmii(struct r
+                    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 |
++                   DELAY_ENABLE(RK3288, tx_delay, rx_delay) |
+                    RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
+                    RK3288_GMAC_CLK_TX_DL_CFG(tx_delay));
+ }
+@@ -460,8 +462,7 @@ static void rk3366_set_to_rgmii(struct r
+                    RK3366_GMAC_PHY_INTF_SEL_RGMII |
+                    RK3366_GMAC_RMII_MODE_CLR);
+       regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON7,
+-                   RK3366_GMAC_RXCLK_DLY_ENABLE |
+-                   RK3366_GMAC_TXCLK_DLY_ENABLE |
++                   DELAY_ENABLE(RK3366, tx_delay, rx_delay) |
+                    RK3366_GMAC_CLK_RX_DL_CFG(rx_delay) |
+                    RK3366_GMAC_CLK_TX_DL_CFG(tx_delay));
+ }
+@@ -572,8 +573,7 @@ static void rk3368_set_to_rgmii(struct r
+                    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 |
++                   DELAY_ENABLE(RK3368, tx_delay, rx_delay) |
+                    RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
+                    RK3368_GMAC_CLK_TX_DL_CFG(tx_delay));
+ }
+@@ -684,8 +684,7 @@ static void rk3399_set_to_rgmii(struct r
+                    RK3399_GMAC_PHY_INTF_SEL_RGMII |
+                    RK3399_GMAC_RMII_MODE_CLR);
+       regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON6,
+-                   RK3399_GMAC_RXCLK_DLY_ENABLE |
+-                   RK3399_GMAC_TXCLK_DLY_ENABLE |
++                   DELAY_ENABLE(RK3399, tx_delay, rx_delay) |
+                    RK3399_GMAC_CLK_RX_DL_CFG(rx_delay) |
+                    RK3399_GMAC_CLK_TX_DL_CFG(tx_delay));
+ }
+@@ -985,14 +984,29 @@ static int rk_gmac_powerup(struct rk_pri
+               return ret;
+       /*rmii or rgmii*/
+-      if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
++      switch (bsp_priv->phy_iface) {
++      case 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) {
++              break;
++      case PHY_INTERFACE_MODE_RGMII_ID:
++              dev_info(dev, "init for RGMII_ID\n");
++              bsp_priv->ops->set_to_rgmii(bsp_priv, 0, 0);
++              break;
++      case PHY_INTERFACE_MODE_RGMII_RXID:
++              dev_info(dev, "init for RGMII_RXID\n");
++              bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay, 0);
++              break;
++      case PHY_INTERFACE_MODE_RGMII_TXID:
++              dev_info(dev, "init for RGMII_TXID\n");
++              bsp_priv->ops->set_to_rgmii(bsp_priv, 0, bsp_priv->rx_delay);
++              break;
++      case PHY_INTERFACE_MODE_RMII:
+               dev_info(dev, "init for RMII\n");
+               bsp_priv->ops->set_to_rmii(bsp_priv);
+-      } else {
++              break;
++      default:
+               dev_err(dev, "NO interface defined!\n");
+       }
+@@ -1022,12 +1036,19 @@ static void rk_fix_speed(void *priv, uns
+       struct rk_priv_data *bsp_priv = priv;
+       struct device *dev = &bsp_priv->pdev->dev;
+-      if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
++      switch (bsp_priv->phy_iface) {
++      case PHY_INTERFACE_MODE_RGMII:
++      case PHY_INTERFACE_MODE_RGMII_ID:
++      case PHY_INTERFACE_MODE_RGMII_RXID:
++      case PHY_INTERFACE_MODE_RGMII_TXID:
+               bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
+-      else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
++              break;
++      case PHY_INTERFACE_MODE_RMII:
+               bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
+-      else
++              break;
++      default:
+               dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
++      }
+ }
+ static int rk_gmac_probe(struct platform_device *pdev)
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+@@ -216,7 +216,8 @@ static void dwmac1000_set_filter(struct
+ static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
+-                              unsigned int fc, unsigned int pause_time)
++                              unsigned int fc, unsigned int pause_time,
++                              u32 tx_cnt)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+       /* Set flow such that DZPQ in Mac Register 6 is 0,
+@@ -412,7 +413,8 @@ static void dwmac1000_get_adv_lp(void __
+       dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
+ }
+-static void dwmac1000_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x)
++static void dwmac1000_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x,
++                          u32 rx_queues, u32 tx_queues)
+ {
+       u32 value = readl(ioaddr + GMAC_DEBUG);
+@@ -488,6 +490,7 @@ static void dwmac1000_debug(void __iomem
+ static const struct stmmac_ops dwmac1000_ops = {
+       .core_init = dwmac1000_core_init,
++      .set_mac = stmmac_set_mac,
+       .rx_ipc = dwmac1000_rx_ipc_enable,
+       .dump_regs = dwmac1000_dump_regs,
+       .host_irq_status = dwmac1000_irq_status,
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+@@ -247,7 +247,8 @@ static void dwmac1000_get_hw_feature(voi
+       dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
+ }
+-static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
++static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt,
++                                u32 number_chan)
+ {
+       writel(riwt, ioaddr + DMA_RX_WATCHDOG);
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+@@ -131,7 +131,8 @@ static void dwmac100_set_filter(struct m
+ }
+ static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
+-                             unsigned int fc, unsigned int pause_time)
++                             unsigned int fc, unsigned int pause_time,
++                             u32 tx_cnt)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+       unsigned int flow = MAC_FLOW_CTRL_ENABLE;
+@@ -149,6 +150,7 @@ static void dwmac100_pmt(struct mac_devi
+ static const struct stmmac_ops dwmac100_ops = {
+       .core_init = dwmac100_core_init,
++      .set_mac = stmmac_set_mac,
+       .rx_ipc = dwmac100_rx_ipc_enable,
+       .dump_regs = dwmac100_dump_mac_regs,
+       .host_irq_status = dwmac100_irq_status,
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+@@ -22,9 +22,15 @@
+ #define GMAC_HASH_TAB_32_63           0x00000014
+ #define GMAC_RX_FLOW_CTRL             0x00000090
+ #define GMAC_QX_TX_FLOW_CTRL(x)               (0x70 + x * 4)
++#define GMAC_TXQ_PRTY_MAP0            0x98
++#define GMAC_TXQ_PRTY_MAP1            0x9C
+ #define GMAC_RXQ_CTRL0                        0x000000a0
++#define GMAC_RXQ_CTRL1                        0x000000a4
++#define GMAC_RXQ_CTRL2                        0x000000a8
++#define GMAC_RXQ_CTRL3                        0x000000ac
+ #define GMAC_INT_STATUS                       0x000000b0
+ #define GMAC_INT_EN                   0x000000b4
++#define GMAC_1US_TIC_COUNTER          0x000000dc
+ #define GMAC_PCS_BASE                 0x000000e0
+ #define GMAC_PHYIF_CONTROL_STATUS     0x000000f8
+ #define GMAC_PMT                      0x000000c0
+@@ -38,6 +44,22 @@
+ #define GMAC_ADDR_HIGH(reg)           (0x300 + reg * 8)
+ #define GMAC_ADDR_LOW(reg)            (0x304 + reg * 8)
++/* RX Queues Routing */
++#define GMAC_RXQCTRL_AVCPQ_MASK               GENMASK(2, 0)
++#define GMAC_RXQCTRL_AVCPQ_SHIFT      0
++#define GMAC_RXQCTRL_PTPQ_MASK                GENMASK(6, 4)
++#define GMAC_RXQCTRL_PTPQ_SHIFT               4
++#define GMAC_RXQCTRL_DCBCPQ_MASK      GENMASK(10, 8)
++#define GMAC_RXQCTRL_DCBCPQ_SHIFT     8
++#define GMAC_RXQCTRL_UPQ_MASK         GENMASK(14, 12)
++#define GMAC_RXQCTRL_UPQ_SHIFT                12
++#define GMAC_RXQCTRL_MCBCQ_MASK               GENMASK(18, 16)
++#define GMAC_RXQCTRL_MCBCQ_SHIFT      16
++#define GMAC_RXQCTRL_MCBCQEN          BIT(20)
++#define GMAC_RXQCTRL_MCBCQEN_SHIFT    20
++#define GMAC_RXQCTRL_TACPQE           BIT(21)
++#define GMAC_RXQCTRL_TACPQE_SHIFT     21
++
+ /* MAC Packet Filtering */
+ #define GMAC_PACKET_FILTER_PR         BIT(0)
+ #define GMAC_PACKET_FILTER_HMC                BIT(2)
+@@ -53,6 +75,14 @@
+ /* MAC Flow Control RX */
+ #define GMAC_RX_FLOW_CTRL_RFE         BIT(0)
++/* RX Queues Priorities */
++#define GMAC_RXQCTRL_PSRQX_MASK(x)    GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
++#define GMAC_RXQCTRL_PSRQX_SHIFT(x)   ((x) * 8)
++
++/* TX Queues Priorities */
++#define GMAC_TXQCTRL_PSTQX_MASK(x)    GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
++#define GMAC_TXQCTRL_PSTQX_SHIFT(x)   ((x) * 8)
++
+ /* MAC Flow Control TX */
+ #define GMAC_TX_FLOW_CTRL_TFE         BIT(1)
+ #define GMAC_TX_FLOW_CTRL_PT_SHIFT    16
+@@ -148,6 +178,8 @@ enum power_event {
+ /* MAC HW features1 bitmap */
+ #define GMAC_HW_FEAT_AVSEL            BIT(20)
+ #define GMAC_HW_TSOEN                 BIT(18)
++#define GMAC_HW_TXFIFOSIZE            GENMASK(10, 6)
++#define GMAC_HW_RXFIFOSIZE            GENMASK(4, 0)
+ /* MAC HW features2 bitmap */
+ #define GMAC_HW_FEAT_TXCHCNT          GENMASK(21, 18)
+@@ -161,8 +193,25 @@ enum power_event {
+ #define GMAC_HI_REG_AE                        BIT(31)
+ /*  MTL registers */
++#define MTL_OPERATION_MODE            0x00000c00
++#define MTL_OPERATION_SCHALG_MASK     GENMASK(6, 5)
++#define MTL_OPERATION_SCHALG_WRR      (0x0 << 5)
++#define MTL_OPERATION_SCHALG_WFQ      (0x1 << 5)
++#define MTL_OPERATION_SCHALG_DWRR     (0x2 << 5)
++#define MTL_OPERATION_SCHALG_SP               (0x3 << 5)
++#define MTL_OPERATION_RAA             BIT(2)
++#define MTL_OPERATION_RAA_SP          (0x0 << 2)
++#define MTL_OPERATION_RAA_WSP         (0x1 << 2)
++
+ #define MTL_INT_STATUS                        0x00000c20
+-#define MTL_INT_Q0                    BIT(0)
++#define MTL_INT_QX(x)                 BIT(x)
++
++#define MTL_RXQ_DMA_MAP0              0x00000c30 /* queue 0 to 3 */
++#define MTL_RXQ_DMA_MAP1              0x00000c34 /* queue 4 to 7 */
++#define MTL_RXQ_DMA_Q04MDMACH_MASK    GENMASK(3, 0)
++#define MTL_RXQ_DMA_Q04MDMACH(x)      ((x) << 0)
++#define MTL_RXQ_DMA_QXMDMACH_MASK(x)  GENMASK(11 + (8 * ((x) - 1)), 8 * (x))
++#define MTL_RXQ_DMA_QXMDMACH(chan, q) ((chan) << (8 * (q)))
+ #define MTL_CHAN_BASE_ADDR            0x00000d00
+ #define MTL_CHAN_BASE_OFFSET          0x40
+@@ -180,6 +229,7 @@ enum power_event {
+ #define MTL_OP_MODE_TSF                       BIT(1)
+ #define MTL_OP_MODE_TQS_MASK          GENMASK(24, 16)
++#define MTL_OP_MODE_TQS_SHIFT         16
+ #define MTL_OP_MODE_TTC_MASK          0x70
+ #define MTL_OP_MODE_TTC_SHIFT         4
+@@ -193,6 +243,17 @@ enum power_event {
+ #define MTL_OP_MODE_TTC_384           (6 << MTL_OP_MODE_TTC_SHIFT)
+ #define MTL_OP_MODE_TTC_512           (7 << MTL_OP_MODE_TTC_SHIFT)
++#define MTL_OP_MODE_RQS_MASK          GENMASK(29, 20)
++#define MTL_OP_MODE_RQS_SHIFT         20
++
++#define MTL_OP_MODE_RFD_MASK          GENMASK(19, 14)
++#define MTL_OP_MODE_RFD_SHIFT         14
++
++#define MTL_OP_MODE_RFA_MASK          GENMASK(13, 8)
++#define MTL_OP_MODE_RFA_SHIFT         8
++
++#define MTL_OP_MODE_EHFC              BIT(7)
++
+ #define MTL_OP_MODE_RTC_MASK          0x18
+ #define MTL_OP_MODE_RTC_SHIFT         3
+@@ -201,6 +262,46 @@ enum power_event {
+ #define MTL_OP_MODE_RTC_96            (2 << MTL_OP_MODE_RTC_SHIFT)
+ #define MTL_OP_MODE_RTC_128           (3 << MTL_OP_MODE_RTC_SHIFT)
++/* MTL ETS Control register */
++#define MTL_ETS_CTRL_BASE_ADDR                0x00000d10
++#define MTL_ETS_CTRL_BASE_OFFSET      0x40
++#define MTL_ETSX_CTRL_BASE_ADDR(x)    (MTL_ETS_CTRL_BASE_ADDR + \
++                                      ((x) * MTL_ETS_CTRL_BASE_OFFSET))
++
++#define MTL_ETS_CTRL_CC                       BIT(3)
++#define MTL_ETS_CTRL_AVALG            BIT(2)
++
++/* MTL Queue Quantum Weight */
++#define MTL_TXQ_WEIGHT_BASE_ADDR      0x00000d18
++#define MTL_TXQ_WEIGHT_BASE_OFFSET    0x40
++#define MTL_TXQX_WEIGHT_BASE_ADDR(x)  (MTL_TXQ_WEIGHT_BASE_ADDR + \
++                                      ((x) * MTL_TXQ_WEIGHT_BASE_OFFSET))
++#define MTL_TXQ_WEIGHT_ISCQW_MASK     GENMASK(20, 0)
++
++/* MTL sendSlopeCredit register */
++#define MTL_SEND_SLP_CRED_BASE_ADDR   0x00000d1c
++#define MTL_SEND_SLP_CRED_OFFSET      0x40
++#define MTL_SEND_SLP_CREDX_BASE_ADDR(x)       (MTL_SEND_SLP_CRED_BASE_ADDR + \
++                                      ((x) * MTL_SEND_SLP_CRED_OFFSET))
++
++#define MTL_SEND_SLP_CRED_SSC_MASK    GENMASK(13, 0)
++
++/* MTL hiCredit register */
++#define MTL_HIGH_CRED_BASE_ADDR               0x00000d20
++#define MTL_HIGH_CRED_OFFSET          0x40
++#define MTL_HIGH_CREDX_BASE_ADDR(x)   (MTL_HIGH_CRED_BASE_ADDR + \
++                                      ((x) * MTL_HIGH_CRED_OFFSET))
++
++#define MTL_HIGH_CRED_HC_MASK         GENMASK(28, 0)
++
++/* MTL loCredit register */
++#define MTL_LOW_CRED_BASE_ADDR                0x00000d24
++#define MTL_LOW_CRED_OFFSET           0x40
++#define MTL_LOW_CREDX_BASE_ADDR(x)    (MTL_LOW_CRED_BASE_ADDR + \
++                                      ((x) * MTL_LOW_CRED_OFFSET))
++
++#define MTL_HIGH_CRED_LC_MASK         GENMASK(28, 0)
++
+ /*  MTL debug */
+ #define MTL_DEBUG_TXSTSFSTS           BIT(5)
+ #define MTL_DEBUG_TXFSTS              BIT(4)
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+@@ -59,17 +59,211 @@ static void dwmac4_core_init(struct mac_
+       writel(value, ioaddr + GMAC_INT_EN);
+ }
+-static void dwmac4_rx_queue_enable(struct mac_device_info *hw, u32 queue)
++static void dwmac4_rx_queue_enable(struct mac_device_info *hw,
++                                 u8 mode, u32 queue)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+       u32 value = readl(ioaddr + GMAC_RXQ_CTRL0);
+       value &= GMAC_RX_QUEUE_CLEAR(queue);
+-      value |= GMAC_RX_AV_QUEUE_ENABLE(queue);
++      if (mode == MTL_QUEUE_AVB)
++              value |= GMAC_RX_AV_QUEUE_ENABLE(queue);
++      else if (mode == MTL_QUEUE_DCB)
++              value |= GMAC_RX_DCB_QUEUE_ENABLE(queue);
+       writel(value, ioaddr + GMAC_RXQ_CTRL0);
+ }
++static void dwmac4_rx_queue_priority(struct mac_device_info *hw,
++                                   u32 prio, u32 queue)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 base_register;
++      u32 value;
++
++      base_register = (queue < 4) ? GMAC_RXQ_CTRL2 : GMAC_RXQ_CTRL3;
++
++      value = readl(ioaddr + base_register);
++
++      value &= ~GMAC_RXQCTRL_PSRQX_MASK(queue);
++      value |= (prio << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) &
++                                              GMAC_RXQCTRL_PSRQX_MASK(queue);
++      writel(value, ioaddr + base_register);
++}
++
++static void dwmac4_tx_queue_priority(struct mac_device_info *hw,
++                                   u32 prio, u32 queue)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 base_register;
++      u32 value;
++
++      base_register = (queue < 4) ? GMAC_TXQ_PRTY_MAP0 : GMAC_TXQ_PRTY_MAP1;
++
++      value = readl(ioaddr + base_register);
++
++      value &= ~GMAC_TXQCTRL_PSTQX_MASK(queue);
++      value |= (prio << GMAC_TXQCTRL_PSTQX_SHIFT(queue)) &
++                                              GMAC_TXQCTRL_PSTQX_MASK(queue);
++
++      writel(value, ioaddr + base_register);
++}
++
++static void dwmac4_tx_queue_routing(struct mac_device_info *hw,
++                                  u8 packet, u32 queue)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value;
++
++      const struct stmmac_rx_routing route_possibilities[] = {
++              { GMAC_RXQCTRL_AVCPQ_MASK, GMAC_RXQCTRL_AVCPQ_SHIFT },
++              { GMAC_RXQCTRL_PTPQ_MASK, GMAC_RXQCTRL_PTPQ_SHIFT },
++              { GMAC_RXQCTRL_DCBCPQ_MASK, GMAC_RXQCTRL_DCBCPQ_SHIFT },
++              { GMAC_RXQCTRL_UPQ_MASK, GMAC_RXQCTRL_UPQ_SHIFT },
++              { GMAC_RXQCTRL_MCBCQ_MASK, GMAC_RXQCTRL_MCBCQ_SHIFT },
++      };
++
++      value = readl(ioaddr + GMAC_RXQ_CTRL1);
++
++      /* routing configuration */
++      value &= ~route_possibilities[packet - 1].reg_mask;
++      value |= (queue << route_possibilities[packet-1].reg_shift) &
++               route_possibilities[packet - 1].reg_mask;
++
++      /* some packets require extra ops */
++      if (packet == PACKET_AVCPQ) {
++              value &= ~GMAC_RXQCTRL_TACPQE;
++              value |= 0x1 << GMAC_RXQCTRL_TACPQE_SHIFT;
++      } else if (packet == PACKET_MCBCQ) {
++              value &= ~GMAC_RXQCTRL_MCBCQEN;
++              value |= 0x1 << GMAC_RXQCTRL_MCBCQEN_SHIFT;
++      }
++
++      writel(value, ioaddr + GMAC_RXQ_CTRL1);
++}
++
++static void dwmac4_prog_mtl_rx_algorithms(struct mac_device_info *hw,
++                                        u32 rx_alg)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value = readl(ioaddr + MTL_OPERATION_MODE);
++
++      value &= ~MTL_OPERATION_RAA;
++      switch (rx_alg) {
++      case MTL_RX_ALGORITHM_SP:
++              value |= MTL_OPERATION_RAA_SP;
++              break;
++      case MTL_RX_ALGORITHM_WSP:
++              value |= MTL_OPERATION_RAA_WSP;
++              break;
++      default:
++              break;
++      }
++
++      writel(value, ioaddr + MTL_OPERATION_MODE);
++}
++
++static void dwmac4_prog_mtl_tx_algorithms(struct mac_device_info *hw,
++                                        u32 tx_alg)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value = readl(ioaddr + MTL_OPERATION_MODE);
++
++      value &= ~MTL_OPERATION_SCHALG_MASK;
++      switch (tx_alg) {
++      case MTL_TX_ALGORITHM_WRR:
++              value |= MTL_OPERATION_SCHALG_WRR;
++              break;
++      case MTL_TX_ALGORITHM_WFQ:
++              value |= MTL_OPERATION_SCHALG_WFQ;
++              break;
++      case MTL_TX_ALGORITHM_DWRR:
++              value |= MTL_OPERATION_SCHALG_DWRR;
++              break;
++      case MTL_TX_ALGORITHM_SP:
++              value |= MTL_OPERATION_SCHALG_SP;
++              break;
++      default:
++              break;
++      }
++}
++
++static void dwmac4_set_mtl_tx_queue_weight(struct mac_device_info *hw,
++                                         u32 weight, u32 queue)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value = readl(ioaddr + MTL_TXQX_WEIGHT_BASE_ADDR(queue));
++
++      value &= ~MTL_TXQ_WEIGHT_ISCQW_MASK;
++      value |= weight & MTL_TXQ_WEIGHT_ISCQW_MASK;
++      writel(value, ioaddr + MTL_TXQX_WEIGHT_BASE_ADDR(queue));
++}
++
++static void dwmac4_map_mtl_dma(struct mac_device_info *hw, u32 queue, u32 chan)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value;
++
++      if (queue < 4)
++              value = readl(ioaddr + MTL_RXQ_DMA_MAP0);
++      else
++              value = readl(ioaddr + MTL_RXQ_DMA_MAP1);
++
++      if (queue == 0 || queue == 4) {
++              value &= ~MTL_RXQ_DMA_Q04MDMACH_MASK;
++              value |= MTL_RXQ_DMA_Q04MDMACH(chan);
++      } else {
++              value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue);
++              value |= MTL_RXQ_DMA_QXMDMACH(chan, queue);
++      }
++
++      if (queue < 4)
++              writel(value, ioaddr + MTL_RXQ_DMA_MAP0);
++      else
++              writel(value, ioaddr + MTL_RXQ_DMA_MAP1);
++}
++
++static void dwmac4_config_cbs(struct mac_device_info *hw,
++                            u32 send_slope, u32 idle_slope,
++                            u32 high_credit, u32 low_credit, u32 queue)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 value;
++
++      pr_debug("Queue %d configured as AVB. Parameters:\n", queue);
++      pr_debug("\tsend_slope: 0x%08x\n", send_slope);
++      pr_debug("\tidle_slope: 0x%08x\n", idle_slope);
++      pr_debug("\thigh_credit: 0x%08x\n", high_credit);
++      pr_debug("\tlow_credit: 0x%08x\n", low_credit);
++
++      /* enable AV algorithm */
++      value = readl(ioaddr + MTL_ETSX_CTRL_BASE_ADDR(queue));
++      value |= MTL_ETS_CTRL_AVALG;
++      value |= MTL_ETS_CTRL_CC;
++      writel(value, ioaddr + MTL_ETSX_CTRL_BASE_ADDR(queue));
++
++      /* configure send slope */
++      value = readl(ioaddr + MTL_SEND_SLP_CREDX_BASE_ADDR(queue));
++      value &= ~MTL_SEND_SLP_CRED_SSC_MASK;
++      value |= send_slope & MTL_SEND_SLP_CRED_SSC_MASK;
++      writel(value, ioaddr + MTL_SEND_SLP_CREDX_BASE_ADDR(queue));
++
++      /* configure idle slope (same register as tx weight) */
++      dwmac4_set_mtl_tx_queue_weight(hw, idle_slope, queue);
++
++      /* configure high credit */
++      value = readl(ioaddr + MTL_HIGH_CREDX_BASE_ADDR(queue));
++      value &= ~MTL_HIGH_CRED_HC_MASK;
++      value |= high_credit & MTL_HIGH_CRED_HC_MASK;
++      writel(value, ioaddr + MTL_HIGH_CREDX_BASE_ADDR(queue));
++
++      /* configure high credit */
++      value = readl(ioaddr + MTL_LOW_CREDX_BASE_ADDR(queue));
++      value &= ~MTL_HIGH_CRED_LC_MASK;
++      value |= low_credit & MTL_HIGH_CRED_LC_MASK;
++      writel(value, ioaddr + MTL_LOW_CREDX_BASE_ADDR(queue));
++}
++
+ static void dwmac4_dump_regs(struct mac_device_info *hw, u32 *reg_space)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+@@ -251,11 +445,12 @@ static void dwmac4_set_filter(struct mac
+ }
+ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
+-                           unsigned int fc, unsigned int pause_time)
++                           unsigned int fc, unsigned int pause_time,
++                           u32 tx_cnt)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+-      u32 channel = STMMAC_CHAN0;     /* FIXME */
+       unsigned int flow = 0;
++      u32 queue = 0;
+       pr_debug("GMAC Flow-Control:\n");
+       if (fc & FLOW_RX) {
+@@ -265,13 +460,18 @@ static void dwmac4_flow_ctrl(struct mac_
+       }
+       if (fc & FLOW_TX) {
+               pr_debug("\tTransmit Flow-Control ON\n");
+-              flow |= GMAC_TX_FLOW_CTRL_TFE;
+-              writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(channel));
+-              if (duplex) {
++              if (duplex)
+                       pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
+-                      flow |= (pause_time << GMAC_TX_FLOW_CTRL_PT_SHIFT);
+-                      writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(channel));
++
++              for (queue = 0; queue < tx_cnt; queue++) {
++                      flow |= GMAC_TX_FLOW_CTRL_TFE;
++
++                      if (duplex)
++                              flow |=
++                              (pause_time << GMAC_TX_FLOW_CTRL_PT_SHIFT);
++
++                      writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(queue));
+               }
+       }
+ }
+@@ -325,11 +525,34 @@ static void dwmac4_phystatus(void __iome
+       }
+ }
++static int dwmac4_irq_mtl_status(struct mac_device_info *hw, u32 chan)
++{
++      void __iomem *ioaddr = hw->pcsr;
++      u32 mtl_int_qx_status;
++      int ret = 0;
++
++      mtl_int_qx_status = readl(ioaddr + MTL_INT_STATUS);
++
++      /* Check MTL Interrupt */
++      if (mtl_int_qx_status & MTL_INT_QX(chan)) {
++              /* read Queue x Interrupt status */
++              u32 status = readl(ioaddr + MTL_CHAN_INT_CTRL(chan));
++
++              if (status & MTL_RX_OVERFLOW_INT) {
++                      /*  clear Interrupt */
++                      writel(status | MTL_RX_OVERFLOW_INT,
++                             ioaddr + MTL_CHAN_INT_CTRL(chan));
++                      ret = CORE_IRQ_MTL_RX_OVERFLOW;
++              }
++      }
++
++      return ret;
++}
++
+ static int dwmac4_irq_status(struct mac_device_info *hw,
+                            struct stmmac_extra_stats *x)
+ {
+       void __iomem *ioaddr = hw->pcsr;
+-      u32 mtl_int_qx_status;
+       u32 intr_status;
+       int ret = 0;
+@@ -348,20 +571,6 @@ static int dwmac4_irq_status(struct mac_
+               x->irq_receive_pmt_irq_n++;
+       }
+-      mtl_int_qx_status = readl(ioaddr + MTL_INT_STATUS);
+-      /* Check MTL Interrupt: Currently only one queue is used: Q0. */
+-      if (mtl_int_qx_status & MTL_INT_Q0) {
+-              /* read Queue 0 Interrupt status */
+-              u32 status = readl(ioaddr + MTL_CHAN_INT_CTRL(STMMAC_CHAN0));
+-
+-              if (status & MTL_RX_OVERFLOW_INT) {
+-                      /*  clear Interrupt */
+-                      writel(status | MTL_RX_OVERFLOW_INT,
+-                             ioaddr + MTL_CHAN_INT_CTRL(STMMAC_CHAN0));
+-                      ret = CORE_IRQ_MTL_RX_OVERFLOW;
+-              }
+-      }
+-
+       dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
+       if (intr_status & PCS_RGSMIIIS_IRQ)
+               dwmac4_phystatus(ioaddr, x);
+@@ -369,64 +578,69 @@ static int dwmac4_irq_status(struct mac_
+       return ret;
+ }
+-static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x)
++static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x,
++                       u32 rx_queues, u32 tx_queues)
+ {
+       u32 value;
++      u32 queue;
+-      /*  Currently only channel 0 is supported */
+-      value = readl(ioaddr + MTL_CHAN_TX_DEBUG(STMMAC_CHAN0));
++      for (queue = 0; queue < tx_queues; queue++) {
++              value = readl(ioaddr + MTL_CHAN_TX_DEBUG(queue));
+-      if (value & MTL_DEBUG_TXSTSFSTS)
+-              x->mtl_tx_status_fifo_full++;
+-      if (value & MTL_DEBUG_TXFSTS)
+-              x->mtl_tx_fifo_not_empty++;
+-      if (value & MTL_DEBUG_TWCSTS)
+-              x->mmtl_fifo_ctrl++;
+-      if (value & MTL_DEBUG_TRCSTS_MASK) {
+-              u32 trcsts = (value & MTL_DEBUG_TRCSTS_MASK)
+-                           >> MTL_DEBUG_TRCSTS_SHIFT;
+-              if (trcsts == MTL_DEBUG_TRCSTS_WRITE)
+-                      x->mtl_tx_fifo_read_ctrl_write++;
+-              else if (trcsts == MTL_DEBUG_TRCSTS_TXW)
+-                      x->mtl_tx_fifo_read_ctrl_wait++;
+-              else if (trcsts == MTL_DEBUG_TRCSTS_READ)
+-                      x->mtl_tx_fifo_read_ctrl_read++;
+-              else
+-                      x->mtl_tx_fifo_read_ctrl_idle++;
++              if (value & MTL_DEBUG_TXSTSFSTS)
++                      x->mtl_tx_status_fifo_full++;
++              if (value & MTL_DEBUG_TXFSTS)
++                      x->mtl_tx_fifo_not_empty++;
++              if (value & MTL_DEBUG_TWCSTS)
++                      x->mmtl_fifo_ctrl++;
++              if (value & MTL_DEBUG_TRCSTS_MASK) {
++                      u32 trcsts = (value & MTL_DEBUG_TRCSTS_MASK)
++                                   >> MTL_DEBUG_TRCSTS_SHIFT;
++                      if (trcsts == MTL_DEBUG_TRCSTS_WRITE)
++                              x->mtl_tx_fifo_read_ctrl_write++;
++                      else if (trcsts == MTL_DEBUG_TRCSTS_TXW)
++                              x->mtl_tx_fifo_read_ctrl_wait++;
++                      else if (trcsts == MTL_DEBUG_TRCSTS_READ)
++                              x->mtl_tx_fifo_read_ctrl_read++;
++                      else
++                              x->mtl_tx_fifo_read_ctrl_idle++;
++              }
++              if (value & MTL_DEBUG_TXPAUSED)
++                      x->mac_tx_in_pause++;
+       }
+-      if (value & MTL_DEBUG_TXPAUSED)
+-              x->mac_tx_in_pause++;
+-      value = readl(ioaddr + MTL_CHAN_RX_DEBUG(STMMAC_CHAN0));
++      for (queue = 0; queue < rx_queues; queue++) {
++              value = readl(ioaddr + MTL_CHAN_RX_DEBUG(queue));
+-      if (value & MTL_DEBUG_RXFSTS_MASK) {
+-              u32 rxfsts = (value & MTL_DEBUG_RXFSTS_MASK)
+-                           >> MTL_DEBUG_RRCSTS_SHIFT;
+-
+-              if (rxfsts == MTL_DEBUG_RXFSTS_FULL)
+-                      x->mtl_rx_fifo_fill_level_full++;
+-              else if (rxfsts == MTL_DEBUG_RXFSTS_AT)
+-                      x->mtl_rx_fifo_fill_above_thresh++;
+-              else if (rxfsts == MTL_DEBUG_RXFSTS_BT)
+-                      x->mtl_rx_fifo_fill_below_thresh++;
+-              else
+-                      x->mtl_rx_fifo_fill_level_empty++;
+-      }
+-      if (value & MTL_DEBUG_RRCSTS_MASK) {
+-              u32 rrcsts = (value & MTL_DEBUG_RRCSTS_MASK) >>
+-                           MTL_DEBUG_RRCSTS_SHIFT;
+-
+-              if (rrcsts == MTL_DEBUG_RRCSTS_FLUSH)
+-                      x->mtl_rx_fifo_read_ctrl_flush++;
+-              else if (rrcsts == MTL_DEBUG_RRCSTS_RSTAT)
+-                      x->mtl_rx_fifo_read_ctrl_read_data++;
+-              else if (rrcsts == MTL_DEBUG_RRCSTS_RDATA)
+-                      x->mtl_rx_fifo_read_ctrl_status++;
+-              else
+-                      x->mtl_rx_fifo_read_ctrl_idle++;
++              if (value & MTL_DEBUG_RXFSTS_MASK) {
++                      u32 rxfsts = (value & MTL_DEBUG_RXFSTS_MASK)
++                                   >> MTL_DEBUG_RRCSTS_SHIFT;
++
++                      if (rxfsts == MTL_DEBUG_RXFSTS_FULL)
++                              x->mtl_rx_fifo_fill_level_full++;
++                      else if (rxfsts == MTL_DEBUG_RXFSTS_AT)
++                              x->mtl_rx_fifo_fill_above_thresh++;
++                      else if (rxfsts == MTL_DEBUG_RXFSTS_BT)
++                              x->mtl_rx_fifo_fill_below_thresh++;
++                      else
++                              x->mtl_rx_fifo_fill_level_empty++;
++              }
++              if (value & MTL_DEBUG_RRCSTS_MASK) {
++                      u32 rrcsts = (value & MTL_DEBUG_RRCSTS_MASK) >>
++                                   MTL_DEBUG_RRCSTS_SHIFT;
++
++                      if (rrcsts == MTL_DEBUG_RRCSTS_FLUSH)
++                              x->mtl_rx_fifo_read_ctrl_flush++;
++                      else if (rrcsts == MTL_DEBUG_RRCSTS_RSTAT)
++                              x->mtl_rx_fifo_read_ctrl_read_data++;
++                      else if (rrcsts == MTL_DEBUG_RRCSTS_RDATA)
++                              x->mtl_rx_fifo_read_ctrl_status++;
++                      else
++                              x->mtl_rx_fifo_read_ctrl_idle++;
++              }
++              if (value & MTL_DEBUG_RWCSTS)
++                      x->mtl_rx_fifo_ctrl_active++;
+       }
+-      if (value & MTL_DEBUG_RWCSTS)
+-              x->mtl_rx_fifo_ctrl_active++;
+       /* GMAC debug */
+       value = readl(ioaddr + GMAC_DEBUG);
+@@ -455,10 +669,51 @@ static void dwmac4_debug(void __iomem *i
+ static const struct stmmac_ops dwmac4_ops = {
+       .core_init = dwmac4_core_init,
++      .set_mac = stmmac_set_mac,
+       .rx_ipc = dwmac4_rx_ipc_enable,
+       .rx_queue_enable = dwmac4_rx_queue_enable,
++      .rx_queue_prio = dwmac4_rx_queue_priority,
++      .tx_queue_prio = dwmac4_tx_queue_priority,
++      .rx_queue_routing = dwmac4_tx_queue_routing,
++      .prog_mtl_rx_algorithms = dwmac4_prog_mtl_rx_algorithms,
++      .prog_mtl_tx_algorithms = dwmac4_prog_mtl_tx_algorithms,
++      .set_mtl_tx_queue_weight = dwmac4_set_mtl_tx_queue_weight,
++      .map_mtl_to_dma = dwmac4_map_mtl_dma,
++      .config_cbs = dwmac4_config_cbs,
+       .dump_regs = dwmac4_dump_regs,
+       .host_irq_status = dwmac4_irq_status,
++      .host_mtl_irq_status = dwmac4_irq_mtl_status,
++      .flow_ctrl = dwmac4_flow_ctrl,
++      .pmt = dwmac4_pmt,
++      .set_umac_addr = dwmac4_set_umac_addr,
++      .get_umac_addr = dwmac4_get_umac_addr,
++      .set_eee_mode = dwmac4_set_eee_mode,
++      .reset_eee_mode = dwmac4_reset_eee_mode,
++      .set_eee_timer = dwmac4_set_eee_timer,
++      .set_eee_pls = dwmac4_set_eee_pls,
++      .pcs_ctrl_ane = dwmac4_ctrl_ane,
++      .pcs_rane = dwmac4_rane,
++      .pcs_get_adv_lp = dwmac4_get_adv_lp,
++      .debug = dwmac4_debug,
++      .set_filter = dwmac4_set_filter,
++};
++
++static const struct stmmac_ops dwmac410_ops = {
++      .core_init = dwmac4_core_init,
++      .set_mac = stmmac_dwmac4_set_mac,
++      .rx_ipc = dwmac4_rx_ipc_enable,
++      .rx_queue_enable = dwmac4_rx_queue_enable,
++      .rx_queue_prio = dwmac4_rx_queue_priority,
++      .tx_queue_prio = dwmac4_tx_queue_priority,
++      .rx_queue_routing = dwmac4_tx_queue_routing,
++      .prog_mtl_rx_algorithms = dwmac4_prog_mtl_rx_algorithms,
++      .prog_mtl_tx_algorithms = dwmac4_prog_mtl_tx_algorithms,
++      .set_mtl_tx_queue_weight = dwmac4_set_mtl_tx_queue_weight,
++      .map_mtl_to_dma = dwmac4_map_mtl_dma,
++      .config_cbs = dwmac4_config_cbs,
++      .dump_regs = dwmac4_dump_regs,
++      .host_irq_status = dwmac4_irq_status,
++      .host_mtl_irq_status = dwmac4_irq_mtl_status,
+       .flow_ctrl = dwmac4_flow_ctrl,
+       .pmt = dwmac4_pmt,
+       .set_umac_addr = dwmac4_set_umac_addr,
+@@ -492,8 +747,6 @@ struct mac_device_info *dwmac4_setup(voi
+       if (mac->multicast_filter_bins)
+               mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
+-      mac->mac = &dwmac4_ops;
+-
+       mac->link.port = GMAC_CONFIG_PS;
+       mac->link.duplex = GMAC_CONFIG_DM;
+       mac->link.speed = GMAC_CONFIG_FES;
+@@ -514,5 +767,10 @@ struct mac_device_info *dwmac4_setup(voi
+       else
+               mac->dma = &dwmac4_dma_ops;
++      if (*synopsys_id >= DWMAC_CORE_4_00)
++              mac->mac = &dwmac410_ops;
++      else
++              mac->mac = &dwmac4_ops;
++
+       return mac;
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+@@ -214,13 +214,13 @@ static int dwmac4_wrback_get_tx_timestam
+ {
+       /* Context type from W/B descriptor must be zero */
+       if (le32_to_cpu(p->des3) & TDES3_CONTEXT_TYPE)
+-              return -EINVAL;
++              return 0;
+       /* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
+       if (le32_to_cpu(p->des3) & TDES3_TIMESTAMP_STATUS)
+-              return 0;
++              return 1;
+-      return 1;
++      return 0;
+ }
+ static inline u64 dwmac4_get_timestamp(void *desc, u32 ats)
+@@ -282,7 +282,10 @@ static int dwmac4_wrback_get_rx_timestam
+               }
+       }
+ exit:
+-      return ret;
++      if (likely(ret == 0))
++              return 1;
++
++      return 0;
+ }
+ static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
+@@ -304,12 +307,13 @@ static void dwmac4_rd_init_tx_desc(struc
+ static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+                                     bool csum_flag, int mode, bool tx_own,
+-                                    bool ls)
++                                    bool ls, unsigned int tot_pkt_len)
+ {
+       unsigned int tdes3 = le32_to_cpu(p->des3);
+       p->des2 |= cpu_to_le32(len & TDES2_BUFFER1_SIZE_MASK);
++      tdes3 |= tot_pkt_len & TDES3_PACKET_SIZE_MASK;
+       if (is_fs)
+               tdes3 |= TDES3_FIRST_DESCRIPTOR;
+       else
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+@@ -71,36 +71,48 @@ static void dwmac4_dma_axi(void __iomem
+       writel(value, ioaddr + DMA_SYS_BUS_MODE);
+ }
+-static void dwmac4_dma_init_channel(void __iomem *ioaddr,
+-                                  struct stmmac_dma_cfg *dma_cfg,
+-                                  u32 dma_tx_phy, u32 dma_rx_phy,
+-                                  u32 channel)
++void dwmac4_dma_init_rx_chan(void __iomem *ioaddr,
++                           struct stmmac_dma_cfg *dma_cfg,
++                           u32 dma_rx_phy, u32 chan)
+ {
+       u32 value;
+-      int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
+-      int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
++      u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
+-      /* set PBL for each channels. Currently we affect same configuration
+-       * on each channel
+-       */
+-      value = readl(ioaddr + DMA_CHAN_CONTROL(channel));
+-      if (dma_cfg->pblx8)
+-              value = value | DMA_BUS_MODE_PBL;
+-      writel(value, ioaddr + DMA_CHAN_CONTROL(channel));
++      value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
++      value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
++      writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
++
++      writel(dma_rx_phy, ioaddr + DMA_CHAN_RX_BASE_ADDR(chan));
++}
+-      value = readl(ioaddr + DMA_CHAN_TX_CONTROL(channel));
++void dwmac4_dma_init_tx_chan(void __iomem *ioaddr,
++                           struct stmmac_dma_cfg *dma_cfg,
++                           u32 dma_tx_phy, u32 chan)
++{
++      u32 value;
++      u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
++
++      value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
+       value = value | (txpbl << DMA_BUS_MODE_PBL_SHIFT);
+-      writel(value, ioaddr + DMA_CHAN_TX_CONTROL(channel));
++      writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
+-      value = readl(ioaddr + DMA_CHAN_RX_CONTROL(channel));
+-      value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
+-      writel(value, ioaddr + DMA_CHAN_RX_CONTROL(channel));
++      writel(dma_tx_phy, ioaddr + DMA_CHAN_TX_BASE_ADDR(chan));
++}
+-      /* Mask interrupts by writing to CSR7 */
+-      writel(DMA_CHAN_INTR_DEFAULT_MASK, ioaddr + DMA_CHAN_INTR_ENA(channel));
++void dwmac4_dma_init_channel(void __iomem *ioaddr,
++                           struct stmmac_dma_cfg *dma_cfg, u32 chan)
++{
++      u32 value;
++
++      /* common channel control register config */
++      value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
++      if (dma_cfg->pblx8)
++              value = value | DMA_BUS_MODE_PBL;
++      writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+-      writel(dma_tx_phy, ioaddr + DMA_CHAN_TX_BASE_ADDR(channel));
+-      writel(dma_rx_phy, ioaddr + DMA_CHAN_RX_BASE_ADDR(channel));
++      /* Mask interrupts by writing to CSR7 */
++      writel(DMA_CHAN_INTR_DEFAULT_MASK,
++             ioaddr + DMA_CHAN_INTR_ENA(chan));
+ }
+ static void dwmac4_dma_init(void __iomem *ioaddr,
+@@ -108,7 +120,6 @@ static void dwmac4_dma_init(void __iomem
+                           u32 dma_tx, u32 dma_rx, int atds)
+ {
+       u32 value = readl(ioaddr + DMA_SYS_BUS_MODE);
+-      int i;
+       /* Set the Fixed burst mode */
+       if (dma_cfg->fixed_burst)
+@@ -122,9 +133,6 @@ static void dwmac4_dma_init(void __iomem
+               value |= DMA_SYS_BUS_AAL;
+       writel(value, ioaddr + DMA_SYS_BUS_MODE);
+-
+-      for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
+-              dwmac4_dma_init_channel(ioaddr, dma_cfg, dma_tx, dma_rx, i);
+ }
+ static void _dwmac4_dump_dma_regs(void __iomem *ioaddr, u32 channel,
+@@ -174,46 +182,121 @@ static void dwmac4_dump_dma_regs(void __
+               _dwmac4_dump_dma_regs(ioaddr, i, reg_space);
+ }
+-static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt)
++static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan)
+ {
+-      int i;
++      u32 chan;
+-      for (i = 0; i < DMA_CHANNEL_NB_MAX; i++)
+-              writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(i));
++      for (chan = 0; chan < number_chan; chan++)
++              writel(riwt, ioaddr + DMA_CHAN_RX_WATCHDOG(chan));
+ }
+-static void dwmac4_dma_chan_op_mode(void __iomem *ioaddr, int txmode,
+-                                  int rxmode, u32 channel)
++static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
++                                     u32 channel, int fifosz)
+ {
+-      u32 mtl_tx_op, mtl_rx_op, mtl_rx_int;
++      unsigned int rqs = fifosz / 256 - 1;
++      u32 mtl_rx_op, mtl_rx_int;
+-      /* Following code only done for channel 0, other channels not yet
+-       * supported.
+-       */
+-      mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
++      mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel));
++
++      if (mode == SF_DMA_MODE) {
++              pr_debug("GMAC: enable RX store and forward mode\n");
++              mtl_rx_op |= MTL_OP_MODE_RSF;
++      } else {
++              pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode);
++              mtl_rx_op &= ~MTL_OP_MODE_RSF;
++              mtl_rx_op &= MTL_OP_MODE_RTC_MASK;
++              if (mode <= 32)
++                      mtl_rx_op |= MTL_OP_MODE_RTC_32;
++              else if (mode <= 64)
++                      mtl_rx_op |= MTL_OP_MODE_RTC_64;
++              else if (mode <= 96)
++                      mtl_rx_op |= MTL_OP_MODE_RTC_96;
++              else
++                      mtl_rx_op |= MTL_OP_MODE_RTC_128;
++      }
++
++      mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
++      mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
++
++      /* enable flow control only if each channel gets 4 KiB or more FIFO */
++      if (fifosz >= 4096) {
++              unsigned int rfd, rfa;
++
++              mtl_rx_op |= MTL_OP_MODE_EHFC;
++
++              /* Set Threshold for Activating Flow Control to min 2 frames,
++               * i.e. 1500 * 2 = 3000 bytes.
++               *
++               * Set Threshold for Deactivating Flow Control to min 1 frame,
++               * i.e. 1500 bytes.
++               */
++              switch (fifosz) {
++              case 4096:
++                      /* This violates the above formula because of FIFO size
++                       * limit therefore overflow may occur in spite of this.
++                       */
++                      rfd = 0x03; /* Full-2.5K */
++                      rfa = 0x01; /* Full-1.5K */
++                      break;
++
++              case 8192:
++                      rfd = 0x06; /* Full-4K */
++                      rfa = 0x0a; /* Full-6K */
++                      break;
++
++              case 16384:
++                      rfd = 0x06; /* Full-4K */
++                      rfa = 0x12; /* Full-10K */
++                      break;
++
++              default:
++                      rfd = 0x06; /* Full-4K */
++                      rfa = 0x1e; /* Full-16K */
++                      break;
++              }
+-      if (txmode == SF_DMA_MODE) {
++              mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK;
++              mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT;
++
++              mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK;
++              mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT;
++      }
++
++      writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
++
++      /* Enable MTL RX overflow */
++      mtl_rx_int = readl(ioaddr + MTL_CHAN_INT_CTRL(channel));
++      writel(mtl_rx_int | MTL_RX_OVERFLOW_INT_EN,
++             ioaddr + MTL_CHAN_INT_CTRL(channel));
++}
++
++static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
++                                     u32 channel)
++{
++      u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
++
++      if (mode == SF_DMA_MODE) {
+               pr_debug("GMAC: enable TX store and forward mode\n");
+               /* Transmit COE type 2 cannot be done in cut-through mode. */
+               mtl_tx_op |= MTL_OP_MODE_TSF;
+       } else {
+-              pr_debug("GMAC: disabling TX SF (threshold %d)\n", txmode);
++              pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode);
+               mtl_tx_op &= ~MTL_OP_MODE_TSF;
+               mtl_tx_op &= MTL_OP_MODE_TTC_MASK;
+               /* Set the transmit threshold */
+-              if (txmode <= 32)
++              if (mode <= 32)
+                       mtl_tx_op |= MTL_OP_MODE_TTC_32;
+-              else if (txmode <= 64)
++              else if (mode <= 64)
+                       mtl_tx_op |= MTL_OP_MODE_TTC_64;
+-              else if (txmode <= 96)
++              else if (mode <= 96)
+                       mtl_tx_op |= MTL_OP_MODE_TTC_96;
+-              else if (txmode <= 128)
++              else if (mode <= 128)
+                       mtl_tx_op |= MTL_OP_MODE_TTC_128;
+-              else if (txmode <= 192)
++              else if (mode <= 192)
+                       mtl_tx_op |= MTL_OP_MODE_TTC_192;
+-              else if (txmode <= 256)
++              else if (mode <= 256)
+                       mtl_tx_op |= MTL_OP_MODE_TTC_256;
+-              else if (txmode <= 384)
++              else if (mode <= 384)
+                       mtl_tx_op |= MTL_OP_MODE_TTC_384;
+               else
+                       mtl_tx_op |= MTL_OP_MODE_TTC_512;
+@@ -230,39 +313,6 @@ static void dwmac4_dma_chan_op_mode(void
+        */
+       mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
+       writel(mtl_tx_op, ioaddr +  MTL_CHAN_TX_OP_MODE(channel));
+-
+-      mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(channel));
+-
+-      if (rxmode == SF_DMA_MODE) {
+-              pr_debug("GMAC: enable RX store and forward mode\n");
+-              mtl_rx_op |= MTL_OP_MODE_RSF;
+-      } else {
+-              pr_debug("GMAC: disable RX SF mode (threshold %d)\n", rxmode);
+-              mtl_rx_op &= ~MTL_OP_MODE_RSF;
+-              mtl_rx_op &= MTL_OP_MODE_RTC_MASK;
+-              if (rxmode <= 32)
+-                      mtl_rx_op |= MTL_OP_MODE_RTC_32;
+-              else if (rxmode <= 64)
+-                      mtl_rx_op |= MTL_OP_MODE_RTC_64;
+-              else if (rxmode <= 96)
+-                      mtl_rx_op |= MTL_OP_MODE_RTC_96;
+-              else
+-                      mtl_rx_op |= MTL_OP_MODE_RTC_128;
+-      }
+-
+-      writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(channel));
+-
+-      /* Enable MTL RX overflow */
+-      mtl_rx_int = readl(ioaddr + MTL_CHAN_INT_CTRL(channel));
+-      writel(mtl_rx_int | MTL_RX_OVERFLOW_INT_EN,
+-             ioaddr + MTL_CHAN_INT_CTRL(channel));
+-}
+-
+-static void dwmac4_dma_operation_mode(void __iomem *ioaddr, int txmode,
+-                                    int rxmode, int rxfifosz)
+-{
+-      /* Only Channel 0 is actually configured and used */
+-      dwmac4_dma_chan_op_mode(ioaddr, txmode, rxmode, 0);
+ }
+ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
+@@ -294,6 +344,11 @@ static void dwmac4_get_hw_feature(void _
+       hw_cap = readl(ioaddr + GMAC_HW_FEATURE1);
+       dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20;
+       dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18;
++      /* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by
++       * shifting and store the sizes in bytes.
++       */
++      dma_cap->tx_fifo_size = 128 << ((hw_cap & GMAC_HW_TXFIFOSIZE) >> 6);
++      dma_cap->rx_fifo_size = 128 << ((hw_cap & GMAC_HW_RXFIFOSIZE) >> 0);
+       /* MAC HW feature2 */
+       hw_cap = readl(ioaddr + GMAC_HW_FEATURE2);
+       /* TX and RX number of channels */
+@@ -332,9 +387,13 @@ static void dwmac4_enable_tso(void __iom
+ const struct stmmac_dma_ops dwmac4_dma_ops = {
+       .reset = dwmac4_dma_reset,
+       .init = dwmac4_dma_init,
++      .init_chan = dwmac4_dma_init_channel,
++      .init_rx_chan = dwmac4_dma_init_rx_chan,
++      .init_tx_chan = dwmac4_dma_init_tx_chan,
+       .axi = dwmac4_dma_axi,
+       .dump_regs = dwmac4_dump_dma_regs,
+-      .dma_mode = dwmac4_dma_operation_mode,
++      .dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
++      .dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
+       .enable_dma_irq = dwmac4_enable_dma_irq,
+       .disable_dma_irq = dwmac4_disable_dma_irq,
+       .start_tx = dwmac4_dma_start_tx,
+@@ -354,9 +413,13 @@ const struct stmmac_dma_ops dwmac4_dma_o
+ const struct stmmac_dma_ops dwmac410_dma_ops = {
+       .reset = dwmac4_dma_reset,
+       .init = dwmac4_dma_init,
++      .init_chan = dwmac4_dma_init_channel,
++      .init_rx_chan = dwmac4_dma_init_rx_chan,
++      .init_tx_chan = dwmac4_dma_init_tx_chan,
+       .axi = dwmac4_dma_axi,
+       .dump_regs = dwmac4_dump_dma_regs,
+-      .dma_mode = dwmac4_dma_operation_mode,
++      .dma_rx_mode = dwmac4_dma_rx_chan_op_mode,
++      .dma_tx_mode = dwmac4_dma_tx_chan_op_mode,
+       .enable_dma_irq = dwmac410_enable_dma_irq,
+       .disable_dma_irq = dwmac4_disable_dma_irq,
+       .start_tx = dwmac4_dma_start_tx,
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h
+@@ -185,17 +185,17 @@
+ int dwmac4_dma_reset(void __iomem *ioaddr);
+ void dwmac4_enable_dma_transmission(void __iomem *ioaddr, u32 tail_ptr);
+-void dwmac4_enable_dma_irq(void __iomem *ioaddr);
+-void dwmac410_enable_dma_irq(void __iomem *ioaddr);
+-void dwmac4_disable_dma_irq(void __iomem *ioaddr);
+-void dwmac4_dma_start_tx(void __iomem *ioaddr);
+-void dwmac4_dma_stop_tx(void __iomem *ioaddr);
+-void dwmac4_dma_start_rx(void __iomem *ioaddr);
+-void dwmac4_dma_stop_rx(void __iomem *ioaddr);
++void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan);
++void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan);
++void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan);
++void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan);
++void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan);
++void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan);
++void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan);
+ int dwmac4_dma_interrupt(void __iomem *ioaddr,
+-                       struct stmmac_extra_stats *x);
+-void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len);
+-void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len);
++                       struct stmmac_extra_stats *x, u32 chan);
++void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan);
++void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan);
+ void dwmac4_set_rx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
+ void dwmac4_set_tx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+@@ -37,96 +37,96 @@ int dwmac4_dma_reset(void __iomem *ioadd
+ void dwmac4_set_rx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
+ {
+-      writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(0));
++      writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(chan));
+ }
+ void dwmac4_set_tx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
+ {
+-      writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(0));
++      writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(chan));
+ }
+-void dwmac4_dma_start_tx(void __iomem *ioaddr)
++void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan)
+ {
+-      u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
++      u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
+       value |= DMA_CONTROL_ST;
+-      writel(value, ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
++      writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
+       value = readl(ioaddr + GMAC_CONFIG);
+       value |= GMAC_CONFIG_TE;
+       writel(value, ioaddr + GMAC_CONFIG);
+ }
+-void dwmac4_dma_stop_tx(void __iomem *ioaddr)
++void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan)
+ {
+-      u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
++      u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
+       value &= ~DMA_CONTROL_ST;
+-      writel(value, ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
++      writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
+       value = readl(ioaddr + GMAC_CONFIG);
+       value &= ~GMAC_CONFIG_TE;
+       writel(value, ioaddr + GMAC_CONFIG);
+ }
+-void dwmac4_dma_start_rx(void __iomem *ioaddr)
++void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan)
+ {
+-      u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
++      u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
+       value |= DMA_CONTROL_SR;
+-      writel(value, ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
++      writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
+       value = readl(ioaddr + GMAC_CONFIG);
+       value |= GMAC_CONFIG_RE;
+       writel(value, ioaddr + GMAC_CONFIG);
+ }
+-void dwmac4_dma_stop_rx(void __iomem *ioaddr)
++void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan)
+ {
+-      u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
++      u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
+       value &= ~DMA_CONTROL_SR;
+-      writel(value, ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
++      writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
+       value = readl(ioaddr + GMAC_CONFIG);
+       value &= ~GMAC_CONFIG_RE;
+       writel(value, ioaddr + GMAC_CONFIG);
+ }
+-void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len)
++void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
+ {
+-      writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(STMMAC_CHAN0));
++      writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(chan));
+ }
+-void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len)
++void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
+ {
+-      writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(STMMAC_CHAN0));
++      writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(chan));
+ }
+-void dwmac4_enable_dma_irq(void __iomem *ioaddr)
++void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+ {
+       writel(DMA_CHAN_INTR_DEFAULT_MASK, ioaddr +
+-             DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
++             DMA_CHAN_INTR_ENA(chan));
+ }
+-void dwmac410_enable_dma_irq(void __iomem *ioaddr)
++void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+ {
+       writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
+-             ioaddr + DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
++             ioaddr + DMA_CHAN_INTR_ENA(chan));
+ }
+-void dwmac4_disable_dma_irq(void __iomem *ioaddr)
++void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+ {
+-      writel(0, ioaddr + DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
++      writel(0, ioaddr + DMA_CHAN_INTR_ENA(chan));
+ }
+ int dwmac4_dma_interrupt(void __iomem *ioaddr,
+-                       struct stmmac_extra_stats *x)
++                       struct stmmac_extra_stats *x, u32 chan)
+ {
+       int ret = 0;
+-      u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(0));
++      u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
+       /* ABNORMAL interrupts */
+       if (unlikely(intr_status & DMA_CHAN_STATUS_AIS)) {
+@@ -153,7 +153,7 @@ int dwmac4_dma_interrupt(void __iomem *i
+               if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
+                       u32 value;
+-                      value = readl(ioaddr + DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
++                      value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
+                       /* to schedule NAPI on real RIE event. */
+                       if (likely(value & DMA_CHAN_INTR_ENA_RIE)) {
+                               x->rx_normal_irq_n++;
+@@ -172,7 +172,7 @@ int dwmac4_dma_interrupt(void __iomem *i
+        * status [21-0] expect reserved bits [5-3]
+        */
+       writel((intr_status & 0x3fffc7),
+-             ioaddr + DMA_CHAN_STATUS(STMMAC_CHAN0));
++             ioaddr + DMA_CHAN_STATUS(chan));
+       return ret;
+ }
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+@@ -137,13 +137,14 @@
+ #define DMA_CONTROL_FTF               0x00100000      /* Flush transmit FIFO */
+ void dwmac_enable_dma_transmission(void __iomem *ioaddr);
+-void dwmac_enable_dma_irq(void __iomem *ioaddr);
+-void dwmac_disable_dma_irq(void __iomem *ioaddr);
+-void dwmac_dma_start_tx(void __iomem *ioaddr);
+-void dwmac_dma_stop_tx(void __iomem *ioaddr);
+-void dwmac_dma_start_rx(void __iomem *ioaddr);
+-void dwmac_dma_stop_rx(void __iomem *ioaddr);
+-int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x);
++void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan);
++void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan);
++void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan);
++void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan);
++void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan);
++void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan);
++int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x,
++                      u32 chan);
+ int dwmac_dma_reset(void __iomem *ioaddr);
+ #endif /* __DWMAC_DMA_H__ */
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+@@ -47,38 +47,38 @@ void dwmac_enable_dma_transmission(void
+       writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
+ }
+-void dwmac_enable_dma_irq(void __iomem *ioaddr)
++void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
+ {
+       writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+ }
+-void dwmac_disable_dma_irq(void __iomem *ioaddr)
++void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
+ {
+       writel(0, ioaddr + DMA_INTR_ENA);
+ }
+-void dwmac_dma_start_tx(void __iomem *ioaddr)
++void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
+ {
+       u32 value = readl(ioaddr + DMA_CONTROL);
+       value |= DMA_CONTROL_ST;
+       writel(value, ioaddr + DMA_CONTROL);
+ }
+-void dwmac_dma_stop_tx(void __iomem *ioaddr)
++void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
+ {
+       u32 value = readl(ioaddr + DMA_CONTROL);
+       value &= ~DMA_CONTROL_ST;
+       writel(value, ioaddr + DMA_CONTROL);
+ }
+-void dwmac_dma_start_rx(void __iomem *ioaddr)
++void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)