Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / ethernet / stmicro / stmmac / dwmac1000_dma.c
diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
new file mode 100644 (file)
index 0000000..0e8937c
--- /dev/null
@@ -0,0 +1,221 @@
+/*******************************************************************************
+  This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
+  DWC Ether MAC 10/100/1000 Universal version 3.41a  has been used for
+  developing this code.
+
+  This contains the functions to handle the dma.
+
+  Copyright (C) 2007-2009  STMicroelectronics Ltd
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  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".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <asm/io.h>
+#include "dwmac1000.h"
+#include "dwmac_dma.h"
+
+static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+                             int burst_len, u32 dma_tx, u32 dma_rx, int atds)
+{
+       u32 value = readl(ioaddr + DMA_BUS_MODE);
+       int limit;
+
+       /* 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)
+               return -EBUSY;
+
+       /*
+        * Set the DMA PBL (Programmable Burst Length) mode
+        * Before stmmac core 3.50 this mode bit was 4xPBL, and
+        * post 3.5 mode bit acts as 8*PBL.
+        * For core rev < 3.5, when the core is set for 4xPBL mode, the
+        * DMA transfers the data in 4, 8, 16, 32, 64 & 128 beats
+        * depending on pbl value.
+        * For core rev > 3.5, when the core is set for 8xPBL mode, the
+        * DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
+        * depending on pbl value.
+        */
+       value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
+                                   (pbl << DMA_BUS_MODE_RPBL_SHIFT));
+
+       /* Set the Fixed burst mode */
+       if (fb)
+               value |= DMA_BUS_MODE_FB;
+
+       /* Mixed Burst has no effect when fb is set */
+       if (mb)
+               value |= DMA_BUS_MODE_MB;
+
+       if (atds)
+               value |= DMA_BUS_MODE_ATDS;
+
+       writel(value, ioaddr + DMA_BUS_MODE);
+
+       /* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
+        * for supported bursts.
+        *
+        * Note: This is applicable only for revision GMACv3.61a. For
+        * older version this register is reserved and shall have no
+        * effect.
+        *
+        * Note:
+        *  For Fixed Burst Mode: if we directly write 0xFF to this
+        *  register using the configurations pass from platform code,
+        *  this would ensure that all bursts supported by core are set
+        *  and those which are not supported would remain ineffective.
+        *
+        *  For Non Fixed Burst Mode: provide the maximum value of the
+        *  burst length. Any burst equal or below the provided burst
+        *  length would be allowed to perform.
+        */
+       writel(burst_len, ioaddr + DMA_AXI_BUS_MODE);
+
+       /* Mask interrupts by writing to CSR7 */
+       writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+
+       /* RX/TX descriptor base address lists must be written into
+        * DMA CSR3 and CSR4, respectively
+        */
+       writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
+       writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
+
+       return 0;
+}
+
+static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
+{
+       csr6 &= ~DMA_CONTROL_RFA_MASK;
+       csr6 &= ~DMA_CONTROL_RFD_MASK;
+
+       /* Leave flow control disabled if receive fifo size is less than
+        * 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
+        * and send XON when 2K less than full.
+        */
+       if (rxfifosz < 4096) {
+               csr6 &= ~DMA_CONTROL_EFC;
+               pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
+                        rxfifosz);
+       } else {
+               csr6 |= DMA_CONTROL_EFC;
+               csr6 |= RFA_FULL_MINUS_1K;
+               csr6 |= RFD_FULL_MINUS_2K;
+       }
+       return csr6;
+}
+
+static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
+                                        int rxmode, int rxfifosz)
+{
+       u32 csr6 = readl(ioaddr + DMA_CONTROL);
+
+       if (txmode == SF_DMA_MODE) {
+               pr_debug("GMAC: enable TX store and forward mode\n");
+               /* Transmit COE type 2 cannot be done in cut-through mode. */
+               csr6 |= DMA_CONTROL_TSF;
+               /* Operating on second frame increase the performance
+                * especially when transmit store-and-forward is used.
+                */
+               csr6 |= DMA_CONTROL_OSF;
+       } else {
+               pr_debug("GMAC: disabling TX SF (threshold %d)\n", txmode);
+               csr6 &= ~DMA_CONTROL_TSF;
+               csr6 &= DMA_CONTROL_TC_TX_MASK;
+               /* Set the transmit threshold */
+               if (txmode <= 32)
+                       csr6 |= DMA_CONTROL_TTC_32;
+               else if (txmode <= 64)
+                       csr6 |= DMA_CONTROL_TTC_64;
+               else if (txmode <= 128)
+                       csr6 |= DMA_CONTROL_TTC_128;
+               else if (txmode <= 192)
+                       csr6 |= DMA_CONTROL_TTC_192;
+               else
+                       csr6 |= DMA_CONTROL_TTC_256;
+       }
+
+       if (rxmode == SF_DMA_MODE) {
+               pr_debug("GMAC: enable RX store and forward mode\n");
+               csr6 |= DMA_CONTROL_RSF;
+       } else {
+               pr_debug("GMAC: disable RX SF mode (threshold %d)\n", rxmode);
+               csr6 &= ~DMA_CONTROL_RSF;
+               csr6 &= DMA_CONTROL_TC_RX_MASK;
+               if (rxmode <= 32)
+                       csr6 |= DMA_CONTROL_RTC_32;
+               else if (rxmode <= 64)
+                       csr6 |= DMA_CONTROL_RTC_64;
+               else if (rxmode <= 96)
+                       csr6 |= DMA_CONTROL_RTC_96;
+               else
+                       csr6 |= DMA_CONTROL_RTC_128;
+       }
+
+       /* Configure flow control based on rx fifo size */
+       csr6 = dwmac1000_configure_fc(csr6, rxfifosz);
+
+       writel(csr6, ioaddr + DMA_CONTROL);
+}
+
+static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
+{
+       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));
+               }
+       }
+}
+
+static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
+{
+       return readl(ioaddr + DMA_HW_FEATURE);
+}
+
+static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
+{
+       writel(riwt, ioaddr + DMA_RX_WATCHDOG);
+}
+
+const struct stmmac_dma_ops dwmac1000_dma_ops = {
+       .init = dwmac1000_dma_init,
+       .dump_regs = dwmac1000_dump_dma_regs,
+       .dma_mode = dwmac1000_dma_operation_mode,
+       .enable_dma_transmission = dwmac_enable_dma_transmission,
+       .enable_dma_irq = dwmac_enable_dma_irq,
+       .disable_dma_irq = dwmac_disable_dma_irq,
+       .start_tx = dwmac_dma_start_tx,
+       .stop_tx = dwmac_dma_stop_tx,
+       .start_rx = dwmac_dma_start_rx,
+       .stop_rx = dwmac_dma_stop_rx,
+       .dma_interrupt = dwmac_dma_interrupt,
+       .get_hw_feature = dwmac1000_get_hw_feature,
+       .rx_watchdog = dwmac1000_rx_watchdog,
+};