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