summaryrefslogtreecommitdiff
path: root/src/cim/cim_df.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cim/cim_df.c')
-rw-r--r--src/cim/cim_df.c2581
1 files changed, 2581 insertions, 0 deletions
diff --git a/src/cim/cim_df.c b/src/cim/cim_df.c
new file mode 100644
index 0000000..242603a
--- /dev/null
+++ b/src/cim/cim_df.c
@@ -0,0 +1,2581 @@
+/*
+ * Copyright (c) 2006 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ */
+
+ /*
+ * Cimarron display filter routines. These routines program the video
+ * hardware.
+ */
+
+/*---------------------------------------------------------------------------
+ * df_set_crt_enable
+ *
+ * This routine enables or disables CRT output.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_crt_enable(int crt_output)
+{
+ unsigned long config, misc;
+
+ config = READ_VID32(DF_DISPLAY_CONFIG);
+ misc = READ_VID32(DF_VID_MISC);
+
+ switch (crt_output) {
+ /* DISABLE DISPLAY */
+
+ case DF_CRT_DISABLE:
+
+ config &= ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
+ DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN);
+ misc |= DF_DAC_POWER_DOWN;
+ break;
+
+ /* ENABLE THE DISPLAY */
+
+ case DF_CRT_ENABLE:
+
+ config |= (DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
+ DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN);
+ misc &= ~(DF_DAC_POWER_DOWN | DF_ANALOG_POWER_DOWN);
+ break;
+
+ /* HSYNC:OFF VSYNC:ON */
+
+ case DF_CRT_STANDBY:
+
+ config = (config & ~(DF_DCFG_DIS_EN | DF_DCFG_HSYNC_EN |
+ DF_DCFG_DAC_BL_EN)) | DF_DCFG_VSYNC_EN;
+ misc |= DF_DAC_POWER_DOWN;
+ break;
+
+ /* HSYNC:ON VSYNC:OFF */
+
+ case DF_CRT_SUSPEND:
+
+ config = (config & ~(DF_DCFG_DIS_EN | DF_DCFG_VSYNC_EN |
+ DF_DCFG_DAC_BL_EN)) | DF_DCFG_HSYNC_EN;
+ misc |= DF_DAC_POWER_DOWN;
+ break;
+
+ default:
+ return CIM_STATUS_INVALIDPARAMS;
+ }
+
+ WRITE_VID32(DF_DISPLAY_CONFIG, config);
+ WRITE_VID32(DF_VID_MISC, misc);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_panel_enable
+ *
+ * This routine enables or disables panel output.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_panel_enable(int enable)
+{
+ unsigned long pm;
+
+ pm = READ_VID32(DF_POWER_MANAGEMENT);
+
+ if (enable)
+ pm |= DF_PM_PANEL_ON;
+ else
+ pm &= ~DF_PM_PANEL_ON;
+
+ WRITE_VID32(DF_POWER_MANAGEMENT, pm);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_configure_video_source
+ *
+ * This routine initializes all aspects of the source buffer for a video overlay.
+ *--------------------------------------------------------------------------*/
+
+int
+df_configure_video_source(DF_VIDEO_SOURCE_PARAMS * video_source_odd,
+ DF_VIDEO_SOURCE_PARAMS * video_source_even)
+{
+ unsigned long pitch, ctrl, vcfg;
+ unsigned long lock, vg_line, gcfg;
+ unsigned long width, size, scale;
+ unsigned long misc;
+
+ lock = READ_REG32(DC3_UNLOCK);
+ vg_line = READ_REG32(DC3_LINE_SIZE);
+ gcfg = READ_REG32(DC3_GENERAL_CFG);
+ vcfg = READ_VID32(DF_VIDEO_CONFIG);
+ ctrl = READ_VID32(DF_VID_ALPHA_CONTROL);
+ scale = READ_VID32(DF_VIDEO_SCALER);
+
+ /* STORE THE DESIRED SCALING PROCEDURE */
+ /* Cimarron supports two modes when programming the scale and position */
+ /* of the video window. The first mode is designed to implicitly apply */
+ /* the graphics scale to any video operations. The second applys the */
+ /* video unchanged, allowing complete control by the user. To allow */
+ /* visibility between modules, the current mode is stored in a spare */
+ /* bit in the DF miscellaneous register. */
+
+ misc = READ_VID32(DF_VID_MISC);
+ if (video_source_odd->flags & DF_SOURCEFLAG_IMPLICITSCALING)
+ misc |= DF_USER_IMPLICIT_SCALING;
+ else
+ misc &= DF_USER_IMPLICIT_SCALING;
+ WRITE_VID32(DF_VID_MISC, misc);
+
+ /* PARAMETER - VIDEO PITCH */
+
+ pitch =
+ (video_source_odd->y_pitch >> 3) | ((video_source_odd->
+ uv_pitch >> 3) << 16);
+
+ /* PARAMETER - VIDEO FORMAT */
+
+ gcfg &= ~DC3_GCFG_YUV_420;
+ vcfg &= ~(DF_VCFG_VID_INP_FORMAT | DF_VCFG_4_2_0_MODE);
+ ctrl &= ~(DF_VIDEO_INPUT_IS_RGB | DF_CSC_VIDEO_YUV_TO_RGB | DF_HD_VIDEO |
+ DF_YUV_CSC_EN);
+
+ /* SELECT PIXEL ORDERING */
+
+ switch (video_source_odd->video_format & 3) {
+ case 0:
+ vcfg |= DF_VCFG_UYVY_FORMAT;
+ break;
+ case 1:
+ vcfg |= DF_VCFG_Y2YU_FORMAT;
+ break;
+ case 2:
+ vcfg |= DF_VCFG_YUYV_FORMAT;
+ break;
+ case 3:
+ vcfg |= DF_VCFG_YVYU_FORMAT;
+ break;
+ }
+
+ /* SELECT SOURCE FORMAT (4:2:2, 4:2:0, RGB) */
+
+ switch (video_source_odd->video_format >> 2) {
+ case 0:
+ ctrl |= DF_CSC_VIDEO_YUV_TO_RGB;
+ break;
+
+ case 1:
+ ctrl |= DF_CSC_VIDEO_YUV_TO_RGB;
+ vcfg |= DF_VCFG_4_2_0_MODE;
+ gcfg |= DC3_GCFG_YUV_420;
+ break;
+
+ case 2:
+ ctrl |= DF_VIDEO_INPUT_IS_RGB;
+ break;
+
+ default:
+ return CIM_STATUS_INVALIDPARAMS;
+ }
+
+ /* ALIGN TO APPROPRIATE OUTPUT COLOR SPACE */
+ /* We have assumed until this point that the output color space is RGB */
+ /* and the input (if YUV) is always SDTV video. */
+
+ if (video_source_odd->flags & DF_SOURCEFLAG_HDTVSOURCE)
+ ctrl |= DF_HD_VIDEO;
+
+ if (ctrl & DF_CSC_GRAPHICS_RGB_TO_YUV) {
+ /* YUV OUTPUT - DISABLE YUV->RGB AND ENABLE YUV->YUV */
+
+ ctrl &= ~DF_CSC_VIDEO_YUV_TO_RGB;
+
+ if ((!(ctrl & DF_HD_VIDEO) && (ctrl & DF_HD_GRAPHICS)) ||
+ ((ctrl & DF_HD_VIDEO) && !(ctrl & DF_HD_GRAPHICS))) {
+ ctrl |= DF_YUV_CSC_EN;
+ }
+ }
+
+ /* PARAMETER - DISPLAY FILTER BUFFER SIZE */
+ /* The line size in the video generator must be 32-byte aligned. */
+ /* However, smaller alignments are managed by setting the */
+ /* appropriate pitch and clipping the video window. */
+
+ vcfg &= ~(DF_VCFG_LINE_SIZE_LOWER_MASK | DF_VCFG_LINE_SIZE_BIT8 |
+ DF_VCFG_LINE_SIZE_BIT9);
+
+ size = ((video_source_odd->width >> 1) + 7) & 0xFFF8;
+
+ vcfg |= (size & 0x00FF) << 8;
+ if (size & 0x0100)
+ vcfg |= DF_VCFG_LINE_SIZE_BIT8;
+ if (size & 0x0200)
+ vcfg |= DF_VCFG_LINE_SIZE_BIT9;
+
+ scale = (scale & ~0x7FF) | video_source_odd->height;
+
+ /* PARAMETER - VIDEO GENERATOR BUFFER SIZE */
+
+ vg_line &= ~DC3_LINE_SIZE_VLS_MASK;
+
+ if (gcfg & DC3_GCFG_YUV_420)
+ width = ((video_source_odd->width >> 1) + 7) & 0xFFF8;
+ else
+ width = ((video_source_odd->width << 1) + 31) & 0xFFE0;
+
+ vg_line |= (width >> 3) << DC3_LINE_SIZE_VB_SHIFT;
+
+ /* WRITE ALL PARAMETERS AT ONCE */
+
+ WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ WRITE_VID32(DF_VIDEO_CONFIG, vcfg);
+ WRITE_VID32(DF_VID_ALPHA_CONTROL, ctrl);
+ WRITE_VID32(DF_VIDEO_SCALER, scale);
+ WRITE_REG32(DC3_GENERAL_CFG, gcfg);
+ WRITE_REG32(DC3_LINE_SIZE, vg_line);
+ WRITE_REG32(DC3_VID_YUV_PITCH, pitch);
+
+ /* WRITE EVEN OR ODD BUFFER OFFSETS */
+ /* The even buffer is only valid inside an interlaced display. */
+
+ if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
+ WRITE_REG32(DC3_VID_EVEN_Y_ST_OFFSET, video_source_even->y_offset);
+ WRITE_REG32(DC3_VID_EVEN_U_ST_OFFSET, video_source_even->u_offset);
+ WRITE_REG32(DC3_VID_EVEN_V_ST_OFFSET, video_source_even->v_offset);
+ }
+
+ WRITE_REG32(DC3_VID_Y_ST_OFFSET, video_source_odd->y_offset);
+ WRITE_REG32(DC3_VID_U_ST_OFFSET, video_source_odd->u_offset);
+ WRITE_REG32(DC3_VID_V_ST_OFFSET, video_source_odd->v_offset);
+
+ WRITE_REG32(DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_offsets
+ *
+ * This routine sets the starting offset for the video buffer(s). The buffers
+ * can also be configured inside df_configure_video_source, but a separate
+ * routine is provided here to allow quick buffer flipping.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_offsets(int even, unsigned long y_offset,
+ unsigned long u_offset, unsigned long v_offset)
+{
+ unsigned long lock = READ_REG32(DC3_UNLOCK);
+
+ WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
+
+ if (even) {
+ WRITE_REG32(DC3_VID_EVEN_Y_ST_OFFSET, y_offset);
+ WRITE_REG32(DC3_VID_EVEN_U_ST_OFFSET, u_offset);
+ WRITE_REG32(DC3_VID_EVEN_V_ST_OFFSET, v_offset);
+ } else {
+ WRITE_REG32(DC3_VID_Y_ST_OFFSET, y_offset);
+ WRITE_REG32(DC3_VID_U_ST_OFFSET, u_offset);
+ WRITE_REG32(DC3_VID_V_ST_OFFSET, v_offset);
+ }
+
+ WRITE_REG32(DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_scale
+ *
+ * This routine programs the horizontal/vertical scale factors for video. To
+ * disable scaling/filtering, this routine should be called with identical source
+ * and destination dimensions.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_scale(unsigned long src_width, unsigned long src_height,
+ unsigned long dst_width, unsigned long dst_height, unsigned long flags)
+{
+ unsigned long temp, misc;
+ unsigned long scale, gfxscale;
+ unsigned long fbactive, src;
+ unsigned long size, downscale;
+ unsigned long vcfg, gcfg, unlock;
+
+ /* APPLY THE GRAPHICS SCALE */
+ /* When requested by the user, we will adjust the video scale by the */
+ /* current graphics scale factor. This allows video to be programmed */
+ /* in terms of the graphics source resolution. */
+
+ misc = READ_VID32(DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING) {
+ gfxscale = READ_REG32(DC3_GFX_SCALE);
+ fbactive = READ_REG32(DC3_FB_ACTIVE);
+
+ /* REVERSE ENGINEER THE SCALE FACTOR */
+ /* The graphics scale factor is (source / (dst - 1)), so a little */
+ /* math is performed to reverse engineer the correct scale for */
+ /* video. */
+ /* */
+ /* F = (0x4000*S)/(D-1) -> (D/S) = (((0x4000*S)/F)+1)/S */
+
+ scale = gfxscale & 0xFFFF;
+ src = (fbactive >> 16) + 1;
+ if (scale != 0x4000) {
+ dst_width = dst_width * (((0x4000 * src) / scale) + 1);
+ dst_width /= src;
+ }
+
+ scale = gfxscale >> 16;
+ src = (fbactive & 0xFFFF) + 1;
+ if (scale != 0x4000) {
+ dst_height = dst_height * (((0x4000 * src) / scale) + 1);
+ dst_height /= src;
+ }
+ }
+
+ /* CHECK FOR VALID SCALING FACTOR */
+ /* The display filter/video generator can support up to 8:1 */
+ /* horizontal downscale and up to 4:1 vertical downscale. */
+ /* Scale factors above 4:1 horizontal and 2:1 horizontal */
+ /* will have a quality impact. However, at such large scale */
+ /* factors, it might not matter, */
+
+ if (((flags & DF_SCALEFLAG_CHANGEX) && dst_width < (src_width >> 3)) ||
+ ((flags & DF_SCALEFLAG_CHANGEY) && dst_height < (src_height >> 2))) {
+ return CIM_STATUS_INVALIDSCALE;
+ }
+
+ /* ENABLE OR DISABLE ADVANCED SCALING FEATURES */
+ /* Scaling above 2:1 vertical and 4:1 horizontal relies */
+ /* on mechanisms beside the line filter. */
+
+ if (flags & DF_SCALEFLAG_CHANGEX) {
+ scale = READ_VID32(DF_VIDEO_SCALER);
+ vcfg = READ_VID32(DF_VIDEO_CONFIG);
+ vcfg &= ~(DF_VCFG_LINE_SIZE_LOWER_MASK | DF_VCFG_LINE_SIZE_BIT8 |
+ DF_VCFG_LINE_SIZE_BIT9);
+
+ if (dst_width < (src_width >> 2)) {
+ src_width >>= 1;
+ WRITE_VID32(DF_VIDEO_SCALER, scale | DF_SCALE_DOUBLE_H_DOWNSCALE);
+ } else {
+ WRITE_VID32(DF_VIDEO_SCALER,
+ scale & ~DF_SCALE_DOUBLE_H_DOWNSCALE);
+ }
+
+ /* PROGRAM A NEW LINE SIZE */
+ /* The line size must be updated when using the Double Horizontal */
+ /* Downscale (DHD) bit. This is because the amount of VFIFO space */
+ /* consumed is effectively half in this mode. */
+
+ size = ((src_width >> 1) + 7) & 0xFFF8;
+ vcfg |= (size & 0x00FF) << 8;
+ if (size & 0x0100)
+ vcfg |= DF_VCFG_LINE_SIZE_BIT8;
+ if (size & 0x0200)
+ vcfg |= DF_VCFG_LINE_SIZE_BIT9;
+ WRITE_VID32(DF_VIDEO_CONFIG, vcfg);
+ WRITE_VID32(DF_VIDEO_XSCALE, ((0x10000 * src_width) / dst_width));
+ }
+
+ if (flags & DF_SCALEFLAG_CHANGEY) {
+ unlock = READ_REG32(DC3_UNLOCK);
+ gcfg = READ_REG32(DC3_GENERAL_CFG) & ~DC3_GCFG_VDSE;
+ WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ if (dst_height < (src_height >> 1)) {
+ gcfg |= DC3_GCFG_VDSE;
+ downscale = READ_REG32(DC3_VID_DS_DELTA) & ~DC3_DS_DELTA_MASK;
+ if (dst_height == (src_height >> 2))
+ downscale |= (0x3FFF << 18);
+ else
+ downscale |= (((src_height >> 1) << 14) / dst_height) << 18;
+
+ WRITE_REG32(DC3_VID_DS_DELTA, downscale);
+ WRITE_VID32(DF_VIDEO_YSCALE, 0x20000);
+ } else {
+ WRITE_VID32(DF_VIDEO_YSCALE,
+ ((0x10000 * src_height) / dst_height));
+ }
+ WRITE_REG32(DC3_GENERAL_CFG, gcfg);
+ WRITE_REG32(DC3_UNLOCK, unlock);
+ }
+
+ /* CHECK IF SCALING IS DISABLED */
+ /* If no scaling occurs, we disable the hardware filter. */
+
+ temp = READ_VID32(DF_VIDEO_CONFIG);
+ if ((READ_VID32(DF_VIDEO_XSCALE) == 0x10000) &&
+ (READ_VID32(DF_VIDEO_YSCALE) == 0x10000)) {
+ WRITE_VID32(DF_VIDEO_CONFIG, (temp | DF_VCFG_SC_BYP));
+ } else
+ WRITE_VID32(DF_VIDEO_CONFIG, (temp & ~DF_VCFG_SC_BYP));
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_position
+ *
+ * This routine programs the position of the video window on the display.
+ * An indent parameter is also passed to this program to prevent artifacts
+ * when the video window is moved beyond the left edge of the screen.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_position(DF_VIDEO_POSITION * video_window)
+{
+ unsigned long vblankstart_even, vblankend_even, vsyncend_even,
+ vtotal_even, vactive_even;
+ unsigned long hblankstart, hblankend, hsyncend, htotal, hactive;
+ unsigned long vblankstart, vblankend, vsyncend, vtotal, vactive;
+ unsigned long width, height, height_even;
+ unsigned long adjust, border_x, border_y, border_y_even;
+ unsigned long xstart, xend;
+ unsigned long ystart, yend;
+ unsigned long ckey_x, ckey_y;
+ unsigned long x_copy, y_copy;
+ unsigned long width_copy, height_copy;
+ unsigned long vcfg, initread;
+ unsigned long xscale, dst_clip;
+ unsigned long ypos, ypos_even;
+ unsigned long y, gfxscale;
+ unsigned long misc, fbactive;
+ unsigned long scale, src;
+ unsigned long irq_ctl;
+ unsigned long unlock;
+
+ hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vblankend = ((READ_REG32(DC3_V_BLANK_TIMING) >> 16) & 0xFFF) + 1;
+ hblankend = ((READ_REG32(DC3_H_BLANK_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vblankstart = (READ_REG32(DC3_V_BLANK_TIMING) & 0xFFF) + 1;
+ hblankstart = (READ_REG32(DC3_H_BLANK_TIMING) & 0xFFF) + 1;
+ hactive = (READ_REG32(DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
+ vactive = (READ_REG32(DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
+ unlock = READ_REG32(DC3_UNLOCK);
+
+ /* INCLUDE BORDER IF REQUESTED */
+
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER) {
+ border_x = htotal - hblankend;
+ border_y = vtotal - vblankend;
+ hactive = hblankstart + htotal - hblankend;
+ vactive = vblankstart + vtotal - vblankend;
+ } else {
+ border_x = border_y = 0;
+ }
+
+ /* APPLY THE GRAPHICS SCALE */
+ /* Do not alter the input data. */
+
+ width_copy = video_window->width;
+ height_copy = video_window->height;
+ x_copy = video_window->x;
+ y_copy = video_window->y;
+
+ misc = READ_VID32(DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING) {
+ gfxscale = READ_REG32(DC3_GFX_SCALE);
+ fbactive = READ_REG32(DC3_FB_ACTIVE);
+
+ /* REVERSE ENGINEER THE SCALE FACTOR */
+
+ scale = gfxscale & 0xFFFF;
+ src = (fbactive >> 16) + 1;
+ if (scale != 0x4000) {
+ width_copy = width_copy * (((0x4000 * src) / scale) + 1);
+ width_copy /= src;
+ x_copy = x_copy * (((0x4000 * src) / scale) + 1);
+ x_copy /= src;
+ }
+
+ scale = gfxscale >> 16;
+ src = (fbactive & 0xFFFF) + 1;
+ if (scale != 0x4000) {
+ height_copy = height_copy * (((0x4000 * src) / scale) + 1);
+ height_copy /= src;
+ y_copy = y_copy * (((0x4000 * src) / scale) + 1);
+ y_copy /= src;
+ }
+ }
+
+ /* HANDLE INTERLACING */
+ /* When the output is interlaced, we must set the position and height */
+ /* on the fields and not on the composite image. */
+
+ if ((irq_ctl = READ_REG32(DC3_IRQ_FILT_CTL)) & DC3_IRQFILT_INTL_EN) {
+ vsyncend_even = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal_even = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vblankend_even = ((READ_REG32(DC3_V_BLANK_EVEN) >> 16) & 0xFFF) + 1;
+ vactive_even = (READ_REG32(DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
+ vblankstart_even = (READ_REG32(DC3_V_BLANK_EVEN) & 0xFFF) + 1;
+
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER) {
+ border_y_even = vtotal_even - vblankend_even;
+ vactive_even = vblankstart_even + vtotal_even - vblankend_even;
+ } else
+ border_y_even = 0;
+
+ /*
+ * THE ODD FIELD MUST ALWAYS PRECEDE THE EVEN FIELD
+ * This implies that we can never start video on an odd y position
+ * in the composite image. This is required because the only way
+ * to accomplish an odd y start would be to switch the buffer
+ * which could have serious repercussions for genlocked VIP.
+ */
+
+ y = y_copy >> 1;
+
+ /* CALCULATE Y POSITION FOR ODD FIELD */
+ /* Clip the video window to the odd field timings. Note that the */
+ /* height in the odd field may be greater if the video height is */
+ /* odd. */
+
+ height = (height_copy + 1) >> 1;
+ if ((y + height) > vactive)
+ height = vactive - y;
+
+ ystart = y + vtotal_even - vsyncend_even + 1;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ ystart -= border_y_even;
+
+ yend = ystart + height;
+ ypos = (yend << 16) | ystart;
+
+ /* CALCULATE Y POSITION FOR EVEN FIELD */
+
+ height_even = height_copy >> 1;
+ if ((y + height_even) > vactive_even)
+ height_even = vactive_even - y;
+
+ ystart = y + vtotal - vsyncend + 1;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ ystart -= border_y;
+
+ yend = ystart + height_even;
+ ypos_even = (yend << 16) | ystart;
+
+ /* CALCULATE ACTUAL FRAME BUFFER HEIGHT */
+ /* The y position and height are used to determine the actual */
+ /* placement of the color key region. The region will either be */
+ /* the sum of the even and odd fields (for interlaced addressing */
+ /* or flicker filtering) or it will be the union of the two (for */
+ /* line doubling). We must also adjust the region such that the */
+ /* origin (0, 0) is centered on the beginning of graphics data. */
+ /* This is only a problem if video is being displayed over the */
+ /* overscan area. */
+
+ if ((READ_REG32(DC3_GENLK_CTL) & DC3_GC_FLICKER_FILTER_ENABLE) ||
+ (irq_ctl & DC3_IRQFILT_INTL_ADDR)) {
+ y <<= 1;
+ height += height_even;
+ adjust = border_y + border_y_even;
+ } else {
+ adjust = border_y;
+ if (height_even > height)
+ height = height_even;
+ }
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER) {
+ if (y > adjust) {
+ y -= adjust;
+ adjust = 0;
+ } else {
+ adjust -= y;
+ if (height > adjust)
+ height -= adjust;
+ else
+ height = 0;
+ }
+ }
+
+ } else {
+ y = y_copy;
+
+ height = height_copy;
+ if ((y + height) > vactive)
+ height = vactive - y;
+
+ ystart = y + vtotal - vsyncend + 1;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ ystart -= border_y;
+
+ yend = ystart + height;
+ ypos = (yend << 16) | ystart;
+ ypos_even = 0;
+ }
+
+ /* HORIZONTAL POSITION */
+ /* The horizontal values are identical for the even and odd field. */
+
+ width = width_copy;
+ xstart = x_copy + htotal - hsyncend - 14;
+ if (video_window->flags & DF_POSFLAG_INCLUDEBORDER)
+ xstart -= border_x;
+
+ /* RIGHT CLIPPING */
+
+ if ((x_copy + width) > hactive)
+ width = hactive - x_copy;
+
+ xend = xstart + width;
+
+ /*
+ * CALCULATE LEFT CLIPPING PARAMETER
+ * The value passed in can be interpreted as destination pixels, in
+ * which case the video scale is factored in, or as source pixels, in
+ * which case the value is written directly. Also, the display filter's
+ * initial read address value is only programmable on 4-pixel increments.
+ * However, we can achieve an arbitrary left clip by adjusting the
+ * xstart value, as there is a 14-clock delay in which to play. Also,
+ * according to the designers, 4:2:0 and 4:2:2 behave identically when
+ * setting the initial read address. The addition of scaling further
+ * complicates the algorithm. When setting the initial read address, it
+ * is in terms of source pixels, while adjusting the xstart value is in
+ * destination pixels We may thus not be able to achieve a perfect
+ * clipping fit for scaled video. We compensate by including two
+ * clipping parameters in our structure. This allows us the user
+ * additional control and it allows us to accurately convey to the user
+ * the state of clipping on the machine.
+ */
+
+ initread = video_window->left_clip;
+ dst_clip = 0;
+ if (!(video_window->flags & DF_POSFLAG_DIRECTCLIP)) {
+ xscale = READ_VID32(DF_VIDEO_XSCALE) & 0xFFFFF;
+ initread = (initread * xscale) / 0x10000;
+ if (xscale)
+ dst_clip = ((initread & 3) * 0x10000) / xscale;
+ } else
+ dst_clip = video_window->dst_clip;
+
+ /*
+ * LIMIT THE CLIP
+ * We technically have a 14 pixel window in which to play. However,
+ * taking the entire 14 pixels makes the video timing a little hairy...
+ * Also note that we cannot do this when performing panel centering, as
+ * the video would then exceed the mode size.
+ */
+
+ if (dst_clip > 4)
+ dst_clip = 4;
+ if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
+ dst_clip = 0;
+
+ xstart -= dst_clip;
+
+ vcfg = READ_VID32(DF_VIDEO_CONFIG);
+ vcfg &= ~DF_VCFG_INIT_READ_MASK;
+ vcfg |= (initread >> 2) << 16;
+
+ /* SET COLOR KEY REGION */
+ /* We are assuming that color keying will never be desired outside */
+ /* of the video region. We adjust the color key region for graphics */
+ /* scaling. */
+
+ gfxscale = READ_REG32(DC3_GFX_SCALE);
+
+ ckey_x = ((x_copy * (gfxscale & 0xFFFF)) / 0x4000) |
+ ((((x_copy + width) * (gfxscale & 0xFFFF)) / 0x4000) << 16);
+ ckey_y = ((y * (gfxscale >> 16)) / 0x4000) |
+ ((((y + height) * (gfxscale >> 16)) / 0x4000) << 16);
+
+ /* WRITE ALL PARAMETERS AT ONCE */
+
+ WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ WRITE_REG32(DC3_CLR_KEY_X, ckey_x);
+ WRITE_REG32(DC3_CLR_KEY_Y, ckey_y);
+ WRITE_VID32(DF_VIDEO_X_POS, (xend << 16) | xstart);
+ WRITE_VID32(DF_VIDEO_Y_POS, ypos);
+ WRITE_VID32(DF_VID_YPOS_EVEN, ypos_even);
+ WRITE_VID32(DF_VIDEO_CONFIG, vcfg);
+ WRITE_REG32(DC3_UNLOCK, unlock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_filter_coefficients
+ *
+ * This routine sets the horizontal and vertical filter coefficients for video
+ * scaling. These coefficients are used for upscaling and downscaling video.
+ * If the phase256 parameter is 1, the coefficient arrays are used as single
+ * arrays of 256 phases for both vertical and horizontal scaling. If the
+ * phase256 parameter is clear, the coefficient arrays are used as two
+ * 128-phase arrays. The first 128 entries represent the phases for
+ * vertical scaling. The last 128 entries represent the phases for
+ * horizontal scaling.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_filter_coefficients(long taps[][4], int phase256)
+{
+ unsigned long scale, coeff0, coeff1;
+ unsigned long i;
+ long (*defaults)[2];
+
+ /* SET PHASE COUNT AND CHOOSE COEFFICIENT ARRAY */
+
+ scale = READ_VID32(DF_VIDEO_SCALER);
+ if (phase256) {
+ WRITE_VID32(DF_VIDEO_SCALER, (scale & ~DF_SCALE_128_PHASES));
+ defaults = CimarronVideoFilter256;
+ } else {
+ WRITE_VID32(DF_VIDEO_SCALER, (scale | DF_SCALE_128_PHASES));
+ defaults = CimarronVideoFilter128;
+ }
+
+ /* PROGRAM COEFFICIENTS */
+
+ for (i = 0; i < 256; i++) {
+ if (!taps) {
+ coeff0 = defaults[i][0];
+ coeff1 = defaults[i][1];
+ } else {
+ if (taps[i][1] < 0)
+ coeff0 = -taps[i][1] | 0x8000;
+ else
+ coeff0 = taps[i][1];
+
+ coeff0 <<= 16;
+
+ if (taps[i][0] < 0)
+ coeff0 |= -taps[i][0] | 0x8000;
+ else
+ coeff0 |= taps[i][0];
+
+ if (taps[i][3] < 0)
+ coeff1 = -taps[i][3] | 0x8000;
+ else
+ coeff1 = taps[i][3];
+
+ coeff1 <<= 16;
+
+ if (taps[i][2] < 0)
+ coeff1 |= -taps[i][2] | 0x8000;
+ else
+ coeff1 |= taps[i][2];
+ }
+
+ WRITE_VID32((DF_COEFFICIENT_BASE + (i << 3)), coeff0);
+ WRITE_VID32((DF_COEFFICIENT_BASE + (i << 3) + 4), coeff1);
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_enable
+ *
+ * This routine enables or disables the video overlay.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_enable(int enable, unsigned long flags)
+{
+ unsigned long vcfg, lock, gcfg;
+ unsigned long dcfg, vg_ckey, fifo = 0;
+
+ vcfg = READ_VID32(DF_VIDEO_CONFIG);
+ lock = READ_REG32(DC3_UNLOCK);
+ gcfg = READ_REG32(DC3_GENERAL_CFG);
+
+ /* SET VIDEO FIFO END WATERMARK */
+ /* The video FIFO end watermark is set to 0 when video is disabled */
+ /* to allow low priority transactions in the VG. Otherwise, the */
+ /* priority will be forced high until the VG fills the video FIFO */
+ /* by not fetching video. That could take a while... Note that */
+ /* we set the end priority to be 4 greater than the start. We */
+ /* assume that the start priority has been configured by a modeset. */
+
+ dcfg = READ_REG32(DC3_DISPLAY_CFG) & ~DC3_DCFG_VFHPEL_MASK;
+ if (enable) {
+ fifo = ((dcfg >> 12) & 0x0000000F) + 4;
+ if (fifo > 0xF)
+ fifo = 0xF;
+ }
+ WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
+ WRITE_REG32(DC3_DISPLAY_CFG, dcfg | (fifo << 16));
+
+ /* ENABLE OR DISABLE VIDEO */
+ /* The mechanism to fetch video data is enabled first and */
+ /* disabled last. */
+
+ if (enable) {
+ WRITE_REG32(DC3_GENERAL_CFG, (gcfg | DC3_GCFG_VIDE));
+ WRITE_VID32(DF_VIDEO_CONFIG, (vcfg | DF_VCFG_VID_EN));
+
+ /* DISABLE COLOR KEYING IF REQUESTED BY THE USER */
+
+ if (flags & DF_ENABLEFLAG_NOCOLORKEY) {
+ /* OVERRIDE THE MODE TO COLOR KEYING */
+
+ dcfg = READ_VID32(DF_DISPLAY_CONFIG);
+ WRITE_VID32(DF_DISPLAY_CONFIG, (dcfg & ~DF_DCFG_VG_CK));
+
+ /* DISABLE COLOR KEYING IN THE VG */
+
+ vg_ckey = READ_REG32(DC3_COLOR_KEY);
+ WRITE_REG32(DC3_COLOR_KEY, (vg_ckey & ~DC3_CLR_KEY_ENABLE));
+ } else if (!(READ_VID32(DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK)) {
+ /* OTHERWISE RE-ENABLE COLOR KEYING */
+
+ vg_ckey = READ_REG32(DC3_COLOR_KEY);
+ WRITE_REG32(DC3_COLOR_KEY, (vg_ckey | DC3_CLR_KEY_ENABLE));
+ }
+ } else {
+ WRITE_VID32(DF_VIDEO_CONFIG, (vcfg & ~DF_VCFG_VID_EN));
+ WRITE_REG32(DC3_GENERAL_CFG, (gcfg & ~DC3_GCFG_VIDE));
+
+ /* DISABLE COLOR KEY WINDOW WHEN VIDEO IS INACTIVE */
+ /* To mimic legacy functionality, we disble color keying */
+ /* when the video window is not active. We will restore */
+ /* the enable when video is re-enabled if the appropriate */
+ /* bit is set in display config. */
+
+ vg_ckey = READ_REG32(DC3_COLOR_KEY);
+ WRITE_REG32(DC3_COLOR_KEY, (vg_ckey & ~DC3_CLR_KEY_ENABLE));
+ }
+ WRITE_REG32(DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_color_key
+ *
+ * This routine configures the video color/chroma key mechanism.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_color_key(unsigned long key, unsigned long mask, int graphics)
+{
+ unsigned long lock, vg_ckey, df_dcfg;
+
+ vg_ckey = READ_REG32(DC3_COLOR_KEY);
+ lock = READ_REG32(DC3_UNLOCK);
+ df_dcfg = READ_VID32(DF_DISPLAY_CONFIG);
+
+ WRITE_REG32(DC3_UNLOCK, DC3_UNLOCK_VALUE);
+
+ if (graphics) {
+ /* COLOR KEY - USE VG HARDWARE */
+ /* Note that color key is never enabled unless a video window */
+ /* is active. This is to match legacy behavior. */
+
+ df_dcfg &= ~DF_DCFG_VG_CK;
+ vg_ckey = (vg_ckey & 0xFF000000) | (key & 0xFFFFFF);
+ if (READ_VID32(DF_VIDEO_CONFIG) & DF_VCFG_VID_EN)
+ vg_ckey |= DC3_CLR_KEY_ENABLE;
+ else
+ vg_ckey &= ~DC3_CLR_KEY_ENABLE;
+
+ WRITE_VID32(DF_DISPLAY_CONFIG, df_dcfg);
+ WRITE_REG32(DC3_COLOR_KEY, vg_ckey);
+ WRITE_REG32(DC3_COLOR_MASK, (mask & 0xFFFFFF));
+ } else {
+ /* CHROMA KEY - USE DF HARDWARE */
+
+ df_dcfg |= DF_DCFG_VG_CK;
+ vg_ckey &= ~DC3_CLR_KEY_ENABLE;
+
+ WRITE_REG32(DC3_COLOR_KEY, vg_ckey);
+ WRITE_VID32(DF_DISPLAY_CONFIG, df_dcfg);
+ WRITE_VID32(DF_VIDEO_COLOR_KEY, (key & 0xFFFFFF));
+ WRITE_VID32(DF_VIDEO_COLOR_MASK, (mask & 0xFFFFFF));
+ }
+
+ WRITE_REG32(DC3_UNLOCK, lock);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_palette
+ *
+ * This routine loads the video hardware palette. If a NULL pointer is
+ * specified, the palette is bypassed.
+ *-------------------------------------------------------------------------*/
+
+int
+df_set_video_palette(unsigned long *palette)
+{
+ unsigned long i, entry;
+ unsigned long misc, dcfg;
+
+ /* LOAD GEODE LX VIDEO PALETTE */
+
+ WRITE_VID32(DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++) {
+ if (palette)
+ entry = palette[i];
+ else
+ entry = i | (i << 8) | (i << 16);
+ WRITE_VID32(DF_PALETTE_DATA, entry);
+ }
+
+ /* ENABLE THE VIDEO PALETTE */
+ /* Ensure that the video palette has an effect by routing video data */
+ /* through the palette RAM and clearing the 'Bypass Both' bit. */
+
+ dcfg = READ_VID32(DF_DISPLAY_CONFIG);
+ misc = READ_VID32(DF_VID_MISC);
+
+ dcfg |= DF_DCFG_GV_PAL_BYP;
+ misc &= ~DF_GAMMA_BYPASS_BOTH;
+
+ WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
+ WRITE_VID32(DF_VID_MISC, misc);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_palette_entry
+ *
+ * This routine loads a single entry of the video hardware palette.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_palette_entry(unsigned long index, unsigned long palette)
+{
+ unsigned long misc, dcfg;
+
+ if (index > 0xFF)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ /* SET A SINGLE ENTRY */
+
+ WRITE_VID32(DF_PALETTE_ADDRESS, index);
+ WRITE_VID32(DF_PALETTE_DATA, palette);
+
+ /* ENABLE THE VIDEO PALETTE */
+ /* Ensure that the video palette has an effect by routing video data */
+ /* through the palette RAM and clearing the 'Bypass Both' bit. */
+
+ dcfg = READ_VID32(DF_DISPLAY_CONFIG);
+ misc = READ_VID32(DF_VID_MISC);
+
+ dcfg |= DF_DCFG_GV_PAL_BYP;
+ misc &= ~DF_GAMMA_BYPASS_BOTH;
+
+ WRITE_VID32(DF_DISPLAY_CONFIG, dcfg);
+ WRITE_VID32(DF_VID_MISC, misc);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_configure_video_cursor_color_key
+ *
+ * This routine configures the hardware video cursor color key mechanism.
+ *--------------------------------------------------------------------------*/
+
+int
+df_configure_video_cursor_color_key(DF_VIDEO_CURSOR_PARAMS * cursor_color_key)
+{
+ unsigned long key;
+
+ if (cursor_color_key->select_color2 >= 24)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ key = READ_VID32(DF_CURSOR_COLOR_KEY) & DF_CURSOR_COLOR_KEY_ENABLE;
+ key = key | (cursor_color_key->key & 0xFFFFFF) | (cursor_color_key->
+ select_color2 << 24);
+
+ WRITE_VID32(DF_CURSOR_COLOR_KEY, key);
+ WRITE_VID32(DF_CURSOR_COLOR_MASK, (cursor_color_key->mask & 0xFFFFFF));
+ WRITE_VID32(DF_CURSOR_COLOR_1, (cursor_color_key->color1 & 0xFFFFFF));
+ WRITE_VID32(DF_CURSOR_COLOR_2, (cursor_color_key->color2 & 0xFFFFFF));
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_cursor_color_key_enable
+ *
+ * This routine enables or disables the video cursor color key.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_cursor_color_key_enable(int enable)
+{
+ unsigned long temp = READ_VID32(DF_CURSOR_COLOR_KEY);
+
+ if (enable)
+ temp |= DF_CURSOR_COLOR_KEY_ENABLE;
+ else
+ temp &= ~DF_CURSOR_COLOR_KEY_ENABLE;
+
+ WRITE_VID32(DF_CURSOR_COLOR_KEY, temp);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_configure_alpha_window
+ *
+ * This routine configures one of the three hardware alpha regions.
+ *--------------------------------------------------------------------------*/
+
+int
+df_configure_alpha_window(int window, DF_ALPHA_REGION_PARAMS * alpha_data)
+{
+ unsigned long vsyncend_even, vtotal_even, vactive_even;
+ unsigned long hsyncend, htotal, hactive;
+ unsigned long vsyncend, vtotal, vactive;
+ unsigned long alpha_ctl, pos;
+ unsigned long hadjust, vadjust;
+ unsigned long y, height;
+ unsigned long xstart, xend;
+ unsigned long ystart, yend;
+ unsigned long x_copy, width_copy;
+ unsigned long y_copy, height_copy;
+ unsigned long scale, src, misc;
+ unsigned long gfxscale, fbactive;
+ unsigned long color;
+
+ if (window > 2)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ hactive = (READ_REG32(DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
+ vactive = (READ_REG32(DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
+
+ /* APPLY THE GRAPHICS SCALE */
+
+ width_copy = alpha_data->width;
+ height_copy = alpha_data->height;
+ x_copy = alpha_data->x;
+ y_copy = alpha_data->y;
+
+ misc = READ_VID32(DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING) {
+ gfxscale = READ_REG32(DC3_GFX_SCALE);
+ fbactive = READ_REG32(DC3_FB_ACTIVE);
+
+ /* REVERSE ENGINEER THE SCALE FACTOR */
+
+ scale = gfxscale & 0xFFFF;
+ src = (fbactive >> 16) + 1;
+ if (scale != 0x4000) {
+ width_copy = width_copy * (((0x4000 * src) / scale) + 1);
+ width_copy /= src;
+ x_copy = x_copy * (((0x4000 * src) / scale) + 1);
+ x_copy /= src;
+ }
+
+ scale = gfxscale >> 16;
+ src = (fbactive & 0xFFFF) + 1;
+ if (scale != 0x4000) {
+ height_copy = height_copy * (((0x4000 * src) / scale) + 1);
+ height_copy /= src;
+ y_copy = y_copy * (((0x4000 * src) / scale) + 1);
+ y_copy /= src;
+ }
+ }
+
+ /* SET PRIORITY */
+ /* Priority is the only alpha parameter that is not in a register that */
+ /* can be indexed based on the alpha window number. */
+
+ pos = 16 + (window << 1);
+ alpha_ctl = READ_VID32(DF_VID_ALPHA_CONTROL) & ~(3L << pos);
+ alpha_ctl |= (alpha_data->priority & 3) << pos;
+ WRITE_VID32(DF_VID_ALPHA_CONTROL, alpha_ctl);
+
+ /* HANDLE INTERLACED MODES */
+
+ if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
+ vsyncend_even = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal_even = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vactive_even = (READ_REG32(DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
+
+ y = y_copy >> 1;
+
+ /* SET Y POSITION FOR ODD FIELD */
+
+ height = (height_copy + 1) >> 1;
+ vadjust = vtotal_even - vsyncend_even + 1;
+
+ ystart = y + vadjust;
+ yend = y + vadjust + height;
+
+ if (yend > (vactive + vadjust))
+ yend = vactive + vadjust;
+
+ WRITE_VID32((DF_ALPHA_YPOS_1 + (window << 5)),
+ (ystart | (yend << 16)));
+
+ /* SET Y POSITION FOR EVEN FIELD */
+
+ height = height_copy >> 1;
+ vadjust = vtotal - vsyncend + 1;
+
+ ystart = y + vadjust;
+ yend = y + vadjust + height;
+
+ if (yend > (vactive_even + vadjust))
+ yend = vactive_even + vadjust;
+
+ WRITE_VID32((DF_VID_ALPHA_Y_EVEN_1 + (window << 3)),
+ (ystart | (yend << 16)));
+ } else {
+ y = y_copy;
+ height = height_copy;
+ vadjust = vtotal - vsyncend + 1;
+
+ ystart = y + vadjust;
+ yend = y + vadjust + height;
+
+ if (yend > (vactive + vadjust))
+ yend = vactive + vadjust;
+
+ WRITE_VID32((DF_ALPHA_YPOS_1 + (window << 5)),
+ (ystart | (yend << 16)));
+ }
+
+ /* SET ALPHA X POSITION */
+ /* The x position is the same for both the odd and even fields. */
+
+ hadjust = htotal - hsyncend - 2;
+
+ xstart = x_copy + hadjust;
+ xend = x_copy + hadjust + width_copy;
+
+ if (xend > (hactive + hadjust))
+ xend = hactive + hadjust;
+
+ WRITE_VID32((DF_ALPHA_XPOS_1 + (window << 5)), (xstart | (xend << 16)));
+
+ /* SET COLOR REGISTER */
+
+ color = alpha_data->color & 0xFFFFFF;
+ if (alpha_data->flags & DF_ALPHAFLAG_COLORENABLED)
+ color |= DF_ALPHA_COLOR_ENABLE;
+
+ WRITE_VID32((DF_ALPHA_COLOR_1 + (window << 5)), color);
+
+ /* SET ALPHA VALUE, DELTA AND PER PIXEL */
+
+ alpha_ctl = READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5)) &
+ DF_ACTRL_WIN_ENABLE;
+ alpha_ctl |= (alpha_data->alpha_value & 0xFF) | DF_ACTRL_LOAD_ALPHA |
+ (((unsigned long)alpha_data->delta & 0xFF) << 8);
+ if (alpha_data->flags & DF_ALPHAFLAG_PERPIXELENABLED)
+ alpha_ctl |= DF_ACTRL_PERPIXEL_EN;
+
+ WRITE_VID32((DF_ALPHA_CONTROL_1 + (window << 5)), alpha_ctl);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_alpha_window_enable
+ *
+ * This routine enables or disables one of the three hardware alpha regions.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_alpha_window_enable(int window, int enable)
+{
+ unsigned long alpha_ctl;
+
+ if (window > 2)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ alpha_ctl = READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5));
+ if (enable)
+ alpha_ctl |= DF_ACTRL_WIN_ENABLE;
+ else
+ alpha_ctl &= ~DF_ACTRL_WIN_ENABLE;
+ WRITE_VID32((DF_ALPHA_CONTROL_1 + (window << 5)), alpha_ctl);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_no_ck_outside_alpha
+ *
+ * This function affects how color/chroma keying is performed inside the video
+ * window.
+ *
+ * If enable is 1, color/chroma key comparison is performed only inside
+ * the enabled alpha windows. Outside the enabled alpha windows, video
+ * is displayed if color keying is enabled, or graphics is displayed if
+ * chroma keying is enabled.
+ * If enable is 0, color/chroma key comparison is performed inside the
+ * entire video window.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_no_ck_outside_alpha(int enable)
+{
+ unsigned long value;
+
+ value = READ_VID32(DF_VID_ALPHA_CONTROL);
+ if (enable)
+ value |= DF_NO_CK_OUTSIDE_ALPHA;
+ else
+ value &= ~DF_NO_CK_OUTSIDE_ALPHA;
+ WRITE_VID32(DF_VID_ALPHA_CONTROL, value);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_video_request
+ *
+ * This routine sets the horizontal (pixel) and vertical (line) video request
+ * values.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_video_request(unsigned long x, unsigned long y)
+{
+ unsigned long htotal, hsyncend;
+ unsigned long vtotal, vsyncend;
+
+ hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+
+ /* SET DISPLAY FILTER VIDEO REQUEST */
+
+ x += htotal - hsyncend - 2;
+ y += vtotal - vsyncend + 1;
+
+ if (x >= 0x1000 || y >= 0x800)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ WRITE_VID32(DF_VIDEO_REQUEST, (y | (x << 16)));
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_output_color_space
+ *
+ * This routine sets the color space used when combining graphics and video.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_output_color_space(int color_space)
+{
+ unsigned long alpha_ctl;
+
+ alpha_ctl = READ_VID32(DF_VID_ALPHA_CONTROL);
+
+ alpha_ctl &= ~(DF_CSC_GRAPHICS_RGB_TO_YUV | DF_CSC_VIDEO_YUV_TO_RGB |
+ DF_HD_GRAPHICS | DF_YUV_CSC_EN | DF_ALPHA_DRGB);
+
+ /* OUTPUT IS RGB */
+ /* Enable YUV->RGB CSC if necessary and enable alpha output if */
+ /* requested. */
+
+ if (color_space == DF_OUTPUT_RGB || color_space == DF_OUTPUT_ARGB) {
+ if (!(alpha_ctl & DF_VIDEO_INPUT_IS_RGB))
+ alpha_ctl |= DF_CSC_VIDEO_YUV_TO_RGB;
+
+ if (color_space == DF_OUTPUT_ARGB)
+ alpha_ctl |= DF_ALPHA_DRGB;
+ }
+
+ /* OUTPUT IS YUV */
+ /* Enable YUV->YUV CSC if necessary and enable RGB->YUV CSC. */
+
+ else if (color_space == DF_OUTPUT_SDTV || color_space == DF_OUTPUT_HDTV) {
+ alpha_ctl |= DF_CSC_GRAPHICS_RGB_TO_YUV;
+
+ if (((alpha_ctl & DF_HD_VIDEO) && color_space == DF_OUTPUT_SDTV) ||
+ (!(alpha_ctl & DF_HD_VIDEO) && color_space == DF_OUTPUT_HDTV)) {
+ alpha_ctl |= DF_YUV_CSC_EN;
+ }
+
+ if (color_space == DF_OUTPUT_HDTV)
+ alpha_ctl |= DF_HD_GRAPHICS;
+ } else
+ return CIM_STATUS_INVALIDPARAMS;
+
+ WRITE_VID32(DF_VID_ALPHA_CONTROL, alpha_ctl);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_set_output_path
+ *
+ * This routine changes the current output path in the display filter.
+ *--------------------------------------------------------------------------*/
+
+int
+df_set_output_path(int format)
+{
+ unsigned long panel_tim2, panel_pm;
+ unsigned long output = 0;
+ Q_WORD msr_value;
+
+ msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
+ msr_value.low &= ~(DF_SIMULTANEOUS_CRT_FP | DF_CONFIG_OUTPUT_MASK);
+ panel_tim2 = READ_VID32(DF_VIDEO_PANEL_TIM2);
+ panel_pm = READ_VID32(DF_POWER_MANAGEMENT);
+
+ if (format == DF_DISPLAY_CRT) {
+ /* SiBZ #4188 */
+ /* When CRT output is selected, the DF drives the DISP_EN signal */
+ /* with the CRT display enable. As a consequence, systems that */
+ /* wire the DISP_EN signal to the TFT backlight control will not */
+ /* be able to set CRT-only output without leaving the backlight */
+ /* enabled. To workaround this issue, we are setting simultaneous */
+ /* TFT/CRT and disabling the TFT logic. The only caveat to this */
+ /* is that some TFT pins are shared with VIP 601 pins. VIP 601 */
+ /* will thus not work when in this pseudo-CRT mode. To address */
+ /* THAT issue, normal CRT mode sets (in cim_vg.c) will set CRT */
+ /* as the DF output format. This will allow VIP 601 on CRT-only */
+ /* systems without a TFT attached. */
+
+ panel_pm &= ~DF_PM_PANEL_ON;
+ panel_tim2 |= DF_PMTIM2_TFT_PASSHTHROUGH;
+ output = DF_OUTPUT_PANEL | DF_SIMULTANEOUS_CRT_FP;
+ } else if (format == DF_DISPLAY_FP || format == DF_DISPLAY_CRT_FP) {
+ panel_pm |= DF_PM_PANEL_ON;
+ panel_tim2 &= ~DF_PMTIM2_TFT_PASSHTHROUGH;
+
+ if (format == DF_DISPLAY_FP)
+ output = DF_OUTPUT_PANEL;
+ else if (format == DF_DISPLAY_CRT_FP)
+ output = DF_OUTPUT_PANEL | DF_SIMULTANEOUS_CRT_FP;
+ } else {
+ switch (format) {
+ case DF_DISPLAY_VOP:
+ output = DF_OUTPUT_VOP;
+ break;
+ case DF_DISPLAY_DRGB:
+ output = DF_OUTPUT_DRGB;
+ break;
+ case DF_DISPLAY_CRT_DRGB:
+ output = DF_OUTPUT_DRGB | DF_SIMULTANEOUS_CRT_FP;
+ break;
+ default:
+ return CIM_STATUS_INVALIDPARAMS;
+ }
+ }
+ msr_value.low |= output;
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG, &msr_value);
+ WRITE_VID32(DF_VIDEO_PANEL_TIM2, panel_tim2);
+ WRITE_VID32(DF_POWER_MANAGEMENT, panel_pm);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_test_video_flip_status
+ *
+ * This routine tests if a new video offset has been latched.
+ *--------------------------------------------------------------------------*/
+
+unsigned long
+df_test_video_flip_status(void)
+{
+ return (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VFLIP);
+}
+
+/*---------------------------------------------------------------------------
+ * df_save_state
+ *
+ * This routine saves all persistent DF state information.
+ *--------------------------------------------------------------------------*/
+
+int
+df_save_state(DF_SAVE_RESTORE * df_state)
+{
+ unsigned long i;
+
+ /* READ ALL DF REGISTERS */
+
+ df_state->vcfg = READ_VID32(DF_VIDEO_CONFIG);
+ df_state->dcfg = READ_VID32(DF_DISPLAY_CONFIG);
+ df_state->video_x = READ_VID32(DF_VIDEO_X_POS);
+ df_state->video_y = READ_VID32(DF_VIDEO_Y_POS);
+ df_state->video_scaler = READ_VID32(DF_VIDEO_SCALER);
+ df_state->video_color_key = READ_VID32(DF_VIDEO_COLOR_KEY);
+ df_state->video_color_mask = READ_VID32(DF_VIDEO_COLOR_MASK);
+ df_state->sat_limit = READ_VID32(DF_SATURATION_LIMIT);
+ df_state->vid_misc = READ_VID32(DF_VID_MISC);
+ df_state->video_yscale = READ_VID32(DF_VIDEO_YSCALE);
+ df_state->video_xscale = READ_VID32(DF_VIDEO_XSCALE);
+ df_state->vid_alpha_control = READ_VID32(DF_VID_ALPHA_CONTROL);
+ df_state->cursor_key = READ_VID32(DF_CURSOR_COLOR_KEY);
+ df_state->cursor_mask = READ_VID32(DF_CURSOR_COLOR_MASK);
+ df_state->cursor_color1 = READ_VID32(DF_CURSOR_COLOR_1);
+ df_state->cursor_color2 = READ_VID32(DF_CURSOR_COLOR_2);
+ df_state->alpha_xpos1 = READ_VID32(DF_ALPHA_XPOS_1);
+ df_state->alpha_ypos1 = READ_VID32(DF_ALPHA_YPOS_1);
+ df_state->alpha_color1 = READ_VID32(DF_ALPHA_COLOR_1);
+ df_state->alpha_control1 = READ_VID32(DF_ALPHA_CONTROL_1);
+ df_state->alpha_xpos2 = READ_VID32(DF_ALPHA_XPOS_2);
+ df_state->alpha_ypos2 = READ_VID32(DF_ALPHA_YPOS_2);
+ df_state->alpha_color2 = READ_VID32(DF_ALPHA_COLOR_2);
+ df_state->alpha_control2 = READ_VID32(DF_ALPHA_CONTROL_2);
+ df_state->alpha_xpos3 = READ_VID32(DF_ALPHA_XPOS_3);
+ df_state->alpha_ypos3 = READ_VID32(DF_ALPHA_YPOS_3);
+ df_state->alpha_color3 = READ_VID32(DF_ALPHA_COLOR_3);
+ df_state->alpha_control3 = READ_VID32(DF_ALPHA_CONTROL_3);
+ df_state->vid_request = READ_VID32(DF_VIDEO_REQUEST);
+ df_state->vid_ypos_even = READ_VID32(DF_VID_YPOS_EVEN);
+ df_state->alpha_ypos_even1 = READ_VID32(DF_VID_ALPHA_Y_EVEN_1);
+ df_state->alpha_ypos_even2 = READ_VID32(DF_VID_ALPHA_Y_EVEN_2);
+ df_state->alpha_ypos_even3 = READ_VID32(DF_VID_ALPHA_Y_EVEN_3);
+ df_state->panel_tim1 = READ_VID32(DF_VIDEO_PANEL_TIM1);
+ df_state->panel_tim2 = READ_VID32(DF_VIDEO_PANEL_TIM2);
+ df_state->panel_pm = READ_VID32(DF_POWER_MANAGEMENT);
+ df_state->panel_dither = READ_VID32(DF_DITHER_CONTROL);
+
+ /* READ DF PALETTE */
+
+ WRITE_VID32(DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++)
+ df_state->palette[i] = READ_VID32(DF_PALETTE_DATA);
+
+ /* READ FILTER COEFFICIENTS */
+
+ for (i = 0; i < 512; i++)
+ df_state->coefficients[i] =
+ READ_VID32(DF_COEFFICIENT_BASE + (i << 2));
+
+ /* READ ALL DF MSRS */
+
+ msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CAP,
+ &(df_state->msr_cap));
+ msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG,
+ &(df_state->msr_config));
+ msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_SMI,
+ &(df_state->msr_smi));
+ msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_ERROR,
+ &(df_state->msr_error));
+ msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_PM, &(df_state->msr_pm));
+ msr_read64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG,
+ &(df_state->msr_diag));
+ msr_read64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF,
+ &(df_state->msr_df_diag));
+ msr_read64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL,
+ &(df_state->msr_pad_sel));
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_restore_state
+ *
+ * This routine restores all persistent DF state information.
+ *--------------------------------------------------------------------------*/
+
+int
+df_restore_state(DF_SAVE_RESTORE * df_state)
+{
+ unsigned long i;
+
+ /* CLEAR VCFG AND DCFG */
+
+ WRITE_VID32(DF_VIDEO_CONFIG, 0);
+ WRITE_VID32(DF_DISPLAY_CONFIG, 0);
+
+ /* RESTORE DF MSRS */
+
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CAP,
+ &(df_state->msr_cap));
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_CONFIG,
+ &(df_state->msr_config));
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_SMI,
+ &(df_state->msr_smi));
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_ERROR,
+ &(df_state->msr_error));
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_PM, &(df_state->msr_pm));
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG,
+ &(df_state->msr_diag));
+ msr_write64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF,
+ &(df_state->msr_df_diag));
+ msr_write64(MSR_DEVICE_GEODELX_DF, DF_MSR_PAD_SEL,
+ &(df_state->msr_pad_sel));
+
+ /* RESTORE ALL DF REGISTERS */
+
+ WRITE_VID32(DF_VIDEO_X_POS, df_state->video_x);
+ WRITE_VID32(DF_VIDEO_Y_POS, df_state->video_y);
+ WRITE_VID32(DF_VIDEO_SCALER, df_state->video_scaler);
+ WRITE_VID32(DF_VIDEO_COLOR_KEY, df_state->video_color_key);
+ WRITE_VID32(DF_VIDEO_COLOR_MASK, df_state->video_color_mask);
+ WRITE_VID32(DF_SATURATION_LIMIT, df_state->sat_limit);
+ WRITE_VID32(DF_VID_MISC, df_state->vid_misc);
+ WRITE_VID32(DF_VIDEO_YSCALE, df_state->video_yscale);
+ WRITE_VID32(DF_VIDEO_XSCALE, df_state->video_xscale);
+ WRITE_VID32(DF_VID_ALPHA_CONTROL, df_state->vid_alpha_control);
+ WRITE_VID32(DF_CURSOR_COLOR_KEY, df_state->cursor_key);
+ WRITE_VID32(DF_CURSOR_COLOR_MASK, df_state->cursor_mask);
+ WRITE_VID32(DF_CURSOR_COLOR_1, df_state->cursor_color1);
+ WRITE_VID32(DF_CURSOR_COLOR_2, df_state->cursor_color2);
+ WRITE_VID32(DF_ALPHA_XPOS_1, df_state->alpha_xpos1);
+ WRITE_VID32(DF_ALPHA_YPOS_1, df_state->alpha_ypos1);
+ WRITE_VID32(DF_ALPHA_COLOR_1, df_state->alpha_color1);
+ WRITE_VID32(DF_ALPHA_CONTROL_1, df_state->alpha_control1);
+ WRITE_VID32(DF_ALPHA_XPOS_2, df_state->alpha_xpos2);
+ WRITE_VID32(DF_ALPHA_YPOS_2, df_state->alpha_ypos2);
+ WRITE_VID32(DF_ALPHA_COLOR_2, df_state->alpha_color2);
+ WRITE_VID32(DF_ALPHA_CONTROL_2, df_state->alpha_control1);
+ WRITE_VID32(DF_ALPHA_XPOS_3, df_state->alpha_xpos3);
+ WRITE_VID32(DF_ALPHA_YPOS_3, df_state->alpha_ypos3);
+ WRITE_VID32(DF_ALPHA_COLOR_3, df_state->alpha_color3);
+ WRITE_VID32(DF_ALPHA_CONTROL_3, df_state->alpha_control3);
+ WRITE_VID32(DF_VIDEO_REQUEST, df_state->vid_request);
+ WRITE_VID32(DF_VID_YPOS_EVEN, df_state->vid_ypos_even);
+ WRITE_VID32(DF_VID_ALPHA_Y_EVEN_1, df_state->alpha_ypos_even1);
+ WRITE_VID32(DF_VID_ALPHA_Y_EVEN_2, df_state->alpha_ypos_even2);
+ WRITE_VID32(DF_VID_ALPHA_Y_EVEN_3, df_state->alpha_ypos_even3);
+ WRITE_VID32(DF_VIDEO_PANEL_TIM1, df_state->panel_tim1);
+ WRITE_VID32(DF_VIDEO_PANEL_TIM2, df_state->panel_tim2);
+ WRITE_VID32(DF_POWER_MANAGEMENT, df_state->panel_pm);
+ WRITE_VID32(DF_DITHER_CONTROL, df_state->panel_dither);
+
+ /* RESTORE DF PALETTE */
+
+ WRITE_VID32(DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++)
+ WRITE_VID32(DF_PALETTE_DATA, df_state->palette[i]);
+
+ /* RESTORE FILTER COEFFICIENTS */
+
+ for (i = 0; i < 512; i++)
+ WRITE_VID32(DF_COEFFICIENT_BASE + (i << 2),
+ df_state->coefficients[i]);
+
+ /* RESTORE DCFG AND VCFG */
+
+ WRITE_VID32(DF_DISPLAY_CONFIG, df_state->dcfg);
+ WRITE_VID32(DF_VIDEO_CONFIG, df_state->vcfg);
+
+ return CIM_STATUS_OK;
+}
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ * CIMARRON DF READ ROUTINES
+ * These routines are included for use in diagnostics or when debugging. They
+ * can be optionally excluded from a project.
+ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+#if CIMARRON_INCLUDE_DF_READ_ROUTINES
+
+/*---------------------------------------------------------------------------
+ * df_read_composite_crc
+ *
+ * This routine reads the CRC of the combination of graphics/video data. This
+ * CRC checks data immediately before the CRT DACs.
+ *--------------------------------------------------------------------------*/
+
+unsigned long
+df_read_composite_crc(int crc_source)
+{
+ Q_WORD msr_value;
+ unsigned long crc;
+ unsigned long interlaced;
+ unsigned long line, field;
+ unsigned long timeout = 1000;
+
+ if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
+ return 0xFFFFFFFF;
+
+ /* ENABLE 32-BIT CRCS */
+
+ msr_read64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+ msr_value.low |= DF_DIAG_32BIT_CRC;
+ msr_write64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+
+ /* RESET THE CRC */
+
+ WRITE_VID32(DF_VID_CRC, 0);
+
+ /* WAIT FOR THE RESET TO BE LATCHED */
+
+ while ((READ_VID32(DF_VID_CRC32) != 0x00000001) && timeout)
+ timeout--;
+
+ /* WAIT FOR THE CORRECT FIELD */
+ /* We use the VG line count and field indicator to determine when */
+ /* to kick off a CRC. */
+
+ if (crc_source & DF_CRC_SOURCE_EVEN)
+ field = 0;
+ else
+ field = DC3_LNCNT_EVEN_FIELD;
+
+ if ((interlaced = (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN))) {
+ /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
+ /* Note that we wait for the field to be odd when CRCing the even */
+ /* field and vice versa. This is because the CRC will not begin */
+ /* until the following field. */
+
+ do {
+ line = READ_REG32(DC3_LINE_CNT_STATUS);
+ } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 10 ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 15);
+ } else {
+ /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
+
+ if (crc_source & DF_CRC_SOURCE_EVEN)
+ return 0xFFFFFFFF;
+ }
+
+ /* ENABLE THE CRC */
+
+ WRITE_VID32(DF_VID_CRC, 1);
+
+ /* WAIT FOR THE CRC TO BE COMPLETED */
+
+ while (!(READ_VID32(DF_VID_CRC) & 4)) ;
+
+ crc = READ_VID32(DF_VID_CRC32);
+
+ return crc;
+}
+
+/*---------------------------------------------------------------------------
+ * df_read_composite_window_crc
+ *
+ * This routine reads the CRC of a rectangular subsection of the combination
+ * of graphics/video data.
+ *--------------------------------------------------------------------------*/
+
+unsigned long
+df_read_composite_window_crc(unsigned long x, unsigned long y,
+ unsigned long width, unsigned long height, int source)
+{
+ Q_WORD msr_value;
+ unsigned long interlaced;
+ unsigned long line, field;
+ unsigned long crc = 0;
+ unsigned long hsyncend, htotal, hsyncstart;
+ unsigned long vsyncend, vtotal, vsyncstart;
+ unsigned long hblankstart, hactive;
+ unsigned long vblankstart, vactive;
+
+ hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ hsyncstart = (READ_REG32(DC3_H_SYNC_TIMING) & 0xFFF) + 1;
+ hactive = (READ_REG32(DC3_H_ACTIVE_TIMING) & 0xFFF) + 1;
+ hblankstart = (READ_REG32(DC3_H_BLANK_TIMING) & 0xFFF) + 1;
+ if ((interlaced = (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN)) &&
+ !(source & DF_CRC_SOURCE_EVEN)) {
+ vsyncend = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vsyncstart = (READ_REG32(DC3_V_SYNC_EVEN) & 0xFFF) + 1;
+ vactive = (READ_REG32(DC3_V_ACTIVE_EVEN) & 0xFFF) + 1;
+ vblankstart = (READ_REG32(DC3_V_BLANK_EVEN) & 0xFFF) + 1;
+ } else {
+ vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncstart = (READ_REG32(DC3_V_SYNC_TIMING) & 0xFFF) + 1;
+ vactive = (READ_REG32(DC3_V_ACTIVE_TIMING) & 0xFFF) + 1;
+ vblankstart = (READ_REG32(DC3_V_BLANK_TIMING) & 0xFFF) + 1;
+ }
+
+ /* TIMINGS MUST BE ACTIVE */
+
+ if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
+ return 0xFFFFFFFF;
+
+ /* DISABLE GLCP ACTIONS */
+
+ msr_value.low = 0;
+ msr_value.high = 0;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
+
+ /* ENABLE HW CLOCK GATING AND SET GLCP CLOCK TO DOT CLOCK */
+
+ msr_value.low = 5;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, MSR_GEODELINK_PM, &msr_value);
+ msr_value.low = 0;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
+ msr_value.low = 3;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DBGCLKCTL, &msr_value);
+
+ /* USE H4 FUNCTION A FOR HSYNC AND H4 FUNCTION B FOR NOT HSYNC */
+ /* HSYNC is bit 30 for the DF */
+
+ msr_value.high = 0x00000001;
+ msr_value.low = 0xE0000FF0;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 4, &msr_value);
+
+ /* USE H3 FUNCTION A FOR VSYNC AND H3 FUNCTION B FOR NOT VSYNC */
+ /* VSYNC is bit 54 for VG and bit 29 for DF */
+
+ msr_value.high = 0x00000000;
+ msr_value.low = 0x001D55AA;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_H0CTL + 3, &msr_value);
+
+ /* M4 (XSTATE = 00 AND VSYNC HIGH) */
+ /* Goto state 01 */
+ /* Note: VSync = H3A */
+
+ msr_value.high = 0x00000001;
+ msr_value.low = 0x000000A0;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 4, &msr_value);
+
+ /* N0 (XSTATE = 01 AND VSYNC LOW) */
+ /* Goto state 02 */
+ /* Note: VSync low = H3B */
+
+ msr_value.high = 0x00040000;
+ msr_value.low = 0x000000C0;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL, &msr_value);
+
+ /* M5 (XSTATE = 10 AND VSYNC HIGH) */
+ /* Goto state 11 */
+
+ msr_value.high = 0x00000001;
+ msr_value.low = 0x00000120;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL + 5, &msr_value);
+
+ /* N1 (XSTATE = 10 and HSYNC LOW) */
+ /* Increment H. Counter */
+ /* Note: HSync = H4 */
+
+ msr_value.high = 0x00080000;
+ msr_value.low = 0x00000120;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 1, &msr_value);
+
+ /* M0 (XSTATE = 10 and H. COUNTER == LIMIT) */
+ /* Clear H. Counter and increment V. Counter */
+
+ msr_value.high = 0x00000000;
+ msr_value.low = 0x00000122;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETM0CTL, &msr_value);
+
+ /* N4 (XSTATE = 10 && CMP0 <= H. COUNTER <= CMP1 && CMP2 <= V. COUNTER
+ * <= CMP3)
+ * CRC into REGB
+ */
+
+ msr_value.high = 0x00000000;
+ msr_value.low = 0x10C20120;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_SETN0CTL + 4, &msr_value);
+
+ /* COMPARATOR 0 VALUE */
+ /* Value = xstart + (htotal - hsync_end) - 1 */
+ /* The value will be adjusted for a border if necessary */
+
+ msr_value.low = x + htotal - hsyncend - 1;
+ if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
+ msr_value.low -= hblankstart - hactive;
+ msr_value.low--;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0, &msr_value);
+
+ /* COMPARATOR 1 VALUE */
+ /* Value = xstart + (htotal - hsync_end - 1) - 1 + width */
+
+ msr_value.low += width - 1;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 2, &msr_value);
+
+ /* COMPARATOR 2 VALUE */
+ /* Value = ystart + vtotal - vsyncend */
+
+ msr_value.low = (y + vtotal - vsyncend) << 16;
+ if (READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_DCEN)
+ msr_value.low -= (vblankstart - vactive) << 16;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 4, &msr_value);
+
+ /* COMPARATOR 3 VALUE */
+ /* Value = ystart + vtotal - vsyncend + height - 1 */
+
+ msr_value.low += (height - 1) << 16;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPVAL0 + 6, &msr_value);
+
+ /* COMPARATOR MASKS */
+ /* Comparators 0 and 1 refer to lower 16 bits of RegB */
+
+ msr_value.low = 0x0000FFFF;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 2, &msr_value);
+
+ /* Comparators 2 and 3 refer to upper 16 bits of RegB */
+
+ msr_value.low = 0xFFFF0000;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 4, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_CMPMASK0 + 6, &msr_value);
+
+ /* SET REGB MASK */
+ /* We set the mask such that all only 24 bits of data are CRCed */
+
+ msr_value.low = 0x00FFFFFF;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGBMASK, &msr_value);
+
+ /* SET REGA LIMITS */
+ /* Lower counter uses htotal - sync_time - 1. */
+ /* Upper counter is 0xFFFF to prevent rollover. */
+
+ msr_value.low = 0xFFFF0000 | (htotal - (hsyncend - hsyncstart) - 1);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGAVAL, &msr_value);
+
+ /* ACTIONS */
+
+ /* STATE 00->01 (SET 4M) */
+
+ msr_value.low = 0x000C0000;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 14, &msr_value);
+
+ /* STATE 01->10 (SET 0N) */
+
+ msr_value.low = 0x0000000A;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 15, &msr_value);
+
+ /* STATE 10->11 (SET 5M) */
+
+ msr_value.low = 0x00C00000;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 16, &msr_value);
+
+ /* CLEAR REGA WHEN TRANSITIONING TO STATE 10 */
+ /* Do not clear RegB as the initial value must be 0x00000001 */
+
+ msr_value.low = 0x0000000A;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0, &msr_value);
+
+ /* REGISTER ACTION 1 */
+ /* CRC into RegB if cmp0 <= h.counter <= cmp1 && cmp2 <= v. counter <
+ * cmp3 && 7 xstate = 10 8
+ * Increment h.counter if xstate = 10 and HSync is low.
+ */
+
+ msr_value.low = 0x000A00A0;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 1, &msr_value);
+
+ /* REGISTER ACTION 2 */
+ /* Increment V. Counter in REGA */
+
+ msr_value.low = 0x0000000C;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 2, &msr_value);
+
+ /* SET REGB TO 0x00000001 */
+
+ msr_value.low = 0x00000001;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
+
+ /* SET XSTATE TO 0 */
+
+ msr_value.low = 0x00000000;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
+
+ /* CLEAR ALL OTHER ACTIONS */
+ /* This prevents side-effects from previous accesses to the GLCP */
+ /* debug logic. */
+
+ msr_value.low = 0x00000000;
+ msr_value.high = 0x00000000;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 3, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 4, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 5, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 6, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 7, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 8, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 9, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 10, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 11, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 12, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 13, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 17, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 18, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 19, &msr_value);
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_ACTION0 + 20, &msr_value);
+
+ /* WAIT FOR THE CORRECT FIELD */
+ /* We use the VG line count and field indicator to determine when */
+ /* to kick off a CRC. */
+
+ if (source & DF_CRC_SOURCE_EVEN)
+ field = 0;
+ else
+ field = DC3_LNCNT_EVEN_FIELD;
+
+ if (interlaced) {
+ /* WAIT FOR THE BEGINNING OF THE FIELD (LINE 1-5) */
+ /* Note that we wait for the field to be odd when CRCing the even */
+ /* field and vice versa. This is because the CRC will not begin */
+ /* until the following field. */
+
+ do {
+ line = READ_REG32(DC3_LINE_CNT_STATUS);
+ } while ((line & DC3_LNCNT_EVEN_FIELD) != field ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) < 1 ||
+ ((line & DC3_LNCNT_V_LINE_CNT) >> 16) > 5);
+ } else {
+ /* NON-INTERLACED - EVEN FIELD CRCS ARE INVALID */
+
+ if (source & DF_CRC_SOURCE_EVEN)
+ return 0xFFFFFFFF;
+ }
+
+ /* CONFIGURE DISPLAY FILTER TO LOAD DATA ONTO LOWER 32-BITS */
+
+ msr_value.high = 0;
+ msr_value.low = 0x0000800B;
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &msr_value);
+
+ /* CONFIGURE DIAG CONTROL */
+ /* Set RegA action1 to increment lower 16 bits and clear at limit. (5)
+ * Set RegA action2 to increment upper 16 bits. (6)
+ * Set RegB action1 to CRC32 (1)
+ * Set all comparators to REGA override (0,1 lower mbus, 2,3 upper mbus)
+ * Enable all actions
+ */
+
+ msr_value.low = 0x80EA20A0;
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
+
+ /* DELAY TWO FRAMES */
+
+ while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA) ;
+ while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA)) ;
+ while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA) ;
+ while (!(READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA)) ;
+ while (READ_REG32(DC3_LINE_CNT_STATUS) & DC3_LNCNT_VNA) ;
+
+ /* VERIFY THAT XSTATE = 11 */
+
+ msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_XSTATE, &msr_value);
+ if ((msr_value.low & 3) == 3) {
+ msr_read64(MSR_DEVICE_GEODELX_GLCP, GLCP_REGB, &msr_value);
+
+ crc = msr_value.low;
+ }
+
+ /* DISABLE DF DIAG BUS OUTPUTS */
+
+ msr_value.low = 0x00000000;
+ msr_value.high = 0x00000000;
+ msr_write64(MSR_DEVICE_GEODELX_DF, MSR_GEODELINK_DIAG, &msr_value);
+
+ /* DISABLE GLCP ACTIONS */
+
+ msr_write64(MSR_DEVICE_GEODELX_GLCP, GLCP_DIAGCTL, &msr_value);
+
+ return crc;
+}
+
+/*---------------------------------------------------------------------------
+ * df_read_panel_crc
+ *
+ * This routine reads the CRC for a frame of data after the panel dithering
+ * logic.
+ *--------------------------------------------------------------------------*/
+
+unsigned long
+df_read_panel_crc(void)
+{
+ Q_WORD msr_value;
+ unsigned long timeout = 1000;
+
+ if (!(READ_REG32(DC3_DISPLAY_CFG) & DC3_DCFG_TGEN))
+ return 0xFFFFFFFF;
+
+ /* ENABLE 32-BIT CRCS */
+
+ msr_read64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+ msr_value.low |= DF_DIAG_32BIT_CRC;
+ msr_write64(MSR_DEVICE_GEODELX_DF, DF_MBD_MSR_DIAG_DF, &msr_value);
+
+ /* RESET CRC */
+
+ WRITE_VID32(DF_PANEL_CRC, 0);
+
+ /* WAIT FOR THE RESET TO BE LATCHED */
+
+ while ((READ_VID32(DF_PANEL_CRC32) != 0x00000001) && timeout)
+ timeout--;
+
+ WRITE_VID32(DF_PANEL_CRC, 1);
+
+ /* WAIT FOR THE CRC TO BE COMPLETED */
+
+ while (!(READ_VID32(DF_PANEL_CRC) & 4)) ;
+
+ return READ_VID32(DF_PANEL_CRC32);
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_enable
+ *
+ * This routine reads the enable status of the video overlay.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_enable(int *enable, unsigned long *flags)
+{
+ *enable = 0;
+ *flags = 0;
+ if (READ_VID32(DF_VIDEO_CONFIG) & DF_VCFG_VID_EN) {
+ *enable = 1;
+
+ /* CHECK FOR COLOR KEY DISABLED */
+ /* Color keying can be completely disabled when video is enabled to */
+ /* allow unhindered per-pixel alpha blending. As color keying is */
+ /* always disabled when video is disabled, it is only possible to */
+ /* test for this condition when video is enabled. */
+
+ if (!(READ_VID32(DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK) &&
+ !(READ_REG32(DC3_COLOR_KEY) & DC3_CLR_KEY_ENABLE)) {
+ *flags = DF_ENABLEFLAG_NOCOLORKEY;
+ }
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_source_configuration
+ *
+ * This routine reads the current configuration of the source buffers for the
+ * video overlay.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_source_configuration(DF_VIDEO_SOURCE_PARAMS * video_source_odd,
+ DF_VIDEO_SOURCE_PARAMS * video_source_even)
+{
+ unsigned long format, temp;
+ unsigned long size;
+
+ /* READ VIDEO FORMAT */
+
+ temp = READ_VID32(DF_VIDEO_CONFIG);
+
+ format = (temp >> 2) & 3;
+ if (temp & DF_VCFG_4_2_0_MODE)
+ format |= 4;
+ else if (READ_VID32(DF_VID_ALPHA_CONTROL) & DF_VIDEO_INPUT_IS_RGB)
+ format |= 8;
+ video_source_odd->video_format = format;
+
+ /* CHECK IF SOURCE IS HD VIDEO */
+
+ if (READ_VID32(DF_VID_ALPHA_CONTROL) & DF_HD_VIDEO)
+ video_source_odd->flags = DF_SOURCEFLAG_HDTVSOURCE;
+ else
+ video_source_odd->flags = 0;
+
+ /* READ SCALING ALGORITHM */
+
+ if (READ_VID32(DF_VID_MISC) & DF_USER_IMPLICIT_SCALING)
+ video_source_odd->flags |= DF_SOURCEFLAG_IMPLICITSCALING;
+
+ /* READ VIDEO PITCH */
+
+ temp = READ_REG32(DC3_VID_YUV_PITCH);
+ video_source_odd->y_pitch = (temp & 0xFFFF) << 3;
+ video_source_odd->uv_pitch = (temp >> 16) << 3;
+
+ /* READ VIDEO SIZE */
+
+ temp = READ_VID32(DF_VIDEO_CONFIG);
+ size = (temp >> 8) & 0xFF;
+ if (temp & DF_VCFG_LINE_SIZE_BIT8)
+ size |= 0x100;
+ if (temp & DF_VCFG_LINE_SIZE_BIT9)
+ size |= 0x200;
+
+ video_source_odd->width = size << 1;
+ video_source_odd->height = READ_VID32(DF_VIDEO_SCALER) & 0x7FF;
+
+ /* READ VIDEO OFFSETS */
+
+ video_source_odd->y_offset = READ_REG32(DC3_VID_Y_ST_OFFSET) & 0xFFFFFFF;
+ video_source_odd->u_offset = READ_REG32(DC3_VID_U_ST_OFFSET) & 0xFFFFFFF;
+ video_source_odd->v_offset = READ_REG32(DC3_VID_V_ST_OFFSET) & 0xFFFFFFF;
+
+ if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
+ video_source_even->y_offset =
+ READ_REG32(DC3_VID_EVEN_Y_ST_OFFSET) & 0xFFFFFFF;
+ video_source_even->u_offset =
+ READ_REG32(DC3_VID_EVEN_U_ST_OFFSET) & 0xFFFFFFF;
+ video_source_even->v_offset =
+ READ_REG32(DC3_VID_EVEN_V_ST_OFFSET) & 0xFFFFFFF;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_position
+ *
+ * This routine reads the current position of the video overlay.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_position(DF_VIDEO_POSITION * video_window)
+{
+ unsigned long xreg, yreg, dst_clip, clip;
+ unsigned long height;
+ unsigned long xend, yend;
+ unsigned long hsyncend, htotal;
+ unsigned long vsyncend, vtotal;
+ unsigned long hadjust, vadjust;
+ unsigned long misc, gfxscale;
+ unsigned long temp;
+ long xstart, ystart;
+
+ video_window->flags = DF_POSFLAG_DIRECTCLIP;
+
+ hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+
+ /* ODD FIELD START COUNTS FROM THE EVEN FIELD TIMINGS */
+ /* We assume that the even field y position is always programmed */
+ /* to be just after the odd field. */
+
+ if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
+ vsyncend = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ } else {
+ vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ }
+
+ hadjust = htotal - hsyncend - 14;
+ vadjust = vtotal - vsyncend + 1;
+
+ xreg = READ_VID32(DF_VIDEO_X_POS);
+ yreg = READ_VID32(DF_VIDEO_Y_POS);
+
+ xstart = (xreg & 0xFFF) - hadjust;
+ ystart = (yreg & 0x7FF) - vadjust;
+ xend = ((xreg >> 16) & 0xFFF) - hadjust;
+ yend = ((yreg >> 16) & 0x7FF) - vadjust;
+
+ height = yend - ystart;
+
+ if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
+ /* Y COORDINATE IS ACTUALLY 2X THE ODD FIELD START */
+
+ ystart <<= 1;
+
+ /* CALCULATE THE EXACT VIDEO HEIGHT */
+ /* The height of the video window is the sum of the */
+ /* odd and even field heights. */
+
+ yreg = READ_VID32(DF_VID_YPOS_EVEN);
+ height += ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
+ }
+
+ clip = ((READ_VID32(DF_VIDEO_CONFIG) >> 16) & 0x1FF) << 2;
+
+ /* ADJUST FOR CLIPPING VALUES THAT ARE NOT FOUR-PIXEL ALIGNED */
+
+ dst_clip = 0;
+ if (xstart < 0) {
+ dst_clip += -xstart;
+ xstart = 0;
+ }
+
+ /* REVERSE THE GRAPHICS SCALE */
+
+ misc = READ_VID32(DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING) {
+ gfxscale = READ_REG32(DC3_GFX_SCALE);
+
+ if (gfxscale != 0x40004000) {
+ temp = ystart + height;
+ temp = (temp * (gfxscale >> 16)) / 0x4000;
+
+ xstart = (xstart * (gfxscale & 0xFFFF)) / 0x4000;
+ xend = (xend * (gfxscale & 0xFFFF)) / 0x4000;
+ ystart = (ystart * (gfxscale >> 16)) / 0x4000;
+ height = temp - ystart;
+ }
+ }
+
+ video_window->left_clip = clip;
+ video_window->dst_clip = dst_clip;
+ video_window->x = xstart;
+ video_window->y = ystart;
+ video_window->width = xend - xstart;
+ video_window->height = height;
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_scale
+ *
+ * This routine reads the current scale values for video scaling.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_scale(unsigned long *x_scale, unsigned long *y_scale)
+{
+ *x_scale = READ_VID32(DF_VIDEO_XSCALE) & 0x000FFFFF;
+ *y_scale = READ_VID32(DF_VIDEO_YSCALE) & 0x000FFFFF;
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_filter_coefficients
+ *
+ * This routine reads the coefficients for the video scaler/filter.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_filter_coefficients(long taps[][4], int *phase256)
+{
+ unsigned long i, temp;
+ long coeff;
+
+ if (READ_VID32(DF_VIDEO_SCALER) & DF_SCALE_128_PHASES)
+ *phase256 = 0;
+ else
+ *phase256 = 1;
+
+ for (i = 0; i < 256; i++) {
+ temp = READ_VID32(DF_COEFFICIENT_BASE + (i << 3));
+
+ /* TAP 0 */
+
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000)
+ coeff = -coeff;
+ taps[i][0] = coeff;
+
+ /* TAP 1 */
+
+ temp >>= 16;
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000)
+ coeff = -coeff;
+ taps[i][1] = coeff;
+
+ temp = READ_VID32(DF_COEFFICIENT_BASE + (i << 3) + 4);
+
+ /* TAP 2 */
+
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000)
+ coeff = -coeff;
+ taps[i][2] = coeff;
+
+ /* TAP 3 */
+
+ temp >>= 16;
+ coeff = temp & 0x7FFF;
+ if (temp & 0x8000)
+ coeff = -coeff;
+ taps[i][3] = coeff;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_color_key
+ *
+ * This routine reads the current settings for hardware color/chroma keying.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_color_key(unsigned long *key, unsigned long *mask, int *graphics)
+{
+ unsigned long chroma = READ_VID32(DF_DISPLAY_CONFIG) & DF_DCFG_VG_CK;
+
+ if (chroma) {
+ /* CHROMA KEY - READ KEY AND MASK FROM DF */
+
+ *graphics = 0;
+ *key = READ_VID32(DF_VIDEO_COLOR_KEY) & 0xFFFFFF;
+ *mask = READ_VID32(DF_VIDEO_COLOR_MASK) & 0xFFFFFF;
+ } else {
+ *graphics = 1;
+
+ *key = READ_REG32(DC3_COLOR_KEY) & 0xFFFFFF;
+ *mask = READ_REG32(DC3_COLOR_MASK) & 0xFFFFFF;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_palette_entry
+ *
+ * This routine returns a single palette entry.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_palette_entry(unsigned long index, unsigned long *palette)
+{
+ if (index > 0xFF)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ /* READ A SINGLE ENTRY */
+
+ WRITE_VID32(DF_PALETTE_ADDRESS, index);
+ *palette = READ_VID32(DF_PALETTE_DATA);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_palette
+ *
+ * This routine returns the entire video palette.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_palette(unsigned long *palette)
+{
+ unsigned long i;
+
+ WRITE_VID32(DF_PALETTE_ADDRESS, 0);
+ for (i = 0; i < 256; i++)
+ palette[i] = READ_VID32(DF_PALETTE_DATA);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_cursor_color_key
+ *
+ * This routine returns the current configuration for the hardware video cursor
+ * color key.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_cursor_color_key(DF_VIDEO_CURSOR_PARAMS * cursor_color_key)
+{
+ unsigned long key;
+
+ cursor_color_key->flags = 0;
+ cursor_color_key->color1 = READ_VID32(DF_CURSOR_COLOR_1) & 0xFFFFFF;
+ cursor_color_key->color2 = READ_VID32(DF_CURSOR_COLOR_2) & 0xFFFFFF;
+ cursor_color_key->mask = READ_VID32(DF_CURSOR_COLOR_MASK) & 0xFFFFFF;
+
+ key = READ_VID32(DF_CURSOR_COLOR_KEY);
+ cursor_color_key->key = key & 0xFFFFFF;
+ cursor_color_key->select_color2 = (key >> 24) & 0x1F;
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_cursor_color_key_enable
+ *
+ * This routine returns the current enable status of the hardware video cursor
+ * color key.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_cursor_color_key_enable(void)
+{
+ if (READ_VID32(DF_CURSOR_COLOR_KEY) & DF_CURSOR_COLOR_KEY_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_alpha_window_configuration
+ *
+ * This routine reads the current configuration for one of the three hardware
+ * alpha regions.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_alpha_window_configuration(int window,
+ DF_ALPHA_REGION_PARAMS * alpha_data)
+{
+ unsigned long pos, color, alpha_ctl;
+ unsigned long hsyncend, htotal;
+ unsigned long vsyncend, vtotal;
+ unsigned long hadjust, vadjust;
+ unsigned long xreg, yreg;
+ unsigned long misc, gfxscale;
+ unsigned long temp;
+ char delta;
+
+ if (window > 2)
+ return CIM_STATUS_INVALIDPARAMS;
+
+ hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_EVEN) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32(DC3_V_SYNC_EVEN) >> 16) & 0xFFF) + 1;
+ } else {
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ }
+
+ /* GET PRIORITY */
+
+ pos = 16 + (window << 1);
+ alpha_data->priority = (READ_VID32(DF_VID_ALPHA_CONTROL) >> pos) & 3L;
+
+ /* GET ALPHA WINDOW */
+
+ hadjust = htotal - hsyncend - 2;
+ vadjust = vtotal - vsyncend + 1;
+
+ xreg = READ_VID32(DF_ALPHA_XPOS_1 + (window << 5));
+ yreg = READ_VID32(DF_ALPHA_YPOS_1 + (window << 5));
+ alpha_data->width = ((xreg >> 16) & 0xFFF) - (xreg & 0xFFF);
+ alpha_data->height = ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
+ alpha_data->x = (xreg & 0xFFF) - hadjust;
+ alpha_data->y = (yreg & 0x7FF) - vadjust;
+
+ /* REVERSE THE GRAPHICS SCALE */
+
+ misc = READ_VID32(DF_VID_MISC);
+ if (misc & DF_USER_IMPLICIT_SCALING) {
+ gfxscale = READ_REG32(DC3_GFX_SCALE);
+ if (gfxscale != 0x40004000) {
+ temp = alpha_data->y + alpha_data->height;
+ temp = (temp * (gfxscale >> 16)) / 0x4000;
+
+ alpha_data->x = (alpha_data->x * (gfxscale & 0xFFFF)) / 0x4000;
+ alpha_data->width =
+ (alpha_data->width * (gfxscale & 0xFFFF)) / 0x4000;
+ alpha_data->y = (alpha_data->y * (gfxscale >> 16)) / 0x4000;
+ alpha_data->height = temp - alpha_data->y;
+ }
+ }
+
+ if (READ_REG32(DC3_IRQ_FILT_CTL) & DC3_IRQFILT_INTL_EN) {
+ /* Y COORDINATE IS ACTUALLY 2X THE ODD FIELD START */
+
+ alpha_data->y <<= 1;
+
+ /* CALCULATE THE EXACT VIDEO HEIGHT */
+ /* The height of the video window is the sum of the */
+ /* odd and even field heights. */
+
+ yreg = READ_VID32(DF_VID_ALPHA_Y_EVEN_1 + (window << 3));
+ alpha_data->height += ((yreg >> 16) & 0x7FF) - (yreg & 0x7FF);
+ }
+
+ /* GET COLOR REGISTER */
+
+ color = READ_VID32(DF_ALPHA_COLOR_1 + (window << 5));
+ alpha_data->color = color & 0xFFFFFF;
+ if (color & DF_ALPHA_COLOR_ENABLE)
+ alpha_data->flags = DF_ALPHAFLAG_COLORENABLED;
+ else
+ alpha_data->flags = 0;
+
+ /* GET ALPHA VALUE, DELTA AND PER PIXEL */
+
+ alpha_ctl = READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5));
+ alpha_data->alpha_value = alpha_ctl & 0xFF;
+ if (alpha_ctl & DF_ACTRL_PERPIXEL_EN)
+ alpha_data->flags |= DF_ALPHAFLAG_PERPIXELENABLED;
+
+ delta = (char)((alpha_ctl >> 8) & 0xFF);
+ alpha_data->delta = (long)delta;
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_alpha_window_enable
+ *
+ * This routine reads the current enable status of one of the three hardware
+ * alpha regions.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_alpha_window_enable(int window)
+{
+ if (window > 2)
+ return 0;
+
+ if (READ_VID32(DF_ALPHA_CONTROL_1 + (window << 5)) & DF_ACTRL_WIN_ENABLE)
+ return 1;
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_video_request
+ *
+ * This routine reads the horizontal (pixel) and vertical (line) video request
+ * values.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_video_request(unsigned long *x, unsigned long *y)
+{
+ unsigned long request;
+ unsigned long hsyncend, htotal;
+ unsigned long vsyncend, vtotal;
+
+ hsyncend = ((READ_REG32(DC3_H_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ vsyncend = ((READ_REG32(DC3_V_SYNC_TIMING) >> 16) & 0xFFF) + 1;
+ htotal = ((READ_REG32(DC3_H_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+ vtotal = ((READ_REG32(DC3_V_ACTIVE_TIMING) >> 16) & 0xFFF) + 1;
+
+ request = READ_VID32(DF_VIDEO_REQUEST);
+ *x = ((request >> 16) & 0xFFF) - (htotal - hsyncend - 2);
+ *y = (request & 0x7FF) - (vtotal - vsyncend + 1);
+
+ return CIM_STATUS_OK;
+}
+
+/*---------------------------------------------------------------------------
+ * df_get_output_color_space
+ *
+ * This routine sets the color space used when combining graphics and video.
+ *--------------------------------------------------------------------------*/
+
+int
+df_get_output_color_space(int *color_space)
+{
+ unsigned long alpha_ctl;
+
+ alpha_ctl = READ_VID32(DF_VID_ALPHA_CONTROL);
+
+ if ((alpha_ctl & DF_CSC_VIDEO_YUV_TO_RGB) ||
+ !(alpha_ctl & DF_CSC_GRAPHICS_RGB_TO_YUV)) {
+ if (alpha_ctl & DF_ALPHA_DRGB)
+ *color_space = DF_OUTPUT_ARGB;
+ else
+ *color_space = DF_OUTPUT_RGB;
+ } else {
+ *color_space = DF_OUTPUT_SDTV;
+
+ if (alpha_ctl & DF_HD_GRAPHICS)
+ *color_space = DF_OUTPUT_HDTV;
+ }
+
+ return CIM_STATUS_OK;
+}
+
+#endif