aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorJingchang Lu <jingchang.lu@freescale.com>2014-10-22 04:53:55 -0400
committerVinod Koul <vinod.koul@intel.com>2014-12-09 04:11:58 -0500
commit1e2dbdefe720372d9d8b04d50c29de54e932be3b (patch)
tree4331224fd73596beab023a1770f48cf70fae6463 /drivers/dma
parent6ab55b214c625f4d56199f7ebd0b419f43f23bb2 (diff)
dmaengine: fsl-edma: fixup reg offset and hw S/G support in big-endian model
The offset of all 8-/16-bit registers in big-endian eDMA model are swapped in a 32-bit size opposite those in the little-endian model. The hardware Scatter/Gather requires the subsequent TCDs stored in memory in little endian independent of the register endian model, the eDMA engine will do the swap if need. This patch also use regular assignment for tcd variables r/w instead of with io function previously that may not always be true. Signed-off-by: Jingchang Lu <jingchang.lu@freescale.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/fsl-edma.c189
1 files changed, 96 insertions, 93 deletions
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 58c6fc7e902e..6fb2e902b459 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -118,17 +118,17 @@
118 BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) 118 BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
119 119
120struct fsl_edma_hw_tcd { 120struct fsl_edma_hw_tcd {
121 u32 saddr; 121 __le32 saddr;
122 u16 soff; 122 __le16 soff;
123 u16 attr; 123 __le16 attr;
124 u32 nbytes; 124 __le32 nbytes;
125 u32 slast; 125 __le32 slast;
126 u32 daddr; 126 __le32 daddr;
127 u16 doff; 127 __le16 doff;
128 u16 citer; 128 __le16 citer;
129 u32 dlast_sga; 129 __le32 dlast_sga;
130 u16 csr; 130 __le16 csr;
131 u16 biter; 131 __le16 biter;
132}; 132};
133 133
134struct fsl_edma_sw_tcd { 134struct fsl_edma_sw_tcd {
@@ -175,18 +175,12 @@ struct fsl_edma_engine {
175}; 175};
176 176
177/* 177/*
178 * R/W functions for big- or little-endian registers 178 * R/W functions for big- or little-endian registers:
179 * the eDMA controller's endian is independent of the CPU core's endian. 179 * The eDMA controller's endian is independent of the CPU core's endian.
180 * For the big-endian IP module, the offset for 8-bit or 16-bit registers
181 * should also be swapped opposite to that in little-endian IP.
180 */ 182 */
181 183
182static u16 edma_readw(struct fsl_edma_engine *edma, void __iomem *addr)
183{
184 if (edma->big_endian)
185 return ioread16be(addr);
186 else
187 return ioread16(addr);
188}
189
190static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) 184static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
191{ 185{
192 if (edma->big_endian) 186 if (edma->big_endian)
@@ -197,13 +191,18 @@ static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
197 191
198static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr) 192static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr)
199{ 193{
200 iowrite8(val, addr); 194 /* swap the reg offset for these in big-endian mode */
195 if (edma->big_endian)
196 iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
197 else
198 iowrite8(val, addr);
201} 199}
202 200
203static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr) 201static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr)
204{ 202{
203 /* swap the reg offset for these in big-endian mode */
205 if (edma->big_endian) 204 if (edma->big_endian)
206 iowrite16be(val, addr); 205 iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2));
207 else 206 else
208 iowrite16(val, addr); 207 iowrite16(val, addr);
209} 208}
@@ -254,13 +253,12 @@ static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
254 chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR; 253 chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
255 ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux; 254 ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
256 muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; 255 muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
256 slot = EDMAMUX_CHCFG_SOURCE(slot);
257 257
258 if (enable) 258 if (enable)
259 edma_writeb(fsl_chan->edma, 259 iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
260 EDMAMUX_CHCFG_ENBL | EDMAMUX_CHCFG_SOURCE(slot),
261 muxaddr + ch_off);
262 else 260 else
263 edma_writeb(fsl_chan->edma, EDMAMUX_CHCFG_DIS, muxaddr + ch_off); 261 iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
264} 262}
265 263
266static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width) 264static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
@@ -286,9 +284,8 @@ static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
286 284
287 fsl_desc = to_fsl_edma_desc(vdesc); 285 fsl_desc = to_fsl_edma_desc(vdesc);
288 for (i = 0; i < fsl_desc->n_tcds; i++) 286 for (i = 0; i < fsl_desc->n_tcds; i++)
289 dma_pool_free(fsl_desc->echan->tcd_pool, 287 dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
290 fsl_desc->tcd[i].vtcd, 288 fsl_desc->tcd[i].ptcd);
291 fsl_desc->tcd[i].ptcd);
292 kfree(fsl_desc); 289 kfree(fsl_desc);
293} 290}
294 291
@@ -363,8 +360,8 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
363 360
364 /* calculate the total size in this desc */ 361 /* calculate the total size in this desc */
365 for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++) 362 for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
366 len += edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes)) 363 len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
367 * edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter)); 364 * le16_to_cpu(edesc->tcd[i].vtcd->biter);
368 365
369 if (!in_progress) 366 if (!in_progress)
370 return len; 367 return len;
@@ -376,14 +373,12 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
376 373
377 /* figure out the finished and calculate the residue */ 374 /* figure out the finished and calculate the residue */
378 for (i = 0; i < fsl_chan->edesc->n_tcds; i++) { 375 for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
379 size = edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes)) 376 size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
380 * edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter)); 377 * le16_to_cpu(edesc->tcd[i].vtcd->biter);
381 if (dir == DMA_MEM_TO_DEV) 378 if (dir == DMA_MEM_TO_DEV)
382 dma_addr = edma_readl(fsl_chan->edma, 379 dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
383 &(edesc->tcd[i].vtcd->saddr));
384 else 380 else
385 dma_addr = edma_readl(fsl_chan->edma, 381 dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
386 &(edesc->tcd[i].vtcd->daddr));
387 382
388 len -= size; 383 len -= size;
389 if (cur_addr >= dma_addr && cur_addr < dma_addr + size) { 384 if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
@@ -424,55 +419,67 @@ static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
424 return fsl_chan->status; 419 return fsl_chan->status;
425} 420}
426 421
427static void fsl_edma_set_tcd_params(struct fsl_edma_chan *fsl_chan, 422static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
428 u32 src, u32 dst, u16 attr, u16 soff, u32 nbytes, 423 struct fsl_edma_hw_tcd *tcd)
429 u32 slast, u16 citer, u16 biter, u32 doff, u32 dlast_sga,
430 u16 csr)
431{ 424{
425 struct fsl_edma_engine *edma = fsl_chan->edma;
432 void __iomem *addr = fsl_chan->edma->membase; 426 void __iomem *addr = fsl_chan->edma->membase;
433 u32 ch = fsl_chan->vchan.chan.chan_id; 427 u32 ch = fsl_chan->vchan.chan.chan_id;
434 428
435 /* 429 /*
436 * TCD parameters have been swapped in fill_tcd_params(), 430 * TCD parameters are stored in struct fsl_edma_hw_tcd in little
437 * so just write them to registers in the cpu endian here 431 * endian format. However, we need to load the TCD registers in
432 * big- or little-endian obeying the eDMA engine model endian.
438 */ 433 */
439 writew(0, addr + EDMA_TCD_CSR(ch)); 434 edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch));
440 writel(src, addr + EDMA_TCD_SADDR(ch)); 435 edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch));
441 writel(dst, addr + EDMA_TCD_DADDR(ch)); 436 edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch));
442 writew(attr, addr + EDMA_TCD_ATTR(ch)); 437
443 writew(soff, addr + EDMA_TCD_SOFF(ch)); 438 edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch));
444 writel(nbytes, addr + EDMA_TCD_NBYTES(ch)); 439 edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch));
445 writel(slast, addr + EDMA_TCD_SLAST(ch)); 440
446 writew(citer, addr + EDMA_TCD_CITER(ch)); 441 edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch));
447 writew(biter, addr + EDMA_TCD_BITER(ch)); 442 edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch));
448 writew(doff, addr + EDMA_TCD_DOFF(ch)); 443
449 writel(dlast_sga, addr + EDMA_TCD_DLAST_SGA(ch)); 444 edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch));
450 writew(csr, addr + EDMA_TCD_CSR(ch)); 445 edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch));
451} 446 edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch));
452 447
453static void fill_tcd_params(struct fsl_edma_engine *edma, 448 edma_writel(edma, le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch));
454 struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst, 449
455 u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer, 450 edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch));
456 u16 biter, u16 doff, u32 dlast_sga, bool major_int, 451}
457 bool disable_req, bool enable_sg) 452
453static inline
454void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
455 u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
456 u16 biter, u16 doff, u32 dlast_sga, bool major_int,
457 bool disable_req, bool enable_sg)
458{ 458{
459 u16 csr = 0; 459 u16 csr = 0;
460 460
461 /* 461 /*
462 * eDMA hardware SGs require the TCD parameters stored in memory 462 * eDMA hardware SGs require the TCDs to be stored in little
463 * the same endian as the eDMA module so that they can be loaded 463 * endian format irrespective of the register endian model.
464 * automatically by the engine 464 * So we put the value in little endian in memory, waiting
465 * for fsl_edma_set_tcd_regs doing the swap.
465 */ 466 */
466 edma_writel(edma, src, &(tcd->saddr)); 467 tcd->saddr = cpu_to_le32(src);
467 edma_writel(edma, dst, &(tcd->daddr)); 468 tcd->daddr = cpu_to_le32(dst);
468 edma_writew(edma, attr, &(tcd->attr)); 469
469 edma_writew(edma, EDMA_TCD_SOFF_SOFF(soff), &(tcd->soff)); 470 tcd->attr = cpu_to_le16(attr);
470 edma_writel(edma, EDMA_TCD_NBYTES_NBYTES(nbytes), &(tcd->nbytes)); 471
471 edma_writel(edma, EDMA_TCD_SLAST_SLAST(slast), &(tcd->slast)); 472 tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
472 edma_writew(edma, EDMA_TCD_CITER_CITER(citer), &(tcd->citer)); 473
473 edma_writew(edma, EDMA_TCD_DOFF_DOFF(doff), &(tcd->doff)); 474 tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
474 edma_writel(edma, EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga), &(tcd->dlast_sga)); 475 tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
475 edma_writew(edma, EDMA_TCD_BITER_BITER(biter), &(tcd->biter)); 476
477 tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
478 tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
479
480 tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
481
482 tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
476 if (major_int) 483 if (major_int)
477 csr |= EDMA_TCD_CSR_INT_MAJOR; 484 csr |= EDMA_TCD_CSR_INT_MAJOR;
478 485
@@ -482,7 +489,7 @@ static void fill_tcd_params(struct fsl_edma_engine *edma,
482 if (enable_sg) 489 if (enable_sg)
483 csr |= EDMA_TCD_CSR_E_SG; 490 csr |= EDMA_TCD_CSR_E_SG;
484 491
485 edma_writew(edma, csr, &(tcd->csr)); 492 tcd->csr = cpu_to_le16(csr);
486} 493}
487 494
488static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan, 495static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,
@@ -558,9 +565,9 @@ static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
558 doff = fsl_chan->fsc.addr_width; 565 doff = fsl_chan->fsc.addr_width;
559 } 566 }
560 567
561 fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, src_addr, 568 fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
562 dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0, 569 fsl_chan->fsc.attr, soff, nbytes, 0, iter,
563 iter, iter, doff, last_sg, true, false, true); 570 iter, doff, last_sg, true, false, true);
564 dma_buf_next += period_len; 571 dma_buf_next += period_len;
565 } 572 }
566 573
@@ -607,16 +614,16 @@ static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
607 iter = sg_dma_len(sg) / nbytes; 614 iter = sg_dma_len(sg) / nbytes;
608 if (i < sg_len - 1) { 615 if (i < sg_len - 1) {
609 last_sg = fsl_desc->tcd[(i + 1)].ptcd; 616 last_sg = fsl_desc->tcd[(i + 1)].ptcd;
610 fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, 617 fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
611 src_addr, dst_addr, fsl_chan->fsc.attr, 618 dst_addr, fsl_chan->fsc.attr, soff,
612 soff, nbytes, 0, iter, iter, doff, last_sg, 619 nbytes, 0, iter, iter, doff, last_sg,
613 false, false, true); 620 false, false, true);
614 } else { 621 } else {
615 last_sg = 0; 622 last_sg = 0;
616 fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, 623 fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
617 src_addr, dst_addr, fsl_chan->fsc.attr, 624 dst_addr, fsl_chan->fsc.attr, soff,
618 soff, nbytes, 0, iter, iter, doff, last_sg, 625 nbytes, 0, iter, iter, doff, last_sg,
619 true, true, false); 626 true, true, false);
620 } 627 }
621 } 628 }
622 629
@@ -625,17 +632,13 @@ static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
625 632
626static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan) 633static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
627{ 634{
628 struct fsl_edma_hw_tcd *tcd;
629 struct virt_dma_desc *vdesc; 635 struct virt_dma_desc *vdesc;
630 636
631 vdesc = vchan_next_desc(&fsl_chan->vchan); 637 vdesc = vchan_next_desc(&fsl_chan->vchan);
632 if (!vdesc) 638 if (!vdesc)
633 return; 639 return;
634 fsl_chan->edesc = to_fsl_edma_desc(vdesc); 640 fsl_chan->edesc = to_fsl_edma_desc(vdesc);
635 tcd = fsl_chan->edesc->tcd[0].vtcd; 641 fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
636 fsl_edma_set_tcd_params(fsl_chan, tcd->saddr, tcd->daddr, tcd->attr,
637 tcd->soff, tcd->nbytes, tcd->slast, tcd->citer,
638 tcd->biter, tcd->doff, tcd->dlast_sga, tcd->csr);
639 fsl_edma_enable_request(fsl_chan); 642 fsl_edma_enable_request(fsl_chan);
640 fsl_chan->status = DMA_IN_PROGRESS; 643 fsl_chan->status = DMA_IN_PROGRESS;
641} 644}