diff options
Diffstat (limited to 'arch/arm/mach-msm/dma.c')
-rw-r--r-- | arch/arm/mach-msm/dma.c | 28 |
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 | ||
28 | static DEFINE_SPINLOCK(msm_dmov_lock); | 30 | static DEFINE_SPINLOCK(msm_dmov_lock); |
31 | static struct clk *msm_dmov_clk; | ||
29 | static unsigned int channel_active; | 32 | static unsigned int channel_active; |
30 | static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; | 33 | static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; |
31 | static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; | 34 | static 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; |