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