diff options
Diffstat (limited to 'firmware/target/arm/imx31/sdma-imx31.c')
-rw-r--r-- | firmware/target/arm/imx31/sdma-imx31.c | 807 |
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 */ | ||
39 | static struct sdma_script_start_addrs script_info; | ||
40 | /* Mask of channels with callback enabled */ | ||
41 | static unsigned long sdma_enabled_ints = 0; | ||
42 | /* One channel control block per channel in physically mapped device RAM */ | ||
43 | static struct channel_control_block ccb_array[CH_NUM] DEVBSS_ATTR; | ||
44 | /* Channel 0 (command channel) data */ | ||
45 | static 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 | */ | ||
51 | static 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 */ | ||
75 | static 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 */ | ||
149 | static 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 | |||
349 | static 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. */ | ||
411 | static 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 */ | ||
428 | static 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 | |||
442 | static 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 **/ | ||
518 | void 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 */ | ||
590 | void 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 */ | ||
605 | void 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 */ | ||
617 | void 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 */ | ||
636 | void 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 */ | ||
648 | void 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 */ | ||
660 | void 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 | |||
698 | bool 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 | |||
747 | void 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. */ | ||
780 | void 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. */ | ||
795 | void 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 | } | ||