2 * DMA helper routines for Freescale STMP37XX/STMP378X
4 * Author: dmitry pervushin <dpervushin@embeddedalley.com>
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
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:
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
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>
26 #include <mach/platform.h>
28 #include <mach/regs-apbx.h>
29 #include <mach/regs-apbh.h>
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
{
37 } channels
[MAX_DMA_CHANNELS
];
39 #define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
40 #define IS_USED(ch) (channels[ch].inuse)
42 int stmp3xxx_dma_request(int ch
, struct device
*dev
, const char *name
)
44 struct stmp3xxx_dma_user
*user
;
48 if (!IS_VALID_CHANNEL(ch
)) {
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
) {
68 EXPORT_SYMBOL(stmp3xxx_dma_request
);
70 int stmp3xxx_dma_release(int ch
)
72 struct stmp3xxx_dma_user
*user
= channels
+ ch
;
75 if (!IS_VALID_CHANNEL(ch
)) {
83 BUG_ON(user
->pool
== NULL
);
84 dma_pool_destroy(user
->pool
);
89 EXPORT_SYMBOL(stmp3xxx_dma_release
);
91 int stmp3xxx_dma_read_semaphore(int channel
)
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
;
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
;
114 EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore
);
116 int stmp3xxx_dma_allocate_command(int channel
,
117 struct stmp3xxx_dma_descriptor
*descriptor
)
119 struct stmp3xxx_dma_user
*user
= channels
+ channel
;
122 if (!IS_VALID_CHANNEL(channel
)) {
126 if (!IS_USED(channel
)) {
130 if (descriptor
== NULL
) {
135 /* Allocate memory for a command from the buffer */
136 descriptor
->command
=
137 dma_pool_alloc(user
->pool
, GFP_KERNEL
, &descriptor
->handle
);
139 /* Check it worked */
140 if (!descriptor
->command
) {
145 memset(descriptor
->command
, 0, pool_item_size
);
150 EXPORT_SYMBOL(stmp3xxx_dma_allocate_command
);
152 int stmp3xxx_dma_free_command(int channel
,
153 struct stmp3xxx_dma_descriptor
*descriptor
)
157 if (!IS_VALID_CHANNEL(channel
)) {
161 if (!IS_USED(channel
)) {
166 /* Return the command memory to the pool */
167 dma_pool_free(channels
[channel
].pool
, descriptor
->command
,
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
;
180 EXPORT_SYMBOL(stmp3xxx_dma_free_command
);
182 void stmp3xxx_dma_go(int channel
,
183 struct stmp3xxx_dma_descriptor
*head
, u32 semaphore
)
185 int ch
= STMP3XXX_DMA_CHANNEL(channel
);
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
;
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
;
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
);
209 EXPORT_SYMBOL(stmp3xxx_dma_go
);
211 int stmp3xxx_dma_running(int channel
)
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
;
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
;
228 EXPORT_SYMBOL(stmp3xxx_dma_running
);
231 * Circular dma chain management
233 void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain
*chain
)
237 for (i
= 0; i
< chain
->total_count
; i
++)
238 stmp3xxx_dma_free_command(
239 STMP3XXX_DMA(chain
->channel
, chain
->bus
),
242 EXPORT_SYMBOL(stmp3xxx_dma_free_chain
);
244 int stmp3xxx_dma_make_chain(int ch
, struct stmp37xx_circ_dma_chain
*chain
,
245 struct stmp3xxx_dma_descriptor descriptors
[],
254 for (i
= 0; i
< items
; i
++) {
255 err
= stmp3xxx_dma_allocate_command(ch
, &descriptors
[i
]);
259 * Couldn't allocate the whole chain.
260 * deallocate what has been allocated
264 stmp3xxx_dma_free_command(ch
,
274 descriptors
[i
- 1].next_descr
= &descriptors
[i
];
275 descriptors
[i
- 1].command
->next
=
276 descriptors
[i
].handle
;
280 /* make list circular */
281 descriptors
[items
- 1].next_descr
= &descriptors
[0];
282 descriptors
[items
- 1].command
->next
= descriptors
[0].handle
;
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
);
296 EXPORT_SYMBOL(stmp3xxx_dma_make_chain
);
298 void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain
*chain
)
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;
308 EXPORT_SYMBOL(stmp37xx_circ_clear_chain
);
310 void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain
*chain
,
313 BUG_ON(chain
->cooked_count
< count
);
315 chain
->cooked_count
-= count
;
316 chain
->cooked_index
+= count
;
317 chain
->cooked_index
%= chain
->total_count
;
318 chain
->free_count
+= count
;
320 EXPORT_SYMBOL(stmp37xx_circ_advance_free
);
322 void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain
*chain
,
327 BUG_ON(chain
->free_count
< count
);
329 chain
->free_count
-= count
;
330 chain
->free_index
+= count
;
331 chain
->free_index
%= chain
->total_count
;
332 chain
->active_count
+= count
;
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
);
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
);
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
);
355 EXPORT_SYMBOL(stmp37xx_circ_advance_active
);
357 unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain
*chain
)
361 cooked
= chain
->active_count
-
362 stmp3xxx_dma_read_semaphore(STMP3XXX_DMA(chain
->channel
, chain
->bus
));
364 chain
->active_count
-= cooked
;
365 chain
->active_index
+= cooked
;
366 chain
->active_index
%= chain
->total_count
;
368 chain
->cooked_count
+= cooked
;
372 EXPORT_SYMBOL(stmp37xx_circ_advance_cooked
);
374 void stmp3xxx_dma_set_alt_target(int channel
, int function
)
376 #if defined(CONFIG_ARCH_STMP37XX)
378 #elif defined(CONFIG_ARCH_STMP378X)
383 int shift
= STMP3XXX_DMA_CHANNEL(channel
) * bits
;
384 unsigned mask
= (1<<bits
) - 1;
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
);
391 switch (STMP3XXX_DMA_BUS(channel
)) {
392 case STMP3XXX_BUS_APBH
:
393 c
= REGS_APBH_BASE
+ HW_APBH_DEVSEL
;
395 case STMP3XXX_BUS_APBX
:
396 c
= REGS_APBX_BASE
+ HW_APBX_DEVSEL
;
401 stmp3xxx_clearl(mask
<< shift
, c
);
402 stmp3xxx_setl(mask
<< shift
, c
);
404 EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target
);
406 void stmp3xxx_dma_suspend(void)
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
);
412 void stmp3xxx_dma_resume(void)
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
);
420 #ifdef CONFIG_CPU_FREQ
422 struct dma_notifier_block
{
423 struct notifier_block nb
;
427 static int dma_cpufreq_notifier(struct notifier_block
*self
,
428 unsigned long phase
, void *p
)
431 case CPUFREQ_POSTCHANGE
:
432 stmp3xxx_dma_resume();
435 case CPUFREQ_PRECHANGE
:
436 stmp3xxx_dma_suspend();
446 static struct dma_notifier_block dma_cpufreq_nb
= {
448 .notifier_call
= dma_cpufreq_notifier
,
451 #endif /* CONFIG_CPU_FREQ */
453 void __init
stmp3xxx_dma_init(void)
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 */