diff options
Diffstat (limited to 'drivers/dma/imx-sdma.c')
-rw-r--r-- | drivers/dma/imx-sdma.c | 56 |
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: |