vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon / impactv.c
blob823ee8dbd834e1336937526ee0ee21dfd6036d8b
1 /*
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.
9 */
11 #include "radeon_interface.h"
12 #include "radeon_accelerant.h"
14 #include "tv_out_regs.h"
15 #include "utils.h"
16 #include "set_mode.h"
18 #include <string.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;
37 int line;
38 uint32 how_early = 0;
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
43 h_first = 9;
44 f_first = 0;
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 ) {
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);
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
68 first_num =
69 f_first * mode->timing.v_total * mode->timing.h_total
70 + v_first * mode->timing.h_total
71 + h_first;
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 =
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;
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 );
99 //first_num = 625592;
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 )
144 int flicker_removal;
145 uint i;
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] )
155 break;
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;
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;
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 )
195 uint16
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;
218 // this is a start
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,
230 0x201b, 0
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,
241 0x201b, 0
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[] = {
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
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
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
306 timing->flags = 0;
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 )
336 tv_format = ts_ntsc;
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, &params->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
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 &params->crt_dividers, tweaked_mode );
360 // adopt synchronization to make tweaked mode look like original mode
361 Radeon_AdoptSync( mode, tweaked_mode );
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;
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 );
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;
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 = &params->timing;
423 SHOW_FLOW0( 2, "" );
425 if( tv_format < ts_ntsc || tv_format > ts_max )
426 tv_format = ts_ntsc;
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) |
436 params->uv_inc;
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;
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) |
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);
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);
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;
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;
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) |
530 params->h_inc;
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 ) {
550 case ts_ntsc:
551 values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_NTSC;
552 break;
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:
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);
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;
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 ) {
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;
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;
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;
630 default:
631 // there are many formats missing, sigh...
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);
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;
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) |
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;
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);
667 // RE:
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;
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);
685 // this one too
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;
693 // RE:
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;
707 else
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;
713 else
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 )
749 case 0:
750 return internal_encoder ? RADEON_TV_MAX_FIFO_ADDR_INTERN : RADEON_TV_MAX_FIFO_ADDR;
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;
759 default:
760 return 0;
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 )
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;
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;
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;
783 default:
784 return 0;
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 );
794 int i;
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];
801 write( ai, addr, value );
803 if( values->tv_hor_timing[i] == 0 ||
804 values->tv_hor_timing[i + 1] == 0 )
805 break;
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 );
815 int i;
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];
822 write( ai, addr, value );
824 if( values->tv_vert_timing[i + 1] == 0 ||
825 values->tv_vert_timing[i] == 0 )
826 break;