2 * Enhanced Direct Memory Access (EDMA3) Controller
5 * Texas Instruments Incorporated, <www.ti.com>
7 * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
9 * SPDX-License-Identifier: GPL-2.0+
14 #include <asm/ti-common/ti-edma3.h>
16 #define EDMA3_SL_BASE(slot) (0x4000 + ((slot) << 5))
17 #define EDMA3_SL_MAX_NUM 512
18 #define EDMA3_SLOPT_FIFO_WIDTH_MASK (0x7 << 8)
20 #define EDMA3_QCHMAP(ch) 0x0200 + ((ch) << 2)
21 #define EDMA3_CHMAP_PARSET_MASK 0x1ff
22 #define EDMA3_CHMAP_PARSET_SHIFT 0x5
23 #define EDMA3_CHMAP_TRIGWORD_SHIFT 0x2
25 #define EDMA3_QEMCR 0x314
26 #define EDMA3_IPR 0x1068
27 #define EDMA3_IPRH 0x106c
28 #define EDMA3_ICR 0x1070
29 #define EDMA3_ICRH 0x1074
30 #define EDMA3_QEECR 0x1088
31 #define EDMA3_QEESR 0x108c
32 #define EDMA3_QSECR 0x1094
35 * qedma3_start - start qdma on a channel
36 * @base: base address of edma
37 * @cfg: pinter to struct edma3_channel_config where you can set
38 * the slot number to associate with, the chnum, which corresponds
39 * your quick channel number 0-7, complete code - transfer complete code
40 * and trigger slot word - which has to correspond to the word number in
41 * edma3_slot_layout struct for generating event.
44 void qedma3_start(u32 base
, struct edma3_channel_config
*cfg
)
48 /* Clear the pending int bit */
49 if (cfg
->complete_code
< 32)
50 __raw_writel(1 << cfg
->complete_code
, base
+ EDMA3_ICR
);
52 __raw_writel(1 << cfg
->complete_code
, base
+ EDMA3_ICRH
);
54 /* Map parameter set and trigger word 7 to quick channel */
55 qchmap
= ((EDMA3_CHMAP_PARSET_MASK
& cfg
->slot
)
56 << EDMA3_CHMAP_PARSET_SHIFT
) |
57 (cfg
->trigger_slot_word
<< EDMA3_CHMAP_TRIGWORD_SHIFT
);
59 __raw_writel(qchmap
, base
+ EDMA3_QCHMAP(cfg
->chnum
));
61 /* Clear missed event if set*/
62 __raw_writel(1 << cfg
->chnum
, base
+ EDMA3_QSECR
);
63 __raw_writel(1 << cfg
->chnum
, base
+ EDMA3_QEMCR
);
65 /* Enable qdma channel event */
66 __raw_writel(1 << cfg
->chnum
, base
+ EDMA3_QEESR
);
70 * edma3_set_dest - set initial DMA destination address in parameter RAM slot
71 * @base: base address of edma
72 * @slot: parameter RAM slot being configured
73 * @dst: physical address of destination (memory, controller FIFO, etc)
74 * @addressMode: INCR, except in very rare cases
75 * @width: ignored unless @addressMode is FIFO, else specifies the
76 * width to use when addressing the fifo (e.g. W8BIT, W32BIT)
78 * Note that the destination address is modified during the DMA transfer
79 * according to edma3_set_dest_index().
81 void edma3_set_dest(u32 base
, int slot
, u32 dst
, enum edma3_address_mode mode
,
82 enum edma3_fifo_width width
)
85 struct edma3_slot_layout
*rg
;
87 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
89 opt
= __raw_readl(&rg
->opt
);
91 opt
= (opt
& EDMA3_SLOPT_FIFO_WIDTH_MASK
) |
92 (EDMA3_SLOPT_DST_ADDR_CONST_MODE
|
93 EDMA3_SLOPT_FIFO_WIDTH_SET(width
));
95 opt
&= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE
;
97 __raw_writel(opt
, &rg
->opt
);
98 __raw_writel(dst
, &rg
->dst
);
102 * edma3_set_dest_index - configure DMA destination address indexing
103 * @base: base address of edma
104 * @slot: parameter RAM slot being configured
105 * @bidx: byte offset between destination arrays in a frame
106 * @cidx: byte offset between destination frames in a block
108 * Offsets are specified to support either contiguous or discontiguous
109 * memory transfers, or repeated access to a hardware register, as needed.
110 * When accessing hardware registers, both offsets are normally zero.
112 void edma3_set_dest_index(u32 base
, unsigned slot
, int bidx
, int cidx
)
116 struct edma3_slot_layout
*rg
;
118 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
120 src_dst_bidx
= __raw_readl(&rg
->src_dst_bidx
);
121 src_dst_cidx
= __raw_readl(&rg
->src_dst_cidx
);
123 __raw_writel((src_dst_bidx
& 0x0000ffff) | (bidx
<< 16),
125 __raw_writel((src_dst_cidx
& 0x0000ffff) | (cidx
<< 16),
130 * edma3_set_dest_addr - set destination address for slot only
132 void edma3_set_dest_addr(u32 base
, int slot
, u32 dst
)
134 struct edma3_slot_layout
*rg
;
136 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
137 __raw_writel(dst
, &rg
->dst
);
141 * edma3_set_src - set initial DMA source address in parameter RAM slot
142 * @base: base address of edma
143 * @slot: parameter RAM slot being configured
144 * @src_port: physical address of source (memory, controller FIFO, etc)
145 * @mode: INCR, except in very rare cases
146 * @width: ignored unless @addressMode is FIFO, else specifies the
147 * width to use when addressing the fifo (e.g. W8BIT, W32BIT)
149 * Note that the source address is modified during the DMA transfer
150 * according to edma3_set_src_index().
152 void edma3_set_src(u32 base
, int slot
, u32 src
, enum edma3_address_mode mode
,
153 enum edma3_fifo_width width
)
156 struct edma3_slot_layout
*rg
;
158 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
160 opt
= __raw_readl(&rg
->opt
);
162 opt
= (opt
& EDMA3_SLOPT_FIFO_WIDTH_MASK
) |
163 (EDMA3_SLOPT_DST_ADDR_CONST_MODE
|
164 EDMA3_SLOPT_FIFO_WIDTH_SET(width
));
166 opt
&= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE
;
168 __raw_writel(opt
, &rg
->opt
);
169 __raw_writel(src
, &rg
->src
);
173 * edma3_set_src_index - configure DMA source address indexing
174 * @base: base address of edma
175 * @slot: parameter RAM slot being configured
176 * @bidx: byte offset between source arrays in a frame
177 * @cidx: byte offset between source frames in a block
179 * Offsets are specified to support either contiguous or discontiguous
180 * memory transfers, or repeated access to a hardware register, as needed.
181 * When accessing hardware registers, both offsets are normally zero.
183 void edma3_set_src_index(u32 base
, unsigned slot
, int bidx
, int cidx
)
187 struct edma3_slot_layout
*rg
;
189 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
191 src_dst_bidx
= __raw_readl(&rg
->src_dst_bidx
);
192 src_dst_cidx
= __raw_readl(&rg
->src_dst_cidx
);
194 __raw_writel((src_dst_bidx
& 0xffff0000) | bidx
,
196 __raw_writel((src_dst_cidx
& 0xffff0000) | cidx
,
201 * edma3_set_src_addr - set source address for slot only
203 void edma3_set_src_addr(u32 base
, int slot
, u32 src
)
205 struct edma3_slot_layout
*rg
;
207 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
208 __raw_writel(src
, &rg
->src
);
212 * edma3_set_transfer_params - configure DMA transfer parameters
213 * @base: base address of edma
214 * @slot: parameter RAM slot being configured
215 * @acnt: how many bytes per array (at least one)
216 * @bcnt: how many arrays per frame (at least one)
217 * @ccnt: how many frames per block (at least one)
218 * @bcnt_rld: used only for A-Synchronized transfers; this specifies
219 * the value to reload into bcnt when it decrements to zero
220 * @sync_mode: ASYNC or ABSYNC
222 * See the EDMA3 documentation to understand how to configure and link
223 * transfers using the fields in PaRAM slots. If you are not doing it
224 * all at once with edma3_write_slot(), you will use this routine
225 * plus two calls each for source and destination, setting the initial
226 * address and saying how to index that address.
228 * An example of an A-Synchronized transfer is a serial link using a
229 * single word shift register. In that case, @acnt would be equal to
230 * that word size; the serial controller issues a DMA synchronization
231 * event to transfer each word, and memory access by the DMA transfer
232 * controller will be word-at-a-time.
234 * An example of an AB-Synchronized transfer is a device using a FIFO.
235 * In that case, @acnt equals the FIFO width and @bcnt equals its depth.
236 * The controller with the FIFO issues DMA synchronization events when
237 * the FIFO threshold is reached, and the DMA transfer controller will
238 * transfer one frame to (or from) the FIFO. It will probably use
239 * efficient burst modes to access memory.
241 void edma3_set_transfer_params(u32 base
, int slot
, int acnt
,
242 int bcnt
, int ccnt
, u16 bcnt_rld
,
243 enum edma3_sync_dimension sync_mode
)
247 struct edma3_slot_layout
*rg
;
249 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
251 link_bcntrld
= __raw_readl(&rg
->link_bcntrld
);
253 __raw_writel((bcnt_rld
<< 16) | (0x0000ffff & link_bcntrld
),
256 opt
= __raw_readl(&rg
->opt
);
257 if (sync_mode
== ASYNC
)
258 __raw_writel(opt
& ~EDMA3_SLOPT_AB_SYNC
, &rg
->opt
);
260 __raw_writel(opt
| EDMA3_SLOPT_AB_SYNC
, &rg
->opt
);
262 /* Set the acount, bcount, ccount registers */
263 __raw_writel((bcnt
<< 16) | (acnt
& 0xffff), &rg
->a_b_cnt
);
264 __raw_writel(0xffff & ccnt
, &rg
->ccnt
);
268 * edma3_write_slot - write parameter RAM data for slot
269 * @base: base address of edma
270 * @slot: number of parameter RAM slot being modified
271 * @param: data to be written into parameter RAM slot
273 * Use this to assign all parameters of a transfer at once. This
274 * allows more efficient setup of transfers than issuing multiple
275 * calls to set up those parameters in small pieces, and provides
276 * complete control over all transfer options.
278 void edma3_write_slot(u32 base
, int slot
, struct edma3_slot_layout
*param
)
281 u32
*p
= (u32
*)param
;
282 u32
*addr
= (u32
*)(base
+ EDMA3_SL_BASE(slot
));
284 for (i
= 0; i
< sizeof(struct edma3_slot_layout
)/4; i
+= 4)
285 __raw_writel(*p
++, addr
++);
289 * edma3_read_slot - read parameter RAM data from slot
290 * @base: base address of edma
291 * @slot: number of parameter RAM slot being copied
292 * @param: where to store copy of parameter RAM data
294 * Use this to read data from a parameter RAM slot, perhaps to
295 * save them as a template for later reuse.
297 void edma3_read_slot(u32 base
, int slot
, struct edma3_slot_layout
*param
)
300 u32
*p
= (u32
*)param
;
301 u32
*addr
= (u32
*)(base
+ EDMA3_SL_BASE(slot
));
303 for (i
= 0; i
< sizeof(struct edma3_slot_layout
)/4; i
+= 4)
304 *p
++ = __raw_readl(addr
++);
307 void edma3_slot_configure(u32 base
, int slot
, struct edma3_slot_config
*cfg
)
309 struct edma3_slot_layout
*rg
;
311 rg
= (struct edma3_slot_layout
*)(base
+ EDMA3_SL_BASE(slot
));
313 __raw_writel(cfg
->opt
, &rg
->opt
);
314 __raw_writel(cfg
->src
, &rg
->src
);
315 __raw_writel((cfg
->bcnt
<< 16) | (cfg
->acnt
& 0xffff), &rg
->a_b_cnt
);
316 __raw_writel(cfg
->dst
, &rg
->dst
);
317 __raw_writel((cfg
->dst_bidx
<< 16) |
318 (cfg
->src_bidx
& 0xffff), &rg
->src_dst_bidx
);
319 __raw_writel((cfg
->bcntrld
<< 16) |
320 (cfg
->link
& 0xffff), &rg
->link_bcntrld
);
321 __raw_writel((cfg
->dst_cidx
<< 16) |
322 (cfg
->src_cidx
& 0xffff), &rg
->src_dst_cidx
);
323 __raw_writel(0xffff & cfg
->ccnt
, &rg
->ccnt
);
327 * edma3_check_for_transfer - check if transfer coplete by checking
328 * interrupt pending bit. Clear interrupt pending bit if complete.
329 * @base: base address of edma
330 * @cfg: pinter to struct edma3_channel_config which was passed
331 * to qedma3_start when you started qdma channel
333 * Return 0 if complete, 1 if not.
335 int edma3_check_for_transfer(u32 base
, struct edma3_channel_config
*cfg
)
341 if (cfg
->complete_code
< 32) {
342 ipr_base
= base
+ EDMA3_IPR
;
343 icr_base
= base
+ EDMA3_ICR
;
344 inum
= 1 << cfg
->complete_code
;
346 ipr_base
= base
+ EDMA3_IPRH
;
347 icr_base
= base
+ EDMA3_ICRH
;
348 inum
= 1 << (cfg
->complete_code
- 32);
351 /* check complete interrupt */
352 if (!(__raw_readl(ipr_base
) & inum
))
355 /* clean up the pending int bit */
356 __raw_writel(inum
, icr_base
);
362 * qedma3_stop - stops dma on the channel passed
363 * @base: base address of edma
364 * @cfg: pinter to struct edma3_channel_config which was passed
365 * to qedma3_start when you started qdma channel
367 void qedma3_stop(u32 base
, struct edma3_channel_config
*cfg
)
369 /* Disable qdma channel event */
370 __raw_writel(1 << cfg
->chnum
, base
+ EDMA3_QEECR
);
372 /* clean up the interrupt indication */
373 if (cfg
->complete_code
< 32)
374 __raw_writel(1 << cfg
->complete_code
, base
+ EDMA3_ICR
);
376 __raw_writel(1 << cfg
->complete_code
, base
+ EDMA3_ICRH
);
378 /* Clear missed event if set*/
379 __raw_writel(1 << cfg
->chnum
, base
+ EDMA3_QSECR
);
380 __raw_writel(1 << cfg
->chnum
, base
+ EDMA3_QEMCR
);
382 /* Clear the channel map */
383 __raw_writel(0, base
+ EDMA3_QCHMAP(cfg
->chnum
));