diff options
-rw-r--r-- | drivers/dma/fsl-edma.c | 189 |
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 | ||
120 | struct fsl_edma_hw_tcd { | 120 | struct 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 | ||
134 | struct fsl_edma_sw_tcd { | 134 | struct 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 | ||
182 | static 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 | |||
190 | static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) | 184 | static 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 | ||
198 | static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr) | 192 | static 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 | ||
203 | static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr) | 201 | static 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 | ||
266 | static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width) | 264 | static 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 | ||
427 | static void fsl_edma_set_tcd_params(struct fsl_edma_chan *fsl_chan, | 422 | static 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 | ||
453 | static 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 | |
453 | static inline | ||
454 | void 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 | ||
488 | static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan, | 495 | static 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 | ||
626 | static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan) | 633 | static 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 | } |