From db803896dbf8cc7037f381d4bd2e369a8cff4009 Mon Sep 17 00:00:00 2001 From: Eunok Jo Date: Mon, 20 Jul 2015 02:20:19 +0000 Subject: [PATCH] dma: restore instruction wrapper register Wrapper register for instruction address should be restored after power mode. Change-Id: Icbaf3fe80be32fc496cfdc22dc7ebc34dd00671a Signed-off-by: Eunok Jo Signed-off-by: Seokju Yoon --- drivers/dma/pl330.c | 64 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 96fe56eb2c28..287ee47546e6 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -29,6 +29,8 @@ #include #include "dmaengine.h" +#include + #define PL330_MAX_CHAN 8 #define PL330_MAX_IRQS 32 #define PL330_MAX_PERI 32 @@ -486,6 +488,8 @@ struct pl330_dmac { void __iomem *base; /* Used the DMA wrapper */ bool wrapper; + /* Notifier block for powermode */ + struct notifier_block lpa_nb; void __iomem *inst_wrapper; int usage_count; /* Populated by the PL330 core driver during pl330_add */ @@ -2981,25 +2985,51 @@ static int __maybe_unused pl330_suspend(struct device *dev) return 0; } -static int __maybe_unused pl330_resume(struct device *dev) +#ifdef CONFIG_CPU_IDLE +static int pl330_notifier(struct notifier_block *nb, + unsigned long event, void *data) { - struct amba_device *pcdev = to_amba_device(dev); - int ret; + struct pl330_dmac *pl330 = + container_of(nb, struct pl330_dmac, lpa_nb); - ret = amba_pclk_prepare(pcdev); - if (ret) - return ret; + switch (event) { + case LPA_EXIT: + if (pl330->inst_wrapper) + __raw_writel((pl330->mcode_bus >> 32) & 0xf, pl330->inst_wrapper); + break; + } - if (!pm_runtime_status_suspended(dev)) - ret = amba_pclk_enable(pcdev); + return NOTIFY_OK; +} +#endif /* CONFIG_CPU_IDLE */ - pm_runtime_enable(dev); +#ifdef CONFIG_PM +static int pl330_resume(struct device *dev) +{ + struct pl330_dmac *pl330; - return ret; + pl330 = (struct pl330_dmac *)dev_get_drvdata(dev); + + if (pl330->inst_wrapper) + __raw_writel((pl330->mcode_bus >> 32) & 0xf, pl330->inst_wrapper); + + return 0; } +static const struct dev_pm_ops pl330_pm_ops = { + .resume = pl330_resume, +}; + static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume); +#define PL330_PM (&pl330_pm_ops) + +#else /* CONFIG_PM */ + +#define PL330_PM NULL + +#endif /* !CONFIG_PM */ + static int pl330_probe(struct amba_device *adev, const struct amba_id *id) { @@ -3165,6 +3195,18 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pm_runtime_mark_last_busy(&adev->dev); pm_runtime_put_autosuspend(&adev->dev); +#ifdef CONFIG_CPU_IDLE + pl330->lpa_nb.notifier_call = pl330_notifier; + pl330->lpa_nb.next = NULL; + pl330->lpa_nb.priority = 0; + + ret = exynos_pm_register_notifier(&pl330->lpa_nb); + if (ret) { + dev_err(&adev->dev, "failed to register pm notifier\n"); + goto probe_err3; + } +#endif + return 0; probe_err3: /* Idle the DMAC */ @@ -3237,8 +3279,8 @@ MODULE_DEVICE_TABLE(amba, pl330_ids); static struct amba_driver pl330_driver = { .drv = { .owner = THIS_MODULE, + .pm = PL330_PM, .name = "dma-pl330", - .pm = &pl330_pm, }, .id_table = pl330_ids, .probe = pl330_probe, -- 2.20.1