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 "TheatreReg.h" 14 #include "lendian_bitfield.h" 15 16 17 CTheater::CTheater(CRadeon & radeon) 18 : fPort(radeon), 19 fDevice(0), 20 fClock(C_RADEON_NO_VIDEO_CLOCK), 21 fTunerPort(0), 22 fCompositePort(0), 23 fSVideoPort(0), 24 fStandard(C_THEATER_NTSC), 25 fSource(C_THEATER_TUNER), 26 fBrightness(0), 27 fContrast(0), 28 fSaturation(0), 29 fHue(0), 30 fDeinterlace(true) 31 { 32 PRINT(("CTheater::CTheater()\n")); 33 34 if( fPort.InitCheck() == B_OK ) { 35 radeon_video_tuner tuner; 36 radeon_video_decoder video; 37 38 radeon.GetMMParameters(tuner, video, fClock, 39 fTunerPort, fCompositePort, fSVideoPort); 40 41 if (fClock != C_RADEON_VIDEO_CLOCK_29_49892_MHZ && 42 fClock != C_RADEON_VIDEO_CLOCK_27_00000_MHZ) 43 PRINT(("CTheater::CTheater() - Unsupported crystal clock!\n")); 44 45 fDevice = fPort.FindVIPDevice( 46 (C_THEATER_VIP_VENDOR_ID << 0) | 47 (C_THEATER_VIP_DEVICE_ID << 16)); 48 } 49 if( InitCheck() != B_OK ) 50 PRINT(("CTheater::CTheater() - Rage Theater not found!\n")); 51 } 52 53 CTheater::~CTheater() 54 { 55 PRINT(("CTheater::~CTheater()\n")); 56 57 if( InitCheck() == B_OK ) 58 SetEnable(false, false); 59 } 60 61 status_t CTheater::InitCheck() const 62 { 63 status_t res; 64 65 res = fPort.InitCheck(); 66 if( res != B_OK ) 67 return res; 68 69 return (fDevice >= C_VIP_PORT_DEVICE_0 && fDevice <= C_VIP_PORT_DEVICE_3) ? B_OK : B_ERROR; 70 } 71 72 void CTheater::Reset() 73 { 74 PRINT(("CTheater::Reset()\n")); 75 76 SetHue(0); 77 SetBrightness(0); 78 SetSaturation(0); 79 SetContrast(0); 80 SetSharpness(false); 81 } 82 83 // disable/enable capturing 84 void CTheater::SetEnable(bool enable, bool vbi) 85 { 86 PRINT(("CTheater::SetEnable(%d, %d)\n", enable, vbi)); 87 88 #if 0 89 //@ reset ADC? 90 SetRegister(VIP_ADC_CNTL, ADC_CPRESET, ADC_CPRESET); 91 snooze(1000); 92 SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0); 93 snooze(1000); 94 SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_DOWN); 95 #endif 96 97 98 WaitVSYNC(); 99 100 /* Disable the Video In, Scaler and DVS port */ 101 SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, VIN_ASYNC_RST); 102 SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, DVS_ASYNC_RST); 103 104 /* select the reference clock for the Video In */ 105 SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK); 106 107 /* reset the VIN/L54 PLL clocks */ 108 SetRegister(VIP_PLL_CNTL1, VINRST, VINRST); 109 SetRegister(VIP_PLL_CNTL1, L54RST, L54RST); 110 111 /* power down the ADC block */ 112 SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN); 113 114 /* set DVS port to input mode */ 115 SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_INPUT); 116 117 /* select DVS clock to 8xFsc and disable continuous mode */ 118 SetRegister(VIP_DVS_PORT_CTRL, DVS_CLK_SELECT, DVS_CLK_SELECT_8X); 119 SetRegister(VIP_DVS_PORT_CTRL, CONTINUOUS_STREAM, 0); 120 121 if (enable) { 122 WaitVSYNC(); 123 124 SetClock(fStandard, fClock); 125 SetADC(fStandard, fSource); 126 SetLuminanceProcessor(fStandard); 127 SetChromaProcessor(fStandard); 128 SetVSYNC(fStandard); 129 SetClipWindow(fStandard, vbi); 130 SetCombFilter(fStandard, fSource); 131 SetHSYNC(fStandard); 132 SetSyncGenerator(fStandard); 133 SetScaler(fStandard, fHActive, fVActive, fDeinterlace); 134 135 /* Enable ADC block */ 136 SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_UP); 137 138 WaitVSYNC(); 139 140 /* Enable the Video In, Scaler and DVS port */ 141 SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, 0); 142 SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, 0); 143 144 /* set DVS port to output mode */ 145 SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_OUTPUT); 146 147 //WaitHSYNC(); 148 149 /* restore luminance and chroma settings */ 150 SetLuminanceLevels(fStandard, fBrightness, fContrast); 151 SetChromaLevels(fStandard, fSaturation, fHue); 152 } 153 } 154 155 void CTheater::SetStandard(theater_standard standard, theater_source source) 156 { 157 PRINT(("CTheater::SetStandard(%s, %s)\n", 158 "NTSC\0\0\0\0\0\0NTSC-J\0\0\0\0NTSC-443\0\0PAL-M\0\0\0\0\0" 159 "PAL-N\0\0\0\0\0PAL-NC\0\0\0\0PAL-BDGHI\0PAL-60\0\0\0\0" 160 "SECAM\0\0\0\0\0"+10*standard, 161 "TUNER\0COMP\0\0SVIDEO"+6*source)); 162 163 fStandard = standard; 164 fSource = source; 165 } 166 167 void CTheater::SetSize(int hactive, int vactive) 168 { 169 PRINT(("CTheater::SetSize(%d, %d)\n", hactive, vactive)); 170 171 fHActive = hactive; 172 fVActive = vactive; 173 } 174 175 void CTheater::SetDeinterlace(bool deinterlace) 176 { 177 PRINT(("CTheater::SetDeinterlace(%d)\n", deinterlace)); 178 179 fDeinterlace = deinterlace; 180 } 181 182 void CTheater::SetSharpness(int sharpness) 183 { 184 PRINT(("CTheater::SetSharpness(%d)\n", sharpness)); 185 186 SetRegister(VIP_H_SCALER_CONTROL, H_SHARPNESS, sharpness << 25); 187 } 188 189 void CTheater::SetBrightness(int brightness) 190 { 191 PRINT(("CTheater::SetBrightness(%d)\n", brightness)); 192 193 fBrightness = brightness; 194 SetLuminanceLevels(fStandard, fBrightness, fContrast); 195 } 196 197 void CTheater::SetContrast(int contrast) 198 { 199 PRINT(("CTheater::SetContrast(%d)\n", contrast)); 200 201 fContrast = contrast; 202 SetLuminanceLevels(fStandard, fBrightness, fContrast); 203 } 204 205 void CTheater::SetSaturation(int saturation) 206 { 207 PRINT(("CTheater::SetSaturation(%d)\n", saturation)); 208 209 fSaturation = saturation; 210 SetChromaLevels(fStandard, fSaturation, fHue); 211 } 212 213 void CTheater::SetHue(int hue) 214 { 215 PRINT(("CTheater::SetHue(%d)\n", hue)); 216 217 fHue = hue; 218 SetChromaLevels(fStandard, fSaturation, fHue); 219 } 220 221 222 // set pixel clock 223 void CTheater::SetClock(theater_standard standard, radeon_video_clock clock) 224 { 225 // set VIN PLL clock dividers 226 int referenceDivider, feedbackDivider, postDivider; 227 228 switch (standard) { 229 case C_THEATER_NTSC: 230 case C_THEATER_NTSC_JAPAN: 231 if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { 232 referenceDivider = 0x39; 233 feedbackDivider = 0x14c; 234 postDivider = 0x6; 235 } 236 else { 237 referenceDivider = 0x0b; 238 feedbackDivider = 0x46; 239 postDivider = 0x6; 240 } 241 break; 242 case C_THEATER_NTSC_443: 243 if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { 244 referenceDivider = 0x23; 245 feedbackDivider = 0x88; 246 postDivider = 0x7; 247 } 248 else { 249 referenceDivider = 0x2c; 250 feedbackDivider = 0x121; 251 postDivider = 0x5; 252 } 253 break; 254 case C_THEATER_PAL_M: 255 if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { 256 referenceDivider = 0x2c; 257 feedbackDivider = 0x12b; 258 postDivider = 0x7; 259 } 260 else { 261 referenceDivider = 0x0b; 262 feedbackDivider = 0x46; 263 postDivider = 0x6; 264 } 265 break; 266 case C_THEATER_PAL_BDGHI: 267 case C_THEATER_PAL_N: 268 case C_THEATER_PAL_60: 269 case C_THEATER_SECAM: 270 if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { 271 referenceDivider = 0x0e; 272 feedbackDivider = 0x65; 273 postDivider = 0x6; 274 } 275 else { 276 referenceDivider = 0x2c; 277 feedbackDivider = 0x121; 278 postDivider = 0x5; 279 } 280 break; 281 case C_THEATER_PAL_NC: 282 if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) { 283 referenceDivider = 0x23; 284 feedbackDivider = 0x88; 285 postDivider = 0x7; 286 } 287 else { 288 referenceDivider = 0x37; 289 feedbackDivider = 0x1d3; 290 postDivider = 0x8; 291 } 292 break; 293 default: 294 PRINT(("CTheater::SetClock() - Bad standard\n")); 295 return; 296 } 297 298 // reset VIN PLL and select the reference clock 299 SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK); 300 SetRegister(VIP_PLL_CNTL1, VINRST, VINRST); 301 SetRegister(VIP_PLL_CNTL1, L54RST, L54RST); 302 303 // set up the VIN PLL clock control 304 SetRegister(VIP_VIN_PLL_CNTL, VIN_M0, referenceDivider << 0); 305 SetRegister(VIP_VIN_PLL_CNTL, VIN_N0, feedbackDivider << 11); 306 SetRegister(VIP_VIN_PLL_CNTL, VIN_P, postDivider << 24); 307 308 // active the VIN/L54 PLL and attach the VIN PLL to the VIN clock 309 SetRegister(VIP_PLL_CNTL1, VINRST, 0); 310 SetRegister(VIP_PLL_CNTL1, L54RST, 0); 311 SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_VIPLL_CLK); 312 313 PRINT(("CTheater::SetClock(Fsamp=%g, Fref=%g)\n", 314 ((fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0) * feedbackDivider) / (referenceDivider * postDivider), 315 (fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0))); 316 } 317 318 319 // setup analog-digital converter 320 void CTheater::SetADC(theater_standard standard, theater_source source) 321 { 322 PRINT(("CTheater::SetADC(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); 323 324 // set HW_DEBUG before setting the standard 325 SetRegister(VIP_HW_DEBUG, 0x0000f000); 326 327 // select the video standard 328 switch (standard) { 329 case C_THEATER_NTSC: 330 case C_THEATER_NTSC_JAPAN: 331 case C_THEATER_NTSC_443: 332 case C_THEATER_PAL_M: 333 SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_NTSC); 334 break; 335 case C_THEATER_PAL_BDGHI: 336 case C_THEATER_PAL_N: 337 case C_THEATER_PAL_60: 338 case C_THEATER_PAL_NC: 339 SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_PAL); 340 break; 341 case C_THEATER_SECAM: 342 SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_SECAM); 343 break; 344 default: 345 PRINT(("CTheater::SetADC() - Bad standard\n")); 346 return; 347 } 348 349 // select input connector and Y/C mode 350 switch (source) { 351 case C_THEATER_TUNER: 352 SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fTunerPort); 353 SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE); 354 break; 355 case C_THEATER_COMPOSITE: 356 SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fCompositePort); 357 SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE); 358 break; 359 case C_THEATER_SVIDEO: 360 SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fSVideoPort); 361 SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_SVIDEO); 362 break; 363 default: 364 PRINT(("CTheater::SetADC() - Bad source\n")); 365 return; 366 } 367 368 SetRegister(VIP_ADC_CNTL, I_CLAMP_SEL, I_CLAMP_SEL_22); 369 SetRegister(VIP_ADC_CNTL, I_AGC_SEL, I_AGC_SEL_7); 370 371 SetRegister(VIP_ADC_CNTL, EXT_CLAMP_CAP, EXT_CLAMP_CAP_EXTERNAL); 372 SetRegister(VIP_ADC_CNTL, EXT_AGC_CAP, EXT_AGC_CAP_EXTERNAL); 373 SetRegister(VIP_ADC_CNTL, ADC_DECI_BYPASS, ADC_DECI_WITH_FILTER); 374 SetRegister(VIP_ADC_CNTL, VBI_DECI_BYPASS, VBI_DECI_WITH_FILTER); 375 SetRegister(VIP_ADC_CNTL, DECI_DITHER_EN, 0 << 12); 376 SetRegister(VIP_ADC_CNTL, ADC_CLK_SEL, ADC_CLK_SEL_8X); 377 SetRegister(VIP_ADC_CNTL, ADC_BYPASS, ADC_BYPASS_INTERNAL); 378 switch (standard) { 379 case C_THEATER_NTSC: 380 case C_THEATER_NTSC_JAPAN: 381 case C_THEATER_NTSC_443: 382 case C_THEATER_PAL_M: 383 SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_NTSC); 384 break; 385 case C_THEATER_PAL_BDGHI: 386 case C_THEATER_PAL_N: 387 case C_THEATER_PAL_60: 388 case C_THEATER_PAL_NC: 389 case C_THEATER_SECAM: 390 SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_PAL); 391 break; 392 } 393 SetRegister(VIP_ADC_CNTL, ADC_PAICM, 1 << 18); 394 395 SetRegister(VIP_ADC_CNTL, ADC_PDCBIAS, 2 << 20); 396 SetRegister(VIP_ADC_CNTL, ADC_PREFHI, ADC_PREFHI_2_7); 397 SetRegister(VIP_ADC_CNTL, ADC_PREFLO, ADC_PREFLO_1_5); 398 399 SetRegister(VIP_ADC_CNTL, ADC_IMUXOFF, 0 << 26); 400 SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0 << 27); 401 } 402 403 404 // setup horizontal sync PLL 405 void CTheater::SetHSYNC(theater_standard standard) 406 { 407 static const uint16 hs_line_total[] = { 408 0x38E, 0x38E, 0x46F, 0x38D, 0x46F, 0x395, 0x46F, 0x467, 0x46F }; 409 410 static const uint32 hs_dto_inc[] = { 411 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x3E7A2 }; 412 413 // TK: completely different in gatos 414 static const uint8 hs_pll_sgain[] = { 415 2, 2, 2, 2, 2, 2, 2, 2, 2 }; 416 static const uint8 hs_pll_fgain[] = { 417 8, 8, 8, 8, 8, 8, 8, 8, 8 }; 418 419 static const uint8 gen_lock_delay[] = { 420 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }; 421 422 static const uint8 min_pulse_width[] = { 423 0x21, 0x21, 0x29, 0x21, 0x29, 0x21, 0x29, 0x29, 0x29 }; 424 static const uint8 max_pulse_width[] = { 425 0x64, 0x64, 0x7D, 0x64, 0x7D, 0x65, 0x7D, 0x7D, 0x7D }; 426 427 static const uint16 win_close_limit[] = { 428 0x0A0, 0x0A0, 0x0C7, 0x0A0, 0x0C7, 0x0A0, 0x0C7, 0x0C7, 0x0C7 }; 429 static const uint16 win_open_limit[] = { 430 0x1B7, 0x1B7, 0x228, 0x1B7, 0x228, 0x1BB, 0x228, 0x224, 0x228 }; 431 432 433 // set number of samples per line 434 SetRegister(VIP_HS_PLINE, HS_LINE_TOTAL, hs_line_total[standard]); 435 436 SetRegister(VIP_HS_DTOINC, HS_DTO_INC, hs_dto_inc[standard]); 437 438 SetRegister(VIP_HS_PLLGAIN, HS_PLL_SGAIN, hs_pll_sgain[standard] << 0); 439 SetRegister(VIP_HS_PLLGAIN, HS_PLL_FGAIN, (uint32)hs_pll_fgain[standard] << 4); 440 441 SetRegister(VIP_HS_GENLOCKDELAY, GEN_LOCK_DELAY, gen_lock_delay[standard]); 442 443 // set min/max pulse width in samples 444 SetRegister(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH, min_pulse_width[standard] << 0); 445 SetRegister(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH, (uint32)max_pulse_width[standard] << 8); 446 447 SetRegister(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT, win_close_limit[standard] << 0); 448 SetRegister(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT, (uint32)win_open_limit[standard] << 16); 449 450 451 PRINT(("CTheater::SetHSYNC(total=%d, pulse=%d/%d, window=%d/%d)\n", 452 Register(VIP_HS_PLINE, HS_LINE_TOTAL), 453 Register(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH) >> 0, 454 Register(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH) >> 8, 455 Register(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT) >> 0, 456 Register(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT) >> 16)); 457 } 458 459 460 // wait until horizontal scaler is locked 461 void CTheater::WaitHSYNC() 462 { 463 for (int timeout = 0; timeout < 1000; timeout++) { 464 if (Register(VIP_HS_PULSE_WIDTH, HS_GENLOCKED) != 0) 465 return; 466 snooze(20); 467 } 468 PRINT(("CTheater::WaitHSYNC() - wait for HSync locking time out!\n")); 469 } 470 471 472 // setup vertical sync and field detector 473 void CTheater::SetVSYNC(theater_standard standard) 474 { 475 static const uint16 vsync_int_trigger[] = { 476 0x2AA, 0x2AA, 0x353, 0x2AA, 0x353, 0x2B0, 0x353, 0x34D, 0x353 }; 477 static const uint16 vsync_int_hold[] = { 478 0x017, 0x017, 0x01C, 0x017, 0x01C, 0x017, 0x01C, 0x01C, 0x01C }; 479 // PAL value changed from 26b to 26d - else, odd/even field detection fails sometimes; 480 // did the same for PAL N, PAL NC and SECAM 481 static const uint16 vs_field_blank_start[] = { 482 0x206, 0x206, 0x206, 0x206, 0x26d, 0x26d, 0x26d, 0x206, 0x26d }; 483 static const uint8 vs_field_blank_end[] = { 484 0x00a, 0x00a, 0x00a, 0x00a, 0x02a, 0x02a, 0x02a, 0x00a, 0x02a }; 485 // NTSC value changed from 1 to 105 - else, odd/even fields were always swapped; 486 // did the same for NTSC Japan, NTSC 443, PAL M and PAL 60 487 static const uint16 vs_field_id_location[] = { 488 0x105, 0x105, 0x105, 0x105, 0x1, 0x1, 0x1, 0x105, 0x1 }; 489 static const uint16 vs_frame_total[] = { 490 0x217, 0x217, 0x217, 0x217, 0x27B, 0x27B, 0x27B, 0x217, 0x27B }; 491 492 SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_TRIGGER, vsync_int_trigger[standard] << 0); 493 SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_HOLD, (uint32)vsync_int_hold[standard] << 16); 494 495 SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_START, vs_field_blank_start[standard] << 0); 496 SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_END, (uint32)vs_field_blank_end[standard] << 16); 497 SetRegister(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL, vs_frame_total[standard]); 498 499 SetRegister(VIP_VS_FIELD_ID_CNTL, VS_FIELD_ID_LOCATION, vs_field_id_location[standard] << 0); 500 501 // auto-detect fields 502 SetRegister(VIP_VS_COUNTER_CNTL, FIELD_DETECT_MODE, FIELD_DETECT_DETECTED); 503 504 // don't flip fields 505 SetRegister(VIP_VS_COUNTER_CNTL, FIELD_FLIP_EN, 0 ); 506 507 PRINT(("CTheater::SetVSYNC(total=%d)\n", 508 Register(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL))); 509 } 510 511 // wait until a visible line is viewed 512 void CTheater::WaitVSYNC() 513 { 514 for (int timeout = 0; timeout < 1000; timeout++) { 515 int lineCount = Register(VIP_VS_LINE_COUNT, VS_LINE_COUNT); 516 if (lineCount > 1 && lineCount < 20) 517 return; 518 snooze(20); 519 } 520 PRINT(("CTheater::WaitVSYNC() - wait for VBI timed out!\n")); 521 } 522 523 524 // setup timing generator 525 void CTheater::SetSyncGenerator(theater_standard standard) 526 { 527 static const uint16 blank_int_start[] = { 528 0x031, 0x031, 0x046, 0x031, 0x046, 0x046, 0x046, 0x031, 0x046 }; 529 static const uint8 blank_int_length[] = { 530 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; 531 532 static const uint16 sync_tip_start[] = { 533 0x0372, 0x0372, 0x0453, 0x0371, 0x0453, 0x0379, 0x0453, 0x044B, 0x0453 }; 534 static const uint8 sync_tip_length[] = { 535 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; 536 537 static const uint8 uv_int_start[] = { 538 0x03B, 0x03B, 0x052, 0x03B, 0x052, 0x03B, 0x052, 0x03C, 0x068 }; 539 static const uint8 u_int_length[] = { 540 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; 541 static const uint8 v_int_length[] = { 542 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }; 543 544 // set blank interrupt position 545 SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_START, blank_int_start[standard] ); 546 SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH, (uint32)blank_int_length[standard] << 8); 547 548 SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START, sync_tip_start[standard]); 549 SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH, (uint32)sync_tip_length[standard] << 12); 550 551 SetRegister(VIP_SG_UVGATE_GATE, UV_INT_START, uv_int_start[standard] << 0); 552 553 SetRegister(VIP_SG_UVGATE_GATE, U_INT_LENGTH, (uint32)u_int_length[standard] << 8); 554 SetRegister(VIP_SG_UVGATE_GATE, V_INT_LENGTH, (uint32)v_int_length[standard] << 12); 555 556 PRINT(("CTheater::SetSyncGenerator(black=%d/%d, synctip=%d/%d, uvgate=%d/%d-%d)\n", 557 Register(VIP_SG_BLACK_GATE, BLANK_INT_START) >> 0, 558 Register(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH) >> 8, 559 Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START), 560 Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH) >> 12, 561 Register(VIP_SG_UVGATE_GATE, UV_INT_START), 562 Register(VIP_SG_UVGATE_GATE, U_INT_LENGTH) >> 8, 563 Register(VIP_SG_UVGATE_GATE, V_INT_LENGTH) >> 12)); 564 } 565 566 567 // setup input comb filter. 568 // this is really ugly but I cannot find a scheme 569 void CTheater::SetCombFilter(theater_standard standard, theater_source source) 570 { 571 enum { 572 _3Tap_2D_adaptive_Comb = 1, // composite 573 _2Tap_C_combed_Y_Sub = 2, 574 _2Tap_C_combed_Y_combed = 3, 575 _3Tap_C_combed_Y_Sub = 4, 576 _3Tap_C_combed_Y_combed = 5, 577 YC_mode_Comb_filter_off = 6, // S-Video 578 YC_mode_2Tap_YV_filter = 7, 579 YC_mode_3Tap_YV_filter = 8 580 }; 581 582 // make sure to keep bitfield in sync with register definition! 583 // we could define each component as an uint8, but this would waste space 584 // and would require an extra register-composition 585 typedef struct { 586 LBITFIELD32_12 ( 587 comb_hck : 8, 588 comb_vck : 8, 589 comb_filter_en : 1, 590 comb_adaptiv_en : 1, 591 comb_bpfmuxsel : 3, 592 comb_coutsel : 2, 593 comb_sumdiff0sel : 1, 594 comb_sumdiff1sel : 2, 595 comb_yvlpfsel : 1, 596 comb_dlylinesel : 2, 597 comb_ydlyinsel : 2, 598 comb_ysubbw : 1 599 ); 600 } comb_cntl0; 601 602 typedef struct { 603 LBITFIELD32_7 ( 604 comb_ydlyoutsel : 2, 605 comb_coresize : 2, 606 comb_ysuben : 1, 607 comb_youtsel : 1, 608 comb_syncpfsel : 2, 609 comb_synclpfrst : 1, 610 comb_debug : 1 611 ); 612 } comb_cntl1; 613 614 typedef struct { 615 LBITFIELD32_4 ( 616 comb_hyk0 : 8, 617 comb_vyk0 : 8, 618 comb_hyk1 : 8, 619 comb_vyk1 : 8 620 ); 621 } comb_cntl2; 622 623 typedef struct { 624 LBITFIELD32_2 ( 625 comb_tap0length : 16, 626 comb_tap1length : 12 627 ); 628 } comb_line_length; 629 630 typedef struct { 631 const uint8 *types; 632 const comb_cntl0 *cntl0; 633 const comb_cntl1 *cntl1; 634 const comb_cntl2 *cntl2; 635 const comb_line_length *line_length; 636 } comb_settings; 637 638 static const uint8 comb_types_ntsc_m[] = { 639 _3Tap_2D_adaptive_Comb, 640 _2Tap_C_combed_Y_Sub, 641 _2Tap_C_combed_Y_combed, 642 _3Tap_C_combed_Y_Sub, 643 _3Tap_C_combed_Y_combed, 644 YC_mode_Comb_filter_off, 645 YC_mode_2Tap_YV_filter, 646 YC_mode_3Tap_YV_filter, 647 0 648 }; 649 650 static const comb_cntl0 comb_cntl0_ntsc_m[] = { 651 { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, 652 { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 0, 0 }, 653 { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 1, 0 }, 654 { 0, 0, 1, 0, 1, 2, 0, 1, 0, 1, 0, 0 }, 655 { 0, 0, 1, 0, 1, 2, 0, 1, 1, 1, 0, 0 }, 656 { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 2, 0 }, 657 { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 1, 0 }, 658 { 0, 0, 0, 0, 5, 2, 0, 0, 1, 1, 0, 0 } 659 }; 660 661 static const comb_cntl1 comb_cntl1_ntsc_m[] = { 662 { 0, 0, 1, 0, 0, 0, 0 }, 663 { 2, 0, 1, 0, 0, 0, 0 }, 664 { 3, 0, 0, 0, 0, 0, 0 }, 665 { 0, 0, 1, 0, 1, 0, 0 }, 666 { 3, 0, 0, 0, 1, 0, 0 }, 667 { 1, 0, 0, 0, 2, 0, 0 }, 668 { 3, 0, 0, 0, 0, 0, 0 }, 669 { 3, 0, 0, 0, 1, 0, 0 } 670 }; 671 672 static const comb_cntl2 comb_cntl2_ntsc_m[] = { 673 { 0x10, 0x10, 0x16, 0x16 }, 674 { 0xFF, 0xFF, 0xFF, 0xFF }, 675 { 0xFF, 0xFF, 0xFF, 0xFF }, 676 { 0xFF, 0xFF, 0xFF, 0xFF }, 677 { 0xFF, 0xFF, 0xFF, 0xFF }, 678 { 0xFF, 0xFF, 0xFF, 0xFF }, 679 { 0xFF, 0xFF, 0xFF, 0xFF }, 680 { 0xFF, 0xFF, 0xFF, 0xFF } 681 }; 682 683 static const comb_line_length comb_line_length_ntsc_m[] = { 684 { 0x38A, 0x718 }, 685 { 0x38A, 0x718 }, 686 { 0x38A, 0x718 }, 687 { 0x38A, 0x718 }, 688 { 0x38A, 0x718 }, 689 { 0, 0 }, 690 { 0x38A, 0 }, 691 { 0x38A, 0x718 } 692 }; 693 694 695 static const uint8 comb_types_ntsc_433[] = { 696 _2Tap_C_combed_Y_Sub, 697 _2Tap_C_combed_Y_combed, 698 _3Tap_C_combed_Y_Sub, 699 _3Tap_C_combed_Y_combed, 700 YC_mode_Comb_filter_off, 701 YC_mode_2Tap_YV_filter, 702 YC_mode_3Tap_YV_filter, 703 0 704 }; 705 706 static const comb_cntl0 comb_cntl0_ntsc_433[] = { 707 { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 0, 0 }, 708 { 0, 0, 1, 0, 3, 2, 0, 0, 0, 1, 1, 0 }, 709 { 0, 0, 1, 0, 1, 2, 0, 1, 0, 1, 0, 0 }, 710 { 0, 0, 1, 0, 1, 2, 0, 1, 1, 1, 0, 0 }, 711 { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 2, 0 }, 712 { 0, 0, 0, 0, 5, 2, 0, 0, 0, 1, 1, 0 }, 713 { 0, 0, 0, 0, 5, 2, 0, 0, 1, 1, 0, 0 } 714 }; 715 716 static const comb_cntl1 comb_cntl1_ntsc_433[] = { 717 { 2, 0, 1, 0, 0, 0, 0 }, 718 { 3, 0, 0, 0, 0, 0, 0 }, 719 { 0, 0, 1, 0, 1, 0, 0 }, 720 { 3, 0, 0, 0, 1, 0, 0 }, 721 { 1, 0, 0, 0, 2, 0, 0 }, 722 { 3, 0, 0, 0, 0, 0, 0 }, 723 { 3, 0, 0, 0, 1, 0, 0 } 724 }; 725 726 static const comb_cntl2 comb_cntl2_ntsc_433[] = { 727 { 0xFF, 0xFF, 0xFF, 0xFF }, 728 { 0xFF, 0xFF, 0xFF, 0xFF }, 729 { 0xFF, 0xFF, 0xFF, 0xFF }, 730 { 0xFF, 0xFF, 0xFF, 0xFF }, 731 { 0xFF, 0xFF, 0xFF, 0xFF }, 732 { 0xFF, 0xFF, 0xFF, 0xFF }, 733 { 0xFF, 0xFF, 0xFF, 0xFF } 734 }; 735 736 static const comb_line_length comb_line_length_ntsc_433[] = { 737 { 0x462, 0x8C9 }, 738 { 0x462, 0x8C9 }, 739 { 0x462, 0x8C9 }, 740 { 0x462, 0x8C9 }, 741 { 0, 0 }, 742 { 0x462, 0x8C9 }, 743 { 0x462, 0x8C9 } 744 }; 745 746 747 static const uint8 comb_types_pal_m[] = { 748 _2Tap_C_combed_Y_Sub, 749 YC_mode_2Tap_YV_filter, 750 0 751 }; 752 753 static const comb_cntl0 comb_cntl0_pal_m[] = { 754 { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, 755 { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } 756 }; 757 758 static const comb_cntl1 comb_cntl1_pal_m[] = { 759 { 1, 0, 1, 1, 2, 0, 0 }, 760 { 1, 0, 0, 1, 2, 0, 0 } 761 }; 762 763 static const comb_cntl2 comb_cntl2_pal_m[] = { 764 { 0xFF, 0xFF, 0xFF, 0xFF }, 765 { 0xFF, 0xFF, 0xFF, 0xFF } 766 }; 767 768 static const comb_line_length comb_line_length_pal_m[] = { 769 { 0x389, 0 }, 770 { 0x389, 0 } 771 }; 772 773 774 static const uint8 comb_types_pal_n[] = { 775 _3Tap_2D_adaptive_Comb, 776 _2Tap_C_combed_Y_Sub, 777 YC_mode_2Tap_YV_filter, 778 0 779 }; 780 781 static const comb_cntl0 comb_cntl0_pal_n[] = { 782 { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, 783 { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, 784 { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } 785 }; 786 787 static const comb_cntl1 comb_cntl1_pal_n[] = { 788 { 0, 0, 1, 0, 0, 0, 0 }, 789 { 1, 0, 1, 1, 2, 0, 0 }, 790 { 1, 0, 0, 1, 2, 0, 0 } 791 }; 792 793 static const comb_cntl2 comb_cntl2_pal_n[] = { 794 { 0x10, 0x10, 0x16, 0x16 }, 795 { 0xFF, 0xFF, 0xFF, 0xFF }, 796 { 0xFF, 0xFF, 0xFF, 0xFF } 797 }; 798 799 static const comb_line_length comb_line_length_pal_n[] = { 800 { 0x46B, 0x8DA }, 801 { 0x46C, 0 }, 802 { 0x46C, 0 } 803 }; 804 805 806 static const uint8 comb_types_pal_nc[] = { 807 _3Tap_2D_adaptive_Comb, 808 _2Tap_C_combed_Y_Sub, 809 YC_mode_2Tap_YV_filter, 810 0 811 }; 812 813 // used to represent an N/A for easier copy'n'paste 814 #define X 0 815 816 static const comb_cntl0 comb_cntl0_pal_nc[] = { 817 { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, 818 { X, X, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, 819 { X, X, 1, 0, 5, 0, 1, 2, X, 0, 2, 0 } 820 }; 821 822 static const comb_cntl1 comb_cntl1_pal_nc[] = { 823 { 0, 0, 1, 0, 0, 0, 0 }, 824 { 1, 0, 1, 1, 2, 0, 0 }, 825 { 1, 0, 0, 1, 2, 0, 0 } 826 }; 827 828 static const comb_cntl2 comb_cntl2_pal_nc[] = { 829 { 0x10, 0x10, 0x16, 0x16 }, 830 { 0xFF, 0xFF, 0xFF, 0xFF }, 831 { 0xFF, 0xFF, 0xFF, 0xFF } 832 }; 833 834 static const comb_line_length comb_line_length_pal_nc[] = { 835 { 0x391, 0x726 }, 836 { 0x394, X }, 837 { 0x394, X } 838 }; 839 840 841 static const uint8 comb_types_pal[] = { 842 _3Tap_2D_adaptive_Comb, 843 _2Tap_C_combed_Y_Sub, 844 YC_mode_2Tap_YV_filter, 845 0 846 }; 847 848 static const comb_cntl0 comb_cntl0_pal[] = { 849 { 0x90, 0x80, 1, 1, 0, 2, 0, 1, 0, 1, 0, 0 }, 850 { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, 851 { 0, 0, 1, 0, 5, 0, 1, 2, X, 0, 2, 0 } 852 }; 853 854 static const comb_cntl1 comb_cntl1_pal[] = { 855 { 0, 0, 1, 0, 0, 0, 0 }, 856 { 1, 0, 1, 1, 2, 0, 0 }, 857 { 1, 0, 0, 1, 2, 0, 0 } 858 }; 859 860 static const comb_cntl2 comb_cntl2_pal[] = { 861 { 2, 1, 8, 6 }, 862 { 0xFF, 0xFF, 0xFF, 0xFF }, 863 { 0xFF, 0xFF, 0xFF, 0xFF } 864 }; 865 866 static const comb_line_length comb_line_length_pal[] = { 867 { 0x46B, 0x8DA }, 868 { 0x46C, X }, 869 { 0x46C, X } 870 }; 871 872 873 static const uint8 comb_types_pal_60[] = { 874 _2Tap_C_combed_Y_Sub, 875 YC_mode_2Tap_YV_filter, 876 0 877 }; 878 879 static const comb_cntl0 comb_cntl0_pal_60[] = { 880 { 0, 0, 1, 0, 4, 0, 1, 2, 0, 0, 2, 0 }, 881 { 0, 0, 1, 0, 5, 0, 1, 2, 0, 0, 2, 0 } 882 }; 883 884 static const comb_cntl1 comb_cntl1_pal_60[] = { 885 { 1, 0, 1, 1, 2, 0, 0 }, 886 { 1, 0, 0, 1, 2, 0, 0 } 887 }; 888 889 static const comb_cntl2 comb_cntl2_pal_60[] = { 890 { 0xFF, 0xFF, 0xFF, 0xFF }, 891 { 0xFF, 0xFF, 0xFF, 0xFF } 892 }; 893 894 static const comb_line_length comb_line_length_pal_60[] = { 895 { 0x463, 0 }, 896 { 0x463, 0 } 897 }; 898 899 900 static const uint8 comb_types_secam[] = { 901 _2Tap_C_combed_Y_Sub, // could be another type, spec is unclear here 902 YC_mode_2Tap_YV_filter, 903 0, 904 }; 905 906 static const comb_cntl0 comb_cntl0_secam[] = { 907 { X, X, 0, 0, 4, X, X, X, X, 2, 2, 1 }, 908 { X, X, 0, 0, 5, X, X, X, X, 2, 2, X } 909 }; 910 911 static const comb_cntl1 comb_cntl1_secam[] = { 912 { 1, 0, 1, 0, 2, 0, 0 }, 913 { 1, X, 0, 0, 2, 0, 0 } 914 }; 915 916 static const comb_cntl2 comb_cntl2_secam[] = { 917 { 0xFF, 0xFF, 0xFF, 0xFF }, 918 { 0xFF, 0xFF, 0xFF, 0xFF } 919 }; 920 921 static const comb_line_length comb_line_length_secam[] = { 922 { 0x46A, 0 }, 923 { 0x46A, 0 } 924 }; 925 926 #undef X 927 928 static const comb_settings comb_settings_list[] = { 929 { comb_types_ntsc_m, comb_cntl0_ntsc_m, comb_cntl1_ntsc_m, comb_cntl2_ntsc_m, comb_line_length_ntsc_m }, 930 { comb_types_ntsc_m, comb_cntl0_ntsc_m, comb_cntl1_ntsc_m, comb_cntl2_ntsc_m, comb_line_length_ntsc_m }, 931 { comb_types_ntsc_433, comb_cntl0_ntsc_433, comb_cntl1_ntsc_433, comb_cntl2_ntsc_433, comb_line_length_ntsc_433 }, 932 { comb_types_pal_m, comb_cntl0_pal_m, comb_cntl1_pal_m, comb_cntl2_pal_m, comb_line_length_pal_m }, 933 { comb_types_pal_n, comb_cntl0_pal_n, comb_cntl1_pal_n, comb_cntl2_pal_n, comb_line_length_pal_n }, 934 { comb_types_pal_nc, comb_cntl0_pal_nc, comb_cntl1_pal_nc, comb_cntl2_pal_nc, comb_line_length_pal_nc }, 935 { comb_types_pal, comb_cntl0_pal, comb_cntl1_pal, comb_cntl2_pal, comb_line_length_pal }, 936 { comb_types_pal_60, comb_cntl0_pal_60, comb_cntl1_pal_60, comb_cntl2_pal_60, comb_line_length_pal_60 }, 937 { comb_types_secam, comb_cntl0_secam, comb_cntl1_secam, comb_cntl2_secam, comb_line_length_secam } 938 }; 939 940 int min_type, max_type, type; 941 const comb_settings *settings; 942 int i = 0; 943 944 PRINT(("CTheater::SetCombFilter(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source])); 945 946 // I don't really understand what the different types mean; 947 // what is particularly strange is that many types are defined for few standards only 948 if( source == C_THEATER_TUNER || source == C_THEATER_COMPOSITE ) { 949 min_type = _3Tap_2D_adaptive_Comb; 950 max_type = _3Tap_C_combed_Y_combed; 951 } else { 952 min_type = YC_mode_Comb_filter_off; 953 max_type = YC_mode_3Tap_YV_filter; 954 } 955 956 settings = &comb_settings_list[standard]; 957 958 for( type = min_type; type <= max_type; ++type ) { 959 for( i = 0; settings->types[i]; ++i ) { 960 if( settings->types[i] == type ) 961 break; 962 } 963 964 if( settings->types[i] != 0 ) 965 break; 966 } 967 968 if( type > max_type ) { 969 PRINT(("CTheater::SetCombFilter() - No settings for this standard and input type combination!!!\n")); 970 return; 971 } 972 973 SetRegister(VIP_COMB_CNTL0, *(const int32 *)(settings->cntl0 + i)); 974 SetRegister(VIP_COMB_CNTL1, *(const int32 *)(settings->cntl1 + i)); 975 SetRegister(VIP_COMB_CNTL2, *(const int32 *)(settings->cntl2 + i)); 976 SetRegister(VIP_COMB_LINE_LENGTH, *(const int32 *)(settings->line_length + i)); 977 978 979 // reset the comb filter 980 SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST); 981 SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST); 982 } 983 984 985 // setup luma processor 986 void CTheater::SetLuminanceProcessor(theater_standard standard) 987 { 988 static const uint16 synctip_ref0[] = { 989 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037, 0x037 }; 990 static const uint16 synctip_ref1[] = { 991 0x029, 0x029, 0x029, 0x029, 0x029, 0x026, 0x026, 0x026, 0x026 }; 992 static const uint16 clamp_ref[] = { 993 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B, 0x03B }; 994 static const uint16 agc_peakwhite[] = { 995 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF, 0x0FF }; 996 static const uint16 vbi_peakwhite[] = { 997 0x0D2, 0x0D2, 0xD2, 0x0D2, 0x0D2, 0x0C6, 0x0C6, 0x0C6, 0x0C6 }; 998 999 static const uint16 wpa_threshold[] = { 1000 0x406, 0x406, 0x4FC, 0x406, 0x59C, 0x488, 0x59C, 0x59C, 0x57A }; 1001 static const uint16 wpa_trigger_lo[] = { 1002 0x0B3, 0x0B3, 0x0B3, 0x0B3, 0x096, 0x096, 0x096, 0x0B3, 0x096 }; 1003 static const uint16 wpa_trigger_hi[] = { 1004 0x21B, 0x21B, 0x21B, 0x21B, 0x1C2, 0x1C2, 0x1C2, 0x21B, 0x1C2 }; 1005 static const uint16 lp_lockout_start[] = { 1006 0x206, 0x206, 0x206, 0x206, 0x263, 0x263, 0x263, 0x206, 0x263 }; 1007 // PAL: changed 0x2c to 0x0c; NTSC: changed 0x21 to 0x0b 1008 static const uint16 lp_lockout_end[] = { 1009 0x00B, 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00C, 0x00B, 0x00C }; 1010 1011 PRINT(("CTheater::SetLuminanceProcessor(%c)\n", "NJ4MNCB6S"[standard])); 1012 1013 SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0, synctip_ref0[standard] << 0); 1014 SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF1, (uint32)synctip_ref1[standard] << 8); 1015 SetRegister(VIP_LP_AGC_CLAMP_CNTL0, CLAMP_REF, (uint32)clamp_ref[standard] << 16); 1016 SetRegister(VIP_LP_AGC_CLAMP_CNTL0, AGC_PEAKWHITE, (uint32)agc_peakwhite[standard] << 24); 1017 SetRegister(VIP_LP_AGC_CLAMP_CNTL1, VBI_PEAKWHITE, (uint32)vbi_peakwhite[standard] << 0); 1018 1019 SetRegister(VIP_LP_WPA_CNTL0, WPA_THRESHOLD, wpa_threshold[standard] << 0); 1020 SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_LO, wpa_trigger_lo[standard] << 0); 1021 SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_HI, (uint32)wpa_trigger_hi[standard] << 16); 1022 SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_START, lp_lockout_start[standard] << 0); 1023 SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_END, (uint32)lp_lockout_end[standard] << 16); 1024 } 1025 1026 1027 // setup brightness and contrast 1028 void CTheater::SetLuminanceLevels(theater_standard standard, int brightness, int contrast) 1029 { 1030 double ref0, setup, gain; 1031 1032 ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0); 1033 1034 switch (standard) { 1035 case C_THEATER_NTSC: 1036 case C_THEATER_PAL_M: 1037 case C_THEATER_NTSC_443: 1038 setup = 7.5 * ref0 / 40.0; 1039 gain = 219.0 / (92.5 * ref0 / 40.0); 1040 break; 1041 1042 case C_THEATER_NTSC_JAPAN: 1043 setup = 0.0; 1044 gain = 219.0 / (100.0 * ref0 / 40.0); 1045 break; 1046 1047 case C_THEATER_PAL_BDGHI: 1048 case C_THEATER_PAL_N: 1049 case C_THEATER_SECAM: 1050 case C_THEATER_PAL_60: 1051 case C_THEATER_PAL_NC: 1052 setup = 0.0; 1053 gain = 219.0 / (100.0 * ref0 / 43.0); 1054 break; 1055 1056 default: 1057 setup = 0.0; 1058 gain = 0.0; 1059 break; 1060 } 1061 1062 if (contrast <= -100) 1063 contrast = -99; 1064 1065 /* set luminance processor constrast (7:0) */ 1066 SetRegister(VIP_LP_CONTRAST, CONTRAST, 1067 int(64.0 * ((contrast + 100) / 100.0) * gain) << 0); 1068 1069 /* set luminance processor brightness (13:0) */ 1070 SetRegister(VIP_LP_BRIGHTNESS, BRIGHTNESS, 1071 int(16.0 * ((brightness - setup) + 16.0 / ((contrast + 100) * gain / 100.0))) & BRIGHTNESS); 1072 } 1073 1074 1075 // setup chroma demodulator 1076 void CTheater::SetChromaProcessor(theater_standard standard) 1077 { 1078 PRINT(("CTheater::SetChromaProcessor(%c)\n", "NJ4MNCB6S"[standard])); 1079 1080 static const uint32 ch_dto_inc[] = { 1081 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x400000, 0x3E7A28 }; 1082 static const uint8 ch_pll_sgain[] = { 1083 1, 1, 1, 1, 1, 1, 1, 1, 5 }; 1084 static const uint8 ch_pll_fgain[] = { 1085 2, 2, 2, 2, 2, 2, 2, 2, 6 }; 1086 1087 static const uint8 ch_height[] = { 1088 0xCD, 0xCD, 0xCD, 0x91, 0x91, 0x9C, 0x9C, 0x9C, 0x66 }; 1089 static const uint8 ch_kill_level[] = { 1090 0x0C0, 0xC0, 0xC0, 0x8C, 0x8C, 0x90, 0x90, 0x90, 0x60 }; 1091 static const uint8 ch_agc_error_lim[] = { 1092 2, 2, 2, 2, 2, 2, 2, 2, 3 }; 1093 static const uint8 ch_agc_filter_en[] = { 1094 0, 0, 0, 0, 0, 0, 1, 0, 0 }; 1095 static const uint8 ch_agc_loop_speed[] = { 1096 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1097 1098 static const uint16 cr_burst_gain[] = { 1099 0x7A, 0x71, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x1FF }; 1100 static const uint16 cb_burst_gain[] = { 1101 0xAC, 0x9F, 0xAC, 0xAC, 0xAC, 0xAB, 0xAB, 0xAB, 0x1FF }; 1102 static const uint16 crdr_active_gain[] = { 1103 0x7A, 0x71, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x11C }; 1104 static const uint16 cbdb_active_gain[] = { 1105 0xAC, 0x9F, 0xAC, 0xAC, 0xAC, 0xAB, 0xAB, 0xAB, 0x15A }; 1106 static const uint16 cp_vert_lockout_start[] = { 1107 0x207, 0x207, 0x207, 0x207, 0x269, 0x269, 0x269, 0x207, 0x269 }; 1108 static const uint8 cp_vert_lockout_end[] = { 1109 0x00E, 0x00E, 0x00E, 0x00E, 0x00E, 0x012, 0x012, 0x00E, 0x012 }; 1110 1111 SetRegister(VIP_CP_PLL_CNTL0, CH_DTO_INC, ch_dto_inc[standard] << 0); 1112 SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_SGAIN, (uint32)ch_pll_sgain[standard] << 24); 1113 SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_FGAIN, (uint32)ch_pll_fgain[standard] << 28); 1114 1115 SetRegister(VIP_CP_AGC_CNTL, CH_HEIGHT, ch_height[standard] << 0); 1116 SetRegister(VIP_CP_AGC_CNTL, CH_KILL_LEVEL, (uint32)ch_kill_level[standard] << 8); 1117 SetRegister(VIP_CP_AGC_CNTL, CH_AGC_ERROR_LIM, (uint32)ch_agc_error_lim[standard] << 16); 1118 SetRegister(VIP_CP_AGC_CNTL, CH_AGC_FILTER_EN, (uint32)ch_agc_filter_en[standard] << 18); 1119 SetRegister(VIP_CP_AGC_CNTL, CH_AGC_LOOP_SPEED, (uint32)ch_agc_loop_speed[standard] << 19); 1120 1121 SetRegister(VIP_CP_BURST_GAIN, CR_BURST_GAIN, cr_burst_gain[standard] << 0); 1122 SetRegister(VIP_CP_BURST_GAIN, CB_BURST_GAIN, (uint32)cb_burst_gain[standard] << 16); 1123 1124 SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, crdr_active_gain[standard] << 0); 1125 SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, (uint32)cbdb_active_gain[standard] << 16); 1126 1127 SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_START, cp_vert_lockout_start[standard] << 0); 1128 SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_END, (uint32)cp_vert_lockout_end[standard] << 16); 1129 } 1130 1131 1132 // set colour saturation and hue. 1133 // hue makes sense for NTSC only and seems to act as saturation for PAL 1134 void CTheater::SetChromaLevels(theater_standard standard, int saturation, int hue) 1135 { 1136 int ref0; 1137 double gain, CRgain, CBgain; 1138 1139 /* compute Cr/Cb gains */ 1140 ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0); 1141 1142 switch (standard) { 1143 case C_THEATER_NTSC: 1144 case C_THEATER_NTSC_443: 1145 case C_THEATER_PAL_M: 1146 CRgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; 1147 CBgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; 1148 break; 1149 1150 case C_THEATER_NTSC_JAPAN: 1151 CRgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; 1152 CBgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; 1153 break; 1154 1155 case C_THEATER_PAL_BDGHI: 1156 case C_THEATER_PAL_60: 1157 case C_THEATER_PAL_NC: 1158 case C_THEATER_PAL_N: 1159 CRgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5; 1160 CBgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5; 1161 break; 1162 1163 case C_THEATER_SECAM: 1164 CRgain = 32.0 * 32768.0 / 280000.0 / (33554432.0 / 35.46985) * (1.597 / 1.902) / 1.5; 1165 CBgain = 32.0 * 32768.0 / 230000.0 / (33554432.0 / 35.46985) * (1.267 / 1.505) / 1.5; 1166 break; 1167 1168 default: 1169 PRINT(("CTheater::SetChromaLevels() - Bad standard\n")); 1170 CRgain = 0.0; 1171 CBgain = 0.0; 1172 break; 1173 } 1174 1175 if (saturation >= 0) 1176 gain = 1.0 + 4.9 * saturation / 100.0; 1177 else 1178 gain = 1.0 + saturation / 100.0; 1179 1180 SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, int(128 * CRgain * gain) << 0); 1181 SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, int(128 * CBgain * gain) << 16); 1182 1183 if (hue >= 0) 1184 hue = (256 * hue) / 360; 1185 else 1186 hue = (256 * (hue + 360)) / 360; 1187 1188 SetRegister(VIP_CP_HUE_CNTL, HUE_ADJ, hue << 0); 1189 } 1190 1191 1192 // these values are used by scaler as well 1193 static const uint16 h_active_start[] = { 1194 0x06b, 0x06B, 0x07E, 0x067, 0x09A, 0x07D, 0x09A, 0x084, 0x095 }; 1195 static const uint16 h_active_end[] = { 1196 0x363, 0x363, 0x42A, 0x363, 0x439, 0x439, 0x439, 0x363, 0x439 }; 1197 static const uint16 v_active_start[] = { 1198 0x025, 0x025, 0x025, 0x025, 0x02E, 0x02E, 0x02E, 0x025, 0x02E }; 1199 // PAL height is too small (572 instead of 576 lines), but changing 0x269 to 0x26d 1200 // leads to trouble, and the last 2 lines seem to be used for VBI data 1201 // (read: garbage) anyway 1202 static const uint16 v_active_end[] = { 1203 0x204, 0x204, 0x204, 0x204, 0x269, 0x269, 0x269, 0x204, 0x269 }; 1204 static const uint16 h_vbi_wind_start[] = { 1205 0x064, 0x064, 0x064, 0x064, 0x084, 0x084, 0x084, 0x064, 0x084 }; 1206 static const uint16 h_vbi_wind_end[] = { 1207 0x366, 0x366, 0x366, 0x366, 0x41F, 0x41F, 0x41F, 0x366, 0x41F }; 1208 static const uint16 v_vbi_wind_start[] = { 1209 0x00b, 0x00b, 0x00b, 0x00b, 0x008, 0x008, 0x008, 0x00b, 0x008 }; 1210 static const uint16 v_vbi_wind_end[] = { 1211 0x024, 0x024, 0x024, 0x024, 0x02d, 0x02d, 0x02d, 0x024, 0x02d }; 1212 1213 void CTheater::getActiveRange( theater_standard standard, CRadeonRect &rect ) 1214 { 1215 rect.SetTo( 1216 h_active_start[standard], v_active_start[standard], 1217 h_active_end[standard], v_active_end[standard] ); 1218 } 1219 1220 void CTheater::getVBIRange( theater_standard standard, CRadeonRect &rect ) 1221 { 1222 rect.SetTo( 1223 h_vbi_wind_start[standard], v_vbi_wind_start[standard], 1224 h_vbi_wind_end[standard], v_vbi_wind_end[standard] ); 1225 } 1226 1227 // program clipping engine 1228 void CTheater::SetClipWindow(theater_standard standard, bool vbi) 1229 { 1230 // set horizontal active window 1231 SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START, h_active_start[standard] << 0); 1232 SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END, (uint32)h_active_end[standard] << 16); 1233 1234 // set vertical active window 1235 SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START, v_active_start[standard] << 0); 1236 SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END, (uint32)v_active_end[standard] << 16); 1237 1238 // set horizontal VBI window 1239 SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_START, h_vbi_wind_start[standard] << 0); 1240 SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_END, (uint32)h_vbi_wind_end[standard] << 16); 1241 1242 // set vertical VBI window 1243 SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_START, v_vbi_wind_start[standard] << 0); 1244 SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_END, (uint32)v_vbi_wind_end[standard] << 16); 1245 1246 // set VBI scaler control 1247 SetRegister(VIP_VBI_SCALER_CONTROL, (1 << 16) & VBI_SCALING_RATIO); 1248 1249 // enable/disable VBI capture 1250 SetRegister(VIP_VBI_CONTROL, VBI_CAPTURE_ENABLE, 1251 vbi ? VBI_CAPTURE_EN : VBI_CAPTURE_DIS); 1252 1253 PRINT(("CTheater::SetClipWindow(active=%d/%d/%d/%d, vbi=%d/%d/%d/%d)\n", 1254 Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START) >> 0, 1255 Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END) >> 16, 1256 Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START) >> 0, 1257 Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END) >> 16, 1258 Register(VIP_H_VBI_WINDOW, H_VBI_WIND_START) >> 0, 1259 Register(VIP_H_VBI_WINDOW, H_VBI_WIND_END) >> 16, 1260 Register(VIP_V_VBI_WINDOW, V_VBI_WIND_START) >> 0, 1261 Register(VIP_V_VBI_WINDOW, V_VBI_WIND_END) >> 16)); 1262 1263 } 1264 1265 1266 // setup capture scaler. 1267 void CTheater::SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace) 1268 { 1269 int oddOffset, evenOffset; 1270 uint16 h_active_width, v_active_height; 1271 1272 // ASSERT(vactive <= 511); 1273 1274 // TK: Gatos uses different values here 1275 h_active_width = h_active_end[standard] - h_active_start[standard] + 1; 1276 v_active_height = v_active_end[standard] - v_active_start[standard] + 1; 1277 1278 // for PAL, we have 572 lines only, but need 576 lines; 1279 // my attempts to find those missing lines all failed, so if the application requests 1280 // 576 lines, we had to upscale the video which is not supported by hardware; 1281 // solution: restrict to 572 lines - the scaler will fill out the missing lines with black 1282 if( vactive > v_active_height ) 1283 vactive = v_active_height; 1284 1285 if (deinterlace) { 1286 // progressive scan 1287 evenOffset = oddOffset = 512 - (int) ((512 * vactive) / v_active_height); 1288 } 1289 else { 1290 // interlaced 1291 evenOffset = (int) ((512 * vactive) / v_active_height); 1292 oddOffset = 2048 - evenOffset; 1293 } 1294 1295 // set scale input window 1296 SetRegister(VIP_SCALER_IN_WINDOW, H_IN_WIND_START, h_active_start[standard] << 0); 1297 SetRegister(VIP_SCALER_IN_WINDOW, V_IN_WIND_START, (uint32)v_active_start[standard] << 16); 1298 1299 SetRegister(VIP_SCALER_OUT_WINDOW, H_OUT_WIND_WIDTH, hactive << 0); 1300 SetRegister(VIP_SCALER_OUT_WINDOW, V_OUT_WIND_HEIGHT, (vactive / 2) << 16); 1301 1302 SetRegister(VIP_H_SCALER_CONTROL, H_SCALE_RATIO, (((uint32)h_active_width << 16) / hactive) << 0); 1303 SetRegister(VIP_V_SCALER_CONTROL, V_SCALE_RATIO, ((vactive << 11) / v_active_height) << 0); 1304 1305 // enable horizontal and vertical scaler 1306 SetRegister(VIP_H_SCALER_CONTROL, H_BYPASS, 1307 h_active_width == hactive ? H_BYPASS : 0); 1308 SetRegister(VIP_V_SCALER_CONTROL, V_BYPASS, 1309 v_active_height == vactive ? V_BYPASS : 0); 1310 1311 // set deinterlace control 1312 SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0); 1313 SetRegister(VIP_V_DEINTERLACE_CONTROL, EVENF_OFFSET, evenOffset << 0); 1314 SetRegister(VIP_V_DEINTERLACE_CONTROL, ODDF_OFFSET, oddOffset << 11); 1315 1316 SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0); 1317 1318 PRINT(("CTheater::SetScaler(active=%d/%d/%d/%d, scale=%d/%d)\n", 1319 Register(VIP_SCALER_IN_WINDOW, H_IN_WIND_START) >> 0, 1320 Register(VIP_SCALER_IN_WINDOW, V_IN_WIND_START) >> 16, 1321 hactive, vactive, 1322 Register(VIP_H_SCALER_CONTROL, H_SCALE_RATIO), 1323 Register(VIP_V_SCALER_CONTROL, V_SCALE_RATIO))); 1324 } 1325 1326 1327 int CTheater::Register(int index) 1328 { 1329 return fPort.Register(fDevice, index); 1330 } 1331 1332 int CTheater::Register(int index, int mask) 1333 { 1334 return fPort.Register(fDevice, index) & mask; 1335 } 1336 1337 void CTheater::SetRegister(int index, int value) 1338 { 1339 fPort.SetRegister(fDevice, index, value); 1340 } 1341 1342 void CTheater::SetRegister(int index, int mask, int value) 1343 { 1344 if ((value & ~mask) != 0) 1345 PRINT(("WARNING: CTheater::SetRegister(0x%04x, 0x%08x, 0x%08x)\n", index, mask, value)); 1346 1347 fPort.SetRegister(fDevice, index, 1348 (fPort.Register(fDevice, index) & ~mask) | (value & mask)); 1349 } 1350 1351 int CTheater::CurrentLine() 1352 { 1353 return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT; 1354 } 1355 1356 void CTheater::PrintToStream() 1357 { 1358 PRINT(("<<< Rage Theater Registers >>>\n")); 1359 for (int index = 0x0400; index <= 0x06ff; index += 4) { 1360 int value = Register(index); 1361 PRINT(("REG_0x%04x = 0x%08x\n", index, value)); 1362 } 1363 } 1364