aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.1/0163-bcm2708-dmaengine-Use-more-DMA-channels-but-not-12.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.1/0163-bcm2708-dmaengine-Use-more-DMA-channels-but-not-12.patch')
-rw-r--r--target/linux/brcm2708/patches-4.1/0163-bcm2708-dmaengine-Use-more-DMA-channels-but-not-12.patch173
1 files changed, 173 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.1/0163-bcm2708-dmaengine-Use-more-DMA-channels-but-not-12.patch b/target/linux/brcm2708/patches-4.1/0163-bcm2708-dmaengine-Use-more-DMA-channels-but-not-12.patch
new file mode 100644
index 0000000..6e5cf52
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.1/0163-bcm2708-dmaengine-Use-more-DMA-channels-but-not-12.patch
@@ -0,0 +1,173 @@
+From a3414b2d51a0fa2b4cea7886168e5e14013904c8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 20 Aug 2015 13:50:18 +0100
+Subject: [PATCH 163/203] bcm2708-dmaengine: Use more DMA channels (but not 12)
+
+1) Only the bcm2708_fb drivers uses the legacy DMA API, and
+it requires a BULK-capable channel, so all other types
+(FAST, NORMAL and LITE) can be made available to the regular
+DMA API.
+
+2) DMA channels 11-14 share an interrupt. The driver can't
+handle this, so don't use channels 12-14 (12 was used, probably
+because it appears to have an interrupt, but in reality that
+interrupt is for activity on ANY channel). This may explain
+a lockup encountered when running out of DMA channels.
+
+The combined effect of this patch is to leave 7 DMA channels
+available + channel 0 for bcm2708_fb via the legacy API.
+
+See: https://github.com/raspberrypi/linux/issues/1110
+ https://github.com/raspberrypi/linux/issues/1108
+---
+ arch/arm/boot/dts/bcm2708_common.dtsi | 5 ++--
+ drivers/dma/bcm2708-dmaengine.c | 43 +++++++++++++++++++++++------------
+ 2 files changed, 31 insertions(+), 17 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2708_common.dtsi
++++ b/arch/arm/boot/dts/bcm2708_common.dtsi
+@@ -59,11 +59,10 @@
+ <1 24>,
+ <1 25>,
+ <1 26>,
+- <1 27>,
+- <1 28>;
++ <1 27>;
+
+ #dma-cells = <1>;
+- brcm,dma-channel-mask = <0x7f35>;
++ brcm,dma-channel-mask = <0x0f35>;
+ };
+
+ intc: interrupt-controller {
+--- a/drivers/dma/bcm2708-dmaengine.c
++++ b/drivers/dma/bcm2708-dmaengine.c
+@@ -184,7 +184,7 @@ static void vc_dmaman_init(struct vc_dma
+ }
+
+ static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman,
+- unsigned preferred_feature_set)
++ unsigned required_feature_set)
+ {
+ u32 chans;
+ int chan = 0;
+@@ -193,10 +193,8 @@ static int vc_dmaman_chan_alloc(struct v
+ chans = dmaman->chan_available;
+ for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++)
+ /* select the subset of available channels with the desired
+- feature so long as some of the candidate channels have that
+- feature */
+- if ((preferred_feature_set & (1 << feature)) &&
+- (chans & dmaman->has_feature[feature]))
++ features */
++ if (required_feature_set & (1 << feature))
+ chans &= dmaman->has_feature[feature];
+
+ if (!chans)
+@@ -228,7 +226,7 @@ static int vc_dmaman_chan_free(struct vc
+
+ /* DMA Manager Monitor */
+
+-extern int bcm_dma_chan_alloc(unsigned preferred_feature_set,
++extern int bcm_dma_chan_alloc(unsigned required_feature_set,
+ void __iomem **out_dma_base, int *out_dma_irq)
+ {
+ struct vc_dmaman *dmaman = g_dmaman;
+@@ -240,7 +238,7 @@ extern int bcm_dma_chan_alloc(unsigned p
+ return -ENODEV;
+
+ mutex_lock(&dmaman->lock);
+- chan = vc_dmaman_chan_alloc(dmaman, preferred_feature_set);
++ chan = vc_dmaman_chan_alloc(dmaman, required_feature_set);
+ if (chan < 0)
+ goto out;
+
+@@ -442,6 +440,7 @@ static inline struct bcm2835_desc *to_bc
+ return container_of(t, struct bcm2835_desc, vd.tx);
+ }
+
++#if 0
+ static void dma_dumpregs(struct bcm2835_chan *c)
+ {
+ pr_debug("-------------DMA DUMPREGS-------------\n");
+@@ -457,6 +456,7 @@ static void dma_dumpregs(struct bcm2835_
+ readl(c->chan_base + BCM2835_DMA_NEXTCB));
+ pr_debug("--------------------------------------\n");
+ }
++#endif
+
+ static void bcm2835_dma_desc_free(struct virt_dma_desc *vd)
+ {
+@@ -862,6 +862,7 @@ static struct dma_async_tx_descriptor *b
+ uint32_t len = sg_dma_len(sgent);
+
+ for (j = 0; j < len; j += max_size) {
++ u32 waits;
+ struct bcm2835_dma_cb *control_block =
+ &d->control_block_base[i+splitct];
+
+@@ -879,7 +880,7 @@ static struct dma_async_tx_descriptor *b
+ }
+
+ /* Common part */
+- u32 waits = SDHCI_BCM_DMA_WAITS;
++ waits = SDHCI_BCM_DMA_WAITS;
+ if ((dma_debug >> 0) & 0x1f)
+ waits = (dma_debug >> 0) & 0x1f;
+ control_block->info |= BCM2835_DMA_WAITS(waits);
+@@ -1074,6 +1075,14 @@ static int bcm2835_dma_probe(struct plat
+ int rc;
+ int i;
+ int irq;
++#ifdef CONFIG_DMA_BCM2708_LEGACY
++ static const u32 wanted_features[] = {
++ BCM_DMA_FEATURE_FAST,
++ BCM_DMA_FEATURE_NORMAL,
++ BCM_DMA_FEATURE_LITE
++ };
++ int j;
++#endif
+
+
+ if (!pdev->dev.dma_mask)
+@@ -1120,20 +1129,24 @@ static int bcm2835_dma_probe(struct plat
+
+ platform_set_drvdata(pdev, od);
+
+- for (i = 0; i < 5; i++) {
++ for (i = 0, j = 0; j < ARRAY_SIZE(wanted_features);) {
++
+ void __iomem *chan_base;
+ int chan_id;
+
+- chan_id = bcm_dma_chan_alloc(BCM_DMA_FEATURE_LITE,
+- &chan_base,
+- &irq);
+-
+- if (chan_id < 0)
+- break;
++ chan_id = bcm_dma_chan_alloc(wanted_features[j],
++ &chan_base,
++ &irq);
++
++ if (chan_id < 0) {
++ j++;
++ continue;
++ }
+
+ rc = bcm2708_dma_chan_init(od, chan_base, chan_id, irq);
+ if (rc)
+ goto err_no_dma;
++ i++;
+ }
+
+ if (pdev->dev.of_node) {
+@@ -1146,6 +1159,8 @@ static int bcm2835_dma_probe(struct plat
+ }
+ }
+
++ dev_info(&pdev->dev, "Initialized %i DMA channels (+ 1 legacy)\n", i);
++
+ #else
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc)