1 /****************************************************************************** 2 / 3 / File: Theater.cpp 4 / 5 / Description: ATI Rage Theater Video Decoder interface. 6 / 7 / Copyright 2001, Carlos Hasan 8 / 9 *******************************************************************************/ 10 11 #include <Debug.h> 12 #include "Theater.h" 13 #include "Theater200.h" 14 #include "TheatreReg.h" 15 #include "lendian_bitfield.h" 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <OS.h> 19 20 21 const char* DEFAULT_MICROC_PATH = "/boot/home/config/settings/Media/RageTheater200/ativmc20.cod"; 22 const char* DEFAULT_MICROC_TYPE = "BINARY"; 23 24 CTheater200::CTheater200(CRadeon & radeon, int device) 25 :CTheater(radeon, device), 26 fMode(MODE_UNINITIALIZED), 27 microcode_path(NULL), 28 microcode_type(NULL) 29 30 { 31 PRINT(("CTheater200::CTheater200()\n")); 32 33 fMode = MODE_UNINITIALIZED; 34 35 if( fPort.InitCheck() == B_OK ) { 36 radeon_video_tuner tuner; 37 radeon_video_decoder video; 38 39 radeon.GetMMParameters(tuner, video, fClock, 40 fTunerPort, fCompositePort, fSVideoPort); 41 42 if (fClock != C_RADEON_VIDEO_CLOCK_29_49892_MHZ && 43 fClock != C_RADEON_VIDEO_CLOCK_27_00000_MHZ) 44 PRINT(("CTheater200::CTheater200() - Unsupported crystal clock!\n")); 45 46 // fDevice = fPort.FindVIPDevice( C_THEATER200_VIP_DEVICE_ID ); 47 48 } 49 50 if( InitCheck() != B_OK ) 51 PRINT(("CTheater200::CTheater200() - Rage Theater not found!\n")); 52 53 InitTheatre(); 54 55 } 56 57 CTheater200::~CTheater200() 58 { 59 PRINT(("CTheater200::~CTheater200()\n")); 60 61 if( InitCheck() == B_OK ) 62 SetEnable(false, false); 63 64 } 65 66 status_t CTheater200::InitCheck() const 67 { 68 status_t res; 69 70 res = fPort.InitCheck(); 71 if( res != B_OK ) 72 { 73 PRINT(("CTheater200::InitCheck() fPort Failed\n")); 74 return res; 75 } 76 77 res = (fDevice >= C_VIP_PORT_DEVICE_0 && fDevice <= C_VIP_PORT_DEVICE_3) ? B_OK : B_ERROR; 78 if( res != B_OK ) 79 { 80 PRINT(("CTheater200::InitCheck() Invalid VIP Channel\n")); 81 return res; 82 } 83 84 if (fMode != MODE_INITIALIZED_FOR_TV_IN); 85 return B_ERROR; 86 87 PRINT(("CTheater200::InitCheck() Sucess\n")); 88 return res; 89 } 90 91 void CTheater200::Reset() 92 { 93 PRINT(("CTheater200::Reset()\n")); 94 95 SetHue(0); 96 SetBrightness(0); 97 SetSaturation(0); 98 SetContrast(0); 99 SetSharpness(false); 100 } 101 102 status_t CTheater200::DSPLoadMicrocode(char* micro_path, char* micro_type, struct rt200_microc_data* microc_datap) 103 { 104 FILE* file; 105 struct rt200_microc_head* microc_headp = µc_datap->microc_head; 106 struct rt200_microc_seg* seg_list = NULL; 107 struct rt200_microc_seg* curr_seg = NULL; 108 struct rt200_microc_seg* prev_seg = NULL; 109 uint32 i; 110 111 if (micro_path == NULL) 112 return -1; 113 114 if (micro_type == NULL) 115 return -1; 116 117 file = fopen(micro_path, "r"); 118 if (file == NULL) { 119 PRINT(("Cannot open microcode file\n")); 120 return -1; 121 } 122 123 if (!strcmp(micro_type, "BINARY")) 124 { 125 if (fread(microc_headp, sizeof(struct rt200_microc_head), 1, file) != 1) 126 { 127 PRINT(("Cannot read header from file: %s\n", micro_path)); 128 goto fail_exit; 129 } 130 131 PRINT(("Microcode: num_seg: %x\n", microc_headp->num_seg)); 132 133 if (microc_headp->num_seg == 0) 134 goto fail_exit; 135 136 for (i = 0; i < microc_headp->num_seg; i++) 137 { 138 int ret; 139 140 curr_seg = (struct rt200_microc_seg*) malloc(sizeof(struct rt200_microc_seg)); 141 if (curr_seg == NULL) 142 { 143 PRINT(("Cannot allocate memory\n")); 144 goto fail_exit; 145 } 146 147 ret = fread(&curr_seg->num_bytes, 4, 1, file); 148 ret += fread(&curr_seg->download_dst, 4, 1, file); 149 ret += fread(&curr_seg->crc_val, 4, 1, file); 150 if (ret != 3) 151 { 152 PRINT(("Cannot read segment from microcode file: %s\n", micro_path)); 153 goto fail_exit; 154 } 155 156 curr_seg->data = (unsigned char*) malloc(curr_seg->num_bytes); 157 if (curr_seg->data == NULL) 158 { 159 PRINT(("cannot allocate memory\n")); 160 goto fail_exit; 161 } 162 163 PRINT(("Microcode: segment number: %x\n", i)); 164 PRINT(("Microcode: curr_seg->num_bytes: %x\n", curr_seg->num_bytes)); 165 PRINT(("Microcode: curr_seg->download_dst: %x\n", curr_seg->download_dst)); 166 PRINT(("Microcode: curr_seg->crc_val: %x\n", curr_seg->crc_val)); 167 168 if (seg_list) 169 { 170 prev_seg->next = curr_seg; 171 curr_seg->next = NULL; 172 prev_seg = curr_seg; 173 } 174 else 175 seg_list = prev_seg = curr_seg; 176 177 } 178 179 curr_seg = seg_list; 180 while (curr_seg) 181 { 182 if ( fread(curr_seg->data, curr_seg->num_bytes, 1, file) != 1 ) 183 { 184 PRINT(("Cannot read segment data\n")); 185 goto fail_exit; 186 } 187 188 curr_seg = curr_seg->next; 189 } 190 } 191 else if (!strcmp(micro_type, "ASCII")) 192 { 193 char tmp1[12], tmp2[12], tmp3[12], tmp4[12]; 194 unsigned int ltmp; 195 196 if ((fgets(tmp1, 12, file) != NULL) && 197 (fgets(tmp2, 12, file) != NULL) && 198 (fgets(tmp3, 12, file) != NULL) && 199 fgets(tmp4, 12, file) != NULL) 200 { 201 microc_headp->device_id = strtoul(tmp1, NULL, 16); 202 microc_headp->vendor_id = strtoul(tmp2, NULL, 16); 203 microc_headp->revision_id = strtoul(tmp3, NULL, 16); 204 microc_headp->num_seg = strtoul(tmp4, NULL, 16); 205 } 206 else 207 { 208 PRINT(("Cannot read header from file: %s\n", micro_path)); 209 goto fail_exit; 210 } 211 212 PRINT(("Microcode: num_seg: %x\n", microc_headp->num_seg)); 213 214 if (microc_headp->num_seg == 0) 215 goto fail_exit; 216 217 for (i = 0; i < microc_headp->num_seg; i++) 218 { 219 curr_seg = (struct rt200_microc_seg*) malloc(sizeof(struct rt200_microc_seg)); 220 if (curr_seg == NULL) 221 { 222 PRINT(("Cannot allocate memory\n")); 223 goto fail_exit; 224 } 225 226 if (fgets(tmp1, 12, file) != NULL && 227 fgets(tmp2, 12, file) != NULL && 228 fgets(tmp3, 12, file) != NULL) 229 { 230 curr_seg->num_bytes = strtoul(tmp1, NULL, 16); 231 curr_seg->download_dst = strtoul(tmp2, NULL, 16); 232 curr_seg->crc_val = strtoul(tmp3, NULL, 16); 233 } 234 else 235 { 236 PRINT(("Cannot read segment from microcode file: %s\n", micro_path)); 237 goto fail_exit; 238 } 239 240 curr_seg->data = (unsigned char*) malloc(curr_seg->num_bytes); 241 if (curr_seg->data == NULL) 242 { 243 PRINT(("cannot allocate memory\n")); 244 goto fail_exit; 245 } 246 247 PRINT(("Microcode: segment number: %x\n", i)); 248 PRINT(("Microcode: curr_seg->num_bytes: %x\n", curr_seg->num_bytes)); 249 PRINT(("Microcode: curr_seg->download_dst: %x\n", curr_seg->download_dst)); 250 PRINT(("Microcode: curr_seg->crc_val: %x\n", curr_seg->crc_val)); 251 252 if (seg_list) 253 { 254 curr_seg->next = NULL; 255 prev_seg->next = curr_seg; 256 prev_seg = curr_seg; 257 } 258 else 259 seg_list = prev_seg = curr_seg; 260 } 261 262 curr_seg = seg_list; 263 while (curr_seg) 264 { 265 for ( i = 0; i < curr_seg->num_bytes; i+=4) 266 { 267 268 if ( fgets(tmp1, 12, file) == NULL ) 269 { 270 PRINT(("Cannot read from file\n")); 271 goto fail_exit; 272 } 273 ltmp = strtoul(tmp1, NULL, 16); 274 275 *(unsigned int*)(curr_seg->data + i) = ltmp; 276 } 277 278 curr_seg = curr_seg->next; 279 } 280 281 } 282 else 283 { 284 PRINT(("File type %s unknown\n", micro_type)); 285 } 286 287 microc_datap->microc_seg_list = seg_list; 288 289 fclose(file); 290 return 0; 291 292 fail_exit: 293 curr_seg = seg_list; 294 while(curr_seg) 295 { 296 free(curr_seg->data); 297 prev_seg = curr_seg; 298 curr_seg = curr_seg->next; 299 free(prev_seg); 300 } 301 fclose(file); 302 303 return -1; 304 } 305 306 307 void CTheater200::DSPCleanMicrocode(struct rt200_microc_data* microc_datap) 308 { 309 struct rt200_microc_seg* seg_list = microc_datap->microc_seg_list; 310 struct rt200_microc_seg* prev_seg; 311 312 while(seg_list) 313 { 314 free(seg_list->data); 315 prev_seg = seg_list; 316 seg_list = seg_list->next; 317 free(prev_seg); 318 } 319 } 320 321 322 status_t CTheater200::DspInit() 323 { 324 uint32 data; 325 int i = 0; 326 327 PRINT(("CTheater200::Dsp_Init()\n")); 328 329 /* Map FIFOD to DSP Port I/O port */ 330 data = Register(VIP_HOSTINTF_PORT_CNTL); 331 SetRegister(VIP_HOSTINTF_PORT_CNTL, data & (~VIP_HOSTINTF_PORT_CNTL__FIFO_RW_MODE)); 332 333 /* The default endianess is LE. It matches the ost one for x86 */ 334 data = Register(VIP_HOSTINTF_PORT_CNTL); 335 SetRegister(VIP_HOSTINTF_PORT_CNTL, data & (~VIP_HOSTINTF_PORT_CNTL__FIFOD_ENDIAN_SWAP)); 336 337 /* Wait until Shuttle bus channel 14 is available */ 338 data = Register(VIP_TC_STATUS); 339 while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) 340 data = Register(VIP_TC_STATUS); 341 342 PRINT(("Microcode: dsp_init: channel 14 available\n")); 343 344 return B_OK; 345 } 346 347 status_t CTheater200::DspLoad( struct rt200_microc_data* microc_datap ) 348 { 349 350 struct rt200_microc_seg* seg_list = microc_datap->microc_seg_list; 351 uint8 data8; 352 uint32 data, fb_scratch0, fb_scratch1; 353 uint32 i; 354 uint32 tries = 0; 355 uint32 result = 0; 356 uint32 seg_id = 0; 357 358 PRINT(("Microcode: before everything: %x\n", data8)); 359 360 if (ReadFifo(0x000, &data8)) 361 PRINT(("Microcode: FIFO status0: %x\n", data8)); 362 else 363 { 364 PRINT(("Microcode: error reading FIFO status0\n")); 365 return -1; 366 } 367 368 369 if (ReadFifo(0x100, &data8)) 370 PRINT(("Microcode: FIFO status1: %x\n", data8)); 371 else 372 { 373 PRINT(("Microcode: error reading FIFO status1\n")); 374 return -1; 375 } 376 377 /* 378 * Download the Boot Code and CRC Checking Code (first segment) 379 */ 380 //debugger("DSPLoad"); 381 seg_id = 1; 382 while(result != DSP_OK && tries++ < 10) 383 { 384 385 /* Put DSP in reset before download (0x02) */ 386 data = Register(VIP_TC_DOWNLOAD); 387 SetRegister(VIP_TC_DOWNLOAD, (data & ~VIP_TC_DOWNLOAD__TC_RESET_MODE) | (0x02 << 17)); 388 389 /* 390 * Configure shuttle bus for tranfer between DSP I/O "Program Interface" 391 * and Program Memory at address 0 392 */ 393 394 SetRegister(VIP_TC_SOURCE, 0x90000000); 395 SetRegister(VIP_TC_DESTINATION, 0x00000000); 396 SetRegister(VIP_TC_COMMAND, 0xe0000044 | ((seg_list->num_bytes - 1) << 7)); 397 398 /* Load first segment */ 399 PRINT(("Microcode: Loading first segment\n")); 400 401 if (!WriteFifo(0x700, seg_list->num_bytes, seg_list->data)) 402 { 403 PRINT(("Microcode: write to FIFOD failed\n")); 404 return -1; 405 } 406 407 /* Wait until Shuttle bus channel 14 is available */ 408 i = data = 0; 409 data = Register(VIP_TC_STATUS); 410 while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) 411 data = Register(VIP_TC_STATUS); 412 413 if (i >= 10000) 414 { 415 PRINT(("Microcode: channel 14 timeout\n")); 416 return -1; 417 } 418 419 PRINT(("Microcode: dsp_load: checkpoint 1\n")); 420 PRINT(("Microcode: TC_STATUS: %x\n", data)); 421 422 /* transfer the code from program memory to data memory */ 423 SetRegister(VIP_TC_SOURCE, 0x00000000); 424 SetRegister(VIP_TC_DESTINATION, 0x10000000); 425 SetRegister(VIP_TC_COMMAND, 0xe0000006 | ((seg_list->num_bytes - 1) << 7)); 426 427 /* Wait until Shuttle bus channel 14 is available */ 428 i = data = 0; 429 data = Register(VIP_TC_STATUS); 430 while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) 431 data = Register(VIP_TC_STATUS); 432 433 if (i >= 10000) 434 { 435 PRINT(("Microcode: channel 14 timeout\n")); 436 return -1; 437 } 438 PRINT(("Microcode: dsp_load: checkpoint 2\n")); 439 PRINT(("Microcode: TC_STATUS: %x\n", data)); 440 441 /* Take DSP out from reset (0x0) */ 442 data = Register(VIP_TC_DOWNLOAD); 443 SetRegister(VIP_TC_DOWNLOAD, data & ~VIP_TC_DOWNLOAD__TC_RESET_MODE); 444 445 data = Register(VIP_TC_STATUS); 446 PRINT(("Microcode: dsp_load: checkpoint 3\n")); 447 PRINT(("Microcode: TC_STATUS: %x\n", data)); 448 449 /* send dsp_download_check_CRC */ 450 fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 193); 451 fb_scratch1 = (unsigned int)seg_list->crc_val; 452 453 result = DspSendCommand(fb_scratch1, fb_scratch0); 454 455 PRINT(("Microcode: dsp_load: checkpoint 4\n")); 456 } 457 458 //debugger("DSPLoad"); 459 460 if (tries >= 10) 461 { 462 PRINT(("Microcode: Download of boot degment failed\n")); 463 return -1; 464 } 465 466 PRINT(("Microcode: Download of boot code succeeded\n")); 467 468 while((seg_list = seg_list->next) != NULL) 469 { 470 seg_id++; 471 result = tries = 0; 472 while(result != DSP_OK && tries++ < 10) 473 { 474 /* 475 * Configure shuttle bus for tranfer between DSP I/O "Program Interface" 476 * and Data Memory at address 0 477 */ 478 479 SetRegister(VIP_TC_SOURCE, 0x90000000); 480 SetRegister(VIP_TC_DESTINATION, 0x10000000); 481 SetRegister(VIP_TC_COMMAND, 0xe0000044 | ((seg_list->num_bytes - 1) << 7)); 482 483 if (!WriteFifo(0x700, seg_list->num_bytes, seg_list->data)) 484 { 485 PRINT(("Microcode: write to FIFOD failed\n")); 486 return -1; 487 } 488 489 i = data = 0; 490 data = Register(VIP_TC_STATUS); 491 while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000)) 492 data = Register(VIP_TC_STATUS); 493 494 /* send dsp_download_check_CRC */ 495 fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 193); 496 fb_scratch1 = (unsigned int)seg_list->crc_val; 497 498 result = DspSendCommand(fb_scratch1, fb_scratch0); 499 } 500 501 if (i >=10) 502 { 503 PRINT(("Microcode: DSP failed to move seg: %x from data to code memory\n", seg_id)); 504 return -1; 505 } 506 507 PRINT(("Microcode: segment: %x loaded\n", seg_id)); 508 509 /* 510 * The segment is downloaded correctly to data memory. Now move it to code memory 511 * by using dsp_download_code_transfer command. 512 */ 513 514 fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 194); 515 fb_scratch1 = (unsigned int)seg_list->download_dst; 516 517 result = DspSendCommand(fb_scratch1, fb_scratch0); 518 519 if (result != DSP_OK) 520 { 521 PRINT(("Microcode: DSP failed to move seg: %x from data to code memory\n", seg_id)); 522 return -1; 523 } 524 } 525 526 PRINT(("Microcode: download complete\n")); 527 528 /* 529 * The last step is sending dsp_download_check_CRC with "download complete" 530 */ 531 532 fb_scratch0 = ((165 << 8) & 0xff00) | (0xff & 193); 533 fb_scratch1 = (unsigned int)0x11111; 534 535 result = DspSendCommand(fb_scratch1, fb_scratch0); 536 537 if (result == DSP_OK) 538 PRINT(("Microcode: DSP microcode successfully loaded\n")); 539 else 540 { 541 PRINT(("Microcode: DSP microcode UNsuccessfully loaded\n")); 542 return -1; 543 } 544 545 return 0; 546 } 547 548 status_t CTheater200::DspSendCommand(uint32 fb_scratch1, uint32 fb_scratch0) 549 { 550 uint32 data; 551 int i; 552 553 /* 554 * Clear the FB_INT0 bit in INT_CNTL 555 */ 556 data = Register(VIP_INT_CNTL); 557 SetRegister(VIP_INT_CNTL, data | VIP_INT_CNTL__FB_INT0_CLR); 558 559 /* 560 * Write FB_SCRATCHx registers. If FB_SCRATCH1==0 then we have a DWORD command. 561 */ 562 SetRegister(VIP_FB_SCRATCH0, fb_scratch0); 563 if (fb_scratch1 != 0) 564 SetRegister(VIP_FB_SCRATCH1, fb_scratch1); 565 566 /* 567 * Attention DSP. We are talking to you. 568 */ 569 data = Register(VIP_FB_INT); 570 SetRegister(VIP_FB_INT, data | VIP_FB_INT__INT_7); 571 572 /* 573 * Wait (by polling) for the DSP to process the command. 574 */ 575 i = 0; 576 data = Register(VIP_INT_CNTL); 577 while((!(data & VIP_INT_CNTL__FB_INT0)) && (i++ < 10)) 578 { 579 snooze(1000); 580 data = Register(VIP_INT_CNTL); 581 } 582 583 /* 584 * The return code is in FB_SCRATCH0 585 */ 586 fb_scratch0 = Register(VIP_FB_SCRATCH0); 587 588 /* 589 * If we are here it means we got an answer. Clear the FB_INT0 bit. 590 */ 591 data = Register(VIP_INT_CNTL); 592 SetRegister(VIP_INT_CNTL, data | VIP_INT_CNTL__FB_INT0_CLR); 593 594 return fb_scratch0; 595 } 596 597 void CTheater200::InitTheatre() 598 { 599 uint32 data; 600 uint32 M, N, P; 601 602 /* this will give 108Mhz at 27Mhz reference */ 603 M = 28; 604 N = 224; 605 P = 1; 606 607 ShutdownTheatre(); 608 snooze(100000); 609 fMode = MODE_INITIALIZATION_IN_PROGRESS; 610 611 data = M | (N << 11) | (P <<24); 612 SetRegister(VIP_DSP_PLL_CNTL, data); 613 614 Register(VIP_PLL_CNTL0, data); 615 data |= 0x2000; 616 SetRegister(VIP_PLL_CNTL0, data); 617 618 /* RT_regw(VIP_I2C_SLVCNTL, 0x249); */ 619 Register(VIP_PLL_CNTL1, data); 620 data |= 0x00030003; 621 SetRegister(VIP_PLL_CNTL1, data); 622 623 Register(VIP_PLL_CNTL0, data); 624 data &= 0xfffffffc; 625 SetRegister(VIP_PLL_CNTL0, data); 626 snooze(15000); 627 628 Register(VIP_CLOCK_SEL_CNTL, data); 629 data |= 0x1b; 630 SetRegister(VIP_CLOCK_SEL_CNTL, data); 631 632 Register(VIP_MASTER_CNTL, data); 633 data &= 0xffffff07; 634 SetRegister(VIP_MASTER_CNTL, data); 635 data &= 0xffffff03; 636 SetRegister(VIP_MASTER_CNTL, data); 637 snooze(1000); 638 639 if (microcode_path == NULL) 640 { 641 microcode_path = const_cast<char *>(DEFAULT_MICROC_PATH); 642 PRINT(("Microcode: Use default microcode path: %s\n", DEFAULT_MICROC_PATH)); 643 } 644 else 645 { 646 PRINT(("Microcode: Use microcode path: %s\n", microcode_path)); 647 } 648 649 if (microcode_type == NULL) 650 { 651 microcode_type = const_cast<char *>(DEFAULT_MICROC_TYPE); 652 PRINT(("Microcode: Use default microcode type: %s\n", DEFAULT_MICROC_TYPE)); 653 } 654 else 655 { 656 PRINT(("Microcode: Use microcode type: %s\n", microcode_type)); 657 } 658 659 if (DSPDownloadMicrocode() < 0) 660 { 661 ShutdownTheatre(); 662 return; 663 } 664 665 //DspSetLowPowerState(1); 666 //DspSetVideoStreamFormat(1); 667 668 fMode = MODE_INITIALIZED_FOR_TV_IN; 669 } 670 671 int CTheater200::DSPDownloadMicrocode() 672 { 673 struct rt200_microc_data microc_data; 674 microc_data.microc_seg_list = NULL; 675 676 if (DSPLoadMicrocode(microcode_path, microcode_type, µc_data) < 0) 677 { 678 PRINT(("Microcode: cannot load microcode\n")); 679 goto err_exit; 680 } 681 else 682 { 683 PRINT(("Microcode: device_id: %x\n", microc_data.microc_head.device_id)); 684 PRINT(("Microcode: vendor_id: %x\n", microc_data.microc_head.vendor_id)); 685 PRINT(("Microcode: rev_id: %x\n", microc_data.microc_head.revision_id)); 686 PRINT(("Microcode: num_seg: %x\n", microc_data.microc_head.num_seg)); 687 } 688 689 if (DspInit() < 0) 690 { 691 PRINT(("Microcode: dsp_init failed\n")); 692 goto err_exit; 693 } 694 else 695 { 696 PRINT(("Microcode: dsp_init OK\n")); 697 } 698 699 if (DspLoad(µc_data) < 0) 700 { 701 PRINT(("Microcode: dsp_download failed\n")); 702 goto err_exit; 703 } 704 else 705 { 706 PRINT(("Microcode: dsp_download OK\n")); 707 } 708 709 DSPCleanMicrocode(µc_data); 710 return 0; 711 712 err_exit: 713 714 DSPCleanMicrocode(µc_data); 715 return -1; 716 717 } 718 719 void CTheater200::ShutdownTheatre() 720 { 721 fMode = MODE_UNINITIALIZED; 722 } 723 724 void CTheater200::ResetTheatreRegsForNoTVout() 725 { 726 SetRegister(VIP_CLKOUT_CNTL, 0x0); 727 SetRegister(VIP_HCOUNT, 0x0); 728 SetRegister(VIP_VCOUNT, 0x0); 729 SetRegister(VIP_DFCOUNT, 0x0); 730 #if 0 731 SetRegister(VIP_CLOCK_SEL_CNTL, 0x2b7); /* versus 0x237 <-> 0x2b7 */ 732 SetRegister(VIP_VIN_PLL_CNTL, 0x60a6039); 733 #endif 734 SetRegister(VIP_FRAME_LOCK_CNTL, 0x0); 735 } 736 737 void CTheater200::ResetTheatreRegsForTVout() 738 { 739 SetRegister(VIP_CLKOUT_CNTL, 0x29); 740 #if 1 741 SetRegister(VIP_HCOUNT, 0x1d1); 742 SetRegister(VIP_VCOUNT, 0x1e3); 743 #else 744 SetRegister(VIP_HCOUNT, 0x322); 745 SetRegister(VIP_VCOUNT, 0x151); 746 #endif 747 SetRegister(VIP_DFCOUNT, 0x01); 748 SetRegister(VIP_CLOCK_SEL_CNTL, 0x2b7); /* versus 0x237 <-> 0x2b7 */ 749 SetRegister(VIP_VIN_PLL_CNTL, 0x60a6039); 750 SetRegister(VIP_FRAME_LOCK_CNTL, 0x0f); 751 } 752 753 int32 CTheater200::DspSetVideostreamformat(int32 format) 754 { 755 int32 fb_scratch0 = 0; 756 int32 result; 757 758 fb_scratch0 = ((format << 8) & 0xff00) | (65 & 0xff); 759 result = DspSendCommand(0, fb_scratch0); 760 761 PRINT(("dsp_set_videostreamformat: %x\n", result)); 762 763 return result; 764 } 765 766 int32 CTheater200::DspGetSignalLockStatus() 767 { 768 int32 fb_scratch1 = 0; 769 int32 fb_scratch0 = 0; 770 int32 result; 771 772 fb_scratch0 = 0 | (77 & 0xff); 773 774 result = DspSendCommand(fb_scratch1, fb_scratch0); 775 776 PRINT(("dsp_get_signallockstatus: %x, h_pll: %x, v_pll: %x\n", \ 777 result, (result >> 8) & 0xff, (result >> 16) & 0xff)); 778 779 return result; 780 } 781 782 // disable/enable capturing 783 void CTheater200::SetEnable(bool enable, bool vbi) 784 { 785 786 PRINT(("CTheater200::SetEnable(%d, %d)\n", enable, vbi)); 787 788 if (enable) { 789 WaitVSYNC(); 790 791 SetADC(fStandard, fSource); 792 793 SetScaler(fStandard, fHActive, fVActive, fDeinterlace); 794 795 // Enable ADC block 796 SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_UP); 797 798 WaitVSYNC(); 799 800 // restore luminance and chroma settings 801 SetLuminanceLevels(fStandard, fBrightness, fContrast); 802 SetChromaLevels(fStandard, fSaturation, fHue); 803 } 804 } 805 806 void CTheater200::SetStandard(theater_standard standard, theater_source source) 807 { 808 PRINT(("CTheater200::SetStandard(%s, %s)\n", 809 "NTSC\0\0\0\0\0\0NTSC-J\0\0\0\0NTSC-443\0\0PAL-M\0\0\0\0\0" 810 "PAL-N\0\0\0\0\0PAL-NC\0\0\0\0PAL-BDGHI\0PAL-60\0\0\0\0" 811 "SECAM\0\0\0\0\0"+10*standard, 812 "TUNER\0COMP\0\0SVIDEO"+6*source)); 813 814 fStandard = standard; 815 fSource = source; 816 } 817 818 void CTheater200::SetSize(int hactive, int vactive) 819 { 820 PRINT(("CTheater200::SetSize(%d, %d)\n", hactive, vactive)); 821 822 fHActive = hactive; 823 fVActive = vactive; 824 } 825 826 void CTheater200::SetDeinterlace(bool deinterlace) 827 { 828 PRINT(("CTheater200::SetDeinterlace(%d)\n", deinterlace)); 829 830 fDeinterlace = deinterlace; 831 } 832 833 /* one assumes as sharpness is not used it's not supported */ 834 void CTheater200::SetSharpness(int sharpness) 835 { 836 int32 fb_scratch0 = 0; 837 int32 fb_scratch1 = 1; 838 int32 result; 839 840 PRINT(("CTheater200::SetSharpness(%d)\n", sharpness)); 841 842 fb_scratch0 = 0 | (73 & 0xff); 843 result = DspSendCommand(fb_scratch1, fb_scratch0); 844 } 845 846 void CTheater200::SetBrightness(int brightness) 847 { 848 PRINT(("CTheater200::SetBrightness(%d)\n", brightness)); 849 850 fBrightness = brightness; 851 SetLuminanceLevels(fStandard, fBrightness, fContrast); 852 } 853 854 void CTheater200::SetContrast(int contrast) 855 { 856 PRINT(("CTheater200::SetContrast(%d)\n", contrast)); 857 858 fContrast = contrast; 859 SetLuminanceLevels(fStandard, fBrightness, fContrast); 860 } 861 862 void CTheater200::SetSaturation(int saturation) 863 { 864 PRINT(("CTheater200::SetSaturation(%d)\n", saturation)); 865 866 fSaturation = saturation; 867 SetChromaLevels(fStandard, fSaturation, fHue); 868 } 869 870 void CTheater200::SetHue(int hue) 871 { 872 PRINT(("CTheater200::SetHue(%d)\n", hue)); 873 874 fHue = hue; 875 SetChromaLevels(fStandard, fSaturation, fHue); 876 } 877 878 // setup analog-digital converter 879 void CTheater200::SetADC(theater_standard standard, theater_source source) 880 { 881 uint32 fb_scratch0 = 0; 882 uint32 result; 883 uint32 data = 0; 884 885 PRINT(("CTheater200::SetADC(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); 886 887 // set HW_DEBUG before setting the standard 888 SetRegister(VIP_HW_DEBUG, 0x0000f000); 889 890 // select the video standard 891 switch (standard) { 892 case C_THEATER_NTSC: 893 case C_THEATER_NTSC_JAPAN: 894 case C_THEATER_NTSC_443: 895 case C_THEATER_PAL_M: 896 // SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_NTSC); 897 // break; 898 case C_THEATER_PAL_BDGHI: 899 case C_THEATER_PAL_N: 900 case C_THEATER_PAL_60: 901 case C_THEATER_PAL_NC: 902 // SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_PAL); 903 // break; 904 case C_THEATER_SECAM: 905 // SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_SECAM); 906 fb_scratch0 = ((standard << 8) & 0xff00) | (52 & 0xff); 907 result = DspSendCommand(0, fb_scratch0); 908 break; 909 default: 910 PRINT(("CTheater200::SetADC() - Bad standard\n")); 911 return; 912 } 913 914 Register(VIP_GPIO_CNTL, data); 915 PRINT(("VIP_GPIO_CNTL: %x\n", data)); 916 917 Register(VIP_GPIO_INOUT, data); 918 PRINT(("VIP_GPIO_INOUT: %x\n", data)); 919 920 // select input connector and Y/C mode 921 switch (source) { 922 case C_THEATER_TUNER: 923 // set video input connector 924 fb_scratch0 = ((fTunerPort << 8) & 0xff00) | (55 & 0xff); 925 DspSendCommand(0, fb_scratch0); 926 927 /* this is to set the analog mux used for sond */ 928 Register(VIP_GPIO_CNTL, data); 929 data &= ~0x10; 930 SetRegister(VIP_GPIO_CNTL, data); 931 932 Register(VIP_GPIO_INOUT, data); 933 data &= ~0x10; 934 SetRegister(VIP_GPIO_INOUT, data); 935 break; 936 case C_THEATER_COMPOSITE: 937 // set video input connector 938 fb_scratch0 = ((fCompositePort << 8) & 0xff00) | (55 & 0xff); 939 DspSendCommand(0, fb_scratch0); 940 941 /* this is to set the analog mux used for sond */ 942 Register(VIP_GPIO_CNTL, data); 943 data |= 0x10; 944 SetRegister(VIP_GPIO_CNTL, data); 945 946 Register(VIP_GPIO_INOUT, data); 947 data |= 0x10; 948 SetRegister(VIP_GPIO_INOUT, data); 949 break; 950 case C_THEATER_SVIDEO: 951 // set video input connector 952 fb_scratch0 = ((fSVideoPort << 8) & 0xff00) | (55 & 0xff); 953 DspSendCommand(0, fb_scratch0); 954 955 /* this is to set the analog mux used for sond */ 956 Register(VIP_GPIO_CNTL, data); 957 data |= 0x10; 958 SetRegister(VIP_GPIO_CNTL, data); 959 960 Register(VIP_GPIO_INOUT, data); 961 data |= 0x10; 962 SetRegister(VIP_GPIO_INOUT, data); 963 break; 964 default: 965 PRINT(("CTheater200::SetADC() - Bad source\n")); 966 return; 967 } 968 969 970 Register(VIP_GPIO_CNTL, data); 971 PRINT(("VIP_GPIO_CNTL: %x\n", data)); 972 973 Register(VIP_GPIO_INOUT, data); 974 PRINT(("VIP_GPIO_INOUT: %x\n", data)); 975 976 977 DspConfigureI2SPort(0, 0, 0); 978 DspConfigureSpdifPort(0); 979 980 /*dsp_audio_detection(t, 0);*/ 981 DspAudioMute(1, 1); 982 DspSetAudioVolume(128, 128, 0); 983 984 } 985 986 // wait until horizontal scaler is locked 987 void CTheater200::WaitHSYNC() 988 { 989 for (int timeout = 0; timeout < 1000; timeout++) { 990 if (Register(VIP_HS_PULSE_WIDTH, HS_GENLOCKED) != 0) 991 return; 992 snooze(20); 993 } 994 PRINT(("CTheater200::WaitHSYNC() - wait for HSync locking time out!\n")); 995 } 996 997 998 999 // wait until a visible line is viewed 1000 void CTheater200::WaitVSYNC() 1001 { 1002 for (int timeout = 0; timeout < 1000; timeout++) { 1003 int lineCount = CurrentLine(); 1004 if (lineCount > 1 && lineCount < 20) 1005 return; 1006 snooze(20); 1007 } 1008 PRINT(("CTheater200::WaitVSYNC() - wait for VBI timed out!\n")); 1009 } 1010 1011 // setup brightness and contrast 1012 void CTheater200::SetLuminanceLevels(theater_standard standard, int brightness, int contrast) 1013 { 1014 1015 int32 fb_scratch1 = 0; 1016 int32 fb_scratch0 = 0; 1017 int32 result; 1018 1019 /* set luminance processor constrast */ 1020 fb_scratch0 = ((contrast << 8) & 0xff00) | (71 & 0xff); 1021 result = DspSendCommand(fb_scratch1, fb_scratch0); 1022 PRINT(("dsp_set_contrast: %x\n", result)); 1023 1024 /* set luminance processor brightness */ 1025 fb_scratch0 = ((brightness << 8) & 0xff00) | (67 & 0xff); 1026 DspSendCommand(fb_scratch1, fb_scratch0); 1027 PRINT(("dsp_set_brightness: %x\n", result)); 1028 1029 } 1030 1031 // set colour saturation and hue. 1032 // hue makes sense for NTSC only and seems to act as saturation for PAL 1033 void CTheater200::SetChromaLevels(theater_standard standard, int saturation, int hue) 1034 { 1035 1036 int32 fb_scratch1 = 0; 1037 int32 fb_scratch0 = 0; 1038 1039 // Set Hue 1040 fb_scratch0 = ((hue << 8) & 0xff00) | (75 & 0xff); 1041 DspSendCommand(fb_scratch1, fb_scratch0); 1042 1043 // Set Saturation 1044 fb_scratch0 = ((saturation << 8) & 0xff00) | (69 & 0xff); 1045 DspSendCommand(fb_scratch1, fb_scratch0); 1046 1047 PRINT(("dsp_set_saturation: %x\n", saturation)); 1048 PRINT(("dsp_set_tint: %x\n", hue)); 1049 } 1050 1051 1052 // these values are used by scaler as well 1053 static const uint16 h_active_start[] = { 1054 0x06b, 0x06B, 0x07E, 0x067, 0x09A, 0x07D, 0x09A, 0x084, 0x095 }; 1055 static const uint16 h_active_end[] = { 1056 0x363, 0x363, 0x42A, 0x363, 0x439, 0x439, 0x439, 0x363, 0x439 }; 1057 static const uint16 v_active_start[] = { 1058 0x025, 0x025, 0x025, 0x025, 0x02E, 0x02E, 0x02E, 0x025, 0x02E }; 1059 // PAL height is too small (572 instead of 576 lines), but changing 0x269 to 0x26d 1060 // leads to trouble, and the last 2 lines seem to be used for VBI data 1061 // (read: garbage) anyway 1062 static const uint16 v_active_end[] = { 1063 0x204, 0x204, 0x204, 0x204, 0x269, 0x269, 0x269, 0x204, 0x269 }; 1064 static const uint16 h_vbi_wind_start[] = { 1065 0x064, 0x064, 0x064, 0x064, 0x084, 0x084, 0x084, 0x064, 0x084 }; 1066 static const uint16 h_vbi_wind_end[] = { 1067 0x366, 0x366, 0x366, 0x366, 0x41F, 0x41F, 0x41F, 0x366, 0x41F }; 1068 static const uint16 v_vbi_wind_start[] = { 1069 0x00b, 0x00b, 0x00b, 0x00b, 0x008, 0x008, 0x008, 0x00b, 0x008 }; 1070 static const uint16 v_vbi_wind_end[] = { 1071 0x024, 0x024, 0x024, 0x024, 0x02d, 0x02d, 0x02d, 0x024, 0x02d }; 1072 1073 1074 void CTheater200::getActiveRange( theater_standard standard, CRadeonRect &rect ) 1075 { 1076 1077 rect.SetTo( 1078 h_active_start[standard], v_active_start[standard], 1079 h_active_end[standard], v_active_end[standard] ); 1080 1081 } 1082 1083 void CTheater200::getVBIRange( theater_standard standard, CRadeonRect &rect ) 1084 { 1085 1086 rect.SetTo( 1087 h_vbi_wind_start[standard], v_vbi_wind_start[standard], 1088 h_vbi_wind_end[standard], v_vbi_wind_end[standard] ); 1089 1090 } 1091 1092 // setup capture scaler. 1093 void CTheater200::SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace) 1094 { 1095 1096 int32 fb_scratch1 = 0; 1097 int32 fb_scratch0 = 0; 1098 int oddOffset, evenOffset; 1099 uint16 h_active_width, v_active_height; 1100 1101 // ASSERT(vactive <= 511); 1102 1103 // TK: Gatos uses different values here 1104 h_active_width = h_active_end[standard] - h_active_start[standard] + 1; 1105 v_active_height = v_active_end[standard] - v_active_start[standard] + 1; 1106 1107 // for PAL, we have 572 lines only, but need 576 lines; 1108 // my attempts to find those missing lines all failed, so if the application requests 1109 // 576 lines, we had to upscale the video which is not supported by hardware; 1110 // solution: restrict to 572 lines - the scaler will fill out the missing lines with black 1111 if( vactive > v_active_height ) 1112 vactive = v_active_height; 1113 1114 if (deinterlace) { 1115 // progressive scan 1116 evenOffset = oddOffset = 512 - (int) ((512 * vactive) / v_active_height); 1117 } 1118 else { 1119 // interlaced 1120 evenOffset = (int) ((512 * vactive) / v_active_height); 1121 oddOffset = 2048 - evenOffset; 1122 } 1123 1124 // Set Horizontal Size 1125 fb_scratch0 = ((h_active_width << 8) & 0x00ffff00) | (195 & 0xff); 1126 fb_scratch1 = ((h_active_end[standard] << 16) & 0xffff0000) | (h_active_start[standard] & 0xffff); 1127 DspSendCommand(fb_scratch1, fb_scratch0); 1128 1129 // Set Vertical Size 1130 fb_scratch0 = ((v_active_height << 8) & 0x00ffff00) | (196 & 0xff); 1131 fb_scratch1 = ((v_active_end[standard] << 16) & 0xffff0000) | (v_active_start[standard] + 1 & 0xffff); 1132 DspSendCommand(fb_scratch1, fb_scratch0); 1133 } 1134 1135 int32 CTheater200::DspAudioMute(int8 left, int8 right) 1136 { 1137 int32 fb_scratch1 = 0; 1138 int32 fb_scratch0 = 0; 1139 int32 result; 1140 1141 fb_scratch0 = ((right << 16) & 0xff0000) | ((left << 8) & 0xff00) | (21 & 0xff); 1142 result = DspSendCommand(fb_scratch1, fb_scratch0); 1143 1144 PRINT(("dsp_audio_mute: %x\n", result)); 1145 1146 return result; 1147 } 1148 1149 int32 CTheater200::DspSetAudioVolume(int8 left, int8 right, int8 auto_mute) 1150 { 1151 int32 fb_scratch1 = 0; 1152 int32 fb_scratch0 = 0; 1153 int32 result; 1154 1155 fb_scratch0 = ((auto_mute << 24) & 0xff000000) 1156 | ((right << 16) & 0xff0000) 1157 | ((left << 8) & 0xff00) | (22 & 0xff); 1158 result = DspSendCommand(fb_scratch1, fb_scratch0); 1159 1160 PRINT(("dsp_set_audio_volume: %x\n", result)); 1161 1162 return result; 1163 } 1164 1165 int32 CTheater200::DspConfigureI2SPort(int8 tx_mode, int8 rx_mode, int8 clk_mode) 1166 { 1167 int32 fb_scratch1 = 0; 1168 int32 fb_scratch0 = 0; 1169 int32 result; 1170 1171 fb_scratch0 = ((clk_mode << 24) & 0xff000000) | ((rx_mode << 16) & 0xff0000) 1172 | ((tx_mode << 8) & 0xff00) | (40 & 0xff); 1173 1174 result = DspSendCommand(fb_scratch1, fb_scratch0); 1175 1176 PRINT(("dsp_configure_i2s_port: %x\n", result)); 1177 1178 return result; 1179 } 1180 1181 int32 CTheater200::DspConfigureSpdifPort(int8 state) 1182 { 1183 int32 fb_scratch1 = 0; 1184 int32 fb_scratch0 = 0; 1185 int32 result; 1186 1187 fb_scratch0 = ((state << 8) & 0xff00) | (41 & 0xff); 1188 1189 result = DspSendCommand(fb_scratch1, fb_scratch0); 1190 1191 PRINT(("dsp_configure_spdif_port: %x\n", result)); 1192 1193 return result; 1194 } 1195 1196 int CTheater200::ReadFifo( uint32 address, uint8 *buffer) 1197 { 1198 return fPort.ReadFifo(fDevice, address, 1, buffer); 1199 } 1200 1201 int CTheater200::WriteFifo( uint32 address, uint32 count, uint8 *buffer) 1202 { 1203 return fPort.WriteFifo(fDevice, address, count, buffer); 1204 } 1205 1206 int CTheater200::CurrentLine() 1207 { 1208 // return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT; 1209 int32 fb_scratch1 = 0; 1210 int32 fb_scratch0 = 0; 1211 int32 result; 1212 1213 fb_scratch0 = 0 | (78 & 0xff); 1214 result = DspSendCommand(fb_scratch1, fb_scratch0); 1215 1216 PRINT(("dsp_get_signallinenumber: %x, linenum: %x\n", \ 1217 result, (result >> 8) & 0xffff)); 1218 1219 return result; 1220 1221 } 1222 1223 void CTheater200::PrintToStream() 1224 { 1225 PRINT(("<<< Rage Theater Registers >>>\n")); 1226 /*for (int index = 0x0400; index <= 0x06ff; index += 4) { 1227 int value = Register(index); 1228 PRINT(("REG_0x%04x = 0x%08x\n", index, value)); 1229 } */ 1230 } 1231