diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 506b024..64e8189 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -157,6 +157,7 @@ source "drivers/net/ethernet/sgi/Kconfig"
 source "drivers/net/ethernet/smsc/Kconfig"
 source "drivers/net/ethernet/stmicro/Kconfig"
 source "drivers/net/ethernet/sun/Kconfig"
+source "drivers/net/ethernet/synopsys/Kconfig"
 source "drivers/net/ethernet/tehuti/Kconfig"
 source "drivers/net/ethernet/ti/Kconfig"
 source "drivers/net/ethernet/tile/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index c0b8789..57e4967 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
 obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
 obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
 obj-$(CONFIG_NET_VENDOR_SUN) += sun/
+obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
 obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/
 obj-$(CONFIG_NET_VENDOR_TI) += ti/
 obj-$(CONFIG_TILE_NET) += tile/
diff --git a/drivers/net/ethernet/synopsys/Kconfig b/drivers/net/ethernet/synopsys/Kconfig
new file mode 100644
index 0000000..90dceb2
--- /dev/null
+++ b/drivers/net/ethernet/synopsys/Kconfig
@@ -0,0 +1,24 @@
+#
+# Synopsys network device configuration
+#
+
+config NET_VENDOR_SYNOPSYS
+       bool "Synopsys devices"
+       default y
+       ---help---
+         If you have a network (Ethernet) device belonging to this class, say Y
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about Synopsys devices. If you say Y, you will be asked
+         for your specific device in the following questions.
+
+if NET_VENDOR_SYNOPSYS
+
+config SYNOPSYS_DWC_ETH_QOS
+       tristate "Sypnopsys DWC Ethernet QOS v4.00a support"
+       select PHYLIB
+       ---help---
+         This driver supports the DWC Ethernet QoS from Synopsys
+
+endif # NET_VENDOR_SYNOPSYS
diff --git a/drivers/net/ethernet/synopsys/Makefile b/drivers/net/ethernet/synopsys/Makefile
new file mode 100644
index 0000000..7a37572
--- /dev/null
+++ b/drivers/net/ethernet/synopsys/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Synopsys network device drivers.
+#
+
+obj-$(CONFIG_SYNOPSYS_DWC_ETH_QOS) += dwc_eth_qos.o
diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
new file mode 100644
index 0000000..20b1a9e
--- /dev/null
+++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
@@ -0,0 +1,706 @@
+/*  Synopsys DWC Ethernet: Linux driver for Ethernet
+ *
+ *  This is a driver for the Synopsys DWC Ethernet IP version 4.00a. This
+ *  version introduced a lot of changes which breaks backwards compatibility
+ *  with version 3 of the same IP (Used in ST Micro drivers).
+ *
+ *  This driver only support basic functionality and Gigabit Ethernet Only. It
+ *  uses polling for TX and IRQ-driven RX with NAPI support. No hardware
+ *  checksumming or scatter-gather are supported. There are many things left to
+ *  implement: Scatter-gather, TCP Segmentation Offloading, HW Checksumming,
+ *  IRQ-driven TX, link handling, and a lot of general error handling.
+ *
+ *  Copyright (C) 2014 Axis Communications AB.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms and conditions of the GNU General Public License,
+ *  version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/stat.h>
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/mii.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/version.h>
+#include <linux/of.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/net_tstamp.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_net.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/timer.h>
+#include "dwc_eth_qos.h"
+
+#define DRIVER_NAME                    "dwceqos"
+#define DRIVER_DESCRIPTION             "Synopsys DWC Ethernet QoS driver"
+#define DRIVER_VERSION                 "0.1"
+
+#ifdef DWCEQOS_DEBUG
+static void dwceqos_write(void __iomem *p, u32 offset, u32 v)
+{
+       printk(KERN_DEBUG "Write: Addr=%08x, Data=%08x\n", (u32)p + offset , v);
+       writel(v, p + offset);
+}
+
+static u32 dwceqos_read(void __iomem *p, u32 offset)
+{
+       u32 v = 0;
+       v = readl(p + offset);
+       printk(KERN_DEBUG "Read: Addr=%08x, Data=%08x\n", (u32)p + offset, v);
+       return v;
+}
+#else
+#define dwceqos_read(base, reg)                                                \
+       __raw_readl(((void __iomem *)(base)) + (reg))
+#define dwceqos_write(base, reg, val)                                  \
+       __raw_writel((val), ((void __iomem *)(base)) + (reg))
+#endif
+
+/* DMA ring descriptor. These are used as support descriptors for the HW DMA */
+struct ring_info {
+       struct sk_buff *skb;
+       dma_addr_t mapping;
+       size_t len;
+};
+
+struct net_local {
+       void __iomem *baseaddr;
+       struct clk *phy_ref_clk;
+       struct clk *apb_pclk;
+
+       struct net_device *ndev;
+       struct platform_device *pdev;
+
+       volatile struct dwc_eth_qos_txdesc *tx_descs;
+       volatile struct dwc_eth_qos_rxdesc *rx_descs;
+
+       void *tx_buf;
+
+       struct ring_info *rx_skb;
+
+       dma_addr_t tx_descs_addr;
+       dma_addr_t rx_descs_addr;
+
+       u32 next_tx;
+       u32 next_rx;
+
+       struct napi_struct napi;
+
+       struct net_device_stats stats;
+       spinlock_t rx_lock;
+};
+
+/* Allocate DMA helper structure at position given by index */
+static void dwceqos_alloc_rxring_desc(struct net_local *lp, int index)
+{
+       struct sk_buff *new_skb;
+       u32 new_skb_baddr = 0;
+       new_skb = netdev_alloc_skb(lp->ndev, DWCEQOS_RX_BUF_SIZE);
+       if (!new_skb) {
+               dev_err(&lp->ndev->dev, "alloc_skb error for desc %d\n", index);
+               goto out;
+       }
+
+       /* Get dma handle of skb->data */
+       new_skb_baddr = (u32)dma_map_single(lp->ndev->dev.parent,
+               new_skb->data, DWCEQOS_RX_BUF_SIZE, DMA_FROM_DEVICE);
+       if (dma_mapping_error(lp->ndev->dev.parent, new_skb_baddr)) {
+               dev_err(&lp->pdev->dev, "DMA map error\n");
+               dev_kfree_skb(new_skb);
+               new_skb = NULL;
+       }
+out:
+       lp->rx_skb[index].skb = new_skb;
+       lp->rx_skb[index].mapping = new_skb_baddr;
+       lp->rx_skb[index].len = DWCEQOS_RX_BUF_SIZE;
+
+       return;
+}
+
+static void dwceqos_mtl_init(struct net_local *lp)
+{
+       dwceqos_write(lp->baseaddr, DWCEQOS_MTL_OP_MODE, 0x00000060);
+}
+
+static void dwceqos_mtl_tx_init(struct net_local *lp)
+{
+       dwceqos_write(lp->baseaddr, DWCEQOS_MTL_TXQ0_OP_MODE,
+                       DWCEQOS_MTL_TXQ_EN);
+}
+
+static void dwceqos_mtl_rx_init(struct net_local *lp)
+{
+       dwceqos_write(lp->baseaddr, DWCEQOS_MTL_RXQ0_OP_MODE,
+               DWCEQOS_MTL_RXQ_RQS256 | DWCEQOS_MTL_RXQ_DIS_TCP_EF |
+               DWCEQOS_MTL_RXQ_FEP | DWCEQOS_MTL_RXQ_FUP |
+               DWCEQOS_MTL_RXQ_RTC32);
+}
+
+static void dwceqos_mac_rx_init(struct net_local *lp)
+{
+       u32 val;
+       dwceqos_write(lp->baseaddr, DWCEQOS_MAC_RXQ_CTRL0, 2);
+       val = DWCEQOS_MAC_PKT_FILTER_RX_ALL | DWCEQOS_MAC_PKT_FILTER_PCF_ALL |
+               DWCEQOS_MAC_PKT_FILTER_PROMISCUOUS;
+       dwceqos_write(lp->baseaddr, DWCEQOS_MAC_PKT_FILTER, val);
+}
+
+static int dwceqos_mac_enable(struct net_local *lp)
+{
+       dwceqos_write(lp->baseaddr, DWCEQOS_MAC_CFG,
+               DWCEQOS_MAC_CFG_DM | DWCEQOS_MAC_CFG_TE |
+               DWCEQOS_MAC_CFG_RE);
+       return 0;
+}
+
+static void dwceqos_dma_wake_rx(struct net_local *lp)
+{
+       u32 offset;
+       offset = DWCEQOS_RX_DCNT * sizeof(struct dwc_eth_qos_rxdesc);
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_RXDESC_TAIL,
+               (u32)lp->rx_descs_addr + offset);
+}
+
+static inline void dwceqos_dma_rx_start(struct net_local *lp)
+{
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_RX_CTRL,
+               DWCEQOS_DMA_CH0_TXRX_CONTROL_START |
+               DWCEQOS_DMA_CH0_TXRX_CONTROL_PBL16 |
+               DWCEQOS_RX_BUF_SIZE);
+       dwceqos_dma_wake_rx(lp);
+}
+
+static inline void dwceqos_dma_tx_start(struct net_local *lp)
+{
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_TX_CTRL,
+               DWCEQOS_DMA_CH0_TXRX_CONTROL_START |
+               DWCEQOS_DMA_CH0_TXRX_CONTROL_PBL16);
+}
+
+static void dwceqos_dma_setmode(struct net_local *lp)
+{
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_MODE,
+               DWCEQOS_DMA_MODE_TXPR | DWCEQOS_DMA_MODE_DA);
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_SYSBUS_MODE,
+               DWCEQOS_DMA_SYSBUS_MB);
+}
+
+static void dwceqos_dma_txenable(struct net_local *lp)
+{
+       u32 val;
+       val = DWCEQOS_DMA_CH0_TXRX_CONTROL_PBL16 |
+               DWCEQOS_DMA_CH0_TXRX_CONTROL_START;
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_TX_CTRL, val);
+}
+
+static void dwceqos_dma_rx_enable(struct net_local *lp)
+{
+       u32 val;
+       val = DWCEQOS_DMA_CH0_TXRX_CONTROL_PBL16 |
+               DWCEQOS_RX_BUF_SIZE | DWCEQOS_DMA_CH0_TXRX_CONTROL_START;
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_RX_CTRL, val);
+}
+
+/* Initialize DMA descriptors to their start values */
+static void dwceqos_dma_prepare(struct net_local *lp)
+{
+       int i;
+       for (i = 0; i < DWCEQOS_TX_DCNT; ++i) {
+               lp->tx_descs[i].tdes0.raw = 0;
+               lp->tx_descs[i].tdes1.raw = 0;
+               lp->tx_descs[i].tdes2.raw = 0;
+               lp->tx_descs[i].tdes3.raw = 0;
+       }
+
+       for (i = 0; i < DWCEQOS_RX_DCNT; ++i) {
+               lp->rx_descs[i].rdes0.rd.buffer1 = lp->rx_skb[i].mapping;
+               lp->rx_descs[i].rdes1.raw = 0;
+               lp->rx_descs[i].rdes2.rd.buffer2 = 0;
+               lp->rx_descs[i].rdes3.raw = 0;
+               lp->rx_descs[i].rdes3.rd.buf1v = 1;
+               lp->rx_descs[i].rdes3.rd.inte = 1;
+               lp->rx_descs[i].rdes3.rd.own = 1;
+       }
+       lp->next_tx = 0;
+       lp->next_rx = 0;
+}
+
+/* Allocate and initiate DMA rings for TX and RX. Also allocates RX buffers for
+ * incoming packets.
+ */
+static int dwceqos_dma_alloc(struct net_local *lp)
+{
+       u32 size;
+       int i;
+
+       size = DWCEQOS_RX_DCNT * sizeof(struct ring_info);
+       lp->rx_skb = kzalloc(size, GFP_KERNEL);
+       if (!lp->rx_skb) {
+               dev_err(&lp->pdev->dev, "Unable to allocate ring descriptor area\n");
+               return -ENOMEM;
+       }
+
+       /* Allocate DMA descriptors */
+       size = DWCEQOS_TX_DCNT * sizeof(struct dwc_eth_qos_txdesc);
+       lp->tx_descs = dma_alloc_coherent(&lp->pdev->dev, size,
+                       &lp->tx_descs_addr, 0);
+       if (!lp->tx_descs) {
+               dev_err(&lp->pdev->dev, "Failed to allocate TX DMA descriptors\n");
+               /* Should deallocate memory here */
+               return -ENOMEM;
+       }
+       size = DWCEQOS_RX_DCNT * sizeof(struct dwc_eth_qos_rxdesc);
+       lp->rx_descs = dma_alloc_coherent(&lp->pdev->dev, size,
+                       &lp->rx_descs_addr, 0);
+       if (!lp->rx_descs) {
+               dev_err(&lp->pdev->dev, "Failed to allocate RX DMA descriptors\n");
+               /* Should deallocate memory here */
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < DWCEQOS_RX_DCNT; ++i) {
+               dwceqos_alloc_rxring_desc(lp, i);
+               if (!(lp->rx_skb[lp->next_rx].skb)) {
+                       dev_err(&lp->pdev->dev, "Unable to map descriptor %d to DMA\n",
+                               lp->next_rx);
+                       /* What error code to return for mapping error? */
+                       return -1;
+               }
+       }
+
+       dwceqos_dma_prepare(lp);
+
+       /* Tell HW where to look*/
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_RXDESC_RING_LEN,
+               DWCEQOS_RX_DCNT-1);
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_TXDESC_RING_LEN,
+               DWCEQOS_TX_DCNT-1);
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_RXDESC_LIST_ADDR,
+               (u32)lp->rx_descs_addr);
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_TXDESC_LIST_ADDR,
+               (u32)lp->tx_descs_addr);
+       return 0;
+}
+
+/* Checks if there are any available incoming packets ready for processing */
+int dwceqos_packet_avail(struct net_local *lp)
+{
+       return !lp->rx_descs[lp->next_rx].rdes3.wr.own;
+}
+
+/* Free DMA descriptor area */
+static void dwceqos_dma_free(struct net_local *lp)
+{
+       u32 size;
+       size = DWCEQOS_TX_DCNT * sizeof(struct dwc_eth_qos_txdesc);
+       if (lp->tx_descs)
+               dma_free_coherent(&lp->pdev->dev, size,
+                       lp->tx_descs, lp->tx_descs_addr);
+       size = DWCEQOS_RX_DCNT * sizeof(struct dwc_eth_qos_rxdesc);
+       if (lp->rx_descs)
+               dma_free_coherent(&lp->pdev->dev, size,
+                       lp->rx_descs, lp->rx_descs_addr);
+}
+
+/* HW transmit function. */
+static void dwceqos_dma_xmit(struct net_local *lp, void *data, int len)
+{
+       u32 regval;
+       int i = lp->next_tx;
+       int dwc_wait;
+       dma_addr_t dma_handle;
+
+       dma_handle = dma_map_single(lp->ndev->dev.parent,
+               data, DWCEQOS_RX_BUF_SIZE, DMA_TO_DEVICE);
+       if (dma_mapping_error(lp->ndev->dev.parent, dma_handle)) {
+               dev_err(&lp->pdev->dev, "DMA Mapping error\n");
+               return;
+       }
+
+       lp->tx_descs[i].tdes0.rd.buffer1 = dma_handle;
+       lp->tx_descs[i].tdes2.rd.buf1len = len;
+       lp->tx_descs[i].tdes3.rd.fl = len;
+       lp->tx_descs[i].tdes3.rd.fd = 1;
+       lp->tx_descs[i].tdes3.rd.ld = 1;
+       lp->tx_descs[i].tdes3.rd.own = 1;
+
+       /* Issue Transmit Poll by writing address of next free descriptor */
+       regval = lp->tx_descs_addr + (i+1) * sizeof(struct dwc_eth_qos_txdesc);
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_TXDESC_TAIL, regval);
+
+       /* Set poll wait timeout to 2 seconds */
+       dwc_wait = 200;
+
+       while (lp->tx_descs[i].tdes3.wr.own) {
+               mdelay(10);
+               if (!dwc_wait--)
+                       break;
+       }
+       if (lp->tx_descs[i].tdes3.wr.own)
+               dev_err(&lp->pdev->dev, "Failed to transmit: Timed out\n");
+
+       lp->next_tx = (lp->next_tx + 1) % DWCEQOS_TX_DCNT;
+       dma_unmap_single(lp->ndev->dev.parent,
+                       dma_handle, DWCEQOS_RX_BUF_SIZE, DMA_TO_DEVICE);
+}
+
+/* Store HW Addr in MAC registers. Source Address Replacement not used yet */
+static void dwceqos_set_hwaddr(struct net_local *lp)
+{
+       u32 val;
+
+       val = DWCEQOS_MAC_ADDR_HI_EN | (lp->ndev->dev_addr[0] << 8) |
+               (lp->ndev->dev_addr[1]);
+       dwceqos_write(lp->baseaddr, DWCEQOS_MAC_ADDR_HI, val);
+       val = (lp->ndev->dev_addr[2] << 24) | (lp->ndev->dev_addr[3] << 16) |
+               (lp->ndev->dev_addr[4] << 8)  | (lp->ndev->dev_addr[5]);
+       dwceqos_write(lp->baseaddr, DWCEQOS_MAC_ADDR_LO, val);
+}
+
+/* DMA reset. When issued also resets all MTL and MAC registers as well */
+static void dwceqos_dma_reset(struct net_local *lp)
+{
+       /* Wait 5 seconds for DMA reset*/
+       int i = 5000;
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_MODE, 1);
+
+       do {
+               mdelay(1);
+       } while ((dwceqos_read(lp->baseaddr, DWCEQOS_DMA_MODE) & 0x1) && i--);
+}
+
+/* Interrupt handler. So far only RX interrupts are used */
+static irqreturn_t dwceqos_interrupt(int irq, void *dev_id)
+{
+       struct net_device *ndev = dev_id;
+       struct net_local *lp = netdev_priv(ndev);
+
+       u32 cause;
+       u32 val;
+
+       cause = dwceqos_read(lp->baseaddr, DWCEQOS_DMA_INT_STAT);
+       if (cause & 0x00000001) {
+               /* DMA Channel 0 Interrupt. Assume RX interrupt for now */
+               val = dwceqos_read(lp->baseaddr, DWCEQOS_DMA_CH0_STAT);
+               /* Ack */
+               dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_STAT, val);
+               if (val & 0x00000040)
+                       napi_schedule(&lp->napi);
+       } else if (unlikely(!cause)) {
+               return IRQ_NONE;
+       }
+       return IRQ_HANDLED;
+}
+
+static int dwceqos_open(struct net_device *ndev)
+{
+       /* Allocate Buffers & DMA Descr. + Initiate DMA descriptors */
+       struct net_local *lp = netdev_priv(ndev);
+
+       /* Set up hardware. It looks like order of writes is important here.
+        * Only gigatbit support, no advanced MTL or MAC configuration yet.
+        */
+       dwceqos_dma_reset(lp);
+       dwceqos_mtl_init(lp);
+       dwceqos_mtl_tx_init(lp);
+       dwceqos_dma_setmode(lp);
+       dwceqos_dma_alloc(lp);
+       dwceqos_dma_wake_rx(lp);
+       dwceqos_dma_txenable(lp);
+       dwceqos_mtl_rx_init(lp);
+       dwceqos_mac_rx_init(lp);
+       dwceqos_dma_rx_enable(lp);
+       dwceqos_dma_wake_rx(lp);
+       dwceqos_set_hwaddr(lp);
+       dwceqos_mac_enable(lp);
+
+       /* Enable RX Interrupts */
+       dwceqos_write(lp->baseaddr, DWCEQOS_DMA_CH0_INT_EN, 0x00010040);
+
+       napi_enable(&lp->napi);
+       netif_carrier_on(ndev);
+       netif_start_queue(ndev);
+       return 0;
+}
+
+
+int dwceqos_stop(struct net_device *ndev)
+{
+       struct net_local *lp = netdev_priv(ndev);
+       dwceqos_dma_free(lp);
+       netif_stop_queue(ndev);
+       napi_disable(&lp->napi);
+       netif_carrier_off(ndev);
+       return 0;
+}
+
+/* Receive one packet and return skb */
+struct sk_buff *
+dwceqos_recv_packet(struct net_local *lp)
+{
+       struct sk_buff *skb;
+       u32 len;
+
+       skb = lp->rx_skb[lp->next_rx].skb;
+       len = lp->rx_descs[lp->next_rx].rdes3.wr.length;
+
+       /* Unmap old buffer */
+       dma_unmap_single(lp->ndev->dev.parent, lp->rx_skb[lp->next_rx].mapping,
+               lp->rx_skb[lp->next_rx].len, DMA_FROM_DEVICE);
+       skb_put(skb, len);
+       skb->protocol = eth_type_trans(skb, lp->ndev);
+       skb->ip_summed = 0;
+
+       /* Initialize new Buffer descriptor */
+       dwceqos_alloc_rxring_desc(lp, lp->next_rx);
+       if (!(lp->rx_skb[lp->next_rx].skb)) {
+               dev_err(&lp->pdev->dev, "Unable to map descriptor %d to DMA\n",
+                       lp->next_rx);
+               return NULL;
+       }
+
+       /* Initialize new DMA descriptor */
+       lp->rx_descs[lp->next_rx].rdes0.rd.buffer1 =
+               lp->rx_skb[lp->next_rx].mapping;
+       lp->rx_descs[lp->next_rx].rdes1.raw = 0;
+       lp->rx_descs[lp->next_rx].rdes2.rd.buffer2 = 0;
+       lp->rx_descs[lp->next_rx].rdes3.raw = 0;
+       lp->rx_descs[lp->next_rx].rdes3.rd.buf1v = 1;
+       lp->rx_descs[lp->next_rx].rdes3.rd.inte = 1;
+       lp->rx_descs[lp->next_rx].rdes3.rd.own = 1;
+       lp->next_rx = (lp->next_rx + 1) % DWCEQOS_RX_DCNT;
+       return skb;
+}
+
+
+/* NAPI poll routine */
+int dwceqos_rx_poll(struct napi_struct *napi, int budget)
+{
+       struct net_local *lp = container_of(napi, struct net_local, napi);
+       int npackets = 0;
+       struct sk_buff *skb;
+
+       spin_lock(&lp->rx_lock);
+       while (npackets < budget && dwceqos_packet_avail(lp)) {
+
+               skb = dwceqos_recv_packet(lp);
+               if (!skb)
+                       break;
+
+               netif_receive_skb(skb);
+
+               lp->stats.rx_packets++;
+               lp->stats.rx_bytes += skb->len;
+               npackets++;
+       }
+       if (npackets < budget)
+               napi_complete(napi);
+
+       spin_unlock(&lp->rx_lock);
+       return npackets;
+}
+
+/* Main transmit function called from kernel */
+int dwceqos_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+       int len;
+       struct net_local *lp = netdev_priv(ndev);
+       char *data;
+       data = skb->data;
+       len = skb->len;
+
+       /* Send packet on wire */
+       dwceqos_dma_xmit(lp, data, len);
+
+       skb_tx_timestamp(skb);
+
+       ndev->stats.tx_bytes += len;
+       dev_kfree_skb(skb);
+
+       return 0;
+}
+
+struct net_device_ops dwceq_netdev_ops;
+
+#ifdef CONFIG_OF
+static inline int dwceqos_probe_config_dt(struct platform_device *pdev)
+{
+       struct net_device *ndev;
+       const void *mac_address;
+
+       ndev = platform_get_drvdata(pdev);
+       /* Set the MAC address. */
+       mac_address = of_get_mac_address(pdev->dev.of_node);
+       if (mac_address)
+               memcpy(ndev->dev_addr, mac_address, ETH_ALEN);
+       else
+               dev_warn(&pdev->dev, "No MAC address found\n");
+       return 0;
+}
+#else
+static inline int dwceqos_probe_config_dt()
+{
+       return -ENOSYS;
+}
+#endif
+
+
+/**
+ * dwceqos_probe - Platform driver probe
+ * @pdev: Pointer to platform device structure
+ *
+ * Return 0 on success, negative value if error
+ */
+int dwceqos_probe(struct platform_device *pdev)
+{
+       struct resource *r_mem = NULL;
+       struct resource *r_irq = NULL;
+       struct net_device *ndev;
+       struct net_local *lp;
+       int ret = -ENXIO;
+
+       r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!r_mem || !r_irq) {
+               dev_err(&pdev->dev, "no IO resource defined.\n");
+               return -ENXIO;
+       }
+       ndev = alloc_etherdev(sizeof(*lp));
+       if (!ndev) {
+               dev_err(&pdev->dev, "etherdev allocation failed.\n");
+               return -ENOMEM;
+       }
+
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+
+       lp = netdev_priv(ndev);
+       lp->ndev = ndev;
+       lp->pdev = pdev;
+
+       lp->baseaddr = devm_ioremap_resource(&pdev->dev, r_mem);
+       if (IS_ERR(lp->baseaddr)) {
+               dev_err(&pdev->dev, "failed to map baseaddress.\n");
+               ret = PTR_ERR(lp->baseaddr);
+               goto err_out_free_netdev;
+       }
+
+
+       dev_dbg(&lp->pdev->dev, "BASEADDRESS hw: %p virt: %p\n",
+                       (void *)r_mem->start, lp->baseaddr);
+
+       ndev->irq = platform_get_irq(pdev, 0);
+       ndev->netdev_ops = &dwceq_netdev_ops;
+       ndev->base_addr = r_mem->start;
+       ndev->features = 0;
+
+       netif_napi_add(ndev, &lp->napi, dwceqos_rx_poll, 64);
+
+       ret = register_netdev(ndev);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+               goto err_out_free_netdev;
+       }
+
+       lp->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk");
+       if (IS_ERR(lp->apb_pclk)) {
+               dev_err(&pdev->dev, "apb_pclk clock not found.\n");
+               ret = PTR_ERR(lp->apb_pclk);
+               goto err_out_unregister_netdev;
+       }
+       lp->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk");
+       if (IS_ERR(lp->phy_ref_clk)) {
+               dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
+               ret = PTR_ERR(lp->phy_ref_clk);
+               goto err_out_unregister_netdev;
+       }
+
+       ret = clk_prepare_enable(lp->apb_pclk);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to enable APER clock.\n");
+               goto err_out_unregister_netdev;
+       }
+       ret = clk_prepare_enable(lp->phy_ref_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to enable device clock.\n");
+               goto err_out_clk_dis_aper;
+       }
+
+       platform_set_drvdata(pdev, ndev);
+       dwceqos_probe_config_dt(pdev);
+       dev_info(&lp->pdev->dev, "pdev->id %d, baseaddr 0x%08lx, irq %d\n",
+                       pdev->id, ndev->base_addr, ndev->irq);
+
+       ret = devm_request_irq(&pdev->dev, ndev->irq, &dwceqos_interrupt, 0,
+               ndev->name, ndev);
+       if (ret) {
+               dev_err(&lp->pdev->dev, "Unable to request IRQ %p, error %d\n",
+                       r_irq, ret);
+               goto err_out_unregister_clk_notifier;
+       }
+
+       return 0;
+
+err_out_unregister_clk_notifier:
+       clk_disable_unprepare(lp->phy_ref_clk);
+err_out_clk_dis_aper:
+       clk_disable_unprepare(lp->apb_pclk);
+err_out_unregister_netdev:
+       unregister_netdev(ndev);
+err_out_free_netdev:
+       free_netdev(ndev);
+       platform_set_drvdata(pdev, NULL);
+       return ret;
+}
+
+int dwceqos_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       unregister_netdev(ndev);
+       free_netdev(ndev);
+       return 0;
+}
+
+struct net_device_ops dwceq_netdev_ops = {
+       .ndo_open       = dwceqos_open,
+       .ndo_stop       = dwceqos_stop,
+       .ndo_start_xmit = dwceqos_start_xmit,
+};
+
+struct of_device_id dwceq_of_match[] = {
+       { .compatible = "dwc,qos-ethernet", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, dwceq_of_match);
+
+struct platform_driver dwceqos_driver = {
+       .probe   = dwceqos_probe,
+       .remove  = dwceqos_remove,
+       .driver  = {
+               .name  = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = dwceq_of_match,
+       },
+};
+
+module_platform_driver(dwceqos_driver);
+
+MODULE_DESCRIPTION("DWC Ethernet QoS v4.00a driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Andreas Irestaal");
diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.h b/drivers/net/ethernet/synopsys/dwc_eth_qos.h
new file mode 100644
index 0000000..9aa84a0
--- /dev/null
+++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.h
@@ -0,0 +1,308 @@
+#ifndef DWC_ETH_QOS_H
+#define DWC_ETH_QOS_H
+
+#define DWCEQOS_RX_BUF_SIZE 2048
+
+#define DWCEQOS_RX_DCNT 16
+#define DWCEQOS_TX_DCNT 16
+
+/* DMA Registers */
+#define DWCEQOS_DMA_MODE                       0x1000
+#define DWCEQOS_DMA_SYSBUS_MODE                        0x1004
+#define DWCEQOS_DMA_INT_STAT                   0x1008
+#define DWCEQOS_DMA_DEBUG_STAT0                        0x100c
+#define DWCEQOS_DMA_DEBUG_STAT1                        0x1010
+#define DWCEQOS_DMA_DEBUG_STAT2                        0x1014
+#define DWCEQOS_DMA_CH0_CTRL                   0x1100
+#define DWCEQOS_DMA_CH0_TX_CTRL                        0x1104
+#define DWCEQOS_DMA_CH0_RX_CTRL                        0x1108
+#define DWCEQOS_DMA_CH0_TXDESC_LIST_ADDR       0x1114
+#define DWCEQOS_DMA_CH0_RXDESC_LIST_ADDR       0x111C
+#define DWCEQOS_DMA_CH0_TXDESC_TAIL            0x1120
+#define DWCEQOS_DMA_CH0_RXDESC_TAIL            0x1128
+#define DWCEQOS_DMA_CH0_TXDESC_RING_LEN                0x112c
+#define DWCEQOS_DMA_CH0_RXDESC_RING_LEN                0x1130
+#define DWCEQOS_DMA_CH0_INT_EN                 0x1134
+#define DWCEQOS_DMA_CH0_INT_WATCHDOG_T         0x1138
+#define DWCEQOS_DMA_CH0_SLOT_FUNC_CTRL_STAT    0x113c
+#define DWCEQOS_DMA_CH0_CUR_APP_TXDESC         0x1144
+#define DWCEQOS_DMA_CH0_CUR_APP_RXDESC         0x114c
+#define DWCEQOS_DMA_CH0_CUR_APP_TXBUF          0x1154
+#define DWCEQOS_DMA_CH0_CUR_APP_RXBUF          0x115c
+#define DWCEQOS_DMA_CH0_STAT                   0x1160
+
+/* MAC Registers */
+#define DWCEQOS_MAC_CFG                                0x0000
+#define DWCEQOS_MAC_EXT_CFG                    0x0004
+#define DWCEQOS_MAC_PACKET_FILTER              0x0008
+#define DWCEQOS_MAC_RXQ_CTRL0                  0x00a0
+#define DWCEQOS_MAC_IE                         0x00b4
+#define DWCEQOS_MAC_RX_TX_STATUS               0x00b8
+#define DWCEQOS_MAC_PHYIF_CTRL_STATUS          0x00f8
+#define DWCEQOS_MAC_DEBUG                      0x0114
+#define DWCEQOS_MAC_HW_FEATURE0                        0x011c
+#define DWCEQOS_MAC_HW_FEATURE1                        0x0120
+#define DWCEQOS_MAC_HW_FEATURE2                        0x0124
+#define DWCEQOS_MAC_ADDR_HI                    0x0300
+#define DWCEQOS_MAC_ADDR_LO                    0x0304
+#define DWCEQOS_MAC_MDIO_ADDR                  0x0200
+#define DWCEQOS_MAC_MDIO_DATA                  0x0204
+#define DWCEQOS_MAC_PKT_FILTER                 0x8
+
+/* MTL Registers */
+#define DWCEQOS_MTL_OP_MODE                    0x0c00
+#define DWCEQOS_MTL_DEUBIG_CTRL                        0x0c08
+#define DWCEQOS_MTL_DEBUG_STATUS               0x0c0c
+#define DWCEQOS_MTL_FIFO_DEBUG_DATA            0x0c10
+#define DWCEQOS_MTL_INT_STATUS                 0x0c20
+#define DWCEQOS_MTL_RXQ0_DMA_MAP0              0x0c30
+#define DWCEQOS_MTL_RXQ0_DMA_MAP1              0x0c34
+#define DWCEQOS_MTL_TXQ0_OP_MODE               0x0d00
+#define DWCEQOS_MTL_TXQ0_UNDERFLOW             0x0d04
+#define DWCEQOS_MTL_TXQ0_DEBUG                 0x0d08
+#define DWCEQOS_MTL_TXQ0_ETS_STATUS            0x0d14
+#define DWCEQOS_MTL_TXQ0_QUANTUM               0x0d18
+#define DWCEQOS_MTL_TXQ0_INT_CTRL_STATUS       0x0d2c
+#define DWCEQOS_MTL_RXQ0_OP_MODE               0x0d30
+#define DWCEQOS_MTL_RXQ0_MISSED_PACKET_OF_CNT  0x0d34
+#define DWCEQOS_MTL_RXQ0_DEBUG                 0x0d38
+#define DWCEQOS_MTL_RXQ0_CTRL                  0x0d3c
+
+
+/* Fields/constants */
+#define DWCEQOS_DMA_MODE_SWR                   1
+#define DWCEQOS_DMA_MODE_TXPR                  (1 << 11)
+#define DWCEQOS_DMA_MODE_DA                    (1 << 1)
+#define DWCEQOS_DMA_SYSBUS_MB                  (1 << 14)
+
+#define DWCEQOS_DMA_CH0_TXRX_CONTROL_PBL16     (1 << 20)
+#define DWCEQOS_DMA_CH0_TXRX_CONTROL_OSP       (1 << 4)
+#define DWCEQOS_DMA_CH0_TXRX_CONTROL_START     1
+
+#define DWCEQOS_MTL_TXQ_TTC32                  0
+#define DWCEQOS_MTL_TXQ_EN                     (1 << 3)
+#define DWCEQOS_MTL_RXQ_EN                     (1 << 3)
+#define DWCEQOS_MTL_TXQ_TSF                    (1 << 1)
+
+#define DWCEQOS_MTL_TXQ0_DEBUG_TRQSTS          (1 << 4)
+#define DWCEQOS_MTL_TXQ0_DEBUG_TRCSTS          (3 << 3)
+#define DWCEQOS_MTL_TXQ0_DEBUG_TRCSTS_READ     (1 << 3)
+
+#define DWCEQOS_MTL_RXQ_RQS256                 (3 << 20)
+#define DWCEQOS_MTL_RXQ_RTC128                 3
+#define DWCEQOS_MTL_RXQ_RTC32                  1
+
+#define DWCEQOS_MTL_RXQ_DIS_TCP_EF             (1 << 6)
+#define DWCEQOS_MTL_RXQ_FEP                    (1 << 4)
+#define DWCEQOS_MTL_RXQ_FUP                    (1 << 3)
+
+#define DWCEQOS_MAC_CFG_PS                     (1 << 15)
+#define DWCEQOS_MAC_CFG_DM                     (1 << 13)
+#define DWCEQOS_MAC_CFG_TE                     (1 << 1)
+#define DWCEQOS_MAC_CFG_RE                     1
+
+#define DWCEQOS_MAC_CFG_SARC_A0                        (3 << 28)
+#define DWCEQOS_MAC_CFG_SARC_A1                        (7 << 28)
+
+#define DWCEQOS_MAC_PKT_FILTER_RX_ALL          (1 << 31)
+#define DWCEQOS_MAC_PKT_FILTER_PCF_ALL         (2 << 6)
+#define DWCEQOS_MAC_PKT_FILTER_PROMISCUOUS     (1 << 0)
+
+#define DWCEQOS_MAC_MDIO_ADDR_CSR_20_30_MHZ    (2 << 8)
+#define DWCEQOS_MAC_MDIO_ADDR_WRITE            (1 << 2)
+#define DWCEQOS_MAC_MDIO_ADDR_READ             (3 << 2)
+#define DWCEQOS_MAC_MDIO_ADDR_BUSY             1
+
+#define DWCEQOS_MAC_ADDR_HI_EN                 (1 << 31)
+
+
+#define DWCEQOS_MAC_INT_RXSTSIE                        (1 << 14)
+
+/* DMA Structs */
+struct tdes0_rd {
+       u32 buffer1;
+};
+
+struct tdes1_rd {
+       u32 buffer2;
+};
+
+struct tdes2_rd {
+       u32 buf1len:14;
+       u32 vtir:2;
+       u32 buf2len:14;
+       u32 ttse:1;
+       u32 ioc:1;
+};
+
+struct tdes3_rd {
+       u32 fl:15;
+       u32 tiplh:1;
+       u32 cic:2;
+       u32 tse:1;
+       u32 slotnum:4;
+       u32 saic:3;
+       u32 cpc:2;
+       u32 ld:1;
+       u32 fd:1;
+       u32 ctxt:1;
+       u32 own:1;
+};
+
+struct tdes0_wr {
+       u32 ts_lo;
+};
+
+struct tdes1_wr {
+       u32 ts_hi;
+};
+
+struct tdes2_wr {
+       u32 rsvd;
+};
+
+struct tdes3_wr {
+       u32 ihe:1;
+       u32 db:1;
+       u32 uf:1;
+       u32 ed:1;
+       u32 cc:4;
+       u32 ec:1;
+       u32 lc:1;
+       u32 nc:1;
+       u32 loc:1;
+       u32 pce:1;
+       u32 ff:1;
+       u32 jt:1;
+       u32 es:1;
+       u32 rsvd1:1;
+       u32 ttss:1;
+       u32 rsvd:10;
+       u32 ld:1;
+       u32 fd:1;
+       u32 ctxt:1;
+       u32 own:1;
+};
+
+struct rdes0_rd {
+       u32 buffer1;
+};
+
+struct rdes1_rd {
+       u32 reserved;
+};
+
+struct rdes2_rd {
+       u32 buffer2;
+};
+
+struct rdes3_rd {
+       u32 rsvd1:24;
+       u32 buf1v:1;
+       u32 buf2v:1;
+       u32 rsvd:4;
+       u32 inte:1;
+       u32 own:1;
+};
+
+struct rdes0_wr {
+       u32 vt:16;
+       u32 rsvd:16;
+};
+
+struct rdes1_wr {
+       u32 pt:3;
+       u32 iphe:1;
+       u32 ipv4:1;
+       u32 ipv6:1;
+       u32 ipcb:1;
+       u32 ipce:1;
+       u32 pmt:4;
+       u32 pft:1;
+       u32 pv:1;
+       u32 tsa:1;
+       u32 td:1;
+       u32 ipt1c:16;
+};
+
+struct rdes2_wr {
+       u32 hl:10;
+       u32 arprcvf:1;
+       u32 arpnr:1;
+       u32 rsvd:3;
+       u32 vf:1;
+       u32 saf:1;
+       u32 daf:1;
+       u32 hf:1;
+       u32 madrm:8;
+       u32 l3fm:1;
+       u32 l4fm:1;
+       u32 l3l4fm:3;
+};
+
+struct rdes3_wr {
+       u32 length:15;
+       u32 es:1;
+       u32 lt:3;
+       u32 de:1;
+       u32 re:1;
+       u32 oe:1;
+       u32 rwt:1;
+       u32 gp:1;
+       u32 ce:1;
+       u32 rs0v:1;
+       u32 rs1v:1;
+       u32 rs2v:1;
+       u32 ld:1;
+       u32 fd:1;
+       u32 ctxt:1;
+       u32 own:1;
+};
+
+struct dwc_eth_qos_txdesc {
+       union {
+               struct tdes0_rd rd;
+               struct tdes0_wr wr;
+               u32 raw;
+       } tdes0;
+       union {
+               struct tdes1_rd rd;
+               struct tdes1_wr wr;
+               u32 raw;
+       } tdes1;
+       union {
+               struct tdes2_rd rd;
+               struct tdes2_wr wr;
+               u32 raw;
+       } tdes2;
+       union {
+               struct tdes3_rd rd;
+               struct tdes3_wr wr;
+               u32 raw;
+       } tdes3;
+};
+
+struct dwc_eth_qos_rxdesc {
+       union {
+               struct rdes0_rd rd;
+               struct rdes0_wr wr;
+               u32 raw;
+       } rdes0;
+       union {
+               struct rdes1_rd rd;
+               struct rdes1_wr wr;
+               u32 raw;
+       } rdes1;
+       union {
+               struct rdes2_rd rd;
+               struct rdes2_wr wr;
+               u32 raw;
+       } rdes2;
+       union {
+               struct rdes3_rd rd;
+               struct rdes3_wr wr;
+               u32 raw;
+       } rdes3;
+};
+
+#endif
