aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ste_dma40_ll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/ste_dma40_ll.c')
-rw-r--r--drivers/dma/ste_dma40_ll.c218
1 files changed, 79 insertions, 139 deletions
diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c
index 0b096a38322d..cad9e1daedff 100644
--- a/drivers/dma/ste_dma40_ll.c
+++ b/drivers/dma/ste_dma40_ll.c
@@ -125,13 +125,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
125static int d40_phy_fill_lli(struct d40_phy_lli *lli, 125static int d40_phy_fill_lli(struct d40_phy_lli *lli,
126 dma_addr_t data, 126 dma_addr_t data,
127 u32 data_size, 127 u32 data_size,
128 int psize,
129 dma_addr_t next_lli, 128 dma_addr_t next_lli,
130 u32 reg_cfg, 129 u32 reg_cfg,
131 bool term_int, 130 struct stedma40_half_channel_info *info,
132 u32 data_width, 131 unsigned int flags)
133 bool is_device)
134{ 132{
133 bool addr_inc = flags & LLI_ADDR_INC;
134 bool term_int = flags & LLI_TERM_INT;
135 unsigned int data_width = info->data_width;
136 int psize = info->psize;
135 int num_elems; 137 int num_elems;
136 138
137 if (psize == STEDMA40_PSIZE_PHY_1) 139 if (psize == STEDMA40_PSIZE_PHY_1)
@@ -154,7 +156,7 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli,
154 * Distance to next element sized entry. 156 * Distance to next element sized entry.
155 * Usually the size of the element unless you want gaps. 157 * Usually the size of the element unless you want gaps.
156 */ 158 */
157 if (!is_device) 159 if (addr_inc)
158 lli->reg_elt |= (0x1 << data_width) << 160 lli->reg_elt |= (0x1 << data_width) <<
159 D40_SREG_ELEM_PHY_EIDX_POS; 161 D40_SREG_ELEM_PHY_EIDX_POS;
160 162
@@ -198,47 +200,51 @@ static int d40_seg_size(int size, int data_width1, int data_width2)
198 return seg_max; 200 return seg_max;
199} 201}
200 202
201struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, 203static struct d40_phy_lli *
202 dma_addr_t addr, 204d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size,
203 u32 size, 205 dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg,
204 int psize, 206 struct stedma40_half_channel_info *info,
205 dma_addr_t lli_phys, 207 struct stedma40_half_channel_info *otherinfo,
206 u32 reg_cfg, 208 unsigned long flags)
207 bool term_int,
208 u32 data_width1,
209 u32 data_width2,
210 bool is_device)
211{ 209{
210 bool lastlink = flags & LLI_LAST_LINK;
211 bool addr_inc = flags & LLI_ADDR_INC;
212 bool term_int = flags & LLI_TERM_INT;
213 bool cyclic = flags & LLI_CYCLIC;
212 int err; 214 int err;
213 dma_addr_t next = lli_phys; 215 dma_addr_t next = lli_phys;
214 int size_rest = size; 216 int size_rest = size;
215 int size_seg = 0; 217 int size_seg = 0;
216 218
219 /*
220 * This piece may be split up based on d40_seg_size(); we only want the
221 * term int on the last part.
222 */
223 if (term_int)
224 flags &= ~LLI_TERM_INT;
225
217 do { 226 do {
218 size_seg = d40_seg_size(size_rest, data_width1, data_width2); 227 size_seg = d40_seg_size(size_rest, info->data_width,
228 otherinfo->data_width);
219 size_rest -= size_seg; 229 size_rest -= size_seg;
220 230
221 if (term_int && size_rest == 0) 231 if (size_rest == 0 && term_int)
222 next = 0; 232 flags |= LLI_TERM_INT;
233
234 if (size_rest == 0 && lastlink)
235 next = cyclic ? first_phys : 0;
223 else 236 else
224 next = ALIGN(next + sizeof(struct d40_phy_lli), 237 next = ALIGN(next + sizeof(struct d40_phy_lli),
225 D40_LLI_ALIGN); 238 D40_LLI_ALIGN);
226 239
227 err = d40_phy_fill_lli(lli, 240 err = d40_phy_fill_lli(lli, addr, size_seg, next,
228 addr, 241 reg_cfg, info, flags);
229 size_seg,
230 psize,
231 next,
232 reg_cfg,
233 !next,
234 data_width1,
235 is_device);
236 242
237 if (err) 243 if (err)
238 goto err; 244 goto err;
239 245
240 lli++; 246 lli++;
241 if (!is_device) 247 if (addr_inc)
242 addr += size_seg; 248 addr += size_seg;
243 } while (size_rest); 249 } while (size_rest);
244 250
@@ -254,39 +260,35 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
254 struct d40_phy_lli *lli_sg, 260 struct d40_phy_lli *lli_sg,
255 dma_addr_t lli_phys, 261 dma_addr_t lli_phys,
256 u32 reg_cfg, 262 u32 reg_cfg,
257 u32 data_width1, 263 struct stedma40_half_channel_info *info,
258 u32 data_width2, 264 struct stedma40_half_channel_info *otherinfo,
259 int psize) 265 unsigned long flags)
260{ 266{
261 int total_size = 0; 267 int total_size = 0;
262 int i; 268 int i;
263 struct scatterlist *current_sg = sg; 269 struct scatterlist *current_sg = sg;
264 dma_addr_t dst;
265 struct d40_phy_lli *lli = lli_sg; 270 struct d40_phy_lli *lli = lli_sg;
266 dma_addr_t l_phys = lli_phys; 271 dma_addr_t l_phys = lli_phys;
267 272
273 if (!target)
274 flags |= LLI_ADDR_INC;
275
268 for_each_sg(sg, current_sg, sg_len, i) { 276 for_each_sg(sg, current_sg, sg_len, i) {
277 dma_addr_t sg_addr = sg_dma_address(current_sg);
278 unsigned int len = sg_dma_len(current_sg);
279 dma_addr_t dst = target ?: sg_addr;
269 280
270 total_size += sg_dma_len(current_sg); 281 total_size += sg_dma_len(current_sg);
271 282
272 if (target) 283 if (i == sg_len - 1)
273 dst = target; 284 flags |= LLI_TERM_INT | LLI_LAST_LINK;
274 else
275 dst = sg_phys(current_sg);
276 285
277 l_phys = ALIGN(lli_phys + (lli - lli_sg) * 286 l_phys = ALIGN(lli_phys + (lli - lli_sg) *
278 sizeof(struct d40_phy_lli), D40_LLI_ALIGN); 287 sizeof(struct d40_phy_lli), D40_LLI_ALIGN);
279 288
280 lli = d40_phy_buf_to_lli(lli, 289 lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys,
281 dst, 290 reg_cfg, info, otherinfo, flags);
282 sg_dma_len(current_sg), 291
283 psize,
284 l_phys,
285 reg_cfg,
286 sg_len - 1 == i,
287 data_width1,
288 data_width2,
289 target == dst);
290 if (lli == NULL) 292 if (lli == NULL)
291 return -EINVAL; 293 return -EINVAL;
292 } 294 }
@@ -295,45 +297,22 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
295} 297}
296 298
297 299
298void d40_phy_lli_write(void __iomem *virtbase,
299 u32 phy_chan_num,
300 struct d40_phy_lli *lli_dst,
301 struct d40_phy_lli *lli_src)
302{
303
304 writel(lli_src->reg_cfg, virtbase + D40_DREG_PCBASE +
305 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSCFG);
306 writel(lli_src->reg_elt, virtbase + D40_DREG_PCBASE +
307 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT);
308 writel(lli_src->reg_ptr, virtbase + D40_DREG_PCBASE +
309 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSPTR);
310 writel(lli_src->reg_lnk, virtbase + D40_DREG_PCBASE +
311 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSLNK);
312
313 writel(lli_dst->reg_cfg, virtbase + D40_DREG_PCBASE +
314 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDCFG);
315 writel(lli_dst->reg_elt, virtbase + D40_DREG_PCBASE +
316 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT);
317 writel(lli_dst->reg_ptr, virtbase + D40_DREG_PCBASE +
318 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDPTR);
319 writel(lli_dst->reg_lnk, virtbase + D40_DREG_PCBASE +
320 phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDLNK);
321
322}
323
324/* DMA logical lli operations */ 300/* DMA logical lli operations */
325 301
326static void d40_log_lli_link(struct d40_log_lli *lli_dst, 302static void d40_log_lli_link(struct d40_log_lli *lli_dst,
327 struct d40_log_lli *lli_src, 303 struct d40_log_lli *lli_src,
328 int next) 304 int next, unsigned int flags)
329{ 305{
306 bool interrupt = flags & LLI_TERM_INT;
330 u32 slos = 0; 307 u32 slos = 0;
331 u32 dlos = 0; 308 u32 dlos = 0;
332 309
333 if (next != -EINVAL) { 310 if (next != -EINVAL) {
334 slos = next * 2; 311 slos = next * 2;
335 dlos = next * 2 + 1; 312 dlos = next * 2 + 1;
336 } else { 313 }
314
315 if (interrupt) {
337 lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; 316 lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
338 lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; 317 lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
339 } 318 }
@@ -348,9 +327,9 @@ static void d40_log_lli_link(struct d40_log_lli *lli_dst,
348void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, 327void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
349 struct d40_log_lli *lli_dst, 328 struct d40_log_lli *lli_dst,
350 struct d40_log_lli *lli_src, 329 struct d40_log_lli *lli_src,
351 int next) 330 int next, unsigned int flags)
352{ 331{
353 d40_log_lli_link(lli_dst, lli_src, next); 332 d40_log_lli_link(lli_dst, lli_src, next, flags);
354 333
355 writel(lli_src->lcsp02, &lcpa[0].lcsp0); 334 writel(lli_src->lcsp02, &lcpa[0].lcsp0);
356 writel(lli_src->lcsp13, &lcpa[0].lcsp1); 335 writel(lli_src->lcsp13, &lcpa[0].lcsp1);
@@ -361,9 +340,9 @@ void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
361void d40_log_lli_lcla_write(struct d40_log_lli *lcla, 340void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
362 struct d40_log_lli *lli_dst, 341 struct d40_log_lli *lli_dst,
363 struct d40_log_lli *lli_src, 342 struct d40_log_lli *lli_src,
364 int next) 343 int next, unsigned int flags)
365{ 344{
366 d40_log_lli_link(lli_dst, lli_src, next); 345 d40_log_lli_link(lli_dst, lli_src, next, flags);
367 346
368 writel(lli_src->lcsp02, &lcla[0].lcsp02); 347 writel(lli_src->lcsp02, &lcla[0].lcsp02);
369 writel(lli_src->lcsp13, &lcla[0].lcsp13); 348 writel(lli_src->lcsp13, &lcla[0].lcsp13);
@@ -375,8 +354,10 @@ static void d40_log_fill_lli(struct d40_log_lli *lli,
375 dma_addr_t data, u32 data_size, 354 dma_addr_t data, u32 data_size,
376 u32 reg_cfg, 355 u32 reg_cfg,
377 u32 data_width, 356 u32 data_width,
378 bool addr_inc) 357 unsigned int flags)
379{ 358{
359 bool addr_inc = flags & LLI_ADDR_INC;
360
380 lli->lcsp13 = reg_cfg; 361 lli->lcsp13 = reg_cfg;
381 362
382 /* The number of elements to transfer */ 363 /* The number of elements to transfer */
@@ -395,67 +376,15 @@ static void d40_log_fill_lli(struct d40_log_lli *lli,
395 376
396} 377}
397 378
398int d40_log_sg_to_dev(struct scatterlist *sg, 379static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
399 int sg_len,
400 struct d40_log_lli_bidir *lli,
401 struct d40_def_lcsp *lcsp,
402 u32 src_data_width,
403 u32 dst_data_width,
404 enum dma_data_direction direction,
405 dma_addr_t dev_addr)
406{
407 int total_size = 0;
408 struct scatterlist *current_sg = sg;
409 int i;
410 struct d40_log_lli *lli_src = lli->src;
411 struct d40_log_lli *lli_dst = lli->dst;
412
413 for_each_sg(sg, current_sg, sg_len, i) {
414 total_size += sg_dma_len(current_sg);
415
416 if (direction == DMA_TO_DEVICE) {
417 lli_src =
418 d40_log_buf_to_lli(lli_src,
419 sg_phys(current_sg),
420 sg_dma_len(current_sg),
421 lcsp->lcsp1, src_data_width,
422 dst_data_width,
423 true);
424 lli_dst =
425 d40_log_buf_to_lli(lli_dst,
426 dev_addr,
427 sg_dma_len(current_sg),
428 lcsp->lcsp3, dst_data_width,
429 src_data_width,
430 false);
431 } else {
432 lli_dst =
433 d40_log_buf_to_lli(lli_dst,
434 sg_phys(current_sg),
435 sg_dma_len(current_sg),
436 lcsp->lcsp3, dst_data_width,
437 src_data_width,
438 true);
439 lli_src =
440 d40_log_buf_to_lli(lli_src,
441 dev_addr,
442 sg_dma_len(current_sg),
443 lcsp->lcsp1, src_data_width,
444 dst_data_width,
445 false);
446 }
447 }
448 return total_size;
449}
450
451struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
452 dma_addr_t addr, 380 dma_addr_t addr,
453 int size, 381 int size,
454 u32 lcsp13, /* src or dst*/ 382 u32 lcsp13, /* src or dst*/
455 u32 data_width1, 383 u32 data_width1,
456 u32 data_width2, 384 u32 data_width2,
457 bool addr_inc) 385 unsigned int flags)
458{ 386{
387 bool addr_inc = flags & LLI_ADDR_INC;
459 struct d40_log_lli *lli = lli_sg; 388 struct d40_log_lli *lli = lli_sg;
460 int size_rest = size; 389 int size_rest = size;
461 int size_seg = 0; 390 int size_seg = 0;
@@ -468,7 +397,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
468 addr, 397 addr,
469 size_seg, 398 size_seg,
470 lcsp13, data_width1, 399 lcsp13, data_width1,
471 addr_inc); 400 flags);
472 if (addr_inc) 401 if (addr_inc)
473 addr += size_seg; 402 addr += size_seg;
474 lli++; 403 lli++;
@@ -479,6 +408,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
479 408
480int d40_log_sg_to_lli(struct scatterlist *sg, 409int d40_log_sg_to_lli(struct scatterlist *sg,
481 int sg_len, 410 int sg_len,
411 dma_addr_t dev_addr,
482 struct d40_log_lli *lli_sg, 412 struct d40_log_lli *lli_sg,
483 u32 lcsp13, /* src or dst*/ 413 u32 lcsp13, /* src or dst*/
484 u32 data_width1, u32 data_width2) 414 u32 data_width1, u32 data_width2)
@@ -487,14 +417,24 @@ int d40_log_sg_to_lli(struct scatterlist *sg,
487 struct scatterlist *current_sg = sg; 417 struct scatterlist *current_sg = sg;
488 int i; 418 int i;
489 struct d40_log_lli *lli = lli_sg; 419 struct d40_log_lli *lli = lli_sg;
420 unsigned long flags = 0;
421
422 if (!dev_addr)
423 flags |= LLI_ADDR_INC;
490 424
491 for_each_sg(sg, current_sg, sg_len, i) { 425 for_each_sg(sg, current_sg, sg_len, i) {
426 dma_addr_t sg_addr = sg_dma_address(current_sg);
427 unsigned int len = sg_dma_len(current_sg);
428 dma_addr_t addr = dev_addr ?: sg_addr;
429
492 total_size += sg_dma_len(current_sg); 430 total_size += sg_dma_len(current_sg);
493 lli = d40_log_buf_to_lli(lli, 431
494 sg_phys(current_sg), 432 lli = d40_log_buf_to_lli(lli, addr, len,
495 sg_dma_len(current_sg),
496 lcsp13, 433 lcsp13,
497 data_width1, data_width2, true); 434 data_width1,
435 data_width2,
436 flags);
498 } 437 }
438
499 return total_size; 439 return total_size;
500} 440}