aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/sun6i-dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/sun6i-dma.c')
-rw-r--r--drivers/dma/sun6i-dma.c160
1 files changed, 87 insertions, 73 deletions
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 159f1736a16f..7ebcf9bec698 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -355,38 +355,6 @@ static void sun6i_dma_free_desc(struct virt_dma_desc *vd)
355 kfree(txd); 355 kfree(txd);
356} 356}
357 357
358static int sun6i_dma_terminate_all(struct sun6i_vchan *vchan)
359{
360 struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device);
361 struct sun6i_pchan *pchan = vchan->phy;
362 unsigned long flags;
363 LIST_HEAD(head);
364
365 spin_lock(&sdev->lock);
366 list_del_init(&vchan->node);
367 spin_unlock(&sdev->lock);
368
369 spin_lock_irqsave(&vchan->vc.lock, flags);
370
371 vchan_get_all_descriptors(&vchan->vc, &head);
372
373 if (pchan) {
374 writel(DMA_CHAN_ENABLE_STOP, pchan->base + DMA_CHAN_ENABLE);
375 writel(DMA_CHAN_PAUSE_RESUME, pchan->base + DMA_CHAN_PAUSE);
376
377 vchan->phy = NULL;
378 pchan->vchan = NULL;
379 pchan->desc = NULL;
380 pchan->done = NULL;
381 }
382
383 spin_unlock_irqrestore(&vchan->vc.lock, flags);
384
385 vchan_dma_desc_free_list(&vchan->vc, &head);
386
387 return 0;
388}
389
390static int sun6i_dma_start_desc(struct sun6i_vchan *vchan) 358static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
391{ 359{
392 struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device); 360 struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device);
@@ -675,57 +643,92 @@ err_lli_free:
675 return NULL; 643 return NULL;
676} 644}
677 645
678static int sun6i_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 646static int sun6i_dma_config(struct dma_chan *chan,
679 unsigned long arg) 647 struct dma_slave_config *config)
648{
649 struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
650
651 memcpy(&vchan->cfg, config, sizeof(*config));
652
653 return 0;
654}
655
656static int sun6i_dma_pause(struct dma_chan *chan)
657{
658 struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
659 struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
660 struct sun6i_pchan *pchan = vchan->phy;
661
662 dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc);
663
664 if (pchan) {
665 writel(DMA_CHAN_PAUSE_PAUSE,
666 pchan->base + DMA_CHAN_PAUSE);
667 } else {
668 spin_lock(&sdev->lock);
669 list_del_init(&vchan->node);
670 spin_unlock(&sdev->lock);
671 }
672
673 return 0;
674}
675
676static int sun6i_dma_resume(struct dma_chan *chan)
680{ 677{
681 struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 678 struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
682 struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 679 struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
683 struct sun6i_pchan *pchan = vchan->phy; 680 struct sun6i_pchan *pchan = vchan->phy;
684 unsigned long flags; 681 unsigned long flags;
685 int ret = 0;
686 682
687 switch (cmd) { 683 dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
688 case DMA_RESUME:
689 dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
690 684
691 spin_lock_irqsave(&vchan->vc.lock, flags); 685 spin_lock_irqsave(&vchan->vc.lock, flags);
692 686
693 if (pchan) { 687 if (pchan) {
694 writel(DMA_CHAN_PAUSE_RESUME, 688 writel(DMA_CHAN_PAUSE_RESUME,
695 pchan->base + DMA_CHAN_PAUSE); 689 pchan->base + DMA_CHAN_PAUSE);
696 } else if (!list_empty(&vchan->vc.desc_issued)) { 690 } else if (!list_empty(&vchan->vc.desc_issued)) {
697 spin_lock(&sdev->lock); 691 spin_lock(&sdev->lock);
698 list_add_tail(&vchan->node, &sdev->pending); 692 list_add_tail(&vchan->node, &sdev->pending);
699 spin_unlock(&sdev->lock); 693 spin_unlock(&sdev->lock);
700 } 694 }
701 695
702 spin_unlock_irqrestore(&vchan->vc.lock, flags); 696 spin_unlock_irqrestore(&vchan->vc.lock, flags);
703 break;
704 697
705 case DMA_PAUSE: 698 return 0;
706 dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc); 699}
707 700
708 if (pchan) { 701static int sun6i_dma_terminate_all(struct dma_chan *chan)
709 writel(DMA_CHAN_PAUSE_PAUSE, 702{
710 pchan->base + DMA_CHAN_PAUSE); 703 struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
711 } else { 704 struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
712 spin_lock(&sdev->lock); 705 struct sun6i_pchan *pchan = vchan->phy;
713 list_del_init(&vchan->node); 706 unsigned long flags;
714 spin_unlock(&sdev->lock); 707 LIST_HEAD(head);
715 } 708
716 break; 709 spin_lock(&sdev->lock);
717 710 list_del_init(&vchan->node);
718 case DMA_TERMINATE_ALL: 711 spin_unlock(&sdev->lock);
719 ret = sun6i_dma_terminate_all(vchan); 712
720 break; 713 spin_lock_irqsave(&vchan->vc.lock, flags);
721 case DMA_SLAVE_CONFIG: 714
722 memcpy(&vchan->cfg, (void *)arg, sizeof(struct dma_slave_config)); 715 vchan_get_all_descriptors(&vchan->vc, &head);
723 break; 716
724 default: 717 if (pchan) {
725 ret = -ENXIO; 718 writel(DMA_CHAN_ENABLE_STOP, pchan->base + DMA_CHAN_ENABLE);
726 break; 719 writel(DMA_CHAN_PAUSE_RESUME, pchan->base + DMA_CHAN_PAUSE);
720
721 vchan->phy = NULL;
722 pchan->vchan = NULL;
723 pchan->desc = NULL;
724 pchan->done = NULL;
727 } 725 }
728 return ret; 726
727 spin_unlock_irqrestore(&vchan->vc.lock, flags);
728
729 vchan_dma_desc_free_list(&vchan->vc, &head);
730
731 return 0;
729} 732}
730 733
731static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan, 734static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
@@ -960,9 +963,20 @@ static int sun6i_dma_probe(struct platform_device *pdev)
960 sdc->slave.device_issue_pending = sun6i_dma_issue_pending; 963 sdc->slave.device_issue_pending = sun6i_dma_issue_pending;
961 sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg; 964 sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg;
962 sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy; 965 sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy;
963 sdc->slave.device_control = sun6i_dma_control;
964 sdc->slave.copy_align = 4; 966 sdc->slave.copy_align = 4;
965 967 sdc->slave.device_config = sun6i_dma_config;
968 sdc->slave.device_pause = sun6i_dma_pause;
969 sdc->slave.device_resume = sun6i_dma_resume;
970 sdc->slave.device_terminate_all = sun6i_dma_terminate_all;
971 sdc->slave.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
972 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
973 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
974 sdc->slave.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
975 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
976 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
977 sdc->slave.directions = BIT(DMA_DEV_TO_MEM) |
978 BIT(DMA_MEM_TO_DEV);
979 sdc->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
966 sdc->slave.dev = &pdev->dev; 980 sdc->slave.dev = &pdev->dev;
967 981
968 sdc->pchans = devm_kcalloc(&pdev->dev, sdc->cfg->nr_max_channels, 982 sdc->pchans = devm_kcalloc(&pdev->dev, sdc->cfg->nr_max_channels,