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