1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) ST-Ericsson SA 2007-2010
4 * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
5 * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
8 #include <linux/kernel.h>
9 #include <linux/dmaengine.h>
11 #include "ste_dma40.h"
12 #include "ste_dma40_ll.h"
14 static u8
d40_width_to_bits(enum dma_slave_buswidth width
)
16 if (width
== DMA_SLAVE_BUSWIDTH_1_BYTE
)
17 return STEDMA40_ESIZE_8_BIT
;
18 else if (width
== DMA_SLAVE_BUSWIDTH_2_BYTES
)
19 return STEDMA40_ESIZE_16_BIT
;
20 else if (width
== DMA_SLAVE_BUSWIDTH_8_BYTES
)
21 return STEDMA40_ESIZE_64_BIT
;
23 return STEDMA40_ESIZE_32_BIT
;
26 /* Sets up proper LCSP1 and LCSP3 register for a logical channel */
27 void d40_log_cfg(struct stedma40_chan_cfg
*cfg
,
28 u32
*lcsp1
, u32
*lcsp3
)
33 /* src is mem? -> increase address pos */
34 if (cfg
->dir
== DMA_MEM_TO_DEV
||
35 cfg
->dir
== DMA_MEM_TO_MEM
)
36 l1
|= BIT(D40_MEM_LCSP1_SCFG_INCR_POS
);
38 /* dst is mem? -> increase address pos */
39 if (cfg
->dir
== DMA_DEV_TO_MEM
||
40 cfg
->dir
== DMA_MEM_TO_MEM
)
41 l3
|= BIT(D40_MEM_LCSP3_DCFG_INCR_POS
);
43 /* src is hw? -> master port 1 */
44 if (cfg
->dir
== DMA_DEV_TO_MEM
||
45 cfg
->dir
== DMA_DEV_TO_DEV
)
46 l1
|= BIT(D40_MEM_LCSP1_SCFG_MST_POS
);
48 /* dst is hw? -> master port 1 */
49 if (cfg
->dir
== DMA_MEM_TO_DEV
||
50 cfg
->dir
== DMA_DEV_TO_DEV
)
51 l3
|= BIT(D40_MEM_LCSP3_DCFG_MST_POS
);
53 l3
|= BIT(D40_MEM_LCSP3_DCFG_EIM_POS
);
54 l3
|= cfg
->dst_info
.psize
<< D40_MEM_LCSP3_DCFG_PSIZE_POS
;
55 l3
|= d40_width_to_bits(cfg
->dst_info
.data_width
)
56 << D40_MEM_LCSP3_DCFG_ESIZE_POS
;
58 l1
|= BIT(D40_MEM_LCSP1_SCFG_EIM_POS
);
59 l1
|= cfg
->src_info
.psize
<< D40_MEM_LCSP1_SCFG_PSIZE_POS
;
60 l1
|= d40_width_to_bits(cfg
->src_info
.data_width
)
61 << D40_MEM_LCSP1_SCFG_ESIZE_POS
;
68 void d40_phy_cfg(struct stedma40_chan_cfg
*cfg
, u32
*src_cfg
, u32
*dst_cfg
)
73 if ((cfg
->dir
== DMA_DEV_TO_MEM
) ||
74 (cfg
->dir
== DMA_DEV_TO_DEV
)) {
75 /* Set master port to 1 */
76 src
|= BIT(D40_SREG_CFG_MST_POS
);
77 src
|= D40_TYPE_TO_EVENT(cfg
->dev_type
);
79 if (cfg
->src_info
.flow_ctrl
== STEDMA40_NO_FLOW_CTRL
)
80 src
|= BIT(D40_SREG_CFG_PHY_TM_POS
);
82 src
|= 3 << D40_SREG_CFG_PHY_TM_POS
;
84 if ((cfg
->dir
== DMA_MEM_TO_DEV
) ||
85 (cfg
->dir
== DMA_DEV_TO_DEV
)) {
86 /* Set master port to 1 */
87 dst
|= BIT(D40_SREG_CFG_MST_POS
);
88 dst
|= D40_TYPE_TO_EVENT(cfg
->dev_type
);
90 if (cfg
->dst_info
.flow_ctrl
== STEDMA40_NO_FLOW_CTRL
)
91 dst
|= BIT(D40_SREG_CFG_PHY_TM_POS
);
93 dst
|= 3 << D40_SREG_CFG_PHY_TM_POS
;
95 /* Interrupt on end of transfer for destination */
96 dst
|= BIT(D40_SREG_CFG_TIM_POS
);
98 /* Generate interrupt on error */
99 src
|= BIT(D40_SREG_CFG_EIM_POS
);
100 dst
|= BIT(D40_SREG_CFG_EIM_POS
);
103 if (cfg
->src_info
.psize
!= STEDMA40_PSIZE_PHY_1
) {
104 src
|= BIT(D40_SREG_CFG_PHY_PEN_POS
);
105 src
|= cfg
->src_info
.psize
<< D40_SREG_CFG_PSIZE_POS
;
107 if (cfg
->dst_info
.psize
!= STEDMA40_PSIZE_PHY_1
) {
108 dst
|= BIT(D40_SREG_CFG_PHY_PEN_POS
);
109 dst
|= cfg
->dst_info
.psize
<< D40_SREG_CFG_PSIZE_POS
;
113 src
|= d40_width_to_bits(cfg
->src_info
.data_width
)
114 << D40_SREG_CFG_ESIZE_POS
;
115 dst
|= d40_width_to_bits(cfg
->dst_info
.data_width
)
116 << D40_SREG_CFG_ESIZE_POS
;
118 /* Set the priority bit to high for the physical channel */
119 if (cfg
->high_priority
) {
120 src
|= BIT(D40_SREG_CFG_PRI_POS
);
121 dst
|= BIT(D40_SREG_CFG_PRI_POS
);
124 if (cfg
->src_info
.big_endian
)
125 src
|= BIT(D40_SREG_CFG_LBE_POS
);
126 if (cfg
->dst_info
.big_endian
)
127 dst
|= BIT(D40_SREG_CFG_LBE_POS
);
133 static int d40_phy_fill_lli(struct d40_phy_lli
*lli
,
138 struct stedma40_half_channel_info
*info
,
141 bool addr_inc
= flags
& LLI_ADDR_INC
;
142 bool term_int
= flags
& LLI_TERM_INT
;
143 unsigned int data_width
= info
->data_width
;
144 int psize
= info
->psize
;
147 if (psize
== STEDMA40_PSIZE_PHY_1
)
150 num_elems
= 2 << psize
;
152 /* Must be aligned */
153 if (!IS_ALIGNED(data
, data_width
))
156 /* Transfer size can't be smaller than (num_elms * elem_size) */
157 if (data_size
< num_elems
* data_width
)
160 /* The number of elements. IE now many chunks */
161 lli
->reg_elt
= (data_size
/ data_width
) << D40_SREG_ELEM_PHY_ECNT_POS
;
164 * Distance to next element sized entry.
165 * Usually the size of the element unless you want gaps.
168 lli
->reg_elt
|= data_width
<< D40_SREG_ELEM_PHY_EIDX_POS
;
170 /* Where the data is */
172 lli
->reg_cfg
= reg_cfg
;
174 /* If this scatter list entry is the last one, no next link */
176 lli
->reg_lnk
= BIT(D40_SREG_LNK_PHY_TCP_POS
);
178 lli
->reg_lnk
= next_lli
;
180 /* Set/clear interrupt generation on this link item.*/
182 lli
->reg_cfg
|= BIT(D40_SREG_CFG_TIM_POS
);
184 lli
->reg_cfg
&= ~BIT(D40_SREG_CFG_TIM_POS
);
187 * Post link - D40_SREG_LNK_PHY_PRE_POS = 0
188 * Relink happens after transfer completion.
194 static int d40_seg_size(int size
, int data_width1
, int data_width2
)
196 u32 max_w
= max(data_width1
, data_width2
);
197 u32 min_w
= min(data_width1
, data_width2
);
198 u32 seg_max
= ALIGN(STEDMA40_MAX_SEG_SIZE
* min_w
, max_w
);
200 if (seg_max
> STEDMA40_MAX_SEG_SIZE
)
206 if (size
<= 2 * seg_max
)
207 return ALIGN(size
/ 2, max_w
);
212 static struct d40_phy_lli
*
213 d40_phy_buf_to_lli(struct d40_phy_lli
*lli
, dma_addr_t addr
, u32 size
,
214 dma_addr_t lli_phys
, dma_addr_t first_phys
, u32 reg_cfg
,
215 struct stedma40_half_channel_info
*info
,
216 struct stedma40_half_channel_info
*otherinfo
,
219 bool lastlink
= flags
& LLI_LAST_LINK
;
220 bool addr_inc
= flags
& LLI_ADDR_INC
;
221 bool term_int
= flags
& LLI_TERM_INT
;
222 bool cyclic
= flags
& LLI_CYCLIC
;
224 dma_addr_t next
= lli_phys
;
225 int size_rest
= size
;
229 * This piece may be split up based on d40_seg_size(); we only want the
230 * term int on the last part.
233 flags
&= ~LLI_TERM_INT
;
236 size_seg
= d40_seg_size(size_rest
, info
->data_width
,
237 otherinfo
->data_width
);
238 size_rest
-= size_seg
;
240 if (size_rest
== 0 && term_int
)
241 flags
|= LLI_TERM_INT
;
243 if (size_rest
== 0 && lastlink
)
244 next
= cyclic
? first_phys
: 0;
246 next
= ALIGN(next
+ sizeof(struct d40_phy_lli
),
249 err
= d40_phy_fill_lli(lli
, addr
, size_seg
, next
,
250 reg_cfg
, info
, flags
);
266 int d40_phy_sg_to_lli(struct scatterlist
*sg
,
269 struct d40_phy_lli
*lli_sg
,
272 struct stedma40_half_channel_info
*info
,
273 struct stedma40_half_channel_info
*otherinfo
,
278 struct scatterlist
*current_sg
= sg
;
279 struct d40_phy_lli
*lli
= lli_sg
;
280 dma_addr_t l_phys
= lli_phys
;
283 flags
|= LLI_ADDR_INC
;
285 for_each_sg(sg
, current_sg
, sg_len
, i
) {
286 dma_addr_t sg_addr
= sg_dma_address(current_sg
);
287 unsigned int len
= sg_dma_len(current_sg
);
288 dma_addr_t dst
= target
?: sg_addr
;
290 total_size
+= sg_dma_len(current_sg
);
293 flags
|= LLI_TERM_INT
| LLI_LAST_LINK
;
295 l_phys
= ALIGN(lli_phys
+ (lli
- lli_sg
) *
296 sizeof(struct d40_phy_lli
), D40_LLI_ALIGN
);
298 lli
= d40_phy_buf_to_lli(lli
, dst
, len
, l_phys
, lli_phys
,
299 reg_cfg
, info
, otherinfo
, flags
);
309 /* DMA logical lli operations */
311 static void d40_log_lli_link(struct d40_log_lli
*lli_dst
,
312 struct d40_log_lli
*lli_src
,
313 int next
, unsigned int flags
)
315 bool interrupt
= flags
& LLI_TERM_INT
;
319 if (next
!= -EINVAL
) {
325 lli_dst
->lcsp13
|= D40_MEM_LCSP1_SCFG_TIM_MASK
;
326 lli_dst
->lcsp13
|= D40_MEM_LCSP3_DTCP_MASK
;
329 lli_src
->lcsp13
= (lli_src
->lcsp13
& ~D40_MEM_LCSP1_SLOS_MASK
) |
330 (slos
<< D40_MEM_LCSP1_SLOS_POS
);
332 lli_dst
->lcsp13
= (lli_dst
->lcsp13
& ~D40_MEM_LCSP1_SLOS_MASK
) |
333 (dlos
<< D40_MEM_LCSP1_SLOS_POS
);
336 void d40_log_lli_lcpa_write(struct d40_log_lli_full
*lcpa
,
337 struct d40_log_lli
*lli_dst
,
338 struct d40_log_lli
*lli_src
,
339 int next
, unsigned int flags
)
341 d40_log_lli_link(lli_dst
, lli_src
, next
, flags
);
343 writel_relaxed(lli_src
->lcsp02
, &lcpa
[0].lcsp0
);
344 writel_relaxed(lli_src
->lcsp13
, &lcpa
[0].lcsp1
);
345 writel_relaxed(lli_dst
->lcsp02
, &lcpa
[0].lcsp2
);
346 writel_relaxed(lli_dst
->lcsp13
, &lcpa
[0].lcsp3
);
349 void d40_log_lli_lcla_write(struct d40_log_lli
*lcla
,
350 struct d40_log_lli
*lli_dst
,
351 struct d40_log_lli
*lli_src
,
352 int next
, unsigned int flags
)
354 d40_log_lli_link(lli_dst
, lli_src
, next
, flags
);
356 writel_relaxed(lli_src
->lcsp02
, &lcla
[0].lcsp02
);
357 writel_relaxed(lli_src
->lcsp13
, &lcla
[0].lcsp13
);
358 writel_relaxed(lli_dst
->lcsp02
, &lcla
[1].lcsp02
);
359 writel_relaxed(lli_dst
->lcsp13
, &lcla
[1].lcsp13
);
362 static void d40_log_fill_lli(struct d40_log_lli
*lli
,
363 dma_addr_t data
, u32 data_size
,
368 bool addr_inc
= flags
& LLI_ADDR_INC
;
370 lli
->lcsp13
= reg_cfg
;
372 /* The number of elements to transfer */
373 lli
->lcsp02
= ((data_size
/ data_width
) <<
374 D40_MEM_LCSP0_ECNT_POS
) & D40_MEM_LCSP0_ECNT_MASK
;
376 BUG_ON((data_size
/ data_width
) > STEDMA40_MAX_SEG_SIZE
);
378 /* 16 LSBs address of the current element */
379 lli
->lcsp02
|= data
& D40_MEM_LCSP0_SPTR_MASK
;
380 /* 16 MSBs address of the current element */
381 lli
->lcsp13
|= data
& D40_MEM_LCSP1_SPTR_MASK
;
384 lli
->lcsp13
|= D40_MEM_LCSP1_SCFG_INCR_MASK
;
388 static struct d40_log_lli
*d40_log_buf_to_lli(struct d40_log_lli
*lli_sg
,
391 u32 lcsp13
, /* src or dst*/
396 bool addr_inc
= flags
& LLI_ADDR_INC
;
397 struct d40_log_lli
*lli
= lli_sg
;
398 int size_rest
= size
;
402 size_seg
= d40_seg_size(size_rest
, data_width1
, data_width2
);
403 size_rest
-= size_seg
;
405 d40_log_fill_lli(lli
,
418 int d40_log_sg_to_lli(struct scatterlist
*sg
,
421 struct d40_log_lli
*lli_sg
,
422 u32 lcsp13
, /* src or dst*/
423 u32 data_width1
, u32 data_width2
)
426 struct scatterlist
*current_sg
= sg
;
428 struct d40_log_lli
*lli
= lli_sg
;
429 unsigned long flags
= 0;
432 flags
|= LLI_ADDR_INC
;
434 for_each_sg(sg
, current_sg
, sg_len
, i
) {
435 dma_addr_t sg_addr
= sg_dma_address(current_sg
);
436 unsigned int len
= sg_dma_len(current_sg
);
437 dma_addr_t addr
= dev_addr
?: sg_addr
;
439 total_size
+= sg_dma_len(current_sg
);
441 lli
= d40_log_buf_to_lli(lli
, addr
, len
,