dma: restore instruction wrapper register
authorEunok Jo <eunok25.jo@samsung.com>
Mon, 20 Jul 2015 02:20:19 +0000 (02:20 +0000)
committerTaekki Kim <taekki.kim@samsung.com>
Mon, 14 May 2018 05:42:46 +0000 (14:42 +0900)
Wrapper register for instruction address should be restored after power mode.

Change-Id: Icbaf3fe80be32fc496cfdc22dc7ebc34dd00671a
Signed-off-by: Eunok Jo <eunok25.jo@samsung.com>
Signed-off-by: Seokju Yoon <sukju.yoon@samsung.com>
drivers/dma/pl330.c

index 96fe56eb2c2862e050681578e21e3776e5c3e484..287ee47546e63c79058efe4ef704ffb598b7405e 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/pm_runtime.h>
 
 #include "dmaengine.h"
+#include <soc/samsung/exynos-pm.h>
+
 #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,