18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * 2002-07 Benny Sjostrand benny@hostmobility.com
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/pm.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
168c2ecf20Sopenharmony_ci#include <linux/mutex.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <sound/core.h>
198c2ecf20Sopenharmony_ci#include <sound/control.h>
208c2ecf20Sopenharmony_ci#include <sound/info.h>
218c2ecf20Sopenharmony_ci#include <sound/asoundef.h>
228c2ecf20Sopenharmony_ci#include "cs46xx.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "cs46xx_lib.h"
258c2ecf20Sopenharmony_ci#include "dsp_spos.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
288c2ecf20Sopenharmony_ci				  struct dsp_scb_descriptor * fg_entry);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic const enum wide_opcode wide_opcodes[] = {
318c2ecf20Sopenharmony_ci	WIDE_FOR_BEGIN_LOOP,
328c2ecf20Sopenharmony_ci	WIDE_FOR_BEGIN_LOOP2,
338c2ecf20Sopenharmony_ci	WIDE_COND_GOTO_ADDR,
348c2ecf20Sopenharmony_ci	WIDE_COND_GOTO_CALL,
358c2ecf20Sopenharmony_ci	WIDE_TBEQ_COND_GOTO_ADDR,
368c2ecf20Sopenharmony_ci	WIDE_TBEQ_COND_CALL_ADDR,
378c2ecf20Sopenharmony_ci	WIDE_TBEQ_NCOND_GOTO_ADDR,
388c2ecf20Sopenharmony_ci	WIDE_TBEQ_NCOND_CALL_ADDR,
398c2ecf20Sopenharmony_ci	WIDE_TBEQ_COND_GOTO1_ADDR,
408c2ecf20Sopenharmony_ci	WIDE_TBEQ_COND_CALL1_ADDR,
418c2ecf20Sopenharmony_ci	WIDE_TBEQ_NCOND_GOTOI_ADDR,
428c2ecf20Sopenharmony_ci	WIDE_TBEQ_NCOND_CALL1_ADDR
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 size,
468c2ecf20Sopenharmony_ci				       u32 overlay_begin_address)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	unsigned int i = 0, j, nreallocated = 0;
498c2ecf20Sopenharmony_ci	u32 hival,loval,address;
508c2ecf20Sopenharmony_ci	u32 mop_operands,mop_type,wide_op;
518c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (snd_BUG_ON(size %2))
548c2ecf20Sopenharmony_ci		return -EINVAL;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	while (i < size) {
578c2ecf20Sopenharmony_ci		loval = data[i++];
588c2ecf20Sopenharmony_ci		hival = data[i++];
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		if (ins->code.offset > 0) {
618c2ecf20Sopenharmony_ci			mop_operands = (hival >> 6) & 0x03fff;
628c2ecf20Sopenharmony_ci			mop_type = mop_operands >> 10;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci			/* check for wide type instruction */
658c2ecf20Sopenharmony_ci			if (mop_type == 0 &&
668c2ecf20Sopenharmony_ci			    (mop_operands & WIDE_LADD_INSTR_MASK) == 0 &&
678c2ecf20Sopenharmony_ci			    (mop_operands & WIDE_INSTR_MASK) != 0) {
688c2ecf20Sopenharmony_ci				wide_op = loval & 0x7f;
698c2ecf20Sopenharmony_ci				for (j = 0;j < ARRAY_SIZE(wide_opcodes); ++j) {
708c2ecf20Sopenharmony_ci					if (wide_opcodes[j] == wide_op) {
718c2ecf20Sopenharmony_ci						/* need to reallocate instruction */
728c2ecf20Sopenharmony_ci						address  = (hival & 0x00FFF) << 5;
738c2ecf20Sopenharmony_ci						address |=  loval >> 15;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci						dev_dbg(chip->card->dev,
768c2ecf20Sopenharmony_ci							"handle_wideop[1]: %05x:%05x addr %04x\n",
778c2ecf20Sopenharmony_ci							hival, loval, address);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci						if ( !(address & 0x8000) ) {
808c2ecf20Sopenharmony_ci							address += (ins->code.offset / 2) - overlay_begin_address;
818c2ecf20Sopenharmony_ci						} else {
828c2ecf20Sopenharmony_ci							dev_dbg(chip->card->dev,
838c2ecf20Sopenharmony_ci								"handle_wideop[1]: ROM symbol not reallocated\n");
848c2ecf20Sopenharmony_ci						}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci						hival &= 0xFF000;
878c2ecf20Sopenharmony_ci						loval &= 0x07FFF;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci						hival |= ( (address >> 5)  & 0x00FFF);
908c2ecf20Sopenharmony_ci						loval |= ( (address << 15) & 0xF8000);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci						address  = (hival & 0x00FFF) << 5;
938c2ecf20Sopenharmony_ci						address |=  loval >> 15;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci						dev_dbg(chip->card->dev,
968c2ecf20Sopenharmony_ci							"handle_wideop:[2] %05x:%05x addr %04x\n",
978c2ecf20Sopenharmony_ci							hival, loval, address);
988c2ecf20Sopenharmony_ci						nreallocated++;
998c2ecf20Sopenharmony_ci					} /* wide_opcodes[j] == wide_op */
1008c2ecf20Sopenharmony_ci				} /* for */
1018c2ecf20Sopenharmony_ci			} /* mod_type == 0 ... */
1028c2ecf20Sopenharmony_ci		} /* ins->code.offset > 0 */
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci		ins->code.data[ins->code.size++] = loval;
1058c2ecf20Sopenharmony_ci		ins->code.data[ins->code.size++] = hival;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	dev_dbg(chip->card->dev,
1098c2ecf20Sopenharmony_ci		"dsp_spos: %d instructions reallocated\n", nreallocated);
1108c2ecf20Sopenharmony_ci	return nreallocated;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic struct dsp_segment_desc * get_segment_desc (struct dsp_module_desc * module, int seg_type)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	int i;
1168c2ecf20Sopenharmony_ci	for (i = 0;i < module->nsegments; ++i) {
1178c2ecf20Sopenharmony_ci		if (module->segments[i].segment_type == seg_type) {
1188c2ecf20Sopenharmony_ci			return (module->segments + i);
1198c2ecf20Sopenharmony_ci		}
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return NULL;
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int find_free_symbol_index (struct dsp_spos_instance * ins)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	int index = ins->symbol_table.nsymbols,i;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	for (i = ins->symbol_table.highest_frag_index; i < ins->symbol_table.nsymbols; ++i) {
1308c2ecf20Sopenharmony_ci		if (ins->symbol_table.symbols[i].deleted) {
1318c2ecf20Sopenharmony_ci			index = i;
1328c2ecf20Sopenharmony_ci			break;
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return index;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * module)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	int i;
1428c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (module->symbol_table.nsymbols > 0) {
1458c2ecf20Sopenharmony_ci		if (!strcmp(module->symbol_table.symbols[0].symbol_name, "OVERLAYBEGINADDRESS") &&
1468c2ecf20Sopenharmony_ci		    module->symbol_table.symbols[0].symbol_type == SYMBOL_CONSTANT ) {
1478c2ecf20Sopenharmony_ci			module->overlay_begin_address = module->symbol_table.symbols[0].address;
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	for (i = 0;i < module->symbol_table.nsymbols; ++i) {
1528c2ecf20Sopenharmony_ci		if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
1538c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
1548c2ecf20Sopenharmony_ci				"dsp_spos: symbol table is full\n");
1558c2ecf20Sopenharmony_ci			return -ENOMEM;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		if (cs46xx_dsp_lookup_symbol(chip,
1608c2ecf20Sopenharmony_ci					     module->symbol_table.symbols[i].symbol_name,
1618c2ecf20Sopenharmony_ci					     module->symbol_table.symbols[i].symbol_type) == NULL) {
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci			ins->symbol_table.symbols[ins->symbol_table.nsymbols] = module->symbol_table.symbols[i];
1648c2ecf20Sopenharmony_ci			ins->symbol_table.symbols[ins->symbol_table.nsymbols].address += ((ins->code.offset / 2) - module->overlay_begin_address);
1658c2ecf20Sopenharmony_ci			ins->symbol_table.symbols[ins->symbol_table.nsymbols].module = module;
1668c2ecf20Sopenharmony_ci			ins->symbol_table.symbols[ins->symbol_table.nsymbols].deleted = 0;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci			if (ins->symbol_table.nsymbols > ins->symbol_table.highest_frag_index)
1698c2ecf20Sopenharmony_ci				ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci			ins->symbol_table.nsymbols++;
1728c2ecf20Sopenharmony_ci		} else {
1738c2ecf20Sopenharmony_ci#if 0
1748c2ecf20Sopenharmony_ci			dev_dbg(chip->card->dev,
1758c2ecf20Sopenharmony_ci				"dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
1768c2ecf20Sopenharmony_ci				module->symbol_table.symbols[i].symbol_name); */
1778c2ecf20Sopenharmony_ci#endif
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return 0;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic struct dsp_symbol_entry *
1858c2ecf20Sopenharmony_ciadd_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1888c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * symbol = NULL;
1898c2ecf20Sopenharmony_ci	int index;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
1928c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "dsp_spos: symbol table is full\n");
1938c2ecf20Sopenharmony_ci		return NULL;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (cs46xx_dsp_lookup_symbol(chip,
1978c2ecf20Sopenharmony_ci				     symbol_name,
1988c2ecf20Sopenharmony_ci				     type) != NULL) {
1998c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
2008c2ecf20Sopenharmony_ci			"dsp_spos: symbol <%s> duplicated\n", symbol_name);
2018c2ecf20Sopenharmony_ci		return NULL;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	index = find_free_symbol_index (ins);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	strcpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);
2078c2ecf20Sopenharmony_ci	ins->symbol_table.symbols[index].address = address;
2088c2ecf20Sopenharmony_ci	ins->symbol_table.symbols[index].symbol_type = type;
2098c2ecf20Sopenharmony_ci	ins->symbol_table.symbols[index].module = NULL;
2108c2ecf20Sopenharmony_ci	ins->symbol_table.symbols[index].deleted = 0;
2118c2ecf20Sopenharmony_ci	symbol = (ins->symbol_table.symbols + index);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (index > ins->symbol_table.highest_frag_index)
2148c2ecf20Sopenharmony_ci		ins->symbol_table.highest_frag_index = index;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (index == ins->symbol_table.nsymbols)
2178c2ecf20Sopenharmony_ci		ins->symbol_table.nsymbols++; /* no frag. in list */
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	return symbol;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistruct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = kzalloc(sizeof(struct dsp_spos_instance), GFP_KERNEL);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (ins == NULL)
2278c2ecf20Sopenharmony_ci		return NULL;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* better to use vmalloc for this big table */
2308c2ecf20Sopenharmony_ci	ins->symbol_table.symbols =
2318c2ecf20Sopenharmony_ci		vmalloc(array_size(DSP_MAX_SYMBOLS,
2328c2ecf20Sopenharmony_ci				   sizeof(struct dsp_symbol_entry)));
2338c2ecf20Sopenharmony_ci	ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
2348c2ecf20Sopenharmony_ci	ins->modules = kmalloc_array(DSP_MAX_MODULES,
2358c2ecf20Sopenharmony_ci				     sizeof(struct dsp_module_desc),
2368c2ecf20Sopenharmony_ci				     GFP_KERNEL);
2378c2ecf20Sopenharmony_ci	if (!ins->symbol_table.symbols || !ins->code.data || !ins->modules) {
2388c2ecf20Sopenharmony_ci		cs46xx_dsp_spos_destroy(chip);
2398c2ecf20Sopenharmony_ci		goto error;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci	ins->symbol_table.nsymbols = 0;
2428c2ecf20Sopenharmony_ci	ins->symbol_table.highest_frag_index = 0;
2438c2ecf20Sopenharmony_ci	ins->code.offset = 0;
2448c2ecf20Sopenharmony_ci	ins->code.size = 0;
2458c2ecf20Sopenharmony_ci	ins->nscb = 0;
2468c2ecf20Sopenharmony_ci	ins->ntask = 0;
2478c2ecf20Sopenharmony_ci	ins->nmodules = 0;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	/* default SPDIF input sample rate
2508c2ecf20Sopenharmony_ci	   to 48000 khz */
2518c2ecf20Sopenharmony_ci	ins->spdif_in_sample_rate = 48000;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* maximize volume */
2548c2ecf20Sopenharmony_ci	ins->dac_volume_right = 0x8000;
2558c2ecf20Sopenharmony_ci	ins->dac_volume_left = 0x8000;
2568c2ecf20Sopenharmony_ci	ins->spdif_input_volume_right = 0x8000;
2578c2ecf20Sopenharmony_ci	ins->spdif_input_volume_left = 0x8000;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* set left and right validity bits and
2608c2ecf20Sopenharmony_ci	   default channel status */
2618c2ecf20Sopenharmony_ci	ins->spdif_csuv_default =
2628c2ecf20Sopenharmony_ci		ins->spdif_csuv_stream =
2638c2ecf20Sopenharmony_ci	 /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |
2648c2ecf20Sopenharmony_ci	 /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |
2658c2ecf20Sopenharmony_ci	 /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
2668c2ecf20Sopenharmony_ci	 /* left and right validity bits */ (1 << 13) | (1 << 12);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	return ins;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cierror:
2718c2ecf20Sopenharmony_ci	kfree(ins->modules);
2728c2ecf20Sopenharmony_ci	kfree(ins->code.data);
2738c2ecf20Sopenharmony_ci	vfree(ins->symbol_table.symbols);
2748c2ecf20Sopenharmony_ci	kfree(ins);
2758c2ecf20Sopenharmony_ci	return NULL;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_civoid  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	int i;
2818c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins))
2848c2ecf20Sopenharmony_ci		return;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
2878c2ecf20Sopenharmony_ci	for (i = 0; i < ins->nscb; ++i) {
2888c2ecf20Sopenharmony_ci		if (ins->scbs[i].deleted) continue;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
2918c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
2928c2ecf20Sopenharmony_ci		kfree(ins->scbs[i].data);
2938c2ecf20Sopenharmony_ci#endif
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	kfree(ins->code.data);
2978c2ecf20Sopenharmony_ci	vfree(ins->symbol_table.symbols);
2988c2ecf20Sopenharmony_ci	kfree(ins->modules);
2998c2ecf20Sopenharmony_ci	kfree(ins);
3008c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int dsp_load_parameter(struct snd_cs46xx *chip,
3048c2ecf20Sopenharmony_ci			      struct dsp_segment_desc *parameter)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	u32 doffset, dsize;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (!parameter) {
3098c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
3108c2ecf20Sopenharmony_ci			"dsp_spos: module got no parameter segment\n");
3118c2ecf20Sopenharmony_ci		return 0;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
3158c2ecf20Sopenharmony_ci	dsize   = parameter->size * 4;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	dev_dbg(chip->card->dev,
3188c2ecf20Sopenharmony_ci		"dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
3198c2ecf20Sopenharmony_ci		    doffset,doffset + dsize);
3208c2ecf20Sopenharmony_ci	if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
3218c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
3228c2ecf20Sopenharmony_ci			"dsp_spos: failed to download parameter data to DSP\n");
3238c2ecf20Sopenharmony_ci		return -EINVAL;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci	return 0;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int dsp_load_sample(struct snd_cs46xx *chip,
3298c2ecf20Sopenharmony_ci			   struct dsp_segment_desc *sample)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	u32 doffset, dsize;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (!sample) {
3348c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
3358c2ecf20Sopenharmony_ci			"dsp_spos: module got no sample segment\n");
3368c2ecf20Sopenharmony_ci		return 0;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
3408c2ecf20Sopenharmony_ci	dsize   =  sample->size * 4;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	dev_dbg(chip->card->dev,
3438c2ecf20Sopenharmony_ci		"dsp_spos: downloading sample data to chip (%08x-%08x)\n",
3448c2ecf20Sopenharmony_ci		    doffset,doffset + dsize);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
3478c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
3488c2ecf20Sopenharmony_ci			"dsp_spos: failed to sample data to DSP\n");
3498c2ecf20Sopenharmony_ci		return -EINVAL;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci	return 0;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ciint cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
3578c2ecf20Sopenharmony_ci	struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
3588c2ecf20Sopenharmony_ci	u32 doffset, dsize;
3598c2ecf20Sopenharmony_ci	int err;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (ins->nmodules == DSP_MAX_MODULES - 1) {
3628c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
3638c2ecf20Sopenharmony_ci			"dsp_spos: to many modules loaded into DSP\n");
3648c2ecf20Sopenharmony_ci		return -ENOMEM;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	dev_dbg(chip->card->dev,
3688c2ecf20Sopenharmony_ci		"dsp_spos: loading module %s into DSP\n", module->module_name);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (ins->nmodules == 0) {
3718c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "dsp_spos: clearing parameter area\n");
3728c2ecf20Sopenharmony_ci		snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	err = dsp_load_parameter(chip, get_segment_desc(module,
3768c2ecf20Sopenharmony_ci							SEGTYPE_SP_PARAMETER));
3778c2ecf20Sopenharmony_ci	if (err < 0)
3788c2ecf20Sopenharmony_ci		return err;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (ins->nmodules == 0) {
3818c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "dsp_spos: clearing sample area\n");
3828c2ecf20Sopenharmony_ci		snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	err = dsp_load_sample(chip, get_segment_desc(module,
3868c2ecf20Sopenharmony_ci						     SEGTYPE_SP_SAMPLE));
3878c2ecf20Sopenharmony_ci	if (err < 0)
3888c2ecf20Sopenharmony_ci		return err;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (ins->nmodules == 0) {
3918c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "dsp_spos: clearing code area\n");
3928c2ecf20Sopenharmony_ci		snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (code == NULL) {
3968c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
3978c2ecf20Sopenharmony_ci			"dsp_spos: module got no code segment\n");
3988c2ecf20Sopenharmony_ci	} else {
3998c2ecf20Sopenharmony_ci		if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {
4008c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
4018c2ecf20Sopenharmony_ci				"dsp_spos: no space available in DSP\n");
4028c2ecf20Sopenharmony_ci			return -ENOMEM;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		module->load_address = ins->code.offset;
4068c2ecf20Sopenharmony_ci		module->overlay_begin_address = 0x000;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		/* if module has a code segment it must have
4098c2ecf20Sopenharmony_ci		   symbol table */
4108c2ecf20Sopenharmony_ci		if (snd_BUG_ON(!module->symbol_table.symbols))
4118c2ecf20Sopenharmony_ci			return -ENOMEM;
4128c2ecf20Sopenharmony_ci		if (add_symbols(chip,module)) {
4138c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
4148c2ecf20Sopenharmony_ci				"dsp_spos: failed to load symbol table\n");
4158c2ecf20Sopenharmony_ci			return -ENOMEM;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci		doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);
4198c2ecf20Sopenharmony_ci		dsize   = code->size * 4;
4208c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev,
4218c2ecf20Sopenharmony_ci			"dsp_spos: downloading code to chip (%08x-%08x)\n",
4228c2ecf20Sopenharmony_ci			    doffset,doffset + dsize);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {
4278c2ecf20Sopenharmony_ci			dev_err(chip->card->dev,
4288c2ecf20Sopenharmony_ci				"dsp_spos: failed to download code to DSP\n");
4298c2ecf20Sopenharmony_ci			return -EINVAL;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		ins->code.offset += code->size;
4338c2ecf20Sopenharmony_ci	}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	/* NOTE: module segments and symbol table must be
4368c2ecf20Sopenharmony_ci	   statically allocated. Case that module data is
4378c2ecf20Sopenharmony_ci	   not generated by the ospparser */
4388c2ecf20Sopenharmony_ci	ins->modules[ins->nmodules] = *module;
4398c2ecf20Sopenharmony_ci	ins->nmodules++;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return 0;
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistruct dsp_symbol_entry *
4458c2ecf20Sopenharmony_cics46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, int symbol_type)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	int i;
4488c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		if (ins->symbol_table.symbols[i].deleted)
4538c2ecf20Sopenharmony_ci			continue;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		if (!strcmp(ins->symbol_table.symbols[i].symbol_name,symbol_name) &&
4568c2ecf20Sopenharmony_ci		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
4578c2ecf20Sopenharmony_ci			return (ins->symbol_table.symbols + i);
4588c2ecf20Sopenharmony_ci		}
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci#if 0
4628c2ecf20Sopenharmony_ci	dev_err(chip->card->dev, "dsp_spos: symbol <%s> type %02x not found\n",
4638c2ecf20Sopenharmony_ci		symbol_name,symbol_type);
4648c2ecf20Sopenharmony_ci#endif
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return NULL;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_PROC_FS
4718c2ecf20Sopenharmony_cistatic struct dsp_symbol_entry *
4728c2ecf20Sopenharmony_cics46xx_dsp_lookup_symbol_addr (struct snd_cs46xx * chip, u32 address, int symbol_type)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	int i;
4758c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci		if (ins->symbol_table.symbols[i].deleted)
4808c2ecf20Sopenharmony_ci			continue;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci		if (ins->symbol_table.symbols[i].address == address &&
4838c2ecf20Sopenharmony_ci		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
4848c2ecf20Sopenharmony_ci			return (ins->symbol_table.symbols + i);
4858c2ecf20Sopenharmony_ci		}
4868c2ecf20Sopenharmony_ci	}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	return NULL;
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic void cs46xx_dsp_proc_symbol_table_read (struct snd_info_entry *entry,
4948c2ecf20Sopenharmony_ci					       struct snd_info_buffer *buffer)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip = entry->private_data;
4978c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
4988c2ecf20Sopenharmony_ci	int i;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "SYMBOLS:\n");
5018c2ecf20Sopenharmony_ci	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
5028c2ecf20Sopenharmony_ci		char *module_str = "system";
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		if (ins->symbol_table.symbols[i].deleted)
5058c2ecf20Sopenharmony_ci			continue;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		if (ins->symbol_table.symbols[i].module != NULL) {
5088c2ecf20Sopenharmony_ci			module_str = ins->symbol_table.symbols[i].module->module_name;
5098c2ecf20Sopenharmony_ci		}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "%04X <%02X> %s [%s]\n",
5138c2ecf20Sopenharmony_ci			    ins->symbol_table.symbols[i].address,
5148c2ecf20Sopenharmony_ci			    ins->symbol_table.symbols[i].symbol_type,
5158c2ecf20Sopenharmony_ci			    ins->symbol_table.symbols[i].symbol_name,
5168c2ecf20Sopenharmony_ci			    module_str);
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic void cs46xx_dsp_proc_modules_read (struct snd_info_entry *entry,
5228c2ecf20Sopenharmony_ci					  struct snd_info_buffer *buffer)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip = entry->private_data;
5258c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
5268c2ecf20Sopenharmony_ci	int i,j;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
5298c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "MODULES:\n");
5308c2ecf20Sopenharmony_ci	for ( i = 0; i < ins->nmodules; ++i ) {
5318c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
5328c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "   %d symbols\n", ins->modules[i].symbol_table.nsymbols);
5338c2ecf20Sopenharmony_ci		snd_iprintf(buffer, "   %d fixups\n", ins->modules[i].nfixups);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		for (j = 0; j < ins->modules[i].nsegments; ++ j) {
5368c2ecf20Sopenharmony_ci			struct dsp_segment_desc * desc = (ins->modules[i].segments + j);
5378c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "   segment %02x offset %08x size %08x\n",
5388c2ecf20Sopenharmony_ci				    desc->segment_type,desc->offset, desc->size);
5398c2ecf20Sopenharmony_ci		}
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
5458c2ecf20Sopenharmony_ci					    struct snd_info_buffer *buffer)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip = entry->private_data;
5488c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
5498c2ecf20Sopenharmony_ci	int i, j, col;
5508c2ecf20Sopenharmony_ci	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
5538c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "TASK TREES:\n");
5548c2ecf20Sopenharmony_ci	for ( i = 0; i < ins->ntask; ++i) {
5558c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		for (col = 0,j = 0;j < ins->tasks[i].size; j++,col++) {
5588c2ecf20Sopenharmony_ci			u32 val;
5598c2ecf20Sopenharmony_ci			if (col == 4) {
5608c2ecf20Sopenharmony_ci				snd_iprintf(buffer,"\n");
5618c2ecf20Sopenharmony_ci				col = 0;
5628c2ecf20Sopenharmony_ci			}
5638c2ecf20Sopenharmony_ci			val = readl(dst + (ins->tasks[i].address + j) * sizeof(u32));
5648c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"%08x ",val);
5658c2ecf20Sopenharmony_ci		}
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\n");
5698c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
5738c2ecf20Sopenharmony_ci				      struct snd_info_buffer *buffer)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip = entry->private_data;
5768c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
5778c2ecf20Sopenharmony_ci	int i;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
5808c2ecf20Sopenharmony_ci	snd_iprintf(buffer, "SCB's:\n");
5818c2ecf20Sopenharmony_ci	for ( i = 0; i < ins->nscb; ++i) {
5828c2ecf20Sopenharmony_ci		if (ins->scbs[i].deleted)
5838c2ecf20Sopenharmony_ci			continue;
5848c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"\n%04x %s:\n\n",ins->scbs[i].address,ins->scbs[i].scb_name);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		if (ins->scbs[i].parent_scb_ptr != NULL) {
5878c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"parent [%s:%04x] ",
5888c2ecf20Sopenharmony_ci				    ins->scbs[i].parent_scb_ptr->scb_name,
5898c2ecf20Sopenharmony_ci				    ins->scbs[i].parent_scb_ptr->address);
5908c2ecf20Sopenharmony_ci		} else snd_iprintf(buffer,"parent [none] ");
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
5938c2ecf20Sopenharmony_ci			    ins->scbs[i].sub_list_ptr->scb_name,
5948c2ecf20Sopenharmony_ci			    ins->scbs[i].sub_list_ptr->address,
5958c2ecf20Sopenharmony_ci			    ins->scbs[i].next_scb_ptr->scb_name,
5968c2ecf20Sopenharmony_ci			    ins->scbs[i].next_scb_ptr->address,
5978c2ecf20Sopenharmony_ci			    ins->scbs[i].task_entry->symbol_name,
5988c2ecf20Sopenharmony_ci			    ins->scbs[i].task_entry->address);
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\n");
6028c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry,
6068c2ecf20Sopenharmony_ci						 struct snd_info_buffer *buffer)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip = entry->private_data;
6098c2ecf20Sopenharmony_ci	/*struct dsp_spos_instance * ins = chip->dsp_spos_instance; */
6108c2ecf20Sopenharmony_ci	unsigned int i, col = 0;
6118c2ecf20Sopenharmony_ci	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
6128c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * symbol;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	for (i = 0;i < DSP_PARAMETER_BYTE_SIZE; i += sizeof(u32),col ++) {
6158c2ecf20Sopenharmony_ci		if (col == 4) {
6168c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
6178c2ecf20Sopenharmony_ci			col = 0;
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		if ( (symbol = cs46xx_dsp_lookup_symbol_addr (chip,i / sizeof(u32), SYMBOL_PARAMETER)) != NULL) {
6218c2ecf20Sopenharmony_ci			col = 0;
6228c2ecf20Sopenharmony_ci			snd_iprintf (buffer,"\n%s:\n",symbol->symbol_name);
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		if (col == 0) {
6268c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ", i / (unsigned int)sizeof(u32));
6278c2ecf20Sopenharmony_ci		}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic void cs46xx_dsp_proc_sample_dump_read (struct snd_info_entry *entry,
6348c2ecf20Sopenharmony_ci					      struct snd_info_buffer *buffer)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	struct snd_cs46xx *chip = entry->private_data;
6378c2ecf20Sopenharmony_ci	int i,col = 0;
6388c2ecf20Sopenharmony_ci	void __iomem *dst = chip->region.idx[2].remap_addr;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"PCMREADER:\n");
6418c2ecf20Sopenharmony_ci	for (i = PCM_READER_BUF1;i < PCM_READER_BUF1 + 0x30; i += sizeof(u32),col ++) {
6428c2ecf20Sopenharmony_ci		if (col == 4) {
6438c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
6448c2ecf20Sopenharmony_ci			col = 0;
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		if (col == 0) {
6488c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\nMIX_SAMPLE_BUF1:\n");
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	col = 0;
6578c2ecf20Sopenharmony_ci	for (i = MIX_SAMPLE_BUF1;i < MIX_SAMPLE_BUF1 + 0x40; i += sizeof(u32),col ++) {
6588c2ecf20Sopenharmony_ci		if (col == 4) {
6598c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
6608c2ecf20Sopenharmony_ci			col = 0;
6618c2ecf20Sopenharmony_ci		}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		if (col == 0) {
6648c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
6658c2ecf20Sopenharmony_ci		}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\nSRC_TASK_SCB1:\n");
6718c2ecf20Sopenharmony_ci	col = 0;
6728c2ecf20Sopenharmony_ci	for (i = 0x2480 ; i < 0x2480 + 0x40 ; i += sizeof(u32),col ++) {
6738c2ecf20Sopenharmony_ci		if (col == 4) {
6748c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
6758c2ecf20Sopenharmony_ci			col = 0;
6768c2ecf20Sopenharmony_ci		}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci		if (col == 0) {
6798c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
6808c2ecf20Sopenharmony_ci		}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\nSPDIFO_BUFFER:\n");
6878c2ecf20Sopenharmony_ci	col = 0;
6888c2ecf20Sopenharmony_ci	for (i = SPDIFO_IP_OUTPUT_BUFFER1;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x30; i += sizeof(u32),col ++) {
6898c2ecf20Sopenharmony_ci		if (col == 4) {
6908c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
6918c2ecf20Sopenharmony_ci			col = 0;
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		if (col == 0) {
6958c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
6968c2ecf20Sopenharmony_ci		}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\n...\n");
7028c2ecf20Sopenharmony_ci	col = 0;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	for (i = SPDIFO_IP_OUTPUT_BUFFER1+0xD0;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x110; i += sizeof(u32),col ++) {
7058c2ecf20Sopenharmony_ci		if (col == 4) {
7068c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
7078c2ecf20Sopenharmony_ci			col = 0;
7088c2ecf20Sopenharmony_ci		}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci		if (col == 0) {
7118c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
7128c2ecf20Sopenharmony_ci		}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\nOUTPUT_SNOOP:\n");
7198c2ecf20Sopenharmony_ci	col = 0;
7208c2ecf20Sopenharmony_ci	for (i = OUTPUT_SNOOP_BUFFER;i < OUTPUT_SNOOP_BUFFER + 0x40; i += sizeof(u32),col ++) {
7218c2ecf20Sopenharmony_ci		if (col == 4) {
7228c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
7238c2ecf20Sopenharmony_ci			col = 0;
7248c2ecf20Sopenharmony_ci		}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		if (col == 0) {
7278c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
7288c2ecf20Sopenharmony_ci		}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\nCODEC_INPUT_BUF1: \n");
7348c2ecf20Sopenharmony_ci	col = 0;
7358c2ecf20Sopenharmony_ci	for (i = CODEC_INPUT_BUF1;i < CODEC_INPUT_BUF1 + 0x40; i += sizeof(u32),col ++) {
7368c2ecf20Sopenharmony_ci		if (col == 4) {
7378c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
7388c2ecf20Sopenharmony_ci			col = 0;
7398c2ecf20Sopenharmony_ci		}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		if (col == 0) {
7428c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci#if 0
7488c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n");
7498c2ecf20Sopenharmony_ci	col = 0;
7508c2ecf20Sopenharmony_ci	for (i = WRITE_BACK_BUF1;i < WRITE_BACK_BUF1 + 0x40; i += sizeof(u32),col ++) {
7518c2ecf20Sopenharmony_ci		if (col == 4) {
7528c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
7538c2ecf20Sopenharmony_ci			col = 0;
7548c2ecf20Sopenharmony_ci		}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci		if (col == 0) {
7578c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
7588c2ecf20Sopenharmony_ci		}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
7618c2ecf20Sopenharmony_ci	}
7628c2ecf20Sopenharmony_ci#endif
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\nSPDIFI_IP_OUTPUT_BUFFER1: \n");
7658c2ecf20Sopenharmony_ci	col = 0;
7668c2ecf20Sopenharmony_ci	for (i = SPDIFI_IP_OUTPUT_BUFFER1;i < SPDIFI_IP_OUTPUT_BUFFER1 + 0x80; i += sizeof(u32),col ++) {
7678c2ecf20Sopenharmony_ci		if (col == 4) {
7688c2ecf20Sopenharmony_ci			snd_iprintf(buffer,"\n");
7698c2ecf20Sopenharmony_ci			col = 0;
7708c2ecf20Sopenharmony_ci		}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci		if (col == 0) {
7738c2ecf20Sopenharmony_ci			snd_iprintf(buffer, "%04X ",i);
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci		snd_iprintf(buffer,"%08X ",readl(dst + i));
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci	snd_iprintf(buffer,"\n");
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ciint cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct snd_info_entry *entry;
7848c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
7858c2ecf20Sopenharmony_ci	int i;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	ins->snd_card = card;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	entry = snd_info_create_card_entry(card, "dsp", card->proc_root);
7908c2ecf20Sopenharmony_ci	if (entry)
7918c2ecf20Sopenharmony_ci		entry->mode = S_IFDIR | 0555;
7928c2ecf20Sopenharmony_ci	ins->proc_dsp_dir = entry;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (!ins->proc_dsp_dir)
7958c2ecf20Sopenharmony_ci		return -ENOMEM;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	entry = snd_info_create_card_entry(card, "spos_symbols",
7988c2ecf20Sopenharmony_ci					   ins->proc_dsp_dir);
7998c2ecf20Sopenharmony_ci	if (entry)
8008c2ecf20Sopenharmony_ci		snd_info_set_text_ops(entry, chip,
8018c2ecf20Sopenharmony_ci				      cs46xx_dsp_proc_symbol_table_read);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	entry = snd_info_create_card_entry(card, "spos_modules",
8048c2ecf20Sopenharmony_ci					   ins->proc_dsp_dir);
8058c2ecf20Sopenharmony_ci	if (entry)
8068c2ecf20Sopenharmony_ci		snd_info_set_text_ops(entry, chip,
8078c2ecf20Sopenharmony_ci				      cs46xx_dsp_proc_modules_read);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	entry = snd_info_create_card_entry(card, "parameter",
8108c2ecf20Sopenharmony_ci					   ins->proc_dsp_dir);
8118c2ecf20Sopenharmony_ci	if (entry)
8128c2ecf20Sopenharmony_ci		snd_info_set_text_ops(entry, chip,
8138c2ecf20Sopenharmony_ci				      cs46xx_dsp_proc_parameter_dump_read);
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	entry = snd_info_create_card_entry(card, "sample",
8168c2ecf20Sopenharmony_ci					   ins->proc_dsp_dir);
8178c2ecf20Sopenharmony_ci	if (entry)
8188c2ecf20Sopenharmony_ci		snd_info_set_text_ops(entry, chip,
8198c2ecf20Sopenharmony_ci				      cs46xx_dsp_proc_sample_dump_read);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	entry = snd_info_create_card_entry(card, "task_tree",
8228c2ecf20Sopenharmony_ci					   ins->proc_dsp_dir);
8238c2ecf20Sopenharmony_ci	if (entry)
8248c2ecf20Sopenharmony_ci		snd_info_set_text_ops(entry, chip,
8258c2ecf20Sopenharmony_ci				      cs46xx_dsp_proc_task_tree_read);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	entry = snd_info_create_card_entry(card, "scb_info",
8288c2ecf20Sopenharmony_ci					   ins->proc_dsp_dir);
8298c2ecf20Sopenharmony_ci	if (entry)
8308c2ecf20Sopenharmony_ci		snd_info_set_text_ops(entry, chip,
8318c2ecf20Sopenharmony_ci				      cs46xx_dsp_proc_scb_read);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
8348c2ecf20Sopenharmony_ci	/* register/update SCB's entries on proc */
8358c2ecf20Sopenharmony_ci	for (i = 0; i < ins->nscb; ++i) {
8368c2ecf20Sopenharmony_ci		if (ins->scbs[i].deleted) continue;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci		cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	return 0;
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ciint cs46xx_dsp_proc_done (struct snd_cs46xx *chip)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
8488c2ecf20Sopenharmony_ci	int i;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	if (!ins)
8518c2ecf20Sopenharmony_ci		return 0;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
8548c2ecf20Sopenharmony_ci	for (i = 0; i < ins->nscb; ++i) {
8558c2ecf20Sopenharmony_ci		if (ins->scbs[i].deleted) continue;
8568c2ecf20Sopenharmony_ci		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	snd_info_free_entry(ins->proc_dsp_dir);
8618c2ecf20Sopenharmony_ci	ins->proc_dsp_dir = NULL;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	return 0;
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci#endif /* CONFIG_SND_PROC_FS */
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data,
8688c2ecf20Sopenharmony_ci				   u32  dest, int size)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	void __iomem *spdst = chip->region.idx[1].remap_addr +
8718c2ecf20Sopenharmony_ci		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
8728c2ecf20Sopenharmony_ci	int i;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	for (i = 0; i < size; ++i) {
8758c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "addr %p, val %08x\n",
8768c2ecf20Sopenharmony_ci			spdst, task_data[i]);
8778c2ecf20Sopenharmony_ci		writel(task_data[i],spdst);
8788c2ecf20Sopenharmony_ci		spdst += sizeof(u32);
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_cistatic void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	void __iomem *spdst = chip->region.idx[1].remap_addr +
8858c2ecf20Sopenharmony_ci		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
8868c2ecf20Sopenharmony_ci	int i;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	for (i = 0; i < 0x10; ++i) {
8898c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "addr %p, val %08x\n",
8908c2ecf20Sopenharmony_ci			spdst, scb_data[i]);
8918c2ecf20Sopenharmony_ci		writel(scb_data[i],spdst);
8928c2ecf20Sopenharmony_ci		spdst += sizeof(u32);
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_cistatic int find_free_scb_index (struct dsp_spos_instance * ins)
8978c2ecf20Sopenharmony_ci{
8988c2ecf20Sopenharmony_ci	int index = ins->nscb, i;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	for (i = ins->scb_highest_frag_index; i < ins->nscb; ++i) {
9018c2ecf20Sopenharmony_ci		if (ins->scbs[i].deleted) {
9028c2ecf20Sopenharmony_ci			index = i;
9038c2ecf20Sopenharmony_ci			break;
9048c2ecf20Sopenharmony_ci		}
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	return index;
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cistatic struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * name, u32 dest)
9118c2ecf20Sopenharmony_ci{
9128c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
9138c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * desc = NULL;
9148c2ecf20Sopenharmony_ci	int index;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	if (ins->nscb == DSP_MAX_SCB_DESC - 1) {
9178c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
9188c2ecf20Sopenharmony_ci			"dsp_spos: got no place for other SCB\n");
9198c2ecf20Sopenharmony_ci		return NULL;
9208c2ecf20Sopenharmony_ci	}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	index = find_free_scb_index (ins);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	memset(&ins->scbs[index], 0, sizeof(ins->scbs[index]));
9258c2ecf20Sopenharmony_ci	strcpy(ins->scbs[index].scb_name, name);
9268c2ecf20Sopenharmony_ci	ins->scbs[index].address = dest;
9278c2ecf20Sopenharmony_ci	ins->scbs[index].index = index;
9288c2ecf20Sopenharmony_ci	ins->scbs[index].ref_count = 1;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	desc = (ins->scbs + index);
9318c2ecf20Sopenharmony_ci	ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	if (index > ins->scb_highest_frag_index)
9348c2ecf20Sopenharmony_ci		ins->scb_highest_frag_index = index;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (index == ins->nscb)
9378c2ecf20Sopenharmony_ci		ins->nscb++;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	return desc;
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic struct dsp_task_descriptor *
9438c2ecf20Sopenharmony_ci_map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
9468c2ecf20Sopenharmony_ci	struct dsp_task_descriptor * desc = NULL;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	if (ins->ntask == DSP_MAX_TASK_DESC - 1) {
9498c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
9508c2ecf20Sopenharmony_ci			"dsp_spos: got no place for other TASK\n");
9518c2ecf20Sopenharmony_ci		return NULL;
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	if (name)
9558c2ecf20Sopenharmony_ci		strcpy(ins->tasks[ins->ntask].task_name, name);
9568c2ecf20Sopenharmony_ci	else
9578c2ecf20Sopenharmony_ci		strcpy(ins->tasks[ins->ntask].task_name, "(NULL)");
9588c2ecf20Sopenharmony_ci	ins->tasks[ins->ntask].address = dest;
9598c2ecf20Sopenharmony_ci	ins->tasks[ins->ntask].size = size;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	/* quick find in list */
9628c2ecf20Sopenharmony_ci	ins->tasks[ins->ntask].index = ins->ntask;
9638c2ecf20Sopenharmony_ci	desc = (ins->tasks + ins->ntask);
9648c2ecf20Sopenharmony_ci	ins->ntask++;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	if (name)
9678c2ecf20Sopenharmony_ci		add_symbol (chip,name,dest,SYMBOL_PARAMETER);
9688c2ecf20Sopenharmony_ci	return desc;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci#define SCB_BYTES	(0x10 * 4)
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_cistruct dsp_scb_descriptor *
9748c2ecf20Sopenharmony_cics46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * desc;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
9798c2ecf20Sopenharmony_ci	/* copy the data for resume */
9808c2ecf20Sopenharmony_ci	scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
9818c2ecf20Sopenharmony_ci	if (!scb_data)
9828c2ecf20Sopenharmony_ci		return NULL;
9838c2ecf20Sopenharmony_ci#endif
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	desc = _map_scb (chip,name,dest);
9868c2ecf20Sopenharmony_ci	if (desc) {
9878c2ecf20Sopenharmony_ci		desc->data = scb_data;
9888c2ecf20Sopenharmony_ci		_dsp_create_scb(chip,scb_data,dest);
9898c2ecf20Sopenharmony_ci	} else {
9908c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "dsp_spos: failed to map SCB\n");
9918c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
9928c2ecf20Sopenharmony_ci		kfree(scb_data);
9938c2ecf20Sopenharmony_ci#endif
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	return desc;
9978c2ecf20Sopenharmony_ci}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cistatic struct dsp_task_descriptor *
10018c2ecf20Sopenharmony_cics46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_data,
10028c2ecf20Sopenharmony_ci			     u32 dest, int size)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	struct dsp_task_descriptor * desc;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	desc = _map_task_tree (chip,name,dest,size);
10078c2ecf20Sopenharmony_ci	if (desc) {
10088c2ecf20Sopenharmony_ci		desc->data = task_data;
10098c2ecf20Sopenharmony_ci		_dsp_create_task_tree(chip,task_data,dest,size);
10108c2ecf20Sopenharmony_ci	} else {
10118c2ecf20Sopenharmony_ci		dev_err(chip->card->dev, "dsp_spos: failed to map TASK\n");
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	return desc;
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ciint cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
10208c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * fg_task_tree_header_code;
10218c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * task_tree_header_code;
10228c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * task_tree_thread;
10238c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * null_algorithm;
10248c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * magic_snoop_task;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * timing_master_scb;
10278c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * codec_out_scb;
10288c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * codec_in_scb;
10298c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * src_task_scb;
10308c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * master_mix_scb;
10318c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * rear_mix_scb;
10328c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * record_mix_scb;
10338c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * write_back_scb;
10348c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * vari_decimate_scb;
10358c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * rear_codec_out_scb;
10368c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * clfe_codec_out_scb;
10378c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * magic_snoop_scb;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	int fifo_addr, fifo_span, valid_slots;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	static const struct dsp_spos_control_block sposcb = {
10428c2ecf20Sopenharmony_ci		/* 0 */ HFG_TREE_SCB,HFG_STACK,
10438c2ecf20Sopenharmony_ci		/* 1 */ SPOSCB_ADDR,BG_TREE_SCB_ADDR,
10448c2ecf20Sopenharmony_ci		/* 2 */ DSP_SPOS_DC,0,
10458c2ecf20Sopenharmony_ci		/* 3 */ DSP_SPOS_DC,DSP_SPOS_DC,
10468c2ecf20Sopenharmony_ci		/* 4 */ 0,0,
10478c2ecf20Sopenharmony_ci		/* 5 */ DSP_SPOS_UU,0,
10488c2ecf20Sopenharmony_ci		/* 6 */ FG_TASK_HEADER_ADDR,0,
10498c2ecf20Sopenharmony_ci		/* 7 */ 0,0,
10508c2ecf20Sopenharmony_ci		/* 8 */ DSP_SPOS_UU,DSP_SPOS_DC,
10518c2ecf20Sopenharmony_ci		/* 9 */ 0,
10528c2ecf20Sopenharmony_ci		/* A */ 0,HFG_FIRST_EXECUTE_MODE,
10538c2ecf20Sopenharmony_ci		/* B */ DSP_SPOS_UU,DSP_SPOS_UU,
10548c2ecf20Sopenharmony_ci		/* C */ DSP_SPOS_DC_DC,
10558c2ecf20Sopenharmony_ci		/* D */ DSP_SPOS_DC_DC,
10568c2ecf20Sopenharmony_ci		/* E */ DSP_SPOS_DC_DC,
10578c2ecf20Sopenharmony_ci		/* F */ DSP_SPOS_DC_DC
10588c2ecf20Sopenharmony_ci	};
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	cs46xx_dsp_create_task_tree(chip, "sposCB", (u32 *)&sposcb, SPOSCB_ADDR, 0x10);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	null_algorithm  = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE);
10638c2ecf20Sopenharmony_ci	if (null_algorithm == NULL) {
10648c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
10658c2ecf20Sopenharmony_ci			"dsp_spos: symbol NULLALGORITHM not found\n");
10668c2ecf20Sopenharmony_ci		return -EIO;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE);
10708c2ecf20Sopenharmony_ci	if (fg_task_tree_header_code == NULL) {
10718c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
10728c2ecf20Sopenharmony_ci			"dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
10738c2ecf20Sopenharmony_ci		return -EIO;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE);
10778c2ecf20Sopenharmony_ci	if (task_tree_header_code == NULL) {
10788c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
10798c2ecf20Sopenharmony_ci			"dsp_spos: symbol TASKTREEHEADERCODE not found\n");
10808c2ecf20Sopenharmony_ci		return -EIO;
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE);
10848c2ecf20Sopenharmony_ci	if (task_tree_thread == NULL) {
10858c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
10868c2ecf20Sopenharmony_ci			"dsp_spos: symbol TASKTREETHREAD not found\n");
10878c2ecf20Sopenharmony_ci		return -EIO;
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE);
10918c2ecf20Sopenharmony_ci	if (magic_snoop_task == NULL) {
10928c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
10938c2ecf20Sopenharmony_ci			"dsp_spos: symbol MAGICSNOOPTASK not found\n");
10948c2ecf20Sopenharmony_ci		return -EIO;
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	{
10988c2ecf20Sopenharmony_ci		/* create the null SCB */
10998c2ecf20Sopenharmony_ci		static struct dsp_generic_scb null_scb = {
11008c2ecf20Sopenharmony_ci			{ 0, 0, 0, 0 },
11018c2ecf20Sopenharmony_ci			{ 0, 0, 0, 0, 0 },
11028c2ecf20Sopenharmony_ci			NULL_SCB_ADDR, NULL_SCB_ADDR,
11038c2ecf20Sopenharmony_ci			0, 0, 0, 0, 0,
11048c2ecf20Sopenharmony_ci			{
11058c2ecf20Sopenharmony_ci				0,0,
11068c2ecf20Sopenharmony_ci				0,0,
11078c2ecf20Sopenharmony_ci			}
11088c2ecf20Sopenharmony_ci		};
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci		null_scb.entry_point = null_algorithm->address;
11118c2ecf20Sopenharmony_ci		ins->the_null_scb = cs46xx_dsp_create_scb(chip, "nullSCB", (u32 *)&null_scb, NULL_SCB_ADDR);
11128c2ecf20Sopenharmony_ci		ins->the_null_scb->task_entry = null_algorithm;
11138c2ecf20Sopenharmony_ci		ins->the_null_scb->sub_list_ptr = ins->the_null_scb;
11148c2ecf20Sopenharmony_ci		ins->the_null_scb->next_scb_ptr = ins->the_null_scb;
11158c2ecf20Sopenharmony_ci		ins->the_null_scb->parent_scb_ptr = NULL;
11168c2ecf20Sopenharmony_ci		cs46xx_dsp_proc_register_scb_desc (chip,ins->the_null_scb);
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	{
11208c2ecf20Sopenharmony_ci		/* setup foreground task tree */
11218c2ecf20Sopenharmony_ci		static struct dsp_task_tree_control_block fg_task_tree_hdr =  {
11228c2ecf20Sopenharmony_ci			{ FG_TASK_HEADER_ADDR | (DSP_SPOS_DC << 0x10),
11238c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
11248c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
11258c2ecf20Sopenharmony_ci			  0x0000,DSP_SPOS_DC,
11268c2ecf20Sopenharmony_ci			  DSP_SPOS_DC, DSP_SPOS_DC,
11278c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
11288c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
11298c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
11308c2ecf20Sopenharmony_ci			  DSP_SPOS_DC,DSP_SPOS_DC },
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci			{
11338c2ecf20Sopenharmony_ci				BG_TREE_SCB_ADDR,TIMINGMASTER_SCB_ADDR,
11348c2ecf20Sopenharmony_ci				0,
11358c2ecf20Sopenharmony_ci				FG_TASK_HEADER_ADDR + TCBData,
11368c2ecf20Sopenharmony_ci			},
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci			{
11398c2ecf20Sopenharmony_ci				4,0,
11408c2ecf20Sopenharmony_ci				1,0,
11418c2ecf20Sopenharmony_ci				2,SPOSCB_ADDR + HFGFlags,
11428c2ecf20Sopenharmony_ci				0,0,
11438c2ecf20Sopenharmony_ci				FG_TASK_HEADER_ADDR + TCBContextBlk,FG_STACK
11448c2ecf20Sopenharmony_ci			},
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci			{
11478c2ecf20Sopenharmony_ci				DSP_SPOS_DC,0,
11488c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
11498c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
11508c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
11518c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
11528c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11538c2ecf20Sopenharmony_ci				DSP_SPOS_UU,1,
11548c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11558c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11568c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11578c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11588c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11598c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11608c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11618c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11628c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11638c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11648c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11658c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11668c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11678c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11688c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11698c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11708c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11718c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11728c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11738c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11748c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11758c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11768c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11778c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11788c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11798c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11808c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
11818c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC
11828c2ecf20Sopenharmony_ci			},
11838c2ecf20Sopenharmony_ci			{
11848c2ecf20Sopenharmony_ci				FG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
11858c2ecf20Sopenharmony_ci				0,0
11868c2ecf20Sopenharmony_ci			}
11878c2ecf20Sopenharmony_ci		};
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci		fg_task_tree_hdr.links.entry_point = fg_task_tree_header_code->address;
11908c2ecf20Sopenharmony_ci		fg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
11918c2ecf20Sopenharmony_ci		cs46xx_dsp_create_task_tree(chip,"FGtaskTreeHdr",(u32 *)&fg_task_tree_hdr,FG_TASK_HEADER_ADDR,0x35);
11928c2ecf20Sopenharmony_ci	}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	{
11968c2ecf20Sopenharmony_ci		/* setup foreground task tree */
11978c2ecf20Sopenharmony_ci		static struct dsp_task_tree_control_block bg_task_tree_hdr =  {
11988c2ecf20Sopenharmony_ci			{ DSP_SPOS_DC_DC,
11998c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
12008c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
12018c2ecf20Sopenharmony_ci			  DSP_SPOS_DC, DSP_SPOS_DC,
12028c2ecf20Sopenharmony_ci			  DSP_SPOS_DC, DSP_SPOS_DC,
12038c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
12048c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
12058c2ecf20Sopenharmony_ci			  DSP_SPOS_DC_DC,
12068c2ecf20Sopenharmony_ci			  DSP_SPOS_DC,DSP_SPOS_DC },
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci			{
12098c2ecf20Sopenharmony_ci				NULL_SCB_ADDR,NULL_SCB_ADDR,  /* Set up the background to do nothing */
12108c2ecf20Sopenharmony_ci				0,
12118c2ecf20Sopenharmony_ci				BG_TREE_SCB_ADDR + TCBData,
12128c2ecf20Sopenharmony_ci			},
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci			{
12158c2ecf20Sopenharmony_ci				9999,0,
12168c2ecf20Sopenharmony_ci				0,1,
12178c2ecf20Sopenharmony_ci				0,SPOSCB_ADDR + HFGFlags,
12188c2ecf20Sopenharmony_ci				0,0,
12198c2ecf20Sopenharmony_ci				BG_TREE_SCB_ADDR + TCBContextBlk,BG_STACK
12208c2ecf20Sopenharmony_ci			},
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci			{
12238c2ecf20Sopenharmony_ci				DSP_SPOS_DC,0,
12248c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
12258c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
12268c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
12278c2ecf20Sopenharmony_ci				DSP_SPOS_DC,DSP_SPOS_DC,
12288c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12298c2ecf20Sopenharmony_ci				DSP_SPOS_UU,1,
12308c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12318c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12328c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12338c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12348c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12358c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12368c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12378c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12388c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12398c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12408c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12418c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12428c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12438c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12448c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12458c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12468c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12478c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12488c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12498c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12508c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12518c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12528c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12538c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12548c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12558c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12568c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC,
12578c2ecf20Sopenharmony_ci				DSP_SPOS_DCDC
12588c2ecf20Sopenharmony_ci			},
12598c2ecf20Sopenharmony_ci			{
12608c2ecf20Sopenharmony_ci				BG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
12618c2ecf20Sopenharmony_ci				0,0
12628c2ecf20Sopenharmony_ci			}
12638c2ecf20Sopenharmony_ci		};
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci		bg_task_tree_hdr.links.entry_point = task_tree_header_code->address;
12668c2ecf20Sopenharmony_ci		bg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
12678c2ecf20Sopenharmony_ci		cs46xx_dsp_create_task_tree(chip,"BGtaskTreeHdr",(u32 *)&bg_task_tree_hdr,BG_TREE_SCB_ADDR,0x35);
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	/* create timing master SCB */
12718c2ecf20Sopenharmony_ci	timing_master_scb = cs46xx_dsp_create_timing_master_scb(chip);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	/* create the CODEC output task */
12748c2ecf20Sopenharmony_ci	codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_I",0x0010,0x0000,
12758c2ecf20Sopenharmony_ci							MASTERMIX_SCB_ADDR,
12768c2ecf20Sopenharmony_ci							CODECOUT_SCB_ADDR,timing_master_scb,
12778c2ecf20Sopenharmony_ci							SCB_ON_PARENT_SUBLIST_SCB);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (!codec_out_scb) goto _fail_end;
12808c2ecf20Sopenharmony_ci	/* create the master mix SCB */
12818c2ecf20Sopenharmony_ci	master_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"MasterMixSCB",
12828c2ecf20Sopenharmony_ci							MIX_SAMPLE_BUF1,MASTERMIX_SCB_ADDR,
12838c2ecf20Sopenharmony_ci							codec_out_scb,
12848c2ecf20Sopenharmony_ci							SCB_ON_PARENT_SUBLIST_SCB);
12858c2ecf20Sopenharmony_ci	ins->master_mix_scb = master_mix_scb;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	if (!master_mix_scb) goto _fail_end;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	/* create codec in */
12908c2ecf20Sopenharmony_ci	codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0,
12918c2ecf20Sopenharmony_ci						      CODEC_INPUT_BUF1,
12928c2ecf20Sopenharmony_ci						      CODECIN_SCB_ADDR,codec_out_scb,
12938c2ecf20Sopenharmony_ci						      SCB_ON_PARENT_NEXT_SCB);
12948c2ecf20Sopenharmony_ci	if (!codec_in_scb) goto _fail_end;
12958c2ecf20Sopenharmony_ci	ins->codec_in_scb = codec_in_scb;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	/* create write back scb */
12988c2ecf20Sopenharmony_ci	write_back_scb = cs46xx_dsp_create_mix_to_ostream_scb(chip,"WriteBackSCB",
12998c2ecf20Sopenharmony_ci							      WRITE_BACK_BUF1,WRITE_BACK_SPB,
13008c2ecf20Sopenharmony_ci							      WRITEBACK_SCB_ADDR,
13018c2ecf20Sopenharmony_ci							      timing_master_scb,
13028c2ecf20Sopenharmony_ci							      SCB_ON_PARENT_NEXT_SCB);
13038c2ecf20Sopenharmony_ci	if (!write_back_scb) goto _fail_end;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	{
13068c2ecf20Sopenharmony_ci		static struct dsp_mix2_ostream_spb mix2_ostream_spb = {
13078c2ecf20Sopenharmony_ci			0x00020000,
13088c2ecf20Sopenharmony_ci			0x0000ffff
13098c2ecf20Sopenharmony_ci		};
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci		if (!cs46xx_dsp_create_task_tree(chip, NULL,
13128c2ecf20Sopenharmony_ci						 (u32 *)&mix2_ostream_spb,
13138c2ecf20Sopenharmony_ci						 WRITE_BACK_SPB, 2))
13148c2ecf20Sopenharmony_ci			goto _fail_end;
13158c2ecf20Sopenharmony_ci	}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	/* input sample converter */
13188c2ecf20Sopenharmony_ci	vari_decimate_scb = cs46xx_dsp_create_vari_decimate_scb(chip,"VariDecimateSCB",
13198c2ecf20Sopenharmony_ci								VARI_DECIMATE_BUF0,
13208c2ecf20Sopenharmony_ci								VARI_DECIMATE_BUF1,
13218c2ecf20Sopenharmony_ci								VARIDECIMATE_SCB_ADDR,
13228c2ecf20Sopenharmony_ci								write_back_scb,
13238c2ecf20Sopenharmony_ci								SCB_ON_PARENT_SUBLIST_SCB);
13248c2ecf20Sopenharmony_ci	if (!vari_decimate_scb) goto _fail_end;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	/* create the record mixer SCB */
13278c2ecf20Sopenharmony_ci	record_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RecordMixerSCB",
13288c2ecf20Sopenharmony_ci							MIX_SAMPLE_BUF2,
13298c2ecf20Sopenharmony_ci							RECORD_MIXER_SCB_ADDR,
13308c2ecf20Sopenharmony_ci							vari_decimate_scb,
13318c2ecf20Sopenharmony_ci							SCB_ON_PARENT_SUBLIST_SCB);
13328c2ecf20Sopenharmony_ci	ins->record_mixer_scb = record_mix_scb;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	if (!record_mix_scb) goto _fail_end;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (snd_BUG_ON(chip->nr_ac97_codecs != 1 && chip->nr_ac97_codecs != 2))
13398c2ecf20Sopenharmony_ci		goto _fail_end;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	if (chip->nr_ac97_codecs == 1) {
13428c2ecf20Sopenharmony_ci		/* output on slot 5 and 11
13438c2ecf20Sopenharmony_ci		   on primary CODEC */
13448c2ecf20Sopenharmony_ci		fifo_addr = 0x20;
13458c2ecf20Sopenharmony_ci		fifo_span = 0x60;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci		/* enable slot 5 and 11 */
13488c2ecf20Sopenharmony_ci		valid_slots |= ACOSV_SLV5 | ACOSV_SLV11;
13498c2ecf20Sopenharmony_ci	} else {
13508c2ecf20Sopenharmony_ci		/* output on slot 7 and 8
13518c2ecf20Sopenharmony_ci		   on secondary CODEC */
13528c2ecf20Sopenharmony_ci		fifo_addr = 0x40;
13538c2ecf20Sopenharmony_ci		fifo_span = 0x10;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci		/* enable slot 7 and 8 */
13568c2ecf20Sopenharmony_ci		valid_slots |= ACOSV_SLV7 | ACOSV_SLV8;
13578c2ecf20Sopenharmony_ci	}
13588c2ecf20Sopenharmony_ci	/* create CODEC tasklet for rear speakers output*/
13598c2ecf20Sopenharmony_ci	rear_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_Rear",fifo_span,fifo_addr,
13608c2ecf20Sopenharmony_ci							     REAR_MIXER_SCB_ADDR,
13618c2ecf20Sopenharmony_ci							     REAR_CODECOUT_SCB_ADDR,codec_in_scb,
13628c2ecf20Sopenharmony_ci							     SCB_ON_PARENT_NEXT_SCB);
13638c2ecf20Sopenharmony_ci	if (!rear_codec_out_scb) goto _fail_end;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	/* create the rear PCM channel  mixer SCB */
13678c2ecf20Sopenharmony_ci	rear_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RearMixerSCB",
13688c2ecf20Sopenharmony_ci						      MIX_SAMPLE_BUF3,
13698c2ecf20Sopenharmony_ci						      REAR_MIXER_SCB_ADDR,
13708c2ecf20Sopenharmony_ci						      rear_codec_out_scb,
13718c2ecf20Sopenharmony_ci						      SCB_ON_PARENT_SUBLIST_SCB);
13728c2ecf20Sopenharmony_ci	ins->rear_mix_scb = rear_mix_scb;
13738c2ecf20Sopenharmony_ci	if (!rear_mix_scb) goto _fail_end;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (chip->nr_ac97_codecs == 2) {
13768c2ecf20Sopenharmony_ci		/* create CODEC tasklet for rear Center/LFE output
13778c2ecf20Sopenharmony_ci		   slot 6 and 9 on secondary CODEC */
13788c2ecf20Sopenharmony_ci		clfe_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_CLFE",0x0030,0x0030,
13798c2ecf20Sopenharmony_ci								     CLFE_MIXER_SCB_ADDR,
13808c2ecf20Sopenharmony_ci								     CLFE_CODEC_SCB_ADDR,
13818c2ecf20Sopenharmony_ci								     rear_codec_out_scb,
13828c2ecf20Sopenharmony_ci								     SCB_ON_PARENT_NEXT_SCB);
13838c2ecf20Sopenharmony_ci		if (!clfe_codec_out_scb) goto _fail_end;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		/* create the rear PCM channel  mixer SCB */
13878c2ecf20Sopenharmony_ci		ins->center_lfe_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"CLFEMixerSCB",
13888c2ecf20Sopenharmony_ci									 MIX_SAMPLE_BUF4,
13898c2ecf20Sopenharmony_ci									 CLFE_MIXER_SCB_ADDR,
13908c2ecf20Sopenharmony_ci									 clfe_codec_out_scb,
13918c2ecf20Sopenharmony_ci									 SCB_ON_PARENT_SUBLIST_SCB);
13928c2ecf20Sopenharmony_ci		if (!ins->center_lfe_mix_scb) goto _fail_end;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci		/* enable slot 6 and 9 */
13958c2ecf20Sopenharmony_ci		valid_slots |= ACOSV_SLV6 | ACOSV_SLV9;
13968c2ecf20Sopenharmony_ci	} else {
13978c2ecf20Sopenharmony_ci		clfe_codec_out_scb = rear_codec_out_scb;
13988c2ecf20Sopenharmony_ci		ins->center_lfe_mix_scb = rear_mix_scb;
13998c2ecf20Sopenharmony_ci	}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	/* enable slots depending on CODEC configuration */
14028c2ecf20Sopenharmony_ci	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	/* the magic snooper */
14058c2ecf20Sopenharmony_ci	magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR,
14068c2ecf20Sopenharmony_ci							     OUTPUT_SNOOP_BUFFER,
14078c2ecf20Sopenharmony_ci							     codec_out_scb,
14088c2ecf20Sopenharmony_ci							     clfe_codec_out_scb,
14098c2ecf20Sopenharmony_ci							     SCB_ON_PARENT_NEXT_SCB);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (!magic_snoop_scb) goto _fail_end;
14138c2ecf20Sopenharmony_ci	ins->ref_snoop_scb = magic_snoop_scb;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	/* SP IO access */
14168c2ecf20Sopenharmony_ci	if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR,
14178c2ecf20Sopenharmony_ci					      magic_snoop_scb,
14188c2ecf20Sopenharmony_ci					      SCB_ON_PARENT_NEXT_SCB))
14198c2ecf20Sopenharmony_ci		goto _fail_end;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	/* SPDIF input sampel rate converter */
14228c2ecf20Sopenharmony_ci	src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
14238c2ecf20Sopenharmony_ci						      ins->spdif_in_sample_rate,
14248c2ecf20Sopenharmony_ci						      SRC_OUTPUT_BUF1,
14258c2ecf20Sopenharmony_ci						      SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
14268c2ecf20Sopenharmony_ci						      master_mix_scb,
14278c2ecf20Sopenharmony_ci						      SCB_ON_PARENT_SUBLIST_SCB,1);
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	if (!src_task_scb) goto _fail_end;
14308c2ecf20Sopenharmony_ci	cs46xx_src_unlink(chip,src_task_scb);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	/* NOTE: when we now how to detect the SPDIF input
14338c2ecf20Sopenharmony_ci	   sample rate we will use this SRC to adjust it */
14348c2ecf20Sopenharmony_ci	ins->spdif_in_src = src_task_scb;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	cs46xx_dsp_async_init(chip,timing_master_scb);
14378c2ecf20Sopenharmony_ci	return 0;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci _fail_end:
14408c2ecf20Sopenharmony_ci	dev_err(chip->card->dev, "dsp_spos: failed to setup SCB's in DSP\n");
14418c2ecf20Sopenharmony_ci	return -EINVAL;
14428c2ecf20Sopenharmony_ci}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_cistatic int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
14458c2ecf20Sopenharmony_ci				  struct dsp_scb_descriptor * fg_entry)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
14488c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * s16_async_codec_input_task;
14498c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * spdifo_task;
14508c2ecf20Sopenharmony_ci	struct dsp_symbol_entry * spdifi_task;
14518c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * spdifi_scb_desc, * spdifo_scb_desc, * async_codec_scb_desc;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE);
14548c2ecf20Sopenharmony_ci	if (s16_async_codec_input_task == NULL) {
14558c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
14568c2ecf20Sopenharmony_ci			"dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
14578c2ecf20Sopenharmony_ci		return -EIO;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci	spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE);
14608c2ecf20Sopenharmony_ci	if (spdifo_task == NULL) {
14618c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
14628c2ecf20Sopenharmony_ci			"dsp_spos: symbol SPDIFOTASK not found\n");
14638c2ecf20Sopenharmony_ci		return -EIO;
14648c2ecf20Sopenharmony_ci	}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE);
14678c2ecf20Sopenharmony_ci	if (spdifi_task == NULL) {
14688c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
14698c2ecf20Sopenharmony_ci			"dsp_spos: symbol SPDIFITASK not found\n");
14708c2ecf20Sopenharmony_ci		return -EIO;
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	{
14748c2ecf20Sopenharmony_ci		/* 0xBC0 */
14758c2ecf20Sopenharmony_ci		struct dsp_spdifoscb spdifo_scb = {
14768c2ecf20Sopenharmony_ci			/* 0 */ DSP_SPOS_UUUU,
14778c2ecf20Sopenharmony_ci			{
14788c2ecf20Sopenharmony_ci				/* 1 */ 0xb0,
14798c2ecf20Sopenharmony_ci				/* 2 */ 0,
14808c2ecf20Sopenharmony_ci				/* 3 */ 0,
14818c2ecf20Sopenharmony_ci				/* 4 */ 0,
14828c2ecf20Sopenharmony_ci			},
14838c2ecf20Sopenharmony_ci			/* NOTE: the SPDIF output task read samples in mono
14848c2ecf20Sopenharmony_ci			   format, the AsynchFGTxSCB task writes to buffer
14858c2ecf20Sopenharmony_ci			   in stereo format
14868c2ecf20Sopenharmony_ci			*/
14878c2ecf20Sopenharmony_ci			/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_256,
14888c2ecf20Sopenharmony_ci			/* 6 */ ( SPDIFO_IP_OUTPUT_BUFFER1 << 0x10 )  |  0xFFFC,
14898c2ecf20Sopenharmony_ci			/* 7 */ 0,0,
14908c2ecf20Sopenharmony_ci			/* 8 */ 0,
14918c2ecf20Sopenharmony_ci			/* 9 */ FG_TASK_HEADER_ADDR, NULL_SCB_ADDR,
14928c2ecf20Sopenharmony_ci			/* A */ spdifo_task->address,
14938c2ecf20Sopenharmony_ci			SPDIFO_SCB_INST + SPDIFOFIFOPointer,
14948c2ecf20Sopenharmony_ci			{
14958c2ecf20Sopenharmony_ci				/* B */ 0x0040, /*DSP_SPOS_UUUU,*/
14968c2ecf20Sopenharmony_ci				/* C */ 0x20ff, /*DSP_SPOS_UUUU,*/
14978c2ecf20Sopenharmony_ci			},
14988c2ecf20Sopenharmony_ci			/* D */ 0x804c,0,							  /* SPDIFOFIFOPointer:SPDIFOStatRegAddr; */
14998c2ecf20Sopenharmony_ci			/* E */ 0x0108,0x0001,					  /* SPDIFOStMoFormat:SPDIFOFIFOBaseAddr; */
15008c2ecf20Sopenharmony_ci			/* F */ DSP_SPOS_UUUU	  			          /* SPDIFOFree; */
15018c2ecf20Sopenharmony_ci		};
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci		/* 0xBB0 */
15048c2ecf20Sopenharmony_ci		struct dsp_spdifiscb spdifi_scb = {
15058c2ecf20Sopenharmony_ci			/* 0 */ DSP_SPOS_UULO,DSP_SPOS_UUHI,
15068c2ecf20Sopenharmony_ci			/* 1 */ 0,
15078c2ecf20Sopenharmony_ci			/* 2 */ 0,
15088c2ecf20Sopenharmony_ci			/* 3 */ 1,4000,        /* SPDIFICountLimit SPDIFICount */
15098c2ecf20Sopenharmony_ci			/* 4 */ DSP_SPOS_UUUU, /* SPDIFIStatusData */
15108c2ecf20Sopenharmony_ci			/* 5 */ 0,DSP_SPOS_UUHI, /* StatusData, Free4 */
15118c2ecf20Sopenharmony_ci			/* 6 */ DSP_SPOS_UUUU,  /* Free3 */
15128c2ecf20Sopenharmony_ci			/* 7 */ DSP_SPOS_UU,DSP_SPOS_DC,  /* Free2 BitCount*/
15138c2ecf20Sopenharmony_ci			/* 8 */ DSP_SPOS_UUUU,	/* TempStatus */
15148c2ecf20Sopenharmony_ci			/* 9 */ SPDIFO_SCB_INST, NULL_SCB_ADDR,
15158c2ecf20Sopenharmony_ci			/* A */ spdifi_task->address,
15168c2ecf20Sopenharmony_ci			SPDIFI_SCB_INST + SPDIFIFIFOPointer,
15178c2ecf20Sopenharmony_ci			/* NOTE: The SPDIF input task write the sample in mono
15188c2ecf20Sopenharmony_ci			   format from the HW FIFO, the AsynchFGRxSCB task  reads
15198c2ecf20Sopenharmony_ci			   them in stereo
15208c2ecf20Sopenharmony_ci			*/
15218c2ecf20Sopenharmony_ci			/* B */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_128,
15228c2ecf20Sopenharmony_ci			/* C */ (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
15238c2ecf20Sopenharmony_ci			/* D */ 0x8048,0,
15248c2ecf20Sopenharmony_ci			/* E */ 0x01f0,0x0001,
15258c2ecf20Sopenharmony_ci			/* F */ DSP_SPOS_UUUU /* SPDIN_STATUS monitor */
15268c2ecf20Sopenharmony_ci		};
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci		/* 0xBA0 */
15298c2ecf20Sopenharmony_ci		struct dsp_async_codec_input_scb async_codec_input_scb = {
15308c2ecf20Sopenharmony_ci			/* 0 */ DSP_SPOS_UUUU,
15318c2ecf20Sopenharmony_ci			/* 1 */ 0,
15328c2ecf20Sopenharmony_ci			/* 2 */ 0,
15338c2ecf20Sopenharmony_ci			/* 3 */ 1,4000,
15348c2ecf20Sopenharmony_ci			/* 4 */ 0x0118,0x0001,
15358c2ecf20Sopenharmony_ci			/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_64,
15368c2ecf20Sopenharmony_ci			/* 6 */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
15378c2ecf20Sopenharmony_ci			/* 7 */ DSP_SPOS_UU,0x3,
15388c2ecf20Sopenharmony_ci			/* 8 */ DSP_SPOS_UUUU,
15398c2ecf20Sopenharmony_ci			/* 9 */ SPDIFI_SCB_INST,NULL_SCB_ADDR,
15408c2ecf20Sopenharmony_ci			/* A */ s16_async_codec_input_task->address,
15418c2ecf20Sopenharmony_ci			HFG_TREE_SCB + AsyncCIOFIFOPointer,
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci			/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
15448c2ecf20Sopenharmony_ci			/* C */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10),  /*(ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,*/
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci#ifdef UseASER1Input
15478c2ecf20Sopenharmony_ci			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
15488c2ecf20Sopenharmony_ci			   Init. 0000:8042: for ASER1
15498c2ecf20Sopenharmony_ci			   0000:8044: for ASER2 */
15508c2ecf20Sopenharmony_ci			/* D */ 0x8042,0,
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
15538c2ecf20Sopenharmony_ci			   Init 1 stero:8050 ASER1
15548c2ecf20Sopenharmony_ci			   Init 0  mono:8070 ASER2
15558c2ecf20Sopenharmony_ci			   Init 1 Stereo : 0100 ASER1 (Set by script) */
15568c2ecf20Sopenharmony_ci			/* E */ 0x0100,0x0001,
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci#endif
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci#ifdef UseASER2Input
15618c2ecf20Sopenharmony_ci			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
15628c2ecf20Sopenharmony_ci			   Init. 0000:8042: for ASER1
15638c2ecf20Sopenharmony_ci			   0000:8044: for ASER2 */
15648c2ecf20Sopenharmony_ci			/* D */ 0x8044,0,
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
15678c2ecf20Sopenharmony_ci			   Init 1 stero:8050 ASER1
15688c2ecf20Sopenharmony_ci			   Init 0  mono:8070 ASER2
15698c2ecf20Sopenharmony_ci			   Init 1 Stereo : 0100 ASER1 (Set by script) */
15708c2ecf20Sopenharmony_ci			/* E */ 0x0110,0x0001,
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci#endif
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci			/* short AsyncCIOutputBufModulo:AsyncCIFree;
15758c2ecf20Sopenharmony_ci			   AsyncCIOutputBufModulo: The modulo size for
15768c2ecf20Sopenharmony_ci			   the output buffer of this task */
15778c2ecf20Sopenharmony_ci			/* F */ 0, /* DSP_SPOS_UUUU */
15788c2ecf20Sopenharmony_ci		};
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci		spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci		if (snd_BUG_ON(!spdifo_scb_desc))
15838c2ecf20Sopenharmony_ci			return -EIO;
15848c2ecf20Sopenharmony_ci		spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
15858c2ecf20Sopenharmony_ci		if (snd_BUG_ON(!spdifi_scb_desc))
15868c2ecf20Sopenharmony_ci			return -EIO;
15878c2ecf20Sopenharmony_ci		async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB);
15888c2ecf20Sopenharmony_ci		if (snd_BUG_ON(!async_codec_scb_desc))
15898c2ecf20Sopenharmony_ci			return -EIO;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci		async_codec_scb_desc->parent_scb_ptr = NULL;
15928c2ecf20Sopenharmony_ci		async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc;
15938c2ecf20Sopenharmony_ci		async_codec_scb_desc->sub_list_ptr = ins->the_null_scb;
15948c2ecf20Sopenharmony_ci		async_codec_scb_desc->task_entry = s16_async_codec_input_task;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		spdifi_scb_desc->parent_scb_ptr = async_codec_scb_desc;
15978c2ecf20Sopenharmony_ci		spdifi_scb_desc->next_scb_ptr = spdifo_scb_desc;
15988c2ecf20Sopenharmony_ci		spdifi_scb_desc->sub_list_ptr = ins->the_null_scb;
15998c2ecf20Sopenharmony_ci		spdifi_scb_desc->task_entry = spdifi_task;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci		spdifo_scb_desc->parent_scb_ptr = spdifi_scb_desc;
16028c2ecf20Sopenharmony_ci		spdifo_scb_desc->next_scb_ptr = fg_entry;
16038c2ecf20Sopenharmony_ci		spdifo_scb_desc->sub_list_ptr = ins->the_null_scb;
16048c2ecf20Sopenharmony_ci		spdifo_scb_desc->task_entry = spdifo_task;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci		/* this one is faked, as the parnet of SPDIFO task
16078c2ecf20Sopenharmony_ci		   is the FG task tree */
16088c2ecf20Sopenharmony_ci		fg_entry->parent_scb_ptr = spdifo_scb_desc;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci		/* for proc fs */
16118c2ecf20Sopenharmony_ci		cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc);
16128c2ecf20Sopenharmony_ci		cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc);
16138c2ecf20Sopenharmony_ci		cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci		/* Async MASTER ENABLE, affects both SPDIF input and output */
16168c2ecf20Sopenharmony_ci		snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	return 0;
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_cistatic void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip)
16238c2ecf20Sopenharmony_ci{
16248c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	/* set SPDIF output FIFO slot */
16278c2ecf20Sopenharmony_ci	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0);
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	/* SPDIF output MASTER ENABLE */
16308c2ecf20Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0);
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	/* right and left validate bit */
16338c2ecf20Sopenharmony_ci	/*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);*/
16348c2ecf20Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x0);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	/* clear fifo pointer */
16378c2ecf20Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	/* monitor state */
16408c2ecf20Sopenharmony_ci	ins->spdif_status_out &= ~DSP_SPDIF_STATUS_HW_ENABLED;
16418c2ecf20Sopenharmony_ci}
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ciint cs46xx_dsp_enable_spdif_hw (struct snd_cs46xx *chip)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	/* if hw-ctrl already enabled, turn off to reset logic ... */
16488c2ecf20Sopenharmony_ci	cs46xx_dsp_disable_spdif_hw (chip);
16498c2ecf20Sopenharmony_ci	udelay(50);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	/* set SPDIF output FIFO slot */
16528c2ecf20Sopenharmony_ci	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, ( 0x8000 | ((SP_SPDOUT_FIFO >> 4) << 4) ));
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	/* SPDIF output MASTER ENABLE */
16558c2ecf20Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	/* right and left validate bit */
16588c2ecf20Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	/* monitor state */
16618c2ecf20Sopenharmony_ci	ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	return 0;
16648c2ecf20Sopenharmony_ci}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ciint cs46xx_dsp_enable_spdif_in (struct snd_cs46xx *chip)
16678c2ecf20Sopenharmony_ci{
16688c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	/* turn on amplifier */
16718c2ecf20Sopenharmony_ci	chip->active_ctrl(chip, 1);
16728c2ecf20Sopenharmony_ci	chip->amplifier_ctrl(chip, 1);
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->asynch_rx_scb))
16758c2ecf20Sopenharmony_ci		return -EINVAL;
16768c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->spdif_in_src))
16778c2ecf20Sopenharmony_ci		return -EINVAL;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) {
16828c2ecf20Sopenharmony_ci		/* time countdown enable */
16838c2ecf20Sopenharmony_ci		cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000005);
16848c2ecf20Sopenharmony_ci		/* NOTE: 80000005 value is just magic. With all values
16858c2ecf20Sopenharmony_ci		   that I've tested this one seem to give the best result.
16868c2ecf20Sopenharmony_ci		   Got no explication why. (Benny) */
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci		/* SPDIF input MASTER ENABLE */
16898c2ecf20Sopenharmony_ci		cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff);
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci		ins->spdif_status_out |= DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED;
16928c2ecf20Sopenharmony_ci	}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	/* create and start the asynchronous receiver SCB */
16958c2ecf20Sopenharmony_ci	ins->asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb(chip,"AsynchFGRxSCB",
16968c2ecf20Sopenharmony_ci								ASYNCRX_SCB_ADDR,
16978c2ecf20Sopenharmony_ci								SPDIFI_SCB_INST,
16988c2ecf20Sopenharmony_ci								SPDIFI_IP_OUTPUT_BUFFER1,
16998c2ecf20Sopenharmony_ci								ins->spdif_in_src,
17008c2ecf20Sopenharmony_ci								SCB_ON_PARENT_SUBLIST_SCB);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	spin_lock_irq(&chip->reg_lock);
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	/* reset SPDIF input sample buffer pointer */
17058c2ecf20Sopenharmony_ci	/*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2,
17068c2ecf20Sopenharmony_ci	  (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC);*/
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	/* reset FIFO ptr */
17098c2ecf20Sopenharmony_ci	/*cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);*/
17108c2ecf20Sopenharmony_ci	cs46xx_src_link(chip,ins->spdif_in_src);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	/* unmute SRC volume */
17138c2ecf20Sopenharmony_ci	cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	spin_unlock_irq(&chip->reg_lock);
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	/* set SPDIF input sample rate and unmute
17188c2ecf20Sopenharmony_ci	   NOTE: only 48khz support for SPDIF input this time */
17198c2ecf20Sopenharmony_ci	/* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	/* monitor state */
17228c2ecf20Sopenharmony_ci	ins->spdif_status_in = 1;
17238c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	return 0;
17268c2ecf20Sopenharmony_ci}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ciint cs46xx_dsp_disable_spdif_in (struct snd_cs46xx *chip)
17298c2ecf20Sopenharmony_ci{
17308c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->asynch_rx_scb))
17338c2ecf20Sopenharmony_ci		return -EINVAL;
17348c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->spdif_in_src))
17358c2ecf20Sopenharmony_ci		return -EINVAL;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	/* Remove the asynchronous receiver SCB */
17408c2ecf20Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb);
17418c2ecf20Sopenharmony_ci	ins->asynch_rx_scb = NULL;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	cs46xx_src_unlink(chip,ins->spdif_in_src);
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	/* monitor state */
17468c2ecf20Sopenharmony_ci	ins->spdif_status_in = 0;
17478c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	/* restore amplifier */
17508c2ecf20Sopenharmony_ci	chip->active_ctrl(chip, -1);
17518c2ecf20Sopenharmony_ci	chip->amplifier_ctrl(chip, -1);
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	return 0;
17548c2ecf20Sopenharmony_ci}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ciint cs46xx_dsp_enable_pcm_capture (struct snd_cs46xx *chip)
17578c2ecf20Sopenharmony_ci{
17588c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->pcm_input))
17618c2ecf20Sopenharmony_ci		return -EINVAL;
17628c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->ref_snoop_scb))
17638c2ecf20Sopenharmony_ci		return -EINVAL;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
17668c2ecf20Sopenharmony_ci	ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
17678c2ecf20Sopenharmony_ci                                                  "PCMSerialInput_Wave");
17688c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	return 0;
17718c2ecf20Sopenharmony_ci}
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ciint cs46xx_dsp_disable_pcm_capture (struct snd_cs46xx *chip)
17748c2ecf20Sopenharmony_ci{
17758c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->pcm_input))
17788c2ecf20Sopenharmony_ci		return -EINVAL;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
17818c2ecf20Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->pcm_input);
17828c2ecf20Sopenharmony_ci	ins->pcm_input = NULL;
17838c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	return 0;
17868c2ecf20Sopenharmony_ci}
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ciint cs46xx_dsp_enable_adc_capture (struct snd_cs46xx *chip)
17898c2ecf20Sopenharmony_ci{
17908c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	if (snd_BUG_ON(ins->adc_input))
17938c2ecf20Sopenharmony_ci		return -EINVAL;
17948c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->codec_in_scb))
17958c2ecf20Sopenharmony_ci		return -EINVAL;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
17988c2ecf20Sopenharmony_ci	ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
17998c2ecf20Sopenharmony_ci						  "PCMSerialInput_ADC");
18008c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	return 0;
18038c2ecf20Sopenharmony_ci}
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ciint cs46xx_dsp_disable_adc_capture (struct snd_cs46xx *chip)
18068c2ecf20Sopenharmony_ci{
18078c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!ins->adc_input))
18108c2ecf20Sopenharmony_ci		return -EINVAL;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
18138c2ecf20Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->adc_input);
18148c2ecf20Sopenharmony_ci	ins->adc_input = NULL;
18158c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	return 0;
18188c2ecf20Sopenharmony_ci}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ciint cs46xx_poke_via_dsp (struct snd_cs46xx *chip, u32 address, u32 data)
18218c2ecf20Sopenharmony_ci{
18228c2ecf20Sopenharmony_ci	u32 temp;
18238c2ecf20Sopenharmony_ci	int  i;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	/* santiy check the parameters.  (These numbers are not 100% correct.  They are
18268c2ecf20Sopenharmony_ci	   a rough guess from looking at the controller spec.) */
18278c2ecf20Sopenharmony_ci	if (address < 0x8000 || address >= 0x9000)
18288c2ecf20Sopenharmony_ci		return -EINVAL;
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	/* initialize the SP_IO_WRITE SCB with the data. */
18318c2ecf20Sopenharmony_ci	temp = ( address << 16 ) | ( address & 0x0000FFFF);   /* offset 0 <-- address2 : address1 */
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	snd_cs46xx_poke(chip,( SPIOWRITE_SCB_ADDR      << 2), temp);
18348c2ecf20Sopenharmony_ci	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 1) << 2), data); /* offset 1 <-- data1 */
18358c2ecf20Sopenharmony_ci	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2 */
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	/* Poke this location to tell the task to start */
18388c2ecf20Sopenharmony_ci	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 6) << 2), SPIOWRITE_SCB_ADDR << 0x10);
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci	/* Verify that the task ran */
18418c2ecf20Sopenharmony_ci	for (i=0; i<25; i++) {
18428c2ecf20Sopenharmony_ci		udelay(125);
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci		temp =  snd_cs46xx_peek(chip,((SPIOWRITE_SCB_ADDR + 6) << 2));
18458c2ecf20Sopenharmony_ci		if (temp == 0x00000000)
18468c2ecf20Sopenharmony_ci			break;
18478c2ecf20Sopenharmony_ci	}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	if (i == 25) {
18508c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
18518c2ecf20Sopenharmony_ci			"dsp_spos: SPIOWriteTask not responding\n");
18528c2ecf20Sopenharmony_ci		return -EBUSY;
18538c2ecf20Sopenharmony_ci	}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	return 0;
18568c2ecf20Sopenharmony_ci}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ciint cs46xx_dsp_set_dac_volume (struct snd_cs46xx * chip, u16 left, u16 right)
18598c2ecf20Sopenharmony_ci{
18608c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
18618c2ecf20Sopenharmony_ci	struct dsp_scb_descriptor * scb;
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	/* main output */
18668c2ecf20Sopenharmony_ci	scb = ins->master_mix_scb->sub_list_ptr;
18678c2ecf20Sopenharmony_ci	while (scb != ins->the_null_scb) {
18688c2ecf20Sopenharmony_ci		cs46xx_dsp_scb_set_volume (chip,scb,left,right);
18698c2ecf20Sopenharmony_ci		scb = scb->next_scb_ptr;
18708c2ecf20Sopenharmony_ci	}
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci	/* rear output */
18738c2ecf20Sopenharmony_ci	scb = ins->rear_mix_scb->sub_list_ptr;
18748c2ecf20Sopenharmony_ci	while (scb != ins->the_null_scb) {
18758c2ecf20Sopenharmony_ci		cs46xx_dsp_scb_set_volume (chip,scb,left,right);
18768c2ecf20Sopenharmony_ci		scb = scb->next_scb_ptr;
18778c2ecf20Sopenharmony_ci	}
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	ins->dac_volume_left = left;
18808c2ecf20Sopenharmony_ci	ins->dac_volume_right = right;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	return 0;
18858c2ecf20Sopenharmony_ci}
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ciint cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
18888c2ecf20Sopenharmony_ci{
18898c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	if (ins->asynch_rx_scb != NULL)
18948c2ecf20Sopenharmony_ci		cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
18958c2ecf20Sopenharmony_ci					   left,right);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	ins->spdif_input_volume_left = left;
18988c2ecf20Sopenharmony_ci	ins->spdif_input_volume_right = right;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	return 0;
19038c2ecf20Sopenharmony_ci}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
19068c2ecf20Sopenharmony_ciint cs46xx_dsp_resume(struct snd_cs46xx * chip)
19078c2ecf20Sopenharmony_ci{
19088c2ecf20Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
19098c2ecf20Sopenharmony_ci	int i, err;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	/* clear parameter, sample and code areas */
19128c2ecf20Sopenharmony_ci	snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET,
19138c2ecf20Sopenharmony_ci			     DSP_PARAMETER_BYTE_SIZE);
19148c2ecf20Sopenharmony_ci	snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET,
19158c2ecf20Sopenharmony_ci			     DSP_SAMPLE_BYTE_SIZE);
19168c2ecf20Sopenharmony_ci	snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	for (i = 0; i < ins->nmodules; i++) {
19198c2ecf20Sopenharmony_ci		struct dsp_module_desc *module = &ins->modules[i];
19208c2ecf20Sopenharmony_ci		struct dsp_segment_desc *seg;
19218c2ecf20Sopenharmony_ci		u32 doffset, dsize;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci		seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER);
19248c2ecf20Sopenharmony_ci		err = dsp_load_parameter(chip, seg);
19258c2ecf20Sopenharmony_ci		if (err < 0)
19268c2ecf20Sopenharmony_ci			return err;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci		seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE);
19298c2ecf20Sopenharmony_ci		err = dsp_load_sample(chip, seg);
19308c2ecf20Sopenharmony_ci		if (err < 0)
19318c2ecf20Sopenharmony_ci			return err;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci		seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM);
19348c2ecf20Sopenharmony_ci		if (!seg)
19358c2ecf20Sopenharmony_ci			continue;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci		doffset = seg->offset * 4 + module->load_address * 4
19388c2ecf20Sopenharmony_ci			+ DSP_CODE_BYTE_OFFSET;
19398c2ecf20Sopenharmony_ci		dsize   = seg->size * 4;
19408c2ecf20Sopenharmony_ci		err = snd_cs46xx_download(chip,
19418c2ecf20Sopenharmony_ci					  ins->code.data + module->load_address,
19428c2ecf20Sopenharmony_ci					  doffset, dsize);
19438c2ecf20Sopenharmony_ci		if (err < 0)
19448c2ecf20Sopenharmony_ci			return err;
19458c2ecf20Sopenharmony_ci	}
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	for (i = 0; i < ins->ntask; i++) {
19488c2ecf20Sopenharmony_ci		struct dsp_task_descriptor *t = &ins->tasks[i];
19498c2ecf20Sopenharmony_ci		_dsp_create_task_tree(chip, t->data, t->address, t->size);
19508c2ecf20Sopenharmony_ci	}
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	for (i = 0; i < ins->nscb; i++) {
19538c2ecf20Sopenharmony_ci		struct dsp_scb_descriptor *s = &ins->scbs[i];
19548c2ecf20Sopenharmony_ci		if (s->deleted)
19558c2ecf20Sopenharmony_ci			continue;
19568c2ecf20Sopenharmony_ci		_dsp_create_scb(chip, s->data, s->address);
19578c2ecf20Sopenharmony_ci	}
19588c2ecf20Sopenharmony_ci	for (i = 0; i < ins->nscb; i++) {
19598c2ecf20Sopenharmony_ci		struct dsp_scb_descriptor *s = &ins->scbs[i];
19608c2ecf20Sopenharmony_ci		if (s->deleted)
19618c2ecf20Sopenharmony_ci			continue;
19628c2ecf20Sopenharmony_ci		if (s->updated)
19638c2ecf20Sopenharmony_ci			cs46xx_dsp_spos_update_scb(chip, s);
19648c2ecf20Sopenharmony_ci		if (s->volume_set)
19658c2ecf20Sopenharmony_ci			cs46xx_dsp_scb_set_volume(chip, s,
19668c2ecf20Sopenharmony_ci						  s->volume[0], s->volume[1]);
19678c2ecf20Sopenharmony_ci	}
19688c2ecf20Sopenharmony_ci	if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
19698c2ecf20Sopenharmony_ci		cs46xx_dsp_enable_spdif_hw(chip);
19708c2ecf20Sopenharmony_ci		snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2,
19718c2ecf20Sopenharmony_ci				(OUTPUT_SNOOP_BUFFER + 0x10) << 0x10);
19728c2ecf20Sopenharmony_ci		if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN)
19738c2ecf20Sopenharmony_ci			cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV,
19748c2ecf20Sopenharmony_ci					    ins->spdif_csuv_stream);
19758c2ecf20Sopenharmony_ci	}
19768c2ecf20Sopenharmony_ci	if (chip->dsp_spos_instance->spdif_status_in) {
19778c2ecf20Sopenharmony_ci		cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005);
19788c2ecf20Sopenharmony_ci		cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff);
19798c2ecf20Sopenharmony_ci	}
19808c2ecf20Sopenharmony_ci	return 0;
19818c2ecf20Sopenharmony_ci}
19828c2ecf20Sopenharmony_ci#endif
1983