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
CTheater100(CRadeon & radeon,int device)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
~CTheater100()41 CTheater100::~CTheater100()
42 {
43 PRINT(("CTheater100::~CTheater100()\n"));
44
45 if( InitCheck() == B_OK )
46 SetEnable(false, false);
47 }
48
InitCheck() const49 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
Reset()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
SetEnable(bool enable,bool vbi)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
SetStandard(theater_standard standard,theater_source source)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
SetSize(int hactive,int vactive)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
SetDeinterlace(bool deinterlace)163 void CTheater100::SetDeinterlace(bool deinterlace)
164 {
165 PRINT(("CTheater100::SetDeinterlace(%d)\n", deinterlace));
166
167 fDeinterlace = deinterlace;
168 }
169
SetSharpness(int sharpness)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
SetBrightness(int brightness)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
SetContrast(int contrast)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
SetSaturation(int saturation)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
SetHue(int hue)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
SetClock(theater_standard standard,radeon_video_clock 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
SetADC(theater_standard standard,theater_source source)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
SetHSYNC(theater_standard standard)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
WaitHSYNC()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
SetVSYNC(theater_standard standard)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
WaitVSYNC()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
SetSyncGenerator(theater_standard standard)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
SetCombFilter(theater_standard standard,theater_source source)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
SetLuminanceProcessor(theater_standard standard)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
SetLuminanceLevels(theater_standard standard,int brightness,int 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
SetChromaProcessor(theater_standard standard)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
SetChromaLevels(theater_standard standard,int saturation,int hue)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
getActiveRange(theater_standard standard,CRadeonRect & rect)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
getVBIRange(theater_standard standard,CRadeonRect & rect)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
SetClipWindow(theater_standard standard,bool vbi)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.
SetScaler(theater_standard standard,int hactive,int vactive,bool deinterlace)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
CurrentLine()1314 int CTheater100::CurrentLine()
1315 {
1316 return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT;
1317 }
1318
PrintToStream()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