diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index c555a421f647..acca7cbf9e6b 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -29,8 +29,13 @@
  */
 #define FEC_IEVENT		0x004 /* Interrupt event reg */
 #define FEC_IMASK		0x008 /* Interrupt mask reg */
+#ifdef CONFIG_NET_DSA_MTIP_L2SW
+#define FEC_R_DES_ACTIVE_0	0x018 /* L2 switch Receive descriptor reg */
+#define FEC_X_DES_ACTIVE_0	0x01C /* L2 switch Transmit descriptor reg */
+#else
 #define FEC_R_DES_ACTIVE_0	0x010 /* Receive descriptor reg */
 #define FEC_X_DES_ACTIVE_0	0x014 /* Transmit descriptor reg */
+#endif
 #define FEC_ECNTRL		0x024 /* Ethernet control reg */
 #define FEC_MII_DATA		0x040 /* MII manage frame reg */
 #define FEC_MII_SPEED		0x044 /* MII speed control reg */
@@ -59,8 +64,13 @@
 #define FEC_R_DES_START_2	0x16c /* Receive descriptor ring 2 */
 #define FEC_X_DES_START_2	0x170 /* Transmit descriptor ring 2 */
 #define FEC_R_BUFF_SIZE_2	0x174 /* Maximum receive buff ring2 size */
+#ifdef CONFIG_NET_DSA_MTIP_L2SW
+#define FEC_R_DES_START_0	0x0C /* L2 switch Receive descriptor ring */
+#define FEC_X_DES_START_0	0x10 /* L2 switch Transmit descriptor ring */
+#else
 #define FEC_R_DES_START_0	0x180 /* Receive descriptor ring */
 #define FEC_X_DES_START_0	0x184 /* Transmit descriptor ring */
+#endif
 #define FEC_R_BUFF_SIZE_0	0x188 /* Maximum receive buff size */
 #define FEC_R_FIFO_RSFL		0x190 /* Receive FIFO section full threshold */
 #define FEC_R_FIFO_RSEM		0x194 /* Receive FIFO section empty threshold */
@@ -363,13 +373,25 @@ struct bufdesc_ex {
 #define FEC_ENET_BABR   ((uint)0x40000000)      /* Babbling receiver */
 #define FEC_ENET_BABT   ((uint)0x20000000)      /* Babbling transmitter */
 #define FEC_ENET_GRA    ((uint)0x10000000)      /* Graceful stop complete */
+#ifdef CONFIG_NET_DSA_MTIP_L2SW
+#define FEC_ENET_TXF_0	BIT(4)
+#define FEC_ENET_TXF_1	0
+#define FEC_ENET_TXF_2	0
+#else
 #define FEC_ENET_TXF_0	((uint)0x08000000)	/* Full frame transmitted */
 #define FEC_ENET_TXF_1	((uint)0x00000008)	/* Full frame transmitted */
 #define FEC_ENET_TXF_2	((uint)0x00000080)	/* Full frame transmitted */
+#endif
 #define FEC_ENET_TXB    ((uint)0x04000000)      /* A buffer was transmitted */
+#ifdef CONFIG_NET_DSA_MTIP_L2SW
+#define FEC_ENET_RXF_0	BIT(2)
+#define FEC_ENET_RXF_1	0
+#define FEC_ENET_RXF_2	0
+#else
 #define FEC_ENET_RXF_0	((uint)0x02000000)	/* Full frame received */
 #define FEC_ENET_RXF_1	((uint)0x00000002)	/* Full frame received */
 #define FEC_ENET_RXF_2	((uint)0x00000020)	/* Full frame received */
+#endif
 #define FEC_ENET_RXB    ((uint)0x01000000)      /* A buffer was received */
 #define FEC_ENET_MII    ((uint)0x00800000)      /* MII interrupt */
 #define FEC_ENET_EBERR  ((uint)0x00400000)      /* SDMA bus error */
@@ -380,6 +402,7 @@ struct bufdesc_ex {
 #define FEC_ENET_TS_TIMER       ((uint)0x00008000)
 
 #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF)
+#define FEC_NAPI_IMASK	FEC_ENET_MII
 #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
 
 /* ENET interrupt coalescing macro define */
@@ -587,9 +610,25 @@ struct fec_enet_private {
 	int pps_enable;
 	unsigned int next_counter;
 
+	/* More Than IP L2 switch */
+	void __iomem *hwpsw;
+	bool l2switch;
+
 	u64 ethtool_stats[];
 };
 
+/* L2 switch */
+#define L2SW_CTRL_REG_OFFSET (0x4)
+/* Get proper base address for either L2 switch or MAC ENET */
+static inline void __iomem *fec_hwp(struct fec_enet_private *fep)
+{
+#ifdef CONFIG_NET_DSA_MTIP_L2SW
+	if (fep->l2switch)
+		return fep->hwpsw;
+#endif
+	return fep->hwp;
+}
+
 void fec_ptp_init(struct platform_device *pdev, int irq_idx);
 void fec_ptp_stop(struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index bd29c84fd89a..32dbb1d18785 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -65,10 +65,12 @@
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 #include <soc/imx/cpuidle.h>
+#include <net/dsa.h>
 
 #include <asm/cacheflush.h>
 
 #include "fec.h"
+#include "../../dsa/mtip-l2switch.h"
 
 static void set_multicast_list(struct net_device *ndev);
 static void fec_enet_itr_coal_init(struct net_device *ndev);
@@ -103,6 +105,11 @@ static const struct fec_devinfo fec_imx28_info = {
 		  FEC_QUIRK_HAS_FRREG,
 };
 
+static const struct fec_devinfo fec_imx28l2sw_info = {
+	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
+		  FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_FRREG,
+};
+
 static const struct fec_devinfo fec_imx6q_info = {
 	.quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
 		  FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
@@ -144,6 +151,9 @@ static struct platform_device_id fec_devtype[] = {
 	}, {
 		.name = "imx28-fec",
 		.driver_data = (kernel_ulong_t)&fec_imx28_info,
+	}, {
+		.name = "imx28-l2switch",
+		.driver_data = (kernel_ulong_t)&fec_imx28l2sw_info,
 	}, {
 		.name = "imx6q-fec",
 		.driver_data = (kernel_ulong_t)&fec_imx6q_info,
@@ -166,6 +176,7 @@ enum imx_fec_type {
 	IMX25_FEC = 1,	/* runs on i.mx25/50/53 */
 	IMX27_FEC,	/* runs on i.mx27/35/51 */
 	IMX28_FEC,
+	IMX28_L2SWITCH,
 	IMX6Q_FEC,
 	MVF600_FEC,
 	IMX6SX_FEC,
@@ -176,6 +187,8 @@ static const struct of_device_id fec_dt_ids[] = {
 	{ .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
 	{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
 	{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
+	{ .compatible = "fsl,imx28-l2switch",
+	  .data = &fec_devtype[IMX28_L2SWITCH], },
 	{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
 	{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
 	{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
@@ -893,7 +906,7 @@ static void fec_enet_enable_ring(struct net_device *ndev)
 
 	for (i = 0; i < fep->num_rx_queues; i++) {
 		rxq = fep->rx_queue[i];
-		writel(rxq->bd.dma, fep->hwp + FEC_R_DES_START(i));
+		writel(rxq->bd.dma, fec_hwp(fep) + FEC_R_DES_START(i));
 		writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_R_BUFF_SIZE(i));
 
 		/* enable DMA1/2 */
@@ -904,7 +917,7 @@ static void fec_enet_enable_ring(struct net_device *ndev)
 
 	for (i = 0; i < fep->num_tx_queues; i++) {
 		txq = fep->tx_queue[i];
-		writel(txq->bd.dma, fep->hwp + FEC_X_DES_START(i));
+		writel(txq->bd.dma, fec_hwp(fep) + FEC_X_DES_START(i));
 
 		/* enable DMA1/2 */
 		if (i)
@@ -1078,6 +1091,29 @@ fec_restart(struct net_device *ndev)
 	}
 #endif /* !defined(CONFIG_M5272) */
 
+	if (fep->l2switch) {
+		/*
+		 * Set PROMISC mode for MAC0/1 - it is necessary for L2 switch
+		 * correct operation.
+		 */
+		rcntl |= MCF_FEC_RCR_PROM;
+
+		/*
+		 * In fec_restart, the FEC_R_CNTRL register is only configured
+		 * for MAC0 controller (when 'mac1' DTS node is NOT enabled).
+		 *
+		 * For L2 switch we configure only one DTS node - 'eth_switch'
+		 * so the same value shall be written to MAC1 corresponding
+		 * register.
+		 *
+		 * The port configuration is finished in the DSA's 'link_adjust'
+		 * callback - which also modifies FEC_R_CNTRL register to set
+		 * proper link speed.
+		 */
+		writel(rcntl,
+		       fep->hwp + ENET_L2_SW_PORT1_OFFSET + FEC_R_CNTRL);
+	}
+
 	writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
 	/* Setup multicast filter. */
@@ -1109,8 +1145,12 @@ fec_restart(struct net_device *ndev)
 	if (fep->bufdesc_ex)
 		fec_ptp_start_cyclecounter(ndev);
 
-	/* Enable interrupts we wish to service */
-	if (fep->link)
+	/*
+	 * Enable interrupts we wish to service - for L2 switch only
+	 * MII interrupts are required for MAC{01} to allow proper
+	 * PHY configuration.
+	 */
+	if (!fep->l2switch && fep->link)
 		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 	else
 		writel(0, fep->hwp + FEC_IMASK);
@@ -1407,7 +1447,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 	unsigned short status;
 	struct  sk_buff *skb_new = NULL;
 	struct  sk_buff *skb;
-	ushort	pkt_len;
+	ushort	pkt_len, l2pl;
 	__u8 *data;
 	int	pkt_received = 0;
 	struct	bufdesc_ex *ebdp = NULL;
@@ -1433,7 +1473,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 			break;
 		pkt_received++;
 
-		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
+		writel(FEC_ENET_RXF, fec_hwp(fep) + FEC_IEVENT);
 
 		/* Check for errors. */
 		status ^= BD_ENET_RX_LAST;
@@ -1473,7 +1513,16 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 		 * include that when passing upstream as it messes up
 		 * bridging applications.
 		 */
-		is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4,
+		/*
+		 * When the L2 switch support is enabled the FCS is removed
+		 * by it and hence the pkt_len shall be passed without
+		 * substracting 4 bytes.
+		 */
+		l2pl = pkt_len - 4;
+		if (fep->l2switch)
+			l2pl = pkt_len;
+
+		is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, l2pl,
 						  need_swap);
 		if (!is_copybreak) {
 			skb_new = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
@@ -1488,7 +1537,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 		}
 
 		prefetch(skb->data - NET_IP_ALIGN);
-		skb_put(skb, pkt_len - 4);
+		skb_put(skb, l2pl);
 		data = skb->data;
 
 		if (!is_copybreak && need_swap)
@@ -1605,12 +1654,12 @@ static bool fec_enet_collect_events(struct fec_enet_private *fep)
 {
 	uint int_events;
 
-	int_events = readl(fep->hwp + FEC_IEVENT);
+	int_events = readl(fec_hwp(fep) + FEC_IEVENT);
 
 	/* Don't clear MDIO events, we poll for those */
 	int_events &= ~FEC_ENET_MII;
 
-	writel(int_events, fep->hwp + FEC_IEVENT);
+	writel(int_events, fec_hwp(fep) + FEC_IEVENT);
 
 	return int_events != 0;
 }
@@ -1635,6 +1684,27 @@ fec_enet_interrupt(int irq, void *dev_id)
 	return ret;
 }
 
+#ifdef CONFIG_NET_DSA_MTIP_L2SW
+static irqreturn_t
+l2switch_interrupt_handler(int irq, void *dev_id)
+{
+	struct net_device *ndev = dev_id;
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	irqreturn_t ret = IRQ_NONE;
+
+	if (fec_enet_collect_events(fep) && fep->link) {
+		ret = IRQ_HANDLED;
+
+		if (napi_schedule_prep(&fep->napi)) {
+			/* Disable NAPI interrupts */
+			writel(0, fep->hwpsw + FEC_IMASK);
+			__napi_schedule(&fep->napi);
+		}
+	}
+	return ret;
+}
+#endif
+
 static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
 {
 	struct net_device *ndev = napi->dev;
@@ -1648,7 +1718,7 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
 
 	if (done < budget) {
 		napi_complete_done(napi, done);
-		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+		writel(FEC_DEFAULT_IMASK, fec_hwp(fep) + FEC_IMASK);
 	}
 
 	return done;
@@ -3065,6 +3135,10 @@ static void set_multicast_list(struct net_device *ndev)
 	unsigned char hash;
 	unsigned int hash_high = 0, hash_low = 0;
 
+	/* DSA subsystem will handle multicast/broadcast setup for L2 switch */
+	if (fep->l2switch)
+		return;
+
 	if (ndev->flags & IFF_PROMISC) {
 		tmp = readl(fep->hwp + FEC_R_CNTRL);
 		tmp |= 0x8;
@@ -3279,7 +3353,8 @@ static int fec_enet_init(struct net_device *ndev)
 		rxq->bd.dma = bd_dma;
 		rxq->bd.dsize = dsize;
 		rxq->bd.dsize_log2 = dsize_log2;
-		rxq->bd.reg_desc_active = fep->hwp + offset_des_active_rxq[i];
+		rxq->bd.reg_desc_active =
+			fec_hwp(fep) + offset_des_active_rxq[i];
 		bd_dma += size;
 		cbd_base = (struct bufdesc *)(((void *)cbd_base) + size);
 		rxq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize);
@@ -3295,7 +3370,8 @@ static int fec_enet_init(struct net_device *ndev)
 		txq->bd.dma = bd_dma;
 		txq->bd.dsize = dsize;
 		txq->bd.dsize_log2 = dsize_log2;
-		txq->bd.reg_desc_active = fep->hwp + offset_des_active_txq[i];
+		txq->bd.reg_desc_active =
+			fec_hwp(fep) + offset_des_active_txq[i];
 		bd_dma += size;
 		cbd_base = (struct bufdesc *)(((void *)cbd_base) + size);
 		txq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize);
@@ -3306,8 +3382,7 @@ static int fec_enet_init(struct net_device *ndev)
 	ndev->watchdog_timeo = TX_TIMEOUT;
 	ndev->netdev_ops = &fec_netdev_ops;
 	ndev->ethtool_ops = &fec_enet_ethtool_ops;
-
-	writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
+	writel(FEC_RX_DISABLED_IMASK, fec_hwp(fep) + FEC_IMASK);
 	netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);
 
 	if (fep->quirks & FEC_QUIRK_HAS_VLAN)
@@ -3544,6 +3619,23 @@ fec_probe(struct platform_device *pdev)
 	fep->pdev = pdev;
 	fep->dev_id = dev_id++;
 
+	if (of_device_is_compatible(np, "fsl,imx28-l2switch")) {
+		fep->l2switch = true;
+		fep->hwpsw = devm_platform_ioremap_resource(pdev, 1);
+		/*
+		 * MAC{01} interrupt and descriptors registers have 4 bytes
+		 * offset when compared to L2 switch IP block.
+		 *
+		 * When L2 switch is added "between" ENET (eth0) and MAC{01}
+		 * the code for interrupts and setting up descriptors is
+		 * reused.
+		 *
+		 * As for example FEC_IMASK are used also on MAC{01} to
+		 * perform MII transmission it is better to subtract the
+		 * offset from the outset and reuse defines.
+		 */
+		fep->hwpsw -= L2SW_CTRL_REG_OFFSET;
+	}
 	platform_set_drvdata(pdev, ndev);
 
 	if ((of_machine_is_compatible("fsl,imx6q") ||
@@ -3669,8 +3761,16 @@ fec_probe(struct platform_device *pdev)
 			ret = irq;
 			goto failed_irq;
 		}
-		ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,
-				       0, pdev->name, ndev);
+#ifdef CONFIG_NET_DSA_MTIP_L2SW
+		if (fep->l2switch && i == 0)
+			ret = devm_request_irq(&pdev->dev, irq,
+					       l2switch_interrupt_handler,
+					       0, "l2switch", ndev);
+		else
+#endif
+			ret = devm_request_irq(&pdev->dev, irq,
+					       fec_enet_interrupt,
+					       0, pdev->name, ndev);
 		if (ret)
 			goto failed_irq;
 
@@ -3683,7 +3783,16 @@ fec_probe(struct platform_device *pdev)
 
 	/* Carrier starts down, phylib will bring it up */
 	netif_carrier_off(ndev);
-	fec_enet_clk_enable(ndev, false);
+	/*
+	 * For L2 switch proper initialization this clk cannot be disabled,
+	 * as it uses is to access shared MAC registers for proper MDIO
+	 * operation.
+	 *
+	 * DSA switch will also use it afterwards to setup its ports.
+	 */
+	if (!fep->l2switch)
+		fec_enet_clk_enable(ndev, false);
+
 	pinctrl_pm_select_sleep_state(&pdev->dev);
 
 	ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN;
