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