diff options
Diffstat (limited to 'lib/rbcodec/dsp/dsp_core.c')
-rw-r--r-- | lib/rbcodec/dsp/dsp_core.c | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/lib/rbcodec/dsp/dsp_core.c b/lib/rbcodec/dsp/dsp_core.c new file mode 100644 index 0000000000..84fe64adb0 --- /dev/null +++ b/lib/rbcodec/dsp/dsp_core.c | |||
@@ -0,0 +1,554 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Miika Pekkarinen | ||
11 | * Copyright (C) 2012 Michael Sevakis | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "config.h" | ||
23 | #include "system.h" | ||
24 | #include "dsp.h" | ||
25 | #include "dsp_sample_io.h" | ||
26 | #include <sys/types.h> | ||
27 | |||
28 | /* Define LOGF_ENABLE to enable logf output in this file */ | ||
29 | /*#define LOGF_ENABLE*/ | ||
30 | #include "logf.h" | ||
31 | |||
32 | /* Actually generate the database of stages */ | ||
33 | #define DSP_PROC_DB_CREATE | ||
34 | #include "dsp_proc_entry.h" | ||
35 | |||
36 | /* Linked lists give fewer loads in processing loop compared to some index | ||
37 | * list, which is more important than keeping occasionally executed code | ||
38 | * simple */ | ||
39 | |||
40 | struct dsp_config | ||
41 | { | ||
42 | /** General DSP-local data **/ | ||
43 | struct sample_io_data io_data; /* Sample input-output data (first) */ | ||
44 | uint32_t slot_free_mask; /* Mask of free slots for this DSP */ | ||
45 | uint32_t proc_masks[2]; /* Mask of active/enabled stages */ | ||
46 | struct dsp_proc_slot | ||
47 | { | ||
48 | struct dsp_proc_entry proc_entry; /* This enabled stage */ | ||
49 | struct dsp_proc_slot *next[2]; /* [0]=active next, [1]=enabled next */ | ||
50 | const struct dsp_proc_db_entry *db_entry; | ||
51 | } *proc_slots[2]; /* Pointer to first in list of | ||
52 | active/enabled stages */ | ||
53 | |||
54 | /** Misc. extra stuff **/ | ||
55 | #ifdef CPU_COLDFIRE | ||
56 | unsigned long old_macsr; /* Old macsr value to restore */ | ||
57 | #endif | ||
58 | #if 0 /* Not needed now but enable if something must know this */ | ||
59 | bool processing; /* DSP is processing (to thwart inopportune | ||
60 | buffer moves) */ | ||
61 | #endif | ||
62 | }; | ||
63 | |||
64 | /* Pool of slots for stages - supports 32 or fewer combined as-is atm. */ | ||
65 | static struct dsp_proc_slot | ||
66 | dsp_proc_slot_arr[DSP_NUM_PROC_STAGES+DSP_VOICE_NUM_PROC_STAGES] IBSS_ATTR; | ||
67 | |||
68 | /* General DSP config */ | ||
69 | static struct dsp_config dsp_conf[DSP_COUNT] IBSS_ATTR; | ||
70 | |||
71 | /** Processing stages support functions **/ | ||
72 | |||
73 | /* Find the slot for a given enabled id */ | ||
74 | static struct dsp_proc_slot * find_proc_slot(struct dsp_config *dsp, | ||
75 | unsigned int id) | ||
76 | { | ||
77 | const uint32_t mask = BIT_N(id); | ||
78 | |||
79 | if ((dsp->proc_masks[1] & mask) == 0) | ||
80 | return NULL; /* Not enabled */ | ||
81 | |||
82 | struct dsp_proc_slot *s = dsp->proc_slots[1]; | ||
83 | |||
84 | while (1) /* In proc_masks == it must be there */ | ||
85 | { | ||
86 | if (BIT_N(s->db_entry->id) == mask) | ||
87 | return s; | ||
88 | |||
89 | s = s->next[1]; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* Broadcast to all enabled stages or to the one with the specifically | ||
94 | * crafted setting */ | ||
95 | static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting, | ||
96 | intptr_t value) | ||
97 | { | ||
98 | bool multi = setting < DSP_PROC_SETTING; | ||
99 | struct dsp_proc_slot *s = multi ? | ||
100 | dsp->proc_slots[1] : find_proc_slot(dsp, setting - DSP_PROC_SETTING); | ||
101 | |||
102 | while (s != NULL) | ||
103 | { | ||
104 | intptr_t ret = s->db_entry->configure(&s->proc_entry, dsp, setting, | ||
105 | value); | ||
106 | if (!multi) | ||
107 | return ret; | ||
108 | |||
109 | s = s->next[1]; | ||
110 | } | ||
111 | |||
112 | return multi ? 1 : 0; | ||
113 | } | ||
114 | |||
115 | /* Generic handler for this->process[0] */ | ||
116 | static void dsp_process_null(struct dsp_proc_entry *this, | ||
117 | struct dsp_buffer **buf_p) | ||
118 | { | ||
119 | (void)this; (void)buf_p; | ||
120 | } | ||
121 | |||
122 | /* Generic handler for this->process[1] */ | ||
123 | static void dsp_format_change_process(struct dsp_proc_entry *this, | ||
124 | struct dsp_buffer **buf_p) | ||
125 | { | ||
126 | enum dsp_proc_ids id = | ||
127 | TYPE_FROM_MEMBER(struct dsp_proc_slot, this, proc_entry)->db_entry->id; | ||
128 | |||
129 | DSP_PRINT_FORMAT(<Default Handler>, id, (*buf_p)->format); | ||
130 | |||
131 | /* We don't keep back references to the DSP, so just search for it */ | ||
132 | struct dsp_config *dsp; | ||
133 | for (int i = 0; (dsp = dsp_get_config(i)); i++) | ||
134 | { | ||
135 | struct dsp_proc_slot *slot = find_proc_slot(dsp, id); | ||
136 | /* Found one with the id, check if it's this one */ | ||
137 | if (&slot->proc_entry == this && dsp_proc_active(dsp, id)) | ||
138 | { | ||
139 | dsp_proc_call(this, buf_p, 0); | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /* Add an item to the enabled list */ | ||
146 | static struct dsp_proc_slot * | ||
147 | dsp_proc_enable_enlink(struct dsp_config *dsp, uint32_t mask) | ||
148 | { | ||
149 | /* Use the lowest-indexed available slot */ | ||
150 | int slot = find_first_set_bit(dsp->slot_free_mask); | ||
151 | |||
152 | if (slot == 32) | ||
153 | { | ||
154 | /* Should NOT happen, ever, unless called before init */ | ||
155 | DEBUGF("DSP %d: no slots!\n", (int)dsp_get_id(dsp)); | ||
156 | return NULL; | ||
157 | } | ||
158 | |||
159 | const struct dsp_proc_db_entry *db_entry_prev = NULL; | ||
160 | const struct dsp_proc_db_entry *db_entry; | ||
161 | |||
162 | /* Order of enabled list is same as DB array */ | ||
163 | for (unsigned int i = 0;; i++) | ||
164 | { | ||
165 | if (i >= DSP_NUM_PROC_STAGES) | ||
166 | return NULL; | ||
167 | |||
168 | db_entry = dsp_proc_database[i]; | ||
169 | |||
170 | uint32_t m = BIT_N(db_entry->id); | ||
171 | |||
172 | if (m == mask) | ||
173 | break; /* This is the one */ | ||
174 | |||
175 | if (dsp->proc_masks[1] & m) | ||
176 | db_entry_prev = db_entry; | ||
177 | } | ||
178 | |||
179 | struct dsp_proc_slot *s = &dsp_proc_slot_arr[slot]; | ||
180 | |||
181 | if (db_entry_prev != NULL) | ||
182 | { | ||
183 | struct dsp_proc_slot *prev = find_proc_slot(dsp, db_entry_prev->id); | ||
184 | s->next[0] = prev->next[0]; | ||
185 | s->next[1] = prev->next[1]; | ||
186 | prev->next[1] = s; | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | s->next[0] = dsp->proc_slots[0]; | ||
191 | s->next[1] = dsp->proc_slots[1]; | ||
192 | dsp->proc_slots[1] = s; | ||
193 | } | ||
194 | |||
195 | s->db_entry = db_entry; /* record DB entry */ | ||
196 | dsp->proc_masks[1] |= mask; | ||
197 | dsp->slot_free_mask &= ~BIT_N(slot); | ||
198 | |||
199 | return s; | ||
200 | } | ||
201 | |||
202 | /* Remove an item from the enabled list */ | ||
203 | static struct dsp_proc_slot * | ||
204 | dsp_proc_enable_delink(struct dsp_config *dsp, uint32_t mask) | ||
205 | { | ||
206 | struct dsp_proc_slot *s = dsp->proc_slots[1]; | ||
207 | struct dsp_proc_slot *prev = NULL; | ||
208 | |||
209 | while (1) /* In proc_masks == it must be there */ | ||
210 | { | ||
211 | if (BIT_N(s->db_entry->id) == mask) | ||
212 | { | ||
213 | if (prev) | ||
214 | prev->next[1] = s->next[1]; | ||
215 | else | ||
216 | dsp->proc_slots[1] = s->next[1]; | ||
217 | |||
218 | dsp->proc_masks[1] &= ~mask; | ||
219 | dsp->slot_free_mask |= BIT_N(s - dsp_proc_slot_arr); | ||
220 | return s; | ||
221 | } | ||
222 | |||
223 | prev = s; | ||
224 | s = s->next[1]; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, | ||
229 | bool enable) | ||
230 | { | ||
231 | uint32_t mask = BIT_N(id); | ||
232 | bool enabled = dsp->proc_masks[1] & mask; | ||
233 | |||
234 | if (enable) | ||
235 | { | ||
236 | /* If enabled, just find it in list, if not, link a new one */ | ||
237 | struct dsp_proc_slot *s = enabled ? find_proc_slot(dsp, id) : | ||
238 | dsp_proc_enable_enlink(dsp, mask); | ||
239 | |||
240 | if (s == NULL) | ||
241 | { | ||
242 | DEBUGF("DSP- proc id not valid: %d\n", (int)id); | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | if (!enabled) | ||
247 | { | ||
248 | /* New entry - set defaults */ | ||
249 | s->proc_entry.data = 0; | ||
250 | s->proc_entry.ip_mask = mask; | ||
251 | s->proc_entry.process[0] = dsp_process_null; | ||
252 | s->proc_entry.process[1] = dsp_format_change_process; | ||
253 | } | ||
254 | |||
255 | enabled = s->db_entry->configure(&s->proc_entry, dsp, DSP_PROC_INIT, | ||
256 | enabled) >= 0; | ||
257 | if (enabled) | ||
258 | return; | ||
259 | |||
260 | DEBUGF("DSP- proc init failed: %d\n", (int)id); | ||
261 | /* Cleanup below */ | ||
262 | } | ||
263 | else if (!enabled) | ||
264 | { | ||
265 | return; /* No change */ | ||
266 | } | ||
267 | |||
268 | dsp_proc_activate(dsp, id, false); /* Deactivate it first */ | ||
269 | struct dsp_proc_slot *s = dsp_proc_enable_delink(dsp, mask); | ||
270 | s->db_entry->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0); | ||
271 | } | ||
272 | |||
273 | /* Maintain the list structure for the active list where each enabled entry | ||
274 | * has a link to the next active item, even if not active which facilitates | ||
275 | * switching out of format change mode by a stage during a format change. | ||
276 | * When that happens, the iterator must jump over inactive but enabled | ||
277 | * stages after its current position. */ | ||
278 | static struct dsp_proc_slot * | ||
279 | dsp_proc_activate_link(struct dsp_config *dsp, uint32_t mask, | ||
280 | struct dsp_proc_slot *s) | ||
281 | { | ||
282 | uint32_t m = BIT_N(s->db_entry->id); | ||
283 | uint32_t mor = m | mask; | ||
284 | |||
285 | if (mor == m) /* Only if same single bit in common */ | ||
286 | { | ||
287 | dsp->proc_masks[0] |= mask; | ||
288 | return s; | ||
289 | } | ||
290 | else if (~mor == 0) /* Only if bits complement */ | ||
291 | { | ||
292 | dsp->proc_masks[0] &= mask; | ||
293 | return s->next[0]; | ||
294 | } | ||
295 | |||
296 | struct dsp_proc_slot *next = s->next[1]; | ||
297 | next = dsp_proc_activate_link(dsp, mask, next); | ||
298 | |||
299 | s->next[0] = next; | ||
300 | |||
301 | return (m & dsp->proc_masks[0]) ? s : next; | ||
302 | } | ||
303 | |||
304 | /* Activate or deactivate a stage */ | ||
305 | void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id, | ||
306 | bool activate) | ||
307 | { | ||
308 | const uint32_t mask = BIT_N(id); | ||
309 | |||
310 | if (!(dsp->proc_masks[1] & mask)) | ||
311 | return; /* Not enabled */ | ||
312 | |||
313 | if (activate != !(dsp->proc_masks[0] & mask)) | ||
314 | return; /* No change in state */ | ||
315 | |||
316 | /* Send mask bit if activating and ones complement if deactivating */ | ||
317 | dsp->proc_slots[0] = dsp_proc_activate_link( | ||
318 | dsp, activate ? mask : ~mask, dsp->proc_slots[1]); | ||
319 | } | ||
320 | |||
321 | /* Is the stage specified by the id currently active? */ | ||
322 | bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id) | ||
323 | { | ||
324 | return (dsp->proc_masks[0] & BIT_N(id)) != 0; | ||
325 | } | ||
326 | |||
327 | /* Determine by the rules if the processing function should be called */ | ||
328 | static FORCE_INLINE bool dsp_proc_should_call(struct dsp_proc_entry *this, | ||
329 | struct dsp_buffer *buf, | ||
330 | unsigned int fmt) | ||
331 | { | ||
332 | uint32_t ip_mask = this->ip_mask; | ||
333 | |||
334 | return UNLIKELY(fmt != 0) || /* Also pass override value */ | ||
335 | ip_mask == 0 || /* Not in-place */ | ||
336 | ((ip_mask & buf->proc_mask) == 0 && | ||
337 | (buf->proc_mask |= ip_mask, buf->remcount > 0)); | ||
338 | } | ||
339 | |||
340 | /* Call this->process[fmt] according to the rules (for external call) */ | ||
341 | bool dsp_proc_call(struct dsp_proc_entry *this, struct dsp_buffer **buf_p, | ||
342 | unsigned int fmt) | ||
343 | { | ||
344 | if (dsp_proc_should_call(this, *buf_p, fmt)) | ||
345 | { | ||
346 | this->process[fmt == (0u-1u) ? 0 : fmt](this, buf_p); | ||
347 | return true; | ||
348 | } | ||
349 | |||
350 | return false; | ||
351 | } | ||
352 | |||
353 | static inline void dsp_process_start(struct dsp_config *dsp) | ||
354 | { | ||
355 | #if defined(CPU_COLDFIRE) | ||
356 | /* set emac unit for dsp processing, and save old macsr, we're running in | ||
357 | codec thread context at this point, so can't clobber it */ | ||
358 | dsp->old_macsr = coldfire_get_macsr(); | ||
359 | coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); | ||
360 | #endif | ||
361 | #if 0 /* Not needed now but enable if something must know this */ | ||
362 | dsp->processing = true; | ||
363 | #endif | ||
364 | (void)dsp; | ||
365 | } | ||
366 | |||
367 | static inline void dsp_process_end(struct dsp_config *dsp) | ||
368 | { | ||
369 | #if 0 /* Not needed now but enable if something must know this */ | ||
370 | dsp->processing = false; | ||
371 | #endif | ||
372 | #if defined(CPU_COLDFIRE) | ||
373 | /* set old macsr again */ | ||
374 | coldfire_set_macsr(dsp->old_macsr); | ||
375 | #endif | ||
376 | (void)dsp; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * dsp_process: | ||
381 | * | ||
382 | * Process and convert src audio to dst based on the DSP configuration. | ||
383 | * dsp: the DSP instance in use | ||
384 | * | ||
385 | * src: | ||
386 | * remcount = number of input samples remaining; set to desired | ||
387 | * number of samples to be processed | ||
388 | * pin[0] = left channel if non-interleaved, audio data if | ||
389 | * interleaved or mono | ||
390 | * pin[1] = right channel if non-interleaved, ignored if | ||
391 | * interleaved or mono | ||
392 | * proc_mask = set to zero on first call, updated by this function | ||
393 | * to keep track of which in-place stages have been | ||
394 | * run on the buffers to avoid multiple applications of | ||
395 | * them | ||
396 | * format = for internal buffers, gives the relevant format | ||
397 | * details | ||
398 | * | ||
399 | * dst: | ||
400 | * remcount = number of samples placed in buffer so far; set to | ||
401 | * zero on first call | ||
402 | * p16out = current fill pointer in destination buffer; set to | ||
403 | * buffer start on first call | ||
404 | * bufcount = remaining buffer space in samples; set to maximum | ||
405 | * desired output count on first call | ||
406 | * format = ignored | ||
407 | * | ||
408 | * Processing stops when src is exhausted or dst is filled, whichever | ||
409 | * happens first. Samples can still be output when src buffer is empty | ||
410 | * if samples are held internally. Generally speaking, continue calling | ||
411 | * until no data is consumed and no data is produced to purge the DSP | ||
412 | * to the maximum extent feasible. Some internal processing stages may | ||
413 | * require more input before more output can be generated, thus there | ||
414 | * is no guarantee the DSP is free of data awaiting processing at that | ||
415 | * point. | ||
416 | * | ||
417 | * Additionally, samples consumed and samples produced do not necessarily | ||
418 | * have a direct correlation. Samples may be consumed without producing | ||
419 | * any output and samples may be produced without consuming any input. | ||
420 | * It depends on which stages are actively processing data at the time | ||
421 | * of the call and how they function internally. | ||
422 | */ | ||
423 | void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, | ||
424 | struct dsp_buffer *dst) | ||
425 | { | ||
426 | if (dst->bufcount <= 0) | ||
427 | { | ||
428 | /* No place to put anything thus nothing may be safely consumed */ | ||
429 | return; | ||
430 | } | ||
431 | |||
432 | /* At least perform one yield before starting */ | ||
433 | long last_yield = current_tick; | ||
434 | yield(); | ||
435 | |||
436 | dsp_process_start(dsp); | ||
437 | |||
438 | /* Tag input with codec-specified sample format */ | ||
439 | src->format = dsp->io_data.format; | ||
440 | |||
441 | while (1) | ||
442 | { | ||
443 | /* Out-of-place-processing stages take the current buf as input | ||
444 | * and switch the buffer to their own output buffer */ | ||
445 | struct dsp_buffer *buf = src; | ||
446 | unsigned int fmt = buf->format.changed; | ||
447 | |||
448 | /* Convert input samples to internal format */ | ||
449 | dsp->io_data.input_samples[fmt](&dsp->io_data, &buf); | ||
450 | fmt = buf->format.changed; | ||
451 | |||
452 | struct dsp_proc_slot *s = dsp->proc_slots[fmt]; | ||
453 | |||
454 | /* Call all active/enabled stages depending if format is | ||
455 | same/changed on the last output buffer */ | ||
456 | while (s != NULL) | ||
457 | { | ||
458 | if (dsp_proc_should_call(&s->proc_entry, buf, fmt)) | ||
459 | { | ||
460 | s->proc_entry.process[fmt](&s->proc_entry, &buf); | ||
461 | fmt = buf->format.changed; | ||
462 | } | ||
463 | |||
464 | /* The buffer may have changed along with the format flag */ | ||
465 | s = s->next[fmt]; | ||
466 | } | ||
467 | |||
468 | /* Don't overread/write src/destination */ | ||
469 | int outcount = MIN(dst->bufcount, buf->remcount); | ||
470 | |||
471 | if (fmt == 0 && outcount <= 0) | ||
472 | break; /* Output full or purged internal buffers */ | ||
473 | |||
474 | dsp->io_data.outcount = outcount; | ||
475 | dsp->io_data.output_samples[fmt](&dsp->io_data, buf, dst); | ||
476 | |||
477 | /* Advance buffers by what output consumed and produced */ | ||
478 | dsp_advance_buffer32(buf, outcount); | ||
479 | dsp_advance_buffer_output(dst, outcount); | ||
480 | |||
481 | /* Yield at least once each tick */ | ||
482 | long tick = current_tick; | ||
483 | if (TIME_AFTER(tick, last_yield)) | ||
484 | { | ||
485 | last_yield = tick; | ||
486 | yield(); | ||
487 | } | ||
488 | } /* while */ | ||
489 | |||
490 | dsp_process_end(dsp); | ||
491 | } | ||
492 | |||
493 | intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting, | ||
494 | intptr_t value) | ||
495 | { | ||
496 | dsp_sample_io_configure(&dsp->io_data, setting, value); | ||
497 | return proc_broadcast(dsp, setting, value); | ||
498 | } | ||
499 | |||
500 | struct dsp_config * dsp_get_config(enum dsp_ids id) | ||
501 | { | ||
502 | if (id >= DSP_COUNT) | ||
503 | return NULL; | ||
504 | |||
505 | return &dsp_conf[id]; | ||
506 | } | ||
507 | |||
508 | /* Return the id given a dsp pointer (or even via something within | ||
509 | the struct itself) */ | ||
510 | enum dsp_ids dsp_get_id(const struct dsp_config *dsp) | ||
511 | { | ||
512 | ptrdiff_t id = dsp - dsp_conf; | ||
513 | |||
514 | if (id < 0 || id >= DSP_COUNT) | ||
515 | return DSP_COUNT; /* obviously invalid */ | ||
516 | |||
517 | return (enum dsp_ids)id; | ||
518 | } | ||
519 | |||
520 | #if 0 /* Not needed now but enable if something must know this */ | ||
521 | bool dsp_is_busy(const struct dsp_config *dsp) | ||
522 | { | ||
523 | return dsp->processing; | ||
524 | } | ||
525 | #endif /* 0 */ | ||
526 | |||
527 | /* Do what needs initializing before enable/disable calls can be made. | ||
528 | * Must be done before changing settings for the first time. */ | ||
529 | void INIT_ATTR dsp_init(void) | ||
530 | { | ||
531 | static const uint8_t slot_count[DSP_COUNT] /* INITDATA_ATTR */ = | ||
532 | { | ||
533 | [CODEC_IDX_AUDIO] = DSP_NUM_PROC_STAGES, | ||
534 | [CODEC_IDX_VOICE] = DSP_VOICE_NUM_PROC_STAGES | ||
535 | }; | ||
536 | |||
537 | for (unsigned int i = 0, count, shift = 0; | ||
538 | i < DSP_COUNT; | ||
539 | i++, shift += count) | ||
540 | { | ||
541 | struct dsp_config *dsp = &dsp_conf[i]; | ||
542 | |||
543 | count = slot_count[i]; | ||
544 | dsp->slot_free_mask = MASK_N(uint32_t, count, shift); | ||
545 | |||
546 | dsp_sample_io_configure(&dsp->io_data, DSP_INIT, i); | ||
547 | |||
548 | /* Notify each db entry of global init for each DSP */ | ||
549 | for (unsigned int j = 0; j < DSP_NUM_PROC_STAGES; j++) | ||
550 | dsp_proc_database[j]->configure(NULL, dsp, DSP_INIT, i); | ||
551 | |||
552 | dsp_configure(dsp, DSP_RESET, 0); | ||
553 | } | ||
554 | } | ||