summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2013-05-15 16:46:18 -0500
committerRanjani Vaidyanathan <ra5478@freescale.com>2013-05-21 11:54:27 -0500
commit57d7bacf4e355ba4de3ff370b885a420598acdce (patch)
treea11c1ad73780c9f74afb3583ef40ae28e17a0536 /drivers/dma
parente35452756af6068a7f5ffe9b5d9c44740f112a12 (diff)
ENGR00262815-2 MX6SL-Add support for SDMA buffers in IRAM
Store SDMA channel and buffer descriptors in IRAM for MX6SL. This will improve the audio playback power when both the SDMA and audio buffers are all in IRAM. The DDR will be self-refresh for longer periods of time. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/imx-sdma.c64
1 files changed, 62 insertions, 2 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 6b7af2cc047e..934307f4d931 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -7,7 +7,7 @@
*
* Based on code from Freescale:
*
- * Copyright 2004-2012 Freescale Semiconductor, Inc.
+ * Copyright 2004-2013 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -33,11 +33,14 @@
#include <linux/platform_device.h>
#include <linux/dmaengine.h>
#include <linux/delay.h>
+#include <linux/genalloc.h>
#include <asm/irq.h>
#include <mach/sdma.h>
#include <mach/dma.h>
#include <mach/hardware.h>
+#include <mach/iram.h>
+
/* SDMA registers */
#define SDMA_H_C0PTR 0x000
@@ -335,6 +338,35 @@ struct sdma_engine {
#define SDMA_H_CONFIG_ACR (1 << 4) /* indicates if AHB freq /core freq = 2 or 1 */
#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/
+#ifdef CONFIG_SDMA_IRAM
+static unsigned long sdma_iram_paddr;
+static void *sdma_iram_vaddr;
+#define sdma_iram_phys_to_virt(p) (sdma_iram_vaddr + ((p) - sdma_iram_paddr))
+#define sdma_iram_virt_to_phys(v) (sdma_iram_paddr + ((v) - sdma_iram_vaddr))
+static struct gen_pool *sdma_iram_pool;
+
+/*!
+ * Allocates uncacheable buffer from IRAM
+ */
+void __iomem *sdma_iram_malloc(size_t size, unsigned long *buf)
+{
+ *buf = gen_pool_alloc(sdma_iram_pool, size);
+ if (!buf)
+ return NULL;
+
+ return sdma_iram_phys_to_virt(*buf);
+}
+
+void sdma_iram_free(unsigned long *buf, u32 size)
+{
+ if (!sdma_iram_pool)
+ return;
+
+ gen_pool_free(sdma_iram_pool, buf, size);
+}
+#endif /*CONFIG_SDMA_IRAM */
+
+
static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
{
u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1);
@@ -405,9 +437,13 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
dma_addr_t buf_phys;
int ret;
+#ifdef CONFIG_SDMA_IRAM
+ buf_virt = sdma_iram_malloc(size, (unsigned long)&buf_phys);
+#else
buf_virt = dma_alloc_coherent(NULL,
size,
&buf_phys, GFP_KERNEL);
+#endif
if (!buf_virt)
return -ENOMEM;
@@ -421,7 +457,11 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
ret = sdma_run_channel(&sdma->channel[0]);
+#ifdef CONFIG_SDMA_IRAM
+ sdma_iram_free(buf_phys, size);
+#else
dma_free_coherent(NULL, size, buf_virt, buf_phys);
+#endif
return ret;
}
@@ -882,7 +922,12 @@ static int sdma_request_channel(struct sdma_channel *sdmac)
int channel = sdmac->channel;
int ret = -EBUSY;
+#ifdef CONFIG_SDMA_IRAM
+ sdmac->bd = sdma_iram_malloc(sizeof(sdmac->bd),
+ (unsigned long)&sdmac->bd_phys);
+#else
sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL);
+#endif
if (!sdmac->bd) {
ret = -ENOMEM;
goto out;
@@ -1045,8 +1090,11 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdma_set_channel_priority(sdmac, 0);
+#ifdef CONFIG_SDMA_IRAM
+ sdma_iram_free(sdmac->bd_phys, sizeof(sdmac->bd));
+#else
dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
-
+#endif
clk_disable(sdma->clk);
}
@@ -1430,10 +1478,22 @@ static int __init sdma_init(struct sdma_engine *sdma)
/* Be sure SDMA has not started yet */
writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
+#ifdef CONFIG_SDMA_IRAM
+ /* Allocate memory for SDMA channel and buffer descriptors */
+ sdma_iram_vaddr = iram_alloc(SZ_4K, &sdma_iram_paddr);
+ sdma_iram_pool = gen_pool_create(PAGE_SHIFT/2, -1);
+ gen_pool_add(sdma_iram_pool, sdma_iram_paddr, SZ_4K, -1);
+
+ sdma->channel_control = sdma_iram_malloc(MAX_DMA_CHANNELS *
+ sizeof(struct sdma_channel_control)
+ + sizeof(struct sdma_context_data),
+ &ccb_phys);
+#else
sdma->channel_control = dma_alloc_coherent(NULL,
MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
sizeof(struct sdma_context_data),
&ccb_phys, GFP_KERNEL);
+#endif
if (!sdma->channel_control) {
ret = -ENOMEM;