2 Copyright (c) 2002-04, Thomas Kurschel
5 Part of Radeon accelerant
7 ImpacTV programming. As this unit is contained in various chips,
8 the code to actually access the unit is separated.
11 #include "radeon_interface.h"
12 #include "radeon_accelerant.h"
14 #include "tv_out_regs.h"
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)
25 // fixed point resolution of UV scaler initialization (uv_accum_init)
26 #define TV_UV_INIT_FIX_SHIFT 6
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
)
34 uint32 h_first
, v_first
= 0, f_first
;
35 uint32 tmp_uv_accum_sum
;
36 uint16 uv_accum_frac
, uv_accum_int
;
39 int32 first_num
, restart_to_first_active_pixel_to_FIFO
;
40 uint32 time_to_active
;
42 // this is all black magic - you are not supposed to understand this
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;
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 ) {
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);
65 SHOW_FLOW( 3, "f_first=%d, v_first=%d, h_first=%d", f_first
, v_first
, h_first
);
67 // theoretical time when restart should be started
69 f_first
* mode
->timing
.v_total
* mode
->timing
.h_total
70 + v_first
* mode
->timing
.h_total
73 first_num
+= (how_early
+ TV_UV_INC_FIX_SCALE
/ 2) >> TV_UV_INC_FIX_SHIFT
;
75 SHOW_FLOW( 3, "first_num=%d", first_num
);
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;
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
);
84 // get delay until first bytes can be read from FIFO
85 restart_to_first_active_pixel_to_FIFO
=
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;
92 // do restart a bit early to compensate delays
93 first_num
-= restart_to_first_active_pixel_to_FIFO
;
95 SHOW_FLOW( 3, "restart_to_first_active_pixel_to_FIFO=%d", restart_to_first_active_pixel_to_FIFO
);
97 SHOW_FLOW( 3, "after delay compensation first_num=%d", first_num
);
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
;
105 //SHOW_FLOW( 2, "first_num=%d", first_num );
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
;
114 /*params->v_restart = 623;
115 params->h_restart = 580;*/
117 SHOW_FLOW( 2, "Restart in frame %d, line %d, pixel %d",
118 params
->f_restart
, params
->v_restart
, params
->h_restart
);
122 // thresholds for flicker fixer algorithm
123 static int8 y_flicker_removal
[5] = { 6, 5, 4, 3, 2 };
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 };
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)
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)
140 // calculate flicker fixer parameters
141 static void Radeon_CalcImpacTVFlickerFixer(
142 impactv_params
*params
)
146 int lower_border
, upper_border
;
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
);
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
] )
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;
162 flicker_removal
= y_flicker_removal
[i
];
164 SHOW_FLOW( 3, "flicker removal=%d", flicker_removal
);
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
;
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
)) );
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
)))
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
;
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
;
186 params
->y_coeff_enable
= y_coeff_enable
[i
];
187 params
->y_coeff_value
= y_coeff_value
[i
] * TV_Y_COEFF_FIX_SCALE
/ 8;
191 // correct sync position after tweaking total size
192 static void Radeon_AdoptSync(
193 const display_mode
*mode
, display_mode
*tweaked_mode
)
196 h_over_plus
, h_sync_width
, tweaked_h_over_plus
,
197 v_over_plus
, v_sync_width
, tweaked_v_over_plus
;
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
;
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
);
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
;
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
;
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
);
217 // we really should verify whether the resulting mode is still valid;
219 tweaked_v_over_plus
= min( 1, tweaked_v_over_plus
);
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
;
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,
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
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,
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
249 static const uint16
*hor_timings
[] = {
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
258 static const uint16
*vert_timings
[] = {
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
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 */
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
)
287 const tv_timing
*tv_timing
= &radeon_std_tv_timing
[tv_format
-1];
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;
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
;
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
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
);
319 #define TV_VERT_LEAD_IN_LINES 2
320 #define TV_UV_ADR_INI 0xc8
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
)
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];
332 SHOW_FLOW( 2, "internal_encoder=%s, format=%d",
333 internal_encoder
? "yes" : "no", tv_format
);
335 if( tv_format
< ts_ntsc
|| tv_format
> ts_max
)
338 params
->mode888
= true;
339 params
->timing
= *tv_timing
;
341 Radeon_GetTVPLLConfiguration( general_pll
, &tv_pll
, internal_encoder
);
342 Radeon_CalcPLLDividers( &tv_pll
, tv_timing
->freq
, 0, ¶ms
->tv_dividers
);
344 Radeon_GetTVCRTPLLConfiguration( general_pll
, &crt_pll
, internal_encoder
);
346 // initially, we try to keep to requested mode
347 *tweaked_mode
= *mode
;
349 Radeon_MakeOverscanMode( &tweaked_mode
->timing
, tv_format
);
351 // tweak CRT mode if necessary to match TV frame timing
354 tv_timing
->v_total
, tv_timing
->h_total
, tv_timing
->frame_size_adjust
,
357 internal_encoder
? 0/*6*/ : 0, 2 + params
->mode888
,
358 ¶ms
->crt_dividers
, tweaked_mode
);
360 // adopt synchronization to make tweaked mode look like original mode
361 Radeon_AdoptSync( mode
, tweaked_mode
);
365 tv_timing
->h_sync_len
366 + tv_timing
->h_setup_delay
367 + tv_timing
->h_active_delay
368 - tv_timing
->h_genclk_delay
;
370 lines_before_active
=
371 (tv_timing
->v_field_total
- tv_timing
->v_active_lines
) / 2 - 1
372 - TV_VERT_LEAD_IN_LINES
+ 1;
374 SHOW_FLOW( 3, "lines_before_active=%d, start_line=%d", lines_before_active
, start_line
);
376 params
->tv_clocks_to_active
= (uint32
)lines_before_active
* tv_timing
->h_total
+ start_line
;
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
;
390 SHOW_FLOW( 3, "uv_inc=%d", params
->uv_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
;
396 Radeon_CalcImpacTVRestart( params
, tweaked_mode
,
397 tv_timing
->h_total
- tv_timing
->h_active_len
, tv_timing
->f_total
);
398 Radeon_CalcImpacTVFlickerFixer( params
);
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
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
)
421 const tv_timing
*timing
= ¶ms
->timing
;
425 if( tv_format
< ts_ntsc
|| tv_format
> ts_max
)
428 values
->tv_ftotal
= timing
->f_total
;
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
;
434 values
->tv_vscaler_cntl1
=
435 (values
->tv_vscaler_cntl1
& 0xe3ff0000) |
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
;
444 values
->tv_vscaler_cntl1
|= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT
;
446 values
->tv_vscaler_cntl1
|= 2 << RADEON_TV_VSCALER_CNTL1_Y_DEL_W_SIG_SHIFT
;
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
);
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
);
459 values
->tv_y_rise_cntl
=
460 params
->y_rise_accum_init
|
461 RADEON_TV_Y_RISE_CNTL_Y_RISE_PING_PONG
;
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
);
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
;
476 values
->tv_hrestart
= params
->h_restart
;
477 values
->tv_vrestart
= params
->v_restart
;
478 values
->tv_frestart
= params
->f_restart
;
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
) |
489 //RADEON_TV_PLL_CNTL_TV_SLIP_EN |
490 (params
->tv_dividers
.post
<< RADEON_TV_PLL_CNTL_TV_P_SHIFT
); //|
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);
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
=
508 ((/*params->crt_dividers.post_code - 1*/0) << RADEON_TV_CLOCK_SEL_CNTL_BYTCLK_SHIFT
) |
509 (1 << RADEON_TV_CLOCK_SEL_CNTL_BYTCLKD_SHIFT
);
511 values
->tv_clkout_cntl
= 0x09;
512 if( !internal_encoder
)
513 values
->tv_clkout_cntl
|= 1 << 5;
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;
519 // TK: was -12, but this cuts off the left border of the image
521 values
->tv_hdisp
+ 1 - params
->mode888
+ 12 :
522 values
->tv_hdisp
+ 1 - params
->mode888
+ 12;
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;
528 values
->tv_timing_cntl
=
529 (values
->tv_timing_cntl
& 0xfffff000) |
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
);
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
);
549 switch( tv_format
) {
551 values
->tv_dac_cntl
|= RADEON_TV_DAC_CNTL_STD_NTSC
;
559 values
->tv_dac_cntl
|= RADEON_TV_DAC_CNTL_STD_PAL
;
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
;
571 if( (display_device
& dd_ctv
) != 0 ) {
572 values
->tv_dac_cntl
&=
573 ~RADEON_TV_DAC_CNTL_BDACPD
;
576 if( (display_device
& dd_stv
) != 0 ) {
577 values
->tv_dac_cntl
&=
578 ~(RADEON_TV_DAC_CNTL_RDACPD
|
579 RADEON_TV_DAC_CNTL_GDACPD
);
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
;
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
);
596 switch( tv_format
) {
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
);
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
);
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
);
631 // there are many formats missing, sigh...
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
);
642 if( internal_encoder
) {
643 values
->tv_data_delay_a
= 0x0b0c0a06;
644 values
->tv_data_delay_b
= 0x070a0a0c;
646 values
->tv_data_delay_a
= 0x07080604;
647 values
->tv_data_delay_b
= 0x03070607;
650 values
->tv_frame_lock_cntl
= internal_encoder
? 0 : 0xf0f;
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
) |
657 (1 << RADEON_TV_PLL_CNTL1_TVPDC_SHIFT
) |
658 RADEON_TV_PLL_CNTL1_TVCLK_SRC_SEL_TVPLLCLK
|
659 RADEON_TV_PLL_CNTL1_TVPLL_TEST
;
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
);
668 values
->tv_rgb_cntl
|= 0x4000000;
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
;
678 (0x2c << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/
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);
686 values
->tv_rgb_cntl
= params
->mode888
;
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
;
694 /*(0xaf << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/
697 values
->tv_pll_fine_cntl
= 0;
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
;
705 if( tv_format
== ts_ntsc
)
706 values
->tv_master_cntl
|= RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX
;
708 values
->tv_master_cntl
&= ~RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX
;
710 // this is missing in the sample code
711 if( internal_encoder
)
712 values
->tv_master_cntl
|= RADEON_TV_MASTER_CNTL_TV_ON
;
714 values
->tv_master_cntl
|=
715 RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX
| // RE: guessed
717 RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST
|
718 RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST
|
719 RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST
;
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;
726 SHOW_FLOW( 2, "tv_master_cntl=%x", values
->tv_master_cntl
);
728 memcpy( values
->tv_upsample_filter_coeff
, std_upsample_filter_coeff
,
729 RADEON_TV_UPSAMP_COEFF_NUM
* sizeof( uint32
));
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
) );
737 // arbitrary position of vertical timing table in FIFO
738 values
->tv_uv_adr
= TV_UV_ADR_INI
;
742 // get address of horizontal timing table in FIFO
743 static uint16
getHorTimingTableAddr(
744 impactv_regs
*values
, bool internal_encoder
)
746 switch( (values
->tv_uv_adr
& RADEON_TV_UV_ADR_HCODE_TABLE_SEL_MASK
)
747 >> RADEON_TV_UV_ADR_HCODE_TABLE_SEL_SHIFT
)
750 return internal_encoder
? RADEON_TV_MAX_FIFO_ADDR_INTERN
: RADEON_TV_MAX_FIFO_ADDR
;
753 return ((values
->tv_uv_adr
& RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK
)
754 >> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT
) * 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;
764 // get address of vertical timing table in FIFO
765 static uint16
getVertTimingTableAddr(
766 impactv_regs
*values
)
768 switch( (values
->tv_uv_adr
& RADEON_TV_UV_ADR_VCODE_TABLE_SEL_MASK
)
769 >> RADEON_TV_UV_ADR_VCODE_TABLE_SEL_SHIFT
)
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;
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;
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;
789 // write horizontal timing table
790 void Radeon_ImpacTVwriteHorTimingTable(
791 accelerator_info
*ai
, impactv_write_FIFO write
, impactv_regs
*values
, bool internal_encoder
)
793 uint16 addr
= getHorTimingTableAddr( values
, internal_encoder
);
796 for( i
= 0; i
< RADEON_TV_TIMING_SIZE
; i
+= 2, --addr
) {
798 ((uint32
)values
->tv_hor_timing
[i
] << 14) |
799 values
->tv_hor_timing
[i
+ 1];
801 write( ai
, addr
, value
);
803 if( values
->tv_hor_timing
[i
] == 0 ||
804 values
->tv_hor_timing
[i
+ 1] == 0 )
810 // write vertical timing table
811 void Radeon_ImpacTVwriteVertTimingTable(
812 accelerator_info
*ai
, impactv_write_FIFO write
, impactv_regs
*values
)
814 uint16 addr
= getVertTimingTableAddr( values
);
817 for( i
= 0; i
< RADEON_TV_TIMING_SIZE
; i
+= 2 , ++addr
) {
819 ((uint32
)values
->tv_vert_timing
[i
+ 1] << 14) |
820 values
->tv_vert_timing
[i
];
822 write( ai
, addr
, value
);
824 if( values
->tv_vert_timing
[i
+ 1] == 0 ||
825 values
->tv_vert_timing
[i
] == 0 )