xref: /openbmc/u-boot/drivers/dma/bcm6348-iudma.c (revision 7e40d0a3)
1*ccfd6988SÁlvaro Fernández Rojas // SPDX-License-Identifier: GPL-2.0+
2*ccfd6988SÁlvaro Fernández Rojas /*
3*ccfd6988SÁlvaro Fernández Rojas  * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
4*ccfd6988SÁlvaro Fernández Rojas  *
5*ccfd6988SÁlvaro Fernández Rojas  * Derived from linux/drivers/dma/bcm63xx-iudma.c:
6*ccfd6988SÁlvaro Fernández Rojas  *	Copyright (C) 2015 Simon Arlott <simon@fire.lp0.eu>
7*ccfd6988SÁlvaro Fernández Rojas  *
8*ccfd6988SÁlvaro Fernández Rojas  * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
9*ccfd6988SÁlvaro Fernández Rojas  *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
10*ccfd6988SÁlvaro Fernández Rojas  *
11*ccfd6988SÁlvaro Fernández Rojas  * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
12*ccfd6988SÁlvaro Fernández Rojas  *	Copyright (C) 2000-2010 Broadcom Corporation
13*ccfd6988SÁlvaro Fernández Rojas  *
14*ccfd6988SÁlvaro Fernández Rojas  * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/net/enet/impl4/bcmenet.c:
15*ccfd6988SÁlvaro Fernández Rojas  *	Copyright (C) 2010 Broadcom Corporation
16*ccfd6988SÁlvaro Fernández Rojas  */
17*ccfd6988SÁlvaro Fernández Rojas 
18*ccfd6988SÁlvaro Fernández Rojas #include <common.h>
19*ccfd6988SÁlvaro Fernández Rojas #include <clk.h>
20*ccfd6988SÁlvaro Fernández Rojas #include <dm.h>
21*ccfd6988SÁlvaro Fernández Rojas #include <dma-uclass.h>
22*ccfd6988SÁlvaro Fernández Rojas #include <memalign.h>
23*ccfd6988SÁlvaro Fernández Rojas #include <reset.h>
24*ccfd6988SÁlvaro Fernández Rojas #include <asm/io.h>
25*ccfd6988SÁlvaro Fernández Rojas 
26*ccfd6988SÁlvaro Fernández Rojas #define DMA_RX_DESC	6
27*ccfd6988SÁlvaro Fernández Rojas #define DMA_TX_DESC	1
28*ccfd6988SÁlvaro Fernández Rojas 
29*ccfd6988SÁlvaro Fernández Rojas /* DMA Channels */
30*ccfd6988SÁlvaro Fernández Rojas #define DMA_CHAN_FLOWC(x)		((x) >> 1)
31*ccfd6988SÁlvaro Fernández Rojas #define DMA_CHAN_MAX			16
32*ccfd6988SÁlvaro Fernández Rojas #define DMA_CHAN_SIZE			0x10
33*ccfd6988SÁlvaro Fernández Rojas #define DMA_CHAN_TOUT			500
34*ccfd6988SÁlvaro Fernández Rojas 
35*ccfd6988SÁlvaro Fernández Rojas /* DMA Global Configuration register */
36*ccfd6988SÁlvaro Fernández Rojas #define DMA_CFG_REG			0x00
37*ccfd6988SÁlvaro Fernández Rojas #define  DMA_CFG_ENABLE_SHIFT		0
38*ccfd6988SÁlvaro Fernández Rojas #define  DMA_CFG_ENABLE_MASK		(1 << DMA_CFG_ENABLE_SHIFT)
39*ccfd6988SÁlvaro Fernández Rojas #define  DMA_CFG_FLOWC_ENABLE(x)	BIT(DMA_CHAN_FLOWC(x) + 1)
40*ccfd6988SÁlvaro Fernández Rojas #define  DMA_CFG_NCHANS_SHIFT		24
41*ccfd6988SÁlvaro Fernández Rojas #define  DMA_CFG_NCHANS_MASK		(0xf << DMA_CFG_NCHANS_SHIFT)
42*ccfd6988SÁlvaro Fernández Rojas 
43*ccfd6988SÁlvaro Fernández Rojas /* DMA Global Flow Control registers */
44*ccfd6988SÁlvaro Fernández Rojas #define DMA_FLOWC_THR_LO_REG(x)		(0x04 + DMA_CHAN_FLOWC(x) * 0x0c)
45*ccfd6988SÁlvaro Fernández Rojas #define DMA_FLOWC_THR_HI_REG(x)		(0x08 + DMA_CHAN_FLOWC(x) * 0x0c)
46*ccfd6988SÁlvaro Fernández Rojas #define DMA_FLOWC_ALLOC_REG(x)		(0x0c + DMA_CHAN_FLOWC(x) * 0x0c)
47*ccfd6988SÁlvaro Fernández Rojas #define  DMA_FLOWC_ALLOC_FORCE_SHIFT	31
48*ccfd6988SÁlvaro Fernández Rojas #define  DMA_FLOWC_ALLOC_FORCE_MASK	(1 << DMA_FLOWC_ALLOC_FORCE_SHIFT)
49*ccfd6988SÁlvaro Fernández Rojas 
50*ccfd6988SÁlvaro Fernández Rojas /* DMA Global Reset register */
51*ccfd6988SÁlvaro Fernández Rojas #define DMA_RST_REG			0x34
52*ccfd6988SÁlvaro Fernández Rojas #define  DMA_RST_CHAN_SHIFT		0
53*ccfd6988SÁlvaro Fernández Rojas #define  DMA_RST_CHAN_MASK(x)		(1 << x)
54*ccfd6988SÁlvaro Fernández Rojas 
55*ccfd6988SÁlvaro Fernández Rojas /* DMA Channel Configuration register */
56*ccfd6988SÁlvaro Fernández Rojas #define DMAC_CFG_REG(x)			(DMA_CHAN_SIZE * (x) + 0x00)
57*ccfd6988SÁlvaro Fernández Rojas #define  DMAC_CFG_ENABLE_SHIFT		0
58*ccfd6988SÁlvaro Fernández Rojas #define  DMAC_CFG_ENABLE_MASK		(1 << DMAC_CFG_ENABLE_SHIFT)
59*ccfd6988SÁlvaro Fernández Rojas #define  DMAC_CFG_PKT_HALT_SHIFT	1
60*ccfd6988SÁlvaro Fernández Rojas #define  DMAC_CFG_PKT_HALT_MASK		(1 << DMAC_CFG_PKT_HALT_SHIFT)
61*ccfd6988SÁlvaro Fernández Rojas #define  DMAC_CFG_BRST_HALT_SHIFT	2
62*ccfd6988SÁlvaro Fernández Rojas #define  DMAC_CFG_BRST_HALT_MASK	(1 << DMAC_CFG_BRST_HALT_SHIFT)
63*ccfd6988SÁlvaro Fernández Rojas 
64*ccfd6988SÁlvaro Fernández Rojas /* DMA Channel Max Burst Length register */
65*ccfd6988SÁlvaro Fernández Rojas #define DMAC_BURST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x0c)
66*ccfd6988SÁlvaro Fernández Rojas 
67*ccfd6988SÁlvaro Fernández Rojas /* DMA SRAM Descriptor Ring Start register */
68*ccfd6988SÁlvaro Fernández Rojas #define DMAS_RSTART_REG(x)		(DMA_CHAN_SIZE * (x) + 0x00)
69*ccfd6988SÁlvaro Fernández Rojas 
70*ccfd6988SÁlvaro Fernández Rojas /* DMA SRAM State/Bytes done/ring offset register */
71*ccfd6988SÁlvaro Fernández Rojas #define DMAS_STATE_DATA_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
72*ccfd6988SÁlvaro Fernández Rojas 
73*ccfd6988SÁlvaro Fernández Rojas /* DMA SRAM Buffer Descriptor status and length register */
74*ccfd6988SÁlvaro Fernández Rojas #define DMAS_DESC_LEN_STATUS_REG(x)	(DMA_CHAN_SIZE * (x) + 0x08)
75*ccfd6988SÁlvaro Fernández Rojas 
76*ccfd6988SÁlvaro Fernández Rojas /* DMA SRAM Buffer Descriptor status and length register */
77*ccfd6988SÁlvaro Fernández Rojas #define DMAS_DESC_BASE_BUFPTR_REG(x)	(DMA_CHAN_SIZE * (x) + 0x0c)
78*ccfd6988SÁlvaro Fernández Rojas 
79*ccfd6988SÁlvaro Fernández Rojas /* DMA Descriptor Status */
80*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_CRC_SHIFT		8
81*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_CRC_MASK		(1 << DMAD_ST_CRC_SHIFT)
82*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_WRAP_SHIFT		12
83*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_WRAP_MASK		(1 << DMAD_ST_WRAP_SHIFT)
84*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_SOP_SHIFT		13
85*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_SOP_MASK		(1 << DMAD_ST_SOP_SHIFT)
86*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_EOP_SHIFT		14
87*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_EOP_MASK		(1 << DMAD_ST_EOP_SHIFT)
88*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_OWN_SHIFT		15
89*ccfd6988SÁlvaro Fernández Rojas #define DMAD_ST_OWN_MASK		(1 << DMAD_ST_OWN_SHIFT)
90*ccfd6988SÁlvaro Fernández Rojas 
91*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_OV_ERR_SHIFT	0
92*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_OV_ERR_MASK		(1 << DMAD6348_ST_OV_ERR_SHIFT)
93*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_CRC_ERR_SHIFT	1
94*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_CRC_ERR_MASK	(1 << DMAD6348_ST_CRC_ERR_SHIFT)
95*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_RX_ERR_SHIFT	2
96*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_RX_ERR_MASK		(1 << DMAD6348_ST_RX_ERR_SHIFT)
97*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_OS_ERR_SHIFT	4
98*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_OS_ERR_MASK		(1 << DMAD6348_ST_OS_ERR_SHIFT)
99*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_UN_ERR_SHIFT	9
100*ccfd6988SÁlvaro Fernández Rojas #define DMAD6348_ST_UN_ERR_MASK		(1 << DMAD6348_ST_UN_ERR_SHIFT)
101*ccfd6988SÁlvaro Fernández Rojas 
102*ccfd6988SÁlvaro Fernández Rojas struct bcm6348_dma_desc {
103*ccfd6988SÁlvaro Fernández Rojas 	uint16_t length;
104*ccfd6988SÁlvaro Fernández Rojas 	uint16_t status;
105*ccfd6988SÁlvaro Fernández Rojas 	uint32_t address;
106*ccfd6988SÁlvaro Fernández Rojas };
107*ccfd6988SÁlvaro Fernández Rojas 
108*ccfd6988SÁlvaro Fernández Rojas struct bcm6348_chan_priv {
109*ccfd6988SÁlvaro Fernández Rojas 	void __iomem *dma_ring;
110*ccfd6988SÁlvaro Fernández Rojas 	uint8_t dma_ring_size;
111*ccfd6988SÁlvaro Fernández Rojas 	uint8_t desc_id;
112*ccfd6988SÁlvaro Fernández Rojas 	uint8_t desc_cnt;
113*ccfd6988SÁlvaro Fernández Rojas 	bool *busy_desc;
114*ccfd6988SÁlvaro Fernández Rojas 	bool running;
115*ccfd6988SÁlvaro Fernández Rojas };
116*ccfd6988SÁlvaro Fernández Rojas 
117*ccfd6988SÁlvaro Fernández Rojas struct bcm6348_iudma_hw {
118*ccfd6988SÁlvaro Fernández Rojas 	uint16_t err_mask;
119*ccfd6988SÁlvaro Fernández Rojas };
120*ccfd6988SÁlvaro Fernández Rojas 
121*ccfd6988SÁlvaro Fernández Rojas struct bcm6348_iudma_priv {
122*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_hw *hw;
123*ccfd6988SÁlvaro Fernández Rojas 	void __iomem *base;
124*ccfd6988SÁlvaro Fernández Rojas 	void __iomem *chan;
125*ccfd6988SÁlvaro Fernández Rojas 	void __iomem *sram;
126*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv **ch_priv;
127*ccfd6988SÁlvaro Fernández Rojas 	uint8_t n_channels;
128*ccfd6988SÁlvaro Fernández Rojas };
129*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_chan_is_rx(uint8_t ch)130*ccfd6988SÁlvaro Fernández Rojas static inline bool bcm6348_iudma_chan_is_rx(uint8_t ch)
131*ccfd6988SÁlvaro Fernández Rojas {
132*ccfd6988SÁlvaro Fernández Rojas 	return !(ch & 1);
133*ccfd6988SÁlvaro Fernández Rojas }
134*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_fdc(void * ptr,ulong size)135*ccfd6988SÁlvaro Fernández Rojas static inline void bcm6348_iudma_fdc(void *ptr, ulong size)
136*ccfd6988SÁlvaro Fernández Rojas {
137*ccfd6988SÁlvaro Fernández Rojas 	ulong start = (ulong) ptr;
138*ccfd6988SÁlvaro Fernández Rojas 
139*ccfd6988SÁlvaro Fernández Rojas 	flush_dcache_range(start, start + size);
140*ccfd6988SÁlvaro Fernández Rojas }
141*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_idc(void * ptr,ulong size)142*ccfd6988SÁlvaro Fernández Rojas static inline void bcm6348_iudma_idc(void *ptr, ulong size)
143*ccfd6988SÁlvaro Fernández Rojas {
144*ccfd6988SÁlvaro Fernández Rojas 	ulong start = (ulong) ptr;
145*ccfd6988SÁlvaro Fernández Rojas 
146*ccfd6988SÁlvaro Fernández Rojas 	invalidate_dcache_range(start, start + size);
147*ccfd6988SÁlvaro Fernández Rojas }
148*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv * priv,uint8_t ch)149*ccfd6988SÁlvaro Fernández Rojas static void bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv *priv,
150*ccfd6988SÁlvaro Fernández Rojas 				    uint8_t ch)
151*ccfd6988SÁlvaro Fernández Rojas {
152*ccfd6988SÁlvaro Fernández Rojas 	unsigned int timeout = DMA_CHAN_TOUT;
153*ccfd6988SÁlvaro Fernández Rojas 
154*ccfd6988SÁlvaro Fernández Rojas 	do {
155*ccfd6988SÁlvaro Fernández Rojas 		uint32_t cfg, halt;
156*ccfd6988SÁlvaro Fernández Rojas 
157*ccfd6988SÁlvaro Fernández Rojas 		if (timeout > DMA_CHAN_TOUT / 2)
158*ccfd6988SÁlvaro Fernández Rojas 			halt = DMAC_CFG_PKT_HALT_MASK;
159*ccfd6988SÁlvaro Fernández Rojas 		else
160*ccfd6988SÁlvaro Fernández Rojas 			halt = DMAC_CFG_BRST_HALT_MASK;
161*ccfd6988SÁlvaro Fernández Rojas 
162*ccfd6988SÁlvaro Fernández Rojas 		/* try to stop dma channel */
163*ccfd6988SÁlvaro Fernández Rojas 		writel_be(halt, priv->chan + DMAC_CFG_REG(ch));
164*ccfd6988SÁlvaro Fernández Rojas 		mb();
165*ccfd6988SÁlvaro Fernández Rojas 
166*ccfd6988SÁlvaro Fernández Rojas 		/* check if channel was stopped */
167*ccfd6988SÁlvaro Fernández Rojas 		cfg = readl_be(priv->chan + DMAC_CFG_REG(ch));
168*ccfd6988SÁlvaro Fernández Rojas 		if (!(cfg & DMAC_CFG_ENABLE_MASK))
169*ccfd6988SÁlvaro Fernández Rojas 			break;
170*ccfd6988SÁlvaro Fernández Rojas 
171*ccfd6988SÁlvaro Fernández Rojas 		udelay(1);
172*ccfd6988SÁlvaro Fernández Rojas 	} while (--timeout);
173*ccfd6988SÁlvaro Fernández Rojas 
174*ccfd6988SÁlvaro Fernández Rojas 	if (!timeout)
175*ccfd6988SÁlvaro Fernández Rojas 		pr_err("unable to stop channel %u\n", ch);
176*ccfd6988SÁlvaro Fernández Rojas 
177*ccfd6988SÁlvaro Fernández Rojas 	/* reset dma channel */
178*ccfd6988SÁlvaro Fernández Rojas 	setbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
179*ccfd6988SÁlvaro Fernández Rojas 	mb();
180*ccfd6988SÁlvaro Fernández Rojas 	clrbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
181*ccfd6988SÁlvaro Fernández Rojas }
182*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_disable(struct dma * dma)183*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_disable(struct dma *dma)
184*ccfd6988SÁlvaro Fernández Rojas {
185*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
186*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
187*ccfd6988SÁlvaro Fernández Rojas 
188*ccfd6988SÁlvaro Fernández Rojas 	/* stop dma channel */
189*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_chan_stop(priv, dma->id);
190*ccfd6988SÁlvaro Fernández Rojas 
191*ccfd6988SÁlvaro Fernández Rojas 	/* dma flow control */
192*ccfd6988SÁlvaro Fernández Rojas 	if (bcm6348_iudma_chan_is_rx(dma->id))
193*ccfd6988SÁlvaro Fernández Rojas 		writel_be(DMA_FLOWC_ALLOC_FORCE_MASK,
194*ccfd6988SÁlvaro Fernández Rojas 			  DMA_FLOWC_ALLOC_REG(dma->id));
195*ccfd6988SÁlvaro Fernández Rojas 
196*ccfd6988SÁlvaro Fernández Rojas 	/* init channel config */
197*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->running = false;
198*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->desc_id = 0;
199*ccfd6988SÁlvaro Fernández Rojas 	if (bcm6348_iudma_chan_is_rx(dma->id))
200*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->desc_cnt = 0;
201*ccfd6988SÁlvaro Fernández Rojas 	else
202*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->desc_cnt = ch_priv->dma_ring_size;
203*ccfd6988SÁlvaro Fernández Rojas 
204*ccfd6988SÁlvaro Fernández Rojas 	return 0;
205*ccfd6988SÁlvaro Fernández Rojas }
206*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_enable(struct dma * dma)207*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_enable(struct dma *dma)
208*ccfd6988SÁlvaro Fernández Rojas {
209*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
210*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
211*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_dma_desc *dma_desc = ch_priv->dma_ring;
212*ccfd6988SÁlvaro Fernández Rojas 	uint8_t i;
213*ccfd6988SÁlvaro Fernández Rojas 
214*ccfd6988SÁlvaro Fernández Rojas 	/* dma ring init */
215*ccfd6988SÁlvaro Fernández Rojas 	for (i = 0; i < ch_priv->desc_cnt; i++) {
216*ccfd6988SÁlvaro Fernández Rojas 		if (bcm6348_iudma_chan_is_rx(dma->id)) {
217*ccfd6988SÁlvaro Fernández Rojas 			ch_priv->busy_desc[i] = false;
218*ccfd6988SÁlvaro Fernández Rojas 			dma_desc->status |= DMAD_ST_OWN_MASK;
219*ccfd6988SÁlvaro Fernández Rojas 		} else {
220*ccfd6988SÁlvaro Fernández Rojas 			dma_desc->status = 0;
221*ccfd6988SÁlvaro Fernández Rojas 			dma_desc->length = 0;
222*ccfd6988SÁlvaro Fernández Rojas 			dma_desc->address = 0;
223*ccfd6988SÁlvaro Fernández Rojas 		}
224*ccfd6988SÁlvaro Fernández Rojas 
225*ccfd6988SÁlvaro Fernández Rojas 		if (i == ch_priv->desc_cnt - 1)
226*ccfd6988SÁlvaro Fernández Rojas 			dma_desc->status |= DMAD_ST_WRAP_MASK;
227*ccfd6988SÁlvaro Fernández Rojas 
228*ccfd6988SÁlvaro Fernández Rojas 		dma_desc++;
229*ccfd6988SÁlvaro Fernández Rojas 	}
230*ccfd6988SÁlvaro Fernández Rojas 
231*ccfd6988SÁlvaro Fernández Rojas 	/* init to first descriptor */
232*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->desc_id = 0;
233*ccfd6988SÁlvaro Fernández Rojas 
234*ccfd6988SÁlvaro Fernández Rojas 	/* force cache writeback */
235*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_fdc(ch_priv->dma_ring,
236*ccfd6988SÁlvaro Fernández Rojas 			  sizeof(*dma_desc) * ch_priv->desc_cnt);
237*ccfd6988SÁlvaro Fernández Rojas 
238*ccfd6988SÁlvaro Fernández Rojas 	/* clear sram */
239*ccfd6988SÁlvaro Fernández Rojas 	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
240*ccfd6988SÁlvaro Fernández Rojas 	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
241*ccfd6988SÁlvaro Fernández Rojas 	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
242*ccfd6988SÁlvaro Fernández Rojas 
243*ccfd6988SÁlvaro Fernández Rojas 	/* set dma ring start */
244*ccfd6988SÁlvaro Fernández Rojas 	writel_be(virt_to_phys(ch_priv->dma_ring),
245*ccfd6988SÁlvaro Fernández Rojas 		  priv->sram + DMAS_RSTART_REG(dma->id));
246*ccfd6988SÁlvaro Fernández Rojas 
247*ccfd6988SÁlvaro Fernández Rojas 	/* set flow control */
248*ccfd6988SÁlvaro Fernández Rojas 	if (bcm6348_iudma_chan_is_rx(dma->id)) {
249*ccfd6988SÁlvaro Fernández Rojas 		u32 val;
250*ccfd6988SÁlvaro Fernández Rojas 
251*ccfd6988SÁlvaro Fernández Rojas 		setbits_be32(priv->base + DMA_CFG_REG,
252*ccfd6988SÁlvaro Fernández Rojas 			     DMA_CFG_FLOWC_ENABLE(dma->id));
253*ccfd6988SÁlvaro Fernández Rojas 
254*ccfd6988SÁlvaro Fernández Rojas 		val = ch_priv->desc_cnt / 3;
255*ccfd6988SÁlvaro Fernández Rojas 		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
256*ccfd6988SÁlvaro Fernández Rojas 
257*ccfd6988SÁlvaro Fernández Rojas 		val = (ch_priv->desc_cnt * 2) / 3;
258*ccfd6988SÁlvaro Fernández Rojas 		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
259*ccfd6988SÁlvaro Fernández Rojas 
260*ccfd6988SÁlvaro Fernández Rojas 		writel_be(0, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
261*ccfd6988SÁlvaro Fernández Rojas 	}
262*ccfd6988SÁlvaro Fernández Rojas 
263*ccfd6988SÁlvaro Fernández Rojas 	/* set dma max burst */
264*ccfd6988SÁlvaro Fernández Rojas 	writel_be(ch_priv->desc_cnt,
265*ccfd6988SÁlvaro Fernández Rojas 		  priv->chan + DMAC_BURST_REG(dma->id));
266*ccfd6988SÁlvaro Fernández Rojas 
267*ccfd6988SÁlvaro Fernández Rojas 	/* kick rx dma channel */
268*ccfd6988SÁlvaro Fernández Rojas 	if (bcm6348_iudma_chan_is_rx(dma->id))
269*ccfd6988SÁlvaro Fernández Rojas 		setbits_be32(priv->chan + DMAC_CFG_REG(dma->id),
270*ccfd6988SÁlvaro Fernández Rojas 			     DMAC_CFG_ENABLE_MASK);
271*ccfd6988SÁlvaro Fernández Rojas 
272*ccfd6988SÁlvaro Fernández Rojas 	/* channel is now enabled */
273*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->running = true;
274*ccfd6988SÁlvaro Fernández Rojas 
275*ccfd6988SÁlvaro Fernández Rojas 	return 0;
276*ccfd6988SÁlvaro Fernández Rojas }
277*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_request(struct dma * dma)278*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_request(struct dma *dma)
279*ccfd6988SÁlvaro Fernández Rojas {
280*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
281*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv;
282*ccfd6988SÁlvaro Fernández Rojas 
283*ccfd6988SÁlvaro Fernández Rojas 	/* check if channel is valid */
284*ccfd6988SÁlvaro Fernández Rojas 	if (dma->id >= priv->n_channels)
285*ccfd6988SÁlvaro Fernández Rojas 		return -ENODEV;
286*ccfd6988SÁlvaro Fernández Rojas 
287*ccfd6988SÁlvaro Fernández Rojas 	/* alloc channel private data */
288*ccfd6988SÁlvaro Fernández Rojas 	priv->ch_priv[dma->id] = calloc(1, sizeof(struct bcm6348_chan_priv));
289*ccfd6988SÁlvaro Fernández Rojas 	if (!priv->ch_priv[dma->id])
290*ccfd6988SÁlvaro Fernández Rojas 		return -ENOMEM;
291*ccfd6988SÁlvaro Fernández Rojas 	ch_priv = priv->ch_priv[dma->id];
292*ccfd6988SÁlvaro Fernández Rojas 
293*ccfd6988SÁlvaro Fernández Rojas 	/* alloc dma ring */
294*ccfd6988SÁlvaro Fernández Rojas 	if (bcm6348_iudma_chan_is_rx(dma->id))
295*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->dma_ring_size = DMA_RX_DESC;
296*ccfd6988SÁlvaro Fernández Rojas 	else
297*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->dma_ring_size = DMA_TX_DESC;
298*ccfd6988SÁlvaro Fernández Rojas 
299*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->dma_ring =
300*ccfd6988SÁlvaro Fernández Rojas 		malloc_cache_aligned(sizeof(struct bcm6348_dma_desc) *
301*ccfd6988SÁlvaro Fernández Rojas 				     ch_priv->dma_ring_size);
302*ccfd6988SÁlvaro Fernández Rojas 	if (!ch_priv->dma_ring)
303*ccfd6988SÁlvaro Fernández Rojas 		return -ENOMEM;
304*ccfd6988SÁlvaro Fernández Rojas 
305*ccfd6988SÁlvaro Fernández Rojas 	/* init channel config */
306*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->running = false;
307*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->desc_id = 0;
308*ccfd6988SÁlvaro Fernández Rojas 	if (bcm6348_iudma_chan_is_rx(dma->id)) {
309*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->desc_cnt = 0;
310*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->busy_desc = calloc(ch_priv->desc_cnt, sizeof(bool));
311*ccfd6988SÁlvaro Fernández Rojas 	} else {
312*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->desc_cnt = ch_priv->dma_ring_size;
313*ccfd6988SÁlvaro Fernández Rojas 		ch_priv->busy_desc = NULL;
314*ccfd6988SÁlvaro Fernández Rojas 	}
315*ccfd6988SÁlvaro Fernández Rojas 
316*ccfd6988SÁlvaro Fernández Rojas 	return 0;
317*ccfd6988SÁlvaro Fernández Rojas }
318*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_receive(struct dma * dma,void ** dst,void * metadata)319*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_receive(struct dma *dma, void **dst, void *metadata)
320*ccfd6988SÁlvaro Fernández Rojas {
321*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
322*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_hw *hw = priv->hw;
323*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
324*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_dma_desc *dma_desc = dma_desc = ch_priv->dma_ring;
325*ccfd6988SÁlvaro Fernández Rojas 	int ret;
326*ccfd6988SÁlvaro Fernández Rojas 
327*ccfd6988SÁlvaro Fernández Rojas 	/* get dma ring descriptor address */
328*ccfd6988SÁlvaro Fernández Rojas 	dma_desc += ch_priv->desc_id;
329*ccfd6988SÁlvaro Fernández Rojas 
330*ccfd6988SÁlvaro Fernández Rojas 	/* invalidate cache data */
331*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_idc(dma_desc, sizeof(*dma_desc));
332*ccfd6988SÁlvaro Fernández Rojas 
333*ccfd6988SÁlvaro Fernández Rojas 	/* check dma own */
334*ccfd6988SÁlvaro Fernández Rojas 	if (dma_desc->status & DMAD_ST_OWN_MASK)
335*ccfd6988SÁlvaro Fernández Rojas 		return -EAGAIN;
336*ccfd6988SÁlvaro Fernández Rojas 
337*ccfd6988SÁlvaro Fernández Rojas 	/* check pkt */
338*ccfd6988SÁlvaro Fernández Rojas 	if (!(dma_desc->status & DMAD_ST_EOP_MASK) ||
339*ccfd6988SÁlvaro Fernández Rojas 	    !(dma_desc->status & DMAD_ST_SOP_MASK) ||
340*ccfd6988SÁlvaro Fernández Rojas 	    (dma_desc->status & hw->err_mask)) {
341*ccfd6988SÁlvaro Fernández Rojas 		pr_err("invalid pkt received (ch=%ld desc=%u) (st=%04x)\n",
342*ccfd6988SÁlvaro Fernández Rojas 		       dma->id, ch_priv->desc_id, dma_desc->status);
343*ccfd6988SÁlvaro Fernández Rojas 		ret = -EAGAIN;
344*ccfd6988SÁlvaro Fernández Rojas 	} else {
345*ccfd6988SÁlvaro Fernández Rojas 		/* set dma buffer address */
346*ccfd6988SÁlvaro Fernández Rojas 		*dst = phys_to_virt(dma_desc->address);
347*ccfd6988SÁlvaro Fernández Rojas 
348*ccfd6988SÁlvaro Fernández Rojas 		/* invalidate cache data */
349*ccfd6988SÁlvaro Fernández Rojas 		bcm6348_iudma_idc(*dst, dma_desc->length);
350*ccfd6988SÁlvaro Fernández Rojas 
351*ccfd6988SÁlvaro Fernández Rojas 		/* return packet length */
352*ccfd6988SÁlvaro Fernández Rojas 		ret = dma_desc->length;
353*ccfd6988SÁlvaro Fernández Rojas 	}
354*ccfd6988SÁlvaro Fernández Rojas 
355*ccfd6988SÁlvaro Fernández Rojas 	/* busy dma descriptor */
356*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->busy_desc[ch_priv->desc_id] = true;
357*ccfd6988SÁlvaro Fernández Rojas 
358*ccfd6988SÁlvaro Fernández Rojas 	/* increment dma descriptor */
359*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->desc_cnt;
360*ccfd6988SÁlvaro Fernández Rojas 
361*ccfd6988SÁlvaro Fernández Rojas 	return ret;
362*ccfd6988SÁlvaro Fernández Rojas }
363*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_send(struct dma * dma,void * src,size_t len,void * metadata)364*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len,
365*ccfd6988SÁlvaro Fernández Rojas 			      void *metadata)
366*ccfd6988SÁlvaro Fernández Rojas {
367*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
368*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
369*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_dma_desc *dma_desc;
370*ccfd6988SÁlvaro Fernández Rojas 	uint16_t status;
371*ccfd6988SÁlvaro Fernández Rojas 
372*ccfd6988SÁlvaro Fernández Rojas 	/* flush cache */
373*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_fdc(src, len);
374*ccfd6988SÁlvaro Fernández Rojas 
375*ccfd6988SÁlvaro Fernández Rojas 	/* get dma ring descriptor address */
376*ccfd6988SÁlvaro Fernández Rojas 	dma_desc = ch_priv->dma_ring;
377*ccfd6988SÁlvaro Fernández Rojas 	dma_desc += ch_priv->desc_id;
378*ccfd6988SÁlvaro Fernández Rojas 
379*ccfd6988SÁlvaro Fernández Rojas 	/* config dma descriptor */
380*ccfd6988SÁlvaro Fernández Rojas 	status = (DMAD_ST_OWN_MASK |
381*ccfd6988SÁlvaro Fernández Rojas 		  DMAD_ST_EOP_MASK |
382*ccfd6988SÁlvaro Fernández Rojas 		  DMAD_ST_CRC_MASK |
383*ccfd6988SÁlvaro Fernández Rojas 		  DMAD_ST_SOP_MASK);
384*ccfd6988SÁlvaro Fernández Rojas 	if (ch_priv->desc_id == ch_priv->desc_cnt - 1)
385*ccfd6988SÁlvaro Fernández Rojas 		status |= DMAD_ST_WRAP_MASK;
386*ccfd6988SÁlvaro Fernández Rojas 
387*ccfd6988SÁlvaro Fernández Rojas 	/* set dma descriptor */
388*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->address = virt_to_phys(src);
389*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->length = len;
390*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->status = status;
391*ccfd6988SÁlvaro Fernández Rojas 
392*ccfd6988SÁlvaro Fernández Rojas 	/* flush cache */
393*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_fdc(dma_desc, sizeof(*dma_desc));
394*ccfd6988SÁlvaro Fernández Rojas 
395*ccfd6988SÁlvaro Fernández Rojas 	/* kick tx dma channel */
396*ccfd6988SÁlvaro Fernández Rojas 	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
397*ccfd6988SÁlvaro Fernández Rojas 
398*ccfd6988SÁlvaro Fernández Rojas 	/* poll dma status */
399*ccfd6988SÁlvaro Fernández Rojas 	do {
400*ccfd6988SÁlvaro Fernández Rojas 		/* invalidate cache */
401*ccfd6988SÁlvaro Fernández Rojas 		bcm6348_iudma_idc(dma_desc, sizeof(*dma_desc));
402*ccfd6988SÁlvaro Fernández Rojas 
403*ccfd6988SÁlvaro Fernández Rojas 		if (!(dma_desc->status & DMAD_ST_OWN_MASK))
404*ccfd6988SÁlvaro Fernández Rojas 			break;
405*ccfd6988SÁlvaro Fernández Rojas 	} while(1);
406*ccfd6988SÁlvaro Fernández Rojas 
407*ccfd6988SÁlvaro Fernández Rojas 	/* increment dma descriptor */
408*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->desc_cnt;
409*ccfd6988SÁlvaro Fernández Rojas 
410*ccfd6988SÁlvaro Fernández Rojas 	return 0;
411*ccfd6988SÁlvaro Fernández Rojas }
412*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_free_rcv_buf(struct dma * dma,void * dst,size_t size)413*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_free_rcv_buf(struct dma *dma, void *dst, size_t size)
414*ccfd6988SÁlvaro Fernández Rojas {
415*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
416*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
417*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_dma_desc *dma_desc = ch_priv->dma_ring;
418*ccfd6988SÁlvaro Fernández Rojas 	uint16_t status;
419*ccfd6988SÁlvaro Fernández Rojas 	uint8_t i;
420*ccfd6988SÁlvaro Fernández Rojas 	u32 cfg;
421*ccfd6988SÁlvaro Fernández Rojas 
422*ccfd6988SÁlvaro Fernández Rojas 	/* get dirty dma descriptor */
423*ccfd6988SÁlvaro Fernández Rojas 	for (i = 0; i < ch_priv->desc_cnt; i++) {
424*ccfd6988SÁlvaro Fernández Rojas 		if (phys_to_virt(dma_desc->address) == dst)
425*ccfd6988SÁlvaro Fernández Rojas 			break;
426*ccfd6988SÁlvaro Fernández Rojas 
427*ccfd6988SÁlvaro Fernández Rojas 		dma_desc++;
428*ccfd6988SÁlvaro Fernández Rojas 	}
429*ccfd6988SÁlvaro Fernández Rojas 
430*ccfd6988SÁlvaro Fernández Rojas 	/* dma descriptor not found */
431*ccfd6988SÁlvaro Fernández Rojas 	if (i == ch_priv->desc_cnt) {
432*ccfd6988SÁlvaro Fernández Rojas 		pr_err("dirty dma descriptor not found\n");
433*ccfd6988SÁlvaro Fernández Rojas 		return -ENOENT;
434*ccfd6988SÁlvaro Fernández Rojas 	}
435*ccfd6988SÁlvaro Fernández Rojas 
436*ccfd6988SÁlvaro Fernández Rojas 	/* invalidate cache */
437*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_idc(ch_priv->dma_ring,
438*ccfd6988SÁlvaro Fernández Rojas 			  sizeof(*dma_desc) * ch_priv->desc_cnt);
439*ccfd6988SÁlvaro Fernández Rojas 
440*ccfd6988SÁlvaro Fernández Rojas 	/* free dma descriptor */
441*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->busy_desc[i] = false;
442*ccfd6988SÁlvaro Fernández Rojas 
443*ccfd6988SÁlvaro Fernández Rojas 	status = DMAD_ST_OWN_MASK;
444*ccfd6988SÁlvaro Fernández Rojas 	if (i == ch_priv->desc_cnt - 1)
445*ccfd6988SÁlvaro Fernández Rojas 		status |= DMAD_ST_WRAP_MASK;
446*ccfd6988SÁlvaro Fernández Rojas 
447*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->status |= status;
448*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->length = PKTSIZE_ALIGN;
449*ccfd6988SÁlvaro Fernández Rojas 
450*ccfd6988SÁlvaro Fernández Rojas 	/* tell dma we allocated one buffer */
451*ccfd6988SÁlvaro Fernández Rojas 	writel_be(1, DMA_FLOWC_ALLOC_REG(dma->id));
452*ccfd6988SÁlvaro Fernández Rojas 
453*ccfd6988SÁlvaro Fernández Rojas 	/* flush cache */
454*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_fdc(ch_priv->dma_ring,
455*ccfd6988SÁlvaro Fernández Rojas 			  sizeof(*dma_desc) * ch_priv->desc_cnt);
456*ccfd6988SÁlvaro Fernández Rojas 
457*ccfd6988SÁlvaro Fernández Rojas 	/* kick rx dma channel if disabled */
458*ccfd6988SÁlvaro Fernández Rojas 	cfg = readl_be(priv->chan + DMAC_CFG_REG(dma->id));
459*ccfd6988SÁlvaro Fernández Rojas 	if (!(cfg & DMAC_CFG_ENABLE_MASK))
460*ccfd6988SÁlvaro Fernández Rojas 		setbits_be32(priv->chan + DMAC_CFG_REG(dma->id),
461*ccfd6988SÁlvaro Fernández Rojas 			     DMAC_CFG_ENABLE_MASK);
462*ccfd6988SÁlvaro Fernández Rojas 
463*ccfd6988SÁlvaro Fernández Rojas 	return 0;
464*ccfd6988SÁlvaro Fernández Rojas }
465*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_add_rcv_buf(struct dma * dma,void * dst,size_t size)466*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_add_rcv_buf(struct dma *dma, void *dst, size_t size)
467*ccfd6988SÁlvaro Fernández Rojas {
468*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
469*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
470*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_dma_desc *dma_desc = ch_priv->dma_ring;
471*ccfd6988SÁlvaro Fernández Rojas 
472*ccfd6988SÁlvaro Fernández Rojas 	/* no more dma descriptors available */
473*ccfd6988SÁlvaro Fernández Rojas 	if (ch_priv->desc_cnt == ch_priv->dma_ring_size) {
474*ccfd6988SÁlvaro Fernández Rojas 		pr_err("max number of buffers reached\n");
475*ccfd6988SÁlvaro Fernández Rojas 		return -EINVAL;
476*ccfd6988SÁlvaro Fernández Rojas 	}
477*ccfd6988SÁlvaro Fernández Rojas 
478*ccfd6988SÁlvaro Fernández Rojas 	/* get next dma descriptor */
479*ccfd6988SÁlvaro Fernández Rojas 	dma_desc += ch_priv->desc_cnt;
480*ccfd6988SÁlvaro Fernández Rojas 
481*ccfd6988SÁlvaro Fernández Rojas 	/* init dma descriptor */
482*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->address = virt_to_phys(dst);
483*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->length = size;
484*ccfd6988SÁlvaro Fernández Rojas 	dma_desc->status = 0;
485*ccfd6988SÁlvaro Fernández Rojas 
486*ccfd6988SÁlvaro Fernández Rojas 	/* flush cache */
487*ccfd6988SÁlvaro Fernández Rojas 	bcm6348_iudma_fdc(dma_desc, sizeof(*dma_desc));
488*ccfd6988SÁlvaro Fernández Rojas 
489*ccfd6988SÁlvaro Fernández Rojas 	/* increment dma descriptors */
490*ccfd6988SÁlvaro Fernández Rojas 	ch_priv->desc_cnt++;
491*ccfd6988SÁlvaro Fernández Rojas 
492*ccfd6988SÁlvaro Fernández Rojas 	return 0;
493*ccfd6988SÁlvaro Fernández Rojas }
494*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_prepare_rcv_buf(struct dma * dma,void * dst,size_t size)495*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_prepare_rcv_buf(struct dma *dma, void *dst,
496*ccfd6988SÁlvaro Fernández Rojas 					 size_t size)
497*ccfd6988SÁlvaro Fernández Rojas {
498*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
499*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
500*ccfd6988SÁlvaro Fernández Rojas 
501*ccfd6988SÁlvaro Fernández Rojas 	/* only add new rx buffers if channel isn't running */
502*ccfd6988SÁlvaro Fernández Rojas 	if (ch_priv->running)
503*ccfd6988SÁlvaro Fernández Rojas 		return bcm6348_iudma_free_rcv_buf(dma, dst, size);
504*ccfd6988SÁlvaro Fernández Rojas 	else
505*ccfd6988SÁlvaro Fernández Rojas 		return bcm6348_iudma_add_rcv_buf(dma, dst, size);
506*ccfd6988SÁlvaro Fernández Rojas }
507*ccfd6988SÁlvaro Fernández Rojas 
508*ccfd6988SÁlvaro Fernández Rojas static const struct dma_ops bcm6348_iudma_ops = {
509*ccfd6988SÁlvaro Fernández Rojas 	.disable = bcm6348_iudma_disable,
510*ccfd6988SÁlvaro Fernández Rojas 	.enable = bcm6348_iudma_enable,
511*ccfd6988SÁlvaro Fernández Rojas 	.prepare_rcv_buf = bcm6348_iudma_prepare_rcv_buf,
512*ccfd6988SÁlvaro Fernández Rojas 	.request = bcm6348_iudma_request,
513*ccfd6988SÁlvaro Fernández Rojas 	.receive = bcm6348_iudma_receive,
514*ccfd6988SÁlvaro Fernández Rojas 	.send = bcm6348_iudma_send,
515*ccfd6988SÁlvaro Fernández Rojas };
516*ccfd6988SÁlvaro Fernández Rojas 
517*ccfd6988SÁlvaro Fernández Rojas static const struct bcm6348_iudma_hw bcm6348_hw = {
518*ccfd6988SÁlvaro Fernández Rojas 	.err_mask = (DMAD6348_ST_OV_ERR_MASK |
519*ccfd6988SÁlvaro Fernández Rojas 		     DMAD6348_ST_CRC_ERR_MASK |
520*ccfd6988SÁlvaro Fernández Rojas 		     DMAD6348_ST_RX_ERR_MASK |
521*ccfd6988SÁlvaro Fernández Rojas 		     DMAD6348_ST_OS_ERR_MASK |
522*ccfd6988SÁlvaro Fernández Rojas 		     DMAD6348_ST_UN_ERR_MASK),
523*ccfd6988SÁlvaro Fernández Rojas };
524*ccfd6988SÁlvaro Fernández Rojas 
525*ccfd6988SÁlvaro Fernández Rojas static const struct bcm6348_iudma_hw bcm6368_hw = {
526*ccfd6988SÁlvaro Fernández Rojas 	.err_mask = 0,
527*ccfd6988SÁlvaro Fernández Rojas };
528*ccfd6988SÁlvaro Fernández Rojas 
529*ccfd6988SÁlvaro Fernández Rojas static const struct udevice_id bcm6348_iudma_ids[] = {
530*ccfd6988SÁlvaro Fernández Rojas 	{
531*ccfd6988SÁlvaro Fernández Rojas 		.compatible = "brcm,bcm6348-iudma",
532*ccfd6988SÁlvaro Fernández Rojas 		.data = (ulong)&bcm6348_hw,
533*ccfd6988SÁlvaro Fernández Rojas 	}, {
534*ccfd6988SÁlvaro Fernández Rojas 		.compatible = "brcm,bcm6368-iudma",
535*ccfd6988SÁlvaro Fernández Rojas 		.data = (ulong)&bcm6368_hw,
536*ccfd6988SÁlvaro Fernández Rojas 	}, { /* sentinel */ }
537*ccfd6988SÁlvaro Fernández Rojas };
538*ccfd6988SÁlvaro Fernández Rojas 
bcm6348_iudma_probe(struct udevice * dev)539*ccfd6988SÁlvaro Fernández Rojas static int bcm6348_iudma_probe(struct udevice *dev)
540*ccfd6988SÁlvaro Fernández Rojas {
541*ccfd6988SÁlvaro Fernández Rojas 	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
542*ccfd6988SÁlvaro Fernández Rojas 	struct bcm6348_iudma_priv *priv = dev_get_priv(dev);
543*ccfd6988SÁlvaro Fernández Rojas 	const struct bcm6348_iudma_hw *hw =
544*ccfd6988SÁlvaro Fernández Rojas 		(const struct bcm6348_iudma_hw *)dev_get_driver_data(dev);
545*ccfd6988SÁlvaro Fernández Rojas 	uint8_t ch;
546*ccfd6988SÁlvaro Fernández Rojas 	int i;
547*ccfd6988SÁlvaro Fernández Rojas 
548*ccfd6988SÁlvaro Fernández Rojas 	uc_priv->supported = (DMA_SUPPORTS_DEV_TO_MEM |
549*ccfd6988SÁlvaro Fernández Rojas 			      DMA_SUPPORTS_MEM_TO_DEV);
550*ccfd6988SÁlvaro Fernández Rojas 	priv->hw = hw;
551*ccfd6988SÁlvaro Fernández Rojas 
552*ccfd6988SÁlvaro Fernández Rojas 	/* dma global base address */
553*ccfd6988SÁlvaro Fernández Rojas 	priv->base = dev_remap_addr_name(dev, "dma");
554*ccfd6988SÁlvaro Fernández Rojas 	if (!priv->base)
555*ccfd6988SÁlvaro Fernández Rojas 		return -EINVAL;
556*ccfd6988SÁlvaro Fernández Rojas 
557*ccfd6988SÁlvaro Fernández Rojas 	/* dma channels base address */
558*ccfd6988SÁlvaro Fernández Rojas 	priv->chan = dev_remap_addr_name(dev, "dma-channels");
559*ccfd6988SÁlvaro Fernández Rojas 	if (!priv->chan)
560*ccfd6988SÁlvaro Fernández Rojas 		return -EINVAL;
561*ccfd6988SÁlvaro Fernández Rojas 
562*ccfd6988SÁlvaro Fernández Rojas 	/* dma sram base address */
563*ccfd6988SÁlvaro Fernández Rojas 	priv->sram = dev_remap_addr_name(dev, "dma-sram");
564*ccfd6988SÁlvaro Fernández Rojas 	if (!priv->sram)
565*ccfd6988SÁlvaro Fernández Rojas 		return -EINVAL;
566*ccfd6988SÁlvaro Fernández Rojas 
567*ccfd6988SÁlvaro Fernández Rojas 	/* get number of channels */
568*ccfd6988SÁlvaro Fernández Rojas 	priv->n_channels = dev_read_u32_default(dev, "dma-channels", 8);
569*ccfd6988SÁlvaro Fernández Rojas 	if (priv->n_channels > DMA_CHAN_MAX)
570*ccfd6988SÁlvaro Fernández Rojas 		return -EINVAL;
571*ccfd6988SÁlvaro Fernández Rojas 
572*ccfd6988SÁlvaro Fernández Rojas 	/* try to enable clocks */
573*ccfd6988SÁlvaro Fernández Rojas 	for (i = 0; ; i++) {
574*ccfd6988SÁlvaro Fernández Rojas 		struct clk clk;
575*ccfd6988SÁlvaro Fernández Rojas 		int ret;
576*ccfd6988SÁlvaro Fernández Rojas 
577*ccfd6988SÁlvaro Fernández Rojas 		ret = clk_get_by_index(dev, i, &clk);
578*ccfd6988SÁlvaro Fernández Rojas 		if (ret < 0)
579*ccfd6988SÁlvaro Fernández Rojas 			break;
580*ccfd6988SÁlvaro Fernández Rojas 
581*ccfd6988SÁlvaro Fernández Rojas 		ret = clk_enable(&clk);
582*ccfd6988SÁlvaro Fernández Rojas 		if (ret < 0) {
583*ccfd6988SÁlvaro Fernández Rojas 			pr_err("error enabling clock %d\n", i);
584*ccfd6988SÁlvaro Fernández Rojas 			return ret;
585*ccfd6988SÁlvaro Fernández Rojas 		}
586*ccfd6988SÁlvaro Fernández Rojas 
587*ccfd6988SÁlvaro Fernández Rojas 		ret = clk_free(&clk);
588*ccfd6988SÁlvaro Fernández Rojas 		if (ret < 0) {
589*ccfd6988SÁlvaro Fernández Rojas 			pr_err("error freeing clock %d\n", i);
590*ccfd6988SÁlvaro Fernández Rojas 			return ret;
591*ccfd6988SÁlvaro Fernández Rojas 		}
592*ccfd6988SÁlvaro Fernández Rojas 	}
593*ccfd6988SÁlvaro Fernández Rojas 
594*ccfd6988SÁlvaro Fernández Rojas 	/* try to perform resets */
595*ccfd6988SÁlvaro Fernández Rojas 	for (i = 0; ; i++) {
596*ccfd6988SÁlvaro Fernández Rojas 		struct reset_ctl reset;
597*ccfd6988SÁlvaro Fernández Rojas 		int ret;
598*ccfd6988SÁlvaro Fernández Rojas 
599*ccfd6988SÁlvaro Fernández Rojas 		ret = reset_get_by_index(dev, i, &reset);
600*ccfd6988SÁlvaro Fernández Rojas 		if (ret < 0)
601*ccfd6988SÁlvaro Fernández Rojas 			break;
602*ccfd6988SÁlvaro Fernández Rojas 
603*ccfd6988SÁlvaro Fernández Rojas 		ret = reset_deassert(&reset);
604*ccfd6988SÁlvaro Fernández Rojas 		if (ret < 0) {
605*ccfd6988SÁlvaro Fernández Rojas 			pr_err("error deasserting reset %d\n", i);
606*ccfd6988SÁlvaro Fernández Rojas 			return ret;
607*ccfd6988SÁlvaro Fernández Rojas 		}
608*ccfd6988SÁlvaro Fernández Rojas 
609*ccfd6988SÁlvaro Fernández Rojas 		ret = reset_free(&reset);
610*ccfd6988SÁlvaro Fernández Rojas 		if (ret < 0) {
611*ccfd6988SÁlvaro Fernández Rojas 			pr_err("error freeing reset %d\n", i);
612*ccfd6988SÁlvaro Fernández Rojas 			return ret;
613*ccfd6988SÁlvaro Fernández Rojas 		}
614*ccfd6988SÁlvaro Fernández Rojas 	}
615*ccfd6988SÁlvaro Fernández Rojas 
616*ccfd6988SÁlvaro Fernández Rojas 	/* disable dma controller */
617*ccfd6988SÁlvaro Fernández Rojas 	clrbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
618*ccfd6988SÁlvaro Fernández Rojas 
619*ccfd6988SÁlvaro Fernández Rojas 	/* alloc channel private data pointers */
620*ccfd6988SÁlvaro Fernández Rojas 	priv->ch_priv = calloc(priv->n_channels,
621*ccfd6988SÁlvaro Fernández Rojas 			       sizeof(struct bcm6348_chan_priv*));
622*ccfd6988SÁlvaro Fernández Rojas 	if (!priv->ch_priv)
623*ccfd6988SÁlvaro Fernández Rojas 		return -ENOMEM;
624*ccfd6988SÁlvaro Fernández Rojas 
625*ccfd6988SÁlvaro Fernández Rojas 	/* stop dma channels */
626*ccfd6988SÁlvaro Fernández Rojas 	for (ch = 0; ch < priv->n_channels; ch++)
627*ccfd6988SÁlvaro Fernández Rojas 		bcm6348_iudma_chan_stop(priv, ch);
628*ccfd6988SÁlvaro Fernández Rojas 
629*ccfd6988SÁlvaro Fernández Rojas 	/* enable dma controller */
630*ccfd6988SÁlvaro Fernández Rojas 	setbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
631*ccfd6988SÁlvaro Fernández Rojas 
632*ccfd6988SÁlvaro Fernández Rojas 	return 0;
633*ccfd6988SÁlvaro Fernández Rojas }
634*ccfd6988SÁlvaro Fernández Rojas 
635*ccfd6988SÁlvaro Fernández Rojas U_BOOT_DRIVER(bcm6348_iudma) = {
636*ccfd6988SÁlvaro Fernández Rojas 	.name = "bcm6348_iudma",
637*ccfd6988SÁlvaro Fernández Rojas 	.id = UCLASS_DMA,
638*ccfd6988SÁlvaro Fernández Rojas 	.of_match = bcm6348_iudma_ids,
639*ccfd6988SÁlvaro Fernández Rojas 	.ops = &bcm6348_iudma_ops,
640*ccfd6988SÁlvaro Fernández Rojas 	.priv_auto_alloc_size = sizeof(struct bcm6348_iudma_priv),
641*ccfd6988SÁlvaro Fernández Rojas 	.probe = bcm6348_iudma_probe,
642*ccfd6988SÁlvaro Fernández Rojas };
643