summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/Kconfig13
-rw-r--r--drivers/dma/Makefile3
-rw-r--r--drivers/dma/mcf_edma_test.c229
3 files changed, 241 insertions, 4 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 56ca74b7e438..cac205c9fbd9 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -108,13 +108,20 @@ config FSL_DMA
Elo Plus is the DMA controller on 85xx and 86xx parts.
config MCF_EDMA
-tristate "Coldfire eDMA support"
+ tristate "Faraday eDMA support"
default y
depends on ARCH_MVF
select DMA_ENGINE
help
- Enable support for Coldfire eDMA controller. For example
- used by Coldfire SSI Audio device driver.
+ Enable support for Faraday eDMA controller. For example
+ used by Faraday SAI Audio device driver.
+
+config MCF_EDMA_TEST
+ tristate "MCF eDMA simple test module"
+ depends on MCF_EDMA
+ default m
+ help
+ This is simple eDMA test module.
config MPC512X_DMA
tristate "Freescale MPC512x built-in DMA engine support"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index e28412b592ef..6a5eadee7b5e 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -8,7 +8,8 @@ obj-$(CONFIG_DMATEST) += dmatest.o
obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
-obj-y += mcf_edma.o
+obj-$(CONFIG_MCF_EDMA) += mcf_edma.o
+obj-$(CONFIG_MCF_EDMA_TEST) += mcf_edma_test.o
obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
diff --git a/drivers/dma/mcf_edma_test.c b/drivers/dma/mcf_edma_test.c
new file mode 100644
index 000000000000..61bf0c24277c
--- /dev/null
+++ b/drivers/dma/mcf_edma_test.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Andrey Butok
+ *
+ * Simple test/example module for Coldfire eDMA.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ ***************************************************************************
+ * Changes:
+ * v0.001 29 February 2008 Andrey Butok
+ * Initial Release
+ *
+ * NOTE: This module tests eDMA driver performing
+ * a simple memory to memory transfer with a 32 bit
+ * source and destination transfer size that generates
+ * an interrupt when the transfer is complete.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <asm/cacheflush.h>
+#include <mach/mcf_edma.h>
+#include <linux/slab.h>
+
+#define MCF_EDMA_TEST_DRIVER_VERSION "Revision: 0.001"
+#define MCF_EDMA_TEST_DRIVER_AUTHOR \
+ "Freescale Semiconductor Inc, Andrey Butok"
+#define MCF_EDMA_TEST_DRIVER_DESC \
+ "Simple testing module for Coldfire eDMA "
+#define MCF_EDMA_TEST_DRIVER_INFO \
+ MCF_EDMA_TEST_DRIVER_VERSION " " MCF_EDMA_TEST_DRIVER_DESC
+#define MCF_EDMA_TEST_DRIVER_LICENSE "GPL"
+#define MCF_EDMA_TEST_DRIVER_NAME "mcf_edma_test"
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/* Global variable used to signal main process when interrupt is recognized */
+static int mcf_edma_test_interrupt;
+int *mcf_edma_test_interrupt_p = &mcf_edma_test_interrupt;
+
+/********************************************************************/
+static int
+mcf_edma_test_handler(int channel, void *dev_id)
+{
+ /* Clear interrupt flag */
+ mcf_edma_confirm_interrupt_handled(channel);
+
+ /* Set interrupt status flag to TRUE */
+ mcf_edma_test_interrupt = TRUE;
+
+ return IRQ_HANDLED;
+}
+
+/********************************************************************/
+
+int
+mcf_edma_test_block_compare(u8 *block1, u8 *block2, u32 size)
+{
+ u32 i;
+
+ asm("nop;\n");
+ asm("nop;\n");
+ for (i = 0; i < (size); i++) {
+ if ((*(u8 *) (block1 + i)) != (*(u8 *) (block2 + i))) {
+ printk(KERN_INFO "Invalid edma test value: ");
+ printk(KERN_INFO "0x%x != 0x%x\n", *(u8 *)(block1 + i),
+ *(u8 *)(block2 + i));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/********************************************************************/
+
+void
+mcf_edma_test_run(void)
+{
+ u16 byte_count;
+ u32 i, j;
+ u8 *start_address;
+ u8 *dest_address;
+ u32 test_data;
+ int channel;
+ u32 allocated_channels = 0;
+
+ printk(KERN_INFO "\n===============================================\n");
+ printk(KERN_INFO "\nStarting eDMA transfer tests!\n");
+
+ /* Initialize test variables */
+ byte_count = 0x20;
+ test_data = 0xA5A5A5A5;
+
+ /* DMA buffer must be from GFP_DMA zone, so it will not be cached */
+ start_address = kmalloc(byte_count, GFP_DMA);
+ if (start_address == NULL) {
+ printk(KERN_INFO MCF_EDMA_TEST_DRIVER_NAME
+ ": failed to allocate DMA[%d] buffer\n", byte_count);
+ goto err_out;
+ }
+ dest_address = kmalloc(byte_count, GFP_DMA);
+ if (dest_address == NULL) {
+ printk(KERN_INFO MCF_EDMA_TEST_DRIVER_NAME
+ ": failed to allocate DMA[%d] buffer\n", byte_count);
+ goto err_free_mem;
+ }
+
+
+ /* Test all automatically allocated DMA channels. The test data is
+ * complemented at the end of the loop, so that the testData value
+ * isn't the same twice in a row */
+ for (i = 0; i < 16; i++) {
+ /* request eDMA channel */
+ channel = mcf_edma_request_channel(
+ /* MCF_EDMA_CHANNEL_ANY*/i,
+ mcf_edma_test_handler,
+ NULL,
+ 0x6,
+ NULL,
+ NULL,
+ MCF_EDMA_TEST_DRIVER_NAME);
+
+ if (channel < 0)
+ goto test_end;
+
+ allocated_channels |= (1 << channel);
+
+ /* Initialize data for DMA to move */
+ for (j = 0; j < byte_count; j = j + 4)
+ *((u32 *) (start_address + j)) = test_data;
+
+ flush_cache_all();
+ /* Clear interrupt status indicator */
+ mcf_edma_test_interrupt = FALSE;
+
+ /* Configure DMA Channel TCD */
+ mcf_edma_set_tcd_params(channel, (u32) start_address,
+ (u32) dest_address,
+ (0 | MCF_EDMA_TCD_ATTR_SSIZE_32BIT |
+ MCF_EDMA_TCD_ATTR_DSIZE_32BIT), 0x04,
+ byte_count, 0x0, 1, 1, 0x04, 0x0, 0x1,
+ 0x0, 0x0);
+
+ /* Start DMA. */
+ mcf_edma_start_transfer(channel);
+
+ printk(KERN_INFO "DMA channel %d testing started.\n", channel);
+
+ /* Wait for DMA to complete */
+ while (!*mcf_edma_test_interrupt_p)
+ ;
+
+ /* Test data */
+ if (mcf_edma_test_block_compare
+ (start_address, dest_address, byte_count))
+ printk(KERN_INFO "Data transfered correctly.\n");
+ else
+ printk(KERN_INFO "ERROR: Data error!\n");
+
+ printk(KERN_INFO "DMA channel %d testing complete.\n", channel);
+ printk(KERN_INFO "-------------------------------\n");
+
+ /* Complement test data so next channel test does not
+ * use same values */
+ test_data = ~test_data;
+ }
+
+test_end:
+ printk(KERN_INFO "All tests have completed\n\n");
+ printk(KERN_INFO "Automatically allocated %d eDMA channels:\n", i);
+ for (i = 0; i < MCF_EDMA_CHANNELS; i++) {
+ if (allocated_channels & (1 << i)) {
+ printk(KERN_INFO "%d,\n", i);
+ mcf_edma_free_channel(i, NULL);
+ }
+ }
+ printk(KERN_INFO "===============================================\n\n");
+
+ kfree(dest_address);
+err_free_mem:
+ kfree(start_address);
+err_out:
+ return;
+}
+
+/********************************************************************/
+
+static int __init
+mcf_edma_test_init(void)
+{
+ mcf_edma_test_run();
+
+ /* We intentionaly return -EAGAIN to prevent keeping
+ * the module. It does all its work from init()
+ * and doesn't offer any runtime functionality */
+ return -EAGAIN;
+}
+
+static void __exit
+mcf_edma_test_exit(void)
+{
+}
+
+module_init(mcf_edma_test_init);
+module_exit(mcf_edma_test_exit);
+
+MODULE_DESCRIPTION(MCF_EDMA_TEST_DRIVER_INFO);
+MODULE_AUTHOR(MCF_EDMA_TEST_DRIVER_AUTHOR);
+MODULE_LICENSE(MCF_EDMA_TEST_DRIVER_LICENSE);