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/gfp.h>
19 #include <linux/kernel.h>
20 #include <linux/device.h>
21 #include <linux/dmapool.h>
22 #include <linux/sysdev.h>
23 #include <linux/cpufreq.h>
27 #include <mach/platform.h>
29 #include <mach/regs-apbx.h>
30 #include <mach/regs-apbh.h>
32 static const size_t pool_item_size
= sizeof(struct stmp3xxx_dma_command
);
33 static const size_t pool_alignment
= 8;
34 static struct stmp3xxx_dma_user
{
38 } channels
[MAX_DMA_CHANNELS
];
40 #define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
41 #define IS_USED(ch) (channels[ch].inuse)
43 int stmp3xxx_dma_request(int ch
, struct device
*dev
, const char *name
)
45 struct stmp3xxx_dma_user
*user
;
49 if (!IS_VALID_CHANNEL(ch
)) {
57 /* Create a pool to allocate dma commands from */
58 user
->pool
= dma_pool_create(name
, dev
, pool_item_size
,
59 pool_alignment
, PAGE_SIZE
);
60 if (user
->pool
== NULL
) {
69 EXPORT_SYMBOL(stmp3xxx_dma_request
);
71 int stmp3xxx_dma_release(int ch
)
73 struct stmp3xxx_dma_user
*user
= channels
+ ch
;
76 if (!IS_VALID_CHANNEL(ch
)) {
84 BUG_ON(user
->pool
== NULL
);
85 dma_pool_destroy(user
->pool
);
90 EXPORT_SYMBOL(stmp3xxx_dma_release
);
92 int stmp3xxx_dma_read_semaphore(int channel
)
96 switch (STMP3XXX_DMA_BUS(channel
)) {
97 case STMP3XXX_BUS_APBH
:
98 sem
= __raw_readl(REGS_APBH_BASE
+ HW_APBH_CHn_SEMA
+
99 STMP3XXX_DMA_CHANNEL(channel
) * 0x70);
100 sem
&= BM_APBH_CHn_SEMA_PHORE
;
101 sem
>>= BP_APBH_CHn_SEMA_PHORE
;
104 case STMP3XXX_BUS_APBX
:
105 sem
= __raw_readl(REGS_APBX_BASE
+ HW_APBX_CHn_SEMA
+
106 STMP3XXX_DMA_CHANNEL(channel
) * 0x70);
107 sem
&= BM_APBX_CHn_SEMA_PHORE
;
108 sem
>>= BP_APBX_CHn_SEMA_PHORE
;
115 EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore
);
117 int stmp3xxx_dma_allocate_command(int channel
,
118 struct stmp3xxx_dma_descriptor
*descriptor
)
120 struct stmp3xxx_dma_user
*user
= channels
+ channel
;
123 if (!IS_VALID_CHANNEL(channel
)) {
127 if (!IS_USED(channel
)) {
131 if (descriptor
== NULL
) {
136 /* Allocate memory for a command from the buffer */
137 descriptor
->command
=
138 dma_pool_alloc(user
->pool
, GFP_KERNEL
, &descriptor
->handle
);
140 /* Check it worked */
141 if (!descriptor
->command
) {
146 memset(descriptor
->command
, 0, pool_item_size
);
151 EXPORT_SYMBOL(stmp3xxx_dma_allocate_command
);
153 int stmp3xxx_dma_free_command(int channel
,
154 struct stmp3xxx_dma_descriptor
*descriptor
)
158 if (!IS_VALID_CHANNEL(channel
)) {
162 if (!IS_USED(channel
)) {
167 /* Return the command memory to the pool */
168 dma_pool_free(channels
[channel
].pool
, descriptor
->command
,
171 /* Initialise descriptor so we're not tempted to use it */
172 descriptor
->command
= NULL
;
173 descriptor
->handle
= 0;
174 descriptor
->virtual_buf_ptr
= NULL
;
175 descriptor
->next_descr
= NULL
;
181 EXPORT_SYMBOL(stmp3xxx_dma_free_command
);
183 void stmp3xxx_dma_go(int channel
,
184 struct stmp3xxx_dma_descriptor
*head
, u32 semaphore
)
186 int ch
= STMP3XXX_DMA_CHANNEL(channel
);
189 switch (STMP3XXX_DMA_BUS(channel
)) {
190 case STMP3XXX_BUS_APBH
:
191 c
= REGS_APBH_BASE
+ HW_APBH_CHn_NXTCMDAR
+ 0x70 * ch
;
192 s
= REGS_APBH_BASE
+ HW_APBH_CHn_SEMA
+ 0x70 * ch
;
195 case STMP3XXX_BUS_APBX
:
196 c
= REGS_APBX_BASE
+ HW_APBX_CHn_NXTCMDAR
+ 0x70 * ch
;
197 s
= REGS_APBX_BASE
+ HW_APBX_CHn_SEMA
+ 0x70 * ch
;
204 /* Set next command */
205 __raw_writel(head
->handle
, c
);
206 /* Set counting semaphore (kicks off transfer). Assumes
207 peripheral has been set up correctly */
208 __raw_writel(semaphore
, s
);
210 EXPORT_SYMBOL(stmp3xxx_dma_go
);
212 int stmp3xxx_dma_running(int channel
)
214 switch (STMP3XXX_DMA_BUS(channel
)) {
215 case STMP3XXX_BUS_APBH
:
216 return (__raw_readl(REGS_APBH_BASE
+ HW_APBH_CHn_SEMA
+
217 0x70 * STMP3XXX_DMA_CHANNEL(channel
))) &
218 BM_APBH_CHn_SEMA_PHORE
;
220 case STMP3XXX_BUS_APBX
:
221 return (__raw_readl(REGS_APBX_BASE
+ HW_APBX_CHn_SEMA
+
222 0x70 * STMP3XXX_DMA_CHANNEL(channel
))) &
223 BM_APBX_CHn_SEMA_PHORE
;
229 EXPORT_SYMBOL(stmp3xxx_dma_running
);
232 * Circular dma chain management
234 void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain
*chain
)
238 for (i
= 0; i
< chain
->total_count
; i
++)
239 stmp3xxx_dma_free_command(
240 STMP3XXX_DMA(chain
->channel
, chain
->bus
),
243 EXPORT_SYMBOL(stmp3xxx_dma_free_chain
);
245 int stmp3xxx_dma_make_chain(int ch
, struct stmp37xx_circ_dma_chain
*chain
,
246 struct stmp3xxx_dma_descriptor descriptors
[],
255 for (i
= 0; i
< items
; i
++) {
256 err
= stmp3xxx_dma_allocate_command(ch
, &descriptors
[i
]);
260 * Couldn't allocate the whole chain.
261 * deallocate what has been allocated
265 stmp3xxx_dma_free_command(ch
,
275 descriptors
[i
- 1].next_descr
= &descriptors
[i
];
276 descriptors
[i
- 1].command
->next
=
277 descriptors
[i
].handle
;
281 /* make list circular */
282 descriptors
[items
- 1].next_descr
= &descriptors
[0];
283 descriptors
[items
- 1].command
->next
= descriptors
[0].handle
;
285 chain
->total_count
= items
;
286 chain
->chain
= descriptors
;
287 chain
->free_index
= 0;
288 chain
->active_index
= 0;
289 chain
->cooked_index
= 0;
290 chain
->free_count
= items
;
291 chain
->active_count
= 0;
292 chain
->cooked_count
= 0;
293 chain
->bus
= STMP3XXX_DMA_BUS(ch
);
294 chain
->channel
= STMP3XXX_DMA_CHANNEL(ch
);
297 EXPORT_SYMBOL(stmp3xxx_dma_make_chain
);
299 void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain
*chain
)
301 BUG_ON(stmp3xxx_dma_running(STMP3XXX_DMA(chain
->channel
, chain
->bus
)));
302 chain
->free_index
= 0;
303 chain
->active_index
= 0;
304 chain
->cooked_index
= 0;
305 chain
->free_count
= chain
->total_count
;
306 chain
->active_count
= 0;
307 chain
->cooked_count
= 0;
309 EXPORT_SYMBOL(stmp37xx_circ_clear_chain
);
311 void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain
*chain
,
314 BUG_ON(chain
->cooked_count
< count
);
316 chain
->cooked_count
-= count
;
317 chain
->cooked_index
+= count
;
318 chain
->cooked_index
%= chain
->total_count
;
319 chain
->free_count
+= count
;
321 EXPORT_SYMBOL(stmp37xx_circ_advance_free
);
323 void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain
*chain
,
328 BUG_ON(chain
->free_count
< count
);
330 chain
->free_count
-= count
;
331 chain
->free_index
+= count
;
332 chain
->free_index
%= chain
->total_count
;
333 chain
->active_count
+= count
;
335 switch (chain
->bus
) {
336 case STMP3XXX_BUS_APBH
:
337 c
= REGS_APBH_BASE
+ HW_APBH_CHn_SEMA
+ 0x70 * chain
->channel
;
338 mask_clr
= BM_APBH_CHn_SEMA_INCREMENT_SEMA
;
339 mask
= BF(count
, APBH_CHn_SEMA_INCREMENT_SEMA
);
341 case STMP3XXX_BUS_APBX
:
342 c
= REGS_APBX_BASE
+ HW_APBX_CHn_SEMA
+ 0x70 * chain
->channel
;
343 mask_clr
= BM_APBX_CHn_SEMA_INCREMENT_SEMA
;
344 mask
= BF(count
, APBX_CHn_SEMA_INCREMENT_SEMA
);
351 /* Set counting semaphore (kicks off transfer). Assumes
352 peripheral has been set up correctly */
353 stmp3xxx_clearl(mask_clr
, c
);
354 stmp3xxx_setl(mask
, c
);
356 EXPORT_SYMBOL(stmp37xx_circ_advance_active
);
358 unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain
*chain
)
362 cooked
= chain
->active_count
-
363 stmp3xxx_dma_read_semaphore(STMP3XXX_DMA(chain
->channel
, chain
->bus
));
365 chain
->active_count
-= cooked
;
366 chain
->active_index
+= cooked
;
367 chain
->active_index
%= chain
->total_count
;
369 chain
->cooked_count
+= cooked
;
373 EXPORT_SYMBOL(stmp37xx_circ_advance_cooked
);
375 void stmp3xxx_dma_set_alt_target(int channel
, int function
)
377 #if defined(CONFIG_ARCH_STMP37XX)
379 #elif defined(CONFIG_ARCH_STMP378X)
384 int shift
= STMP3XXX_DMA_CHANNEL(channel
) * bits
;
385 unsigned mask
= (1<<bits
) - 1;
388 BUG_ON(function
< 0 || function
>= (1<<bits
));
389 pr_debug("%s: channel = %d, using mask %x, "
390 "shift = %d\n", __func__
, channel
, mask
, shift
);
392 switch (STMP3XXX_DMA_BUS(channel
)) {
393 case STMP3XXX_BUS_APBH
:
394 c
= REGS_APBH_BASE
+ HW_APBH_DEVSEL
;
396 case STMP3XXX_BUS_APBX
:
397 c
= REGS_APBX_BASE
+ HW_APBX_DEVSEL
;
402 stmp3xxx_clearl(mask
<< shift
, c
);
403 stmp3xxx_setl(mask
<< shift
, c
);
405 EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target
);
407 void stmp3xxx_dma_suspend(void)
409 stmp3xxx_setl(BM_APBH_CTRL0_CLKGATE
, REGS_APBH_BASE
+ HW_APBH_CTRL0
);
410 stmp3xxx_setl(BM_APBX_CTRL0_CLKGATE
, REGS_APBX_BASE
+ HW_APBX_CTRL0
);
413 void stmp3xxx_dma_resume(void)
415 stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE
| BM_APBH_CTRL0_SFTRST
,
416 REGS_APBH_BASE
+ HW_APBH_CTRL0
);
417 stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE
| BM_APBX_CTRL0_SFTRST
,
418 REGS_APBX_BASE
+ HW_APBX_CTRL0
);
421 #ifdef CONFIG_CPU_FREQ
423 struct dma_notifier_block
{
424 struct notifier_block nb
;
428 static int dma_cpufreq_notifier(struct notifier_block
*self
,
429 unsigned long phase
, void *p
)
432 case CPUFREQ_POSTCHANGE
:
433 stmp3xxx_dma_resume();
436 case CPUFREQ_PRECHANGE
:
437 stmp3xxx_dma_suspend();
447 static struct dma_notifier_block dma_cpufreq_nb
= {
449 .notifier_call
= dma_cpufreq_notifier
,
452 #endif /* CONFIG_CPU_FREQ */
454 void __init
stmp3xxx_dma_init(void)
456 stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE
| BM_APBH_CTRL0_SFTRST
,
457 REGS_APBH_BASE
+ HW_APBH_CTRL0
);
458 stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE
| BM_APBX_CTRL0_SFTRST
,
459 REGS_APBX_BASE
+ HW_APBX_CTRL0
);
460 #ifdef CONFIG_CPU_FREQ
461 cpufreq_register_notifier(&dma_cpufreq_nb
.nb
,
462 CPUFREQ_TRANSITION_NOTIFIER
);
463 #endif /* CONFIG_CPU_FREQ */