/* -*- 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* * Authors: * Gareth Hughes * Leif Delgass */ #include #include #include /* Driver data structures */ #include "ati.h" #include "atibus.h" #include "atidri.h" #include "atiregs.h" #include "atistruct.h" #include "atimach64io.h" #include "atimach64version.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" /* DRI/DRM definitions */ #define _XF86DRI_SERVER_ #include "sarea.h" static char ATIKernelDriverName[] = "mach64"; static char ATIClientDriverName[] = "mach64"; /* 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 = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); if ( pATI->directRenderingEnabled ) { ATIDRIMarkSyncInt(pScreenInfo); ATIDRIMarkSyncExt(pScreenInfo); } } /* 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 ); } } #ifdef USE_EXA static void ATIDRITransitionTo2d_EXA(ScreenPtr pScreen) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; exaEnableDisableFBAccess(SCREEN_ARG(pScreen), FALSE); pATI->pExa->offScreenBase = pATIDRIServer->backOffset; exaEnableDisableFBAccess(SCREEN_ARG(pScreen), TRUE); pATI->have3DWindows = FALSE; } static void ATIDRITransitionTo3d_EXA(ScreenPtr pScreen) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; exaEnableDisableFBAccess(SCREEN_ARG(pScreen), FALSE); pATI->pExa->offScreenBase = pATIDRIServer->textureOffset + pATIDRIServer->textureSize; exaEnableDisableFBAccess(SCREEN_ARG(pScreen), TRUE); pATI->have3DWindows = TRUE; } #endif /* USE_EXA */ /* Initialize the state of the back and depth buffers. */ static void ATIDRIInitBuffers( WindowPtr pWin, RegionPtr prgn, CARD32 indx ) { } /* 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 ) { } /* 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 ATIDRISetBufSize( ScreenPtr pScreen, unsigned int maxSize ) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; if (pATI->OptionBufferSize) { if (pATI->OptionBufferSize < 1 || pATI->OptionBufferSize > maxSize ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[drm] Illegal DMA buffers size: %d MB\n", pATI->OptionBufferSize ); return FALSE; } if (pATI->OptionBufferSize > 2) { xf86DrvMsg( pScreen->myNum, X_WARNING, "[drm] Illegal DMA buffers size: %d MB\n", pATI->OptionBufferSize ); xf86DrvMsg( pScreen->myNum, X_WARNING, "[drm] Clamping DMA buffers size to 2 MB\n"); pATIDRIServer->bufferSize = 2; } else { pATIDRIServer->bufferSize = pATI->OptionBufferSize; xf86DrvMsg( pScreen->myNum, X_CONFIG, "[drm] Using %d MB for DMA buffers\n", pATIDRIServer->bufferSize ); } } else { xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[drm] Using %d MB for DMA buffers\n", pATIDRIServer->bufferSize ); } return TRUE; } static Bool ATIDRISetAgpMode( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); 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; /* FALLTHROUGH */ case 1: default: mode |= AGP_MODE_1X; } if (pATI->OptionAGPSize) { switch (pATI->OptionAGPSize) { 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, PCI_DEV_VENDOR_ID(pATI->PCIInfo), PCI_DEV_DEVICE_ID(pATI->PCIInfo) ); 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 = xf86ScreenToScrn(pScreen); 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 ( !ATIDRISetBufSize( pScreen, pATIDRIServer->agpSize ) ) return FALSE; 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%08x\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, DRM_READ_ONLY, &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%08x\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%08x\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; } static Bool ATIDRIPciInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE; pATIDRIServer->ringSize = 16; /* 16 kB ring */ if ( !ATIDRISetBufSize( pScreen, (unsigned)(-1) ) ) return FALSE; /* Set size of the DMA descriptor ring */ pATIDRIServer->ringStart = 0; pATIDRIServer->ringMapSize = pATIDRIServer->ringSize*1024; /* ringSize is in kB */ /* Set size of the vertex buffer */ pATIDRIServer->bufferStart = 0; pATIDRIServer->bufferMapSize = pATIDRIServer->bufferSize*1024*1024; /* Map DMA descriptor ring */ if ( drmAddMap( pATI->drmFD, 0, pATIDRIServer->ringMapSize, DRM_CONSISTENT, DRM_RESTRICTED, &pATIDRIServer->ringHandle ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[pci] Could not add ring mapping\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[pci] ring handle = 0x%08x\n", pATIDRIServer->ringHandle ); if ( drmMap( pATI->drmFD, pATIDRIServer->ringHandle, pATIDRIServer->ringMapSize, &pATIDRIServer->ringMap ) < 0 ) { xf86DrvMsg( pScreen->myNum, X_ERROR, "[pci] Could not map ring\n" ); return FALSE; } xf86DrvMsg( pScreen->myNum, X_INFO, "[pci] Ring mapped at 0x%08lx\n", (unsigned long)pATIDRIServer->ringMap ); /* Disable AGP for ForcePCIMode */ if ( pATI->BusType != ATI_BUS_PCI ) { outm( AGP_BASE, 0 ); outm( AGP_CNTL, 0 ); } 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 = xf86ScreenToScrn(pScreen); 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%08x\n", pATIDRIServer->regsHandle ); return TRUE; } /* Initialize the kernel data structures. */ static Bool ATIDRIKernelInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); 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 = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; /* Initialize vertex buffers */ if ( pATIDRIServer->IsPCI ) { pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD, pATIDRIServer->bufferMapSize/MACH64_BUFFER_SIZE, MACH64_BUFFER_SIZE, DRM_PCI_BUFFER_RO, 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 = xf86ScreenToScrn(pScreen); 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, (unsigned long)pATIDRIServer->drmBuffers->list->address ); return TRUE; } static Bool ATIDRIIrqInit( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); if ( pATI->irq <= 0 ) { pATI->irq = drmGetInterruptFromBusID(pATI->drmFD, PCI_CFG_BUS(pATI->PCIInfo), PCI_CFG_DEV(pATI->PCIInfo), PCI_CFG_FUNC(pATI->PCIInfo)); if ( pATI->irq <= 0 ) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "[drm] Couldn't find IRQ for bus id %d:%d:%d\n", PCI_CFG_BUS(pATI->PCIInfo), PCI_CFG_DEV(pATI->PCIInfo), PCI_CFG_FUNC(pATI->PCIInfo)); 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"); 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 = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); DRIInfoPtr pDRIInfo; ATIDRIPtr pATIDRI; ATIDRIServerInfoPtr pATIDRIServer; drmVersionPtr version; int major, minor, patch; /* Check that the DRI, and DRM modules have been loaded by testing * for known symbols in each module. */ 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 != DRIINFO_MAJOR_VERSION || 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 %d.%d.x is needed.\n" "[dri] Disabling the DRI.\n", major, minor, patch, DRIINFO_MAJOR_VERSION, 0 ); 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 { XNFasprintf(&pDRIInfo->busIdString, "PCI:%d:%d:%d", PCI_DEV_BUS(pATI->PCIInfo), PCI_DEV_DEV(pATI->PCIInfo), PCI_DEV_FUNC(pATI->PCIInfo) ); } pDRIInfo->ddxDriverMajorVersion = MACH64_VERSION_MAJOR; pDRIInfo->ddxDriverMinorVersion = MACH64_VERSION_MINOR; pDRIInfo->ddxDriverPatchVersion = MACH64_VERSION_PATCH; pDRIInfo->frameBufferPhysicalAddress = (void *)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 %u+%u: %u\n", (unsigned)sizeof(XF86DRISAREARec), (unsigned)sizeof(ATISAREAPrivRec), (unsigned)(sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec)) ); pDRIInfo->SAREASize = SAREA_MAX; pATIDRI = (ATIDRIPtr) XNFcallocarray( 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) XNFcallocarray( sizeof(ATIDRIServerInfoRec), 1 ); if ( !pATIDRIServer ) { free( 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; #ifdef USE_EXA if (pATI->useEXA) { pDRIInfo->TransitionTo2d = ATIDRITransitionTo2d_EXA; pDRIInfo->TransitionTo3d = ATIDRITransitionTo3d_EXA; } #endif /* USE_EXA */ pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; pDRIInfo->createDummyCtx = TRUE; pDRIInfo->createDummyCtxPriv = FALSE; pATI->have3DWindows = FALSE; if ( !DRIScreenInit( pScreen, pDRIInfo, &pATI->drmFD ) ) { free( pATIDRIServer ); pATI->pDRIServerInfo = NULL; free( 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 != 2 || 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 2.x is needed (with 2.x >= 2.0).\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 ) { xf86DrvMsg(pScreen->myNum, X_CONFIG, "[dri] Forcing PCI mode\n"); } /* Initialize AGP */ if ( !pATIDRIServer->IsPCI && !ATIDRIAgpInit( pScreen ) ) { pATIDRIServer->IsPCI = TRUE; 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" ); } /* Initialize PCI */ if ( pATIDRIServer->IsPCI && !ATIDRIPciInit( pScreen ) ) { ATIDRICloseScreen( pScreen ); return FALSE; } if ( !ATIDRIMapInit( 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 = xf86ScreenToScrn(pScreen); 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 incompatible ways. * How will this code react to resuming after a failed resumeor pci based dri ? */ void ATIDRIResume( ScreenPtr pScreen ) { ScrnInfoPtr pScreenInfo = xf86ScreenToScrn(pScreen); ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; 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 = xf86ScreenToScrn(pScreen); 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->ringMap ) { drmUnmap( pATIDRIServer->ringMap, pATIDRIServer->ringMapSize ); pATIDRIServer->ringMap = NULL; } if ( pATIDRIServer->agpHandle ) { drmAgpUnbind( pATI->drmFD, pATIDRIServer->agpHandle ); drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle ); pATIDRIServer->agpHandle = 0; drmAgpRelease( pATI->drmFD ); } /* De-allocate all PCI resources */ if ( pATIDRIServer->IsPCI && pATIDRIServer->ringHandle ) { drmRmMap( pATI->drmFD, pATIDRIServer->ringHandle ); pATIDRIServer->ringHandle = 0; } /* De-allocate all DRI resources */ DRICloseScreen( pScreen ); /* De-allocate all DRI data structures */ if ( pATI->pDRIInfo ) { if ( pATI->pDRIInfo->devPrivate ) { free( pATI->pDRIInfo->devPrivate ); pATI->pDRIInfo->devPrivate = NULL; } DRIDestroyInfoRec( pATI->pDRIInfo ); pATI->pDRIInfo = NULL; } if ( pATI->pDRIServerInfo ) { free( pATI->pDRIServerInfo ); pATI->pDRIServerInfo = NULL; } }