1 /* 2 Copyright (c) 2002-04, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 ImpacTV programming. As this unit is contained in various chips, 8 the code to actually access the unit is separated. 9 */ 10 11 #include "radeon_interface.h" 12 #include "radeon_accelerant.h" 13 14 #include "tv_out_regs.h" 15 #include "utils.h" 16 #include "set_mode.h" 17 18 #include <string.h> 19 20 21 // fixed-point resolution of UV scaler increment 22 #define TV_UV_INC_FIX_SHIFT 14 23 #define TV_UV_INC_FIX_SCALE (1 << TV_UV_INC_FIX_SHIFT) 24 25 // fixed point resolution of UV scaler initialization (uv_accum_init) 26 #define TV_UV_INIT_FIX_SHIFT 6 27 28 29 // calculate time when TV timing must be restarted 30 static void Radeon_CalcImpacTVRestart( 31 impactv_params *params, const display_mode *mode, 32 uint16 h_blank, uint16 f_total ) 33 { 34 uint32 h_first, v_first = 0, f_first; 35 uint32 tmp_uv_accum_sum; 36 uint16 uv_accum_frac, uv_accum_int; 37 int line; 38 uint32 how_early = 0; 39 int32 first_num, restart_to_first_active_pixel_to_FIFO; 40 uint32 time_to_active; 41 42 // this is all black magic - you are not supposed to understand this 43 h_first = 9; 44 f_first = 0; 45 46 tmp_uv_accum_sum = params->uv_accum_init << (TV_UV_INC_FIX_SHIFT - TV_UV_INIT_FIX_SHIFT); 47 uv_accum_frac = tmp_uv_accum_sum & (TV_UV_INC_FIX_SCALE - 1); 48 uv_accum_int = (tmp_uv_accum_sum >> TV_UV_INC_FIX_SHIFT) & 7; 49 50 // at line disp + 18 the accumulator is initialized; 51 // simulate timing during vertical blank and find the last CRT line where 52 // a new TV line is started 53 // (actually, I think this calculation is wrong) 54 for( line = mode->timing.v_display - 1 + 18; line < mode->timing.v_total - 2; ++line ) { 55 if( uv_accum_int > 0 ) { 56 --uv_accum_int; 57 } else { 58 v_first = line + 1; 59 how_early = uv_accum_frac * mode->timing.h_total; 60 uv_accum_int = ((uv_accum_frac + params->uv_inc) >> TV_UV_INC_FIX_SHIFT) - 1; 61 uv_accum_frac = (uv_accum_frac + params->uv_inc) & (TV_UV_INC_FIX_SCALE - 1); 62 } 63 } 64 65 SHOW_FLOW( 3, "f_first=%d, v_first=%d, h_first=%d", f_first, v_first, h_first ); 66 67 // theoretical time when restart should be started 68 first_num = 69 f_first * mode->timing.v_total * mode->timing.h_total 70 + v_first * mode->timing.h_total 71 + h_first; 72 73 first_num += (how_early + TV_UV_INC_FIX_SCALE / 2) >> TV_UV_INC_FIX_SHIFT; 74 75 SHOW_FLOW( 3, "first_num=%d", first_num ); 76 77 // TV logic needs extra clocks to restart 78 //params->tv_clocks_to_active = 0; 79 time_to_active = params->tv_clocks_to_active + 3; 80 81 SHOW_FLOW( 3, "time_to_active=%d, crt_freq=%d, tv_freq=%d", 82 time_to_active, params->crt_dividers.freq, params->tv_dividers.freq ); 83 84 // get delay until first bytes can be read from FIFO 85 restart_to_first_active_pixel_to_FIFO = 86 (int)( 87 (int64)time_to_active * params->crt_dividers.freq / params->tv_dividers.freq 88 - (int64)h_blank * params->crt_dividers.freq / params->tv_dividers.freq / 2) 89 - mode->timing.h_display / 2 90 + mode->timing.h_total / 2; 91 92 // do restart a bit early to compensate delays 93 first_num -= restart_to_first_active_pixel_to_FIFO; 94 95 SHOW_FLOW( 3, "restart_to_first_active_pixel_to_FIFO=%d", restart_to_first_active_pixel_to_FIFO ); 96 97 SHOW_FLOW( 3, "after delay compensation first_num=%d", first_num ); 98 99 //first_num = 625592; 100 101 // make restart time positive 102 // ("%" operator doesn't like negative numbers) 103 first_num += f_total * mode->timing.v_total * mode->timing.h_total; 104 105 //SHOW_FLOW( 2, "first_num=%d", first_num ); 106 107 // convert clocks to screen position 108 params->f_restart = (first_num / (mode->timing.v_total * mode->timing.h_total)) % f_total; 109 first_num %= mode->timing.v_total * mode->timing.h_total; 110 params->v_restart = (first_num / mode->timing.h_total) % mode->timing.v_total; 111 first_num %= mode->timing.h_total; 112 params->h_restart = first_num; 113 114 /*params->v_restart = 623; 115 params->h_restart = 580;*/ 116 117 SHOW_FLOW( 2, "Restart in frame %d, line %d, pixel %d", 118 params->f_restart, params->v_restart, params->h_restart ); 119 } 120 121 122 // thresholds for flicker fixer algorithm 123 static int8 y_flicker_removal[5] = { 6, 5, 4, 3, 2 }; 124 125 // associated filter parameters scaled by 8(!) 126 static int8 y_saw_tooth_slope[5] = { 1, 2, 2, 4, 8 }; 127 // these values are not scaled 128 static int8 y_coeff_value[5] = { 2, 2, 0, 4, 0 }; 129 static bool y_coeff_enable[5] = { 1, 1, 0, 1, 0 }; 130 131 #define countof( a ) (sizeof( (a) ) / sizeof( (a)[0] )) 132 133 // fixed point resolution of saw filter parameters 134 #define TV_SAW_FILTER_FIX_SHIFT 13 135 #define TV_SAW_FILTER_FIX_SCALE (1 << TV_SAW_FILTER_FIX_SHIFT) 136 137 // fixed point resolution of flat filter parameter 138 #define TV_Y_COEFF_FIX_SHIFT 8 139 #define TV_Y_COEFF_FIX_SCALE (1 << TV_Y_COEFF_FIX_SHIFT) 140 141 142 // calculate flicker fixer parameters 143 static void Radeon_CalcImpacTVFlickerFixer( 144 impactv_params *params ) 145 { 146 int flicker_removal; 147 uint i; 148 int lower_border, upper_border; 149 150 // flicker_removal must be within [uv_inc..uv_inc*2); take care of fraction 151 lower_border = ((params->uv_inc + TV_UV_INC_FIX_SCALE - 1) >> TV_UV_INC_FIX_SHIFT); 152 upper_border = ((2 * params->uv_inc) >> TV_UV_INC_FIX_SHIFT); 153 154 for( i = 0; i < countof( y_flicker_removal ); ++i ) { 155 if( lower_border <= y_flicker_removal[i] && 156 upper_border > y_flicker_removal[i] ) 157 break; 158 } 159 160 // use least aggresive filtering if not in list 161 if( i >= countof( y_flicker_removal )) 162 i = countof( y_flicker_removal ) - 1; 163 164 flicker_removal = y_flicker_removal[i]; 165 166 SHOW_FLOW( 3, "flicker removal=%d", flicker_removal ); 167 168 params->y_saw_tooth_slope = y_saw_tooth_slope[i] * (TV_SAW_FILTER_FIX_SCALE / 8); 169 params->y_saw_tooth_amp = ((uint32)params->y_saw_tooth_slope * params->uv_inc) >> TV_UV_INC_FIX_SHIFT; 170 params->y_fall_accum_init = ((uint32)params->y_saw_tooth_slope * params->uv_accum_init) >> TV_UV_INIT_FIX_SHIFT; 171 172 SHOW_FLOW( 3, "%d < %d ?", 173 (flicker_removal << 16) - ((int32)params->uv_inc << (16 - TV_UV_INC_FIX_SHIFT)), 174 ((int32)params->uv_accum_init << (16 - TV_UV_INIT_FIX_SHIFT)) ); 175 176 if( (flicker_removal << 16) - ((int32)params->uv_inc << (16 - TV_UV_INC_FIX_SHIFT)) 177 < ((int32)params->uv_accum_init << (16 - TV_UV_INIT_FIX_SHIFT))) 178 { 179 params->y_rise_accum_init = 180 (((flicker_removal << TV_UV_INIT_FIX_SHIFT) - params->uv_accum_init) * 181 params->y_saw_tooth_slope) >> TV_UV_INIT_FIX_SHIFT; 182 } else { 183 params->y_rise_accum_init = 184 (((flicker_removal << TV_UV_INIT_FIX_SHIFT) - params->uv_accum_init - params->y_accum_init) * 185 params->y_saw_tooth_slope) >> TV_UV_INIT_FIX_SHIFT; 186 } 187 188 params->y_coeff_enable = y_coeff_enable[i]; 189 params->y_coeff_value = y_coeff_value[i] * TV_Y_COEFF_FIX_SCALE / 8; 190 } 191 192 193 // correct sync position after tweaking total size 194 static void Radeon_AdoptSync( 195 const display_mode *mode, display_mode *tweaked_mode ) 196 { 197 uint16 198 h_over_plus, h_sync_width, tweaked_h_over_plus, 199 v_over_plus, v_sync_width, tweaked_v_over_plus; 200 201 h_over_plus = mode->timing.h_sync_start - mode->timing.h_display; 202 h_sync_width = mode->timing.h_sync_end - mode->timing.h_sync_start; 203 204 // we want start of sync at same relative position of blank 205 tweaked_h_over_plus = (uint32)h_over_plus * 206 (tweaked_mode->timing.h_total - mode->timing.h_display - h_sync_width ) / 207 (mode->timing.h_total - mode->timing.h_display - h_sync_width); 208 209 tweaked_mode->timing.h_sync_start = mode->timing.h_display + tweaked_h_over_plus; 210 tweaked_mode->timing.h_sync_end = tweaked_mode->timing.h_sync_start + h_sync_width; 211 212 v_over_plus = mode->timing.v_sync_start - mode->timing.v_display; 213 v_sync_width = mode->timing.v_sync_end - mode->timing.v_sync_start; 214 215 tweaked_v_over_plus = (uint32)v_over_plus * 216 (tweaked_mode->timing.v_total - mode->timing.v_display - v_sync_width ) / 217 (mode->timing.v_total - mode->timing.v_display - v_sync_width); 218 219 // we really should verify whether the resulting mode is still valid; 220 // this is a start 221 tweaked_v_over_plus = min( 1, tweaked_v_over_plus ); 222 223 tweaked_mode->timing.v_sync_start = mode->timing.v_display + tweaked_v_over_plus; 224 tweaked_mode->timing.v_sync_end = tweaked_mode->timing.v_sync_start + v_sync_width; 225 } 226 227 228 static const uint16 hor_timing_NTSC[RADEON_TV_TIMING_SIZE] = { 229 // moved to left as much as possible 230 0x0007, 0x003f, 0x0263, 0x0a24, 0x2a6b, 0x0a36, 0x126d-100, 0x1bfe, 231 0x1a8f+100, 0x1ec7, 0x3863, 0x1bfe, 0x1bfe, 0x1a2a, 0x1e95, 0x0e31, 232 0x201b, 0 233 }; 234 235 static const uint16 vert_timing_NTSC[RADEON_TV_TIMING_SIZE] = { 236 0x2001, 0x200d, 0x1006, 0x0c06, 0x1006, 0x1818, 0x21e3, 0x1006, 237 0x0c06, 0x1006, 0x1817, 0x21d4, 0x0002, 0 238 }; 239 240 static const uint16 hor_timing_PAL[RADEON_TV_TIMING_SIZE] = { 241 0x0007, 0x0058, 0x027c, 0x0a31, 0x2a77, 0x0a95, 0x124f - 60, 0x1bfe, 242 0x1b22 + 60, 0x1ef9, 0x387c, 0x1bfe, 0x1bfe, 0x1b31, 0x1eb5, 0x0e43, 243 0x201b, 0 244 }; 245 246 static const uint16 vert_timing_PAL[RADEON_TV_TIMING_SIZE] = { 247 0x2001, 0x200c, 0x1005, 0x0c05, 0x1005, 0x1401, 0x1821, 0x2240, 248 0x1005, 0x0c05, 0x1005, 0x1401, 0x1822, 0x2230, 0x0002, 0 249 }; 250 251 static const uint16 *hor_timings[] = { 252 hor_timing_NTSC, 253 hor_timing_PAL, 254 hor_timing_NTSC, // palm: looks similar to NTSC, but differs slightly 255 hor_timing_NTSC, // palnc: looks a bit like NTSC, probably won't work 256 hor_timing_PAL, // scart pal 257 hor_timing_PAL // pal 60: horizontally, it is PAL 258 }; 259 260 static const uint16 *vert_timings[] = { 261 vert_timing_NTSC, 262 vert_timing_PAL, 263 vert_timing_NTSC, // palm: vertically, this is PAL 264 vert_timing_PAL, // palnc: a bit like PAL, but not really 265 vert_timing_PAL, // scart pal 266 vert_timing_NTSC // pal 60: vertically, it is NTSC 267 }; 268 269 270 // timing of TV standards; 271 // the index is of type tv_standard 272 static const tv_timing radeon_std_tv_timing[6] = { 273 // TK: hand-tuned v_active_lines and horizontal zoom 274 {42954540, 2730, 200, 28, 200, 110, 2170, 525, 466/*440*/, 525, 2, 1, 0, 0.95/*0.88*/ * FIX_SCALE/2}, /* ntsc */ 275 // TK: frame_size_adjust was -6, but using 12 leads to perfect 25 Hz 276 {53203425, 3405, 250, 28, 320, 80, 2627, 625, 555/*498*/, 625, 2, 3, 12, 0.98/*0.91*/ * FIX_SCALE/2}, /* pal */ 277 {42907338, 2727, 200, 28, 200, 110, 2170, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE/2}, /* palm */ 278 {42984675, 2751, 202, 28, 202, 110, 2190, 625, 510, 625, 2, 3, 0, 0.91 * FIX_SCALE/2}, /* palnc */ 279 {53203425, 3405, 250, 28, 320, 80, 2627, 625, 498, 625, 2, 3, 0, 0.91 * FIX_SCALE/2}, /* scart pal ??? */ 280 {53203425, 3405, 250, 28, 320, 80, 2627, 525, 440, 525, 2, 1, 0, 0.91 * FIX_SCALE/2}, /* pal 60 */ 281 }; 282 283 284 // adjust timing so it fills the entire visible area; 285 // the result may not be CRT compatible! 286 static void Radeon_MakeOverscanMode( 287 display_timing *timing, tv_standard_e tv_format ) 288 { 289 const tv_timing *tv_timing = &radeon_std_tv_timing[tv_format-1]; 290 291 // vertical is easy: ratio of displayed lines and blank must be 292 // according to TV standard, having the sync delay of 1 line and 293 // sync len of 3 lines is used by most VESA modes 294 timing->v_total = timing->v_display * tv_timing->v_total / tv_timing->v_active_lines; 295 timing->v_sync_start = timing->v_display + 1; 296 timing->v_sync_end = timing->v_sync_start + 3; 297 298 // horizontal is tricky: the ratio may not be important (as it's 299 // scaled by the TV-out unit anyway), but the sync position and length 300 // is pure guessing - VESA modes don't exhibit particular scheme 301 timing->h_total = timing->h_display * tv_timing->h_total / tv_timing->h_active_len; 302 timing->h_sync_start = min( timing->h_total * 30 / 1000, 2 * 8 ) + timing->h_display; 303 timing->h_sync_end = min( timing->h_total * 80 / 1000, 3 * 8 ) + timing->h_sync_start; 304 305 // set some pixel clock - it's replaced during fine tuning anyway 306 timing->pixel_clock = timing->h_total * timing->v_total * 60; 307 // most (but not all) 60 Hz modes have all negative sync, so use that too 308 timing->flags = 0; 309 310 SHOW_INFO0( 4, "got:" ); 311 SHOW_INFO( 4, "H: %4d %4d %4d %4d", 312 timing->h_display, timing->h_sync_start, 313 timing->h_sync_end, timing->h_total ); 314 SHOW_INFO( 4, "V: %4d %4d %4d %4d", 315 timing->v_display, timing->v_sync_start, 316 timing->v_sync_end, timing->v_total ); 317 SHOW_INFO( 4, "clk: %ld", timing->pixel_clock ); 318 } 319 320 321 #define TV_VERT_LEAD_IN_LINES 2 322 #define TV_UV_ADR_INI 0xc8 323 324 // calculate TV parameters 325 void Radeon_CalcImpacTVParams( 326 const general_pll_info *general_pll, impactv_params *params, 327 tv_standard_e tv_format, bool internal_encoder, 328 const display_mode *mode, display_mode *tweaked_mode ) 329 { 330 pll_info tv_pll, crt_pll; 331 uint16 start_line, lines_before_active; 332 const tv_timing *tv_timing = &radeon_std_tv_timing[tv_format-1]; 333 334 SHOW_FLOW( 2, "internal_encoder=%s, format=%d", 335 internal_encoder ? "yes" : "no", tv_format ); 336 337 if( tv_format < ts_ntsc || tv_format > ts_max ) 338 tv_format = ts_ntsc; 339 340 params->mode888 = true; 341 params->timing = *tv_timing; 342 343 Radeon_GetTVPLLConfiguration( general_pll, &tv_pll, internal_encoder ); 344 Radeon_CalcPLLDividers( &tv_pll, tv_timing->freq, 0, ¶ms->tv_dividers ); 345 346 Radeon_GetTVCRTPLLConfiguration( general_pll, &crt_pll, internal_encoder ); 347 348 // initially, we try to keep to requested mode 349 *tweaked_mode = *mode; 350 351 Radeon_MakeOverscanMode( &tweaked_mode->timing, tv_format ); 352 353 // tweak CRT mode if necessary to match TV frame timing 354 Radeon_MatchCRTPLL( 355 &crt_pll, 356 tv_timing->v_total, tv_timing->h_total, tv_timing->frame_size_adjust, 357 tv_timing->freq, 358 tweaked_mode, 2, 40, 359 internal_encoder ? 0/*6*/ : 0, 2 + params->mode888, 360 ¶ms->crt_dividers, tweaked_mode ); 361 362 // adopt synchronization to make tweaked mode look like original mode 363 Radeon_AdoptSync( mode, tweaked_mode ); 364 365 // timing magic 366 start_line = 367 tv_timing->h_sync_len 368 + tv_timing->h_setup_delay 369 + tv_timing->h_active_delay 370 - tv_timing->h_genclk_delay; 371 372 lines_before_active = 373 (tv_timing->v_field_total - tv_timing->v_active_lines) / 2 - 1 374 - TV_VERT_LEAD_IN_LINES + 1; 375 376 SHOW_FLOW( 3, "lines_before_active=%d, start_line=%d", lines_before_active, start_line ); 377 378 params->tv_clocks_to_active = (uint32)lines_before_active * tv_timing->h_total + start_line; 379 380 // calculate scaling. 381 // this must be done before CalcTVRestart() or TVFlickerFixer() is called 382 // start accumulator always with 0.25 383 params->uv_accum_init = 0x10; 384 // this value seems to be fixed (it's not written to any register but used 385 // at some calculations) 386 params->y_accum_init = 0; 387 // for scaling ratio, take care that v_field_total is for full, not for half frames, 388 // therefore we devide v_field_total by 2 389 params->uv_inc = (tweaked_mode->timing.v_total << TV_UV_INC_FIX_SHIFT) 390 * 2 / tv_timing->v_field_total; 391 392 SHOW_FLOW( 3, "uv_inc=%d", params->uv_inc ); 393 394 params->h_inc = 395 ((int64)tweaked_mode->timing.h_display * 4096 / 396 (tv_timing->h_active_len + tv_timing->h_active_delay) << (FIX_SHIFT - 1)) / tv_timing->scale; 397 398 Radeon_CalcImpacTVRestart( params, tweaked_mode, 399 tv_timing->h_total - tv_timing->h_active_len, tv_timing->f_total ); 400 Radeon_CalcImpacTVFlickerFixer( params ); 401 } 402 403 404 // standard upsample coefficients (external Theatre only) 405 static uint32 std_upsample_filter_coeff[RADEON_TV_UPSAMP_COEFF_NUM] = { 406 0x3f010000, 0x7b008002, 0x00003f01, 407 0x341b7405, 0x7f3a7617, 0x00003d04, 408 0x2d296c0a, 0x0e316c2c, 0x00003e7d, 409 0x2d1f7503, 0x2927643b, 0x0000056f, 410 0x29257205, 0x25295050, 0x00000572 411 }; 412 413 414 // compose TV register content 415 // as TV-Out uses a CRTC, it reprograms a PLL to create an unscaled image; 416 // as a result, you must not call Radeon_CalcPLLRegisters() afterwards 417 // TBD: what's special in terms of PLL in TV-Out mode? 418 void Radeon_CalcImpacTVRegisters( 419 accelerator_info *ai, display_mode *mode, 420 impactv_params *params, impactv_regs *values, int crtc_idx, 421 bool internal_encoder, tv_standard_e tv_format, display_device_e display_device ) 422 { 423 const tv_timing *timing = ¶ms->timing; 424 425 SHOW_FLOW0( 2, "" ); 426 427 if( tv_format < ts_ntsc || tv_format > ts_max ) 428 tv_format = ts_ntsc; 429 430 values->tv_ftotal = timing->f_total; 431 432 // RE: UV_THINNER should affect sharpness only, but the only effect is that 433 // the colour fades out, so I leave it zero 434 values->tv_vscaler_cntl1 = RADEON_TV_VSCALER_CNTL1_Y_W_EN; 435 436 values->tv_vscaler_cntl1 = 437 (values->tv_vscaler_cntl1 & 0xe3ff0000) | 438 params->uv_inc; 439 440 if( internal_encoder ) { 441 // RE: was on - update: disabling it breaks restart 442 values->tv_vscaler_cntl1 |= RADEON_TV_VSCALER_CNTL1_RESTART_FIELD; 443 if( mode->timing.h_display == 1024 ) 444 values->tv_vscaler_cntl1 |= 4 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT; 445 else 446 values->tv_vscaler_cntl1 |= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT; 447 } else { 448 values->tv_vscaler_cntl1 |= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT; 449 } 450 451 values->tv_y_saw_tooth_cntl = 452 params->y_saw_tooth_amp | 453 (params->y_saw_tooth_slope << RADEON_TV_Y_SAW_TOOTH_CNTL_SLOPE_SHIFT); 454 455 values->tv_y_fall_cntl = 456 params->y_fall_accum_init | 457 RADEON_TV_Y_FALL_CNTL_Y_FALL_PING_PONG | 458 (params->y_coeff_enable ? RADEON_TV_Y_FALL_CNTL_Y_COEFF_EN : 0) | 459 (params->y_coeff_value << RADEON_TV_Y_FALL_CNTL_Y_COEFF_VALUE_SHIFT); 460 461 values->tv_y_rise_cntl = 462 params->y_rise_accum_init | 463 RADEON_TV_Y_RISE_CNTL_Y_RISE_PING_PONG; 464 465 // RE: all dither flags/values were zero 466 values->tv_vscaler_cntl2 = 467 (values->tv_vscaler_cntl2 & 0x00fffff0) | 468 (params->uv_accum_init << RADEON_TV_VSCALER_CNTL2_UV_ACCUM_INIT_SHIFT); 469 470 if( internal_encoder ) { 471 values->tv_vscaler_cntl2 |= 472 RADEON_TV_VSCALER_CNTL2_DITHER_MODE | 473 RADEON_TV_VSCALER_CNTL2_Y_OUTPUT_DITHER_EN | 474 RADEON_TV_VSCALER_CNTL2_UV_OUTPUT_DITHER_EN | 475 RADEON_TV_VSCALER_CNTL2_UV_TO_BUF_DITHER_EN; 476 } 477 478 values->tv_hrestart = params->h_restart; 479 values->tv_vrestart = params->v_restart; 480 values->tv_frestart = params->f_restart; 481 482 values->tv_tv_pll_cntl = 483 (params->tv_dividers.ref & RADEON_TV_PLL_CNTL_TV_M0_LO_MASK) | 484 ((params->tv_dividers.feedback & RADEON_TV_PLL_CNTL_TV_N0_LO_MASK) 485 << RADEON_TV_PLL_CNTL_TV_N0_LO_SHIFT) | 486 ((params->tv_dividers.ref >> RADEON_TV_PLL_CNTL_TV_M0_LO_BITS) 487 << RADEON_TV_PLL_CNTL_TV_M0_HI_SHIFT) | 488 ((params->tv_dividers.feedback >> RADEON_TV_PLL_CNTL_TV_N0_LO_BITS) 489 << RADEON_TV_PLL_CNTL_TV_N0_HI_SHIFT) | 490 // RE: was on 491 //RADEON_TV_PLL_CNTL_TV_SLIP_EN | 492 (params->tv_dividers.post << RADEON_TV_PLL_CNTL_TV_P_SHIFT); //| 493 // RE: was on 494 //RADEON_TV_PLL_CNTL_TV_DTO_EN; 495 values->tv_crt_pll_cntl = 496 (params->crt_dividers.ref & RADEON_TV_CRT_PLL_CNTL_M0_LO_MASK) | 497 ((params->crt_dividers.feedback & RADEON_TV_CRT_PLL_CNTL_N0_LO_MASK) 498 << RADEON_TV_CRT_PLL_CNTL_N0_LO_SHIFT) | 499 ((params->crt_dividers.ref >> RADEON_TV_CRT_PLL_CNTL_M0_LO_BITS) 500 << RADEON_TV_CRT_PLL_CNTL_M0_HI_SHIFT) | 501 ((params->crt_dividers.feedback >> RADEON_TV_CRT_PLL_CNTL_N0_LO_BITS) 502 << RADEON_TV_CRT_PLL_CNTL_N0_HI_SHIFT) | 503 (params->crt_dividers.extra_post == 2 ? RADEON_TV_CRT_PLL_CNTL_CLKBY2 : 0); 504 505 // TK: from Gatos 506 // in terms of byte clock devider, I have no clue how that works, 507 // but leaving it 1 seems to be save 508 values->tv_clock_sel_cntl = 509 0x33 | 510 ((/*params->crt_dividers.post_code - 1*/0) << RADEON_TV_CLOCK_SEL_CNTL_BYTCLK_SHIFT) | 511 (1 << RADEON_TV_CLOCK_SEL_CNTL_BYTCLKD_SHIFT); 512 513 values->tv_clkout_cntl = 0x09; 514 if( !internal_encoder ) 515 values->tv_clkout_cntl |= 1 << 5; 516 517 values->tv_htotal = mode->timing.h_total - 1; 518 values->tv_hsize = mode->timing.h_display; 519 values->tv_hdisp = mode->timing.h_display - 1; 520 values->tv_hstart = 521 // TK: was -12, but this cuts off the left border of the image 522 internal_encoder ? 523 values->tv_hdisp + 1 - params->mode888 + 12 : 524 values->tv_hdisp + 1 - params->mode888 + 12; 525 526 values->tv_vtotal = mode->timing.v_total - 1; 527 values->tv_vdisp = mode->timing.v_display - 1; 528 values->tv_sync_size = mode->timing.h_display + 8; 529 530 values->tv_timing_cntl = 531 (values->tv_timing_cntl & 0xfffff000) | 532 params->h_inc; 533 534 if( ai->si->asic >= rt_r300 ) { 535 // this is a hack to fix improper UV scaling 536 // (at least this is what the sample code says) 537 values->tv_timing_cntl = 538 (values->tv_timing_cntl & 0x00ffffff) | 539 ((0x72 * 640 / mode->timing.h_display) 540 << RADEON_TV_TIMING_CNTL_UV_OUTPUT_POST_SCALE_SHIFT); 541 } 542 543 if( internal_encoder ) { 544 // tell TV-DAC to generate proper NTSC/PAL signal 545 values->tv_dac_cntl = 546 RADEON_TV_DAC_CNTL_NBLANK | 547 RADEON_TV_DAC_CNTL_NHOLD | 548 (8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) | 549 (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT); 550 551 switch( tv_format ) { 552 case ts_ntsc: 553 values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_NTSC; 554 break; 555 556 case ts_pal_bdghi: 557 case ts_pal_m: 558 case ts_pal_nc: 559 case ts_scart_pal: 560 case ts_pal_60: 561 values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_PAL; 562 break; 563 default: 564 ; 565 } 566 567 // enable composite or S-Video DAC 568 values->tv_dac_cntl |= 569 RADEON_TV_DAC_CNTL_RDACPD | 570 RADEON_TV_DAC_CNTL_GDACPD | 571 RADEON_TV_DAC_CNTL_BDACPD; 572 573 if( (display_device & dd_ctv) != 0 ) { 574 values->tv_dac_cntl &= 575 ~RADEON_TV_DAC_CNTL_BDACPD; 576 } 577 578 if( (display_device & dd_stv) != 0 ) { 579 values->tv_dac_cntl &= 580 ~(RADEON_TV_DAC_CNTL_RDACPD | 581 RADEON_TV_DAC_CNTL_GDACPD); 582 } 583 } else { 584 values->tv_dac_cntl = 585 (values->tv_dac_cntl & ~(RADEON_TV_DAC_CNTL_STD_NTSC | 0x88 | 586 RADEON_TV_DAC_CNTL_BGSLEEP | RADEON_TV_DAC_CNTL_PEDESTAL)) | 587 RADEON_TV_DAC_CNTL_DETECT | 588 RADEON_TV_DAC_CNTL_NBLANK | 589 RADEON_TV_DAC_CNTL_NHOLD; 590 } 591 592 values->tv_modulator_cntl1 &= ~( 593 RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | 594 RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | 595 RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_MASK | 596 RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_MASK); 597 598 switch( tv_format ) { 599 case ts_ntsc: 600 // RE: typo? 601 //values->tv_dac_cntl |= 602 values->tv_modulator_cntl1 |= 603 RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | 604 (0x46 << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) | 605 (0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT); 606 values->tv_modulator_cntl2 = 607 (-111 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) | 608 ((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT); 609 break; 610 611 case ts_pal_bdghi: 612 values->tv_modulator_cntl1 |= 613 RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | 614 RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL | 615 (0x3b << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) | 616 (0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT); 617 values->tv_modulator_cntl2 = 618 (-78 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) | 619 ((62 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT); 620 break; 621 622 case ts_scart_pal: 623 // from register spec 624 values->tv_modulator_cntl1 |= 625 RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN | 626 RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL; 627 values->tv_modulator_cntl2 = 628 (0 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) | 629 ((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT); 630 break; 631 632 default: 633 // there are many formats missing, sigh... 634 ; 635 } 636 637 // RE: 638 values->tv_modulator_cntl1 |= 639 RADEON_TV_MODULATOR_CNTL1_YFLT_EN | 640 RADEON_TV_MODULATOR_CNTL1_UVFLT_EN | 641 RADEON_TV_MODULATOR_CNTL1_SLEW_RATE_LIMIT | 642 (2 << RADEON_TV_MODULATOR_CNTL1_CY_FILT_BLEND_SHIFT); 643 644 if( internal_encoder ) { 645 values->tv_data_delay_a = 0x0b0c0a06; 646 values->tv_data_delay_b = 0x070a0a0c; 647 } else { 648 values->tv_data_delay_a = 0x07080604; 649 values->tv_data_delay_b = 0x03070607; 650 } 651 652 values->tv_frame_lock_cntl = internal_encoder ? 0 : 0xf0f; 653 654 if( internal_encoder ) { 655 values->tv_pll_cntl1 = 656 (4 << RADEON_TV_PLL_CNTL1_TVPCP_SHIFT) | 657 (4 << RADEON_TV_PLL_CNTL1_TVPVG_SHIFT) | 658 // RE: was 2 659 (1 << RADEON_TV_PLL_CNTL1_TVPDC_SHIFT) | 660 RADEON_TV_PLL_CNTL1_TVCLK_SRC_SEL_TVPLLCLK | 661 RADEON_TV_PLL_CNTL1_TVPLL_TEST; 662 663 values->tv_rgb_cntl = 664 ((crtc_idx == 1 ? 2 : 0) << RADEON_TV_RGB_CNTL_RGB_SRC_SEL_SHIFT) | 665 RADEON_TV_RGB_CNTL_RGB_DITHER_EN | 666 (0xb << RADEON_TV_RGB_CNTL_UVRAM_READ_MARGIN_SHIFT) | 667 (7 << RADEON_TV_RGB_CNTL_FIFORAM_FIFOMACRO_READ_MARGIN_SHIFT); 668 669 // RE: 670 values->tv_rgb_cntl |= 0x4000000; 671 672 values->tv_pre_dac_mux_cntl = 673 RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | 674 RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | 675 RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | 676 RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN; 677 678 // RE: 679 /* | 680 (0x2c << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/ 681 } else { 682 // this register seems to have completely different meaning on Theatre chip 683 values->tv_pll_cntl1 = 684 (1 << 3) | (1 << 4) | (4 << 8) | (1 << 11) 685 | (5 << 13) | (4 << 16) | (1 << 19) | (5 << 21); 686 687 // this one too 688 values->tv_rgb_cntl = params->mode888; 689 690 values->tv_pre_dac_mux_cntl = 691 RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | 692 RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN | 693 RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | 694 RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN; 695 // RE: 696 /*(0xaf << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/ 697 } 698 699 values->tv_pll_fine_cntl = 0; 700 701 // TBD: this is certainly broken 702 // (they do an ((orig & 0xe0) & 0x600) which is constant zero) 703 values->tv_master_cntl = 704 RADEON_TV_MASTER_CNTL_CRT_FIFO_CE_EN | 705 RADEON_TV_MASTER_CNTL_TV_FIFO_CE_EN; 706 707 if( tv_format == ts_ntsc ) 708 values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX; 709 else 710 values->tv_master_cntl &= ~RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX; 711 712 // this is missing in the sample code 713 if( internal_encoder ) 714 values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_TV_ON; 715 else 716 values->tv_master_cntl |= 717 RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX | // RE: guessed 718 719 RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST | 720 RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST | 721 RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST; 722 723 values->tv_gain_limit_settings = 0x017f05ff; 724 values->tv_linear_gain_settings = 0x01000100; 725 values->tv_upsamp_and_gain_cntl = 0x00000005; 726 values->tv_crc_cntl = 0; 727 728 SHOW_FLOW( 2, "tv_master_cntl=%x", values->tv_master_cntl ); 729 730 memcpy( values->tv_upsample_filter_coeff, std_upsample_filter_coeff, 731 RADEON_TV_UPSAMP_COEFF_NUM * sizeof( uint32 )); 732 733 // setup output timing 734 memcpy( values->tv_hor_timing, hor_timings[tv_format-1], 735 RADEON_TV_TIMING_SIZE * sizeof( uint16 )); 736 memcpy( values->tv_vert_timing, vert_timings[tv_format-1], 737 RADEON_TV_TIMING_SIZE * sizeof( uint16 ) ); 738 739 // arbitrary position of vertical timing table in FIFO 740 values->tv_uv_adr = TV_UV_ADR_INI; 741 } 742 743 744 // get address of horizontal timing table in FIFO 745 static uint16 getHorTimingTableAddr( 746 impactv_regs *values, bool internal_encoder ) 747 { 748 switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_HCODE_TABLE_SEL_MASK) 749 >> RADEON_TV_UV_ADR_HCODE_TABLE_SEL_SHIFT ) 750 { 751 case 0: 752 return internal_encoder ? RADEON_TV_MAX_FIFO_ADDR_INTERN : RADEON_TV_MAX_FIFO_ADDR; 753 754 case 1: 755 return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK) 756 >> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2; 757 case 2: 758 return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK) 759 >> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2; 760 761 default: 762 return 0; 763 } 764 } 765 766 // get address of vertical timing table in FIFO 767 static uint16 getVertTimingTableAddr( 768 impactv_regs *values ) 769 { 770 switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_VCODE_TABLE_SEL_MASK) 771 >> RADEON_TV_UV_ADR_VCODE_TABLE_SEL_SHIFT ) 772 { 773 case 0: 774 return ((values->tv_uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK) 775 >> RADEON_TV_UV_ADR_MAX_UV_ADR_SHIFT) * 2 + 1; 776 777 case 1: 778 return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK) 779 >> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2 + 1; 780 781 case 2: 782 return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK) 783 >> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2 + 1; 784 785 default: 786 return 0; 787 } 788 } 789 790 791 // write horizontal timing table 792 void Radeon_ImpacTVwriteHorTimingTable( 793 accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values, bool internal_encoder ) 794 { 795 uint16 addr = getHorTimingTableAddr( values, internal_encoder ); 796 int i; 797 798 for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2, --addr ) { 799 uint32 value = 800 ((uint32)values->tv_hor_timing[i] << 14) | 801 values->tv_hor_timing[i + 1]; 802 803 write( ai, addr, value ); 804 805 if( values->tv_hor_timing[i] == 0 || 806 values->tv_hor_timing[i + 1] == 0 ) 807 break; 808 } 809 } 810 811 812 // write vertical timing table 813 void Radeon_ImpacTVwriteVertTimingTable( 814 accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values ) 815 { 816 uint16 addr = getVertTimingTableAddr( values ); 817 int i; 818 819 for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2 , ++addr ) { 820 uint32 value = 821 ((uint32)values->tv_vert_timing[i + 1] << 14) | 822 values->tv_vert_timing[i]; 823 824 write( ai, addr, value ); 825 826 if( values->tv_vert_timing[i + 1] == 0 || 827 values->tv_vert_timing[i] == 0 ) 828 break; 829 } 830 } 831