11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds */
41da177e4SLinus Torvalds
51da177e4SLinus Torvalds /*
61da177e4SLinus Torvalds * 2002-07 Benny Sjostrand benny@hostmobility.com
71da177e4SLinus Torvalds */
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds
106cbbfe1cSTakashi Iwai #include <linux/io.h>
111da177e4SLinus Torvalds #include <linux/delay.h>
121da177e4SLinus Torvalds #include <linux/pm.h>
131da177e4SLinus Torvalds #include <linux/init.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
1562932df8SIngo Molnar #include <linux/mutex.h>
1662932df8SIngo Molnar
171da177e4SLinus Torvalds #include <sound/core.h>
181da177e4SLinus Torvalds #include <sound/control.h>
191da177e4SLinus Torvalds #include <sound/info.h>
2081fcb170STakashi Iwai #include "cs46xx.h"
211da177e4SLinus Torvalds
221da177e4SLinus Torvalds #include "cs46xx_lib.h"
231da177e4SLinus Torvalds #include "dsp_spos.h"
241da177e4SLinus Torvalds
253d19f804STakashi Iwai struct proc_scb_info {
263d19f804STakashi Iwai struct dsp_scb_descriptor * scb_desc;
273d19f804STakashi Iwai struct snd_cs46xx *chip;
283d19f804STakashi Iwai };
291da177e4SLinus Torvalds
remove_symbol(struct snd_cs46xx * chip,struct dsp_symbol_entry * symbol)303d19f804STakashi Iwai static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
311da177e4SLinus Torvalds {
323d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
331da177e4SLinus Torvalds int symbol_index = (int)(symbol - ins->symbol_table.symbols);
341da177e4SLinus Torvalds
35da3cec35STakashi Iwai if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
36da3cec35STakashi Iwai return;
37da3cec35STakashi Iwai if (snd_BUG_ON(symbol_index < 0 ||
38da3cec35STakashi Iwai symbol_index >= ins->symbol_table.nsymbols))
39da3cec35STakashi Iwai return;
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds ins->symbol_table.symbols[symbol_index].deleted = 1;
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds if (symbol_index < ins->symbol_table.highest_frag_index) {
441da177e4SLinus Torvalds ins->symbol_table.highest_frag_index = symbol_index;
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds if (symbol_index == ins->symbol_table.nsymbols - 1)
481da177e4SLinus Torvalds ins->symbol_table.nsymbols --;
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
511da177e4SLinus Torvalds ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds
5695bb6258STakashi Iwai #ifdef CONFIG_SND_PROC_FS
cs46xx_dsp_proc_scb_info_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)573d19f804STakashi Iwai static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
583d19f804STakashi Iwai struct snd_info_buffer *buffer)
591da177e4SLinus Torvalds {
603d19f804STakashi Iwai struct proc_scb_info * scb_info = entry->private_data;
613d19f804STakashi Iwai struct dsp_scb_descriptor * scb = scb_info->scb_desc;
623d19f804STakashi Iwai struct snd_cs46xx *chip = scb_info->chip;
631da177e4SLinus Torvalds int j,col;
641da177e4SLinus Torvalds void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
651da177e4SLinus Torvalds
6662932df8SIngo Molnar mutex_lock(&chip->spos_mutex);
671da177e4SLinus Torvalds snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds for (col = 0,j = 0;j < 0x10; j++,col++) {
701da177e4SLinus Torvalds if (col == 4) {
711da177e4SLinus Torvalds snd_iprintf(buffer,"\n");
721da177e4SLinus Torvalds col = 0;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds snd_iprintf(buffer,"\n");
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds if (scb->parent_scb_ptr != NULL) {
801da177e4SLinus Torvalds snd_iprintf(buffer,"parent [%s:%04x] ",
811da177e4SLinus Torvalds scb->parent_scb_ptr->scb_name,
821da177e4SLinus Torvalds scb->parent_scb_ptr->address);
831da177e4SLinus Torvalds } else snd_iprintf(buffer,"parent [none] ");
841da177e4SLinus Torvalds
851da177e4SLinus Torvalds snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
861da177e4SLinus Torvalds scb->sub_list_ptr->scb_name,
871da177e4SLinus Torvalds scb->sub_list_ptr->address,
881da177e4SLinus Torvalds scb->next_scb_ptr->scb_name,
891da177e4SLinus Torvalds scb->next_scb_ptr->address,
901da177e4SLinus Torvalds scb->task_entry->symbol_name,
911da177e4SLinus Torvalds scb->task_entry->address);
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
9462932df8SIngo Molnar mutex_unlock(&chip->spos_mutex);
951da177e4SLinus Torvalds }
96adf1b3d2STakashi Iwai #endif
971da177e4SLinus Torvalds
_dsp_unlink_scb(struct snd_cs46xx * chip,struct dsp_scb_descriptor * scb)983d19f804STakashi Iwai static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
991da177e4SLinus Torvalds {
1003d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds if ( scb->parent_scb_ptr ) {
1031da177e4SLinus Torvalds /* unlink parent SCB */
104da3cec35STakashi Iwai if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
105da3cec35STakashi Iwai scb->parent_scb_ptr->next_scb_ptr != scb))
106da3cec35STakashi Iwai return;
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds if (scb->parent_scb_ptr->sub_list_ptr == scb) {
1091da177e4SLinus Torvalds
1101da177e4SLinus Torvalds if (scb->next_scb_ptr == ins->the_null_scb) {
1111da177e4SLinus Torvalds /* last and only node in parent sublist */
1121da177e4SLinus Torvalds scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds if (scb->sub_list_ptr != ins->the_null_scb) {
1151da177e4SLinus Torvalds scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds scb->sub_list_ptr = ins->the_null_scb;
1181da177e4SLinus Torvalds } else {
1191da177e4SLinus Torvalds /* first node in parent sublist */
1201da177e4SLinus Torvalds scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
1211da177e4SLinus Torvalds
1221da177e4SLinus Torvalds if (scb->next_scb_ptr != ins->the_null_scb) {
1231da177e4SLinus Torvalds /* update next node parent ptr. */
1241da177e4SLinus Torvalds scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds scb->next_scb_ptr = ins->the_null_scb;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds } else {
1291da177e4SLinus Torvalds scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds if (scb->next_scb_ptr != ins->the_null_scb) {
1321da177e4SLinus Torvalds /* update next node parent ptr. */
1331da177e4SLinus Torvalds scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds scb->next_scb_ptr = ins->the_null_scb;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds /* update parent first entry in DSP RAM */
1391da177e4SLinus Torvalds cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds /* then update entry in DSP RAM */
1421da177e4SLinus Torvalds cs46xx_dsp_spos_update_scb(chip,scb);
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds scb->parent_scb_ptr = NULL;
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds
_dsp_clear_sample_buffer(struct snd_cs46xx * chip,u32 sample_buffer_addr,int dword_count)1483d19f804STakashi Iwai static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
1493d19f804STakashi Iwai int dword_count)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
1521da177e4SLinus Torvalds int i;
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds for (i = 0; i < dword_count ; ++i ) {
1551da177e4SLinus Torvalds writel(0, dst);
1561da177e4SLinus Torvalds dst += 4;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds
cs46xx_dsp_remove_scb(struct snd_cs46xx * chip,struct dsp_scb_descriptor * scb)1603d19f804STakashi Iwai void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
1611da177e4SLinus Torvalds {
1623d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
163c6482ddeSArjan van de Ven unsigned long flags;
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds /* check integrety */
166da3cec35STakashi Iwai if (snd_BUG_ON(scb->index < 0 ||
167da3cec35STakashi Iwai scb->index >= ins->nscb ||
168da3cec35STakashi Iwai (ins->scbs + scb->index) != scb))
169da3cec35STakashi Iwai return;
1701da177e4SLinus Torvalds
1711da177e4SLinus Torvalds #if 0
1721da177e4SLinus Torvalds /* can't remove a SCB with childs before
1731da177e4SLinus Torvalds removing childs first */
174da3cec35STakashi Iwai if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
175da3cec35STakashi Iwai scb->next_scb_ptr != ins->the_null_scb))
176da3cec35STakashi Iwai goto _end;
1771da177e4SLinus Torvalds #endif
1781da177e4SLinus Torvalds
17941116e92STakashi Iwai spin_lock_irqsave(&chip->reg_lock, flags);
1801da177e4SLinus Torvalds _dsp_unlink_scb (chip,scb);
18141116e92STakashi Iwai spin_unlock_irqrestore(&chip->reg_lock, flags);
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds cs46xx_dsp_proc_free_scb_desc(scb);
184da3cec35STakashi Iwai if (snd_BUG_ON(!scb->scb_symbol))
185da3cec35STakashi Iwai return;
1861da177e4SLinus Torvalds remove_symbol (chip,scb->scb_symbol);
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds ins->scbs[scb->index].deleted = 1;
189c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
19041116e92STakashi Iwai kfree(ins->scbs[scb->index].data);
19141116e92STakashi Iwai ins->scbs[scb->index].data = NULL;
19241116e92STakashi Iwai #endif
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds if (scb->index < ins->scb_highest_frag_index)
1951da177e4SLinus Torvalds ins->scb_highest_frag_index = scb->index;
1961da177e4SLinus Torvalds
1971da177e4SLinus Torvalds if (scb->index == ins->nscb - 1) {
1981da177e4SLinus Torvalds ins->nscb --;
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds if (ins->scb_highest_frag_index > ins->nscb) {
2021da177e4SLinus Torvalds ins->scb_highest_frag_index = ins->nscb;
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds
2051da177e4SLinus Torvalds #if 0
2061da177e4SLinus Torvalds /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
2071da177e4SLinus Torvalds for(i = scb->index + 1;i < ins->nscb; ++i) {
2081da177e4SLinus Torvalds ins->scbs[i - 1].index = i - 1;
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds #endif
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds
2131da177e4SLinus Torvalds
21495bb6258STakashi Iwai #ifdef CONFIG_SND_PROC_FS
cs46xx_dsp_proc_free_scb_desc(struct dsp_scb_descriptor * scb)2153d19f804STakashi Iwai void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds if (scb->proc_info) {
2183d19f804STakashi Iwai struct proc_scb_info * scb_info = scb->proc_info->private_data;
2192b96a7f1STakashi Iwai struct snd_cs46xx *chip = scb_info->chip;
2201da177e4SLinus Torvalds
2212b96a7f1STakashi Iwai dev_dbg(chip->card->dev,
2222b96a7f1STakashi Iwai "cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
2232b96a7f1STakashi Iwai scb->scb_name);
2241da177e4SLinus Torvalds
225746d4a02STakashi Iwai snd_info_free_entry(scb->proc_info);
2261da177e4SLinus Torvalds scb->proc_info = NULL;
2271da177e4SLinus Torvalds
2281da177e4SLinus Torvalds kfree (scb_info);
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds }
2311da177e4SLinus Torvalds
cs46xx_dsp_proc_register_scb_desc(struct snd_cs46xx * chip,struct dsp_scb_descriptor * scb)2323d19f804STakashi Iwai void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
2333d19f804STakashi Iwai struct dsp_scb_descriptor * scb)
2341da177e4SLinus Torvalds {
2353d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
2363d19f804STakashi Iwai struct snd_info_entry * entry;
2373d19f804STakashi Iwai struct proc_scb_info * scb_info;
2381da177e4SLinus Torvalds
2391da177e4SLinus Torvalds /* register to proc */
2401da177e4SLinus Torvalds if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
2411da177e4SLinus Torvalds scb->proc_info == NULL) {
2421da177e4SLinus Torvalds
2430b2338a9STakashi Iwai entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
2440b2338a9STakashi Iwai ins->proc_dsp_dir);
2450b2338a9STakashi Iwai if (entry) {
2463d19f804STakashi Iwai scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
2471da177e4SLinus Torvalds if (!scb_info) {
2481da177e4SLinus Torvalds snd_info_free_entry(entry);
2491da177e4SLinus Torvalds entry = NULL;
2501da177e4SLinus Torvalds goto out;
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds
2531da177e4SLinus Torvalds scb_info->chip = chip;
2541da177e4SLinus Torvalds scb_info->scb_desc = scb;
2550b2338a9STakashi Iwai snd_info_set_text_ops(entry, scb_info,
2560b2338a9STakashi Iwai cs46xx_dsp_proc_scb_info_read);
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds out:
2591da177e4SLinus Torvalds scb->proc_info = entry;
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds }
26295bb6258STakashi Iwai #endif /* CONFIG_SND_PROC_FS */
2631da177e4SLinus Torvalds
2643d19f804STakashi Iwai static struct dsp_scb_descriptor *
_dsp_create_generic_scb(struct snd_cs46xx * chip,char * name,u32 * scb_data,u32 dest,struct dsp_symbol_entry * task_entry,struct dsp_scb_descriptor * parent_scb,int scb_child_type)2653d19f804STakashi Iwai _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
2663d19f804STakashi Iwai struct dsp_symbol_entry * task_entry,
2673d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
2681da177e4SLinus Torvalds int scb_child_type)
2691da177e4SLinus Torvalds {
2703d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
2713d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
2721da177e4SLinus Torvalds
2731da177e4SLinus Torvalds unsigned long flags;
2741da177e4SLinus Torvalds
275da3cec35STakashi Iwai if (snd_BUG_ON(!ins->the_null_scb))
276da3cec35STakashi Iwai return NULL;
2771da177e4SLinus Torvalds
2781da177e4SLinus Torvalds /* fill the data that will be wroten to DSP */
2791da177e4SLinus Torvalds scb_data[SCBsubListPtr] =
2801da177e4SLinus Torvalds (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
2811da177e4SLinus Torvalds
2821da177e4SLinus Torvalds scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
2831da177e4SLinus Torvalds scb_data[SCBfuncEntryPtr] |= task_entry->address;
2841da177e4SLinus Torvalds
2852b96a7f1STakashi Iwai dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
2881da177e4SLinus Torvalds
2891da177e4SLinus Torvalds
2901da177e4SLinus Torvalds scb->sub_list_ptr = ins->the_null_scb;
2911da177e4SLinus Torvalds scb->next_scb_ptr = ins->the_null_scb;
2921da177e4SLinus Torvalds
2931da177e4SLinus Torvalds scb->parent_scb_ptr = parent_scb;
2941da177e4SLinus Torvalds scb->task_entry = task_entry;
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds
2971da177e4SLinus Torvalds /* update parent SCB */
2981da177e4SLinus Torvalds if (scb->parent_scb_ptr) {
2991da177e4SLinus Torvalds #if 0
3002b96a7f1STakashi Iwai dev_dbg(chip->card->dev,
3012b96a7f1STakashi Iwai "scb->parent_scb_ptr = %s\n",
3022b96a7f1STakashi Iwai scb->parent_scb_ptr->scb_name);
3032b96a7f1STakashi Iwai dev_dbg(chip->card->dev,
3042b96a7f1STakashi Iwai "scb->parent_scb_ptr->next_scb_ptr = %s\n",
3052b96a7f1STakashi Iwai scb->parent_scb_ptr->next_scb_ptr->scb_name);
3062b96a7f1STakashi Iwai dev_dbg(chip->card->dev,
3072b96a7f1STakashi Iwai "scb->parent_scb_ptr->sub_list_ptr = %s\n",
3082b96a7f1STakashi Iwai scb->parent_scb_ptr->sub_list_ptr->scb_name);
3091da177e4SLinus Torvalds #endif
3101da177e4SLinus Torvalds /* link to parent SCB */
3111da177e4SLinus Torvalds if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
312da3cec35STakashi Iwai if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
313da3cec35STakashi Iwai ins->the_null_scb))
314da3cec35STakashi Iwai return NULL;
3151da177e4SLinus Torvalds
3161da177e4SLinus Torvalds scb->parent_scb_ptr->next_scb_ptr = scb;
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
319da3cec35STakashi Iwai if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
320da3cec35STakashi Iwai ins->the_null_scb))
321da3cec35STakashi Iwai return NULL;
3221da177e4SLinus Torvalds
3231da177e4SLinus Torvalds scb->parent_scb_ptr->sub_list_ptr = scb;
3241da177e4SLinus Torvalds } else {
325da3cec35STakashi Iwai snd_BUG();
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds spin_lock_irqsave(&chip->reg_lock, flags);
3291da177e4SLinus Torvalds
3301da177e4SLinus Torvalds /* update entry in DSP RAM */
3311da177e4SLinus Torvalds cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
3321da177e4SLinus Torvalds
3331da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->reg_lock, flags);
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds
3361da177e4SLinus Torvalds
3371da177e4SLinus Torvalds cs46xx_dsp_proc_register_scb_desc (chip,scb);
3381da177e4SLinus Torvalds
3391da177e4SLinus Torvalds return scb;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds
3423d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_generic_scb(struct snd_cs46xx * chip,char * name,u32 * scb_data,u32 dest,char * task_entry_name,struct dsp_scb_descriptor * parent_scb,int scb_child_type)3433d19f804STakashi Iwai cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
3443d19f804STakashi Iwai u32 dest, char * task_entry_name,
3453d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
3461da177e4SLinus Torvalds int scb_child_type)
3471da177e4SLinus Torvalds {
3483d19f804STakashi Iwai struct dsp_symbol_entry * task_entry;
3491da177e4SLinus Torvalds
3501da177e4SLinus Torvalds task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
3511da177e4SLinus Torvalds SYMBOL_CODE);
3521da177e4SLinus Torvalds
3531da177e4SLinus Torvalds if (task_entry == NULL) {
3542b96a7f1STakashi Iwai dev_err(chip->card->dev,
3552b96a7f1STakashi Iwai "dsp_spos: symbol %s not found\n", task_entry_name);
3561da177e4SLinus Torvalds return NULL;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
3601da177e4SLinus Torvalds parent_scb,scb_child_type);
3611da177e4SLinus Torvalds }
3621da177e4SLinus Torvalds
3633d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_timing_master_scb(struct snd_cs46xx * chip)3643d19f804STakashi Iwai cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
3651da177e4SLinus Torvalds {
3663d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
3671da177e4SLinus Torvalds
3683d19f804STakashi Iwai struct dsp_timing_master_scb timing_master_scb = {
3691da177e4SLinus Torvalds { 0,
3701da177e4SLinus Torvalds 0,
3711da177e4SLinus Torvalds 0,
3721da177e4SLinus Torvalds 0
3731da177e4SLinus Torvalds },
3741da177e4SLinus Torvalds { 0,
3751da177e4SLinus Torvalds 0,
3761da177e4SLinus Torvalds 0,
3771da177e4SLinus Torvalds 0,
3781da177e4SLinus Torvalds 0
3791da177e4SLinus Torvalds },
3801da177e4SLinus Torvalds 0,0,
3811da177e4SLinus Torvalds 0,NULL_SCB_ADDR,
3821da177e4SLinus Torvalds 0,0, /* extraSampleAccum:TMreserved */
3831da177e4SLinus Torvalds 0,0, /* codecFIFOptr:codecFIFOsyncd */
3841da177e4SLinus Torvalds 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
3851da177e4SLinus Torvalds 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
3861da177e4SLinus Torvalds 0x00060000 /* nSampPerFrmQ15 */
3871da177e4SLinus Torvalds };
3881da177e4SLinus Torvalds
3891da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
3901da177e4SLinus Torvalds TIMINGMASTER_SCB_ADDR,
3911da177e4SLinus Torvalds "TIMINGMASTER",NULL,SCB_NO_PARENT);
3921da177e4SLinus Torvalds
3931da177e4SLinus Torvalds return scb;
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds
3973d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip,char * codec_name,u16 channel_disp,u16 fifo_addr,u16 child_scb_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)3983d19f804STakashi Iwai cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
3993d19f804STakashi Iwai u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
4003d19f804STakashi Iwai u32 dest, struct dsp_scb_descriptor * parent_scb,
4011da177e4SLinus Torvalds int scb_child_type)
4021da177e4SLinus Torvalds {
4033d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
4041da177e4SLinus Torvalds
4053d19f804STakashi Iwai struct dsp_codec_output_scb codec_out_scb = {
4061da177e4SLinus Torvalds { 0,
4071da177e4SLinus Torvalds 0,
4081da177e4SLinus Torvalds 0,
4091da177e4SLinus Torvalds 0
4101da177e4SLinus Torvalds },
4111da177e4SLinus Torvalds {
4121da177e4SLinus Torvalds 0,
4131da177e4SLinus Torvalds 0,
4141da177e4SLinus Torvalds 0,
4151da177e4SLinus Torvalds 0,
4161da177e4SLinus Torvalds 0
4171da177e4SLinus Torvalds },
4181da177e4SLinus Torvalds 0,0,
4191da177e4SLinus Torvalds 0,NULL_SCB_ADDR,
4201da177e4SLinus Torvalds 0, /* COstrmRsConfig */
4211da177e4SLinus Torvalds 0, /* COstrmBufPtr */
4221da177e4SLinus Torvalds channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
4231da177e4SLinus Torvalds 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
4241da177e4SLinus Torvalds 0,child_scb_addr /* COreserved - need child scb to work with rom code */
4251da177e4SLinus Torvalds };
4261da177e4SLinus Torvalds
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
4291da177e4SLinus Torvalds dest,"S16_CODECOUTPUTTASK",parent_scb,
4301da177e4SLinus Torvalds scb_child_type);
4311da177e4SLinus Torvalds
4321da177e4SLinus Torvalds return scb;
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds
4353d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip,char * codec_name,u16 channel_disp,u16 fifo_addr,u16 sample_buffer_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)4363d19f804STakashi Iwai cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
4373d19f804STakashi Iwai u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
4383d19f804STakashi Iwai u32 dest, struct dsp_scb_descriptor * parent_scb,
4391da177e4SLinus Torvalds int scb_child_type)
4401da177e4SLinus Torvalds {
4411da177e4SLinus Torvalds
4423d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
4433d19f804STakashi Iwai struct dsp_codec_input_scb codec_input_scb = {
4441da177e4SLinus Torvalds { 0,
4451da177e4SLinus Torvalds 0,
4461da177e4SLinus Torvalds 0,
4471da177e4SLinus Torvalds 0
4481da177e4SLinus Torvalds },
4491da177e4SLinus Torvalds {
4501da177e4SLinus Torvalds 0,
4511da177e4SLinus Torvalds 0,
4521da177e4SLinus Torvalds 0,
4531da177e4SLinus Torvalds 0,
4541da177e4SLinus Torvalds 0
4551da177e4SLinus Torvalds },
4561da177e4SLinus Torvalds
4571da177e4SLinus Torvalds #if 0 /* cs4620 */
4581da177e4SLinus Torvalds SyncIOSCB,NULL_SCB_ADDR
4591da177e4SLinus Torvalds #else
4601da177e4SLinus Torvalds 0 , 0,
4611da177e4SLinus Torvalds #endif
4621da177e4SLinus Torvalds 0,0,
4631da177e4SLinus Torvalds
4641da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
4651da177e4SLinus Torvalds sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
4661da177e4SLinus Torvalds channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
4671da177e4SLinus Torvalds link input slot 3 :rightChanINdisp=""slot 4 */
4681da177e4SLinus Torvalds 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
4691da177e4SLinus Torvalds because AC97 is already 20 bits */
4701da177e4SLinus Torvalds 0x80008000 /* ??clw cwcgame.scb has 0 */
4711da177e4SLinus Torvalds };
4721da177e4SLinus Torvalds
4731da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
4741da177e4SLinus Torvalds dest,"S16_CODECINPUTTASK",parent_scb,
4751da177e4SLinus Torvalds scb_child_type);
4761da177e4SLinus Torvalds return scb;
4771da177e4SLinus Torvalds }
4781da177e4SLinus Torvalds
4791da177e4SLinus Torvalds
4803d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip,char * scb_name,u16 sample_buffer_addr,u32 dest,int virtual_channel,u32 playback_hw_addr,struct dsp_scb_descriptor * parent_scb,int scb_child_type)4813d19f804STakashi Iwai cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
4821da177e4SLinus Torvalds u16 sample_buffer_addr, u32 dest,
4831da177e4SLinus Torvalds int virtual_channel, u32 playback_hw_addr,
4843d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
4851da177e4SLinus Torvalds int scb_child_type)
4861da177e4SLinus Torvalds {
4873d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
4883d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
4891da177e4SLinus Torvalds
4903d19f804STakashi Iwai struct dsp_generic_scb pcm_reader_scb = {
4911da177e4SLinus Torvalds
4921da177e4SLinus Torvalds /*
4931da177e4SLinus Torvalds Play DMA Task xfers data from host buffer to SP buffer
4941da177e4SLinus Torvalds init/runtime variables:
4951da177e4SLinus Torvalds PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
4961da177e4SLinus Torvalds DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
4971da177e4SLinus Torvalds DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
4981da177e4SLinus Torvalds DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
4991da177e4SLinus Torvalds DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
5001da177e4SLinus Torvalds DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
5011da177e4SLinus Torvalds DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
5021da177e4SLinus Torvalds DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
5031da177e4SLinus Torvalds DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
5041da177e4SLinus Torvalds ? Other combinations possible from:
5051da177e4SLinus Torvalds DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
5061da177e4SLinus Torvalds DMA_RQ_C2_AC_NONE 0x00000000L
5071da177e4SLinus Torvalds DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
5081da177e4SLinus Torvalds DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
5091da177e4SLinus Torvalds DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
5101da177e4SLinus Torvalds DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
5111da177e4SLinus Torvalds
5121da177e4SLinus Torvalds HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
5131da177e4SLinus Torvalds aligned to dword boundary
5141da177e4SLinus Torvalds */
5151da177e4SLinus Torvalds /* Basic (non scatter/gather) DMA requestor (4 ints) */
5161da177e4SLinus Torvalds { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
5171da177e4SLinus Torvalds DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
5181da177e4SLinus Torvalds DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
5191da177e4SLinus Torvalds DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
5201da177e4SLinus Torvalds DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
5211da177e4SLinus Torvalds 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
5221da177e4SLinus Torvalds /* Barnette said that is what we should use since */
5231da177e4SLinus Torvalds /* we are not running in optimized mode? */
5241da177e4SLinus Torvalds DMA_RQ_C2_AC_NONE +
5251da177e4SLinus Torvalds DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
5261da177e4SLinus Torvalds /* buffer (on host) crosses half-way point */
5271da177e4SLinus Torvalds virtual_channel, /* Play DMA channel arbitrarily set to 0 */
5281da177e4SLinus Torvalds playback_hw_addr, /* HostBuffAddr (source) */
5291da177e4SLinus Torvalds DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
5301da177e4SLinus Torvalds sample_buffer_addr /* SP Buffer Address (destination) */
5311da177e4SLinus Torvalds },
5321da177e4SLinus Torvalds /* Scatter/gather DMA requestor extension (5 ints) */
5331da177e4SLinus Torvalds {
5341da177e4SLinus Torvalds 0,
5351da177e4SLinus Torvalds 0,
5361da177e4SLinus Torvalds 0,
5371da177e4SLinus Torvalds 0,
5381da177e4SLinus Torvalds 0
5391da177e4SLinus Torvalds },
5401da177e4SLinus Torvalds /* Sublist pointer & next stream control block (SCB) link. */
5411da177e4SLinus Torvalds NULL_SCB_ADDR,NULL_SCB_ADDR,
5421da177e4SLinus Torvalds /* Pointer to this tasks parameter block & stream function pointer */
5431da177e4SLinus Torvalds 0,NULL_SCB_ADDR,
5441da177e4SLinus Torvalds /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
5451da177e4SLinus Torvalds /* for incoming streams, or basicReq.saw, for outgoing streams) */
5461da177e4SLinus Torvalds RSCONFIG_DMA_ENABLE + /* enable DMA */
5471da177e4SLinus Torvalds (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
5481da177e4SLinus Torvalds /* uses it for some reason */
5491da177e4SLinus Torvalds ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
5501da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO +
5511da177e4SLinus Torvalds RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
5521da177e4SLinus Torvalds /* Stream sample pointer & MAC-unit mode for this stream */
5531da177e4SLinus Torvalds (sample_buffer_addr << 0x10),
5541da177e4SLinus Torvalds /* Fractional increment per output sample in the input sample buffer */
5551da177e4SLinus Torvalds 0,
5561da177e4SLinus Torvalds {
5571da177e4SLinus Torvalds /* Standard stereo volume control
5581da177e4SLinus Torvalds default muted */
5591da177e4SLinus Torvalds 0xffff,0xffff,
5601da177e4SLinus Torvalds 0xffff,0xffff
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds };
5631da177e4SLinus Torvalds
5641da177e4SLinus Torvalds if (ins->null_algorithm == NULL) {
5651da177e4SLinus Torvalds ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
5661da177e4SLinus Torvalds SYMBOL_CODE);
5671da177e4SLinus Torvalds
5681da177e4SLinus Torvalds if (ins->null_algorithm == NULL) {
5692b96a7f1STakashi Iwai dev_err(chip->card->dev,
5702b96a7f1STakashi Iwai "dsp_spos: symbol NULLALGORITHM not found\n");
5711da177e4SLinus Torvalds return NULL;
5721da177e4SLinus Torvalds }
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds
5751da177e4SLinus Torvalds scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
5761da177e4SLinus Torvalds dest,ins->null_algorithm,parent_scb,
5771da177e4SLinus Torvalds scb_child_type);
5781da177e4SLinus Torvalds
5791da177e4SLinus Torvalds return scb;
5801da177e4SLinus Torvalds }
5811da177e4SLinus Torvalds
5821da177e4SLinus Torvalds #define GOF_PER_SEC 200
5831da177e4SLinus Torvalds
5843d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip,char * scb_name,int rate,u16 src_buffer_addr,u16 src_delay_buffer_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type,int pass_through)5853d19f804STakashi Iwai cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
5861da177e4SLinus Torvalds int rate,
5871da177e4SLinus Torvalds u16 src_buffer_addr,
5881da177e4SLinus Torvalds u16 src_delay_buffer_addr, u32 dest,
5893d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
5901da177e4SLinus Torvalds int scb_child_type,
5911da177e4SLinus Torvalds int pass_through)
5921da177e4SLinus Torvalds {
5931da177e4SLinus Torvalds
5943d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
5953d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
5961da177e4SLinus Torvalds unsigned int tmp1, tmp2;
5971da177e4SLinus Torvalds unsigned int phiIncr;
5981da177e4SLinus Torvalds unsigned int correctionPerGOF, correctionPerSec;
5991da177e4SLinus Torvalds
6002b96a7f1STakashi Iwai dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
6012b96a7f1STakashi Iwai scb_name, rate);
6021da177e4SLinus Torvalds
6031da177e4SLinus Torvalds /*
6041da177e4SLinus Torvalds * Compute the values used to drive the actual sample rate conversion.
6051da177e4SLinus Torvalds * The following formulas are being computed, using inline assembly
6061da177e4SLinus Torvalds * since we need to use 64 bit arithmetic to compute the values:
6071da177e4SLinus Torvalds *
6081da177e4SLinus Torvalds * phiIncr = floor((Fs,in * 2^26) / Fs,out)
6091da177e4SLinus Torvalds * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
6101da177e4SLinus Torvalds * GOF_PER_SEC)
6111da177e4SLinus Torvalds * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
6121da177e4SLinus Torvalds * GOF_PER_SEC * correctionPerGOF
6131da177e4SLinus Torvalds *
6141da177e4SLinus Torvalds * i.e.
6151da177e4SLinus Torvalds *
6161da177e4SLinus Torvalds * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
6171da177e4SLinus Torvalds * correctionPerGOF:correctionPerSec =
6181da177e4SLinus Torvalds * dividend:remainder(ulOther / GOF_PER_SEC)
6191da177e4SLinus Torvalds */
6201da177e4SLinus Torvalds tmp1 = rate << 16;
6211da177e4SLinus Torvalds phiIncr = tmp1 / 48000;
6221da177e4SLinus Torvalds tmp1 -= phiIncr * 48000;
6231da177e4SLinus Torvalds tmp1 <<= 10;
6241da177e4SLinus Torvalds phiIncr <<= 10;
6251da177e4SLinus Torvalds tmp2 = tmp1 / 48000;
6261da177e4SLinus Torvalds phiIncr += tmp2;
6271da177e4SLinus Torvalds tmp1 -= tmp2 * 48000;
6281da177e4SLinus Torvalds correctionPerGOF = tmp1 / GOF_PER_SEC;
6291da177e4SLinus Torvalds tmp1 -= correctionPerGOF * GOF_PER_SEC;
6301da177e4SLinus Torvalds correctionPerSec = tmp1;
6311da177e4SLinus Torvalds
6321da177e4SLinus Torvalds {
6333d19f804STakashi Iwai struct dsp_src_task_scb src_task_scb = {
6341da177e4SLinus Torvalds 0x0028,0x00c8,
6351da177e4SLinus Torvalds 0x5555,0x0000,
6361da177e4SLinus Torvalds 0x0000,0x0000,
6371da177e4SLinus Torvalds src_buffer_addr,1,
6381da177e4SLinus Torvalds correctionPerGOF,correctionPerSec,
6391da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
6401da177e4SLinus Torvalds 0x0000,src_delay_buffer_addr,
6411da177e4SLinus Torvalds 0x0,
6421da177e4SLinus Torvalds 0x080,(src_delay_buffer_addr + (24 * 4)),
6431da177e4SLinus Torvalds 0,0, /* next_scb, sub_list_ptr */
6441da177e4SLinus Torvalds 0,0, /* entry, this_spb */
6451da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
6461da177e4SLinus Torvalds src_buffer_addr << 0x10,
6471da177e4SLinus Torvalds phiIncr,
6481da177e4SLinus Torvalds {
6491da177e4SLinus Torvalds 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
6501da177e4SLinus Torvalds 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds };
6531da177e4SLinus Torvalds
6541da177e4SLinus Torvalds if (ins->s16_up == NULL) {
6551da177e4SLinus Torvalds ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
6561da177e4SLinus Torvalds SYMBOL_CODE);
6571da177e4SLinus Torvalds
6581da177e4SLinus Torvalds if (ins->s16_up == NULL) {
6592b96a7f1STakashi Iwai dev_err(chip->card->dev,
6602b96a7f1STakashi Iwai "dsp_spos: symbol S16_UPSRC not found\n");
6611da177e4SLinus Torvalds return NULL;
6621da177e4SLinus Torvalds }
6631da177e4SLinus Torvalds }
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds /* clear buffers */
6661da177e4SLinus Torvalds _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
6671da177e4SLinus Torvalds _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
6681da177e4SLinus Torvalds
6691da177e4SLinus Torvalds if (pass_through) {
6701da177e4SLinus Torvalds /* wont work with any other rate than
6711da177e4SLinus Torvalds the native DSP rate */
672da3cec35STakashi Iwai snd_BUG_ON(rate != 48000);
6731da177e4SLinus Torvalds
6741da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
6751da177e4SLinus Torvalds dest,"DMAREADER",parent_scb,
6761da177e4SLinus Torvalds scb_child_type);
6771da177e4SLinus Torvalds } else {
6781da177e4SLinus Torvalds scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
6791da177e4SLinus Torvalds dest,ins->s16_up,parent_scb,
6801da177e4SLinus Torvalds scb_child_type);
6811da177e4SLinus Torvalds }
6821da177e4SLinus Torvalds
6831da177e4SLinus Torvalds
6841da177e4SLinus Torvalds }
6851da177e4SLinus Torvalds
6861da177e4SLinus Torvalds return scb;
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds
6891da177e4SLinus Torvalds #if 0 /* not used */
6903d19f804STakashi Iwai struct dsp_scb_descriptor *
6913d19f804STakashi Iwai cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
6921da177e4SLinus Torvalds u16 buffer_addr, u32 dest,
6933d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
6941da177e4SLinus Torvalds int scb_child_type) {
6953d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
6961da177e4SLinus Torvalds
6973d19f804STakashi Iwai struct dsp_filter_scb filter_scb = {
6981da177e4SLinus Torvalds .a0_right = 0x41a9,
6991da177e4SLinus Torvalds .a0_left = 0x41a9,
7001da177e4SLinus Torvalds .a1_right = 0xb8e4,
7011da177e4SLinus Torvalds .a1_left = 0xb8e4,
7021da177e4SLinus Torvalds .a2_right = 0x3e55,
7031da177e4SLinus Torvalds .a2_left = 0x3e55,
7041da177e4SLinus Torvalds
7051da177e4SLinus Torvalds .filter_unused3 = 0x0000,
7061da177e4SLinus Torvalds .filter_unused2 = 0x0000,
7071da177e4SLinus Torvalds
7081da177e4SLinus Torvalds .output_buf_ptr = buffer_addr,
7091da177e4SLinus Torvalds .init = 0x000,
7101da177e4SLinus Torvalds
7111da177e4SLinus Torvalds .prev_sample_output1 = 0x00000000,
7121da177e4SLinus Torvalds .prev_sample_output2 = 0x00000000,
7131da177e4SLinus Torvalds
7141da177e4SLinus Torvalds .prev_sample_input1 = 0x00000000,
7151da177e4SLinus Torvalds .prev_sample_input2 = 0x00000000,
7161da177e4SLinus Torvalds
7171da177e4SLinus Torvalds .next_scb_ptr = 0x0000,
7181da177e4SLinus Torvalds .sub_list_ptr = 0x0000,
7191da177e4SLinus Torvalds
7201da177e4SLinus Torvalds .entry_point = 0x0000,
7211da177e4SLinus Torvalds .spb_ptr = 0x0000,
7221da177e4SLinus Torvalds
7231da177e4SLinus Torvalds .b0_right = 0x0e38,
7241da177e4SLinus Torvalds .b0_left = 0x0e38,
7251da177e4SLinus Torvalds .b1_right = 0x1c71,
7261da177e4SLinus Torvalds .b1_left = 0x1c71,
7271da177e4SLinus Torvalds .b2_right = 0x0e38,
7281da177e4SLinus Torvalds .b2_left = 0x0e38,
7291da177e4SLinus Torvalds };
7301da177e4SLinus Torvalds
7311da177e4SLinus Torvalds
7321da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
7331da177e4SLinus Torvalds dest,"FILTERTASK",parent_scb,
7341da177e4SLinus Torvalds scb_child_type);
7351da177e4SLinus Torvalds
7361da177e4SLinus Torvalds return scb;
7371da177e4SLinus Torvalds }
7381da177e4SLinus Torvalds #endif /* not used */
7391da177e4SLinus Torvalds
7403d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip,char * scb_name,u16 mix_buffer_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)7413d19f804STakashi Iwai cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
7421da177e4SLinus Torvalds u16 mix_buffer_addr, u32 dest,
7433d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
7441da177e4SLinus Torvalds int scb_child_type)
7451da177e4SLinus Torvalds {
7463d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
7471da177e4SLinus Torvalds
7483d19f804STakashi Iwai struct dsp_mix_only_scb master_mix_scb = {
7491da177e4SLinus Torvalds /* 0 */ { 0,
7501da177e4SLinus Torvalds /* 1 */ 0,
7511da177e4SLinus Torvalds /* 2 */ mix_buffer_addr,
7521da177e4SLinus Torvalds /* 3 */ 0
7531da177e4SLinus Torvalds /* */ },
7541da177e4SLinus Torvalds {
7551da177e4SLinus Torvalds /* 4 */ 0,
7561da177e4SLinus Torvalds /* 5 */ 0,
7571da177e4SLinus Torvalds /* 6 */ 0,
7581da177e4SLinus Torvalds /* 7 */ 0,
7591da177e4SLinus Torvalds /* 8 */ 0x00000080
7601da177e4SLinus Torvalds },
7611da177e4SLinus Torvalds /* 9 */ 0,0,
7621da177e4SLinus Torvalds /* A */ 0,0,
7631da177e4SLinus Torvalds /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
7641da177e4SLinus Torvalds /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
7651da177e4SLinus Torvalds /* D */ 0,
7661da177e4SLinus Torvalds {
7671da177e4SLinus Torvalds /* E */ 0x8000,0x8000,
7681da177e4SLinus Torvalds /* F */ 0x8000,0x8000
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds };
7711da177e4SLinus Torvalds
7721da177e4SLinus Torvalds
7731da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
7741da177e4SLinus Torvalds dest,"S16_MIX",parent_scb,
7751da177e4SLinus Torvalds scb_child_type);
7761da177e4SLinus Torvalds return scb;
7771da177e4SLinus Torvalds }
7781da177e4SLinus Torvalds
7791da177e4SLinus Torvalds
7803d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip,char * scb_name,u16 mix_buffer_addr,u16 writeback_spb,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)7813d19f804STakashi Iwai cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
7821da177e4SLinus Torvalds u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
7833d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
7841da177e4SLinus Torvalds int scb_child_type)
7851da177e4SLinus Torvalds {
7863d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
7871da177e4SLinus Torvalds
7883d19f804STakashi Iwai struct dsp_mix2_ostream_scb mix2_ostream_scb = {
7891da177e4SLinus Torvalds /* Basic (non scatter/gather) DMA requestor (4 ints) */
7901da177e4SLinus Torvalds {
7911da177e4SLinus Torvalds DMA_RQ_C1_SOURCE_MOD64 +
7921da177e4SLinus Torvalds DMA_RQ_C1_DEST_ON_HOST +
7931da177e4SLinus Torvalds DMA_RQ_C1_DEST_MOD1024 +
7941da177e4SLinus Torvalds DMA_RQ_C1_WRITEBACK_SRC_FLAG +
7951da177e4SLinus Torvalds DMA_RQ_C1_WRITEBACK_DEST_FLAG +
7961da177e4SLinus Torvalds 15,
7971da177e4SLinus Torvalds
7981da177e4SLinus Torvalds DMA_RQ_C2_AC_NONE +
7991da177e4SLinus Torvalds DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
8001da177e4SLinus Torvalds
8011da177e4SLinus Torvalds CS46XX_DSP_CAPTURE_CHANNEL,
8021da177e4SLinus Torvalds DMA_RQ_SD_SP_SAMPLE_ADDR +
8031da177e4SLinus Torvalds mix_buffer_addr,
8041da177e4SLinus Torvalds 0x0
8051da177e4SLinus Torvalds },
8061da177e4SLinus Torvalds
8071da177e4SLinus Torvalds { 0, 0, 0, 0, 0, },
8081da177e4SLinus Torvalds 0,0,
8091da177e4SLinus Torvalds 0,writeback_spb,
8101da177e4SLinus Torvalds
8111da177e4SLinus Torvalds RSCONFIG_DMA_ENABLE +
8121da177e4SLinus Torvalds (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
8131da177e4SLinus Torvalds
8141da177e4SLinus Torvalds ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
8151da177e4SLinus Torvalds RSCONFIG_DMA_TO_HOST +
8161da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO +
8171da177e4SLinus Torvalds RSCONFIG_MODULO_64,
8181da177e4SLinus Torvalds (mix_buffer_addr + (32 * 4)) << 0x10,
8191da177e4SLinus Torvalds 1,0,
8201da177e4SLinus Torvalds 0x0001,0x0080,
8211da177e4SLinus Torvalds 0xFFFF,0
8221da177e4SLinus Torvalds };
8231da177e4SLinus Torvalds
8241da177e4SLinus Torvalds
8251da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
8261da177e4SLinus Torvalds
8271da177e4SLinus Torvalds dest,"S16_MIX_TO_OSTREAM",parent_scb,
8281da177e4SLinus Torvalds scb_child_type);
8291da177e4SLinus Torvalds
8301da177e4SLinus Torvalds return scb;
8311da177e4SLinus Torvalds }
8321da177e4SLinus Torvalds
8331da177e4SLinus Torvalds
8343d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,u16 vari_buffer_addr0,u16 vari_buffer_addr1,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)8353d19f804STakashi Iwai cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
8361da177e4SLinus Torvalds u16 vari_buffer_addr0,
8371da177e4SLinus Torvalds u16 vari_buffer_addr1,
8381da177e4SLinus Torvalds u32 dest,
8393d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
8401da177e4SLinus Torvalds int scb_child_type)
8411da177e4SLinus Torvalds {
8421da177e4SLinus Torvalds
8433d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
8441da177e4SLinus Torvalds
8453d19f804STakashi Iwai struct dsp_vari_decimate_scb vari_decimate_scb = {
8461da177e4SLinus Torvalds 0x0028,0x00c8,
8471da177e4SLinus Torvalds 0x5555,0x0000,
8481da177e4SLinus Torvalds 0x0000,0x0000,
8491da177e4SLinus Torvalds vari_buffer_addr0,vari_buffer_addr1,
8501da177e4SLinus Torvalds
8511da177e4SLinus Torvalds 0x0028,0x00c8,
8521da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
8531da177e4SLinus Torvalds
8541da177e4SLinus Torvalds 0xFF800000,
8551da177e4SLinus Torvalds 0,
8561da177e4SLinus Torvalds 0x0080,vari_buffer_addr1 + (25 * 4),
8571da177e4SLinus Torvalds
8581da177e4SLinus Torvalds 0,0,
8591da177e4SLinus Torvalds 0,0,
8601da177e4SLinus Torvalds
8611da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
8621da177e4SLinus Torvalds vari_buffer_addr0 << 0x10,
8631da177e4SLinus Torvalds 0x04000000,
8641da177e4SLinus Torvalds {
8651da177e4SLinus Torvalds 0x8000,0x8000,
8661da177e4SLinus Torvalds 0xFFFF,0xFFFF
8671da177e4SLinus Torvalds }
8681da177e4SLinus Torvalds };
8691da177e4SLinus Torvalds
8701da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
8711da177e4SLinus Torvalds dest,"VARIDECIMATE",parent_scb,
8721da177e4SLinus Torvalds scb_child_type);
8731da177e4SLinus Torvalds
8741da177e4SLinus Torvalds return scb;
8751da177e4SLinus Torvalds }
8761da177e4SLinus Torvalds
8771da177e4SLinus Torvalds
8783d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,struct dsp_scb_descriptor * input_scb,struct dsp_scb_descriptor * parent_scb,int scb_child_type)8793d19f804STakashi Iwai cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
8803d19f804STakashi Iwai struct dsp_scb_descriptor * input_scb,
8813d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
8821da177e4SLinus Torvalds int scb_child_type)
8831da177e4SLinus Torvalds {
8841da177e4SLinus Torvalds
8853d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
8861da177e4SLinus Torvalds
8871da177e4SLinus Torvalds
8883d19f804STakashi Iwai struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
8891da177e4SLinus Torvalds { 0,
8901da177e4SLinus Torvalds 0,
8911da177e4SLinus Torvalds 0,
8921da177e4SLinus Torvalds 0
8931da177e4SLinus Torvalds },
8941da177e4SLinus Torvalds {
8951da177e4SLinus Torvalds 0,
8961da177e4SLinus Torvalds 0,
8971da177e4SLinus Torvalds 0,
8981da177e4SLinus Torvalds 0,
8991da177e4SLinus Torvalds 0
9001da177e4SLinus Torvalds },
9011da177e4SLinus Torvalds
9021da177e4SLinus Torvalds 0,0,
9031da177e4SLinus Torvalds 0,0,
9041da177e4SLinus Torvalds
9051da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
9061da177e4SLinus Torvalds 0,
9071da177e4SLinus Torvalds /* 0xD */ 0,input_scb->address,
9081da177e4SLinus Torvalds {
9091da177e4SLinus Torvalds /* 0xE */ 0x8000,0x8000,
9101da177e4SLinus Torvalds /* 0xF */ 0x8000,0x8000
9111da177e4SLinus Torvalds }
9121da177e4SLinus Torvalds };
9131da177e4SLinus Torvalds
9141da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
9151da177e4SLinus Torvalds dest,"PCMSERIALINPUTTASK",parent_scb,
9161da177e4SLinus Torvalds scb_child_type);
9171da177e4SLinus Torvalds return scb;
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds
9201da177e4SLinus Torvalds
9213d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,u16 hfg_scb_address,u16 asynch_buffer_address,struct dsp_scb_descriptor * parent_scb,int scb_child_type)9223d19f804STakashi Iwai cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
9231da177e4SLinus Torvalds u16 hfg_scb_address,
9241da177e4SLinus Torvalds u16 asynch_buffer_address,
9253d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
9261da177e4SLinus Torvalds int scb_child_type)
9271da177e4SLinus Torvalds {
9281da177e4SLinus Torvalds
9293d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
9301da177e4SLinus Torvalds
9313d19f804STakashi Iwai struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
9321da177e4SLinus Torvalds 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
9331da177e4SLinus Torvalds 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
9341da177e4SLinus Torvalds /* : Max delta 25 dwords == 100 bytes */
9351da177e4SLinus Torvalds 0,hfg_scb_address, /* Point to HFG task SCB */
9361da177e4SLinus Torvalds 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
9371da177e4SLinus Torvalds 0, /* Initialize accumulated Phi to 0 */
9381da177e4SLinus Torvalds 0,0x2aab, /* Const 1/3 */
9391da177e4SLinus Torvalds
9401da177e4SLinus Torvalds {
9411da177e4SLinus Torvalds 0, /* Define the unused elements */
9421da177e4SLinus Torvalds 0,
9431da177e4SLinus Torvalds 0
9441da177e4SLinus Torvalds },
9451da177e4SLinus Torvalds
9461da177e4SLinus Torvalds 0,0,
9471da177e4SLinus Torvalds 0,dest + AFGTxAccumPhi,
9481da177e4SLinus Torvalds
9491da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
9501da177e4SLinus Torvalds (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
9511da177e4SLinus Torvalds to the producer pointer */
9521da177e4SLinus Torvalds
9531da177e4SLinus Torvalds /* There is no correct initial value, it will depend upon the detected
9541da177e4SLinus Torvalds rate etc */
9551da177e4SLinus Torvalds 0x18000000, /* Phi increment for approx 32k operation */
9561da177e4SLinus Torvalds 0x8000,0x8000, /* Volume controls are unused at this time */
9571da177e4SLinus Torvalds 0x8000,0x8000
9581da177e4SLinus Torvalds };
9591da177e4SLinus Torvalds
9601da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
9611da177e4SLinus Torvalds dest,"ASYNCHFGTXCODE",parent_scb,
9621da177e4SLinus Torvalds scb_child_type);
9631da177e4SLinus Torvalds
9641da177e4SLinus Torvalds return scb;
9651da177e4SLinus Torvalds }
9661da177e4SLinus Torvalds
9671da177e4SLinus Torvalds
9683d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,u16 hfg_scb_address,u16 asynch_buffer_address,struct dsp_scb_descriptor * parent_scb,int scb_child_type)9693d19f804STakashi Iwai cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
9701da177e4SLinus Torvalds u16 hfg_scb_address,
9711da177e4SLinus Torvalds u16 asynch_buffer_address,
9723d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
9731da177e4SLinus Torvalds int scb_child_type)
9741da177e4SLinus Torvalds {
9753d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
9763d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
9771da177e4SLinus Torvalds
9783d19f804STakashi Iwai struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
9791da177e4SLinus Torvalds 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
9801da177e4SLinus Torvalds 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
9811da177e4SLinus Torvalds /* : Max delta 25 dwords == 100 bytes */
9821da177e4SLinus Torvalds 0,hfg_scb_address, /* Point to HFG task SCB */
9831da177e4SLinus Torvalds 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
9841da177e4SLinus Torvalds {
9851da177e4SLinus Torvalds 0, /* Define the unused elements */
9861da177e4SLinus Torvalds 0,
9871da177e4SLinus Torvalds 0,
9881da177e4SLinus Torvalds 0,
9891da177e4SLinus Torvalds 0
9901da177e4SLinus Torvalds },
9911da177e4SLinus Torvalds
9921da177e4SLinus Torvalds 0,0,
9931da177e4SLinus Torvalds 0,dest,
9941da177e4SLinus Torvalds
9951da177e4SLinus Torvalds RSCONFIG_MODULO_128 |
9961da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
9971da177e4SLinus Torvalds ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
9981da177e4SLinus Torvalds synchrinized to the producer pointer */
9991da177e4SLinus Torvalds
10001da177e4SLinus Torvalds /* There is no correct initial value, it will depend upon the detected
10011da177e4SLinus Torvalds rate etc */
10021da177e4SLinus Torvalds 0x18000000,
10031da177e4SLinus Torvalds
10041da177e4SLinus Torvalds /* Set IEC958 input volume */
10051da177e4SLinus Torvalds 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
10061da177e4SLinus Torvalds 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
10071da177e4SLinus Torvalds };
10081da177e4SLinus Torvalds
10091da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
10101da177e4SLinus Torvalds dest,"ASYNCHFGRXCODE",parent_scb,
10111da177e4SLinus Torvalds scb_child_type);
10121da177e4SLinus Torvalds
10131da177e4SLinus Torvalds return scb;
10141da177e4SLinus Torvalds }
10151da177e4SLinus Torvalds
10161da177e4SLinus Torvalds
10171da177e4SLinus Torvalds #if 0 /* not used */
10183d19f804STakashi Iwai struct dsp_scb_descriptor *
10193d19f804STakashi Iwai cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10201da177e4SLinus Torvalds u16 snoop_buffer_address,
10213d19f804STakashi Iwai struct dsp_scb_descriptor * snoop_scb,
10223d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
10231da177e4SLinus Torvalds int scb_child_type)
10241da177e4SLinus Torvalds {
10251da177e4SLinus Torvalds
10263d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
10271da177e4SLinus Torvalds
10283d19f804STakashi Iwai struct dsp_output_snoop_scb output_snoop_scb = {
10291da177e4SLinus Torvalds { 0, /* not used. Zero */
10301da177e4SLinus Torvalds 0,
10311da177e4SLinus Torvalds 0,
10321da177e4SLinus Torvalds 0,
10331da177e4SLinus Torvalds },
10341da177e4SLinus Torvalds {
10351da177e4SLinus Torvalds 0, /* not used. Zero */
10361da177e4SLinus Torvalds 0,
10371da177e4SLinus Torvalds 0,
10381da177e4SLinus Torvalds 0,
10391da177e4SLinus Torvalds 0
10401da177e4SLinus Torvalds },
10411da177e4SLinus Torvalds
10421da177e4SLinus Torvalds 0,0,
10431da177e4SLinus Torvalds 0,0,
10441da177e4SLinus Torvalds
10451da177e4SLinus Torvalds RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
10461da177e4SLinus Torvalds snoop_buffer_address << 0x10,
10471da177e4SLinus Torvalds 0,0,
10481da177e4SLinus Torvalds 0,
10491da177e4SLinus Torvalds 0,snoop_scb->address
10501da177e4SLinus Torvalds };
10511da177e4SLinus Torvalds
10521da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
10531da177e4SLinus Torvalds dest,"OUTPUTSNOOP",parent_scb,
10541da177e4SLinus Torvalds scb_child_type);
10551da177e4SLinus Torvalds return scb;
10561da177e4SLinus Torvalds }
10571da177e4SLinus Torvalds #endif /* not used */
10581da177e4SLinus Torvalds
10591da177e4SLinus Torvalds
10603d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)10613d19f804STakashi Iwai cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10623d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
10631da177e4SLinus Torvalds int scb_child_type)
10641da177e4SLinus Torvalds {
10653d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
10661da177e4SLinus Torvalds
10673d19f804STakashi Iwai struct dsp_spio_write_scb spio_write_scb = {
10681da177e4SLinus Torvalds 0,0, /* SPIOWAddress2:SPIOWAddress1; */
10691da177e4SLinus Torvalds 0, /* SPIOWData1; */
10701da177e4SLinus Torvalds 0, /* SPIOWData2; */
10711da177e4SLinus Torvalds 0,0, /* SPIOWAddress4:SPIOWAddress3; */
10721da177e4SLinus Torvalds 0, /* SPIOWData3; */
10731da177e4SLinus Torvalds 0, /* SPIOWData4; */
10741da177e4SLinus Torvalds 0,0, /* SPIOWDataPtr:Unused1; */
10751da177e4SLinus Torvalds { 0,0 }, /* Unused2[2]; */
10761da177e4SLinus Torvalds
10771da177e4SLinus Torvalds 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
10781da177e4SLinus Torvalds 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
10791da177e4SLinus Torvalds
10801da177e4SLinus Torvalds {
10811da177e4SLinus Torvalds 0,
10821da177e4SLinus Torvalds 0,
10831da177e4SLinus Torvalds 0,
10841da177e4SLinus Torvalds 0,
10851da177e4SLinus Torvalds 0 /* Unused3[5]; */
10861da177e4SLinus Torvalds }
10871da177e4SLinus Torvalds };
10881da177e4SLinus Torvalds
10891da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
10901da177e4SLinus Torvalds dest,"SPIOWRITE",parent_scb,
10911da177e4SLinus Torvalds scb_child_type);
10921da177e4SLinus Torvalds
10931da177e4SLinus Torvalds return scb;
10941da177e4SLinus Torvalds }
10951da177e4SLinus Torvalds
10963d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,u16 snoop_buffer_address,struct dsp_scb_descriptor * snoop_scb,struct dsp_scb_descriptor * parent_scb,int scb_child_type)10973d19f804STakashi Iwai cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10981da177e4SLinus Torvalds u16 snoop_buffer_address,
10993d19f804STakashi Iwai struct dsp_scb_descriptor * snoop_scb,
11003d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb,
11011da177e4SLinus Torvalds int scb_child_type)
11021da177e4SLinus Torvalds {
11033d19f804STakashi Iwai struct dsp_scb_descriptor * scb;
11041da177e4SLinus Torvalds
11053d19f804STakashi Iwai struct dsp_magic_snoop_task magic_snoop_scb = {
11061da177e4SLinus Torvalds /* 0 */ 0, /* i0 */
11071da177e4SLinus Torvalds /* 1 */ 0, /* i1 */
11081da177e4SLinus Torvalds /* 2 */ snoop_buffer_address << 0x10,
11091da177e4SLinus Torvalds /* 3 */ 0,snoop_scb->address,
11101da177e4SLinus Torvalds /* 4 */ 0, /* i3 */
11111da177e4SLinus Torvalds /* 5 */ 0, /* i4 */
11121da177e4SLinus Torvalds /* 6 */ 0, /* i5 */
11131da177e4SLinus Torvalds /* 7 */ 0, /* i6 */
11141da177e4SLinus Torvalds /* 8 */ 0, /* i7 */
11151da177e4SLinus Torvalds /* 9 */ 0,0, /* next_scb, sub_list_ptr */
11161da177e4SLinus Torvalds /* A */ 0,0, /* entry_point, this_ptr */
11171da177e4SLinus Torvalds /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
11181da177e4SLinus Torvalds /* C */ snoop_buffer_address << 0x10,
11191da177e4SLinus Torvalds /* D */ 0,
11201da177e4SLinus Torvalds /* E */ { 0x8000,0x8000,
11211da177e4SLinus Torvalds /* F */ 0xffff,0xffff
11221da177e4SLinus Torvalds }
11231da177e4SLinus Torvalds };
11241da177e4SLinus Torvalds
11251da177e4SLinus Torvalds scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
11261da177e4SLinus Torvalds dest,"MAGICSNOOPTASK",parent_scb,
11271da177e4SLinus Torvalds scb_child_type);
11281da177e4SLinus Torvalds
11291da177e4SLinus Torvalds return scb;
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds
11323d19f804STakashi Iwai static struct dsp_scb_descriptor *
find_next_free_scb(struct snd_cs46xx * chip,struct dsp_scb_descriptor * from)11333d19f804STakashi Iwai find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
11341da177e4SLinus Torvalds {
11353d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
11363d19f804STakashi Iwai struct dsp_scb_descriptor * scb = from;
11371da177e4SLinus Torvalds
11381da177e4SLinus Torvalds while (scb->next_scb_ptr != ins->the_null_scb) {
1139da3cec35STakashi Iwai if (snd_BUG_ON(!scb->next_scb_ptr))
1140da3cec35STakashi Iwai return NULL;
11411da177e4SLinus Torvalds
11421da177e4SLinus Torvalds scb = scb->next_scb_ptr;
11431da177e4SLinus Torvalds }
11441da177e4SLinus Torvalds
11451da177e4SLinus Torvalds return scb;
11461da177e4SLinus Torvalds }
11471da177e4SLinus Torvalds
1148ba09f5d8STakashi Iwai static const u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
11491da177e4SLinus Torvalds 0x0600, /* 1 */
11501da177e4SLinus Torvalds 0x1500, /* 2 */
11511da177e4SLinus Torvalds 0x1580, /* 3 */
11521da177e4SLinus Torvalds 0x1600, /* 4 */
11531da177e4SLinus Torvalds 0x1680, /* 5 */
11541da177e4SLinus Torvalds 0x1700, /* 6 */
11551da177e4SLinus Torvalds 0x1780, /* 7 */
11561da177e4SLinus Torvalds 0x1800, /* 8 */
11571da177e4SLinus Torvalds 0x1880, /* 9 */
11581da177e4SLinus Torvalds 0x1900, /* 10 */
11591da177e4SLinus Torvalds 0x1980, /* 11 */
11601da177e4SLinus Torvalds 0x1A00, /* 12 */
11611da177e4SLinus Torvalds 0x1A80, /* 13 */
11621da177e4SLinus Torvalds 0x1B00, /* 14 */
11631da177e4SLinus Torvalds 0x1B80, /* 15 */
11641da177e4SLinus Torvalds 0x1C00, /* 16 */
11651da177e4SLinus Torvalds 0x1C80, /* 17 */
11661da177e4SLinus Torvalds 0x1D00, /* 18 */
11671da177e4SLinus Torvalds 0x1D80, /* 19 */
11681da177e4SLinus Torvalds 0x1E00, /* 20 */
11691da177e4SLinus Torvalds 0x1E80, /* 21 */
11701da177e4SLinus Torvalds 0x1F00, /* 22 */
11711da177e4SLinus Torvalds 0x1F80, /* 23 */
11721da177e4SLinus Torvalds 0x2000, /* 24 */
11731da177e4SLinus Torvalds 0x2080, /* 25 */
11741da177e4SLinus Torvalds 0x2100, /* 26 */
11751da177e4SLinus Torvalds 0x2180, /* 27 */
11761da177e4SLinus Torvalds 0x2200, /* 28 */
11771da177e4SLinus Torvalds 0x2280, /* 29 */
11781da177e4SLinus Torvalds 0x2300, /* 30 */
11791da177e4SLinus Torvalds 0x2380, /* 31 */
11801da177e4SLinus Torvalds 0x2400, /* 32 */
11811da177e4SLinus Torvalds };
11821da177e4SLinus Torvalds
1183ba09f5d8STakashi Iwai static const u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
11841da177e4SLinus Torvalds 0x2B80,
11851da177e4SLinus Torvalds 0x2BA0,
11861da177e4SLinus Torvalds 0x2BC0,
11871da177e4SLinus Torvalds 0x2BE0,
11881da177e4SLinus Torvalds 0x2D00,
11891da177e4SLinus Torvalds 0x2D20,
11901da177e4SLinus Torvalds 0x2D40,
11911da177e4SLinus Torvalds 0x2D60,
11921da177e4SLinus Torvalds 0x2D80,
11931da177e4SLinus Torvalds 0x2DA0,
11941da177e4SLinus Torvalds 0x2DC0,
11951da177e4SLinus Torvalds 0x2DE0,
11961da177e4SLinus Torvalds 0x2E00,
11971da177e4SLinus Torvalds 0x2E20
11981da177e4SLinus Torvalds };
11991da177e4SLinus Torvalds
1200ba09f5d8STakashi Iwai static const u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
12011da177e4SLinus Torvalds 0x2480,
12021da177e4SLinus Torvalds 0x2500,
12031da177e4SLinus Torvalds 0x2580,
12041da177e4SLinus Torvalds 0x2600,
12051da177e4SLinus Torvalds 0x2680,
12061da177e4SLinus Torvalds 0x2700,
12071da177e4SLinus Torvalds 0x2780,
12081da177e4SLinus Torvalds 0x2800,
12091da177e4SLinus Torvalds 0x2880,
12101da177e4SLinus Torvalds 0x2900,
12111da177e4SLinus Torvalds 0x2980,
12121da177e4SLinus Torvalds 0x2A00,
12131da177e4SLinus Torvalds 0x2A80,
12141da177e4SLinus Torvalds 0x2B00
12151da177e4SLinus Torvalds };
12161da177e4SLinus Torvalds
12173d19f804STakashi Iwai struct dsp_pcm_channel_descriptor *
cs46xx_dsp_create_pcm_channel(struct snd_cs46xx * chip,u32 sample_rate,void * private_data,u32 hw_dma_addr,int pcm_channel_id)12183d19f804STakashi Iwai cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
12191da177e4SLinus Torvalds u32 sample_rate, void * private_data,
12201da177e4SLinus Torvalds u32 hw_dma_addr,
12211da177e4SLinus Torvalds int pcm_channel_id)
12221da177e4SLinus Torvalds {
12233d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
12243d19f804STakashi Iwai struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
12253d19f804STakashi Iwai struct dsp_scb_descriptor * src_parent_scb = NULL;
12261da177e4SLinus Torvalds
12273d19f804STakashi Iwai /* struct dsp_scb_descriptor * pcm_parent_scb; */
12281da177e4SLinus Torvalds char scb_name[DSP_MAX_SCB_NAME];
12291da177e4SLinus Torvalds int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
12301da177e4SLinus Torvalds unsigned long flags;
12311da177e4SLinus Torvalds
12321da177e4SLinus Torvalds switch (pcm_channel_id) {
12331da177e4SLinus Torvalds case DSP_PCM_MAIN_CHANNEL:
12341da177e4SLinus Torvalds mixer_scb = ins->master_mix_scb;
12351da177e4SLinus Torvalds break;
12361da177e4SLinus Torvalds case DSP_PCM_REAR_CHANNEL:
12371da177e4SLinus Torvalds mixer_scb = ins->rear_mix_scb;
12381da177e4SLinus Torvalds break;
12391da177e4SLinus Torvalds case DSP_PCM_CENTER_LFE_CHANNEL:
12401da177e4SLinus Torvalds mixer_scb = ins->center_lfe_mix_scb;
12411da177e4SLinus Torvalds break;
12421da177e4SLinus Torvalds case DSP_PCM_S71_CHANNEL:
12431da177e4SLinus Torvalds /* TODO */
1244da3cec35STakashi Iwai snd_BUG();
12451da177e4SLinus Torvalds break;
12461da177e4SLinus Torvalds case DSP_IEC958_CHANNEL:
1247da3cec35STakashi Iwai if (snd_BUG_ON(!ins->asynch_tx_scb))
1248da3cec35STakashi Iwai return NULL;
12491da177e4SLinus Torvalds mixer_scb = ins->asynch_tx_scb;
12501da177e4SLinus Torvalds
12511da177e4SLinus Torvalds /* if sample rate is set to 48khz we pass
12521da177e4SLinus Torvalds the Sample Rate Converted (which could
12531da177e4SLinus Torvalds alter the raw data stream ...) */
12541da177e4SLinus Torvalds if (sample_rate == 48000) {
12552b96a7f1STakashi Iwai dev_dbg(chip->card->dev, "IEC958 pass through\n");
12561da177e4SLinus Torvalds /* Hack to bypass creating a new SRC */
12571da177e4SLinus Torvalds pass_through = 1;
12581da177e4SLinus Torvalds }
12591da177e4SLinus Torvalds break;
12601da177e4SLinus Torvalds default:
1261da3cec35STakashi Iwai snd_BUG();
12621da177e4SLinus Torvalds return NULL;
12631da177e4SLinus Torvalds }
12641da177e4SLinus Torvalds /* default sample rate is 44100 */
12651da177e4SLinus Torvalds if (!sample_rate) sample_rate = 44100;
12661da177e4SLinus Torvalds
12671da177e4SLinus Torvalds /* search for a already created SRC SCB with the same sample rate */
12681da177e4SLinus Torvalds for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
12691da177e4SLinus Torvalds (pcm_index == -1 || src_scb == NULL); ++i) {
12701da177e4SLinus Torvalds
12711da177e4SLinus Torvalds /* virtual channel reserved
12721da177e4SLinus Torvalds for capture */
12731da177e4SLinus Torvalds if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
12741da177e4SLinus Torvalds
12751da177e4SLinus Torvalds if (ins->pcm_channels[i].active) {
12761da177e4SLinus Torvalds if (!src_scb &&
12771da177e4SLinus Torvalds ins->pcm_channels[i].sample_rate == sample_rate &&
12781da177e4SLinus Torvalds ins->pcm_channels[i].mixer_scb == mixer_scb) {
12791da177e4SLinus Torvalds src_scb = ins->pcm_channels[i].src_scb;
12801da177e4SLinus Torvalds ins->pcm_channels[i].src_scb->ref_count ++;
12811da177e4SLinus Torvalds src_index = ins->pcm_channels[i].src_slot;
12821da177e4SLinus Torvalds }
12831da177e4SLinus Torvalds } else if (pcm_index == -1) {
12841da177e4SLinus Torvalds pcm_index = i;
12851da177e4SLinus Torvalds }
12861da177e4SLinus Torvalds }
12871da177e4SLinus Torvalds
12881da177e4SLinus Torvalds if (pcm_index == -1) {
12892b96a7f1STakashi Iwai dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
12901da177e4SLinus Torvalds return NULL;
12911da177e4SLinus Torvalds }
12921da177e4SLinus Torvalds
12931da177e4SLinus Torvalds if (src_scb == NULL) {
12941da177e4SLinus Torvalds if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
12952b96a7f1STakashi Iwai dev_err(chip->card->dev,
12965396c4bdSColin Ian King "dsp_spos: too many SRC instances\n!");
12971da177e4SLinus Torvalds return NULL;
12981da177e4SLinus Torvalds }
12991da177e4SLinus Torvalds
13001da177e4SLinus Torvalds /* find a free slot */
13011da177e4SLinus Torvalds for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
13021da177e4SLinus Torvalds if (ins->src_scb_slots[i] == 0) {
13031da177e4SLinus Torvalds src_index = i;
13041da177e4SLinus Torvalds ins->src_scb_slots[i] = 1;
13051da177e4SLinus Torvalds break;
13061da177e4SLinus Torvalds }
13071da177e4SLinus Torvalds }
1308da3cec35STakashi Iwai if (snd_BUG_ON(src_index == -1))
1309da3cec35STakashi Iwai return NULL;
13101da177e4SLinus Torvalds
13111da177e4SLinus Torvalds /* we need to create a new SRC SCB */
13121da177e4SLinus Torvalds if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
13131da177e4SLinus Torvalds src_parent_scb = mixer_scb;
13141da177e4SLinus Torvalds insert_point = SCB_ON_PARENT_SUBLIST_SCB;
13151da177e4SLinus Torvalds } else {
13161da177e4SLinus Torvalds src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
13171da177e4SLinus Torvalds insert_point = SCB_ON_PARENT_NEXT_SCB;
13181da177e4SLinus Torvalds }
13191da177e4SLinus Torvalds
13201da177e4SLinus Torvalds snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
13211da177e4SLinus Torvalds
13222b96a7f1STakashi Iwai dev_dbg(chip->card->dev,
13232b96a7f1STakashi Iwai "dsp_spos: creating SRC \"%s\"\n", scb_name);
13241da177e4SLinus Torvalds src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
13251da177e4SLinus Torvalds sample_rate,
13261da177e4SLinus Torvalds src_output_buffer_addr[src_index],
13271da177e4SLinus Torvalds src_delay_buffer_addr[src_index],
13281da177e4SLinus Torvalds /* 0x400 - 0x600 source SCBs */
13291da177e4SLinus Torvalds 0x400 + (src_index * 0x10) ,
13301da177e4SLinus Torvalds src_parent_scb,
13311da177e4SLinus Torvalds insert_point,
13321da177e4SLinus Torvalds pass_through);
13331da177e4SLinus Torvalds
13341da177e4SLinus Torvalds if (!src_scb) {
13352b96a7f1STakashi Iwai dev_err(chip->card->dev,
13362b96a7f1STakashi Iwai "dsp_spos: failed to create SRCtaskSCB\n");
13371da177e4SLinus Torvalds return NULL;
13381da177e4SLinus Torvalds }
13391da177e4SLinus Torvalds
13401da177e4SLinus Torvalds /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
13411da177e4SLinus Torvalds
13421da177e4SLinus Torvalds ins->nsrc_scb ++;
13431da177e4SLinus Torvalds }
13441da177e4SLinus Torvalds
13451da177e4SLinus Torvalds
13461da177e4SLinus Torvalds snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
13471da177e4SLinus Torvalds
13482b96a7f1STakashi Iwai dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
13492b96a7f1STakashi Iwai scb_name, pcm_channel_id);
13501da177e4SLinus Torvalds
13511da177e4SLinus Torvalds pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
13521da177e4SLinus Torvalds pcm_reader_buffer_addr[pcm_index],
13531da177e4SLinus Torvalds /* 0x200 - 400 PCMreader SCBs */
13541da177e4SLinus Torvalds (pcm_index * 0x10) + 0x200,
13551da177e4SLinus Torvalds pcm_index, /* virtual channel 0-31 */
13561da177e4SLinus Torvalds hw_dma_addr, /* pcm hw addr */
13571da177e4SLinus Torvalds NULL, /* parent SCB ptr */
13581da177e4SLinus Torvalds 0 /* insert point */
13591da177e4SLinus Torvalds );
13601da177e4SLinus Torvalds
13611da177e4SLinus Torvalds if (!pcm_scb) {
13622b96a7f1STakashi Iwai dev_err(chip->card->dev,
13632b96a7f1STakashi Iwai "dsp_spos: failed to create PCMreaderSCB\n");
13641da177e4SLinus Torvalds return NULL;
13651da177e4SLinus Torvalds }
13661da177e4SLinus Torvalds
13671da177e4SLinus Torvalds spin_lock_irqsave(&chip->reg_lock, flags);
13681da177e4SLinus Torvalds ins->pcm_channels[pcm_index].sample_rate = sample_rate;
13691da177e4SLinus Torvalds ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
13701da177e4SLinus Torvalds ins->pcm_channels[pcm_index].src_scb = src_scb;
13711da177e4SLinus Torvalds ins->pcm_channels[pcm_index].unlinked = 1;
13721da177e4SLinus Torvalds ins->pcm_channels[pcm_index].private_data = private_data;
13731da177e4SLinus Torvalds ins->pcm_channels[pcm_index].src_slot = src_index;
13741da177e4SLinus Torvalds ins->pcm_channels[pcm_index].active = 1;
13751da177e4SLinus Torvalds ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
13761da177e4SLinus Torvalds ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
13771da177e4SLinus Torvalds ins->npcm_channels ++;
13781da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->reg_lock, flags);
13791da177e4SLinus Torvalds
13801da177e4SLinus Torvalds return (ins->pcm_channels + pcm_index);
13811da177e4SLinus Torvalds }
13821da177e4SLinus Torvalds
cs46xx_dsp_pcm_channel_set_period(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel,int period_size)13833d19f804STakashi Iwai int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
13843d19f804STakashi Iwai struct dsp_pcm_channel_descriptor * pcm_channel,
13851da177e4SLinus Torvalds int period_size)
13861da177e4SLinus Torvalds {
13871da177e4SLinus Torvalds u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
13881da177e4SLinus Torvalds temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
13891da177e4SLinus Torvalds
13901da177e4SLinus Torvalds switch (period_size) {
13911da177e4SLinus Torvalds case 2048:
13921da177e4SLinus Torvalds temp |= DMA_RQ_C1_SOURCE_MOD1024;
13931da177e4SLinus Torvalds break;
13941da177e4SLinus Torvalds case 1024:
13951da177e4SLinus Torvalds temp |= DMA_RQ_C1_SOURCE_MOD512;
13961da177e4SLinus Torvalds break;
13971da177e4SLinus Torvalds case 512:
13981da177e4SLinus Torvalds temp |= DMA_RQ_C1_SOURCE_MOD256;
13991da177e4SLinus Torvalds break;
14001da177e4SLinus Torvalds case 256:
14011da177e4SLinus Torvalds temp |= DMA_RQ_C1_SOURCE_MOD128;
14021da177e4SLinus Torvalds break;
14031da177e4SLinus Torvalds case 128:
14041da177e4SLinus Torvalds temp |= DMA_RQ_C1_SOURCE_MOD64;
14051da177e4SLinus Torvalds break;
14061da177e4SLinus Torvalds case 64:
14071da177e4SLinus Torvalds temp |= DMA_RQ_C1_SOURCE_MOD32;
14081da177e4SLinus Torvalds break;
14091da177e4SLinus Torvalds case 32:
14101da177e4SLinus Torvalds temp |= DMA_RQ_C1_SOURCE_MOD16;
14111da177e4SLinus Torvalds break;
14121da177e4SLinus Torvalds default:
14132b96a7f1STakashi Iwai dev_dbg(chip->card->dev,
14142b96a7f1STakashi Iwai "period size (%d) not supported by HW\n", period_size);
14151da177e4SLinus Torvalds return -EINVAL;
14161da177e4SLinus Torvalds }
14171da177e4SLinus Torvalds
14181da177e4SLinus Torvalds snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
14191da177e4SLinus Torvalds
14201da177e4SLinus Torvalds return 0;
14211da177e4SLinus Torvalds }
14221da177e4SLinus Torvalds
cs46xx_dsp_pcm_ostream_set_period(struct snd_cs46xx * chip,int period_size)14233d19f804STakashi Iwai int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
14241da177e4SLinus Torvalds int period_size)
14251da177e4SLinus Torvalds {
14261da177e4SLinus Torvalds u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
14271da177e4SLinus Torvalds temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
14281da177e4SLinus Torvalds
14291da177e4SLinus Torvalds switch (period_size) {
14301da177e4SLinus Torvalds case 2048:
14311da177e4SLinus Torvalds temp |= DMA_RQ_C1_DEST_MOD1024;
14321da177e4SLinus Torvalds break;
14331da177e4SLinus Torvalds case 1024:
14341da177e4SLinus Torvalds temp |= DMA_RQ_C1_DEST_MOD512;
14351da177e4SLinus Torvalds break;
14361da177e4SLinus Torvalds case 512:
14371da177e4SLinus Torvalds temp |= DMA_RQ_C1_DEST_MOD256;
14381da177e4SLinus Torvalds break;
14391da177e4SLinus Torvalds case 256:
14401da177e4SLinus Torvalds temp |= DMA_RQ_C1_DEST_MOD128;
14411da177e4SLinus Torvalds break;
14421da177e4SLinus Torvalds case 128:
14431da177e4SLinus Torvalds temp |= DMA_RQ_C1_DEST_MOD64;
14441da177e4SLinus Torvalds break;
14451da177e4SLinus Torvalds case 64:
14461da177e4SLinus Torvalds temp |= DMA_RQ_C1_DEST_MOD32;
14471da177e4SLinus Torvalds break;
14481da177e4SLinus Torvalds case 32:
14491da177e4SLinus Torvalds temp |= DMA_RQ_C1_DEST_MOD16;
14501da177e4SLinus Torvalds break;
14511da177e4SLinus Torvalds default:
14522b96a7f1STakashi Iwai dev_dbg(chip->card->dev,
14532b96a7f1STakashi Iwai "period size (%d) not supported by HW\n", period_size);
14541da177e4SLinus Torvalds return -EINVAL;
14551da177e4SLinus Torvalds }
14561da177e4SLinus Torvalds
14571da177e4SLinus Torvalds snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
14581da177e4SLinus Torvalds
14591da177e4SLinus Torvalds return 0;
14601da177e4SLinus Torvalds }
14611da177e4SLinus Torvalds
cs46xx_dsp_destroy_pcm_channel(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel)14623d19f804STakashi Iwai void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
14633d19f804STakashi Iwai struct dsp_pcm_channel_descriptor * pcm_channel)
14641da177e4SLinus Torvalds {
14653d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
14661da177e4SLinus Torvalds unsigned long flags;
14671da177e4SLinus Torvalds
1468da3cec35STakashi Iwai if (snd_BUG_ON(!pcm_channel->active ||
1469da3cec35STakashi Iwai ins->npcm_channels <= 0 ||
1470da3cec35STakashi Iwai pcm_channel->src_scb->ref_count <= 0))
1471da3cec35STakashi Iwai return;
14721da177e4SLinus Torvalds
14731da177e4SLinus Torvalds spin_lock_irqsave(&chip->reg_lock, flags);
14741da177e4SLinus Torvalds pcm_channel->unlinked = 1;
14751da177e4SLinus Torvalds pcm_channel->active = 0;
14761da177e4SLinus Torvalds pcm_channel->private_data = NULL;
14771da177e4SLinus Torvalds pcm_channel->src_scb->ref_count --;
14781da177e4SLinus Torvalds ins->npcm_channels --;
14791da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->reg_lock, flags);
14801da177e4SLinus Torvalds
14811da177e4SLinus Torvalds cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
14821da177e4SLinus Torvalds
14831da177e4SLinus Torvalds if (!pcm_channel->src_scb->ref_count) {
14841da177e4SLinus Torvalds cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
14851da177e4SLinus Torvalds
1486da3cec35STakashi Iwai if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1487da3cec35STakashi Iwai pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1488da3cec35STakashi Iwai return;
14891da177e4SLinus Torvalds
14901da177e4SLinus Torvalds ins->src_scb_slots[pcm_channel->src_slot] = 0;
14911da177e4SLinus Torvalds ins->nsrc_scb --;
14921da177e4SLinus Torvalds }
14931da177e4SLinus Torvalds }
14941da177e4SLinus Torvalds
cs46xx_dsp_pcm_unlink(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel)14953d19f804STakashi Iwai int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
14963d19f804STakashi Iwai struct dsp_pcm_channel_descriptor * pcm_channel)
14971da177e4SLinus Torvalds {
14981da177e4SLinus Torvalds unsigned long flags;
14991da177e4SLinus Torvalds
1500da3cec35STakashi Iwai if (snd_BUG_ON(!pcm_channel->active ||
1501da3cec35STakashi Iwai chip->dsp_spos_instance->npcm_channels <= 0))
1502da3cec35STakashi Iwai return -EIO;
15031da177e4SLinus Torvalds
150441116e92STakashi Iwai spin_lock_irqsave(&chip->reg_lock, flags);
15051da177e4SLinus Torvalds if (pcm_channel->unlinked) {
150641116e92STakashi Iwai spin_unlock_irqrestore(&chip->reg_lock, flags);
15071da177e4SLinus Torvalds return -EIO;
15081da177e4SLinus Torvalds }
15091da177e4SLinus Torvalds
15101da177e4SLinus Torvalds pcm_channel->unlinked = 1;
15111da177e4SLinus Torvalds
15121da177e4SLinus Torvalds _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
151341116e92STakashi Iwai spin_unlock_irqrestore(&chip->reg_lock, flags);
15141da177e4SLinus Torvalds
15151da177e4SLinus Torvalds return 0;
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds
cs46xx_dsp_pcm_link(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel)15183d19f804STakashi Iwai int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
15193d19f804STakashi Iwai struct dsp_pcm_channel_descriptor * pcm_channel)
15201da177e4SLinus Torvalds {
15213d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
15223d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb;
15233d19f804STakashi Iwai struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
15241da177e4SLinus Torvalds unsigned long flags;
15251da177e4SLinus Torvalds
152641116e92STakashi Iwai spin_lock_irqsave(&chip->reg_lock, flags);
15271da177e4SLinus Torvalds
15281da177e4SLinus Torvalds if (pcm_channel->unlinked == 0) {
152941116e92STakashi Iwai spin_unlock_irqrestore(&chip->reg_lock, flags);
15301da177e4SLinus Torvalds return -EIO;
15311da177e4SLinus Torvalds }
15321da177e4SLinus Torvalds
15331da177e4SLinus Torvalds parent_scb = src_scb;
15341da177e4SLinus Torvalds
15351da177e4SLinus Torvalds if (src_scb->sub_list_ptr != ins->the_null_scb) {
15361da177e4SLinus Torvalds src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
15371da177e4SLinus Torvalds pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
15381da177e4SLinus Torvalds }
15391da177e4SLinus Torvalds
15401da177e4SLinus Torvalds src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
15411da177e4SLinus Torvalds
1542da3cec35STakashi Iwai snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
15431da177e4SLinus Torvalds pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
15441da177e4SLinus Torvalds
15451da177e4SLinus Torvalds /* update SCB entry in DSP RAM */
15461da177e4SLinus Torvalds cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
15471da177e4SLinus Torvalds
15481da177e4SLinus Torvalds /* update parent SCB entry */
15491da177e4SLinus Torvalds cs46xx_dsp_spos_update_scb(chip,parent_scb);
15501da177e4SLinus Torvalds
15511da177e4SLinus Torvalds pcm_channel->unlinked = 0;
15521da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->reg_lock, flags);
15531da177e4SLinus Torvalds return 0;
15541da177e4SLinus Torvalds }
15551da177e4SLinus Torvalds
15563d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_add_record_source(struct snd_cs46xx * chip,struct dsp_scb_descriptor * source,u16 addr,char * scb_name)15573d19f804STakashi Iwai cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
15581da177e4SLinus Torvalds u16 addr, char * scb_name)
15591da177e4SLinus Torvalds {
15603d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
15613d19f804STakashi Iwai struct dsp_scb_descriptor * parent;
15623d19f804STakashi Iwai struct dsp_scb_descriptor * pcm_input;
15631da177e4SLinus Torvalds int insert_point;
15641da177e4SLinus Torvalds
1565da3cec35STakashi Iwai if (snd_BUG_ON(!ins->record_mixer_scb))
1566da3cec35STakashi Iwai return NULL;
15671da177e4SLinus Torvalds
15681da177e4SLinus Torvalds if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
15691da177e4SLinus Torvalds parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
15701da177e4SLinus Torvalds insert_point = SCB_ON_PARENT_NEXT_SCB;
15711da177e4SLinus Torvalds } else {
15721da177e4SLinus Torvalds parent = ins->record_mixer_scb;
15731da177e4SLinus Torvalds insert_point = SCB_ON_PARENT_SUBLIST_SCB;
15741da177e4SLinus Torvalds }
15751da177e4SLinus Torvalds
15761da177e4SLinus Torvalds pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
15771da177e4SLinus Torvalds source, parent,
15781da177e4SLinus Torvalds insert_point);
15791da177e4SLinus Torvalds
15801da177e4SLinus Torvalds return pcm_input;
15811da177e4SLinus Torvalds }
15821da177e4SLinus Torvalds
cs46xx_src_unlink(struct snd_cs46xx * chip,struct dsp_scb_descriptor * src)15833d19f804STakashi Iwai int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
15841da177e4SLinus Torvalds {
158541116e92STakashi Iwai unsigned long flags;
158641116e92STakashi Iwai
1587da3cec35STakashi Iwai if (snd_BUG_ON(!src->parent_scb_ptr))
1588da3cec35STakashi Iwai return -EINVAL;
15891da177e4SLinus Torvalds
15901da177e4SLinus Torvalds /* mute SCB */
15911da177e4SLinus Torvalds cs46xx_dsp_scb_set_volume (chip,src,0,0);
15921da177e4SLinus Torvalds
159341116e92STakashi Iwai spin_lock_irqsave(&chip->reg_lock, flags);
15941da177e4SLinus Torvalds _dsp_unlink_scb (chip,src);
159541116e92STakashi Iwai spin_unlock_irqrestore(&chip->reg_lock, flags);
15961da177e4SLinus Torvalds
15971da177e4SLinus Torvalds return 0;
15981da177e4SLinus Torvalds }
15991da177e4SLinus Torvalds
cs46xx_src_link(struct snd_cs46xx * chip,struct dsp_scb_descriptor * src)16003d19f804STakashi Iwai int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
16011da177e4SLinus Torvalds {
16023d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16033d19f804STakashi Iwai struct dsp_scb_descriptor * parent_scb;
16041da177e4SLinus Torvalds
1605da3cec35STakashi Iwai if (snd_BUG_ON(src->parent_scb_ptr))
1606da3cec35STakashi Iwai return -EINVAL;
1607da3cec35STakashi Iwai if (snd_BUG_ON(!ins->master_mix_scb))
1608da3cec35STakashi Iwai return -EINVAL;
16091da177e4SLinus Torvalds
16101da177e4SLinus Torvalds if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
16111da177e4SLinus Torvalds parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
16121da177e4SLinus Torvalds parent_scb->next_scb_ptr = src;
16131da177e4SLinus Torvalds } else {
16141da177e4SLinus Torvalds parent_scb = ins->master_mix_scb;
16151da177e4SLinus Torvalds parent_scb->sub_list_ptr = src;
16161da177e4SLinus Torvalds }
16171da177e4SLinus Torvalds
16181da177e4SLinus Torvalds src->parent_scb_ptr = parent_scb;
16191da177e4SLinus Torvalds
16201da177e4SLinus Torvalds /* update entry in DSP RAM */
16211da177e4SLinus Torvalds cs46xx_dsp_spos_update_scb(chip,parent_scb);
16221da177e4SLinus Torvalds
16231da177e4SLinus Torvalds return 0;
16241da177e4SLinus Torvalds }
16251da177e4SLinus Torvalds
cs46xx_dsp_enable_spdif_out(struct snd_cs46xx * chip)16263d19f804STakashi Iwai int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
16271da177e4SLinus Torvalds {
16283d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16291da177e4SLinus Torvalds
16301da177e4SLinus Torvalds if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
16311da177e4SLinus Torvalds cs46xx_dsp_enable_spdif_hw (chip);
16321da177e4SLinus Torvalds }
16331da177e4SLinus Torvalds
16341da177e4SLinus Torvalds /* dont touch anything if SPDIF is open */
16351da177e4SLinus Torvalds if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
16361da177e4SLinus Torvalds /* when cs46xx_iec958_post_close(...) is called it
16371da177e4SLinus Torvalds will call this function if necessary depending on
16381da177e4SLinus Torvalds this bit */
16391da177e4SLinus Torvalds ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16401da177e4SLinus Torvalds
16411da177e4SLinus Torvalds return -EBUSY;
16421da177e4SLinus Torvalds }
16431da177e4SLinus Torvalds
1644da3cec35STakashi Iwai if (snd_BUG_ON(ins->asynch_tx_scb))
1645da3cec35STakashi Iwai return -EINVAL;
1646da3cec35STakashi Iwai if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1647da3cec35STakashi Iwai ins->the_null_scb))
1648da3cec35STakashi Iwai return -EINVAL;
16491da177e4SLinus Torvalds
16501da177e4SLinus Torvalds /* reset output snooper sample buffer pointer */
16511da177e4SLinus Torvalds snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
16521da177e4SLinus Torvalds (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
16531da177e4SLinus Torvalds
16541da177e4SLinus Torvalds /* The asynch. transfer task */
16551da177e4SLinus Torvalds ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
16561da177e4SLinus Torvalds SPDIFO_SCB_INST,
16571da177e4SLinus Torvalds SPDIFO_IP_OUTPUT_BUFFER1,
16581da177e4SLinus Torvalds ins->master_mix_scb,
16591da177e4SLinus Torvalds SCB_ON_PARENT_NEXT_SCB);
16601da177e4SLinus Torvalds if (!ins->asynch_tx_scb) return -ENOMEM;
16611da177e4SLinus Torvalds
16621da177e4SLinus Torvalds ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
16631da177e4SLinus Torvalds PCMSERIALINII_SCB_ADDR,
16641da177e4SLinus Torvalds ins->ref_snoop_scb,
16651da177e4SLinus Torvalds ins->asynch_tx_scb,
16661da177e4SLinus Torvalds SCB_ON_PARENT_SUBLIST_SCB);
16671da177e4SLinus Torvalds
16681da177e4SLinus Torvalds
16691da177e4SLinus Torvalds if (!ins->spdif_pcm_input_scb) return -ENOMEM;
16701da177e4SLinus Torvalds
16711da177e4SLinus Torvalds /* monitor state */
16721da177e4SLinus Torvalds ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16731da177e4SLinus Torvalds
16741da177e4SLinus Torvalds return 0;
16751da177e4SLinus Torvalds }
16761da177e4SLinus Torvalds
cs46xx_dsp_disable_spdif_out(struct snd_cs46xx * chip)16773d19f804STakashi Iwai int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
16781da177e4SLinus Torvalds {
16793d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16801da177e4SLinus Torvalds
16811da177e4SLinus Torvalds /* dont touch anything if SPDIF is open */
16821da177e4SLinus Torvalds if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
16831da177e4SLinus Torvalds ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16841da177e4SLinus Torvalds return -EBUSY;
16851da177e4SLinus Torvalds }
16861da177e4SLinus Torvalds
16871da177e4SLinus Torvalds /* check integrety */
1688da3cec35STakashi Iwai if (snd_BUG_ON(!ins->asynch_tx_scb))
1689da3cec35STakashi Iwai return -EINVAL;
1690da3cec35STakashi Iwai if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1691da3cec35STakashi Iwai return -EINVAL;
1692da3cec35STakashi Iwai if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1693da3cec35STakashi Iwai return -EINVAL;
1694da3cec35STakashi Iwai if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1695da3cec35STakashi Iwai ins->master_mix_scb))
1696da3cec35STakashi Iwai return -EINVAL;
16971da177e4SLinus Torvalds
16981da177e4SLinus Torvalds cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
16991da177e4SLinus Torvalds cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
17001da177e4SLinus Torvalds
17011da177e4SLinus Torvalds ins->spdif_pcm_input_scb = NULL;
17021da177e4SLinus Torvalds ins->asynch_tx_scb = NULL;
17031da177e4SLinus Torvalds
17041da177e4SLinus Torvalds /* clear buffer to prevent any undesired noise */
17051da177e4SLinus Torvalds _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
17061da177e4SLinus Torvalds
17071da177e4SLinus Torvalds /* monitor state */
17081da177e4SLinus Torvalds ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
17091da177e4SLinus Torvalds
17101da177e4SLinus Torvalds
17111da177e4SLinus Torvalds return 0;
17121da177e4SLinus Torvalds }
17131da177e4SLinus Torvalds
cs46xx_iec958_pre_open(struct snd_cs46xx * chip)17143d19f804STakashi Iwai int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
17151da177e4SLinus Torvalds {
17163d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17171da177e4SLinus Torvalds
17181da177e4SLinus Torvalds if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1719*c7fabbc5SRandy Dunlap /* remove AsynchFGTxSCB and PCMSerialInput_II */
17201da177e4SLinus Torvalds cs46xx_dsp_disable_spdif_out (chip);
17211da177e4SLinus Torvalds
17221da177e4SLinus Torvalds /* save state */
17231da177e4SLinus Torvalds ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
17241da177e4SLinus Torvalds }
17251da177e4SLinus Torvalds
17261da177e4SLinus Torvalds /* if not enabled already */
17271da177e4SLinus Torvalds if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
17281da177e4SLinus Torvalds cs46xx_dsp_enable_spdif_hw (chip);
17291da177e4SLinus Torvalds }
17301da177e4SLinus Torvalds
17311da177e4SLinus Torvalds /* Create the asynch. transfer task for playback */
17321da177e4SLinus Torvalds ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
17331da177e4SLinus Torvalds SPDIFO_SCB_INST,
17341da177e4SLinus Torvalds SPDIFO_IP_OUTPUT_BUFFER1,
17351da177e4SLinus Torvalds ins->master_mix_scb,
17361da177e4SLinus Torvalds SCB_ON_PARENT_NEXT_SCB);
17371da177e4SLinus Torvalds
17381da177e4SLinus Torvalds
17391da177e4SLinus Torvalds /* set spdif channel status value for streaming */
17401da177e4SLinus Torvalds cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
17411da177e4SLinus Torvalds
17421da177e4SLinus Torvalds ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
17431da177e4SLinus Torvalds
17441da177e4SLinus Torvalds return 0;
17451da177e4SLinus Torvalds }
17461da177e4SLinus Torvalds
cs46xx_iec958_post_close(struct snd_cs46xx * chip)17473d19f804STakashi Iwai int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
17481da177e4SLinus Torvalds {
17493d19f804STakashi Iwai struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17501da177e4SLinus Torvalds
1751da3cec35STakashi Iwai if (snd_BUG_ON(!ins->asynch_tx_scb))
1752da3cec35STakashi Iwai return -EINVAL;
17531da177e4SLinus Torvalds
17541da177e4SLinus Torvalds ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
17551da177e4SLinus Torvalds
17561da177e4SLinus Torvalds /* restore settings */
17571da177e4SLinus Torvalds cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
17581da177e4SLinus Torvalds
17591da177e4SLinus Torvalds /* deallocate stuff */
17601da177e4SLinus Torvalds if (ins->spdif_pcm_input_scb != NULL) {
17611da177e4SLinus Torvalds cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
17621da177e4SLinus Torvalds ins->spdif_pcm_input_scb = NULL;
17631da177e4SLinus Torvalds }
17641da177e4SLinus Torvalds
17651da177e4SLinus Torvalds cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
17661da177e4SLinus Torvalds ins->asynch_tx_scb = NULL;
17671da177e4SLinus Torvalds
17681da177e4SLinus Torvalds /* clear buffer to prevent any undesired noise */
17691da177e4SLinus Torvalds _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
17701da177e4SLinus Torvalds
17711da177e4SLinus Torvalds /* restore state */
17721da177e4SLinus Torvalds if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
17731da177e4SLinus Torvalds cs46xx_dsp_enable_spdif_out (chip);
17741da177e4SLinus Torvalds }
17751da177e4SLinus Torvalds
17761da177e4SLinus Torvalds return 0;
17771da177e4SLinus Torvalds }
1778