From c66ecf19b98ffac86177c29859e683de39f44e73 Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Wed, 15 Jun 2016 17:24:03 +0800 Subject: [PATCH] dmaengine: pl330: support transfer that doesn't align with (burst len * burst size) Below code transfers 0x10002 bytes: First loop 256*16*16=0x10000, burst size is 1, burst length is 16. Then the second loop 2 bytes, burst size is 1, burst length is 1. f0041000: DMAMOV CCR 0xbc02f1 f0041006: DMAMOV SAR 0xdd6c0000 f004100c: DMAMOV DAR 0xff1d0400 f0041012: DMALP_0 15 f0041014: DMALP_1 255 f0041016: DMAWFPB 12 f0041018: DMALDA f0041019: DMASTPB 12 f004101b: DMAFLUSHP 12 f004101d: DMALPENDA_1 bjmpto_7 f004101f: DMALPENDA_0 bjmpto_b f0041021: DMAMOV CCR 0x800201 f0041027: DMALP_1 1 f0041029: DMAWFPB 12 f004102b: DMALDA f004102c: DMASTPB 12 f004102e: DMAFLUSHP 12 f0041030: DMALPENDA_1 bjmpto_7 f0041032: DMASEV 0 f0041034: DMAEND Change-Id: I97ef33aeac8ebe18c63201cf4c1c04f5548e9a4a Signed-off-by: Huibin Hong --- drivers/dma/pl330.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index dece7d2d024f..63db9e30e02a 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -240,6 +240,7 @@ enum pl330_byteswap { #define BYTE_TO_BURST(b, ccr) ((b) / BRST_SIZE(ccr) / BRST_LEN(ccr)) #define BURST_TO_BYTE(c, ccr) ((c) * BRST_SIZE(ccr) * BRST_LEN(ccr)) +#define BYTE_MOD_BURST_LEN(b, ccr) (((b) / BRST_SIZE(ccr)) % BRST_LEN(ccr)) /* * With 256 bytes, we can do more than 2.5MB and 5MB xfers per req @@ -1331,6 +1332,20 @@ static inline int _setup_xfer(struct pl330_dmac *pl330, /* Setup Loop(s) */ off += _setup_loops(pl330, dry_run, &buf[off], pxs); + if (pl330->peripherals_req_type == BURST) { + unsigned int ccr = pxs->ccr; + unsigned long c = 0; + + c = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr); + + if (c) { + ccr &= ~(0xf << CC_SRCBRSTLEN_SHFT); + ccr &= ~(0xf << CC_DSTBRSTLEN_SHFT); + off += _emit_MOV(dry_run, &buf[off], CCR, ccr); + off += _loop(pl330, dry_run, &buf[off], &c, pxs); + } + } + return off; } @@ -1353,9 +1368,11 @@ static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run, off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); x = &pxs->desc->px; - /* Error if xfer length is not aligned at burst size */ - if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr))) - return -EINVAL; + if (pl330->peripherals_req_type != BURST) { + /* Error if xfer length is not aligned at burst size */ + if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr))) + return -EINVAL; + } off += _setup_xfer(pl330, dry_run, &buf[off], pxs); -- 2.34.1