summaryrefslogtreecommitdiff
path: root/drivers/dma/imx-sdma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/imx-sdma.c')
-rw-r--r--drivers/dma/imx-sdma.c56
1 files changed, 51 insertions, 5 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index f086d9ca74c7..ec33c53b15a9 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/genalloc.h>
#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
@@ -368,7 +369,8 @@ struct sdma_channel {
unsigned int fifo_num;
bool sw_done;
u32 sw_done_sel;
- struct work_struct terminate_worker;
+ struct work_struct terminate_worker;
+ struct dma_pool *bd_pool;
};
#define IMX_DMA_SG_LOOP BIT(0)
@@ -1259,8 +1261,8 @@ static int sdma_alloc_bd(struct sdma_desc *desc)
&desc->bd_phys);
if (!desc->bd) {
desc->bd_iram = false;
- desc->bd = dma_zalloc_coherent(desc->sdmac->sdma->dev, bd_size,
- &desc->bd_phys, GFP_NOWAIT);
+ desc->bd = dma_pool_alloc(desc->sdmac->bd_pool, GFP_ATOMIC,
+ &desc->bd_phys);
if (!desc->bd)
return ret;
}
@@ -1268,6 +1270,8 @@ static int sdma_alloc_bd(struct sdma_desc *desc)
desc->sdmac->bd_size_sum += bd_size;
spin_unlock_irqrestore(&desc->sdmac->vc.lock, flags);
+ memset(desc->bd, 0, bd_size);
+
return 0;
}
@@ -1281,8 +1285,8 @@ static void sdma_free_bd(struct sdma_desc *desc)
gen_pool_free(desc->sdmac->sdma->iram_pool,
(unsigned long)desc->bd, bd_size);
else
- dma_free_coherent(desc->sdmac->sdma->dev, bd_size,
- desc->bd, desc->bd_phys);
+ dma_pool_free(desc->sdmac->bd_pool, desc->bd,
+ desc->bd_phys);
spin_lock_irqsave(&desc->sdmac->vc.lock, flags);
desc->sdmac->bd_size_sum -= bd_size;
spin_unlock_irqrestore(&desc->sdmac->vc.lock, flags);
@@ -1473,6 +1477,10 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
sdmac->bd_size_sum = 0;
+ sdmac->bd_pool = dma_pool_create("bd_pool", chan->device->dev,
+ sizeof(struct sdma_buffer_descriptor),
+ 32, 0);
+
return 0;
disable_clk_ahb:
@@ -1502,6 +1510,9 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
clk_disable(sdma->clk_ipg);
clk_disable(sdma->clk_ahb);
+
+ dma_pool_destroy(sdmac->bd_pool);
+ sdmac->bd_pool = NULL;
}
static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
@@ -1947,6 +1958,14 @@ static void sdma_add_scripts(struct sdma_engine *sdma,
if (!sdma->script_number)
sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
+ if (sdma->script_number > sizeof(struct sdma_script_start_addrs)
+ / sizeof(s32)) {
+ dev_err(sdma->dev,
+ "SDMA script number %d not match with firmware.\n",
+ sdma->script_number);
+ return;
+ }
+
for (i = 0; i < sdma->script_number; i++)
if (addr_arr[i] > 0)
saddr_arr[i] = addr_arr[i];
@@ -2414,6 +2433,33 @@ static int sdma_probe(struct platform_device *pdev)
/* There maybe multi sdma devices such as i.mx8mscale */
sdma->idx = sdma_dev_idx++;
+ /*
+ * Kick off firmware loading as the very last step:
+ * attempt to load firmware only if we're not on the error path, because
+ * the firmware callback requires a fully functional and allocated sdma
+ * instance.
+ */
+ if (pdata) {
+ ret = sdma_get_firmware(sdma, pdata->fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
+ } else {
+ /*
+ * Because that device tree does not encode ROM script address,
+ * the RAM script in firmware is mandatory for device tree
+ * probe, otherwise it fails.
+ */
+ ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
+ &fw_name);
+ if (ret) {
+ dev_warn(&pdev->dev, "failed to get firmware name\n");
+ } else {
+ ret = sdma_get_firmware(sdma, fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
+ }
+ }
+
return 0;
err_register: