Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[pandora-kernel.git] / arch / arm / plat-stmp3xxx / dma.c
1 /*
2  * DMA helper routines for Freescale STMP37XX/STMP378X
3  *
4  * Author: dmitry pervushin <dpervushin@embeddedalley.com>
5  *
6  * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7  * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8  */
9
10 /*
11  * The code contained herein is licensed under the GNU General Public
12  * License. You may obtain a copy of the GNU General Public License
13  * Version 2 or later at the following locations:
14  *
15  * http://www.opensource.org/licenses/gpl-license.html
16  * http://www.gnu.org/copyleft/gpl.html
17  */
18 #include <linux/kernel.h>
19 #include <linux/device.h>
20 #include <linux/dmapool.h>
21 #include <linux/sysdev.h>
22 #include <linux/cpufreq.h>
23
24 #include <asm/page.h>
25
26 #include <mach/platform.h>
27 #include <mach/dma.h>
28 #include <mach/regs-apbx.h>
29 #include <mach/regs-apbh.h>
30
31 static const size_t pool_item_size = sizeof(struct stmp3xxx_dma_command);
32 static const size_t pool_alignment = 8;
33 static struct stmp3xxx_dma_user {
34         void *pool;
35         int inuse;
36         const char *name;
37 } channels[MAX_DMA_CHANNELS];
38
39 #define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
40 #define IS_USED(ch) (channels[ch].inuse)
41
42 int stmp3xxx_dma_request(int ch, struct device *dev, const char *name)
43 {
44         struct stmp3xxx_dma_user *user;
45         int err = 0;
46
47         user = channels + ch;
48         if (!IS_VALID_CHANNEL(ch)) {
49                 err = -ENODEV;
50                 goto out;
51         }
52         if (IS_USED(ch)) {
53                 err = -EBUSY;
54                 goto out;
55         }
56         /* Create a pool to allocate dma commands from */
57         user->pool = dma_pool_create(name, dev, pool_item_size,
58                                      pool_alignment, PAGE_SIZE);
59         if (user->pool == NULL) {
60                 err = -ENOMEM;
61                 goto out;
62         }
63         user->name = name;
64         user->inuse++;
65 out:
66         return err;
67 }
68 EXPORT_SYMBOL(stmp3xxx_dma_request);
69
70 int stmp3xxx_dma_release(int ch)
71 {
72         struct stmp3xxx_dma_user *user = channels + ch;
73         int err = 0;
74
75         if (!IS_VALID_CHANNEL(ch)) {
76                 err = -ENODEV;
77                 goto out;
78         }
79         if (!IS_USED(ch)) {
80                 err = -EBUSY;
81                 goto out;
82         }
83         BUG_ON(user->pool == NULL);
84         dma_pool_destroy(user->pool);
85         user->inuse--;
86 out:
87         return err;
88 }
89 EXPORT_SYMBOL(stmp3xxx_dma_release);
90
91 int stmp3xxx_dma_read_semaphore(int channel)
92 {
93         int sem = -1;
94
95         switch (STMP3XXX_DMA_BUS(channel)) {
96         case STMP3XXX_BUS_APBH:
97                 sem = __raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
98                                 STMP3XXX_DMA_CHANNEL(channel) * 0x70);
99                 sem &= BM_APBH_CHn_SEMA_PHORE;
100                 sem >>= BP_APBH_CHn_SEMA_PHORE;
101                 break;
102
103         case STMP3XXX_BUS_APBX:
104                 sem = __raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
105                                 STMP3XXX_DMA_CHANNEL(channel) * 0x70);
106                 sem &= BM_APBX_CHn_SEMA_PHORE;
107                 sem >>= BP_APBX_CHn_SEMA_PHORE;
108                 break;
109         default:
110                 BUG();
111         }
112         return sem;
113 }
114 EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore);
115
116 int stmp3xxx_dma_allocate_command(int channel,
117                                   struct stmp3xxx_dma_descriptor *descriptor)
118 {
119         struct stmp3xxx_dma_user *user = channels + channel;
120         int err = 0;
121
122         if (!IS_VALID_CHANNEL(channel)) {
123                 err = -ENODEV;
124                 goto out;
125         }
126         if (!IS_USED(channel)) {
127                 err = -EBUSY;
128                 goto out;
129         }
130         if (descriptor == NULL) {
131                 err = -EINVAL;
132                 goto out;
133         }
134
135         /* Allocate memory for a command from the buffer */
136         descriptor->command =
137             dma_pool_alloc(user->pool, GFP_KERNEL, &descriptor->handle);
138
139         /* Check it worked */
140         if (!descriptor->command) {
141                 err = -ENOMEM;
142                 goto out;
143         }
144
145         memset(descriptor->command, 0, pool_item_size);
146 out:
147         WARN_ON(err);
148         return err;
149 }
150 EXPORT_SYMBOL(stmp3xxx_dma_allocate_command);
151
152 int stmp3xxx_dma_free_command(int channel,
153                               struct stmp3xxx_dma_descriptor *descriptor)
154 {
155         int err = 0;
156
157         if (!IS_VALID_CHANNEL(channel)) {
158                 err = -ENODEV;
159                 goto out;
160         }
161         if (!IS_USED(channel)) {
162                 err = -EBUSY;
163                 goto out;
164         }
165
166         /* Return the command memory to the pool */
167         dma_pool_free(channels[channel].pool, descriptor->command,
168                       descriptor->handle);
169
170         /* Initialise descriptor so we're not tempted to use it */
171         descriptor->command = NULL;
172         descriptor->handle = 0;
173         descriptor->virtual_buf_ptr = NULL;
174         descriptor->next_descr = NULL;
175
176         WARN_ON(err);
177 out:
178         return err;
179 }
180 EXPORT_SYMBOL(stmp3xxx_dma_free_command);
181
182 void stmp3xxx_dma_go(int channel,
183                      struct stmp3xxx_dma_descriptor *head, u32 semaphore)
184 {
185         int ch = STMP3XXX_DMA_CHANNEL(channel);
186         void __iomem *c, *s;
187
188         switch (STMP3XXX_DMA_BUS(channel)) {
189         case STMP3XXX_BUS_APBH:
190                 c = REGS_APBH_BASE + HW_APBH_CHn_NXTCMDAR + 0x70 * ch;
191                 s = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * ch;
192                 break;
193
194         case STMP3XXX_BUS_APBX:
195                 c = REGS_APBX_BASE + HW_APBX_CHn_NXTCMDAR + 0x70 * ch;
196                 s = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * ch;
197                 break;
198
199         default:
200                 return;
201         }
202
203         /* Set next command */
204         __raw_writel(head->handle, c);
205         /* Set counting semaphore (kicks off transfer). Assumes
206            peripheral has been set up correctly */
207         __raw_writel(semaphore, s);
208 }
209 EXPORT_SYMBOL(stmp3xxx_dma_go);
210
211 int stmp3xxx_dma_running(int channel)
212 {
213         switch (STMP3XXX_DMA_BUS(channel)) {
214         case STMP3XXX_BUS_APBH:
215                 return (__raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
216                         0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
217                             BM_APBH_CHn_SEMA_PHORE;
218
219         case STMP3XXX_BUS_APBX:
220                 return (__raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
221                         0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
222                             BM_APBX_CHn_SEMA_PHORE;
223         default:
224                 BUG();
225                 return 0;
226         }
227 }
228 EXPORT_SYMBOL(stmp3xxx_dma_running);
229
230 /*
231  * Circular dma chain management
232  */
233 void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain)
234 {
235         int i;
236
237         for (i = 0; i < chain->total_count; i++)
238                 stmp3xxx_dma_free_command(
239                         STMP3XXX_DMA(chain->channel, chain->bus),
240                         &chain->chain[i]);
241 }
242 EXPORT_SYMBOL(stmp3xxx_dma_free_chain);
243
244 int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
245                             struct stmp3xxx_dma_descriptor descriptors[],
246                             unsigned items)
247 {
248         int i;
249         int err = 0;
250
251         if (items == 0)
252                 return err;
253
254         for (i = 0; i < items; i++) {
255                 err = stmp3xxx_dma_allocate_command(ch, &descriptors[i]);
256                 if (err) {
257                         WARN_ON(err);
258                         /*
259                          * Couldn't allocate the whole chain.
260                          * deallocate what has been allocated
261                          */
262                         if (i) {
263                                 do {
264                                         stmp3xxx_dma_free_command(ch,
265                                                                   &descriptors
266                                                                   [i]);
267                                 } while (i-- >= 0);
268                         }
269                         return err;
270                 }
271
272                 /* link them! */
273                 if (i > 0) {
274                         descriptors[i - 1].next_descr = &descriptors[i];
275                         descriptors[i - 1].command->next =
276                                                 descriptors[i].handle;
277                 }
278         }
279
280         /* make list circular */
281         descriptors[items - 1].next_descr = &descriptors[0];
282         descriptors[items - 1].command->next = descriptors[0].handle;
283
284         chain->total_count = items;
285         chain->chain = descriptors;
286         chain->free_index = 0;
287         chain->active_index = 0;
288         chain->cooked_index = 0;
289         chain->free_count = items;
290         chain->active_count = 0;
291         chain->cooked_count = 0;
292         chain->bus = STMP3XXX_DMA_BUS(ch);
293         chain->channel = STMP3XXX_DMA_CHANNEL(ch);
294         return err;
295 }
296 EXPORT_SYMBOL(stmp3xxx_dma_make_chain);
297
298 void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain)
299 {
300         BUG_ON(stmp3xxx_dma_running(STMP3XXX_DMA(chain->channel, chain->bus)));
301         chain->free_index = 0;
302         chain->active_index = 0;
303         chain->cooked_index = 0;
304         chain->free_count = chain->total_count;
305         chain->active_count = 0;
306         chain->cooked_count = 0;
307 }
308 EXPORT_SYMBOL(stmp37xx_circ_clear_chain);
309
310 void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
311                 unsigned count)
312 {
313         BUG_ON(chain->cooked_count < count);
314
315         chain->cooked_count -= count;
316         chain->cooked_index += count;
317         chain->cooked_index %= chain->total_count;
318         chain->free_count += count;
319 }
320 EXPORT_SYMBOL(stmp37xx_circ_advance_free);
321
322 void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
323                 unsigned count)
324 {
325         void __iomem *c;
326         u32 mask_clr, mask;
327         BUG_ON(chain->free_count < count);
328
329         chain->free_count -= count;
330         chain->free_index += count;
331         chain->free_index %= chain->total_count;
332         chain->active_count += count;
333
334         switch (chain->bus) {
335         case STMP3XXX_BUS_APBH:
336                 c = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * chain->channel;
337                 mask_clr = BM_APBH_CHn_SEMA_INCREMENT_SEMA;
338                 mask = BF(count, APBH_CHn_SEMA_INCREMENT_SEMA);
339                 break;
340         case STMP3XXX_BUS_APBX:
341                 c = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * chain->channel;
342                 mask_clr = BM_APBX_CHn_SEMA_INCREMENT_SEMA;
343                 mask = BF(count, APBX_CHn_SEMA_INCREMENT_SEMA);
344                 break;
345         default:
346                 BUG();
347                 return;
348         }
349
350         /* Set counting semaphore (kicks off transfer). Assumes
351            peripheral has been set up correctly */
352         stmp3xxx_clearl(mask_clr, c);
353         stmp3xxx_setl(mask, c);
354 }
355 EXPORT_SYMBOL(stmp37xx_circ_advance_active);
356
357 unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain)
358 {
359         unsigned cooked;
360
361         cooked = chain->active_count -
362           stmp3xxx_dma_read_semaphore(STMP3XXX_DMA(chain->channel, chain->bus));
363
364         chain->active_count -= cooked;
365         chain->active_index += cooked;
366         chain->active_index %= chain->total_count;
367
368         chain->cooked_count += cooked;
369
370         return cooked;
371 }
372 EXPORT_SYMBOL(stmp37xx_circ_advance_cooked);
373
374 void stmp3xxx_dma_set_alt_target(int channel, int function)
375 {
376 #if defined(CONFIG_ARCH_STMP37XX)
377         unsigned bits = 4;
378 #elif defined(CONFIG_ARCH_STMP378X)
379         unsigned bits = 2;
380 #else
381 #error wrong arch
382 #endif
383         int shift = STMP3XXX_DMA_CHANNEL(channel) * bits;
384         unsigned mask = (1<<bits) - 1;
385         void __iomem *c;
386
387         BUG_ON(function < 0 || function >= (1<<bits));
388         pr_debug("%s: channel = %d, using mask %x, "
389                  "shift = %d\n", __func__, channel, mask, shift);
390
391         switch (STMP3XXX_DMA_BUS(channel)) {
392         case STMP3XXX_BUS_APBH:
393                 c = REGS_APBH_BASE + HW_APBH_DEVSEL;
394                 break;
395         case STMP3XXX_BUS_APBX:
396                 c = REGS_APBX_BASE + HW_APBX_DEVSEL;
397                 break;
398         default:
399                 BUG();
400         }
401         stmp3xxx_clearl(mask << shift, c);
402         stmp3xxx_setl(mask << shift, c);
403 }
404 EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target);
405
406 void stmp3xxx_dma_suspend(void)
407 {
408         stmp3xxx_setl(BM_APBH_CTRL0_CLKGATE, REGS_APBH_BASE + HW_APBH_CTRL0);
409         stmp3xxx_setl(BM_APBX_CTRL0_CLKGATE, REGS_APBX_BASE + HW_APBX_CTRL0);
410 }
411
412 void stmp3xxx_dma_resume(void)
413 {
414         stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
415                         REGS_APBH_BASE + HW_APBH_CTRL0);
416         stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
417                         REGS_APBX_BASE + HW_APBX_CTRL0);
418 }
419
420 #ifdef CONFIG_CPU_FREQ
421
422 struct dma_notifier_block {
423         struct notifier_block nb;
424         void *data;
425 };
426
427 static int dma_cpufreq_notifier(struct notifier_block *self,
428                                 unsigned long phase, void *p)
429 {
430         switch (phase) {
431         case CPUFREQ_POSTCHANGE:
432                 stmp3xxx_dma_resume();
433                 break;
434
435         case CPUFREQ_PRECHANGE:
436                 stmp3xxx_dma_suspend();
437                 break;
438
439         default:
440                 break;
441         }
442
443         return NOTIFY_DONE;
444 }
445
446 static struct dma_notifier_block dma_cpufreq_nb = {
447         .nb = {
448                 .notifier_call = dma_cpufreq_notifier,
449         },
450 };
451 #endif /* CONFIG_CPU_FREQ */
452
453 void __init stmp3xxx_dma_init(void)
454 {
455         stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
456                         REGS_APBH_BASE + HW_APBH_CTRL0);
457         stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
458                         REGS_APBX_BASE + HW_APBX_CTRL0);
459 #ifdef CONFIG_CPU_FREQ
460         cpufreq_register_notifier(&dma_cpufreq_nb.nb,
461                                 CPUFREQ_TRANSITION_NOTIFIER);
462 #endif /* CONFIG_CPU_FREQ */
463 }