(file) Return to atimach64.c CVS log (file) (dir) Up to [XFree86 CVS] / xc / programs / Xserver / hw / xfree86 / drivers / ati

File: [XFree86 CVS] / xc / programs / Xserver / hw / xfree86 / drivers / ati / atimach64.c (download)
Revision: 1.27, Wed Dec 13 00:25:12 2000 UTC (12 years, 6 months ago) by tsi
Branch: MAIN
CVS Tags: xf-4_0_3b, xf-4_0_3a, xf-4_0_3, xf-4_0_2c, xf-4_0_2b, xf-4_0_2a, xf-4_0_2-branch, xf-4_0_2-bindist, xf-4_0_2, xf-4_0_1Zc, xf-4_0_1Zb
Changes since 1.26: +76 -38 lines
1175. Fix ATI DPMS support on panels by mimicking BIOS behaviour more closely
      (Marc La France).

/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64.c,v 1.26 2000/11/02 16:55:28 tsi Exp $ */
/*
 * Copyright 1997 through 2000 by Marc Aurele La France (TSI @ UQV), tsi@ualberta.ca
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of Marc Aurele La France not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  Marc Aurele La France makes no representations
 * about the suitability of this software for any purpose.  It is provided
 * "as-is" without express or implied warranty.
 *
 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */
/*
 * Copyright 1999-2000 Precision Insight, Inc., Cedar Park, Texas.
 * All Rights Reserved.
 *
 * 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 (including the next
 * paragraph) 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 NON-INFRINGEMENT.  IN NO EVENT SHALL
 * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
 */

#include "ati.h"
#include "atibus.h"
#include "atichip.h"
#include "atimach64.h"
#include "atimach64io.h"

#include "miline.h"

#ifndef DPMS_SERVER
# define DPMS_SERVER
#endif
#include "extensions/dpms.h"

/*
 * X-to-Mach64 mix translation table.
 */
static CARD8 ATIMach64ALU[16] =
{
    MIX_0,
    MIX_AND,
    MIX_SRC_AND_NOT_DST,
    MIX_SRC,
    MIX_NOT_SRC_AND_DST,
    MIX_DST,
    MIX_XOR,
    MIX_OR,
    MIX_NOR,
    MIX_XNOR,
    MIX_NOT_DST,
    MIX_SRC_OR_NOT_DST,
    MIX_NOT_SRC,
    MIX_NOT_SRC_OR_DST,
    MIX_NAND,
    MIX_1
};

/*
 * ATIMach64PreInit --
 *
 * This function fills in the Mach64 portion of an ATIHWRec that is common to
 * all video modes generated by the driver.
 */
void
ATIMach64PreInit
(
    ScrnInfoPtr pScreenInfo,
    ATIPtr      pATI,
    ATIHWPtr    pATIHW
)
{
    CARD32 bus_cntl, config_cntl;
    int    tmp;

#ifndef AVOID_CPIO

    if (pATI->depth <= 4)
        pATIHW->crtc_off_pitch = SetBits(pATI->displayWidth >> 4, CRTC_PITCH);
    else

#endif /* AVOID_CPIO */

    {
        pATIHW->crtc_off_pitch = SetBits(pATI->displayWidth >> 3, CRTC_PITCH);
    }

    bus_cntl = inr(BUS_CNTL);
    pATIHW->bus_cntl = (bus_cntl & ~BUS_HOST_ERR_INT_EN) | BUS_HOST_ERR_INT;
    if (pATI->Chip < ATI_CHIP_264VTB)
    {
        pATIHW->bus_cntl &= ~(BUS_FIFO_ERR_INT_EN | BUS_ROM_DIS);
        pATIHW->bus_cntl |= SetBits(15, BUS_FIFO_WS) | BUS_FIFO_ERR_INT;
    }
    else
        pATIHW->bus_cntl |= BUS_APER_REG_DIS;
    if (pATI->Chip >= ATI_CHIP_264VT)
        pATIHW->bus_cntl |= BUS_EXT_REG_EN;     /* Enable Block 1 */

#ifdef AVOID_CPIO

    pATIHW->mem_vga_wp_sel = SetBits(0, MEM_VGA_WPS0) |
        SetBits(1, MEM_VGA_WPS1);
    pATIHW->mem_vga_rp_sel = SetBits(0, MEM_VGA_RPS0) |
        SetBits(1, MEM_VGA_RPS1);

#else /* AVOID_CPIO */

    pATIHW->mem_vga_wp_sel = SetBits(0, MEM_VGA_WPS0) |
        SetBits(pATIHW->nPlane, MEM_VGA_WPS1);
    pATIHW->mem_vga_rp_sel = SetBits(0, MEM_VGA_RPS0) |
        SetBits(pATIHW->nPlane, MEM_VGA_RPS1);

#endif /* AVOID_CPIO */

    pATIHW->dac_cntl = inr(DAC_CNTL) &
        ~(DAC1_CLK_SEL | DAC_PALETTE_ACCESS_CNTL | DAC_8BIT_EN);
    if ((pATI->depth > 8) || (pScreenInfo->rgbBits == 8))
        pATIHW->dac_cntl |= DAC_8BIT_EN;

    pATIHW->config_cntl = config_cntl = inr(CONFIG_CNTL);

#ifndef AVOID_CPIO

    if (pATI->UseSmallApertures)
        pATIHW->config_cntl |= CFG_MEM_VGA_AP_EN;
    else

#endif /* AVOID_CPIO */

    {
        pATIHW->config_cntl &= ~CFG_MEM_VGA_AP_EN;
    }

    if (pATI->LinearBase && (pATI->Chip < ATI_CHIP_264CT))
    {
        /* Replace linear aperture size and address */
        pATIHW->config_cntl &= ~(CFG_MEM_AP_LOC | CFG_MEM_AP_SIZE);
        pATIHW->config_cntl |= SetBits(pATI->LinearBase >> 22, CFG_MEM_AP_LOC);
        if ((pATI->Chip < ATI_CHIP_264CT) && (pATI->VideoRAM < 4096))
            pATIHW->config_cntl |= SetBits(1, CFG_MEM_AP_SIZE);
        else
            pATIHW->config_cntl |= SetBits(2, CFG_MEM_AP_SIZE);
    }

    /* Draw engine setup */
    if (pATI->OptionAccel)
    {
        /* Ensure apertures are enabled */
        outr(BUS_CNTL, pATIHW->bus_cntl);
        outr(CONFIG_CNTL, pATIHW->config_cntl);

        /*
         * When possible, max out command FIFO size.
         */
        if (pATI->Chip >= ATI_CHIP_264VT4)
            pATIHW->gui_cntl = inm(GUI_CNTL) & ~CMDFIFO_SIZE_MODE;

        /* Initialise destination registers */
        pATIHW->dst_off_pitch =
            SetBits((pATI->displayWidth * pATI->XModifier) >> 3, DST_PITCH);
        pATIHW->dst_cntl = DST_X_DIR | DST_Y_DIR | DST_LAST_PEL;

        /* Initialise source registers */
        pATIHW->src_off_pitch = pATIHW->dst_off_pitch;
        pATIHW->src_width1 = pATIHW->src_height1 =
            pATIHW->src_width2 = pATIHW->src_height2 = 1;
        pATIHW->src_cntl = SRC_LINE_X_DIR;

        /* Initialise scissor, allowing for offscreen areas */
        pATIHW->sc_right = (pATI->displayWidth * pATI->XModifier) - 1;
        tmp = (pScreenInfo->videoRam * (1024 * 8) /
            pATI->displayWidth / pATI->bitsPerPixel) - 1;
        if (tmp > ATIMach64MaxY)
            tmp = ATIMach64MaxY;
        pATIHW->sc_bottom = tmp;
        pATI->sc_left_right = SetWord(pATI->NewHW.sc_right, 1) |
            SetWord(pATI->NewHW.sc_left, 0);
        pATI->sc_top_bottom =  SetWord(pATI->NewHW.sc_bottom, 1) |
            SetWord(pATI->NewHW.sc_top, 0);

        /* Initialise data path */
        pATIHW->dp_frgd_clr = (CARD32)(-1);
        pATIHW->dp_write_mask = (CARD32)(-1);

        switch (pATI->depth)
        {
            case 8:
                pATIHW->dp_chain_mask = DP_CHAIN_8BPP;
                pATIHW->dp_pix_width = DP_BYTE_PIX_ORDER |
                    SetBits(PIX_WIDTH_8BPP, DP_DST_PIX_WIDTH) |
                    SetBits(PIX_WIDTH_8BPP, DP_SRC_PIX_WIDTH) |
                    SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
                break;

            case 15:
                pATIHW->dp_chain_mask = DP_CHAIN_15BPP_1555;
                pATIHW->dp_pix_width = DP_BYTE_PIX_ORDER |
                    SetBits(PIX_WIDTH_15BPP, DP_DST_PIX_WIDTH) |
                    SetBits(PIX_WIDTH_15BPP, DP_SRC_PIX_WIDTH) |
                    SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
                break;

            case 16:
                pATIHW->dp_chain_mask = DP_CHAIN_16BPP_565;
                pATIHW->dp_pix_width = DP_BYTE_PIX_ORDER |
                    SetBits(PIX_WIDTH_16BPP, DP_DST_PIX_WIDTH) |
                    SetBits(PIX_WIDTH_16BPP, DP_SRC_PIX_WIDTH) |
                    SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
                break;

            case 24:
                if (pATI->bitsPerPixel == 24)
                {
                    pATIHW->dp_chain_mask = DP_CHAIN_24BPP_888;
                    pATIHW->dp_pix_width = DP_BYTE_PIX_ORDER |
                        SetBits(PIX_WIDTH_8BPP, DP_DST_PIX_WIDTH) |
                        SetBits(PIX_WIDTH_8BPP, DP_SRC_PIX_WIDTH) |
                        SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
                }
                else
                {
                    pATIHW->dp_chain_mask = DP_CHAIN_32BPP_8888;
                    pATIHW->dp_pix_width = DP_BYTE_PIX_ORDER |
                        SetBits(PIX_WIDTH_32BPP, DP_DST_PIX_WIDTH) |
                        SetBits(PIX_WIDTH_32BPP, DP_SRC_PIX_WIDTH) |
                        SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH);
                }
                break;

            default:
                break;
        }

        pATIHW->dp_mix = SetBits(MIX_SRC, DP_FRGD_MIX) |
            SetBits(MIX_DST, DP_BKGD_MIX);
        pATIHW->dp_src = DP_MONO_SRC_ALLONES |
            SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC);

        /* Initialise colour compare */
        pATIHW->clr_cmp_msk = (1 << pATI->depth) - 1;

        /* Restore aperture enablement */
        outr(BUS_CNTL, bus_cntl);
        outr(CONFIG_CNTL, config_cntl);
    }
}

/*
 * ATIMach64Save --
 *
 * This function is called to save the Mach64 portion of the current video
 * state.
 */
void
ATIMach64Save
(
    ATIPtr      pATI,
    ATIHWPtr    pATIHW
)
{
    pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP);
    pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID);
    pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP);
    pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID);

    pATIHW->crtc_off_pitch = inr(CRTC_OFF_PITCH);

    pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL);

    pATIHW->ovr_clr = inr(OVR_CLR);
    pATIHW->ovr_wid_left_right = inr(OVR_WID_LEFT_RIGHT);
    pATIHW->ovr_wid_top_bottom = inr(OVR_WID_TOP_BOTTOM);

    pATIHW->clock_cntl = inr(CLOCK_CNTL);

    pATIHW->bus_cntl = inr(BUS_CNTL);

    pATIHW->mem_vga_wp_sel = inr(MEM_VGA_WP_SEL);
    pATIHW->mem_vga_rp_sel = inr(MEM_VGA_RP_SEL);

    pATIHW->dac_cntl = inr(DAC_CNTL);

    pATIHW->config_cntl = inr(CONFIG_CNTL);

    /* Save draw engine state */
    if (pATI->OptionAccel && (pATIHW == &pATI->OldHW))
    {
        /* Ensure apertures are enabled */
        outr(BUS_CNTL, pATI->NewHW.bus_cntl);
        outr(CONFIG_CNTL, pATI->NewHW.config_cntl);

        ATIMach64WaitForIdle(pATI);

        /* Save FIFO size */
        if (pATI->Chip >= ATI_CHIP_264VT4)
            pATIHW->gui_cntl = inm(GUI_CNTL);

        /* Save destination registers */
        pATIHW->dst_off_pitch = inm(DST_OFF_PITCH);
        pATIHW->dst_x = inm(DST_X);
        pATIHW->dst_y = inm(DST_Y);
        pATIHW->dst_height = inm(DST_HEIGHT);
        pATIHW->dst_bres_err = inm(DST_BRES_ERR);
        pATIHW->dst_bres_inc = inm(DST_BRES_INC);
        pATIHW->dst_bres_dec = inm(DST_BRES_DEC);
        pATIHW->dst_cntl = inm(DST_CNTL);

        /* Save source registers */
        pATIHW->src_off_pitch = inm(SRC_OFF_PITCH);
        pATIHW->src_x = inm(SRC_X);
        pATIHW->src_y = inm(SRC_Y);
        pATIHW->src_width1 = inm(SRC_WIDTH1);
        pATIHW->src_height1 = inm(SRC_HEIGHT1);
        pATIHW->src_x_start = inm(SRC_X_START);
        pATIHW->src_y_start = inm(SRC_Y_START);
        pATIHW->src_width2 = inm(SRC_WIDTH2);
        pATIHW->src_height2 = inm(SRC_HEIGHT2);
        pATIHW->src_cntl = inm(SRC_CNTL);

        /* Save host data register */
        pATIHW->host_cntl = inm(HOST_CNTL);

        /* Save pattern registers */
        pATIHW->pat_reg0 = inm(PAT_REG0);
        pATIHW->pat_reg1 = inm(PAT_REG1);
        pATIHW->pat_cntl = inm(PAT_CNTL);

        /* Save scissor registers */
        pATIHW->sc_left = pATI->sc_left = inm(SC_LEFT);
        pATIHW->sc_right = pATI->sc_right = inm(SC_RIGHT);
        pATIHW->sc_top = pATI->sc_top = inm(SC_TOP);
        pATIHW->sc_bottom = pATI->sc_bottom = inm(SC_BOTTOM);

        /* Save data path registers */
        pATIHW->dp_bkgd_clr = inm(DP_BKGD_CLR);
        pATIHW->dp_frgd_clr = inm(DP_FRGD_CLR);
        pATIHW->dp_write_mask = inm(DP_WRITE_MASK);
        pATIHW->dp_chain_mask = inm(DP_CHAIN_MASK);
        pATIHW->dp_pix_width = inm(DP_PIX_WIDTH);
        pATIHW->dp_mix = inm(DP_MIX);
        pATIHW->dp_src = inm(DP_SRC);

        /* Save colour compare registers */
        pATIHW->clr_cmp_clr = inm(CLR_CMP_CLR);
        pATIHW->clr_cmp_msk = inm(CLR_CMP_MSK);
        pATIHW->clr_cmp_cntl = inm(CLR_CMP_CNTL);

        /* Save context */
        pATIHW->context_mask = inm(CONTEXT_MASK);

        /* Restore aperture enablement */
        outr(BUS_CNTL, pATIHW->bus_cntl);
        outr(CONFIG_CNTL, pATIHW->config_cntl);
    }
}

/*
 * ATIMach64Calculate --
 *
 * This function is called to fill in the Mach64 portion of an ATIHWRec.
 */
void
ATIMach64Calculate
(
    ATIPtr         pATI,
    ATIHWPtr       pATIHW,
    DisplayModePtr pMode
)
{
    int VDisplay;

    /* If not already done adjust horizontal timings */
    if (!pMode->CrtcHAdjusted)
    {
        pMode->CrtcHAdjusted = TRUE;
        /* XXX Deal with Blank Start/End and overscan later */
        pMode->CrtcHDisplay = (pMode->HDisplay >> 3) - 1;
        pMode->CrtcHSyncStart = (pMode->HSyncStart >> 3) - 1;
        pMode->CrtcHSyncEnd = (pMode->HSyncEnd >> 3) - 1;
        pMode->CrtcHTotal = (pMode->HTotal >> 3) - 1;

        /* Make adjustments if sync pulse width is out-of-bounds */
        if ((pMode->CrtcHSyncEnd - pMode->CrtcHSyncStart) >
            (int)MaxBits(CRTC_H_SYNC_WID))
            pMode->CrtcHSyncEnd =
                pMode->CrtcHSyncStart + MaxBits(CRTC_H_SYNC_WID);
        else if (pMode->CrtcHSyncStart == pMode->CrtcHSyncEnd)
        {
            if (pMode->CrtcHDisplay < pMode->CrtcHSyncStart)
                pMode->CrtcHSyncStart--;
            else if (pMode->CrtcHSyncEnd < pMode->CrtcHTotal)
                pMode->CrtcHSyncEnd++;
        }
    }

    /*
     * Always re-do vertical adjustments.
     */
    pMode->CrtcVDisplay = pMode->VDisplay;
    pMode->CrtcVSyncStart = pMode->VSyncStart;
    pMode->CrtcVSyncEnd = pMode->VSyncEnd;
    pMode->CrtcVTotal = pMode->VTotal;

    if ((pATI->Chip >= ATI_CHIP_264CT) &&
        ((pMode->Flags & V_DBLSCAN) || (pMode->VScan > 1)))
    {
        pMode->CrtcVDisplay <<= 1;
        pMode->CrtcVSyncStart <<= 1;
        pMode->CrtcVSyncEnd <<= 1;
        pMode->CrtcVTotal <<= 1;
    }

    /*
     * Might as well default to the same as VGA with respect to sync
     * polarities.
     */
    if ((!(pMode->Flags & (V_PHSYNC | V_NHSYNC))) ||
        (!(pMode->Flags & (V_PVSYNC | V_NVSYNC))))
    {
        pMode->Flags &= ~(V_PHSYNC | V_NHSYNC | V_PVSYNC | V_NVSYNC);

        if (!pATI->OptionCRT && (pATI->LCDPanelID >= 0))
            VDisplay = pATI->LCDVertical;
        else
            VDisplay = pMode->CrtcVDisplay;

        if (VDisplay < 400)
            pMode->Flags |= V_PHSYNC | V_NVSYNC;
        else if (VDisplay < 480)
            pMode->Flags |= V_NHSYNC | V_PVSYNC;
        else if (VDisplay < 768)
            pMode->Flags |= V_NHSYNC | V_NVSYNC;
        else
            pMode->Flags |= V_PHSYNC | V_PVSYNC;
    }

    pMode->CrtcVDisplay--;
    pMode->CrtcVSyncStart--;
    pMode->CrtcVSyncEnd--;
    pMode->CrtcVTotal--;
    /* Make sure sync pulse is not too wide */
    if ((pMode->CrtcVSyncEnd - pMode->CrtcVSyncStart) >
         (int)MaxBits(CRTC_V_SYNC_WID))
        pMode->CrtcVSyncEnd = pMode->CrtcVSyncStart + MaxBits(CRTC_V_SYNC_WID);
    pMode->CrtcVAdjusted = TRUE;                /* Redundant */

    /* Build register contents */
    pATIHW->crtc_h_total_disp =
        SetBits(pMode->CrtcHTotal, CRTC_H_TOTAL) |
            SetBits(pMode->CrtcHDisplay, CRTC_H_DISP);
    pATIHW->crtc_h_sync_strt_wid =
        SetBits(pMode->CrtcHSyncStart, CRTC_H_SYNC_STRT) |
            SetBits(pMode->CrtcHSkew, CRTC_H_SYNC_DLY) |         /* ? */
            SetBits(GetBits(pMode->CrtcHSyncStart, 0x0100U),
                CRTC_H_SYNC_STRT_HI) |
            SetBits(pMode->CrtcHSyncEnd - pMode->CrtcHSyncStart,
                CRTC_H_SYNC_WID);
    if (pMode->Flags & V_NHSYNC)
        pATIHW->crtc_h_sync_strt_wid |= CRTC_H_SYNC_POL;

    pATIHW->crtc_v_total_disp =
        SetBits(pMode->CrtcVTotal, CRTC_V_TOTAL) |
            SetBits(pMode->CrtcVDisplay, CRTC_V_DISP);
    pATIHW->crtc_v_sync_strt_wid =
        SetBits(pMode->CrtcVSyncStart, CRTC_V_SYNC_STRT) |
            SetBits(pMode->CrtcVSyncEnd - pMode->CrtcVSyncStart,
                CRTC_V_SYNC_WID);
    if (pMode->Flags & V_NVSYNC)
        pATIHW->crtc_v_sync_strt_wid |= CRTC_V_SYNC_POL;

    pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL) &
        ~(CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN |
          CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_CSYNC_EN |
          CRTC_PIX_BY_2_EN | CRTC_DISPLAY_DIS | CRTC_VGA_XOVERSCAN |
          CRTC_PIX_WIDTH | CRTC_BYTE_PIX_ORDER | CRTC_FIFO_LWM |
          CRTC_VGA_128KAP_PAGING | CRTC_VFC_SYNC_TRISTATE |
          CRTC_LOCK_REGS |              /* Already off, but ... */
          CRTC_SYNC_TRISTATE | CRTC_DISP_REQ_EN |
          CRTC_VGA_TEXT_132 | CRTC_CUR_B_TEST);
    pATIHW->crtc_gen_cntl |=
        CRTC_EXT_DISP_EN | CRTC_EN | CRTC_VGA_LINEAR | CRTC_CNT_EN;
    switch (pATI->depth)
    {

#ifndef AVOID_CPIO

        case 1:
            pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_1BPP, CRTC_PIX_WIDTH);
            break;

        case 4:
            pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_4BPP, CRTC_PIX_WIDTH);
            break;

#endif /* AVOID_CPIO */

        case 8:
            pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_8BPP, CRTC_PIX_WIDTH);
            break;

        case 15:
            pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_15BPP, CRTC_PIX_WIDTH);
            break;

        case 16:
            pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_16BPP, CRTC_PIX_WIDTH);
            break;

        case 24:
            if (pATI->bitsPerPixel == 24)
            {
                pATIHW->crtc_gen_cntl |=
                    SetBits(PIX_WIDTH_24BPP, CRTC_PIX_WIDTH);
                break;
            }
            if (pATI->bitsPerPixel != 32)
                break;
            /* Fall through */

        case 32:
            pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_32BPP, CRTC_PIX_WIDTH);
            break;

        default:
            break;
    }
    if ((pMode->Flags & V_DBLSCAN) || (pMode->VScan > 1))
        pATIHW->crtc_gen_cntl |= CRTC_DBL_SCAN_EN;
    if (pMode->Flags & V_INTERLACE)
        pATIHW->crtc_gen_cntl |= CRTC_INTERLACE_EN;
    if (pATI->OptionCSync || (pMode->Flags & (V_CSYNC | V_PCSYNC)))
        pATIHW->crtc_gen_cntl |= CRTC_CSYNC_EN;
    /* For now, set display FIFO low water mark as high as possible */
    if (pATI->Chip < ATI_CHIP_264VTB)
        pATIHW->crtc_gen_cntl |= CRTC_FIFO_LWM;
}

/*
 * ATIMach64Set --
 *
 * This function is called to load a Mach64's accelerator CRTC and draw engine.
 */
void
ATIMach64Set
(
    ATIPtr      pATI,
    ATIHWPtr    pATIHW
)
{
    /* First, turn off the display */
    outr(CRTC_GEN_CNTL, pATIHW->crtc_gen_cntl & ~CRTC_EN);

    if ((pATIHW->FeedbackDivider > 0) &&
        (pATI->ProgrammableClock != ATI_CLOCK_NONE))
        ATIClockSet(pATI, pATIHW);              /* Programme clock */

    /* Load Mach64 CRTC registers */
    outr(CRTC_H_TOTAL_DISP, pATIHW->crtc_h_total_disp);
    outr(CRTC_H_SYNC_STRT_WID, pATIHW->crtc_h_sync_strt_wid);
    outr(CRTC_V_TOTAL_DISP, pATIHW->crtc_v_total_disp);
    outr(CRTC_V_SYNC_STRT_WID, pATIHW->crtc_v_sync_strt_wid);

    outr(CRTC_OFF_PITCH, pATIHW->crtc_off_pitch);

    /* Set pixel clock */
    outr(CLOCK_CNTL, pATIHW->clock_cntl | CLOCK_STROBE);

    /* Load overscan registers */
    outr(OVR_CLR, pATIHW->ovr_clr);
    outr(OVR_WID_LEFT_RIGHT, pATIHW->ovr_wid_left_right);
    outr(OVR_WID_TOP_BOTTOM, pATIHW->ovr_wid_top_bottom);

    /* Finalise CRTC setup and turn on the screen */
    outr(CRTC_GEN_CNTL, pATIHW->crtc_gen_cntl);

    /* Load draw engine */
    if (pATI->OptionAccel)
    {
        /* Clobber MMIO cache */
        (void)memset(pATI->MMIOCached, 0, SizeOf(pATI->MMIOCached));

        /* Ensure apertures are enabled */
        outr(BUS_CNTL, pATI->NewHW.bus_cntl);
        outr(CONFIG_CNTL, pATI->NewHW.config_cntl);

        pATI->EngineIsBusy = TRUE;      /* Force engine poll */
        ATIMach64WaitForIdle(pATI);

        /* Load FIFO size */
        if (pATI->Chip >= ATI_CHIP_264VT4)
        {
            outm(GUI_CNTL, pATIHW->gui_cntl);
            pATI->nAvailableFIFOEntries = 0;
            ATIMach64PollEngineStatus(pATI);
        }

        /* Set FIFO depth */
        pATI->nFIFOEntries = pATI->nAvailableFIFOEntries;

        /* Load destination registers */
        ATIMach64WaitForFIFO(pATI, 7);
        outf(DST_OFF_PITCH, pATIHW->dst_off_pitch);
        outf(DST_Y_X, SetWord(pATIHW->dst_x, 1) | SetWord(pATIHW->dst_y, 0));
        outf(DST_HEIGHT, pATIHW->dst_height);
        outf(DST_BRES_ERR, pATIHW->dst_bres_err);
        outf(DST_BRES_INC, pATIHW->dst_bres_inc);
        outf(DST_BRES_DEC, pATIHW->dst_bres_dec);
        outf(DST_CNTL, pATIHW->dst_cntl);

        /* Load source registers */
        ATIMach64WaitForFIFO(pATI, 6);
        outf(SRC_OFF_PITCH, pATIHW->src_off_pitch);
        outf(SRC_Y_X, SetWord(pATIHW->src_x, 1) | SetWord(pATIHW->src_y, 0));
        outf(SRC_HEIGHT1_WIDTH1,
            SetWord(pATIHW->src_width1, 1) | SetWord(pATIHW->src_height1, 0));
        outf(SRC_Y_X_START,
            SetWord(pATIHW->src_x_start, 1) | SetWord(pATIHW->src_y_start, 0));
        outf(SRC_HEIGHT2_WIDTH2,
            SetWord(pATIHW->src_width2, 1) | SetWord(pATIHW->src_height2, 0));
        outf(SRC_CNTL, pATIHW->src_cntl);

        /* Load host data register */
        ATIMach64WaitForFIFO(pATI, 1);
        outf(HOST_CNTL, pATIHW->host_cntl);

        /* Set host transfer window address and size clamp */
        pATI->pHOST_DATA =
            (CARD8 *)pATI->pBlock[GetBits(HOST_DATA_0, BLOCK_SELECT)] +
            (HOST_DATA_0 & MM_IO_SELECT);
        pATI->nHostFIFOEntries = pATI->nFIFOEntries >> 1;
        if (pATI->nHostFIFOEntries > 16)
            pATI->nHostFIFOEntries = 16;

        /* Load pattern registers */
        ATIMach64WaitForFIFO(pATI, 3);
        outf(PAT_REG0, pATIHW->pat_reg0);
        outf(PAT_REG1, pATIHW->pat_reg1);
        outf(PAT_CNTL, pATIHW->pat_cntl);

        /* Load scissor registers */
        ATIMach64WaitForFIFO(pATI, 2);
        outf(SC_LEFT_RIGHT,
            SetWord(pATIHW->sc_right, 1) | SetWord(pATIHW->sc_left, 0));
        outf(SC_TOP_BOTTOM,
            SetWord(pATIHW->sc_bottom, 1) | SetWord(pATIHW->sc_top, 0));
        pATI->sc_left = pATIHW->sc_left;
        pATI->sc_right = pATIHW->sc_right;
        pATI->sc_top = pATIHW->sc_top;
        pATI->sc_bottom = pATIHW->sc_bottom;

        /* Load data path registers */
        ATIMach64WaitForFIFO(pATI, 7);
        outf(DP_BKGD_CLR, pATIHW->dp_bkgd_clr);
        outf(DP_FRGD_CLR, pATIHW->dp_frgd_clr);
        outf(DP_WRITE_MASK, pATIHW->dp_write_mask);
        outf(DP_CHAIN_MASK, pATIHW->dp_chain_mask);
        outf(DP_PIX_WIDTH, pATIHW->dp_pix_width);
        outf(DP_MIX, pATIHW->dp_mix);
        outf(DP_SRC, pATIHW->dp_src);

        /* Load colour compare registers */
        ATIMach64WaitForFIFO(pATI, 3);
        outf(CLR_CMP_CLR, pATIHW->clr_cmp_clr);
        outf(CLR_CMP_MSK, pATIHW->clr_cmp_msk);
        outf(CLR_CMP_CNTL, pATIHW->clr_cmp_cntl);

        /* Load context mask */
        ATIMach64WaitForFIFO(pATI, 1);
        outf(CONTEXT_MASK, pATIHW->context_mask);

        ATIMach64WaitForIdle(pATI);

        if (pATI->OptionMMIOCache)
        {
            /*
             * Enable write caching for selected MMIO registers.  This can only
             * be done for those registers whose value does not change without
             * driver intervention.
             */

            CacheRegister(SRC_CNTL);

            CacheRegister(HOST_CNTL);

            CacheRegister(PAT_REG0);
            CacheRegister(PAT_REG1);
            CacheRegister(PAT_CNTL);

            CacheRegister(SC_LEFT_RIGHT);
            CacheRegister(SC_TOP_BOTTOM);

            CacheRegister(DP_BKGD_CLR);
            CacheRegister(DP_FRGD_CLR);
            CacheRegister(DP_WRITE_MASK);
            CacheRegister(DP_MIX);

            CacheRegister(CLR_CMP_CLR);
            CacheRegister(CLR_CMP_MSK);
            CacheRegister(CLR_CMP_CNTL);
        }
    }

    /* Aperture setup */
    outr(MEM_VGA_WP_SEL, pATIHW->mem_vga_wp_sel);
    outr(MEM_VGA_RP_SEL, pATIHW->mem_vga_rp_sel);

    outr(DAC_CNTL, pATIHW->dac_cntl);

    outr(CONFIG_CNTL, pATIHW->config_cntl);
    outr(BUS_CNTL, pATIHW->bus_cntl);
}

/*
 * ATIMach64SaveScreen --
 *
 * This function blanks or unblanks a Mach64 screen.
 */
void
ATIMach64SaveScreen
(
    ATIPtr pATI,
    int    Mode
)
{
    CARD32 crtc_gen_cntl = inr(CRTC_GEN_CNTL);

    switch (Mode)
    {
        case SCREEN_SAVER_OFF:
        case SCREEN_SAVER_FORCER:
            outr(CRTC_GEN_CNTL, crtc_gen_cntl & ~CRTC_DISPLAY_DIS);
            break;

        case SCREEN_SAVER_ON:
        case SCREEN_SAVER_CYCLE:
            outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_DISPLAY_DIS);
            break;

        default:
            break;
    }
}

/*
 * ATIMach64SetDPMSMode --
 *
 * This function sets a Mach64's VESA Display Power Management Signaling mode.
 */
void
ATIMach64SetDPMSMode
(
    ATIPtr pATI,
    int    DPMSMode
)
{
    CARD32 crtc_gen_cntl =
        inr(CRTC_GEN_CNTL) & ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS);

    switch (DPMSMode)
    {
        case DPMSModeOn:        /* HSync on, VSync on */
            break;

        case DPMSModeStandby:   /* HSync off, VSync on */
            crtc_gen_cntl |= CRTC_HSYNC_DIS;
            break;

        case DPMSModeSuspend:   /* HSync on, VSync off */
            crtc_gen_cntl |= CRTC_VSYNC_DIS;
            break;

        case DPMSModeOff:       /* HSync off, VSync off */
            crtc_gen_cntl |= CRTC_HSYNC_DIS | CRTC_VSYNC_DIS;
            break;

        default:                /* Muffle compiler */
            return;
    }

    outr(CRTC_GEN_CNTL, crtc_gen_cntl);

    if ((pATI->LCDPanelID >= 0) && !pATI->OptionCRT)
    {
        CARD32 lcd_index = 0;

        /*
         * ATI's BIOS simply turns the panel on and off, so do the same by
         * default, but keep the previous behaviour around for reference.
         */
        if (pATI->OptionDevel)
        {
            CARD32 power_management;

            if (pATI->Chip == ATI_CHIP_264LT)
                power_management = inr(POWER_MANAGEMENT);
            else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
                        (pATI->Chip == ATI_CHIP_264XL) ||
                        (pATI->Chip == ATI_CHIP_MOBILITY)) */
            {
                lcd_index = inr(LCD_INDEX);
                power_management = ATIGetMach64LCDReg(LCD_POWER_MANAGEMENT);
            }

            power_management &= ~(STANDBY_NOW | SUSPEND_NOW);

            switch (DPMSMode)
            {
                case DPMSModeOn:
                    break;

                case DPMSModeStandby:
                    power_management |= STANDBY_NOW;
                    break;

                case DPMSModeSuspend:
                    power_management |= SUSPEND_NOW;
                    break;

                case DPMSModeOff:
                    power_management |= STANDBY_NOW | SUSPEND_NOW;  /* ? */
                    break;

                default:        /* Muffle compiler */
                    return;
            }

            /* Panel power management seems to involve the engine */
            if (pATI->OptionAccel)
                ATIMach64WaitForIdle(pATI);

            if (pATI->Chip == ATI_CHIP_264LT)
                outr(POWER_MANAGEMENT, power_management);
            else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
                        (pATI->Chip == ATI_CHIP_264XL) ||
                        (pATI->Chip == ATI_CHIP_MOBILITY)) */
            {
                ATIPutMach64LCDReg(LCD_POWER_MANAGEMENT, power_management);
                outr(LCD_INDEX, lcd_index);
            }
        }
        else
        {
            CARD32 lcd_gen_ctrl;

            if (pATI->Chip == ATI_CHIP_264LT)
                lcd_gen_ctrl = inr(LCD_GEN_CTRL);
            else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
                        (pATI->Chip == ATI_CHIP_264XL) ||
                        (pATI->Chip == ATI_CHIP_MOBILITY)) */
            {
                lcd_index = inr(LCD_INDEX);
                lcd_gen_ctrl = ATIGetMach64LCDReg(LCD_GEN_CNTL);
            }

            if (DPMSMode == DPMSModeOn)
                lcd_gen_ctrl |= LCD_ON;
            else
                lcd_gen_ctrl &= ~LCD_ON;

            if (pATI->Chip == ATI_CHIP_264LT)
                outr(LCD_GEN_CTRL, lcd_gen_ctrl);
            else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) ||
                        (pATI->Chip == ATI_CHIP_264XL) ||
                        (pATI->Chip == ATI_CHIP_MOBILITY)) */
            {
                ATIPutMach64LCDReg(LCD_GEN_CNTL, lcd_gen_ctrl);
                outr(LCD_INDEX, lcd_index);
            }
        }
    }
}

/*
 * ATIMach64ValidateClip --
 *
 * This function ensures the current scissor settings do not interfere with
 * the current draw request.
 */
static void
ATIMach64ValidateClip
(
    ATIPtr pATI,
    int    sc_left,
    int    sc_right,
    int    sc_top,
    int    sc_bottom
)
{
    if ((sc_left < (int)pATI->sc_left) || (sc_right > (int)pATI->sc_right))
    {
        outf(SC_LEFT_RIGHT, pATI->sc_left_right);
        pATI->sc_left = pATI->NewHW.sc_left;
        pATI->sc_right = pATI->NewHW.sc_right;
    }

    if ((sc_top < (int)pATI->sc_top) || (sc_bottom > (int)pATI->sc_bottom))
    {
        outf(SC_TOP_BOTTOM, pATI->sc_top_bottom);
        pATI->sc_top = pATI->NewHW.sc_top;
        pATI->sc_bottom = pATI->NewHW.sc_bottom;
    }
}

/*
 * ATIMach64Sync --
 *
 * This is called to wait for the draw engine to become idle.
 */
static void
ATIMach64Sync
(
    ScrnInfoPtr pScreenInfo
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    ATIMach64WaitForIdle(pATI);

    if (pATI->OptionMMIOCache)
    {
        /*
         * For debugging purposes, attempt to verify that each cached register
         * should actually be cached.
         */
        if (RegisterIsCached(SRC_CNTL) &&
            (CacheSlot(SRC_CNTL) != inm(SRC_CNTL)))
        {
            UncacheRegister(SRC_CNTL);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "SRC_CNTL write cache disabled!\n");
        }

        if (RegisterIsCached(HOST_CNTL) &&
            (CacheSlot(HOST_CNTL) != inm(HOST_CNTL)))
        {
            UncacheRegister(HOST_CNTL);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "HOST_CNTL write cache disabled!\n");
        }

        if (RegisterIsCached(PAT_REG0) &&
            (CacheSlot(PAT_REG0) != inm(PAT_REG0)))
        {
            UncacheRegister(PAT_REG0);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "PAT_REG0 write cache disabled!\n");
        }

        if (RegisterIsCached(PAT_REG1) &&
            (CacheSlot(PAT_REG1) != inm(PAT_REG1)))
        {
            UncacheRegister(PAT_REG1);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "PAT_REG1 write cache disabled!\n");
        }

        if (RegisterIsCached(PAT_CNTL) &&
            (CacheSlot(PAT_CNTL) != inm(PAT_CNTL)))
        {
            UncacheRegister(PAT_CNTL);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "PAT_CNTL write cache disabled!\n");
        }

        if (RegisterIsCached(SC_LEFT_RIGHT) &&
            (CacheSlot(SC_LEFT_RIGHT) !=
             (SetWord(inm(SC_RIGHT), 1) | SetWord(inm(SC_LEFT), 0))))
        {
            UncacheRegister(SC_LEFT_RIGHT);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "SC_LEFT_RIGHT write cache disabled!\n");
        }

        if (RegisterIsCached(SC_TOP_BOTTOM) &&
            (CacheSlot(SC_TOP_BOTTOM) !=
             (SetWord(inm(SC_BOTTOM), 1) | SetWord(inm(SC_TOP), 0))))
        {
            UncacheRegister(SC_TOP_BOTTOM);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "SC_TOP_BOTTOM write cache disabled!\n");
        }

        if (RegisterIsCached(DP_BKGD_CLR) &&
            (CacheSlot(DP_BKGD_CLR) != inm(DP_BKGD_CLR)))
        {
            UncacheRegister(DP_BKGD_CLR);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "DP_BKGD_CLR write cache disabled!\n");
        }

        if (RegisterIsCached(DP_FRGD_CLR) &&
            (CacheSlot(DP_FRGD_CLR) != inm(DP_FRGD_CLR)))
        {
            UncacheRegister(DP_FRGD_CLR);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "DP_FRGD_CLR write cache disabled!\n");
        }

        if (RegisterIsCached(DP_WRITE_MASK) &&
            (CacheSlot(DP_WRITE_MASK) != inm(DP_WRITE_MASK)))
        {
            UncacheRegister(DP_WRITE_MASK);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "DP_WRITE_MASK write cache disabled!\n");
        }

        if (RegisterIsCached(DP_MIX) &&
            (CacheSlot(DP_MIX) != inm(DP_MIX)))
        {
            UncacheRegister(DP_MIX);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "DP_MIX write cache disabled!\n");
        }

        if (RegisterIsCached(CLR_CMP_CLR) &&
            (CacheSlot(CLR_CMP_CLR) != inm(CLR_CMP_CLR)))
        {
            UncacheRegister(CLR_CMP_CLR);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "CLR_CMP_CLR write cache disabled!\n");
        }

        if (RegisterIsCached(CLR_CMP_MSK) &&
            (CacheSlot(CLR_CMP_MSK) != inm(CLR_CMP_MSK)))
        {
            UncacheRegister(CLR_CMP_MSK);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "CLR_CMP_MSK write cache disabled!\n");
        }

        if (RegisterIsCached(CLR_CMP_CNTL) &&
            (CacheSlot(CLR_CMP_CNTL) != inm(CLR_CMP_CNTL)))
        {
            UncacheRegister(CLR_CMP_CNTL);
            xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
                "CLR_CMP_CNTL write cache disabled!\n");
        }

    }

    /*
     * For VTB's and later, the first CPU read of the framebuffer will return
     * zeroes, so do it here.  This appears to be due to some kind of engine
     * caching of framebuffer data I haven't found any way of disabling, or
     * otherwise circumventing.  Thanks to Mark Vojkovich for the suggestion.
     */
    pATI = *(volatile ATIPtr *)pATI->pMemory;
}

/*
 * ATIMach64SetupForScreenToScreenCopy --
 *
 * This function sets up the draw engine for a series of screen-to-screen copy
 * operations.
 */
static void
ATIMach64SetupForScreenToScreenCopy
(
    ScrnInfoPtr  pScreenInfo,
    int          xdir,
    int          ydir,
    int          rop,
    unsigned int planemask,
    int          TransparencyColour
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    pATI->dst_cntl = 0;

    if (ydir > 0)
        pATI->dst_cntl |= DST_Y_DIR;
    if (xdir > 0)
        pATI->dst_cntl |= DST_X_DIR;

    if (pATI->XModifier == 1)
        outf(DST_CNTL, pATI->dst_cntl);
    else
        pATI->dst_cntl |= DST_24_ROT_EN;

    ATIMach64WaitForFIFO(pATI, 3);
    outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX));
    outf(DP_WRITE_MASK, planemask);
    outf(DP_SRC, DP_MONO_SRC_ALLONES |
        SetBits(SRC_BLIT, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC));

    if (TransparencyColour == -1)
        outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE);
    else
    {
        ATIMach64WaitForFIFO(pATI, 2);
        outf(CLR_CMP_CLR, TransparencyColour);
        outf(CLR_CMP_CNTL, CLR_CMP_FN_EQUAL | CLR_CMP_SRC_2D);
    }
}

/*
 * ATIMach64SubsequentScreenToScreenCopy --
 *
 * This function performs a screen-to-screen copy operation.
 */
static void
ATIMach64SubsequentScreenToScreenCopy
(
    ScrnInfoPtr pScreenInfo,
    int         xSrc,
    int         ySrc,
    int         xDst,
    int         yDst,
    int         w,
    int         h
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    xSrc *= pATI->XModifier;
    xDst *= pATI->XModifier;
    w    *= pATI->XModifier;

    /* Disable clipping if it gets in the way */
    ATIMach64ValidateClip(pATI, xDst, xDst + w - 1, yDst, yDst + h - 1);

    if (!(pATI->dst_cntl & DST_X_DIR))
    {
        xSrc += w - 1;
        xDst += w - 1;
    }

    if (!(pATI->dst_cntl & DST_Y_DIR))
    {
        ySrc += h - 1;
        yDst += h - 1;
    }

    if (pATI->XModifier != 1)
        outf(DST_CNTL, pATI->dst_cntl | SetBits((xDst / 4) % 6, DST_24_ROT));

    ATIMach64WaitForFIFO(pATI, 4);
    outf(SRC_Y_X, SetWord(xSrc, 1) | SetWord(ySrc, 0));
    outf(SRC_WIDTH1, w);
    outf(DST_Y_X, SetWord(xDst, 1) | SetWord(yDst, 0));
    outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0));
}

/*
 * ATIMach64SetupForSolidFill --
 *
 * This function sets up the draw engine for a series of solid fills.
 */
static void
ATIMach64SetupForSolidFill
(
    ScrnInfoPtr  pScreenInfo,
    int          colour,
    int          rop,
    unsigned int planemask
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    if (pATI->XModifier == 1)
        outf(DST_CNTL, DST_X_DIR | DST_Y_DIR);

    ATIMach64WaitForFIFO(pATI, 5);
    outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX));
    outf(DP_WRITE_MASK, planemask);
    outf(DP_SRC, DP_MONO_SRC_ALLONES |
        SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC));
    outf(DP_FRGD_CLR, colour);

    outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE);
}

/*
 * ATIMach64SubsequentSolidFillRect --
 *
 * This function performs a solid rectangle fill.
 */
static void
ATIMach64SubsequentSolidFillRect
(
    ScrnInfoPtr pScreenInfo,
    int         x,
    int         y,
    int         w,
    int         h
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    if (pATI->XModifier != 1)
    {
        x *= pATI->XModifier;
        w *= pATI->XModifier;

        outf(DST_CNTL, SetBits((x / 4) % 6, DST_24_ROT) |
            (DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN));
    }

    /* Disable clipping if it gets in the way */
    ATIMach64ValidateClip(pATI, x, x + w - 1, y, y + h - 1);

    ATIMach64WaitForFIFO(pATI, 2);
    outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0));
    outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0));
}

/*
 * ATIMach64SetupForSolidLine --
 *
 * This function sets up the draw engine for a series of solid lines.  It is
 * not used for 24bpp because the engine doesn't support it.
 */
static void
ATIMach64SetupForSolidLine
(
    ScrnInfoPtr  pScreenInfo,
    int          colour,
    int          rop,
    unsigned int planemask
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    ATIMach64WaitForFIFO(pATI, 5);
    outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX));
    outf(DP_WRITE_MASK, planemask);
    outf(DP_SRC, DP_MONO_SRC_ALLONES |
        SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC));
    outf(DP_FRGD_CLR, colour);

    outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE);

    ATIMach64ValidateClip(pATI, pATI->NewHW.sc_left, pATI->NewHW.sc_right,
        pATI->NewHW.sc_top, pATI->NewHW.sc_bottom);
}

/*
 * ATIMach64SubsequentSolidHorVertLine --
 *
 * This is called to draw a solid horizontal or vertical line.  This does a
 * one-pixel wide solid fill.
 */
static void
ATIMach64SubsequentSolidHorVertLine
(
    ScrnInfoPtr pScreenInfo,
    int         x,
    int         y,
    int         len,
    int         dir
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    ATIMach64WaitForFIFO(pATI, 3);
    outf(DST_CNTL, DST_X_DIR | DST_Y_DIR);
    outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0));

    if (dir == DEGREES_0)
        outf(DST_HEIGHT_WIDTH, SetWord(len, 1) | SetWord(1, 0));
    else /* if (dir == DEGREES_270) */
        outf(DST_HEIGHT_WIDTH, SetWord(1, 1) | SetWord(len, 0));
}

/*
 * ATIMach64SubsequentSolidBresenhamLine --
 *
 * This function draws a line using the Bresenham line engine.
 */
static void
ATIMach64SubsequentSolidBresenhamLine
(
    ScrnInfoPtr pScreenInfo,
    int         x,
    int         y,
    int         major,
    int         minor,
    int         err,
    int         len,
    int         octant
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);
    CARD32 dst_cntl = DST_LAST_PEL;

    if (octant & YMAJOR)
        dst_cntl |= DST_Y_MAJOR;

    if (!(octant & XDECREASING))
        dst_cntl |= DST_X_DIR;

    if (!(octant & YDECREASING))
        dst_cntl |= DST_Y_DIR;

    ATIMach64WaitForFIFO(pATI, 6);
    outf(DST_CNTL, dst_cntl);
    outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0));
    outf(DST_BRES_ERR, minor + err);
    outf(DST_BRES_INC, minor);
    outf(DST_BRES_DEC, minor - major);
    outf(DST_BRES_LNTH, len);
}

/*
 * ATIMach64SetupForMono8x8PatternFill --
 *
 * This function sets up the draw engine for a series of 8x8 1bpp pattern
 * fills.
 */
static void
ATIMach64SetupForMono8x8PatternFill
(
    ScrnInfoPtr  pScreenInfo,
    int          patx,
    int          paty,
    int          fg,
    int          bg,
    int          rop,
    unsigned int planemask
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    if (pATI->XModifier == 1)
        outf(DST_CNTL, DST_X_DIR | DST_Y_DIR);

    if (bg == -1)
        outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) |
            SetBits(MIX_DST, DP_BKGD_MIX));
    else
    {
        ATIMach64WaitForFIFO(pATI, 2);
        outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) |
            SetBits(ATIMach64ALU[rop], DP_BKGD_MIX));
        outf(DP_BKGD_CLR, bg);
    }

    ATIMach64WaitForFIFO(pATI, 7);
    outf(DP_WRITE_MASK, planemask);
    outf(DP_SRC, DP_MONO_SRC_PATTERN |
        SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC));
    outf(DP_FRGD_CLR, fg);

    outf(PAT_REG0, patx);
    outf(PAT_REG1, paty);
    outf(PAT_CNTL, PAT_MONO_EN);

    outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE);
}

/*
 * ATIMach64SubsequentMono8x8PatternFillRect --
 *
 * This function performs an 8x8 1bpp pattern fill.
 */
static void
ATIMach64SubsequentMono8x8PatternFillRect
(
    ScrnInfoPtr pScreenInfo,
    int         patx,
    int         paty,
    int         x,
    int         y,
    int         w,
    int         h
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    if (pATI->XModifier != 1)
    {
        x *= pATI->XModifier;
        w *= pATI->XModifier;

        outf(DST_CNTL, SetBits((x / 4) % 6, DST_24_ROT) |
            (DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN));
    }

    /* Disable clipping if it gets in the way */
    ATIMach64ValidateClip(pATI, x, x + w - 1, y, y + h - 1);

    ATIMach64WaitForFIFO(pATI, 2);
    outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0));
    outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0));
}

/*
 * ATIMach64SetupForScanlineCPUToScreenColorExpandFill --
 *
 * This function sets up the engine for a series of colour expansion fills.
 */
static void
ATIMach64SetupForScanlineCPUToScreenColorExpandFill
(
    ScrnInfoPtr  pScreenInfo,
    int          fg,
    int          bg,
    int          rop,
    unsigned int planemask
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    if (pATI->XModifier == 1)
        outf(DST_CNTL, DST_X_DIR | DST_Y_DIR);

    if (bg == -1)
        outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) |
            SetBits(MIX_DST, DP_BKGD_MIX));
    else
    {
        ATIMach64WaitForFIFO(pATI, 2);
        outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) |
            SetBits(ATIMach64ALU[rop], DP_BKGD_MIX));
        outf(DP_BKGD_CLR, bg);
    }

    ATIMach64WaitForFIFO(pATI, 4);
    outf(DP_WRITE_MASK, planemask);
    outf(DP_SRC, DP_MONO_SRC_HOST |
        SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC));
    outf(DP_FRGD_CLR, fg);

    outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE);
}

/*
 * ATIMach64SubsequentScanlineCPUToScreenColorExpandFill --
 *
 * This function sets up the engine for a single colour expansion fill.
 */
static void
ATIMach64SubsequentScanlineCPUToScreenColorExpandFill
(
    ScrnInfoPtr pScreenInfo,
    int         x,
    int         y,
    int         w,
    int         h,
    int         skipleft
)
{
    ATIPtr pATI = ATIPTR(pScreenInfo);

    if (pATI->XModifier != 1)
    {
        x *= pATI->XModifier;
        w *= pATI->XModifier;
        skipleft *= pATI->XModifier;

        outf(DST_CNTL, SetBits((x / 4) % 6, DST_24_ROT) |
            (DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN));
    }

    pATI->ExpansionBitmapWidth = (w + 31) / 32;

    ATIMach64WaitForFIFO(pATI, 3);
    pATI->sc_left = x + skipleft;
    pATI->sc_right = x + w - 1;
    outf(SC_LEFT_RIGHT,
        SetWord(pATI->sc_right, 1) | SetWord(pATI->sc_left, 0));
    outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0));
    outf(DST_HEIGHT_WIDTH,
        SetWord(pATI->ExpansionBitmapWidth * 32, 1) | SetWord(h, 0));
}

/*
 * ATIMach64SubsequentColorExpandScanline --
 *
 * This function feeds a bitmap scanline to the engine for a colour expansion
 * fill.  This is written to do burst transfers for those platforms that can do
 * them, and to improve CPU/engine concurrency.
 */
static void
ATIMach64SubsequentColorExpandScanline
(
    ScrnInfoPtr pScreenInfo,
    int         iBuffer
)
{
    ATIPtr       pATI         = ATIPTR(pScreenInfo);
    CARD32       *pBitmapData = pATI->ExpansionBitmapScanlinePtr[iBuffer];
    CARD32       *pDst, *pSrc;
    int          w            = pATI->ExpansionBitmapWidth;
    int          nDWord;
    unsigned int iDWord;

    while (w > 0)
    {
        /*
         * Transfers are done in chunks of up to 64 bytes in length (32 on
         * earlier controllers).
         */
        nDWord = w;
        if (nDWord > pATI->nHostFIFOEntries)
            nDWord = pATI->nHostFIFOEntries;

        /* Make enough FIFO slots available */
        ATIMach64WaitForFIFO(pATI, nDWord);

        /*
         * Always start transfers on a chuck-sized boundary.  Note that
         * HOST_DATA_0 is actually on a 512-byte boundary, but *pBitmapData can
         * only be guaranteed to be on a chunk-sized boundary.
         */
        iDWord = 16 - nDWord;
        pDst = (CARD32 *)pATI->pHOST_DATA - iDWord;
        pSrc = pBitmapData - iDWord;

        /*
         * Transfer current chunk.  With any luck, the compiler won't mangle
         * this too badly...
         */
        switch (iDWord)
        {
            case  0:  MMIO_OUT32(pDst +  0, 0, *(pSrc +  0));
            case  1:  MMIO_OUT32(pDst +  1, 0, *(pSrc +  1));
            case  2:  MMIO_OUT32(pDst +  2, 0, *(pSrc +  2));
            case  3:  MMIO_OUT32(pDst +  3, 0, *(pSrc +  3));
            case  4:  MMIO_OUT32(pDst +  4, 0, *(pSrc +  4));
            case  5:  MMIO_OUT32(pDst +  5, 0, *(pSrc +  5));
            case  6:  MMIO_OUT32(pDst +  6, 0, *(pSrc +  6));
            case  7:  MMIO_OUT32(pDst +  7, 0, *(pSrc +  7));
            case  8:  MMIO_OUT32(pDst +  8, 0, *(pSrc +  8));
            case  9:  MMIO_OUT32(pDst +  9, 0, *(pSrc +  9));
            case 10:  MMIO_OUT32(pDst + 10, 0, *(pSrc + 10));
            case 11:  MMIO_OUT32(pDst + 11, 0, *(pSrc + 11));
            case 12:  MMIO_OUT32(pDst + 12, 0, *(pSrc + 12));
            case 13:  MMIO_OUT32(pDst + 13, 0, *(pSrc + 13));
            case 14:  MMIO_OUT32(pDst + 14, 0, *(pSrc + 14));
            case 15:  MMIO_OUT32(pDst + 15, 0, *(pSrc + 15));

            default:    /* Muffle compiler */
                break;
        }

        /* Step to next chunk */
        pBitmapData += nDWord;
        w -= nDWord;
        pATI->nAvailableFIFOEntries -= nDWord;
    }

    pATI->EngineIsBusy = TRUE;
}

/*
 * ATIMach64AccelInit --
 *
 * This function fills in structure fields needed for acceleration on Mach64
 * variants.
 */
Bool
ATIMach64AccelInit
(
    ATIPtr        pATI,
    XAAInfoRecPtr pXAAInfo
)
{
    /* This doesn't seem quite right... */
    if (pATI->XModifier == 1)
    {
        pXAAInfo->Flags = PIXMAP_CACHE | OFFSCREEN_PIXMAPS;

#ifndef AVOID_CPIO

        if (!pATI->BankInfo.BankSize)

#endif /* AVOID_CPIO */

        {
            pXAAInfo->Flags |= LINEAR_FRAMEBUFFER;
        }
    }

    /* Sync */
    pXAAInfo->Sync = ATIMach64Sync;

    /* Screen-to-screen copy */
    pXAAInfo->SetupForScreenToScreenCopy = ATIMach64SetupForScreenToScreenCopy;
    pXAAInfo->SubsequentScreenToScreenCopy =
        ATIMach64SubsequentScreenToScreenCopy;

    /* Solid fills */
    pXAAInfo->SetupForSolidFill = ATIMach64SetupForSolidFill;
    pXAAInfo->SubsequentSolidFillRect = ATIMach64SubsequentSolidFillRect;

    /* 8x8 mono pattern fills */
    pXAAInfo->Mono8x8PatternFillFlags =
        HARDWARE_PATTERN_PROGRAMMED_BITS | HARDWARE_PATTERN_SCREEN_ORIGIN;
    pXAAInfo->SetupForMono8x8PatternFill = ATIMach64SetupForMono8x8PatternFill;
    pXAAInfo->SubsequentMono8x8PatternFillRect =
        ATIMach64SubsequentMono8x8PatternFillRect;

    /*
     * Use scanline version of colour expansion, not only for the non-ix86
     * case, but also to avoid PCI retries.
     */
    pXAAInfo->ScanlineCPUToScreenColorExpandFillFlags =
        LEFT_EDGE_CLIPPING | LEFT_EDGE_CLIPPING_NEGATIVE_X |
        CPU_TRANSFER_PAD_DWORD | SCANLINE_PAD_DWORD;
    if (pATI->XModifier != 1)
        pXAAInfo->ScanlineCPUToScreenColorExpandFillFlags |= TRIPLE_BITS_24BPP;
    pXAAInfo->NumScanlineColorExpandBuffers = 1;

    /* Align bitmap data on a 64-byte boundary */
    pATI->ExpansionBitmapWidth =        /* DWord size in bits */
        ((pATI->displayWidth * pATI->XModifier) + 31) & ~31U;
    pATI->ExpansionBitmapScanlinePtr[1] =
        (CARD32 *)xnfalloc((pATI->ExpansionBitmapWidth >> 3) + 63);
    pATI->ExpansionBitmapScanlinePtr[0] =
        (pointer)(((unsigned long)pATI->ExpansionBitmapScanlinePtr[1] + 63) &
                  ~63UL);
    pXAAInfo->ScanlineColorExpandBuffers =
        (CARD8 **)pATI->ExpansionBitmapScanlinePtr;
    pXAAInfo->SetupForScanlineCPUToScreenColorExpandFill =
        ATIMach64SetupForScanlineCPUToScreenColorExpandFill;
    pXAAInfo->SubsequentScanlineCPUToScreenColorExpandFill =
        ATIMach64SubsequentScanlineCPUToScreenColorExpandFill;
    pXAAInfo->SubsequentColorExpandScanline =
        ATIMach64SubsequentColorExpandScanline;

    /* The engine does not support the following primitives for 24bpp */
    if (pATI->XModifier != 1)
        return TRUE;

    /* Solid lines */
    pXAAInfo->SetupForSolidLine = ATIMach64SetupForSolidLine;
    pXAAInfo->SubsequentSolidHorVertLine = ATIMach64SubsequentSolidHorVertLine;
    pXAAInfo->SubsequentSolidBresenhamLine =
        ATIMach64SubsequentSolidBresenhamLine;

    return TRUE;
}

Powered by
ViewCVS 0.9.2