Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jingchang Lu and committed by
Vinod Koul
1e2dbdef 6ab55b21

+94 -91
+94 -91
drivers/dma/fsl-edma.c
··· 118 118 BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) 119 119 120 120 struct fsl_edma_hw_tcd { 121 - u32 saddr; 122 - u16 soff; 123 - u16 attr; 124 - u32 nbytes; 125 - u32 slast; 126 - u32 daddr; 127 - u16 doff; 128 - u16 citer; 129 - u32 dlast_sga; 130 - u16 csr; 131 - u16 biter; 121 + __le32 saddr; 122 + __le16 soff; 123 + __le16 attr; 124 + __le32 nbytes; 125 + __le32 slast; 126 + __le32 daddr; 127 + __le16 doff; 128 + __le16 citer; 129 + __le32 dlast_sga; 130 + __le16 csr; 131 + __le16 biter; 132 132 }; 133 133 134 134 struct fsl_edma_sw_tcd { ··· 175 175 }; 176 176 177 177 /* 178 - * R/W functions for big- or little-endian registers 179 - * the eDMA controller's endian is independent of the CPU core's endian. 178 + * R/W functions for big- or little-endian registers: 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 - 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 183 190 184 static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr) 191 185 { ··· 191 197 192 198 static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr) 193 199 { 194 - iowrite8(val, addr); 200 + /* swap the reg offset for these in big-endian mode */ 201 + if (edma->big_endian) 202 + iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3)); 203 + else 204 + iowrite8(val, addr); 195 205 } 196 206 197 207 static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr) 198 208 { 209 + /* swap the reg offset for these in big-endian mode */ 199 210 if (edma->big_endian) 200 - iowrite16be(val, addr); 211 + iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2)); 201 212 else 202 213 iowrite16(val, addr); 203 214 } ··· 253 254 chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR; 254 255 ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux; 255 256 muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; 257 + slot = EDMAMUX_CHCFG_SOURCE(slot); 256 258 257 259 if (enable) 258 - edma_writeb(fsl_chan->edma, 259 - EDMAMUX_CHCFG_ENBL | EDMAMUX_CHCFG_SOURCE(slot), 260 - muxaddr + ch_off); 260 + iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off); 261 261 else 262 - edma_writeb(fsl_chan->edma, EDMAMUX_CHCFG_DIS, muxaddr + ch_off); 262 + iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off); 263 263 } 264 264 265 265 static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width) ··· 284 286 285 287 fsl_desc = to_fsl_edma_desc(vdesc); 286 288 for (i = 0; i < fsl_desc->n_tcds; i++) 287 - dma_pool_free(fsl_desc->echan->tcd_pool, 288 - fsl_desc->tcd[i].vtcd, 289 - fsl_desc->tcd[i].ptcd); 289 + dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd, 290 + fsl_desc->tcd[i].ptcd); 290 291 kfree(fsl_desc); 291 292 } 292 293 ··· 360 363 361 364 /* calculate the total size in this desc */ 362 365 for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++) 363 - len += edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes)) 364 - * edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter)); 366 + len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes) 367 + * le16_to_cpu(edesc->tcd[i].vtcd->biter); 365 368 366 369 if (!in_progress) 367 370 return len; ··· 373 376 374 377 /* figure out the finished and calculate the residue */ 375 378 for (i = 0; i < fsl_chan->edesc->n_tcds; i++) { 376 - size = edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes)) 377 - * edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter)); 379 + size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes) 380 + * le16_to_cpu(edesc->tcd[i].vtcd->biter); 378 381 if (dir == DMA_MEM_TO_DEV) 379 - dma_addr = edma_readl(fsl_chan->edma, 380 - &(edesc->tcd[i].vtcd->saddr)); 382 + dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr); 381 383 else 382 - dma_addr = edma_readl(fsl_chan->edma, 383 - &(edesc->tcd[i].vtcd->daddr)); 384 + dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr); 384 385 385 386 len -= size; 386 387 if (cur_addr >= dma_addr && cur_addr < dma_addr + size) { ··· 419 424 return fsl_chan->status; 420 425 } 421 426 422 - static void fsl_edma_set_tcd_params(struct fsl_edma_chan *fsl_chan, 423 - u32 src, u32 dst, u16 attr, u16 soff, u32 nbytes, 424 - u32 slast, u16 citer, u16 biter, u32 doff, u32 dlast_sga, 425 - u16 csr) 427 + static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan, 428 + struct fsl_edma_hw_tcd *tcd) 426 429 { 430 + struct fsl_edma_engine *edma = fsl_chan->edma; 427 431 void __iomem *addr = fsl_chan->edma->membase; 428 432 u32 ch = fsl_chan->vchan.chan.chan_id; 429 433 430 434 /* 431 - * TCD parameters have been swapped in fill_tcd_params(), 432 - * so just write them to registers in the cpu endian here 435 + * TCD parameters are stored in struct fsl_edma_hw_tcd in little 436 + * endian format. However, we need to load the TCD registers in 437 + * big- or little-endian obeying the eDMA engine model endian. 433 438 */ 434 - writew(0, addr + EDMA_TCD_CSR(ch)); 435 - writel(src, addr + EDMA_TCD_SADDR(ch)); 436 - writel(dst, addr + EDMA_TCD_DADDR(ch)); 437 - writew(attr, addr + EDMA_TCD_ATTR(ch)); 438 - writew(soff, addr + EDMA_TCD_SOFF(ch)); 439 - writel(nbytes, addr + EDMA_TCD_NBYTES(ch)); 440 - writel(slast, addr + EDMA_TCD_SLAST(ch)); 441 - writew(citer, addr + EDMA_TCD_CITER(ch)); 442 - writew(biter, addr + EDMA_TCD_BITER(ch)); 443 - writew(doff, addr + EDMA_TCD_DOFF(ch)); 444 - writel(dlast_sga, addr + EDMA_TCD_DLAST_SGA(ch)); 445 - writew(csr, addr + EDMA_TCD_CSR(ch)); 439 + edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch)); 440 + edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch)); 441 + edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch)); 442 + 443 + edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch)); 444 + edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch)); 445 + 446 + edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch)); 447 + edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch)); 448 + 449 + edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch)); 450 + edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch)); 451 + edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch)); 452 + 453 + edma_writel(edma, le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch)); 454 + 455 + edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch)); 446 456 } 447 457 448 - static void fill_tcd_params(struct fsl_edma_engine *edma, 449 - struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst, 450 - u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer, 451 - u16 biter, u16 doff, u32 dlast_sga, bool major_int, 452 - bool disable_req, bool enable_sg) 458 + static inline 459 + void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst, 460 + u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer, 461 + u16 biter, u16 doff, u32 dlast_sga, bool major_int, 462 + bool disable_req, bool enable_sg) 453 463 { 454 464 u16 csr = 0; 455 465 456 466 /* 457 - * eDMA hardware SGs require the TCD parameters stored in memory 458 - * the same endian as the eDMA module so that they can be loaded 459 - * automatically by the engine 467 + * eDMA hardware SGs require the TCDs to be stored in little 468 + * endian format irrespective of the register endian model. 469 + * So we put the value in little endian in memory, waiting 470 + * for fsl_edma_set_tcd_regs doing the swap. 460 471 */ 461 - edma_writel(edma, src, &(tcd->saddr)); 462 - edma_writel(edma, dst, &(tcd->daddr)); 463 - edma_writew(edma, attr, &(tcd->attr)); 464 - edma_writew(edma, EDMA_TCD_SOFF_SOFF(soff), &(tcd->soff)); 465 - edma_writel(edma, EDMA_TCD_NBYTES_NBYTES(nbytes), &(tcd->nbytes)); 466 - edma_writel(edma, EDMA_TCD_SLAST_SLAST(slast), &(tcd->slast)); 467 - edma_writew(edma, EDMA_TCD_CITER_CITER(citer), &(tcd->citer)); 468 - edma_writew(edma, EDMA_TCD_DOFF_DOFF(doff), &(tcd->doff)); 469 - edma_writel(edma, EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga), &(tcd->dlast_sga)); 470 - edma_writew(edma, EDMA_TCD_BITER_BITER(biter), &(tcd->biter)); 472 + tcd->saddr = cpu_to_le32(src); 473 + tcd->daddr = cpu_to_le32(dst); 474 + 475 + tcd->attr = cpu_to_le16(attr); 476 + 477 + tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff)); 478 + 479 + tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes)); 480 + tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast)); 481 + 482 + tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer)); 483 + tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff)); 484 + 485 + tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga)); 486 + 487 + tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter)); 471 488 if (major_int) 472 489 csr |= EDMA_TCD_CSR_INT_MAJOR; 473 490 ··· 489 482 if (enable_sg) 490 483 csr |= EDMA_TCD_CSR_E_SG; 491 484 492 - edma_writew(edma, csr, &(tcd->csr)); 485 + tcd->csr = cpu_to_le16(csr); 493 486 } 494 487 495 488 static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan, ··· 565 558 doff = fsl_chan->fsc.addr_width; 566 559 } 567 560 568 - fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, src_addr, 569 - dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0, 570 - iter, iter, doff, last_sg, true, false, true); 561 + fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr, 562 + fsl_chan->fsc.attr, soff, nbytes, 0, iter, 563 + iter, doff, last_sg, true, false, true); 571 564 dma_buf_next += period_len; 572 565 } 573 566 ··· 614 607 iter = sg_dma_len(sg) / nbytes; 615 608 if (i < sg_len - 1) { 616 609 last_sg = fsl_desc->tcd[(i + 1)].ptcd; 617 - fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, 618 - src_addr, dst_addr, fsl_chan->fsc.attr, 619 - soff, nbytes, 0, iter, iter, doff, last_sg, 620 - false, false, true); 610 + fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, 611 + dst_addr, fsl_chan->fsc.attr, soff, 612 + nbytes, 0, iter, iter, doff, last_sg, 613 + false, false, true); 621 614 } else { 622 615 last_sg = 0; 623 - fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, 624 - src_addr, dst_addr, fsl_chan->fsc.attr, 625 - soff, nbytes, 0, iter, iter, doff, last_sg, 626 - true, true, false); 616 + fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, 617 + dst_addr, fsl_chan->fsc.attr, soff, 618 + nbytes, 0, iter, iter, doff, last_sg, 619 + true, true, false); 627 620 } 628 621 } 629 622 ··· 632 625 633 626 static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan) 634 627 { 635 - struct fsl_edma_hw_tcd *tcd; 636 628 struct virt_dma_desc *vdesc; 637 629 638 630 vdesc = vchan_next_desc(&fsl_chan->vchan); 639 631 if (!vdesc) 640 632 return; 641 633 fsl_chan->edesc = to_fsl_edma_desc(vdesc); 642 - tcd = fsl_chan->edesc->tcd[0].vtcd; 643 - fsl_edma_set_tcd_params(fsl_chan, tcd->saddr, tcd->daddr, tcd->attr, 644 - tcd->soff, tcd->nbytes, tcd->slast, tcd->citer, 645 - tcd->biter, tcd->doff, tcd->dlast_sga, tcd->csr); 634 + fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd); 646 635 fsl_edma_enable_request(fsl_chan); 647 636 fsl_chan->status = DMA_IN_PROGRESS; 648 637 }