diff options
author | Robin Gong <yibin.gong@nxp.com> | 2020-04-29 18:25:41 +0800 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2020-05-07 15:19:02 +0800 |
commit | 4da4ba1aed135fa1a760497e2be52d077794a463 (patch) | |
tree | dd20fbc478238966eb4d50a3db61cab655cdfac8 /drivers/dma | |
parent | 52aa8b0564d37d2be66fb44c15ad9dd92f1e3efe (diff) |
MLK-23869-1 dmaengine: imx-sdma: split sdma init hw and sw
Split sdma_init_sw and sdma_init_hw from sdma_init, so that sdma_init_hw
could be delayed in channel allocate phase and it's easier for implementing
runtime suspend/resume in the next.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/imx-sdma.c | 154 |
1 files changed, 81 insertions, 73 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index b8ae49ee69b2..da449d031a7d 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -465,6 +465,8 @@ struct sdma_engine { void __iomem *regs; struct sdma_context_data *context; dma_addr_t context_phys; + dma_addr_t ccb_phys; + bool hw_init; struct dma_device dma_device; struct clk *clk_ipg; struct clk *clk_ahb; @@ -489,6 +491,9 @@ static int sdma_config_write(struct dma_chan *chan, struct dma_slave_config *dmaengine_cfg, enum dma_transfer_direction direction); +static int sdma_get_firmware(struct sdma_engine *sdma, + const char *fw_name); + static struct sdma_driver_data sdma_imx31 = { .chnenbl0 = SDMA_CHNENBL0_IMX31, .num_events = 32, @@ -1458,6 +1463,69 @@ static void sdma_desc_free(struct virt_dma_desc *vd) kfree(desc); } +static int sdma_init_hw(struct sdma_engine *sdma) +{ + int i, ret; + /* Check fw_loaded to know ensure sdma_init_hw only called by once */ + if (sdma->hw_init) + return 0; + + ret = clk_enable(sdma->clk_ipg); + if (ret) + return ret; + ret = clk_enable(sdma->clk_ahb); + if (ret) + goto disable_clk_ipg; + + /* Be sure SDMA has not started yet */ + writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); + + /* disable all channels */ + for (i = 0; i < sdma->drvdata->num_events; i++) + writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i)); + + /* All channels have priority 0 */ + for (i = 0; i < MAX_DMA_CHANNELS; i++) + writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4); + + ret = sdma_request_channel0(sdma); + if (ret) + return ret; + + sdma_config_ownership(&sdma->channel[0], false, true, false); + + /* Set Command Channel (Channel Zero) */ + writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR); + + /* Set bits of CONFIG register but with static context switching */ + if (sdma->clk_ratio) + writel_relaxed(SDMA_H_CONFIG_ACR, sdma->regs + SDMA_H_CONFIG); + else + writel_relaxed(0, sdma->regs + SDMA_H_CONFIG); + + writel_relaxed(sdma->ccb_phys, sdma->regs + SDMA_H_C0PTR); + + /* Initializes channel's priorities */ + sdma_set_channel_priority(&sdma->channel[0], 7); + + sdma->hw_init = true; + + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); + + ret = sdma_get_firmware(sdma, sdma->fw_name); + if (ret) + dev_warn(sdma->dev, "failed to get firmware.\n"); + + return 0; + +disable_clk_ipg: + clk_disable(sdma->clk_ipg); + dev_err(sdma->dev, "initialisation failed with %d\n", ret); + + return ret; +} + static int sdma_alloc_chan_resources(struct dma_chan *chan) { struct sdma_channel *sdmac = to_sdma_chan(chan); @@ -1465,6 +1533,8 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan) struct imx_dma_data mem_data; int prio, ret; + sdma_init_hw(sdmac->sdma); + /* * MEMCPY may never setup chan->private by filter function such as * dmatest, thus create 'struct imx_dma_data mem_data' for this case. @@ -2103,83 +2173,34 @@ static int sdma_get_firmware(struct sdma_engine *sdma, return ret; } -static int sdma_init(struct sdma_engine *sdma) +static int sdma_init_sw(struct sdma_engine *sdma) { - int i, ret, ccbsize; - dma_addr_t ccb_phys; - - ret = clk_enable(sdma->clk_ipg); - if (ret) - return ret; - ret = clk_enable(sdma->clk_ahb); - if (ret) - goto disable_clk_ipg; + int ret, ccbsize; if (sdma->drvdata->check_ratio && (clk_get_rate(sdma->clk_ahb) == clk_get_rate(sdma->clk_ipg))) sdma->clk_ratio = 1; - /* Be sure SDMA has not started yet */ - writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); - ccbsize = MAX_DMA_CHANNELS * (sizeof(struct sdma_channel_control) + sizeof(struct sdma_context_data)); if (sdma->iram_pool) sdma->channel_control = gen_pool_dma_alloc(sdma->iram_pool, - ccbsize, &ccb_phys); + ccbsize, &sdma->ccb_phys); else sdma->channel_control = dma_alloc_coherent(sdma->dev, ccbsize, - &ccb_phys, GFP_KERNEL); + &sdma->ccb_phys, GFP_KERNEL); if (!sdma->channel_control) { ret = -ENOMEM; - goto err_dma_alloc; + return ret; } sdma->context = (void *)sdma->channel_control + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); - sdma->context_phys = ccb_phys + + sdma->context_phys = sdma->ccb_phys + MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control); - /* disable all channels */ - for (i = 0; i < sdma->drvdata->num_events; i++) - writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i)); - - /* All channels have priority 0 */ - for (i = 0; i < MAX_DMA_CHANNELS; i++) - writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4); - - ret = sdma_request_channel0(sdma); - if (ret) - goto err_dma_alloc; - - sdma_config_ownership(&sdma->channel[0], false, true, false); - - /* Set Command Channel (Channel Zero) */ - writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR); - - /* Set bits of CONFIG register but with static context switching */ - if (sdma->clk_ratio) - writel_relaxed(SDMA_H_CONFIG_ACR, sdma->regs + SDMA_H_CONFIG); - else - writel_relaxed(0, sdma->regs + SDMA_H_CONFIG); - - writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR); - - /* Initializes channel's priorities */ - sdma_set_channel_priority(&sdma->channel[0], 7); - - clk_disable(sdma->clk_ipg); - clk_disable(sdma->clk_ahb); - return 0; - -err_dma_alloc: - clk_disable(sdma->clk_ahb); -disable_clk_ipg: - clk_disable(sdma->clk_ipg); - dev_err(sdma->dev, "initialisation failed with %d\n", ret); - return ret; } static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param) @@ -2334,7 +2355,7 @@ static int sdma_probe(struct platform_device *pdev) vchan_init(&sdmac->vc, &sdma->dma_device); } - ret = sdma_init(sdma); + ret = sdma_init_sw(sdma); if (ret) goto err_init; @@ -2395,16 +2416,8 @@ static int sdma_probe(struct platform_device *pdev) dev_info(&pdev->dev, "alloc bd from iram. \n"); } - /* - * 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"); + sdma->fw_name = pdata->fw_name; } else { /* * Because that device tree does not encode ROM script address, @@ -2413,17 +2426,12 @@ static int sdma_probe(struct platform_device *pdev) */ ret = of_property_read_string(np, "fsl,sdma-ram-script-name", &fw_name); - if (ret) { + 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"); - } + else + sdma->fw_name = fw_name; } - sdma->fw_name = fw_name; - return 0; err_register: |