Home | History | Annotate | Line # | Download | only in cim
      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 
     38 int
     39 df_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 
     99 int
    100 df_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 
    122 int
    123 df_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 
    287 int
    288 df_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 
    319 int
    320 df_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 
    451 int
    452 df_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 
    744 int
    745 df_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 
    809 int
    810 df_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 
    888 int
    889 df_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 
    939 int
    940 df_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 
    978 int
    979 df_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 
   1024 int
   1025 df_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 
   1051 int
   1052 df_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 
   1072 int
   1073 df_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 
   1232 int
   1233 df_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 
   1264 int
   1265 df_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 
   1286 int
   1287 df_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 
   1315 int
   1316 df_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 
   1365 int
   1366 df_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 
   1433 unsigned long
   1434 df_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 
   1445 int
   1446 df_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 
   1525 int
   1526 df_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 
   1623 unsigned long
   1624 df_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 
   1698 unsigned long
   1699 df_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 
   2022 unsigned long
   2023 df_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 
   2061 int
   2062 df_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 
   2091 int
   2092 df_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 
   2163 int
   2164 df_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 
   2263 int
   2264 df_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 
   2277 int
   2278 df_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 
   2333 int
   2334 df_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 
   2361 int
   2362 df_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 
   2381 int
   2382 df_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 
   2400 int
   2401 df_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 
   2424 int
   2425 df_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 
   2440 int
   2441 df_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 
   2542 int
   2543 df_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 
   2561 int
   2562 df_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 
   2586 int
   2587 df_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