diff options
author | Martin Sperl <kernel@martin.sperl.org> | 2016-04-11 09:29:08 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2016-04-19 11:32:48 -0400 |
commit | e2eca6389b031cdbbc4172eee89ce271c00cb672 (patch) | |
tree | 8d04e37288b8d3b47c6972794d629fb8eee21f0d /drivers/dma/bcm2835-dma.c | |
parent | e7679db714c356f8e27df2dc3ff721c0d3775448 (diff) |
dmaengine: bcm2835: use platform_get_irq_byname
Use platform_get_irq_byname to allow for correct mapping of
interrupts to dma channels.
The currently implemented device tree is unfortunately
implemented with the wrong assumption, that each dma-channel
has its own dma channel, but dma-irq 11 is handling
dma-channel 11-14 and dma-irq 12 is actually a "catch all"
interrupt.
So here we use the byname variant and require that interrupts
are explicitly named via the interrupts-name property in the
device tree.
The use of shared interrupts is also implemented.
As a side-effect this means we can now use dma channels 12, 13 and 14
in a correct manner - also testing shows that onl using
channels 11 to 14 for spi and i2s works perfectly (when playing
some video)
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Acked-by: Eric Anholt <eric@anholt.net>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/bcm2835-dma.c')
-rw-r--r-- | drivers/dma/bcm2835-dma.c | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index cc771cd35dd0..974015193b93 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c | |||
@@ -46,6 +46,9 @@ | |||
46 | 46 | ||
47 | #include "virt-dma.h" | 47 | #include "virt-dma.h" |
48 | 48 | ||
49 | #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 | ||
50 | #define BCM2835_DMA_CHAN_NAME_SIZE 8 | ||
51 | |||
49 | struct bcm2835_dmadev { | 52 | struct bcm2835_dmadev { |
50 | struct dma_device ddev; | 53 | struct dma_device ddev; |
51 | spinlock_t lock; | 54 | spinlock_t lock; |
@@ -81,6 +84,7 @@ struct bcm2835_chan { | |||
81 | 84 | ||
82 | void __iomem *chan_base; | 85 | void __iomem *chan_base; |
83 | int irq_number; | 86 | int irq_number; |
87 | unsigned int irq_flags; | ||
84 | 88 | ||
85 | bool is_lite_channel; | 89 | bool is_lite_channel; |
86 | }; | 90 | }; |
@@ -466,6 +470,15 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) | |||
466 | struct bcm2835_desc *d; | 470 | struct bcm2835_desc *d; |
467 | unsigned long flags; | 471 | unsigned long flags; |
468 | 472 | ||
473 | /* check the shared interrupt */ | ||
474 | if (c->irq_flags & IRQF_SHARED) { | ||
475 | /* check if the interrupt is enabled */ | ||
476 | flags = readl(c->chan_base + BCM2835_DMA_CS); | ||
477 | /* if not set then we are not the reason for the irq */ | ||
478 | if (!(flags & BCM2835_DMA_INT)) | ||
479 | return IRQ_NONE; | ||
480 | } | ||
481 | |||
469 | spin_lock_irqsave(&c->vc.lock, flags); | 482 | spin_lock_irqsave(&c->vc.lock, flags); |
470 | 483 | ||
471 | /* Acknowledge interrupt */ | 484 | /* Acknowledge interrupt */ |
@@ -506,8 +519,8 @@ static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan) | |||
506 | return -ENOMEM; | 519 | return -ENOMEM; |
507 | } | 520 | } |
508 | 521 | ||
509 | return request_irq(c->irq_number, | 522 | return request_irq(c->irq_number, bcm2835_dma_callback, |
510 | bcm2835_dma_callback, 0, "DMA IRQ", c); | 523 | c->irq_flags, "DMA IRQ", c); |
511 | } | 524 | } |
512 | 525 | ||
513 | static void bcm2835_dma_free_chan_resources(struct dma_chan *chan) | 526 | static void bcm2835_dma_free_chan_resources(struct dma_chan *chan) |
@@ -819,7 +832,8 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) | |||
819 | return 0; | 832 | return 0; |
820 | } | 833 | } |
821 | 834 | ||
822 | static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) | 835 | static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, |
836 | int irq, unsigned int irq_flags) | ||
823 | { | 837 | { |
824 | struct bcm2835_chan *c; | 838 | struct bcm2835_chan *c; |
825 | 839 | ||
@@ -834,6 +848,7 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq) | |||
834 | c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id); | 848 | c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id); |
835 | c->ch = chan_id; | 849 | c->ch = chan_id; |
836 | c->irq_number = irq; | 850 | c->irq_number = irq; |
851 | c->irq_flags = irq_flags; | ||
837 | 852 | ||
838 | /* check in DEBUG register if this is a LITE channel */ | 853 | /* check in DEBUG register if this is a LITE channel */ |
839 | if (readl(c->chan_base + BCM2835_DMA_DEBUG) & | 854 | if (readl(c->chan_base + BCM2835_DMA_DEBUG) & |
@@ -882,9 +897,11 @@ static int bcm2835_dma_probe(struct platform_device *pdev) | |||
882 | struct resource *res; | 897 | struct resource *res; |
883 | void __iomem *base; | 898 | void __iomem *base; |
884 | int rc; | 899 | int rc; |
885 | int i; | 900 | int i, j; |
886 | int irq; | 901 | int irq[BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1]; |
902 | int irq_flags; | ||
887 | uint32_t chans_available; | 903 | uint32_t chans_available; |
904 | char chan_name[BCM2835_DMA_CHAN_NAME_SIZE]; | ||
888 | 905 | ||
889 | if (!pdev->dev.dma_mask) | 906 | if (!pdev->dev.dma_mask) |
890 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; | 907 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; |
@@ -941,16 +958,48 @@ static int bcm2835_dma_probe(struct platform_device *pdev) | |||
941 | goto err_no_dma; | 958 | goto err_no_dma; |
942 | } | 959 | } |
943 | 960 | ||
944 | for (i = 0; i < pdev->num_resources; i++) { | 961 | /* get irqs for each channel that we support */ |
945 | irq = platform_get_irq(pdev, i); | 962 | for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) { |
946 | if (irq < 0) | 963 | /* skip masked out channels */ |
947 | break; | 964 | if (!(chans_available & (1 << i))) { |
948 | 965 | irq[i] = -1; | |
949 | if (chans_available & (1 << i)) { | 966 | continue; |
950 | rc = bcm2835_dma_chan_init(od, i, irq); | ||
951 | if (rc) | ||
952 | goto err_no_dma; | ||
953 | } | 967 | } |
968 | |||
969 | /* get the named irq */ | ||
970 | snprintf(chan_name, sizeof(chan_name), "dma%i", i); | ||
971 | irq[i] = platform_get_irq_byname(pdev, chan_name); | ||
972 | if (irq[i] >= 0) | ||
973 | continue; | ||
974 | |||
975 | /* legacy device tree case handling */ | ||
976 | dev_warn_once(&pdev->dev, | ||
977 | "missing interrupts-names property in device tree - legacy interpretation is used"); | ||
978 | /* | ||
979 | * in case of channel >= 11 | ||
980 | * use the 11th interrupt and that is shared | ||
981 | */ | ||
982 | irq[i] = platform_get_irq(pdev, i < 11 ? i : 11); | ||
983 | } | ||
984 | |||
985 | /* get irqs for each channel */ | ||
986 | for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) { | ||
987 | /* skip channels without irq */ | ||
988 | if (irq[i] < 0) | ||
989 | continue; | ||
990 | |||
991 | /* check if there are other channels that also use this irq */ | ||
992 | irq_flags = 0; | ||
993 | for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++) | ||
994 | if ((i != j) && (irq[j] == irq[i])) { | ||
995 | irq_flags = IRQF_SHARED; | ||
996 | break; | ||
997 | } | ||
998 | |||
999 | /* initialize the channel */ | ||
1000 | rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags); | ||
1001 | if (rc) | ||
1002 | goto err_no_dma; | ||
954 | } | 1003 | } |
955 | 1004 | ||
956 | dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i); | 1005 | dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i); |