Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 26int 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 */
 45void dwmac_enable_dma_transmission(void __iomem *ioaddr)
 46{
 47	writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
 48}
 49
 50void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
 51{
 52	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
 53}
 54
 55void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
 56{
 57	writel(0, ioaddr + DMA_INTR_ENA);
 58}
 59
 60void 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
 67void 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
 74void 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
 81void 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
 89static 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
120static 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
158int 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
229void 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
237void 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}
251EXPORT_SYMBOL_GPL(stmmac_set_mac_addr);
252
253/* Enable disable MAC RX/TX */
254void 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
266void 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}
283EXPORT_SYMBOL_GPL(stmmac_get_mac_addr);