summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorRobin Gong <yibin.gong@nxp.com>2020-04-29 18:25:41 +0800
committerJason Liu <jason.hui.liu@nxp.com>2020-05-07 15:19:02 +0800
commit4da4ba1aed135fa1a760497e2be52d077794a463 (patch)
treedd20fbc478238966eb4d50a3db61cab655cdfac8 /drivers/dma
parent52aa8b0564d37d2be66fb44c15ad9dd92f1e3efe (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.c154
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: