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
30static 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
123static int8 y_flicker_removal[5] = { 6, 5, 4, 3, 2 };
124
125// associated filter parameters scaled by 8(!)
126static int8 y_saw_tooth_slope[5] = { 1, 2, 2, 4, 8 };
127// these values are not scaled
128static int8 y_coeff_value[5] = { 2, 2, 0, 4, 0 };
129static 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
141static 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
192static 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
226static 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
233static 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
238static 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
244static 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
249static 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
258static 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
270static 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!
284static 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
323void 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, &params->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		&params->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)
403static 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?
416void 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 = &params->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		values->tv_hdisp + 1 - params->mode888 + 12;
521
522	values->tv_vtotal = mode->timing.v_total - 1;
523	values->tv_vdisp = mode->timing.v_display - 1;
524	values->tv_sync_size = mode->timing.h_display + 8;
525
526	values->tv_timing_cntl =
527		(values->tv_timing_cntl & 0xfffff000) |
528		params->h_inc;
529
530	if( ai->si->asic >= rt_r300 ) {
531		// this is a hack to fix improper UV scaling
532		// (at least this is what the sample code says)
533		values->tv_timing_cntl =
534			(values->tv_timing_cntl & 0x00ffffff) |
535			((0x72 * 640 / mode->timing.h_display)
536				<< RADEON_TV_TIMING_CNTL_UV_OUTPUT_POST_SCALE_SHIFT);
537	}
538
539	if( internal_encoder ) {
540		// tell TV-DAC to generate proper NTSC/PAL signal
541		values->tv_dac_cntl =
542			RADEON_TV_DAC_CNTL_NBLANK |
543			RADEON_TV_DAC_CNTL_NHOLD |
544			(8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) |
545			(6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT);
546
547		switch( tv_format ) {
548		case ts_ntsc:
549			values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_NTSC;
550			break;
551
552		case ts_pal_bdghi:
553		case ts_pal_m:
554		case ts_pal_nc:
555		case ts_scart_pal:
556		case ts_pal_60:
557			values->tv_dac_cntl |= RADEON_TV_DAC_CNTL_STD_PAL;
558			break;
559		default:
560			;
561		}
562
563		// enable composite or S-Video DAC
564		values->tv_dac_cntl |=
565			RADEON_TV_DAC_CNTL_RDACPD |
566			RADEON_TV_DAC_CNTL_GDACPD |
567			RADEON_TV_DAC_CNTL_BDACPD;
568
569		if( (display_device & dd_ctv) != 0 ) {
570			values->tv_dac_cntl &=
571				~RADEON_TV_DAC_CNTL_BDACPD;
572		}
573
574		if( (display_device & dd_stv) != 0 ) {
575			values->tv_dac_cntl &=
576				~(RADEON_TV_DAC_CNTL_RDACPD |
577				  RADEON_TV_DAC_CNTL_GDACPD);
578		}
579	} else {
580		values->tv_dac_cntl =
581			(values->tv_dac_cntl & ~(RADEON_TV_DAC_CNTL_STD_NTSC | 0x88 |
582				RADEON_TV_DAC_CNTL_BGSLEEP | RADEON_TV_DAC_CNTL_PEDESTAL)) |
583			RADEON_TV_DAC_CNTL_DETECT |
584			RADEON_TV_DAC_CNTL_NBLANK |
585			RADEON_TV_DAC_CNTL_NHOLD;
586	}
587
588	values->tv_modulator_cntl1 &= ~(
589		RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN |
590		RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL |
591		RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_MASK |
592		RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_MASK);
593
594	switch( tv_format ) {
595	case ts_ntsc:
596		// RE: typo?
597		//values->tv_dac_cntl |=
598		values->tv_modulator_cntl1 |=
599			RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL |
600			(0x46 << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) |
601			(0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT);
602		values->tv_modulator_cntl2 =
603			(-111 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) |
604			((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT);
605		break;
606
607	case ts_pal_bdghi:
608		values->tv_modulator_cntl1 |=
609			RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN |
610			RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL |
611			(0x3b << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) |
612			(0x3b << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT);
613		values->tv_modulator_cntl2 =
614			(-78 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) |
615			((62 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT);
616		break;
617
618	case ts_scart_pal:
619		// from register spec
620		values->tv_modulator_cntl1 |=
621			RADEON_TV_MODULATOR_CNTL1_ALT_PHASE_EN |
622			RADEON_TV_MODULATOR_CNTL1_SYNC_TIP_LEVEL;
623		values->tv_modulator_cntl2 =
624			(0 & TV_MODULATOR_CNTL2_U_BURST_LEVEL_MASK) |
625			((0 & TV_MODULATOR_CNTL2_V_BURST_LEVEL_MASK) << TV_MODULATOR_CNTL2_V_BURST_LEVEL_SHIFT);
626		break;
627
628    default:
629		// there are many formats missing, sigh...
630		;
631    }
632
633    // RE:
634    values->tv_modulator_cntl1 |=
635    	RADEON_TV_MODULATOR_CNTL1_YFLT_EN |
636    	RADEON_TV_MODULATOR_CNTL1_UVFLT_EN |
637    	RADEON_TV_MODULATOR_CNTL1_SLEW_RATE_LIMIT |
638    	(2 << RADEON_TV_MODULATOR_CNTL1_CY_FILT_BLEND_SHIFT);
639
640	if( internal_encoder ) {
641		values->tv_data_delay_a = 0x0b0c0a06;
642		values->tv_data_delay_b = 0x070a0a0c;
643	} else {
644		values->tv_data_delay_a = 0x07080604;
645		values->tv_data_delay_b = 0x03070607;
646	}
647
648	values->tv_frame_lock_cntl = internal_encoder ? 0 : 0xf0f;
649
650	if( internal_encoder ) {
651		values->tv_pll_cntl1 =
652			(4 << RADEON_TV_PLL_CNTL1_TVPCP_SHIFT) |
653			(4 << RADEON_TV_PLL_CNTL1_TVPVG_SHIFT) |
654			// RE: was 2
655			(1 << RADEON_TV_PLL_CNTL1_TVPDC_SHIFT) |
656			RADEON_TV_PLL_CNTL1_TVCLK_SRC_SEL_TVPLLCLK |
657			RADEON_TV_PLL_CNTL1_TVPLL_TEST;
658
659		values->tv_rgb_cntl =
660			((crtc_idx == 1 ? 2 : 0) << RADEON_TV_RGB_CNTL_RGB_SRC_SEL_SHIFT) |
661			RADEON_TV_RGB_CNTL_RGB_DITHER_EN |
662			(0xb << RADEON_TV_RGB_CNTL_UVRAM_READ_MARGIN_SHIFT) |
663			(7 << RADEON_TV_RGB_CNTL_FIFORAM_FIFOMACRO_READ_MARGIN_SHIFT);
664
665		// RE:
666		values->tv_rgb_cntl |= 0x4000000;
667
668		values->tv_pre_dac_mux_cntl =
669			RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN |
670			RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN |
671			RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN |
672			RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN;
673
674		// RE:
675		/* |
676			(0x2c << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/
677	} else {
678		// this register seems to have completely different meaning on Theatre chip
679		values->tv_pll_cntl1 =
680			(1 << 3) | (1 << 4) | (4 << 8) | (1 << 11)
681		    | (5 << 13) | (4 << 16) | (1 << 19) | (5 << 21);
682
683		// this one too
684		values->tv_rgb_cntl = params->mode888;
685
686		values->tv_pre_dac_mux_cntl =
687			RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN |
688			RADEON_TV_PRE_DAC_MUX_CNTL_C_GRN_EN |
689			RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN |
690			RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN;
691			// RE:
692			/*(0xaf << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT);*/
693	}
694
695	values->tv_pll_fine_cntl = 0;
696
697	// TBD: this is certainly broken
698	// (they do an ((orig & 0xe0) & 0x600) which is constant zero)
699	values->tv_master_cntl =
700		RADEON_TV_MASTER_CNTL_CRT_FIFO_CE_EN |
701		RADEON_TV_MASTER_CNTL_TV_FIFO_CE_EN;
702
703	if( tv_format == ts_ntsc )
704		values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX;
705	else
706		values->tv_master_cntl &= ~RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX;
707
708	// this is missing in the sample code
709	if( internal_encoder )
710		values->tv_master_cntl |= RADEON_TV_MASTER_CNTL_TV_ON;
711	else
712		values->tv_master_cntl |=
713			RADEON_TV_MASTER_CNTL_RESTART_PHASE_FIX | // RE: guessed
714
715			RADEON_TV_MASTER_CNTL_VIN_ASYNC_RST |
716			RADEON_TV_MASTER_CNTL_AUD_ASYNC_RST |
717			RADEON_TV_MASTER_CNTL_DVS_ASYNC_RST;
718
719	values->tv_gain_limit_settings = 0x017f05ff;
720	values->tv_linear_gain_settings = 0x01000100;
721	values->tv_upsamp_and_gain_cntl = 0x00000005;
722	values->tv_crc_cntl = 0;
723
724	SHOW_FLOW( 2, "tv_master_cntl=%x", values->tv_master_cntl );
725
726	memcpy( values->tv_upsample_filter_coeff, std_upsample_filter_coeff,
727		RADEON_TV_UPSAMP_COEFF_NUM * sizeof( uint32 ));
728
729	// setup output timing
730	memcpy( values->tv_hor_timing, hor_timings[tv_format-1],
731		RADEON_TV_TIMING_SIZE * sizeof( uint16 ));
732	memcpy( values->tv_vert_timing, vert_timings[tv_format-1],
733		RADEON_TV_TIMING_SIZE * sizeof( uint16 ) );
734
735	// arbitrary position of vertical timing table in FIFO
736	values->tv_uv_adr = TV_UV_ADR_INI;
737}
738
739
740// get address of horizontal timing table in FIFO
741static uint16 getHorTimingTableAddr(
742	impactv_regs *values, bool internal_encoder )
743{
744	switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_HCODE_TABLE_SEL_MASK)
745		>> RADEON_TV_UV_ADR_HCODE_TABLE_SEL_SHIFT )
746	{
747	case 0:
748		return internal_encoder ? RADEON_TV_MAX_FIFO_ADDR_INTERN : RADEON_TV_MAX_FIFO_ADDR;
749
750	case 1:
751		return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK)
752			>> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2;
753	case 2:
754		return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK)
755			>> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2;
756
757	default:
758		return 0;
759	}
760}
761
762// get address of vertical timing table in FIFO
763static uint16 getVertTimingTableAddr(
764	impactv_regs *values )
765{
766	switch( (values->tv_uv_adr & RADEON_TV_UV_ADR_VCODE_TABLE_SEL_MASK)
767		>> RADEON_TV_UV_ADR_VCODE_TABLE_SEL_SHIFT )
768	{
769	case 0:
770		return ((values->tv_uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK)
771			>> RADEON_TV_UV_ADR_MAX_UV_ADR_SHIFT) * 2 + 1;
772
773	case 1:
774		return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE1_BOT_ADR_MASK)
775			>> RADEON_TV_UV_ADR_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
776
777	case 2:
778		return ((values->tv_uv_adr & RADEON_TV_UV_ADR_TABLE3_TOP_ADR_MASK)
779			>> RADEON_TV_UV_ADR_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
780
781	default:
782		return 0;
783	}
784}
785
786
787// write horizontal timing table
788void Radeon_ImpacTVwriteHorTimingTable(
789	accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values, bool internal_encoder )
790{
791	uint16 addr = getHorTimingTableAddr( values, internal_encoder );
792	int i;
793
794	for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2, --addr ) {
795		uint32 value =
796			((uint32)values->tv_hor_timing[i] << 14) |
797			values->tv_hor_timing[i + 1];
798
799		write( ai, addr, value );
800
801		if( values->tv_hor_timing[i] == 0 ||
802			values->tv_hor_timing[i + 1] == 0 )
803			break;
804	}
805}
806
807
808// write vertical timing table
809void Radeon_ImpacTVwriteVertTimingTable(
810	accelerator_info *ai, impactv_write_FIFO write, impactv_regs *values )
811{
812	uint16 addr = getVertTimingTableAddr( values );
813	int i;
814
815	for( i = 0; i < RADEON_TV_TIMING_SIZE; i += 2 , ++addr ) {
816		uint32 value =
817			((uint32)values->tv_vert_timing[i + 1] << 14) |
818			values->tv_vert_timing[i];
819
820		write( ai, addr, value );
821
822		if( values->tv_vert_timing[i + 1] == 0 ||
823			values->tv_vert_timing[i] == 0 )
824			break;
825	}
826}
827