xref: /haiku/src/add-ons/media/media-add-ons/radeon/Theater100.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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 
17 CTheater100::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 
41 CTheater100::~CTheater100()
42 {
43 	PRINT(("CTheater100::~CTheater100()\n"));
44 
45 	if( InitCheck() == B_OK )
46 		SetEnable(false, false);
47 }
48 
49 status_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 
60 void 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
72 void 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 
143 void 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 
155 void 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 
163 void CTheater100::SetDeinterlace(bool deinterlace)
164 {
165 	PRINT(("CTheater100::SetDeinterlace(%d)\n", deinterlace));
166 
167 	fDeinterlace = deinterlace;
168 }
169 
170 void 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 
177 void CTheater100::SetBrightness(int brightness)
178 {
179 	PRINT(("CTheater100::SetBrightness(%d)\n", brightness));
180 
181 	fBrightness = brightness;
182 	SetLuminanceLevels(fStandard, fBrightness, fContrast);
183 }
184 
185 void CTheater100::SetContrast(int contrast)
186 {
187 	PRINT(("CTheater100::SetContrast(%d)\n", contrast));
188 
189 	fContrast = contrast;
190 	SetLuminanceLevels(fStandard, fBrightness, fContrast);
191 }
192 
193 void CTheater100::SetSaturation(int saturation)
194 {
195 	PRINT(("CTheater100::SetSaturation(%d)\n", saturation));
196 
197 	fSaturation = saturation;
198 	SetChromaLevels(fStandard, fSaturation, fHue);
199 }
200 
201 void 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
211 void 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
308 void 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
393 void 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
449 void 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
461 void 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
500 void 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
513 void 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
557 void 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
974 void 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
1016 void 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
1064 void 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
1122 void 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
1181 static const uint16 h_active_start[] = {
1182 	0x06b,	0x06B,	0x07E,	0x067,	0x09A,	0x07D,	0x09A,	0x084,	0x095 };
1183 static const uint16 h_active_end[] = {
1184 	0x363,	0x363,	0x42A,	0x363,	0x439,	0x439,	0x439,	0x363,	0x439 };
1185 static 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
1190 static const uint16 v_active_end[] = {
1191 	0x204,	0x204,	0x204,	0x204,	0x269,	0x269,	0x269,	0x204,	0x269 };
1192 static const uint16 h_vbi_wind_start[] = {
1193 	0x064,	0x064,	0x064,	0x064,	0x084,	0x084,	0x084,	0x064,	0x084 };
1194 static const uint16 h_vbi_wind_end[] = {
1195 	0x366,	0x366,	0x366,	0x366,	0x41F,	0x41F,	0x41F,	0x366,	0x41F };
1196 static const uint16 v_vbi_wind_start[] = {
1197 	0x00b,	0x00b,	0x00b,	0x00b,	0x008,	0x008,	0x008,	0x00b,	0x008 };
1198 static const uint16 v_vbi_wind_end[] = {
1199 	0x024,	0x024,	0x024,	0x024,	0x02d,	0x02d,	0x02d,	0x024,	0x02d };
1200 
1201 void 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 
1208 void 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
1216 void 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.
1255 void 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 
1314 int CTheater100::CurrentLine()
1315 {
1316 	return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT;
1317 }
1318 
1319 void 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