.. | .. |
---|
29 | 29 | #include <linux/slab.h> |
---|
30 | 30 | #include <linux/io.h> |
---|
31 | 31 | #include <linux/spinlock.h> |
---|
| 32 | +#include <linux/irqstage.h> |
---|
32 | 33 | #include <linux/of.h> |
---|
33 | 34 | #include <linux/of_dma.h> |
---|
34 | 35 | |
---|
.. | .. |
---|
435 | 436 | writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS); |
---|
436 | 437 | } |
---|
437 | 438 | |
---|
| 439 | +static inline void bcm2835_dma_enable_channel(struct bcm2835_chan *c) |
---|
| 440 | +{ |
---|
| 441 | + writel(c->desc->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); |
---|
| 442 | + writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); |
---|
| 443 | +} |
---|
| 444 | + |
---|
| 445 | +static inline bool bcm2835_dma_oob_capable(void) |
---|
| 446 | +{ |
---|
| 447 | + return IS_ENABLED(CONFIG_DMA_BCM2835_OOB); |
---|
| 448 | +} |
---|
| 449 | + |
---|
438 | 450 | static void bcm2835_dma_start_desc(struct bcm2835_chan *c) |
---|
439 | 451 | { |
---|
440 | 452 | struct virt_dma_desc *vd = vchan_next_desc(&c->vc); |
---|
441 | | - struct bcm2835_desc *d; |
---|
442 | 453 | |
---|
443 | 454 | if (!vd) { |
---|
444 | 455 | c->desc = NULL; |
---|
.. | .. |
---|
447 | 458 | |
---|
448 | 459 | list_del(&vd->node); |
---|
449 | 460 | |
---|
450 | | - c->desc = d = to_bcm2835_dma_desc(&vd->tx); |
---|
| 461 | + c->desc = to_bcm2835_dma_desc(&vd->tx); |
---|
| 462 | + if (!bcm2835_dma_oob_capable() || !vchan_oob_pulsed(vd)) |
---|
| 463 | + bcm2835_dma_enable_channel(c); |
---|
| 464 | +} |
---|
451 | 465 | |
---|
452 | | - writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); |
---|
453 | | - writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); |
---|
| 466 | +static bool do_channel(struct bcm2835_chan *c, struct bcm2835_desc *d) |
---|
| 467 | +{ |
---|
| 468 | + struct dmaengine_desc_callback cb; |
---|
| 469 | + |
---|
| 470 | + if (running_oob()) { |
---|
| 471 | + if (!vchan_oob_handled(&d->vd)) |
---|
| 472 | + return false; |
---|
| 473 | + dmaengine_desc_get_callback(&d->vd.tx, &cb); |
---|
| 474 | + if (dmaengine_desc_callback_valid(&cb)) { |
---|
| 475 | + vchan_unlock(&c->vc); |
---|
| 476 | + dmaengine_desc_callback_invoke(&cb, NULL); |
---|
| 477 | + vchan_lock(&c->vc); |
---|
| 478 | + } |
---|
| 479 | + return true; |
---|
| 480 | + } |
---|
| 481 | + |
---|
| 482 | + if (d->cyclic) { |
---|
| 483 | + /* call the cyclic callback */ |
---|
| 484 | + vchan_cyclic_callback(&d->vd); |
---|
| 485 | + } else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) { |
---|
| 486 | + vchan_cookie_complete(&c->desc->vd); |
---|
| 487 | + bcm2835_dma_start_desc(c); |
---|
| 488 | + } |
---|
| 489 | + |
---|
| 490 | + return true; |
---|
| 491 | +} |
---|
| 492 | + |
---|
| 493 | +static inline bool is_base_irq_handler(void) |
---|
| 494 | +{ |
---|
| 495 | + return !bcm2835_dma_oob_capable() || running_oob(); |
---|
454 | 496 | } |
---|
455 | 497 | |
---|
456 | 498 | static irqreturn_t bcm2835_dma_callback(int irq, void *data) |
---|
.. | .. |
---|
460 | 502 | unsigned long flags; |
---|
461 | 503 | |
---|
462 | 504 | /* check the shared interrupt */ |
---|
463 | | - if (c->irq_flags & IRQF_SHARED) { |
---|
| 505 | + if (is_base_irq_handler() && c->irq_flags & IRQF_SHARED) { |
---|
464 | 506 | /* check if the interrupt is enabled */ |
---|
465 | 507 | flags = readl(c->chan_base + BCM2835_DMA_CS); |
---|
466 | 508 | /* if not set then we are not the reason for the irq */ |
---|
.. | .. |
---|
468 | 510 | return IRQ_NONE; |
---|
469 | 511 | } |
---|
470 | 512 | |
---|
471 | | - spin_lock_irqsave(&c->vc.lock, flags); |
---|
| 513 | + /* CAUTION: If running in-band, hard irqs are on. */ |
---|
| 514 | + vchan_lock_irqsave(&c->vc, flags); |
---|
472 | 515 | |
---|
473 | 516 | /* |
---|
474 | 517 | * Clear the INT flag to receive further interrupts. Keep the channel |
---|
.. | .. |
---|
477 | 520 | * if this IRQ handler is threaded.) If the channel is finished, it |
---|
478 | 521 | * will remain idle despite the ACTIVE flag being set. |
---|
479 | 522 | */ |
---|
480 | | - writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE, |
---|
481 | | - c->chan_base + BCM2835_DMA_CS); |
---|
| 523 | + if (is_base_irq_handler()) |
---|
| 524 | + writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE, |
---|
| 525 | + c->chan_base + BCM2835_DMA_CS); |
---|
482 | 526 | |
---|
483 | 527 | d = c->desc; |
---|
| 528 | + if (!d) |
---|
| 529 | + goto out; |
---|
484 | 530 | |
---|
485 | | - if (d) { |
---|
486 | | - if (d->cyclic) { |
---|
487 | | - /* call the cyclic callback */ |
---|
488 | | - vchan_cyclic_callback(&d->vd); |
---|
489 | | - } else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) { |
---|
490 | | - vchan_cookie_complete(&c->desc->vd); |
---|
491 | | - bcm2835_dma_start_desc(c); |
---|
492 | | - } |
---|
| 531 | + if (bcm2835_dma_oob_capable() && running_oob()) { |
---|
| 532 | + /* |
---|
| 533 | + * If we cannot process this from the out-of-band |
---|
| 534 | + * stage, schedule a callback from in-band context. |
---|
| 535 | + */ |
---|
| 536 | + if (!do_channel(c, d)) |
---|
| 537 | + irq_post_inband(irq); |
---|
| 538 | + } else { |
---|
| 539 | + do_channel(c, d); |
---|
493 | 540 | } |
---|
494 | 541 | |
---|
495 | | - spin_unlock_irqrestore(&c->vc.lock, flags); |
---|
| 542 | +out: |
---|
| 543 | + vchan_unlock_irqrestore(&c->vc, flags); |
---|
496 | 544 | |
---|
497 | 545 | return IRQ_HANDLED; |
---|
498 | 546 | } |
---|
.. | .. |
---|
571 | 619 | if (ret == DMA_COMPLETE || !txstate) |
---|
572 | 620 | return ret; |
---|
573 | 621 | |
---|
574 | | - spin_lock_irqsave(&c->vc.lock, flags); |
---|
| 622 | + vchan_lock_irqsave(&c->vc, flags); |
---|
575 | 623 | vd = vchan_find_desc(&c->vc, cookie); |
---|
576 | 624 | if (vd) { |
---|
577 | 625 | txstate->residue = |
---|
.. | .. |
---|
592 | 640 | txstate->residue = 0; |
---|
593 | 641 | } |
---|
594 | 642 | |
---|
595 | | - spin_unlock_irqrestore(&c->vc.lock, flags); |
---|
| 643 | + vchan_unlock_irqrestore(&c->vc, flags); |
---|
596 | 644 | |
---|
597 | 645 | return ret; |
---|
598 | 646 | } |
---|
.. | .. |
---|
602 | 650 | struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); |
---|
603 | 651 | unsigned long flags; |
---|
604 | 652 | |
---|
605 | | - spin_lock_irqsave(&c->vc.lock, flags); |
---|
| 653 | + vchan_lock_irqsave(&c->vc, flags); |
---|
606 | 654 | if (vchan_issue_pending(&c->vc) && !c->desc) |
---|
607 | 655 | bcm2835_dma_start_desc(c); |
---|
608 | 656 | |
---|
609 | | - spin_unlock_irqrestore(&c->vc.lock, flags); |
---|
| 657 | + vchan_unlock_irqrestore(&c->vc, flags); |
---|
610 | 658 | } |
---|
| 659 | + |
---|
| 660 | +#ifdef CONFIG_DMA_BCM2835_OOB |
---|
| 661 | +static int bcm2835_dma_pulse_oob(struct dma_chan *chan) |
---|
| 662 | +{ |
---|
| 663 | + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); |
---|
| 664 | + unsigned long flags; |
---|
| 665 | + int ret = -EIO; |
---|
| 666 | + |
---|
| 667 | + vchan_lock_irqsave(&c->vc, flags); |
---|
| 668 | + if (c->desc && vchan_oob_pulsed(&c->desc->vd)) { |
---|
| 669 | + bcm2835_dma_enable_channel(c); |
---|
| 670 | + ret = 0; |
---|
| 671 | + } |
---|
| 672 | + vchan_unlock_irqrestore(&c->vc, flags); |
---|
| 673 | + |
---|
| 674 | + return ret; |
---|
| 675 | +} |
---|
| 676 | +#else |
---|
| 677 | +static int bcm2835_dma_pulse_oob(struct dma_chan *chan) |
---|
| 678 | +{ |
---|
| 679 | + return -ENOTSUPP; |
---|
| 680 | +} |
---|
| 681 | +#endif |
---|
611 | 682 | |
---|
612 | 683 | static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( |
---|
613 | 684 | struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, |
---|
.. | .. |
---|
649 | 720 | u32 info = BCM2835_DMA_WAIT_RESP; |
---|
650 | 721 | u32 extra = BCM2835_DMA_INT_EN; |
---|
651 | 722 | size_t frames; |
---|
| 723 | + |
---|
| 724 | + if (!bcm2835_dma_oob_capable()) { |
---|
| 725 | + if (flags & (DMA_OOB_INTERRUPT|DMA_OOB_PULSE)) { |
---|
| 726 | + dev_err(chan->device->dev, |
---|
| 727 | + "%s: out-of-band slave transfers disabled\n", |
---|
| 728 | + __func__); |
---|
| 729 | + return NULL; |
---|
| 730 | + } |
---|
| 731 | + } |
---|
652 | 732 | |
---|
653 | 733 | if (!is_slave_direction(direction)) { |
---|
654 | 734 | dev_err(chan->device->dev, |
---|
.. | .. |
---|
715 | 795 | return NULL; |
---|
716 | 796 | } |
---|
717 | 797 | |
---|
718 | | - if (flags & DMA_PREP_INTERRUPT) |
---|
| 798 | + if (!bcm2835_dma_oob_capable()) { |
---|
| 799 | + if (flags & DMA_OOB_INTERRUPT) { |
---|
| 800 | + dev_err(chan->device->dev, |
---|
| 801 | + "%s: out-of-band cyclic transfers disabled\n", |
---|
| 802 | + __func__); |
---|
| 803 | + return NULL; |
---|
| 804 | + } |
---|
| 805 | + } else if (flags & DMA_OOB_PULSE) { |
---|
| 806 | + dev_err(chan->device->dev, |
---|
| 807 | + "%s: no pulse mode with out-of-band cyclic transfers\n", |
---|
| 808 | + __func__); |
---|
| 809 | + return NULL; |
---|
| 810 | + } |
---|
| 811 | + |
---|
| 812 | + if (flags & (DMA_PREP_INTERRUPT|DMA_OOB_INTERRUPT)) |
---|
719 | 813 | extra |= BCM2835_DMA_INT_EN; |
---|
720 | 814 | else |
---|
721 | 815 | period_len = buf_len; |
---|
.. | .. |
---|
791 | 885 | unsigned long flags; |
---|
792 | 886 | LIST_HEAD(head); |
---|
793 | 887 | |
---|
794 | | - spin_lock_irqsave(&c->vc.lock, flags); |
---|
| 888 | + vchan_lock_irqsave(&c->vc, flags); |
---|
795 | 889 | |
---|
796 | 890 | /* stop DMA activity */ |
---|
797 | 891 | if (c->desc) { |
---|
.. | .. |
---|
801 | 895 | } |
---|
802 | 896 | |
---|
803 | 897 | vchan_get_all_descriptors(&c->vc, &head); |
---|
804 | | - spin_unlock_irqrestore(&c->vc.lock, flags); |
---|
| 898 | + vchan_unlock_irqrestore(&c->vc, flags); |
---|
805 | 899 | vchan_dma_desc_free_list(&c->vc, &head); |
---|
806 | 900 | |
---|
807 | 901 | return 0; |
---|
.. | .. |
---|
912 | 1006 | dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); |
---|
913 | 1007 | dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask); |
---|
914 | 1008 | dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); |
---|
| 1009 | + dma_cap_set(DMA_OOB, od->ddev.cap_mask); |
---|
915 | 1010 | dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask); |
---|
916 | 1011 | od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources; |
---|
917 | 1012 | od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources; |
---|
918 | 1013 | od->ddev.device_tx_status = bcm2835_dma_tx_status; |
---|
919 | 1014 | od->ddev.device_issue_pending = bcm2835_dma_issue_pending; |
---|
| 1015 | + od->ddev.device_pulse_oob = bcm2835_dma_pulse_oob; |
---|
920 | 1016 | od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic; |
---|
921 | 1017 | od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg; |
---|
922 | 1018 | od->ddev.device_prep_dma_memcpy = bcm2835_dma_prep_dma_memcpy; |
---|
.. | .. |
---|
982 | 1078 | continue; |
---|
983 | 1079 | |
---|
984 | 1080 | /* check if there are other channels that also use this irq */ |
---|
985 | | - irq_flags = 0; |
---|
| 1081 | + irq_flags = IS_ENABLED(CONFIG_DMA_BCM2835_OOB) ? IRQF_OOB : 0; |
---|
986 | 1082 | for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++) |
---|
987 | 1083 | if ((i != j) && (irq[j] == irq[i])) { |
---|
988 | | - irq_flags = IRQF_SHARED; |
---|
| 1084 | + irq_flags |= IRQF_SHARED; |
---|
989 | 1085 | break; |
---|
990 | 1086 | } |
---|
991 | 1087 | |
---|