xref: /rk3399_rockchip-uboot/drivers/dma/ti-edma3.c (revision 90aa625c9a9e1fb7a2f001fd8e50099bacaf92b8)
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>
149d922450SSimon Glass #include <dm.h>
151218e5c5SMugunthan V N #include <dma.h>
161218e5c5SMugunthan V N #include <asm/omap_common.h>
17e165b1d3SKhoronzhuk, Ivan #include <asm/ti-common/ti-edma3.h>
18e165b1d3SKhoronzhuk, Ivan 
19e165b1d3SKhoronzhuk, Ivan #define EDMA3_SL_BASE(slot)			(0x4000 + ((slot) << 5))
20e165b1d3SKhoronzhuk, Ivan #define EDMA3_SL_MAX_NUM			512
21e165b1d3SKhoronzhuk, Ivan #define EDMA3_SLOPT_FIFO_WIDTH_MASK		(0x7 << 8)
22e165b1d3SKhoronzhuk, Ivan 
23e165b1d3SKhoronzhuk, Ivan #define EDMA3_QCHMAP(ch)			0x0200 + ((ch) << 2)
24e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_PARSET_MASK			0x1ff
25e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_PARSET_SHIFT		0x5
26e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_TRIGWORD_SHIFT		0x2
27e165b1d3SKhoronzhuk, Ivan 
28e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEMCR				0x314
29e165b1d3SKhoronzhuk, Ivan #define EDMA3_IPR				0x1068
30e165b1d3SKhoronzhuk, Ivan #define EDMA3_IPRH				0x106c
31e165b1d3SKhoronzhuk, Ivan #define EDMA3_ICR				0x1070
32e165b1d3SKhoronzhuk, Ivan #define EDMA3_ICRH				0x1074
33e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEECR				0x1088
34e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEESR				0x108c
35e165b1d3SKhoronzhuk, Ivan #define EDMA3_QSECR				0x1094
36e165b1d3SKhoronzhuk, Ivan 
371218e5c5SMugunthan V N struct ti_edma3_priv {
381218e5c5SMugunthan V N 	u32 base;
391218e5c5SMugunthan V N };
401218e5c5SMugunthan V N 
41e165b1d3SKhoronzhuk, Ivan /**
42e165b1d3SKhoronzhuk, Ivan  * qedma3_start - start qdma on a channel
43e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
44e165b1d3SKhoronzhuk, Ivan  * @cfg: pinter to struct edma3_channel_config where you can set
45e165b1d3SKhoronzhuk, Ivan  * the slot number to associate with, the chnum, which corresponds
46e165b1d3SKhoronzhuk, Ivan  * your quick channel number 0-7, complete code - transfer complete code
47e165b1d3SKhoronzhuk, Ivan  * and trigger slot word - which has to correspond to the word number in
48e165b1d3SKhoronzhuk, Ivan  * edma3_slot_layout struct for generating event.
49e165b1d3SKhoronzhuk, Ivan  *
50e165b1d3SKhoronzhuk, Ivan  */
qedma3_start(u32 base,struct edma3_channel_config * cfg)51e165b1d3SKhoronzhuk, Ivan void qedma3_start(u32 base, struct edma3_channel_config *cfg)
52e165b1d3SKhoronzhuk, Ivan {
53e165b1d3SKhoronzhuk, Ivan 	u32 qchmap;
54e165b1d3SKhoronzhuk, Ivan 
55e165b1d3SKhoronzhuk, Ivan 	/* Clear the pending int bit */
56e165b1d3SKhoronzhuk, Ivan 	if (cfg->complete_code < 32)
57e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
58e165b1d3SKhoronzhuk, Ivan 	else
59e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
60e165b1d3SKhoronzhuk, Ivan 
61e165b1d3SKhoronzhuk, Ivan 	/* Map parameter set and trigger word 7 to quick channel */
62e165b1d3SKhoronzhuk, Ivan 	qchmap = ((EDMA3_CHMAP_PARSET_MASK & cfg->slot)
63e165b1d3SKhoronzhuk, Ivan 		  << EDMA3_CHMAP_PARSET_SHIFT) |
64e165b1d3SKhoronzhuk, Ivan 		  (cfg->trigger_slot_word << EDMA3_CHMAP_TRIGWORD_SHIFT);
65e165b1d3SKhoronzhuk, Ivan 
66e165b1d3SKhoronzhuk, Ivan 	__raw_writel(qchmap, base + EDMA3_QCHMAP(cfg->chnum));
67e165b1d3SKhoronzhuk, Ivan 
68e165b1d3SKhoronzhuk, Ivan 	/* Clear missed event if set*/
69e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
70e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
71e165b1d3SKhoronzhuk, Ivan 
72e165b1d3SKhoronzhuk, Ivan 	/* Enable qdma channel event */
73e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEESR);
74e165b1d3SKhoronzhuk, Ivan }
75e165b1d3SKhoronzhuk, Ivan 
76e165b1d3SKhoronzhuk, Ivan /**
77e165b1d3SKhoronzhuk, Ivan  * edma3_set_dest - set initial DMA destination address in parameter RAM slot
78e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
79e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
80e165b1d3SKhoronzhuk, Ivan  * @dst: physical address of destination (memory, controller FIFO, etc)
81e165b1d3SKhoronzhuk, Ivan  * @addressMode: INCR, except in very rare cases
82e165b1d3SKhoronzhuk, Ivan  * @width: ignored unless @addressMode is FIFO, else specifies the
83e165b1d3SKhoronzhuk, Ivan  *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
84e165b1d3SKhoronzhuk, Ivan  *
85e165b1d3SKhoronzhuk, Ivan  * Note that the destination address is modified during the DMA transfer
86e165b1d3SKhoronzhuk, Ivan  * according to edma3_set_dest_index().
87e165b1d3SKhoronzhuk, Ivan  */
edma3_set_dest(u32 base,int slot,u32 dst,enum edma3_address_mode mode,enum edma3_fifo_width width)88e165b1d3SKhoronzhuk, Ivan void edma3_set_dest(u32 base, int slot, u32 dst, enum edma3_address_mode mode,
89e165b1d3SKhoronzhuk, Ivan 		    enum edma3_fifo_width width)
90e165b1d3SKhoronzhuk, Ivan {
91e165b1d3SKhoronzhuk, Ivan 	u32 opt;
92e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
93e165b1d3SKhoronzhuk, Ivan 
94e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
95e165b1d3SKhoronzhuk, Ivan 
96e165b1d3SKhoronzhuk, Ivan 	opt = __raw_readl(&rg->opt);
97e165b1d3SKhoronzhuk, Ivan 	if (mode == FIFO)
98e165b1d3SKhoronzhuk, Ivan 		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
99e165b1d3SKhoronzhuk, Ivan 		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
100e165b1d3SKhoronzhuk, Ivan 			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
101e165b1d3SKhoronzhuk, Ivan 	else
102e165b1d3SKhoronzhuk, Ivan 		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
103e165b1d3SKhoronzhuk, Ivan 
104e165b1d3SKhoronzhuk, Ivan 	__raw_writel(opt, &rg->opt);
105e165b1d3SKhoronzhuk, Ivan 	__raw_writel(dst, &rg->dst);
106e165b1d3SKhoronzhuk, Ivan }
107e165b1d3SKhoronzhuk, Ivan 
108e165b1d3SKhoronzhuk, Ivan /**
109e165b1d3SKhoronzhuk, Ivan  * edma3_set_dest_index - configure DMA destination address indexing
110e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
111e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
112e165b1d3SKhoronzhuk, Ivan  * @bidx: byte offset between destination arrays in a frame
113e165b1d3SKhoronzhuk, Ivan  * @cidx: byte offset between destination frames in a block
114e165b1d3SKhoronzhuk, Ivan  *
115e165b1d3SKhoronzhuk, Ivan  * Offsets are specified to support either contiguous or discontiguous
116e165b1d3SKhoronzhuk, Ivan  * memory transfers, or repeated access to a hardware register, as needed.
117e165b1d3SKhoronzhuk, Ivan  * When accessing hardware registers, both offsets are normally zero.
118e165b1d3SKhoronzhuk, Ivan  */
edma3_set_dest_index(u32 base,unsigned slot,int bidx,int cidx)119e165b1d3SKhoronzhuk, Ivan void edma3_set_dest_index(u32 base, unsigned slot, int bidx, int cidx)
120e165b1d3SKhoronzhuk, Ivan {
121e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_bidx;
122e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_cidx;
123e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
124e165b1d3SKhoronzhuk, Ivan 
125e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
126e165b1d3SKhoronzhuk, Ivan 
127e165b1d3SKhoronzhuk, Ivan 	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
128e165b1d3SKhoronzhuk, Ivan 	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
129e165b1d3SKhoronzhuk, Ivan 
130e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_bidx & 0x0000ffff) | (bidx << 16),
131e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_bidx);
132e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_cidx & 0x0000ffff) | (cidx << 16),
133e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_cidx);
134e165b1d3SKhoronzhuk, Ivan }
135e165b1d3SKhoronzhuk, Ivan 
136e165b1d3SKhoronzhuk, Ivan /**
137e165b1d3SKhoronzhuk, Ivan  * edma3_set_dest_addr - set destination address for slot only
138e165b1d3SKhoronzhuk, Ivan  */
edma3_set_dest_addr(u32 base,int slot,u32 dst)139e165b1d3SKhoronzhuk, Ivan void edma3_set_dest_addr(u32 base, int slot, u32 dst)
140e165b1d3SKhoronzhuk, Ivan {
141e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
142e165b1d3SKhoronzhuk, Ivan 
143e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
144e165b1d3SKhoronzhuk, Ivan 	__raw_writel(dst, &rg->dst);
145e165b1d3SKhoronzhuk, Ivan }
146e165b1d3SKhoronzhuk, Ivan 
147e165b1d3SKhoronzhuk, Ivan /**
148e165b1d3SKhoronzhuk, Ivan  * edma3_set_src - set initial DMA source address in parameter RAM slot
149e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
150e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
151e165b1d3SKhoronzhuk, Ivan  * @src_port: physical address of source (memory, controller FIFO, etc)
152e165b1d3SKhoronzhuk, Ivan  * @mode: INCR, except in very rare cases
153e165b1d3SKhoronzhuk, Ivan  * @width: ignored unless @addressMode is FIFO, else specifies the
154e165b1d3SKhoronzhuk, Ivan  *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
155e165b1d3SKhoronzhuk, Ivan  *
156e165b1d3SKhoronzhuk, Ivan  * Note that the source address is modified during the DMA transfer
157e165b1d3SKhoronzhuk, Ivan  * according to edma3_set_src_index().
158e165b1d3SKhoronzhuk, Ivan  */
edma3_set_src(u32 base,int slot,u32 src,enum edma3_address_mode mode,enum edma3_fifo_width width)159e165b1d3SKhoronzhuk, Ivan void edma3_set_src(u32 base, int slot, u32 src, enum edma3_address_mode mode,
160e165b1d3SKhoronzhuk, Ivan 		   enum edma3_fifo_width width)
161e165b1d3SKhoronzhuk, Ivan {
162e165b1d3SKhoronzhuk, Ivan 	u32 opt;
163e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
164e165b1d3SKhoronzhuk, Ivan 
165e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
166e165b1d3SKhoronzhuk, Ivan 
167e165b1d3SKhoronzhuk, Ivan 	opt = __raw_readl(&rg->opt);
168e165b1d3SKhoronzhuk, Ivan 	if (mode == FIFO)
169e165b1d3SKhoronzhuk, Ivan 		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
170e165b1d3SKhoronzhuk, Ivan 		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
171e165b1d3SKhoronzhuk, Ivan 			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
172e165b1d3SKhoronzhuk, Ivan 	else
173e165b1d3SKhoronzhuk, Ivan 		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
174e165b1d3SKhoronzhuk, Ivan 
175e165b1d3SKhoronzhuk, Ivan 	__raw_writel(opt, &rg->opt);
176e165b1d3SKhoronzhuk, Ivan 	__raw_writel(src, &rg->src);
177e165b1d3SKhoronzhuk, Ivan }
178e165b1d3SKhoronzhuk, Ivan 
179e165b1d3SKhoronzhuk, Ivan /**
180e165b1d3SKhoronzhuk, Ivan  * edma3_set_src_index - configure DMA source address indexing
181e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
182e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
183e165b1d3SKhoronzhuk, Ivan  * @bidx: byte offset between source arrays in a frame
184e165b1d3SKhoronzhuk, Ivan  * @cidx: byte offset between source frames in a block
185e165b1d3SKhoronzhuk, Ivan  *
186e165b1d3SKhoronzhuk, Ivan  * Offsets are specified to support either contiguous or discontiguous
187e165b1d3SKhoronzhuk, Ivan  * memory transfers, or repeated access to a hardware register, as needed.
188e165b1d3SKhoronzhuk, Ivan  * When accessing hardware registers, both offsets are normally zero.
189e165b1d3SKhoronzhuk, Ivan  */
edma3_set_src_index(u32 base,unsigned slot,int bidx,int cidx)190e165b1d3SKhoronzhuk, Ivan void edma3_set_src_index(u32 base, unsigned slot, int bidx, int cidx)
191e165b1d3SKhoronzhuk, Ivan {
192e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_bidx;
193e165b1d3SKhoronzhuk, Ivan 	u32 src_dst_cidx;
194e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
195e165b1d3SKhoronzhuk, Ivan 
196e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
197e165b1d3SKhoronzhuk, Ivan 
198e165b1d3SKhoronzhuk, Ivan 	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
199e165b1d3SKhoronzhuk, Ivan 	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
200e165b1d3SKhoronzhuk, Ivan 
201e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_bidx & 0xffff0000) | bidx,
202e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_bidx);
203e165b1d3SKhoronzhuk, Ivan 	__raw_writel((src_dst_cidx & 0xffff0000) | cidx,
204e165b1d3SKhoronzhuk, Ivan 		     &rg->src_dst_cidx);
205e165b1d3SKhoronzhuk, Ivan }
206e165b1d3SKhoronzhuk, Ivan 
207e165b1d3SKhoronzhuk, Ivan /**
208e165b1d3SKhoronzhuk, Ivan  * edma3_set_src_addr - set source address for slot only
209e165b1d3SKhoronzhuk, Ivan  */
edma3_set_src_addr(u32 base,int slot,u32 src)210e165b1d3SKhoronzhuk, Ivan void edma3_set_src_addr(u32 base, int slot, u32 src)
211e165b1d3SKhoronzhuk, Ivan {
212e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
213e165b1d3SKhoronzhuk, Ivan 
214e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
215e165b1d3SKhoronzhuk, Ivan 	__raw_writel(src, &rg->src);
216e165b1d3SKhoronzhuk, Ivan }
217e165b1d3SKhoronzhuk, Ivan 
218e165b1d3SKhoronzhuk, Ivan /**
219e165b1d3SKhoronzhuk, Ivan  * edma3_set_transfer_params - configure DMA transfer parameters
220e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
221e165b1d3SKhoronzhuk, Ivan  * @slot: parameter RAM slot being configured
222e165b1d3SKhoronzhuk, Ivan  * @acnt: how many bytes per array (at least one)
223e165b1d3SKhoronzhuk, Ivan  * @bcnt: how many arrays per frame (at least one)
224e165b1d3SKhoronzhuk, Ivan  * @ccnt: how many frames per block (at least one)
225e165b1d3SKhoronzhuk, Ivan  * @bcnt_rld: used only for A-Synchronized transfers; this specifies
226e165b1d3SKhoronzhuk, Ivan  *	the value to reload into bcnt when it decrements to zero
227e165b1d3SKhoronzhuk, Ivan  * @sync_mode: ASYNC or ABSYNC
228e165b1d3SKhoronzhuk, Ivan  *
229e165b1d3SKhoronzhuk, Ivan  * See the EDMA3 documentation to understand how to configure and link
230e165b1d3SKhoronzhuk, Ivan  * transfers using the fields in PaRAM slots.  If you are not doing it
231e165b1d3SKhoronzhuk, Ivan  * all at once with edma3_write_slot(), you will use this routine
232e165b1d3SKhoronzhuk, Ivan  * plus two calls each for source and destination, setting the initial
233e165b1d3SKhoronzhuk, Ivan  * address and saying how to index that address.
234e165b1d3SKhoronzhuk, Ivan  *
235e165b1d3SKhoronzhuk, Ivan  * An example of an A-Synchronized transfer is a serial link using a
236e165b1d3SKhoronzhuk, Ivan  * single word shift register.  In that case, @acnt would be equal to
237e165b1d3SKhoronzhuk, Ivan  * that word size; the serial controller issues a DMA synchronization
238e165b1d3SKhoronzhuk, Ivan  * event to transfer each word, and memory access by the DMA transfer
239e165b1d3SKhoronzhuk, Ivan  * controller will be word-at-a-time.
240e165b1d3SKhoronzhuk, Ivan  *
241e165b1d3SKhoronzhuk, Ivan  * An example of an AB-Synchronized transfer is a device using a FIFO.
242e165b1d3SKhoronzhuk, Ivan  * In that case, @acnt equals the FIFO width and @bcnt equals its depth.
243e165b1d3SKhoronzhuk, Ivan  * The controller with the FIFO issues DMA synchronization events when
244e165b1d3SKhoronzhuk, Ivan  * the FIFO threshold is reached, and the DMA transfer controller will
245e165b1d3SKhoronzhuk, Ivan  * transfer one frame to (or from) the FIFO.  It will probably use
246e165b1d3SKhoronzhuk, Ivan  * efficient burst modes to access memory.
247e165b1d3SKhoronzhuk, Ivan  */
edma3_set_transfer_params(u32 base,int slot,int acnt,int bcnt,int ccnt,u16 bcnt_rld,enum edma3_sync_dimension sync_mode)248e165b1d3SKhoronzhuk, Ivan void edma3_set_transfer_params(u32 base, int slot, int acnt,
249e165b1d3SKhoronzhuk, Ivan 			       int bcnt, int ccnt, u16 bcnt_rld,
250e165b1d3SKhoronzhuk, Ivan 			       enum edma3_sync_dimension sync_mode)
251e165b1d3SKhoronzhuk, Ivan {
252e165b1d3SKhoronzhuk, Ivan 	u32 opt;
253e165b1d3SKhoronzhuk, Ivan 	u32 link_bcntrld;
254e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
255e165b1d3SKhoronzhuk, Ivan 
256e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
257e165b1d3SKhoronzhuk, Ivan 
258e165b1d3SKhoronzhuk, Ivan 	link_bcntrld = __raw_readl(&rg->link_bcntrld);
259e165b1d3SKhoronzhuk, Ivan 
260e165b1d3SKhoronzhuk, Ivan 	__raw_writel((bcnt_rld << 16) | (0x0000ffff & link_bcntrld),
261e165b1d3SKhoronzhuk, Ivan 		     &rg->link_bcntrld);
262e165b1d3SKhoronzhuk, Ivan 
263e165b1d3SKhoronzhuk, Ivan 	opt = __raw_readl(&rg->opt);
264e165b1d3SKhoronzhuk, Ivan 	if (sync_mode == ASYNC)
265e165b1d3SKhoronzhuk, Ivan 		__raw_writel(opt & ~EDMA3_SLOPT_AB_SYNC, &rg->opt);
266e165b1d3SKhoronzhuk, Ivan 	else
267e165b1d3SKhoronzhuk, Ivan 		__raw_writel(opt | EDMA3_SLOPT_AB_SYNC, &rg->opt);
268e165b1d3SKhoronzhuk, Ivan 
269e165b1d3SKhoronzhuk, Ivan 	/* Set the acount, bcount, ccount registers */
270e165b1d3SKhoronzhuk, Ivan 	__raw_writel((bcnt << 16) | (acnt & 0xffff), &rg->a_b_cnt);
271e165b1d3SKhoronzhuk, Ivan 	__raw_writel(0xffff & ccnt, &rg->ccnt);
272e165b1d3SKhoronzhuk, Ivan }
273e165b1d3SKhoronzhuk, Ivan 
274e165b1d3SKhoronzhuk, Ivan /**
275e165b1d3SKhoronzhuk, Ivan  * edma3_write_slot - write parameter RAM data for slot
276e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
277e165b1d3SKhoronzhuk, Ivan  * @slot: number of parameter RAM slot being modified
278e165b1d3SKhoronzhuk, Ivan  * @param: data to be written into parameter RAM slot
279e165b1d3SKhoronzhuk, Ivan  *
280e165b1d3SKhoronzhuk, Ivan  * Use this to assign all parameters of a transfer at once.  This
281e165b1d3SKhoronzhuk, Ivan  * allows more efficient setup of transfers than issuing multiple
282e165b1d3SKhoronzhuk, Ivan  * calls to set up those parameters in small pieces, and provides
283e165b1d3SKhoronzhuk, Ivan  * complete control over all transfer options.
284e165b1d3SKhoronzhuk, Ivan  */
edma3_write_slot(u32 base,int slot,struct edma3_slot_layout * param)285e165b1d3SKhoronzhuk, Ivan void edma3_write_slot(u32 base, int slot, struct edma3_slot_layout *param)
286e165b1d3SKhoronzhuk, Ivan {
287e165b1d3SKhoronzhuk, Ivan 	int i;
288e165b1d3SKhoronzhuk, Ivan 	u32 *p = (u32 *)param;
289e165b1d3SKhoronzhuk, Ivan 	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
290e165b1d3SKhoronzhuk, Ivan 
291e165b1d3SKhoronzhuk, Ivan 	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
292e165b1d3SKhoronzhuk, Ivan 		__raw_writel(*p++, addr++);
293e165b1d3SKhoronzhuk, Ivan }
294e165b1d3SKhoronzhuk, Ivan 
295e165b1d3SKhoronzhuk, Ivan /**
296e165b1d3SKhoronzhuk, Ivan  * edma3_read_slot - read parameter RAM data from slot
297e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
298e165b1d3SKhoronzhuk, Ivan  * @slot: number of parameter RAM slot being copied
299e165b1d3SKhoronzhuk, Ivan  * @param: where to store copy of parameter RAM data
300e165b1d3SKhoronzhuk, Ivan  *
301e165b1d3SKhoronzhuk, Ivan  * Use this to read data from a parameter RAM slot, perhaps to
302e165b1d3SKhoronzhuk, Ivan  * save them as a template for later reuse.
303e165b1d3SKhoronzhuk, Ivan  */
edma3_read_slot(u32 base,int slot,struct edma3_slot_layout * param)304e165b1d3SKhoronzhuk, Ivan void edma3_read_slot(u32 base, int slot, struct edma3_slot_layout *param)
305e165b1d3SKhoronzhuk, Ivan {
306e165b1d3SKhoronzhuk, Ivan 	int i;
307e165b1d3SKhoronzhuk, Ivan 	u32 *p = (u32 *)param;
308e165b1d3SKhoronzhuk, Ivan 	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
309e165b1d3SKhoronzhuk, Ivan 
310e165b1d3SKhoronzhuk, Ivan 	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
311e165b1d3SKhoronzhuk, Ivan 		*p++ = __raw_readl(addr++);
312e165b1d3SKhoronzhuk, Ivan }
313e165b1d3SKhoronzhuk, Ivan 
edma3_slot_configure(u32 base,int slot,struct edma3_slot_config * cfg)314e165b1d3SKhoronzhuk, Ivan void edma3_slot_configure(u32 base, int slot, struct edma3_slot_config *cfg)
315e165b1d3SKhoronzhuk, Ivan {
316e165b1d3SKhoronzhuk, Ivan 	struct edma3_slot_layout *rg;
317e165b1d3SKhoronzhuk, Ivan 
318e165b1d3SKhoronzhuk, Ivan 	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
319e165b1d3SKhoronzhuk, Ivan 
320e165b1d3SKhoronzhuk, Ivan 	__raw_writel(cfg->opt, &rg->opt);
321e165b1d3SKhoronzhuk, Ivan 	__raw_writel(cfg->src, &rg->src);
322e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->bcnt << 16) | (cfg->acnt & 0xffff), &rg->a_b_cnt);
323e165b1d3SKhoronzhuk, Ivan 	__raw_writel(cfg->dst, &rg->dst);
324e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->dst_bidx << 16) |
325e165b1d3SKhoronzhuk, Ivan 		     (cfg->src_bidx & 0xffff), &rg->src_dst_bidx);
326e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->bcntrld << 16) |
327e165b1d3SKhoronzhuk, Ivan 		     (cfg->link & 0xffff), &rg->link_bcntrld);
328e165b1d3SKhoronzhuk, Ivan 	__raw_writel((cfg->dst_cidx << 16) |
329e165b1d3SKhoronzhuk, Ivan 		     (cfg->src_cidx & 0xffff), &rg->src_dst_cidx);
330e165b1d3SKhoronzhuk, Ivan 	__raw_writel(0xffff & cfg->ccnt, &rg->ccnt);
331e165b1d3SKhoronzhuk, Ivan }
332e165b1d3SKhoronzhuk, Ivan 
333e165b1d3SKhoronzhuk, Ivan /**
334e165b1d3SKhoronzhuk, Ivan  * edma3_check_for_transfer - check if transfer coplete by checking
335e165b1d3SKhoronzhuk, Ivan  * interrupt pending bit. Clear interrupt pending bit if complete.
336e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
337e165b1d3SKhoronzhuk, Ivan  * @cfg: pinter to struct edma3_channel_config which was passed
338e165b1d3SKhoronzhuk, Ivan  * to qedma3_start when you started qdma channel
339e165b1d3SKhoronzhuk, Ivan  *
340e165b1d3SKhoronzhuk, Ivan  * Return 0 if complete, 1 if not.
341e165b1d3SKhoronzhuk, Ivan  */
edma3_check_for_transfer(u32 base,struct edma3_channel_config * cfg)342e165b1d3SKhoronzhuk, Ivan int edma3_check_for_transfer(u32 base, struct edma3_channel_config *cfg)
343e165b1d3SKhoronzhuk, Ivan {
344e165b1d3SKhoronzhuk, Ivan 	u32 inum;
345e165b1d3SKhoronzhuk, Ivan 	u32 ipr_base;
346e165b1d3SKhoronzhuk, Ivan 	u32 icr_base;
347e165b1d3SKhoronzhuk, Ivan 
348e165b1d3SKhoronzhuk, Ivan 	if (cfg->complete_code < 32) {
349e165b1d3SKhoronzhuk, Ivan 		ipr_base = base + EDMA3_IPR;
350e165b1d3SKhoronzhuk, Ivan 		icr_base = base + EDMA3_ICR;
351e165b1d3SKhoronzhuk, Ivan 		inum = 1 << cfg->complete_code;
352e165b1d3SKhoronzhuk, Ivan 	} else {
353e165b1d3SKhoronzhuk, Ivan 		ipr_base = base + EDMA3_IPRH;
354e165b1d3SKhoronzhuk, Ivan 		icr_base = base + EDMA3_ICRH;
355e165b1d3SKhoronzhuk, Ivan 		inum = 1 << (cfg->complete_code - 32);
356e165b1d3SKhoronzhuk, Ivan 	}
357e165b1d3SKhoronzhuk, Ivan 
358e165b1d3SKhoronzhuk, Ivan 	/* check complete interrupt */
359e165b1d3SKhoronzhuk, Ivan 	if (!(__raw_readl(ipr_base) & inum))
360e165b1d3SKhoronzhuk, Ivan 		return 1;
361e165b1d3SKhoronzhuk, Ivan 
362e165b1d3SKhoronzhuk, Ivan 	/* clean up the pending int bit */
363e165b1d3SKhoronzhuk, Ivan 	__raw_writel(inum, icr_base);
364e165b1d3SKhoronzhuk, Ivan 
365e165b1d3SKhoronzhuk, Ivan 	return 0;
366e165b1d3SKhoronzhuk, Ivan }
367e165b1d3SKhoronzhuk, Ivan 
368e165b1d3SKhoronzhuk, Ivan /**
369e165b1d3SKhoronzhuk, Ivan  * qedma3_stop - stops dma on the channel passed
370e165b1d3SKhoronzhuk, Ivan  * @base: base address of edma
371e165b1d3SKhoronzhuk, Ivan  * @cfg: pinter to struct edma3_channel_config which was passed
372e165b1d3SKhoronzhuk, Ivan  * to qedma3_start when you started qdma channel
373e165b1d3SKhoronzhuk, Ivan  */
qedma3_stop(u32 base,struct edma3_channel_config * cfg)374e165b1d3SKhoronzhuk, Ivan void qedma3_stop(u32 base, struct edma3_channel_config *cfg)
375e165b1d3SKhoronzhuk, Ivan {
376e165b1d3SKhoronzhuk, Ivan 	/* Disable qdma channel event */
377e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEECR);
378e165b1d3SKhoronzhuk, Ivan 
379e165b1d3SKhoronzhuk, Ivan 	/* clean up the interrupt indication */
380e165b1d3SKhoronzhuk, Ivan 	if (cfg->complete_code < 32)
381e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
382e165b1d3SKhoronzhuk, Ivan 	else
383e165b1d3SKhoronzhuk, Ivan 		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
384e165b1d3SKhoronzhuk, Ivan 
385e165b1d3SKhoronzhuk, Ivan 	/* Clear missed event if set*/
386e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
387e165b1d3SKhoronzhuk, Ivan 	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
388e165b1d3SKhoronzhuk, Ivan 
389e165b1d3SKhoronzhuk, Ivan 	/* Clear the channel map */
390e165b1d3SKhoronzhuk, Ivan 	__raw_writel(0, base + EDMA3_QCHMAP(cfg->chnum));
391e165b1d3SKhoronzhuk, Ivan }
392664ab2c9SVignesh R 
__edma3_transfer(unsigned long edma3_base_addr,unsigned int edma_slot_num,void * dst,void * src,size_t len)3931218e5c5SMugunthan V N void __edma3_transfer(unsigned long edma3_base_addr, unsigned int edma_slot_num,
3941218e5c5SMugunthan V N 		      void *dst, void *src, size_t len)
395664ab2c9SVignesh R {
396664ab2c9SVignesh R 	struct edma3_slot_config        slot;
397664ab2c9SVignesh R 	struct edma3_channel_config     edma_channel;
398664ab2c9SVignesh R 	int                             b_cnt_value = 1;
399664ab2c9SVignesh R 	int                             rem_bytes  = 0;
400664ab2c9SVignesh R 	int                             a_cnt_value = len;
401664ab2c9SVignesh R 	unsigned int                    addr = (unsigned int) (dst);
402664ab2c9SVignesh R 	unsigned int                    max_acnt  = 0x7FFFU;
403664ab2c9SVignesh R 
404664ab2c9SVignesh R 	if (len > max_acnt) {
405664ab2c9SVignesh R 		b_cnt_value = (len / max_acnt);
406664ab2c9SVignesh R 		rem_bytes  = (len % max_acnt);
407664ab2c9SVignesh R 		a_cnt_value = max_acnt;
408664ab2c9SVignesh R 	}
409664ab2c9SVignesh R 
410664ab2c9SVignesh R 	slot.opt        = 0;
411664ab2c9SVignesh R 	slot.src        = ((unsigned int) src);
412664ab2c9SVignesh R 	slot.acnt       = a_cnt_value;
413664ab2c9SVignesh R 	slot.bcnt       = b_cnt_value;
414664ab2c9SVignesh R 	slot.ccnt       = 1;
415664ab2c9SVignesh R 	slot.src_bidx   = a_cnt_value;
416664ab2c9SVignesh R 	slot.dst_bidx   = a_cnt_value;
417664ab2c9SVignesh R 	slot.src_cidx   = 0;
418664ab2c9SVignesh R 	slot.dst_cidx   = 0;
419664ab2c9SVignesh R 	slot.link       = EDMA3_PARSET_NULL_LINK;
420664ab2c9SVignesh R 	slot.bcntrld    = 0;
421664ab2c9SVignesh R 	slot.opt        = EDMA3_SLOPT_TRANS_COMP_INT_ENB |
422664ab2c9SVignesh R 			  EDMA3_SLOPT_COMP_CODE(0) |
423664ab2c9SVignesh R 			  EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC;
424664ab2c9SVignesh R 
425664ab2c9SVignesh R 	edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot);
426664ab2c9SVignesh R 	edma_channel.slot = edma_slot_num;
427664ab2c9SVignesh R 	edma_channel.chnum = 0;
428664ab2c9SVignesh R 	edma_channel.complete_code = 0;
429664ab2c9SVignesh R 	 /* set event trigger to dst update */
430664ab2c9SVignesh R 	edma_channel.trigger_slot_word = EDMA3_TWORD(dst);
431664ab2c9SVignesh R 
432664ab2c9SVignesh R 	qedma3_start(edma3_base_addr, &edma_channel);
433664ab2c9SVignesh R 	edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr);
434664ab2c9SVignesh R 
435664ab2c9SVignesh R 	while (edma3_check_for_transfer(edma3_base_addr, &edma_channel))
436664ab2c9SVignesh R 		;
437664ab2c9SVignesh R 	qedma3_stop(edma3_base_addr, &edma_channel);
438664ab2c9SVignesh R 
439664ab2c9SVignesh R 	if (rem_bytes != 0) {
440664ab2c9SVignesh R 		slot.opt        = 0;
441664ab2c9SVignesh R 		slot.src        =
442664ab2c9SVignesh R 			(b_cnt_value * max_acnt) + ((unsigned int) src);
443664ab2c9SVignesh R 		slot.acnt       = rem_bytes;
444664ab2c9SVignesh R 		slot.bcnt       = 1;
445664ab2c9SVignesh R 		slot.ccnt       = 1;
446664ab2c9SVignesh R 		slot.src_bidx   = rem_bytes;
447664ab2c9SVignesh R 		slot.dst_bidx   = rem_bytes;
448664ab2c9SVignesh R 		slot.src_cidx   = 0;
449664ab2c9SVignesh R 		slot.dst_cidx   = 0;
450664ab2c9SVignesh R 		slot.link       = EDMA3_PARSET_NULL_LINK;
451664ab2c9SVignesh R 		slot.bcntrld    = 0;
452664ab2c9SVignesh R 		slot.opt        = EDMA3_SLOPT_TRANS_COMP_INT_ENB |
453664ab2c9SVignesh R 				  EDMA3_SLOPT_COMP_CODE(0) |
454664ab2c9SVignesh R 				  EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC;
455664ab2c9SVignesh R 		edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot);
456664ab2c9SVignesh R 		edma_channel.slot = edma_slot_num;
457664ab2c9SVignesh R 		edma_channel.chnum = 0;
458664ab2c9SVignesh R 		edma_channel.complete_code = 0;
459664ab2c9SVignesh R 		/* set event trigger to dst update */
460664ab2c9SVignesh R 		edma_channel.trigger_slot_word = EDMA3_TWORD(dst);
461664ab2c9SVignesh R 
462664ab2c9SVignesh R 		qedma3_start(edma3_base_addr, &edma_channel);
463664ab2c9SVignesh R 		edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr +
464664ab2c9SVignesh R 				    (max_acnt * b_cnt_value));
465664ab2c9SVignesh R 		while (edma3_check_for_transfer(edma3_base_addr, &edma_channel))
466664ab2c9SVignesh R 			;
467664ab2c9SVignesh R 		qedma3_stop(edma3_base_addr, &edma_channel);
468664ab2c9SVignesh R 	}
469664ab2c9SVignesh R }
4701218e5c5SMugunthan V N 
4711218e5c5SMugunthan V N #ifndef CONFIG_DMA
4721218e5c5SMugunthan V N 
edma3_transfer(unsigned long edma3_base_addr,unsigned int edma_slot_num,void * dst,void * src,size_t len)4731218e5c5SMugunthan V N void edma3_transfer(unsigned long edma3_base_addr, unsigned int edma_slot_num,
4741218e5c5SMugunthan V N 		    void *dst, void *src, size_t len)
4751218e5c5SMugunthan V N {
4761218e5c5SMugunthan V N 	__edma3_transfer(edma3_base_addr, edma_slot_num, dst, src, len);
4771218e5c5SMugunthan V N }
4781218e5c5SMugunthan V N 
4791218e5c5SMugunthan V N #else
4801218e5c5SMugunthan V N 
ti_edma3_transfer(struct udevice * dev,int direction,void * dst,void * src,size_t len)4811218e5c5SMugunthan V N static int ti_edma3_transfer(struct udevice *dev, int direction, void *dst,
4821218e5c5SMugunthan V N 			     void *src, size_t len)
4831218e5c5SMugunthan V N {
4841218e5c5SMugunthan V N 	struct ti_edma3_priv *priv = dev_get_priv(dev);
4851218e5c5SMugunthan V N 
4861218e5c5SMugunthan V N 	/* enable edma3 clocks */
4871218e5c5SMugunthan V N 	enable_edma3_clocks();
4881218e5c5SMugunthan V N 
4891218e5c5SMugunthan V N 	switch (direction) {
4901218e5c5SMugunthan V N 	case DMA_MEM_TO_MEM:
4911218e5c5SMugunthan V N 		__edma3_transfer(priv->base, 1, dst, src, len);
4921218e5c5SMugunthan V N 		break;
4931218e5c5SMugunthan V N 	default:
494*90aa625cSMasahiro Yamada 		pr_err("Transfer type not implemented in DMA driver\n");
4951218e5c5SMugunthan V N 		break;
4961218e5c5SMugunthan V N 	}
4971218e5c5SMugunthan V N 
4981218e5c5SMugunthan V N 	/* disable edma3 clocks */
4991218e5c5SMugunthan V N 	disable_edma3_clocks();
5001218e5c5SMugunthan V N 
5011218e5c5SMugunthan V N 	return 0;
5021218e5c5SMugunthan V N }
5031218e5c5SMugunthan V N 
ti_edma3_ofdata_to_platdata(struct udevice * dev)5041218e5c5SMugunthan V N static int ti_edma3_ofdata_to_platdata(struct udevice *dev)
5051218e5c5SMugunthan V N {
5061218e5c5SMugunthan V N 	struct ti_edma3_priv *priv = dev_get_priv(dev);
5071218e5c5SMugunthan V N 
508a821c4afSSimon Glass 	priv->base = devfdt_get_addr(dev);
5091218e5c5SMugunthan V N 
5101218e5c5SMugunthan V N 	return 0;
5111218e5c5SMugunthan V N }
5121218e5c5SMugunthan V N 
ti_edma3_probe(struct udevice * dev)5131218e5c5SMugunthan V N static int ti_edma3_probe(struct udevice *dev)
5141218e5c5SMugunthan V N {
5151218e5c5SMugunthan V N 	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
5161218e5c5SMugunthan V N 
5171218e5c5SMugunthan V N 	uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM;
5181218e5c5SMugunthan V N 
5191218e5c5SMugunthan V N 	return 0;
5201218e5c5SMugunthan V N }
5211218e5c5SMugunthan V N 
5221218e5c5SMugunthan V N static const struct dma_ops ti_edma3_ops = {
5231218e5c5SMugunthan V N 	.transfer	= ti_edma3_transfer,
5241218e5c5SMugunthan V N };
5251218e5c5SMugunthan V N 
5261218e5c5SMugunthan V N static const struct udevice_id ti_edma3_ids[] = {
5271218e5c5SMugunthan V N 	{ .compatible = "ti,edma3" },
5281218e5c5SMugunthan V N 	{ }
5291218e5c5SMugunthan V N };
5301218e5c5SMugunthan V N 
5311218e5c5SMugunthan V N U_BOOT_DRIVER(ti_edma3) = {
5321218e5c5SMugunthan V N 	.name	= "ti_edma3",
5331218e5c5SMugunthan V N 	.id	= UCLASS_DMA,
5341218e5c5SMugunthan V N 	.of_match = ti_edma3_ids,
5351218e5c5SMugunthan V N 	.ops	= &ti_edma3_ops,
5361218e5c5SMugunthan V N 	.ofdata_to_platdata = ti_edma3_ofdata_to_platdata,
5371218e5c5SMugunthan V N 	.probe	= ti_edma3_probe,
5381218e5c5SMugunthan V N 	.priv_auto_alloc_size = sizeof(struct ti_edma3_priv),
5391218e5c5SMugunthan V N };
5401218e5c5SMugunthan V N #endif /* CONFIG_DMA */
541