summaryrefslogtreecommitdiff
path: root/drivers/staging/nmf-cm/cm_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/nmf-cm/cm_dma.c')
-rw-r--r--drivers/staging/nmf-cm/cm_dma.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/drivers/staging/nmf-cm/cm_dma.c b/drivers/staging/nmf-cm/cm_dma.c
new file mode 100644
index 00000000000..652b504324c
--- /dev/null
+++ b/drivers/staging/nmf-cm/cm_dma.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+#include <mach/db8500-regs.h>
+
+#include "cm_dma.h"
+
+#define CMDMA_LIDX (2)
+#define CMDMA_REG_LCLA (0x024)
+
+static void __iomem *virtbase = NULL;
+
+static int cmdma_write_cyclic_list_mem2per(
+ unsigned int from_addr,
+ unsigned int to_addr,
+ unsigned int segments,
+ unsigned int segmentsize,
+ unsigned int LOS);
+
+static int cmdma_write_cyclic_list_per2mem(
+ unsigned int from_addr,
+ unsigned int to_addr,
+ unsigned int segments,
+ unsigned int segmentsize,
+ unsigned int LOS);
+
+static bool cmdma_setup_relink_area_called = false;
+
+int cmdma_setup_relink_area( unsigned int mem_addr,
+ unsigned int per_addr,
+ unsigned int segments,
+ unsigned int segmentsize,
+ unsigned int LOS,
+ enum cmdma_type type)
+{
+ if (!cmdma_setup_relink_area_called)
+ cmdma_setup_relink_area_called = true;
+
+ switch (type) {
+
+ case CMDMA_MEM_2_PER:
+ return cmdma_write_cyclic_list_mem2per(
+ mem_addr,
+ per_addr,
+ segments,
+ segmentsize,
+ LOS);
+
+ case CMDMA_PER_2_MEM:
+ return cmdma_write_cyclic_list_per2mem(
+ per_addr,
+ mem_addr,
+ segments,
+ segmentsize,
+ LOS);
+
+ default :
+ return -EINVAL;
+ }
+ }
+
+ static unsigned int cmdma_getlcla( void) {
+
+ if(!virtbase)
+ virtbase = ioremap(U8500_DMA_BASE, CMDMA_REG_LCLA + sizeof(int) );
+
+ return readl(virtbase + CMDMA_REG_LCLA);
+ }
+
+ static void cmdma_write_relink_params_mem2per (
+ int * relink,
+ unsigned int LOS,
+ unsigned int nb_element,
+ unsigned int src_addr,
+ unsigned int dst_addr,
+ unsigned int burst_size) {
+
+ relink[0] = (((long)(nb_element & 0xFFFF)) << 16) |
+ (src_addr & 0xFFFF);
+
+ relink[1] = (((src_addr >> 16) & 0xFFFFUL) << 16) |
+ (0x1200UL | (LOS << 1) | (burst_size<<10));
+
+ relink[2] = ((nb_element & 0xFFFF) << 16) |
+ (dst_addr & 0xFFFF);
+
+ relink[3] = (((dst_addr >> 16) & 0xFFFFUL) << 16 ) |
+ 0x8201UL | ((LOS+1) << 1) | (burst_size<<10);
+}
+
+static void cmdma_write_relink_params_per2mem (
+ int * relink,
+ unsigned int LOS,
+ unsigned int nb_element,
+ unsigned int src_addr,
+ unsigned int dst_addr,
+ unsigned int burst_size) {
+
+ relink[0] = (((long)(nb_element & 0xFFFF)) << 16) |
+ (src_addr & 0xFFFF);
+
+ relink[1] = (((src_addr >> 16) & 0xFFFFUL) << 16) |
+ (0x8201UL | (LOS << 1) | (burst_size<<10));
+
+ relink[2] = ((nb_element & 0xFFFF) << 16) |
+ (dst_addr & 0xFFFF);
+
+ relink[3] = (((dst_addr >> 16) & 0xFFFFUL) << 16 ) |
+ 0x1200UL | ((LOS+1) << 1) | (burst_size<<10);
+}
+
+static int cmdma_write_cyclic_list_mem2per(
+ unsigned int from_addr,
+ unsigned int to_addr,
+ unsigned int segments,
+ unsigned int segmentsize,
+ unsigned int LOS) {
+
+ unsigned int i,j;
+ int *relink;
+
+ j = LOS;
+
+ for ( i = 0; i < segments; i++) {
+ relink = ioremap_nocache (cmdma_getlcla() + 1024 * CMDMA_LIDX + 8 * j, 4 * sizeof(int));
+
+ if (i == (segments-1))
+ j = LOS;
+ else
+ j += 2;
+
+ cmdma_write_relink_params_mem2per (
+ relink,
+ j,
+ segmentsize / 4,
+ from_addr,
+ to_addr,
+ 0x2);
+
+ iounmap(relink);
+
+ from_addr += segmentsize;
+ }
+
+ return 0;
+}
+
+static int cmdma_write_cyclic_list_per2mem(
+ unsigned int from_addr,
+ unsigned int to_addr,
+ unsigned int segments,
+ unsigned int segmentsize,
+ unsigned int LOS) {
+
+ unsigned int i,j;
+ int *relink;
+ j = LOS;
+
+ for ( i = 0; i < segments; i++) {
+ relink = ioremap_nocache (cmdma_getlcla() + 1024 * CMDMA_LIDX + 8 * j, 4 * sizeof(int));
+
+ if (i == (segments-1))
+ j = LOS;
+ else
+ j += 2;
+
+ cmdma_write_relink_params_per2mem (
+ relink,
+ j,
+ segmentsize / 4,
+ from_addr,
+ to_addr,
+ 0x2);
+
+ iounmap(relink);
+
+ to_addr += segmentsize;
+ }
+
+ return 0;
+}
+
+static void __iomem *dmabase = 0;
+int cmdma_init(void)
+{
+ dmabase = ioremap_nocache(U8500_DMA_BASE, PAGE_SIZE);
+ if (dmabase == NULL)
+ return -ENOMEM;
+ else
+ return 0;
+}
+
+void cmdma_destroy(void)
+{
+ iounmap(dmabase);
+}
+
+#define SSLNK_CHAN_2 (0x40C + 0x20 * 2)
+#define SDLNK_CHAN_2 (0x41C + 0x20 * 2)
+
+void cmdma_stop_dma(void)
+{
+ if(cmdma_setup_relink_area_called) {
+ cmdma_setup_relink_area_called = false;
+ if (readl(dmabase + SSLNK_CHAN_2) & (0x3 << 28)) {
+ printk(KERN_ERR "CM: ERROR - RX DMA was running\n");
+ }
+ if (readl(dmabase + SDLNK_CHAN_2) & (0x3 << 28)) {
+ printk(KERN_ERR "CM: ERROR - TX DMA was running\n");
+ }
+
+ writel(~(1 << 28), dmabase + SSLNK_CHAN_2);
+ while (readl(dmabase + SSLNK_CHAN_2) & (0x3 << 28));
+
+ writel(~(1 << 28), dmabase + SDLNK_CHAN_2);
+ while (readl(dmabase + SDLNK_CHAN_2) & (0x3 << 28));
+ }
+}