1/******************************************************************************
2/
3/	File:			Theater.cpp
4/
5/	Description:	ATI Rage Theater Video Decoder interface.
6/
7/	Copyright 2001, Carlos Hasan
8/
9*******************************************************************************/
10
11#include <Debug.h>
12#include "Theater100.h"
13#include "Theater.h"
14#include "TheatreReg.h"
15#include "lendian_bitfield.h"
16
17CTheater100::CTheater100(CRadeon & radeon, int device)
18:CTheater(radeon, device)
19{
20	PRINT(("CTheater100::CTheater100()\n"));
21
22	if( fPort.InitCheck() == B_OK ) {
23		radeon_video_tuner tuner;
24		radeon_video_decoder video;
25
26		radeon.GetMMParameters(tuner, video, fClock,
27			fTunerPort, fCompositePort, fSVideoPort);
28
29		if (fClock != C_RADEON_VIDEO_CLOCK_29_49892_MHZ &&
30			fClock != C_RADEON_VIDEO_CLOCK_27_00000_MHZ)
31			PRINT(("CTheater100::CTheater100() - Unsupported crystal clock!\n"));
32
33		//fDevice = fPort.FindVIPDevice( C_THEATER100_VIP_DEVICE_ID );
34
35	}
36
37	if( InitCheck() != B_OK )
38		PRINT(("CTheater100::CTheater100() - Rage Theater not found!\n"));
39}
40
41CTheater100::~CTheater100()
42{
43	PRINT(("CTheater100::~CTheater100()\n"));
44
45	if( InitCheck() == B_OK )
46		SetEnable(false, false);
47}
48
49status_t CTheater100::InitCheck() const
50{
51	status_t res;
52
53	res = fPort.InitCheck();
54	if( res != B_OK )
55		return res;
56
57	return (fDevice >= C_VIP_PORT_DEVICE_0 && fDevice <= C_VIP_PORT_DEVICE_3) ? B_OK : B_ERROR;
58}
59
60void CTheater100::Reset()
61{
62	PRINT(("CTheater100::Reset()\n"));
63
64	SetHue(0);
65	SetBrightness(0);
66	SetSaturation(0);
67	SetContrast(0);
68	SetSharpness(false);
69}
70
71// disable/enable capturing
72void CTheater100::SetEnable(bool enable, bool vbi)
73{
74	PRINT(("CTheater100::SetEnable(%d, %d)\n", enable, vbi));
75
76#if 0
77	//@ reset ADC?
78	SetRegister(VIP_ADC_CNTL, ADC_CPRESET, ADC_CPRESET);
79	snooze(1000);
80	SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0);
81	snooze(1000);
82	SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_DOWN);
83#endif
84
85
86	WaitVSYNC();
87
88	/* Disable the Video In, Scaler and DVS port */
89	SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, VIN_ASYNC_RST);
90	SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, DVS_ASYNC_RST);
91
92	/* select the reference clock for the Video In */
93	SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK);
94
95	/* reset the VIN/L54 PLL clocks */
96	SetRegister(VIP_PLL_CNTL1, VINRST, VINRST);
97	SetRegister(VIP_PLL_CNTL1, L54RST, L54RST);
98
99	/* power down the ADC block */
100	SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN);
101
102	/* set DVS port to input mode */
103	SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_INPUT);
104
105	/* select DVS clock to 8xFsc and disable continuous mode */
106	SetRegister(VIP_DVS_PORT_CTRL, DVS_CLK_SELECT, DVS_CLK_SELECT_8X);
107	SetRegister(VIP_DVS_PORT_CTRL, CONTINUOUS_STREAM, 0);
108
109	if (enable) {
110		WaitVSYNC();
111
112		SetClock(fStandard, fClock);
113		SetADC(fStandard, fSource);
114		SetLuminanceProcessor(fStandard);
115		SetChromaProcessor(fStandard);
116		SetVSYNC(fStandard);
117		SetClipWindow(fStandard, vbi);
118		SetCombFilter(fStandard, fSource);
119		SetHSYNC(fStandard);
120		SetSyncGenerator(fStandard);
121		SetScaler(fStandard, fHActive, fVActive, fDeinterlace);
122
123		/* Enable ADC block */
124		SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_UP);
125
126		WaitVSYNC();
127
128		/* Enable the Video In, Scaler and DVS port */
129		SetRegister(VIP_MASTER_CNTL, VIN_ASYNC_RST, 0);
130		SetRegister(VIP_MASTER_CNTL, DVS_ASYNC_RST, 0);
131
132		/* set DVS port to output mode */
133		SetRegister(VIP_DVS_PORT_CTRL, DVS_DIRECTION, DVS_DIRECTION_OUTPUT);
134
135		//WaitHSYNC();
136
137		/* restore luminance and chroma settings */
138		SetLuminanceLevels(fStandard, fBrightness, fContrast);
139		SetChromaLevels(fStandard, fSaturation, fHue);
140	}
141}
142
143void CTheater100::SetStandard(theater_standard standard, theater_source source)
144{
145	PRINT(("CTheater100::SetStandard(%s, %s)\n",
146		"NTSC\0\0\0\0\0\0NTSC-J\0\0\0\0NTSC-443\0\0PAL-M\0\0\0\0\0"
147		"PAL-N\0\0\0\0\0PAL-NC\0\0\0\0PAL-BDGHI\0PAL-60\0\0\0\0"
148		"SECAM\0\0\0\0\0"+10*standard,
149		"TUNER\0COMP\0\0SVIDEO"+6*source));
150
151	fStandard = standard;
152	fSource = source;
153}
154
155void CTheater100::SetSize(int hactive, int vactive)
156{
157	PRINT(("CTheater100::SetSize(%d, %d)\n", hactive, vactive));
158
159	fHActive = hactive;
160	fVActive = vactive;
161}
162
163void CTheater100::SetDeinterlace(bool deinterlace)
164{
165	PRINT(("CTheater100::SetDeinterlace(%d)\n", deinterlace));
166
167	fDeinterlace = deinterlace;
168}
169
170void CTheater100::SetSharpness(int sharpness)
171{
172	PRINT(("CTheater100::SetSharpness(%d)\n", sharpness));
173
174	SetRegister(VIP_H_SCALER_CONTROL, H_SHARPNESS, sharpness << 25);
175}
176
177void CTheater100::SetBrightness(int brightness)
178{
179	PRINT(("CTheater100::SetBrightness(%d)\n", brightness));
180
181	fBrightness = brightness;
182	SetLuminanceLevels(fStandard, fBrightness, fContrast);
183}
184
185void CTheater100::SetContrast(int contrast)
186{
187	PRINT(("CTheater100::SetContrast(%d)\n", contrast));
188
189	fContrast = contrast;
190	SetLuminanceLevels(fStandard, fBrightness, fContrast);
191}
192
193void CTheater100::SetSaturation(int saturation)
194{
195	PRINT(("CTheater100::SetSaturation(%d)\n", saturation));
196
197	fSaturation = saturation;
198	SetChromaLevels(fStandard, fSaturation, fHue);
199}
200
201void CTheater100::SetHue(int hue)
202{
203	PRINT(("CTheater100::SetHue(%d)\n", hue));
204
205	fHue = hue;
206	SetChromaLevels(fStandard, fSaturation, fHue);
207}
208
209
210// set pixel clock
211void CTheater100::SetClock(theater_standard standard, radeon_video_clock clock)
212{
213	// set VIN PLL clock dividers
214	int referenceDivider, feedbackDivider, postDivider;
215
216	switch (standard) {
217	case C_THEATER_NTSC:
218	case C_THEATER_NTSC_JAPAN:
219		if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) {
220			referenceDivider = 0x39;
221			feedbackDivider = 0x14c;
222			postDivider = 0x6;
223		}
224		else {
225			referenceDivider = 0x0b;
226			feedbackDivider = 0x46;
227			postDivider = 0x6;
228		}
229		break;
230	case C_THEATER_NTSC_443:
231		if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) {
232			referenceDivider = 0x23;
233			feedbackDivider = 0x88;
234			postDivider = 0x7;
235		}
236		else {
237			referenceDivider = 0x2c;
238			feedbackDivider = 0x121;
239			postDivider = 0x5;
240		}
241		break;
242	case C_THEATER_PAL_M:
243		if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) {
244			referenceDivider = 0x2c;
245			feedbackDivider = 0x12b;
246			postDivider = 0x7;
247		}
248		else {
249			referenceDivider = 0x0b;
250			feedbackDivider = 0x46;
251			postDivider = 0x6;
252		}
253		break;
254	case C_THEATER_PAL_BDGHI:
255	case C_THEATER_PAL_N:
256	case C_THEATER_PAL_60:
257	case C_THEATER_SECAM:
258		if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) {
259			referenceDivider = 0x0e;
260			feedbackDivider = 0x65;
261			postDivider = 0x6;
262		}
263		else {
264			referenceDivider = 0x2c;
265			feedbackDivider = 0x121;
266			postDivider = 0x5;
267		}
268		break;
269	case C_THEATER_PAL_NC:
270		if (clock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ) {
271			referenceDivider = 0x23;
272			feedbackDivider = 0x88;
273			postDivider = 0x7;
274		}
275		else {
276			referenceDivider = 0x37;
277			feedbackDivider = 0x1d3;
278			postDivider = 0x8;
279		}
280		break;
281	default:
282		PRINT(("CTheater100::SetClock() - Bad standard\n"));
283		return;
284	}
285
286	// reset VIN PLL and select the reference clock
287	SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_REF_CLK);
288	SetRegister(VIP_PLL_CNTL1, VINRST, VINRST);
289	SetRegister(VIP_PLL_CNTL1, L54RST, L54RST);
290
291	// set up the VIN PLL clock control
292	SetRegister(VIP_VIN_PLL_CNTL, VIN_M0, referenceDivider << 0);
293	SetRegister(VIP_VIN_PLL_CNTL, VIN_N0, feedbackDivider << 11);
294	SetRegister(VIP_VIN_PLL_CNTL, VIN_P, postDivider << 24);
295
296	// active the VIN/L54 PLL and attach the VIN PLL to the VIN clock
297	SetRegister(VIP_PLL_CNTL1, VINRST, 0);
298	SetRegister(VIP_PLL_CNTL1, L54RST, 0);
299	SetRegister(VIP_CLOCK_SEL_CNTL, VIN_CLK_SEL, VIN_CLK_SEL_VIPLL_CLK);
300
301	PRINT(("CTheater100::SetClock(Fsamp=%g, Fref=%g)\n",
302		((fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0) * feedbackDivider) / (referenceDivider * postDivider),
303		(fClock == C_RADEON_VIDEO_CLOCK_29_49892_MHZ ? 29.49892 : 27.0)));
304}
305
306
307// setup analog-digital converter
308void CTheater100::SetADC(theater_standard standard, theater_source source)
309{
310	PRINT(("CTheater100::SetADC(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source]));
311
312	// set HW_DEBUG before setting the standard
313	SetRegister(VIP_HW_DEBUG, 0x0000f000);
314
315	// select the video standard
316	switch (standard) {
317	case C_THEATER_NTSC:
318	case C_THEATER_NTSC_JAPAN:
319	case C_THEATER_NTSC_443:
320	case C_THEATER_PAL_M:
321		SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_NTSC);
322		break;
323	case C_THEATER_PAL_BDGHI:
324	case C_THEATER_PAL_N:
325	case C_THEATER_PAL_60:
326	case C_THEATER_PAL_NC:
327		SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_PAL);
328		break;
329	case C_THEATER_SECAM:
330		SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_SECAM);
331		break;
332	default:
333		PRINT(("CTheater100::SetADC() - Bad standard\n"));
334		return;
335	}
336
337	// select input connector and Y/C mode
338	switch (source) {
339	case C_THEATER_TUNER:
340		SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fTunerPort);
341		SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE);
342		break;
343	case C_THEATER_COMPOSITE:
344		SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fCompositePort);
345		SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_COMPOSITE);
346		break;
347	case C_THEATER_SVIDEO:
348		SetRegister(VIP_ADC_CNTL, INPUT_SELECT, fSVideoPort);
349		SetRegister(VIP_STANDARD_SELECT, YC_MODE, YC_MODE_SVIDEO);
350		break;
351	default:
352		PRINT(("CTheater100::SetADC() - Bad source\n"));
353		return;
354	}
355
356	SetRegister(VIP_ADC_CNTL, I_CLAMP_SEL, I_CLAMP_SEL_22);
357	SetRegister(VIP_ADC_CNTL, I_AGC_SEL, I_AGC_SEL_7);
358
359	SetRegister(VIP_ADC_CNTL, EXT_CLAMP_CAP, EXT_CLAMP_CAP_EXTERNAL);
360	SetRegister(VIP_ADC_CNTL, EXT_AGC_CAP, EXT_AGC_CAP_EXTERNAL);
361	SetRegister(VIP_ADC_CNTL, ADC_DECI_BYPASS, ADC_DECI_WITH_FILTER);
362	SetRegister(VIP_ADC_CNTL, VBI_DECI_BYPASS, VBI_DECI_WITH_FILTER);
363	SetRegister(VIP_ADC_CNTL, DECI_DITHER_EN, 0 << 12);
364	SetRegister(VIP_ADC_CNTL, ADC_CLK_SEL, ADC_CLK_SEL_8X);
365	SetRegister(VIP_ADC_CNTL, ADC_BYPASS, ADC_BYPASS_INTERNAL);
366	switch (standard) {
367	case C_THEATER_NTSC:
368	case C_THEATER_NTSC_JAPAN:
369	case C_THEATER_NTSC_443:
370	case C_THEATER_PAL_M:
371		SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_NTSC);
372		break;
373	case C_THEATER_PAL_BDGHI:
374	case C_THEATER_PAL_N:
375	case C_THEATER_PAL_60:
376	case C_THEATER_PAL_NC:
377	case C_THEATER_SECAM:
378		SetRegister(VIP_ADC_CNTL, ADC_CH_GAIN_SEL, ADC_CH_GAIN_SEL_PAL);
379		break;
380	}
381	SetRegister(VIP_ADC_CNTL, ADC_PAICM, 1 << 18);
382
383	SetRegister(VIP_ADC_CNTL, ADC_PDCBIAS, 2 << 20);
384	SetRegister(VIP_ADC_CNTL, ADC_PREFHI, ADC_PREFHI_2_7);
385	SetRegister(VIP_ADC_CNTL, ADC_PREFLO, ADC_PREFLO_1_5);
386
387	SetRegister(VIP_ADC_CNTL, ADC_IMUXOFF, 0 << 26);
388	SetRegister(VIP_ADC_CNTL, ADC_CPRESET, 0 << 27);
389}
390
391
392// setup horizontal sync PLL
393void CTheater100::SetHSYNC(theater_standard standard)
394{
395	static const uint16 hs_line_total[] = {
396		0x38E,	0x38E,	0x46F,	0x38D,	0x46F,	0x395,	0x46F,	0x467,	0x46F };
397
398	static const uint32 hs_dto_inc[] = {
399		0x40000,	0x40000,	0x40000,	0x40000,	0x40000,	0x40000,	0x40000,	0x40000,	0x3E7A2 };
400
401	// TK: completely different in gatos
402	static const uint8 hs_pll_sgain[] = {
403		2,		2,		2,		2,		2,		2,		2,		2,		2 };
404	static const uint8 hs_pll_fgain[] = {
405		8,		8,		8,		8,		8,		8,		8,		8,		8 };
406
407	static const uint8 gen_lock_delay[] = {
408		0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10,	0x10 };
409
410	static const uint8 min_pulse_width[] = {
411		0x21,	0x21,	0x29,	0x21,	0x29,	0x21,	0x29,	0x29,	0x29 };
412	static const uint8 max_pulse_width[] = {
413		0x64,	0x64,	0x7D,	0x64,	0x7D,	0x65,	0x7D,	0x7D,	0x7D };
414
415	static const uint16 win_close_limit[] = {
416		0x0A0,	0x0A0,	0x0C7,	0x0A0,	0x0C7,	0x0A0,	0x0C7,	0x0C7,	0x0C7 };
417	static const uint16 win_open_limit[] = {
418		0x1B7,	0x1B7,	0x228,	0x1B7,	0x228,	0x1BB,	0x228,	0x224,	0x228 };
419
420
421	// set number of samples per line
422	SetRegister(VIP_HS_PLINE, HS_LINE_TOTAL, hs_line_total[standard]);
423
424	SetRegister(VIP_HS_DTOINC, HS_DTO_INC, hs_dto_inc[standard]);
425
426	SetRegister(VIP_HS_PLLGAIN, HS_PLL_SGAIN, hs_pll_sgain[standard] << 0);
427	SetRegister(VIP_HS_PLLGAIN, HS_PLL_FGAIN, (uint32)hs_pll_fgain[standard] << 4);
428
429	SetRegister(VIP_HS_GENLOCKDELAY, GEN_LOCK_DELAY, gen_lock_delay[standard]);
430
431	// set min/max pulse width in samples
432	SetRegister(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH, min_pulse_width[standard] << 0);
433	SetRegister(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH, (uint32)max_pulse_width[standard] << 8);
434
435	SetRegister(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT, win_close_limit[standard] << 0);
436	SetRegister(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT, (uint32)win_open_limit[standard] << 16);
437
438
439	PRINT(("CTheater100::SetHSYNC(total=%d, pulse=%d/%d, window=%d/%d)\n",
440		Register(VIP_HS_PLINE, HS_LINE_TOTAL),
441		Register(VIP_HS_MINMAXWIDTH, MIN_PULSE_WIDTH) >> 0,
442		Register(VIP_HS_MINMAXWIDTH, MAX_PULSE_WIDTH) >> 8,
443		Register(VIP_HS_WINDOW_LIMIT, WIN_CLOSE_LIMIT) >> 0,
444		Register(VIP_HS_WINDOW_LIMIT, WIN_OPEN_LIMIT) >> 16));
445}
446
447
448// wait until horizontal scaler is locked
449void CTheater100::WaitHSYNC()
450{
451	for (int timeout = 0; timeout < 1000; timeout++) {
452		if (Register(VIP_HS_PULSE_WIDTH, HS_GENLOCKED) != 0)
453			return;
454		snooze(20);
455	}
456	PRINT(("CTheater100::WaitHSYNC() - wait for HSync locking time out!\n"));
457}
458
459
460// setup vertical sync and field detector
461void CTheater100::SetVSYNC(theater_standard standard)
462{
463	static const uint16 vsync_int_trigger[] = {
464		0x2AA,	0x2AA,	0x353,	0x2AA,	0x353,	0x2B0,	0x353,	0x34D,	0x353 };
465	static const uint16 vsync_int_hold[] = {
466		0x017,	0x017,	0x01C,	0x017,	0x01C,	0x017,	0x01C,	0x01C,	0x01C };
467	// PAL value changed from 26b to 26d - else, odd/even field detection fails sometimes;
468	// did the same for PAL N, PAL NC and SECAM
469	static const uint16 vs_field_blank_start[] = {
470		0x206,	0x206,	0x206,	0x206,	0x26d,	0x26d,	0x26d,	0x206,	0x26d };
471	static const uint8 vs_field_blank_end[] = {
472		0x00a,	0x00a,	0x00a,	0x00a,	0x02a,	0x02a,	0x02a,	0x00a,	0x02a };
473	// NTSC value changed from 1 to 105 - else, odd/even fields were always swapped;
474	// did the same for NTSC Japan, NTSC 443, PAL M and PAL 60
475	static const uint16 vs_field_id_location[] = {
476		0x105,	0x105,	0x105,	0x105,	0x1,	0x1,	0x1,	0x105,	0x1 };
477	static const uint16 vs_frame_total[] = {
478		0x217,	0x217,	0x217,	0x217,	0x27B,	0x27B,	0x27B,	0x217,	0x27B };
479
480	SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_TRIGGER, vsync_int_trigger[standard] << 0);
481	SetRegister(VIP_VS_DETECTOR_CNTL, VSYNC_INT_HOLD, (uint32)vsync_int_hold[standard] << 16);
482
483	SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_START, vs_field_blank_start[standard] << 0);
484	SetRegister(VIP_VS_BLANKING_CNTL, VS_FIELD_BLANK_END, (uint32)vs_field_blank_end[standard] << 16);
485	SetRegister(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL, vs_frame_total[standard]);
486
487	SetRegister(VIP_VS_FIELD_ID_CNTL, VS_FIELD_ID_LOCATION, vs_field_id_location[standard] << 0);
488
489	// auto-detect fields
490	SetRegister(VIP_VS_COUNTER_CNTL, FIELD_DETECT_MODE, FIELD_DETECT_DETECTED);
491
492	// don't flip fields
493	SetRegister(VIP_VS_COUNTER_CNTL, FIELD_FLIP_EN, 0 );
494
495	PRINT(("CTheater100::SetVSYNC(total=%d)\n",
496		Register(VIP_VS_FRAME_TOTAL, VS_FRAME_TOTAL)));
497}
498
499// wait until a visible line is viewed
500void CTheater100::WaitVSYNC()
501{
502	for (int timeout = 0; timeout < 1000; timeout++) {
503		int lineCount = Register(VIP_VS_LINE_COUNT, VS_LINE_COUNT);
504		if (lineCount > 1 && lineCount < 20)
505			return;
506		snooze(20);
507	}
508	PRINT(("CTheater100::WaitVSYNC() - wait for VBI timed out!\n"));
509}
510
511
512// setup timing generator
513void CTheater100::SetSyncGenerator(theater_standard standard)
514{
515	static const uint16 blank_int_start[] = {
516		0x031,	0x031,	0x046,	0x031,	0x046,	0x046,	0x046,	0x031,	0x046 };
517	static const uint8 blank_int_length[] = {
518		0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F };
519
520	static const uint16 sync_tip_start[] = {
521		0x0372,	0x0372,	0x0453,	0x0371,	0x0453,	0x0379,	0x0453,	0x044B,	0x0453 };
522	static const uint8 sync_tip_length[] = {
523		0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F };
524
525	static const uint8 uv_int_start[] = {
526		0x03B,	0x03B,	0x052,	0x03B,	0x052,	0x03B,	0x052,	0x03C,	0x068 };
527	static const uint8 u_int_length[] = {
528		0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F };
529	static const uint8 v_int_length[] = {
530		0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F,	0x0F };
531
532	// set blank interrupt position
533	SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_START, blank_int_start[standard] );
534	SetRegister(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH, (uint32)blank_int_length[standard] << 8);
535
536	SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START, sync_tip_start[standard]);
537	SetRegister(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH, (uint32)sync_tip_length[standard] << 12);
538
539	SetRegister(VIP_SG_UVGATE_GATE, UV_INT_START, uv_int_start[standard] << 0);
540
541	SetRegister(VIP_SG_UVGATE_GATE, U_INT_LENGTH, (uint32)u_int_length[standard] << 8);
542	SetRegister(VIP_SG_UVGATE_GATE, V_INT_LENGTH, (uint32)v_int_length[standard] << 12);
543
544	PRINT(("CTheater100::SetSyncGenerator(black=%d/%d, synctip=%d/%d, uvgate=%d/%d-%d)\n",
545		Register(VIP_SG_BLACK_GATE, BLANK_INT_START) >> 0,
546		Register(VIP_SG_BLACK_GATE, BLANK_INT_LENGTH) >> 8,
547		Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_START),
548		Register(VIP_SG_SYNCTIP_GATE, SYNC_TIP_LENGTH) >> 12,
549		Register(VIP_SG_UVGATE_GATE, UV_INT_START),
550		Register(VIP_SG_UVGATE_GATE, U_INT_LENGTH) >> 8,
551		Register(VIP_SG_UVGATE_GATE, V_INT_LENGTH) >> 12));
552}
553
554
555// setup input comb filter.
556// this is really ugly but I cannot find a scheme
557void CTheater100::SetCombFilter(theater_standard standard, theater_source source)
558{
559	enum {
560		_3Tap_2D_adaptive_Comb = 1,	// composite
561		_2Tap_C_combed_Y_Sub = 2,
562		_2Tap_C_combed_Y_combed = 3,
563		_3Tap_C_combed_Y_Sub = 4,
564		_3Tap_C_combed_Y_combed = 5,
565		YC_mode_Comb_filter_off = 6,	// S-Video
566		YC_mode_2Tap_YV_filter = 7,
567		YC_mode_3Tap_YV_filter = 8
568	};
569
570	// make sure to keep bitfield in sync with register definition!
571	// we could define each component as an uint8, but this would waste space
572	// and would require an extra register-composition
573	typedef struct {
574		LBITFIELD32_12 (
575			comb_hck			: 8,
576			comb_vck			: 8,
577			comb_filter_en		: 1,
578			comb_adaptiv_en		: 1,
579			comb_bpfmuxsel		: 3,
580			comb_coutsel		: 2,
581			comb_sumdiff0sel	: 1,
582			comb_sumdiff1sel	: 2,
583			comb_yvlpfsel		: 1,
584			comb_dlylinesel		: 2,
585			comb_ydlyinsel		: 2,
586			comb_ysubbw			: 1
587		);
588	} comb_cntl0;
589
590	typedef struct {
591		LBITFIELD32_7 (
592			comb_ydlyoutsel		: 2,
593			comb_coresize		: 2,
594			comb_ysuben			: 1,
595			comb_youtsel		: 1,
596			comb_syncpfsel		: 2,
597			comb_synclpfrst		: 1,
598			comb_debug			: 1
599		);
600	} comb_cntl1;
601
602	typedef struct {
603		LBITFIELD32_4 (
604			comb_hyk0			: 8,
605			comb_vyk0			: 8,
606			comb_hyk1			: 8,
607			comb_vyk1			: 8
608		);
609	} comb_cntl2;
610
611	typedef struct {
612		LBITFIELD32_2 (
613			comb_tap0length		: 16,
614			comb_tap1length		: 12
615		);
616	} comb_line_length;
617
618	typedef struct {
619		const uint8				*types;
620		const comb_cntl0		*cntl0;
621		const comb_cntl1		*cntl1;
622		const comb_cntl2		*cntl2;
623		const comb_line_length	*line_length;
624	} comb_settings;
625
626	static const uint8 comb_types_ntsc_m[] = {
627		_3Tap_2D_adaptive_Comb,
628		_2Tap_C_combed_Y_Sub,
629		_2Tap_C_combed_Y_combed,
630		_3Tap_C_combed_Y_Sub,
631		_3Tap_C_combed_Y_combed,
632		YC_mode_Comb_filter_off,
633		YC_mode_2Tap_YV_filter,
634		YC_mode_3Tap_YV_filter,
635		0
636	};
637
638	static const comb_cntl0 comb_cntl0_ntsc_m[] = {
639		{	0x90,	0x80,	1,	1,	0,	2,	0,	1,	0,	1,	0,	0 },
640		{	0,	0,	1,	0,	3,	2,	0,	0,	0,	1,	0,	0 },
641		{	0,	0,	1,	0,	3,	2,	0,	0,	0,	1,	1,	0 },
642		{	0,	0,	1,	0,	1,	2,	0,	1,	0,	1,	0,	0 },
643		{	0,	0,	1,	0,	1,	2,	0,	1,	1,	1,	0,	0 },
644		{	0,	0,	0,	0,	5,	2,	0,	0,	0,	1,	2,	0 },
645		{	0,	0,	0,	0,	5,	2,	0,	0,	0,	1,	1,	0 },
646		{	0,	0,	0,	0,	5,	2,	0,	0,	1,	1,	0,	0 }
647	};
648
649	static const comb_cntl1 comb_cntl1_ntsc_m[] = {
650		{	0,	0,	1,	0,	0,	0,	0 },
651		{	2,	0,	1,	0,	0,	0,	0 },
652		{	3,	0,	0,	0,	0,	0,	0 },
653		{	0,	0,	1,	0,	1,	0,	0 },
654		{	3,	0,	0,	0,	1,	0,	0 },
655		{	1,	0,	0,	0,	2,	0,	0 },
656		{	3,	0,	0,	0,	0,	0,	0 },
657		{	3,	0,	0,	0,	1,	0,	0 }
658	};
659
660	static const comb_cntl2 comb_cntl2_ntsc_m[] = {
661		{	0x10,	0x10,	0x16,	0x16 },
662		{	0xFF,	0xFF,	0xFF,	0xFF },
663		{	0xFF,	0xFF,	0xFF,	0xFF },
664		{	0xFF,	0xFF,	0xFF,	0xFF },
665		{	0xFF,	0xFF,	0xFF,	0xFF },
666		{	0xFF,	0xFF,	0xFF,	0xFF },
667		{	0xFF,	0xFF,	0xFF,	0xFF },
668		{	0xFF,	0xFF,	0xFF,	0xFF }
669	};
670
671	static const comb_line_length comb_line_length_ntsc_m[] = {
672		{	0x38A,	0x718 },
673		{	0x38A,	0x718 },
674		{	0x38A,	0x718 },
675		{	0x38A,	0x718 },
676		{	0x38A,	0x718 },
677		{	0,		0 },
678		{	0x38A,	0 },
679		{	0x38A,	0x718 }
680	};
681
682
683	static const uint8 comb_types_ntsc_433[] = {
684		_2Tap_C_combed_Y_Sub,
685		_2Tap_C_combed_Y_combed,
686		_3Tap_C_combed_Y_Sub,
687		_3Tap_C_combed_Y_combed,
688		YC_mode_Comb_filter_off,
689		YC_mode_2Tap_YV_filter,
690		YC_mode_3Tap_YV_filter,
691		0
692	};
693
694	static const comb_cntl0 comb_cntl0_ntsc_433[] = {
695		{	0,	0,	1,	0,	3,	2,	0,	0,	0,	1,	0,	0 },
696		{	0,	0,	1,	0,	3,	2,	0,	0,	0,	1,	1,	0 },
697		{	0,	0,	1,	0,	1,	2,	0,	1,	0,	1,	0,	0 },
698		{	0,	0,	1,	0,	1,	2,	0,	1,	1,	1,	0,	0 },
699		{	0,	0,	0,	0,	5,	2,	0,	0,	0,	1,	2,	0 },
700		{	0,	0,	0,	0,	5,	2,	0,	0,	0,	1,	1,	0 },
701		{	0,	0,	0,	0,	5,	2,	0,	0,	1,	1,	0,	0 }
702	};
703
704	static const comb_cntl1 comb_cntl1_ntsc_433[] = {
705		{	2,	0,	1,	0,	0,	0,	0 },
706		{	3,	0,	0,	0,	0,	0,	0 },
707		{	0,	0,	1,	0,	1,	0,	0 },
708		{	3,	0,	0,	0,	1,	0,	0 },
709		{	1,	0,	0,	0,	2,	0,	0 },
710		{	3,	0,	0,	0,	0,	0,	0 },
711		{	3,	0,	0,	0,	1,	0,	0 }
712	};
713
714	static const comb_cntl2 comb_cntl2_ntsc_433[] = {
715		{	0xFF,	0xFF,	0xFF,	0xFF },
716		{	0xFF,	0xFF,	0xFF,	0xFF },
717		{	0xFF,	0xFF,	0xFF,	0xFF },
718		{	0xFF,	0xFF,	0xFF,	0xFF },
719		{	0xFF,	0xFF,	0xFF,	0xFF },
720		{	0xFF,	0xFF,	0xFF,	0xFF },
721		{	0xFF,	0xFF,	0xFF,	0xFF }
722	};
723
724	static const comb_line_length comb_line_length_ntsc_433[] = {
725		{	0x462,	0x8C9 },
726		{	0x462,	0x8C9 },
727		{	0x462,	0x8C9 },
728		{	0x462,	0x8C9 },
729		{	0,		0 },
730		{	0x462,	0x8C9 },
731		{	0x462,	0x8C9 }
732	};
733
734
735	static const uint8 comb_types_pal_m[] = {
736		_2Tap_C_combed_Y_Sub,
737		YC_mode_2Tap_YV_filter,
738		0
739	};
740
741	static const comb_cntl0 comb_cntl0_pal_m[] = {
742		{	0,	0,	1,	0,	4,	0,	1,	2,	0,	0,	2,	0 },
743		{	0,	0,	1,	0,	5,	0,	1,	2,	0,	0,	2,	0 }
744	};
745
746	static const comb_cntl1 comb_cntl1_pal_m[] = {
747		{	1,	0,	1,	1,	2,	0,	0 },
748		{	1,	0,	0,	1,	2,	0,	0 }
749	};
750
751	static const comb_cntl2 comb_cntl2_pal_m[] = {
752		{	0xFF,	0xFF,	0xFF,	0xFF },
753		{	0xFF,	0xFF,	0xFF,	0xFF }
754	};
755
756	static const comb_line_length comb_line_length_pal_m[] = {
757		{	0x389,	0 },
758		{	0x389,	0 }
759	};
760
761
762	static const uint8 comb_types_pal_n[] = {
763		_3Tap_2D_adaptive_Comb,
764		_2Tap_C_combed_Y_Sub,
765		YC_mode_2Tap_YV_filter,
766		0
767	};
768
769	static const comb_cntl0 comb_cntl0_pal_n[] = {
770		{	0x90,	0x80,	1,	1,	0,	2,	0,	1,	0,	1,	0,	0 },
771		{	0,	0,	1,	0,	4,	0,	1,	2,	0,	0,	2,	0 },
772		{	0,	0,	1,	0,	5,	0,	1,	2,	0,	0,	2,	0 }
773	};
774
775	static const comb_cntl1 comb_cntl1_pal_n[] = {
776		{	0,	0,	1,	0,	0,	0,	0 },
777		{	1,	0,	1,	1,	2,	0,	0 },
778		{	1,	0,	0,	1,	2,	0,	0 }
779	};
780
781	static const comb_cntl2 comb_cntl2_pal_n[] = {
782		{	0x10,	0x10,	0x16,	0x16 },
783		{	0xFF,	0xFF,	0xFF,	0xFF },
784		{	0xFF,	0xFF,	0xFF,	0xFF }
785	};
786
787	static const comb_line_length comb_line_length_pal_n[] = {
788		{	0x46B,	0x8DA },
789		{	0x46C,	0 },
790		{	0x46C,	0 }
791	};
792
793
794	static const uint8 comb_types_pal_nc[] = {
795		_3Tap_2D_adaptive_Comb,
796		_2Tap_C_combed_Y_Sub,
797		YC_mode_2Tap_YV_filter,
798		0
799	};
800
801	// used to represent an N/A for easier copy'n'paste
802#define X 0
803
804	static const comb_cntl0 comb_cntl0_pal_nc[] = {
805		{	0x90,	0x80,	1,	1,	0,	2,	0,	1,	0,	1,	0,	0 },
806		{	X,	X,	1,	0,	4,	0,	1,	2,	0,	0,	2,	0 },
807		{	X,	X,	1,	0,	5,	0,	1,	2,	X,	0,	2,	0 }
808	};
809
810	static const comb_cntl1 comb_cntl1_pal_nc[] = {
811		{	0,	0,	1,	0,	0,	0,	0 },
812		{	1,	0,	1,	1,	2,	0,	0 },
813		{	1,	0,	0,	1,	2,	0,	0 }
814	};
815
816	static const comb_cntl2 comb_cntl2_pal_nc[] = {
817		{	0x10,	0x10,	0x16,	0x16 },
818		{	0xFF,	0xFF,	0xFF,	0xFF },
819		{	0xFF,	0xFF,	0xFF,	0xFF }
820	};
821
822	static const comb_line_length comb_line_length_pal_nc[] = {
823		{	0x391,	0x726 },
824		{	0x394,	X },
825		{	0x394,	X }
826	};
827
828
829	static const uint8 comb_types_pal[] = {
830		_3Tap_2D_adaptive_Comb,
831		_2Tap_C_combed_Y_Sub,
832		YC_mode_2Tap_YV_filter,
833		0
834	};
835
836	static const comb_cntl0 comb_cntl0_pal[] = {
837		{	0x90,	0x80,	1,	1,	0,	2,	0,	1,	0,	1,	0,	0 },
838		{	0,	0,	1,	0,	4,	0,	1,	2,	0,	0,	2,	0 },
839		{	0,	0,	1,	0,	5,	0,	1,	2,	X,	0,	2,	0 }
840	};
841
842	static const comb_cntl1 comb_cntl1_pal[] = {
843		{	0,	0,	1,	0,	0,	0,	0 },
844		{	1,	0,	1,	1,	2,	0,	0 },
845		{	1,	0,	0,	1,	2,	0,	0 }
846	};
847
848	static const comb_cntl2 comb_cntl2_pal[] = {
849		{	2,	1,	8,	6 },
850		{	0xFF,	0xFF,	0xFF,	0xFF },
851		{	0xFF,	0xFF,	0xFF,	0xFF }
852	};
853
854	static const comb_line_length comb_line_length_pal[] = {
855		{	0x46B,	0x8DA },
856		{	0x46C,	X },
857		{	0x46C,	X }
858	};
859
860
861	static const uint8 comb_types_pal_60[] = {
862		_2Tap_C_combed_Y_Sub,
863		YC_mode_2Tap_YV_filter,
864		0
865	};
866
867	static const comb_cntl0 comb_cntl0_pal_60[] = {
868		{	0,	0,	1,	0,	4,	0,	1,	2,	0,	0,	2,	0 },
869		{	0,	0,	1,	0,	5,	0,	1,	2,	0,	0,	2,	0 }
870	};
871
872	static const comb_cntl1 comb_cntl1_pal_60[] = {
873		{	1,	0,	1,	1,	2,	0,	0 },
874		{	1,	0,	0,	1,	2,	0,	0 }
875	};
876
877	static const comb_cntl2 comb_cntl2_pal_60[] = {
878		{	0xFF,	0xFF,	0xFF,	0xFF },
879		{	0xFF,	0xFF,	0xFF,	0xFF }
880	};
881
882	static const comb_line_length comb_line_length_pal_60[] = {
883		{	0x463,	0 },
884		{	0x463,	0 }
885	};
886
887
888	static const uint8 comb_types_secam[] = {
889		_2Tap_C_combed_Y_Sub,		// could be another type, spec is unclear here
890		YC_mode_2Tap_YV_filter,
891		0,
892	};
893
894	static const comb_cntl0 comb_cntl0_secam[] = {
895		{	X,	X,	0,	0,	4,	X,	X,	X,	X,	2,	2,	1 },
896		{	X,	X,	0,	0,	5,	X,	X,	X,	X,	2,	2,	X }
897	};
898
899	static const comb_cntl1 comb_cntl1_secam[] = {
900		{	1,	0,	1,	0,	2,	0,	0 },
901		{	1,	X,	0,	0,	2,	0,	0 }
902	};
903
904	static const comb_cntl2 comb_cntl2_secam[] = {
905		{	0xFF,	0xFF,	0xFF,	0xFF },
906		{	0xFF,	0xFF,	0xFF,	0xFF }
907	};
908
909	static const comb_line_length comb_line_length_secam[] = {
910		{	0x46A,	0 },
911		{	0x46A,	0 }
912	};
913
914#undef X
915
916	static const comb_settings comb_settings_list[] = {
917		{ comb_types_ntsc_m,	comb_cntl0_ntsc_m,		comb_cntl1_ntsc_m,		comb_cntl2_ntsc_m,		comb_line_length_ntsc_m },
918		{ comb_types_ntsc_m,	comb_cntl0_ntsc_m,		comb_cntl1_ntsc_m,		comb_cntl2_ntsc_m,		comb_line_length_ntsc_m },
919		{ comb_types_ntsc_433,	comb_cntl0_ntsc_433,	comb_cntl1_ntsc_433,	comb_cntl2_ntsc_433,	comb_line_length_ntsc_433 },
920		{ comb_types_pal_m,		comb_cntl0_pal_m,		comb_cntl1_pal_m,		comb_cntl2_pal_m,		comb_line_length_pal_m },
921		{ comb_types_pal_n,		comb_cntl0_pal_n,		comb_cntl1_pal_n,		comb_cntl2_pal_n,		comb_line_length_pal_n },
922		{ comb_types_pal_nc,	comb_cntl0_pal_nc,		comb_cntl1_pal_nc,		comb_cntl2_pal_nc,		comb_line_length_pal_nc },
923		{ comb_types_pal,		comb_cntl0_pal,			comb_cntl1_pal,			comb_cntl2_pal,			comb_line_length_pal },
924		{ comb_types_pal_60,	comb_cntl0_pal_60,		comb_cntl1_pal_60,		comb_cntl2_pal_60,		comb_line_length_pal_60 },
925		{ comb_types_secam,		comb_cntl0_secam,		comb_cntl1_secam,		comb_cntl2_secam,		comb_line_length_secam }
926	};
927
928	int min_type, max_type, type;
929	const comb_settings *settings;
930	int i = 0;
931
932	PRINT(("CTheater100::SetCombFilter(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source]));
933
934	// I don't really understand what the different types mean;
935	// what is particularly strange is that many types are defined for few standards only
936	if( source == C_THEATER_TUNER || source == C_THEATER_COMPOSITE ) {
937		min_type = _3Tap_2D_adaptive_Comb;
938		max_type = _3Tap_C_combed_Y_combed;
939	} else {
940		min_type = YC_mode_Comb_filter_off;
941		max_type = YC_mode_3Tap_YV_filter;
942	}
943
944	settings = &comb_settings_list[standard];
945
946	for( type = min_type; type <= max_type; ++type ) {
947		for( i = 0; settings->types[i]; ++i ) {
948			if( settings->types[i] == type )
949				break;
950		}
951
952		if( settings->types[i] != 0 )
953			break;
954	}
955
956	if( type > max_type ) {
957		PRINT(("CTheater100::SetCombFilter() - No settings for this standard and input type combination!!!\n"));
958		return;
959	}
960
961	SetRegister(VIP_COMB_CNTL0, *(const int32 *)(settings->cntl0 + i));
962	SetRegister(VIP_COMB_CNTL1, *(const int32 *)(settings->cntl1 + i));
963	SetRegister(VIP_COMB_CNTL2, *(const int32 *)(settings->cntl2 + i));
964	SetRegister(VIP_COMB_LINE_LENGTH, *(const int32 *)(settings->line_length + i));
965
966
967	// reset the comb filter
968	SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST);
969	SetRegister(VIP_COMB_CNTL1, Register(VIP_COMB_CNTL1) ^ COMB_SYNCLPFRST);
970}
971
972
973// setup luma processor
974void CTheater100::SetLuminanceProcessor(theater_standard standard)
975{
976	static const uint16 synctip_ref0[] = {
977		0x037,	0x037,	0x037,	0x037,	0x037,	0x037,	0x037,	0x037,	0x037 };
978	static const uint16 synctip_ref1[] = {
979		0x029,	0x029,	0x029,	0x029,	0x029,	0x026,	0x026,	0x026,	0x026 };
980	static const uint16 clamp_ref[] = {
981		0x03B,	0x03B,	0x03B,	0x03B,	0x03B,	0x03B,	0x03B,	0x03B,	0x03B };
982	static const uint16 agc_peakwhite[] = {
983		0x0FF,	0x0FF,	0x0FF,	0x0FF,	0x0FF,	0x0FF,	0x0FF,	0x0FF,	0x0FF };
984	static const uint16 vbi_peakwhite[] = {
985		0x0D2,	0x0D2,	0xD2,	0x0D2,	0x0D2,	0x0C6,	0x0C6,	0x0C6,	0x0C6 };
986
987	static const uint16 wpa_threshold[] = {
988		0x406,	0x406,	0x4FC,	0x406,	0x59C,	0x488,	0x59C,	0x59C,	0x57A };
989	static const uint16 wpa_trigger_lo[] = {
990		0x0B3,	0x0B3,	0x0B3,	0x0B3,	0x096,	0x096,	0x096,	0x0B3,	0x096 };
991	static const uint16 wpa_trigger_hi[] = {
992		0x21B,	0x21B,	0x21B,	0x21B,	0x1C2,	0x1C2,	0x1C2,	0x21B,	0x1C2 };
993	static const uint16 lp_lockout_start[] = {
994		0x206,	0x206,	0x206,	0x206,	0x263,	0x263,	0x263,	0x206,	0x263 };
995	// PAL: changed 0x2c to 0x0c; NTSC: changed 0x21 to 0x0b
996	static const uint16 lp_lockout_end[] = {
997		0x00B,	0x00B,	0x00B,	0x00B,	0x00C,	0x00C,	0x00C,	0x00B,	0x00C };
998
999	PRINT(("CTheater100::SetLuminanceProcessor(%c)\n", "NJ4MNCB6S"[standard]));
1000
1001	SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0, synctip_ref0[standard] << 0);
1002	SetRegister(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF1, (uint32)synctip_ref1[standard] << 8);
1003	SetRegister(VIP_LP_AGC_CLAMP_CNTL0, CLAMP_REF, (uint32)clamp_ref[standard] << 16);
1004	SetRegister(VIP_LP_AGC_CLAMP_CNTL0, AGC_PEAKWHITE, (uint32)agc_peakwhite[standard] << 24);
1005	SetRegister(VIP_LP_AGC_CLAMP_CNTL1, VBI_PEAKWHITE, (uint32)vbi_peakwhite[standard] << 0);
1006
1007	SetRegister(VIP_LP_WPA_CNTL0, WPA_THRESHOLD, wpa_threshold[standard] << 0);
1008	SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_LO, wpa_trigger_lo[standard] << 0);
1009	SetRegister(VIP_LP_WPA_CNTL1, WPA_TRIGGER_HI, (uint32)wpa_trigger_hi[standard] << 16);
1010	SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_START, lp_lockout_start[standard] << 0);
1011	SetRegister(VIP_LP_VERT_LOCKOUT, LP_LOCKOUT_END, (uint32)lp_lockout_end[standard] << 16);
1012}
1013
1014
1015// setup brightness and contrast
1016void CTheater100::SetLuminanceLevels(theater_standard standard, int brightness, int contrast)
1017{
1018	double ref0, setup, gain;
1019
1020	ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0);
1021
1022	switch (standard) {
1023	case C_THEATER_NTSC:
1024	case C_THEATER_PAL_M:
1025	case C_THEATER_NTSC_443:
1026		setup = 7.5 * ref0 / 40.0;
1027		gain = 219.0 / (92.5 * ref0 / 40.0);
1028		break;
1029
1030	case C_THEATER_NTSC_JAPAN:
1031		setup = 0.0;
1032		gain = 219.0 / (100.0 * ref0 / 40.0);
1033		break;
1034
1035	case C_THEATER_PAL_BDGHI:
1036	case C_THEATER_PAL_N:
1037	case C_THEATER_SECAM:
1038	case C_THEATER_PAL_60:
1039	case C_THEATER_PAL_NC:
1040		setup = 0.0;
1041		gain = 219.0 / (100.0 * ref0 / 43.0);
1042		break;
1043
1044	default:
1045		setup = 0.0;
1046		gain = 0.0;
1047		break;
1048	}
1049
1050	if (contrast <= -100)
1051		contrast = -99;
1052
1053	/* set luminance processor constrast (7:0) */
1054	SetRegister(VIP_LP_CONTRAST, CONTRAST,
1055		int(64.0 * ((contrast + 100) / 100.0) * gain) << 0);
1056
1057	/* set luminance processor brightness (13:0) */
1058	SetRegister(VIP_LP_BRIGHTNESS, BRIGHTNESS,
1059		int(16.0 * ((brightness - setup) + 16.0 / ((contrast + 100) * gain / 100.0))) & BRIGHTNESS);
1060}
1061
1062
1063// setup chroma demodulator
1064void CTheater100::SetChromaProcessor(theater_standard standard)
1065{
1066	PRINT(("CTheater100::SetChromaProcessor(%c)\n", "NJ4MNCB6S"[standard]));
1067
1068	static const uint32 ch_dto_inc[] = {
1069		0x400000,	0x400000,	0x400000,	0x400000,	0x400000,	0x400000,	0x400000,	0x400000,	0x3E7A28 };
1070	static const uint8 ch_pll_sgain[] = {
1071		1,		1,		1,		1,		1,		1,		1,		1,		5 };
1072	static const uint8 ch_pll_fgain[] = {
1073		2,		2,		2,		2,		2,		2,		2,		2,		6 };
1074
1075	static const uint8 ch_height[] = {
1076		0xCD,	0xCD,	0xCD,	0x91,	0x91,	0x9C,	0x9C,	0x9C,	0x66 };
1077	static const uint8 ch_kill_level[] = {
1078		0x0C0,	0xC0,	0xC0,	0x8C,	0x8C,	0x90,	0x90,	0x90,	0x60 };
1079	static const uint8 ch_agc_error_lim[] = {
1080		2,		2,		2,		2,		2,		2,		2,		2,		3 };
1081	static const uint8 ch_agc_filter_en[] = {
1082		0,		0,		0,		0,		0,		0,		1,		0,		0 };
1083	static const uint8 ch_agc_loop_speed[] = {
1084		0,		0,		0,		0,		0,		0,		0,		0,		0 };
1085
1086	static const uint16 cr_burst_gain[] = {
1087		0x7A,	0x71,	0x7A,	0x7A,	0x7A,	0x7A,	0x7A,	0x7A,	0x1FF };
1088	static const uint16 cb_burst_gain[] = {
1089		0xAC,	0x9F,	0xAC,	0xAC,	0xAC,	0xAB,	0xAB,	0xAB,	0x1FF };
1090	static const uint16 crdr_active_gain[] = {
1091		0x7A,	0x71,	0x7A,	0x7A,	0x7A,	0x7A,	0x7A,	0x7A,	0x11C };
1092	static const uint16 cbdb_active_gain[] = {
1093		0xAC,	0x9F,	0xAC,	0xAC,	0xAC,	0xAB,	0xAB,	0xAB,	0x15A };
1094	static const uint16 cp_vert_lockout_start[] = {
1095		0x207,	0x207,	0x207,	0x207,	0x269,	0x269,	0x269,	0x207,	0x269 };
1096	static const uint8 cp_vert_lockout_end[] = {
1097		0x00E,	0x00E,	0x00E,	0x00E,	0x00E,	0x012,	0x012,	0x00E,	0x012 };
1098
1099	SetRegister(VIP_CP_PLL_CNTL0, CH_DTO_INC, ch_dto_inc[standard] << 0);
1100	SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_SGAIN, (uint32)ch_pll_sgain[standard] << 24);
1101	SetRegister(VIP_CP_PLL_CNTL0, CH_PLL_FGAIN, (uint32)ch_pll_fgain[standard] << 28);
1102
1103	SetRegister(VIP_CP_AGC_CNTL, CH_HEIGHT, ch_height[standard] << 0);
1104	SetRegister(VIP_CP_AGC_CNTL, CH_KILL_LEVEL, (uint32)ch_kill_level[standard] << 8);
1105	SetRegister(VIP_CP_AGC_CNTL, CH_AGC_ERROR_LIM, (uint32)ch_agc_error_lim[standard] << 16);
1106	SetRegister(VIP_CP_AGC_CNTL, CH_AGC_FILTER_EN, (uint32)ch_agc_filter_en[standard] << 18);
1107	SetRegister(VIP_CP_AGC_CNTL, CH_AGC_LOOP_SPEED, (uint32)ch_agc_loop_speed[standard] << 19);
1108
1109	SetRegister(VIP_CP_BURST_GAIN, CR_BURST_GAIN, cr_burst_gain[standard] << 0);
1110	SetRegister(VIP_CP_BURST_GAIN, CB_BURST_GAIN, (uint32)cb_burst_gain[standard] << 16);
1111
1112	SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, crdr_active_gain[standard] << 0);
1113	SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, (uint32)cbdb_active_gain[standard] << 16);
1114
1115	SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_START, cp_vert_lockout_start[standard] << 0);
1116	SetRegister(VIP_CP_VERT_LOCKOUT, CP_LOCKOUT_END, (uint32)cp_vert_lockout_end[standard] << 16);
1117}
1118
1119
1120// set colour saturation and hue.
1121// hue makes sense for NTSC only and seems to act as saturation for PAL
1122void CTheater100::SetChromaLevels(theater_standard standard, int saturation, int hue)
1123{
1124	int ref0;
1125	double gain, CRgain, CBgain;
1126
1127	/* compute Cr/Cb gains */
1128	ref0 = Register(VIP_LP_AGC_CLAMP_CNTL0, SYNCTIP_REF0);
1129
1130	switch (standard) {
1131	case C_THEATER_NTSC:
1132	case C_THEATER_NTSC_443:
1133	case C_THEATER_PAL_M:
1134		CRgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5;
1135		CBgain = (40.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5;
1136		break;
1137
1138	case C_THEATER_NTSC_JAPAN:
1139		CRgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5;
1140		CBgain = (40.0 / ref0) * (100.0 / 100.0) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5;
1141		break;
1142
1143	case C_THEATER_PAL_BDGHI:
1144	case C_THEATER_PAL_60:
1145	case C_THEATER_PAL_NC:
1146	case C_THEATER_PAL_N:
1147		CRgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.877) * (112.0 / 70.1) / 1.5;
1148		CBgain = (43.0 / ref0) * (100.0 / 92.5) * (1.0 / 0.492) * (112.0 / 88.6) / 1.5;
1149		break;
1150
1151	case C_THEATER_SECAM:
1152		CRgain = 32.0 * 32768.0 / 280000.0 / (33554432.0 / 35.46985) * (1.597 / 1.902) / 1.5;
1153		CBgain = 32.0 * 32768.0 / 230000.0 / (33554432.0 / 35.46985) * (1.267 / 1.505) / 1.5;
1154		break;
1155
1156	default:
1157		PRINT(("CTheater100::SetChromaLevels() - Bad standard\n"));
1158		CRgain = 0.0;
1159		CBgain = 0.0;
1160		break;
1161	}
1162
1163	if (saturation >= 0)
1164		gain = 1.0 + 4.9 * saturation / 100.0;
1165	else
1166		gain = 1.0 + saturation / 100.0;
1167
1168	SetRegister(VIP_CP_ACTIVE_GAIN, CRDR_ACTIVE_GAIN, int(128 * CRgain * gain) << 0);
1169	SetRegister(VIP_CP_ACTIVE_GAIN, CBDB_ACTIVE_GAIN, int(128 * CBgain * gain) << 16);
1170
1171	if (hue >= 0)
1172		hue = (256 * hue) / 360;
1173	else
1174		hue = (256 * (hue + 360)) / 360;
1175
1176	SetRegister(VIP_CP_HUE_CNTL, HUE_ADJ, hue << 0);
1177}
1178
1179
1180// these values are used by scaler as well
1181static const uint16 h_active_start[] = {
1182	0x06b,	0x06B,	0x07E,	0x067,	0x09A,	0x07D,	0x09A,	0x084,	0x095 };
1183static const uint16 h_active_end[] = {
1184	0x363,	0x363,	0x42A,	0x363,	0x439,	0x439,	0x439,	0x363,	0x439 };
1185static const uint16 v_active_start[] = {
1186	0x025,	0x025,	0x025,	0x025,	0x02E,	0x02E,	0x02E,	0x025,	0x02E };
1187// PAL height is too small (572 instead of 576 lines), but changing 0x269 to 0x26d
1188// leads to trouble, and the last 2 lines seem to be used for VBI data
1189// (read: garbage) anyway
1190static const uint16 v_active_end[] = {
1191	0x204,	0x204,	0x204,	0x204,	0x269,	0x269,	0x269,	0x204,	0x269 };
1192static const uint16 h_vbi_wind_start[] = {
1193	0x064,	0x064,	0x064,	0x064,	0x084,	0x084,	0x084,	0x064,	0x084 };
1194static const uint16 h_vbi_wind_end[] = {
1195	0x366,	0x366,	0x366,	0x366,	0x41F,	0x41F,	0x41F,	0x366,	0x41F };
1196static const uint16 v_vbi_wind_start[] = {
1197	0x00b,	0x00b,	0x00b,	0x00b,	0x008,	0x008,	0x008,	0x00b,	0x008 };
1198static const uint16 v_vbi_wind_end[] = {
1199	0x024,	0x024,	0x024,	0x024,	0x02d,	0x02d,	0x02d,	0x024,	0x02d };
1200
1201void CTheater100::getActiveRange( theater_standard standard, CRadeonRect &rect )
1202{
1203	rect.SetTo(
1204		h_active_start[standard], v_active_start[standard],
1205		h_active_end[standard], v_active_end[standard] );
1206}
1207
1208void CTheater100::getVBIRange( theater_standard standard, CRadeonRect &rect )
1209{
1210	rect.SetTo(
1211		h_vbi_wind_start[standard], v_vbi_wind_start[standard],
1212		h_vbi_wind_end[standard], v_vbi_wind_end[standard] );
1213}
1214
1215// program clipping engine
1216void CTheater100::SetClipWindow(theater_standard standard, bool vbi)
1217{
1218	// set horizontal active window
1219	SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START, h_active_start[standard] << 0);
1220	SetRegister(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END, (uint32)h_active_end[standard] << 16);
1221
1222	// set vertical active window
1223	SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START, v_active_start[standard] << 0);
1224	SetRegister(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END, (uint32)v_active_end[standard] << 16);
1225
1226	// set horizontal VBI window
1227	SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_START, h_vbi_wind_start[standard] << 0);
1228	SetRegister(VIP_H_VBI_WINDOW, H_VBI_WIND_END, (uint32)h_vbi_wind_end[standard] << 16);
1229
1230	// set vertical VBI window
1231	SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_START, v_vbi_wind_start[standard] << 0);
1232	SetRegister(VIP_V_VBI_WINDOW, V_VBI_WIND_END, (uint32)v_vbi_wind_end[standard]  << 16);
1233
1234	// set VBI scaler control
1235	SetRegister(VIP_VBI_SCALER_CONTROL, (1 << 16) & VBI_SCALING_RATIO);
1236
1237	// enable/disable VBI capture
1238	SetRegister(VIP_VBI_CONTROL, VBI_CAPTURE_ENABLE,
1239		vbi ? VBI_CAPTURE_EN : VBI_CAPTURE_DIS);
1240
1241	PRINT(("CTheater100::SetClipWindow(active=%d/%d/%d/%d, vbi=%d/%d/%d/%d)\n",
1242		Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_START) >> 0,
1243		Register(VIP_H_ACTIVE_WINDOW, H_ACTIVE_END) >> 16,
1244		Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_START) >> 0,
1245		Register(VIP_V_ACTIVE_WINDOW, V_ACTIVE_END) >> 16,
1246		Register(VIP_H_VBI_WINDOW, H_VBI_WIND_START) >> 0,
1247		Register(VIP_H_VBI_WINDOW, H_VBI_WIND_END) >> 16,
1248		Register(VIP_V_VBI_WINDOW, V_VBI_WIND_START) >> 0,
1249		Register(VIP_V_VBI_WINDOW, V_VBI_WIND_END) >> 16));
1250
1251}
1252
1253
1254// setup capture scaler.
1255void CTheater100::SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace)
1256{
1257	int oddOffset, evenOffset;
1258	uint16 h_active_width, v_active_height;
1259
1260//	ASSERT(vactive <= 511);
1261
1262	// TK: Gatos uses different values here
1263	h_active_width = h_active_end[standard] - h_active_start[standard] + 1;
1264	v_active_height = v_active_end[standard] - v_active_start[standard] + 1;
1265
1266	// for PAL, we have 572 lines only, but need 576 lines;
1267	// my attempts to find those missing lines all failed, so if the application requests
1268	// 576 lines, we had to upscale the video which is not supported by hardware;
1269	// solution: restrict to 572 lines - the scaler will fill out the missing lines with black
1270	if( vactive > v_active_height )
1271		vactive = v_active_height;
1272
1273	if (deinterlace) {
1274		// progressive scan
1275		evenOffset = oddOffset = 512 - (int) ((512 * vactive) / v_active_height);
1276	}
1277	else {
1278		// interlaced
1279		evenOffset = (int) ((512 * vactive) / v_active_height);
1280		oddOffset = 2048 - evenOffset;
1281	}
1282
1283	// set scale input window
1284	SetRegister(VIP_SCALER_IN_WINDOW, H_IN_WIND_START, h_active_start[standard] << 0);
1285	SetRegister(VIP_SCALER_IN_WINDOW, V_IN_WIND_START, (uint32)v_active_start[standard] << 16);
1286
1287	SetRegister(VIP_SCALER_OUT_WINDOW, H_OUT_WIND_WIDTH, hactive << 0);
1288	SetRegister(VIP_SCALER_OUT_WINDOW, V_OUT_WIND_HEIGHT, (vactive / 2) << 16);
1289
1290	SetRegister(VIP_H_SCALER_CONTROL, H_SCALE_RATIO, (((uint32)h_active_width << 16) / hactive) << 0);
1291	SetRegister(VIP_V_SCALER_CONTROL, V_SCALE_RATIO, ((vactive << 11) / v_active_height) << 0);
1292
1293	// enable horizontal and vertical scaler
1294	SetRegister(VIP_H_SCALER_CONTROL, H_BYPASS,
1295		h_active_width == hactive ? H_BYPASS : 0);
1296	SetRegister(VIP_V_SCALER_CONTROL, V_BYPASS,
1297		v_active_height == vactive ? V_BYPASS : 0);
1298
1299	// set deinterlace control
1300	SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0);
1301	SetRegister(VIP_V_DEINTERLACE_CONTROL, EVENF_OFFSET, evenOffset << 0);
1302	SetRegister(VIP_V_DEINTERLACE_CONTROL, ODDF_OFFSET, oddOffset << 11);
1303
1304	SetRegister(VIP_V_SCALER_CONTROL, V_DEINTERLACE_ON, deinterlace ? V_DEINTERLACE_ON : 0);
1305
1306	PRINT(("CTheater100::SetScaler(active=%d/%d/%d/%d, scale=%d/%d)\n",
1307		Register(VIP_SCALER_IN_WINDOW, H_IN_WIND_START) >> 0,
1308		Register(VIP_SCALER_IN_WINDOW, V_IN_WIND_START) >> 16,
1309		hactive, vactive,
1310		Register(VIP_H_SCALER_CONTROL, H_SCALE_RATIO),
1311		Register(VIP_V_SCALER_CONTROL, V_SCALE_RATIO)));
1312}
1313
1314int CTheater100::CurrentLine()
1315{
1316	return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT;
1317}
1318
1319void CTheater100::PrintToStream()
1320{
1321	PRINT(("<<< Rage Theater Registers >>>\n"));
1322	for (int index = 0x0400; index <= 0x06ff; index += 4) {
1323		int value = Register(index);
1324		value = value; // unused var if debug is off
1325		PRINT(("REG_0x%04x = 0x%08x\n", index, value));
1326	}
1327}
1328