/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ /* * Copyright 2000 Gareth Hughes * 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 NONINFRINGEMENT. IN NO EVENT SHALL * GARETH HUGHES 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. */ /* * Authors: * Gareth Hughes * Leif Delgass */ /* Driver data structures */ #include "ati.h" #include "atibus.h" #include "atidri.h" #include "atiregs.h" #include "atistruct.h" #include "ativersion.h" #include "atimach64io.h" #include "mach64_dri.h" #include "mach64_common.h" #include "mach64_sarea.h" /* X and server generic header files */ #include "xf86.h" #include "windowstr.h" /* GLX/DRI/DRM definitions */ #define _XF86DRI_SERVER_ #include "GL/glxtokens.h" #include "sarea.h" static char ATIKernelDriverName[] = "mach64"; static char ATIClientDriverName[] = "mach64"; /* Initialize the visual configs that are supported by the hardware. * These are combined with the visual configs that the indirect * rendering core supports, and the intersection is exported to the * client. */ static Bool ATIInitVisualConfigs( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); int numConfigs = 0; __GLXvisualConfig *pConfigs = NULL; ATIConfigPrivPtr pATIConfigs = NULL; ATIConfigPrivPtr *pATIConfigPtrs = NULL; int i, accum, stencil, db; switch ( pATI->bitsPerPixel ) { case 8: /* 8bpp mode is not support */ case 15: /* FIXME */ case 24: /* FIXME */ xf86DrvMsg(pScreen->myNum, X_ERROR, "[dri] ATIInitVisualConfigs failed (%d bpp not supported). " "Disabling DRI.\n", pATI->bitsPerPixel); return FALSE; #define ATI_USE_ACCUM 1 #define ATI_USE_STENCIL 1 case 16: if ( pATI->depth != 16) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[dri] ATIInitVisualConfigs failed (depth %d at 16 bpp not supported). " "Disabling DRI.\n", pATI->depth); return FALSE; } numConfigs = 1; if ( ATI_USE_ACCUM ) numConfigs *= 2; if ( ATI_USE_STENCIL ) numConfigs *= 2; numConfigs *= 2; /* single- and double-buffered */ pConfigs = (__GLXvisualConfig*) xnfcalloc( sizeof(__GLXvisualConfig), numConfigs ); if ( !pConfigs ) { return FALSE; } pATIConfigs = (ATIConfigPrivPtr) xnfcalloc( sizeof(ATIConfigPrivRec), numConfigs ); if ( !pATIConfigs ) { xfree( pConfigs ); return FALSE; } pATIConfigPtrs = (ATIConfigPrivPtr*) xnfcalloc( sizeof(ATIConfigPrivPtr), numConfigs ); if ( !pATIConfigPtrs ) { xfree( pConfigs ); xfree( pATIConfigs ); return FALSE; } i = 0; for (db = 0; db <= 1; db++) { for ( accum = 0 ; accum <= ATI_USE_ACCUM ; accum++ ) { for ( stencil = 0 ; stencil <= ATI_USE_STENCIL ; stencil++ ) { pATIConfigPtrs[i] = &pATIConfigs[i]; pConfigs[i].vid = -1; pConfigs[i].class = -1; pConfigs[i].rgba = TRUE; pConfigs[i].redSize = 5; pConfigs[i].greenSize = 6; pConfigs[i].blueSize = 5; pConfigs[i].alphaSize = 0; pConfigs[i].redMask = 0x0000F800; pConfigs[i].greenMask = 0x000007E0; pConfigs[i].blueMask = 0x0000001F; pConfigs[i].alphaMask = 0x00000000; if ( accum ) { /* Simulated in software */ pConfigs[i].accumRedSize = 16; pConfigs[i].accumGreenSize = 16; pConfigs[i].accumBlueSize = 16; pConfigs[i].accumAlphaSize = 0; } else { pConfigs[i].accumRedSize = 0; pConfigs[i].accumGreenSize = 0; pConfigs[i].accumBlueSize = 0; pConfigs[i].accumAlphaSize = 0; } pConfigs[i].doubleBuffer = db ? TRUE : FALSE; pConfigs[i].stereo = FALSE; pConfigs[i].bufferSize = 16; pConfigs[i].depthSize = 16; if ( stencil ) { /* Simulated in software */ pConfigs[i].stencilSize = 8; } else { pConfigs[i].stencilSize = 0; } pConfigs[i].auxBuffers = 0; pConfigs[i].level = 0; if ( accum || stencil ) { pConfigs[i].visualRating = GLX_SLOW_CONFIG; } else { pConfigs[i].visualRating = GLX_NONE; } pConfigs[i].transparentPixel = GLX_NONE; pConfigs[i].transparentRed = 0; pConfigs[i].transparentGreen = 0; pConfigs[i].transparentBlue = 0; pConfigs[i].transparentAlpha = 0; pConfigs[i].transparentIndex = 0; i++; } } } break; case 32: numConfigs = 1; if ( ATI_USE_ACCUM ) numConfigs *= 2; if ( ATI_USE_STENCIL ) numConfigs *= 2; numConfigs *= 2; /* single- and double-buffered */ pConfigs = (__GLXvisualConfig*) xnfcalloc( sizeof(__GLXvisualConfig), numConfigs ); if ( !pConfigs ) { return FALSE; } pATIConfigs = (ATIConfigPrivPtr) xnfcalloc( sizeof(ATIConfigPrivRec), numConfigs ); if ( !pATIConfigs ) { xfree( pConfigs ); return FALSE; } pATIConfigPtrs = (ATIConfigPrivPtr*) xnfcalloc( sizeof(ATIConfigPrivPtr), numConfigs ); if ( !pATIConfigPtrs ) { xfree( pConfigs ); xfree( pATIConfigs ); return FALSE; } i = 0; for (db = 0; db <= 1; db++) { for ( accum = 0 ; accum <= ATI_USE_ACCUM ; accum++ ) { for ( stencil = 0 ; stencil <= ATI_USE_STENCIL ; stencil++ ) { pATIConfigPtrs[i] = &pATIConfigs[i]; pConfigs[i].vid = -1; pConfigs[i].class = -1; pConfigs[i].rgba = TRUE; pConfigs[i].redSize = 8; pConfigs[i].greenSize = 8; pConfigs[i].blueSize = 8; pConfigs[i].alphaSize = 0; pConfigs[i].redMask = 0x00FF0000; pConfigs[i].greenMask = 0x0000FF00; pConfigs[i].blueMask = 0x000000FF; pConfigs[i].alphaMask = 0x00000000; if ( accum ) { /* Simulated in software */ pConfigs[i].accumRedSize = 16; pConfigs[i].accumGreenSize = 16; pConfigs[i].accumBlueSize = 16; pConfigs[i].accumAlphaSize = 0; } else { pConfigs[i].accumRedSize = 0; pConfigs[i].accumGreenSize = 0; pConfigs[i].accumBlueSize = 0; pConfigs[i].accumAlphaSize = 0; } pConfigs[i].doubleBuffer = db ? TRUE : FALSE; pConfigs[i].stereo = FALSE; pConfigs[i].bufferSize = 24; if ( stencil ) { /* Simulated in software */ pConfigs[i].depthSize = 16; pConfigs[i].stencilSize = 8; } else { pConfigs[i].depthSize = 16; pConfigs[i].stencilSize = 0; } pConfigs[i].auxBuffers = 0; pConfigs[i].level = 0; if ( accum || stencil ) { pConfigs[i].visualRating = GLX_SLOW_CONFIG; } else { pConfigs[i].visualRating = GLX_NONE; } pConfigs[i].transparentPixel = GLX_NONE; pConfigs[i].transparentRed = 0; pConfigs[i].transparentGreen = 0; pConfigs[i].transparentBlue = 0; pConfigs[i].transparentAlpha = 0; pConfigs[i].transparentIndex = 0; i++; } } } break; } pATI->numVisualConfigs = numConfigs; pATI->pVisualConfigs = pConfigs; pATI->pVisualConfigsPriv = pATIConfigs; GlxSetVisualConfigs( numConfigs, pConfigs, (void**)pATIConfigPtrs ); return TRUE; } /* Create the ATI-specific context information */ static Bool ATICreateContext( ScreenPtr pScreen, VisualPtr visual, drm_context_t hwContext, void *pVisualConfigPriv, DRIContextType contextStore ) { /* Nothing yet */ return TRUE; } /* Destroy the ATI-specific context information */ static void ATIDestroyContext( ScreenPtr pScreen, drm_context_t hwContext, DRIContextType contextStore ) { /* Nothing yet */ } /* Called when the X server is woken up to allow the last client's * context to be saved and the X server's context to be loaded. * The client detects when it's context is not currently loaded and * then loads it itself. The X server's context is loaded in the * XAA Sync callback if NeedDRISync is set. */ static void ATIEnterServer( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); if ( pATI->directRenderingEnabled && pATI->pXAAInfo ) { pATI->pXAAInfo->NeedToSync = TRUE; pATI->NeedDRISync = TRUE; } } /* Called when the X server goes to sleep to allow the X server's * context to be saved and the last client's context to be loaded. * The client detects when it's context is not currently loaded and * then loads it itself. The X server keeps track of it's own state. */ static void ATILeaveServer( ScreenPtr pScreen ) { /* Nothing yet */ } /* Contexts can be swapped by the X server if necessary. This callback * is currently only used to perform any functions necessary when * entering or leaving the X server, and in the future might not be * necessary. */ static void ATIDRISwapContext( ScreenPtr pScreen, DRISyncType syncType, DRIContextType oldContextType, void *oldContext, DRIContextType newContextType, void *newContext ) { if ( ( syncType == DRI_3D_SYNC ) && ( oldContextType == DRI_2D_CONTEXT ) && ( newContextType == DRI_2D_CONTEXT ) ) { /* Entering from Wakeup */ ATIEnterServer( pScreen ); } if ( ( syncType == DRI_2D_SYNC ) && ( oldContextType == DRI_NO_CONTEXT ) && ( newContextType == DRI_2D_CONTEXT ) ) { /* Exiting from Block Handler */ ATILeaveServer( pScreen ); } } static void ATIDRITransitionTo2d(ScreenPtr pScreen) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); if (pATI->backArea) { xf86FreeOffscreenArea(pATI->backArea); pATI->backArea = NULL; } if (pATI->depthTexArea) { xf86FreeOffscreenArea(pATI->depthTexArea); pATI->depthTexArea = NULL; } pATI->have3DWindows = FALSE; } static void ATIDRITransitionTo3d(ScreenPtr pScreen) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); FBAreaPtr fbArea; int width, height; xf86PurgeUnlockedOffscreenAreas(pScreen); xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0); xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Largest offscreen area available: %d x %d\n", width, height); fbArea = xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, height - pATI->depthTexLines - pATI->backLines, pScreenInfo->displayWidth, NULL, NULL, NULL); if (!fbArea) xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve placeholder " "offscreen area, you might experience screen corruption\n"); if (!pATI->backArea) { pATI->backArea = xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, pATI->backLines, pScreenInfo->displayWidth, NULL, NULL, NULL); } if (!pATI->backArea) xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area " "for back buffer, you might experience screen corruption\n"); if (!pATI->depthTexArea) { pATI->depthTexArea = xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, pATI->depthTexLines, pScreenInfo->displayWidth, NULL, NULL, NULL); } if (!pATI->depthTexArea) xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area " "for depth buffer and textures, you might experience screen corruption\n"); if (fbArea) xf86FreeOffscreenArea(fbArea); pATI->have3DWindows = TRUE; } /* Initialize the state of the back and depth buffers. */ static void ATIDRIInitBuffers( WindowPtr pWin, RegionPtr prgn, CARD32 indx ) { ScreenPtr pScreen = pWin->drawable.pScreen; ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; BoxPtr pbox, pboxSave; int nbox, nboxSave; int depth; depth = 0x0000ffff; if (!pXAAInfo) return; if (!pXAAInfo->SetupForSolidFill) return; /* FIXME: Only initialize the back and depth buffers for contexts that request them */ /* FIXME: Use drm clear? (see Radeon driver) */ pboxSave = pbox = REGION_RECTS(prgn); nboxSave = nbox = REGION_NUM_RECTS(prgn); (*pXAAInfo->SetupForSolidFill)(pScreenInfo, 0, GXcopy, (CARD32)(-1)); for (; nbox; nbox--, pbox++) { (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, pbox->x1 + pATIDRIServer->fbX, pbox->y1 + pATIDRIServer->fbY, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, pbox->x1 + pATIDRIServer->backX, pbox->y1 + pATIDRIServer->backY, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); } pbox = pboxSave; nbox = nboxSave; (*pXAAInfo->SetupForSolidFill)(pScreenInfo, depth, GXcopy, (CARD32)(-1)); for (; nbox; nbox--, pbox++) (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, pbox->x1 + pATIDRIServer->depthX, pbox->y1 + pATIDRIServer->depthY, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); pXAAInfo->NeedToSync = TRUE; } /* Copy the back and depth buffers when the X server moves a window. * * Note: this function was copied from the Radeon driver... * * This routine is a modified form of XAADoBitBlt with the calls to * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source * instead of destination. My origin is upside down so the ydir cases * are reversed. */ static void ATIDRIMoveBuffers( WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc, CARD32 indx ) { ScreenPtr pScreen = pWin->drawable.pScreen; ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; int backOffsetPitch = (((pATI->pDRIServerInfo->backPitch/8) << 22) | (pATI->pDRIServerInfo->backOffset >> 3)); #if 0 int depthOffsetPitch = (((pATI->pDRIServerInfo->depthPitch/8) << 22) | (pATI->pDRIServerInfo->depthOffset >> 3)); #endif BoxPtr pboxTmp, pboxNext, pboxBase; DDXPointPtr pptTmp; int xdir, ydir; int screenwidth = pScreenInfo->virtualX; int screenheight = pScreenInfo->virtualY; BoxPtr pbox = REGION_RECTS(prgnSrc); int nbox = REGION_NUM_RECTS(prgnSrc); BoxPtr pboxNew1 = NULL; BoxPtr pboxNew2 = NULL; DDXPointPtr pptNew1 = NULL; DDXPointPtr pptNew2 = NULL; DDXPointPtr pptSrc = &ptOldOrg; int dx = pWin->drawable.x - ptOldOrg.x; int dy = pWin->drawable.y - ptOldOrg.y; if (!pXAAInfo) return; if (!pXAAInfo->SetupForScreenToScreenCopy) return; /* FIXME: Only move the back and depth buffers for contexts * that request them. */ /* If the copy will overlap in Y, reverse the order */ if (dy > 0) { ydir = -1; if (nbox > 1) { /* Keep ordering in each band, reverse order of bands */ pboxNew1 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); if (!pboxNew1) return; pptNew1 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); if (!pptNew1) { DEALLOCATE_LOCAL(pboxNew1); return; } pboxBase = pboxNext = pbox+nbox-1; while (pboxBase >= pbox) { while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1)) pboxNext--; pboxTmp = pboxNext+1; pptTmp = pptSrc + (pboxTmp - pbox); while (pboxTmp <= pboxBase) { *pboxNew1++ = *pboxTmp++; *pptNew1++ = *pptTmp++; } pboxBase = pboxNext; } pboxNew1 -= nbox; pbox = pboxNew1; pptNew1 -= nbox; pptSrc = pptNew1; } } else { /* No changes required */ ydir = 1; } /* If the regions will overlap in X, reverse the order */ if (dx > 0) { xdir = -1; if (nbox > 1) { /* reverse order of rects in each band */ pboxNew2 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); pptNew2 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); if (!pboxNew2 || !pptNew2) { DEALLOCATE_LOCAL(pptNew2); DEALLOCATE_LOCAL(pboxNew2); DEALLOCATE_LOCAL(pptNew1); DEALLOCATE_LOCAL(pboxNew1); return; } pboxBase = pboxNext = pbox; while (pboxBase < pbox+nbox) { while ((pboxNext < pbox+nbox) && (pboxNext->y1 == pboxBase->y1)) pboxNext++; pboxTmp = pboxNext; pptTmp = pptSrc + (pboxTmp - pbox); while (pboxTmp != pboxBase) { *pboxNew2++ = *--pboxTmp; *pptNew2++ = *--pptTmp; } pboxBase = pboxNext; } pboxNew2 -= nbox; pbox = pboxNew2; pptNew2 -= nbox; pptSrc = pptNew2; } } else { /* No changes are needed */ xdir = 1; } (*pXAAInfo->SetupForScreenToScreenCopy)(pScreenInfo, xdir, ydir, GXcopy, (CARD32)(-1), -1); for (; nbox-- ; pbox++) { int xa = pbox->x1; int ya = pbox->y1; int destx = xa + dx; int desty = ya + dy; int w = pbox->x2 - xa + 1; int h = pbox->y2 - ya + 1; if (destx < 0) xa -= destx, w += destx, destx = 0; if (desty < 0) ya -= desty, h += desty, desty = 0; if (destx + w > screenwidth) w = screenwidth - destx; if (desty + h > screenheight) h = screenheight - desty; if (w <= 0) continue; if (h <= 0) continue; ATIMach64WaitForFIFO(pATI, 2); outf(SRC_OFF_PITCH, backOffsetPitch); outf(DST_OFF_PITCH, backOffsetPitch); (*pXAAInfo->SubsequentScreenToScreenCopy)(pScreenInfo, xa, ya, destx, desty, w, h); #if 0 /* FIXME: Move depth buffers? */ ATIMach64WaitForFIFO(pATI, 2); outf(SRC_OFF_PITCH, depthOffsetPitch); outf(DST_OFF_PITCH, depthOffsetPitch); if (pATI->depthMoves) ATIScreenToScreenCopyDepth(pScreenInfo, xa, ya, destx, desty, w, h); #endif } ATIMach64WaitForFIFO(pATI, 2); outf(SRC_OFF_PITCH, pATI->NewHW.dst_off_pitch); outf(DST_OFF_PITCH, pATI->NewHW.src_off_pitch); DEALLOCATE_LOCAL(pptNew2); DEALLOCATE_LOCAL(pboxNew2); DEALLOCATE_LOCAL(pptNew1); DEALLOCATE_LOCAL(pboxNew1); pXAAInfo->NeedToSync = TRUE; } /* Compute log base 2 of val. */ static int Mach64MinBits(int val) { int bits; if (!val) return 1; for (bits = 0; val; val >>= 1, ++bits); return bits; } static Bool ATIDRISetAgpMode( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; unsigned long mode = drmAgpGetMode( pATI->drmFD ); /* Default mode */ unsigned int vendor = drmAgpVendorId( pATI->drmFD ); unsigned int device = drmAgpDeviceId( pATI->drmFD ); if (pATI->OptionAGPMode > 0 && pATI->OptionAGPMode <= ATI_AGP_MAX_MODE) { pATIDRIServer->agpMode = pATI->OptionAGPMode; xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using AGP %dx Mode\n", pATIDRIServer->agpMode ); } else if (pATI->OptionAGPMode > 0) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal AGP Mode: %d\n", pATI->OptionAGPMode ); return FALSE; } else { /* If no mode configured, use the default mode obtained from agpgart */ if ( mode & AGP_MODE_2X ) { pATIDRIServer->agpMode = 2; } else if ( mode & AGP_MODE_1X ) { pATIDRIServer->agpMode = 1; } xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using AGP %dx Mode\n", pATIDRIServer->agpMode ); } mode &= ~AGP_MODE_MASK; switch ( pATIDRIServer->agpMode ) { case 2: mode |= AGP_MODE_2X; case 1: default: mode |= AGP_MODE_1X; } if (pATI->OptionAGPSize) { switch (pATI->OptionAGPSize) { case 256: case 128: case 64: case 32: case 16: case 8: case 4: pATIDRIServer->agpSize = pATI->OptionAGPSize; xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using %d MB AGP aperture\n", pATIDRIServer->agpSize ); break; default: xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal aperture size %d MB\n", pATI->OptionAGPSize ); return FALSE; } } else { xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using %d MB AGP aperture\n", pATIDRIServer->agpSize ); } xf86DrvMsg( pScreen->myNum, X_INFO, "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", mode, vendor, device, pATI->PCIInfo->vendor, pATI->PCIInfo->chipType ); if ( drmAgpEnable( pATI->drmFD, mode ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n" ); drmAgpRelease( pATI->drmFD ); return FALSE; } return TRUE; } /* Initialize the AGP state. Request memory for use in AGP space, and * initialize the Rage Pro registers to point to that memory. */ static Bool ATIDRIAgpInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; int ret; unsigned long cntl; int s, l; pATIDRIServer->agpSize = ATI_DEFAULT_AGP_SIZE; pATIDRIServer->agpMode = ATI_DEFAULT_AGP_MODE; pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE; pATIDRIServer->ringSize = 16; /* 16 kB ring */ if ( drmAgpAcquire( pATI->drmFD ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP not available\n" ); return FALSE; } if (!ATIDRISetAgpMode( pScreen )) return FALSE; pATIDRIServer->agpOffset = 0; ret = drmAgpAlloc( pATI->drmFD, pATIDRIServer->agpSize*1024*1024, 0, NULL, &pATIDRIServer->agpHandle ); if ( ret < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret ); drmAgpRelease( pATI->drmFD ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[agp] %d kB allocated with handle 0x%08x\n", pATIDRIServer->agpSize*1024, pATIDRIServer->agpHandle ); if ( drmAgpBind( pATI->drmFD, pATIDRIServer->agpHandle, pATIDRIServer->agpOffset) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not bind\n" ); drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle ); drmAgpRelease( pATI->drmFD ); return FALSE; } xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] Using %d kB for DMA descriptor ring\n", pATIDRIServer->ringSize); if (pATI->OptionBufferSize) { if (pATI->OptionBufferSize < 1 || pATI->OptionBufferSize > pATIDRIServer->agpSize ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal DMA buffers size: %d MB\n", pATI->OptionBufferSize ); return FALSE; } if (pATI->OptionBufferSize > 2) { xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Illegal DMA buffers size: %d MB\n", pATI->OptionBufferSize ); xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Clamping DMA buffers size to 2 MB\n", pATI->OptionBufferSize ); pATIDRIServer->bufferSize = 2; } else { pATIDRIServer->bufferSize = pATI->OptionBufferSize; xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using %d MB for DMA buffers\n", pATIDRIServer->bufferSize ); } } else { xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using %d MB for DMA buffers\n", pATIDRIServer->bufferSize ); } pATIDRIServer->agpTexSize = pATIDRIServer->agpSize - pATIDRIServer->bufferSize; /* Reserve space for the DMA descriptor ring */ pATIDRIServer->ringStart = pATIDRIServer->agpOffset; pATIDRIServer->ringMapSize = pATIDRIServer->ringSize*1024; /* ringSize is in kB */ /* Reserve space for the vertex buffer */ pATIDRIServer->bufferStart = pATIDRIServer->ringStart + pATIDRIServer->ringMapSize; pATIDRIServer->bufferMapSize = pATIDRIServer->bufferSize*1024*1024; /* Reserve the rest for AGP textures */ pATIDRIServer->agpTexStart = pATIDRIServer->bufferStart + pATIDRIServer->bufferMapSize; s = (pATIDRIServer->agpSize*1024*1024 - pATIDRIServer->agpTexStart); l = Mach64MinBits((s-1) / MACH64_NR_TEX_REGIONS); if (l < MACH64_LOG_TEX_GRANULARITY) l = MACH64_LOG_TEX_GRANULARITY; pATIDRIServer->agpTexMapSize = (s >> l) << l; pATIDRIServer->log2AGPTexGran = l; xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] Using %d kB for AGP textures\n", pATIDRIServer->agpTexMapSize/1024); /* Map DMA descriptor ring */ if ( drmAddMap( pATI->drmFD, pATIDRIServer->ringStart, pATIDRIServer->ringMapSize, DRM_AGP, DRM_RESTRICTED, &pATIDRIServer->ringHandle ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not add ring mapping\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[agp] ring handle = 0x%08lx\n", pATIDRIServer->ringHandle ); if ( drmMap( pATI->drmFD, pATIDRIServer->ringHandle, pATIDRIServer->ringMapSize, &pATIDRIServer->ringMap ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not map ring\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[agp] Ring mapped at 0x%08lx\n", (unsigned long)pATIDRIServer->ringMap ); /* Map vertex buffers */ if ( drmAddMap( pATI->drmFD, pATIDRIServer->bufferStart, pATIDRIServer->bufferMapSize, DRM_AGP, 0, &pATIDRIServer->bufferHandle ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not add vertex buffers mapping\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[agp] vertex buffers handle = 0x%08lx\n", pATIDRIServer->bufferHandle ); if ( drmMap( pATI->drmFD, pATIDRIServer->bufferHandle, pATIDRIServer->bufferMapSize, &pATIDRIServer->bufferMap ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not map vertex buffers\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[agp] Vertex buffers mapped at 0x%08lx\n", (unsigned long)pATIDRIServer->bufferMap ); /* Map AGP Textures */ if (drmAddMap(pATI->drmFD, pATIDRIServer->agpTexStart, pATIDRIServer->agpTexMapSize, DRM_AGP, 0, &pATIDRIServer->agpTexHandle) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not add AGP texture region mapping\n"); return FALSE; } xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] AGP texture region handle = 0x%08lx\n", pATIDRIServer->agpTexHandle); if (drmMap(pATI->drmFD, pATIDRIServer->agpTexHandle, pATIDRIServer->agpTexMapSize, &pATIDRIServer->agpTexMap) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map AGP texture region\n"); return FALSE; } xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] AGP Texture region mapped at 0x%08lx\n", (unsigned long)pATIDRIServer->agpTexMap); /* Initialize Mach64's AGP registers */ cntl = inm( AGP_CNTL ); cntl &= ~AGP_APER_SIZE_MASK; switch ( pATIDRIServer->agpSize ) { case 256: cntl |= AGP_APER_SIZE_256MB; break; case 128: cntl |= AGP_APER_SIZE_128MB; break; case 64: cntl |= AGP_APER_SIZE_64MB; break; case 32: cntl |= AGP_APER_SIZE_32MB; break; case 16: cntl |= AGP_APER_SIZE_16MB; break; case 8: cntl |= AGP_APER_SIZE_8MB; break; case 4: cntl |= AGP_APER_SIZE_4MB; break; default: xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal aperture size %d kB\n", pATIDRIServer->agpSize*1024 ); return FALSE; } /* 1 = DATA comes in clock in which TRDY sampled (default) */ /* 0 = DATA comes in clock after TRDY sampled */ cntl |= AGP_TRDY_MODE; /* 1 = generate all reads as high priority */ /* 0 = generate all reads as their default priority (default) */ /* Setting this only works for me at AGP 1x mode (LLD) */ if (pATIDRIServer->agpMode == 1) { cntl |= HIGH_PRIORITY_READ_EN; } else { cntl &= ~HIGH_PRIORITY_READ_EN; } outm( AGP_BASE, drmAgpBase(pATI->drmFD) ); outm( AGP_CNTL, cntl ); return TRUE; } /* Add a map for the MMIO registers that will be accessed by any * DRI-based clients. */ static Bool ATIDRIMapInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; pATIDRIServer->regsSize = getpagesize(); if ( drmAddMap( pATI->drmFD, pATI->Block1Base, pATIDRIServer->regsSize, DRM_REGISTERS, DRM_READ_ONLY, &pATIDRIServer->regsHandle ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[drm] failed to map registers\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[drm] register handle = 0x%08lx\n", pATIDRIServer->regsHandle ); return TRUE; } /* Initialize the kernel data structures. */ static Bool ATIDRIKernelInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; drmMach64Init info; memset( &info, 0, sizeof(drmMach64Init) ); info.func = DRM_MACH64_INIT_DMA; info.sarea_priv_offset = sizeof(XF86DRISAREARec); info.is_pci = pATIDRIServer->IsPCI; info.dma_mode = pATI->OptionDMAMode; info.fb_bpp = pATI->bitsPerPixel; info.front_offset = pATIDRIServer->frontOffset; info.front_pitch = pATIDRIServer->frontPitch; info.back_offset = pATIDRIServer->backOffset; info.back_pitch = pATIDRIServer->backPitch; info.depth_bpp = 16; info.depth_offset = pATIDRIServer->depthOffset; info.depth_pitch = pATIDRIServer->depthPitch; info.fb_offset = pATI->LinearBase; info.mmio_offset = pATIDRIServer->regsHandle; info.ring_offset = pATIDRIServer->ringHandle; info.buffers_offset = pATIDRIServer->bufferHandle; info.agp_textures_offset = pATIDRIServer->agpTexHandle; if ( drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT, &info, sizeof(drmMach64Init) ) < 0 ) { return FALSE; } else { return TRUE; } } /* Add a map for the DMA buffers that will be accessed by any * DRI-based clients. */ static Bool ATIDRIAddBuffers( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; /* Initialize vertex buffers */ if ( pATIDRIServer->IsPCI ) { pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD, (pATIDRIServer->bufferSize*1024*1024)/MACH64_BUFFER_SIZE, MACH64_BUFFER_SIZE, 0, 0 ); } else { pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD, pATIDRIServer->bufferMapSize/MACH64_BUFFER_SIZE, MACH64_BUFFER_SIZE, DRM_AGP_BUFFER, pATIDRIServer->bufferStart ); } if ( pATIDRIServer->numBuffers <= 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[drm] Could not create DMA buffers list\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[drm] Added %d %d byte DMA buffers\n", pATIDRIServer->numBuffers, MACH64_BUFFER_SIZE ); return TRUE; } static Bool ATIDRIMapBuffers( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; pATIDRIServer->drmBuffers = drmMapBufs( pATI->drmFD ); if ( !pATIDRIServer->drmBuffers ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[drm] Failed to map DMA buffers list\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[drm] Mapped %d DMA buffers at 0x%08lx\n", pATIDRIServer->drmBuffers->count, pATIDRIServer->drmBuffers->list->address ); return TRUE; } static Bool ATIDRIIrqInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); if ( pATI->irq <= 0 ) { pATI->irq = drmGetInterruptFromBusID(pATI->drmFD, ((pciConfigPtr)pATI->PCIInfo ->thisCard)->busnum, ((pciConfigPtr)pATI->PCIInfo ->thisCard)->devnum, ((pciConfigPtr)pATI->PCIInfo ->thisCard)->funcnum); if ( pATI->irq <= 0 ) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "[drm] Couldn't find IRQ for bus id %d:%d:%d\n", ((pciConfigPtr)pATI->PCIInfo->thisCard)->busnum, ((pciConfigPtr)pATI->PCIInfo->thisCard)->devnum, ((pciConfigPtr)pATI->PCIInfo->thisCard)->funcnum); pATI->irq = 0; } else if ((drmCtlInstHandler(pATI->drmFD, pATI->irq)) != 0) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "[drm] Failed to initialize interrupt handler with IRQ %d\n", pATI->irq); pATI->irq = 0; } if (pATI->irq) xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "[drm] Installed interrupt handler, using IRQ %d\n", pATI->irq); else { xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "[drm] Falling back to irq-free operation\n", pATI->irq); return FALSE; } } return TRUE; } /* Initialize the screen-specific data structures for the DRI and the * Rage Pro. This is the main entry point to the device-specific * initialization code. It calls device-independent DRI functions to * create the DRI data structures and initialize the DRI state. */ Bool ATIDRIScreenInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); DRIInfoPtr pDRIInfo; ATIDRIPtr pATIDRI; ATIDRIServerInfoPtr pATIDRIServer; drmVersionPtr version; int major, minor, patch; /* Check that the GLX, DRI, and DRM modules have been loaded by testing * for known symbols in each module. */ if ( !xf86LoaderCheckSymbol("GlxSetVisualConfigs") ) return FALSE; if ( !xf86LoaderCheckSymbol("DRIScreenInit") ) return FALSE; if ( !xf86LoaderCheckSymbol("drmAvailable") ) return FALSE; if ( !xf86LoaderCheckSymbol("DRIQueryVersion") ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[dri] ATIDRIScreenInit failed (libdri.a too old)\n" ); return FALSE; } /* Check the DRI version */ DRIQueryVersion( &major, &minor, &patch ); if ( major != 4 || minor < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" "[dri] libDRI version is %d.%d.%d but version 4.0.x is needed.\n" "[dri] Disabling the DRI.\n", major, minor, patch ); return FALSE; } switch ( pATI->bitsPerPixel ) { case 8: /* These modes are not supported (yet). */ case 15: case 24: xf86DrvMsg( pScreen->myNum, X_ERROR, "[dri] Direct rendering only supported in 16 and 32 bpp modes\n"); return FALSE; /* Only 16 and 32 color depths are supported currently. */ case 16: if ( pATI->depth != 16) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[dri] Direct rendering not supported for depth %d at fbbpp 16.\n", pATI->depth ); return FALSE; } break; case 32: break; } /* Create the DRI data structure, and fill it in before calling the * DRIScreenInit(). */ pDRIInfo = DRICreateInfoRec(); if ( !pDRIInfo ) return FALSE; pATI->pDRIInfo = pDRIInfo; pDRIInfo->drmDriverName = ATIKernelDriverName; pDRIInfo->clientDriverName = ATIClientDriverName; if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) { pDRIInfo->busIdString = DRICreatePCIBusID(pATI->PCIInfo); } else { pDRIInfo->busIdString = xalloc( 64 ); sprintf( pDRIInfo->busIdString, "PCI:%d:%d:%d", pATI->PCIInfo->bus, pATI->PCIInfo->device, pATI->PCIInfo->func ); } pDRIInfo->ddxDriverMajorVersion = ATI_VERSION_MAJOR; pDRIInfo->ddxDriverMinorVersion = ATI_VERSION_MINOR; pDRIInfo->ddxDriverPatchVersion = ATI_VERSION_PATCH; pDRIInfo->frameBufferPhysicalAddress = pATI->LinearBase; pDRIInfo->frameBufferSize = pATI->LinearSize; pDRIInfo->frameBufferStride = (pScreenInfo->displayWidth * pATI->FBBytesPerPixel); pDRIInfo->ddxDrawableTableEntry = ATI_MAX_DRAWABLES; if ( SAREA_MAX_DRAWABLES < ATI_MAX_DRAWABLES ) { pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES; } else { pDRIInfo->maxDrawableTableEntry = ATI_MAX_DRAWABLES; } /* For now the mapping works by using a fixed size defined * in the SAREA header */ if ( sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec) > SAREA_MAX ) { ErrorF( "[dri] Data does not fit in SAREA\n" ); return FALSE; } xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, "[drm] SAREA %d+%d: %d\n", sizeof(XF86DRISAREARec), sizeof(ATISAREAPrivRec), sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec) ); pDRIInfo->SAREASize = SAREA_MAX; pATIDRI = (ATIDRIPtr) xnfcalloc( sizeof(ATIDRIRec), 1 ); if ( !pATIDRI ) { DRIDestroyInfoRec( pATI->pDRIInfo ); pATI->pDRIInfo = NULL; xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR, "[dri] Failed to allocate memory for private record\n" ); return FALSE; } pATIDRIServer = (ATIDRIServerInfoPtr) xnfcalloc( sizeof(ATIDRIServerInfoRec), 1 ); if ( !pATIDRIServer ) { xfree( pATIDRI ); DRIDestroyInfoRec( pATI->pDRIInfo ); pATI->pDRIInfo = NULL; xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR, "[dri] Failed to allocate memory for private record\n" ); return FALSE; } pATI->pDRIServerInfo = pATIDRIServer; pDRIInfo->devPrivate = pATIDRI; pDRIInfo->devPrivateSize = sizeof(ATIDRIRec); pDRIInfo->contextSize = sizeof(ATIDRIContextRec); pDRIInfo->CreateContext = ATICreateContext; pDRIInfo->DestroyContext = ATIDestroyContext; pDRIInfo->SwapContext = ATIDRISwapContext; pDRIInfo->InitBuffers = ATIDRIInitBuffers; pDRIInfo->MoveBuffers = ATIDRIMoveBuffers; pDRIInfo->TransitionTo2d = ATIDRITransitionTo2d; pDRIInfo->TransitionTo3d = ATIDRITransitionTo3d; pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; pDRIInfo->createDummyCtx = TRUE; pDRIInfo->createDummyCtxPriv = FALSE; pATI->have3DWindows = FALSE; if ( !DRIScreenInit( pScreen, pDRIInfo, &pATI->drmFD ) ) { xfree( pATIDRIServer ); pATI->pDRIServerInfo = NULL; xfree( pDRIInfo->devPrivate ); pDRIInfo->devPrivate = NULL; DRIDestroyInfoRec( pDRIInfo ); pDRIInfo = NULL; xf86DrvMsg( pScreen->myNum, X_ERROR, "[dri] DRIScreenInit Failed\n" ); return FALSE; } /* Check the DRM lib version. drmGetLibVersion was not supported in version 1.0, so check for symbol first to avoid possible crash or hang. */ if (xf86LoaderCheckSymbol("drmGetLibVersion")) { version = drmGetLibVersion(pATI->drmFD); } else { /* drmlib version 1.0.0 didn't have the drmGetLibVersion entry point. Fake it by allocating a version record via drmGetVersion and changing it to version 1.0.0 */ version = drmGetVersion(pATI->drmFD); version->version_major = 1; version->version_minor = 0; version->version_patchlevel = 0; } if (version) { if (version->version_major != 1 || version->version_minor < 1) { /* incompatible drm library version */ xf86DrvMsg(pScreen->myNum, X_ERROR, "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n" "[dri] Disabling DRI.\n", version->version_major, version->version_minor, version->version_patchlevel); drmFreeVersion(version); ATIDRICloseScreen(pScreen); return FALSE; } drmFreeVersion(version); } /* Check the mach64 DRM version */ version = drmGetVersion( pATI->drmFD ); if ( version ) { if ( version->version_major != 1 || version->version_minor < 0 ) { /* Incompatible DRM version */ xf86DrvMsg( pScreen->myNum, X_ERROR, "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" "[dri] mach64.o kernel module version is %d.%d.%d, but version 1.0 or greater is needed.\n" "[dri] Disabling DRI.\n", version->version_major, version->version_minor, version->version_patchlevel ); drmFreeVersion( version ); ATIDRICloseScreen( pScreen ); return FALSE; } drmFreeVersion( version ); } switch ( pATI->OptionDMAMode ) { case MACH64_MODE_DMA_ASYNC: xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request asynchronous DMA mode\n"); break; case MACH64_MODE_DMA_SYNC: xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request synchronous DMA mode\n"); break; case MACH64_MODE_MMIO: xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request pseudo-DMA (MMIO) mode\n"); break; default: xf86DrvMsg(pScreen->myNum, X_WARNING, "[drm] Unknown DMA mode\n"); } pATIDRIServer->IsPCI = (pATI->BusType == ATI_BUS_PCI || pATI->OptionIsPCI) ? TRUE : FALSE; if ( pATI->BusType != ATI_BUS_PCI && pATI->OptionIsPCI ) { outm( AGP_BASE, 0 ); outm( AGP_CNTL, 0 ); xf86DrvMsg(pScreen->myNum, X_CONFIG, "[dri] Forcing PCI mode\n"); } /* Check buffer size option for PCI, since it won't be done in ATIDRIAgpInit */ if ( pATIDRIServer->IsPCI) { pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE; if (pATI->OptionBufferSize) { if (pATI->OptionBufferSize < 1) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[pci] Illegal DMA buffers size: %d MB\n", pATI->OptionBufferSize ); ATIDRICloseScreen( pScreen ); return FALSE; } if (pATI->OptionBufferSize > 2) { xf86DrvMsg( pScreen->myNum, X_WARNING, "[pci] Illegal DMA buffers size: %d MB\n", pATI->OptionBufferSize ); xf86DrvMsg( pScreen->myNum, X_WARNING, "[pci] Clamping DMA buffers size to 2 MB\n", pATI->OptionBufferSize ); pATIDRIServer->bufferSize = 2; } else { pATIDRIServer->bufferSize = pATI->OptionBufferSize; xf86DrvMsg( pScreen->myNum, X_CONFIG, "[pci] Using %d MB DMA buffer size\n", pATIDRIServer->bufferSize ); } } else { xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[pci] Using %d MB DMA buffer size\n", pATIDRIServer->bufferSize ); } } /* Initialize AGP */ if ( !pATIDRIServer->IsPCI && !ATIDRIAgpInit( pScreen ) ) { pATIDRIServer->IsPCI = TRUE; if ( pATI->BusType != ATI_BUS_PCI ) { outm( AGP_BASE, 0 ); outm( AGP_CNTL, 0 ); } xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP failed to initialize -- falling back to PCI mode.\n" ); xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Make sure you have the agpgart kernel module loaded.\n" ); } if ( !ATIDRIMapInit( pScreen ) ) { ATIDRICloseScreen( pScreen ); return FALSE; } if ( !ATIInitVisualConfigs( pScreen ) ) { ATIDRICloseScreen( pScreen ); return FALSE; } xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, "[dri] Visual configs initialized\n" ); xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, "[dri] Block 0 base at 0x%08lx\n", pATI->Block0Base ); return TRUE; } /* Finish initializing the device-dependent DRI state, and call * DRIFinishScreenInit() to complete the device-independent DRI * initialization. */ Bool ATIDRIFinishScreenInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATISAREAPrivPtr pSAREAPriv; ATIDRIPtr pATIDRI; ATIDRIServerInfoPtr pATIDRIServer; pATI->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit * because *DRIKernelInit requires that the hardware lock is held by * the X server, and the first time the hardware lock is grabbed is * in DRIFinishScreenInit. */ if ( !DRIFinishScreenInit( pScreen ) ) { ATIDRICloseScreen( pScreen ); return FALSE; } /* Initialize the DMA buffer list */ /* Need to do this before ATIDRIKernelInit so we can init the freelist */ if ( !ATIDRIAddBuffers( pScreen ) ) { ATIDRICloseScreen( pScreen ); return FALSE; } /* Initialize the kernel data structures */ if ( !ATIDRIKernelInit( pScreen ) ) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "[drm] Failed to initialize the mach64.o kernel module\n"); xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "[drm] Check the system log for more information.\n"); ATIDRICloseScreen( pScreen ); return FALSE; } if ( !ATIDRIMapBuffers( pScreen ) ) { ATIDRICloseScreen( pScreen ); return FALSE; } /* Initialize IRQ */ ATIDRIIrqInit( pScreen ); pSAREAPriv = (ATISAREAPrivPtr) DRIGetSAREAPrivate( pScreen ); memset( pSAREAPriv, 0, sizeof(*pSAREAPriv) ); pATIDRI = (ATIDRIPtr)pATI->pDRIInfo->devPrivate; pATIDRIServer = pATI->pDRIServerInfo; pATIDRI->width = pScreenInfo->virtualX; pATIDRI->height = pScreenInfo->virtualY; pATIDRI->mem = pScreenInfo->videoRam * 1024; pATIDRI->cpp = pScreenInfo->bitsPerPixel / 8; pATIDRI->IsPCI = pATIDRIServer->IsPCI; pATIDRI->AGPMode = pATIDRIServer->agpMode; pATIDRI->frontOffset = pATIDRIServer->frontOffset; pATIDRI->frontPitch = pATIDRIServer->frontPitch; pATIDRI->backOffset = pATIDRIServer->backOffset; pATIDRI->backPitch = pATIDRIServer->backPitch; pATIDRI->depthOffset = pATIDRIServer->depthOffset; pATIDRI->depthPitch = pATIDRIServer->depthPitch; pATIDRI->textureOffset = pATIDRIServer->textureOffset; pATIDRI->textureSize = pATIDRIServer->textureSize; pATIDRI->logTextureGranularity = pATIDRIServer->logTextureGranularity; pATIDRI->regs = pATIDRIServer->regsHandle; pATIDRI->regsSize = pATIDRIServer->regsSize; pATIDRI->agp = pATIDRIServer->agpTexHandle; pATIDRI->agpSize = pATIDRIServer->agpTexMapSize; pATIDRI->logAgpTextureGranularity = pATIDRIServer->log2AGPTexGran; pATIDRI->agpTextureOffset = pATIDRIServer->agpTexStart; return TRUE; } /* * This function will attempt to get the Mach64 hardware back into shape * after a resume from disc. Its an extract from ATIDRIAgpInit and ATIDRIFinishScreenInit * This also calls a new ioctl in the mach64 DRM that in its turn is * an extraction of the hardware-affecting bits from mach64_do_init_drm() * (see atidrm.c) * I am assuming here that pATI->pDRIServerInfo doesn't change * elsewhere in incomaptible ways. * How will this code react to resuming after a failed resumeor pci based dri ? */ void ATIDRIResume( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; int ret; xf86DrvMsg( pScreen->myNum, X_INFO, "[RESUME] Attempting to re-init Mach64 hardware.\n"); if (!pATIDRIServer->IsPCI) { if (!ATIDRISetAgpMode(pScreen)) return; outm( AGP_BASE, drmAgpBase(pATI->drmFD) ); } } /* The screen is being closed, so clean up any state and free any * resources used by the DRI. */ void ATIDRICloseScreen( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; drmMach64Init info; /* Stop interrupt generation and handling if used */ if ( pATI->irq > 0 ) { if ( drmCtlUninstHandler(pATI->drmFD) != 0 ) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "[drm] Error uninstalling interrupt handler for IRQ %d\n", pATI->irq); } else { xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "[drm] Uninstalled interrupt handler for IRQ %d\n", pATI->irq); } pATI->irq = 0; } /* De-allocate DMA buffers */ if ( pATIDRIServer->drmBuffers ) { drmUnmapBufs( pATIDRIServer->drmBuffers ); pATIDRIServer->drmBuffers = NULL; } /* De-allocate all kernel resources */ memset(&info, 0, sizeof(drmMach64Init)); info.func = DRM_MACH64_CLEANUP_DMA; drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT, &info, sizeof(drmMach64Init) ); /* De-allocate all AGP resources */ if ( pATIDRIServer->agpTexMap ) { drmUnmap( pATIDRIServer->agpTexMap, pATIDRIServer->agpTexMapSize ); pATIDRIServer->agpTexMap = NULL; } if ( pATIDRIServer->bufferMap ) { drmUnmap( pATIDRIServer->bufferMap, pATIDRIServer->bufferMapSize ); pATIDRIServer->bufferMap = NULL; } if ( pATIDRIServer->agpHandle ) { drmAgpUnbind( pATI->drmFD, pATIDRIServer->agpHandle ); drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle ); pATIDRIServer->agpHandle = 0; drmAgpRelease( pATI->drmFD ); } /* De-allocate all DRI resources */ DRICloseScreen( pScreen ); /* De-allocate all DRI data structures */ if ( pATI->pDRIInfo ) { if ( pATI->pDRIInfo->devPrivate ) { xfree( pATI->pDRIInfo->devPrivate ); pATI->pDRIInfo->devPrivate = NULL; } DRIDestroyInfoRec( pATI->pDRIInfo ); pATI->pDRIInfo = NULL; } if ( pATI->pDRIServerInfo ) { xfree( pATI->pDRIServerInfo ); pATI->pDRIServerInfo = NULL; } if ( pATI->pVisualConfigs ) { xfree( pATI->pVisualConfigs ); pATI->pVisualConfigs = NULL; } if ( pATI->pVisualConfigsPriv ) { xfree( pATI->pVisualConfigsPriv ); pATI->pVisualConfigsPriv = NULL; } }