summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorNicolin Chen <b42378@freescale.com>2013-11-05 19:19:07 +0800
committerNitin Garg <nitin.garg@freescale.com>2015-01-15 21:18:50 -0600
commit5a51766b4bdc676e69caaed381da54a98bc9e7b9 (patch)
tree04ecae633deb26d6ca3df2360cf1e357237293f3 /drivers/dma
parentf8e3c74b470d47e9e45eb2553f270bf5e9842d62 (diff)
ENGR00286273-1 dma: imx-sdma: allocate memory from iram
We try to allocate memory from SoC internal SRAM so that we can turn off voltage of external DDR to save power. Surely, if we failed to get the iram DT node or allocate memory due to no enough SRAM space, we would allow SDMA driver to allocate memory in a traditional way. Signed-off-by: Nicolin Chen <b42378@freescale.com> Signed-off-by: Robin Gong <b38343@freescale.com> (cherry picked from commit f6924fbdb90d1f01266fc018caff953457e04d34)
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/imx-sdma.c57
1 files changed, 41 insertions, 16 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 36c0b9294a60..3c77922aee81 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -30,6 +30,7 @@
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/device.h>
+#include <linux/genalloc.h>
#include <linux/dma-mapping.h>
#include <linux/firmware.h>
#include <linux/slab.h>
@@ -247,6 +248,7 @@ struct sdma_engine;
* @word_size peripheral access size
* @buf_tail ID of the buffer that was processed
* @num_bd max NUM_BD. number of descriptors currently handling
+ * @bd_iram flag indicating the memory location of buffer descriptor
*/
struct sdma_channel {
struct sdma_engine *sdma;
@@ -261,6 +263,7 @@ struct sdma_channel {
unsigned int period_len;
struct sdma_buffer_descriptor *bd;
dma_addr_t bd_phys;
+ bool bd_iram;
unsigned int pc_from_device, pc_to_device;
unsigned int device_to_device;
unsigned long flags;
@@ -332,6 +335,7 @@ struct sdma_engine {
u32 script_number;
struct sdma_script_start_addrs *script_addrs;
const struct sdma_driver_data *drvdata;
+ struct gen_pool *iram_pool;
};
static struct sdma_driver_data sdma_imx31 = {
@@ -546,12 +550,14 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
dma_addr_t buf_phys;
int ret;
unsigned long flags;
+ bool use_iram = true;
- buf_virt = dma_alloc_coherent(NULL,
- size,
- &buf_phys, GFP_KERNEL);
+ buf_virt = gen_pool_dma_alloc(sdma->iram_pool, size, &buf_phys);
if (!buf_virt) {
- return -ENOMEM;
+ use_iram = false;
+ buf_virt = dma_alloc_coherent(NULL, size, &buf_phys, GFP_KERNEL);
+ if (!buf_virt)
+ return -ENOMEM;
}
spin_lock_irqsave(&sdma->channel_0_lock, flags);
@@ -568,7 +574,10 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
- dma_free_coherent(NULL, size, buf_virt, buf_phys);
+ if (use_iram)
+ gen_pool_free(sdma->iram_pool, (unsigned long)buf_virt, size);
+ else
+ dma_free_coherent(NULL, size, buf_virt, buf_phys);
return ret;
}
@@ -1012,10 +1021,15 @@ static int sdma_request_channel(struct sdma_channel *sdmac)
int channel = sdmac->channel;
int ret = -EBUSY;
- sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL);
+ sdmac->bd_iram = true;
+ sdmac->bd = gen_pool_dma_alloc(sdma->iram_pool, PAGE_SIZE, &sdmac->bd_phys);
if (!sdmac->bd) {
- ret = -ENOMEM;
- goto out;
+ sdmac->bd_iram = false;
+ sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL);
+ if (!sdmac->bd) {
+ ret = -ENOMEM;
+ goto out;
+ }
}
memset(sdmac->bd, 0, PAGE_SIZE);
@@ -1112,7 +1126,10 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdma_set_channel_priority(sdmac, 0);
- dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
+ if (sdmac->bd_iram)
+ gen_pool_free(sdma->iram_pool, (unsigned long)sdmac->bd, PAGE_SIZE);
+ else
+ dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
clk_disable(sdma->clk_ipg);
clk_disable(sdma->clk_ahb);
@@ -1541,7 +1558,7 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma,
static int __init sdma_init(struct sdma_engine *sdma)
{
- int i, ret;
+ int i, ret, ccbsize;
dma_addr_t ccb_phys;
clk_enable(sdma->clk_ipg);
@@ -1550,14 +1567,17 @@ static int __init sdma_init(struct sdma_engine *sdma)
/* Be sure SDMA has not started yet */
writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
- sdma->channel_control = dma_alloc_coherent(NULL,
- MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
- sizeof(struct sdma_context_data),
- &ccb_phys, GFP_KERNEL);
+ ccbsize = MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control)
+ + sizeof(struct sdma_context_data);
+ sdma->channel_control = gen_pool_dma_alloc(sdma->iram_pool, ccbsize, &ccb_phys);
if (!sdma->channel_control) {
- ret = -ENOMEM;
- goto err_dma_alloc;
+ sdma->channel_control = dma_alloc_coherent(NULL, ccbsize,
+ &ccb_phys, GFP_KERNEL);
+ if (!sdma->channel_control) {
+ ret = -ENOMEM;
+ goto err_dma_alloc;
+ }
}
sdma->context = (void *)sdma->channel_control +
@@ -1763,6 +1783,11 @@ static int __init sdma_probe(struct platform_device *pdev)
&sdma->dma_device.channels);
}
+ if (np)
+ sdma->iram_pool = of_get_named_gen_pool(np, "iram", 0);
+ if (!sdma->iram_pool)
+ dev_warn(&pdev->dev, "no iram assigned, using external mem\n");
+
ret = sdma_init(sdma);
if (ret)
goto err_init;