net: dsa: mt7530: set CPU port to fallback mode
[linux/fpc-iii.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blob8d0a3d357345776658610abb7c314018a38a5b10
1 /*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * 2002-07 Benny Sjostrand benny@hostmobility.com
24 #include <linux/io.h>
25 #include <linux/delay.h>
26 #include <linux/pm.h>
27 #include <linux/init.h>
28 #include <linux/slab.h>
29 #include <linux/mutex.h>
31 #include <sound/core.h>
32 #include <sound/control.h>
33 #include <sound/info.h>
34 #include "cs46xx.h"
36 #include "cs46xx_lib.h"
37 #include "dsp_spos.h"
39 struct proc_scb_info {
40 struct dsp_scb_descriptor * scb_desc;
41 struct snd_cs46xx *chip;
44 static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
46 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
47 int symbol_index = (int)(symbol - ins->symbol_table.symbols);
49 if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
50 return;
51 if (snd_BUG_ON(symbol_index < 0 ||
52 symbol_index >= ins->symbol_table.nsymbols))
53 return;
55 ins->symbol_table.symbols[symbol_index].deleted = 1;
57 if (symbol_index < ins->symbol_table.highest_frag_index) {
58 ins->symbol_table.highest_frag_index = symbol_index;
61 if (symbol_index == ins->symbol_table.nsymbols - 1)
62 ins->symbol_table.nsymbols --;
64 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
65 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
70 #ifdef CONFIG_SND_PROC_FS
71 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
72 struct snd_info_buffer *buffer)
74 struct proc_scb_info * scb_info = entry->private_data;
75 struct dsp_scb_descriptor * scb = scb_info->scb_desc;
76 struct snd_cs46xx *chip = scb_info->chip;
77 int j,col;
78 void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
80 mutex_lock(&chip->spos_mutex);
81 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
83 for (col = 0,j = 0;j < 0x10; j++,col++) {
84 if (col == 4) {
85 snd_iprintf(buffer,"\n");
86 col = 0;
88 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
91 snd_iprintf(buffer,"\n");
93 if (scb->parent_scb_ptr != NULL) {
94 snd_iprintf(buffer,"parent [%s:%04x] ",
95 scb->parent_scb_ptr->scb_name,
96 scb->parent_scb_ptr->address);
97 } else snd_iprintf(buffer,"parent [none] ");
99 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
100 scb->sub_list_ptr->scb_name,
101 scb->sub_list_ptr->address,
102 scb->next_scb_ptr->scb_name,
103 scb->next_scb_ptr->address,
104 scb->task_entry->symbol_name,
105 scb->task_entry->address);
107 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
108 mutex_unlock(&chip->spos_mutex);
110 #endif
112 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
114 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
116 if ( scb->parent_scb_ptr ) {
117 /* unlink parent SCB */
118 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
119 scb->parent_scb_ptr->next_scb_ptr != scb))
120 return;
122 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
124 if (scb->next_scb_ptr == ins->the_null_scb) {
125 /* last and only node in parent sublist */
126 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
128 if (scb->sub_list_ptr != ins->the_null_scb) {
129 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
131 scb->sub_list_ptr = ins->the_null_scb;
132 } else {
133 /* first node in parent sublist */
134 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
136 if (scb->next_scb_ptr != ins->the_null_scb) {
137 /* update next node parent ptr. */
138 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
140 scb->next_scb_ptr = ins->the_null_scb;
142 } else {
143 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
145 if (scb->next_scb_ptr != ins->the_null_scb) {
146 /* update next node parent ptr. */
147 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
149 scb->next_scb_ptr = ins->the_null_scb;
152 /* update parent first entry in DSP RAM */
153 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
155 /* then update entry in DSP RAM */
156 cs46xx_dsp_spos_update_scb(chip,scb);
158 scb->parent_scb_ptr = NULL;
162 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
163 int dword_count)
165 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
166 int i;
168 for (i = 0; i < dword_count ; ++i ) {
169 writel(0, dst);
170 dst += 4;
174 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
176 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
177 unsigned long flags;
179 /* check integrety */
180 if (snd_BUG_ON(scb->index < 0 ||
181 scb->index >= ins->nscb ||
182 (ins->scbs + scb->index) != scb))
183 return;
185 #if 0
186 /* can't remove a SCB with childs before
187 removing childs first */
188 if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
189 scb->next_scb_ptr != ins->the_null_scb))
190 goto _end;
191 #endif
193 spin_lock_irqsave(&chip->reg_lock, flags);
194 _dsp_unlink_scb (chip,scb);
195 spin_unlock_irqrestore(&chip->reg_lock, flags);
197 cs46xx_dsp_proc_free_scb_desc(scb);
198 if (snd_BUG_ON(!scb->scb_symbol))
199 return;
200 remove_symbol (chip,scb->scb_symbol);
202 ins->scbs[scb->index].deleted = 1;
203 #ifdef CONFIG_PM_SLEEP
204 kfree(ins->scbs[scb->index].data);
205 ins->scbs[scb->index].data = NULL;
206 #endif
208 if (scb->index < ins->scb_highest_frag_index)
209 ins->scb_highest_frag_index = scb->index;
211 if (scb->index == ins->nscb - 1) {
212 ins->nscb --;
215 if (ins->scb_highest_frag_index > ins->nscb) {
216 ins->scb_highest_frag_index = ins->nscb;
219 #if 0
220 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
221 for(i = scb->index + 1;i < ins->nscb; ++i) {
222 ins->scbs[i - 1].index = i - 1;
224 #endif
228 #ifdef CONFIG_SND_PROC_FS
229 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
231 if (scb->proc_info) {
232 struct proc_scb_info * scb_info = scb->proc_info->private_data;
233 struct snd_cs46xx *chip = scb_info->chip;
235 dev_dbg(chip->card->dev,
236 "cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
237 scb->scb_name);
239 snd_info_free_entry(scb->proc_info);
240 scb->proc_info = NULL;
242 kfree (scb_info);
246 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
247 struct dsp_scb_descriptor * scb)
249 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
250 struct snd_info_entry * entry;
251 struct proc_scb_info * scb_info;
253 /* register to proc */
254 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
255 scb->proc_info == NULL) {
257 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
258 ins->proc_dsp_dir)) != NULL) {
259 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
260 if (!scb_info) {
261 snd_info_free_entry(entry);
262 entry = NULL;
263 goto out;
266 scb_info->chip = chip;
267 scb_info->scb_desc = scb;
269 entry->content = SNDRV_INFO_CONTENT_TEXT;
270 entry->private_data = scb_info;
271 entry->mode = S_IFREG | 0644;
273 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
275 if (snd_info_register(entry) < 0) {
276 snd_info_free_entry(entry);
277 kfree (scb_info);
278 entry = NULL;
281 out:
282 scb->proc_info = entry;
285 #endif /* CONFIG_SND_PROC_FS */
287 static struct dsp_scb_descriptor *
288 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
289 struct dsp_symbol_entry * task_entry,
290 struct dsp_scb_descriptor * parent_scb,
291 int scb_child_type)
293 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
294 struct dsp_scb_descriptor * scb;
296 unsigned long flags;
298 if (snd_BUG_ON(!ins->the_null_scb))
299 return NULL;
301 /* fill the data that will be wroten to DSP */
302 scb_data[SCBsubListPtr] =
303 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
305 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
306 scb_data[SCBfuncEntryPtr] |= task_entry->address;
308 dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
310 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
313 scb->sub_list_ptr = ins->the_null_scb;
314 scb->next_scb_ptr = ins->the_null_scb;
316 scb->parent_scb_ptr = parent_scb;
317 scb->task_entry = task_entry;
320 /* update parent SCB */
321 if (scb->parent_scb_ptr) {
322 #if 0
323 dev_dbg(chip->card->dev,
324 "scb->parent_scb_ptr = %s\n",
325 scb->parent_scb_ptr->scb_name);
326 dev_dbg(chip->card->dev,
327 "scb->parent_scb_ptr->next_scb_ptr = %s\n",
328 scb->parent_scb_ptr->next_scb_ptr->scb_name);
329 dev_dbg(chip->card->dev,
330 "scb->parent_scb_ptr->sub_list_ptr = %s\n",
331 scb->parent_scb_ptr->sub_list_ptr->scb_name);
332 #endif
333 /* link to parent SCB */
334 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
335 if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
336 ins->the_null_scb))
337 return NULL;
339 scb->parent_scb_ptr->next_scb_ptr = scb;
341 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
342 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
343 ins->the_null_scb))
344 return NULL;
346 scb->parent_scb_ptr->sub_list_ptr = scb;
347 } else {
348 snd_BUG();
351 spin_lock_irqsave(&chip->reg_lock, flags);
353 /* update entry in DSP RAM */
354 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
356 spin_unlock_irqrestore(&chip->reg_lock, flags);
360 cs46xx_dsp_proc_register_scb_desc (chip,scb);
362 return scb;
365 static struct dsp_scb_descriptor *
366 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
367 u32 dest, char * task_entry_name,
368 struct dsp_scb_descriptor * parent_scb,
369 int scb_child_type)
371 struct dsp_symbol_entry * task_entry;
373 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
374 SYMBOL_CODE);
376 if (task_entry == NULL) {
377 dev_err(chip->card->dev,
378 "dsp_spos: symbol %s not found\n", task_entry_name);
379 return NULL;
382 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
383 parent_scb,scb_child_type);
386 struct dsp_scb_descriptor *
387 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
389 struct dsp_scb_descriptor * scb;
391 struct dsp_timing_master_scb timing_master_scb = {
392 { 0,
397 { 0,
403 0,0,
404 0,NULL_SCB_ADDR,
405 0,0, /* extraSampleAccum:TMreserved */
406 0,0, /* codecFIFOptr:codecFIFOsyncd */
407 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
408 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
409 0x00060000 /* nSampPerFrmQ15 */
412 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
413 TIMINGMASTER_SCB_ADDR,
414 "TIMINGMASTER",NULL,SCB_NO_PARENT);
416 return scb;
420 struct dsp_scb_descriptor *
421 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
422 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
423 u32 dest, struct dsp_scb_descriptor * parent_scb,
424 int scb_child_type)
426 struct dsp_scb_descriptor * scb;
428 struct dsp_codec_output_scb codec_out_scb = {
429 { 0,
441 0,0,
442 0,NULL_SCB_ADDR,
443 0, /* COstrmRsConfig */
444 0, /* COstrmBufPtr */
445 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
446 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
447 0,child_scb_addr /* COreserved - need child scb to work with rom code */
451 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
452 dest,"S16_CODECOUTPUTTASK",parent_scb,
453 scb_child_type);
455 return scb;
458 struct dsp_scb_descriptor *
459 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
460 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
461 u32 dest, struct dsp_scb_descriptor * parent_scb,
462 int scb_child_type)
465 struct dsp_scb_descriptor * scb;
466 struct dsp_codec_input_scb codec_input_scb = {
467 { 0,
480 #if 0 /* cs4620 */
481 SyncIOSCB,NULL_SCB_ADDR
482 #else
483 0 , 0,
484 #endif
485 0,0,
487 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
488 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
489 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
490 link input slot 3 :rightChanINdisp=""slot 4 */
491 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
492 because AC97 is already 20 bits */
493 0x80008000 /* ??clw cwcgame.scb has 0 */
496 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
497 dest,"S16_CODECINPUTTASK",parent_scb,
498 scb_child_type);
499 return scb;
503 static struct dsp_scb_descriptor *
504 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
505 u16 sample_buffer_addr, u32 dest,
506 int virtual_channel, u32 playback_hw_addr,
507 struct dsp_scb_descriptor * parent_scb,
508 int scb_child_type)
510 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
511 struct dsp_scb_descriptor * scb;
513 struct dsp_generic_scb pcm_reader_scb = {
516 Play DMA Task xfers data from host buffer to SP buffer
517 init/runtime variables:
518 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
519 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
520 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
521 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
522 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
523 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
524 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
525 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
526 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
527 ? Other combinations possible from:
528 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
529 DMA_RQ_C2_AC_NONE 0x00000000L
530 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
531 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
532 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
533 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
535 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
536 aligned to dword boundary
538 /* Basic (non scatter/gather) DMA requestor (4 ints) */
539 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
540 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
541 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
542 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
543 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
544 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
545 /* Barnette said that is what we should use since */
546 /* we are not running in optimized mode? */
547 DMA_RQ_C2_AC_NONE +
548 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
549 /* buffer (on host) crosses half-way point */
550 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
551 playback_hw_addr, /* HostBuffAddr (source) */
552 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
553 sample_buffer_addr /* SP Buffer Address (destination) */
555 /* Scatter/gather DMA requestor extension (5 ints) */
563 /* Sublist pointer & next stream control block (SCB) link. */
564 NULL_SCB_ADDR,NULL_SCB_ADDR,
565 /* Pointer to this tasks parameter block & stream function pointer */
566 0,NULL_SCB_ADDR,
567 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
568 /* for incoming streams, or basicReq.saw, for outgoing streams) */
569 RSCONFIG_DMA_ENABLE + /* enable DMA */
570 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
571 /* uses it for some reason */
572 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
573 RSCONFIG_SAMPLE_16STEREO +
574 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
575 /* Stream sample pointer & MAC-unit mode for this stream */
576 (sample_buffer_addr << 0x10),
577 /* Fractional increment per output sample in the input sample buffer */
580 /* Standard stereo volume control
581 default muted */
582 0xffff,0xffff,
583 0xffff,0xffff
587 if (ins->null_algorithm == NULL) {
588 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
589 SYMBOL_CODE);
591 if (ins->null_algorithm == NULL) {
592 dev_err(chip->card->dev,
593 "dsp_spos: symbol NULLALGORITHM not found\n");
594 return NULL;
598 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
599 dest,ins->null_algorithm,parent_scb,
600 scb_child_type);
602 return scb;
605 #define GOF_PER_SEC 200
607 struct dsp_scb_descriptor *
608 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
609 int rate,
610 u16 src_buffer_addr,
611 u16 src_delay_buffer_addr, u32 dest,
612 struct dsp_scb_descriptor * parent_scb,
613 int scb_child_type,
614 int pass_through)
617 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
618 struct dsp_scb_descriptor * scb;
619 unsigned int tmp1, tmp2;
620 unsigned int phiIncr;
621 unsigned int correctionPerGOF, correctionPerSec;
623 dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
624 scb_name, rate);
627 * Compute the values used to drive the actual sample rate conversion.
628 * The following formulas are being computed, using inline assembly
629 * since we need to use 64 bit arithmetic to compute the values:
631 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
632 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
633 * GOF_PER_SEC)
634 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
635 * GOF_PER_SEC * correctionPerGOF
637 * i.e.
639 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
640 * correctionPerGOF:correctionPerSec =
641 * dividend:remainder(ulOther / GOF_PER_SEC)
643 tmp1 = rate << 16;
644 phiIncr = tmp1 / 48000;
645 tmp1 -= phiIncr * 48000;
646 tmp1 <<= 10;
647 phiIncr <<= 10;
648 tmp2 = tmp1 / 48000;
649 phiIncr += tmp2;
650 tmp1 -= tmp2 * 48000;
651 correctionPerGOF = tmp1 / GOF_PER_SEC;
652 tmp1 -= correctionPerGOF * GOF_PER_SEC;
653 correctionPerSec = tmp1;
656 struct dsp_src_task_scb src_task_scb = {
657 0x0028,0x00c8,
658 0x5555,0x0000,
659 0x0000,0x0000,
660 src_buffer_addr,1,
661 correctionPerGOF,correctionPerSec,
662 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
663 0x0000,src_delay_buffer_addr,
664 0x0,
665 0x080,(src_delay_buffer_addr + (24 * 4)),
666 0,0, /* next_scb, sub_list_ptr */
667 0,0, /* entry, this_spb */
668 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
669 src_buffer_addr << 0x10,
670 phiIncr,
672 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
673 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
677 if (ins->s16_up == NULL) {
678 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
679 SYMBOL_CODE);
681 if (ins->s16_up == NULL) {
682 dev_err(chip->card->dev,
683 "dsp_spos: symbol S16_UPSRC not found\n");
684 return NULL;
688 /* clear buffers */
689 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
690 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
692 if (pass_through) {
693 /* wont work with any other rate than
694 the native DSP rate */
695 snd_BUG_ON(rate != 48000);
697 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
698 dest,"DMAREADER",parent_scb,
699 scb_child_type);
700 } else {
701 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
702 dest,ins->s16_up,parent_scb,
703 scb_child_type);
709 return scb;
712 #if 0 /* not used */
713 struct dsp_scb_descriptor *
714 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
715 u16 buffer_addr, u32 dest,
716 struct dsp_scb_descriptor * parent_scb,
717 int scb_child_type) {
718 struct dsp_scb_descriptor * scb;
720 struct dsp_filter_scb filter_scb = {
721 .a0_right = 0x41a9,
722 .a0_left = 0x41a9,
723 .a1_right = 0xb8e4,
724 .a1_left = 0xb8e4,
725 .a2_right = 0x3e55,
726 .a2_left = 0x3e55,
728 .filter_unused3 = 0x0000,
729 .filter_unused2 = 0x0000,
731 .output_buf_ptr = buffer_addr,
732 .init = 0x000,
734 .prev_sample_output1 = 0x00000000,
735 .prev_sample_output2 = 0x00000000,
737 .prev_sample_input1 = 0x00000000,
738 .prev_sample_input2 = 0x00000000,
740 .next_scb_ptr = 0x0000,
741 .sub_list_ptr = 0x0000,
743 .entry_point = 0x0000,
744 .spb_ptr = 0x0000,
746 .b0_right = 0x0e38,
747 .b0_left = 0x0e38,
748 .b1_right = 0x1c71,
749 .b1_left = 0x1c71,
750 .b2_right = 0x0e38,
751 .b2_left = 0x0e38,
755 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
756 dest,"FILTERTASK",parent_scb,
757 scb_child_type);
759 return scb;
761 #endif /* not used */
763 struct dsp_scb_descriptor *
764 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
765 u16 mix_buffer_addr, u32 dest,
766 struct dsp_scb_descriptor * parent_scb,
767 int scb_child_type)
769 struct dsp_scb_descriptor * scb;
771 struct dsp_mix_only_scb master_mix_scb = {
772 /* 0 */ { 0,
773 /* 1 */ 0,
774 /* 2 */ mix_buffer_addr,
775 /* 3 */ 0
776 /* */ },
778 /* 4 */ 0,
779 /* 5 */ 0,
780 /* 6 */ 0,
781 /* 7 */ 0,
782 /* 8 */ 0x00000080
784 /* 9 */ 0,0,
785 /* A */ 0,0,
786 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
787 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
788 /* D */ 0,
790 /* E */ 0x8000,0x8000,
791 /* F */ 0x8000,0x8000
796 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
797 dest,"S16_MIX",parent_scb,
798 scb_child_type);
799 return scb;
803 struct dsp_scb_descriptor *
804 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
805 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
806 struct dsp_scb_descriptor * parent_scb,
807 int scb_child_type)
809 struct dsp_scb_descriptor * scb;
811 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
812 /* Basic (non scatter/gather) DMA requestor (4 ints) */
814 DMA_RQ_C1_SOURCE_MOD64 +
815 DMA_RQ_C1_DEST_ON_HOST +
816 DMA_RQ_C1_DEST_MOD1024 +
817 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
818 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
819 15,
821 DMA_RQ_C2_AC_NONE +
822 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
824 CS46XX_DSP_CAPTURE_CHANNEL,
825 DMA_RQ_SD_SP_SAMPLE_ADDR +
826 mix_buffer_addr,
827 0x0
830 { 0, 0, 0, 0, 0, },
831 0,0,
832 0,writeback_spb,
834 RSCONFIG_DMA_ENABLE +
835 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
837 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
838 RSCONFIG_DMA_TO_HOST +
839 RSCONFIG_SAMPLE_16STEREO +
840 RSCONFIG_MODULO_64,
841 (mix_buffer_addr + (32 * 4)) << 0x10,
842 1,0,
843 0x0001,0x0080,
844 0xFFFF,0
848 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
850 dest,"S16_MIX_TO_OSTREAM",parent_scb,
851 scb_child_type);
853 return scb;
857 struct dsp_scb_descriptor *
858 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
859 u16 vari_buffer_addr0,
860 u16 vari_buffer_addr1,
861 u32 dest,
862 struct dsp_scb_descriptor * parent_scb,
863 int scb_child_type)
866 struct dsp_scb_descriptor * scb;
868 struct dsp_vari_decimate_scb vari_decimate_scb = {
869 0x0028,0x00c8,
870 0x5555,0x0000,
871 0x0000,0x0000,
872 vari_buffer_addr0,vari_buffer_addr1,
874 0x0028,0x00c8,
875 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
877 0xFF800000,
879 0x0080,vari_buffer_addr1 + (25 * 4),
881 0,0,
882 0,0,
884 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
885 vari_buffer_addr0 << 0x10,
886 0x04000000,
888 0x8000,0x8000,
889 0xFFFF,0xFFFF
893 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
894 dest,"VARIDECIMATE",parent_scb,
895 scb_child_type);
897 return scb;
901 static struct dsp_scb_descriptor *
902 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
903 struct dsp_scb_descriptor * input_scb,
904 struct dsp_scb_descriptor * parent_scb,
905 int scb_child_type)
908 struct dsp_scb_descriptor * scb;
911 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
912 { 0,
925 0,0,
926 0,0,
928 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
930 /* 0xD */ 0,input_scb->address,
932 /* 0xE */ 0x8000,0x8000,
933 /* 0xF */ 0x8000,0x8000
937 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
938 dest,"PCMSERIALINPUTTASK",parent_scb,
939 scb_child_type);
940 return scb;
944 static struct dsp_scb_descriptor *
945 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
946 u16 hfg_scb_address,
947 u16 asynch_buffer_address,
948 struct dsp_scb_descriptor * parent_scb,
949 int scb_child_type)
952 struct dsp_scb_descriptor * scb;
954 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
955 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
956 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
957 /* : Max delta 25 dwords == 100 bytes */
958 0,hfg_scb_address, /* Point to HFG task SCB */
959 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
960 0, /* Initialize accumulated Phi to 0 */
961 0,0x2aab, /* Const 1/3 */
964 0, /* Define the unused elements */
969 0,0,
970 0,dest + AFGTxAccumPhi,
972 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
973 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
974 to the producer pointer */
976 /* There is no correct initial value, it will depend upon the detected
977 rate etc */
978 0x18000000, /* Phi increment for approx 32k operation */
979 0x8000,0x8000, /* Volume controls are unused at this time */
980 0x8000,0x8000
983 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
984 dest,"ASYNCHFGTXCODE",parent_scb,
985 scb_child_type);
987 return scb;
991 struct dsp_scb_descriptor *
992 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
993 u16 hfg_scb_address,
994 u16 asynch_buffer_address,
995 struct dsp_scb_descriptor * parent_scb,
996 int scb_child_type)
998 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
999 struct dsp_scb_descriptor * scb;
1001 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
1002 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
1003 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
1004 /* : Max delta 25 dwords == 100 bytes */
1005 0,hfg_scb_address, /* Point to HFG task SCB */
1006 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
1008 0, /* Define the unused elements */
1015 0,0,
1016 0,dest,
1018 RSCONFIG_MODULO_128 |
1019 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
1020 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
1021 synchrinized to the producer pointer */
1023 /* There is no correct initial value, it will depend upon the detected
1024 rate etc */
1025 0x18000000,
1027 /* Set IEC958 input volume */
1028 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1029 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1032 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1033 dest,"ASYNCHFGRXCODE",parent_scb,
1034 scb_child_type);
1036 return scb;
1040 #if 0 /* not used */
1041 struct dsp_scb_descriptor *
1042 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1043 u16 snoop_buffer_address,
1044 struct dsp_scb_descriptor * snoop_scb,
1045 struct dsp_scb_descriptor * parent_scb,
1046 int scb_child_type)
1049 struct dsp_scb_descriptor * scb;
1051 struct dsp_output_snoop_scb output_snoop_scb = {
1052 { 0, /* not used. Zero */
1058 0, /* not used. Zero */
1065 0,0,
1066 0,0,
1068 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1069 snoop_buffer_address << 0x10,
1070 0,0,
1072 0,snoop_scb->address
1075 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1076 dest,"OUTPUTSNOOP",parent_scb,
1077 scb_child_type);
1078 return scb;
1080 #endif /* not used */
1083 struct dsp_scb_descriptor *
1084 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1085 struct dsp_scb_descriptor * parent_scb,
1086 int scb_child_type)
1088 struct dsp_scb_descriptor * scb;
1090 struct dsp_spio_write_scb spio_write_scb = {
1091 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1092 0, /* SPIOWData1; */
1093 0, /* SPIOWData2; */
1094 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1095 0, /* SPIOWData3; */
1096 0, /* SPIOWData4; */
1097 0,0, /* SPIOWDataPtr:Unused1; */
1098 { 0,0 }, /* Unused2[2]; */
1100 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1101 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1108 0 /* Unused3[5]; */
1112 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1113 dest,"SPIOWRITE",parent_scb,
1114 scb_child_type);
1116 return scb;
1119 struct dsp_scb_descriptor *
1120 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1121 u16 snoop_buffer_address,
1122 struct dsp_scb_descriptor * snoop_scb,
1123 struct dsp_scb_descriptor * parent_scb,
1124 int scb_child_type)
1126 struct dsp_scb_descriptor * scb;
1128 struct dsp_magic_snoop_task magic_snoop_scb = {
1129 /* 0 */ 0, /* i0 */
1130 /* 1 */ 0, /* i1 */
1131 /* 2 */ snoop_buffer_address << 0x10,
1132 /* 3 */ 0,snoop_scb->address,
1133 /* 4 */ 0, /* i3 */
1134 /* 5 */ 0, /* i4 */
1135 /* 6 */ 0, /* i5 */
1136 /* 7 */ 0, /* i6 */
1137 /* 8 */ 0, /* i7 */
1138 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1139 /* A */ 0,0, /* entry_point, this_ptr */
1140 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1141 /* C */ snoop_buffer_address << 0x10,
1142 /* D */ 0,
1143 /* E */ { 0x8000,0x8000,
1144 /* F */ 0xffff,0xffff
1148 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1149 dest,"MAGICSNOOPTASK",parent_scb,
1150 scb_child_type);
1152 return scb;
1155 static struct dsp_scb_descriptor *
1156 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1158 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1159 struct dsp_scb_descriptor * scb = from;
1161 while (scb->next_scb_ptr != ins->the_null_scb) {
1162 if (snd_BUG_ON(!scb->next_scb_ptr))
1163 return NULL;
1165 scb = scb->next_scb_ptr;
1168 return scb;
1171 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1172 0x0600, /* 1 */
1173 0x1500, /* 2 */
1174 0x1580, /* 3 */
1175 0x1600, /* 4 */
1176 0x1680, /* 5 */
1177 0x1700, /* 6 */
1178 0x1780, /* 7 */
1179 0x1800, /* 8 */
1180 0x1880, /* 9 */
1181 0x1900, /* 10 */
1182 0x1980, /* 11 */
1183 0x1A00, /* 12 */
1184 0x1A80, /* 13 */
1185 0x1B00, /* 14 */
1186 0x1B80, /* 15 */
1187 0x1C00, /* 16 */
1188 0x1C80, /* 17 */
1189 0x1D00, /* 18 */
1190 0x1D80, /* 19 */
1191 0x1E00, /* 20 */
1192 0x1E80, /* 21 */
1193 0x1F00, /* 22 */
1194 0x1F80, /* 23 */
1195 0x2000, /* 24 */
1196 0x2080, /* 25 */
1197 0x2100, /* 26 */
1198 0x2180, /* 27 */
1199 0x2200, /* 28 */
1200 0x2280, /* 29 */
1201 0x2300, /* 30 */
1202 0x2380, /* 31 */
1203 0x2400, /* 32 */
1206 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1207 0x2B80,
1208 0x2BA0,
1209 0x2BC0,
1210 0x2BE0,
1211 0x2D00,
1212 0x2D20,
1213 0x2D40,
1214 0x2D60,
1215 0x2D80,
1216 0x2DA0,
1217 0x2DC0,
1218 0x2DE0,
1219 0x2E00,
1220 0x2E20
1223 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1224 0x2480,
1225 0x2500,
1226 0x2580,
1227 0x2600,
1228 0x2680,
1229 0x2700,
1230 0x2780,
1231 0x2800,
1232 0x2880,
1233 0x2900,
1234 0x2980,
1235 0x2A00,
1236 0x2A80,
1237 0x2B00
1240 struct dsp_pcm_channel_descriptor *
1241 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1242 u32 sample_rate, void * private_data,
1243 u32 hw_dma_addr,
1244 int pcm_channel_id)
1246 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1247 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1248 struct dsp_scb_descriptor * src_parent_scb = NULL;
1250 /* struct dsp_scb_descriptor * pcm_parent_scb; */
1251 char scb_name[DSP_MAX_SCB_NAME];
1252 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1253 unsigned long flags;
1255 switch (pcm_channel_id) {
1256 case DSP_PCM_MAIN_CHANNEL:
1257 mixer_scb = ins->master_mix_scb;
1258 break;
1259 case DSP_PCM_REAR_CHANNEL:
1260 mixer_scb = ins->rear_mix_scb;
1261 break;
1262 case DSP_PCM_CENTER_LFE_CHANNEL:
1263 mixer_scb = ins->center_lfe_mix_scb;
1264 break;
1265 case DSP_PCM_S71_CHANNEL:
1266 /* TODO */
1267 snd_BUG();
1268 break;
1269 case DSP_IEC958_CHANNEL:
1270 if (snd_BUG_ON(!ins->asynch_tx_scb))
1271 return NULL;
1272 mixer_scb = ins->asynch_tx_scb;
1274 /* if sample rate is set to 48khz we pass
1275 the Sample Rate Converted (which could
1276 alter the raw data stream ...) */
1277 if (sample_rate == 48000) {
1278 dev_dbg(chip->card->dev, "IEC958 pass through\n");
1279 /* Hack to bypass creating a new SRC */
1280 pass_through = 1;
1282 break;
1283 default:
1284 snd_BUG();
1285 return NULL;
1287 /* default sample rate is 44100 */
1288 if (!sample_rate) sample_rate = 44100;
1290 /* search for a already created SRC SCB with the same sample rate */
1291 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1292 (pcm_index == -1 || src_scb == NULL); ++i) {
1294 /* virtual channel reserved
1295 for capture */
1296 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1298 if (ins->pcm_channels[i].active) {
1299 if (!src_scb &&
1300 ins->pcm_channels[i].sample_rate == sample_rate &&
1301 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1302 src_scb = ins->pcm_channels[i].src_scb;
1303 ins->pcm_channels[i].src_scb->ref_count ++;
1304 src_index = ins->pcm_channels[i].src_slot;
1306 } else if (pcm_index == -1) {
1307 pcm_index = i;
1311 if (pcm_index == -1) {
1312 dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
1313 return NULL;
1316 if (src_scb == NULL) {
1317 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1318 dev_err(chip->card->dev,
1319 "dsp_spos: to many SRC instances\n!");
1320 return NULL;
1323 /* find a free slot */
1324 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1325 if (ins->src_scb_slots[i] == 0) {
1326 src_index = i;
1327 ins->src_scb_slots[i] = 1;
1328 break;
1331 if (snd_BUG_ON(src_index == -1))
1332 return NULL;
1334 /* we need to create a new SRC SCB */
1335 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1336 src_parent_scb = mixer_scb;
1337 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1338 } else {
1339 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1340 insert_point = SCB_ON_PARENT_NEXT_SCB;
1343 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1345 dev_dbg(chip->card->dev,
1346 "dsp_spos: creating SRC \"%s\"\n", scb_name);
1347 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1348 sample_rate,
1349 src_output_buffer_addr[src_index],
1350 src_delay_buffer_addr[src_index],
1351 /* 0x400 - 0x600 source SCBs */
1352 0x400 + (src_index * 0x10) ,
1353 src_parent_scb,
1354 insert_point,
1355 pass_through);
1357 if (!src_scb) {
1358 dev_err(chip->card->dev,
1359 "dsp_spos: failed to create SRCtaskSCB\n");
1360 return NULL;
1363 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1365 ins->nsrc_scb ++;
1369 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1371 dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
1372 scb_name, pcm_channel_id);
1374 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1375 pcm_reader_buffer_addr[pcm_index],
1376 /* 0x200 - 400 PCMreader SCBs */
1377 (pcm_index * 0x10) + 0x200,
1378 pcm_index, /* virtual channel 0-31 */
1379 hw_dma_addr, /* pcm hw addr */
1380 NULL, /* parent SCB ptr */
1381 0 /* insert point */
1384 if (!pcm_scb) {
1385 dev_err(chip->card->dev,
1386 "dsp_spos: failed to create PCMreaderSCB\n");
1387 return NULL;
1390 spin_lock_irqsave(&chip->reg_lock, flags);
1391 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1392 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1393 ins->pcm_channels[pcm_index].src_scb = src_scb;
1394 ins->pcm_channels[pcm_index].unlinked = 1;
1395 ins->pcm_channels[pcm_index].private_data = private_data;
1396 ins->pcm_channels[pcm_index].src_slot = src_index;
1397 ins->pcm_channels[pcm_index].active = 1;
1398 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1399 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1400 ins->npcm_channels ++;
1401 spin_unlock_irqrestore(&chip->reg_lock, flags);
1403 return (ins->pcm_channels + pcm_index);
1406 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1407 struct dsp_pcm_channel_descriptor * pcm_channel,
1408 int period_size)
1410 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1411 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1413 switch (period_size) {
1414 case 2048:
1415 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1416 break;
1417 case 1024:
1418 temp |= DMA_RQ_C1_SOURCE_MOD512;
1419 break;
1420 case 512:
1421 temp |= DMA_RQ_C1_SOURCE_MOD256;
1422 break;
1423 case 256:
1424 temp |= DMA_RQ_C1_SOURCE_MOD128;
1425 break;
1426 case 128:
1427 temp |= DMA_RQ_C1_SOURCE_MOD64;
1428 break;
1429 case 64:
1430 temp |= DMA_RQ_C1_SOURCE_MOD32;
1431 break;
1432 case 32:
1433 temp |= DMA_RQ_C1_SOURCE_MOD16;
1434 break;
1435 default:
1436 dev_dbg(chip->card->dev,
1437 "period size (%d) not supported by HW\n", period_size);
1438 return -EINVAL;
1441 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1443 return 0;
1446 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1447 int period_size)
1449 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1450 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1452 switch (period_size) {
1453 case 2048:
1454 temp |= DMA_RQ_C1_DEST_MOD1024;
1455 break;
1456 case 1024:
1457 temp |= DMA_RQ_C1_DEST_MOD512;
1458 break;
1459 case 512:
1460 temp |= DMA_RQ_C1_DEST_MOD256;
1461 break;
1462 case 256:
1463 temp |= DMA_RQ_C1_DEST_MOD128;
1464 break;
1465 case 128:
1466 temp |= DMA_RQ_C1_DEST_MOD64;
1467 break;
1468 case 64:
1469 temp |= DMA_RQ_C1_DEST_MOD32;
1470 break;
1471 case 32:
1472 temp |= DMA_RQ_C1_DEST_MOD16;
1473 break;
1474 default:
1475 dev_dbg(chip->card->dev,
1476 "period size (%d) not supported by HW\n", period_size);
1477 return -EINVAL;
1480 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1482 return 0;
1485 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1486 struct dsp_pcm_channel_descriptor * pcm_channel)
1488 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1489 unsigned long flags;
1491 if (snd_BUG_ON(!pcm_channel->active ||
1492 ins->npcm_channels <= 0 ||
1493 pcm_channel->src_scb->ref_count <= 0))
1494 return;
1496 spin_lock_irqsave(&chip->reg_lock, flags);
1497 pcm_channel->unlinked = 1;
1498 pcm_channel->active = 0;
1499 pcm_channel->private_data = NULL;
1500 pcm_channel->src_scb->ref_count --;
1501 ins->npcm_channels --;
1502 spin_unlock_irqrestore(&chip->reg_lock, flags);
1504 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1506 if (!pcm_channel->src_scb->ref_count) {
1507 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1509 if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1510 pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1511 return;
1513 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1514 ins->nsrc_scb --;
1518 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1519 struct dsp_pcm_channel_descriptor * pcm_channel)
1521 unsigned long flags;
1523 if (snd_BUG_ON(!pcm_channel->active ||
1524 chip->dsp_spos_instance->npcm_channels <= 0))
1525 return -EIO;
1527 spin_lock_irqsave(&chip->reg_lock, flags);
1528 if (pcm_channel->unlinked) {
1529 spin_unlock_irqrestore(&chip->reg_lock, flags);
1530 return -EIO;
1533 pcm_channel->unlinked = 1;
1535 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1536 spin_unlock_irqrestore(&chip->reg_lock, flags);
1538 return 0;
1541 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1542 struct dsp_pcm_channel_descriptor * pcm_channel)
1544 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1545 struct dsp_scb_descriptor * parent_scb;
1546 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1547 unsigned long flags;
1549 spin_lock_irqsave(&chip->reg_lock, flags);
1551 if (pcm_channel->unlinked == 0) {
1552 spin_unlock_irqrestore(&chip->reg_lock, flags);
1553 return -EIO;
1556 parent_scb = src_scb;
1558 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1559 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1560 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1563 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1565 snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
1566 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1568 /* update SCB entry in DSP RAM */
1569 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1571 /* update parent SCB entry */
1572 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1574 pcm_channel->unlinked = 0;
1575 spin_unlock_irqrestore(&chip->reg_lock, flags);
1576 return 0;
1579 struct dsp_scb_descriptor *
1580 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1581 u16 addr, char * scb_name)
1583 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1584 struct dsp_scb_descriptor * parent;
1585 struct dsp_scb_descriptor * pcm_input;
1586 int insert_point;
1588 if (snd_BUG_ON(!ins->record_mixer_scb))
1589 return NULL;
1591 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1592 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1593 insert_point = SCB_ON_PARENT_NEXT_SCB;
1594 } else {
1595 parent = ins->record_mixer_scb;
1596 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1599 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1600 source, parent,
1601 insert_point);
1603 return pcm_input;
1606 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1608 unsigned long flags;
1610 if (snd_BUG_ON(!src->parent_scb_ptr))
1611 return -EINVAL;
1613 /* mute SCB */
1614 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1616 spin_lock_irqsave(&chip->reg_lock, flags);
1617 _dsp_unlink_scb (chip,src);
1618 spin_unlock_irqrestore(&chip->reg_lock, flags);
1620 return 0;
1623 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1625 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1626 struct dsp_scb_descriptor * parent_scb;
1628 if (snd_BUG_ON(src->parent_scb_ptr))
1629 return -EINVAL;
1630 if (snd_BUG_ON(!ins->master_mix_scb))
1631 return -EINVAL;
1633 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1634 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1635 parent_scb->next_scb_ptr = src;
1636 } else {
1637 parent_scb = ins->master_mix_scb;
1638 parent_scb->sub_list_ptr = src;
1641 src->parent_scb_ptr = parent_scb;
1643 /* update entry in DSP RAM */
1644 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1646 return 0;
1649 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1651 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1653 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1654 cs46xx_dsp_enable_spdif_hw (chip);
1657 /* dont touch anything if SPDIF is open */
1658 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1659 /* when cs46xx_iec958_post_close(...) is called it
1660 will call this function if necessary depending on
1661 this bit */
1662 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1664 return -EBUSY;
1667 if (snd_BUG_ON(ins->asynch_tx_scb))
1668 return -EINVAL;
1669 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1670 ins->the_null_scb))
1671 return -EINVAL;
1673 /* reset output snooper sample buffer pointer */
1674 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1675 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1677 /* The asynch. transfer task */
1678 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1679 SPDIFO_SCB_INST,
1680 SPDIFO_IP_OUTPUT_BUFFER1,
1681 ins->master_mix_scb,
1682 SCB_ON_PARENT_NEXT_SCB);
1683 if (!ins->asynch_tx_scb) return -ENOMEM;
1685 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1686 PCMSERIALINII_SCB_ADDR,
1687 ins->ref_snoop_scb,
1688 ins->asynch_tx_scb,
1689 SCB_ON_PARENT_SUBLIST_SCB);
1692 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1694 /* monitor state */
1695 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1697 return 0;
1700 int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1702 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1704 /* dont touch anything if SPDIF is open */
1705 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1706 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1707 return -EBUSY;
1710 /* check integrety */
1711 if (snd_BUG_ON(!ins->asynch_tx_scb))
1712 return -EINVAL;
1713 if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1714 return -EINVAL;
1715 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1716 return -EINVAL;
1717 if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1718 ins->master_mix_scb))
1719 return -EINVAL;
1721 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1722 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1724 ins->spdif_pcm_input_scb = NULL;
1725 ins->asynch_tx_scb = NULL;
1727 /* clear buffer to prevent any undesired noise */
1728 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1730 /* monitor state */
1731 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1734 return 0;
1737 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1739 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1741 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1742 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1743 cs46xx_dsp_disable_spdif_out (chip);
1745 /* save state */
1746 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1749 /* if not enabled already */
1750 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1751 cs46xx_dsp_enable_spdif_hw (chip);
1754 /* Create the asynch. transfer task for playback */
1755 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1756 SPDIFO_SCB_INST,
1757 SPDIFO_IP_OUTPUT_BUFFER1,
1758 ins->master_mix_scb,
1759 SCB_ON_PARENT_NEXT_SCB);
1762 /* set spdif channel status value for streaming */
1763 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1765 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1767 return 0;
1770 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1772 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1774 if (snd_BUG_ON(!ins->asynch_tx_scb))
1775 return -EINVAL;
1777 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1779 /* restore settings */
1780 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1782 /* deallocate stuff */
1783 if (ins->spdif_pcm_input_scb != NULL) {
1784 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1785 ins->spdif_pcm_input_scb = NULL;
1788 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1789 ins->asynch_tx_scb = NULL;
1791 /* clear buffer to prevent any undesired noise */
1792 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1794 /* restore state */
1795 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1796 cs46xx_dsp_enable_spdif_out (chip);
1799 return 0;