aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/amba-pl08x.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index f70aa574c58f..a59c3c47286c 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -66,11 +66,6 @@
66 * after the final transfer signalled by LBREQ or LSREQ. The DMAC 66 * after the final transfer signalled by LBREQ or LSREQ. The DMAC
67 * will then move to the next LLI entry. 67 * will then move to the next LLI entry.
68 * 68 *
69 * Only the former works sanely with scatter lists, so we only implement
70 * the DMAC flow control method. However, peripherals which use the LBREQ
71 * and LSREQ signals (eg, MMCI) are unable to use this mode, which through
72 * these hardware restrictions prevents them from using scatter DMA.
73 *
74 * Global TODO: 69 * Global TODO:
75 * - Break out common code from arch/arm/mach-s3c64xx and share 70 * - Break out common code from arch/arm/mach-s3c64xx and share
76 */ 71 */
@@ -618,6 +613,49 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
618 sbus == &bd.srcbus ? "src" : "dst"); 613 sbus == &bd.srcbus ? "src" : "dst");
619 614
620 /* 615 /*
616 * Zero length is only allowed if all these requirements are met:
617 * - flow controller is peripheral.
618 * - src.addr is aligned to src.width
619 * - dst.addr is aligned to dst.width
620 *
621 * sg_len == 1 should be true, as there can be two cases here:
622 * - Memory addresses are contiguous and are not scattered. Here, Only
623 * one sg will be passed by user driver, with memory address and zero
624 * length. We pass this to controller and after the transfer it will
625 * receive the last burst request from peripheral and so transfer
626 * finishes.
627 *
628 * - Memory addresses are scattered and are not contiguous. Here,
629 * Obviously as DMA controller doesn't know when a lli's transfer gets
630 * over, it can't load next lli. So in this case, there has to be an
631 * assumption that only one lli is supported. Thus, we can't have
632 * scattered addresses.
633 */
634 if (!bd.remainder) {
635 u32 fc = (txd->ccfg & PL080_CONFIG_FLOW_CONTROL_MASK) >>
636 PL080_CONFIG_FLOW_CONTROL_SHIFT;
637 if (!((fc >= PL080_FLOW_SRC2DST_DST) &&
638 (fc <= PL080_FLOW_SRC2DST_SRC))) {
639 dev_err(&pl08x->adev->dev, "%s sg len can't be zero",
640 __func__);
641 return 0;
642 }
643
644 if ((bd.srcbus.addr % bd.srcbus.buswidth) ||
645 (bd.srcbus.addr % bd.srcbus.buswidth)) {
646 dev_err(&pl08x->adev->dev,
647 "%s src & dst address must be aligned to src"
648 " & dst width if peripheral is flow controller",
649 __func__);
650 return 0;
651 }
652
653 cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
654 bd.dstbus.buswidth, 0);
655 pl08x_fill_lli_for_desc(&bd, num_llis++, 0, cctl);
656 }
657
658 /*
621 * Send byte by byte for following cases 659 * Send byte by byte for following cases
622 * - Less than a bus width available 660 * - Less than a bus width available
623 * - until master bus is aligned 661 * - until master bus is aligned
@@ -1250,7 +1288,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
1250 struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); 1288 struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
1251 struct pl08x_driver_data *pl08x = plchan->host; 1289 struct pl08x_driver_data *pl08x = plchan->host;
1252 struct pl08x_txd *txd; 1290 struct pl08x_txd *txd;
1253 int ret; 1291 int ret, tmp;
1254 1292
1255 /* 1293 /*
1256 * Current implementation ASSUMES only one sg 1294 * Current implementation ASSUMES only one sg
@@ -1284,12 +1322,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
1284 txd->len = sgl->length; 1322 txd->len = sgl->length;
1285 1323
1286 if (direction == DMA_TO_DEVICE) { 1324 if (direction == DMA_TO_DEVICE) {
1287 txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
1288 txd->cctl = plchan->dst_cctl; 1325 txd->cctl = plchan->dst_cctl;
1289 txd->src_addr = sgl->dma_address; 1326 txd->src_addr = sgl->dma_address;
1290 txd->dst_addr = plchan->dst_addr; 1327 txd->dst_addr = plchan->dst_addr;
1291 } else if (direction == DMA_FROM_DEVICE) { 1328 } else if (direction == DMA_FROM_DEVICE) {
1292 txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
1293 txd->cctl = plchan->src_cctl; 1329 txd->cctl = plchan->src_cctl;
1294 txd->src_addr = plchan->src_addr; 1330 txd->src_addr = plchan->src_addr;
1295 txd->dst_addr = sgl->dma_address; 1331 txd->dst_addr = sgl->dma_address;
@@ -1299,6 +1335,15 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
1299 return NULL; 1335 return NULL;
1300 } 1336 }
1301 1337
1338 if (plchan->cd->device_fc)
1339 tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER_PER :
1340 PL080_FLOW_PER2MEM_PER;
1341 else
1342 tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER :
1343 PL080_FLOW_PER2MEM;
1344
1345 txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT;
1346
1302 ret = pl08x_prep_channel_resources(plchan, txd); 1347 ret = pl08x_prep_channel_resources(plchan, txd);
1303 if (ret) 1348 if (ret)
1304 return NULL; 1349 return NULL;