xref: /rk3399_rockchip-uboot/drivers/dma/ti-edma3.c (revision 664ab2c992d1e06c4381f66c93d2e155fc7722e1)
1e165b1d3SKhoronzhuk, Ivan /*
2e165b1d3SKhoronzhuk, Ivan  * Enhanced Direct Memory Access (EDMA3) Controller
3e165b1d3SKhoronzhuk, Ivan  *
4e165b1d3SKhoronzhuk, Ivan  * (C) Copyright 2014
5e165b1d3SKhoronzhuk, Ivan  *     Texas Instruments Incorporated, <www.ti.com>
6e165b1d3SKhoronzhuk, Ivan  *
7e165b1d3SKhoronzhuk, Ivan  * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
8e165b1d3SKhoronzhuk, Ivan  *
9e165b1d3SKhoronzhuk, Ivan  * SPDX-License-Identifier:     GPL-2.0+
10e165b1d3SKhoronzhuk, Ivan  */
11e165b1d3SKhoronzhuk, Ivan 
12e165b1d3SKhoronzhuk, Ivan #include <asm/io.h>
13e165b1d3SKhoronzhuk, Ivan #include <common.h>
14e165b1d3SKhoronzhuk, Ivan #include <asm/ti-common/ti-edma3.h>
15e165b1d3SKhoronzhuk, Ivan 
16e165b1d3SKhoronzhuk, Ivan #define EDMA3_SL_BASE(slot)			(0x4000 + ((slot) << 5))
17e165b1d3SKhoronzhuk, Ivan #define EDMA3_SL_MAX_NUM			512
18e165b1d3SKhoronzhuk, Ivan #define EDMA3_SLOPT_FIFO_WIDTH_MASK		(0x7 << 8)
19e165b1d3SKhoronzhuk, Ivan 
20e165b1d3SKhoronzhuk, Ivan #define EDMA3_QCHMAP(ch)			0x0200 + ((ch) << 2)
21e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_PARSET_MASK			0x1ff
22e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_PARSET_SHIFT		0x5
23e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_TRIGWORD_SHIFT		0x2
24e165b1d3SKhoronzhuk, Ivan 
25e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEMCR				0x314
26e165b1d3SKhoronzhuk, Ivan #define EDMA3_IPR				0x1068
27e165b1d3SKhoronzhuk, Ivan #define EDMA3_IPRH				0x106c
28e165b1d3SKhoronzhuk, Ivan #define EDMA3_ICR				0x1070
29e165b1d3SKhoronzhuk, Ivan #define EDMA3_ICRH				0x1074
30e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEECR				0x1088
31e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEESR				0x108c
32e165b1d3SKhoronzhuk, Ivan #define EDMA3_QSECR				0x1094
33e165b1d3SKhoronzhuk, Ivan 
34e165b1d3SKhoronzhuk, Ivan /**
35e165b1d3SKhoronzhuk, Ivan  * qedma3_start - start qdma on a channel
36e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
37e165b1d3SKhoronzhuk, Ivan  * @cfg: pinter to struct edma3_channel_config where you can set
38e165b1d3SKhoronzhuk, Ivan  * the slot number to associate with, the chnum, which corresponds
39e165b1d3SKhoronzhuk, Ivan  * your quick channel number 0-7, complete code - transfer complete code
40e165b1d3SKhoronzhuk, Ivan  * and trigger slot word - which has to correspond to the word number in
41e165b1d3SKhoronzhuk, Ivan  * edma3_slot_layout struct for generating event.
42e165b1d3SKhoronzhuk, Ivan  *
43e165b1d3SKhoronzhuk, Ivan  */
44e165b1d3SKhoronzhuk, Ivan void qedma3_start(u32 base, struct edma3_channel_config *cfg)
45e165b1d3SKhoronzhuk, Ivan {
46e165b1d3SKhoronzhuk, Ivan 	u32 qchmap;
47e165b1d3SKhoronzhuk, Ivan 
48e165b1d3SKhoronzhuk, Ivan 	/* Clear the pending int bit */
49e165b1d3SKhoronzhuk, Ivan 	if (cfg->complete_code < 32)
50e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
51e165b1d3SKhoronzhuk, Ivan 	else
52e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
53e165b1d3SKhoronzhuk, Ivan 
54e165b1d3SKhoronzhuk, Ivan 	/* Map parameter set and trigger word 7 to quick channel */
55e165b1d3SKhoronzhuk, Ivan 	qchmap = ((EDMA3_CHMAP_PARSET_MASK & cfg->slot)
56e165b1d3SKhoronzhuk, Ivan 		  << EDMA3_CHMAP_PARSET_SHIFT) |
57e165b1d3SKhoronzhuk, Ivan 		  (cfg->trigger_slot_word << EDMA3_CHMAP_TRIGWORD_SHIFT);
58e165b1d3SKhoronzhuk, Ivan 
59e165b1d3SKhoronzhuk, Ivan 	__raw_writel(qchmap, base + EDMA3_QCHMAP(cfg->chnum));
60e165b1d3SKhoronzhuk, Ivan 
61e165b1d3SKhoronzhuk, Ivan 	/* Clear missed event if set*/
62e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
63e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
64e165b1d3SKhoronzhuk, Ivan 
65e165b1d3SKhoronzhuk, Ivan 	/* Enable qdma channel event */
66e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEESR);
67e165b1d3SKhoronzhuk, Ivan }
68e165b1d3SKhoronzhuk, Ivan 
69e165b1d3SKhoronzhuk, Ivan /**
70e165b1d3SKhoronzhuk, Ivan  * edma3_set_dest - set initial DMA destination address in parameter RAM slot
71e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
72e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
73e165b1d3SKhoronzhuk, Ivan  * @dst: physical address of destination (memory, controller FIFO, etc)
74e165b1d3SKhoronzhuk, Ivan  * @addressMode: INCR, except in very rare cases
75e165b1d3SKhoronzhuk, Ivan  * @width: ignored unless @addressMode is FIFO, else specifies the
76e165b1d3SKhoronzhuk, Ivan  *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
77e165b1d3SKhoronzhuk, Ivan  *
78e165b1d3SKhoronzhuk, Ivan  * Note that the destination address is modified during the DMA transfer
79e165b1d3SKhoronzhuk, Ivan  * according to edma3_set_dest_index().
80e165b1d3SKhoronzhuk, Ivan  */
81e165b1d3SKhoronzhuk, Ivan void edma3_set_dest(u32 base, int slot, u32 dst, enum edma3_address_mode mode,
82e165b1d3SKhoronzhuk, Ivan 		    enum edma3_fifo_width width)
83e165b1d3SKhoronzhuk, Ivan {
84e165b1d3SKhoronzhuk, Ivan 	u32 opt;
85e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
86e165b1d3SKhoronzhuk, Ivan 
87e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
88e165b1d3SKhoronzhuk, Ivan 
89e165b1d3SKhoronzhuk, Ivan 	opt = __raw_readl(&rg->opt);
90e165b1d3SKhoronzhuk, Ivan 	if (mode == FIFO)
91e165b1d3SKhoronzhuk, Ivan 		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
92e165b1d3SKhoronzhuk, Ivan 		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
93e165b1d3SKhoronzhuk, Ivan 			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
94e165b1d3SKhoronzhuk, Ivan 	else
95e165b1d3SKhoronzhuk, Ivan 		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
96e165b1d3SKhoronzhuk, Ivan 
97e165b1d3SKhoronzhuk, Ivan 	__raw_writel(opt, &rg->opt);
98e165b1d3SKhoronzhuk, Ivan 	__raw_writel(dst, &rg->dst);
99e165b1d3SKhoronzhuk, Ivan }
100e165b1d3SKhoronzhuk, Ivan 
101e165b1d3SKhoronzhuk, Ivan /**
102e165b1d3SKhoronzhuk, Ivan  * edma3_set_dest_index - configure DMA destination address indexing
103e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
104e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
105e165b1d3SKhoronzhuk, Ivan  * @bidx: byte offset between destination arrays in a frame
106e165b1d3SKhoronzhuk, Ivan  * @cidx: byte offset between destination frames in a block
107e165b1d3SKhoronzhuk, Ivan  *
108e165b1d3SKhoronzhuk, Ivan  * Offsets are specified to support either contiguous or discontiguous
109e165b1d3SKhoronzhuk, Ivan  * memory transfers, or repeated access to a hardware register, as needed.
110e165b1d3SKhoronzhuk, Ivan  * When accessing hardware registers, both offsets are normally zero.
111e165b1d3SKhoronzhuk, Ivan  */
112e165b1d3SKhoronzhuk, Ivan void edma3_set_dest_index(u32 base, unsigned slot, int bidx, int cidx)
113e165b1d3SKhoronzhuk, Ivan {
114e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_bidx;
115e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_cidx;
116e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
117e165b1d3SKhoronzhuk, Ivan 
118e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
119e165b1d3SKhoronzhuk, Ivan 
120e165b1d3SKhoronzhuk, Ivan 	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
121e165b1d3SKhoronzhuk, Ivan 	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
122e165b1d3SKhoronzhuk, Ivan 
123e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_bidx & 0x0000ffff) | (bidx << 16),
124e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_bidx);
125e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_cidx & 0x0000ffff) | (cidx << 16),
126e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_cidx);
127e165b1d3SKhoronzhuk, Ivan }
128e165b1d3SKhoronzhuk, Ivan 
129e165b1d3SKhoronzhuk, Ivan /**
130e165b1d3SKhoronzhuk, Ivan  * edma3_set_dest_addr - set destination address for slot only
131e165b1d3SKhoronzhuk, Ivan  */
132e165b1d3SKhoronzhuk, Ivan void edma3_set_dest_addr(u32 base, int slot, u32 dst)
133e165b1d3SKhoronzhuk, Ivan {
134e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
135e165b1d3SKhoronzhuk, Ivan 
136e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
137e165b1d3SKhoronzhuk, Ivan 	__raw_writel(dst, &rg->dst);
138e165b1d3SKhoronzhuk, Ivan }
139e165b1d3SKhoronzhuk, Ivan 
140e165b1d3SKhoronzhuk, Ivan /**
141e165b1d3SKhoronzhuk, Ivan  * edma3_set_src - set initial DMA source address in parameter RAM slot
142e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
143e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
144e165b1d3SKhoronzhuk, Ivan  * @src_port: physical address of source (memory, controller FIFO, etc)
145e165b1d3SKhoronzhuk, Ivan  * @mode: INCR, except in very rare cases
146e165b1d3SKhoronzhuk, Ivan  * @width: ignored unless @addressMode is FIFO, else specifies the
147e165b1d3SKhoronzhuk, Ivan  *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
148e165b1d3SKhoronzhuk, Ivan  *
149e165b1d3SKhoronzhuk, Ivan  * Note that the source address is modified during the DMA transfer
150e165b1d3SKhoronzhuk, Ivan  * according to edma3_set_src_index().
151e165b1d3SKhoronzhuk, Ivan  */
152e165b1d3SKhoronzhuk, Ivan void edma3_set_src(u32 base, int slot, u32 src, enum edma3_address_mode mode,
153e165b1d3SKhoronzhuk, Ivan 		   enum edma3_fifo_width width)
154e165b1d3SKhoronzhuk, Ivan {
155e165b1d3SKhoronzhuk, Ivan 	u32 opt;
156e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
157e165b1d3SKhoronzhuk, Ivan 
158e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
159e165b1d3SKhoronzhuk, Ivan 
160e165b1d3SKhoronzhuk, Ivan 	opt = __raw_readl(&rg->opt);
161e165b1d3SKhoronzhuk, Ivan 	if (mode == FIFO)
162e165b1d3SKhoronzhuk, Ivan 		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
163e165b1d3SKhoronzhuk, Ivan 		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
164e165b1d3SKhoronzhuk, Ivan 			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
165e165b1d3SKhoronzhuk, Ivan 	else
166e165b1d3SKhoronzhuk, Ivan 		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
167e165b1d3SKhoronzhuk, Ivan 
168e165b1d3SKhoronzhuk, Ivan 	__raw_writel(opt, &rg->opt);
169e165b1d3SKhoronzhuk, Ivan 	__raw_writel(src, &rg->src);
170e165b1d3SKhoronzhuk, Ivan }
171e165b1d3SKhoronzhuk, Ivan 
172e165b1d3SKhoronzhuk, Ivan /**
173e165b1d3SKhoronzhuk, Ivan  * edma3_set_src_index - configure DMA source address indexing
174e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
175e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
176e165b1d3SKhoronzhuk, Ivan  * @bidx: byte offset between source arrays in a frame
177e165b1d3SKhoronzhuk, Ivan  * @cidx: byte offset between source frames in a block
178e165b1d3SKhoronzhuk, Ivan  *
179e165b1d3SKhoronzhuk, Ivan  * Offsets are specified to support either contiguous or discontiguous
180e165b1d3SKhoronzhuk, Ivan  * memory transfers, or repeated access to a hardware register, as needed.
181e165b1d3SKhoronzhuk, Ivan  * When accessing hardware registers, both offsets are normally zero.
182e165b1d3SKhoronzhuk, Ivan  */
183e165b1d3SKhoronzhuk, Ivan void edma3_set_src_index(u32 base, unsigned slot, int bidx, int cidx)
184e165b1d3SKhoronzhuk, Ivan {
185e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_bidx;
186e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_cidx;
187e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
188e165b1d3SKhoronzhuk, Ivan 
189e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
190e165b1d3SKhoronzhuk, Ivan 
191e165b1d3SKhoronzhuk, Ivan 	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
192e165b1d3SKhoronzhuk, Ivan 	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
193e165b1d3SKhoronzhuk, Ivan 
194e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_bidx & 0xffff0000) | bidx,
195e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_bidx);
196e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_cidx & 0xffff0000) | cidx,
197e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_cidx);
198e165b1d3SKhoronzhuk, Ivan }
199e165b1d3SKhoronzhuk, Ivan 
200e165b1d3SKhoronzhuk, Ivan /**
201e165b1d3SKhoronzhuk, Ivan  * edma3_set_src_addr - set source address for slot only
202e165b1d3SKhoronzhuk, Ivan  */
203e165b1d3SKhoronzhuk, Ivan void edma3_set_src_addr(u32 base, int slot, u32 src)
204e165b1d3SKhoronzhuk, Ivan {
205e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
206e165b1d3SKhoronzhuk, Ivan 
207e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
208e165b1d3SKhoronzhuk, Ivan 	__raw_writel(src, &rg->src);
209e165b1d3SKhoronzhuk, Ivan }
210e165b1d3SKhoronzhuk, Ivan 
211e165b1d3SKhoronzhuk, Ivan /**
212e165b1d3SKhoronzhuk, Ivan  * edma3_set_transfer_params - configure DMA transfer parameters
213e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
214e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
215e165b1d3SKhoronzhuk, Ivan  * @acnt: how many bytes per array (at least one)
216e165b1d3SKhoronzhuk, Ivan  * @bcnt: how many arrays per frame (at least one)
217e165b1d3SKhoronzhuk, Ivan  * @ccnt: how many frames per block (at least one)
218e165b1d3SKhoronzhuk, Ivan  * @bcnt_rld: used only for A-Synchronized transfers; this specifies
219e165b1d3SKhoronzhuk, Ivan  *	the value to reload into bcnt when it decrements to zero
220e165b1d3SKhoronzhuk, Ivan  * @sync_mode: ASYNC or ABSYNC
221e165b1d3SKhoronzhuk, Ivan  *
222e165b1d3SKhoronzhuk, Ivan  * See the EDMA3 documentation to understand how to configure and link
223e165b1d3SKhoronzhuk, Ivan  * transfers using the fields in PaRAM slots.  If you are not doing it
224e165b1d3SKhoronzhuk, Ivan  * all at once with edma3_write_slot(), you will use this routine
225e165b1d3SKhoronzhuk, Ivan  * plus two calls each for source and destination, setting the initial
226e165b1d3SKhoronzhuk, Ivan  * address and saying how to index that address.
227e165b1d3SKhoronzhuk, Ivan  *
228e165b1d3SKhoronzhuk, Ivan  * An example of an A-Synchronized transfer is a serial link using a
229e165b1d3SKhoronzhuk, Ivan  * single word shift register.  In that case, @acnt would be equal to
230e165b1d3SKhoronzhuk, Ivan  * that word size; the serial controller issues a DMA synchronization
231e165b1d3SKhoronzhuk, Ivan  * event to transfer each word, and memory access by the DMA transfer
232e165b1d3SKhoronzhuk, Ivan  * controller will be word-at-a-time.
233e165b1d3SKhoronzhuk, Ivan  *
234e165b1d3SKhoronzhuk, Ivan  * An example of an AB-Synchronized transfer is a device using a FIFO.
235e165b1d3SKhoronzhuk, Ivan  * In that case, @acnt equals the FIFO width and @bcnt equals its depth.
236e165b1d3SKhoronzhuk, Ivan  * The controller with the FIFO issues DMA synchronization events when
237e165b1d3SKhoronzhuk, Ivan  * the FIFO threshold is reached, and the DMA transfer controller will
238e165b1d3SKhoronzhuk, Ivan  * transfer one frame to (or from) the FIFO.  It will probably use
239e165b1d3SKhoronzhuk, Ivan  * efficient burst modes to access memory.
240e165b1d3SKhoronzhuk, Ivan  */
241e165b1d3SKhoronzhuk, Ivan void edma3_set_transfer_params(u32 base, int slot, int acnt,
242e165b1d3SKhoronzhuk, Ivan 			       int bcnt, int ccnt, u16 bcnt_rld,
243e165b1d3SKhoronzhuk, Ivan 			       enum edma3_sync_dimension sync_mode)
244e165b1d3SKhoronzhuk, Ivan {
245e165b1d3SKhoronzhuk, Ivan 	u32 opt;
246e165b1d3SKhoronzhuk, Ivan 	u32 link_bcntrld;
247e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
248e165b1d3SKhoronzhuk, Ivan 
249e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
250e165b1d3SKhoronzhuk, Ivan 
251e165b1d3SKhoronzhuk, Ivan 	link_bcntrld = __raw_readl(&rg->link_bcntrld);
252e165b1d3SKhoronzhuk, Ivan 
253e165b1d3SKhoronzhuk, Ivan 	__raw_writel((bcnt_rld << 16) | (0x0000ffff & link_bcntrld),
254e165b1d3SKhoronzhuk, Ivan 		     &rg->link_bcntrld);
255e165b1d3SKhoronzhuk, Ivan 
256e165b1d3SKhoronzhuk, Ivan 	opt = __raw_readl(&rg->opt);
257e165b1d3SKhoronzhuk, Ivan 	if (sync_mode == ASYNC)
258e165b1d3SKhoronzhuk, Ivan 		__raw_writel(opt & ~EDMA3_SLOPT_AB_SYNC, &rg->opt);
259e165b1d3SKhoronzhuk, Ivan 	else
260e165b1d3SKhoronzhuk, Ivan 		__raw_writel(opt | EDMA3_SLOPT_AB_SYNC, &rg->opt);
261e165b1d3SKhoronzhuk, Ivan 
262e165b1d3SKhoronzhuk, Ivan 	/* Set the acount, bcount, ccount registers */
263e165b1d3SKhoronzhuk, Ivan 	__raw_writel((bcnt << 16) | (acnt & 0xffff), &rg->a_b_cnt);
264e165b1d3SKhoronzhuk, Ivan 	__raw_writel(0xffff & ccnt, &rg->ccnt);
265e165b1d3SKhoronzhuk, Ivan }
266e165b1d3SKhoronzhuk, Ivan 
267e165b1d3SKhoronzhuk, Ivan /**
268e165b1d3SKhoronzhuk, Ivan  * edma3_write_slot - write parameter RAM data for slot
269e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
270e165b1d3SKhoronzhuk, Ivan  * @slot: number of parameter RAM slot being modified
271e165b1d3SKhoronzhuk, Ivan  * @param: data to be written into parameter RAM slot
272e165b1d3SKhoronzhuk, Ivan  *
273e165b1d3SKhoronzhuk, Ivan  * Use this to assign all parameters of a transfer at once.  This
274e165b1d3SKhoronzhuk, Ivan  * allows more efficient setup of transfers than issuing multiple
275e165b1d3SKhoronzhuk, Ivan  * calls to set up those parameters in small pieces, and provides
276e165b1d3SKhoronzhuk, Ivan  * complete control over all transfer options.
277e165b1d3SKhoronzhuk, Ivan  */
278e165b1d3SKhoronzhuk, Ivan void edma3_write_slot(u32 base, int slot, struct edma3_slot_layout *param)
279e165b1d3SKhoronzhuk, Ivan {
280e165b1d3SKhoronzhuk, Ivan 	int i;
281e165b1d3SKhoronzhuk, Ivan 	u32 *p = (u32 *)param;
282e165b1d3SKhoronzhuk, Ivan 	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
283e165b1d3SKhoronzhuk, Ivan 
284e165b1d3SKhoronzhuk, Ivan 	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
285e165b1d3SKhoronzhuk, Ivan 		__raw_writel(*p++, addr++);
286e165b1d3SKhoronzhuk, Ivan }
287e165b1d3SKhoronzhuk, Ivan 
288e165b1d3SKhoronzhuk, Ivan /**
289e165b1d3SKhoronzhuk, Ivan  * edma3_read_slot - read parameter RAM data from slot
290e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
291e165b1d3SKhoronzhuk, Ivan  * @slot: number of parameter RAM slot being copied
292e165b1d3SKhoronzhuk, Ivan  * @param: where to store copy of parameter RAM data
293e165b1d3SKhoronzhuk, Ivan  *
294e165b1d3SKhoronzhuk, Ivan  * Use this to read data from a parameter RAM slot, perhaps to
295e165b1d3SKhoronzhuk, Ivan  * save them as a template for later reuse.
296e165b1d3SKhoronzhuk, Ivan  */
297e165b1d3SKhoronzhuk, Ivan void edma3_read_slot(u32 base, int slot, struct edma3_slot_layout *param)
298e165b1d3SKhoronzhuk, Ivan {
299e165b1d3SKhoronzhuk, Ivan 	int i;
300e165b1d3SKhoronzhuk, Ivan 	u32 *p = (u32 *)param;
301e165b1d3SKhoronzhuk, Ivan 	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
302e165b1d3SKhoronzhuk, Ivan 
303e165b1d3SKhoronzhuk, Ivan 	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
304e165b1d3SKhoronzhuk, Ivan 		*p++ = __raw_readl(addr++);
305e165b1d3SKhoronzhuk, Ivan }
306e165b1d3SKhoronzhuk, Ivan 
307e165b1d3SKhoronzhuk, Ivan void edma3_slot_configure(u32 base, int slot, struct edma3_slot_config *cfg)
308e165b1d3SKhoronzhuk, Ivan {
309e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
310e165b1d3SKhoronzhuk, Ivan 
311e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
312e165b1d3SKhoronzhuk, Ivan 
313e165b1d3SKhoronzhuk, Ivan 	__raw_writel(cfg->opt, &rg->opt);
314e165b1d3SKhoronzhuk, Ivan 	__raw_writel(cfg->src, &rg->src);
315e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->bcnt << 16) | (cfg->acnt & 0xffff), &rg->a_b_cnt);
316e165b1d3SKhoronzhuk, Ivan 	__raw_writel(cfg->dst, &rg->dst);
317e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->dst_bidx << 16) |
318e165b1d3SKhoronzhuk, Ivan 		     (cfg->src_bidx & 0xffff), &rg->src_dst_bidx);
319e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->bcntrld << 16) |
320e165b1d3SKhoronzhuk, Ivan 		     (cfg->link & 0xffff), &rg->link_bcntrld);
321e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->dst_cidx << 16) |
322e165b1d3SKhoronzhuk, Ivan 		     (cfg->src_cidx & 0xffff), &rg->src_dst_cidx);
323e165b1d3SKhoronzhuk, Ivan 	__raw_writel(0xffff & cfg->ccnt, &rg->ccnt);
324e165b1d3SKhoronzhuk, Ivan }
325e165b1d3SKhoronzhuk, Ivan 
326e165b1d3SKhoronzhuk, Ivan /**
327e165b1d3SKhoronzhuk, Ivan  * edma3_check_for_transfer - check if transfer coplete by checking
328e165b1d3SKhoronzhuk, Ivan  * interrupt pending bit. Clear interrupt pending bit if complete.
329e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
330e165b1d3SKhoronzhuk, Ivan  * @cfg: pinter to struct edma3_channel_config which was passed
331e165b1d3SKhoronzhuk, Ivan  * to qedma3_start when you started qdma channel
332e165b1d3SKhoronzhuk, Ivan  *
333e165b1d3SKhoronzhuk, Ivan  * Return 0 if complete, 1 if not.
334e165b1d3SKhoronzhuk, Ivan  */
335e165b1d3SKhoronzhuk, Ivan int edma3_check_for_transfer(u32 base, struct edma3_channel_config *cfg)
336e165b1d3SKhoronzhuk, Ivan {
337e165b1d3SKhoronzhuk, Ivan 	u32 inum;
338e165b1d3SKhoronzhuk, Ivan 	u32 ipr_base;
339e165b1d3SKhoronzhuk, Ivan 	u32 icr_base;
340e165b1d3SKhoronzhuk, Ivan 
341e165b1d3SKhoronzhuk, Ivan 	if (cfg->complete_code < 32) {
342e165b1d3SKhoronzhuk, Ivan 		ipr_base = base + EDMA3_IPR;
343e165b1d3SKhoronzhuk, Ivan 		icr_base = base + EDMA3_ICR;
344e165b1d3SKhoronzhuk, Ivan 		inum = 1 << cfg->complete_code;
345e165b1d3SKhoronzhuk, Ivan 	} else {
346e165b1d3SKhoronzhuk, Ivan 		ipr_base = base + EDMA3_IPRH;
347e165b1d3SKhoronzhuk, Ivan 		icr_base = base + EDMA3_ICRH;
348e165b1d3SKhoronzhuk, Ivan 		inum = 1 << (cfg->complete_code - 32);
349e165b1d3SKhoronzhuk, Ivan 	}
350e165b1d3SKhoronzhuk, Ivan 
351e165b1d3SKhoronzhuk, Ivan 	/* check complete interrupt */
352e165b1d3SKhoronzhuk, Ivan 	if (!(__raw_readl(ipr_base) & inum))
353e165b1d3SKhoronzhuk, Ivan 		return 1;
354e165b1d3SKhoronzhuk, Ivan 
355e165b1d3SKhoronzhuk, Ivan 	/* clean up the pending int bit */
356e165b1d3SKhoronzhuk, Ivan 	__raw_writel(inum, icr_base);
357e165b1d3SKhoronzhuk, Ivan 
358e165b1d3SKhoronzhuk, Ivan 	return 0;
359e165b1d3SKhoronzhuk, Ivan }
360e165b1d3SKhoronzhuk, Ivan 
361e165b1d3SKhoronzhuk, Ivan /**
362e165b1d3SKhoronzhuk, Ivan  * qedma3_stop - stops dma on the channel passed
363e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
364e165b1d3SKhoronzhuk, Ivan  * @cfg: pinter to struct edma3_channel_config which was passed
365e165b1d3SKhoronzhuk, Ivan  * to qedma3_start when you started qdma channel
366e165b1d3SKhoronzhuk, Ivan  */
367e165b1d3SKhoronzhuk, Ivan void qedma3_stop(u32 base, struct edma3_channel_config *cfg)
368e165b1d3SKhoronzhuk, Ivan {
369e165b1d3SKhoronzhuk, Ivan 	/* Disable qdma channel event */
370e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEECR);
371e165b1d3SKhoronzhuk, Ivan 
372e165b1d3SKhoronzhuk, Ivan 	/* clean up the interrupt indication */
373e165b1d3SKhoronzhuk, Ivan 	if (cfg->complete_code < 32)
374e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
375e165b1d3SKhoronzhuk, Ivan 	else
376e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
377e165b1d3SKhoronzhuk, Ivan 
378e165b1d3SKhoronzhuk, Ivan 	/* Clear missed event if set*/
379e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
380e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
381e165b1d3SKhoronzhuk, Ivan 
382e165b1d3SKhoronzhuk, Ivan 	/* Clear the channel map */
383e165b1d3SKhoronzhuk, Ivan 	__raw_writel(0, base + EDMA3_QCHMAP(cfg->chnum));
384e165b1d3SKhoronzhuk, Ivan }
385*664ab2c9SVignesh R 
386*664ab2c9SVignesh R void edma3_transfer(unsigned long edma3_base_addr, unsigned int
387*664ab2c9SVignesh R 		    edma_slot_num, void *dst, void *src, size_t len)
388*664ab2c9SVignesh R {
389*664ab2c9SVignesh R 	struct edma3_slot_config        slot;
390*664ab2c9SVignesh R 	struct edma3_channel_config     edma_channel;
391*664ab2c9SVignesh R 	int                             b_cnt_value = 1;
392*664ab2c9SVignesh R 	int                             rem_bytes  = 0;
393*664ab2c9SVignesh R 	int                             a_cnt_value = len;
394*664ab2c9SVignesh R 	unsigned int                    addr = (unsigned int) (dst);
395*664ab2c9SVignesh R 	unsigned int                    max_acnt  = 0x7FFFU;
396*664ab2c9SVignesh R 
397*664ab2c9SVignesh R 	if (len > max_acnt) {
398*664ab2c9SVignesh R 		b_cnt_value = (len / max_acnt);
399*664ab2c9SVignesh R 		rem_bytes  = (len % max_acnt);
400*664ab2c9SVignesh R 		a_cnt_value = max_acnt;
401*664ab2c9SVignesh R 	}
402*664ab2c9SVignesh R 
403*664ab2c9SVignesh R 	slot.opt        = 0;
404*664ab2c9SVignesh R 	slot.src        = ((unsigned int) src);
405*664ab2c9SVignesh R 	slot.acnt       = a_cnt_value;
406*664ab2c9SVignesh R 	slot.bcnt       = b_cnt_value;
407*664ab2c9SVignesh R 	slot.ccnt       = 1;
408*664ab2c9SVignesh R 	slot.src_bidx   = a_cnt_value;
409*664ab2c9SVignesh R 	slot.dst_bidx   = a_cnt_value;
410*664ab2c9SVignesh R 	slot.src_cidx   = 0;
411*664ab2c9SVignesh R 	slot.dst_cidx   = 0;
412*664ab2c9SVignesh R 	slot.link       = EDMA3_PARSET_NULL_LINK;
413*664ab2c9SVignesh R 	slot.bcntrld    = 0;
414*664ab2c9SVignesh R 	slot.opt        = EDMA3_SLOPT_TRANS_COMP_INT_ENB |
415*664ab2c9SVignesh R 			  EDMA3_SLOPT_COMP_CODE(0) |
416*664ab2c9SVignesh R 			  EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC;
417*664ab2c9SVignesh R 
418*664ab2c9SVignesh R 	edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot);
419*664ab2c9SVignesh R 	edma_channel.slot = edma_slot_num;
420*664ab2c9SVignesh R 	edma_channel.chnum = 0;
421*664ab2c9SVignesh R 	edma_channel.complete_code = 0;
422*664ab2c9SVignesh R 	 /* set event trigger to dst update */
423*664ab2c9SVignesh R 	edma_channel.trigger_slot_word = EDMA3_TWORD(dst);
424*664ab2c9SVignesh R 
425*664ab2c9SVignesh R 	qedma3_start(edma3_base_addr, &edma_channel);
426*664ab2c9SVignesh R 	edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr);
427*664ab2c9SVignesh R 
428*664ab2c9SVignesh R 	while (edma3_check_for_transfer(edma3_base_addr, &edma_channel))
429*664ab2c9SVignesh R 		;
430*664ab2c9SVignesh R 	qedma3_stop(edma3_base_addr, &edma_channel);
431*664ab2c9SVignesh R 
432*664ab2c9SVignesh R 	if (rem_bytes != 0) {
433*664ab2c9SVignesh R 		slot.opt        = 0;
434*664ab2c9SVignesh R 		slot.src        =
435*664ab2c9SVignesh R 			(b_cnt_value * max_acnt) + ((unsigned int) src);
436*664ab2c9SVignesh R 		slot.acnt       = rem_bytes;
437*664ab2c9SVignesh R 		slot.bcnt       = 1;
438*664ab2c9SVignesh R 		slot.ccnt       = 1;
439*664ab2c9SVignesh R 		slot.src_bidx   = rem_bytes;
440*664ab2c9SVignesh R 		slot.dst_bidx   = rem_bytes;
441*664ab2c9SVignesh R 		slot.src_cidx   = 0;
442*664ab2c9SVignesh R 		slot.dst_cidx   = 0;
443*664ab2c9SVignesh R 		slot.link       = EDMA3_PARSET_NULL_LINK;
444*664ab2c9SVignesh R 		slot.bcntrld    = 0;
445*664ab2c9SVignesh R 		slot.opt        = EDMA3_SLOPT_TRANS_COMP_INT_ENB |
446*664ab2c9SVignesh R 				  EDMA3_SLOPT_COMP_CODE(0) |
447*664ab2c9SVignesh R 				  EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC;
448*664ab2c9SVignesh R 		edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot);
449*664ab2c9SVignesh R 		edma_channel.slot = edma_slot_num;
450*664ab2c9SVignesh R 		edma_channel.chnum = 0;
451*664ab2c9SVignesh R 		edma_channel.complete_code = 0;
452*664ab2c9SVignesh R 		/* set event trigger to dst update */
453*664ab2c9SVignesh R 		edma_channel.trigger_slot_word = EDMA3_TWORD(dst);
454*664ab2c9SVignesh R 
455*664ab2c9SVignesh R 		qedma3_start(edma3_base_addr, &edma_channel);
456*664ab2c9SVignesh R 		edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr +
457*664ab2c9SVignesh R 				    (max_acnt * b_cnt_value));
458*664ab2c9SVignesh R 		while (edma3_check_for_transfer(edma3_base_addr, &edma_channel))
459*664ab2c9SVignesh R 			;
460*664ab2c9SVignesh R 		qedma3_stop(edma3_base_addr, &edma_channel);
461*664ab2c9SVignesh R 	}
462*664ab2c9SVignesh R }
463