summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-bcm2708/Makefile2
-rw-r--r--arch/arm/mach-bcm2708/include/mach/dma.h96
-rw-r--r--arch/arm/mach-bcm2709/Makefile2
-rw-r--r--arch/arm/mach-bcm2709/include/mach/dma.h96
-rw-r--r--drivers/dma/Kconfig9
-rw-r--r--drivers/dma/bcm2708-dmaengine.c333
-rw-r--r--include/linux/platform_data/dma-bcm2708.h127
7 files changed, 457 insertions, 208 deletions
diff --git a/arch/arm/mach-bcm2708/Makefile b/arch/arm/mach-bcm2708/Makefile
index 21e352166d9e..454408cbeade 100644
--- a/arch/arm/mach-bcm2708/Makefile
+++ b/arch/arm/mach-bcm2708/Makefile
@@ -2,6 +2,6 @@
# Makefile for the linux kernel.
#
-obj-$(CONFIG_MACH_BCM2708) += bcm2708.o armctrl.o vcio.o power.o dma.o
+obj-$(CONFIG_MACH_BCM2708) += bcm2708.o armctrl.o vcio.o power.o
obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h
index d03e7b5a1f6b..d826705e1574 100644
--- a/arch/arm/mach-bcm2708/include/mach/dma.h
+++ b/arch/arm/mach-bcm2708/include/mach/dma.h
@@ -1,94 +1,2 @@
-/*
- * linux/arch/arm/mach-bcm2708/include/mach/dma.h
- *
- * Copyright (C) 2010 Broadcom
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-
-#ifndef _MACH_BCM2708_DMA_H
-#define _MACH_BCM2708_DMA_H
-
-#define BCM_DMAMAN_DRIVER_NAME "bcm2708_dma"
-
-/* DMA CS Control and Status bits */
-#define BCM2708_DMA_ACTIVE (1 << 0)
-#define BCM2708_DMA_INT (1 << 2)
-#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */
-#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */
-#define BCM2708_DMA_ERR (1 << 8)
-#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */
-#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */
-
-/* DMA control block "info" field bits */
-#define BCM2708_DMA_INT_EN (1 << 0)
-#define BCM2708_DMA_TDMODE (1 << 1)
-#define BCM2708_DMA_WAIT_RESP (1 << 3)
-#define BCM2708_DMA_D_INC (1 << 4)
-#define BCM2708_DMA_D_WIDTH (1 << 5)
-#define BCM2708_DMA_D_DREQ (1 << 6)
-#define BCM2708_DMA_S_INC (1 << 8)
-#define BCM2708_DMA_S_WIDTH (1 << 9)
-#define BCM2708_DMA_S_DREQ (1 << 10)
-
-#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12)
-#define BCM2708_DMA_PER_MAP(x) ((x) << 16)
-#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21)
-
-#define BCM2708_DMA_DREQ_EMMC 11
-#define BCM2708_DMA_DREQ_SDHOST 13
-
-#define BCM2708_DMA_CS 0x00 /* Control and Status */
-#define BCM2708_DMA_ADDR 0x04
-/* the current control block appears in the following registers - read only */
-#define BCM2708_DMA_INFO 0x08
-#define BCM2708_DMA_SOURCE_AD 0x0c
-#define BCM2708_DMA_DEST_AD 0x10
-#define BCM2708_DMA_NEXTCB 0x1C
-#define BCM2708_DMA_DEBUG 0x20
-
-#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS)
-#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR)
-
-#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
-
-struct bcm2708_dma_cb {
- unsigned long info;
- unsigned long src;
- unsigned long dst;
- unsigned long length;
- unsigned long stride;
- unsigned long next;
- unsigned long pad[2];
-};
-struct scatterlist;
-
-extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
-extern void bcm_dma_start(void __iomem *dma_chan_base,
- dma_addr_t control_block);
-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base);
-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base);
-extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base);
-
-/* When listing features we can ask for when allocating DMA channels give
- those with higher priority smaller ordinal numbers */
-#define BCM_DMA_FEATURE_FAST_ORD 0
-#define BCM_DMA_FEATURE_BULK_ORD 1
-#define BCM_DMA_FEATURE_NORMAL_ORD 2
-#define BCM_DMA_FEATURE_LITE_ORD 3
-#define BCM_DMA_FEATURE_FAST (1<<BCM_DMA_FEATURE_FAST_ORD)
-#define BCM_DMA_FEATURE_BULK (1<<BCM_DMA_FEATURE_BULK_ORD)
-#define BCM_DMA_FEATURE_NORMAL (1<<BCM_DMA_FEATURE_NORMAL_ORD)
-#define BCM_DMA_FEATURE_LITE (1<<BCM_DMA_FEATURE_LITE_ORD)
-#define BCM_DMA_FEATURE_COUNT 4
-
-/* return channel no or -ve error */
-extern int bcm_dma_chan_alloc(unsigned preferred_feature_set,
- void __iomem **out_dma_base, int *out_dma_irq);
-extern int bcm_dma_chan_free(int channel);
-
-
-#endif /* _MACH_BCM2708_DMA_H */
+/* This file can be removed when all the drivers have been updated */
+#include <linux/platform_data/dma-bcm2708.h>
diff --git a/arch/arm/mach-bcm2709/Makefile b/arch/arm/mach-bcm2709/Makefile
index 2a803bb6bf45..f07c38b77aba 100644
--- a/arch/arm/mach-bcm2709/Makefile
+++ b/arch/arm/mach-bcm2709/Makefile
@@ -2,6 +2,6 @@
# Makefile for the linux kernel.
#
-obj-$(CONFIG_MACH_BCM2709) += bcm2709.o armctrl.o vcio.o power.o dma.o
+obj-$(CONFIG_MACH_BCM2709) += bcm2709.o armctrl.o vcio.o power.o
obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
diff --git a/arch/arm/mach-bcm2709/include/mach/dma.h b/arch/arm/mach-bcm2709/include/mach/dma.h
index d03e7b5a1f6b..d826705e1574 100644
--- a/arch/arm/mach-bcm2709/include/mach/dma.h
+++ b/arch/arm/mach-bcm2709/include/mach/dma.h
@@ -1,94 +1,2 @@
-/*
- * linux/arch/arm/mach-bcm2708/include/mach/dma.h
- *
- * Copyright (C) 2010 Broadcom
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-
-#ifndef _MACH_BCM2708_DMA_H
-#define _MACH_BCM2708_DMA_H
-
-#define BCM_DMAMAN_DRIVER_NAME "bcm2708_dma"
-
-/* DMA CS Control and Status bits */
-#define BCM2708_DMA_ACTIVE (1 << 0)
-#define BCM2708_DMA_INT (1 << 2)
-#define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */
-#define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */
-#define BCM2708_DMA_ERR (1 << 8)
-#define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */
-#define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */
-
-/* DMA control block "info" field bits */
-#define BCM2708_DMA_INT_EN (1 << 0)
-#define BCM2708_DMA_TDMODE (1 << 1)
-#define BCM2708_DMA_WAIT_RESP (1 << 3)
-#define BCM2708_DMA_D_INC (1 << 4)
-#define BCM2708_DMA_D_WIDTH (1 << 5)
-#define BCM2708_DMA_D_DREQ (1 << 6)
-#define BCM2708_DMA_S_INC (1 << 8)
-#define BCM2708_DMA_S_WIDTH (1 << 9)
-#define BCM2708_DMA_S_DREQ (1 << 10)
-
-#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12)
-#define BCM2708_DMA_PER_MAP(x) ((x) << 16)
-#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21)
-
-#define BCM2708_DMA_DREQ_EMMC 11
-#define BCM2708_DMA_DREQ_SDHOST 13
-
-#define BCM2708_DMA_CS 0x00 /* Control and Status */
-#define BCM2708_DMA_ADDR 0x04
-/* the current control block appears in the following registers - read only */
-#define BCM2708_DMA_INFO 0x08
-#define BCM2708_DMA_SOURCE_AD 0x0c
-#define BCM2708_DMA_DEST_AD 0x10
-#define BCM2708_DMA_NEXTCB 0x1C
-#define BCM2708_DMA_DEBUG 0x20
-
-#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS)
-#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR)
-
-#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
-
-struct bcm2708_dma_cb {
- unsigned long info;
- unsigned long src;
- unsigned long dst;
- unsigned long length;
- unsigned long stride;
- unsigned long next;
- unsigned long pad[2];
-};
-struct scatterlist;
-
-extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
-extern void bcm_dma_start(void __iomem *dma_chan_base,
- dma_addr_t control_block);
-extern void bcm_dma_wait_idle(void __iomem *dma_chan_base);
-extern bool bcm_dma_is_busy(void __iomem *dma_chan_base);
-extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base);
-
-/* When listing features we can ask for when allocating DMA channels give
- those with higher priority smaller ordinal numbers */
-#define BCM_DMA_FEATURE_FAST_ORD 0
-#define BCM_DMA_FEATURE_BULK_ORD 1
-#define BCM_DMA_FEATURE_NORMAL_ORD 2
-#define BCM_DMA_FEATURE_LITE_ORD 3
-#define BCM_DMA_FEATURE_FAST (1<<BCM_DMA_FEATURE_FAST_ORD)
-#define BCM_DMA_FEATURE_BULK (1<<BCM_DMA_FEATURE_BULK_ORD)
-#define BCM_DMA_FEATURE_NORMAL (1<<BCM_DMA_FEATURE_NORMAL_ORD)
-#define BCM_DMA_FEATURE_LITE (1<<BCM_DMA_FEATURE_LITE_ORD)
-#define BCM_DMA_FEATURE_COUNT 4
-
-/* return channel no or -ve error */
-extern int bcm_dma_chan_alloc(unsigned preferred_feature_set,
- void __iomem **out_dma_base, int *out_dma_irq);
-extern int bcm_dma_chan_free(int channel);
-
-
-#endif /* _MACH_BCM2708_DMA_H */
+/* This file can be removed when all the drivers have been updated */
+#include <linux/platform_data/dma-bcm2708.h>
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 2395f637f7d4..41097c744a6a 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -339,10 +339,15 @@ config DMA_BCM2835
config DMA_BCM2708
tristate "BCM2708 DMA engine support"
- depends on MACH_BCM2708 || MACH_BCM2709
+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
+config DMA_BCM2708_LEGACY
+ bool "BCM2708 DMA legacy API support"
+ depends on DMA_BCM2708
+ default y
+
config TI_CPPI41
tristate "AM33xx CPPI41 DMA support"
depends on ARCH_OMAP
@@ -381,7 +386,7 @@ config MOXART_DMA
select DMA_VIRTUAL_CHANNELS
help
Enable support for the MOXA ART SoC DMA controller.
-
+
config FSL_EDMA
tristate "Freescale eDMA engine support"
depends on OF
diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c
index 8182b1622cc0..937fd60c5092 100644
--- a/drivers/dma/bcm2708-dmaengine.c
+++ b/drivers/dma/bcm2708-dmaengine.c
@@ -37,26 +37,304 @@
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/platform_data/dma-bcm2708.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
-#ifndef CONFIG_ARCH_BCM2835
+#include "virt-dma.h"
-/* dma manager */
-#include <mach/dma.h>
+static unsigned dma_debug;
-//#define DMA_COMPLETE DMA_SUCCESS
+/*
+ * Legacy DMA API
+ */
-#endif
+#ifdef CONFIG_DMA_BCM2708_LEGACY
-#include <linux/of.h>
-#include <linux/of_dma.h>
+#define CACHE_LINE_MASK 31
+#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */
-#include "virt-dma.h"
+/* valid only for channels 0 - 14, 15 has its own base address */
+#define BCM2708_DMA_CHAN(n) ((n) << 8) /* base address */
+#define BCM2708_DMA_CHANIO(dma_base, n) \
+ ((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n)))
-static unsigned dma_debug;
+struct vc_dmaman {
+ void __iomem *dma_base;
+ u32 chan_available; /* bitmap of available channels */
+ u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */
+ struct mutex lock;
+};
+
+static struct device *dmaman_dev; /* we assume there's only one! */
+static struct vc_dmaman *g_dmaman; /* DMA manager */
+static int dmachans = -1; /* module parameter */
+
+/* DMA Auxiliary Functions */
+
+/* A DMA buffer on an arbitrary boundary may separate a cache line into a
+ section inside the DMA buffer and another section outside it.
+ Even if we flush DMA buffers from the cache there is always the chance that
+ during a DMA someone will access the part of a cache line that is outside
+ the DMA buffer - which will then bring in unwelcome data.
+ Without being able to dictate our own buffer pools we must insist that
+ DMA buffers consist of a whole number of cache lines.
+*/
+extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len)
+{
+ int i;
+
+ for (i = 0; i < sg_len; i++) {
+ if (sg_ptr[i].offset & CACHE_LINE_MASK ||
+ sg_ptr[i].length & CACHE_LINE_MASK)
+ return 0;
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma);
+
+extern void bcm_dma_start(void __iomem *dma_chan_base,
+ dma_addr_t control_block)
+{
+ dsb(); /* ARM data synchronization (push) operation */
+
+ writel(control_block, dma_chan_base + BCM2708_DMA_ADDR);
+ writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS);
+}
+EXPORT_SYMBOL_GPL(bcm_dma_start);
+
+extern void bcm_dma_wait_idle(void __iomem *dma_chan_base)
+{
+ dsb();
+
+ /* ugly busy wait only option for now */
+ while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE)
+ cpu_relax();
+}
+EXPORT_SYMBOL_GPL(bcm_dma_wait_idle);
+
+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base)
+{
+ dsb();
+
+ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_is_busy);
+
+/* Complete an ongoing DMA (assuming its results are to be ignored)
+ Does nothing if there is no DMA in progress.
+ This routine waits for the current AXI transfer to complete before
+ terminating the current DMA. If the current transfer is hung on a DREQ used
+ by an uncooperative peripheral the AXI transfer may never complete. In this
+ case the routine times out and return a non-zero error code.
+ Use of this routine doesn't guarantee that the ongoing or aborted DMA
+ does not produce an interrupt.
+*/
+extern int bcm_dma_abort(void __iomem *dma_chan_base)
+{
+ unsigned long int cs;
+ int rc = 0;
+
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
+
+ if (BCM2708_DMA_ACTIVE & cs) {
+ long int timeout = 10000;
+
+ /* write 0 to the active bit - pause the DMA */
+ writel(0, dma_chan_base + BCM2708_DMA_CS);
+
+ /* wait for any current AXI transfer to complete */
+ while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0)
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
+
+ if (0 != (cs & BCM2708_DMA_ISPAUSED)) {
+ /* we'll un-pause when we set of our next DMA */
+ rc = -ETIMEDOUT;
+
+ } else if (BCM2708_DMA_ACTIVE & cs) {
+ /* terminate the control block chain */
+ writel(0, dma_chan_base + BCM2708_DMA_NEXTCB);
+
+ /* abort the whole DMA */
+ writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE,
+ dma_chan_base + BCM2708_DMA_CS);
+ }
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_abort);
+
+ /* DMA Manager Device Methods */
+
+static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base,
+ u32 chans_available)
+{
+ dmaman->dma_base = dma_base;
+ dmaman->chan_available = chans_available;
+ dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* 2 & 3 */
+ dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* 0 */
+ dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* 1 to 7 */
+ dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* 8 to 14 */
+}
+
+static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman,
+ unsigned preferred_feature_set)
+{
+ u32 chans;
+ int chan = 0;
+ int feature;
+
+ 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]))
+ chans &= dmaman->has_feature[feature];
+
+ if (!chans)
+ return -ENOENT;
+
+ /* return the ordinal of the first channel in the bitmap */
+ while (chans != 0 && (chans & 1) == 0) {
+ chans >>= 1;
+ chan++;
+ }
+ /* claim the channel */
+ dmaman->chan_available &= ~(1 << chan);
+
+ return chan;
+}
+
+static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan)
+{
+ if (chan < 0)
+ return -EINVAL;
+
+ if ((1 << chan) & dmaman->chan_available)
+ return -EIDRM;
+
+ dmaman->chan_available |= (1 << chan);
+
+ return 0;
+}
+
+/* DMA Manager Monitor */
+
+extern int bcm_dma_chan_alloc(unsigned preferred_feature_set,
+ void __iomem **out_dma_base, int *out_dma_irq)
+{
+ struct vc_dmaman *dmaman = g_dmaman;
+ struct platform_device *pdev = to_platform_device(dmaman_dev);
+ struct resource *r;
+ int chan;
+
+ if (!dmaman_dev)
+ return -ENODEV;
+
+ mutex_lock(&dmaman->lock);
+ chan = vc_dmaman_chan_alloc(dmaman, preferred_feature_set);
+ if (chan < 0)
+ goto out;
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan);
+ if (!r) {
+ dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n",
+ chan);
+ vc_dmaman_chan_free(dmaman, chan);
+ chan = -ENOENT;
+ goto out;
+ }
+
+ *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan);
+ *out_dma_irq = r->start;
+ dev_dbg(dmaman_dev,
+ "Legacy API allocated channel=%d, base=%p, irq=%i\n",
+ chan, *out_dma_base, *out_dma_irq);
+
+out:
+ mutex_unlock(&dmaman->lock);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc);
+
+extern int bcm_dma_chan_free(int channel)
+{
+ struct vc_dmaman *dmaman = g_dmaman;
+ int rc;
+
+ if (!dmaman_dev)
+ return -ENODEV;
+
+ mutex_lock(&dmaman->lock);
+ rc = vc_dmaman_chan_free(dmaman, channel);
+ mutex_unlock(&dmaman->lock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_dma_chan_free);
+
+static int bcm_dmaman_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct vc_dmaman *dmaman;
+ struct resource *r;
+ void __iomem *dma_base;
+ uint32_t val;
+
+ if (!of_property_read_u32(dev->of_node,
+ "brcm,dma-channel-mask", &val))
+ dmachans = val;
+ else if (dmachans == -1)
+ dmachans = DEFAULT_DMACHAN_BITMAP;
+
+ dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL);
+ if (!dmaman)
+ return -ENOMEM;
+
+ mutex_init(&dmaman->lock);
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dma_base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(dma_base))
+ return PTR_ERR(dma_base);
+
+ vc_dmaman_init(dmaman, dma_base, dmachans);
+ g_dmaman = dmaman;
+ dmaman_dev = dev;
+
+ dev_info(dev, "DMA legacy API manager at %p, dmachans=0x%x\n",
+ dma_base, dmachans);
+
+ return 0;
+}
+
+static int bcm_dmaman_remove(struct platform_device *pdev)
+{
+ dmaman_dev = NULL;
+
+ return 0;
+}
+
+#else /* CONFIG_DMA_BCM2708_LEGACY */
+
+static int bcm_dmaman_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#endif /* CONFIG_DMA_BCM2708_LEGACY */
+
+/*
+ * DMA engine
+ */
struct bcm2835_dmadev {
struct dma_device ddev;
@@ -709,7 +987,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
return 0;
}
-#ifdef CONFIG_ARCH_BCM2835
+#ifndef CONFIG_DMA_BCM2708_LEGACY
static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq)
{
struct bcm2835_chan *c;
@@ -787,7 +1065,7 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec,
static int bcm2835_dma_probe(struct platform_device *pdev)
{
struct bcm2835_dmadev *od;
-#ifdef CONFIG_ARCH_BCM2835
+#ifndef CONFIG_DMA_BCM2708_LEGACY
struct resource *res;
void __iomem *base;
uint32_t chans_available;
@@ -800,10 +1078,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
- /* If CONFIG_ARCH_BCM2835 is selected, device tree is used */
- /* hence the difference between probing */
-
-#ifndef CONFIG_ARCH_BCM2835
+#ifdef CONFIG_DMA_BCM2708_LEGACY
rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (rc)
@@ -815,6 +1090,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
if (!od)
return -ENOMEM;
+ rc = bcm_dmaman_probe(pdev);
+ if (rc)
+ return rc;
+
pdev->dev.dma_parms = &od->dma_parms;
dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
@@ -971,6 +1250,7 @@ static int bcm2835_dma_remove(struct platform_device *pdev)
dma_async_device_unregister(&od->ddev);
bcm2835_dma_free(od);
+ bcm_dmaman_remove(pdev);
return 0;
}
@@ -985,9 +1265,30 @@ static struct platform_driver bcm2835_dma_driver = {
},
};
-module_platform_driver(bcm2835_dma_driver);
+static int bcm2835_init(void)
+{
+ return platform_driver_register(&bcm2835_dma_driver);
+}
+
+static void bcm2835_exit(void)
+{
+ platform_driver_unregister(&bcm2835_dma_driver);
+}
+
+/*
+ * Load after serial driver (arch_initcall) so we see the messages if it fails,
+ * but before drivers (module_init) that need a DMA channel.
+ */
+subsys_initcall(bcm2835_init);
+module_exit(bcm2835_exit);
module_param(dma_debug, uint, 0644);
+#ifdef CONFIG_DMA_BCM2708_LEGACY
+/* Keep backward compatibility: dma.dmachans= */
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "dma."
+module_param(dmachans, int, 0644);
+#endif
MODULE_ALIAS("platform:bcm2835-dma");
MODULE_DESCRIPTION("BCM2835 DMA engine driver");
MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
diff --git a/include/linux/platform_data/dma-bcm2708.h b/include/linux/platform_data/dma-bcm2708.h
new file mode 100644
index 000000000000..2310e347c6a1
--- /dev/null
+++ b/include/linux/platform_data/dma-bcm2708.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PLAT_BCM2708_DMA_H
+#define _PLAT_BCM2708_DMA_H
+
+/* DMA CS Control and Status bits */
+#define BCM2708_DMA_ACTIVE BIT(0)
+#define BCM2708_DMA_INT BIT(2)
+#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */
+#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */
+#define BCM2708_DMA_ERR BIT(8)
+#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */
+#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */
+
+/* DMA control block "info" field bits */
+#define BCM2708_DMA_INT_EN BIT(0)
+#define BCM2708_DMA_TDMODE BIT(1)
+#define BCM2708_DMA_WAIT_RESP BIT(3)
+#define BCM2708_DMA_D_INC BIT(4)
+#define BCM2708_DMA_D_WIDTH BIT(5)
+#define BCM2708_DMA_D_DREQ BIT(6)
+#define BCM2708_DMA_S_INC BIT(8)
+#define BCM2708_DMA_S_WIDTH BIT(9)
+#define BCM2708_DMA_S_DREQ BIT(10)
+
+#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12)
+#define BCM2708_DMA_PER_MAP(x) ((x) << 16)
+#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21)
+
+#define BCM2708_DMA_DREQ_EMMC 11
+#define BCM2708_DMA_DREQ_SDHOST 13
+
+#define BCM2708_DMA_CS 0x00 /* Control and Status */
+#define BCM2708_DMA_ADDR 0x04
+/* the current control block appears in the following registers - read only */
+#define BCM2708_DMA_INFO 0x08
+#define BCM2708_DMA_SOURCE_AD 0x0c
+#define BCM2708_DMA_DEST_AD 0x10
+#define BCM2708_DMA_NEXTCB 0x1C
+#define BCM2708_DMA_DEBUG 0x20
+
+#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS)
+#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR)
+
+#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
+
+/* When listing features we can ask for when allocating DMA channels give
+ those with higher priority smaller ordinal numbers */
+#define BCM_DMA_FEATURE_FAST_ORD 0
+#define BCM_DMA_FEATURE_BULK_ORD 1
+#define BCM_DMA_FEATURE_NORMAL_ORD 2
+#define BCM_DMA_FEATURE_LITE_ORD 3
+#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD)
+#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD)
+#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD)
+#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD)
+#define BCM_DMA_FEATURE_COUNT 4
+
+struct bcm2708_dma_cb {
+ unsigned long info;
+ unsigned long src;
+ unsigned long dst;
+ unsigned long length;
+ unsigned long stride;
+ unsigned long next;
+ unsigned long pad[2];
+};
+
+struct scatterlist;
+
+#ifdef CONFIG_DMA_BCM2708_LEGACY
+
+int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
+void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block);
+void bcm_dma_wait_idle(void __iomem *dma_chan_base);
+bool bcm_dma_is_busy(void __iomem *dma_chan_base);
+int bcm_dma_abort(void __iomem *dma_chan_base);
+
+/* return channel no or -ve error */
+int bcm_dma_chan_alloc(unsigned preferred_feature_set,
+ void __iomem **out_dma_base, int *out_dma_irq);
+int bcm_dma_chan_free(int channel);
+
+#else /* CONFIG_DMA_BCM2708_LEGACY */
+
+static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr,
+ int sg_len)
+{
+ return 0;
+}
+
+static inline void bcm_dma_start(void __iomem *dma_chan_base,
+ dma_addr_t control_block) { }
+
+static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { }
+
+static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base)
+{
+ return false;
+}
+
+static inline int bcm_dma_abort(void __iomem *dma_chan_base)
+{
+ return -EINVAL;
+}
+
+static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set,
+ void __iomem **out_dma_base,
+ int *out_dma_irq)
+{
+ return -EINVAL;
+}
+
+static inline int bcm_dma_chan_free(int channel)
+{
+ return -EINVAL;
+}
+
+#endif /* CONFIG_DMA_BCM2708_LEGACY */
+
+#endif /* _PLAT_BCM2708_DMA_H */