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