1 /*******************************************************************************
2 This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
3 DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
6 This contains the functions to handle the dma.
8 Copyright (C) 2007-2009 STMicroelectronics Ltd
10 This program is free software; you can redistribute it and/or modify it
11 under the terms and conditions of the GNU General Public License,
12 version 2, as published by the Free Software Foundation.
14 This program is distributed in the hope it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 The full GNU General Public License is included in this distribution in
24 the file called "COPYING".
26 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
27 *******************************************************************************/
30 #include "dwmac1000.h"
31 #include "dwmac_dma.h"
33 static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
35 u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
38 pr_info("dwmac1000: Master AXI performs %s burst length\n",
39 !(value & DMA_AXI_UNDEF) ? "fixed" : "any");
42 value |= DMA_AXI_EN_LPI;
44 value |= DMA_AXI_LPI_XIT_FRM;
46 value &= ~DMA_AXI_WR_OSR_LMT;
47 value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
48 DMA_AXI_WR_OSR_LMT_SHIFT;
50 value &= ~DMA_AXI_RD_OSR_LMT;
51 value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
52 DMA_AXI_RD_OSR_LMT_SHIFT;
54 /* Depending on the UNDEF bit the Master AXI will perform any burst
55 * length according to the BLEN programmed (by default all BLEN are
58 for (i = 0; i < AXI_BLEN; i++) {
59 switch (axi->axi_blen[i]) {
61 value |= DMA_AXI_BLEN256;
64 value |= DMA_AXI_BLEN128;
67 value |= DMA_AXI_BLEN64;
70 value |= DMA_AXI_BLEN32;
73 value |= DMA_AXI_BLEN16;
76 value |= DMA_AXI_BLEN8;
79 value |= DMA_AXI_BLEN4;
84 writel(value, ioaddr + DMA_AXI_BUS_MODE);
87 static void dwmac1000_dma_init(void __iomem *ioaddr,
88 struct stmmac_dma_cfg *dma_cfg,
89 u32 dma_tx, u32 dma_rx, int atds)
91 u32 value = readl(ioaddr + DMA_BUS_MODE);
92 int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
93 int rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
96 * Set the DMA PBL (Programmable Burst Length) mode.
98 * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
99 * post 3.5 mode bit acts as 8*PBL.
101 value |= DMA_BUS_MODE_MAXPBL;
102 value |= DMA_BUS_MODE_USP;
103 value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
104 value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
105 value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
107 /* Set the Fixed burst mode */
108 if (dma_cfg->fixed_burst)
109 value |= DMA_BUS_MODE_FB;
111 /* Mixed Burst has no effect when fb is set */
112 if (dma_cfg->mixed_burst)
113 value |= DMA_BUS_MODE_MB;
116 value |= DMA_BUS_MODE_ATDS;
119 value |= DMA_BUS_MODE_AAL;
121 writel(value, ioaddr + DMA_BUS_MODE);
123 /* Mask interrupts by writing to CSR7 */
124 writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
126 /* RX/TX descriptor base address lists must be written into
127 * DMA CSR3 and CSR4, respectively
129 writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
130 writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
133 static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
135 csr6 &= ~DMA_CONTROL_RFA_MASK;
136 csr6 &= ~DMA_CONTROL_RFD_MASK;
138 /* Leave flow control disabled if receive fifo size is less than
139 * 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
140 * and send XON when 2K less than full.
142 if (rxfifosz < 4096) {
143 csr6 &= ~DMA_CONTROL_EFC;
144 pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
147 csr6 |= DMA_CONTROL_EFC;
148 csr6 |= RFA_FULL_MINUS_1K;
149 csr6 |= RFD_FULL_MINUS_2K;
154 static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
155 int rxmode, int rxfifosz)
157 u32 csr6 = readl(ioaddr + DMA_CONTROL);
159 if (txmode == SF_DMA_MODE) {
160 pr_debug("GMAC: enable TX store and forward mode\n");
161 /* Transmit COE type 2 cannot be done in cut-through mode. */
162 csr6 |= DMA_CONTROL_TSF;
163 /* Operating on second frame increase the performance
164 * especially when transmit store-and-forward is used.
166 csr6 |= DMA_CONTROL_OSF;
168 pr_debug("GMAC: disabling TX SF (threshold %d)\n", txmode);
169 csr6 &= ~DMA_CONTROL_TSF;
170 csr6 &= DMA_CONTROL_TC_TX_MASK;
171 /* Set the transmit threshold */
173 csr6 |= DMA_CONTROL_TTC_32;
174 else if (txmode <= 64)
175 csr6 |= DMA_CONTROL_TTC_64;
176 else if (txmode <= 128)
177 csr6 |= DMA_CONTROL_TTC_128;
178 else if (txmode <= 192)
179 csr6 |= DMA_CONTROL_TTC_192;
181 csr6 |= DMA_CONTROL_TTC_256;
184 if (rxmode == SF_DMA_MODE) {
185 pr_debug("GMAC: enable RX store and forward mode\n");
186 csr6 |= DMA_CONTROL_RSF;
188 pr_debug("GMAC: disable RX SF mode (threshold %d)\n", rxmode);
189 csr6 &= ~DMA_CONTROL_RSF;
190 csr6 &= DMA_CONTROL_TC_RX_MASK;
192 csr6 |= DMA_CONTROL_RTC_32;
193 else if (rxmode <= 64)
194 csr6 |= DMA_CONTROL_RTC_64;
195 else if (rxmode <= 96)
196 csr6 |= DMA_CONTROL_RTC_96;
198 csr6 |= DMA_CONTROL_RTC_128;
201 /* Configure flow control based on rx fifo size */
202 csr6 = dwmac1000_configure_fc(csr6, rxfifosz);
204 writel(csr6, ioaddr + DMA_CONTROL);
207 static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
210 pr_info(" DMA registers\n");
211 for (i = 0; i < 22; i++) {
212 if ((i < 9) || (i > 17)) {
214 pr_err("\t Reg No. %d (offset 0x%x): 0x%08x\n", i,
215 (DMA_BUS_MODE + offset),
216 readl(ioaddr + DMA_BUS_MODE + offset));
221 static void dwmac1000_get_hw_feature(void __iomem *ioaddr,
222 struct dma_features *dma_cap)
224 u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE);
226 dma_cap->mbps_10_100 = (hw_cap & DMA_HW_FEAT_MIISEL);
227 dma_cap->mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
228 dma_cap->half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
229 dma_cap->hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
230 dma_cap->multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5;
231 dma_cap->pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
232 dma_cap->sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
233 dma_cap->pmt_remote_wake_up = (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
234 dma_cap->pmt_magic_frame = (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
236 dma_cap->rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
238 dma_cap->time_stamp =
239 (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
241 dma_cap->atime_stamp = (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
242 /* 802.3az - Energy-Efficient Ethernet (EEE) */
243 dma_cap->eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
244 dma_cap->av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
246 dma_cap->tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
247 dma_cap->rx_coe_type1 = (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
248 dma_cap->rx_coe_type2 = (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
249 dma_cap->rxfifo_over_2048 = (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
250 /* TX and RX number of channels */
251 dma_cap->number_rx_channel = (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
252 dma_cap->number_tx_channel = (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
253 /* Alternate (enhanced) DESC mode */
254 dma_cap->enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
257 static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
259 writel(riwt, ioaddr + DMA_RX_WATCHDOG);
262 const struct stmmac_dma_ops dwmac1000_dma_ops = {
263 .reset = dwmac_dma_reset,
264 .init = dwmac1000_dma_init,
265 .axi = dwmac1000_dma_axi,
266 .dump_regs = dwmac1000_dump_dma_regs,
267 .dma_mode = dwmac1000_dma_operation_mode,
268 .enable_dma_transmission = dwmac_enable_dma_transmission,
269 .enable_dma_irq = dwmac_enable_dma_irq,
270 .disable_dma_irq = dwmac_disable_dma_irq,
271 .start_tx = dwmac_dma_start_tx,
272 .stop_tx = dwmac_dma_stop_tx,
273 .start_rx = dwmac_dma_start_rx,
274 .stop_rx = dwmac_dma_stop_rx,
275 .dma_interrupt = dwmac_dma_interrupt,
276 .get_hw_feature = dwmac1000_get_hw_feature,
277 .rx_watchdog = dwmac1000_rx_watchdog,