1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2007-2015  STMicroelectronics Ltd
4 *
5 * Author: Alexandre Torgue <alexandre.torgue@st.com>
6 */
7
8#include <linux/io.h>
9#include <linux/iopoll.h>
10#include <linux/delay.h>
11#include "common.h"
12#include "dwmac4_dma.h"
13#include "dwmac4.h"
14
15int dwmac4_dma_reset(void __iomem *ioaddr)
16{
17	u32 value = readl(ioaddr + DMA_BUS_MODE);
18
19	/* DMA SW reset */
20	value |= DMA_BUS_MODE_SFT_RESET;
21	writel(value, ioaddr + DMA_BUS_MODE);
22
23	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
24				 !(value & DMA_BUS_MODE_SFT_RESET),
25				 10000, 1000000);
26}
27
28void dwmac4_set_rx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
29{
30	writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(chan));
31}
32
33void dwmac4_set_tx_tail_ptr(void __iomem *ioaddr, u32 tail_ptr, u32 chan)
34{
35	writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(chan));
36}
37
38void dwmac4_dma_start_tx(void __iomem *ioaddr, u32 chan)
39{
40	u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
41
42	value |= DMA_CONTROL_ST;
43	writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
44
45	value = readl(ioaddr + GMAC_CONFIG);
46	value |= GMAC_CONFIG_TE;
47	writel(value, ioaddr + GMAC_CONFIG);
48}
49
50void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan)
51{
52	u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(chan));
53
54	value &= ~DMA_CONTROL_ST;
55	writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
56}
57
58void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan)
59{
60	u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
61
62	value |= DMA_CONTROL_SR;
63
64	writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
65
66	value = readl(ioaddr + GMAC_CONFIG);
67	value |= GMAC_CONFIG_RE;
68	writel(value, ioaddr + GMAC_CONFIG);
69}
70
71void dwmac4_dma_stop_rx(void __iomem *ioaddr, u32 chan)
72{
73	u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(chan));
74
75	value &= ~DMA_CONTROL_SR;
76	writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan));
77}
78
79void dwmac4_set_tx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
80{
81	writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(chan));
82}
83
84void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len, u32 chan)
85{
86	writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(chan));
87}
88
89void dwmac4_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
90{
91	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
92
93	if (rx)
94		value |= DMA_CHAN_INTR_DEFAULT_RX;
95	if (tx)
96		value |= DMA_CHAN_INTR_DEFAULT_TX;
97
98	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
99}
100
101void dwmac410_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
102{
103	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
104
105	if (rx)
106		value |= DMA_CHAN_INTR_DEFAULT_RX_4_10;
107	if (tx)
108		value |= DMA_CHAN_INTR_DEFAULT_TX_4_10;
109
110	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
111}
112
113void dwmac4_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
114{
115	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
116
117	if (rx)
118		value &= ~DMA_CHAN_INTR_DEFAULT_RX;
119	if (tx)
120		value &= ~DMA_CHAN_INTR_DEFAULT_TX;
121
122	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
123}
124
125void dwmac410_disable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx)
126{
127	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
128
129	if (rx)
130		value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10;
131	if (tx)
132		value &= ~DMA_CHAN_INTR_DEFAULT_TX_4_10;
133
134	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));
135}
136
137int dwmac4_dma_interrupt(void __iomem *ioaddr,
138			 struct stmmac_extra_stats *x, u32 chan)
139{
140	u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));
141	u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));
142	int ret = 0;
143
144	/* ABNORMAL interrupts */
145	if (unlikely(intr_status & DMA_CHAN_STATUS_AIS)) {
146		if (unlikely(intr_status & DMA_CHAN_STATUS_RBU))
147			x->rx_buf_unav_irq++;
148		if (unlikely(intr_status & DMA_CHAN_STATUS_RPS))
149			x->rx_process_stopped_irq++;
150		if (unlikely(intr_status & DMA_CHAN_STATUS_RWT))
151			x->rx_watchdog_irq++;
152		if (unlikely(intr_status & DMA_CHAN_STATUS_ETI))
153			x->tx_early_irq++;
154		if (unlikely(intr_status & DMA_CHAN_STATUS_TPS)) {
155			x->tx_process_stopped_irq++;
156			ret = tx_hard_error;
157		}
158		if (unlikely(intr_status & DMA_CHAN_STATUS_FBE)) {
159			x->fatal_bus_error_irq++;
160			ret = tx_hard_error;
161		}
162	}
163	/* TX/RX NORMAL interrupts */
164	if (likely(intr_status & DMA_CHAN_STATUS_NIS)) {
165		x->normal_irq_n++;
166		if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
167			x->rx_normal_irq_n++;
168			ret |= handle_rx;
169		}
170		if (likely(intr_status & (DMA_CHAN_STATUS_TI |
171					  DMA_CHAN_STATUS_TBU))) {
172			x->tx_normal_irq_n++;
173			ret |= handle_tx;
174		}
175		if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
176			x->rx_early_irq++;
177	}
178
179	writel(intr_status & intr_en, ioaddr + DMA_CHAN_STATUS(chan));
180	return ret;
181}
182
183void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
184				unsigned int high, unsigned int low)
185{
186	unsigned long data;
187
188	data = (addr[5] << 8) | addr[4];
189	/* For MAC Addr registers se have to set the Address Enable (AE)
190	 * bit that has no effect on the High Reg 0 where the bit 31 (MO)
191	 * is RO.
192	 */
193	data |= (STMMAC_CHAN0 << GMAC_HI_DCS_SHIFT);
194	writel(data | GMAC_HI_REG_AE, ioaddr + high);
195	data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
196	writel(data, ioaddr + low);
197}
198
199/* Enable disable MAC RX/TX */
200void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable)
201{
202	u32 value = readl(ioaddr + GMAC_CONFIG);
203
204	if (enable)
205		value |= GMAC_CONFIG_RE | GMAC_CONFIG_TE;
206	else
207		value &= ~(GMAC_CONFIG_TE | GMAC_CONFIG_RE);
208
209	writel(value, ioaddr + GMAC_CONFIG);
210}
211
212void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
213				unsigned int high, unsigned int low)
214{
215	unsigned int hi_addr, lo_addr;
216
217	/* Read the MAC address from the hardware */
218	hi_addr = readl(ioaddr + high);
219	lo_addr = readl(ioaddr + low);
220
221	/* Extract the MAC address from the high and low words */
222	addr[0] = lo_addr & 0xff;
223	addr[1] = (lo_addr >> 8) & 0xff;
224	addr[2] = (lo_addr >> 16) & 0xff;
225	addr[3] = (lo_addr >> 24) & 0xff;
226	addr[4] = hi_addr & 0xff;
227	addr[5] = (hi_addr >> 8) & 0xff;
228}
229