diff options
author | Ludovic Desroches <ludovic.desroches@atmel.com> | 2015-01-27 10:30:32 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2015-02-05 02:12:29 -0500 |
commit | 6d3a7d9e3ada345948f72564ce638c412ccd8c4a (patch) | |
tree | d76e829bc3b094b12676cf6ff7220615412da764 /drivers/dma/at_xdmac.c | |
parent | be835074829b13c5f635ef78ed911b13b9c15fa9 (diff) |
dmaengine: at_xdmac: allow muliple dwidths when doing slave transfers
When using FIFO, we need to support differents data width in a single
transfer. For example, serial device which usually uses 1-byte data
width will use 4-bytes data width when using the FIFO. If the transfer
size is not aligned on 4-bytes then the end of the transfer will be
performed with 1-byte data-width. For that reason,
at_xdmac_prep_slave_sg() now builds linked list descriptors using view 2
instead of view 1 so each of them can update the DWIDTH field into the
Channel Configuration Register.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/at_xdmac.c')
-rw-r--r-- | drivers/dma/at_xdmac.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index eba66a22a265..09e2825a547a 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/dmapool.h> | 25 | #include <linux/dmapool.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/irq.h> | 27 | #include <linux/irq.h> |
28 | #include <linux/kernel.h> | ||
28 | #include <linux/list.h> | 29 | #include <linux/list.h> |
29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
30 | #include <linux/of_dma.h> | 31 | #include <linux/of_dma.h> |
@@ -351,11 +352,11 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan, | |||
351 | at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg); | 352 | at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg); |
352 | 353 | ||
353 | /* | 354 | /* |
354 | * When doing memory to memory transfer we need to use the next | 355 | * When doing non cyclic transfer we need to use the next |
355 | * descriptor view 2 since some fields of the configuration register | 356 | * descriptor view 2 since some fields of the configuration register |
356 | * depend on transfer size and src/dest addresses. | 357 | * depend on transfer size and src/dest addresses. |
357 | */ | 358 | */ |
358 | if (is_slave_direction(first->direction)) { | 359 | if (at_xdmac_chan_is_cyclic(atchan)) { |
359 | reg = AT_XDMAC_CNDC_NDVIEW_NDV1; | 360 | reg = AT_XDMAC_CNDC_NDVIEW_NDV1; |
360 | at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg); | 361 | at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg); |
361 | } else { | 362 | } else { |
@@ -582,7 +583,7 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
582 | /* Prepare descriptors. */ | 583 | /* Prepare descriptors. */ |
583 | for_each_sg(sgl, sg, sg_len, i) { | 584 | for_each_sg(sgl, sg, sg_len, i) { |
584 | struct at_xdmac_desc *desc = NULL; | 585 | struct at_xdmac_desc *desc = NULL; |
585 | u32 len, mem; | 586 | u32 len, mem, dwidth, fixed_dwidth; |
586 | 587 | ||
587 | len = sg_dma_len(sg); | 588 | len = sg_dma_len(sg); |
588 | mem = sg_dma_address(sg); | 589 | mem = sg_dma_address(sg); |
@@ -613,11 +614,15 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | |||
613 | desc->lld.mbr_da = atchan->per_dst_addr; | 614 | desc->lld.mbr_da = atchan->per_dst_addr; |
614 | desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG]; | 615 | desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG]; |
615 | } | 616 | } |
616 | desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1 /* next descriptor view */ | 617 | dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg); |
618 | fixed_dwidth = IS_ALIGNED(len, 1 << dwidth) | ||
619 | ? at_xdmac_get_dwidth(desc->lld.mbr_cfg) | ||
620 | : AT_XDMAC_CC_DWIDTH_BYTE; | ||
621 | desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2 /* next descriptor view */ | ||
617 | | AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */ | 622 | | AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */ |
618 | | AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */ | 623 | | AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */ |
619 | | (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */ | 624 | | (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */ |
620 | | len / (1 << at_xdmac_get_dwidth(desc->lld.mbr_cfg)); /* microblock length */ | 625 | | (len >> fixed_dwidth); /* microblock length */ |
621 | dev_dbg(chan2dev(chan), | 626 | dev_dbg(chan2dev(chan), |
622 | "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n", | 627 | "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n", |
623 | __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc); | 628 | __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc); |