1/* Copyright (c) 2005 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 * */
25
26/*
27 * This file contains routines to control the Philips SAA7114 video decoder.
28 * */
29
30/*---------------------------*/
31/*  TABLE OF DEFAULT VALUES  */
32/*---------------------------*/
33
34typedef struct tagGFX_SAA7114_INIT {
35    unsigned char index;
36    unsigned char value;
37} GFX_SAA7114_INIT;
38
39/* Task A is for VBI raw data and task B is for video */
40
41GFX_SAA7114_INIT gfx_saa7114_init_values[] = {
42    {0x01, 0x08}, {0x02, 0xC0}, {0x03, 0x00}, {0x04, 0x90},
43    {0x05, 0x90}, {0x06, 0xEB}, {0x07, 0xE0}, {0x08, 0x88},
44    {0x09, 0x40}, {0x0A, 0x80}, {0x0B, 0x44}, {0x0C, 0x40},
45    {0x0D, 0x00}, {0x0E, 0x89}, {0x0F, 0x2E}, {0x10, 0x0E},
46    {0x11, 0x00}, {0x12, 0x05}, {0x13, 0x00}, {0x14, 0x08},
47    {0x15, 0x11}, {0x16, 0xFE}, {0x17, 0x00}, {0x18, 0x40},
48    {0x19, 0x80}, {0x30, 0xBC}, {0x31, 0xDF}, {0x32, 0x02},
49    {0x34, 0xCD}, {0x35, 0xCC}, {0x36, 0x3A}, {0x38, 0x03},
50    {0x39, 0x10}, {0x3A, 0x00}, {0x40, 0x00}, {0x41, 0xFF},
51    {0x42, 0xFF}, {0x43, 0xFF}, {0x44, 0xFF}, {0x45, 0xFF},
52    {0x46, 0xFF}, {0x47, 0xFF}, {0x48, 0xFF}, {0x49, 0xFF},
53    {0x4A, 0xFF}, {0x4B, 0xFF}, {0x4C, 0xFF}, {0x4D, 0xFF},
54    {0x4E, 0xFF}, {0x4F, 0xFF}, {0x50, 0xFF}, {0x51, 0xFF},
55    {0x52, 0xFF}, {0x53, 0xFF}, {0x54, 0xFF}, {0x55, 0xFF},
56    {0x56, 0xFF}, {0x57, 0xFF}, {0x58, 0x00}, {0x59, 0x47},
57    {0x5A, 0x06}, {0x5B, 0x43}, {0x5D, 0x3E}, {0x5E, 0x00},
58    {0x80, 0x30}, {0x83, 0x00}, {0x84, 0x60}, {0x85, 0x00},
59    {0x86, 0xE5}, {0x87, 0x01}, {0x88, 0xF8},
60
61    /* VBI task */
62
63    {0x90, 0x01}, {0x91, 0xC8}, {0x92, 0x08}, {0x93, 0x84},
64    {0x94, 0x10}, {0x95, 0x00}, {0x96, 0xD0}, {0x97, 0x02},
65    {0x98, 0x05}, {0x99, 0x00}, {0x9A, 0x0B}, {0x9B, 0x00},
66    {0x9C, 0xA0}, {0x9D, 0x05}, {0x9E, 0x0B}, {0x9F, 0x00},
67    {0xA0, 0x01}, {0xA1, 0x00}, {0xA2, 0x00}, {0xA4, 0x80},
68    {0xA5, 0x40}, {0xA6, 0x40}, {0xA8, 0x00}, {0xA9, 0x02},
69    {0xAA, 0x00}, {0xAC, 0x00}, {0xAD, 0x01}, {0xAE, 0x00},
70    {0xB0, 0x00}, {0xB1, 0x04}, {0xB2, 0x00}, {0xB3, 0x04},
71    {0xB4, 0x00}, {0xB8, 0x00}, {0xB9, 0x00}, {0xBA, 0x00},
72    {0xBB, 0x00}, {0xBC, 0x00}, {0xBD, 0x00}, {0xBE, 0x00},
73    {0xBF, 0x00},
74
75    /* Video task */
76
77    {0xC0, 0x80}, {0xC1, 0x08}, {0xC2, 0x00}, {0xC3, 0x80},
78    {0xC4, 0x10}, {0xC5, 0x00}, {0xC6, 0xD0}, {0xC7, 0x02},
79    {0xC8, 0x11}, {0xC9, 0x00}, {0xCA, 0xF1}, {0xCB, 0x00},
80    {0xCC, 0xD0}, {0xCD, 0x02}, {0xCE, 0xF1}, {0xCF, 0x00},
81    {0xD0, 0x01}, {0xD1, 0x00}, {0xD2, 0x00}, {0xD4, 0x80},
82    {0xD5, 0x40}, {0xD6, 0x40}, {0xD8, 0x00}, {0xD9, 0x04},
83    {0xDA, 0x00}, {0xDC, 0x00}, {0xDD, 0x02}, {0xDE, 0x00},
84    {0xE0, 0x00}, {0xE1, 0x04}, {0xE2, 0x00}, {0xE3, 0x04},
85    {0xE4, 0x00}, {0xE8, 0x00}, {0xE9, 0x00}, {0xEA, 0x00},
86    {0xEB, 0x00}, {0xEC, 0x00}, {0xED, 0x00}, {0xEE, 0x00},
87    {0xEF, 0x00},
88};
89
90#define GFX_NUM_SAA7114_INIT_VALUES 	\
91		sizeof(gfx_saa7114_init_values)/sizeof(GFX_SAA7114_INIT)
92
93/*-----------------------------------------------------*/
94/*	  TABLE OF FIR PREFILTER RECOMMENDED VALUES        */
95/*-----------------------------------------------------*/
96
97int optimize_for_aliasing = 0;
98
99typedef struct tagGFX_SAA7114_FIR_PREFILTER {
100    unsigned char prescaler;
101    unsigned char acl_low;
102    unsigned char prefilter_low;
103    unsigned char acl_high;
104    unsigned char prefilter_high;
105} GFX_SAA7114_FIR_PREFILTER;
106
107GFX_SAA7114_FIR_PREFILTER gfx_saa7114_fir_values[] = {
108    {0x01, 0x00, 0x00, 0x00, 0x00}, {0x02, 0x02, 0x5A, 0x01, 0x51},
109    {0x03, 0x04, 0xAB, 0x03, 0xA2}, {0x04, 0x07, 0xA3, 0x04, 0xAB},
110    {0x05, 0x08, 0xAC, 0x07, 0xA3}, {0x06, 0x08, 0xFC, 0x07, 0xF3},
111    {0x07, 0x08, 0xFC, 0x07, 0xF3}, {0x08, 0x0F, 0xF4, 0x08, 0xFC},
112    {0x09, 0x0F, 0xF4, 0x08, 0xFC}, {0x0A, 0x10, 0xFD, 0x08, 0xFC},
113    {0x0B, 0x10, 0xFD, 0x08, 0xFC}, {0x0C, 0x10, 0xFD, 0x08, 0xFC},
114    {0x0D, 0x10, 0xFD, 0x10, 0xFD}, {0x0E, 0x10, 0xFD, 0x10, 0xFD},
115    {0x0F, 0x1F, 0xF5, 0x10, 0xFD}, {0x10, 0x20, 0xFE, 0x10, 0xFD},
116    {0x11, 0x20, 0xFE, 0x10, 0xFD}, {0x12, 0x20, 0xFE, 0x10, 0xFD},
117    {0x13, 0x20, 0xFE, 0x20, 0xFE}, {0x14, 0x20, 0xFE, 0x20, 0xFE},
118    {0x15, 0x20, 0xFE, 0x20, 0xFE}, {0x16, 0x20, 0xFE, 0x20, 0xFE},
119    {0x17, 0x20, 0xFE, 0x20, 0xFE}, {0x18, 0x20, 0xFE, 0x20, 0xFE},
120    {0x19, 0x20, 0xFE, 0x20, 0xFE}, {0x1A, 0x20, 0xFE, 0x20, 0xFE},
121    {0x1B, 0x20, 0xFE, 0x20, 0xFE}, {0x1C, 0x20, 0xFE, 0x20, 0xFE},
122    {0x1D, 0x20, 0xFE, 0x20, 0xFE}, {0x1E, 0x20, 0xFE, 0x20, 0xFE},
123    {0x1F, 0x20, 0xFE, 0x20, 0xFE}, {0x20, 0x3F, 0xFF, 0x20, 0xFE},
124    {0x21, 0x3F, 0xFF, 0x20, 0xFE}, {0x22, 0x3F, 0xFF, 0x20, 0xFE},
125    {0x23, 0x3F, 0xFF, 0x20, 0xFF}
126};
127
128int
129saa7114_write_reg(unsigned char reg, unsigned char val)
130{
131    return gfx_i2c_write(2, SAA7114_CHIPADDR, reg, 1, &val);
132}
133
134int
135saa7114_read_reg(unsigned char reg, unsigned char *val)
136{
137    return gfx_i2c_read(2, SAA7114_CHIPADDR, reg, 1, val);
138}
139
140/*----------------------------------------------------------------------------
141 * gfx_set_decoder_vbi_upscale
142 *
143 * This routine configures the video decoder task A to upscale raw VBI data
144 * horizontally to match a different system clock.
145 * The upscale is from 13.5 MHz (SAA7114) to 14.318 MHz (Bt835).
146 *----------------------------------------------------------------------------
147 */
148#if GFX_DECODER_DYNAMIC
149int
150saa7114_set_decoder_vbi_upscale(void)
151#else
152int
153gfx_set_decoder_vbi_upscale(void)
154#endif
155{
156    /* Set horizontal output length to 1528 (720 * 2 * 14.318 / 13.5) */
157    saa7114_write_reg(SAA7114_TASK_A_HORZ_OUTPUT_LO, 0xF8);
158    saa7114_write_reg(SAA7114_TASK_A_HORZ_OUTPUT_HI, 0x05);
159
160    /* Set horizontal luminance scaling increment to 484 (1024 * 13.5 /
161     * 28.636) */
162    saa7114_write_reg(SAA7114_TASK_A_HSCALE_LUMA_LO, 0xE4);
163    saa7114_write_reg(SAA7114_TASK_A_HSCALE_LUMA_HI, 0x01);
164
165    /* Set horizontal chrominance scaling increment to 242 */
166    saa7114_write_reg(SAA7114_TASK_A_HSCALE_CHROMA_LO, 0xF2);
167    saa7114_write_reg(SAA7114_TASK_A_HSCALE_CHROMA_HI, 0x00);
168
169    return GFX_STATUS_OK;
170}
171
172/*----------------------------------------------------------------------------
173 * gfx_decoder_software_reset
174 *
175 * This routine performs a software reset of the decoder.
176 *----------------------------------------------------------------------------
177 */
178#if GFX_DECODER_DYNAMIC
179int
180saa7114_decoder_software_reset(void)
181#else
182int
183gfx_decoder_software_reset(void)
184#endif
185{
186    saa7114_write_reg(0x88, 0xC0);
187    /* I2C-bus latency should be sufficient for resetting the internal state
188     * machine. */
189    /* gfx_delay_milliseconds(10); */
190    saa7114_write_reg(0x88, 0xF0);
191    return GFX_STATUS_OK;
192}
193
194/*----------------------------------------------------------------------------
195 * gfx_decoder_detect_macrovision
196 *
197 * This routine detects if macrovision exists in the input of the video
198 * decoder.
199 *----------------------------------------------------------------------------
200 */
201#if GFX_DECODER_DYNAMIC
202int
203saa7114_decoder_detect_macrovision(void)
204#else
205int
206gfx_decoder_detect_macrovision(void)
207#endif
208{
209    unsigned char macrovision = 0xff;
210
211    saa7114_read_reg(SAA7114_STATUS, &macrovision);
212    return ((macrovision & 0x02) >> 1);
213}
214
215/*----------------------------------------------------------------------------
216 * gfx_decoder_detect_video
217 *
218 * This routine detects if video exists in the input of the video decoder.
219 *----------------------------------------------------------------------------
220 */
221#if GFX_DECODER_DYNAMIC
222int
223saa7114_decoder_detect_video(void)
224#else
225int
226gfx_decoder_detect_video(void)
227#endif
228{
229    unsigned char video = 0xff;
230
231    saa7114_read_reg(SAA7114_STATUS, &video);
232    return !((video & 0x40) >> 6);
233}
234
235/*----------------------------------------------------------------------------
236 * gfx_set_decoder_defaults
237 *
238 * This routine is called to set the initial register values of the
239 * video decoder.
240 *----------------------------------------------------------------------------
241 */
242#if GFX_DECODER_DYNAMIC
243int
244saa7114_set_decoder_defaults(void)
245#else
246int
247gfx_set_decoder_defaults(void)
248#endif
249{
250    unsigned int i;
251
252    /* LOOP THROUGH INDEX/DATA PAIRS IN THE TABLE */
253
254    for (i = 0; i < GFX_NUM_SAA7114_INIT_VALUES; i++) {
255        saa7114_write_reg(gfx_saa7114_init_values[i].index,
256                          gfx_saa7114_init_values[i].value);
257    }
258
259    gfx_decoder_software_reset();
260    return (0);
261}
262
263/*----------------------------------------------------------------------------
264 * gfx_set_decoder_analog_input
265 *
266 * This routine sets the analog input of the video decoder.
267 *----------------------------------------------------------------------------
268 */
269#if GFX_DECODER_DYNAMIC
270int
271saa7114_set_decoder_analog_input(unsigned char input)
272#else
273int
274gfx_set_decoder_analog_input(unsigned char input)
275#endif
276{
277    saa7114_write_reg(SAA7114_ANALOG_INPUT_CTRL1, input);
278    return (0);
279}
280
281/*----------------------------------------------------------------------------
282 * gfx_set_decoder_brightness
283 *
284 * This routine sets the brightness of the video decoder.
285 *----------------------------------------------------------------------------
286 */
287#if GFX_DECODER_DYNAMIC
288int
289saa7114_set_decoder_brightness(unsigned char brightness)
290#else
291int
292gfx_set_decoder_brightness(unsigned char brightness)
293#endif
294{
295    saa7114_write_reg(SAA7114_BRIGHTNESS, brightness);
296    return (0);
297}
298
299/*----------------------------------------------------------------------------
300 * gfx_set_decoder_contrast
301 *
302 * This routine sets the contrast of the video decoder.
303 *----------------------------------------------------------------------------
304 */
305#if GFX_DECODER_DYNAMIC
306int
307saa7114_set_decoder_contrast(unsigned char contrast)
308#else
309int
310gfx_set_decoder_contrast(unsigned char contrast)
311#endif
312{
313    saa7114_write_reg(SAA7114_CONTRAST, (unsigned char) (contrast >> 1));
314    return (0);
315}
316
317/*----------------------------------------------------------------------------
318 * gfx_set_decoder_hue
319 *
320 * This routine sets the hue control of the video decoder.
321 *----------------------------------------------------------------------------
322 */
323#if GFX_DECODER_DYNAMIC
324int
325saa7114_set_decoder_hue(char hue)
326#else
327int
328gfx_set_decoder_hue(char hue)
329#endif
330{
331    saa7114_write_reg(SAA7114_HUE, (unsigned char) hue);
332    return (0);
333}
334
335/*----------------------------------------------------------------------------
336 * gfx_set_decoder_saturation
337 *
338 * This routine sets the saturation adjustment of the video decoder.
339 *----------------------------------------------------------------------------
340 */
341#if GFX_DECODER_DYNAMIC
342int
343saa7114_set_decoder_saturation(unsigned char saturation)
344#else
345int
346gfx_set_decoder_saturation(unsigned char saturation)
347#endif
348{
349    saa7114_write_reg(SAA7114_SATURATION, (unsigned char) (saturation >> 1));
350    return (0);
351}
352
353/*----------------------------------------------------------------------------
354 * gfx_set_decoder_input_offset
355 *
356 * This routine sets the size of the decoder input window.
357 *----------------------------------------------------------------------------
358 */
359#if GFX_DECODER_DYNAMIC
360int
361saa7114_set_decoder_input_offset(unsigned short x, unsigned short y)
362#else
363int
364gfx_set_decoder_input_offset(unsigned short x, unsigned short y)
365#endif
366{
367    /* SET THE INPUT WINDOW OFFSET */
368
369    saa7114_write_reg(SAA7114_HORZ_OFFSET_LO, (unsigned char) (x & 0x00FF));
370    saa7114_write_reg(SAA7114_HORZ_OFFSET_HI, (unsigned char) (x >> 8));
371    saa7114_write_reg(SAA7114_VERT_OFFSET_LO, (unsigned char) (y & 0x00FF));
372    saa7114_write_reg(SAA7114_VERT_OFFSET_HI, (unsigned char) (y >> 8));
373
374    gfx_decoder_software_reset();
375    return (0);
376}
377
378/*----------------------------------------------------------------------------
379 * gfx_set_decoder_input_size
380 *
381 * This routine sets the size of the decoder input window.
382 *----------------------------------------------------------------------------
383 */
384#if GFX_DECODER_DYNAMIC
385int
386saa7114_set_decoder_input_size(unsigned short width, unsigned short height)
387#else
388int
389gfx_set_decoder_input_size(unsigned short width, unsigned short height)
390#endif
391{
392    /* DIVIDE HEIGHT BY TWO FOR INTERLACING */
393
394    height = (height + 1) >> 1;
395
396    /* SET THE INPUT WINDOW SIZE */
397
398    saa7114_write_reg(SAA7114_HORZ_INPUT_LO, (unsigned char) (width & 0x00FF));
399    saa7114_write_reg(SAA7114_HORZ_INPUT_HI, (unsigned char) (width >> 8));
400    saa7114_write_reg(SAA7114_VERT_INPUT_LO, (unsigned char) (height & 0x00FF));
401    saa7114_write_reg(SAA7114_VERT_INPUT_HI, (unsigned char) (height >> 8));
402
403    gfx_decoder_software_reset();
404    return (0);
405}
406
407/*----------------------------------------------------------------------------
408 * gfx_set_decoder_output_size
409 *
410 * This routine sets the size of the decoder output window.
411 *----------------------------------------------------------------------------
412 */
413#if GFX_DECODER_DYNAMIC
414int
415saa7114_set_decoder_output_size(unsigned short width, unsigned short height)
416#else
417int
418gfx_set_decoder_output_size(unsigned short width, unsigned short height)
419#endif
420{
421    /* ROUND WIDTH UP TO EVEN NUMBER TO PREVENT DECODER BECOMING STUCK */
422
423    width = ((width + 1) >> 1) << 1;
424
425    /* DIVIDE HEIGHT BY TWO FOR INTERLACING */
426
427    height = (height + 1) >> 1;
428
429    /* SET THE OUTPUT WINDOW SIZE */
430
431    saa7114_write_reg(SAA7114_HORZ_OUTPUT_LO, (unsigned char) (width & 0x00FF));
432    saa7114_write_reg(SAA7114_HORZ_OUTPUT_HI, (unsigned char) (width >> 8));
433    saa7114_write_reg(SAA7114_VERT_OUTPUT_LO,
434                      (unsigned char) (height & 0x00FF));
435    saa7114_write_reg(SAA7114_VERT_OUTPUT_HI, (unsigned char) (height >> 8));
436
437    gfx_decoder_software_reset();
438    return (0);
439}
440
441/*----------------------------------------------------------------------------
442 * gfx_set_decoder_scale
443 *
444 * This routine sets the scaling of the video decoder.
445 *----------------------------------------------------------------------------
446 */
447#if GFX_DECODER_DYNAMIC
448int
449saa7114_set_decoder_scale(unsigned short srcw, unsigned short srch,
450                          unsigned short dstw, unsigned short dsth)
451#else
452int
453gfx_set_decoder_scale(unsigned short srcw, unsigned short srch,
454                      unsigned short dstw, unsigned short dsth)
455#endif
456{
457    unsigned char prescale = 0;
458    int scale = 0;
459
460    /* SET THE HORIZONTAL PRESCALE */
461    /* Downscale from 1 to 1/63 source size. */
462
463    if (dstw)
464        prescale = (unsigned char) (srcw / dstw);
465    if (!prescale)
466        prescale = 1;
467    if (prescale > 63)
468        return (1);
469    saa7114_write_reg(SAA7114_HORZ_PRESCALER, prescale);
470
471    /* USE FIR PREFILTER FUNCTIONALITY (OPTIMISATION) */
472
473    if (prescale < 36) {
474        if (optimize_for_aliasing) {
475            saa7114_write_reg(SAA7114_HORZ_ACL,
476                              gfx_saa7114_fir_values[prescale - 1].acl_low);
477            saa7114_write_reg(SAA7114_HORZ_FIR_PREFILTER,
478                              gfx_saa7114_fir_values[prescale -
479                                                     1].prefilter_low);
480        }
481        else {
482            saa7114_write_reg(SAA7114_HORZ_ACL,
483                              gfx_saa7114_fir_values[prescale - 1].acl_high);
484            saa7114_write_reg(SAA7114_HORZ_FIR_PREFILTER,
485                              gfx_saa7114_fir_values[prescale -
486                                                     1].prefilter_high);
487        }
488    }
489    else {
490        /* SAME SETTINGS FOR RATIO 1/35 DOWNTO 1/63 */
491        if (optimize_for_aliasing) {
492            saa7114_write_reg(SAA7114_HORZ_ACL,
493                              gfx_saa7114_fir_values[34].acl_low);
494            saa7114_write_reg(SAA7114_HORZ_FIR_PREFILTER,
495                              gfx_saa7114_fir_values[34].prefilter_low);
496        }
497        else {
498            saa7114_write_reg(SAA7114_HORZ_ACL,
499                              gfx_saa7114_fir_values[34].acl_high);
500            saa7114_write_reg(SAA7114_HORZ_FIR_PREFILTER,
501                              gfx_saa7114_fir_values[34].prefilter_high);
502        }
503    }
504
505    /* SET THE HORIZONTAL SCALING */
506
507    if (!dstw)
508        return (1);
509    scale = ((1024 * srcw * 1000) / (dstw * prescale)) / 1000;
510    if ((scale > 8191) || (scale < 300))
511        return (1);
512    saa7114_write_reg(SAA7114_HSCALE_LUMA_LO, (unsigned char) (scale & 0x00FF));
513    saa7114_write_reg(SAA7114_HSCALE_LUMA_HI, (unsigned char) (scale >> 8));
514    scale >>= 1;
515    saa7114_write_reg(SAA7114_HSCALE_CHROMA_LO,
516                      (unsigned char) (scale & 0x00FF));
517    saa7114_write_reg(SAA7114_HSCALE_CHROMA_HI, (unsigned char) (scale >> 8));
518
519    /* SET THE VERTICAL SCALING (INTERPOLATION MODE) */
520
521    if (!dsth)
522        return (1);
523
524    /* ROUND DESTINATION HEIGHT UP TO EVEN NUMBER TO PREVENT DECODER BECOMING
525     * STUCK */
526
527    dsth = ((dsth + 1) >> 1) << 1;
528
529    scale = (int) ((1024 * srch) / dsth);
530    saa7114_write_reg(SAA7114_VSCALE_LUMA_LO, (unsigned char) (scale & 0x00FF));
531    saa7114_write_reg(SAA7114_VSCALE_LUMA_HI, (unsigned char) (scale >> 8));
532    saa7114_write_reg(SAA7114_VSCALE_CHROMA_LO,
533                      (unsigned char) (scale & 0x00FF));
534    saa7114_write_reg(SAA7114_VSCALE_CHROMA_HI, (unsigned char) (scale >> 8));
535
536    if (dsth >= (srch >> 1)) {
537        /* USE INTERPOLATION MODE FOR SCALE FACTOR ABOVE 0.5 */
538
539        saa7114_write_reg(SAA7114_VSCALE_CONTROL, 0x00);
540
541        /* SET VERTICAL PHASE REGISTER FOR CORRECT SCALED INTERLACED OUTPUT
542         * (OPTIMISATION) */
543        /* THE OPTIMISATION IS BASED ON OFIDC = 0 (REG 90h[6] = 0 ) */
544        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS0, SAA7114_VSCALE_PHO);
545        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS1, SAA7114_VSCALE_PHO);
546        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS2,
547                          (unsigned char) (SAA7114_VSCALE_PHO + scale / 64 -
548                                           16));
549        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS3,
550                          (unsigned char) (SAA7114_VSCALE_PHO + scale / 64 -
551                                           16));
552
553        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS0, SAA7114_VSCALE_PHO);
554        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS1, SAA7114_VSCALE_PHO);
555        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS2,
556                          (unsigned char) (SAA7114_VSCALE_PHO + scale / 64 -
557                                           16));
558        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS3,
559                          (unsigned char) (SAA7114_VSCALE_PHO + scale / 64 -
560                                           16));
561
562        /* RESTORE CONTRAST AND SATURATION FOR INTERPOLATION MODE */
563
564        saa7114_write_reg(SAA7114_FILTER_CONTRAST, (unsigned char) 0x40);
565        saa7114_write_reg(SAA7114_FILTER_SATURATION, (unsigned char) 0x40);
566    }
567    else {
568        /* USE ACCUMULATION MODE FOR DOWNSCALING BY MORE THAN 2x */
569
570        saa7114_write_reg(SAA7114_VSCALE_CONTROL, 0x01);
571
572        /* SET VERTICAL PHASE OFFSETS OFF (OPTIMISATION) */
573        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS0, 0x00);
574        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS1, 0x00);
575        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS2, 0x00);
576        saa7114_write_reg(SAA7114_VSCALE_CHROMA_OFFS3, 0x00);
577
578        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS0, 0x00);
579        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS1, 0x00);
580        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS2, 0x00);
581        saa7114_write_reg(SAA7114_VSCALE_LUMINA_OFFS3, 0x00);
582
583        /* ADJUST CONTRAST AND SATURATION FOR ACCUMULATION MODE */
584
585        if (srch)
586            scale = (64 * dsth) / srch;
587        saa7114_write_reg(SAA7114_FILTER_CONTRAST, (unsigned char) scale);
588        saa7114_write_reg(SAA7114_FILTER_SATURATION, (unsigned char) scale);
589    }
590
591    gfx_decoder_software_reset();
592    return (0);
593}
594
595/*----------------------------------------------------------------------------
596 * gfx_set_decoder_vbi_format
597 *
598 * This routine programs the decoder to produce the specified format of VBI
599 * data for the specified lines.
600 *----------------------------------------------------------------------------
601 */
602#if GFX_DECODER_DYNAMIC
603int
604saa7114_set_decoder_vbi_format(int start, int end, int format)
605#else
606int
607gfx_set_decoder_vbi_format(int start, int end, int format)
608#endif
609{
610    int i;
611    unsigned char data;
612
613    for (i = start; i <= end; i++) {
614        switch (format) {
615        case VBI_FORMAT_VIDEO:
616            data = 0xFF;
617            break;              /* Active video */
618        case VBI_FORMAT_RAW:
619            data = 0x77;
620            break;              /* Raw VBI data */
621        case VBI_FORMAT_CC:
622            data = 0x55;
623            break;              /* US CC        */
624        case VBI_FORMAT_NABTS:
625            data = 0xCC;
626            break;              /* US NABTS     */
627        default:
628            return GFX_STATUS_BAD_PARAMETER;
629        }
630        saa7114_write_reg((unsigned char) (0x3F + i), data);
631    }
632    return GFX_STATUS_OK;
633}
634
635/*----------------------------------------------------------------------------
636 * gfx_set_decoder_vbi_enable
637 *
638 * This routine enables or disables VBI transfer in the decoder.
639 *----------------------------------------------------------------------------
640 */
641#if GFX_DECODER_DYNAMIC
642int
643saa7114_set_decoder_vbi_enable(int enable)
644#else
645int
646gfx_set_decoder_vbi_enable(int enable)
647#endif
648{
649    unsigned char data;
650
651    saa7114_read_reg(SAA7114_IPORT_CONTROL, &data);
652    if (enable)
653        data |= 0x80;
654    else
655        data &= ~0x80;
656    saa7114_write_reg(SAA7114_IPORT_CONTROL, data);
657    return GFX_STATUS_OK;
658}
659
660/*----------------------------------------------------------------------------
661 * gfx_set_decoder_TV_standard
662 *
663 * This routine configures the decoder for the required TV standard.
664 *----------------------------------------------------------------------------
665 */
666#if GFX_DECODER_DYNAMIC
667int
668saa7114_set_decoder_TV_standard(TVStandardType TVStandard)
669#else
670int
671gfx_set_decoder_TV_standard(TVStandardType TVStandard)
672#endif
673{
674    switch (TVStandard) {
675    case TV_STANDARD_NTSC:
676        saa7114_write_reg(0x0E, 0x89);
677        saa7114_write_reg(0x5A, 0x06);
678        break;
679    case TV_STANDARD_PAL:
680        saa7114_write_reg(0x0E, 0x81);
681        saa7114_write_reg(0x5A, 0x03);
682        break;
683    default:
684        return GFX_STATUS_BAD_PARAMETER;
685    }
686    gfx_decoder_software_reset();
687    return GFX_STATUS_OK;
688}
689
690/*----------------------------------------------------------------------------
691 * gfx_set_decoder_luminance_filter
692 *
693 * This routine sets the hue control of the video decoder.
694 *----------------------------------------------------------------------------
695 */
696#if GFX_DECODER_DYNAMIC
697int
698saa7114_set_decoder_luminance_filter(unsigned char lufi)
699#else
700int
701gfx_set_decoder_luminance_filter(unsigned char lufi)
702#endif
703{
704    unsigned char data;
705
706    saa7114_read_reg(SAA7114_LUMINANCE_CONTROL, &data);
707    saa7114_write_reg(SAA7114_LUMINANCE_CONTROL,
708                      (unsigned char) ((data & ~0x0F) | (lufi & 0x0F)));
709    return (0);
710}
711
712/*************************************************************/
713/*  READ ROUTINES  |  INCLUDED FOR DIAGNOSTIC PURPOSES ONLY  */
714/*************************************************************/
715
716#if GFX_READ_ROUTINES
717
718/*----------------------------------------------------------------------------
719 * gfx_get_decoder_brightness
720 *
721 * This routine returns the current brightness of the video decoder.
722 *----------------------------------------------------------------------------
723 */
724#if GFX_DECODER_DYNAMIC
725unsigned char
726saa7114_get_decoder_brightness(void)
727#else
728unsigned char
729gfx_get_decoder_brightness(void)
730#endif
731{
732    unsigned char brightness = 0;
733
734    saa7114_read_reg(SAA7114_BRIGHTNESS, &brightness);
735    return (brightness);
736}
737
738/*----------------------------------------------------------------------------
739 * gfx_get_decoder_contrast
740 *
741 * This routine returns the current contrast of the video decoder.
742 *----------------------------------------------------------------------------
743 */
744#if GFX_DECODER_DYNAMIC
745unsigned char
746saa7114_get_decoder_contrast(void)
747#else
748unsigned char
749gfx_get_decoder_contrast(void)
750#endif
751{
752    unsigned char contrast = 0;
753
754    saa7114_read_reg(SAA7114_CONTRAST, &contrast);
755    contrast <<= 1;
756    return (contrast);
757}
758
759/*----------------------------------------------------------------------------
760 * gfx_get_decoder_hue
761 *
762 * This routine returns the current hue of the video decoder.
763 *----------------------------------------------------------------------------
764 */
765#if GFX_DECODER_DYNAMIC
766char
767saa7114_get_decoder_hue(void)
768#else
769char
770gfx_get_decoder_hue(void)
771#endif
772{
773    unsigned char hue = 0;
774
775    saa7114_read_reg(SAA7114_HUE, &hue);
776    return ((char) hue);
777}
778
779/*----------------------------------------------------------------------------
780 * gfx_get_decoder_saturation
781 *
782 * This routine returns the current saturation of the video decoder.
783 *----------------------------------------------------------------------------
784 */
785#if GFX_DECODER_DYNAMIC
786unsigned char
787saa7114_get_decoder_saturation(void)
788#else
789unsigned char
790gfx_get_decoder_saturation(void)
791#endif
792{
793    unsigned char saturation = 0;
794
795    saa7114_read_reg(SAA7114_SATURATION, &saturation);
796    saturation <<= 1;
797    return (saturation);
798}
799
800/*----------------------------------------------------------------------------
801 * gfx_get_decoder_input_offset
802 *
803 * This routine returns the offset into the input window.
804 *----------------------------------------------------------------------------
805 */
806#if GFX_DECODER_DYNAMIC
807unsigned long
808saa7114_get_decoder_input_offset(void)
809#else
810unsigned long
811gfx_get_decoder_input_offset(void)
812#endif
813{
814    unsigned long value = 0;
815    unsigned char data;
816
817    saa7114_read_reg(SAA7114_HORZ_OFFSET_LO, &data);
818    value = (unsigned long) data;
819    saa7114_read_reg(SAA7114_HORZ_OFFSET_HI, &data);
820    value |= ((unsigned long) data) << 8;
821    saa7114_read_reg(SAA7114_VERT_OFFSET_LO, &data);
822    value |= ((unsigned long) data) << 16;
823    saa7114_read_reg(SAA7114_VERT_OFFSET_HI, &data);
824    value |= ((unsigned long) data) << 24;
825    return (value);
826}
827
828/*----------------------------------------------------------------------------
829 * gfx_get_decoder_input_size
830 *
831 * This routine returns the current size of the input window
832 *----------------------------------------------------------------------------
833 */
834#if GFX_DECODER_DYNAMIC
835unsigned long
836saa7114_get_decoder_input_size(void)
837#else
838unsigned long
839gfx_get_decoder_input_size(void)
840#endif
841{
842    unsigned long value = 0;
843    unsigned char data;
844
845    saa7114_read_reg(SAA7114_HORZ_INPUT_LO, &data);
846    value = (unsigned long) data;
847    saa7114_read_reg(SAA7114_HORZ_INPUT_HI, &data);
848    value |= ((unsigned long) data) << 8;
849    saa7114_read_reg(SAA7114_VERT_INPUT_LO, &data);
850    value |= ((unsigned long) data) << 17;
851    saa7114_read_reg(SAA7114_VERT_INPUT_HI, &data);
852    value |= ((unsigned long) data) << 25;
853    return (value);
854}
855
856/*----------------------------------------------------------------------------
857 * gfx_get_decoder_output_size
858 *
859 * This routine returns the current size of the output window.
860 *----------------------------------------------------------------------------
861 */
862#if GFX_DECODER_DYNAMIC
863unsigned long
864saa7114_get_decoder_output_size(void)
865#else
866unsigned long
867gfx_get_decoder_output_size(void)
868#endif
869{
870    unsigned long value = 0;
871    unsigned char data;
872
873    saa7114_read_reg(SAA7114_HORZ_OUTPUT_LO, &data);
874    value = (unsigned long) data;
875    saa7114_read_reg(SAA7114_HORZ_OUTPUT_HI, &data);
876    value |= ((unsigned long) data) << 8;
877    saa7114_read_reg(SAA7114_VERT_OUTPUT_LO, &data);
878    value |= ((unsigned long) data) << 17;
879    saa7114_read_reg(SAA7114_VERT_OUTPUT_HI, &data);
880    value |= ((unsigned long) data) << 25;
881    return (value);
882}
883
884/*----------------------------------------------------------------------------
885 * gfx_get_decoder_vbi_format
886 *
887 * This routine returns the current format of VBI data for the specified line.
888 *----------------------------------------------------------------------------
889 */
890#if GFX_DECODER_DYNAMIC
891int
892saa7114_get_decoder_vbi_format(int line)
893#else
894int
895gfx_get_decoder_vbi_format(int line)
896#endif
897{
898    unsigned char format = 0, data;
899
900    saa7114_read_reg((unsigned char) (0x3F + line), &data);
901    switch (data) {
902    case 0xFF:
903        format = VBI_FORMAT_VIDEO;
904        break;                  /* Active video */
905    case 0x77:
906        format = VBI_FORMAT_RAW;
907        break;                  /* Raw VBI data */
908    case 0x55:
909        format = VBI_FORMAT_CC;
910        break;                  /* US CC        */
911    case 0xCC:
912        format = VBI_FORMAT_NABTS;
913        break;                  /* US NABTS     */
914    }
915    return (format);
916}
917
918#endif                          /* GFX_READ_ROUTINES */
919
920/* END OF FILE */
921