aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/bcm2835-dma.c
diff options
context:
space:
mode:
authorMartin Sperl <kernel@martin.sperl.org>2016-03-16 15:25:01 -0400
committerVinod Koul <vinod.koul@intel.com>2016-04-15 00:27:22 -0400
commit388cc7a281c06e484afcc3c5125b3271316209ef (patch)
treedc56a3a11f76a30547dd9c04a99026aeb6672a80 /drivers/dma/bcm2835-dma.c
parent4087412258276be37c5660fc6caf5d4e08920193 (diff)
dmaengine: bcm2835: add slave_sg support to bcm2835-dma
Add slave_sg support to bcm2835-dma using shared allocation code for bcm2835_desc and DMA-control blocks already used by dma_cyclic. Note that bcm2835_dma_callback had to get modified to support both modes of operation (cyclic and non-cyclic). Tested using: * Hifiberry I2S card (using cyclic DMA) * fb_st7735r SPI-framebuffer (using slave_sg DMA via spi-bcm2835) playing BigBuckBunny for audio and video. Signed-off-by: Martin Sperl <kernel@martin.sperl.org> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/bcm2835-dma.c')
-rw-r--r--drivers/dma/bcm2835-dma.c113
1 files changed, 108 insertions, 5 deletions
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 59c5ef36d970..b46b12f66f38 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -260,6 +260,23 @@ static void bcm2835_dma_create_cb_set_length(
260 control_block->info |= finalextrainfo; 260 control_block->info |= finalextrainfo;
261} 261}
262 262
263static inline size_t bcm2835_dma_count_frames_for_sg(
264 struct bcm2835_chan *c,
265 struct scatterlist *sgl,
266 unsigned int sg_len)
267{
268 size_t frames = 0;
269 struct scatterlist *sgent;
270 unsigned int i;
271 size_t plength = bcm2835_dma_max_frame_length(c);
272
273 for_each_sg(sgl, sgent, sg_len, i)
274 frames += bcm2835_dma_frames_for_length(
275 sg_dma_len(sgent), plength);
276
277 return frames;
278}
279
263/** 280/**
264 * bcm2835_dma_create_cb_chain - create a control block and fills data in 281 * bcm2835_dma_create_cb_chain - create a control block and fills data in
265 * 282 *
@@ -361,6 +378,32 @@ error_cb:
361 return NULL; 378 return NULL;
362} 379}
363 380
381static void bcm2835_dma_fill_cb_chain_with_sg(
382 struct dma_chan *chan,
383 enum dma_transfer_direction direction,
384 struct bcm2835_cb_entry *cb,
385 struct scatterlist *sgl,
386 unsigned int sg_len)
387{
388 struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
389 size_t max_len = bcm2835_dma_max_frame_length(c);
390 unsigned int i, len;
391 dma_addr_t addr;
392 struct scatterlist *sgent;
393
394 for_each_sg(sgl, sgent, sg_len, i) {
395 for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
396 len > 0;
397 addr += cb->cb->length, len -= cb->cb->length, cb++) {
398 if (direction == DMA_DEV_TO_MEM)
399 cb->cb->dst = addr;
400 else
401 cb->cb->src = addr;
402 cb->cb->length = min(len, max_len);
403 }
404 }
405}
406
364static int bcm2835_dma_abort(void __iomem *chan_base) 407static int bcm2835_dma_abort(void __iomem *chan_base)
365{ 408{
366 unsigned long cs; 409 unsigned long cs;
@@ -428,13 +471,19 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
428 d = c->desc; 471 d = c->desc;
429 472
430 if (d) { 473 if (d) {
431 /* TODO Only works for cyclic DMA */ 474 if (d->cyclic) {
432 vchan_cyclic_callback(&d->vd); 475 /* call the cyclic callback */
476 vchan_cyclic_callback(&d->vd);
477
478 /* Keep the DMA engine running */
479 writel(BCM2835_DMA_ACTIVE,
480 c->chan_base + BCM2835_DMA_CS);
481 } else {
482 vchan_cookie_complete(&c->desc->vd);
483 bcm2835_dma_start_desc(c);
484 }
433 } 485 }
434 486
435 /* Keep the DMA engine running */
436 writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
437
438 spin_unlock_irqrestore(&c->vc.lock, flags); 487 spin_unlock_irqrestore(&c->vc.lock, flags);
439 488
440 return IRQ_HANDLED; 489 return IRQ_HANDLED;
@@ -548,6 +597,58 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan)
548 spin_unlock_irqrestore(&c->vc.lock, flags); 597 spin_unlock_irqrestore(&c->vc.lock, flags);
549} 598}
550 599
600static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg(
601 struct dma_chan *chan,
602 struct scatterlist *sgl, unsigned int sg_len,
603 enum dma_transfer_direction direction,
604 unsigned long flags, void *context)
605{
606 struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
607 struct bcm2835_desc *d;
608 dma_addr_t src = 0, dst = 0;
609 u32 info = BCM2835_DMA_WAIT_RESP;
610 u32 extra = BCM2835_DMA_INT_EN;
611 size_t frames;
612
613 if (!is_slave_direction(direction)) {
614 dev_err(chan->device->dev,
615 "%s: bad direction?\n", __func__);
616 return NULL;
617 }
618
619 if (c->dreq != 0)
620 info |= BCM2835_DMA_PER_MAP(c->dreq);
621
622 if (direction == DMA_DEV_TO_MEM) {
623 if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
624 return NULL;
625 src = c->cfg.src_addr;
626 info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
627 } else {
628 if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
629 return NULL;
630 dst = c->cfg.dst_addr;
631 info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
632 }
633
634 /* count frames in sg list */
635 frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len);
636
637 /* allocate the CB chain */
638 d = bcm2835_dma_create_cb_chain(chan, direction, false,
639 info, extra,
640 frames, src, dst, 0, 0,
641 GFP_KERNEL);
642 if (!d)
643 return NULL;
644
645 /* fill in frames with scatterlist pointers */
646 bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
647 sgl, sg_len);
648
649 return vchan_tx_prep(&c->vc, &d->vd, flags);
650}
651
551static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( 652static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
552 struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, 653 struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
553 size_t period_len, enum dma_transfer_direction direction, 654 size_t period_len, enum dma_transfer_direction direction,
@@ -778,11 +879,13 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
778 dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); 879 dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
779 dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask); 880 dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask);
780 dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); 881 dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
882 dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
781 od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources; 883 od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources;
782 od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources; 884 od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources;
783 od->ddev.device_tx_status = bcm2835_dma_tx_status; 885 od->ddev.device_tx_status = bcm2835_dma_tx_status;
784 od->ddev.device_issue_pending = bcm2835_dma_issue_pending; 886 od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
785 od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic; 887 od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
888 od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg;
786 od->ddev.device_config = bcm2835_dma_slave_config; 889 od->ddev.device_config = bcm2835_dma_slave_config;
787 od->ddev.device_terminate_all = bcm2835_dma_terminate_all; 890 od->ddev.device_terminate_all = bcm2835_dma_terminate_all;
788 od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); 891 od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);