summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/sdma-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/sdma-imx31.c')
-rw-r--r--firmware/target/arm/imx31/sdma-imx31.c807
1 files changed, 807 insertions, 0 deletions
diff --git a/firmware/target/arm/imx31/sdma-imx31.c b/firmware/target/arm/imx31/sdma-imx31.c
new file mode 100644
index 0000000000..f845ed18d8
--- /dev/null
+++ b/firmware/target/arm/imx31/sdma-imx31.c
@@ -0,0 +1,807 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include <string.h>
24#include "logf.h"
25#include "panic.h"
26#include "clkctl-imx31.h"
27#include "avic-imx31.h"
28#include "sdma_struct.h"
29#include "sdma-imx31.h"
30#include "sdma_script_code.h"
31#include "mmu-imx31.h"
32
33/* Most of the code in here is based upon the Linux BSP provided by Freescale
34 * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. */
35
36/* Cut down to bare bones essentials */
37
38/* Script information that depends on system revision */
39static struct sdma_script_start_addrs script_info;
40/* Mask of channels with callback enabled */
41static unsigned long sdma_enabled_ints = 0;
42/* One channel control block per channel in physically mapped device RAM */
43static struct channel_control_block ccb_array[CH_NUM] DEVBSS_ATTR;
44/* Channel 0 (command channel) data */
45static struct buffer_descriptor_extd c0_buffer_desc DEVBSS_ATTR;
46
47/* All SDMA channel interrupts are handled here.
48 * Dispatches lower channel numbers first (prioritized by SDMA API callers
49 * who specify the desired channel number).
50 */
51static void __attribute__((interrupt("IRQ"))) SDMA_HANDLER(void)
52{
53 unsigned long pending = SDMA_INTR;
54
55 SDMA_INTR = pending; /* Ack all ints */
56 pending &= sdma_enabled_ints; /* Only dispatch ints with callback */
57
58 while (1)
59 {
60 unsigned int channel;
61
62 if (pending == 0)
63 break; /* No bits set */
64
65 channel = find_first_set_bit(pending);
66
67 pending &= ~(1ul << channel);
68
69 /* Call callback (required if using an interrupt) */
70 ccb_array[channel].channel_desc->callback();
71 }
72}
73
74/* Initialize script information based upon the system revision */
75static void init_script_info(void)
76{
77 if (iim_system_rev() == IIM_SREV_1_0)
78 {
79 /* Channel script info */
80 script_info.app_2_mcu_addr = app_2_mcu_ADDR_1;
81 script_info.ap_2_ap_addr = ap_2_ap_ADDR_1;
82 script_info.ap_2_bp_addr = -1;
83 script_info.bp_2_ap_addr = -1;
84 script_info.loopback_on_dsp_side_addr = -1;
85 script_info.mcu_2_app_addr = mcu_2_app_ADDR_1;
86 script_info.mcu_2_shp_addr = mcu_2_shp_ADDR_1;
87 script_info.mcu_interrupt_only_addr = -1;
88 script_info.shp_2_mcu_addr = shp_2_mcu_ADDR_1;
89 script_info.uartsh_2_mcu_addr = uartsh_2_mcu_ADDR_1;
90 script_info.uart_2_mcu_addr = uart_2_mcu_ADDR_1;
91 script_info.dptc_dvfs_addr = dptc_dvfs_ADDR_1;
92 script_info.firi_2_mcu_addr = firi_2_mcu_ADDR_1;
93 script_info.firi_2_per_addr = -1;
94 script_info.mshc_2_mcu_addr = mshc_2_mcu_ADDR_1;
95 script_info.per_2_app_addr = -1;
96 script_info.per_2_firi_addr = -1;
97 script_info.per_2_shp_addr = -1;
98 script_info.mcu_2_ata_addr = mcu_2_ata_ADDR_1;
99 script_info.mcu_2_firi_addr = mcu_2_firi_ADDR_1;
100 script_info.mcu_2_mshc_addr = mcu_2_mshc_ADDR_1;
101 script_info.ata_2_mcu_addr = ata_2_mcu_ADDR_1;
102 script_info.uartsh_2_per_addr = -1;
103 script_info.shp_2_per_addr = -1;
104 script_info.uart_2_per_addr = -1;
105 script_info.app_2_per_addr = -1;
106 /* Main code block info */
107 script_info.ram_code_size = RAM_CODE_SIZE_1;
108 script_info.ram_code_start_addr = RAM_CODE_START_ADDR_1;
109 script_info.mcu_start_addr = (unsigned long)sdma_code_1;
110 }
111 else
112 {
113 /* Channel script info */
114 script_info.app_2_mcu_addr = app_2_mcu_patched_ADDR_2;
115 script_info.ap_2_ap_addr = ap_2_ap_ADDR_2;
116 script_info.ap_2_bp_addr = ap_2_bp_ADDR_2;
117 script_info.bp_2_ap_addr = bp_2_ap_ADDR_2;
118 script_info.loopback_on_dsp_side_addr = -1;
119 script_info.mcu_2_app_addr = mcu_2_app_ADDR_2;
120 script_info.mcu_2_shp_addr = mcu_2_shp_patched_ADDR_2;
121 script_info.mcu_interrupt_only_addr = -1;
122 script_info.shp_2_mcu_addr = shp_2_mcu_patched_ADDR_2;
123 script_info.uartsh_2_mcu_addr = uartsh_2_mcu_patched_ADDR_2;
124 script_info.uart_2_mcu_addr = uart_2_mcu_patched_ADDR_2;
125 script_info.dptc_dvfs_addr = -1;
126 script_info.firi_2_mcu_addr = firi_2_mcu_ADDR_2;
127 script_info.firi_2_per_addr = -1;
128 script_info.mshc_2_mcu_addr = -1;
129 script_info.per_2_app_addr = -1;
130 script_info.per_2_firi_addr = -1;
131 script_info.per_2_shp_addr = per_2_shp_ADDR_2;
132 script_info.mcu_2_ata_addr = mcu_2_ata_ADDR_2;
133 script_info.mcu_2_firi_addr = mcu_2_firi_ADDR_2;
134 script_info.mcu_2_mshc_addr = -1;
135 script_info.ata_2_mcu_addr = ata_2_mcu_ADDR_2;
136 script_info.uartsh_2_per_addr = -1;
137 script_info.shp_2_per_addr = shp_2_per_ADDR_2;
138 script_info.uart_2_per_addr = -1;
139 script_info.app_2_per_addr = -1;
140 /* Main code block info */
141 script_info.ram_code_size = RAM_CODE_SIZE_2;
142 script_info.ram_code_start_addr = RAM_CODE_START_ADDR_2;
143 script_info.mcu_start_addr = (unsigned long)sdma_code_2;
144 }
145}
146
147/* Return pc of SDMA script in SDMA halfword space according to peripheral
148 * and transfer type */
149static unsigned long get_script_pc(unsigned int peripheral_type,
150 unsigned int transfer_type)
151{
152 unsigned long res = (unsigned short)-1;
153
154 switch (peripheral_type)
155 {
156 case SDMA_PER_MEMORY:
157 switch (transfer_type)
158 {
159 case SDMA_TRAN_EMI_2_INT:
160 case SDMA_TRAN_EMI_2_EMI:
161 case SDMA_TRAN_INT_2_EMI:
162 res = script_info.ap_2_ap_addr;
163 break;
164 default:
165 break;
166 }
167 break;
168
169#if 0 /* Not using this */
170 case SDMA_PER_DSP:
171 switch (transfer_type)
172 {
173 case SDMA_TRAN_EMI_2_DSP:
174 res = script_info.ap_2_bp_addr;
175 break;
176 case SDMA_TRAN_DSP_2_EMI:
177 res = script_info.bp_2_ap_addr;
178 break;
179 case SDMA_TRAN_DSP_2_EMI_LOOP:
180 res = script_info.loopback_on_dsp_side_addr;
181 break;
182 case SDMA_TRAN_EMI_2_DSP_LOOP:
183 res = script_info.mcu_interrupt_only_addr;
184 break;
185 default:
186 break;
187 }
188 break;
189#endif
190
191#if 0 /* Not using this */
192 case SDMA_PER_FIRI:
193 switch (transfer_type)
194 {
195 case SDMA_TRAN_PER_2_INT:
196 res = script_info.firi_2_per_addr;
197 break;
198 case SDMA_TRAN_PER_2_EMI:
199 res = script_info.firi_2_mcu_addr;
200 break;
201 case SDMA_TRAN_INT_2_PER:
202 res = script_info.per_2_firi_addr;
203 break;
204 case SDMA_TRAN_EMI_2_PER:
205 res = script_info.mcu_2_firi_addr;
206 break;
207 default:
208 break;
209 }
210 break;
211#endif
212
213#if 0 /* Not using this */
214 case SDMA_PER_UART:
215 switch (transfer_type)
216 {
217 case SDMA_TRAN_PER_2_INT:
218 res = script_info.uart_2_per_addr;
219 break;
220 case SDMA_TRAN_PER_2_EMI:
221 res = script_info.uart_2_mcu_addr;
222 break;
223 case SDMA_TRAN_INT_2_PER:
224 res = script_info.per_2_app_addr;
225 break;
226 case SDMA_TRAN_EMI_2_PER:
227 res = script_info.mcu_2_app_addr;
228 break;
229 default:
230 break;
231 }
232 break;
233#endif
234
235#if 0 /* Not using this */
236 case SDMA_PER_UART_SP:
237 switch (transfer_type)
238 {
239 case SDMA_TRAN_PER_2_INT:
240 res = script_info.uartsh_2_per_addr;
241 break;
242 case SDMA_TRAN_PER_2_EMI:
243 res = script_info.uartsh_2_mcu_addr;
244 break;
245 case SDMA_TRAN_INT_2_PER:
246 res = script_info.per_2_shp_addr;
247 break;
248 case SDMA_TRAN_EMI_2_PER:
249 res = script_info.mcu_2_shp_addr;
250 break;
251 default:
252 break;
253 }
254 break;
255#endif
256
257 case SDMA_PER_ATA:
258 switch (transfer_type)
259 {
260 case SDMA_TRAN_PER_2_EMI:
261 res = script_info.ata_2_mcu_addr;
262 break;
263 case SDMA_TRAN_EMI_2_PER:
264 res = script_info.mcu_2_ata_addr;
265 break;
266 default:
267 break;
268 }
269 break;
270
271 case SDMA_PER_CSPI:
272 case SDMA_PER_EXT:
273 case SDMA_PER_SSI:
274 switch (transfer_type)
275 {
276 case SDMA_TRAN_PER_2_INT:
277 res = script_info.app_2_per_addr;
278 break;
279 case SDMA_TRAN_PER_2_EMI:
280 res = script_info.app_2_mcu_addr;
281 break;
282 case SDMA_TRAN_INT_2_PER:
283 res = script_info.per_2_app_addr;
284 break;
285 case SDMA_TRAN_EMI_2_PER:
286 res = script_info.mcu_2_app_addr;
287 break;
288 default:
289 break;
290 }
291 break;
292
293#if 0 /* Not using this */
294 case SDMA_PER_MMC:
295 case SDMA_PER_SDHC:
296#endif
297 case SDMA_PER_SSI_SP:
298 case SDMA_PER_CSPI_SP:
299 switch (transfer_type)
300 {
301 case SDMA_TRAN_PER_2_INT:
302 res = script_info.shp_2_per_addr;
303 break;
304 case SDMA_TRAN_PER_2_EMI:
305 res = script_info.shp_2_mcu_addr;
306 break;
307 case SDMA_TRAN_INT_2_PER:
308 res = script_info.per_2_shp_addr;
309 break;
310 case SDMA_TRAN_EMI_2_PER:
311 res = script_info.mcu_2_shp_addr;
312 break;
313 default:
314 break;
315 }
316
317 case SDMA_PER_MSHC:
318 switch (transfer_type)
319 {
320 case SDMA_TRAN_PER_2_EMI:
321 res = script_info.mshc_2_mcu_addr;
322 break;
323 case SDMA_TRAN_EMI_2_PER:
324 res = script_info.mcu_2_mshc_addr;
325 break;
326 default:
327 break;
328 }
329
330 case SDMA_PER_CCM:
331 switch (transfer_type)
332 {
333 case SDMA_TRAN_PER_2_EMI:
334 res = script_info.dptc_dvfs_addr;
335 break;
336 default:
337 break;
338 }
339 }
340
341 if (res == (unsigned short)-1)
342 {
343 logf("SDMA script not found\n");
344 }
345
346 return res;
347}
348
349static unsigned int get_config(unsigned int transfer_type)
350{
351 unsigned int res = -1;
352
353 switch (transfer_type)
354 {
355 case SDMA_TRAN_PER_2_INT:
356 case SDMA_TRAN_PER_2_EMI:
357 case SDMA_TRAN_INT_2_PER:
358 case SDMA_TRAN_EMI_2_PER:
359 /*
360 * Peripheral <------> Memory
361 * evtOvr = 0 mcuOvr = 0 dspOvr = 1
362 */
363 res = CH_OWNSHP_MCU | CH_OWNSHP_EVT;
364 break;
365
366#if 0 /* Not using this */
367 case SDMA_TRAN_DSP_2_PER:
368 res = 0;
369 break;
370 case SDMA_TRAN_EMI_2_DSP:
371 case SDMA_TRAN_INT_2_DSP:
372 case SDMA_TRAN_DSP_2_INT:
373 case SDMA_TRAN_DSP_2_EMI:
374 case SDMA_TRAN_DSP_2_DSP:
375 /*
376 * DSP <-----------> Memory
377 * evtOvr = 1 mcuOvr = 0 dspOvr = 0
378 */
379 res = CH_OWNSHP_MCU | CH_OWNSHP_DSP;
380 break;
381#endif
382
383 case SDMA_TRAN_EMI_2_INT:
384 case SDMA_TRAN_EMI_2_EMI:
385 case SDMA_TRAN_INT_2_INT:
386 case SDMA_TRAN_INT_2_EMI:
387#if 0 /* Not using this */
388 case SDMA_TRAN_DSP_2_EMI_LOOP:
389 case SDMA_TRAN_EMI_2_DSP_LOOP:
390#endif
391 /* evtOvr = 1 mcuOvr = 0 dspOvr = 1 */
392 res = CH_OWNSHP_MCU;
393 break;
394
395#if 0 /* Not using this */
396 case SDMA_TRAN_PER_2_DSP:
397 /* evtOvr = 0 mcuOvr = 1 dspOvr = 0 */
398 res = CH_OWNSHP_DSP | CH_OWNSHP_EVT;
399 break;
400#endif
401
402 default:
403 break;
404 }
405
406 return res;
407}
408
409/* Fill the buffer descriptor with the values given in parameter.
410 * Expects physical addresses. */
411static inline void set_buffer_descriptor(
412 struct buffer_descriptor *bd_p,
413 unsigned int command, /* C0_* command or transfer size */
414 unsigned int status, /* BD_* flags */
415 unsigned int count, /* Size of buffer to transfer */
416 void *buf_addr, /* Buffer to transfer */
417 void *buf_addr_ext)
418{
419 bd_p->mode.command = command;
420 bd_p->mode.status = status;
421 bd_p->mode.count = count;
422 bd_p->buf_addr = buf_addr;
423 if (status & BD_EXTD)
424 ((struct buffer_descriptor_extd *)bd_p)->buf_addr_ext = buf_addr_ext;
425}
426
427/* Configure channel ownership */
428static void set_channel_ownership(unsigned int channel, unsigned int config)
429{
430 unsigned long bit = 1ul << channel;
431
432 /* DSP side */
433#if 0 /* Not using this */
434 imx31_regmod32(&SDMA_DSPOVR, (config & CH_OWNSHP_DSP) ? 0 : bit, bit);
435#endif
436 /* Event */
437 imx31_regmod32(&SDMA_EVTOVR, (config & CH_OWNSHP_EVT) ? 0 : bit, bit);
438 /* MCU side */
439 imx31_regmod32(&SDMA_HOSTOVR, (config & CH_OWNSHP_MCU) ? 0 : bit, bit);
440}
441
442static bool setup_channel(struct channel_control_block *ccb_p)
443{
444 static struct context_data context_buffer DEVBSS_ATTR;
445 struct channel_descriptor *cd_p;
446 unsigned int channel_cfg;
447 unsigned int channel;
448 unsigned long pc;
449
450 memset(&context_buffer, 0x00, sizeof (context_buffer));
451
452 channel = ccb_p - ccb_array;
453 cd_p = ccb_p->channel_desc;
454
455 /* Obtain script start address for perihperal and transfer type */
456 pc = get_script_pc(cd_p->per_type, cd_p->tran_type);
457
458 if (pc == (unsigned short)-1)
459 return false; /* Failed to find a script */
460
461 context_buffer.channel_state.pc = pc;
462
463 if (cd_p->per_type != SDMA_PER_MEMORY && cd_p->per_type != SDMA_PER_DSP)
464 {
465 /* Set peripheral DMA request mask for this channel */
466 context_buffer.event_mask1 = 1ul << cd_p->event_id1;
467
468 if (cd_p->per_type == SDMA_PER_ATA)
469 {
470 /* ATA has two */
471 context_buffer.event_mask2 = 1ul << cd_p->event_id2;
472 }
473
474 context_buffer.shp_addr = cd_p->shp_addr;
475 context_buffer.wml = cd_p->wml;
476 }
477 else
478 {
479 context_buffer.wml = SDMA_PER_ADDR_SDRAM;
480 }
481
482 /* Send channel context to SDMA core */
483 clean_dcache_range(&context_buffer, sizeof (context_buffer));
484 sdma_write_words((unsigned long *)&context_buffer,
485 CHANNEL_CONTEXT_ADDR(channel),
486 sizeof (context_buffer)/4);
487
488 if (cd_p->is_setup != 0)
489 return true; /* No more to do */
490
491 /* Obtain channel ownership configuration */
492 channel_cfg = get_config(cd_p->tran_type);
493
494 if (channel_cfg == (unsigned int)-1)
495 return false;
496
497 /* Set who owns it and thus can activate it */
498 set_channel_ownership(channel, channel_cfg);
499
500 if (channel_cfg & CH_OWNSHP_EVT)
501 {
502 /* Set event ID to channel activation bitmapping */
503 imx31_regset32(&SDMA_CHNENBL(cd_p->event_id1), 1ul << channel);
504
505 if (cd_p->per_type == SDMA_PER_ATA)
506 {
507 /* ATA has two */
508 imx31_regset32(&SDMA_CHNENBL(cd_p->event_id2), 1ul << channel);
509 }
510 }
511
512 cd_p->is_setup = 1;
513
514 return true;
515}
516
517/** Public routines **/
518void sdma_init(void)
519{
520 imx31_clkctl_module_clock_gating(CG_SDMA, CGM_ON_RUN_WAIT);
521 int i;
522 unsigned long acr;
523
524 /* Reset the controller */
525 SDMA_RESET |= SDMA_RESET_RESET;
526 while (SDMA_RESET & SDMA_RESET_RESET);
527
528 init_script_info();
529
530 /* No channel enabled, all priorities 0 */
531 for (i = 0; i < CH_NUM; i++)
532 {
533 SDMA_CHNENBL(i) = 0;
534 SDMA_CHNPRI(i) = 0;
535 }
536
537 /* Ensure no ints pending */
538 SDMA_INTR = 0xffffffff;
539
540 /* Nobody owns any channel (yet) */
541 SDMA_HOSTOVR = 0xffffffff;
542 SDMA_DSPOVR = 0xffffffff;
543 SDMA_EVTOVR = 0xffffffff;
544
545 SDMA_MC0PTR = 0x00000000;
546
547 /* 32-word channel contexts, use default bootscript address */
548 SDMA_CHN0ADDR = SDMA_CHN0ADDR_SMSZ | 0x0050;
549
550 avic_enable_int(SDMA, IRQ, 8, SDMA_HANDLER);
551
552 /* SDMA core must run at the proper frequency based upon the AHB/IPG ratio */
553 acr = (imx31_clkctl_get_ahb_clk() / imx31_clkctl_get_ipg_clk()) < 2 ?
554 SDMA_CONFIG_ACR : 0;
555
556 /* No dsp, no debug
557 * Static context switching - TLSbo86520L SW Workaround for SDMA Chnl0
558 * access issue */
559 SDMA_CONFIG = acr;
560
561 /* Tell SDMA where the host channel table is */
562 SDMA_MC0PTR = (unsigned long)ccb_array;
563
564 ccb_array[0].status.opened_init = 1;
565 ccb_array[0].curr_bd_ptr = &c0_buffer_desc.bd;
566 ccb_array[0].base_bd_ptr = &c0_buffer_desc.bd;
567 ccb_array[0].channel_desc = NULL; /* No channel descriptor */
568
569 /* Command channel owned by AP */
570 set_channel_ownership(0, CH_OWNSHP_MCU);
571
572 sdma_channel_set_priority(0, 1);
573
574 /* Load SDMA script code */
575 set_buffer_descriptor(&c0_buffer_desc.bd,
576 C0_SETPM,
577 BD_DONE | BD_WRAP | BD_EXTD,
578 script_info.ram_code_size,
579 (void *)addr_virt_to_phys(script_info.mcu_start_addr),
580 (void *)(unsigned long)script_info.ram_code_start_addr);
581
582 SDMA_HSTART = 1ul;
583 sdma_channel_wait_nonblocking(0);
584
585 /* No dsp, no debug, dynamic context switching */
586 SDMA_CONFIG = acr | SDMA_CONFIG_CSM_DYNAMIC;
587}
588
589/* Busy wait for a channel to complete */
590void sdma_channel_wait_nonblocking(unsigned int channel)
591{
592 unsigned long mask;
593
594 if (channel >= CH_NUM)
595 return;
596
597 if (ccb_array[channel].status.opened_init == 0)
598 return;
599
600 mask = 1ul << channel;
601 while (SDMA_STOP_STAT & mask);
602}
603
604/* Set a new channel priority */
605void sdma_channel_set_priority(unsigned int channel, unsigned int priority)
606{
607 if (channel >= CH_NUM || priority > MAX_CH_PRIORITY)
608 return;
609
610 if (ccb_array[channel].status.opened_init == 0)
611 return;
612
613 SDMA_CHNPRI(channel) = priority;
614}
615
616/* Start a channel cold - resets execution to start of script */
617void sdma_channel_start(unsigned int channel)
618{
619 struct channel_control_block *ccb_p;
620
621 if (channel == 0 || channel >= CH_NUM)
622 return;
623
624 ccb_p = &ccb_array[channel];
625
626 if (ccb_p->status.opened_init == 0)
627 return;
628
629 if (!setup_channel(ccb_p))
630 return;
631
632 SDMA_HSTART = 1ul << channel;
633}
634
635/* Resume or start execution on a channel */
636void sdma_channel_run(unsigned int channel)
637{
638 if (channel == 0 || channel >= CH_NUM)
639 return;
640
641 if (ccb_array[channel].status.opened_init == 0)
642 return;
643
644 SDMA_HSTART = 1ul << channel;
645}
646
647/* Pause a running channel - can be resumed */
648void sdma_channel_pause(unsigned int channel)
649{
650 if (channel == 0 || channel >= CH_NUM)
651 return;
652
653 if (ccb_array[channel].status.opened_init == 0)
654 return;
655
656 SDMA_STOP_STAT = 1ul << channel;
657}
658
659/* Stop a channel from executing - cannot be resumed */
660void sdma_channel_stop(unsigned int channel)
661{
662 struct channel_control_block *ccb_p;
663 unsigned long chmsk;
664 unsigned long intmsk;
665 int oldstatus;
666 int i;
667
668 if (channel == 0 || channel >= CH_NUM)
669 return;
670
671 ccb_p = &ccb_array[channel];
672
673 if (ccb_p->status.opened_init == 0)
674 return;
675
676 chmsk = 1ul << channel;
677
678 /* Lock callback */
679 oldstatus = disable_irq_save();
680 intmsk = sdma_enabled_ints;
681 sdma_enabled_ints &= ~chmsk;
682 restore_irq(oldstatus);
683
684 /* Stop execution */
685 for (i = ccb_p->channel_desc->bd_count - 1; i >= 0; i--)
686 ccb_p->base_bd_ptr[i].mode.status &= ~BD_DONE;
687
688 SDMA_STOP_STAT = chmsk;
689 while (SDMA_STOP_STAT & chmsk);
690
691 /* Unlock callback if it was set */
692 if (intmsk & chmsk)
693 imx31_regset32(&sdma_enabled_ints, chmsk);
694
695 logf("SDMA ch closed: %d", channel);
696}
697
698bool sdma_channel_init(unsigned int channel,
699 struct channel_descriptor *cd_p,
700 struct buffer_descriptor *base_bd_p)
701{
702 struct channel_control_block *ccb_p;
703
704 if (channel == 0 || channel >= CH_NUM ||
705 cd_p == NULL || base_bd_p == NULL)
706 return false;
707
708 ccb_p = &ccb_array[channel];
709
710 /* If initialized already, should close first then init. */
711 if (ccb_p->status.opened_init != 0)
712 return false;
713
714 /* Initialize channel control block. */
715 ccb_p->curr_bd_ptr = base_bd_p;
716 ccb_p->base_bd_ptr = base_bd_p;
717 ccb_p->channel_desc = cd_p;
718 ccb_p->status.error = 0;
719 ccb_p->status.opened_init = 1;
720 ccb_p->status.state_direction = 0;
721 ccb_p->status.execute = 0;
722
723 /* Finish any channel descriptor inits. */
724 cd_p->ccb_ptr = ccb_p;
725 cd_p->is_setup = 0;
726
727 /* Do an initial setup now. */
728 if (!setup_channel(ccb_p))
729 {
730 logf("SDMA ch init failed: %d", channel);
731 cd_p->ccb_ptr = NULL;
732 memset(ccb_p, 0x00, sizeof (struct channel_control_block));
733 return false;
734 }
735
736 /* Enable interrupt if a callback is specified. */
737 if (cd_p->callback != NULL)
738 imx31_regset32(&sdma_enabled_ints, 1ul << channel);
739
740 /* Minimum schedulable = 1 */
741 sdma_channel_set_priority(channel, 1);
742
743 logf("SDMA ch initialized: %d", channel);
744 return true;
745}
746
747void sdma_channel_close(unsigned int channel)
748{
749 struct channel_control_block *ccb_p;
750 int i;
751
752 if (channel == 0 || channel >= CH_NUM)
753 return;
754
755 ccb_p = &ccb_array[channel];
756
757 /* Block callbacks (if not initialized, it won't be set). */
758 imx31_regclr32(&sdma_enabled_ints, 1ul << channel);
759
760 if (ccb_p->status.opened_init == 0)
761 return;
762
763 /* Stop the channel if running */
764 for (i = ccb_p->channel_desc->bd_count - 1; i >= 0; i--)
765 ccb_p->base_bd_ptr[i].mode.status &= ~BD_DONE;
766
767 sdma_channel_stop(channel);
768
769 /* No ownership */
770 set_channel_ownership(channel, 0);
771
772 /* Cannot schedule it again */
773 sdma_channel_set_priority(channel, 0);
774
775 /* Reset channel control block entry */
776 memset(ccb_p, 0x00, sizeof (struct channel_control_block));
777}
778
779/* Write 32-bit words to SDMA core memory. Host endian->SDMA endian. */
780void sdma_write_words(const unsigned long *buf, unsigned long start, int count)
781{
782 /* Setup buffer descriptor with channel 0 command */
783 set_buffer_descriptor(&c0_buffer_desc.bd,
784 C0_SETDM,
785 BD_DONE | BD_WRAP | BD_EXTD,
786 count,
787 (void *)addr_virt_to_phys((unsigned long)buf),
788 (void *)start);
789
790 SDMA_HSTART = 1ul;
791 sdma_channel_wait_nonblocking(0);
792}
793
794/* Read 32-bit words from SDMA core memory. SDMA endian->host endian. */
795void sdma_read_words(unsigned long *buf, unsigned long start, int count)
796{
797 /* Setup buffer descriptor with channel 0 command */
798 set_buffer_descriptor(&c0_buffer_desc.bd,
799 C0_GETDM,
800 BD_DONE | BD_WRAP | BD_EXTD,
801 count,
802 (void *)addr_virt_to_phys((unsigned long)buf),
803 (void *)start);
804
805 SDMA_HSTART = 1ul;
806 sdma_channel_wait_nonblocking(0);
807}