132b578d3Smrg/* -*- mode: c; c-basic-offset: 3 -*- */
232b578d3Smrg/*
332b578d3Smrg * Copyright 2000 Gareth Hughes
432b578d3Smrg * All Rights Reserved.
532b578d3Smrg *
632b578d3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
732b578d3Smrg * copy of this software and associated documentation files (the "Software"),
832b578d3Smrg * to deal in the Software without restriction, including without limitation
932b578d3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1032b578d3Smrg * and/or sell copies of the Software, and to permit persons to whom the
1132b578d3Smrg * Software is furnished to do so, subject to the following conditions:
1232b578d3Smrg *
1332b578d3Smrg * The above copyright notice and this permission notice (including the next
1432b578d3Smrg * paragraph) shall be included in all copies or substantial portions of the
1532b578d3Smrg * Software.
1632b578d3Smrg *
1732b578d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1832b578d3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1932b578d3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2032b578d3Smrg * GARETH HUGHES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
2132b578d3Smrg * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2232b578d3Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2332b578d3Smrg */
2432b578d3Smrg
2532b578d3Smrg#ifdef HAVE_CONFIG_H
2632b578d3Smrg#include "config.h"
2732b578d3Smrg#endif
2832b578d3Smrg/*
2932b578d3Smrg * Authors:
3032b578d3Smrg *   Gareth Hughes <gareth@valinux.com>
3132b578d3Smrg *   Leif Delgass <ldelgass@retinalburn.net>
3232b578d3Smrg */
3332b578d3Smrg
3432b578d3Smrg#include <string.h>
3532b578d3Smrg#include <stdio.h>
3632b578d3Smrg#include <unistd.h>
3732b578d3Smrg
3832b578d3Smrg/* Driver data structures */
3932b578d3Smrg#include "ati.h"
4032b578d3Smrg#include "atibus.h"
4132b578d3Smrg#include "atidri.h"
4232b578d3Smrg#include "atiregs.h"
4332b578d3Smrg#include "atistruct.h"
4432b578d3Smrg
4532b578d3Smrg#include "atimach64io.h"
4632b578d3Smrg#include "atimach64version.h"
4732b578d3Smrg#include "mach64_dri.h"
4832b578d3Smrg#include "mach64_common.h"
4932b578d3Smrg#include "mach64_sarea.h"
5032b578d3Smrg
5132b578d3Smrg/* X and server generic header files */
5232b578d3Smrg#include "xf86.h"
5332b578d3Smrg#include "windowstr.h"
5432b578d3Smrg
550b0ce0bfSmrg/* DRI/DRM definitions */
5632b578d3Smrg#define _XF86DRI_SERVER_
5732b578d3Smrg#include "sarea.h"
5832b578d3Smrg
5932b578d3Smrgstatic char ATIKernelDriverName[] = "mach64";
6032b578d3Smrgstatic char ATIClientDriverName[] = "mach64";
6132b578d3Smrg
6232b578d3Smrg/* Create the ATI-specific context information */
6332b578d3Smrgstatic Bool ATICreateContext( ScreenPtr pScreen, VisualPtr visual,
6432b578d3Smrg			      drm_context_t hwContext, void *pVisualConfigPriv,
6532b578d3Smrg			      DRIContextType contextStore )
6632b578d3Smrg{
6732b578d3Smrg   /* Nothing yet */
6832b578d3Smrg   return TRUE;
6932b578d3Smrg}
7032b578d3Smrg
7132b578d3Smrg/* Destroy the ATI-specific context information */
7232b578d3Smrgstatic void ATIDestroyContext( ScreenPtr pScreen, drm_context_t hwContext,
7332b578d3Smrg			       DRIContextType contextStore )
7432b578d3Smrg{
7532b578d3Smrg   /* Nothing yet */
7632b578d3Smrg}
7732b578d3Smrg
7832b578d3Smrg/* Called when the X server is woken up to allow the last client's
7932b578d3Smrg * context to be saved and the X server's context to be loaded.
8032b578d3Smrg * The client detects when it's context is not currently loaded and
8132b578d3Smrg * then loads it itself.  The X server's context is loaded in the
8232b578d3Smrg * XAA Sync callback if NeedDRISync is set.
8332b578d3Smrg */
8432b578d3Smrgstatic void ATIEnterServer( ScreenPtr pScreen )
8532b578d3Smrg{
86e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
8732b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
8832b578d3Smrg
8932b578d3Smrg   if ( pATI->directRenderingEnabled ) {
9032b578d3Smrg      ATIDRIMarkSyncInt(pScreenInfo);
9132b578d3Smrg      ATIDRIMarkSyncExt(pScreenInfo);
9232b578d3Smrg   }
9332b578d3Smrg}
9432b578d3Smrg
9532b578d3Smrg/* Called when the X server goes to sleep to allow the X server's
9632b578d3Smrg * context to be saved and the last client's context to be loaded.
9732b578d3Smrg * The client detects when it's context is not currently loaded and
9832b578d3Smrg * then loads it itself.  The X server keeps track of it's own state.
9932b578d3Smrg */
10032b578d3Smrgstatic void ATILeaveServer( ScreenPtr pScreen )
10132b578d3Smrg{
10232b578d3Smrg   /* Nothing yet */
10332b578d3Smrg}
10432b578d3Smrg
10532b578d3Smrg/* Contexts can be swapped by the X server if necessary.  This callback
10632b578d3Smrg * is currently only used to perform any functions necessary when
10732b578d3Smrg * entering or leaving the X server, and in the future might not be
10832b578d3Smrg * necessary.
10932b578d3Smrg */
11032b578d3Smrgstatic void ATIDRISwapContext( ScreenPtr pScreen,
11132b578d3Smrg			       DRISyncType syncType,
11232b578d3Smrg			       DRIContextType oldContextType,
11332b578d3Smrg			       void *oldContext,
11432b578d3Smrg			       DRIContextType newContextType,
11532b578d3Smrg			       void *newContext )
11632b578d3Smrg{
11732b578d3Smrg   if ( ( syncType == DRI_3D_SYNC ) && ( oldContextType == DRI_2D_CONTEXT ) &&
11832b578d3Smrg	( newContextType == DRI_2D_CONTEXT ) ) {
11932b578d3Smrg      /* Entering from Wakeup */
12032b578d3Smrg      ATIEnterServer( pScreen );
12132b578d3Smrg   }
12232b578d3Smrg   if ( ( syncType == DRI_2D_SYNC ) && ( oldContextType == DRI_NO_CONTEXT ) &&
12332b578d3Smrg	( newContextType == DRI_2D_CONTEXT ) ) {
12432b578d3Smrg      /* Exiting from Block Handler */
12532b578d3Smrg      ATILeaveServer( pScreen );
12632b578d3Smrg   }
12732b578d3Smrg}
12832b578d3Smrg
12932b578d3Smrg#ifdef USE_XAA
13032b578d3Smrgstatic void ATIDRITransitionTo2d(ScreenPtr pScreen)
13132b578d3Smrg{
132e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
13332b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
13432b578d3Smrg
13532b578d3Smrg   if (pATI->backArea) {
13632b578d3Smrg      xf86FreeOffscreenArea(pATI->backArea);
13732b578d3Smrg      pATI->backArea = NULL;
13832b578d3Smrg   }
13932b578d3Smrg   if (pATI->depthTexArea) {
14032b578d3Smrg      xf86FreeOffscreenArea(pATI->depthTexArea);
14132b578d3Smrg      pATI->depthTexArea = NULL;
14232b578d3Smrg   }
14332b578d3Smrg   pATI->have3DWindows = FALSE;
14432b578d3Smrg}
14532b578d3Smrg
14632b578d3Smrgstatic void ATIDRITransitionTo3d(ScreenPtr pScreen)
14732b578d3Smrg{
148e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
14932b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
15032b578d3Smrg   FBAreaPtr fbArea;
15132b578d3Smrg   int width, height;
15232b578d3Smrg
15332b578d3Smrg   xf86PurgeUnlockedOffscreenAreas(pScreen);
15432b578d3Smrg
15532b578d3Smrg   xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0);
15632b578d3Smrg
15732b578d3Smrg   xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
15832b578d3Smrg	      "Largest offscreen area available: %d x %d\n",
15932b578d3Smrg	      width, height);
16032b578d3Smrg
16132b578d3Smrg   fbArea = xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth,
16232b578d3Smrg				      height - pATI->depthTexLines -
16332b578d3Smrg				      pATI->backLines,
16432b578d3Smrg				      pScreenInfo->displayWidth, NULL, NULL, NULL);
16532b578d3Smrg
16632b578d3Smrg   if (!fbArea)
16732b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve placeholder "
16832b578d3Smrg		 "offscreen area, you might experience screen corruption\n");
16932b578d3Smrg
17032b578d3Smrg   if (!pATI->backArea) {
17132b578d3Smrg      pATI->backArea =
17232b578d3Smrg	 xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth,
17332b578d3Smrg				   pATI->backLines,
17432b578d3Smrg				   pScreenInfo->displayWidth,
17532b578d3Smrg				   NULL, NULL, NULL);
17632b578d3Smrg   }
17732b578d3Smrg   if (!pATI->backArea)
17832b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area "
17932b578d3Smrg		 "for back buffer, you might experience screen corruption\n");
18032b578d3Smrg
18132b578d3Smrg   if (!pATI->depthTexArea) {
18232b578d3Smrg      pATI->depthTexArea =
18332b578d3Smrg	 xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth,
18432b578d3Smrg				   pATI->depthTexLines,
18532b578d3Smrg				   pScreenInfo->displayWidth,
18632b578d3Smrg				   NULL, NULL, NULL);
18732b578d3Smrg   }
18832b578d3Smrg   if (!pATI->depthTexArea)
18932b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area "
19032b578d3Smrg		 "for depth buffer and textures, you might experience screen corruption\n");
19132b578d3Smrg
19232b578d3Smrg   if (fbArea)
19332b578d3Smrg      xf86FreeOffscreenArea(fbArea);
19432b578d3Smrg
19532b578d3Smrg   pATI->have3DWindows = TRUE;
19632b578d3Smrg}
19732b578d3Smrg#endif /* USE_XAA */
19832b578d3Smrg
19932b578d3Smrg#ifdef USE_EXA
20032b578d3Smrgstatic void ATIDRITransitionTo2d_EXA(ScreenPtr pScreen)
20132b578d3Smrg{
202e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
20332b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
20432b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
20532b578d3Smrg
206e35d4d8eSmrg   exaEnableDisableFBAccess(SCREEN_ARG(pScreen), FALSE);
20732b578d3Smrg
20832b578d3Smrg   pATI->pExa->offScreenBase = pATIDRIServer->backOffset;
20932b578d3Smrg
210e35d4d8eSmrg   exaEnableDisableFBAccess(SCREEN_ARG(pScreen), TRUE);
21132b578d3Smrg
21232b578d3Smrg   pATI->have3DWindows = FALSE;
21332b578d3Smrg}
21432b578d3Smrg
21532b578d3Smrgstatic void ATIDRITransitionTo3d_EXA(ScreenPtr pScreen)
21632b578d3Smrg{
217e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
21832b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
21932b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
22032b578d3Smrg
221e35d4d8eSmrg   exaEnableDisableFBAccess(SCREEN_ARG(pScreen), FALSE);
22232b578d3Smrg
22332b578d3Smrg   pATI->pExa->offScreenBase = pATIDRIServer->textureOffset +
22432b578d3Smrg			       pATIDRIServer->textureSize;
22532b578d3Smrg
226e35d4d8eSmrg   exaEnableDisableFBAccess(SCREEN_ARG(pScreen), TRUE);
22732b578d3Smrg
22832b578d3Smrg   pATI->have3DWindows = TRUE;
22932b578d3Smrg}
23032b578d3Smrg#endif /* USE_EXA */
23132b578d3Smrg
23232b578d3Smrg/* Initialize the state of the back and depth buffers. */
23332b578d3Smrgstatic void ATIDRIInitBuffers( WindowPtr pWin, RegionPtr prgn, CARD32 indx )
23432b578d3Smrg{
23532b578d3Smrg#ifdef USE_XAA
23632b578d3Smrg   ScreenPtr   pScreen = pWin->drawable.pScreen;
237e35d4d8eSmrg   ScrnInfoPtr pScreenInfo   = xf86ScreenToScrn(pScreen);
23832b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
23932b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
24032b578d3Smrg   XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo;
24132b578d3Smrg   BoxPtr      pbox, pboxSave;
24232b578d3Smrg   int         nbox, nboxSave;
24332b578d3Smrg   int         depth;
24432b578d3Smrg
24532b578d3Smrg   depth = 0x0000ffff;
24632b578d3Smrg
24732b578d3Smrg   if (!pXAAInfo)
24832b578d3Smrg      return;
24932b578d3Smrg
25032b578d3Smrg   if (!pXAAInfo->SetupForSolidFill)
25132b578d3Smrg      return;
25232b578d3Smrg
25332b578d3Smrg   /* FIXME: Only initialize the back and depth buffers for contexts
25432b578d3Smrg      that request them */
25532b578d3Smrg
25632b578d3Smrg   /* FIXME: Use drm clear? (see Radeon driver) */
25732b578d3Smrg
25832b578d3Smrg   pboxSave = pbox = REGION_RECTS(prgn);
25932b578d3Smrg   nboxSave = nbox = REGION_NUM_RECTS(prgn);
26032b578d3Smrg
26132b578d3Smrg   (*pXAAInfo->SetupForSolidFill)(pScreenInfo, 0, GXcopy, (CARD32)(-1));
26232b578d3Smrg   for (; nbox; nbox--, pbox++) {
26332b578d3Smrg      (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo,
26432b578d3Smrg					      pbox->x1 + pATIDRIServer->fbX,
26532b578d3Smrg					      pbox->y1 + pATIDRIServer->fbY,
26632b578d3Smrg					      pbox->x2 - pbox->x1,
26732b578d3Smrg					      pbox->y2 - pbox->y1);
26832b578d3Smrg      (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo,
26932b578d3Smrg					      pbox->x1 + pATIDRIServer->backX,
27032b578d3Smrg					      pbox->y1 + pATIDRIServer->backY,
27132b578d3Smrg					      pbox->x2 - pbox->x1,
27232b578d3Smrg					      pbox->y2 - pbox->y1);
27332b578d3Smrg   }
27432b578d3Smrg
27532b578d3Smrg   pbox = pboxSave;
27632b578d3Smrg   nbox = nboxSave;
27732b578d3Smrg
27832b578d3Smrg   (*pXAAInfo->SetupForSolidFill)(pScreenInfo, depth, GXcopy, (CARD32)(-1));
27932b578d3Smrg   for (; nbox; nbox--, pbox++)
28032b578d3Smrg      (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo,
28132b578d3Smrg					      pbox->x1 + pATIDRIServer->depthX,
28232b578d3Smrg					      pbox->y1 + pATIDRIServer->depthY,
28332b578d3Smrg					      pbox->x2 - pbox->x1,
28432b578d3Smrg					      pbox->y2 - pbox->y1);
28532b578d3Smrg
28632b578d3Smrg   ATIDRIMarkSyncInt(pScreenInfo);
28732b578d3Smrg#endif
28832b578d3Smrg}
28932b578d3Smrg
29032b578d3Smrg/* Copy the back and depth buffers when the X server moves a window.
29132b578d3Smrg *
29232b578d3Smrg * Note: this function was copied from the Radeon driver...
29332b578d3Smrg *
29432b578d3Smrg * This routine is a modified form of XAADoBitBlt with the calls to
29532b578d3Smrg * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source
29632b578d3Smrg * instead of destination. My origin is upside down so the ydir cases
29732b578d3Smrg * are reversed.
29832b578d3Smrg */
29932b578d3Smrgstatic void ATIDRIMoveBuffers( WindowPtr pWin, DDXPointRec ptOldOrg,
30032b578d3Smrg			       RegionPtr prgnSrc, CARD32 indx )
30132b578d3Smrg{
30232b578d3Smrg#ifdef USE_XAA
30332b578d3Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
304e35d4d8eSmrg    ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
30532b578d3Smrg    ATIPtr pATI = ATIPTR(pScreenInfo);
30632b578d3Smrg    XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo;
30732b578d3Smrg
30832b578d3Smrg    int backOffsetPitch =  (((pATI->pDRIServerInfo->backPitch/8) << 22) |
30932b578d3Smrg					   (pATI->pDRIServerInfo->backOffset >> 3));
31032b578d3Smrg#if 0
31132b578d3Smrg    int depthOffsetPitch = (((pATI->pDRIServerInfo->depthPitch/8) << 22) |
31232b578d3Smrg					   (pATI->pDRIServerInfo->depthOffset >> 3));
31332b578d3Smrg#endif
31432b578d3Smrg    BoxPtr        pboxTmp, pboxNext, pboxBase;
31532b578d3Smrg    DDXPointPtr   pptTmp;
31632b578d3Smrg    int           xdir, ydir;
31732b578d3Smrg
31832b578d3Smrg    int           screenwidth = pScreenInfo->virtualX;
31932b578d3Smrg    int           screenheight = pScreenInfo->virtualY;
32032b578d3Smrg
32132b578d3Smrg    BoxPtr        pbox     = REGION_RECTS(prgnSrc);
32232b578d3Smrg    int           nbox     = REGION_NUM_RECTS(prgnSrc);
32332b578d3Smrg
32432b578d3Smrg    BoxPtr        pboxNew1 = NULL;
32532b578d3Smrg    BoxPtr        pboxNew2 = NULL;
32632b578d3Smrg    DDXPointPtr   pptNew1  = NULL;
32732b578d3Smrg    DDXPointPtr   pptNew2  = NULL;
32832b578d3Smrg    DDXPointPtr   pptSrc   = &ptOldOrg;
32932b578d3Smrg
33032b578d3Smrg    int           dx       = pWin->drawable.x - ptOldOrg.x;
33132b578d3Smrg    int           dy       = pWin->drawable.y - ptOldOrg.y;
33232b578d3Smrg
33332b578d3Smrg   if (!pXAAInfo)
33432b578d3Smrg      return;
33532b578d3Smrg
33632b578d3Smrg   if (!pXAAInfo->SetupForScreenToScreenCopy)
33732b578d3Smrg      return;
33832b578d3Smrg
33932b578d3Smrg    /* FIXME: Only move the back and depth buffers for contexts
34032b578d3Smrg     * that request them.
34132b578d3Smrg     */
34232b578d3Smrg
34332b578d3Smrg    /* If the copy will overlap in Y, reverse the order */
34432b578d3Smrg    if (dy > 0) {
34532b578d3Smrg	ydir = -1;
34632b578d3Smrg
34732b578d3Smrg	if (nbox > 1) {
34832b578d3Smrg	    /* Keep ordering in each band, reverse order of bands */
3491b12faf6Smrg	    pboxNew1 = (BoxPtr)malloc(sizeof(BoxRec)*nbox);
35032b578d3Smrg	    if (!pboxNew1) return;
3511b12faf6Smrg	    pptNew1 = (DDXPointPtr)malloc(sizeof(DDXPointRec)*nbox);
35232b578d3Smrg	    if (!pptNew1) {
3531b12faf6Smrg		free(pboxNew1);
35432b578d3Smrg		return;
35532b578d3Smrg	    }
35632b578d3Smrg	    pboxBase = pboxNext = pbox+nbox-1;
35732b578d3Smrg	    while (pboxBase >= pbox) {
35832b578d3Smrg		while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1))
35932b578d3Smrg		    pboxNext--;
36032b578d3Smrg		pboxTmp = pboxNext+1;
36132b578d3Smrg		pptTmp  = pptSrc + (pboxTmp - pbox);
36232b578d3Smrg		while (pboxTmp <= pboxBase) {
36332b578d3Smrg		    *pboxNew1++ = *pboxTmp++;
36432b578d3Smrg		    *pptNew1++  = *pptTmp++;
36532b578d3Smrg		}
36632b578d3Smrg		pboxBase = pboxNext;
36732b578d3Smrg	    }
36832b578d3Smrg	    pboxNew1 -= nbox;
36932b578d3Smrg	    pbox      = pboxNew1;
37032b578d3Smrg	    pptNew1  -= nbox;
37132b578d3Smrg	    pptSrc    = pptNew1;
37232b578d3Smrg	}
37332b578d3Smrg    } else {
37432b578d3Smrg	/* No changes required */
37532b578d3Smrg	ydir = 1;
37632b578d3Smrg    }
37732b578d3Smrg
37832b578d3Smrg    /* If the regions will overlap in X, reverse the order */
37932b578d3Smrg    if (dx > 0) {
38032b578d3Smrg	xdir = -1;
38132b578d3Smrg
38232b578d3Smrg	if (nbox > 1) {
38332b578d3Smrg	    /* reverse order of rects in each band */
3841b12faf6Smrg	    pboxNew2 = (BoxPtr)malloc(sizeof(BoxRec)*nbox);
3851b12faf6Smrg	    pptNew2  = (DDXPointPtr)malloc(sizeof(DDXPointRec)*nbox);
38632b578d3Smrg	    if (!pboxNew2 || !pptNew2) {
3871b12faf6Smrg		free(pptNew2);
3881b12faf6Smrg		free(pboxNew2);
3891b12faf6Smrg		free(pptNew1);
3901b12faf6Smrg		free(pboxNew1);
39132b578d3Smrg		return;
39232b578d3Smrg	    }
39332b578d3Smrg	    pboxBase = pboxNext = pbox;
39432b578d3Smrg	    while (pboxBase < pbox+nbox) {
39532b578d3Smrg		while ((pboxNext < pbox+nbox)
39632b578d3Smrg		       && (pboxNext->y1 == pboxBase->y1))
39732b578d3Smrg		    pboxNext++;
39832b578d3Smrg		pboxTmp = pboxNext;
39932b578d3Smrg		pptTmp  = pptSrc + (pboxTmp - pbox);
40032b578d3Smrg		while (pboxTmp != pboxBase) {
40132b578d3Smrg		    *pboxNew2++ = *--pboxTmp;
40232b578d3Smrg		    *pptNew2++  = *--pptTmp;
40332b578d3Smrg		}
40432b578d3Smrg		pboxBase = pboxNext;
40532b578d3Smrg	    }
40632b578d3Smrg	    pboxNew2 -= nbox;
40732b578d3Smrg	    pbox      = pboxNew2;
40832b578d3Smrg	    pptNew2  -= nbox;
40932b578d3Smrg	    pptSrc    = pptNew2;
41032b578d3Smrg	}
41132b578d3Smrg    } else {
41232b578d3Smrg	/* No changes are needed */
41332b578d3Smrg	xdir = 1;
41432b578d3Smrg    }
41532b578d3Smrg
41632b578d3Smrg    (*pXAAInfo->SetupForScreenToScreenCopy)(pScreenInfo, xdir, ydir, GXcopy,
41732b578d3Smrg					       (CARD32)(-1), -1);
41832b578d3Smrg
41932b578d3Smrg    for (; nbox-- ; pbox++) {
42032b578d3Smrg	int xa    = pbox->x1;
42132b578d3Smrg	int ya    = pbox->y1;
42232b578d3Smrg	int destx = xa + dx;
42332b578d3Smrg	int desty = ya + dy;
42432b578d3Smrg	int w     = pbox->x2 - xa + 1;
42532b578d3Smrg	int h     = pbox->y2 - ya + 1;
42632b578d3Smrg
42732b578d3Smrg	if (destx < 0)                xa -= destx, w += destx, destx = 0;
42832b578d3Smrg	if (desty < 0)                ya -= desty, h += desty, desty = 0;
42932b578d3Smrg	if (destx + w > screenwidth)  w = screenwidth  - destx;
43032b578d3Smrg	if (desty + h > screenheight) h = screenheight - desty;
43132b578d3Smrg
43232b578d3Smrg	if (w <= 0) continue;
43332b578d3Smrg	if (h <= 0) continue;
43432b578d3Smrg
43532b578d3Smrg	ATIMach64WaitForFIFO(pATI, 2);
43632b578d3Smrg	outf(SRC_OFF_PITCH, backOffsetPitch);
43732b578d3Smrg	outf(DST_OFF_PITCH, backOffsetPitch);
43832b578d3Smrg
43932b578d3Smrg	(*pXAAInfo->SubsequentScreenToScreenCopy)(pScreenInfo,
44032b578d3Smrg						     xa, ya,
44132b578d3Smrg						     destx, desty,
44232b578d3Smrg						     w, h);
44332b578d3Smrg#if 0
44432b578d3Smrg	/* FIXME: Move depth buffers? */
44532b578d3Smrg	ATIMach64WaitForFIFO(pATI, 2);
44632b578d3Smrg	outf(SRC_OFF_PITCH, depthOffsetPitch);
44732b578d3Smrg	outf(DST_OFF_PITCH, depthOffsetPitch);
44832b578d3Smrg
44932b578d3Smrg	if (pATI->depthMoves)
45032b578d3Smrg	    ATIScreenToScreenCopyDepth(pScreenInfo,
45132b578d3Smrg					  xa, ya,
45232b578d3Smrg					  destx, desty,
45332b578d3Smrg					  w, h);
45432b578d3Smrg#endif
45532b578d3Smrg    }
45632b578d3Smrg
45732b578d3Smrg    ATIMach64WaitForFIFO(pATI, 2);
45832b578d3Smrg    outf(SRC_OFF_PITCH, pATI->NewHW.dst_off_pitch);
45932b578d3Smrg    outf(DST_OFF_PITCH, pATI->NewHW.src_off_pitch);
46032b578d3Smrg
4611b12faf6Smrg    free(pptNew2);
4621b12faf6Smrg    free(pboxNew2);
4631b12faf6Smrg    free(pptNew1);
4641b12faf6Smrg    free(pboxNew1);
46532b578d3Smrg
46632b578d3Smrg    ATIDRIMarkSyncInt(pScreenInfo);
46732b578d3Smrg#endif
46832b578d3Smrg}
46932b578d3Smrg
47032b578d3Smrg/* Compute log base 2 of val. */
47132b578d3Smrgstatic int Mach64MinBits(int val)
47232b578d3Smrg{
47332b578d3Smrg    int bits;
47432b578d3Smrg
47532b578d3Smrg    if (!val) return 1;
47632b578d3Smrg    for (bits = 0; val; val >>= 1, ++bits);
47732b578d3Smrg    return bits;
47832b578d3Smrg}
47932b578d3Smrg
48032b578d3Smrgstatic Bool ATIDRISetBufSize( ScreenPtr pScreen, unsigned int maxSize )
48132b578d3Smrg{
482e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
48332b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
48432b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
48532b578d3Smrg
48632b578d3Smrg   if (pATI->OptionBufferSize) {
48732b578d3Smrg      if (pATI->OptionBufferSize < 1 || pATI->OptionBufferSize > maxSize  ) {
48832b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_ERROR, "[drm] Illegal DMA buffers size: %d MB\n",
48932b578d3Smrg		     pATI->OptionBufferSize );
49032b578d3Smrg	 return FALSE;
49132b578d3Smrg      }
49232b578d3Smrg      if (pATI->OptionBufferSize > 2) {
49332b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_WARNING, "[drm] Illegal DMA buffers size: %d MB\n",
49432b578d3Smrg		     pATI->OptionBufferSize );
49532b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_WARNING, "[drm] Clamping DMA buffers size to 2 MB\n");
49632b578d3Smrg	 pATIDRIServer->bufferSize = 2;
49732b578d3Smrg      } else {
49832b578d3Smrg	 pATIDRIServer->bufferSize = pATI->OptionBufferSize;
49932b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_CONFIG, "[drm] Using %d MB for DMA buffers\n",
50032b578d3Smrg		     pATIDRIServer->bufferSize );
50132b578d3Smrg      }
50232b578d3Smrg   } else {
50332b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[drm] Using %d MB for DMA buffers\n",
50432b578d3Smrg		  pATIDRIServer->bufferSize );
50532b578d3Smrg   }
50632b578d3Smrg
50732b578d3Smrg   return TRUE;
50832b578d3Smrg}
50932b578d3Smrg
51032b578d3Smrgstatic Bool ATIDRISetAgpMode( ScreenPtr pScreen )
51132b578d3Smrg{
512e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
51332b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
51432b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
51532b578d3Smrg
51632b578d3Smrg   unsigned long mode   = drmAgpGetMode( pATI->drmFD );        /* Default mode */
51732b578d3Smrg   unsigned int vendor = drmAgpVendorId( pATI->drmFD );
51832b578d3Smrg   unsigned int device = drmAgpDeviceId( pATI->drmFD );
51932b578d3Smrg
52032b578d3Smrg   if (pATI->OptionAGPMode > 0 && pATI->OptionAGPMode <= ATI_AGP_MAX_MODE) {
52132b578d3Smrg      pATIDRIServer->agpMode = pATI->OptionAGPMode;
52232b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using AGP %dx Mode\n",
52332b578d3Smrg		  pATIDRIServer->agpMode );
52432b578d3Smrg   } else if (pATI->OptionAGPMode > 0) {
52532b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal AGP Mode: %d\n",
52632b578d3Smrg		  pATI->OptionAGPMode );
52732b578d3Smrg      return FALSE;
52832b578d3Smrg   } else {
52932b578d3Smrg      /* If no mode configured, use the default mode obtained from agpgart */
53032b578d3Smrg      if ( mode & AGP_MODE_2X ) {
53132b578d3Smrg	 pATIDRIServer->agpMode = 2;
53232b578d3Smrg      } else if ( mode & AGP_MODE_1X ) {
53332b578d3Smrg	 pATIDRIServer->agpMode = 1;
53432b578d3Smrg      }
53532b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using AGP %dx Mode\n",
53632b578d3Smrg		  pATIDRIServer->agpMode );
53732b578d3Smrg   }
53832b578d3Smrg
53932b578d3Smrg   mode &= ~AGP_MODE_MASK;
54032b578d3Smrg   switch ( pATIDRIServer->agpMode ) {
54132b578d3Smrg   case 2:          mode |= AGP_MODE_2X;
54232b578d3Smrg   case 1: default: mode |= AGP_MODE_1X;
54332b578d3Smrg   }
54432b578d3Smrg
54532b578d3Smrg   if (pATI->OptionAGPSize) {
54632b578d3Smrg      switch (pATI->OptionAGPSize) {
54732b578d3Smrg      case 128:
54832b578d3Smrg      case  64:
54932b578d3Smrg      case  32:
55032b578d3Smrg      case  16:
55132b578d3Smrg      case   8:
55232b578d3Smrg      case   4:
55332b578d3Smrg	 pATIDRIServer->agpSize = pATI->OptionAGPSize;
55432b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using %d MB AGP aperture\n",
55532b578d3Smrg		     pATIDRIServer->agpSize );
55632b578d3Smrg	 break;
55732b578d3Smrg      default:
55832b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_ERROR,
55932b578d3Smrg		     "[agp] Illegal aperture size %d MB\n", pATI->OptionAGPSize );
56032b578d3Smrg	 return FALSE;
56132b578d3Smrg      }
56232b578d3Smrg   } else {
56332b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using %d MB AGP aperture\n",
56432b578d3Smrg		  pATIDRIServer->agpSize );
56532b578d3Smrg   }
56632b578d3Smrg
56732b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
56832b578d3Smrg	       "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n",
56932b578d3Smrg	       mode, vendor, device,
57032b578d3Smrg	       PCI_DEV_VENDOR_ID(pATI->PCIInfo),
57132b578d3Smrg	       PCI_DEV_DEVICE_ID(pATI->PCIInfo) );
57232b578d3Smrg
57332b578d3Smrg   if ( drmAgpEnable( pATI->drmFD, mode ) < 0 ) {
57432b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n" );
57532b578d3Smrg      drmAgpRelease( pATI->drmFD );
57632b578d3Smrg      return FALSE;
57732b578d3Smrg   }
57832b578d3Smrg
57932b578d3Smrg   return TRUE;
58032b578d3Smrg}
58132b578d3Smrg
58232b578d3Smrg/* Initialize the AGP state.  Request memory for use in AGP space, and
58332b578d3Smrg * initialize the Rage Pro registers to point to that memory.
58432b578d3Smrg */
58532b578d3Smrgstatic Bool ATIDRIAgpInit( ScreenPtr pScreen )
58632b578d3Smrg{
587e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
58832b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
58932b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
59032b578d3Smrg
59132b578d3Smrg   int ret;
59232b578d3Smrg   unsigned long cntl;
59332b578d3Smrg   int s, l;
59432b578d3Smrg
59532b578d3Smrg   pATIDRIServer->agpSize = ATI_DEFAULT_AGP_SIZE;
59632b578d3Smrg   pATIDRIServer->agpMode = ATI_DEFAULT_AGP_MODE;
59732b578d3Smrg   pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE;
59832b578d3Smrg   pATIDRIServer->ringSize = 16; /* 16 kB ring */
59932b578d3Smrg
60032b578d3Smrg   if ( drmAgpAcquire( pATI->drmFD ) < 0 ) {
60132b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP not available\n" );
60232b578d3Smrg      return FALSE;
60332b578d3Smrg   }
60432b578d3Smrg
60532b578d3Smrg   if (!ATIDRISetAgpMode( pScreen ))
60632b578d3Smrg      return FALSE;
60732b578d3Smrg
60832b578d3Smrg   pATIDRIServer->agpOffset = 0;
60932b578d3Smrg
61032b578d3Smrg   ret = drmAgpAlloc( pATI->drmFD, pATIDRIServer->agpSize*1024*1024,
61132b578d3Smrg		      0, NULL, &pATIDRIServer->agpHandle );
61232b578d3Smrg   if ( ret < 0 ) {
61332b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret );
61432b578d3Smrg      drmAgpRelease( pATI->drmFD );
61532b578d3Smrg      return FALSE;
61632b578d3Smrg   }
61732b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
61832b578d3Smrg	       "[agp] %d kB allocated with handle 0x%08x\n",
61932b578d3Smrg	       pATIDRIServer->agpSize*1024, pATIDRIServer->agpHandle );
62032b578d3Smrg
62132b578d3Smrg   if ( drmAgpBind( pATI->drmFD, pATIDRIServer->agpHandle, pATIDRIServer->agpOffset) < 0 ) {
62232b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not bind\n" );
62332b578d3Smrg      drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle );
62432b578d3Smrg      drmAgpRelease( pATI->drmFD );
62532b578d3Smrg      return FALSE;
62632b578d3Smrg   }
62732b578d3Smrg
62832b578d3Smrg   xf86DrvMsg(pScreen->myNum, X_INFO,
62932b578d3Smrg	      "[agp] Using %d kB for DMA descriptor ring\n", pATIDRIServer->ringSize);
63032b578d3Smrg
63132b578d3Smrg   if ( !ATIDRISetBufSize( pScreen, pATIDRIServer->agpSize ) )
63232b578d3Smrg      return FALSE;
63332b578d3Smrg
63432b578d3Smrg   pATIDRIServer->agpTexSize    = pATIDRIServer->agpSize - pATIDRIServer->bufferSize;
63532b578d3Smrg
63632b578d3Smrg   /* Reserve space for the DMA descriptor ring */
63732b578d3Smrg   pATIDRIServer->ringStart   = pATIDRIServer->agpOffset;
63832b578d3Smrg   pATIDRIServer->ringMapSize = pATIDRIServer->ringSize*1024; /* ringSize is in kB */
63932b578d3Smrg
64032b578d3Smrg   /* Reserve space for the vertex buffer */
64132b578d3Smrg   pATIDRIServer->bufferStart   = pATIDRIServer->ringStart + pATIDRIServer->ringMapSize;
64232b578d3Smrg   pATIDRIServer->bufferMapSize = pATIDRIServer->bufferSize*1024*1024;
64332b578d3Smrg
64432b578d3Smrg   /* Reserve the rest for AGP textures */
64532b578d3Smrg   pATIDRIServer->agpTexStart = pATIDRIServer->bufferStart + pATIDRIServer->bufferMapSize;
64632b578d3Smrg   s = (pATIDRIServer->agpSize*1024*1024 - pATIDRIServer->agpTexStart);
64732b578d3Smrg   l = Mach64MinBits((s-1) / MACH64_NR_TEX_REGIONS);
64832b578d3Smrg   if (l < MACH64_LOG_TEX_GRANULARITY) l = MACH64_LOG_TEX_GRANULARITY;
64932b578d3Smrg   pATIDRIServer->agpTexMapSize   = (s >> l) << l;
65032b578d3Smrg   pATIDRIServer->log2AGPTexGran  = l;
65132b578d3Smrg
65232b578d3Smrg   xf86DrvMsg(pScreen->myNum, X_INFO,
65332b578d3Smrg	      "[agp] Using %d kB for AGP textures\n", pATIDRIServer->agpTexMapSize/1024);
65432b578d3Smrg
65532b578d3Smrg   /* Map DMA descriptor ring */
65632b578d3Smrg   if ( drmAddMap( pATI->drmFD, pATIDRIServer->ringStart, pATIDRIServer->ringMapSize,
65732b578d3Smrg		   DRM_AGP, DRM_RESTRICTED, &pATIDRIServer->ringHandle ) < 0 ) {
65832b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
65932b578d3Smrg		  "[agp] Could not add ring mapping\n" );
66032b578d3Smrg      return FALSE;
66132b578d3Smrg   }
66232b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
66332b578d3Smrg	       "[agp] ring handle = 0x%08x\n",
66432b578d3Smrg	       pATIDRIServer->ringHandle );
66532b578d3Smrg
66632b578d3Smrg   if ( drmMap( pATI->drmFD, pATIDRIServer->ringHandle,
66732b578d3Smrg		pATIDRIServer->ringMapSize, &pATIDRIServer->ringMap ) < 0 ) {
66832b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
66932b578d3Smrg		  "[agp] Could not map ring\n" );
67032b578d3Smrg      return FALSE;
67132b578d3Smrg   }
67232b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
67332b578d3Smrg	       "[agp] Ring mapped at 0x%08lx\n",
67432b578d3Smrg	       (unsigned long)pATIDRIServer->ringMap );
67532b578d3Smrg
67632b578d3Smrg   /* Map vertex buffers */
67732b578d3Smrg   if ( drmAddMap( pATI->drmFD, pATIDRIServer->bufferStart, pATIDRIServer->bufferMapSize,
67832b578d3Smrg		   DRM_AGP, DRM_READ_ONLY, &pATIDRIServer->bufferHandle ) < 0 ) {
67932b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
68032b578d3Smrg		  "[agp] Could not add vertex buffers mapping\n" );
68132b578d3Smrg      return FALSE;
68232b578d3Smrg   }
68332b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
68432b578d3Smrg	       "[agp] vertex buffers handle = 0x%08x\n",
68532b578d3Smrg	       pATIDRIServer->bufferHandle );
68632b578d3Smrg
68732b578d3Smrg   if ( drmMap( pATI->drmFD, pATIDRIServer->bufferHandle,
68832b578d3Smrg		pATIDRIServer->bufferMapSize, &pATIDRIServer->bufferMap ) < 0 ) {
68932b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
69032b578d3Smrg		  "[agp] Could not map vertex buffers\n" );
69132b578d3Smrg      return FALSE;
69232b578d3Smrg   }
69332b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
69432b578d3Smrg	       "[agp] Vertex buffers mapped at 0x%08lx\n",
69532b578d3Smrg	       (unsigned long)pATIDRIServer->bufferMap );
69632b578d3Smrg
69732b578d3Smrg   /* Map AGP Textures */
69832b578d3Smrg   if (drmAddMap(pATI->drmFD, pATIDRIServer->agpTexStart, pATIDRIServer->agpTexMapSize,
69932b578d3Smrg		 DRM_AGP, 0, &pATIDRIServer->agpTexHandle) < 0) {
70032b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_ERROR,
70132b578d3Smrg		 "[agp] Could not add AGP texture region mapping\n");
70232b578d3Smrg      return FALSE;
70332b578d3Smrg   }
70432b578d3Smrg   xf86DrvMsg(pScreen->myNum, X_INFO,
70532b578d3Smrg	      "[agp] AGP texture region handle = 0x%08x\n",
70632b578d3Smrg	      pATIDRIServer->agpTexHandle);
70732b578d3Smrg
70832b578d3Smrg   if (drmMap(pATI->drmFD, pATIDRIServer->agpTexHandle, pATIDRIServer->agpTexMapSize,
70932b578d3Smrg	      &pATIDRIServer->agpTexMap) < 0) {
71032b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_ERROR,
71132b578d3Smrg		 "[agp] Could not map AGP texture region\n");
71232b578d3Smrg      return FALSE;
71332b578d3Smrg   }
71432b578d3Smrg   xf86DrvMsg(pScreen->myNum, X_INFO,
71532b578d3Smrg	      "[agp] AGP Texture region mapped at 0x%08lx\n",
71632b578d3Smrg	      (unsigned long)pATIDRIServer->agpTexMap);
71732b578d3Smrg
71832b578d3Smrg   /* Initialize Mach64's AGP registers */
71932b578d3Smrg   cntl  = inm( AGP_CNTL );
72032b578d3Smrg   cntl &= ~AGP_APER_SIZE_MASK;
72132b578d3Smrg   switch ( pATIDRIServer->agpSize ) {
72232b578d3Smrg   case 256: cntl |= AGP_APER_SIZE_256MB; break;
72332b578d3Smrg   case 128: cntl |= AGP_APER_SIZE_128MB; break;
72432b578d3Smrg   case  64: cntl |= AGP_APER_SIZE_64MB;  break;
72532b578d3Smrg   case  32: cntl |= AGP_APER_SIZE_32MB;  break;
72632b578d3Smrg   case  16: cntl |= AGP_APER_SIZE_16MB;  break;
72732b578d3Smrg   case   8: cntl |= AGP_APER_SIZE_8MB;   break;
72832b578d3Smrg   case   4: cntl |= AGP_APER_SIZE_4MB;   break;
72932b578d3Smrg   default:
73032b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
73132b578d3Smrg		  "[agp] Illegal aperture size %d kB\n",
73232b578d3Smrg		  pATIDRIServer->agpSize*1024 );
73332b578d3Smrg      return FALSE;
73432b578d3Smrg   }
73532b578d3Smrg
73632b578d3Smrg   /* 1 = DATA comes in clock in which TRDY sampled (default) */
73732b578d3Smrg   /* 0 = DATA comes in clock after TRDY sampled */
73832b578d3Smrg   cntl |= AGP_TRDY_MODE;
73932b578d3Smrg
74032b578d3Smrg   /* 1 = generate all reads as high priority */
74132b578d3Smrg   /* 0 = generate all reads as their default priority (default) */
74232b578d3Smrg   /* Setting this only works for me at AGP 1x mode (LLD) */
74332b578d3Smrg   if (pATIDRIServer->agpMode == 1) {
74432b578d3Smrg      cntl |= HIGH_PRIORITY_READ_EN;
74532b578d3Smrg   } else {
74632b578d3Smrg      cntl &= ~HIGH_PRIORITY_READ_EN;
74732b578d3Smrg   }
74832b578d3Smrg
74932b578d3Smrg   outm( AGP_BASE, drmAgpBase(pATI->drmFD) );
75032b578d3Smrg   outm( AGP_CNTL, cntl );
75132b578d3Smrg
75232b578d3Smrg   return TRUE;
75332b578d3Smrg}
75432b578d3Smrg
75532b578d3Smrgstatic Bool ATIDRIPciInit( ScreenPtr pScreen )
75632b578d3Smrg{
757e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
75832b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
75932b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
76032b578d3Smrg
76132b578d3Smrg   pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE;
76232b578d3Smrg   pATIDRIServer->ringSize = 16; /* 16 kB ring */
76332b578d3Smrg
76432b578d3Smrg   if ( !ATIDRISetBufSize( pScreen, (unsigned)(-1) ) )
76532b578d3Smrg      return FALSE;
76632b578d3Smrg
76732b578d3Smrg   /* Set size of the DMA descriptor ring */
76832b578d3Smrg   pATIDRIServer->ringStart   = 0;
76932b578d3Smrg   pATIDRIServer->ringMapSize = pATIDRIServer->ringSize*1024; /* ringSize is in kB */
77032b578d3Smrg
77132b578d3Smrg   /* Set size of the vertex buffer */
77232b578d3Smrg   pATIDRIServer->bufferStart   = 0;
77332b578d3Smrg   pATIDRIServer->bufferMapSize = pATIDRIServer->bufferSize*1024*1024;
77432b578d3Smrg
77532b578d3Smrg   /* Map DMA descriptor ring */
77632b578d3Smrg   if ( drmAddMap( pATI->drmFD, 0, pATIDRIServer->ringMapSize,
77732b578d3Smrg		   DRM_CONSISTENT, DRM_RESTRICTED, &pATIDRIServer->ringHandle ) < 0 ) {
77832b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
77932b578d3Smrg		  "[pci] Could not add ring mapping\n" );
78032b578d3Smrg      return FALSE;
78132b578d3Smrg   }
78232b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO, "[pci] ring handle = 0x%08x\n",
78332b578d3Smrg	       pATIDRIServer->ringHandle );
78432b578d3Smrg
78532b578d3Smrg   if ( drmMap( pATI->drmFD, pATIDRIServer->ringHandle,
78632b578d3Smrg		pATIDRIServer->ringMapSize, &pATIDRIServer->ringMap ) < 0 ) {
78732b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
78832b578d3Smrg		  "[pci] Could not map ring\n" );
78932b578d3Smrg      return FALSE;
79032b578d3Smrg   }
79132b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
79232b578d3Smrg	       "[pci] Ring mapped at 0x%08lx\n",
79332b578d3Smrg	       (unsigned long)pATIDRIServer->ringMap );
79432b578d3Smrg
79532b578d3Smrg   /* Disable AGP for ForcePCIMode */
79632b578d3Smrg   if ( pATI->BusType != ATI_BUS_PCI ) {
79732b578d3Smrg       outm( AGP_BASE, 0 );
79832b578d3Smrg       outm( AGP_CNTL, 0 );
79932b578d3Smrg   }
80032b578d3Smrg
80132b578d3Smrg   return TRUE;
80232b578d3Smrg}
80332b578d3Smrg
80432b578d3Smrg/* Add a map for the MMIO registers that will be accessed by any
80532b578d3Smrg * DRI-based clients.
80632b578d3Smrg */
80732b578d3Smrgstatic Bool ATIDRIMapInit( ScreenPtr pScreen )
80832b578d3Smrg{
809e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
81032b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
81132b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
81232b578d3Smrg
81332b578d3Smrg   pATIDRIServer->regsSize = getpagesize();
81432b578d3Smrg   if ( drmAddMap( pATI->drmFD, pATI->Block1Base,
81532b578d3Smrg		   pATIDRIServer->regsSize,
81632b578d3Smrg		   DRM_REGISTERS, DRM_READ_ONLY,
81732b578d3Smrg		   &pATIDRIServer->regsHandle ) < 0 ) {
81832b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
81932b578d3Smrg		  "[drm] failed to map registers\n" );
82032b578d3Smrg      return FALSE;
82132b578d3Smrg   }
82232b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
82332b578d3Smrg	       "[drm] register handle = 0x%08x\n",
82432b578d3Smrg	       pATIDRIServer->regsHandle );
82532b578d3Smrg
82632b578d3Smrg   return TRUE;
82732b578d3Smrg}
82832b578d3Smrg
82932b578d3Smrg/* Initialize the kernel data structures. */
83032b578d3Smrgstatic Bool ATIDRIKernelInit( ScreenPtr pScreen )
83132b578d3Smrg{
832e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
83332b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
83432b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
83532b578d3Smrg   drmMach64Init info;
83632b578d3Smrg
83732b578d3Smrg   memset( &info, 0, sizeof(drmMach64Init) );
83832b578d3Smrg
83932b578d3Smrg   info.func 			= DRM_MACH64_INIT_DMA;
84032b578d3Smrg   info.sarea_priv_offset	= sizeof(XF86DRISAREARec);
84132b578d3Smrg   info.is_pci			= pATIDRIServer->IsPCI;
84232b578d3Smrg   info.dma_mode                = pATI->OptionDMAMode;
84332b578d3Smrg
84432b578d3Smrg   info.fb_bpp			= pATI->bitsPerPixel;
84532b578d3Smrg   info.front_offset		= pATIDRIServer->frontOffset;
84632b578d3Smrg   info.front_pitch		= pATIDRIServer->frontPitch;
84732b578d3Smrg   info.back_offset		= pATIDRIServer->backOffset;
84832b578d3Smrg   info.back_pitch		= pATIDRIServer->backPitch;
84932b578d3Smrg
85032b578d3Smrg   info.depth_bpp		= 16;
85132b578d3Smrg   info.depth_offset		= pATIDRIServer->depthOffset;
85232b578d3Smrg   info.depth_pitch		= pATIDRIServer->depthPitch;
85332b578d3Smrg
85432b578d3Smrg   info.fb_offset		= pATI->LinearBase;
85532b578d3Smrg   info.mmio_offset		= pATIDRIServer->regsHandle;
85632b578d3Smrg   info.ring_offset		= pATIDRIServer->ringHandle;
85732b578d3Smrg   info.buffers_offset		= pATIDRIServer->bufferHandle;
85832b578d3Smrg   info.agp_textures_offset	= pATIDRIServer->agpTexHandle;
85932b578d3Smrg
86032b578d3Smrg   if ( drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT,
86132b578d3Smrg			 &info, sizeof(drmMach64Init) ) < 0 ) {
86232b578d3Smrg      return FALSE;
86332b578d3Smrg   } else {
86432b578d3Smrg      return TRUE;
86532b578d3Smrg   }
86632b578d3Smrg}
86732b578d3Smrg
86832b578d3Smrg/* Add a map for the DMA buffers that will be accessed by any
86932b578d3Smrg * DRI-based clients.
87032b578d3Smrg */
87132b578d3Smrgstatic Bool ATIDRIAddBuffers( ScreenPtr pScreen )
87232b578d3Smrg{
873e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
87432b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
87532b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
87632b578d3Smrg
87732b578d3Smrg   /* Initialize vertex buffers */
87832b578d3Smrg   if ( pATIDRIServer->IsPCI ) {
87932b578d3Smrg      pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD,
88032b578d3Smrg					      pATIDRIServer->bufferMapSize/MACH64_BUFFER_SIZE,
88132b578d3Smrg					      MACH64_BUFFER_SIZE,
88232b578d3Smrg					      DRM_PCI_BUFFER_RO,
88332b578d3Smrg					      0 );
88432b578d3Smrg   } else {
88532b578d3Smrg      pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD,
88632b578d3Smrg					      pATIDRIServer->bufferMapSize/MACH64_BUFFER_SIZE,
88732b578d3Smrg					      MACH64_BUFFER_SIZE,
88832b578d3Smrg					      DRM_AGP_BUFFER,
88932b578d3Smrg					      pATIDRIServer->bufferStart );
89032b578d3Smrg   }
89132b578d3Smrg   if ( pATIDRIServer->numBuffers <= 0 ) {
89232b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
89332b578d3Smrg		  "[drm] Could not create DMA buffers list\n" );
89432b578d3Smrg      return FALSE;
89532b578d3Smrg   }
89632b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
89732b578d3Smrg	       "[drm] Added %d %d byte DMA buffers\n",
89832b578d3Smrg	       pATIDRIServer->numBuffers, MACH64_BUFFER_SIZE );
89932b578d3Smrg
90032b578d3Smrg    return TRUE;
90132b578d3Smrg}
90232b578d3Smrg
90332b578d3Smrgstatic Bool ATIDRIMapBuffers( ScreenPtr pScreen )
90432b578d3Smrg{
905e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
90632b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
90732b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
90832b578d3Smrg
90932b578d3Smrg   pATIDRIServer->drmBuffers = drmMapBufs( pATI->drmFD );
91032b578d3Smrg   if ( !pATIDRIServer->drmBuffers ) {
91132b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
91232b578d3Smrg		  "[drm] Failed to map DMA buffers list\n" );
91332b578d3Smrg      return FALSE;
91432b578d3Smrg   }
91532b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
91632b578d3Smrg	       "[drm] Mapped %d DMA buffers at 0x%08lx\n",
91732b578d3Smrg	       pATIDRIServer->drmBuffers->count,
91832b578d3Smrg	       (unsigned long)pATIDRIServer->drmBuffers->list->address );
91932b578d3Smrg
92032b578d3Smrg   return TRUE;
92132b578d3Smrg}
92232b578d3Smrg
92332b578d3Smrgstatic Bool ATIDRIIrqInit( ScreenPtr pScreen )
92432b578d3Smrg{
925e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
92632b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
92732b578d3Smrg
92832b578d3Smrg   if ( pATI->irq <= 0 ) {
92932b578d3Smrg      pATI->irq = drmGetInterruptFromBusID(pATI->drmFD,
93032b578d3Smrg					   PCI_CFG_BUS(pATI->PCIInfo),
93132b578d3Smrg					   PCI_CFG_DEV(pATI->PCIInfo),
93232b578d3Smrg					   PCI_CFG_FUNC(pATI->PCIInfo));
93332b578d3Smrg      if ( pATI->irq <= 0 ) {
93432b578d3Smrg	 xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
93532b578d3Smrg		    "[drm] Couldn't find IRQ for bus id %d:%d:%d\n",
93632b578d3Smrg		    PCI_CFG_BUS(pATI->PCIInfo),
93732b578d3Smrg		    PCI_CFG_DEV(pATI->PCIInfo),
93832b578d3Smrg		    PCI_CFG_FUNC(pATI->PCIInfo));
93932b578d3Smrg	 pATI->irq = 0;
94032b578d3Smrg      } else if ((drmCtlInstHandler(pATI->drmFD, pATI->irq)) != 0) {
94132b578d3Smrg 	 xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
94232b578d3Smrg		    "[drm] Failed to initialize interrupt handler with IRQ %d\n",
94332b578d3Smrg		    pATI->irq);
94432b578d3Smrg	 pATI->irq = 0;
94532b578d3Smrg      }
94632b578d3Smrg
94732b578d3Smrg      if (pATI->irq)
94832b578d3Smrg	 xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
94932b578d3Smrg		    "[drm] Installed interrupt handler, using IRQ %d\n",
95032b578d3Smrg		    pATI->irq);
95132b578d3Smrg      else {
95232b578d3Smrg	 xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
95332b578d3Smrg		    "[drm] Falling back to irq-free operation\n");
95432b578d3Smrg	 return FALSE;
95532b578d3Smrg      }
95632b578d3Smrg   }
95732b578d3Smrg
95832b578d3Smrg   return TRUE;
95932b578d3Smrg
96032b578d3Smrg}
96132b578d3Smrg
96232b578d3Smrg/* Initialize the screen-specific data structures for the DRI and the
96332b578d3Smrg * Rage Pro.  This is the main entry point to the device-specific
96432b578d3Smrg * initialization code.  It calls device-independent DRI functions to
96532b578d3Smrg * create the DRI data structures and initialize the DRI state.
96632b578d3Smrg */
96732b578d3SmrgBool ATIDRIScreenInit( ScreenPtr pScreen )
96832b578d3Smrg{
969e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
97032b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
97132b578d3Smrg   DRIInfoPtr pDRIInfo;
97232b578d3Smrg   ATIDRIPtr pATIDRI;
97332b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer;
97432b578d3Smrg   drmVersionPtr version;
97532b578d3Smrg   int major, minor, patch;
97632b578d3Smrg
9770b0ce0bfSmrg   /* Check that the DRI, and DRM modules have been loaded by testing
97832b578d3Smrg    * for known symbols in each module.
97932b578d3Smrg    */
98032b578d3Smrg   if ( !xf86LoaderCheckSymbol("drmAvailable") ) return FALSE;
98132b578d3Smrg   if ( !xf86LoaderCheckSymbol("DRIQueryVersion") ) {
98232b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
98332b578d3Smrg		  "[dri] ATIDRIScreenInit failed (libdri.a too old)\n" );
98432b578d3Smrg      return FALSE;
98532b578d3Smrg   }
98632b578d3Smrg
98732b578d3Smrg   /* Check the DRI version */
98832b578d3Smrg   DRIQueryVersion( &major, &minor, &patch );
98932b578d3Smrg   if ( major != DRIINFO_MAJOR_VERSION || minor < 0 ) {
99032b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
99132b578d3Smrg		  "[dri] ATIDRIScreenInit failed because of a version mismatch.\n"
99232b578d3Smrg		  "[dri] libdri version is %d.%d.%d but version %d.%d.x is needed.\n"
99332b578d3Smrg		  "[dri] Disabling the DRI.\n",
99432b578d3Smrg		  major, minor, patch,
99532b578d3Smrg                  DRIINFO_MAJOR_VERSION, 0 );
99632b578d3Smrg      return FALSE;
99732b578d3Smrg   }
99832b578d3Smrg
99932b578d3Smrg   switch ( pATI->bitsPerPixel ) {
100032b578d3Smrg   case 8:
100132b578d3Smrg      /* These modes are not supported (yet). */
100232b578d3Smrg   case 15:
100332b578d3Smrg   case 24:
100432b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
100532b578d3Smrg		  "[dri] Direct rendering only supported in 16 and 32 bpp modes\n");
100632b578d3Smrg      return FALSE;
100732b578d3Smrg
100832b578d3Smrg      /* Only 16 and 32 color depths are supported currently. */
100932b578d3Smrg   case 16:
101032b578d3Smrg      if ( pATI->depth != 16) {
101132b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_ERROR,
101232b578d3Smrg		  "[dri] Direct rendering not supported for depth %d at fbbpp 16.\n", pATI->depth );
101332b578d3Smrg	 return FALSE;
101432b578d3Smrg      }
101532b578d3Smrg      break;
101632b578d3Smrg   case 32:
101732b578d3Smrg      break;
101832b578d3Smrg   }
101932b578d3Smrg
102032b578d3Smrg   /* Create the DRI data structure, and fill it in before calling the
102132b578d3Smrg    * DRIScreenInit().
102232b578d3Smrg    */
102332b578d3Smrg   pDRIInfo = DRICreateInfoRec();
102432b578d3Smrg   if ( !pDRIInfo ) return FALSE;
102532b578d3Smrg
102632b578d3Smrg   pATI->pDRIInfo = pDRIInfo;
102732b578d3Smrg   pDRIInfo->drmDriverName = ATIKernelDriverName;
102832b578d3Smrg   pDRIInfo->clientDriverName = ATIClientDriverName;
102932b578d3Smrg   if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
103032b578d3Smrg      pDRIInfo->busIdString = DRICreatePCIBusID(pATI->PCIInfo);
103132b578d3Smrg   } else {
10321b12faf6Smrg      pDRIInfo->busIdString = malloc( 64 );
103332b578d3Smrg      sprintf( pDRIInfo->busIdString,
103432b578d3Smrg	       "PCI:%d:%d:%d",
103532b578d3Smrg	       PCI_DEV_BUS(pATI->PCIInfo),
103632b578d3Smrg	       PCI_DEV_DEV(pATI->PCIInfo),
103732b578d3Smrg	       PCI_DEV_FUNC(pATI->PCIInfo) );
103832b578d3Smrg   }
103932b578d3Smrg   pDRIInfo->ddxDriverMajorVersion = MACH64_VERSION_MAJOR;
104032b578d3Smrg   pDRIInfo->ddxDriverMinorVersion = MACH64_VERSION_MINOR;
104132b578d3Smrg   pDRIInfo->ddxDriverPatchVersion = MACH64_VERSION_PATCH;
104232b578d3Smrg   pDRIInfo->frameBufferPhysicalAddress = (void *)pATI->LinearBase;
104332b578d3Smrg   pDRIInfo->frameBufferSize = pATI->LinearSize;
104432b578d3Smrg   pDRIInfo->frameBufferStride = (pScreenInfo->displayWidth *
104532b578d3Smrg				  pATI->FBBytesPerPixel);
104632b578d3Smrg   pDRIInfo->ddxDrawableTableEntry = ATI_MAX_DRAWABLES;
104732b578d3Smrg
104832b578d3Smrg   if ( SAREA_MAX_DRAWABLES < ATI_MAX_DRAWABLES ) {
104932b578d3Smrg      pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
105032b578d3Smrg   } else {
105132b578d3Smrg      pDRIInfo->maxDrawableTableEntry = ATI_MAX_DRAWABLES;
105232b578d3Smrg   }
105332b578d3Smrg
105432b578d3Smrg   /* For now the mapping works by using a fixed size defined
105532b578d3Smrg    * in the SAREA header
105632b578d3Smrg    */
105732b578d3Smrg   if ( sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec) > SAREA_MAX ) {
105832b578d3Smrg      ErrorF( "[dri] Data does not fit in SAREA\n" );
105932b578d3Smrg      return FALSE;
106032b578d3Smrg   }
106132b578d3Smrg   xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, "[drm] SAREA %u+%u: %u\n",
106232b578d3Smrg	       (unsigned)sizeof(XF86DRISAREARec),
106332b578d3Smrg	       (unsigned)sizeof(ATISAREAPrivRec),
106432b578d3Smrg	       (unsigned)(sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec)) );
106532b578d3Smrg   pDRIInfo->SAREASize = SAREA_MAX;
106632b578d3Smrg
106732b578d3Smrg   pATIDRI = (ATIDRIPtr) xnfcalloc( sizeof(ATIDRIRec), 1 );
106832b578d3Smrg   if ( !pATIDRI ) {
106932b578d3Smrg      DRIDestroyInfoRec( pATI->pDRIInfo );
107032b578d3Smrg      pATI->pDRIInfo = NULL;
107132b578d3Smrg      xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR,
107232b578d3Smrg		  "[dri] Failed to allocate memory for private record\n" );
107332b578d3Smrg      return FALSE;
107432b578d3Smrg   }
107532b578d3Smrg   pATIDRIServer = (ATIDRIServerInfoPtr)
107632b578d3Smrg      xnfcalloc( sizeof(ATIDRIServerInfoRec), 1 );
107732b578d3Smrg   if ( !pATIDRIServer ) {
10781b12faf6Smrg      free( pATIDRI );
107932b578d3Smrg      DRIDestroyInfoRec( pATI->pDRIInfo );
108032b578d3Smrg      pATI->pDRIInfo = NULL;
108132b578d3Smrg      xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR,
108232b578d3Smrg		  "[dri] Failed to allocate memory for private record\n" );
108332b578d3Smrg      return FALSE;
108432b578d3Smrg   }
108532b578d3Smrg
108632b578d3Smrg   pATI->pDRIServerInfo = pATIDRIServer;
108732b578d3Smrg
108832b578d3Smrg   pDRIInfo->devPrivate		= pATIDRI;
108932b578d3Smrg   pDRIInfo->devPrivateSize	= sizeof(ATIDRIRec);
109032b578d3Smrg   pDRIInfo->contextSize	= sizeof(ATIDRIContextRec);
109132b578d3Smrg
109232b578d3Smrg   pDRIInfo->CreateContext	= ATICreateContext;
109332b578d3Smrg   pDRIInfo->DestroyContext	= ATIDestroyContext;
109432b578d3Smrg   pDRIInfo->SwapContext	= ATIDRISwapContext;
109532b578d3Smrg   pDRIInfo->InitBuffers	= ATIDRIInitBuffers;
109632b578d3Smrg   pDRIInfo->MoveBuffers	= ATIDRIMoveBuffers;
109732b578d3Smrg#ifdef USE_XAA
109832b578d3Smrg   if (!pATI->useEXA) {
109932b578d3Smrg      pDRIInfo->TransitionTo2d  = ATIDRITransitionTo2d;
110032b578d3Smrg      pDRIInfo->TransitionTo3d  = ATIDRITransitionTo3d;
110132b578d3Smrg   }
110232b578d3Smrg#endif /* USE_XAA */
110332b578d3Smrg#ifdef USE_EXA
110432b578d3Smrg   if (pATI->useEXA) {
110532b578d3Smrg      pDRIInfo->TransitionTo2d  = ATIDRITransitionTo2d_EXA;
110632b578d3Smrg      pDRIInfo->TransitionTo3d  = ATIDRITransitionTo3d_EXA;
110732b578d3Smrg   }
110832b578d3Smrg#endif /* USE_EXA */
110932b578d3Smrg   pDRIInfo->bufferRequests	= DRI_ALL_WINDOWS;
111032b578d3Smrg
111132b578d3Smrg   pDRIInfo->createDummyCtx     = TRUE;
111232b578d3Smrg   pDRIInfo->createDummyCtxPriv = FALSE;
111332b578d3Smrg
111432b578d3Smrg   pATI->have3DWindows = FALSE;
111532b578d3Smrg
111632b578d3Smrg   if ( !DRIScreenInit( pScreen, pDRIInfo, &pATI->drmFD ) ) {
11171b12faf6Smrg      free( pATIDRIServer );
111832b578d3Smrg      pATI->pDRIServerInfo = NULL;
11191b12faf6Smrg      free( pDRIInfo->devPrivate );
112032b578d3Smrg      pDRIInfo->devPrivate = NULL;
112132b578d3Smrg      DRIDestroyInfoRec( pDRIInfo );
112232b578d3Smrg      pDRIInfo = NULL;
112332b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_ERROR,
112432b578d3Smrg		  "[dri] DRIScreenInit Failed\n" );
112532b578d3Smrg      return FALSE;
112632b578d3Smrg   }
112732b578d3Smrg
112832b578d3Smrg   /* Check the DRM lib version.
112932b578d3Smrg      drmGetLibVersion was not supported in version 1.0, so check for
113032b578d3Smrg      symbol first to avoid possible crash or hang.
113132b578d3Smrg   */
113232b578d3Smrg   if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
113332b578d3Smrg      version = drmGetLibVersion(pATI->drmFD);
113432b578d3Smrg   } else {
113532b578d3Smrg      /* drmlib version 1.0.0 didn't have the drmGetLibVersion
113632b578d3Smrg	 entry point.  Fake it by allocating a version record
113732b578d3Smrg	 via drmGetVersion and changing it to version 1.0.0
113832b578d3Smrg      */
113932b578d3Smrg      version = drmGetVersion(pATI->drmFD);
114032b578d3Smrg      version->version_major      = 1;
114132b578d3Smrg      version->version_minor      = 0;
114232b578d3Smrg      version->version_patchlevel = 0;
114332b578d3Smrg   }
114432b578d3Smrg
114532b578d3Smrg   if (version) {
114632b578d3Smrg      if (version->version_major != 1 ||
114732b578d3Smrg	  version->version_minor < 1) {
114832b578d3Smrg	 /* incompatible drm library version */
114932b578d3Smrg	 xf86DrvMsg(pScreen->myNum, X_ERROR,
115032b578d3Smrg		    "[dri] ATIDRIScreenInit failed because of a version mismatch.\n"
115132b578d3Smrg		    "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n"
115232b578d3Smrg		    "[dri] Disabling DRI.\n",
115332b578d3Smrg		    version->version_major,
115432b578d3Smrg		    version->version_minor,
115532b578d3Smrg		    version->version_patchlevel);
115632b578d3Smrg	 drmFreeVersion(version);
115732b578d3Smrg	 ATIDRICloseScreen(pScreen);
115832b578d3Smrg	 return FALSE;
115932b578d3Smrg      }
116032b578d3Smrg      drmFreeVersion(version);
116132b578d3Smrg   }
116232b578d3Smrg
116332b578d3Smrg   /* Check the mach64 DRM version */
116432b578d3Smrg   version = drmGetVersion( pATI->drmFD );
116532b578d3Smrg   if ( version ) {
116632b578d3Smrg      if ( version->version_major != 2 ||
116732b578d3Smrg	   version->version_minor < 0 ) {
116832b578d3Smrg	 /* Incompatible DRM version */
116932b578d3Smrg	 xf86DrvMsg( pScreen->myNum, X_ERROR,
117032b578d3Smrg		     "[dri] ATIDRIScreenInit failed because of a version mismatch.\n"
117132b578d3Smrg		     "[dri] mach64.o kernel module version is %d.%d.%d, but version 2.x is needed (with 2.x >= 2.0).\n"
117232b578d3Smrg		     "[dri] Disabling DRI.\n",
117332b578d3Smrg		     version->version_major,
117432b578d3Smrg		     version->version_minor,
117532b578d3Smrg		     version->version_patchlevel );
117632b578d3Smrg	 drmFreeVersion( version );
117732b578d3Smrg	 ATIDRICloseScreen( pScreen );
117832b578d3Smrg	 return FALSE;
117932b578d3Smrg      }
118032b578d3Smrg      drmFreeVersion( version );
118132b578d3Smrg   }
118232b578d3Smrg
118332b578d3Smrg   switch ( pATI->OptionDMAMode ) {
118432b578d3Smrg   case MACH64_MODE_DMA_ASYNC:
118532b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request asynchronous DMA mode\n");
118632b578d3Smrg      break;
118732b578d3Smrg   case MACH64_MODE_DMA_SYNC:
118832b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request synchronous DMA mode\n");
118932b578d3Smrg      break;
119032b578d3Smrg   case MACH64_MODE_MMIO:
119132b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request pseudo-DMA (MMIO) mode\n");
119232b578d3Smrg      break;
119332b578d3Smrg   default:
119432b578d3Smrg      xf86DrvMsg(pScreen->myNum, X_WARNING, "[drm] Unknown DMA mode\n");
119532b578d3Smrg   }
119632b578d3Smrg
119732b578d3Smrg   pATIDRIServer->IsPCI = (pATI->BusType == ATI_BUS_PCI || pATI->OptionIsPCI) ? TRUE : FALSE;
119832b578d3Smrg
119932b578d3Smrg   if ( pATI->BusType != ATI_BUS_PCI && pATI->OptionIsPCI ) {
120032b578d3Smrg       xf86DrvMsg(pScreen->myNum, X_CONFIG, "[dri] Forcing PCI mode\n");
120132b578d3Smrg   }
120232b578d3Smrg
120332b578d3Smrg   /* Initialize AGP */
120432b578d3Smrg   if ( !pATIDRIServer->IsPCI && !ATIDRIAgpInit( pScreen ) ) {
120532b578d3Smrg      pATIDRIServer->IsPCI = TRUE;
120632b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP failed to initialize -- falling back to PCI mode.\n" );
120732b578d3Smrg      xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Make sure you have the agpgart kernel module loaded.\n" );
120832b578d3Smrg   }
120932b578d3Smrg
121032b578d3Smrg   /* Initialize PCI */
121132b578d3Smrg   if ( pATIDRIServer->IsPCI && !ATIDRIPciInit( pScreen ) ) {
121232b578d3Smrg      ATIDRICloseScreen( pScreen );
121332b578d3Smrg      return FALSE;
121432b578d3Smrg   }
121532b578d3Smrg
121632b578d3Smrg   if ( !ATIDRIMapInit( pScreen ) ) {
121732b578d3Smrg      ATIDRICloseScreen( pScreen );
121832b578d3Smrg      return FALSE;
121932b578d3Smrg   }
122032b578d3Smrg
122132b578d3Smrg   xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO,
122232b578d3Smrg	       "[dri] Visual configs initialized\n" );
122332b578d3Smrg
122432b578d3Smrg   xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO,
122532b578d3Smrg	       "[dri] Block 0 base at 0x%08lx\n", pATI->Block0Base );
122632b578d3Smrg
122732b578d3Smrg   return TRUE;
122832b578d3Smrg}
122932b578d3Smrg
123032b578d3Smrg/* Finish initializing the device-dependent DRI state, and call
123132b578d3Smrg * DRIFinishScreenInit() to complete the device-independent DRI
123232b578d3Smrg * initialization.
123332b578d3Smrg */
123432b578d3SmrgBool ATIDRIFinishScreenInit( ScreenPtr pScreen )
123532b578d3Smrg{
1236e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
123732b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
123832b578d3Smrg   ATISAREAPrivPtr pSAREAPriv;
123932b578d3Smrg   ATIDRIPtr pATIDRI;
124032b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer;
124132b578d3Smrg
124232b578d3Smrg   pATI->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
124332b578d3Smrg
124432b578d3Smrg   /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
124532b578d3Smrg    * because *DRIKernelInit requires that the hardware lock is held by
124632b578d3Smrg    * the X server, and the first time the hardware lock is grabbed is
124732b578d3Smrg    * in DRIFinishScreenInit.
124832b578d3Smrg    */
124932b578d3Smrg   if ( !DRIFinishScreenInit( pScreen ) ) {
125032b578d3Smrg      ATIDRICloseScreen( pScreen );
125132b578d3Smrg      return FALSE;
125232b578d3Smrg   }
125332b578d3Smrg
125432b578d3Smrg   /* Initialize the DMA buffer list */
125532b578d3Smrg   /* Need to do this before ATIDRIKernelInit so we can init the freelist */
125632b578d3Smrg   if ( !ATIDRIAddBuffers( pScreen ) ) {
125732b578d3Smrg      ATIDRICloseScreen( pScreen );
125832b578d3Smrg      return FALSE;
125932b578d3Smrg   }
126032b578d3Smrg
126132b578d3Smrg   /* Initialize the kernel data structures */
126232b578d3Smrg   if ( !ATIDRIKernelInit( pScreen ) ) {
126332b578d3Smrg      xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
126432b578d3Smrg		 "[drm] Failed to initialize the mach64.o kernel module\n");
126532b578d3Smrg      xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
126632b578d3Smrg		 "[drm] Check the system log for more information.\n");
126732b578d3Smrg      ATIDRICloseScreen( pScreen );
126832b578d3Smrg      return FALSE;
126932b578d3Smrg   }
127032b578d3Smrg
127132b578d3Smrg   if ( !ATIDRIMapBuffers( pScreen ) ) {
127232b578d3Smrg      ATIDRICloseScreen( pScreen );
127332b578d3Smrg      return FALSE;
127432b578d3Smrg   }
127532b578d3Smrg
127632b578d3Smrg   /* Initialize IRQ */
127732b578d3Smrg   ATIDRIIrqInit( pScreen );
127832b578d3Smrg
127932b578d3Smrg   pSAREAPriv = (ATISAREAPrivPtr) DRIGetSAREAPrivate( pScreen );
128032b578d3Smrg   memset( pSAREAPriv, 0, sizeof(*pSAREAPriv) );
128132b578d3Smrg
128232b578d3Smrg   pATIDRI = (ATIDRIPtr)pATI->pDRIInfo->devPrivate;
128332b578d3Smrg   pATIDRIServer = pATI->pDRIServerInfo;
128432b578d3Smrg
128532b578d3Smrg   pATIDRI->width = pScreenInfo->virtualX;
128632b578d3Smrg   pATIDRI->height = pScreenInfo->virtualY;
128732b578d3Smrg   pATIDRI->mem = pScreenInfo->videoRam * 1024;
128832b578d3Smrg   pATIDRI->cpp = pScreenInfo->bitsPerPixel / 8;
128932b578d3Smrg
129032b578d3Smrg   pATIDRI->IsPCI = pATIDRIServer->IsPCI;
129132b578d3Smrg   pATIDRI->AGPMode = pATIDRIServer->agpMode;
129232b578d3Smrg
129332b578d3Smrg   pATIDRI->frontOffset = pATIDRIServer->frontOffset;
129432b578d3Smrg   pATIDRI->frontPitch = pATIDRIServer->frontPitch;
129532b578d3Smrg
129632b578d3Smrg   pATIDRI->backOffset = pATIDRIServer->backOffset;
129732b578d3Smrg   pATIDRI->backPitch = pATIDRIServer->backPitch;
129832b578d3Smrg
129932b578d3Smrg   pATIDRI->depthOffset = pATIDRIServer->depthOffset;
130032b578d3Smrg   pATIDRI->depthPitch = pATIDRIServer->depthPitch;
130132b578d3Smrg
130232b578d3Smrg   pATIDRI->textureOffset = pATIDRIServer->textureOffset;
130332b578d3Smrg   pATIDRI->textureSize	= pATIDRIServer->textureSize;
130432b578d3Smrg   pATIDRI->logTextureGranularity = pATIDRIServer->logTextureGranularity;
130532b578d3Smrg
130632b578d3Smrg   pATIDRI->regs = pATIDRIServer->regsHandle;
130732b578d3Smrg   pATIDRI->regsSize = pATIDRIServer->regsSize;
130832b578d3Smrg
130932b578d3Smrg   pATIDRI->agp = pATIDRIServer->agpTexHandle;
131032b578d3Smrg   pATIDRI->agpSize = pATIDRIServer->agpTexMapSize;
131132b578d3Smrg   pATIDRI->logAgpTextureGranularity = pATIDRIServer->log2AGPTexGran;
131232b578d3Smrg   pATIDRI->agpTextureOffset = pATIDRIServer->agpTexStart;
131332b578d3Smrg
131432b578d3Smrg   return TRUE;
131532b578d3Smrg}
131632b578d3Smrg
131732b578d3Smrg/*
131832b578d3Smrg * This function will attempt to get the Mach64 hardware back into shape
131932b578d3Smrg * after a resume from disc. Its an extract from ATIDRIAgpInit and ATIDRIFinishScreenInit
132032b578d3Smrg * This also calls a new ioctl in the mach64 DRM that in its turn is
132132b578d3Smrg * an extraction of the hardware-affecting bits from mach64_do_init_drm()
132232b578d3Smrg * (see atidrm.c)
132332b578d3Smrg * I am assuming here that pATI->pDRIServerInfo doesn't change
13240b0ce0bfSmrg * elsewhere in incompatible ways.
132532b578d3Smrg * How will this code react to resuming after a failed resumeor pci based dri ?
132632b578d3Smrg */
132732b578d3Smrgvoid ATIDRIResume( ScreenPtr pScreen )
132832b578d3Smrg{
1329e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
133032b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
133132b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
133232b578d3Smrg
133332b578d3Smrg   xf86DrvMsg( pScreen->myNum, X_INFO,
133432b578d3Smrg		 "[RESUME] Attempting to re-init Mach64 hardware.\n");
133532b578d3Smrg
133632b578d3Smrg   if (!pATIDRIServer->IsPCI) {
133732b578d3Smrg      if (!ATIDRISetAgpMode(pScreen))
133832b578d3Smrg      return;
133932b578d3Smrg
134032b578d3Smrg      outm( AGP_BASE, drmAgpBase(pATI->drmFD) );
134132b578d3Smrg   }
134232b578d3Smrg}
134332b578d3Smrg
134432b578d3Smrg/* The screen is being closed, so clean up any state and free any
134532b578d3Smrg * resources used by the DRI.
134632b578d3Smrg */
134732b578d3Smrgvoid ATIDRICloseScreen( ScreenPtr pScreen )
134832b578d3Smrg{
1349e35d4d8eSmrg   ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen);
135032b578d3Smrg   ATIPtr pATI = ATIPTR(pScreenInfo);
135132b578d3Smrg   ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo;
135232b578d3Smrg   drmMach64Init info;
135332b578d3Smrg
135432b578d3Smrg   /* Stop interrupt generation and handling if used */
135532b578d3Smrg   if ( pATI->irq > 0 ) {
135632b578d3Smrg      if ( drmCtlUninstHandler(pATI->drmFD) != 0 ) {
135732b578d3Smrg	 xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
135832b578d3Smrg		    "[drm] Error uninstalling interrupt handler for IRQ %d\n", pATI->irq);
135932b578d3Smrg      } else {
136032b578d3Smrg	 xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,
136132b578d3Smrg		    "[drm] Uninstalled interrupt handler for IRQ %d\n", pATI->irq);
136232b578d3Smrg      }
136332b578d3Smrg      pATI->irq = 0;
136432b578d3Smrg   }
136532b578d3Smrg
136632b578d3Smrg   /* De-allocate DMA buffers */
136732b578d3Smrg   if ( pATIDRIServer->drmBuffers ) {
136832b578d3Smrg      drmUnmapBufs( pATIDRIServer->drmBuffers );
136932b578d3Smrg      pATIDRIServer->drmBuffers = NULL;
137032b578d3Smrg   }
137132b578d3Smrg
137232b578d3Smrg   /* De-allocate all kernel resources */
137332b578d3Smrg   memset(&info, 0, sizeof(drmMach64Init));
137432b578d3Smrg   info.func = DRM_MACH64_CLEANUP_DMA;
137532b578d3Smrg   drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT,
137632b578d3Smrg		    &info, sizeof(drmMach64Init) );
137732b578d3Smrg
137832b578d3Smrg   /* De-allocate all AGP resources */
137932b578d3Smrg   if ( pATIDRIServer->agpTexMap ) {
138032b578d3Smrg      drmUnmap( pATIDRIServer->agpTexMap, pATIDRIServer->agpTexMapSize );
138132b578d3Smrg      pATIDRIServer->agpTexMap = NULL;
138232b578d3Smrg   }
138332b578d3Smrg   if ( pATIDRIServer->bufferMap ) {
138432b578d3Smrg      drmUnmap( pATIDRIServer->bufferMap, pATIDRIServer->bufferMapSize );
138532b578d3Smrg      pATIDRIServer->bufferMap = NULL;
138632b578d3Smrg   }
138732b578d3Smrg   if ( pATIDRIServer->ringMap ) {
138832b578d3Smrg      drmUnmap( pATIDRIServer->ringMap, pATIDRIServer->ringMapSize );
138932b578d3Smrg      pATIDRIServer->ringMap = NULL;
139032b578d3Smrg   }
139132b578d3Smrg   if ( pATIDRIServer->agpHandle ) {
139232b578d3Smrg      drmAgpUnbind( pATI->drmFD, pATIDRIServer->agpHandle );
139332b578d3Smrg      drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle );
139432b578d3Smrg      pATIDRIServer->agpHandle = 0;
139532b578d3Smrg      drmAgpRelease( pATI->drmFD );
139632b578d3Smrg   }
139732b578d3Smrg
139832b578d3Smrg   /* De-allocate all PCI resources */
139932b578d3Smrg   if ( pATIDRIServer->IsPCI && pATIDRIServer->ringHandle ) {
140032b578d3Smrg      drmRmMap( pATI->drmFD, pATIDRIServer->ringHandle );
140132b578d3Smrg      pATIDRIServer->ringHandle = 0;
140232b578d3Smrg   }
140332b578d3Smrg
140432b578d3Smrg   /* De-allocate all DRI resources */
140532b578d3Smrg   DRICloseScreen( pScreen );
140632b578d3Smrg
140732b578d3Smrg   /* De-allocate all DRI data structures */
140832b578d3Smrg   if ( pATI->pDRIInfo ) {
140932b578d3Smrg      if ( pATI->pDRIInfo->devPrivate ) {
14101b12faf6Smrg	 free( pATI->pDRIInfo->devPrivate );
141132b578d3Smrg	 pATI->pDRIInfo->devPrivate = NULL;
141232b578d3Smrg      }
141332b578d3Smrg      DRIDestroyInfoRec( pATI->pDRIInfo );
141432b578d3Smrg      pATI->pDRIInfo = NULL;
141532b578d3Smrg   }
141632b578d3Smrg   if ( pATI->pDRIServerInfo ) {
14171b12faf6Smrg      free( pATI->pDRIServerInfo );
141832b578d3Smrg      pATI->pDRIServerInfo = NULL;
141932b578d3Smrg   }
142032b578d3Smrg}
1421