tv_1200.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 SC1200 TVOUT and TV encoder.
28 * */
29
30/*----------------------------------------------------------------------------
31 * gfx_set_tv_format
32 *
33 * This routine sets the TV encoder registers to the specified format
34 * and resolution.
35 *----------------------------------------------------------------------------
36 */
37#if GFX_TV_DYNAMIC
38int
39sc1200_set_tv_format(TVStandardType format, GfxOnTVType resolution)
40#else
41int
42gfx_set_tv_format(TVStandardType format, GfxOnTVType resolution)
43#endif
44{
45    unsigned long ctrl2, mode;
46
47    /* Save TV output mode */
48    ctrl2 =
49        READ_VID32(SC1200_TVENC_TIM_CTRL_2) & (SC1200_TVENC_OUTPUT_YCBCR |
50        SC1200_TVENC_CFS_MASK);
51    /* Save flicker filter setting */
52    mode =
53        READ_VID32(SC1200_TVOUT_HORZ_SCALING) &
54        SC1200_TVOUT_FLICKER_FILTER_MASK;
55
56    switch (format) {
57    case TV_STANDARD_NTSC:
58        /* Horizontal Sync Start is 848 */
59        /* Horizontal Sync End is 856 */
60        WRITE_VID32(SC1200_TVOUT_HORZ_SYNC, 0x03580350);
61        /* Vertical Sync Start is 0 */
62        /* Vertical Sync End is 1 */
63        /* Vertical Display Start Skew is 1 */
64        /* Vertical Display End Skew is 1 */
65        WRITE_VID32(SC1200_TVOUT_VERT_SYNC, 0x05001000);
66        /* Disable vertical down scaling, take all lines */
67        if (gfx_chip_revision <= SC1200_REV_B3)
68            WRITE_VID32(SC1200_TVOUT_VERT_DOWNSCALE, 0xffffffff);
69        /* Enable video timing */
70        /* Reset sub carrier every two frames */
71        /* Disable BLANK */
72        /* Enable color burst */
73        /* Add the IRE offset */
74        /* NTSC color encoding */
75        /* Video generator timing is 525 lines / 60Hz */
76        /* Horizontal and Vertical counters are initialized to HPHASE &
77         * VPHASE */
78        /* VPHASE is 2, HPHASE is 0x50 */
79        WRITE_VID32(SC1200_TVENC_TIM_CTRL_1, 0xa2a01050);
80        /* Increase horizontal blanking interval */
81        /* Low Water Mark for Y is 0x1F */
82        /* Low Water Mark for Cb is 0xF */
83        /* HUE is 0 */
84        /* SCPHASE is 0xF9 */
85        WRITE_VID32(SC1200_TVENC_TIM_CTRL_2, 0x9ff000f9 | ctrl2);
86        /* Subcarrier Frequency is 3.579545 MHz */
87        WRITE_VID32(SC1200_TVENC_SUB_FREQ, 0x21f07c1f);
88        /* VSTART is 18, HSTART is 113 */
89        WRITE_VID32(SC1200_TVENC_DISP_POS, 0x00120071);
90        /* Display size: HEIGHT is 239, WIDTH is 719 */
91        WRITE_VID32(SC1200_TVENC_DISP_SIZE, 0x00ef02cf);
92        switch (resolution) {
93        case GFX_ON_TV_SQUARE_PIXELS:
94            if (gfx_chip_revision <= SC1200_REV_B3) {
95                /* Horizontal Display start is 116 */
96                /* Total number of pixels per line is 857 */
97                WRITE_VID32(SC1200_TVOUT_HORZ_TIM, 0x00740359);
98                /* HSYNC generated in the TV Encoder module */
99                /* Interval between resets of TV Encoder is once every odd
100                 * field */
101                /* Enable Horizontal interpolation */
102                /* Enable Horizontal up scaling 9/8 */
103                /* Disable Horizontal downscale */
104                WRITE_VID32(SC1200_TVOUT_HORZ_SCALING, 0x10020700 | mode);
105                /* Horizontal display end is 919, i.e. 720 active pixels */
106                /* Total number of display lines per field is 240 */
107                WRITE_VID32(SC1200_TVOUT_LINE_END, 0x039700f0);
108            } else {                   /* Use new scaler available in Rev. C */
109                /* Horizontal Display start is 111 */
110                /* Total number of pixels per line is 857 */
111                WRITE_VID32(SC1200_TVOUT_HORZ_TIM, 0x006f0359);
112                /* HSYNC generated in the TV Encoder module */
113                /* Interval between resets of TV Encoder is once every odd
114                 * field */
115                /* Enable Horizontal interpolation */
116                /* Disable Horizontal up scaling 9/8 */
117                /* Disable Horizontal downscale */
118                WRITE_VID32(SC1200_TVOUT_HORZ_SCALING, 0x10020500 | mode);
119                /* Set Horizontal upscaling to 64/58 (~ 11/10) */
120                WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE, 0x3A000000);
121                /* Horizontal display end is 900, i.e. 706 active pixels */
122                /* Total number of display lines per field is 240 */
123                WRITE_VID32(SC1200_TVOUT_LINE_END, 0x038400f0);
124            }
125            break;
126        case GFX_ON_TV_NO_SCALING:
127            /* Horizontal Display start is 116 */
128            /* Total number of pixels per line is 857 */
129            WRITE_VID32(SC1200_TVOUT_HORZ_TIM, 0x00740359);
130            /* HSYNC generated in the TV Encoder module */
131            /* Interval between resets of TV Encoder is once every odd field */
132            /* Enable Horizontal interpolation */
133            /* Disable Horizontal up scaling 9/8 */
134            /* Disable Horizontal downscale */
135            WRITE_VID32(SC1200_TVOUT_HORZ_SCALING, 0x10020500 | mode);
136            /* Disable Horizontal scaling (set to 64/64) */
137            if (gfx_chip_revision >= SC1200_REV_C1)
138                WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE, 0x40000000);
139            /* Horizontal display end is 919, i.e. 720 active pixels */
140            /* Total number of display lines per field is 240 */
141            WRITE_VID32(SC1200_TVOUT_LINE_END, 0x039700f0);
142            break;
143        default:
144            return (GFX_STATUS_BAD_PARAMETER);
145        }
146        break;
147    case TV_STANDARD_PAL:
148        /* Horizontal Sync Start is 854 */
149        /* Horizontal Sync End is 862 */
150        WRITE_VID32(SC1200_TVOUT_HORZ_SYNC, 0x035e0356);
151        /* Vertical Sync Start is 0 */
152        /* Vertical Sync End is 1 */
153        /* Vertical Display Start Skew is 1 */
154        /* Vertical Display End Skew is 1 */
155        WRITE_VID32(SC1200_TVOUT_VERT_SYNC, 0x05001000);
156        /* Disable vertical down scaling, take all lines */
157        if (gfx_chip_revision <= SC1200_REV_B3)
158            WRITE_VID32(SC1200_TVOUT_VERT_DOWNSCALE, 0xffffffff);
159        /* Enable video timing */
160        /* Never reset sub carrier (should be every 4 frames but doesn't work
161         * with genlock) */
162        /* Disable BLANK */
163        /* Enable color burst */
164        /* Do not add the IRE offset */
165        /* NTSC color encoding */
166        /* Video generator timing is 625 lines / 50Hz */
167        /* Horizontal and Vertical counters are initialized to HPHASE & VPHASE
168         * */
169        /* VPHASE is 2, HPHASE is 50 */
170        WRITE_VID32(SC1200_TVENC_TIM_CTRL_1, 0xB1201050);
171        /* Increase horizontal blanking interval */
172        /* Low Water Mark for Y is 0x1F */
173        /* Low Water Mark for Cb is 0xF */
174        /* HUE is 0 */
175        /* SCPHASE is 0xD9 */
176        WRITE_VID32(SC1200_TVENC_TIM_CTRL_2, 0x9ff000d9 | ctrl2);
177        /* Subcarrier Frequency is 4.43361875 MHz */
178        WRITE_VID32(SC1200_TVENC_SUB_FREQ, 0x2a098acb);
179        /* VSTART is 22, HSTART is 123 */
180        WRITE_VID32(SC1200_TVENC_DISP_POS, 0x0016007b);
181        /* Display size: HEIGHT is 287, WIDTH is 719 */
182        WRITE_VID32(SC1200_TVENC_DISP_SIZE, 0x011f02cf);
183        switch (resolution) {
184        case GFX_ON_TV_NO_SCALING:
185            /* Horizontal Display start is 124 */
186            /* Total number of pixels per line is 863 */
187            WRITE_VID32(SC1200_TVOUT_HORZ_TIM, 0x007c035f);
188            /* HSYNC generated in the TV Encoder module */
189            /* Interval between resets of TV Encoder is once every odd field */
190            /* Enable Horizontal interpolation */
191            /* Disable Horizontal up scaling 9/8 */
192            /* Disable Horizontal downscale */
193            WRITE_VID32(SC1200_TVOUT_HORZ_SCALING, 0x10020500 | mode);
194            /* Disable Horizontal scaling (set to 64/64) */
195            if (gfx_chip_revision >= SC1200_REV_C1)
196                WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE, 0x40000000);
197            /* Horizontal display end is 924, i.e. 720 active pixels */
198            /* Total number of display lines per field is 288 */
199            WRITE_VID32(SC1200_TVOUT_LINE_END, 0x039c0120);
200            break;
201        case GFX_ON_TV_SQUARE_PIXELS:
202            /* Horizontal Display start is 122 */
203            /* Total number of pixels per line is 863 */
204            WRITE_VID32(SC1200_TVOUT_HORZ_TIM, 0x007a035f);
205            if (gfx_chip_revision <= SC1200_REV_B3) {
206                /* HSYNC generated in the TV Encoder module */
207                /* Interval between resets of TV Encoder is once every odd
208                 * field */
209                /* Enable Horizontal interpolation */
210                /* Disable Horizontal up scaling 9/8 */
211                /* Horizontal downscale m/(m+1), m = 11, (i.e. 11/12 - closest
212                 * possible to 54/59) */
213                WRITE_VID32(SC1200_TVOUT_HORZ_SCALING, 0x1002040b | mode);
214                /* Horizontal display end is 906, i.e. 704 active pixels */
215                /* Total number of display lines per field is 288 */
216                WRITE_VID32(SC1200_TVOUT_LINE_END, 0x038a0120);
217            } else {
218                /* HSYNC generated in the TV Encoder module */
219                /* Interval between resets of TV Encoder is once every odd
220                 * field */
221                /* Enable Horizontal interpolation */
222                /* Disable Horizontal up scaling 9/8 */
223                /* Disable Horizontal downscale */
224                WRITE_VID32(SC1200_TVOUT_HORZ_SCALING, 0x10020500 | mode);
225                /* Set Horizontal down scaling to 64/70 (closest possible to
226                 * 54/59) */
227                WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE, 0x46000000);
228                /* Horizontal display end is 904, i.e. 702 active pixels */
229                /* Total number of display lines per field is 288 */
230                WRITE_VID32(SC1200_TVOUT_LINE_END, 0x03880120);
231            }
232            break;
233        default:
234            return (GFX_STATUS_BAD_PARAMETER);
235        }
236        break;
237    default:
238        return (GFX_STATUS_BAD_PARAMETER);
239    }
240    return (GFX_STATUS_OK);
241}
242
243/*----------------------------------------------------------------------------
244 * gfx_set_tv_output
245 *
246 * This routine sets the TV encoder registers to the specified output type.
247 * Supported output types are : S-VIDEO, Composite, YUV and SCART.
248 *----------------------------------------------------------------------------
249 */
250#if GFX_TV_DYNAMIC
251int
252sc1200_set_tv_output(int output)
253#else
254int
255gfx_set_tv_output(int output)
256#endif
257{
258    unsigned long ctrl2, ctrl3;
259
260    ctrl2 = READ_VID32(SC1200_TVENC_TIM_CTRL_2);
261    ctrl3 = READ_VID32(SC1200_TVENC_TIM_CTRL_3);
262    ctrl2 &= ~(SC1200_TVENC_OUTPUT_YCBCR | SC1200_TVENC_CFS_MASK);
263    ctrl3 &=
264        ~(SC1200_TVENC_CM | SC1200_TVENC_SYNCMODE_MASK | SC1200_TVENC_CS);
265    switch (output) {
266    case TV_OUTPUT_COMPOSITE:
267        /* Analog outputs provide Y, C and CVBS */
268        /* Chrominance Lowpass filter is 1.3MHz (for composite video output) */
269        WRITE_VID32(SC1200_TVENC_TIM_CTRL_2, ctrl2 | SC1200_TVENC_CFS_CVBS);
270        WRITE_VID32(SC1200_TVENC_TIM_CTRL_3, ctrl3);
271        break;
272    case TV_OUTPUT_S_VIDEO:
273        /* Analog outputs provide Y, C and CVBS */
274        /* Chrominance Lowpass filter is 1.8MHz (for S-video output) */
275        WRITE_VID32(SC1200_TVENC_TIM_CTRL_2, ctrl2 | SC1200_TVENC_CFS_SVIDEO);
276        WRITE_VID32(SC1200_TVENC_TIM_CTRL_3, ctrl3);
277        break;
278    case TV_OUTPUT_YUV:
279        /* Analog outputs provide Y, Cb and Cr */
280        /* A 7.5 IRE setup is applied to the output */
281        WRITE_VID32(SC1200_TVENC_TIM_CTRL_2,
282            ctrl2 | SC1200_TVENC_OUTPUT_YCBCR | SC1200_TVENC_CFS_BYPASS);
283        WRITE_VID32(SC1200_TVENC_TIM_CTRL_3,
284            ctrl3 | SC1200_TVENC_CM | SC1200_TVENC_CS);
285        break;
286    case TV_OUTPUT_SCART:
287        /* Analog outputs provide SCART (RGB and CVBS) */
288        /* Sync is added to green signal */
289        WRITE_VID32(SC1200_TVENC_TIM_CTRL_2, ctrl2 | SC1200_TVENC_CFS_CVBS);
290        WRITE_VID32(SC1200_TVENC_TIM_CTRL_3,
291            ctrl3 | SC1200_TVENC_CM | SC1200_TVENC_SYNC_ON_GREEN);
292        break;
293    default:
294        return (GFX_STATUS_BAD_PARAMETER);
295    }
296
297    /* Adjusts the internal voltage reference */
298    ctrl2 = READ_VID32(SC1200_TVENC_DAC_CONTROL);
299    ctrl2 &= ~SC1200_TVENC_TRIM_MASK;
300
301    /* Bypass for issue #926 : Inadequate chroma level of S-Video output */
302    if ((gfx_chip_revision == SC1200_REV_B3) && (output == TV_OUTPUT_S_VIDEO))
303        ctrl2 |= 0x7;
304    else
305        ctrl2 |= 0x5;
306
307    WRITE_VID32(SC1200_TVENC_DAC_CONTROL, ctrl2);
308
309    /* Disable 4:2:2 to 4:4:4 converter interpolation */
310    WRITE_VID32(SC1200_TVOUT_DEBUG, SC1200_TVOUT_CONVERTER_INTERPOLATION);
311
312    return (GFX_STATUS_OK);
313}
314
315/*----------------------------------------------------------------------------
316 * gfx_set_tv_enable
317 *
318 * This routine enables or disables the TV output.
319 *----------------------------------------------------------------------------
320 */
321#if GFX_TV_DYNAMIC
322int
323sc1200_set_tv_enable(int enable)
324#else
325int
326gfx_set_tv_enable(int enable)
327#endif
328{
329    unsigned long value_tim, value_dac;
330
331    value_tim = READ_VID32(SC1200_TVENC_TIM_CTRL_1);
332    value_dac = READ_VID32(SC1200_TVENC_DAC_CONTROL);
333
334    if (enable) {
335        value_tim |= SC1200_TVENC_VIDEO_TIMING_ENABLE;
336        value_dac &= ~SC1200_TVENC_POWER_DOWN;
337        /* ENABLE GRAPHICS DISPLAY LOGIC IN VIDEO PROCESSOR */
338        gfx_set_screen_enable(1);
339    } else {
340        value_tim &= ~SC1200_TVENC_VIDEO_TIMING_ENABLE;
341        value_dac |= SC1200_TVENC_POWER_DOWN;
342        /* Do not disable the graphics display logic because it might be
343         * needed for CRT */
344    }
345
346    WRITE_VID32(SC1200_TVENC_TIM_CTRL_1, value_tim);
347    WRITE_VID32(SC1200_TVENC_DAC_CONTROL, value_dac);
348
349    return (GFX_STATUS_OK);
350}
351
352/*----------------------------------------------------------------------------
353 * gfx_set_tv_flicker_filter
354 *
355 * This routine configures the TV out flicker filter.
356 *----------------------------------------------------------------------------
357 */
358#if GFX_TV_DYNAMIC
359int
360sc1200_set_tv_flicker_filter(int ff)
361#else
362int
363gfx_set_tv_flicker_filter(int ff)
364#endif
365{
366    unsigned long mode;
367
368    mode = READ_VID32(SC1200_TVOUT_HORZ_SCALING);
369    mode &= ~SC1200_TVOUT_FLICKER_FILTER_MASK;
370    switch (ff) {
371    case TV_FLICKER_FILTER_NONE:
372        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
373            mode | SC1200_TVOUT_FLICKER_FILTER_DISABLED);
374        break;
375    case TV_FLICKER_FILTER_NORMAL:
376        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
377            mode | SC1200_TVOUT_FLICKER_FILTER_FOURTH_HALF_FOURTH);
378        break;
379    case TV_FLICKER_FILTER_INTERLACED:
380        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
381            mode | SC1200_TVOUT_FLICKER_FILTER_HALF_ONE_HALF);
382        break;
383    default:
384        return GFX_STATUS_BAD_PARAMETER;
385    }
386    return (GFX_STATUS_OK);
387}
388
389/*----------------------------------------------------------------------------
390 * gfx_set_tv_sub_carrier_reset
391 *
392 * This routine configures the TV encoder sub carrier reset interval.
393 *----------------------------------------------------------------------------
394 */
395#if GFX_TV_DYNAMIC
396int
397sc1200_set_tv_sub_carrier_reset(int screset)
398#else
399int
400gfx_set_tv_sub_carrier_reset(int screset)
401#endif
402{
403    unsigned long mode;
404
405    mode = READ_VID32(SC1200_TVENC_TIM_CTRL_1);
406    mode &= ~SC1200_TVENC_SUB_CARRIER_RESET_MASK;
407    switch (screset) {
408    case TV_SUB_CARRIER_RESET_NEVER:
409        WRITE_VID32(SC1200_TVENC_TIM_CTRL_1,
410            mode | SC1200_TVENC_SUB_CARRIER_RESET_NEVER);
411        break;
412    case TV_SUB_CARRIER_RESET_EVERY_TWO_LINES:
413        WRITE_VID32(SC1200_TVENC_TIM_CTRL_1,
414            mode | SC1200_TVENC_SUB_CARRIER_RESET_EVERY_TWO_LINES);
415        break;
416    case TV_SUB_CARRIER_RESET_EVERY_TWO_FRAMES:
417        WRITE_VID32(SC1200_TVENC_TIM_CTRL_1,
418            mode | SC1200_TVENC_SUB_CARRIER_RESET_EVERY_TWO_FRAMES);
419        break;
420    case TV_SUB_CARRIER_RESET_EVERY_FOUR_FRAMES:
421        WRITE_VID32(SC1200_TVENC_TIM_CTRL_1,
422            mode | SC1200_TVENC_SUB_CARRIER_RESET_EVERY_FOUR_FRAMES);
423        break;
424    default:
425        return GFX_STATUS_BAD_PARAMETER;
426    }
427    return (GFX_STATUS_OK);
428}
429
430/*----------------------------------------------------------------------------
431 * gfx_set_tv_vphase
432 *
433 * This routine sets the tv encoder VPHASE value.
434 *----------------------------------------------------------------------------
435 */
436#if GFX_TV_DYNAMIC
437int
438sc1200_set_tv_vphase(int vphase)
439#else
440int
441gfx_set_tv_vphase(int vphase)
442#endif
443{
444    unsigned long mode = READ_VID32(SC1200_TVENC_TIM_CTRL_1);
445
446    mode &= ~SC1200_TVENC_VPHASE_MASK;
447    mode |= (vphase << SC1200_TVENC_VPHASE_POS) & SC1200_TVENC_VPHASE_MASK;
448    WRITE_VID32(SC1200_TVENC_TIM_CTRL_1, mode);
449    return (GFX_STATUS_OK);
450}
451
452/*----------------------------------------------------------------------------
453 * gfx_set_tv_YC_delay
454 *
455 * This routine configures the TV out Y/C delay.
456 *----------------------------------------------------------------------------
457 */
458#if GFX_TV_DYNAMIC
459int
460sc1200_set_tv_YC_delay(int delay)
461#else
462int
463gfx_set_tv_YC_delay(int delay)
464#endif
465{
466    unsigned long mode;
467
468    /* This feature is implemented in Rev C1 */
469    if (gfx_chip_revision < SC1200_REV_C1)
470        return (GFX_STATUS_OK);
471
472    mode = READ_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE);
473    mode &= ~SC1200_TVOUT_YC_DELAY_MASK;
474    switch (delay) {
475    case TV_YC_DELAY_NONE:
476        WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE,
477            mode | SC1200_TVOUT_YC_DELAY_NONE);
478        break;
479    case TV_Y_DELAY_ONE_PIXEL:
480        WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE,
481            mode | SC1200_TVOUT_Y_DELAY_ONE_PIXEL);
482        break;
483    case TV_C_DELAY_ONE_PIXEL:
484        WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE,
485            mode | SC1200_TVOUT_C_DELAY_ONE_PIXEL);
486        break;
487    case TV_C_DELAY_TWO_PIXELS:
488        WRITE_VID32(SC1200_TVOUT_HORZ_PRE_ENCODER_SCALE,
489            mode | SC1200_TVOUT_C_DELAY_TWO_PIXELS);
490        break;
491    default:
492        return GFX_STATUS_BAD_PARAMETER;
493    }
494    return (GFX_STATUS_OK);
495}
496
497/*----------------------------------------------------------------------------
498 * gfx_set_tvenc_reset_interval
499 *
500 * This routine sets the interval between external resets of the TV encoder
501 * timing generator by the TV out.
502 *----------------------------------------------------------------------------
503 */
504#if GFX_TV_DYNAMIC
505int
506sc1200_set_tvenc_reset_interval(int interval)
507#else
508int
509gfx_set_tvenc_reset_interval(int interval)
510#endif
511{
512    unsigned long value;
513
514    value = READ_VID32(SC1200_TVOUT_HORZ_SCALING);
515    value &= ~SC1200_TVENC_EXTERNAL_RESET_INTERVAL_MASK;
516    switch (interval) {
517    case TVENC_RESET_EVERY_ODD_FIELD:
518        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
519            value | SC1200_TVENC_EXTERNAL_RESET_EVERY_ODD_FIELD);
520        break;
521    case TVENC_RESET_EVERY_EVEN_FIELD:
522        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
523            value | SC1200_TVENC_EXTERNAL_RESET_EVERY_EVEN_FIELD);
524        break;
525    case TVENC_RESET_NEXT_ODD_FIELD:
526        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
527            value | SC1200_TVENC_EXTERNAL_RESET_NEXT_ODD_FIELD);
528        break;
529    case TVENC_RESET_NEXT_EVEN_FIELD:
530        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
531            value | SC1200_TVENC_EXTERNAL_RESET_NEXT_EVEN_FIELD);
532        break;
533    case TVENC_RESET_EVERY_FIELD:
534        WRITE_VID32(SC1200_TVOUT_HORZ_SCALING,
535            value | SC1200_TVENC_EXTERNAL_RESET_EVERY_FIELD);
536        break;
537    case TVENC_RESET_EVERY_X_ODD_FIELDS:
538    case TVENC_RESET_EVERY_X_EVEN_FIELDS:
539        return GFX_STATUS_UNSUPPORTED;
540    default:
541        return GFX_STATUS_BAD_PARAMETER;
542    }
543    return (GFX_STATUS_OK);
544}
545
546/*----------------------------------------------------------------------------
547 * gfx_set_tv_cc_enable
548 *
549 * This routine enables or disables the use of the hardware CC registers
550 * in the TV encoder.
551 *----------------------------------------------------------------------------
552 */
553#if GFX_TV_DYNAMIC
554int
555sc1200_set_tv_cc_enable(int enable)
556#else
557int
558gfx_set_tv_cc_enable(int enable)
559#endif
560{
561    unsigned long value;
562
563    value = READ_VID32(SC1200_TVENC_CC_CONTROL);
564    value &= ~(0x0005F);
565    if (enable)
566        value |= 0x51;
567    WRITE_VID32(SC1200_TVENC_CC_CONTROL, value);
568    return (0);
569}
570
571/*---------------------------------------------------------------------------
572 * gfx_set_tv_display
573 *
574 * This routine sets the timings in the display controller to support a
575 * TV resolution.
576 *---------------------------------------------------------------------------
577 */
578#if GFX_TV_DYNAMIC
579int
580sc1200_set_tv_display(int width, int height)
581#else
582int
583gfx_set_tv_display(int width, int height)
584#endif
585{
586    DISPLAYMODE *pMode;
587    unsigned int i;
588
589    for (i = 0; i < NUM_TV_MODES; i++) {
590        pMode = &TVTimings[i];
591        if ((unsigned)width == pMode->hactive
592            && (unsigned)height == pMode->vactive)
593            break;
594    }
595
596    if (i == NUM_TV_MODES)
597        return 0;
598
599    gfx_set_display_timings(gfx_get_display_bpp(),
600        (unsigned short)pMode->flags, pMode->hactive, pMode->hblankstart,
601        pMode->hsyncstart, pMode->hsyncend, pMode->hblankend, pMode->htotal,
602        pMode->vactive, pMode->vblankstart, pMode->vsyncstart,
603        pMode->vsyncend, pMode->vblankend, pMode->vtotal, pMode->frequency);
604
605    return 1;
606}
607
608/*----------------------------------------------------------------------------
609 * cc_add_parity_bit
610 *
611 * This routine adds the (odd) parity bit to the data character.
612 *----------------------------------------------------------------------------
613 */
614unsigned char
615cc_add_parity_bit(unsigned char data)
616{
617    int i, num = 0;
618    unsigned char d = data;
619
620    for (i = 0; i < 7; i++) {
621        if (d & 0x1)
622            num++;
623        d >>= 1;
624    }
625    if (num & 0x1)
626        return (data & ~0x80);
627    else
628        return (data | 0x80);
629}
630
631/*----------------------------------------------------------------------------
632 * gfx_set_tv_cc_data
633 *
634 * This routine writes the two specified characters to the CC data register
635 * of the TV encoder.
636 *----------------------------------------------------------------------------
637 */
638#if GFX_TV_DYNAMIC
639int
640sc1200_set_tv_cc_data(unsigned char data1, unsigned char data2)
641#else
642int
643gfx_set_tv_cc_data(unsigned char data1, unsigned char data2)
644#endif
645{
646    unsigned long value;
647
648    value = cc_add_parity_bit(data1) | (cc_add_parity_bit(data2) << 8);
649    WRITE_VID32(SC1200_TVENC_CC_DATA, value);
650    return (0);
651}
652
653/*---------------------------------------------------------------------------
654 * gfx_test_tvout_odd_field
655 *
656 * This routine returns 1 if the current TVout field is odd. Otherwise returns
657 * 0.
658 *---------------------------------------------------------------------------
659 */
660#if GFX_TV_DYNAMIC
661int
662sc1200_test_tvout_odd_field(void)
663#else
664int
665gfx_test_tvout_odd_field(void)
666#endif
667{
668    unsigned long debug = READ_VID32(SC1200_TVOUT_DEBUG);
669
670    WRITE_VID32(SC1200_TVOUT_DEBUG, debug | SC1200_TVOUT_FIELD_STATUS_TV);
671    if (READ_VID32(SC1200_TVOUT_DEBUG) & SC1200_TVOUT_FIELD_STATUS_EVEN)
672        return (0);
673    else
674        return (1);
675}
676
677/*---------------------------------------------------------------------------
678 * gfx_test_tvenc_odd_field
679 *
680 * This routine returns 1 if the current TV encoder field is odd. Otherwise
681 * returns 0.
682 *---------------------------------------------------------------------------
683 */
684#if GFX_TV_DYNAMIC
685int
686sc1200_test_tvenc_odd_field(void)
687#else
688int
689gfx_test_tvenc_odd_field(void)
690#endif
691{
692    unsigned long debug = READ_VID32(SC1200_TVOUT_DEBUG);
693
694    WRITE_VID32(SC1200_TVOUT_DEBUG, debug & ~SC1200_TVOUT_FIELD_STATUS_TV);
695    if (READ_VID32(SC1200_TVOUT_DEBUG) & SC1200_TVOUT_FIELD_STATUS_EVEN)
696        return (0);
697    else
698        return (1);
699}
700
701/*----------------------------------------------------------------------------
702 * gfx_set_tv_field_status_invert
703 *
704 * This routines determines whether the tvout/tvencoder field status bit is
705 * inverted (enable = 1) or not (enable = 0).
706 *----------------------------------------------------------------------------
707 */
708#if GFX_TV_DYNAMIC
709int
710sc1200_set_tv_field_status_invert(int enable)
711#else
712int
713gfx_set_tv_field_status_invert(int enable)
714#endif
715{
716    unsigned long value;
717
718    value = READ_VID32(SC1200_TVOUT_DEBUG);
719
720    if (enable) {
721        value |= SC1200_TVOUT_FIELD_STATUS_INVERT;
722    } else {
723        value &= ~(SC1200_TVOUT_FIELD_STATUS_INVERT);
724    }
725
726    WRITE_VID32(SC1200_TVOUT_DEBUG, value);
727
728    return (GFX_STATUS_OK);
729}
730
731/*---------------------------------------------------------------------------
732 * gfx_get_tv_vphase
733 *
734 * This routine returns the tv encoder vertical phase.
735 *---------------------------------------------------------------------------
736 */
737#if GFX_TV_DYNAMIC
738int
739sc1200_get_tv_vphase(void)
740#else
741int
742gfx_get_tv_vphase(void)
743#endif
744{
745    unsigned long mode = READ_VID32(SC1200_TVENC_TIM_CTRL_1);
746
747    return (int)((mode & SC1200_TVENC_VPHASE_MASK) >>
748        SC1200_TVENC_VPHASE_POS);
749}
750
751/*---------------------------------------------------------------------------
752 * gfx_get_tv_enable
753 *
754 * This routine returns the current tv enable status
755 *---------------------------------------------------------------------------
756 */
757#if GFX_TV_DYNAMIC
758int
759sc1200_get_tv_enable(unsigned int *p_on)
760#else
761int
762gfx_get_tv_enable(unsigned int *p_on)
763#endif
764{
765    unsigned long control = READ_VID32(SC1200_TVENC_DAC_CONTROL);
766
767    *p_on = (unsigned int)(!(control & SC1200_TVENC_POWER_DOWN));
768
769    return GFX_STATUS_OK;
770}
771
772/*---------------------------------------------------------------------------
773 * gfx_get_tv_output
774 *
775 * This routine returns the current programmed TV output type.  It does not
776 * detect invalid configurations.
777 *---------------------------------------------------------------------------
778 */
779#if GFX_TV_DYNAMIC
780int
781sc1200_get_tv_output(void)
782#else
783int
784gfx_get_tv_output(void)
785#endif
786{
787    unsigned long ctrl2, ctrl3;
788    int format = 0;
789
790    ctrl2 = READ_VID32(SC1200_TVENC_TIM_CTRL_2);
791    ctrl3 = READ_VID32(SC1200_TVENC_TIM_CTRL_3);
792
793    if ((ctrl2 & SC1200_TVENC_CFS_MASK) == SC1200_TVENC_CFS_SVIDEO)
794        format = TV_OUTPUT_S_VIDEO;
795    else if (ctrl2 & SC1200_TVENC_OUTPUT_YCBCR)
796        format = TV_OUTPUT_YUV;
797    else if ((ctrl2 & SC1200_TVENC_CFS_MASK) == SC1200_TVENC_CFS_CVBS) {
798        if (ctrl3 & SC1200_TVENC_CM)
799            format = TV_OUTPUT_SCART;
800        else
801            format = TV_OUTPUT_COMPOSITE;
802    }
803
804    return format;
805}
806
807/*---------------------------------------------------------------------------
808 * gfx_get_tv_mode_count
809 *
810 * This routine returns the number of valid TV out resolutions.
811 *---------------------------------------------------------------------------
812 */
813#if GFX_TV_DYNAMIC
814int
815sc1200_get_tv_mode_count(TVStandardType format)
816#else
817int
818gfx_get_tv_mode_count(TVStandardType format)
819#endif
820{
821    unsigned int mode, count = 0;
822    unsigned long flag;
823
824    switch (format) {
825    case TV_STANDARD_NTSC:
826        flag = GFX_MODE_TV_NTSC;
827        break;
828    case TV_STANDARD_PAL:
829        flag = GFX_MODE_TV_PAL;
830        break;
831    default:
832        return 0;
833    }
834
835    for (mode = 0; mode < NUM_TV_MODES; mode++) {
836        if (TVTimings[mode].flags & flag)
837            count++;
838    }
839
840    return count;
841}
842
843/*---------------------------------------------------------------------------
844 * gfx_get_tv_display_mode
845 *
846 * This routine returns the current TV display parameters.
847 *---------------------------------------------------------------------------
848 */
849#if GFX_TV_DYNAMIC
850int
851sc1200_get_tv_display_mode(int *width, int *height, int *bpp, int *hz)
852#else
853int
854gfx_get_tv_display_mode(int *width, int *height, int *bpp, int *hz)
855#endif
856{
857    unsigned long frequency;
858    unsigned long mode, flags;
859
860    *width = gfx_get_hactive();
861    *height = gfx_get_vactive();
862    *bpp = gfx_get_display_bpp();
863    frequency = gfx_get_clock_frequency();
864
865    for (mode = 0; mode < NUM_TV_MODES; mode++) {
866        if (TVTimings[mode].hactive == (unsigned short)(*width) &&
867            TVTimings[mode].vactive == (unsigned short)(*height) &&
868            TVTimings[mode].frequency == frequency) {
869            flags = TVTimings[mode].flags;
870
871            if (flags & GFX_MODE_TV_NTSC)
872                *hz = 60;
873            else if (flags & GFX_MODE_TV_PAL)
874                *hz = 50;
875            else
876                *hz = 0;
877            return (1);
878        }
879    }
880
881    return -1;
882}
883
884/*---------------------------------------------------------------------------
885 * gfx_get_tv_display_mode_frequency
886 *
887 * This routine returns the PLL frequency of a given TV mode.
888 *---------------------------------------------------------------------------
889 */
890#if GFX_TV_DYNAMIC
891int
892sc1200_get_tv_display_mode_frequency(unsigned short width,
893    unsigned short height, TVStandardType format, int *frequency)
894#else
895int
896gfx_get_tv_display_mode_frequency(unsigned short width, unsigned short height,
897    TVStandardType format, int *frequency)
898#endif
899{
900    unsigned long mode, flag;
901    int retval = -1;
902
903    *frequency = 0;
904
905    switch (format) {
906    case TV_STANDARD_NTSC:
907        flag = GFX_MODE_TV_NTSC;
908        break;
909    case TV_STANDARD_PAL:
910        flag = GFX_MODE_TV_PAL;
911        break;
912    default:
913        return -1;
914    }
915
916    for (mode = 0; mode < NUM_TV_MODES; mode++) {
917        if ((TVTimings[mode].hactive == width) &&
918            (TVTimings[mode].vactive == height) &&
919            (TVTimings[mode].flags & flag)) {
920            *frequency = TVTimings[mode].frequency;
921            retval = 1;
922        }
923    }
924    return retval;
925}
926
927/*---------------------------------------------------------------------------
928 * gfx_is_tv_display_mode_supported
929 *
930 * Returns >= 0 if the mode is available, -1 if the mode could not be found
931 *---------------------------------------------------------------------------
932 */
933#if GFX_TV_DYNAMIC
934int
935sc1200_is_tv_display_mode_supported(unsigned short width,
936    unsigned short height, TVStandardType format)
937#else
938int
939gfx_is_tv_display_mode_supported(unsigned short width, unsigned short height,
940    TVStandardType format)
941#endif
942{
943    unsigned long mode, flag;
944
945    switch (format) {
946    case TV_STANDARD_NTSC:
947        flag = GFX_MODE_TV_NTSC;
948        break;
949    case TV_STANDARD_PAL:
950        flag = GFX_MODE_TV_PAL;
951        break;
952    default:
953        return -1;
954    }
955
956    for (mode = 0; mode < NUM_TV_MODES; mode++) {
957        if (TVTimings[mode].hactive == width &&
958            TVTimings[mode].vactive == height &&
959            (TVTimings[mode].flags & flag)) {
960            return ((int)mode);
961        }
962    }
963
964    return -1;
965}
966
967/* END OF FILE */
968