Blame view

drivers/dma/ste_dma40_ll.c 11 KB
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
1
  /*
767a9675c   Jonas Aaberg   DMAENGINE: ste_dm...
2
   * Copyright (C) ST-Ericsson SA 2007-2010
d49278e33   Per Forlin   dmaengine: dma40:...
3
   * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
767a9675c   Jonas Aaberg   DMAENGINE: ste_dm...
4
   * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
5
   * License terms: GNU General Public License (GPL) version 2
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
   */
  
  #include <linux/kernel.h>
  #include <plat/ste_dma40.h>
  
  #include "ste_dma40_ll.h"
  
  /* Sets up proper LCSP1 and LCSP3 register for a logical channel */
  void d40_log_cfg(struct stedma40_chan_cfg *cfg,
  		 u32 *lcsp1, u32 *lcsp3)
  {
  	u32 l3 = 0; /* dst */
  	u32 l1 = 0; /* src */
  
  	/* src is mem? -> increase address pos */
  	if (cfg->dir ==  STEDMA40_MEM_TO_PERIPH ||
  	    cfg->dir ==  STEDMA40_MEM_TO_MEM)
  		l1 |= 1 << D40_MEM_LCSP1_SCFG_INCR_POS;
  
  	/* dst is mem? -> increase address pos */
  	if (cfg->dir ==  STEDMA40_PERIPH_TO_MEM ||
  	    cfg->dir ==  STEDMA40_MEM_TO_MEM)
  		l3 |= 1 << D40_MEM_LCSP3_DCFG_INCR_POS;
  
  	/* src is hw? -> master port 1 */
  	if (cfg->dir ==  STEDMA40_PERIPH_TO_MEM ||
  	    cfg->dir ==  STEDMA40_PERIPH_TO_PERIPH)
  		l1 |= 1 << D40_MEM_LCSP1_SCFG_MST_POS;
  
  	/* dst is hw? -> master port 1 */
  	if (cfg->dir ==  STEDMA40_MEM_TO_PERIPH ||
  	    cfg->dir ==  STEDMA40_PERIPH_TO_PERIPH)
  		l3 |= 1 << D40_MEM_LCSP3_DCFG_MST_POS;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
39
40
41
  	l3 |= 1 << D40_MEM_LCSP3_DCFG_EIM_POS;
  	l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS;
  	l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
42
43
44
45
  
  	l1 |= 1 << D40_MEM_LCSP1_SCFG_EIM_POS;
  	l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS;
  	l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  
  	*lcsp1 = l1;
  	*lcsp3 = l3;
  
  }
  
  /* Sets up SRC and DST CFG register for both logical and physical channels */
  void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
  		 u32 *src_cfg, u32 *dst_cfg, bool is_log)
  {
  	u32 src = 0;
  	u32 dst = 0;
  
  	if (!is_log) {
  		/* Physical channel */
  		if ((cfg->dir ==  STEDMA40_PERIPH_TO_MEM) ||
  		    (cfg->dir == STEDMA40_PERIPH_TO_PERIPH)) {
  			/* Set master port to 1 */
  			src |= 1 << D40_SREG_CFG_MST_POS;
  			src |= D40_TYPE_TO_EVENT(cfg->src_dev_type);
  
  			if (cfg->src_info.flow_ctrl == STEDMA40_NO_FLOW_CTRL)
  				src |= 1 << D40_SREG_CFG_PHY_TM_POS;
  			else
  				src |= 3 << D40_SREG_CFG_PHY_TM_POS;
  		}
  		if ((cfg->dir ==  STEDMA40_MEM_TO_PERIPH) ||
  		    (cfg->dir == STEDMA40_PERIPH_TO_PERIPH)) {
  			/* Set master port to 1 */
  			dst |= 1 << D40_SREG_CFG_MST_POS;
  			dst |= D40_TYPE_TO_EVENT(cfg->dst_dev_type);
  
  			if (cfg->dst_info.flow_ctrl == STEDMA40_NO_FLOW_CTRL)
  				dst |= 1 << D40_SREG_CFG_PHY_TM_POS;
  			else
  				dst |= 3 << D40_SREG_CFG_PHY_TM_POS;
  		}
  		/* Interrupt on end of transfer for destination */
  		dst |= 1 << D40_SREG_CFG_TIM_POS;
  
  		/* Generate interrupt on error */
  		src |= 1 << D40_SREG_CFG_EIM_POS;
  		dst |= 1 << D40_SREG_CFG_EIM_POS;
  
  		/* PSIZE */
  		if (cfg->src_info.psize != STEDMA40_PSIZE_PHY_1) {
  			src |= 1 << D40_SREG_CFG_PHY_PEN_POS;
  			src |= cfg->src_info.psize << D40_SREG_CFG_PSIZE_POS;
  		}
  		if (cfg->dst_info.psize != STEDMA40_PSIZE_PHY_1) {
  			dst |= 1 << D40_SREG_CFG_PHY_PEN_POS;
  			dst |= cfg->dst_info.psize << D40_SREG_CFG_PSIZE_POS;
  		}
  
  		/* Element size */
  		src |= cfg->src_info.data_width << D40_SREG_CFG_ESIZE_POS;
  		dst |= cfg->dst_info.data_width << D40_SREG_CFG_ESIZE_POS;
  
  	} else {
  		/* Logical channel */
  		dst |= 1 << D40_SREG_CFG_LOG_GIM_POS;
  		src |= 1 << D40_SREG_CFG_LOG_GIM_POS;
  	}
730c18716   Rabin Vincent   ste_dma40: move p...
109
  	if (cfg->high_priority) {
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
110
111
112
  		src |= 1 << D40_SREG_CFG_PRI_POS;
  		dst |= 1 << D40_SREG_CFG_PRI_POS;
  	}
51f5d744e   Rabin Vincent   ste_dma40: remove...
113
114
115
116
  	if (cfg->src_info.big_endian)
  		src |= 1 << D40_SREG_CFG_LBE_POS;
  	if (cfg->dst_info.big_endian)
  		dst |= 1 << D40_SREG_CFG_LBE_POS;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
117
118
119
120
  
  	*src_cfg = src;
  	*dst_cfg = dst;
  }
d49278e33   Per Forlin   dmaengine: dma40:...
121
122
123
  static int d40_phy_fill_lli(struct d40_phy_lli *lli,
  			    dma_addr_t data,
  			    u32 data_size,
d49278e33   Per Forlin   dmaengine: dma40:...
124
125
  			    dma_addr_t next_lli,
  			    u32 reg_cfg,
7f933bed9   Rabin Vincent   dma40: use flags ...
126
127
  			    struct stedma40_half_channel_info *info,
  			    unsigned int flags)
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
128
  {
7f933bed9   Rabin Vincent   dma40: use flags ...
129
130
  	bool addr_inc = flags & LLI_ADDR_INC;
  	bool term_int = flags & LLI_TERM_INT;
cc31b6f79   Rabin Vincent   dma40: pass the i...
131
132
  	unsigned int data_width = info->data_width;
  	int psize = info->psize;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
133
134
135
136
137
138
  	int num_elems;
  
  	if (psize == STEDMA40_PSIZE_PHY_1)
  		num_elems = 1;
  	else
  		num_elems = 2 << psize;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  	/* Must be aligned */
  	if (!IS_ALIGNED(data, 0x1 << data_width))
  		return -EINVAL;
  
  	/* Transfer size can't be smaller than (num_elms * elem_size) */
  	if (data_size < num_elems * (0x1 << data_width))
  		return -EINVAL;
  
  	/* The number of elements. IE now many chunks */
  	lli->reg_elt = (data_size >> data_width) << D40_SREG_ELEM_PHY_ECNT_POS;
  
  	/*
  	 * Distance to next element sized entry.
  	 * Usually the size of the element unless you want gaps.
  	 */
7f933bed9   Rabin Vincent   dma40: use flags ...
154
  	if (addr_inc)
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  		lli->reg_elt |= (0x1 << data_width) <<
  			D40_SREG_ELEM_PHY_EIDX_POS;
  
  	/* Where the data is */
  	lli->reg_ptr = data;
  	lli->reg_cfg = reg_cfg;
  
  	/* If this scatter list entry is the last one, no next link */
  	if (next_lli == 0)
  		lli->reg_lnk = 0x1 << D40_SREG_LNK_PHY_TCP_POS;
  	else
  		lli->reg_lnk = next_lli;
  
  	/* Set/clear interrupt generation on this link item.*/
  	if (term_int)
  		lli->reg_cfg |= 0x1 << D40_SREG_CFG_TIM_POS;
  	else
  		lli->reg_cfg &= ~(0x1 << D40_SREG_CFG_TIM_POS);
  
  	/* Post link */
  	lli->reg_lnk |= 0 << D40_SREG_LNK_PHY_PRE_POS;
  
  	return 0;
  }
d49278e33   Per Forlin   dmaengine: dma40:...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  static int d40_seg_size(int size, int data_width1, int data_width2)
  {
  	u32 max_w = max(data_width1, data_width2);
  	u32 min_w = min(data_width1, data_width2);
  	u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w);
  
  	if (seg_max > STEDMA40_MAX_SEG_SIZE)
  		seg_max -= (1 << max_w);
  
  	if (size <= seg_max)
  		return size;
  
  	if (size <= 2 * seg_max)
  		return ALIGN(size / 2, 1 << max_w);
  
  	return seg_max;
  }
cc31b6f79   Rabin Vincent   dma40: pass the i...
196
197
  static struct d40_phy_lli *
  d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size,
0c842b551   Rabin Vincent   dma40: cyclic xfe...
198
  		   dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg,
7f933bed9   Rabin Vincent   dma40: use flags ...
199
200
201
  		   struct stedma40_half_channel_info *info,
  		   struct stedma40_half_channel_info *otherinfo,
  		   unsigned long flags)
d49278e33   Per Forlin   dmaengine: dma40:...
202
  {
0c842b551   Rabin Vincent   dma40: cyclic xfe...
203
  	bool lastlink = flags & LLI_LAST_LINK;
7f933bed9   Rabin Vincent   dma40: use flags ...
204
205
  	bool addr_inc = flags & LLI_ADDR_INC;
  	bool term_int = flags & LLI_TERM_INT;
0c842b551   Rabin Vincent   dma40: cyclic xfe...
206
  	bool cyclic = flags & LLI_CYCLIC;
d49278e33   Per Forlin   dmaengine: dma40:...
207
208
209
210
  	int err;
  	dma_addr_t next = lli_phys;
  	int size_rest = size;
  	int size_seg = 0;
7f933bed9   Rabin Vincent   dma40: use flags ...
211
212
213
214
215
216
  	/*
  	 * This piece may be split up based on d40_seg_size(); we only want the
  	 * term int on the last part.
  	 */
  	if (term_int)
  		flags &= ~LLI_TERM_INT;
d49278e33   Per Forlin   dmaengine: dma40:...
217
  	do {
cc31b6f79   Rabin Vincent   dma40: pass the i...
218
219
  		size_seg = d40_seg_size(size_rest, info->data_width,
  					otherinfo->data_width);
d49278e33   Per Forlin   dmaengine: dma40:...
220
  		size_rest -= size_seg;
0c842b551   Rabin Vincent   dma40: cyclic xfe...
221
  		if (size_rest == 0 && term_int)
7f933bed9   Rabin Vincent   dma40: use flags ...
222
  			flags |= LLI_TERM_INT;
0c842b551   Rabin Vincent   dma40: cyclic xfe...
223
224
225
226
  
  		if (size_rest == 0 && lastlink)
  			next = cyclic ? first_phys : 0;
  		else
d49278e33   Per Forlin   dmaengine: dma40:...
227
228
  			next = ALIGN(next + sizeof(struct d40_phy_lli),
  				     D40_LLI_ALIGN);
7f933bed9   Rabin Vincent   dma40: use flags ...
229
230
  		err = d40_phy_fill_lli(lli, addr, size_seg, next,
  				       reg_cfg, info, flags);
d49278e33   Per Forlin   dmaengine: dma40:...
231
232
233
234
235
  
  		if (err)
  			goto err;
  
  		lli++;
7f933bed9   Rabin Vincent   dma40: use flags ...
236
  		if (addr_inc)
d49278e33   Per Forlin   dmaengine: dma40:...
237
238
239
240
241
242
243
244
  			addr += size_seg;
  	} while (size_rest);
  
  	return lli;
  
   err:
  	return NULL;
  }
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
245
246
247
  int d40_phy_sg_to_lli(struct scatterlist *sg,
  		      int sg_len,
  		      dma_addr_t target,
d49278e33   Per Forlin   dmaengine: dma40:...
248
  		      struct d40_phy_lli *lli_sg,
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
249
250
  		      dma_addr_t lli_phys,
  		      u32 reg_cfg,
cc31b6f79   Rabin Vincent   dma40: pass the i...
251
  		      struct stedma40_half_channel_info *info,
0c842b551   Rabin Vincent   dma40: cyclic xfe...
252
253
  		      struct stedma40_half_channel_info *otherinfo,
  		      unsigned long flags)
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
254
255
256
257
  {
  	int total_size = 0;
  	int i;
  	struct scatterlist *current_sg = sg;
d49278e33   Per Forlin   dmaengine: dma40:...
258
259
  	struct d40_phy_lli *lli = lli_sg;
  	dma_addr_t l_phys = lli_phys;
7f933bed9   Rabin Vincent   dma40: use flags ...
260
261
262
  
  	if (!target)
  		flags |= LLI_ADDR_INC;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
263
264
  
  	for_each_sg(sg, current_sg, sg_len, i) {
7f933bed9   Rabin Vincent   dma40: use flags ...
265
266
267
  		dma_addr_t sg_addr = sg_dma_address(current_sg);
  		unsigned int len = sg_dma_len(current_sg);
  		dma_addr_t dst = target ?: sg_addr;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
268
269
  
  		total_size += sg_dma_len(current_sg);
7f933bed9   Rabin Vincent   dma40: use flags ...
270
  		if (i == sg_len - 1)
0c842b551   Rabin Vincent   dma40: cyclic xfe...
271
  			flags |= LLI_TERM_INT | LLI_LAST_LINK;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
272

d49278e33   Per Forlin   dmaengine: dma40:...
273
274
  		l_phys = ALIGN(lli_phys + (lli - lli_sg) *
  			       sizeof(struct d40_phy_lli), D40_LLI_ALIGN);
0c842b551   Rabin Vincent   dma40: cyclic xfe...
275
  		lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys,
7f933bed9   Rabin Vincent   dma40: use flags ...
276
  					 reg_cfg, info, otherinfo, flags);
d49278e33   Per Forlin   dmaengine: dma40:...
277
278
  		if (lli == NULL)
  			return -EINVAL;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
279
280
281
  	}
  
  	return total_size;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
282
  }
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
283
  /* DMA logical lli operations */
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
284
285
  static void d40_log_lli_link(struct d40_log_lli *lli_dst,
  			     struct d40_log_lli *lli_src,
0c842b551   Rabin Vincent   dma40: cyclic xfe...
286
  			     int next, unsigned int flags)
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
287
  {
0c842b551   Rabin Vincent   dma40: cyclic xfe...
288
  	bool interrupt = flags & LLI_TERM_INT;
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
289
290
291
292
293
294
  	u32 slos = 0;
  	u32 dlos = 0;
  
  	if (next != -EINVAL) {
  		slos = next * 2;
  		dlos = next * 2 + 1;
0c842b551   Rabin Vincent   dma40: cyclic xfe...
295
296
297
  	}
  
  	if (interrupt) {
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  		lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
  		lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
  	}
  
  	lli_src->lcsp13 = (lli_src->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
  		(slos << D40_MEM_LCSP1_SLOS_POS);
  
  	lli_dst->lcsp13 = (lli_dst->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
  		(dlos << D40_MEM_LCSP1_SLOS_POS);
  }
  
  void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
  			   struct d40_log_lli *lli_dst,
  			   struct d40_log_lli *lli_src,
0c842b551   Rabin Vincent   dma40: cyclic xfe...
312
  			   int next, unsigned int flags)
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
313
  {
0c842b551   Rabin Vincent   dma40: cyclic xfe...
314
  	d40_log_lli_link(lli_dst, lli_src, next, flags);
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
315
316
317
318
319
320
321
322
323
324
  
  	writel(lli_src->lcsp02, &lcpa[0].lcsp0);
  	writel(lli_src->lcsp13, &lcpa[0].lcsp1);
  	writel(lli_dst->lcsp02, &lcpa[0].lcsp2);
  	writel(lli_dst->lcsp13, &lcpa[0].lcsp3);
  }
  
  void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
  			   struct d40_log_lli *lli_dst,
  			   struct d40_log_lli *lli_src,
0c842b551   Rabin Vincent   dma40: cyclic xfe...
325
  			   int next, unsigned int flags)
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
326
  {
0c842b551   Rabin Vincent   dma40: cyclic xfe...
327
  	d40_log_lli_link(lli_dst, lli_src, next, flags);
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
328
329
330
331
332
333
  
  	writel(lli_src->lcsp02, &lcla[0].lcsp02);
  	writel(lli_src->lcsp13, &lcla[0].lcsp13);
  	writel(lli_dst->lcsp02, &lcla[1].lcsp02);
  	writel(lli_dst->lcsp13, &lcla[1].lcsp13);
  }
d49278e33   Per Forlin   dmaengine: dma40:...
334
335
336
337
  static void d40_log_fill_lli(struct d40_log_lli *lli,
  			     dma_addr_t data, u32 data_size,
  			     u32 reg_cfg,
  			     u32 data_width,
7f933bed9   Rabin Vincent   dma40: use flags ...
338
  			     unsigned int flags)
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
339
  {
7f933bed9   Rabin Vincent   dma40: use flags ...
340
  	bool addr_inc = flags & LLI_ADDR_INC;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
341
342
343
344
345
  	lli->lcsp13 = reg_cfg;
  
  	/* The number of elements to transfer */
  	lli->lcsp02 = ((data_size >> data_width) <<
  		       D40_MEM_LCSP0_ECNT_POS) & D40_MEM_LCSP0_ECNT_MASK;
d49278e33   Per Forlin   dmaengine: dma40:...
346
347
  
  	BUG_ON((data_size >> data_width) > STEDMA40_MAX_SEG_SIZE);
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
348
349
350
351
352
353
354
  	/* 16 LSBs address of the current element */
  	lli->lcsp02 |= data & D40_MEM_LCSP0_SPTR_MASK;
  	/* 16 MSBs address of the current element */
  	lli->lcsp13 |= data & D40_MEM_LCSP1_SPTR_MASK;
  
  	if (addr_inc)
  		lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
355
  }
1f7622ca5   Rabin Vincent   dma40: make d40_l...
356
  static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
d49278e33   Per Forlin   dmaengine: dma40:...
357
358
359
360
361
  				       dma_addr_t addr,
  				       int size,
  				       u32 lcsp13, /* src or dst*/
  				       u32 data_width1,
  				       u32 data_width2,
7f933bed9   Rabin Vincent   dma40: use flags ...
362
  				       unsigned int flags)
d49278e33   Per Forlin   dmaengine: dma40:...
363
  {
7f933bed9   Rabin Vincent   dma40: use flags ...
364
  	bool addr_inc = flags & LLI_ADDR_INC;
d49278e33   Per Forlin   dmaengine: dma40:...
365
366
367
368
369
370
371
372
373
374
375
376
  	struct d40_log_lli *lli = lli_sg;
  	int size_rest = size;
  	int size_seg = 0;
  
  	do {
  		size_seg = d40_seg_size(size_rest, data_width1, data_width2);
  		size_rest -= size_seg;
  
  		d40_log_fill_lli(lli,
  				 addr,
  				 size_seg,
  				 lcsp13, data_width1,
7f933bed9   Rabin Vincent   dma40: use flags ...
377
  				 flags);
d49278e33   Per Forlin   dmaengine: dma40:...
378
379
380
381
382
383
384
  		if (addr_inc)
  			addr += size_seg;
  		lli++;
  	} while (size_rest);
  
  	return lli;
  }
698e4732e   Jonas Aaberg   DMAENGINE: ste_dm...
385
  int d40_log_sg_to_lli(struct scatterlist *sg,
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
386
  		      int sg_len,
5ed04b857   Rabin Vincent   dma40: unify d40_...
387
  		      dma_addr_t dev_addr,
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
388
389
  		      struct d40_log_lli *lli_sg,
  		      u32 lcsp13, /* src or dst*/
d49278e33   Per Forlin   dmaengine: dma40:...
390
  		      u32 data_width1, u32 data_width2)
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
391
392
393
394
  {
  	int total_size = 0;
  	struct scatterlist *current_sg = sg;
  	int i;
d49278e33   Per Forlin   dmaengine: dma40:...
395
  	struct d40_log_lli *lli = lli_sg;
7f933bed9   Rabin Vincent   dma40: use flags ...
396
397
398
399
  	unsigned long flags = 0;
  
  	if (!dev_addr)
  		flags |= LLI_ADDR_INC;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
400
401
  
  	for_each_sg(sg, current_sg, sg_len, i) {
5ed04b857   Rabin Vincent   dma40: unify d40_...
402
403
404
  		dma_addr_t sg_addr = sg_dma_address(current_sg);
  		unsigned int len = sg_dma_len(current_sg);
  		dma_addr_t addr = dev_addr ?: sg_addr;
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
405
  		total_size += sg_dma_len(current_sg);
5ed04b857   Rabin Vincent   dma40: unify d40_...
406
407
  
  		lli = d40_log_buf_to_lli(lli, addr, len,
d49278e33   Per Forlin   dmaengine: dma40:...
408
  					 lcsp13,
5ed04b857   Rabin Vincent   dma40: unify d40_...
409
410
  					 data_width1,
  					 data_width2,
7f933bed9   Rabin Vincent   dma40: use flags ...
411
  					 flags);
8d318a50b   Linus Walleij   DMAENGINE: Suppor...
412
  	}
5ed04b857   Rabin Vincent   dma40: unify d40_...
413

8d318a50b   Linus Walleij   DMAENGINE: Suppor...
414
415
  	return total_size;
  }