diff options
| -rw-r--r-- | drivers/dma/amba-pl08x.c | 61 | ||||
| -rw-r--r-- | include/linux/amba/pl08x.h | 4 |
2 files changed, 57 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; |
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index ecd17f581e71..a22662c93981 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h | |||
| @@ -47,6 +47,9 @@ enum { | |||
| 47 | * @muxval: a number usually used to poke into some mux regiser to | 47 | * @muxval: a number usually used to poke into some mux regiser to |
| 48 | * mux in the signal to this channel | 48 | * mux in the signal to this channel |
| 49 | * @cctl_opt: default options for the channel control register | 49 | * @cctl_opt: default options for the channel control register |
| 50 | * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave | ||
| 51 | * channels. Fill with 'true' if peripheral should be flow controller. Direction | ||
| 52 | * will be selected at Runtime. | ||
| 50 | * @addr: source/target address in physical memory for this DMA channel, | 53 | * @addr: source/target address in physical memory for this DMA channel, |
| 51 | * can be the address of a FIFO register for burst requests for example. | 54 | * can be the address of a FIFO register for burst requests for example. |
| 52 | * This can be left undefined if the PrimeCell API is used for configuring | 55 | * This can be left undefined if the PrimeCell API is used for configuring |
| @@ -65,6 +68,7 @@ struct pl08x_channel_data { | |||
| 65 | int max_signal; | 68 | int max_signal; |
| 66 | u32 muxval; | 69 | u32 muxval; |
| 67 | u32 cctl; | 70 | u32 cctl; |
| 71 | bool device_fc; | ||
| 68 | dma_addr_t addr; | 72 | dma_addr_t addr; |
| 69 | bool circular_buffer; | 73 | bool circular_buffer; |
| 70 | bool single; | 74 | bool single; |
