aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>2014-11-14 03:48:57 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-11-17 15:23:36 -0500
commitae43b3289186480f81c78bb63d788a85a3631f47 (patch)
treeacb3bc4f43074d51d0bfbcc91efaf219a62f787f
parent5670c2a52f60418f67dd589e20d30600804fcfde (diff)
ARM: 8202/1: dmaengine: pl330: Add runtime Power Management support v12
This patch adds runtime PM support to pl330 DMA engine driver. The runtime power management for pl330 DMA driver allows gating of AMBA clock (PDMA) in FSYS clock domain, when the device is not processing any requests. This is necessary to enter low power modes on Exynos SoCs (e.g. LPA on Exynos4x12 or W-AFTR on Exynos3250). Runtime PM resuming of the device may happen in atomic context (during call device_issue_pending()) so pm_runtime_irq_safe() is used. This will lead only to disabling/enabling of the clock but this is sufficient for gating the clock and for reducing energy usage. Driver uses runtime PM callbacks from amba/bus.c driver only. Suggested-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/dma/pl330.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 4839bfa74a10..39ea8d436b81 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -27,6 +27,7 @@
27#include <linux/of.h> 27#include <linux/of.h>
28#include <linux/of_dma.h> 28#include <linux/of_dma.h>
29#include <linux/err.h> 29#include <linux/err.h>
30#include <linux/pm_runtime.h>
30 31
31#include "dmaengine.h" 32#include "dmaengine.h"
32#define PL330_MAX_CHAN 8 33#define PL330_MAX_CHAN 8
@@ -265,6 +266,9 @@ static unsigned cmd_line;
265 266
266#define NR_DEFAULT_DESC 16 267#define NR_DEFAULT_DESC 16
267 268
269/* Delay for runtime PM autosuspend, ms */
270#define PL330_AUTOSUSPEND_DELAY 20
271
268/* Populated by the PL330 core driver for DMA API driver's info */ 272/* Populated by the PL330 core driver for DMA API driver's info */
269struct pl330_config { 273struct pl330_config {
270 u32 periph_id; 274 u32 periph_id;
@@ -1958,6 +1962,7 @@ static void pl330_tasklet(unsigned long data)
1958 struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data; 1962 struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
1959 struct dma_pl330_desc *desc, *_dt; 1963 struct dma_pl330_desc *desc, *_dt;
1960 unsigned long flags; 1964 unsigned long flags;
1965 bool power_down = false;
1961 1966
1962 spin_lock_irqsave(&pch->lock, flags); 1967 spin_lock_irqsave(&pch->lock, flags);
1963 1968
@@ -1972,10 +1977,17 @@ static void pl330_tasklet(unsigned long data)
1972 /* Try to submit a req imm. next to the last completed cookie */ 1977 /* Try to submit a req imm. next to the last completed cookie */
1973 fill_queue(pch); 1978 fill_queue(pch);
1974 1979
1975 /* Make sure the PL330 Channel thread is active */ 1980 if (list_empty(&pch->work_list)) {
1976 spin_lock(&pch->thread->dmac->lock); 1981 spin_lock(&pch->thread->dmac->lock);
1977 _start(pch->thread); 1982 _stop(pch->thread);
1978 spin_unlock(&pch->thread->dmac->lock); 1983 spin_unlock(&pch->thread->dmac->lock);
1984 power_down = true;
1985 } else {
1986 /* Make sure the PL330 Channel thread is active */
1987 spin_lock(&pch->thread->dmac->lock);
1988 _start(pch->thread);
1989 spin_unlock(&pch->thread->dmac->lock);
1990 }
1979 1991
1980 while (!list_empty(&pch->completed_list)) { 1992 while (!list_empty(&pch->completed_list)) {
1981 dma_async_tx_callback callback; 1993 dma_async_tx_callback callback;
@@ -1990,6 +2002,12 @@ static void pl330_tasklet(unsigned long data)
1990 if (pch->cyclic) { 2002 if (pch->cyclic) {
1991 desc->status = PREP; 2003 desc->status = PREP;
1992 list_move_tail(&desc->node, &pch->work_list); 2004 list_move_tail(&desc->node, &pch->work_list);
2005 if (power_down) {
2006 spin_lock(&pch->thread->dmac->lock);
2007 _start(pch->thread);
2008 spin_unlock(&pch->thread->dmac->lock);
2009 power_down = false;
2010 }
1993 } else { 2011 } else {
1994 desc->status = FREE; 2012 desc->status = FREE;
1995 list_move_tail(&desc->node, &pch->dmac->desc_pool); 2013 list_move_tail(&desc->node, &pch->dmac->desc_pool);
@@ -2004,6 +2022,12 @@ static void pl330_tasklet(unsigned long data)
2004 } 2022 }
2005 } 2023 }
2006 spin_unlock_irqrestore(&pch->lock, flags); 2024 spin_unlock_irqrestore(&pch->lock, flags);
2025
2026 /* If work list empty, power down */
2027 if (power_down) {
2028 pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
2029 pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
2030 }
2007} 2031}
2008 2032
2009bool pl330_filter(struct dma_chan *chan, void *param) 2033bool pl330_filter(struct dma_chan *chan, void *param)
@@ -2073,6 +2097,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
2073 2097
2074 switch (cmd) { 2098 switch (cmd) {
2075 case DMA_TERMINATE_ALL: 2099 case DMA_TERMINATE_ALL:
2100 pm_runtime_get_sync(pl330->ddma.dev);
2076 spin_lock_irqsave(&pch->lock, flags); 2101 spin_lock_irqsave(&pch->lock, flags);
2077 2102
2078 spin_lock(&pl330->lock); 2103 spin_lock(&pl330->lock);
@@ -2099,10 +2124,15 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
2099 dma_cookie_complete(&desc->txd); 2124 dma_cookie_complete(&desc->txd);
2100 } 2125 }
2101 2126
2127 if (!list_empty(&pch->work_list))
2128 pm_runtime_put(pl330->ddma.dev);
2129
2102 list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool); 2130 list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool);
2103 list_splice_tail_init(&pch->work_list, &pl330->desc_pool); 2131 list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
2104 list_splice_tail_init(&pch->completed_list, &pl330->desc_pool); 2132 list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
2105 spin_unlock_irqrestore(&pch->lock, flags); 2133 spin_unlock_irqrestore(&pch->lock, flags);
2134 pm_runtime_mark_last_busy(pl330->ddma.dev);
2135 pm_runtime_put_autosuspend(pl330->ddma.dev);
2106 break; 2136 break;
2107 case DMA_SLAVE_CONFIG: 2137 case DMA_SLAVE_CONFIG:
2108 slave_config = (struct dma_slave_config *)arg; 2138 slave_config = (struct dma_slave_config *)arg;
@@ -2138,6 +2168,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
2138 2168
2139 tasklet_kill(&pch->task); 2169 tasklet_kill(&pch->task);
2140 2170
2171 pm_runtime_get_sync(pch->dmac->ddma.dev);
2141 spin_lock_irqsave(&pch->lock, flags); 2172 spin_lock_irqsave(&pch->lock, flags);
2142 2173
2143 pl330_release_channel(pch->thread); 2174 pl330_release_channel(pch->thread);
@@ -2147,6 +2178,8 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
2147 list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); 2178 list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
2148 2179
2149 spin_unlock_irqrestore(&pch->lock, flags); 2180 spin_unlock_irqrestore(&pch->lock, flags);
2181 pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
2182 pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
2150} 2183}
2151 2184
2152static enum dma_status 2185static enum dma_status
@@ -2162,6 +2195,15 @@ static void pl330_issue_pending(struct dma_chan *chan)
2162 unsigned long flags; 2195 unsigned long flags;
2163 2196
2164 spin_lock_irqsave(&pch->lock, flags); 2197 spin_lock_irqsave(&pch->lock, flags);
2198 if (list_empty(&pch->work_list)) {
2199 /*
2200 * Warn on nothing pending. Empty submitted_list may
2201 * break our pm_runtime usage counter as it is
2202 * updated on work_list emptiness status.
2203 */
2204 WARN_ON(list_empty(&pch->submitted_list));
2205 pm_runtime_get_sync(pch->dmac->ddma.dev);
2206 }
2165 list_splice_tail_init(&pch->submitted_list, &pch->work_list); 2207 list_splice_tail_init(&pch->submitted_list, &pch->work_list);
2166 spin_unlock_irqrestore(&pch->lock, flags); 2208 spin_unlock_irqrestore(&pch->lock, flags);
2167 2209
@@ -2738,6 +2780,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
2738 pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, 2780 pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
2739 pcfg->num_peri, pcfg->num_events); 2781 pcfg->num_peri, pcfg->num_events);
2740 2782
2783 pm_runtime_irq_safe(&adev->dev);
2784 pm_runtime_use_autosuspend(&adev->dev);
2785 pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY);
2786 pm_runtime_mark_last_busy(&adev->dev);
2787 pm_runtime_put_autosuspend(&adev->dev);
2788
2741 return 0; 2789 return 0;
2742probe_err3: 2790probe_err3:
2743 /* Idle the DMAC */ 2791 /* Idle the DMAC */
@@ -2764,6 +2812,8 @@ static int pl330_remove(struct amba_device *adev)
2764 struct pl330_dmac *pl330 = amba_get_drvdata(adev); 2812 struct pl330_dmac *pl330 = amba_get_drvdata(adev);
2765 struct dma_pl330_chan *pch, *_p; 2813 struct dma_pl330_chan *pch, *_p;
2766 2814
2815 pm_runtime_get_noresume(pl330->ddma.dev);
2816
2767 if (adev->dev.of_node) 2817 if (adev->dev.of_node)
2768 of_dma_controller_free(adev->dev.of_node); 2818 of_dma_controller_free(adev->dev.of_node);
2769 2819