summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.4/0400-dmaengine-bcm2835-use-platform_get_irq_byname.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.4/0400-dmaengine-bcm2835-use-platform_get_irq_byname.patch')
-rw-r--r--target/linux/brcm2708/patches-4.4/0400-dmaengine-bcm2835-use-platform_get_irq_byname.patch170
1 files changed, 170 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.4/0400-dmaengine-bcm2835-use-platform_get_irq_byname.patch b/target/linux/brcm2708/patches-4.4/0400-dmaengine-bcm2835-use-platform_get_irq_byname.patch
new file mode 100644
index 0000000000..b8eecaf4e0
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.4/0400-dmaengine-bcm2835-use-platform_get_irq_byname.patch
@@ -0,0 +1,170 @@
+From 27a895c19212e695f70bd4860d4420f70f915fe1 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Mon, 11 Apr 2016 13:29:08 +0000
+Subject: [PATCH] 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>
+---
+ drivers/dma/bcm2835-dma.c | 77 ++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 63 insertions(+), 14 deletions(-)
+
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -46,6 +46,9 @@
+
+ #include "virt-dma.h"
+
++#define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
++#define BCM2835_DMA_CHAN_NAME_SIZE 8
++
+ struct bcm2835_dmadev {
+ struct dma_device ddev;
+ spinlock_t lock;
+@@ -81,6 +84,7 @@ struct bcm2835_chan {
+
+ void __iomem *chan_base;
+ int irq_number;
++ unsigned int irq_flags;
+
+ bool is_lite_channel;
+ };
+@@ -466,6 +470,15 @@ static irqreturn_t bcm2835_dma_callback(
+ struct bcm2835_desc *d;
+ unsigned long flags;
+
++ /* check the shared interrupt */
++ if (c->irq_flags & IRQF_SHARED) {
++ /* check if the interrupt is enabled */
++ flags = readl(c->chan_base + BCM2835_DMA_CS);
++ /* if not set then we are not the reason for the irq */
++ if (!(flags & BCM2835_DMA_INT))
++ return IRQ_NONE;
++ }
++
+ spin_lock_irqsave(&c->vc.lock, flags);
+
+ /* Acknowledge interrupt */
+@@ -506,8 +519,8 @@ static int bcm2835_dma_alloc_chan_resour
+ return -ENOMEM;
+ }
+
+- return request_irq(c->irq_number,
+- bcm2835_dma_callback, 0, "DMA IRQ", c);
++ return request_irq(c->irq_number, bcm2835_dma_callback,
++ c->irq_flags, "DMA IRQ", c);
+ }
+
+ static void bcm2835_dma_free_chan_resources(struct dma_chan *chan)
+@@ -819,7 +832,8 @@ static int bcm2835_dma_terminate_all(str
+ return 0;
+ }
+
+-static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq)
++static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id,
++ int irq, unsigned int irq_flags)
+ {
+ struct bcm2835_chan *c;
+
+@@ -834,6 +848,7 @@ static int bcm2835_dma_chan_init(struct
+ c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id);
+ c->ch = chan_id;
+ c->irq_number = irq;
++ c->irq_flags = irq_flags;
+
+ /* check in DEBUG register if this is a LITE channel */
+ if (readl(c->chan_base + BCM2835_DMA_DEBUG) &
+@@ -882,9 +897,11 @@ static int bcm2835_dma_probe(struct plat
+ struct resource *res;
+ void __iomem *base;
+ int rc;
+- int i;
+- int irq;
++ int i, j;
++ int irq[BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED + 1];
++ int irq_flags;
+ uint32_t chans_available;
++ char chan_name[BCM2835_DMA_CHAN_NAME_SIZE];
+
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+@@ -941,16 +958,48 @@ static int bcm2835_dma_probe(struct plat
+ goto err_no_dma;
+ }
+
+- for (i = 0; i < pdev->num_resources; i++) {
+- irq = platform_get_irq(pdev, i);
+- if (irq < 0)
+- break;
+-
+- if (chans_available & (1 << i)) {
+- rc = bcm2835_dma_chan_init(od, i, irq);
+- if (rc)
+- goto err_no_dma;
++ /* get irqs for each channel that we support */
++ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
++ /* skip masked out channels */
++ if (!(chans_available & (1 << i))) {
++ irq[i] = -1;
++ continue;
+ }
++
++ /* get the named irq */
++ snprintf(chan_name, sizeof(chan_name), "dma%i", i);
++ irq[i] = platform_get_irq_byname(pdev, chan_name);
++ if (irq[i] >= 0)
++ continue;
++
++ /* legacy device tree case handling */
++ dev_warn_once(&pdev->dev,
++ "missing interrupts-names property in device tree - legacy interpretation is used");
++ /*
++ * in case of channel >= 11
++ * use the 11th interrupt and that is shared
++ */
++ irq[i] = platform_get_irq(pdev, i < 11 ? i : 11);
++ }
++
++ /* get irqs for each channel */
++ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
++ /* skip channels without irq */
++ if (irq[i] < 0)
++ continue;
++
++ /* check if there are other channels that also use this irq */
++ irq_flags = 0;
++ for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++)
++ if ((i != j) && (irq[j] == irq[i])) {
++ irq_flags = IRQF_SHARED;
++ break;
++ }
++
++ /* initialize the channel */
++ rc = bcm2835_dma_chan_init(od, i, irq[i], irq_flags);
++ if (rc)
++ goto err_no_dma;
+ }
+
+ dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);