aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm/dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-msm/dma.c')
-rw-r--r--arch/arm/mach-msm/dma.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index f5420f9585c5..d029d1f5f9e2 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -13,6 +13,8 @@
13 * 13 *
14 */ 14 */
15 15
16#include <linux/clk.h>
17#include <linux/err.h>
16#include <linux/io.h> 18#include <linux/io.h>
17#include <linux/interrupt.h> 19#include <linux/interrupt.h>
18#include <mach/dma.h> 20#include <mach/dma.h>
@@ -26,6 +28,7 @@ enum {
26}; 28};
27 29
28static DEFINE_SPINLOCK(msm_dmov_lock); 30static DEFINE_SPINLOCK(msm_dmov_lock);
31static struct clk *msm_dmov_clk;
29static unsigned int channel_active; 32static unsigned int channel_active;
30static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; 33static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
31static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; 34static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
@@ -54,6 +57,9 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
54 unsigned int status; 57 unsigned int status;
55 58
56 spin_lock_irqsave(&msm_dmov_lock, irq_flags); 59 spin_lock_irqsave(&msm_dmov_lock, irq_flags);
60 if (!channel_active)
61 clk_enable(msm_dmov_clk);
62 dsb();
57 status = readl(DMOV_STATUS(id)); 63 status = readl(DMOV_STATUS(id));
58 if (list_empty(&ready_commands[id]) && 64 if (list_empty(&ready_commands[id]) &&
59 (status & DMOV_STATUS_CMD_PTR_RDY)) { 65 (status & DMOV_STATUS_CMD_PTR_RDY)) {
@@ -63,6 +69,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
63 writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id)); 69 writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id));
64 } 70 }
65#endif 71#endif
72 if (cmd->execute_func)
73 cmd->execute_func(cmd);
66 PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); 74 PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status);
67 list_add_tail(&cmd->list, &active_commands[id]); 75 list_add_tail(&cmd->list, &active_commands[id]);
68 if (!channel_active) 76 if (!channel_active)
@@ -70,6 +78,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
70 channel_active |= 1U << id; 78 channel_active |= 1U << id;
71 writel(cmd->cmdptr, DMOV_CMD_PTR(id)); 79 writel(cmd->cmdptr, DMOV_CMD_PTR(id));
72 } else { 80 } else {
81 if (!channel_active)
82 clk_disable(msm_dmov_clk);
73 if (list_empty(&active_commands[id])) 83 if (list_empty(&active_commands[id]))
74 PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); 84 PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status);
75 85
@@ -108,6 +118,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr)
108 118
109 cmd.dmov_cmd.cmdptr = cmdptr; 119 cmd.dmov_cmd.cmdptr = cmdptr;
110 cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func; 120 cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func;
121 cmd.dmov_cmd.execute_func = NULL;
111 cmd.id = id; 122 cmd.id = id;
112 init_completion(&cmd.complete); 123 init_completion(&cmd.complete);
113 124
@@ -165,6 +176,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
165 "for %p, result %x\n", id, cmd, ch_result); 176 "for %p, result %x\n", id, cmd, ch_result);
166 if (cmd) { 177 if (cmd) {
167 list_del(&cmd->list); 178 list_del(&cmd->list);
179 dsb();
168 cmd->complete_func(cmd, ch_result, NULL); 180 cmd->complete_func(cmd, ch_result, NULL);
169 } 181 }
170 } 182 }
@@ -181,6 +193,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
181 PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); 193 PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]);
182 if (cmd) { 194 if (cmd) {
183 list_del(&cmd->list); 195 list_del(&cmd->list);
196 dsb();
184 cmd->complete_func(cmd, ch_result, &errdata); 197 cmd->complete_func(cmd, ch_result, &errdata);
185 } 198 }
186 } 199 }
@@ -198,6 +211,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
198 PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); 211 PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]);
199 if (cmd) { 212 if (cmd) {
200 list_del(&cmd->list); 213 list_del(&cmd->list);
214 dsb();
201 cmd->complete_func(cmd, ch_result, &errdata); 215 cmd->complete_func(cmd, ch_result, &errdata);
202 } 216 }
203 /* this does not seem to work, once we get an error */ 217 /* this does not seem to work, once we get an error */
@@ -210,6 +224,8 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
210 cmd = list_entry(ready_commands[id].next, typeof(*cmd), list); 224 cmd = list_entry(ready_commands[id].next, typeof(*cmd), list);
211 list_del(&cmd->list); 225 list_del(&cmd->list);
212 list_add_tail(&cmd->list, &active_commands[id]); 226 list_add_tail(&cmd->list, &active_commands[id]);
227 if (cmd->execute_func)
228 cmd->execute_func(cmd);
213 PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id); 229 PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
214 writel(cmd->cmdptr, DMOV_CMD_PTR(id)); 230 writel(cmd->cmdptr, DMOV_CMD_PTR(id));
215 } 231 }
@@ -219,8 +235,10 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
219 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); 235 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
220 } 236 }
221 237
222 if (!channel_active) 238 if (!channel_active) {
223 disable_irq(INT_ADM_AARM); 239 disable_irq_nosync(INT_ADM_AARM);
240 clk_disable(msm_dmov_clk);
241 }
224 242
225 spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); 243 spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
226 return IRQ_HANDLED; 244 return IRQ_HANDLED;
@@ -230,11 +248,17 @@ static int __init msm_init_datamover(void)
230{ 248{
231 int i; 249 int i;
232 int ret; 250 int ret;
251 struct clk *clk;
252
233 for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { 253 for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
234 INIT_LIST_HEAD(&ready_commands[i]); 254 INIT_LIST_HEAD(&ready_commands[i]);
235 INIT_LIST_HEAD(&active_commands[i]); 255 INIT_LIST_HEAD(&active_commands[i]);
236 writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); 256 writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i));
237 } 257 }
258 clk = clk_get(NULL, "adm_clk");
259 if (IS_ERR(clk))
260 return PTR_ERR(clk);
261 msm_dmov_clk = clk;
238 ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); 262 ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL);
239 if (ret) 263 if (ret)
240 return ret; 264 return ret;