1 /*******************************************************************************
2   Copyright (C) 2007-2009  STMicroelectronics Ltd
3 
4   This program is free software; you can redistribute it and/or modify it
5   under the terms and conditions of the GNU General Public License,
6   version 2, as published by the Free Software Foundation.
7 
8   This program is distributed in the hope it will be useful, but WITHOUT
9   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11   more details.
12 
13   The full GNU General Public License is included in this distribution in
14   the file called "COPYING".
15 
16   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
17 *******************************************************************************/
18 
19 #include <linux/io.h>
20 #include <linux/iopoll.h>
21 #include "common.h"
22 #include "dwmac_dma.h"
23 
24 #define GMAC_HI_REG_AE		0x80000000
25 
26 int dwmac_dma_reset(void __iomem *ioaddr)
27 {
28 	u32 value = readl(ioaddr + DMA_BUS_MODE);
29 	int err;
30 
31 	/* DMA SW reset */
32 	value |= DMA_BUS_MODE_SFT_RESET;
33 	writel(value, ioaddr + DMA_BUS_MODE);
34 
35 	err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
36 				 !(value & DMA_BUS_MODE_SFT_RESET),
37 				 10000, 100000);
38 	if (err)
39 		return -EBUSY;
40 
41 	return 0;
42 }
43 
44 /* CSR1 enables the transmit DMA to check for new descriptor */
45 void dwmac_enable_dma_transmission(void __iomem *ioaddr)
46 {
47 	writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
48 }
49 
50 void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
51 {
52 	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
53 }
54 
55 void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
56 {
57 	writel(0, ioaddr + DMA_INTR_ENA);
58 }
59 
60 void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
61 {
62 	u32 value = readl(ioaddr + DMA_CONTROL);
63 	value |= DMA_CONTROL_ST;
64 	writel(value, ioaddr + DMA_CONTROL);
65 }
66 
67 void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
68 {
69 	u32 value = readl(ioaddr + DMA_CONTROL);
70 	value &= ~DMA_CONTROL_ST;
71 	writel(value, ioaddr + DMA_CONTROL);
72 }
73 
74 void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)
75 {
76 	u32 value = readl(ioaddr + DMA_CONTROL);
77 	value |= DMA_CONTROL_SR;
78 	writel(value, ioaddr + DMA_CONTROL);
79 }
80 
81 void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan)
82 {
83 	u32 value = readl(ioaddr + DMA_CONTROL);
84 	value &= ~DMA_CONTROL_SR;
85 	writel(value, ioaddr + DMA_CONTROL);
86 }
87 
88 #ifdef DWMAC_DMA_DEBUG
89 static void show_tx_process_state(unsigned int status)
90 {
91 	unsigned int state;
92 	state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
93 
94 	switch (state) {
95 	case 0:
96 		pr_debug("- TX (Stopped): Reset or Stop command\n");
97 		break;
98 	case 1:
99 		pr_debug("- TX (Running): Fetching the Tx desc\n");
100 		break;
101 	case 2:
102 		pr_debug("- TX (Running): Waiting for end of tx\n");
103 		break;
104 	case 3:
105 		pr_debug("- TX (Running): Reading the data "
106 		       "and queuing the data into the Tx buf\n");
107 		break;
108 	case 6:
109 		pr_debug("- TX (Suspended): Tx Buff Underflow "
110 		       "or an unavailable Transmit descriptor\n");
111 		break;
112 	case 7:
113 		pr_debug("- TX (Running): Closing Tx descriptor\n");
114 		break;
115 	default:
116 		break;
117 	}
118 }
119 
120 static void show_rx_process_state(unsigned int status)
121 {
122 	unsigned int state;
123 	state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
124 
125 	switch (state) {
126 	case 0:
127 		pr_debug("- RX (Stopped): Reset or Stop command\n");
128 		break;
129 	case 1:
130 		pr_debug("- RX (Running): Fetching the Rx desc\n");
131 		break;
132 	case 2:
133 		pr_debug("- RX (Running): Checking for end of pkt\n");
134 		break;
135 	case 3:
136 		pr_debug("- RX (Running): Waiting for Rx pkt\n");
137 		break;
138 	case 4:
139 		pr_debug("- RX (Suspended): Unavailable Rx buf\n");
140 		break;
141 	case 5:
142 		pr_debug("- RX (Running): Closing Rx descriptor\n");
143 		break;
144 	case 6:
145 		pr_debug("- RX(Running): Flushing the current frame"
146 		       " from the Rx buf\n");
147 		break;
148 	case 7:
149 		pr_debug("- RX (Running): Queuing the Rx frame"
150 		       " from the Rx buf into memory\n");
151 		break;
152 	default:
153 		break;
154 	}
155 }
156 #endif
157 
158 int dwmac_dma_interrupt(void __iomem *ioaddr,
159 			struct stmmac_extra_stats *x, u32 chan)
160 {
161 	int ret = 0;
162 	/* read the status register (CSR5) */
163 	u32 intr_status = readl(ioaddr + DMA_STATUS);
164 
165 #ifdef DWMAC_DMA_DEBUG
166 	/* Enable it to monitor DMA rx/tx status in case of critical problems */
167 	pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status);
168 	show_tx_process_state(intr_status);
169 	show_rx_process_state(intr_status);
170 #endif
171 	/* ABNORMAL interrupts */
172 	if (unlikely(intr_status & DMA_STATUS_AIS)) {
173 		if (unlikely(intr_status & DMA_STATUS_UNF)) {
174 			ret = tx_hard_error_bump_tc;
175 			x->tx_undeflow_irq++;
176 		}
177 		if (unlikely(intr_status & DMA_STATUS_TJT))
178 			x->tx_jabber_irq++;
179 
180 		if (unlikely(intr_status & DMA_STATUS_OVF))
181 			x->rx_overflow_irq++;
182 
183 		if (unlikely(intr_status & DMA_STATUS_RU))
184 			x->rx_buf_unav_irq++;
185 		if (unlikely(intr_status & DMA_STATUS_RPS))
186 			x->rx_process_stopped_irq++;
187 		if (unlikely(intr_status & DMA_STATUS_RWT))
188 			x->rx_watchdog_irq++;
189 		if (unlikely(intr_status & DMA_STATUS_ETI))
190 			x->tx_early_irq++;
191 		if (unlikely(intr_status & DMA_STATUS_TPS)) {
192 			x->tx_process_stopped_irq++;
193 			ret = tx_hard_error;
194 		}
195 		if (unlikely(intr_status & DMA_STATUS_FBI)) {
196 			x->fatal_bus_error_irq++;
197 			ret = tx_hard_error;
198 		}
199 	}
200 	/* TX/RX NORMAL interrupts */
201 	if (likely(intr_status & DMA_STATUS_NIS)) {
202 		x->normal_irq_n++;
203 		if (likely(intr_status & DMA_STATUS_RI)) {
204 			u32 value = readl(ioaddr + DMA_INTR_ENA);
205 			/* to schedule NAPI on real RIE event. */
206 			if (likely(value & DMA_INTR_ENA_RIE)) {
207 				x->rx_normal_irq_n++;
208 				ret |= handle_rx;
209 			}
210 		}
211 		if (likely(intr_status & DMA_STATUS_TI)) {
212 			x->tx_normal_irq_n++;
213 			ret |= handle_tx;
214 		}
215 		if (unlikely(intr_status & DMA_STATUS_ERI))
216 			x->rx_early_irq++;
217 	}
218 	/* Optional hardware blocks, interrupts should be disabled */
219 	if (unlikely(intr_status &
220 		     (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
221 		pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
222 
223 	/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
224 	writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
225 
226 	return ret;
227 }
228 
229 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
230 {
231 	u32 csr6 = readl(ioaddr + DMA_CONTROL);
232 	writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
233 
234 	do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
235 }
236 
237 void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
238 			 unsigned int high, unsigned int low)
239 {
240 	unsigned long data;
241 
242 	data = (addr[5] << 8) | addr[4];
243 	/* For MAC Addr registers we have to set the Address Enable (AE)
244 	 * bit that has no effect on the High Reg 0 where the bit 31 (MO)
245 	 * is RO.
246 	 */
247 	writel(data | GMAC_HI_REG_AE, ioaddr + high);
248 	data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
249 	writel(data, ioaddr + low);
250 }
251 EXPORT_SYMBOL_GPL(stmmac_set_mac_addr);
252 
253 /* Enable disable MAC RX/TX */
254 void stmmac_set_mac(void __iomem *ioaddr, bool enable)
255 {
256 	u32 value = readl(ioaddr + MAC_CTRL_REG);
257 
258 	if (enable)
259 		value |= MAC_ENABLE_RX | MAC_ENABLE_TX;
260 	else
261 		value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX);
262 
263 	writel(value, ioaddr + MAC_CTRL_REG);
264 }
265 
266 void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
267 			 unsigned int high, unsigned int low)
268 {
269 	unsigned int hi_addr, lo_addr;
270 
271 	/* Read the MAC address from the hardware */
272 	hi_addr = readl(ioaddr + high);
273 	lo_addr = readl(ioaddr + low);
274 
275 	/* Extract the MAC address from the high and low words */
276 	addr[0] = lo_addr & 0xff;
277 	addr[1] = (lo_addr >> 8) & 0xff;
278 	addr[2] = (lo_addr >> 16) & 0xff;
279 	addr[3] = (lo_addr >> 24) & 0xff;
280 	addr[4] = hi_addr & 0xff;
281 	addr[5] = (hi_addr >> 8) & 0xff;
282 }
283 EXPORT_SYMBOL_GPL(stmmac_get_mac_addr);
284