MLK-16769-4: dma: mxs-dma: enable runtime PM for mxs-dma
enable runtime pm for mxs-dma BuildInfo: - SCFW 60e110f9, IMX-MKIMAGE e131af10, ATF - U-Boot 2017.03-imx_4.9.51_8qm_beta1_8qxp_alpha+gfcc9bdc Signed-off-by: Han Xu <han.xu@nxp.com>pull/10/head
parent
a5b5c43a8a
commit
89e6459a3e
|
@ -29,6 +29,7 @@
|
|||
#include <linux/of_dma.h>
|
||||
#include <linux/list.h>
|
||||
#include <asm/irq.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "dmaengine.h"
|
||||
|
||||
|
@ -41,6 +42,8 @@
|
|||
#define dma_is_apbh(mxs_dma) ((mxs_dma)->type == MXS_DMA_APBH)
|
||||
#define apbh_is_old(mxs_dma) ((mxs_dma)->dev_id == IMX23_DMA)
|
||||
|
||||
#define MXS_DMA_RPM_TIMEOUT 50 /* ms */
|
||||
|
||||
#define HW_APBHX_CTRL0 0x000
|
||||
#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29)
|
||||
#define BM_APBH_CTRL0_APB_BURST_EN (1 << 28)
|
||||
|
@ -434,6 +437,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
{
|
||||
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
|
||||
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
|
||||
struct device *dev = &mxs_dma->pdev->dev;
|
||||
int ret;
|
||||
|
||||
mxs_chan->ccw = dma_zalloc_coherent(mxs_dma->dma_device.dev,
|
||||
|
@ -449,9 +453,11 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
if (ret)
|
||||
goto err_irq;
|
||||
|
||||
ret = clk_prepare_enable(mxs_dma->clk);
|
||||
if (ret)
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable clock\n");
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
mxs_dma_reset_chan(chan);
|
||||
|
||||
|
@ -463,7 +469,6 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
|
|||
|
||||
return 0;
|
||||
|
||||
clk_disable_unprepare(mxs_dma->clk);
|
||||
err_clk:
|
||||
free_irq(mxs_chan->chan_irq, mxs_dma);
|
||||
err_irq:
|
||||
|
@ -477,6 +482,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
|
|||
{
|
||||
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
|
||||
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
|
||||
struct device *dev = &mxs_dma->pdev->dev;
|
||||
|
||||
mxs_dma_disable_chan(chan);
|
||||
|
||||
|
@ -485,7 +491,9 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
|
|||
dma_free_coherent(mxs_dma->dma_device.dev, CCW_BLOCK_SIZE,
|
||||
mxs_chan->ccw, mxs_chan->ccw_phys);
|
||||
|
||||
clk_disable_unprepare(mxs_dma->clk);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -707,14 +715,32 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
|
|||
return mxs_chan->status;
|
||||
}
|
||||
|
||||
static int mxs_dma_init_rpm(struct mxs_dma_engine *mxs_dma)
|
||||
{
|
||||
struct device *dev = &mxs_dma->pdev->dev;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, MXS_DMA_RPM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxs_dma_init(struct mxs_dma_engine *mxs_dma)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = &mxs_dma->pdev->dev;
|
||||
|
||||
ret = clk_prepare_enable(mxs_dma->clk);
|
||||
ret = mxs_dma_init_rpm(mxs_dma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = stmp_reset_block(mxs_dma->base);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
@ -732,7 +758,8 @@ static int mxs_dma_init(struct mxs_dma_engine *mxs_dma)
|
|||
mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_SET);
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(mxs_dma->clk);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -847,11 +874,13 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
|
|||
&mxs_dma->dma_device.channels);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, mxs_dma);
|
||||
mxs_dma->pdev = pdev;
|
||||
|
||||
ret = mxs_dma_init(mxs_dma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mxs_dma->pdev = pdev;
|
||||
mxs_dma->dma_device.dev = &pdev->dev;
|
||||
dev_set_drvdata(&pdev->dev, mxs_dma);
|
||||
|
||||
|
@ -893,11 +922,11 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
|
|||
|
||||
static int mxs_dma_pm_suspend(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* We do not save any registers here, since the gpmi will release its
|
||||
* DMA channel.
|
||||
*/
|
||||
return 0;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxs_dma_pm_resume(struct device *dev)
|
||||
|
@ -905,13 +934,41 @@ static int mxs_dma_pm_resume(struct device *dev)
|
|||
struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mxs_dma_init(mxs_dma);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mxs_dma_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(mxs_dma->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mxs_dma_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(mxs_dma->clk);
|
||||
if (ret) {
|
||||
dev_err(&mxs_dma->pdev->dev, "failed to enable the clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops mxs_dma_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(mxs_dma_runtime_suspend, mxs_dma_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(mxs_dma_pm_suspend, mxs_dma_pm_resume)
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue