2727#include <linux/of.h>
2828#include <linux/of_dma.h>
2929#include <linux/err.h>
30+ #include <linux/pm_runtime.h>
3031
3132#include "dmaengine.h"
3233#define PL330_MAX_CHAN 8
@@ -265,6 +266,9 @@ static unsigned cmd_line;
265266
266267#define NR_DEFAULT_DESC 16
267268
269+ /* Delay for runtime PM autosuspend, ms */
270+ #define PL330_AUTOSUSPEND_DELAY 20
271+
268272/* Populated by the PL330 core driver for DMA API driver's info */
269273struct pl330_config {
270274 u32 periph_id ;
@@ -1958,6 +1962,7 @@ static void pl330_tasklet(unsigned long data)
19581962 struct dma_pl330_chan * pch = (struct dma_pl330_chan * )data ;
19591963 struct dma_pl330_desc * desc , * _dt ;
19601964 unsigned long flags ;
1965+ bool power_down = false;
19611966
19621967 spin_lock_irqsave (& pch -> lock , flags );
19631968
@@ -1972,10 +1977,17 @@ static void pl330_tasklet(unsigned long data)
19721977 /* Try to submit a req imm. next to the last completed cookie */
19731978 fill_queue (pch );
19741979
1975- /* Make sure the PL330 Channel thread is active */
1976- spin_lock (& pch -> thread -> dmac -> lock );
1977- _start (pch -> thread );
1978- spin_unlock (& pch -> thread -> dmac -> lock );
1980+ if (list_empty (& pch -> work_list )) {
1981+ spin_lock (& pch -> thread -> dmac -> lock );
1982+ _stop (pch -> thread );
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+ }
19791991
19801992 while (!list_empty (& pch -> completed_list )) {
19811993 dma_async_tx_callback callback ;
@@ -1990,6 +2002,12 @@ static void pl330_tasklet(unsigned long data)
19902002 if (pch -> cyclic ) {
19912003 desc -> status = PREP ;
19922004 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+ }
19932011 } else {
19942012 desc -> status = FREE ;
19952013 list_move_tail (& desc -> node , & pch -> dmac -> desc_pool );
@@ -2004,6 +2022,12 @@ static void pl330_tasklet(unsigned long data)
20042022 }
20052023 }
20062024 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+ }
20072031}
20082032
20092033bool 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
20732097
20742098 switch (cmd ) {
20752099 case DMA_TERMINATE_ALL :
2100+ pm_runtime_get_sync (pl330 -> ddma .dev );
20762101 spin_lock_irqsave (& pch -> lock , flags );
20772102
20782103 spin_lock (& pl330 -> lock );
@@ -2099,10 +2124,15 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
20992124 dma_cookie_complete (& desc -> txd );
21002125 }
21012126
2127+ if (!list_empty (& pch -> work_list ))
2128+ pm_runtime_put (pl330 -> ddma .dev );
2129+
21022130 list_splice_tail_init (& pch -> submitted_list , & pl330 -> desc_pool );
21032131 list_splice_tail_init (& pch -> work_list , & pl330 -> desc_pool );
21042132 list_splice_tail_init (& pch -> completed_list , & pl330 -> desc_pool );
21052133 spin_unlock_irqrestore (& pch -> lock , flags );
2134+ pm_runtime_mark_last_busy (pl330 -> ddma .dev );
2135+ pm_runtime_put_autosuspend (pl330 -> ddma .dev );
21062136 break ;
21072137 case DMA_SLAVE_CONFIG :
21082138 slave_config = (struct dma_slave_config * )arg ;
@@ -2138,6 +2168,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
21382168
21392169 tasklet_kill (& pch -> task );
21402170
2171+ pm_runtime_get_sync (pch -> dmac -> ddma .dev );
21412172 spin_lock_irqsave (& pch -> lock , flags );
21422173
21432174 pl330_release_channel (pch -> thread );
@@ -2147,6 +2178,8 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
21472178 list_splice_tail_init (& pch -> work_list , & pch -> dmac -> desc_pool );
21482179
21492180 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 );
21502183}
21512184
21522185static enum dma_status
@@ -2162,6 +2195,15 @@ static void pl330_issue_pending(struct dma_chan *chan)
21622195 unsigned long flags ;
21632196
21642197 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+ }
21652207 list_splice_tail_init (& pch -> submitted_list , & pch -> work_list );
21662208 spin_unlock_irqrestore (& pch -> lock , flags );
21672209
@@ -2738,6 +2780,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
27382780 pcfg -> data_buf_dep , pcfg -> data_bus_width / 8 , pcfg -> num_chan ,
27392781 pcfg -> num_peri , pcfg -> num_events );
27402782
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+
27412789 return 0 ;
27422790probe_err3 :
27432791 /* Idle the DMAC */
@@ -2764,6 +2812,8 @@ static int pl330_remove(struct amba_device *adev)
27642812 struct pl330_dmac * pl330 = amba_get_drvdata (adev );
27652813 struct dma_pl330_chan * pch , * _p ;
27662814
2815+ pm_runtime_get_noresume (pl330 -> ddma .dev );
2816+
27672817 if (adev -> dev .of_node )
27682818 of_dma_controller_free (adev -> dev .of_node );
27692819
0 commit comments