summaryrefslogtreecommitdiff
path: root/drivers/dma/mvf_edma_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/mvf_edma_test.c')
-rw-r--r--drivers/dma/mvf_edma_test.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/drivers/dma/mvf_edma_test.c b/drivers/dma/mvf_edma_test.c
new file mode 100644
index 000000000000..cd3065eba950
--- /dev/null
+++ b/drivers/dma/mvf_edma_test.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * Simple test/example module for Faraday 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 Faraday 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
+
+/****************For testing options*************/
+#if 0
+#define ALWAYS_ENABLED_MODE 1 /* test edma always enabled mode */
+#define ROUTETO_DMA1 1 /* test Mux 1,2 sources (64 ~ 117) for dma1 */
+#define ROUTETO_DMA0 1 /* test Mux 0,3 sources (0 ~ 63) for dma0 */
+#endif
+#ifndef ALWAYS_ENABLED_MODE & ROUTETO_DMA1
+#define ROUTETO_DMA0
+#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_dma0 = 0;
+ u32 allocated_channels_dma1 = 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 */
+#ifdef ALWAYS_ENABLED_MODE
+ for (i = 0; i < 20; i++) {
+#elif ROUTETO_DMA1
+ for (i = 64; i < 96; i++) {
+#else
+ for (i = 0; i < 32; i++) {
+#endif
+ /* request eDMA channel */
+ channel = mcf_edma_request_channel(
+#ifdef ALWAYS_ENABLED_MODE
+ MCF_EDMA_CHANNEL_ANY,
+#else
+ i,
+#endif
+ mcf_edma_test_handler,
+ NULL,
+ 0x6,
+ NULL,
+ NULL,
+ MCF_EDMA_TEST_DRIVER_NAME);
+
+ if (channel < 0)
+ goto test_end;
+#ifdef ALWAYS_ENABLED_MODE
+ if (i > 9 && i < 20)
+ printk(KERN_INFO "*****channel: %d ***** routed to : %d\n",
+ i + 118, channel);
+ else
+ printk(KERN_INFO "*****channel: %d ***** routed to : %d\n",
+ i + 54, channel);
+#else
+ printk(KERN_INFO "*****channel: %d ***** routed to : %d\n",
+ i, channel);
+#endif
+ if (channel >= 0 && channel < 16)
+ allocated_channels_dma0 |= (1 << channel);
+ else if (channel >= 48 && channel < 64)
+ allocated_channels_dma0 |= (1 << (channel - 48 + 16));
+ else if (channel >= 16 && channel < 48)
+ allocated_channels_dma1 |= (1 << channel - 16);
+
+ /* 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 */
+#ifdef ALWAYS_ENABLED_MODE
+ 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,
+ 0x1, 0x0);
+#else
+ 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);
+#endif
+ /* 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 "dma0: 0x%08x dma1: 0x%08x\n\n",
+ allocated_channels_dma0, allocated_channels_dma1);
+ printk(KERN_INFO "Automatically allocated eDMA channels:");
+ for (i = 0; i < MCF_EDMA_CHANNELS; i++) {
+ if (i < 16 && allocated_channels_dma0 & (1 << i)) {
+ printk(KERN_INFO "%d,\n", i);
+ mcf_edma_free_channel(i, NULL);
+ }
+
+ if (i >= 48 && allocated_channels_dma0 & (1 << (i - 48 + 16))) {
+ printk(KERN_INFO "%d,\n", i);
+ mcf_edma_free_channel(i, NULL);
+ }
+
+ if (i >= 16 && i <= 47 &&
+ allocated_channels_dma1 & (1 << (i - 16))) {
+ 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);