xref: /linux/sound/pci/cs46xx/dsp_spos.c (revision 05a54fa773284d1a7923cdfdd8f0c8dabb98bd26)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  */
4 
5 /*
6  * 2002-07 Benny Sjostrand benny@hostmobility.com
7  */
8 
9 
10 #include <linux/io.h>
11 #include <linux/delay.h>
12 #include <linux/pm.h>
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/vmalloc.h>
16 #include <linux/mutex.h>
17 
18 #include <sound/core.h>
19 #include <sound/control.h>
20 #include <sound/info.h>
21 #include <sound/asoundef.h>
22 #include "cs46xx.h"
23 
24 #include "cs46xx_lib.h"
25 #include "dsp_spos.h"
26 
27 static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
28 				  struct dsp_scb_descriptor * fg_entry);
29 
30 static const enum wide_opcode wide_opcodes[] = {
31 	WIDE_FOR_BEGIN_LOOP,
32 	WIDE_FOR_BEGIN_LOOP2,
33 	WIDE_COND_GOTO_ADDR,
34 	WIDE_COND_GOTO_CALL,
35 	WIDE_TBEQ_COND_GOTO_ADDR,
36 	WIDE_TBEQ_COND_CALL_ADDR,
37 	WIDE_TBEQ_NCOND_GOTO_ADDR,
38 	WIDE_TBEQ_NCOND_CALL_ADDR,
39 	WIDE_TBEQ_COND_GOTO1_ADDR,
40 	WIDE_TBEQ_COND_CALL1_ADDR,
41 	WIDE_TBEQ_NCOND_GOTOI_ADDR,
42 	WIDE_TBEQ_NCOND_CALL1_ADDR
43 };
44 
45 static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 size,
46 				       u32 overlay_begin_address)
47 {
48 	unsigned int i = 0, j, nreallocated = 0;
49 	u32 hival,loval,address;
50 	u32 mop_operands,mop_type,wide_op;
51 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
52 
53 	if (snd_BUG_ON(size %2))
54 		return -EINVAL;
55 
56 	while (i < size) {
57 		loval = data[i++];
58 		hival = data[i++];
59 
60 		if (ins->code.offset > 0) {
61 			mop_operands = (hival >> 6) & 0x03fff;
62 			mop_type = mop_operands >> 10;
63 
64 			/* check for wide type instruction */
65 			if (mop_type == 0 &&
66 			    (mop_operands & WIDE_LADD_INSTR_MASK) == 0 &&
67 			    (mop_operands & WIDE_INSTR_MASK) != 0) {
68 				wide_op = loval & 0x7f;
69 				for (j = 0;j < ARRAY_SIZE(wide_opcodes); ++j) {
70 					if (wide_opcodes[j] == wide_op) {
71 						/* need to reallocate instruction */
72 						address  = (hival & 0x00FFF) << 5;
73 						address |=  loval >> 15;
74 
75 						dev_dbg(chip->card->dev,
76 							"handle_wideop[1]: %05x:%05x addr %04x\n",
77 							hival, loval, address);
78 
79 						if ( !(address & 0x8000) ) {
80 							address += (ins->code.offset / 2) - overlay_begin_address;
81 						} else {
82 							dev_dbg(chip->card->dev,
83 								"handle_wideop[1]: ROM symbol not reallocated\n");
84 						}
85 
86 						hival &= 0xFF000;
87 						loval &= 0x07FFF;
88 
89 						hival |= ( (address >> 5)  & 0x00FFF);
90 						loval |= ( (address << 15) & 0xF8000);
91 
92 						address  = (hival & 0x00FFF) << 5;
93 						address |=  loval >> 15;
94 
95 						dev_dbg(chip->card->dev,
96 							"handle_wideop:[2] %05x:%05x addr %04x\n",
97 							hival, loval, address);
98 						nreallocated++;
99 					} /* wide_opcodes[j] == wide_op */
100 				} /* for */
101 			} /* mod_type == 0 ... */
102 		} /* ins->code.offset > 0 */
103 
104 		ins->code.data[ins->code.size++] = loval;
105 		ins->code.data[ins->code.size++] = hival;
106 	}
107 
108 	dev_dbg(chip->card->dev,
109 		"dsp_spos: %d instructions reallocated\n", nreallocated);
110 	return nreallocated;
111 }
112 
113 static struct dsp_segment_desc * get_segment_desc (struct dsp_module_desc * module, int seg_type)
114 {
115 	int i;
116 	for (i = 0;i < module->nsegments; ++i) {
117 		if (module->segments[i].segment_type == seg_type) {
118 			return (module->segments + i);
119 		}
120 	}
121 
122 	return NULL;
123 };
124 
125 static int find_free_symbol_index (struct dsp_spos_instance * ins)
126 {
127 	int index = ins->symbol_table.nsymbols,i;
128 
129 	for (i = ins->symbol_table.highest_frag_index; i < ins->symbol_table.nsymbols; ++i) {
130 		if (ins->symbol_table.symbols[i].deleted) {
131 			index = i;
132 			break;
133 		}
134 	}
135 
136 	return index;
137 }
138 
139 static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * module)
140 {
141 	int i;
142 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
143 
144 	if (module->symbol_table.nsymbols > 0) {
145 		if (!strcmp(module->symbol_table.symbols[0].symbol_name, "OVERLAYBEGINADDRESS") &&
146 		    module->symbol_table.symbols[0].symbol_type == SYMBOL_CONSTANT ) {
147 			module->overlay_begin_address = module->symbol_table.symbols[0].address;
148 		}
149 	}
150 
151 	for (i = 0;i < module->symbol_table.nsymbols; ++i) {
152 		if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
153 			dev_err(chip->card->dev,
154 				"dsp_spos: symbol table is full\n");
155 			return -ENOMEM;
156 		}
157 
158 
159 		if (cs46xx_dsp_lookup_symbol(chip,
160 					     module->symbol_table.symbols[i].symbol_name,
161 					     module->symbol_table.symbols[i].symbol_type) == NULL) {
162 
163 			ins->symbol_table.symbols[ins->symbol_table.nsymbols] = module->symbol_table.symbols[i];
164 			ins->symbol_table.symbols[ins->symbol_table.nsymbols].address += ((ins->code.offset / 2) - module->overlay_begin_address);
165 			ins->symbol_table.symbols[ins->symbol_table.nsymbols].module = module;
166 			ins->symbol_table.symbols[ins->symbol_table.nsymbols].deleted = 0;
167 
168 			if (ins->symbol_table.nsymbols > ins->symbol_table.highest_frag_index)
169 				ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
170 
171 			ins->symbol_table.nsymbols++;
172 		} else {
173 #if 0
174 			dev_dbg(chip->card->dev,
175 				"dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
176 				module->symbol_table.symbols[i].symbol_name); */
177 #endif
178 		}
179 	}
180 
181 	return 0;
182 }
183 
184 static struct dsp_symbol_entry *
185 add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type)
186 {
187 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
188 	struct dsp_symbol_entry * symbol = NULL;
189 	int index;
190 
191 	if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
192 		dev_err(chip->card->dev, "dsp_spos: symbol table is full\n");
193 		return NULL;
194 	}
195 
196 	if (cs46xx_dsp_lookup_symbol(chip,
197 				     symbol_name,
198 				     type) != NULL) {
199 		dev_err(chip->card->dev,
200 			"dsp_spos: symbol <%s> duplicated\n", symbol_name);
201 		return NULL;
202 	}
203 
204 	index = find_free_symbol_index (ins);
205 
206 	strscpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);
207 	ins->symbol_table.symbols[index].address = address;
208 	ins->symbol_table.symbols[index].symbol_type = type;
209 	ins->symbol_table.symbols[index].module = NULL;
210 	ins->symbol_table.symbols[index].deleted = 0;
211 	symbol = (ins->symbol_table.symbols + index);
212 
213 	if (index > ins->symbol_table.highest_frag_index)
214 		ins->symbol_table.highest_frag_index = index;
215 
216 	if (index == ins->symbol_table.nsymbols)
217 		ins->symbol_table.nsymbols++; /* no frag. in list */
218 
219 	return symbol;
220 }
221 
222 struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
223 {
224 	struct dsp_spos_instance * ins = kzalloc(sizeof(struct dsp_spos_instance), GFP_KERNEL);
225 
226 	if (ins == NULL)
227 		return NULL;
228 
229 	/* better to use vmalloc for this big table */
230 	ins->symbol_table.symbols =
231 		vmalloc(array_size(DSP_MAX_SYMBOLS,
232 				   sizeof(struct dsp_symbol_entry)));
233 	ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
234 	ins->modules = kmalloc_array(DSP_MAX_MODULES,
235 				     sizeof(struct dsp_module_desc),
236 				     GFP_KERNEL);
237 	if (!ins->symbol_table.symbols || !ins->code.data || !ins->modules) {
238 		cs46xx_dsp_spos_destroy(chip);
239 		goto error;
240 	}
241 	ins->symbol_table.nsymbols = 0;
242 	ins->symbol_table.highest_frag_index = 0;
243 	ins->code.offset = 0;
244 	ins->code.size = 0;
245 	ins->nscb = 0;
246 	ins->ntask = 0;
247 	ins->nmodules = 0;
248 
249 	/* default SPDIF input sample rate
250 	   to 48000 khz */
251 	ins->spdif_in_sample_rate = 48000;
252 
253 	/* maximize volume */
254 	ins->dac_volume_right = 0x8000;
255 	ins->dac_volume_left = 0x8000;
256 	ins->spdif_input_volume_right = 0x8000;
257 	ins->spdif_input_volume_left = 0x8000;
258 
259 	/* set left and right validity bits and
260 	   default channel status */
261 	ins->spdif_csuv_default =
262 		ins->spdif_csuv_stream =
263 	 /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |
264 	 /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |
265 	 /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
266 	 /* left and right validity bits */ (1 << 13) | (1 << 12);
267 
268 	return ins;
269 
270 error:
271 	kfree(ins->modules);
272 	kfree(ins->code.data);
273 	vfree(ins->symbol_table.symbols);
274 	kfree(ins);
275 	return NULL;
276 }
277 
278 void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
279 {
280 	int i;
281 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
282 
283 	if (snd_BUG_ON(!ins))
284 		return;
285 
286 	guard(mutex)(&chip->spos_mutex);
287 	for (i = 0; i < ins->nscb; ++i) {
288 		if (ins->scbs[i].deleted) continue;
289 
290 		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
291 #ifdef CONFIG_PM_SLEEP
292 		kfree(ins->scbs[i].data);
293 #endif
294 	}
295 
296 	kfree(ins->code.data);
297 	vfree(ins->symbol_table.symbols);
298 	kfree(ins->modules);
299 	kfree(ins);
300 }
301 
302 static int dsp_load_parameter(struct snd_cs46xx *chip,
303 			      struct dsp_segment_desc *parameter)
304 {
305 	u32 doffset, dsize;
306 
307 	if (!parameter) {
308 		dev_dbg(chip->card->dev,
309 			"dsp_spos: module got no parameter segment\n");
310 		return 0;
311 	}
312 
313 	doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
314 	dsize   = parameter->size * 4;
315 
316 	dev_dbg(chip->card->dev,
317 		"dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
318 		    doffset,doffset + dsize);
319 	if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
320 		dev_err(chip->card->dev,
321 			"dsp_spos: failed to download parameter data to DSP\n");
322 		return -EINVAL;
323 	}
324 	return 0;
325 }
326 
327 static int dsp_load_sample(struct snd_cs46xx *chip,
328 			   struct dsp_segment_desc *sample)
329 {
330 	u32 doffset, dsize;
331 
332 	if (!sample) {
333 		dev_dbg(chip->card->dev,
334 			"dsp_spos: module got no sample segment\n");
335 		return 0;
336 	}
337 
338 	doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
339 	dsize   =  sample->size * 4;
340 
341 	dev_dbg(chip->card->dev,
342 		"dsp_spos: downloading sample data to chip (%08x-%08x)\n",
343 		    doffset,doffset + dsize);
344 
345 	if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
346 		dev_err(chip->card->dev,
347 			"dsp_spos: failed to sample data to DSP\n");
348 		return -EINVAL;
349 	}
350 	return 0;
351 }
352 
353 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
354 {
355 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
356 	struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
357 	u32 doffset, dsize;
358 	int err;
359 
360 	if (ins->nmodules == DSP_MAX_MODULES - 1) {
361 		dev_err(chip->card->dev,
362 			"dsp_spos: to many modules loaded into DSP\n");
363 		return -ENOMEM;
364 	}
365 
366 	dev_dbg(chip->card->dev,
367 		"dsp_spos: loading module %s into DSP\n", module->module_name);
368 
369 	if (ins->nmodules == 0) {
370 		dev_dbg(chip->card->dev, "dsp_spos: clearing parameter area\n");
371 		snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
372 	}
373 
374 	err = dsp_load_parameter(chip, get_segment_desc(module,
375 							SEGTYPE_SP_PARAMETER));
376 	if (err < 0)
377 		return err;
378 
379 	if (ins->nmodules == 0) {
380 		dev_dbg(chip->card->dev, "dsp_spos: clearing sample area\n");
381 		snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
382 	}
383 
384 	err = dsp_load_sample(chip, get_segment_desc(module,
385 						     SEGTYPE_SP_SAMPLE));
386 	if (err < 0)
387 		return err;
388 
389 	if (ins->nmodules == 0) {
390 		dev_dbg(chip->card->dev, "dsp_spos: clearing code area\n");
391 		snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
392 	}
393 
394 	if (code == NULL) {
395 		dev_dbg(chip->card->dev,
396 			"dsp_spos: module got no code segment\n");
397 	} else {
398 		if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {
399 			dev_err(chip->card->dev,
400 				"dsp_spos: no space available in DSP\n");
401 			return -ENOMEM;
402 		}
403 
404 		module->load_address = ins->code.offset;
405 		module->overlay_begin_address = 0x000;
406 
407 		/* if module has a code segment it must have
408 		   symbol table */
409 		if (snd_BUG_ON(!module->symbol_table.symbols))
410 			return -ENOMEM;
411 		if (add_symbols(chip,module)) {
412 			dev_err(chip->card->dev,
413 				"dsp_spos: failed to load symbol table\n");
414 			return -ENOMEM;
415 		}
416 
417 		doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);
418 		dsize   = code->size * 4;
419 		dev_dbg(chip->card->dev,
420 			"dsp_spos: downloading code to chip (%08x-%08x)\n",
421 			    doffset,doffset + dsize);
422 
423 		module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);
424 
425 		if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {
426 			dev_err(chip->card->dev,
427 				"dsp_spos: failed to download code to DSP\n");
428 			return -EINVAL;
429 		}
430 
431 		ins->code.offset += code->size;
432 	}
433 
434 	/* NOTE: module segments and symbol table must be
435 	   statically allocated. Case that module data is
436 	   not generated by the ospparser */
437 	ins->modules[ins->nmodules] = *module;
438 	ins->nmodules++;
439 
440 	return 0;
441 }
442 
443 struct dsp_symbol_entry *
444 cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, int symbol_type)
445 {
446 	int i;
447 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
448 
449 	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
450 
451 		if (ins->symbol_table.symbols[i].deleted)
452 			continue;
453 
454 		if (!strcmp(ins->symbol_table.symbols[i].symbol_name,symbol_name) &&
455 		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
456 			return (ins->symbol_table.symbols + i);
457 		}
458 	}
459 
460 #if 0
461 	dev_err(chip->card->dev, "dsp_spos: symbol <%s> type %02x not found\n",
462 		symbol_name,symbol_type);
463 #endif
464 
465 	return NULL;
466 }
467 
468 
469 #ifdef CONFIG_SND_PROC_FS
470 static struct dsp_symbol_entry *
471 cs46xx_dsp_lookup_symbol_addr (struct snd_cs46xx * chip, u32 address, int symbol_type)
472 {
473 	int i;
474 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
475 
476 	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
477 
478 		if (ins->symbol_table.symbols[i].deleted)
479 			continue;
480 
481 		if (ins->symbol_table.symbols[i].address == address &&
482 		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
483 			return (ins->symbol_table.symbols + i);
484 		}
485 	}
486 
487 
488 	return NULL;
489 }
490 
491 
492 static void cs46xx_dsp_proc_symbol_table_read (struct snd_info_entry *entry,
493 					       struct snd_info_buffer *buffer)
494 {
495 	struct snd_cs46xx *chip = entry->private_data;
496 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
497 	int i;
498 
499 	snd_iprintf(buffer, "SYMBOLS:\n");
500 	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
501 		char *module_str = "system";
502 
503 		if (ins->symbol_table.symbols[i].deleted)
504 			continue;
505 
506 		if (ins->symbol_table.symbols[i].module != NULL) {
507 			module_str = ins->symbol_table.symbols[i].module->module_name;
508 		}
509 
510 
511 		snd_iprintf(buffer, "%04X <%02X> %s [%s]\n",
512 			    ins->symbol_table.symbols[i].address,
513 			    ins->symbol_table.symbols[i].symbol_type,
514 			    ins->symbol_table.symbols[i].symbol_name,
515 			    module_str);
516 	}
517 }
518 
519 
520 static void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry,
521 					  struct snd_info_buffer *buffer)
522 {
523 	struct snd_cs46xx *chip = entry->private_data;
524 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
525 	int i,j;
526 
527 	guard(mutex)(&chip->spos_mutex);
528 	snd_iprintf(buffer, "MODULES:\n");
529 	for ( i = 0; i < ins->nmodules; ++i ) {
530 		snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
531 		snd_iprintf(buffer, "   %d symbols\n", ins->modules[i].symbol_table.nsymbols);
532 		snd_iprintf(buffer, "   %d fixups\n", ins->modules[i].nfixups);
533 
534 		for (j = 0; j < ins->modules[i].nsegments; ++ j) {
535 			struct dsp_segment_desc * desc = (ins->modules[i].segments + j);
536 			snd_iprintf(buffer, "   segment %02x offset %08x size %08x\n",
537 				    desc->segment_type,desc->offset, desc->size);
538 		}
539 	}
540 }
541 
542 static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
543 					    struct snd_info_buffer *buffer)
544 {
545 	struct snd_cs46xx *chip = entry->private_data;
546 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
547 	int i, j, col;
548 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
549 
550 	guard(mutex)(&chip->spos_mutex);
551 	snd_iprintf(buffer, "TASK TREES:\n");
552 	for ( i = 0; i < ins->ntask; ++i) {
553 		snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
554 
555 		for (col = 0,j = 0;j < ins->tasks[i].size; j++,col++) {
556 			u32 val;
557 			if (col == 4) {
558 				snd_iprintf(buffer,"\n");
559 				col = 0;
560 			}
561 			val = readl(dst + (ins->tasks[i].address + j) * sizeof(u32));
562 			snd_iprintf(buffer,"%08x ",val);
563 		}
564 	}
565 
566 	snd_iprintf(buffer,"\n");
567 }
568 
569 static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
570 				      struct snd_info_buffer *buffer)
571 {
572 	struct snd_cs46xx *chip = entry->private_data;
573 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
574 	int i;
575 
576 	guard(mutex)(&chip->spos_mutex);
577 	snd_iprintf(buffer, "SCB's:\n");
578 	for ( i = 0; i < ins->nscb; ++i) {
579 		if (ins->scbs[i].deleted)
580 			continue;
581 		snd_iprintf(buffer,"\n%04x %s:\n\n",ins->scbs[i].address,ins->scbs[i].scb_name);
582 
583 		if (ins->scbs[i].parent_scb_ptr != NULL) {
584 			snd_iprintf(buffer,"parent [%s:%04x] ",
585 				    ins->scbs[i].parent_scb_ptr->scb_name,
586 				    ins->scbs[i].parent_scb_ptr->address);
587 		} else snd_iprintf(buffer,"parent [none] ");
588 
589 		snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
590 			    ins->scbs[i].sub_list_ptr->scb_name,
591 			    ins->scbs[i].sub_list_ptr->address,
592 			    ins->scbs[i].next_scb_ptr->scb_name,
593 			    ins->scbs[i].next_scb_ptr->address,
594 			    ins->scbs[i].task_entry->symbol_name,
595 			    ins->scbs[i].task_entry->address);
596 	}
597 
598 	snd_iprintf(buffer,"\n");
599 }
600 
601 static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry,
602 						 struct snd_info_buffer *buffer)
603 {
604 	struct snd_cs46xx *chip = entry->private_data;
605 	/*struct dsp_spos_instance * ins = chip->dsp_spos_instance; */
606 	unsigned int i, col = 0;
607 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
608 	struct dsp_symbol_entry * symbol;
609 
610 	for (i = 0;i < DSP_PARAMETER_BYTE_SIZE; i += sizeof(u32),col ++) {
611 		if (col == 4) {
612 			snd_iprintf(buffer,"\n");
613 			col = 0;
614 		}
615 
616 		symbol = cs46xx_dsp_lookup_symbol_addr(chip, i / sizeof(u32), SYMBOL_PARAMETER);
617 		if (symbol) {
618 			col = 0;
619 			snd_iprintf (buffer,"\n%s:\n",symbol->symbol_name);
620 		}
621 
622 		if (col == 0) {
623 			snd_iprintf(buffer, "%04X ", i / (unsigned int)sizeof(u32));
624 		}
625 
626 		snd_iprintf(buffer,"%08X ",readl(dst + i));
627 	}
628 }
629 
630 static void cs46xx_dsp_proc_sample_dump_read (struct snd_info_entry *entry,
631 					      struct snd_info_buffer *buffer)
632 {
633 	struct snd_cs46xx *chip = entry->private_data;
634 	int i,col = 0;
635 	void __iomem *dst = chip->region.idx[2].remap_addr;
636 
637 	snd_iprintf(buffer,"PCMREADER:\n");
638 	for (i = PCM_READER_BUF1;i < PCM_READER_BUF1 + 0x30; i += sizeof(u32),col ++) {
639 		if (col == 4) {
640 			snd_iprintf(buffer,"\n");
641 			col = 0;
642 		}
643 
644 		if (col == 0) {
645 			snd_iprintf(buffer, "%04X ",i);
646 		}
647 
648 		snd_iprintf(buffer,"%08X ",readl(dst + i));
649 	}
650 
651 	snd_iprintf(buffer,"\nMIX_SAMPLE_BUF1:\n");
652 
653 	col = 0;
654 	for (i = MIX_SAMPLE_BUF1;i < MIX_SAMPLE_BUF1 + 0x40; i += sizeof(u32),col ++) {
655 		if (col == 4) {
656 			snd_iprintf(buffer,"\n");
657 			col = 0;
658 		}
659 
660 		if (col == 0) {
661 			snd_iprintf(buffer, "%04X ",i);
662 		}
663 
664 		snd_iprintf(buffer,"%08X ",readl(dst + i));
665 	}
666 
667 	snd_iprintf(buffer,"\nSRC_TASK_SCB1:\n");
668 	col = 0;
669 	for (i = 0x2480 ; i < 0x2480 + 0x40 ; i += sizeof(u32),col ++) {
670 		if (col == 4) {
671 			snd_iprintf(buffer,"\n");
672 			col = 0;
673 		}
674 
675 		if (col == 0) {
676 			snd_iprintf(buffer, "%04X ",i);
677 		}
678 
679 		snd_iprintf(buffer,"%08X ",readl(dst + i));
680 	}
681 
682 
683 	snd_iprintf(buffer,"\nSPDIFO_BUFFER:\n");
684 	col = 0;
685 	for (i = SPDIFO_IP_OUTPUT_BUFFER1;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x30; i += sizeof(u32),col ++) {
686 		if (col == 4) {
687 			snd_iprintf(buffer,"\n");
688 			col = 0;
689 		}
690 
691 		if (col == 0) {
692 			snd_iprintf(buffer, "%04X ",i);
693 		}
694 
695 		snd_iprintf(buffer,"%08X ",readl(dst + i));
696 	}
697 
698 	snd_iprintf(buffer,"\n...\n");
699 	col = 0;
700 
701 	for (i = SPDIFO_IP_OUTPUT_BUFFER1+0xD0;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x110; i += sizeof(u32),col ++) {
702 		if (col == 4) {
703 			snd_iprintf(buffer,"\n");
704 			col = 0;
705 		}
706 
707 		if (col == 0) {
708 			snd_iprintf(buffer, "%04X ",i);
709 		}
710 
711 		snd_iprintf(buffer,"%08X ",readl(dst + i));
712 	}
713 
714 
715 	snd_iprintf(buffer,"\nOUTPUT_SNOOP:\n");
716 	col = 0;
717 	for (i = OUTPUT_SNOOP_BUFFER;i < OUTPUT_SNOOP_BUFFER + 0x40; i += sizeof(u32),col ++) {
718 		if (col == 4) {
719 			snd_iprintf(buffer,"\n");
720 			col = 0;
721 		}
722 
723 		if (col == 0) {
724 			snd_iprintf(buffer, "%04X ",i);
725 		}
726 
727 		snd_iprintf(buffer,"%08X ",readl(dst + i));
728 	}
729 
730 	snd_iprintf(buffer,"\nCODEC_INPUT_BUF1: \n");
731 	col = 0;
732 	for (i = CODEC_INPUT_BUF1;i < CODEC_INPUT_BUF1 + 0x40; i += sizeof(u32),col ++) {
733 		if (col == 4) {
734 			snd_iprintf(buffer,"\n");
735 			col = 0;
736 		}
737 
738 		if (col == 0) {
739 			snd_iprintf(buffer, "%04X ",i);
740 		}
741 
742 		snd_iprintf(buffer,"%08X ",readl(dst + i));
743 	}
744 #if 0
745 	snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n");
746 	col = 0;
747 	for (i = WRITE_BACK_BUF1;i < WRITE_BACK_BUF1 + 0x40; i += sizeof(u32),col ++) {
748 		if (col == 4) {
749 			snd_iprintf(buffer,"\n");
750 			col = 0;
751 		}
752 
753 		if (col == 0) {
754 			snd_iprintf(buffer, "%04X ",i);
755 		}
756 
757 		snd_iprintf(buffer,"%08X ",readl(dst + i));
758 	}
759 #endif
760 
761 	snd_iprintf(buffer,"\nSPDIFI_IP_OUTPUT_BUFFER1: \n");
762 	col = 0;
763 	for (i = SPDIFI_IP_OUTPUT_BUFFER1;i < SPDIFI_IP_OUTPUT_BUFFER1 + 0x80; i += sizeof(u32),col ++) {
764 		if (col == 4) {
765 			snd_iprintf(buffer,"\n");
766 			col = 0;
767 		}
768 
769 		if (col == 0) {
770 			snd_iprintf(buffer, "%04X ",i);
771 		}
772 
773 		snd_iprintf(buffer,"%08X ",readl(dst + i));
774 	}
775 	snd_iprintf(buffer,"\n");
776 }
777 
778 int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
779 {
780 	struct snd_info_entry *entry;
781 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
782 	int i;
783 
784 	ins->snd_card = card;
785 
786 	entry = snd_info_create_card_entry(card, "dsp", card->proc_root);
787 	if (entry)
788 		entry->mode = S_IFDIR | 0555;
789 	ins->proc_dsp_dir = entry;
790 
791 	if (!ins->proc_dsp_dir)
792 		return -ENOMEM;
793 
794 	entry = snd_info_create_card_entry(card, "spos_symbols",
795 					   ins->proc_dsp_dir);
796 	if (entry)
797 		snd_info_set_text_ops(entry, chip,
798 				      cs46xx_dsp_proc_symbol_table_read);
799 
800 	entry = snd_info_create_card_entry(card, "spos_modules",
801 					   ins->proc_dsp_dir);
802 	if (entry)
803 		snd_info_set_text_ops(entry, chip,
804 				      cs46xx_dsp_proc_modules_read);
805 
806 	entry = snd_info_create_card_entry(card, "parameter",
807 					   ins->proc_dsp_dir);
808 	if (entry)
809 		snd_info_set_text_ops(entry, chip,
810 				      cs46xx_dsp_proc_parameter_dump_read);
811 
812 	entry = snd_info_create_card_entry(card, "sample",
813 					   ins->proc_dsp_dir);
814 	if (entry)
815 		snd_info_set_text_ops(entry, chip,
816 				      cs46xx_dsp_proc_sample_dump_read);
817 
818 	entry = snd_info_create_card_entry(card, "task_tree",
819 					   ins->proc_dsp_dir);
820 	if (entry)
821 		snd_info_set_text_ops(entry, chip,
822 				      cs46xx_dsp_proc_task_tree_read);
823 
824 	entry = snd_info_create_card_entry(card, "scb_info",
825 					   ins->proc_dsp_dir);
826 	if (entry)
827 		snd_info_set_text_ops(entry, chip,
828 				      cs46xx_dsp_proc_scb_read);
829 
830 	guard(mutex)(&chip->spos_mutex);
831 	/* register/update SCB's entries on proc */
832 	for (i = 0; i < ins->nscb; ++i) {
833 		if (ins->scbs[i].deleted) continue;
834 
835 		cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
836 	}
837 
838 	return 0;
839 }
840 
841 int cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
842 {
843 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
844 	int i;
845 
846 	if (!ins)
847 		return 0;
848 
849 	scoped_guard(mutex, &chip->spos_mutex) {
850 		for (i = 0; i < ins->nscb; ++i) {
851 			if (ins->scbs[i].deleted)
852 				continue;
853 			cs46xx_dsp_proc_free_scb_desc((ins->scbs + i));
854 		}
855 	}
856 
857 	snd_info_free_entry(ins->proc_dsp_dir);
858 	ins->proc_dsp_dir = NULL;
859 
860 	return 0;
861 }
862 #endif /* CONFIG_SND_PROC_FS */
863 
864 static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data,
865 				   u32  dest, int size)
866 {
867 	void __iomem *spdst = chip->region.idx[1].remap_addr +
868 		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
869 	int i;
870 
871 	for (i = 0; i < size; ++i) {
872 		dev_dbg(chip->card->dev, "addr %p, val %08x\n",
873 			spdst, task_data[i]);
874 		writel(task_data[i],spdst);
875 		spdst += sizeof(u32);
876 	}
877 }
878 
879 static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest)
880 {
881 	void __iomem *spdst = chip->region.idx[1].remap_addr +
882 		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
883 	int i;
884 
885 	for (i = 0; i < 0x10; ++i) {
886 		dev_dbg(chip->card->dev, "addr %p, val %08x\n",
887 			spdst, scb_data[i]);
888 		writel(scb_data[i],spdst);
889 		spdst += sizeof(u32);
890 	}
891 }
892 
893 static int find_free_scb_index (struct dsp_spos_instance * ins)
894 {
895 	int index = ins->nscb, i;
896 
897 	for (i = ins->scb_highest_frag_index; i < ins->nscb; ++i) {
898 		if (ins->scbs[i].deleted) {
899 			index = i;
900 			break;
901 		}
902 	}
903 
904 	return index;
905 }
906 
907 static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * name, u32 dest)
908 {
909 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
910 	struct dsp_scb_descriptor * desc = NULL;
911 	int index;
912 
913 	if (ins->nscb == DSP_MAX_SCB_DESC - 1) {
914 		dev_err(chip->card->dev,
915 			"dsp_spos: got no place for other SCB\n");
916 		return NULL;
917 	}
918 
919 	index = find_free_scb_index (ins);
920 
921 	memset(&ins->scbs[index], 0, sizeof(ins->scbs[index]));
922 	strscpy(ins->scbs[index].scb_name, name);
923 	ins->scbs[index].address = dest;
924 	ins->scbs[index].index = index;
925 	ins->scbs[index].ref_count = 1;
926 
927 	desc = (ins->scbs + index);
928 	ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
929 
930 	if (index > ins->scb_highest_frag_index)
931 		ins->scb_highest_frag_index = index;
932 
933 	if (index == ins->nscb)
934 		ins->nscb++;
935 
936 	return desc;
937 }
938 
939 static struct dsp_task_descriptor *
940 _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
941 {
942 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
943 	struct dsp_task_descriptor * desc = NULL;
944 
945 	if (ins->ntask == DSP_MAX_TASK_DESC - 1) {
946 		dev_err(chip->card->dev,
947 			"dsp_spos: got no place for other TASK\n");
948 		return NULL;
949 	}
950 
951 	if (name)
952 		strscpy(ins->tasks[ins->ntask].task_name, name);
953 	else
954 		strscpy(ins->tasks[ins->ntask].task_name, "(NULL)");
955 	ins->tasks[ins->ntask].address = dest;
956 	ins->tasks[ins->ntask].size = size;
957 
958 	/* quick find in list */
959 	ins->tasks[ins->ntask].index = ins->ntask;
960 	desc = (ins->tasks + ins->ntask);
961 	ins->ntask++;
962 
963 	if (name)
964 		add_symbol (chip,name,dest,SYMBOL_PARAMETER);
965 	return desc;
966 }
967 
968 #define SCB_BYTES	(0x10 * 4)
969 
970 struct dsp_scb_descriptor *
971 cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest)
972 {
973 	struct dsp_scb_descriptor * desc;
974 
975 #ifdef CONFIG_PM_SLEEP
976 	/* copy the data for resume */
977 	scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
978 	if (!scb_data)
979 		return NULL;
980 #endif
981 
982 	desc = _map_scb (chip,name,dest);
983 	if (desc) {
984 		desc->data = scb_data;
985 		_dsp_create_scb(chip,scb_data,dest);
986 	} else {
987 		dev_err(chip->card->dev, "dsp_spos: failed to map SCB\n");
988 #ifdef CONFIG_PM_SLEEP
989 		kfree(scb_data);
990 #endif
991 	}
992 
993 	return desc;
994 }
995 
996 
997 static struct dsp_task_descriptor *
998 cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_data,
999 			     u32 dest, int size)
1000 {
1001 	struct dsp_task_descriptor * desc;
1002 
1003 	desc = _map_task_tree (chip,name,dest,size);
1004 	if (desc) {
1005 		desc->data = task_data;
1006 		_dsp_create_task_tree(chip,task_data,dest,size);
1007 	} else {
1008 		dev_err(chip->card->dev, "dsp_spos: failed to map TASK\n");
1009 	}
1010 
1011 	return desc;
1012 }
1013 
1014 int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
1015 {
1016 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1017 	struct dsp_symbol_entry * fg_task_tree_header_code;
1018 	struct dsp_symbol_entry * task_tree_header_code;
1019 	struct dsp_symbol_entry * task_tree_thread;
1020 	struct dsp_symbol_entry * null_algorithm;
1021 	struct dsp_symbol_entry * magic_snoop_task;
1022 
1023 	struct dsp_scb_descriptor * timing_master_scb;
1024 	struct dsp_scb_descriptor * codec_out_scb;
1025 	struct dsp_scb_descriptor * codec_in_scb;
1026 	struct dsp_scb_descriptor * src_task_scb;
1027 	struct dsp_scb_descriptor * master_mix_scb;
1028 	struct dsp_scb_descriptor * rear_mix_scb;
1029 	struct dsp_scb_descriptor * record_mix_scb;
1030 	struct dsp_scb_descriptor * write_back_scb;
1031 	struct dsp_scb_descriptor * vari_decimate_scb;
1032 	struct dsp_scb_descriptor * rear_codec_out_scb;
1033 	struct dsp_scb_descriptor * clfe_codec_out_scb;
1034 	struct dsp_scb_descriptor * magic_snoop_scb;
1035 
1036 	int fifo_addr, fifo_span, valid_slots;
1037 
1038 	static const struct dsp_spos_control_block sposcb = {
1039 		/* 0 */ HFG_TREE_SCB,HFG_STACK,
1040 		/* 1 */ SPOSCB_ADDR,BG_TREE_SCB_ADDR,
1041 		/* 2 */ DSP_SPOS_DC,0,
1042 		/* 3 */ DSP_SPOS_DC,DSP_SPOS_DC,
1043 		/* 4 */ 0,0,
1044 		/* 5 */ DSP_SPOS_UU,0,
1045 		/* 6 */ FG_TASK_HEADER_ADDR,0,
1046 		/* 7 */ 0,0,
1047 		/* 8 */ DSP_SPOS_UU,DSP_SPOS_DC,
1048 		/* 9 */ 0,
1049 		/* A */ 0,HFG_FIRST_EXECUTE_MODE,
1050 		/* B */ DSP_SPOS_UU,DSP_SPOS_UU,
1051 		/* C */ DSP_SPOS_DC_DC,
1052 		/* D */ DSP_SPOS_DC_DC,
1053 		/* E */ DSP_SPOS_DC_DC,
1054 		/* F */ DSP_SPOS_DC_DC
1055 	};
1056 
1057 	cs46xx_dsp_create_task_tree(chip, "sposCB", (u32 *)&sposcb, SPOSCB_ADDR, 0x10);
1058 
1059 	null_algorithm  = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE);
1060 	if (null_algorithm == NULL) {
1061 		dev_err(chip->card->dev,
1062 			"dsp_spos: symbol NULLALGORITHM not found\n");
1063 		return -EIO;
1064 	}
1065 
1066 	fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE);
1067 	if (fg_task_tree_header_code == NULL) {
1068 		dev_err(chip->card->dev,
1069 			"dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
1070 		return -EIO;
1071 	}
1072 
1073 	task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE);
1074 	if (task_tree_header_code == NULL) {
1075 		dev_err(chip->card->dev,
1076 			"dsp_spos: symbol TASKTREEHEADERCODE not found\n");
1077 		return -EIO;
1078 	}
1079 
1080 	task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE);
1081 	if (task_tree_thread == NULL) {
1082 		dev_err(chip->card->dev,
1083 			"dsp_spos: symbol TASKTREETHREAD not found\n");
1084 		return -EIO;
1085 	}
1086 
1087 	magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE);
1088 	if (magic_snoop_task == NULL) {
1089 		dev_err(chip->card->dev,
1090 			"dsp_spos: symbol MAGICSNOOPTASK not found\n");
1091 		return -EIO;
1092 	}
1093 
1094 	{
1095 		/* create the null SCB */
1096 		static struct dsp_generic_scb null_scb = {
1097 			{ 0, 0, 0, 0 },
1098 			{ 0, 0, 0, 0, 0 },
1099 			NULL_SCB_ADDR, NULL_SCB_ADDR,
1100 			0, 0, 0, 0, 0,
1101 			{
1102 				0,0,
1103 				0,0,
1104 			}
1105 		};
1106 
1107 		null_scb.entry_point = null_algorithm->address;
1108 		ins->the_null_scb = cs46xx_dsp_create_scb(chip, "nullSCB", (u32 *)&null_scb, NULL_SCB_ADDR);
1109 		ins->the_null_scb->task_entry = null_algorithm;
1110 		ins->the_null_scb->sub_list_ptr = ins->the_null_scb;
1111 		ins->the_null_scb->next_scb_ptr = ins->the_null_scb;
1112 		ins->the_null_scb->parent_scb_ptr = NULL;
1113 		cs46xx_dsp_proc_register_scb_desc (chip,ins->the_null_scb);
1114 	}
1115 
1116 	{
1117 		/* setup foreground task tree */
1118 		static struct dsp_task_tree_control_block fg_task_tree_hdr =  {
1119 			{ FG_TASK_HEADER_ADDR | (DSP_SPOS_DC << 0x10),
1120 			  DSP_SPOS_DC_DC,
1121 			  DSP_SPOS_DC_DC,
1122 			  0x0000,DSP_SPOS_DC,
1123 			  DSP_SPOS_DC, DSP_SPOS_DC,
1124 			  DSP_SPOS_DC_DC,
1125 			  DSP_SPOS_DC_DC,
1126 			  DSP_SPOS_DC_DC,
1127 			  DSP_SPOS_DC,DSP_SPOS_DC },
1128 
1129 			{
1130 				BG_TREE_SCB_ADDR,TIMINGMASTER_SCB_ADDR,
1131 				0,
1132 				FG_TASK_HEADER_ADDR + TCBData,
1133 			},
1134 
1135 			{
1136 				4,0,
1137 				1,0,
1138 				2,SPOSCB_ADDR + HFGFlags,
1139 				0,0,
1140 				FG_TASK_HEADER_ADDR + TCBContextBlk,FG_STACK
1141 			},
1142 
1143 			{
1144 				DSP_SPOS_DC,0,
1145 				DSP_SPOS_DC,DSP_SPOS_DC,
1146 				DSP_SPOS_DC,DSP_SPOS_DC,
1147 				DSP_SPOS_DC,DSP_SPOS_DC,
1148 				DSP_SPOS_DC,DSP_SPOS_DC,
1149 				DSP_SPOS_DCDC,
1150 				DSP_SPOS_UU,1,
1151 				DSP_SPOS_DCDC,
1152 				DSP_SPOS_DCDC,
1153 				DSP_SPOS_DCDC,
1154 				DSP_SPOS_DCDC,
1155 				DSP_SPOS_DCDC,
1156 				DSP_SPOS_DCDC,
1157 				DSP_SPOS_DCDC,
1158 				DSP_SPOS_DCDC,
1159 				DSP_SPOS_DCDC,
1160 				DSP_SPOS_DCDC,
1161 				DSP_SPOS_DCDC,
1162 				DSP_SPOS_DCDC,
1163 				DSP_SPOS_DCDC,
1164 				DSP_SPOS_DCDC,
1165 				DSP_SPOS_DCDC,
1166 				DSP_SPOS_DCDC,
1167 				DSP_SPOS_DCDC,
1168 				DSP_SPOS_DCDC,
1169 				DSP_SPOS_DCDC,
1170 				DSP_SPOS_DCDC,
1171 				DSP_SPOS_DCDC,
1172 				DSP_SPOS_DCDC,
1173 				DSP_SPOS_DCDC,
1174 				DSP_SPOS_DCDC,
1175 				DSP_SPOS_DCDC,
1176 				DSP_SPOS_DCDC,
1177 				DSP_SPOS_DCDC,
1178 				DSP_SPOS_DCDC
1179 			},
1180 			{
1181 				FG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
1182 				0,0
1183 			}
1184 		};
1185 
1186 		fg_task_tree_hdr.links.entry_point = fg_task_tree_header_code->address;
1187 		fg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
1188 		cs46xx_dsp_create_task_tree(chip,"FGtaskTreeHdr",(u32 *)&fg_task_tree_hdr,FG_TASK_HEADER_ADDR,0x35);
1189 	}
1190 
1191 
1192 	{
1193 		/* setup foreground task tree */
1194 		static struct dsp_task_tree_control_block bg_task_tree_hdr =  {
1195 			{ DSP_SPOS_DC_DC,
1196 			  DSP_SPOS_DC_DC,
1197 			  DSP_SPOS_DC_DC,
1198 			  DSP_SPOS_DC, DSP_SPOS_DC,
1199 			  DSP_SPOS_DC, DSP_SPOS_DC,
1200 			  DSP_SPOS_DC_DC,
1201 			  DSP_SPOS_DC_DC,
1202 			  DSP_SPOS_DC_DC,
1203 			  DSP_SPOS_DC,DSP_SPOS_DC },
1204 
1205 			{
1206 				NULL_SCB_ADDR,NULL_SCB_ADDR,  /* Set up the background to do nothing */
1207 				0,
1208 				BG_TREE_SCB_ADDR + TCBData,
1209 			},
1210 
1211 			{
1212 				9999,0,
1213 				0,1,
1214 				0,SPOSCB_ADDR + HFGFlags,
1215 				0,0,
1216 				BG_TREE_SCB_ADDR + TCBContextBlk,BG_STACK
1217 			},
1218 
1219 			{
1220 				DSP_SPOS_DC,0,
1221 				DSP_SPOS_DC,DSP_SPOS_DC,
1222 				DSP_SPOS_DC,DSP_SPOS_DC,
1223 				DSP_SPOS_DC,DSP_SPOS_DC,
1224 				DSP_SPOS_DC,DSP_SPOS_DC,
1225 				DSP_SPOS_DCDC,
1226 				DSP_SPOS_UU,1,
1227 				DSP_SPOS_DCDC,
1228 				DSP_SPOS_DCDC,
1229 				DSP_SPOS_DCDC,
1230 				DSP_SPOS_DCDC,
1231 				DSP_SPOS_DCDC,
1232 				DSP_SPOS_DCDC,
1233 				DSP_SPOS_DCDC,
1234 				DSP_SPOS_DCDC,
1235 				DSP_SPOS_DCDC,
1236 				DSP_SPOS_DCDC,
1237 				DSP_SPOS_DCDC,
1238 				DSP_SPOS_DCDC,
1239 				DSP_SPOS_DCDC,
1240 				DSP_SPOS_DCDC,
1241 				DSP_SPOS_DCDC,
1242 				DSP_SPOS_DCDC,
1243 				DSP_SPOS_DCDC,
1244 				DSP_SPOS_DCDC,
1245 				DSP_SPOS_DCDC,
1246 				DSP_SPOS_DCDC,
1247 				DSP_SPOS_DCDC,
1248 				DSP_SPOS_DCDC,
1249 				DSP_SPOS_DCDC,
1250 				DSP_SPOS_DCDC,
1251 				DSP_SPOS_DCDC,
1252 				DSP_SPOS_DCDC,
1253 				DSP_SPOS_DCDC,
1254 				DSP_SPOS_DCDC
1255 			},
1256 			{
1257 				BG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
1258 				0,0
1259 			}
1260 		};
1261 
1262 		bg_task_tree_hdr.links.entry_point = task_tree_header_code->address;
1263 		bg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
1264 		cs46xx_dsp_create_task_tree(chip,"BGtaskTreeHdr",(u32 *)&bg_task_tree_hdr,BG_TREE_SCB_ADDR,0x35);
1265 	}
1266 
1267 	/* create timing master SCB */
1268 	timing_master_scb = cs46xx_dsp_create_timing_master_scb(chip);
1269 
1270 	/* create the CODEC output task */
1271 	codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_I",0x0010,0x0000,
1272 							MASTERMIX_SCB_ADDR,
1273 							CODECOUT_SCB_ADDR,timing_master_scb,
1274 							SCB_ON_PARENT_SUBLIST_SCB);
1275 
1276 	if (!codec_out_scb) goto _fail_end;
1277 	/* create the master mix SCB */
1278 	master_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"MasterMixSCB",
1279 							MIX_SAMPLE_BUF1,MASTERMIX_SCB_ADDR,
1280 							codec_out_scb,
1281 							SCB_ON_PARENT_SUBLIST_SCB);
1282 	ins->master_mix_scb = master_mix_scb;
1283 
1284 	if (!master_mix_scb) goto _fail_end;
1285 
1286 	/* create codec in */
1287 	codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0,
1288 						      CODEC_INPUT_BUF1,
1289 						      CODECIN_SCB_ADDR,codec_out_scb,
1290 						      SCB_ON_PARENT_NEXT_SCB);
1291 	if (!codec_in_scb) goto _fail_end;
1292 	ins->codec_in_scb = codec_in_scb;
1293 
1294 	/* create write back scb */
1295 	write_back_scb = cs46xx_dsp_create_mix_to_ostream_scb(chip,"WriteBackSCB",
1296 							      WRITE_BACK_BUF1,WRITE_BACK_SPB,
1297 							      WRITEBACK_SCB_ADDR,
1298 							      timing_master_scb,
1299 							      SCB_ON_PARENT_NEXT_SCB);
1300 	if (!write_back_scb) goto _fail_end;
1301 
1302 	{
1303 		static struct dsp_mix2_ostream_spb mix2_ostream_spb = {
1304 			0x00020000,
1305 			0x0000ffff
1306 		};
1307 
1308 		if (!cs46xx_dsp_create_task_tree(chip, NULL,
1309 						 (u32 *)&mix2_ostream_spb,
1310 						 WRITE_BACK_SPB, 2))
1311 			goto _fail_end;
1312 	}
1313 
1314 	/* input sample converter */
1315 	vari_decimate_scb = cs46xx_dsp_create_vari_decimate_scb(chip,"VariDecimateSCB",
1316 								VARI_DECIMATE_BUF0,
1317 								VARI_DECIMATE_BUF1,
1318 								VARIDECIMATE_SCB_ADDR,
1319 								write_back_scb,
1320 								SCB_ON_PARENT_SUBLIST_SCB);
1321 	if (!vari_decimate_scb) goto _fail_end;
1322 
1323 	/* create the record mixer SCB */
1324 	record_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RecordMixerSCB",
1325 							MIX_SAMPLE_BUF2,
1326 							RECORD_MIXER_SCB_ADDR,
1327 							vari_decimate_scb,
1328 							SCB_ON_PARENT_SUBLIST_SCB);
1329 	ins->record_mixer_scb = record_mix_scb;
1330 
1331 	if (!record_mix_scb) goto _fail_end;
1332 
1333 	valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
1334 
1335 	if (snd_BUG_ON(chip->nr_ac97_codecs != 1 && chip->nr_ac97_codecs != 2))
1336 		goto _fail_end;
1337 
1338 	if (chip->nr_ac97_codecs == 1) {
1339 		/* output on slot 5 and 11
1340 		   on primary CODEC */
1341 		fifo_addr = 0x20;
1342 		fifo_span = 0x60;
1343 
1344 		/* enable slot 5 and 11 */
1345 		valid_slots |= ACOSV_SLV5 | ACOSV_SLV11;
1346 	} else {
1347 		/* output on slot 7 and 8
1348 		   on secondary CODEC */
1349 		fifo_addr = 0x40;
1350 		fifo_span = 0x10;
1351 
1352 		/* enable slot 7 and 8 */
1353 		valid_slots |= ACOSV_SLV7 | ACOSV_SLV8;
1354 	}
1355 	/* create CODEC tasklet for rear speakers output*/
1356 	rear_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_Rear",fifo_span,fifo_addr,
1357 							     REAR_MIXER_SCB_ADDR,
1358 							     REAR_CODECOUT_SCB_ADDR,codec_in_scb,
1359 							     SCB_ON_PARENT_NEXT_SCB);
1360 	if (!rear_codec_out_scb) goto _fail_end;
1361 
1362 
1363 	/* create the rear PCM channel  mixer SCB */
1364 	rear_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RearMixerSCB",
1365 						      MIX_SAMPLE_BUF3,
1366 						      REAR_MIXER_SCB_ADDR,
1367 						      rear_codec_out_scb,
1368 						      SCB_ON_PARENT_SUBLIST_SCB);
1369 	ins->rear_mix_scb = rear_mix_scb;
1370 	if (!rear_mix_scb) goto _fail_end;
1371 
1372 	if (chip->nr_ac97_codecs == 2) {
1373 		/* create CODEC tasklet for rear Center/LFE output
1374 		   slot 6 and 9 on secondary CODEC */
1375 		clfe_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_CLFE",0x0030,0x0030,
1376 								     CLFE_MIXER_SCB_ADDR,
1377 								     CLFE_CODEC_SCB_ADDR,
1378 								     rear_codec_out_scb,
1379 								     SCB_ON_PARENT_NEXT_SCB);
1380 		if (!clfe_codec_out_scb) goto _fail_end;
1381 
1382 
1383 		/* create the rear PCM channel  mixer SCB */
1384 		ins->center_lfe_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"CLFEMixerSCB",
1385 									 MIX_SAMPLE_BUF4,
1386 									 CLFE_MIXER_SCB_ADDR,
1387 									 clfe_codec_out_scb,
1388 									 SCB_ON_PARENT_SUBLIST_SCB);
1389 		if (!ins->center_lfe_mix_scb) goto _fail_end;
1390 
1391 		/* enable slot 6 and 9 */
1392 		valid_slots |= ACOSV_SLV6 | ACOSV_SLV9;
1393 	} else {
1394 		clfe_codec_out_scb = rear_codec_out_scb;
1395 		ins->center_lfe_mix_scb = rear_mix_scb;
1396 	}
1397 
1398 	/* enable slots depending on CODEC configuration */
1399 	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
1400 
1401 	/* the magic snooper */
1402 	magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR,
1403 							     OUTPUT_SNOOP_BUFFER,
1404 							     codec_out_scb,
1405 							     clfe_codec_out_scb,
1406 							     SCB_ON_PARENT_NEXT_SCB);
1407 
1408 
1409 	if (!magic_snoop_scb) goto _fail_end;
1410 	ins->ref_snoop_scb = magic_snoop_scb;
1411 
1412 	/* SP IO access */
1413 	if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR,
1414 					      magic_snoop_scb,
1415 					      SCB_ON_PARENT_NEXT_SCB))
1416 		goto _fail_end;
1417 
1418 	/* SPDIF input sampel rate converter */
1419 	src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
1420 						      ins->spdif_in_sample_rate,
1421 						      SRC_OUTPUT_BUF1,
1422 						      SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
1423 						      master_mix_scb,
1424 						      SCB_ON_PARENT_SUBLIST_SCB,1);
1425 
1426 	if (!src_task_scb) goto _fail_end;
1427 	cs46xx_src_unlink(chip,src_task_scb);
1428 
1429 	/* NOTE: when we now how to detect the SPDIF input
1430 	   sample rate we will use this SRC to adjust it */
1431 	ins->spdif_in_src = src_task_scb;
1432 
1433 	cs46xx_dsp_async_init(chip,timing_master_scb);
1434 	return 0;
1435 
1436  _fail_end:
1437 	dev_err(chip->card->dev, "dsp_spos: failed to setup SCB's in DSP\n");
1438 	return -EINVAL;
1439 }
1440 
1441 static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
1442 				  struct dsp_scb_descriptor * fg_entry)
1443 {
1444 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1445 	struct dsp_symbol_entry * s16_async_codec_input_task;
1446 	struct dsp_symbol_entry * spdifo_task;
1447 	struct dsp_symbol_entry * spdifi_task;
1448 	struct dsp_scb_descriptor * spdifi_scb_desc, * spdifo_scb_desc, * async_codec_scb_desc;
1449 
1450 	s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE);
1451 	if (s16_async_codec_input_task == NULL) {
1452 		dev_err(chip->card->dev,
1453 			"dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
1454 		return -EIO;
1455 	}
1456 	spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE);
1457 	if (spdifo_task == NULL) {
1458 		dev_err(chip->card->dev,
1459 			"dsp_spos: symbol SPDIFOTASK not found\n");
1460 		return -EIO;
1461 	}
1462 
1463 	spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE);
1464 	if (spdifi_task == NULL) {
1465 		dev_err(chip->card->dev,
1466 			"dsp_spos: symbol SPDIFITASK not found\n");
1467 		return -EIO;
1468 	}
1469 
1470 	{
1471 		/* 0xBC0 */
1472 		struct dsp_spdifoscb spdifo_scb = {
1473 			/* 0 */ DSP_SPOS_UUUU,
1474 			{
1475 				/* 1 */ 0xb0,
1476 				/* 2 */ 0,
1477 				/* 3 */ 0,
1478 				/* 4 */ 0,
1479 			},
1480 			/* NOTE: the SPDIF output task read samples in mono
1481 			   format, the AsynchFGTxSCB task writes to buffer
1482 			   in stereo format
1483 			*/
1484 			/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_256,
1485 			/* 6 */ ( SPDIFO_IP_OUTPUT_BUFFER1 << 0x10 )  |  0xFFFC,
1486 			/* 7 */ 0,0,
1487 			/* 8 */ 0,
1488 			/* 9 */ FG_TASK_HEADER_ADDR, NULL_SCB_ADDR,
1489 			/* A */ spdifo_task->address,
1490 			SPDIFO_SCB_INST + SPDIFOFIFOPointer,
1491 			{
1492 				/* B */ 0x0040, /*DSP_SPOS_UUUU,*/
1493 				/* C */ 0x20ff, /*DSP_SPOS_UUUU,*/
1494 			},
1495 			/* D */ 0x804c,0,							  /* SPDIFOFIFOPointer:SPDIFOStatRegAddr; */
1496 			/* E */ 0x0108,0x0001,					  /* SPDIFOStMoFormat:SPDIFOFIFOBaseAddr; */
1497 			/* F */ DSP_SPOS_UUUU	  			          /* SPDIFOFree; */
1498 		};
1499 
1500 		/* 0xBB0 */
1501 		struct dsp_spdifiscb spdifi_scb = {
1502 			/* 0 */ DSP_SPOS_UULO,DSP_SPOS_UUHI,
1503 			/* 1 */ 0,
1504 			/* 2 */ 0,
1505 			/* 3 */ 1,4000,        /* SPDIFICountLimit SPDIFICount */
1506 			/* 4 */ DSP_SPOS_UUUU, /* SPDIFIStatusData */
1507 			/* 5 */ 0,DSP_SPOS_UUHI, /* StatusData, Free4 */
1508 			/* 6 */ DSP_SPOS_UUUU,  /* Free3 */
1509 			/* 7 */ DSP_SPOS_UU,DSP_SPOS_DC,  /* Free2 BitCount*/
1510 			/* 8 */ DSP_SPOS_UUUU,	/* TempStatus */
1511 			/* 9 */ SPDIFO_SCB_INST, NULL_SCB_ADDR,
1512 			/* A */ spdifi_task->address,
1513 			SPDIFI_SCB_INST + SPDIFIFIFOPointer,
1514 			/* NOTE: The SPDIF input task write the sample in mono
1515 			   format from the HW FIFO, the AsynchFGRxSCB task  reads
1516 			   them in stereo
1517 			*/
1518 			/* B */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_128,
1519 			/* C */ (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
1520 			/* D */ 0x8048,0,
1521 			/* E */ 0x01f0,0x0001,
1522 			/* F */ DSP_SPOS_UUUU /* SPDIN_STATUS monitor */
1523 		};
1524 
1525 		/* 0xBA0 */
1526 		struct dsp_async_codec_input_scb async_codec_input_scb = {
1527 			/* 0 */ DSP_SPOS_UUUU,
1528 			/* 1 */ 0,
1529 			/* 2 */ 0,
1530 			/* 3 */ 1,4000,
1531 			/* 4 */ 0x0118,0x0001,
1532 			/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_64,
1533 			/* 6 */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
1534 			/* 7 */ DSP_SPOS_UU,0x3,
1535 			/* 8 */ DSP_SPOS_UUUU,
1536 			/* 9 */ SPDIFI_SCB_INST,NULL_SCB_ADDR,
1537 			/* A */ s16_async_codec_input_task->address,
1538 			HFG_TREE_SCB + AsyncCIOFIFOPointer,
1539 
1540 			/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1541 			/* C */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10),  /*(ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,*/
1542 
1543 #ifdef UseASER1Input
1544 			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
1545 			   Init. 0000:8042: for ASER1
1546 			   0000:8044: for ASER2 */
1547 			/* D */ 0x8042,0,
1548 
1549 			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
1550 			   Init 1 stero:8050 ASER1
1551 			   Init 0  mono:8070 ASER2
1552 			   Init 1 Stereo : 0100 ASER1 (Set by script) */
1553 			/* E */ 0x0100,0x0001,
1554 
1555 #endif
1556 
1557 #ifdef UseASER2Input
1558 			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
1559 			   Init. 0000:8042: for ASER1
1560 			   0000:8044: for ASER2 */
1561 			/* D */ 0x8044,0,
1562 
1563 			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
1564 			   Init 1 stero:8050 ASER1
1565 			   Init 0  mono:8070 ASER2
1566 			   Init 1 Stereo : 0100 ASER1 (Set by script) */
1567 			/* E */ 0x0110,0x0001,
1568 
1569 #endif
1570 
1571 			/* short AsyncCIOutputBufModulo:AsyncCIFree;
1572 			   AsyncCIOutputBufModulo: The modulo size for
1573 			   the output buffer of this task */
1574 			/* F */ 0, /* DSP_SPOS_UUUU */
1575 		};
1576 
1577 		spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
1578 
1579 		if (snd_BUG_ON(!spdifo_scb_desc))
1580 			return -EIO;
1581 		spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
1582 		if (snd_BUG_ON(!spdifi_scb_desc))
1583 			return -EIO;
1584 		async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB);
1585 		if (snd_BUG_ON(!async_codec_scb_desc))
1586 			return -EIO;
1587 
1588 		async_codec_scb_desc->parent_scb_ptr = NULL;
1589 		async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc;
1590 		async_codec_scb_desc->sub_list_ptr = ins->the_null_scb;
1591 		async_codec_scb_desc->task_entry = s16_async_codec_input_task;
1592 
1593 		spdifi_scb_desc->parent_scb_ptr = async_codec_scb_desc;
1594 		spdifi_scb_desc->next_scb_ptr = spdifo_scb_desc;
1595 		spdifi_scb_desc->sub_list_ptr = ins->the_null_scb;
1596 		spdifi_scb_desc->task_entry = spdifi_task;
1597 
1598 		spdifo_scb_desc->parent_scb_ptr = spdifi_scb_desc;
1599 		spdifo_scb_desc->next_scb_ptr = fg_entry;
1600 		spdifo_scb_desc->sub_list_ptr = ins->the_null_scb;
1601 		spdifo_scb_desc->task_entry = spdifo_task;
1602 
1603 		/* this one is faked, as the parnet of SPDIFO task
1604 		   is the FG task tree */
1605 		fg_entry->parent_scb_ptr = spdifo_scb_desc;
1606 
1607 		/* for proc fs */
1608 		cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc);
1609 		cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc);
1610 		cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc);
1611 
1612 		/* Async MASTER ENABLE, affects both SPDIF input and output */
1613 		snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
1614 	}
1615 
1616 	return 0;
1617 }
1618 
1619 static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip)
1620 {
1621 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1622 
1623 	/* set SPDIF output FIFO slot */
1624 	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0);
1625 
1626 	/* SPDIF output MASTER ENABLE */
1627 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0);
1628 
1629 	/* right and left validate bit */
1630 	/*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);*/
1631 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x0);
1632 
1633 	/* clear fifo pointer */
1634 	cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
1635 
1636 	/* monitor state */
1637 	ins->spdif_status_out &= ~DSP_SPDIF_STATUS_HW_ENABLED;
1638 }
1639 
1640 int cs46xx_dsp_enable_spdif_hw (struct snd_cs46xx *chip)
1641 {
1642 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1643 
1644 	/* if hw-ctrl already enabled, turn off to reset logic ... */
1645 	cs46xx_dsp_disable_spdif_hw (chip);
1646 	udelay(50);
1647 
1648 	/* set SPDIF output FIFO slot */
1649 	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, ( 0x8000 | ((SP_SPDOUT_FIFO >> 4) << 4) ));
1650 
1651 	/* SPDIF output MASTER ENABLE */
1652 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
1653 
1654 	/* right and left validate bit */
1655 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1656 
1657 	/* monitor state */
1658 	ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
1659 
1660 	return 0;
1661 }
1662 
1663 int cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip)
1664 {
1665 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1666 
1667 	/* turn on amplifier */
1668 	chip->active_ctrl(chip, 1);
1669 	chip->amplifier_ctrl(chip, 1);
1670 
1671 	if (snd_BUG_ON(ins->asynch_rx_scb))
1672 		return -EINVAL;
1673 	if (snd_BUG_ON(!ins->spdif_in_src))
1674 		return -EINVAL;
1675 
1676 	guard(mutex)(&chip->spos_mutex);
1677 
1678 	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) {
1679 		/* time countdown enable */
1680 		cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000005);
1681 		/* NOTE: 80000005 value is just magic. With all values
1682 		   that I've tested this one seem to give the best result.
1683 		   Got no explication why. (Benny) */
1684 
1685 		/* SPDIF input MASTER ENABLE */
1686 		cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff);
1687 
1688 		ins->spdif_status_out |= DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED;
1689 	}
1690 
1691 	/* create and start the asynchronous receiver SCB */
1692 	ins->asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb(chip,"AsynchFGRxSCB",
1693 								ASYNCRX_SCB_ADDR,
1694 								SPDIFI_SCB_INST,
1695 								SPDIFI_IP_OUTPUT_BUFFER1,
1696 								ins->spdif_in_src,
1697 								SCB_ON_PARENT_SUBLIST_SCB);
1698 
1699 	guard(spinlock_irq)(&chip->reg_lock);
1700 
1701 	/* reset SPDIF input sample buffer pointer */
1702 	/*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2,
1703 	  (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC);*/
1704 
1705 	/* reset FIFO ptr */
1706 	/*cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);*/
1707 	cs46xx_src_link(chip,ins->spdif_in_src);
1708 
1709 	/* unmute SRC volume */
1710 	cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff);
1711 
1712 	/* set SPDIF input sample rate and unmute
1713 	   NOTE: only 48khz support for SPDIF input this time */
1714 	/* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */
1715 
1716 	/* monitor state */
1717 	ins->spdif_status_in = 1;
1718 
1719 	return 0;
1720 }
1721 
1722 int cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip)
1723 {
1724 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1725 
1726 	if (snd_BUG_ON(!ins->asynch_rx_scb))
1727 		return -EINVAL;
1728 	if (snd_BUG_ON(!ins->spdif_in_src))
1729 		return -EINVAL;
1730 
1731 	scoped_guard(mutex, &chip->spos_mutex) {
1732 		/* Remove the asynchronous receiver SCB */
1733 		cs46xx_dsp_remove_scb(chip, ins->asynch_rx_scb);
1734 		ins->asynch_rx_scb = NULL;
1735 
1736 		cs46xx_src_unlink(chip, ins->spdif_in_src);
1737 
1738 		/* monitor state */
1739 		ins->spdif_status_in = 0;
1740 	}
1741 
1742 	/* restore amplifier */
1743 	chip->active_ctrl(chip, -1);
1744 	chip->amplifier_ctrl(chip, -1);
1745 
1746 	return 0;
1747 }
1748 
1749 int cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip)
1750 {
1751 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1752 
1753 	if (snd_BUG_ON(ins->pcm_input))
1754 		return -EINVAL;
1755 	if (snd_BUG_ON(!ins->ref_snoop_scb))
1756 		return -EINVAL;
1757 
1758 	guard(mutex)(&chip->spos_mutex);
1759 	ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
1760                                                   "PCMSerialInput_Wave");
1761 
1762 	return 0;
1763 }
1764 
1765 int cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip)
1766 {
1767 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1768 
1769 	if (snd_BUG_ON(!ins->pcm_input))
1770 		return -EINVAL;
1771 
1772 	guard(mutex)(&chip->spos_mutex);
1773 	cs46xx_dsp_remove_scb (chip,ins->pcm_input);
1774 	ins->pcm_input = NULL;
1775 
1776 	return 0;
1777 }
1778 
1779 int cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip)
1780 {
1781 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1782 
1783 	if (snd_BUG_ON(ins->adc_input))
1784 		return -EINVAL;
1785 	if (snd_BUG_ON(!ins->codec_in_scb))
1786 		return -EINVAL;
1787 
1788 	guard(mutex)(&chip->spos_mutex);
1789 	ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
1790 						  "PCMSerialInput_ADC");
1791 
1792 	return 0;
1793 }
1794 
1795 int cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip)
1796 {
1797 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1798 
1799 	if (snd_BUG_ON(!ins->adc_input))
1800 		return -EINVAL;
1801 
1802 	guard(mutex)(&chip->spos_mutex);
1803 	cs46xx_dsp_remove_scb (chip,ins->adc_input);
1804 	ins->adc_input = NULL;
1805 
1806 	return 0;
1807 }
1808 
1809 int cs46xx_poke_via_dsp (struct snd_cs46xx *chip, u32 address, u32 data)
1810 {
1811 	u32 temp;
1812 	int  i;
1813 
1814 	/* santiy check the parameters.  (These numbers are not 100% correct.  They are
1815 	   a rough guess from looking at the controller spec.) */
1816 	if (address < 0x8000 || address >= 0x9000)
1817 		return -EINVAL;
1818 
1819 	/* initialize the SP_IO_WRITE SCB with the data. */
1820 	temp = ( address << 16 ) | ( address & 0x0000FFFF);   /* offset 0 <-- address2 : address1 */
1821 
1822 	snd_cs46xx_poke(chip,( SPIOWRITE_SCB_ADDR      << 2), temp);
1823 	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 1) << 2), data); /* offset 1 <-- data1 */
1824 	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2 */
1825 
1826 	/* Poke this location to tell the task to start */
1827 	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 6) << 2), SPIOWRITE_SCB_ADDR << 0x10);
1828 
1829 	/* Verify that the task ran */
1830 	for (i=0; i<25; i++) {
1831 		udelay(125);
1832 
1833 		temp =  snd_cs46xx_peek(chip,((SPIOWRITE_SCB_ADDR + 6) << 2));
1834 		if (temp == 0x00000000)
1835 			break;
1836 	}
1837 
1838 	if (i == 25) {
1839 		dev_err(chip->card->dev,
1840 			"dsp_spos: SPIOWriteTask not responding\n");
1841 		return -EBUSY;
1842 	}
1843 
1844 	return 0;
1845 }
1846 
1847 int cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right)
1848 {
1849 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1850 	struct dsp_scb_descriptor * scb;
1851 
1852 	guard(mutex)(&chip->spos_mutex);
1853 
1854 	/* main output */
1855 	scb = ins->master_mix_scb->sub_list_ptr;
1856 	while (scb != ins->the_null_scb) {
1857 		cs46xx_dsp_scb_set_volume (chip,scb,left,right);
1858 		scb = scb->next_scb_ptr;
1859 	}
1860 
1861 	/* rear output */
1862 	scb = ins->rear_mix_scb->sub_list_ptr;
1863 	while (scb != ins->the_null_scb) {
1864 		cs46xx_dsp_scb_set_volume (chip,scb,left,right);
1865 		scb = scb->next_scb_ptr;
1866 	}
1867 
1868 	ins->dac_volume_left = left;
1869 	ins->dac_volume_right = right;
1870 
1871 	return 0;
1872 }
1873 
1874 int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
1875 {
1876 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1877 
1878 	guard(mutex)(&chip->spos_mutex);
1879 
1880 	if (ins->asynch_rx_scb != NULL)
1881 		cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
1882 					   left,right);
1883 
1884 	ins->spdif_input_volume_left = left;
1885 	ins->spdif_input_volume_right = right;
1886 
1887 	return 0;
1888 }
1889 
1890 #ifdef CONFIG_PM_SLEEP
1891 int cs46xx_dsp_resume(struct snd_cs46xx * chip)
1892 {
1893 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1894 	int i, err;
1895 
1896 	/* clear parameter, sample and code areas */
1897 	snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET,
1898 			     DSP_PARAMETER_BYTE_SIZE);
1899 	snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET,
1900 			     DSP_SAMPLE_BYTE_SIZE);
1901 	snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
1902 
1903 	for (i = 0; i < ins->nmodules; i++) {
1904 		struct dsp_module_desc *module = &ins->modules[i];
1905 		struct dsp_segment_desc *seg;
1906 		u32 doffset, dsize;
1907 
1908 		seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER);
1909 		err = dsp_load_parameter(chip, seg);
1910 		if (err < 0)
1911 			return err;
1912 
1913 		seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE);
1914 		err = dsp_load_sample(chip, seg);
1915 		if (err < 0)
1916 			return err;
1917 
1918 		seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM);
1919 		if (!seg)
1920 			continue;
1921 
1922 		doffset = seg->offset * 4 + module->load_address * 4
1923 			+ DSP_CODE_BYTE_OFFSET;
1924 		dsize   = seg->size * 4;
1925 		err = snd_cs46xx_download(chip,
1926 					  ins->code.data + module->load_address,
1927 					  doffset, dsize);
1928 		if (err < 0)
1929 			return err;
1930 	}
1931 
1932 	for (i = 0; i < ins->ntask; i++) {
1933 		struct dsp_task_descriptor *t = &ins->tasks[i];
1934 		_dsp_create_task_tree(chip, t->data, t->address, t->size);
1935 	}
1936 
1937 	for (i = 0; i < ins->nscb; i++) {
1938 		struct dsp_scb_descriptor *s = &ins->scbs[i];
1939 		if (s->deleted)
1940 			continue;
1941 		_dsp_create_scb(chip, s->data, s->address);
1942 	}
1943 	for (i = 0; i < ins->nscb; i++) {
1944 		struct dsp_scb_descriptor *s = &ins->scbs[i];
1945 		if (s->deleted)
1946 			continue;
1947 		if (s->updated)
1948 			cs46xx_dsp_spos_update_scb(chip, s);
1949 		if (s->volume_set)
1950 			cs46xx_dsp_scb_set_volume(chip, s,
1951 						  s->volume[0], s->volume[1]);
1952 	}
1953 	if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
1954 		cs46xx_dsp_enable_spdif_hw(chip);
1955 		snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2,
1956 				(OUTPUT_SNOOP_BUFFER + 0x10) << 0x10);
1957 		if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN)
1958 			cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV,
1959 					    ins->spdif_csuv_stream);
1960 	}
1961 	if (chip->dsp_spos_instance->spdif_status_in) {
1962 		cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005);
1963 		cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff);
1964 	}
1965 	return 0;
1966 }
1967 #endif
1968