drm/panthor: Don't add write fences to the shared BOs
[drm/drm-misc.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blob1f90ca723f4df72006b072c6416f84e3c3344a46
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 */
5 /*
6 * 2002-07 Benny Sjostrand benny@hostmobility.com
7 */
10 #include <linux/io.h>
11 #include <linux/delay.h>
12 #include <linux/pm.h>
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/mutex.h>
17 #include <sound/core.h>
18 #include <sound/control.h>
19 #include <sound/info.h>
20 #include "cs46xx.h"
22 #include "cs46xx_lib.h"
23 #include "dsp_spos.h"
25 struct proc_scb_info {
26 struct dsp_scb_descriptor * scb_desc;
27 struct snd_cs46xx *chip;
30 static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
32 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
33 int symbol_index = (int)(symbol - ins->symbol_table.symbols);
35 if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
36 return;
37 if (snd_BUG_ON(symbol_index < 0 ||
38 symbol_index >= ins->symbol_table.nsymbols))
39 return;
41 ins->symbol_table.symbols[symbol_index].deleted = 1;
43 if (symbol_index < ins->symbol_table.highest_frag_index) {
44 ins->symbol_table.highest_frag_index = symbol_index;
47 if (symbol_index == ins->symbol_table.nsymbols - 1)
48 ins->symbol_table.nsymbols --;
50 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
51 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
56 #ifdef CONFIG_SND_PROC_FS
57 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
58 struct snd_info_buffer *buffer)
60 struct proc_scb_info * scb_info = entry->private_data;
61 struct dsp_scb_descriptor * scb = scb_info->scb_desc;
62 struct snd_cs46xx *chip = scb_info->chip;
63 int j,col;
64 void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
66 mutex_lock(&chip->spos_mutex);
67 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
69 for (col = 0,j = 0;j < 0x10; j++,col++) {
70 if (col == 4) {
71 snd_iprintf(buffer,"\n");
72 col = 0;
74 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
77 snd_iprintf(buffer,"\n");
79 if (scb->parent_scb_ptr != NULL) {
80 snd_iprintf(buffer,"parent [%s:%04x] ",
81 scb->parent_scb_ptr->scb_name,
82 scb->parent_scb_ptr->address);
83 } else snd_iprintf(buffer,"parent [none] ");
85 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
86 scb->sub_list_ptr->scb_name,
87 scb->sub_list_ptr->address,
88 scb->next_scb_ptr->scb_name,
89 scb->next_scb_ptr->address,
90 scb->task_entry->symbol_name,
91 scb->task_entry->address);
93 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
94 mutex_unlock(&chip->spos_mutex);
96 #endif
98 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
100 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
102 if ( scb->parent_scb_ptr ) {
103 /* unlink parent SCB */
104 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
105 scb->parent_scb_ptr->next_scb_ptr != scb))
106 return;
108 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
110 if (scb->next_scb_ptr == ins->the_null_scb) {
111 /* last and only node in parent sublist */
112 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
114 if (scb->sub_list_ptr != ins->the_null_scb) {
115 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
117 scb->sub_list_ptr = ins->the_null_scb;
118 } else {
119 /* first node in parent sublist */
120 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
122 if (scb->next_scb_ptr != ins->the_null_scb) {
123 /* update next node parent ptr. */
124 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
126 scb->next_scb_ptr = ins->the_null_scb;
128 } else {
129 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
131 if (scb->next_scb_ptr != ins->the_null_scb) {
132 /* update next node parent ptr. */
133 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
135 scb->next_scb_ptr = ins->the_null_scb;
138 /* update parent first entry in DSP RAM */
139 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
141 /* then update entry in DSP RAM */
142 cs46xx_dsp_spos_update_scb(chip,scb);
144 scb->parent_scb_ptr = NULL;
148 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
149 int dword_count)
151 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
152 int i;
154 for (i = 0; i < dword_count ; ++i ) {
155 writel(0, dst);
156 dst += 4;
160 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
162 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
163 unsigned long flags;
165 /* check integrety */
166 if (snd_BUG_ON(scb->index < 0 ||
167 scb->index >= ins->nscb ||
168 (ins->scbs + scb->index) != scb))
169 return;
171 #if 0
172 /* can't remove a SCB with childs before
173 removing childs first */
174 if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
175 scb->next_scb_ptr != ins->the_null_scb))
176 goto _end;
177 #endif
179 spin_lock_irqsave(&chip->reg_lock, flags);
180 _dsp_unlink_scb (chip,scb);
181 spin_unlock_irqrestore(&chip->reg_lock, flags);
183 cs46xx_dsp_proc_free_scb_desc(scb);
184 if (snd_BUG_ON(!scb->scb_symbol))
185 return;
186 remove_symbol (chip,scb->scb_symbol);
188 ins->scbs[scb->index].deleted = 1;
189 #ifdef CONFIG_PM_SLEEP
190 kfree(ins->scbs[scb->index].data);
191 ins->scbs[scb->index].data = NULL;
192 #endif
194 if (scb->index < ins->scb_highest_frag_index)
195 ins->scb_highest_frag_index = scb->index;
197 if (scb->index == ins->nscb - 1) {
198 ins->nscb --;
201 if (ins->scb_highest_frag_index > ins->nscb) {
202 ins->scb_highest_frag_index = ins->nscb;
205 #if 0
206 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
207 for(i = scb->index + 1;i < ins->nscb; ++i) {
208 ins->scbs[i - 1].index = i - 1;
210 #endif
214 #ifdef CONFIG_SND_PROC_FS
215 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
217 if (scb->proc_info) {
218 struct proc_scb_info * scb_info = scb->proc_info->private_data;
219 struct snd_cs46xx *chip = scb_info->chip;
221 dev_dbg(chip->card->dev,
222 "cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
223 scb->scb_name);
225 snd_info_free_entry(scb->proc_info);
226 scb->proc_info = NULL;
228 kfree (scb_info);
232 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
233 struct dsp_scb_descriptor * scb)
235 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
236 struct snd_info_entry * entry;
237 struct proc_scb_info * scb_info;
239 /* register to proc */
240 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
241 scb->proc_info == NULL) {
243 entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
244 ins->proc_dsp_dir);
245 if (entry) {
246 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
247 if (!scb_info) {
248 snd_info_free_entry(entry);
249 entry = NULL;
250 goto out;
253 scb_info->chip = chip;
254 scb_info->scb_desc = scb;
255 snd_info_set_text_ops(entry, scb_info,
256 cs46xx_dsp_proc_scb_info_read);
258 out:
259 scb->proc_info = entry;
262 #endif /* CONFIG_SND_PROC_FS */
264 static struct dsp_scb_descriptor *
265 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
266 struct dsp_symbol_entry * task_entry,
267 struct dsp_scb_descriptor * parent_scb,
268 int scb_child_type)
270 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
271 struct dsp_scb_descriptor * scb;
273 unsigned long flags;
275 if (snd_BUG_ON(!ins->the_null_scb))
276 return NULL;
278 /* fill the data that will be wroten to DSP */
279 scb_data[SCBsubListPtr] =
280 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
282 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
283 scb_data[SCBfuncEntryPtr] |= task_entry->address;
285 dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
287 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
290 scb->sub_list_ptr = ins->the_null_scb;
291 scb->next_scb_ptr = ins->the_null_scb;
293 scb->parent_scb_ptr = parent_scb;
294 scb->task_entry = task_entry;
297 /* update parent SCB */
298 if (scb->parent_scb_ptr) {
299 #if 0
300 dev_dbg(chip->card->dev,
301 "scb->parent_scb_ptr = %s\n",
302 scb->parent_scb_ptr->scb_name);
303 dev_dbg(chip->card->dev,
304 "scb->parent_scb_ptr->next_scb_ptr = %s\n",
305 scb->parent_scb_ptr->next_scb_ptr->scb_name);
306 dev_dbg(chip->card->dev,
307 "scb->parent_scb_ptr->sub_list_ptr = %s\n",
308 scb->parent_scb_ptr->sub_list_ptr->scb_name);
309 #endif
310 /* link to parent SCB */
311 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
312 if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
313 ins->the_null_scb))
314 return NULL;
316 scb->parent_scb_ptr->next_scb_ptr = scb;
318 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
319 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
320 ins->the_null_scb))
321 return NULL;
323 scb->parent_scb_ptr->sub_list_ptr = scb;
324 } else {
325 snd_BUG();
328 spin_lock_irqsave(&chip->reg_lock, flags);
330 /* update entry in DSP RAM */
331 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
333 spin_unlock_irqrestore(&chip->reg_lock, flags);
337 cs46xx_dsp_proc_register_scb_desc (chip,scb);
339 return scb;
342 static struct dsp_scb_descriptor *
343 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
344 u32 dest, char * task_entry_name,
345 struct dsp_scb_descriptor * parent_scb,
346 int scb_child_type)
348 struct dsp_symbol_entry * task_entry;
350 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
351 SYMBOL_CODE);
353 if (task_entry == NULL) {
354 dev_err(chip->card->dev,
355 "dsp_spos: symbol %s not found\n", task_entry_name);
356 return NULL;
359 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
360 parent_scb,scb_child_type);
363 struct dsp_scb_descriptor *
364 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
366 struct dsp_scb_descriptor * scb;
368 struct dsp_timing_master_scb timing_master_scb = {
369 { 0,
374 { 0,
380 0,0,
381 0,NULL_SCB_ADDR,
382 0,0, /* extraSampleAccum:TMreserved */
383 0,0, /* codecFIFOptr:codecFIFOsyncd */
384 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
385 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
386 0x00060000 /* nSampPerFrmQ15 */
389 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
390 TIMINGMASTER_SCB_ADDR,
391 "TIMINGMASTER",NULL,SCB_NO_PARENT);
393 return scb;
397 struct dsp_scb_descriptor *
398 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
399 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
400 u32 dest, struct dsp_scb_descriptor * parent_scb,
401 int scb_child_type)
403 struct dsp_scb_descriptor * scb;
405 struct dsp_codec_output_scb codec_out_scb = {
406 { 0,
418 0,0,
419 0,NULL_SCB_ADDR,
420 0, /* COstrmRsConfig */
421 0, /* COstrmBufPtr */
422 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
423 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
424 0,child_scb_addr /* COreserved - need child scb to work with rom code */
428 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
429 dest,"S16_CODECOUTPUTTASK",parent_scb,
430 scb_child_type);
432 return scb;
435 struct dsp_scb_descriptor *
436 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
437 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
438 u32 dest, struct dsp_scb_descriptor * parent_scb,
439 int scb_child_type)
442 struct dsp_scb_descriptor * scb;
443 struct dsp_codec_input_scb codec_input_scb = {
444 { 0,
457 #if 0 /* cs4620 */
458 SyncIOSCB,NULL_SCB_ADDR
459 #else
460 0 , 0,
461 #endif
462 0,0,
464 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
465 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
466 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
467 link input slot 3 :rightChanINdisp=""slot 4 */
468 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
469 because AC97 is already 20 bits */
470 0x80008000 /* ??clw cwcgame.scb has 0 */
473 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
474 dest,"S16_CODECINPUTTASK",parent_scb,
475 scb_child_type);
476 return scb;
480 static struct dsp_scb_descriptor *
481 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
482 u16 sample_buffer_addr, u32 dest,
483 int virtual_channel, u32 playback_hw_addr,
484 struct dsp_scb_descriptor * parent_scb,
485 int scb_child_type)
487 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
488 struct dsp_scb_descriptor * scb;
490 struct dsp_generic_scb pcm_reader_scb = {
493 Play DMA Task xfers data from host buffer to SP buffer
494 init/runtime variables:
495 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
496 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
497 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
498 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
499 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
500 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
501 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
502 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
503 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
504 ? Other combinations possible from:
505 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
506 DMA_RQ_C2_AC_NONE 0x00000000L
507 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
508 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
509 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
510 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
512 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
513 aligned to dword boundary
515 /* Basic (non scatter/gather) DMA requestor (4 ints) */
516 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
517 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
518 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
519 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
520 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
521 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
522 /* Barnette said that is what we should use since */
523 /* we are not running in optimized mode? */
524 DMA_RQ_C2_AC_NONE +
525 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
526 /* buffer (on host) crosses half-way point */
527 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
528 playback_hw_addr, /* HostBuffAddr (source) */
529 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
530 sample_buffer_addr /* SP Buffer Address (destination) */
532 /* Scatter/gather DMA requestor extension (5 ints) */
540 /* Sublist pointer & next stream control block (SCB) link. */
541 NULL_SCB_ADDR,NULL_SCB_ADDR,
542 /* Pointer to this tasks parameter block & stream function pointer */
543 0,NULL_SCB_ADDR,
544 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
545 /* for incoming streams, or basicReq.saw, for outgoing streams) */
546 RSCONFIG_DMA_ENABLE + /* enable DMA */
547 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
548 /* uses it for some reason */
549 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
550 RSCONFIG_SAMPLE_16STEREO +
551 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
552 /* Stream sample pointer & MAC-unit mode for this stream */
553 (sample_buffer_addr << 0x10),
554 /* Fractional increment per output sample in the input sample buffer */
557 /* Standard stereo volume control
558 default muted */
559 0xffff,0xffff,
560 0xffff,0xffff
564 if (ins->null_algorithm == NULL) {
565 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
566 SYMBOL_CODE);
568 if (ins->null_algorithm == NULL) {
569 dev_err(chip->card->dev,
570 "dsp_spos: symbol NULLALGORITHM not found\n");
571 return NULL;
575 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
576 dest,ins->null_algorithm,parent_scb,
577 scb_child_type);
579 return scb;
582 #define GOF_PER_SEC 200
584 struct dsp_scb_descriptor *
585 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
586 int rate,
587 u16 src_buffer_addr,
588 u16 src_delay_buffer_addr, u32 dest,
589 struct dsp_scb_descriptor * parent_scb,
590 int scb_child_type,
591 int pass_through)
594 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
595 struct dsp_scb_descriptor * scb;
596 unsigned int tmp1, tmp2;
597 unsigned int phiIncr;
598 unsigned int correctionPerGOF, correctionPerSec;
600 dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
601 scb_name, rate);
604 * Compute the values used to drive the actual sample rate conversion.
605 * The following formulas are being computed, using inline assembly
606 * since we need to use 64 bit arithmetic to compute the values:
608 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
609 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
610 * GOF_PER_SEC)
611 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
612 * GOF_PER_SEC * correctionPerGOF
614 * i.e.
616 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
617 * correctionPerGOF:correctionPerSec =
618 * dividend:remainder(ulOther / GOF_PER_SEC)
620 tmp1 = rate << 16;
621 phiIncr = tmp1 / 48000;
622 tmp1 -= phiIncr * 48000;
623 tmp1 <<= 10;
624 phiIncr <<= 10;
625 tmp2 = tmp1 / 48000;
626 phiIncr += tmp2;
627 tmp1 -= tmp2 * 48000;
628 correctionPerGOF = tmp1 / GOF_PER_SEC;
629 tmp1 -= correctionPerGOF * GOF_PER_SEC;
630 correctionPerSec = tmp1;
633 struct dsp_src_task_scb src_task_scb = {
634 0x0028,0x00c8,
635 0x5555,0x0000,
636 0x0000,0x0000,
637 src_buffer_addr,1,
638 correctionPerGOF,correctionPerSec,
639 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
640 0x0000,src_delay_buffer_addr,
641 0x0,
642 0x080,(src_delay_buffer_addr + (24 * 4)),
643 0,0, /* next_scb, sub_list_ptr */
644 0,0, /* entry, this_spb */
645 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
646 src_buffer_addr << 0x10,
647 phiIncr,
649 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
650 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
654 if (ins->s16_up == NULL) {
655 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
656 SYMBOL_CODE);
658 if (ins->s16_up == NULL) {
659 dev_err(chip->card->dev,
660 "dsp_spos: symbol S16_UPSRC not found\n");
661 return NULL;
665 /* clear buffers */
666 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
667 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
669 if (pass_through) {
670 /* wont work with any other rate than
671 the native DSP rate */
672 snd_BUG_ON(rate != 48000);
674 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
675 dest,"DMAREADER",parent_scb,
676 scb_child_type);
677 } else {
678 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
679 dest,ins->s16_up,parent_scb,
680 scb_child_type);
686 return scb;
689 #if 0 /* not used */
690 struct dsp_scb_descriptor *
691 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
692 u16 buffer_addr, u32 dest,
693 struct dsp_scb_descriptor * parent_scb,
694 int scb_child_type) {
695 struct dsp_scb_descriptor * scb;
697 struct dsp_filter_scb filter_scb = {
698 .a0_right = 0x41a9,
699 .a0_left = 0x41a9,
700 .a1_right = 0xb8e4,
701 .a1_left = 0xb8e4,
702 .a2_right = 0x3e55,
703 .a2_left = 0x3e55,
705 .filter_unused3 = 0x0000,
706 .filter_unused2 = 0x0000,
708 .output_buf_ptr = buffer_addr,
709 .init = 0x000,
711 .prev_sample_output1 = 0x00000000,
712 .prev_sample_output2 = 0x00000000,
714 .prev_sample_input1 = 0x00000000,
715 .prev_sample_input2 = 0x00000000,
717 .next_scb_ptr = 0x0000,
718 .sub_list_ptr = 0x0000,
720 .entry_point = 0x0000,
721 .spb_ptr = 0x0000,
723 .b0_right = 0x0e38,
724 .b0_left = 0x0e38,
725 .b1_right = 0x1c71,
726 .b1_left = 0x1c71,
727 .b2_right = 0x0e38,
728 .b2_left = 0x0e38,
732 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
733 dest,"FILTERTASK",parent_scb,
734 scb_child_type);
736 return scb;
738 #endif /* not used */
740 struct dsp_scb_descriptor *
741 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
742 u16 mix_buffer_addr, u32 dest,
743 struct dsp_scb_descriptor * parent_scb,
744 int scb_child_type)
746 struct dsp_scb_descriptor * scb;
748 struct dsp_mix_only_scb master_mix_scb = {
749 /* 0 */ { 0,
750 /* 1 */ 0,
751 /* 2 */ mix_buffer_addr,
752 /* 3 */ 0
753 /* */ },
755 /* 4 */ 0,
756 /* 5 */ 0,
757 /* 6 */ 0,
758 /* 7 */ 0,
759 /* 8 */ 0x00000080
761 /* 9 */ 0,0,
762 /* A */ 0,0,
763 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
764 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
765 /* D */ 0,
767 /* E */ 0x8000,0x8000,
768 /* F */ 0x8000,0x8000
773 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
774 dest,"S16_MIX",parent_scb,
775 scb_child_type);
776 return scb;
780 struct dsp_scb_descriptor *
781 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
782 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
783 struct dsp_scb_descriptor * parent_scb,
784 int scb_child_type)
786 struct dsp_scb_descriptor * scb;
788 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
789 /* Basic (non scatter/gather) DMA requestor (4 ints) */
791 DMA_RQ_C1_SOURCE_MOD64 +
792 DMA_RQ_C1_DEST_ON_HOST +
793 DMA_RQ_C1_DEST_MOD1024 +
794 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
795 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
796 15,
798 DMA_RQ_C2_AC_NONE +
799 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
801 CS46XX_DSP_CAPTURE_CHANNEL,
802 DMA_RQ_SD_SP_SAMPLE_ADDR +
803 mix_buffer_addr,
804 0x0
807 { 0, 0, 0, 0, 0, },
808 0,0,
809 0,writeback_spb,
811 RSCONFIG_DMA_ENABLE +
812 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
814 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
815 RSCONFIG_DMA_TO_HOST +
816 RSCONFIG_SAMPLE_16STEREO +
817 RSCONFIG_MODULO_64,
818 (mix_buffer_addr + (32 * 4)) << 0x10,
819 1,0,
820 0x0001,0x0080,
821 0xFFFF,0
825 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
827 dest,"S16_MIX_TO_OSTREAM",parent_scb,
828 scb_child_type);
830 return scb;
834 struct dsp_scb_descriptor *
835 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
836 u16 vari_buffer_addr0,
837 u16 vari_buffer_addr1,
838 u32 dest,
839 struct dsp_scb_descriptor * parent_scb,
840 int scb_child_type)
843 struct dsp_scb_descriptor * scb;
845 struct dsp_vari_decimate_scb vari_decimate_scb = {
846 0x0028,0x00c8,
847 0x5555,0x0000,
848 0x0000,0x0000,
849 vari_buffer_addr0,vari_buffer_addr1,
851 0x0028,0x00c8,
852 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
854 0xFF800000,
856 0x0080,vari_buffer_addr1 + (25 * 4),
858 0,0,
859 0,0,
861 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
862 vari_buffer_addr0 << 0x10,
863 0x04000000,
865 0x8000,0x8000,
866 0xFFFF,0xFFFF
870 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
871 dest,"VARIDECIMATE",parent_scb,
872 scb_child_type);
874 return scb;
878 static struct dsp_scb_descriptor *
879 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
880 struct dsp_scb_descriptor * input_scb,
881 struct dsp_scb_descriptor * parent_scb,
882 int scb_child_type)
885 struct dsp_scb_descriptor * scb;
888 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
889 { 0,
902 0,0,
903 0,0,
905 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
907 /* 0xD */ 0,input_scb->address,
909 /* 0xE */ 0x8000,0x8000,
910 /* 0xF */ 0x8000,0x8000
914 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
915 dest,"PCMSERIALINPUTTASK",parent_scb,
916 scb_child_type);
917 return scb;
921 static struct dsp_scb_descriptor *
922 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
923 u16 hfg_scb_address,
924 u16 asynch_buffer_address,
925 struct dsp_scb_descriptor * parent_scb,
926 int scb_child_type)
929 struct dsp_scb_descriptor * scb;
931 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
932 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
933 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
934 /* : Max delta 25 dwords == 100 bytes */
935 0,hfg_scb_address, /* Point to HFG task SCB */
936 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
937 0, /* Initialize accumulated Phi to 0 */
938 0,0x2aab, /* Const 1/3 */
941 0, /* Define the unused elements */
946 0,0,
947 0,dest + AFGTxAccumPhi,
949 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
950 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
951 to the producer pointer */
953 /* There is no correct initial value, it will depend upon the detected
954 rate etc */
955 0x18000000, /* Phi increment for approx 32k operation */
956 0x8000,0x8000, /* Volume controls are unused at this time */
957 0x8000,0x8000
960 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
961 dest,"ASYNCHFGTXCODE",parent_scb,
962 scb_child_type);
964 return scb;
968 struct dsp_scb_descriptor *
969 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
970 u16 hfg_scb_address,
971 u16 asynch_buffer_address,
972 struct dsp_scb_descriptor * parent_scb,
973 int scb_child_type)
975 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
976 struct dsp_scb_descriptor * scb;
978 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
979 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
980 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
981 /* : Max delta 25 dwords == 100 bytes */
982 0,hfg_scb_address, /* Point to HFG task SCB */
983 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
985 0, /* Define the unused elements */
992 0,0,
993 0,dest,
995 RSCONFIG_MODULO_128 |
996 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
997 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
998 synchrinized to the producer pointer */
1000 /* There is no correct initial value, it will depend upon the detected
1001 rate etc */
1002 0x18000000,
1004 /* Set IEC958 input volume */
1005 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1006 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1009 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1010 dest,"ASYNCHFGRXCODE",parent_scb,
1011 scb_child_type);
1013 return scb;
1017 #if 0 /* not used */
1018 struct dsp_scb_descriptor *
1019 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1020 u16 snoop_buffer_address,
1021 struct dsp_scb_descriptor * snoop_scb,
1022 struct dsp_scb_descriptor * parent_scb,
1023 int scb_child_type)
1026 struct dsp_scb_descriptor * scb;
1028 struct dsp_output_snoop_scb output_snoop_scb = {
1029 { 0, /* not used. Zero */
1035 0, /* not used. Zero */
1042 0,0,
1043 0,0,
1045 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1046 snoop_buffer_address << 0x10,
1047 0,0,
1049 0,snoop_scb->address
1052 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1053 dest,"OUTPUTSNOOP",parent_scb,
1054 scb_child_type);
1055 return scb;
1057 #endif /* not used */
1060 struct dsp_scb_descriptor *
1061 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1062 struct dsp_scb_descriptor * parent_scb,
1063 int scb_child_type)
1065 struct dsp_scb_descriptor * scb;
1067 struct dsp_spio_write_scb spio_write_scb = {
1068 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1069 0, /* SPIOWData1; */
1070 0, /* SPIOWData2; */
1071 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1072 0, /* SPIOWData3; */
1073 0, /* SPIOWData4; */
1074 0,0, /* SPIOWDataPtr:Unused1; */
1075 { 0,0 }, /* Unused2[2]; */
1077 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1078 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1085 0 /* Unused3[5]; */
1089 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1090 dest,"SPIOWRITE",parent_scb,
1091 scb_child_type);
1093 return scb;
1096 struct dsp_scb_descriptor *
1097 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1098 u16 snoop_buffer_address,
1099 struct dsp_scb_descriptor * snoop_scb,
1100 struct dsp_scb_descriptor * parent_scb,
1101 int scb_child_type)
1103 struct dsp_scb_descriptor * scb;
1105 struct dsp_magic_snoop_task magic_snoop_scb = {
1106 /* 0 */ 0, /* i0 */
1107 /* 1 */ 0, /* i1 */
1108 /* 2 */ snoop_buffer_address << 0x10,
1109 /* 3 */ 0,snoop_scb->address,
1110 /* 4 */ 0, /* i3 */
1111 /* 5 */ 0, /* i4 */
1112 /* 6 */ 0, /* i5 */
1113 /* 7 */ 0, /* i6 */
1114 /* 8 */ 0, /* i7 */
1115 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1116 /* A */ 0,0, /* entry_point, this_ptr */
1117 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1118 /* C */ snoop_buffer_address << 0x10,
1119 /* D */ 0,
1120 /* E */ { 0x8000,0x8000,
1121 /* F */ 0xffff,0xffff
1125 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1126 dest,"MAGICSNOOPTASK",parent_scb,
1127 scb_child_type);
1129 return scb;
1132 static struct dsp_scb_descriptor *
1133 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1135 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1136 struct dsp_scb_descriptor * scb = from;
1138 while (scb->next_scb_ptr != ins->the_null_scb) {
1139 if (snd_BUG_ON(!scb->next_scb_ptr))
1140 return NULL;
1142 scb = scb->next_scb_ptr;
1145 return scb;
1148 static const u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1149 0x0600, /* 1 */
1150 0x1500, /* 2 */
1151 0x1580, /* 3 */
1152 0x1600, /* 4 */
1153 0x1680, /* 5 */
1154 0x1700, /* 6 */
1155 0x1780, /* 7 */
1156 0x1800, /* 8 */
1157 0x1880, /* 9 */
1158 0x1900, /* 10 */
1159 0x1980, /* 11 */
1160 0x1A00, /* 12 */
1161 0x1A80, /* 13 */
1162 0x1B00, /* 14 */
1163 0x1B80, /* 15 */
1164 0x1C00, /* 16 */
1165 0x1C80, /* 17 */
1166 0x1D00, /* 18 */
1167 0x1D80, /* 19 */
1168 0x1E00, /* 20 */
1169 0x1E80, /* 21 */
1170 0x1F00, /* 22 */
1171 0x1F80, /* 23 */
1172 0x2000, /* 24 */
1173 0x2080, /* 25 */
1174 0x2100, /* 26 */
1175 0x2180, /* 27 */
1176 0x2200, /* 28 */
1177 0x2280, /* 29 */
1178 0x2300, /* 30 */
1179 0x2380, /* 31 */
1180 0x2400, /* 32 */
1183 static const u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1184 0x2B80,
1185 0x2BA0,
1186 0x2BC0,
1187 0x2BE0,
1188 0x2D00,
1189 0x2D20,
1190 0x2D40,
1191 0x2D60,
1192 0x2D80,
1193 0x2DA0,
1194 0x2DC0,
1195 0x2DE0,
1196 0x2E00,
1197 0x2E20
1200 static const u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1201 0x2480,
1202 0x2500,
1203 0x2580,
1204 0x2600,
1205 0x2680,
1206 0x2700,
1207 0x2780,
1208 0x2800,
1209 0x2880,
1210 0x2900,
1211 0x2980,
1212 0x2A00,
1213 0x2A80,
1214 0x2B00
1217 struct dsp_pcm_channel_descriptor *
1218 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1219 u32 sample_rate, void * private_data,
1220 u32 hw_dma_addr,
1221 int pcm_channel_id)
1223 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1224 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1225 struct dsp_scb_descriptor * src_parent_scb = NULL;
1227 /* struct dsp_scb_descriptor * pcm_parent_scb; */
1228 char scb_name[DSP_MAX_SCB_NAME];
1229 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1230 unsigned long flags;
1232 switch (pcm_channel_id) {
1233 case DSP_PCM_MAIN_CHANNEL:
1234 mixer_scb = ins->master_mix_scb;
1235 break;
1236 case DSP_PCM_REAR_CHANNEL:
1237 mixer_scb = ins->rear_mix_scb;
1238 break;
1239 case DSP_PCM_CENTER_LFE_CHANNEL:
1240 mixer_scb = ins->center_lfe_mix_scb;
1241 break;
1242 case DSP_PCM_S71_CHANNEL:
1243 /* TODO */
1244 snd_BUG();
1245 break;
1246 case DSP_IEC958_CHANNEL:
1247 if (snd_BUG_ON(!ins->asynch_tx_scb))
1248 return NULL;
1249 mixer_scb = ins->asynch_tx_scb;
1251 /* if sample rate is set to 48khz we pass
1252 the Sample Rate Converted (which could
1253 alter the raw data stream ...) */
1254 if (sample_rate == 48000) {
1255 dev_dbg(chip->card->dev, "IEC958 pass through\n");
1256 /* Hack to bypass creating a new SRC */
1257 pass_through = 1;
1259 break;
1260 default:
1261 snd_BUG();
1262 return NULL;
1264 /* default sample rate is 44100 */
1265 if (!sample_rate) sample_rate = 44100;
1267 /* search for a already created SRC SCB with the same sample rate */
1268 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1269 (pcm_index == -1 || src_scb == NULL); ++i) {
1271 /* virtual channel reserved
1272 for capture */
1273 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1275 if (ins->pcm_channels[i].active) {
1276 if (!src_scb &&
1277 ins->pcm_channels[i].sample_rate == sample_rate &&
1278 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1279 src_scb = ins->pcm_channels[i].src_scb;
1280 ins->pcm_channels[i].src_scb->ref_count ++;
1281 src_index = ins->pcm_channels[i].src_slot;
1283 } else if (pcm_index == -1) {
1284 pcm_index = i;
1288 if (pcm_index == -1) {
1289 dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
1290 return NULL;
1293 if (src_scb == NULL) {
1294 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1295 dev_err(chip->card->dev,
1296 "dsp_spos: too many SRC instances\n!");
1297 return NULL;
1300 /* find a free slot */
1301 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1302 if (ins->src_scb_slots[i] == 0) {
1303 src_index = i;
1304 ins->src_scb_slots[i] = 1;
1305 break;
1308 if (snd_BUG_ON(src_index == -1))
1309 return NULL;
1311 /* we need to create a new SRC SCB */
1312 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1313 src_parent_scb = mixer_scb;
1314 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1315 } else {
1316 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1317 insert_point = SCB_ON_PARENT_NEXT_SCB;
1320 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1322 dev_dbg(chip->card->dev,
1323 "dsp_spos: creating SRC \"%s\"\n", scb_name);
1324 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1325 sample_rate,
1326 src_output_buffer_addr[src_index],
1327 src_delay_buffer_addr[src_index],
1328 /* 0x400 - 0x600 source SCBs */
1329 0x400 + (src_index * 0x10) ,
1330 src_parent_scb,
1331 insert_point,
1332 pass_through);
1334 if (!src_scb) {
1335 dev_err(chip->card->dev,
1336 "dsp_spos: failed to create SRCtaskSCB\n");
1337 return NULL;
1340 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1342 ins->nsrc_scb ++;
1346 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1348 dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
1349 scb_name, pcm_channel_id);
1351 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1352 pcm_reader_buffer_addr[pcm_index],
1353 /* 0x200 - 400 PCMreader SCBs */
1354 (pcm_index * 0x10) + 0x200,
1355 pcm_index, /* virtual channel 0-31 */
1356 hw_dma_addr, /* pcm hw addr */
1357 NULL, /* parent SCB ptr */
1358 0 /* insert point */
1361 if (!pcm_scb) {
1362 dev_err(chip->card->dev,
1363 "dsp_spos: failed to create PCMreaderSCB\n");
1364 return NULL;
1367 spin_lock_irqsave(&chip->reg_lock, flags);
1368 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1369 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1370 ins->pcm_channels[pcm_index].src_scb = src_scb;
1371 ins->pcm_channels[pcm_index].unlinked = 1;
1372 ins->pcm_channels[pcm_index].private_data = private_data;
1373 ins->pcm_channels[pcm_index].src_slot = src_index;
1374 ins->pcm_channels[pcm_index].active = 1;
1375 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1376 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1377 ins->npcm_channels ++;
1378 spin_unlock_irqrestore(&chip->reg_lock, flags);
1380 return (ins->pcm_channels + pcm_index);
1383 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1384 struct dsp_pcm_channel_descriptor * pcm_channel,
1385 int period_size)
1387 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1388 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1390 switch (period_size) {
1391 case 2048:
1392 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1393 break;
1394 case 1024:
1395 temp |= DMA_RQ_C1_SOURCE_MOD512;
1396 break;
1397 case 512:
1398 temp |= DMA_RQ_C1_SOURCE_MOD256;
1399 break;
1400 case 256:
1401 temp |= DMA_RQ_C1_SOURCE_MOD128;
1402 break;
1403 case 128:
1404 temp |= DMA_RQ_C1_SOURCE_MOD64;
1405 break;
1406 case 64:
1407 temp |= DMA_RQ_C1_SOURCE_MOD32;
1408 break;
1409 case 32:
1410 temp |= DMA_RQ_C1_SOURCE_MOD16;
1411 break;
1412 default:
1413 dev_dbg(chip->card->dev,
1414 "period size (%d) not supported by HW\n", period_size);
1415 return -EINVAL;
1418 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1420 return 0;
1423 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1424 int period_size)
1426 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1427 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1429 switch (period_size) {
1430 case 2048:
1431 temp |= DMA_RQ_C1_DEST_MOD1024;
1432 break;
1433 case 1024:
1434 temp |= DMA_RQ_C1_DEST_MOD512;
1435 break;
1436 case 512:
1437 temp |= DMA_RQ_C1_DEST_MOD256;
1438 break;
1439 case 256:
1440 temp |= DMA_RQ_C1_DEST_MOD128;
1441 break;
1442 case 128:
1443 temp |= DMA_RQ_C1_DEST_MOD64;
1444 break;
1445 case 64:
1446 temp |= DMA_RQ_C1_DEST_MOD32;
1447 break;
1448 case 32:
1449 temp |= DMA_RQ_C1_DEST_MOD16;
1450 break;
1451 default:
1452 dev_dbg(chip->card->dev,
1453 "period size (%d) not supported by HW\n", period_size);
1454 return -EINVAL;
1457 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1459 return 0;
1462 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1463 struct dsp_pcm_channel_descriptor * pcm_channel)
1465 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1466 unsigned long flags;
1468 if (snd_BUG_ON(!pcm_channel->active ||
1469 ins->npcm_channels <= 0 ||
1470 pcm_channel->src_scb->ref_count <= 0))
1471 return;
1473 spin_lock_irqsave(&chip->reg_lock, flags);
1474 pcm_channel->unlinked = 1;
1475 pcm_channel->active = 0;
1476 pcm_channel->private_data = NULL;
1477 pcm_channel->src_scb->ref_count --;
1478 ins->npcm_channels --;
1479 spin_unlock_irqrestore(&chip->reg_lock, flags);
1481 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1483 if (!pcm_channel->src_scb->ref_count) {
1484 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1486 if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1487 pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1488 return;
1490 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1491 ins->nsrc_scb --;
1495 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1496 struct dsp_pcm_channel_descriptor * pcm_channel)
1498 unsigned long flags;
1500 if (snd_BUG_ON(!pcm_channel->active ||
1501 chip->dsp_spos_instance->npcm_channels <= 0))
1502 return -EIO;
1504 spin_lock_irqsave(&chip->reg_lock, flags);
1505 if (pcm_channel->unlinked) {
1506 spin_unlock_irqrestore(&chip->reg_lock, flags);
1507 return -EIO;
1510 pcm_channel->unlinked = 1;
1512 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1513 spin_unlock_irqrestore(&chip->reg_lock, flags);
1515 return 0;
1518 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1519 struct dsp_pcm_channel_descriptor * pcm_channel)
1521 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1522 struct dsp_scb_descriptor * parent_scb;
1523 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1524 unsigned long flags;
1526 spin_lock_irqsave(&chip->reg_lock, flags);
1528 if (pcm_channel->unlinked == 0) {
1529 spin_unlock_irqrestore(&chip->reg_lock, flags);
1530 return -EIO;
1533 parent_scb = src_scb;
1535 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1536 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1537 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1540 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1542 snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
1543 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1545 /* update SCB entry in DSP RAM */
1546 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1548 /* update parent SCB entry */
1549 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1551 pcm_channel->unlinked = 0;
1552 spin_unlock_irqrestore(&chip->reg_lock, flags);
1553 return 0;
1556 struct dsp_scb_descriptor *
1557 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1558 u16 addr, char * scb_name)
1560 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1561 struct dsp_scb_descriptor * parent;
1562 struct dsp_scb_descriptor * pcm_input;
1563 int insert_point;
1565 if (snd_BUG_ON(!ins->record_mixer_scb))
1566 return NULL;
1568 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1569 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1570 insert_point = SCB_ON_PARENT_NEXT_SCB;
1571 } else {
1572 parent = ins->record_mixer_scb;
1573 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1576 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1577 source, parent,
1578 insert_point);
1580 return pcm_input;
1583 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1585 unsigned long flags;
1587 if (snd_BUG_ON(!src->parent_scb_ptr))
1588 return -EINVAL;
1590 /* mute SCB */
1591 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1593 spin_lock_irqsave(&chip->reg_lock, flags);
1594 _dsp_unlink_scb (chip,src);
1595 spin_unlock_irqrestore(&chip->reg_lock, flags);
1597 return 0;
1600 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1602 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1603 struct dsp_scb_descriptor * parent_scb;
1605 if (snd_BUG_ON(src->parent_scb_ptr))
1606 return -EINVAL;
1607 if (snd_BUG_ON(!ins->master_mix_scb))
1608 return -EINVAL;
1610 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1611 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1612 parent_scb->next_scb_ptr = src;
1613 } else {
1614 parent_scb = ins->master_mix_scb;
1615 parent_scb->sub_list_ptr = src;
1618 src->parent_scb_ptr = parent_scb;
1620 /* update entry in DSP RAM */
1621 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1623 return 0;
1626 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1628 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1630 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1631 cs46xx_dsp_enable_spdif_hw (chip);
1634 /* dont touch anything if SPDIF is open */
1635 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1636 /* when cs46xx_iec958_post_close(...) is called it
1637 will call this function if necessary depending on
1638 this bit */
1639 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1641 return -EBUSY;
1644 if (snd_BUG_ON(ins->asynch_tx_scb))
1645 return -EINVAL;
1646 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1647 ins->the_null_scb))
1648 return -EINVAL;
1650 /* reset output snooper sample buffer pointer */
1651 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1652 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1654 /* The asynch. transfer task */
1655 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1656 SPDIFO_SCB_INST,
1657 SPDIFO_IP_OUTPUT_BUFFER1,
1658 ins->master_mix_scb,
1659 SCB_ON_PARENT_NEXT_SCB);
1660 if (!ins->asynch_tx_scb) return -ENOMEM;
1662 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1663 PCMSERIALINII_SCB_ADDR,
1664 ins->ref_snoop_scb,
1665 ins->asynch_tx_scb,
1666 SCB_ON_PARENT_SUBLIST_SCB);
1669 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1671 /* monitor state */
1672 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1674 return 0;
1677 int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1679 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1681 /* dont touch anything if SPDIF is open */
1682 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1683 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1684 return -EBUSY;
1687 /* check integrety */
1688 if (snd_BUG_ON(!ins->asynch_tx_scb))
1689 return -EINVAL;
1690 if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1691 return -EINVAL;
1692 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1693 return -EINVAL;
1694 if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1695 ins->master_mix_scb))
1696 return -EINVAL;
1698 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1699 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1701 ins->spdif_pcm_input_scb = NULL;
1702 ins->asynch_tx_scb = NULL;
1704 /* clear buffer to prevent any undesired noise */
1705 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1707 /* monitor state */
1708 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1711 return 0;
1714 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1716 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1718 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1719 /* remove AsynchFGTxSCB and PCMSerialInput_II */
1720 cs46xx_dsp_disable_spdif_out (chip);
1722 /* save state */
1723 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1726 /* if not enabled already */
1727 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1728 cs46xx_dsp_enable_spdif_hw (chip);
1731 /* Create the asynch. transfer task for playback */
1732 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1733 SPDIFO_SCB_INST,
1734 SPDIFO_IP_OUTPUT_BUFFER1,
1735 ins->master_mix_scb,
1736 SCB_ON_PARENT_NEXT_SCB);
1739 /* set spdif channel status value for streaming */
1740 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1742 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1744 return 0;
1747 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1749 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1751 if (snd_BUG_ON(!ins->asynch_tx_scb))
1752 return -EINVAL;
1754 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1756 /* restore settings */
1757 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1759 /* deallocate stuff */
1760 if (ins->spdif_pcm_input_scb != NULL) {
1761 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1762 ins->spdif_pcm_input_scb = NULL;
1765 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1766 ins->asynch_tx_scb = NULL;
1768 /* clear buffer to prevent any undesired noise */
1769 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1771 /* restore state */
1772 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1773 cs46xx_dsp_enable_spdif_out (chip);
1776 return 0;