 /*
  * <LIC_AMD_STD>
  * Copyright (C) 2005 Advanced Micro Devices, Inc.  All Rights Reserved.
  * </LIC_AMD_STD>
  *
  * <CTL_AMD_STD>
  * </CTL_AMD_STD>
  *
  * <DOC_AMD_STD>
  * Cimarron display filter routines.  These routines program the video hardware.
  * </DOC_AMD_STD>
  *
  */

/*---------------------------------------------------------------------------
 * 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 offsets,  */
        /* 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

