cim_df.c revision 170d5fdc
1/*
2 * Copyright (c) 2006 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
23 * contributors may be used to endorse or promote products derived from this
24 * software without specific prior written permission.
25 */
26
27 /*
28  * Cimarron display filter routines.  These routines program the video
29  * hardware.
30  */
31
32/*---------------------------------------------------------------------------
33 * df_set_crt_enable
34 *
35 * This routine enables or disables CRT output.
36 *--------------------------------------------------------------------------*/
37
38int
39df_set_crt_enable(int crt_output)
40{
41    unsigned long config, misc;
42
43    config = READ_VID32(DF_DISPLAY_CONFIG);
44    misc = READ_VID32(DF_VID_MISC);
45
46    switch (crt_output) {
47        /* DISABLE DISPLAY */
48
49    case DF_CRT_DISABLE:
50
51        config &= ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
52            DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN);
53        misc |= DF_DAC_POWER_DOWN;
54        break;
55
56        /* ENABLE THE DISPLAY */
57
58    case DF_CRT_ENABLE:
59
60        config |= (DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
61            DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN);
62        misc &= ~(DF_DAC_POWER_DOWN | DF_ANALOG_POWER_DOWN);
63        break;
64
65        /* HSYNC:OFF VSYNC:ON */
66
67    case DF_CRT_STANDBY:
68
69        config = (config & ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
70                DF_DCFG_DAC_BL_EN)) | DF_DCFG_VSYNC_EN;
71        misc |= DF_DAC_POWER_DOWN;
72        break;
73
74        /* HSYNC:ON VSYNC:OFF */
75
76    case DF_CRT_SUSPEND:
77
78        config = (config & ~(DF_DCFG_DIS_EN | DF_DCFG_VSYNC_EN |
79                DF_DCFG_DAC_BL_EN)) | DF_DCFG_HSYNC_EN;
80        misc |= DF_DAC_POWER_DOWN;
81        break;
82
83    default:
84        return CIM_STATUS_INVALIDPARAMS;
85    }
86
87    WRITE_VID32(DF_DISPLAY_CONFIG, config);
88    WRITE_VID32(DF_VID_MISC, misc);
89
90    return CIM_STATUS_OK;
91}
92
93/*---------------------------------------------------------------------------
94 * df_set_panel_enable
95 *
96 * This routine enables or disables panel output.
97 *--------------------------------------------------------------------------*/
98
99int
100df_set_panel_enable(int enable)
101{
102    unsigned long pm;
103
104    pm = READ_VID32(DF_POWER_MANAGEMENT);
105
106    if (enable)
107        pm |= DF_PM_PANEL_ON;
108    else
109        pm &= ~DF_PM_PANEL_ON;
110
111    WRITE_VID32(DF_POWER_MANAGEMENT, pm);
112
113    return CIM_STATUS_OK;
114}
115
116/*---------------------------------------------------------------------------
117 * df_configure_video_source
118 *
119 * This routine initializes all aspects of the source buffer for a video overlay.
120 *--------------------------------------------------------------------------*/
121
122int
123df_configure_video_source(DF_VIDEO_SOURCE_PARAMS * video_source_odd,
124    DF_VIDEO_SOURCE_PARAMS * video_source_even)
125{
126    unsigned long pitch, ctrl, vcfg;
127    unsigned long lock, vg_line, gcfg;
128    unsigned long width, size, scale;
129    unsigned long misc;
130
131    lock = READ_REG32(DC3_UNLOCK);
132    vg_line = READ_REG32(DC3_LINE_SIZE);
133    gcfg = READ_REG32(DC3_GENERAL_CFG);
134    vcfg = READ_VID32(DF_VIDEO_CONFIG);
135    ctrl = READ_VID32(DF_VID_ALPHA_CONTROL);
136    scale = READ_VID32(DF_VIDEO_SCALER);
137
138    /* STORE THE DESIRED SCALING PROCEDURE */
139    /* Cimarron supports two modes when programming the scale and position  */
140    /* of the video window.  The first mode is designed to implicitly apply */
141    /* the graphics scale to any video operations.  The second applys the   */
142    /* video unchanged, allowing complete control by the user.  To allow    */
143    /* visibility between modules, the current mode is stored in a spare    */
144    /* bit in the DF miscellaneous register.                                */
145
146    misc = READ_VID32(DF_VID_MISC);
147    if (video_source_odd->flags & DF_SOURCEFLAG_IMPLICITSCALING)
148        misc |= DF_USER_IMPLICIT_SCALING;
149    else
150        misc &= DF_USER_IMPLICIT_SCALING;
151    WRITE_VID32(DF_VID_MISC, misc);
152
153    /* PARAMETER - VIDEO PITCH */
154
155    pitch =
156        (video_source_odd->y_pitch >> 3) | ((video_source_odd->
157            uv_pitch >> 3) << 16);
158
159    /* PARAMETER - VIDEO FORMAT */
160
161    gcfg &= ~DC3_GCFG_YUV_420;
162    vcfg &= ~(DF_VCFG_VID_INP_FORMAT | DF_VCFG_4_2_0_MODE);
163    ctrl &= ~(DF_VIDEO_INPUT_IS_RGB | DF_CSC_VIDEO_YUV_TO_RGB | DF_HD_VIDEO |
164        DF_YUV_CSC_EN);
165
166    /* SELECT PIXEL ORDERING */
167
168    switch (video_source_odd->video_format & 3) {
169    case 0:
170        vcfg |= DF_VCFG_UYVY_FORMAT;
171        break;
172    case 1:
173        vcfg |= DF_VCFG_Y2YU_FORMAT;
174        break;
175    case 2:
176        vcfg |= DF_VCFG_YUYV_FORMAT;
177        break;
178    case 3:
179        vcfg |= DF_VCFG_YVYU_FORMAT;
180        break;
181    }
182
183    /* SELECT SOURCE FORMAT (4:2:2, 4:2:0, RGB) */
184
185    switch (video_source_odd->video_format >> 2) {
186    case 0:
187        ctrl |= DF_CSC_VIDEO_YUV_TO_RGB;
188        break;
189
190    case 1:
191        ctrl |= DF_CSC_VIDEO_YUV_TO_RGB;
192        vcfg |= DF_VCFG_4_2_0_MODE;
193        gcfg |= DC3_GCFG_YUV_420;
194        break;
195
196    case 2:
197        ctrl |= DF_VIDEO_INPUT_IS_RGB;
198        break;
199
200    default:
201        return CIM_STATUS_INVALIDPARAMS;
202    }
203
204    /* ALIGN TO APPROPRIATE OUTPUT COLOR SPACE                             */
205    /* We have assumed until this point that the output color space is RGB */
206    /* and the input (if YUV) is always SDTV video.                        */
207
208    if (video_source_odd->flags & DF_SOURCEFLAG_HDTVSOURCE)
209        ctrl |= DF_HD_VIDEO;
210
211    if (ctrl & DF_CSC_GRAPHICS_RGB_TO_YUV) {
212        /* YUV OUTPUT - DISABLE YUV->RGB AND ENABLE YUV->YUV */
213
214        ctrl &= ~DF_CSC_VIDEO_YUV_TO_RGB;
215
216        if ((!(ctrl & DF_HD_VIDEO) && (ctrl & DF_HD_GRAPHICS)) ||
217            ((ctrl & DF_HD_VIDEO) && !(ctrl & DF_HD_GRAPHICS))) {
218            ctrl |= DF_YUV_CSC_EN;
219        }
220    }
221
222    /* PARAMETER - DISPLAY FILTER BUFFER SIZE                        */
223    /* The line size in the video generator must be 32-byte aligned. */
224    /* However, smaller alignments are managed by setting the        */
225    /* appropriate pitch and clipping the video window.              */
226
227    vcfg &= ~(DF_VCFG_LINE_SIZE_LOWER_MASK | DF_VCFG_LINE_SIZE_BIT8 |
228        DF_VCFG_LINE_SIZE_BIT9);
229
230    size = ((video_source_odd->width >> 1) + 7) & 0xFFF8;
231
232    vcfg |= (size & 0x00FF) << 8;
233    if (size & 0x0100)
234        vcfg |= DF_VCFG_LINE_SIZE_BIT8;
235    if (size & 0x0200)
236        vcfg |= DF_VCFG_LINE_SIZE_BIT9;
237
238    scale = (scale & ~0x7FF) | video_source_odd->height;
239
240    /* PARAMETER - VIDEO GENERATOR BUFFER SIZE */
241
242    vg_line &= ~DC3_LINE_SIZE_VLS_MASK;
243
244    if (gcfg & DC3_GCFG_YUV_420)
245        width = ((video_source_odd->width >> 1) + 7) & 0xFFF8;
246    else
247        width = ((video_source_odd->width << 1) + 31) & 0xFFE0;
248
249    vg_line |= (width >> 3) << DC3_LINE_SIZE_VB_SHIFT;
250
251    /* WRITE ALL PARAMETERS AT ONCE */
252
253    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
254    WRITE_VID32(DF_VIDEO_CONFIG, vcfg);
255    WRITE_VID32(DF_VID_ALPHA_CONTROL, ctrl);
256    WRITE_VID32(DF_VIDEO_SCALER, scale);
257    WRITE_REG32(DC3_GENERAL_CFG, gcfg);
258    WRITE_REG32(DC3_LINE_SIZE, vg_line);
259    WRITE_REG32(DC3_VID_YUV_PITCH, pitch);
260
261    /* WRITE EVEN OR ODD BUFFER OFFSETS                            */
262    /* The even buffer is only valid inside an interlaced display. */
263
264    if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
265        WRITE_REG32(DC3_VID_EVEN_Y_ST_OFFSET, video_source_even->y_offset);
266        WRITE_REG32(DC3_VID_EVEN_U_ST_OFFSET, video_source_even->u_offset);
267        WRITE_REG32(DC3_VID_EVEN_V_ST_OFFSET, video_source_even->v_offset);
268    }
269
270    WRITE_REG32(DC3_VID_Y_ST_OFFSET, video_source_odd->y_offset);
271    WRITE_REG32(DC3_VID_U_ST_OFFSET, video_source_odd->u_offset);
272    WRITE_REG32(DC3_VID_V_ST_OFFSET, video_source_odd->v_offset);
273
274    WRITE_REG32(DC3_UNLOCK, lock);
275
276    return CIM_STATUS_OK;
277}
278
279/*---------------------------------------------------------------------------
280 * df_set_video_offsets
281 *
282 * This routine sets the starting offset for the video buffer(s).  The buffers
283 * can also be configured inside df_configure_video_source, but a separate
284 * routine is provided here to allow quick buffer flipping.
285 *--------------------------------------------------------------------------*/
286
287int
288df_set_video_offsets(int even, unsigned long y_offset,
289    unsigned long u_offset, unsigned long v_offset)
290{
291    unsigned long lock = READ_REG32(DC3_UNLOCK);
292
293    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
294
295    if (even) {
296        WRITE_REG32(DC3_VID_EVEN_Y_ST_OFFSET, y_offset);
297        WRITE_REG32(DC3_VID_EVEN_U_ST_OFFSET, u_offset);
298        WRITE_REG32(DC3_VID_EVEN_V_ST_OFFSET, v_offset);
299    } else {
300        WRITE_REG32(DC3_VID_Y_ST_OFFSET, y_offset);
301        WRITE_REG32(DC3_VID_U_ST_OFFSET, u_offset);
302        WRITE_REG32(DC3_VID_V_ST_OFFSET, v_offset);
303    }
304
305    WRITE_REG32(DC3_UNLOCK, lock);
306
307    return CIM_STATUS_OK;
308}
309
310/*---------------------------------------------------------------------------
311 * df_set_video_scale
312 *
313 * This routine programs the horizontal/vertical scale factors for video.  To
314 * disable scaling/filtering, this routine should be called with identical source
315 * and destination dimensions.
316 *--------------------------------------------------------------------------*/
317
318int
319df_set_video_scale(unsigned long src_width, unsigned long src_height,
320    unsigned long dst_width, unsigned long dst_height, unsigned long flags)
321{
322    unsigned long temp, misc;
323    unsigned long scale, gfxscale;
324    unsigned long fbactive, src;
325    unsigned long size, downscale;
326    unsigned long vcfg, gcfg, unlock;
327
328    /* APPLY THE GRAPHICS SCALE */
329    /* When requested by the user, we will adjust the video scale by the  */
330    /* current graphics scale factor.  This allows video to be programmed */
331    /* in terms of the graphics source resolution.                        */
332
333    misc = READ_VID32(DF_VID_MISC);
334    if (misc & DF_USER_IMPLICIT_SCALING) {
335        gfxscale = READ_REG32(DC3_GFX_SCALE);
336        fbactive = READ_REG32(DC3_FB_ACTIVE);
337
338        /* REVERSE ENGINEER THE SCALE FACTOR */
339        /* The graphics scale factor is (source / (dst - 1)), so a little */
340        /* math is performed to reverse engineer the correct scale for    */
341        /* video.                                                         */
342        /*                                                                */
343        /* F = (0x4000*S)/(D-1)  ->  (D/S) = (((0x4000*S)/F)+1)/S         */
344
345        scale = gfxscale & 0xFFFF;
346        src = (fbactive >> 16) + 1;
347        if (scale != 0x4000) {
348            dst_width = dst_width * (((0x4000 * src) / scale) + 1);
349            dst_width /= src;
350        }
351
352        scale = gfxscale >> 16;
353        src = (fbactive & 0xFFFF) + 1;
354        if (scale != 0x4000) {
355            dst_height = dst_height * (((0x4000 * src) / scale) + 1);
356            dst_height /= src;
357        }
358    }
359
360    /* CHECK FOR VALID SCALING FACTOR */
361    /* The display filter/video generator can support up to 8:1  */
362    /* horizontal downscale and up to 4:1 vertical downscale.    */
363    /* Scale factors above 4:1 horizontal and 2:1 horizontal     */
364    /* will have a quality impact.  However, at such large scale */
365    /* factors, it might not matter,                             */
366
367    if (((flags & DF_SCALEFLAG_CHANGEX) && dst_width < (src_width >> 3)) ||
368        ((flags & DF_SCALEFLAG_CHANGEY) && dst_height < (src_height >> 2))) {
369        return CIM_STATUS_INVALIDSCALE;
370    }
371
372    /* ENABLE OR DISABLE ADVANCED SCALING FEATURES          */
373    /* Scaling above 2:1 vertical and 4:1 horizontal relies */
374    /* on mechanisms beside the line filter.                */
375
376    if (flags & DF_SCALEFLAG_CHANGEX) {
377        scale = READ_VID32(DF_VIDEO_SCALER);
378        vcfg = READ_VID32(DF_VIDEO_CONFIG);
379        vcfg &= ~(DF_VCFG_LINE_SIZE_LOWER_MASK | DF_VCFG_LINE_SIZE_BIT8 |
380            DF_VCFG_LINE_SIZE_BIT9);
381
382        if (dst_width < (src_width >> 2)) {
383            src_width >>= 1;
384            WRITE_VID32(DF_VIDEO_SCALER, scale | DF_SCALE_DOUBLE_H_DOWNSCALE);
385        } else {
386            WRITE_VID32(DF_VIDEO_SCALER,
387                scale & ~DF_SCALE_DOUBLE_H_DOWNSCALE);
388        }
389
390        /* PROGRAM A NEW LINE SIZE */
391        /* The line size must be updated when using the Double Horizontal  */
392        /* Downscale (DHD) bit.  This is because the amount of VFIFO space */
393        /* consumed is effectively half in this mode.                      */
394
395        size = ((src_width >> 1) + 7) & 0xFFF8;
396        vcfg |= (size & 0x00FF) << 8;
397        if (size & 0x0100)
398            vcfg |= DF_VCFG_LINE_SIZE_BIT8;
399        if (size & 0x0200)
400            vcfg |= DF_VCFG_LINE_SIZE_BIT9;
401        WRITE_VID32(DF_VIDEO_CONFIG, vcfg);
402        WRITE_VID32(DF_VIDEO_XSCALE, ((0x10000 * src_width) / dst_width));
403    }
404
405    if (flags & DF_SCALEFLAG_CHANGEY) {
406        unlock = READ_REG32(DC3_UNLOCK);
407        gcfg = READ_REG32(DC3_GENERAL_CFG) & ~DC3_GCFG_VDSE;
408        WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
409        if (dst_height < (src_height >> 1)) {
410            gcfg |= DC3_GCFG_VDSE;
411            downscale = READ_REG32(DC3_VID_DS_DELTA) & ~DC3_DS_DELTA_MASK;
412            if (dst_height == (src_height >> 2))
413                downscale |= (0x3FFF << 18);
414            else
415                downscale |= (((src_height >> 1) << 14) / dst_height) << 18;
416
417            WRITE_REG32(DC3_VID_DS_DELTA, downscale);
418            WRITE_VID32(DF_VIDEO_YSCALE, 0x20000);
419        } else {
420            WRITE_VID32(DF_VIDEO_YSCALE,
421                ((0x10000 * src_height) / dst_height));
422        }
423        WRITE_REG32(DC3_GENERAL_CFG, gcfg);
424        WRITE_REG32(DC3_UNLOCK, unlock);
425    }
426
427    /* CHECK IF SCALING IS DISABLED */
428    /* If no scaling occurs, we disable the hardware filter. */
429
430    temp = READ_VID32(DF_VIDEO_CONFIG);
431    if ((READ_VID32(DF_VIDEO_XSCALE) == 0x10000) &&
432        (READ_VID32(DF_VIDEO_YSCALE) == 0x10000)) {
433        WRITE_VID32(DF_VIDEO_CONFIG, (temp | DF_VCFG_SC_BYP));
434    } else
435        WRITE_VID32(DF_VIDEO_CONFIG, (temp & ~DF_VCFG_SC_BYP));
436
437    return CIM_STATUS_OK;
438}
439
440/*---------------------------------------------------------------------------
441 * df_set_video_position
442 *
443 * This routine programs the position of the video window on the display.
444 * An indent parameter is also passed to this program to prevent artifacts
445 * when the video window is moved beyond the left edge of the screen.
446 *--------------------------------------------------------------------------*/
447
448int
449df_set_video_position(DF_VIDEO_POSITION * video_window)
450{
451    unsigned long vblankstart_even, vblankend_even, vsyncend_even,
452        vtotal_even, vactive_even;
453    unsigned long hblankstart, hblankend, hsyncend, htotal, hactive;
454    unsigned long vblankstart, vblankend, vsyncend, vtotal, vactive;
455    unsigned long width, height, height_even;
456    unsigned long adjust, border_x, border_y, border_y_even;
457    unsigned long xstart, xend;
458    unsigned long ystart, yend;
459    unsigned long ckey_x, ckey_y;
460    unsigned long x_copy, y_copy;
461    unsigned long width_copy, height_copy;
462    unsigned long vcfg, initread;
463    unsigned long xscale, dst_clip;
464    unsigned long ypos, ypos_even;
465    unsigned long y, gfxscale;
466    unsigned long misc, fbactive;
467    unsigned long scale, src;
468    unsigned long irq_ctl;
469    unsigned long unlock;
470
471    hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
472    vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
473    vblankend = ((READ_REG32(DC3_V_BLANK_TIMING) >> 16) & 0xFFF) + 1;
474    hblankend = ((READ_REG32(DC3_H_BLANK_TIMING) >> 16) & 0xFFF) + 1;
475    htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
476    vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
477    vblankstart = (READ_REG32(DC3_V_BLANK_TIMING) & 0xFFF) + 1;
478    hblankstart = (READ_REG32(DC3_H_BLANK_TIMING) & 0xFFF) + 1;
479    hactive = (READ_REG32(DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
480    vactive = (READ_REG32(DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
481    unlock = READ_REG32(DC3_UNLOCK);
482
483    /* INCLUDE BORDER IF REQUESTED */
484
485    if (video_window->flags & DF_POSFLAG_INCLUDEBORDER) {
486        border_x = htotal - hblankend;
487        border_y = vtotal - vblankend;
488        hactive = hblankstart + htotal - hblankend;
489        vactive = vblankstart + vtotal - vblankend;
490    } else {
491        border_x = border_y = 0;
492    }
493
494    /* APPLY THE GRAPHICS SCALE     */
495    /* Do not alter the input data. */
496
497    width_copy = video_window->width;
498    height_copy = video_window->height;
499    x_copy = video_window->x;
500    y_copy = video_window->y;
501
502    misc = READ_VID32(DF_VID_MISC);
503    if (misc & DF_USER_IMPLICIT_SCALING) {
504        gfxscale = READ_REG32(DC3_GFX_SCALE);
505        fbactive = READ_REG32(DC3_FB_ACTIVE);
506
507        /* REVERSE ENGINEER THE SCALE FACTOR */
508
509        scale = gfxscale & 0xFFFF;
510        src = (fbactive >> 16) + 1;
511        if (scale != 0x4000) {
512            width_copy = width_copy * (((0x4000 * src) / scale) + 1);
513            width_copy /= src;
514            x_copy = x_copy * (((0x4000 * src) / scale) + 1);
515            x_copy /= src;
516        }
517
518        scale = gfxscale >> 16;
519        src = (fbactive & 0xFFFF) + 1;
520        if (scale != 0x4000) {
521            height_copy = height_copy * (((0x4000 * src) / scale) + 1);
522            height_copy /= src;
523            y_copy = y_copy * (((0x4000 * src) / scale) + 1);
524            y_copy /= src;
525        }
526    }
527
528    /* HANDLE INTERLACING */
529    /* When the output is interlaced, we must set the position and height */
530    /* on the fields and not on the composite image.                      */
531
532    if ((irq_ctl = READ_REG32(DC3_IRQ_FILT_CTL)) & DC3_IRQFILT_INTL_EN) {
533        vsyncend_even = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
534        vtotal_even = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
535        vblankend_even = ((READ_REG32(DC3_V_BLANK_EVEN) >> 16) & 0xFFF) + 1;
536        vactive_even = (READ_REG32(DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
537        vblankstart_even = (READ_REG32(DC3_V_BLANK_EVEN) & 0xFFF) + 1;
538
539        if (video_window->flags & DF_POSFLAG_INCLUDEBORDER) {
540            border_y_even = vtotal_even - vblankend_even;
541            vactive_even = vblankstart_even + vtotal_even - vblankend_even;
542        } else
543            border_y_even = 0;
544
545        /*
546         * THE ODD FIELD MUST ALWAYS PRECEDE THE EVEN FIELD
547         * This implies that we can never start video on an odd y position
548         * in the composite image.  This is required because the only way
549         * to accomplish an odd y start would be to switch the buffer
550         * which could have serious repercussions for genlocked VIP.
551         */
552
553        y = y_copy >> 1;
554
555        /* CALCULATE Y POSITION FOR ODD FIELD */
556        /* Clip the video window to the odd field timings. Note that the */
557        /* height in the odd field may be greater if the video height is */
558        /* odd.                                                          */
559
560        height = (height_copy + 1) >> 1;
561        if ((y + height) > vactive)
562            height = vactive - y;
563
564        ystart = y + vtotal_even - vsyncend_even + 1;
565        if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
566            ystart -= border_y_even;
567
568        yend = ystart + height;
569        ypos = (yend << 16) | ystart;
570
571        /* CALCULATE Y POSITION FOR EVEN FIELD */
572
573        height_even = height_copy >> 1;
574        if ((y + height_even) > vactive_even)
575            height_even = vactive_even - y;
576
577        ystart = y + vtotal - vsyncend + 1;
578        if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
579            ystart -= border_y;
580
581        yend = ystart + height_even;
582        ypos_even = (yend << 16) | ystart;
583
584        /* CALCULATE ACTUAL FRAME BUFFER HEIGHT */
585        /* The y position and height are used to determine the actual    */
586        /* placement of the color key region.  The region will either be */
587        /* the sum of the even and odd fields (for interlaced addressing */
588        /* or flicker filtering) or it will be the union of the two (for */
589        /* line doubling).  We must also adjust the region such that the */
590        /* origin (0, 0) is centered on the beginning of graphics data.  */
591        /* This is only a problem if video is being displayed over the   */
592        /* overscan area.                                                */
593
594        if ((READ_REG32(DC3_GENLK_CTL) & DC3_GC_FLICKER_FILTER_ENABLE) ||
595            (irq_ctl & DC3_IRQFILT_INTL_ADDR)) {
596            y <<= 1;
597            height += height_even;
598            adjust = border_y + border_y_even;
599        } else {
600            adjust = border_y;
601            if (height_even > height)
602                height = height_even;
603        }
604        if (video_window->flags & DF_POSFLAG_INCLUDEBORDER) {
605            if (y > adjust) {
606                y -= adjust;
607                adjust = 0;
608            } else {
609                adjust -= y;
610                if (height > adjust)
611                    height -= adjust;
612                else
613                    height = 0;
614            }
615        }
616
617    } else {
618        y = y_copy;
619
620        height = height_copy;
621        if ((y + height) > vactive)
622            height = vactive - y;
623
624        ystart = y + vtotal - vsyncend + 1;
625        if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
626            ystart -= border_y;
627
628        yend = ystart + height;
629        ypos = (yend << 16) | ystart;
630        ypos_even = 0;
631    }
632
633    /* HORIZONTAL POSITION */
634    /* The horizontal values are identical for the even and odd field. */
635
636    width = width_copy;
637    xstart = x_copy + htotal - hsyncend - 14;
638    if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
639        xstart -= border_x;
640
641    /* RIGHT CLIPPING */
642
643    if ((x_copy + width) > hactive)
644        width = hactive - x_copy;
645
646    xend = xstart + width;
647
648    /*
649     * CALCULATE LEFT CLIPPING PARAMETER
650     * The value passed in can be interpreted as destination pixels, in
651     * which case the video scale is factored in, or as source pixels, in
652     * which case the value is written directly.  Also, the display filter's
653     * initial read address value is only programmable on 4-pixel increments.
654     * However, we can achieve an arbitrary left clip by adjusting the
655     * xstart value, as there is a 14-clock delay in which to play.  Also,
656     * according to the designers, 4:2:0 and 4:2:2 behave identically when
657     * setting the initial read address.  The addition of scaling further
658     * complicates the algorithm.  When setting the initial read address, it
659     * is in terms of source pixels, while adjusting the xstart value is in
660     * destination pixels We may thus not be able to achieve a perfect
661     * clipping fit for scaled video.  We compensate by including two
662     * clipping parameters in our structure.  This allows us the user
663     * additional control and it allows us to accurately convey to the user
664     * the state of clipping on the machine.
665     */
666
667    initread = video_window->left_clip;
668    dst_clip = 0;
669    if (!(video_window->flags & DF_POSFLAG_DIRECTCLIP)) {
670        xscale = READ_VID32(DF_VIDEO_XSCALE) & 0xFFFFF;
671        initread = (initread * xscale) / 0x10000;
672        if (xscale)
673            dst_clip = ((initread & 3) * 0x10000) / xscale;
674    } else
675        dst_clip = video_window->dst_clip;
676
677    /*
678     * LIMIT THE CLIP
679     * We technically have a 14 pixel window in which to play.  However,
680     * taking the entire 14 pixels makes the video timing a little hairy...
681     * Also note that we cannot do this when performing panel centering, as
682     * the video would then exceed the mode size.
683     */
684
685    if (dst_clip > 4)
686        dst_clip = 4;
687    if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
688        dst_clip = 0;
689
690    xstart -= dst_clip;
691
692    vcfg = READ_VID32(DF_VIDEO_CONFIG);
693    vcfg &= ~DF_VCFG_INIT_READ_MASK;
694    vcfg |= (initread >> 2) << 16;
695
696    /* SET COLOR KEY REGION */
697    /* We are assuming that color keying will never be desired outside   */
698    /* of the video region.  We adjust the color key region for graphics */
699    /* scaling.                                                          */
700
701    gfxscale = READ_REG32(DC3_GFX_SCALE);
702
703    ckey_x = ((x_copy * (gfxscale & 0xFFFF)) / 0x4000) |
704        ((((x_copy + width) * (gfxscale & 0xFFFF)) / 0x4000) << 16);
705    ckey_y = ((y * (gfxscale >> 16)) / 0x4000) |
706        ((((y + height) * (gfxscale >> 16)) / 0x4000) << 16);
707
708    /* WRITE ALL PARAMETERS AT ONCE */
709
710    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
711    WRITE_REG32(DC3_CLR_KEY_X, ckey_x);
712    WRITE_REG32(DC3_CLR_KEY_Y, ckey_y);
713    WRITE_VID32(DF_VIDEO_X_POS, (xend << 16) | xstart);
714    WRITE_VID32(DF_VIDEO_Y_POS, ypos);
715    WRITE_VID32(DF_VID_YPOS_EVEN, ypos_even);
716    WRITE_VID32(DF_VIDEO_CONFIG, vcfg);
717    WRITE_REG32(DC3_UNLOCK, unlock);
718
719    return CIM_STATUS_OK;
720}
721
722/*---------------------------------------------------------------------------
723 * df_set_video_filter_coefficients
724 *
725 * This routine sets the horizontal and vertical filter coefficients for video
726 * scaling.  These coefficients are used for upscaling and downscaling video.
727 * If the phase256 parameter is 1, the coefficient arrays are used as single
728 * arrays of 256 phases for both vertical and horizontal scaling.  If the
729 * phase256 parameter is clear, the coefficient arrays are used as two
730 * 128-phase arrays.  The first 128 entries represent the phases for
731 * vertical scaling.  The last 128 entries represent the phases for
732 * horizontal scaling.
733 *--------------------------------------------------------------------------*/
734
735int
736df_set_video_filter_coefficients(long taps[][4], int phase256)
737{
738    unsigned long scale, coeff0, coeff1;
739    unsigned long i;
740    long (*defaults)[2];
741
742    /* SET PHASE COUNT AND CHOOSE COEFFICIENT ARRAY */
743
744    scale = READ_VID32(DF_VIDEO_SCALER);
745    if (phase256) {
746        WRITE_VID32(DF_VIDEO_SCALER, (scale & ~DF_SCALE_128_PHASES));
747        defaults = CimarronVideoFilter256;
748    } else {
749        WRITE_VID32(DF_VIDEO_SCALER, (scale | DF_SCALE_128_PHASES));
750        defaults = CimarronVideoFilter128;
751    }
752
753    /* PROGRAM COEFFICIENTS */
754
755    for (i = 0; i < 256; i++) {
756        if (!taps) {
757            coeff0 = defaults[i][0];
758            coeff1 = defaults[i][1];
759        } else {
760            if (taps[i][1] < 0)
761                coeff0 = -taps[i][1] | 0x8000;
762            else
763                coeff0 = taps[i][1];
764
765            coeff0 <<= 16;
766
767            if (taps[i][0] < 0)
768                coeff0 |= -taps[i][0] | 0x8000;
769            else
770                coeff0 |= taps[i][0];
771
772            if (taps[i][3] < 0)
773                coeff1 = -taps[i][3] | 0x8000;
774            else
775                coeff1 = taps[i][3];
776
777            coeff1 <<= 16;
778
779            if (taps[i][2] < 0)
780                coeff1 |= -taps[i][2] | 0x8000;
781            else
782                coeff1 |= taps[i][2];
783        }
784
785        WRITE_VID32((DF_COEFFICIENT_BASE + (i << 3)), coeff0);
786        WRITE_VID32((DF_COEFFICIENT_BASE + (i << 3) + 4), coeff1);
787    }
788
789    return CIM_STATUS_OK;
790}
791
792/*---------------------------------------------------------------------------
793 * df_set_video_enable
794 *
795 * This routine enables or disables the video overlay.
796 *--------------------------------------------------------------------------*/
797
798int
799df_set_video_enable(int enable, unsigned long flags)
800{
801    unsigned long vcfg, lock, gcfg;
802    unsigned long dcfg, vg_ckey, fifo = 0;
803
804    vcfg = READ_VID32(DF_VIDEO_CONFIG);
805    lock = READ_REG32(DC3_UNLOCK);
806    gcfg = READ_REG32(DC3_GENERAL_CFG);
807
808    /* SET VIDEO FIFO END WATERMARK */
809    /* The video FIFO end watermark is set to 0 when video is disabled  */
810    /* to allow low priority transactions in the VG.  Otherwise, the    */
811    /* priority will be forced high until the VG fills the video FIFO   */
812    /* by not fetching video.  That could take a while...  Note that    */
813    /* we set the end priority to be 4 greater than the start.  We      */
814    /* assume that the start priority has been configured by a modeset. */
815
816    dcfg = READ_REG32(DC3_DISPLAY_CFG) & ~DC3_DCFG_VFHPEL_MASK;
817    if (enable) {
818        fifo = ((dcfg >> 12) & 0x0000000F) + 4;
819        if (fifo > 0xF)
820            fifo = 0xF;
821    }
822    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
823    WRITE_REG32(DC3_DISPLAY_CFG, dcfg | (fifo << 16));
824
825    /* ENABLE OR DISABLE VIDEO */
826    /* The mechanism to fetch video data is enabled first and */
827    /* disabled last.                                         */
828
829    if (enable) {
830        WRITE_REG32(DC3_GENERAL_CFG, (gcfg | DC3_GCFG_VIDE));
831        WRITE_VID32(DF_VIDEO_CONFIG, (vcfg | DF_VCFG_VID_EN));
832
833        /* DISABLE COLOR KEYING IF REQUESTED BY THE USER */
834
835        if (flags & DF_ENABLEFLAG_NOCOLORKEY) {
836            /* OVERRIDE THE MODE TO COLOR KEYING */
837
838            dcfg = READ_VID32(DF_DISPLAY_CONFIG);
839            WRITE_VID32(DF_DISPLAY_CONFIG, (dcfg & ~DF_DCFG_VG_CK));
840
841            /* DISABLE COLOR KEYING IN THE VG */
842
843            vg_ckey = READ_REG32(DC3_COLOR_KEY);
844            WRITE_REG32(DC3_COLOR_KEY, (vg_ckey & ~DC3_CLR_KEY_ENABLE));
845        } else if (!(READ_VID32(DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK)) {
846            /* OTHERWISE RE-ENABLE COLOR KEYING */
847
848            vg_ckey = READ_REG32(DC3_COLOR_KEY);
849            WRITE_REG32(DC3_COLOR_KEY, (vg_ckey | DC3_CLR_KEY_ENABLE));
850        }
851    } else {
852        WRITE_VID32(DF_VIDEO_CONFIG, (vcfg & ~DF_VCFG_VID_EN));
853        WRITE_REG32(DC3_GENERAL_CFG, (gcfg & ~DC3_GCFG_VIDE));
854
855        /* DISABLE COLOR KEY WINDOW WHEN VIDEO IS INACTIVE         */
856        /* To mimic legacy functionality, we disble color keying   */
857        /* when the video window is not active.  We will restore   */
858        /* the enable when video is re-enabled if the appropriate  */
859        /* bit is set in display config.                           */
860
861        vg_ckey = READ_REG32(DC3_COLOR_KEY);
862        WRITE_REG32(DC3_COLOR_KEY, (vg_ckey & ~DC3_CLR_KEY_ENABLE));
863    }
864    WRITE_REG32(DC3_UNLOCK, lock);
865
866    return CIM_STATUS_OK;
867}
868
869/*---------------------------------------------------------------------------
870 * df_set_video_color_key
871 *
872 * This routine configures the video color/chroma key mechanism.
873 *--------------------------------------------------------------------------*/
874
875int
876df_set_video_color_key(unsigned long key, unsigned long mask, int graphics)
877{
878    unsigned long lock, vg_ckey, df_dcfg;
879
880    vg_ckey = READ_REG32(DC3_COLOR_KEY);
881    lock = READ_REG32(DC3_UNLOCK);
882    df_dcfg = READ_VID32(DF_DISPLAY_CONFIG);
883
884    WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
885
886    if (graphics) {
887        /* COLOR KEY - USE VG HARDWARE */
888        /* Note that color key is never enabled unless a video window */
889        /* is active.  This is to match legacy behavior.              */
890
891        df_dcfg &= ~DF_DCFG_VG_CK;
892        vg_ckey = (vg_ckey & 0xFF000000) | (key & 0xFFFFFF);
893        if (READ_VID32(DF_VIDEO_CONFIG) & DF_VCFG_VID_EN)
894            vg_ckey |= DC3_CLR_KEY_ENABLE;
895        else
896            vg_ckey &= ~DC3_CLR_KEY_ENABLE;
897
898        WRITE_VID32(DF_DISPLAY_CONFIG, df_dcfg);
899        WRITE_REG32(DC3_COLOR_KEY, vg_ckey);
900        WRITE_REG32(DC3_COLOR_MASK, (mask & 0xFFFFFF));
901    } else {
902        /* CHROMA KEY - USE DF HARDWARE */
903
904        df_dcfg |= DF_DCFG_VG_CK;
905        vg_ckey &= ~DC3_CLR_KEY_ENABLE;
906
907        WRITE_REG32(DC3_COLOR_KEY, vg_ckey);
908        WRITE_VID32(DF_DISPLAY_CONFIG, df_dcfg);
909        WRITE_VID32(DF_VIDEO_COLOR_KEY, (key & 0xFFFFFF));
910        WRITE_VID32(DF_VIDEO_COLOR_MASK, (mask & 0xFFFFFF));
911    }
912
913    WRITE_REG32(DC3_UNLOCK, lock);
914
915    return CIM_STATUS_OK;
916}
917
918/*---------------------------------------------------------------------------
919 * df_set_video_palette
920 *
921 * This routine loads the video hardware palette.  If a NULL pointer is
922 * specified, the palette is bypassed.
923 *-------------------------------------------------------------------------*/
924
925int
926df_set_video_palette(unsigned long *palette)
927{
928    unsigned long i, entry;
929    unsigned long misc, dcfg;
930
931    /* LOAD GEODE LX VIDEO PALETTE */
932
933    WRITE_VID32(DF_PALETTE_ADDRESS, 0);
934    for (i = 0; i < 256; i++) {
935        if (palette)
936            entry = palette[i];
937        else
938            entry = i | (i << 8) | (i << 16);
939        WRITE_VID32(DF_PALETTE_DATA, entry);
940    }
941
942    /* ENABLE THE VIDEO PALETTE */
943    /* Ensure that the video palette has an effect by routing video data */
944    /* through the palette RAM and clearing the 'Bypass Both' bit.       */
945
946    dcfg = READ_VID32(DF_DISPLAY_CONFIG);
947    misc = READ_VID32(DF_VID_MISC);
948
949    dcfg |= DF_DCFG_GV_PAL_BYP;
950    misc &= ~DF_GAMMA_BYPASS_BOTH;
951
952    WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
953    WRITE_VID32(DF_VID_MISC, misc);
954
955    return CIM_STATUS_OK;
956}
957
958/*---------------------------------------------------------------------------
959 * df_set_video_palette_entry
960 *
961 * This routine loads a single entry of the video hardware palette.
962 *--------------------------------------------------------------------------*/
963
964int
965df_set_video_palette_entry(unsigned long index, unsigned long palette)
966{
967    unsigned long misc, dcfg;
968
969    if (index > 0xFF)
970        return CIM_STATUS_INVALIDPARAMS;
971
972    /* SET A SINGLE ENTRY */
973
974    WRITE_VID32(DF_PALETTE_ADDRESS, index);
975    WRITE_VID32(DF_PALETTE_DATA, palette);
976
977    /* ENABLE THE VIDEO PALETTE */
978    /* Ensure that the video palette has an effect by routing video data */
979    /* through the palette RAM and clearing the 'Bypass Both' bit.       */
980
981    dcfg = READ_VID32(DF_DISPLAY_CONFIG);
982    misc = READ_VID32(DF_VID_MISC);
983
984    /* Ensure that the Graphic data passes through the Gamma
985     * Correction RAM
986     */
987    dcfg &= ~DF_DCFG_GV_PAL_BYP;
988
989    /* The graphics and video data are passed through gamma
990     * correction RAM
991     */
992    misc &= ~DF_GAMMA_BYPASS_BOTH;
993
994    WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
995    WRITE_VID32(DF_VID_MISC, misc);
996
997    return CIM_STATUS_OK;
998}
999
1000/*---------------------------------------------------------------------------
1001 * df_configure_video_cursor_color_key
1002 *
1003 * This routine configures the hardware video cursor color key mechanism.
1004 *--------------------------------------------------------------------------*/
1005
1006int
1007df_configure_video_cursor_color_key(DF_VIDEO_CURSOR_PARAMS * cursor_color_key)
1008{
1009    unsigned long key;
1010
1011    if (cursor_color_key->select_color2 >= 24)
1012        return CIM_STATUS_INVALIDPARAMS;
1013
1014    key = READ_VID32(DF_CURSOR_COLOR_KEY) & DF_CURSOR_COLOR_KEY_ENABLE;
1015    key = key | (cursor_color_key->key & 0xFFFFFF) | (cursor_color_key->
1016        select_color2 << 24);
1017
1018    WRITE_VID32(DF_CURSOR_COLOR_KEY, key);
1019    WRITE_VID32(DF_CURSOR_COLOR_MASK, (cursor_color_key->mask & 0xFFFFFF));
1020    WRITE_VID32(DF_CURSOR_COLOR_1, (cursor_color_key->color1 & 0xFFFFFF));
1021    WRITE_VID32(DF_CURSOR_COLOR_2, (cursor_color_key->color2 & 0xFFFFFF));
1022
1023    return CIM_STATUS_OK;
1024}
1025
1026/*---------------------------------------------------------------------------
1027 * df_set_video_cursor_color_key_enable
1028 *
1029 * This routine enables or disables the video cursor color key.
1030 *--------------------------------------------------------------------------*/
1031
1032int
1033df_set_video_cursor_color_key_enable(int enable)
1034{
1035    unsigned long temp = READ_VID32(DF_CURSOR_COLOR_KEY);
1036
1037    if (enable)
1038        temp |= DF_CURSOR_COLOR_KEY_ENABLE;
1039    else
1040        temp &= ~DF_CURSOR_COLOR_KEY_ENABLE;
1041
1042    WRITE_VID32(DF_CURSOR_COLOR_KEY, temp);
1043
1044    return CIM_STATUS_OK;
1045}
1046
1047/*---------------------------------------------------------------------------
1048 * df_configure_alpha_window
1049 *
1050 * This routine configures one of the three hardware alpha regions.
1051 *--------------------------------------------------------------------------*/
1052
1053int
1054df_configure_alpha_window(int window, DF_ALPHA_REGION_PARAMS * alpha_data)
1055{
1056    unsigned long vsyncend_even, vtotal_even, vactive_even;
1057    unsigned long hsyncend, htotal, hactive;
1058    unsigned long vsyncend, vtotal, vactive;
1059    unsigned long alpha_ctl, pos;
1060    unsigned long hadjust, vadjust;
1061    unsigned long y, height;
1062    unsigned long xstart, xend;
1063    unsigned long ystart, yend;
1064    unsigned long x_copy, width_copy;
1065    unsigned long y_copy, height_copy;
1066    unsigned long scale, src, misc;
1067    unsigned long gfxscale, fbactive;
1068    unsigned long color;
1069
1070    if (window > 2)
1071        return CIM_STATUS_INVALIDPARAMS;
1072
1073    hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
1074    vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
1075    htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
1076    vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
1077    hactive = (READ_REG32(DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
1078    vactive = (READ_REG32(DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
1079
1080    /* APPLY THE GRAPHICS SCALE */
1081
1082    width_copy = alpha_data->width;
1083    height_copy = alpha_data->height;
1084    x_copy = alpha_data->x;
1085    y_copy = alpha_data->y;
1086
1087    misc = READ_VID32(DF_VID_MISC);
1088    if (misc & DF_USER_IMPLICIT_SCALING) {
1089        gfxscale = READ_REG32(DC3_GFX_SCALE);
1090        fbactive = READ_REG32(DC3_FB_ACTIVE);
1091
1092        /* REVERSE ENGINEER THE SCALE FACTOR */
1093
1094        scale = gfxscale & 0xFFFF;
1095        src = (fbactive >> 16) + 1;
1096        if (scale != 0x4000) {
1097            width_copy = width_copy * (((0x4000 * src) / scale) + 1);
1098            width_copy /= src;
1099            x_copy = x_copy * (((0x4000 * src) / scale) + 1);
1100            x_copy /= src;
1101        }
1102
1103        scale = gfxscale >> 16;
1104        src = (fbactive & 0xFFFF) + 1;
1105        if (scale != 0x4000) {
1106            height_copy = height_copy * (((0x4000 * src) / scale) + 1);
1107            height_copy /= src;
1108            y_copy = y_copy * (((0x4000 * src) / scale) + 1);
1109            y_copy /= src;
1110        }
1111    }
1112
1113    /* SET PRIORITY */
1114    /* Priority is the only alpha parameter that is not in a register that */
1115    /* can be indexed based on the alpha window number.                    */
1116
1117    pos = 16 + (window << 1);
1118    alpha_ctl = READ_VID32(DF_VID_ALPHA_CONTROL) & ~(3L << pos);
1119    alpha_ctl |= (alpha_data->priority & 3) << pos;
1120    WRITE_VID32(DF_VID_ALPHA_CONTROL, alpha_ctl);
1121
1122    /* HANDLE INTERLACED MODES */
1123
1124    if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
1125        vsyncend_even = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
1126        vtotal_even = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
1127        vactive_even = (READ_REG32(DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
1128
1129        y = y_copy >> 1;
1130
1131        /* SET Y POSITION FOR ODD FIELD */
1132
1133        height = (height_copy + 1) >> 1;
1134        vadjust = vtotal_even - vsyncend_even + 1;
1135
1136        ystart = y + vadjust;
1137        yend = y + vadjust + height;
1138
1139        if (yend > (vactive + vadjust))
1140            yend = vactive + vadjust;
1141
1142        WRITE_VID32((DF_ALPHA_YPOS_1 + (window << 5)),
1143            (ystart | (yend << 16)));
1144
1145        /* SET Y POSITION FOR EVEN FIELD */
1146
1147        height = height_copy >> 1;
1148        vadjust = vtotal - vsyncend + 1;
1149
1150        ystart = y + vadjust;
1151        yend = y + vadjust + height;
1152
1153        if (yend > (vactive_even + vadjust))
1154            yend = vactive_even + vadjust;
1155
1156        WRITE_VID32((DF_VID_ALPHA_Y_EVEN_1 + (window << 3)),
1157            (ystart | (yend << 16)));
1158    } else {
1159        y = y_copy;
1160        height = height_copy;
1161        vadjust = vtotal - vsyncend + 1;
1162
1163        ystart = y + vadjust;
1164        yend = y + vadjust + height;
1165
1166        if (yend > (vactive + vadjust))
1167            yend = vactive + vadjust;
1168
1169        WRITE_VID32((DF_ALPHA_YPOS_1 + (window << 5)),
1170            (ystart | (yend << 16)));
1171    }
1172
1173    /* SET ALPHA X POSITION */
1174    /* The x position is the same for both the odd and even fields. */
1175
1176    hadjust = htotal - hsyncend - 2;
1177
1178    xstart = x_copy + hadjust;
1179    xend = x_copy + hadjust + width_copy;
1180
1181    if (xend > (hactive + hadjust))
1182        xend = hactive + hadjust;
1183
1184    WRITE_VID32((DF_ALPHA_XPOS_1 + (window << 5)), (xstart | (xend << 16)));
1185
1186    /* SET COLOR REGISTER */
1187
1188    color = alpha_data->color & 0xFFFFFF;
1189    if (alpha_data->flags & DF_ALPHAFLAG_COLORENABLED)
1190        color |= DF_ALPHA_COLOR_ENABLE;
1191
1192    WRITE_VID32((DF_ALPHA_COLOR_1 + (window << 5)), color);
1193
1194    /* SET ALPHA VALUE, DELTA AND PER PIXEL */
1195
1196    alpha_ctl = READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5)) &
1197        DF_ACTRL_WIN_ENABLE;
1198    alpha_ctl |= (alpha_data->alpha_value & 0xFF) | DF_ACTRL_LOAD_ALPHA |
1199        (((unsigned long)alpha_data->delta & 0xFF) << 8);
1200    if (alpha_data->flags & DF_ALPHAFLAG_PERPIXELENABLED)
1201        alpha_ctl |= DF_ACTRL_PERPIXEL_EN;
1202
1203    WRITE_VID32((DF_ALPHA_CONTROL_1 + (window << 5)), alpha_ctl);
1204
1205    return CIM_STATUS_OK;
1206}
1207
1208/*---------------------------------------------------------------------------
1209 * df_set_alpha_window_enable
1210 *
1211 * This routine enables or disables one of the three hardware alpha regions.
1212 *--------------------------------------------------------------------------*/
1213
1214int
1215df_set_alpha_window_enable(int window, int enable)
1216{
1217    unsigned long alpha_ctl;
1218
1219    if (window > 2)
1220        return CIM_STATUS_INVALIDPARAMS;
1221
1222    alpha_ctl = READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5));
1223    if (enable)
1224        alpha_ctl |= DF_ACTRL_WIN_ENABLE;
1225    else
1226        alpha_ctl &= ~DF_ACTRL_WIN_ENABLE;
1227    WRITE_VID32((DF_ALPHA_CONTROL_1 + (window << 5)), alpha_ctl);
1228
1229    return CIM_STATUS_OK;
1230}
1231
1232/*---------------------------------------------------------------------------
1233 * df_set_no_ck_outside_alpha
1234 *
1235 * This function affects how color/chroma keying is performed inside the video
1236 * window.
1237 *
1238 * If enable is 1, color/chroma key comparison is performed only inside
1239 * the enabled alpha windows. Outside the enabled alpha windows, video
1240 * is displayed if color keying is enabled, or graphics is displayed if
1241 * chroma keying is enabled.
1242 * If enable is 0, color/chroma key comparison is performed inside the
1243 * entire video window.
1244 *--------------------------------------------------------------------------*/
1245
1246int
1247df_set_no_ck_outside_alpha(int enable)
1248{
1249    unsigned long value;
1250
1251    value = READ_VID32(DF_VID_ALPHA_CONTROL);
1252    if (enable)
1253        value |= DF_NO_CK_OUTSIDE_ALPHA;
1254    else
1255        value &= ~DF_NO_CK_OUTSIDE_ALPHA;
1256    WRITE_VID32(DF_VID_ALPHA_CONTROL, value);
1257
1258    return CIM_STATUS_OK;
1259}
1260
1261/*---------------------------------------------------------------------------
1262 * df_set_video_request
1263 *
1264 * This routine sets the horizontal (pixel) and vertical (line) video request
1265 * values.
1266 *--------------------------------------------------------------------------*/
1267
1268int
1269df_set_video_request(unsigned long x, unsigned long y)
1270{
1271    unsigned long htotal, hsyncend;
1272    unsigned long vtotal, vsyncend;
1273
1274    hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
1275    vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
1276    htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
1277    vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
1278
1279    /* SET DISPLAY FILTER VIDEO REQUEST */
1280
1281    x += htotal - hsyncend - 2;
1282    y += vtotal - vsyncend + 1;
1283
1284    if (x >= 0x1000 || y >= 0x800)
1285        return CIM_STATUS_INVALIDPARAMS;
1286
1287    WRITE_VID32(DF_VIDEO_REQUEST, (y | (x << 16)));
1288    return CIM_STATUS_OK;
1289}
1290
1291/*---------------------------------------------------------------------------
1292 * df_set_output_color_space
1293 *
1294 * This routine sets the color space used when combining graphics and video.
1295 *--------------------------------------------------------------------------*/
1296
1297int
1298df_set_output_color_space(int color_space)
1299{
1300    unsigned long alpha_ctl;
1301
1302    alpha_ctl = READ_VID32(DF_VID_ALPHA_CONTROL);
1303
1304    alpha_ctl &= ~(DF_CSC_GRAPHICS_RGB_TO_YUV | DF_CSC_VIDEO_YUV_TO_RGB |
1305        DF_HD_GRAPHICS | DF_YUV_CSC_EN | DF_ALPHA_DRGB);
1306
1307    /* OUTPUT IS RGB */
1308    /* Enable YUV->RGB CSC if necessary and enable alpha output if  */
1309    /* requested.                                                   */
1310
1311    if (color_space == DF_OUTPUT_RGB || color_space == DF_OUTPUT_ARGB) {
1312        if (!(alpha_ctl & DF_VIDEO_INPUT_IS_RGB))
1313            alpha_ctl |= DF_CSC_VIDEO_YUV_TO_RGB;
1314
1315        if (color_space == DF_OUTPUT_ARGB)
1316            alpha_ctl |= DF_ALPHA_DRGB;
1317    }
1318
1319    /* OUTPUT IS YUV */
1320    /* Enable YUV->YUV CSC if necessary and enable RGB->YUV CSC. */
1321
1322    else if (color_space == DF_OUTPUT_SDTV || color_space == DF_OUTPUT_HDTV) {
1323        alpha_ctl |= DF_CSC_GRAPHICS_RGB_TO_YUV;
1324
1325        if (((alpha_ctl & DF_HD_VIDEO) && color_space == DF_OUTPUT_SDTV) ||
1326            (!(alpha_ctl & DF_HD_VIDEO) && color_space == DF_OUTPUT_HDTV)) {
1327            alpha_ctl |= DF_YUV_CSC_EN;
1328        }
1329
1330        if (color_space == DF_OUTPUT_HDTV)
1331            alpha_ctl |= DF_HD_GRAPHICS;
1332    } else
1333        return CIM_STATUS_INVALIDPARAMS;
1334
1335    WRITE_VID32(DF_VID_ALPHA_CONTROL, alpha_ctl);
1336
1337    return CIM_STATUS_OK;
1338}
1339
1340/*---------------------------------------------------------------------------
1341 * df_set_output_path
1342 *
1343 * This routine changes the current output path in the display filter.
1344 *--------------------------------------------------------------------------*/
1345
1346int
1347df_set_output_path(int format)
1348{
1349    unsigned long panel_tim2, panel_pm;
1350    unsigned long output = 0;
1351    Q_WORD msr_value;
1352
1353    msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
1354    msr_value.low &= ~(DF_SIMULTANEOUS_CRT_FP | DF_CONFIG_OUTPUT_MASK);
1355    panel_tim2 = READ_VID32(DF_VIDEO_PANEL_TIM2);
1356    panel_pm = READ_VID32(DF_POWER_MANAGEMENT);
1357
1358    if (format == DF_DISPLAY_CRT) {
1359        /* SiBZ #4188 */
1360        /* When CRT output is selected, the DF drives the DISP_EN signal   */
1361        /* with the CRT display enable.  As a consequence, systems that    */
1362        /* wire the DISP_EN signal to the TFT backlight control will not   */
1363        /* be able to set CRT-only output without leaving the backlight    */
1364        /* enabled.  To workaround this issue, we are setting simultaneous */
1365        /* TFT/CRT and disabling the TFT logic.  The only caveat to this   */
1366        /* is that some TFT pins are shared with VIP 601 pins.  VIP 601    */
1367        /* will thus not work when in this pseudo-CRT mode.  To address    */
1368        /* THAT issue, normal CRT mode sets (in cim_vg.c) will set CRT     */
1369        /* as the DF output format.  This will allow VIP 601 on CRT-only   */
1370        /* systems without a TFT attached.                                 */
1371
1372        panel_pm &= ~DF_PM_PANEL_ON;
1373        panel_tim2 |= DF_PMTIM2_TFT_PASSHTHROUGH;
1374        output = DF_OUTPUT_PANEL | DF_SIMULTANEOUS_CRT_FP;
1375    } else if (format == DF_DISPLAY_FP || format == DF_DISPLAY_CRT_FP) {
1376        panel_pm |= DF_PM_PANEL_ON;
1377        panel_tim2 &= ~DF_PMTIM2_TFT_PASSHTHROUGH;
1378
1379        if (format == DF_DISPLAY_FP)
1380            output = DF_OUTPUT_PANEL;
1381        else if (format == DF_DISPLAY_CRT_FP)
1382            output = DF_OUTPUT_PANEL | DF_SIMULTANEOUS_CRT_FP;
1383    } else {
1384        switch (format) {
1385        case DF_DISPLAY_VOP:
1386            output = DF_OUTPUT_VOP;
1387            break;
1388        case DF_DISPLAY_DRGB:
1389            output = DF_OUTPUT_DRGB;
1390            break;
1391        case DF_DISPLAY_CRT_DRGB:
1392            output = DF_OUTPUT_DRGB | DF_SIMULTANEOUS_CRT_FP;
1393            break;
1394        default:
1395            return CIM_STATUS_INVALIDPARAMS;
1396        }
1397    }
1398    msr_value.low |= output;
1399    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
1400    WRITE_VID32(DF_VIDEO_PANEL_TIM2, panel_tim2);
1401    WRITE_VID32(DF_POWER_MANAGEMENT, panel_pm);
1402
1403    return CIM_STATUS_OK;
1404}
1405
1406/*---------------------------------------------------------------------------
1407 * df_test_video_flip_status
1408 *
1409 * This routine tests if a new video offset has been latched.
1410 *--------------------------------------------------------------------------*/
1411
1412unsigned long
1413df_test_video_flip_status(void)
1414{
1415    return (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VFLIP);
1416}
1417
1418/*---------------------------------------------------------------------------
1419 * df_save_state
1420 *
1421 * This routine saves all persistent DF state information.
1422 *--------------------------------------------------------------------------*/
1423
1424int
1425df_save_state(DF_SAVE_RESTORE * df_state)
1426{
1427    unsigned long i;
1428
1429    /* READ ALL DF REGISTERS */
1430
1431    df_state->vcfg = READ_VID32(DF_VIDEO_CONFIG);
1432    df_state->dcfg = READ_VID32(DF_DISPLAY_CONFIG);
1433    df_state->video_x = READ_VID32(DF_VIDEO_X_POS);
1434    df_state->video_y = READ_VID32(DF_VIDEO_Y_POS);
1435    df_state->video_scaler = READ_VID32(DF_VIDEO_SCALER);
1436    df_state->video_color_key = READ_VID32(DF_VIDEO_COLOR_KEY);
1437    df_state->video_color_mask = READ_VID32(DF_VIDEO_COLOR_MASK);
1438    df_state->sat_limit = READ_VID32(DF_SATURATION_LIMIT);
1439    df_state->vid_misc = READ_VID32(DF_VID_MISC);
1440    df_state->video_yscale = READ_VID32(DF_VIDEO_YSCALE);
1441    df_state->video_xscale = READ_VID32(DF_VIDEO_XSCALE);
1442    df_state->vid_alpha_control = READ_VID32(DF_VID_ALPHA_CONTROL);
1443    df_state->cursor_key = READ_VID32(DF_CURSOR_COLOR_KEY);
1444    df_state->cursor_mask = READ_VID32(DF_CURSOR_COLOR_MASK);
1445    df_state->cursor_color1 = READ_VID32(DF_CURSOR_COLOR_1);
1446    df_state->cursor_color2 = READ_VID32(DF_CURSOR_COLOR_2);
1447    df_state->alpha_xpos1 = READ_VID32(DF_ALPHA_XPOS_1);
1448    df_state->alpha_ypos1 = READ_VID32(DF_ALPHA_YPOS_1);
1449    df_state->alpha_color1 = READ_VID32(DF_ALPHA_COLOR_1);
1450    df_state->alpha_control1 = READ_VID32(DF_ALPHA_CONTROL_1);
1451    df_state->alpha_xpos2 = READ_VID32(DF_ALPHA_XPOS_2);
1452    df_state->alpha_ypos2 = READ_VID32(DF_ALPHA_YPOS_2);
1453    df_state->alpha_color2 = READ_VID32(DF_ALPHA_COLOR_2);
1454    df_state->alpha_control2 = READ_VID32(DF_ALPHA_CONTROL_2);
1455    df_state->alpha_xpos3 = READ_VID32(DF_ALPHA_XPOS_3);
1456    df_state->alpha_ypos3 = READ_VID32(DF_ALPHA_YPOS_3);
1457    df_state->alpha_color3 = READ_VID32(DF_ALPHA_COLOR_3);
1458    df_state->alpha_control3 = READ_VID32(DF_ALPHA_CONTROL_3);
1459    df_state->vid_request = READ_VID32(DF_VIDEO_REQUEST);
1460    df_state->vid_ypos_even = READ_VID32(DF_VID_YPOS_EVEN);
1461    df_state->alpha_ypos_even1 = READ_VID32(DF_VID_ALPHA_Y_EVEN_1);
1462    df_state->alpha_ypos_even2 = READ_VID32(DF_VID_ALPHA_Y_EVEN_2);
1463    df_state->alpha_ypos_even3 = READ_VID32(DF_VID_ALPHA_Y_EVEN_3);
1464    df_state->panel_tim1 = READ_VID32(DF_VIDEO_PANEL_TIM1);
1465    df_state->panel_tim2 = READ_VID32(DF_VIDEO_PANEL_TIM2);
1466    df_state->panel_pm = READ_VID32(DF_POWER_MANAGEMENT);
1467    df_state->panel_dither = READ_VID32(DF_DITHER_CONTROL);
1468
1469    /* READ DF PALETTE */
1470
1471    WRITE_VID32(DF_PALETTE_ADDRESS, 0);
1472    for (i = 0; i < 256; i++)
1473        df_state->palette[i] = READ_VID32(DF_PALETTE_DATA);
1474
1475    /* READ FILTER COEFFICIENTS */
1476
1477    for (i = 0; i < 512; i++)
1478        df_state->coefficients[i] =
1479            READ_VID32(DF_COEFFICIENT_BASE + (i << 2));
1480
1481    /* READ ALL DF MSRS */
1482
1483    msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CAP,
1484        &(df_state->msr_cap));
1485    msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG,
1486        &(df_state->msr_config));
1487    msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_SMI,
1488        &(df_state->msr_smi));
1489    msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_ERROR,
1490        &(df_state->msr_error));
1491    msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_PM, &(df_state->msr_pm));
1492    msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG,
1493        &(df_state->msr_diag));
1494    msr_read64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF,
1495        &(df_state->msr_df_diag));
1496    msr_read64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL,
1497        &(df_state->msr_pad_sel));
1498
1499    return CIM_STATUS_OK;
1500}
1501
1502/*---------------------------------------------------------------------------
1503 * df_restore_state
1504 *
1505 * This routine restores all persistent DF state information.
1506 *--------------------------------------------------------------------------*/
1507
1508int
1509df_restore_state(DF_SAVE_RESTORE * df_state)
1510{
1511    unsigned long i;
1512
1513    /* CLEAR VCFG AND DCFG */
1514
1515    WRITE_VID32(DF_VIDEO_CONFIG, 0);
1516    WRITE_VID32(DF_DISPLAY_CONFIG, 0);
1517
1518    /* RESTORE DF MSRS */
1519
1520    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CAP,
1521        &(df_state->msr_cap));
1522    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG,
1523        &(df_state->msr_config));
1524    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_SMI,
1525        &(df_state->msr_smi));
1526    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_ERROR,
1527        &(df_state->msr_error));
1528    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_PM, &(df_state->msr_pm));
1529    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG,
1530        &(df_state->msr_diag));
1531    msr_write64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF,
1532        &(df_state->msr_df_diag));
1533    msr_write64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL,
1534        &(df_state->msr_pad_sel));
1535
1536    /* RESTORE ALL DF REGISTERS */
1537
1538    WRITE_VID32(DF_VIDEO_X_POS, df_state->video_x);
1539    WRITE_VID32(DF_VIDEO_Y_POS, df_state->video_y);
1540    WRITE_VID32(DF_VIDEO_SCALER, df_state->video_scaler);
1541    WRITE_VID32(DF_VIDEO_COLOR_KEY, df_state->video_color_key);
1542    WRITE_VID32(DF_VIDEO_COLOR_MASK, df_state->video_color_mask);
1543    WRITE_VID32(DF_SATURATION_LIMIT, df_state->sat_limit);
1544    WRITE_VID32(DF_VID_MISC, df_state->vid_misc);
1545    WRITE_VID32(DF_VIDEO_YSCALE, df_state->video_yscale);
1546    WRITE_VID32(DF_VIDEO_XSCALE, df_state->video_xscale);
1547    WRITE_VID32(DF_VID_ALPHA_CONTROL, df_state->vid_alpha_control);
1548    WRITE_VID32(DF_CURSOR_COLOR_KEY, df_state->cursor_key);
1549    WRITE_VID32(DF_CURSOR_COLOR_MASK, df_state->cursor_mask);
1550    WRITE_VID32(DF_CURSOR_COLOR_1, df_state->cursor_color1);
1551    WRITE_VID32(DF_CURSOR_COLOR_2, df_state->cursor_color2);
1552    WRITE_VID32(DF_ALPHA_XPOS_1, df_state->alpha_xpos1);
1553    WRITE_VID32(DF_ALPHA_YPOS_1, df_state->alpha_ypos1);
1554    WRITE_VID32(DF_ALPHA_COLOR_1, df_state->alpha_color1);
1555    WRITE_VID32(DF_ALPHA_CONTROL_1, df_state->alpha_control1);
1556    WRITE_VID32(DF_ALPHA_XPOS_2, df_state->alpha_xpos2);
1557    WRITE_VID32(DF_ALPHA_YPOS_2, df_state->alpha_ypos2);
1558    WRITE_VID32(DF_ALPHA_COLOR_2, df_state->alpha_color2);
1559    WRITE_VID32(DF_ALPHA_CONTROL_2, df_state->alpha_control1);
1560    WRITE_VID32(DF_ALPHA_XPOS_3, df_state->alpha_xpos3);
1561    WRITE_VID32(DF_ALPHA_YPOS_3, df_state->alpha_ypos3);
1562    WRITE_VID32(DF_ALPHA_COLOR_3, df_state->alpha_color3);
1563    WRITE_VID32(DF_ALPHA_CONTROL_3, df_state->alpha_control3);
1564    WRITE_VID32(DF_VIDEO_REQUEST, df_state->vid_request);
1565    WRITE_VID32(DF_VID_YPOS_EVEN, df_state->vid_ypos_even);
1566    WRITE_VID32(DF_VID_ALPHA_Y_EVEN_1, df_state->alpha_ypos_even1);
1567    WRITE_VID32(DF_VID_ALPHA_Y_EVEN_2, df_state->alpha_ypos_even2);
1568    WRITE_VID32(DF_VID_ALPHA_Y_EVEN_3, df_state->alpha_ypos_even3);
1569    WRITE_VID32(DF_VIDEO_PANEL_TIM1, df_state->panel_tim1);
1570    WRITE_VID32(DF_VIDEO_PANEL_TIM2, df_state->panel_tim2);
1571    WRITE_VID32(DF_POWER_MANAGEMENT, df_state->panel_pm);
1572    WRITE_VID32(DF_DITHER_CONTROL, df_state->panel_dither);
1573
1574    /* RESTORE DF PALETTE */
1575
1576    WRITE_VID32(DF_PALETTE_ADDRESS, 0);
1577    for (i = 0; i < 256; i++)
1578        WRITE_VID32(DF_PALETTE_DATA, df_state->palette[i]);
1579
1580    /* RESTORE FILTER COEFFICIENTS */
1581
1582    for (i = 0; i < 512; i++)
1583        WRITE_VID32(DF_COEFFICIENT_BASE + (i << 2),
1584            df_state->coefficients[i]);
1585
1586    /* RESTORE DCFG AND VCFG */
1587
1588    WRITE_VID32(DF_DISPLAY_CONFIG, df_state->dcfg);
1589    WRITE_VID32(DF_VIDEO_CONFIG, df_state->vcfg);
1590
1591    return CIM_STATUS_OK;
1592}
1593
1594/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1595 * CIMARRON DF READ ROUTINES
1596 * These routines are included for use in diagnostics or when debugging.  They
1597 * can be optionally excluded from a project.
1598 *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
1599
1600#if CIMARRON_INCLUDE_DF_READ_ROUTINES
1601
1602/*---------------------------------------------------------------------------
1603 * df_read_composite_crc
1604 *
1605 * This routine reads the CRC of the combination of graphics/video data.  This
1606 * CRC checks data immediately before the CRT DACs.
1607 *--------------------------------------------------------------------------*/
1608
1609unsigned long
1610df_read_composite_crc(int crc_source)
1611{
1612    Q_WORD msr_value;
1613    unsigned long crc;
1614    unsigned long interlaced;
1615    unsigned long line, field;
1616    unsigned long timeout = 1000;
1617
1618    if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
1619        return 0xFFFFFFFF;
1620
1621    /* ENABLE 32-BIT CRCS */
1622
1623    msr_read64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
1624    msr_value.low |= DF_DIAG_32BIT_CRC;
1625    msr_write64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
1626
1627    /* RESET THE CRC */
1628
1629    WRITE_VID32(DF_VID_CRC, 0);
1630
1631    /* WAIT FOR THE RESET TO BE LATCHED */
1632
1633    while ((READ_VID32(DF_VID_CRC32) != 0x00000001) && timeout)
1634        timeout--;
1635
1636    /* WAIT FOR THE CORRECT FIELD */
1637    /* We use the VG line count and field indicator to determine when */
1638    /* to kick off a CRC.                                             */
1639
1640    if (crc_source & DF_CRC_SOURCE_EVEN)
1641        field = 0;
1642    else
1643        field = DC3_LNCNT_EVEN_FIELD;
1644
1645    if ((interlaced = (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN))) {
1646        /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
1647        /* Note that we wait for the field to be odd when CRCing the even */
1648        /* field and vice versa.  This is because the CRC will not begin  */
1649        /* until the following field.                                     */
1650
1651        do {
1652            line = READ_REG32(DC3_LINE_CNT_STATUS);
1653        } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
1654            ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 10 ||
1655            ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 15);
1656    } else {
1657        /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
1658
1659        if (crc_source & DF_CRC_SOURCE_EVEN)
1660            return 0xFFFFFFFF;
1661    }
1662
1663    /* ENABLE THE CRC */
1664
1665    WRITE_VID32(DF_VID_CRC, 1);
1666
1667    /* WAIT FOR THE CRC TO BE COMPLETED */
1668
1669    while (!(READ_VID32(DF_VID_CRC) & 4)) ;
1670
1671    crc = READ_VID32(DF_VID_CRC32);
1672
1673    return crc;
1674}
1675
1676/*---------------------------------------------------------------------------
1677 * df_read_composite_window_crc
1678 *
1679 * This routine reads the CRC of a rectangular subsection of the combination
1680 * of graphics/video data.
1681 *--------------------------------------------------------------------------*/
1682
1683unsigned long
1684df_read_composite_window_crc(unsigned long x, unsigned long y,
1685    unsigned long width, unsigned long height, int source)
1686{
1687    Q_WORD msr_value;
1688    unsigned long interlaced;
1689    unsigned long line, field;
1690    unsigned long crc = 0;
1691    unsigned long hsyncend, htotal, hsyncstart;
1692    unsigned long vsyncend, vtotal, vsyncstart;
1693    unsigned long hblankstart, hactive;
1694    unsigned long vblankstart, vactive;
1695
1696    hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
1697    htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
1698    hsyncstart = (READ_REG32(DC3_H_SYNC_TIMING) & 0xFFF) + 1;
1699    hactive = (READ_REG32(DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
1700    hblankstart = (READ_REG32(DC3_H_BLANK_TIMING) & 0xFFF) + 1;
1701    if ((interlaced = (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)) &&
1702        !(source & DF_CRC_SOURCE_EVEN)) {
1703        vsyncend = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
1704        vtotal = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
1705        vsyncstart = (READ_REG32(DC3_V_SYNC_EVEN) & 0xFFF) + 1;
1706        vactive = (READ_REG32(DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
1707        vblankstart = (READ_REG32(DC3_V_BLANK_EVEN) & 0xFFF) + 1;
1708    } else {
1709        vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
1710        vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
1711        vsyncstart = (READ_REG32(DC3_V_SYNC_TIMING) & 0xFFF) + 1;
1712        vactive = (READ_REG32(DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
1713        vblankstart = (READ_REG32(DC3_V_BLANK_TIMING) & 0xFFF) + 1;
1714    }
1715
1716    /* TIMINGS MUST BE ACTIVE */
1717
1718    if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
1719        return 0xFFFFFFFF;
1720
1721    /* DISABLE GLCP ACTIONS */
1722
1723    msr_value.low = 0;
1724    msr_value.high = 0;
1725    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
1726
1727    /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO DOT CLOCK */
1728
1729    msr_value.low = 5;
1730    msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
1731    msr_value.low = 0;
1732    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
1733    msr_value.low = 3;
1734    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
1735
1736    /* USE H4 FUNCTION A FOR HSYNC AND H4 FUNCTION B FOR NOT HSYNC */
1737    /* HSYNC is bit 30 for the DF                                  */
1738
1739    msr_value.high = 0x00000001;
1740    msr_value.low = 0xE0000FF0;
1741    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
1742
1743    /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
1744    /* VSYNC is bit 54 for VG and bit 29 for DF                    */
1745
1746    msr_value.high = 0x00000000;
1747    msr_value.low = 0x001D55AA;
1748    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
1749
1750    /* M4 (XSTATE = 00 AND VSYNC HIGH) */
1751    /* Goto state 01                   */
1752    /* Note: VSync = H3A               */
1753
1754    msr_value.high = 0x00000001;
1755    msr_value.low = 0x000000A0;
1756    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 4, &msr_value);
1757
1758    /* N0 (XSTATE = 01 AND VSYNC LOW) */
1759    /* Goto state 02                  */
1760    /* Note: VSync low = H3B          */
1761
1762    msr_value.high = 0x00040000;
1763    msr_value.low = 0x000000C0;
1764    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL, &msr_value);
1765
1766    /* M5 (XSTATE = 10 AND VSYNC HIGH) */
1767    /* Goto state 11                   */
1768
1769    msr_value.high = 0x00000001;
1770    msr_value.low = 0x00000120;
1771    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 5, &msr_value);
1772
1773    /* N1 (XSTATE = 10 and HSYNC LOW) */
1774    /* Increment H. Counter           */
1775    /* Note: HSync = H4               */
1776
1777    msr_value.high = 0x00080000;
1778    msr_value.low = 0x00000120;
1779    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 1, &msr_value);
1780
1781    /* M0 (XSTATE = 10 and H. COUNTER == LIMIT)  */
1782    /* Clear H. Counter and increment V. Counter */
1783
1784    msr_value.high = 0x00000000;
1785    msr_value.low = 0x00000122;
1786    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL, &msr_value);
1787
1788    /* N4 (XSTATE = 10 && CMP0 <= H. COUNTER <= CMP1 && CMP2 <= V. COUNTER
1789     * <= CMP3)
1790     * CRC into REGB
1791     */
1792
1793    msr_value.high = 0x00000000;
1794    msr_value.low = 0x10C20120;
1795    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 4, &msr_value);
1796
1797    /* COMPARATOR 0 VALUE                                   */
1798    /* Value = xstart + (htotal - hsync_end) - 1            */
1799    /* The value will be adjusted for a border if necessary */
1800
1801    msr_value.low = x + htotal - hsyncend - 1;
1802    if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
1803        msr_value.low -= hblankstart - hactive;
1804    msr_value.low--;
1805    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0, &msr_value);
1806
1807    /* COMPARATOR 1 VALUE                                    */
1808    /* Value = xstart + (htotal - hsync_end - 1) - 1 + width */
1809
1810    msr_value.low += width - 1;
1811    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 2, &msr_value);
1812
1813    /* COMPARATOR 2 VALUE                 */
1814    /* Value = ystart + vtotal - vsyncend */
1815
1816    msr_value.low = (y + vtotal - vsyncend) << 16;
1817    if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
1818        msr_value.low -= (vblankstart - vactive) << 16;
1819    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 4, &msr_value);
1820
1821    /* COMPARATOR 3 VALUE                              */
1822    /* Value = ystart + vtotal - vsyncend + height - 1 */
1823
1824    msr_value.low += (height - 1) << 16;
1825    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 6, &msr_value);
1826
1827    /* COMPARATOR MASKS */
1828    /* Comparators 0 and 1 refer to lower 16 bits of RegB */
1829
1830    msr_value.low = 0x0000FFFF;
1831    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0, &msr_value);
1832    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 2, &msr_value);
1833
1834    /* Comparators 2 and 3 refer to upper 16 bits of RegB */
1835
1836    msr_value.low = 0xFFFF0000;
1837    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 4, &msr_value);
1838    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 6, &msr_value);
1839
1840    /* SET REGB MASK                                                */
1841    /* We set the mask such that all only 24 bits of data are CRCed */
1842
1843    msr_value.low = 0x00FFFFFF;
1844    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGBMASK, &msr_value);
1845
1846    /* SET REGA LIMITS                              */
1847    /* Lower counter uses htotal - sync_time - 1.   */
1848    /* Upper counter is 0xFFFF to prevent rollover. */
1849
1850    msr_value.low = 0xFFFF0000 | (htotal - (hsyncend - hsyncstart) - 1);
1851    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
1852
1853    /* ACTIONS */
1854
1855    /* STATE 00->01 (SET 4M) */
1856
1857    msr_value.low = 0x000C0000;
1858    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 14, &msr_value);
1859
1860    /* STATE 01->10 (SET 0N) */
1861
1862    msr_value.low = 0x0000000A;
1863    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 15, &msr_value);
1864
1865    /* STATE 10->11 (SET 5M) */
1866
1867    msr_value.low = 0x00C00000;
1868    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 16, &msr_value);
1869
1870    /* CLEAR REGA WHEN TRANSITIONING TO STATE 10                 */
1871    /* Do not clear RegB as the initial value must be 0x00000001 */
1872
1873    msr_value.low = 0x0000000A;
1874    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0, &msr_value);
1875
1876    /* REGISTER ACTION 1 */
1877    /* CRC into RegB if cmp0 <= h.counter <= cmp1 && cmp2 <= v. counter <
1878     * cmp3 && 7 xstate = 10 8
1879     * Increment h.counter if xstate = 10 and HSync is low.
1880     */
1881
1882    msr_value.low = 0x000A00A0;
1883    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 1, &msr_value);
1884
1885    /* REGISTER ACTION 2            */
1886    /* Increment V. Counter in REGA */
1887
1888    msr_value.low = 0x0000000C;
1889    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 2, &msr_value);
1890
1891    /* SET REGB TO 0x00000001 */
1892
1893    msr_value.low = 0x00000001;
1894    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
1895
1896    /* SET XSTATE TO 0 */
1897
1898    msr_value.low = 0x00000000;
1899    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
1900
1901    /* CLEAR ALL OTHER ACTIONS */
1902    /* This prevents side-effects from previous accesses to the GLCP */
1903    /* debug logic.                                                  */
1904
1905    msr_value.low = 0x00000000;
1906    msr_value.high = 0x00000000;
1907    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 3, &msr_value);
1908    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 4, &msr_value);
1909    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 5, &msr_value);
1910    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 6, &msr_value);
1911    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 7, &msr_value);
1912    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 8, &msr_value);
1913    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 9, &msr_value);
1914    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 10, &msr_value);
1915    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 11, &msr_value);
1916    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 12, &msr_value);
1917    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 13, &msr_value);
1918    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 17, &msr_value);
1919    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 18, &msr_value);
1920    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 19, &msr_value);
1921    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 20, &msr_value);
1922
1923    /* WAIT FOR THE CORRECT FIELD */
1924    /* We use the VG line count and field indicator to determine when */
1925    /* to kick off a CRC.                                             */
1926
1927    if (source & DF_CRC_SOURCE_EVEN)
1928        field = 0;
1929    else
1930        field = DC3_LNCNT_EVEN_FIELD;
1931
1932    if (interlaced) {
1933        /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
1934        /* Note that we wait for the field to be odd when CRCing the even */
1935        /* field and vice versa.  This is because the CRC will not begin  */
1936        /* until the following field.                                     */
1937
1938        do {
1939            line = READ_REG32(DC3_LINE_CNT_STATUS);
1940        } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
1941            ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 1 ||
1942            ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 5);
1943    } else {
1944        /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
1945
1946        if (source & DF_CRC_SOURCE_EVEN)
1947            return 0xFFFFFFFF;
1948    }
1949
1950    /* CONFIGURE DISPLAY FILTER TO LOAD DATA ONTO LOWER 32-BITS */
1951
1952    msr_value.high = 0;
1953    msr_value.low = 0x0000800B;
1954    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &msr_value);
1955
1956    /* CONFIGURE DIAG CONTROL */
1957    /* Set RegA action1 to increment lower 16 bits and clear at limit. (5)
1958     * Set RegA action2 to increment upper 16 bits. (6)
1959     * Set RegB action1 to CRC32 (1)
1960     * Set all comparators to REGA override (0,1 lower mbus, 2,3 upper mbus)
1961     * Enable all actions
1962     */
1963
1964    msr_value.low = 0x80EA20A0;
1965    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
1966
1967    /* DELAY TWO FRAMES */
1968
1969    while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA) ;
1970    while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA)) ;
1971    while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA) ;
1972    while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA)) ;
1973    while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA) ;
1974
1975    /* VERIFY THAT XSTATE = 11 */
1976
1977    msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
1978    if ((msr_value.low & 3) == 3) {
1979        msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
1980
1981        crc = msr_value.low;
1982    }
1983
1984    /* DISABLE DF DIAG BUS OUTPUTS */
1985
1986    msr_value.low = 0x00000000;
1987    msr_value.high = 0x00000000;
1988    msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &msr_value);
1989
1990    /* DISABLE GLCP ACTIONS */
1991
1992    msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
1993
1994    return crc;
1995}
1996
1997/*---------------------------------------------------------------------------
1998 * df_read_panel_crc
1999 *
2000 * This routine reads the CRC for a frame of data after the panel dithering
2001 * logic.
2002 *--------------------------------------------------------------------------*/
2003
2004unsigned long
2005df_read_panel_crc(void)
2006{
2007    Q_WORD msr_value;
2008    unsigned long timeout = 1000;
2009
2010    if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
2011        return 0xFFFFFFFF;
2012
2013    /* ENABLE 32-BIT CRCS */
2014
2015    msr_read64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
2016    msr_value.low |= DF_DIAG_32BIT_CRC;
2017    msr_write64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
2018
2019    /* RESET CRC */
2020
2021    WRITE_VID32(DF_PANEL_CRC, 0);
2022
2023    /* WAIT FOR THE RESET TO BE LATCHED */
2024
2025    while ((READ_VID32(DF_PANEL_CRC32) != 0x00000001) && timeout)
2026        timeout--;
2027
2028    WRITE_VID32(DF_PANEL_CRC, 1);
2029
2030    /* WAIT FOR THE CRC TO BE COMPLETED */
2031
2032    while (!(READ_VID32(DF_PANEL_CRC) & 4)) ;
2033
2034    return READ_VID32(DF_PANEL_CRC32);
2035}
2036
2037/*---------------------------------------------------------------------------
2038 * df_get_video_enable
2039 *
2040 * This routine reads the enable status of the video overlay.
2041 *--------------------------------------------------------------------------*/
2042
2043int
2044df_get_video_enable(int *enable, unsigned long *flags)
2045{
2046    *enable = 0;
2047    *flags = 0;
2048    if (READ_VID32(DF_VIDEO_CONFIG) & DF_VCFG_VID_EN) {
2049        *enable = 1;
2050
2051        /* CHECK FOR COLOR KEY DISABLED */
2052        /* Color keying can be completely disabled when video is enabled to */
2053        /* allow unhindered per-pixel alpha blending.  As color keying is   */
2054        /* always disabled when video is disabled, it is only possible to   */
2055        /* test for this condition when video is enabled.                   */
2056
2057        if (!(READ_VID32(DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK) &&
2058            !(READ_REG32(DC3_COLOR_KEY) & DC3_CLR_KEY_ENABLE)) {
2059            *flags = DF_ENABLEFLAG_NOCOLORKEY;
2060        }
2061    }
2062
2063    return CIM_STATUS_OK;
2064}
2065
2066/*---------------------------------------------------------------------------
2067 * df_get_video_source_configuration
2068 *
2069 * This routine reads the current configuration of the source buffers for the
2070 * video overlay.
2071 *--------------------------------------------------------------------------*/
2072
2073int
2074df_get_video_source_configuration(DF_VIDEO_SOURCE_PARAMS * video_source_odd,
2075    DF_VIDEO_SOURCE_PARAMS * video_source_even)
2076{
2077    unsigned long format, temp;
2078    unsigned long size;
2079
2080    /* READ VIDEO FORMAT */
2081
2082    temp = READ_VID32(DF_VIDEO_CONFIG);
2083
2084    format = (temp >> 2) & 3;
2085    if (temp & DF_VCFG_4_2_0_MODE)
2086        format |= 4;
2087    else if (READ_VID32(DF_VID_ALPHA_CONTROL) & DF_VIDEO_INPUT_IS_RGB)
2088        format |= 8;
2089    video_source_odd->video_format = format;
2090
2091    /* CHECK IF SOURCE IS HD VIDEO */
2092
2093    if (READ_VID32(DF_VID_ALPHA_CONTROL) & DF_HD_VIDEO)
2094        video_source_odd->flags = DF_SOURCEFLAG_HDTVSOURCE;
2095    else
2096        video_source_odd->flags = 0;
2097
2098    /* READ SCALING ALGORITHM */
2099
2100    if (READ_VID32(DF_VID_MISC) & DF_USER_IMPLICIT_SCALING)
2101        video_source_odd->flags |= DF_SOURCEFLAG_IMPLICITSCALING;
2102
2103    /* READ VIDEO PITCH */
2104
2105    temp = READ_REG32(DC3_VID_YUV_PITCH);
2106    video_source_odd->y_pitch = (temp & 0xFFFF) << 3;
2107    video_source_odd->uv_pitch = (temp >> 16) << 3;
2108
2109    /* READ VIDEO SIZE */
2110
2111    temp = READ_VID32(DF_VIDEO_CONFIG);
2112    size = (temp >> 8) & 0xFF;
2113    if (temp & DF_VCFG_LINE_SIZE_BIT8)
2114        size |= 0x100;
2115    if (temp & DF_VCFG_LINE_SIZE_BIT9)
2116        size |= 0x200;
2117
2118    video_source_odd->width = size << 1;
2119    video_source_odd->height = READ_VID32(DF_VIDEO_SCALER) & 0x7FF;
2120
2121    /* READ VIDEO OFFSETS */
2122
2123    video_source_odd->y_offset = READ_REG32(DC3_VID_Y_ST_OFFSET) & 0xFFFFFFF;
2124    video_source_odd->u_offset = READ_REG32(DC3_VID_U_ST_OFFSET) & 0xFFFFFFF;
2125    video_source_odd->v_offset = READ_REG32(DC3_VID_V_ST_OFFSET) & 0xFFFFFFF;
2126
2127    if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
2128        video_source_even->y_offset =
2129            READ_REG32(DC3_VID_EVEN_Y_ST_OFFSET) & 0xFFFFFFF;
2130        video_source_even->u_offset =
2131            READ_REG32(DC3_VID_EVEN_U_ST_OFFSET) & 0xFFFFFFF;
2132        video_source_even->v_offset =
2133            READ_REG32(DC3_VID_EVEN_V_ST_OFFSET) & 0xFFFFFFF;
2134    }
2135
2136    return CIM_STATUS_OK;
2137}
2138
2139/*---------------------------------------------------------------------------
2140 * df_get_video_position
2141 *
2142 * This routine reads the current position of the video overlay.
2143 *--------------------------------------------------------------------------*/
2144
2145int
2146df_get_video_position(DF_VIDEO_POSITION * video_window)
2147{
2148    unsigned long xreg, yreg, dst_clip, clip;
2149    unsigned long height;
2150    unsigned long xend, yend;
2151    unsigned long hsyncend, htotal;
2152    unsigned long vsyncend, vtotal;
2153    unsigned long hadjust, vadjust;
2154    unsigned long misc, gfxscale;
2155    unsigned long temp;
2156    long xstart, ystart;
2157
2158    video_window->flags = DF_POSFLAG_DIRECTCLIP;
2159
2160    hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
2161    htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2162
2163    /* ODD FIELD START COUNTS FROM THE EVEN FIELD TIMINGS */
2164    /* We assume that the even field y position is always programmed */
2165    /* to be just after the odd field.                               */
2166
2167    if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
2168        vsyncend = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
2169        vtotal = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
2170    } else {
2171        vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
2172        vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2173    }
2174
2175    hadjust = htotal - hsyncend - 14;
2176    vadjust = vtotal - vsyncend + 1;
2177
2178    xreg = READ_VID32(DF_VIDEO_X_POS);
2179    yreg = READ_VID32(DF_VIDEO_Y_POS);
2180
2181    xstart = (xreg & 0xFFF) - hadjust;
2182    ystart = (yreg & 0x7FF) - vadjust;
2183    xend = ((xreg >> 16) & 0xFFF) - hadjust;
2184    yend = ((yreg >> 16) & 0x7FF) - vadjust;
2185
2186    height = yend - ystart;
2187
2188    if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
2189        /* Y COORDINATE IS ACTUALLY 2X THE ODD FIELD START */
2190
2191        ystart <<= 1;
2192
2193        /* CALCULATE THE EXACT VIDEO HEIGHT */
2194        /* The height of the video window is the sum of the */
2195        /* odd and even field heights.                      */
2196
2197        yreg = READ_VID32(DF_VID_YPOS_EVEN);
2198        height += ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
2199    }
2200
2201    clip = ((READ_VID32(DF_VIDEO_CONFIG) >> 16) & 0x1FF) << 2;
2202
2203    /* ADJUST FOR CLIPPING VALUES THAT ARE NOT FOUR-PIXEL ALIGNED */
2204
2205    dst_clip = 0;
2206    if (xstart < 0) {
2207        dst_clip += -xstart;
2208        xstart = 0;
2209    }
2210
2211    /* REVERSE THE GRAPHICS SCALE */
2212
2213    misc = READ_VID32(DF_VID_MISC);
2214    if (misc & DF_USER_IMPLICIT_SCALING) {
2215        gfxscale = READ_REG32(DC3_GFX_SCALE);
2216
2217        if (gfxscale != 0x40004000) {
2218            temp = ystart + height;
2219            temp = (temp * (gfxscale >> 16)) / 0x4000;
2220
2221            xstart = (xstart * (gfxscale & 0xFFFF)) / 0x4000;
2222            xend = (xend * (gfxscale & 0xFFFF)) / 0x4000;
2223            ystart = (ystart * (gfxscale >> 16)) / 0x4000;
2224            height = temp - ystart;
2225        }
2226    }
2227
2228    video_window->left_clip = clip;
2229    video_window->dst_clip = dst_clip;
2230    video_window->x = xstart;
2231    video_window->y = ystart;
2232    video_window->width = xend - xstart;
2233    video_window->height = height;
2234
2235    return CIM_STATUS_OK;
2236}
2237
2238/*---------------------------------------------------------------------------
2239 * df_get_video_scale
2240 *
2241 * This routine reads the current scale values for video scaling.
2242 *--------------------------------------------------------------------------*/
2243
2244int
2245df_get_video_scale(unsigned long *x_scale, unsigned long *y_scale)
2246{
2247    *x_scale = READ_VID32(DF_VIDEO_XSCALE) & 0x000FFFFF;
2248    *y_scale = READ_VID32(DF_VIDEO_YSCALE) & 0x000FFFFF;
2249    return CIM_STATUS_OK;
2250}
2251
2252/*---------------------------------------------------------------------------
2253 * df_get_video_filter_coefficients
2254 *
2255 * This routine reads the coefficients for the video scaler/filter.
2256 *--------------------------------------------------------------------------*/
2257
2258int
2259df_get_video_filter_coefficients(long taps[][4], int *phase256)
2260{
2261    unsigned long i, temp;
2262    long coeff;
2263
2264    if (READ_VID32(DF_VIDEO_SCALER) & DF_SCALE_128_PHASES)
2265        *phase256 = 0;
2266    else
2267        *phase256 = 1;
2268
2269    for (i = 0; i < 256; i++) {
2270        temp = READ_VID32(DF_COEFFICIENT_BASE + (i << 3));
2271
2272        /* TAP 0 */
2273
2274        coeff = temp & 0x7FFF;
2275        if (temp & 0x8000)
2276            coeff = -coeff;
2277        taps[i][0] = coeff;
2278
2279        /* TAP 1 */
2280
2281        temp >>= 16;
2282        coeff = temp & 0x7FFF;
2283        if (temp & 0x8000)
2284            coeff = -coeff;
2285        taps[i][1] = coeff;
2286
2287        temp = READ_VID32(DF_COEFFICIENT_BASE + (i << 3) + 4);
2288
2289        /* TAP 2 */
2290
2291        coeff = temp & 0x7FFF;
2292        if (temp & 0x8000)
2293            coeff = -coeff;
2294        taps[i][2] = coeff;
2295
2296        /* TAP 3 */
2297
2298        temp >>= 16;
2299        coeff = temp & 0x7FFF;
2300        if (temp & 0x8000)
2301            coeff = -coeff;
2302        taps[i][3] = coeff;
2303    }
2304
2305    return CIM_STATUS_OK;
2306}
2307
2308/*---------------------------------------------------------------------------
2309 * df_get_video_color_key
2310 *
2311 * This routine reads the current settings for hardware color/chroma keying.
2312 *--------------------------------------------------------------------------*/
2313
2314int
2315df_get_video_color_key(unsigned long *key, unsigned long *mask, int *graphics)
2316{
2317    unsigned long chroma = READ_VID32(DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK;
2318
2319    if (chroma) {
2320        /* CHROMA KEY - READ KEY AND MASK FROM DF */
2321
2322        *graphics = 0;
2323        *key = READ_VID32(DF_VIDEO_COLOR_KEY) & 0xFFFFFF;
2324        *mask = READ_VID32(DF_VIDEO_COLOR_MASK) & 0xFFFFFF;
2325    } else {
2326        *graphics = 1;
2327
2328        *key = READ_REG32(DC3_COLOR_KEY) & 0xFFFFFF;
2329        *mask = READ_REG32(DC3_COLOR_MASK) & 0xFFFFFF;
2330    }
2331
2332    return CIM_STATUS_OK;
2333}
2334
2335/*---------------------------------------------------------------------------
2336 * df_get_video_palette_entry
2337 *
2338 * This routine returns a single palette entry.
2339 *--------------------------------------------------------------------------*/
2340
2341int
2342df_get_video_palette_entry(unsigned long index, unsigned long *palette)
2343{
2344    if (index > 0xFF)
2345        return CIM_STATUS_INVALIDPARAMS;
2346
2347    /* READ A SINGLE ENTRY */
2348
2349    WRITE_VID32(DF_PALETTE_ADDRESS, index);
2350    *palette = READ_VID32(DF_PALETTE_DATA);
2351
2352    return CIM_STATUS_OK;
2353}
2354
2355/*---------------------------------------------------------------------------
2356 * df_get_video_palette
2357 *
2358 * This routine returns the entire video palette.
2359 *--------------------------------------------------------------------------*/
2360
2361int
2362df_get_video_palette(unsigned long *palette)
2363{
2364    unsigned long i;
2365
2366    WRITE_VID32(DF_PALETTE_ADDRESS, 0);
2367    for (i = 0; i < 256; i++)
2368        palette[i] = READ_VID32(DF_PALETTE_DATA);
2369
2370    return CIM_STATUS_OK;
2371}
2372
2373/*---------------------------------------------------------------------------
2374 * df_get_video_cursor_color_key
2375 *
2376 * This routine returns the current configuration for the hardware video cursor
2377 * color key.
2378 *--------------------------------------------------------------------------*/
2379
2380int
2381df_get_video_cursor_color_key(DF_VIDEO_CURSOR_PARAMS * cursor_color_key)
2382{
2383    unsigned long key;
2384
2385    cursor_color_key->flags = 0;
2386    cursor_color_key->color1 = READ_VID32(DF_CURSOR_COLOR_1) & 0xFFFFFF;
2387    cursor_color_key->color2 = READ_VID32(DF_CURSOR_COLOR_2) & 0xFFFFFF;
2388    cursor_color_key->mask = READ_VID32(DF_CURSOR_COLOR_MASK) & 0xFFFFFF;
2389
2390    key = READ_VID32(DF_CURSOR_COLOR_KEY);
2391    cursor_color_key->key = key & 0xFFFFFF;
2392    cursor_color_key->select_color2 = (key >> 24) & 0x1F;
2393
2394    return CIM_STATUS_OK;
2395}
2396
2397/*---------------------------------------------------------------------------
2398 * df_get_video_cursor_color_key_enable
2399 *
2400 * This routine returns the current enable status of the hardware video cursor
2401 * color key.
2402 *--------------------------------------------------------------------------*/
2403
2404int
2405df_get_video_cursor_color_key_enable(void)
2406{
2407    if (READ_VID32(DF_CURSOR_COLOR_KEY) & DF_CURSOR_COLOR_KEY_ENABLE)
2408        return 1;
2409
2410    return 0;
2411}
2412
2413/*---------------------------------------------------------------------------
2414 * df_get_alpha_window_configuration
2415 *
2416 * This routine reads the current configuration for one of the three hardware
2417 * alpha regions.
2418 *--------------------------------------------------------------------------*/
2419
2420int
2421df_get_alpha_window_configuration(int window,
2422    DF_ALPHA_REGION_PARAMS * alpha_data)
2423{
2424    unsigned long pos, color, alpha_ctl;
2425    unsigned long hsyncend, htotal;
2426    unsigned long vsyncend, vtotal;
2427    unsigned long hadjust, vadjust;
2428    unsigned long xreg, yreg;
2429    unsigned long misc, gfxscale;
2430    unsigned long temp;
2431    char delta;
2432
2433    if (window > 2)
2434        return CIM_STATUS_INVALIDPARAMS;
2435
2436    hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
2437    htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2438    if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
2439        vtotal = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
2440        vsyncend = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
2441    } else {
2442        vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2443        vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
2444    }
2445
2446    /* GET PRIORITY */
2447
2448    pos = 16 + (window << 1);
2449    alpha_data->priority = (READ_VID32(DF_VID_ALPHA_CONTROL) >> pos) & 3L;
2450
2451    /* GET ALPHA WINDOW */
2452
2453    hadjust = htotal - hsyncend - 2;
2454    vadjust = vtotal - vsyncend + 1;
2455
2456    xreg = READ_VID32(DF_ALPHA_XPOS_1 + (window << 5));
2457    yreg = READ_VID32(DF_ALPHA_YPOS_1 + (window << 5));
2458    alpha_data->width = ((xreg >> 16) & 0xFFF) - (xreg & 0xFFF);
2459    alpha_data->height = ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
2460    alpha_data->x = (xreg & 0xFFF) - hadjust;
2461    alpha_data->y = (yreg & 0x7FF) - vadjust;
2462
2463    /* REVERSE THE GRAPHICS SCALE */
2464
2465    misc = READ_VID32(DF_VID_MISC);
2466    if (misc & DF_USER_IMPLICIT_SCALING) {
2467        gfxscale = READ_REG32(DC3_GFX_SCALE);
2468        if (gfxscale != 0x40004000) {
2469            temp = alpha_data->y + alpha_data->height;
2470            temp = (temp * (gfxscale >> 16)) / 0x4000;
2471
2472            alpha_data->x = (alpha_data->x * (gfxscale & 0xFFFF)) / 0x4000;
2473            alpha_data->width =
2474                (alpha_data->width * (gfxscale & 0xFFFF)) / 0x4000;
2475            alpha_data->y = (alpha_data->y * (gfxscale >> 16)) / 0x4000;
2476            alpha_data->height = temp - alpha_data->y;
2477        }
2478    }
2479
2480    if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
2481        /* Y COORDINATE IS ACTUALLY 2X THE ODD FIELD START */
2482
2483        alpha_data->y <<= 1;
2484
2485        /* CALCULATE THE EXACT VIDEO HEIGHT */
2486        /* The height of the video window is the sum of the */
2487        /* odd and even field heights.                      */
2488
2489        yreg = READ_VID32(DF_VID_ALPHA_Y_EVEN_1 + (window << 3));
2490        alpha_data->height += ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
2491    }
2492
2493    /* GET COLOR REGISTER */
2494
2495    color = READ_VID32(DF_ALPHA_COLOR_1 + (window << 5));
2496    alpha_data->color = color & 0xFFFFFF;
2497    if (color & DF_ALPHA_COLOR_ENABLE)
2498        alpha_data->flags = DF_ALPHAFLAG_COLORENABLED;
2499    else
2500        alpha_data->flags = 0;
2501
2502    /* GET ALPHA VALUE, DELTA AND PER PIXEL */
2503
2504    alpha_ctl = READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5));
2505    alpha_data->alpha_value = alpha_ctl & 0xFF;
2506    if (alpha_ctl & DF_ACTRL_PERPIXEL_EN)
2507        alpha_data->flags |= DF_ALPHAFLAG_PERPIXELENABLED;
2508
2509    delta = (char)((alpha_ctl >> 8) & 0xFF);
2510    alpha_data->delta = (long)delta;
2511    return CIM_STATUS_OK;
2512}
2513
2514/*---------------------------------------------------------------------------
2515 * df_get_alpha_window_enable
2516 *
2517 * This routine reads the current enable status of one of the three hardware
2518 * alpha regions.
2519 *--------------------------------------------------------------------------*/
2520
2521int
2522df_get_alpha_window_enable(int window)
2523{
2524    if (window > 2)
2525        return 0;
2526
2527    if (READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5)) & DF_ACTRL_WIN_ENABLE)
2528        return 1;
2529
2530    return 0;
2531}
2532
2533/*---------------------------------------------------------------------------
2534 * df_get_video_request
2535 *
2536 * This routine reads the horizontal (pixel) and vertical (line) video request
2537 * values.
2538 *--------------------------------------------------------------------------*/
2539
2540int
2541df_get_video_request(unsigned long *x, unsigned long *y)
2542{
2543    unsigned long request;
2544    unsigned long hsyncend, htotal;
2545    unsigned long vsyncend, vtotal;
2546
2547    hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
2548    vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
2549    htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2550    vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
2551
2552    request = READ_VID32(DF_VIDEO_REQUEST);
2553    *x = ((request >> 16) & 0xFFF) - (htotal - hsyncend - 2);
2554    *y = (request & 0x7FF) - (vtotal - vsyncend + 1);
2555
2556    return CIM_STATUS_OK;
2557}
2558
2559/*---------------------------------------------------------------------------
2560 * df_get_output_color_space
2561 *
2562 * This routine sets the color space used when combining graphics and video.
2563 *--------------------------------------------------------------------------*/
2564
2565int
2566df_get_output_color_space(int *color_space)
2567{
2568    unsigned long alpha_ctl;
2569
2570    alpha_ctl = READ_VID32(DF_VID_ALPHA_CONTROL);
2571
2572    if ((alpha_ctl & DF_CSC_VIDEO_YUV_TO_RGB) ||
2573        !(alpha_ctl & DF_CSC_GRAPHICS_RGB_TO_YUV)) {
2574        if (alpha_ctl & DF_ALPHA_DRGB)
2575            *color_space = DF_OUTPUT_ARGB;
2576        else
2577            *color_space = DF_OUTPUT_RGB;
2578    } else {
2579        *color_space = DF_OUTPUT_SDTV;
2580
2581        if (alpha_ctl & DF_HD_GRAPHICS)
2582            *color_space = DF_OUTPUT_HDTV;
2583    }
2584
2585    return CIM_STATUS_OK;
2586}
2587
2588#endif
2589