/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dri.c,v 1.28 2003/02/07 20:41:14 martin Exp $ */ /* * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, * Precision Insight, Inc., Cedar Park, Texas, and * VA Linux Systems Inc., Fremont, California. * * 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 on the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* * Authors: * Kevin E. Martin * Rickard E. Faith * Daryll Strauss * Gareth Hughes * */ #include #include #include #include #include // Fix this to use kernel pci_ids.h when all of these IDs make it into the kernel #include "pci_ids.h" #include "driver.h" #include "drm.h" #include "memops.h" #include "r128.h" #include "r128_dri.h" #include "r128_macros.h" #include "r128_reg.h" #include "r128_version.h" #include "r128_drm.h" static size_t r128_drm_page_size; /* Compute log base 2 of val. */ static int R128MinBits(int val) { int bits; if (!val) return 1; for (bits = 0; val; val >>= 1, ++bits); return bits; } /* Initialize the AGP state. Request memory for use in AGP space, and initialize the Rage 128 registers to point to that memory. */ static GLboolean R128DRIAgpInit(const DRIDriverContext *ctx) { unsigned char *R128MMIO = ctx->MMIOAddress; R128InfoPtr info = ctx->driverPrivate; unsigned long mode; unsigned int vendor, device; int ret; unsigned long cntl, chunk; int s, l; int flags; unsigned long agpBase; if (drmAgpAcquire(ctx->drmFD) < 0) { fprintf(stderr, "[agp] AGP not available\n"); return GL_FALSE; } /* Modify the mode if the default mode is not appropriate for this particular combination of graphics card and AGP chipset. */ mode = drmAgpGetMode(ctx->drmFD); /* Default mode */ vendor = drmAgpVendorId(ctx->drmFD); device = drmAgpDeviceId(ctx->drmFD); mode &= ~R128_AGP_MODE_MASK; switch (info->agpMode) { case 4: mode |= R128_AGP_4X_MODE; case 2: mode |= R128_AGP_2X_MODE; case 1: default: mode |= R128_AGP_1X_MODE; } fprintf(stderr, "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", mode, vendor, device, 0x1002, info->Chipset); if (drmAgpEnable(ctx->drmFD, mode) < 0) { fprintf(stderr, "[agp] AGP not enabled\n"); drmAgpRelease(ctx->drmFD); return GL_FALSE; } info->agpOffset = 0; if ((ret = drmAgpAlloc(ctx->drmFD, info->agpSize*1024*1024, 0, NULL, &info->agpMemHandle)) < 0) { fprintf(stderr, "[agp] Out of memory (%d)\n", ret); drmAgpRelease(ctx->drmFD); return GL_FALSE; } fprintf(stderr, "[agp] %d kB allocated with handle 0x%08x\n", info->agpSize*1024, info->agpMemHandle); if (drmAgpBind(ctx->drmFD, info->agpMemHandle, info->agpOffset) < 0) { fprintf(stderr, "[agp] Could not bind\n"); drmAgpFree(ctx->drmFD, info->agpMemHandle); drmAgpRelease(ctx->drmFD); return GL_FALSE; } /* Initialize the CCE ring buffer data */ info->ringStart = info->agpOffset; info->ringMapSize = info->ringSize*1024*1024 + r128_drm_page_size; info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; info->ringReadOffset = info->ringStart + info->ringMapSize; info->ringReadMapSize = r128_drm_page_size; /* Reserve space for vertex/indirect buffers */ info->bufStart = info->ringReadOffset + info->ringReadMapSize; info->bufMapSize = info->bufSize*1024*1024; /* Reserve the rest for AGP textures */ info->agpTexStart = info->bufStart + info->bufMapSize; s = (info->agpSize*1024*1024 - info->agpTexStart); l = R128MinBits((s-1) / R128_NR_TEX_REGIONS); if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; info->agpTexMapSize = (s >> l) << l; info->log2AGPTexGran = l; if (info->CCESecure) flags = DRM_READ_ONLY; else flags = 0; if (drmAddMap(ctx->drmFD, info->ringStart, info->ringMapSize, DRM_AGP, flags, &info->ringHandle) < 0) { fprintf(stderr, "[agp] Could not add ring mapping\n"); return GL_FALSE; } fprintf(stderr, "[agp] ring handle = 0x%08x\n", info->ringHandle); if (drmMap(ctx->drmFD, info->ringHandle, info->ringMapSize, (drmAddressPtr)&info->ring) < 0) { fprintf(stderr, "[agp] Could not map ring\n"); return GL_FALSE; } fprintf(stderr, "[agp] Ring mapped at 0x%08lx\n", (unsigned long)info->ring); if (drmAddMap(ctx->drmFD, info->ringReadOffset, info->ringReadMapSize, DRM_AGP, flags, &info->ringReadPtrHandle) < 0) { fprintf(stderr, "[agp] Could not add ring read ptr mapping\n"); return GL_FALSE; } fprintf(stderr, "[agp] ring read ptr handle = 0x%08x\n", info->ringReadPtrHandle); if (drmMap(ctx->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, (drmAddressPtr)&info->ringReadPtr) < 0) { fprintf(stderr, "[agp] Could not map ring read ptr\n"); return GL_FALSE; } fprintf(stderr, "[agp] Ring read ptr mapped at 0x%08lx\n", (unsigned long)info->ringReadPtr); if (drmAddMap(ctx->drmFD, info->bufStart, info->bufMapSize, DRM_AGP, 0, &info->bufHandle) < 0) { fprintf(stderr, "[agp] Could not add vertex/indirect buffers mapping\n"); return GL_FALSE; } fprintf(stderr, "[agp] vertex/indirect buffers handle = 0x%08lx\n", info->bufHandle); if (drmMap(ctx->drmFD, info->bufHandle, info->bufMapSize, (drmAddressPtr)&info->buf) < 0) { fprintf(stderr, "[agp] Could not map vertex/indirect buffers\n"); return GL_FALSE; } fprintf(stderr, "[agp] Vertex/indirect buffers mapped at 0x%08lx\n", (unsigned long)info->buf); if (drmAddMap(ctx->drmFD, info->agpTexStart, info->agpTexMapSize, DRM_AGP, 0, &info->agpTexHandle) < 0) { fprintf(stderr, "[agp] Could not add AGP texture map mapping\n"); return GL_FALSE; } fprintf(stderr, "[agp] AGP texture map handle = 0x%08lx\n", info->agpTexHandle); if (drmMap(ctx->drmFD, info->agpTexHandle, info->agpTexMapSize, (drmAddressPtr)&info->agpTex) < 0) { fprintf(stderr, "[agp] Could not map AGP texture map\n"); return GL_FALSE; } fprintf(stderr, "[agp] AGP Texture map mapped at 0x%08lx\n", (unsigned long)info->agpTex); /* Initialize Rage 128's AGP registers */ cntl = INREG(R128_AGP_CNTL); cntl &= ~R128_AGP_APER_SIZE_MASK; switch (info->agpSize) { case 256: cntl |= R128_AGP_APER_SIZE_256MB; break; case 128: cntl |= R128_AGP_APER_SIZE_128MB; break; case 64: cntl |= R128_AGP_APER_SIZE_64MB; break; case 32: cntl |= R128_AGP_APER_SIZE_32MB; break; case 16: cntl |= R128_AGP_APER_SIZE_16MB; break; case 8: cntl |= R128_AGP_APER_SIZE_8MB; break; case 4: cntl |= R128_AGP_APER_SIZE_4MB; break; default: fprintf(stderr, "[agp] Illegal aperture size %d kB\n", info->agpSize*1024); return GL_FALSE; } agpBase = drmAgpBase(ctx->drmFD); OUTREG(R128_AGP_BASE, agpBase); OUTREG(R128_AGP_CNTL, cntl); /* Disable Rage 128's PCIGART registers */ chunk = INREG(R128_BM_CHUNK_0_VAL); chunk &= ~(R128_BM_PTR_FORCE_TO_PCI | R128_BM_PM4_RD_FORCE_TO_PCI | R128_BM_GLOBAL_FORCE_TO_PCI); OUTREG(R128_BM_CHUNK_0_VAL, chunk); OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */ return GL_TRUE; } static GLboolean R128DRIPciInit(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; unsigned char *R128MMIO = ctx->MMIOAddress; u_int32_t chunk; int ret; int flags; info->agpOffset = 0; ret = drmScatterGatherAlloc(ctx->drmFD, info->agpSize*1024*1024, &info->pciMemHandle); if (ret < 0) { fprintf(stderr, "[pci] Out of memory (%d)\n", ret); return GL_FALSE; } fprintf(stderr, "[pci] %d kB allocated with handle 0x%08x\n", info->agpSize*1024, info->pciMemHandle); /* Initialize the CCE ring buffer data */ info->ringStart = info->agpOffset; info->ringMapSize = info->ringSize*1024*1024 + r128_drm_page_size; info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; info->ringReadOffset = info->ringStart + info->ringMapSize; info->ringReadMapSize = r128_drm_page_size; /* Reserve space for vertex/indirect buffers */ info->bufStart = info->ringReadOffset + info->ringReadMapSize; info->bufMapSize = info->bufSize*1024*1024; flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL; if (drmAddMap(ctx->drmFD, info->ringStart, info->ringMapSize, DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) { fprintf(stderr, "[pci] Could not add ring mapping\n"); return GL_FALSE; } fprintf(stderr, "[pci] ring handle = 0x%08lx\n", info->ringHandle); if (drmMap(ctx->drmFD, info->ringHandle, info->ringMapSize, (drmAddressPtr)&info->ring) < 0) { fprintf(stderr, "[pci] Could not map ring\n"); return GL_FALSE; } fprintf(stderr, "[pci] Ring mapped at 0x%08lx\n", (unsigned long)info->ring); fprintf(stderr, "[pci] Ring contents 0x%08lx\n", *(unsigned long *)info->ring); if (drmAddMap(ctx->drmFD, info->ringReadOffset, info->ringReadMapSize, DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) { fprintf(stderr, "[pci] Could not add ring read ptr mapping\n"); return GL_FALSE; } fprintf(stderr, "[pci] ring read ptr handle = 0x%08lx\n", info->ringReadPtrHandle); if (drmMap(ctx->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, (drmAddressPtr)&info->ringReadPtr) < 0) { fprintf(stderr, "[pci] Could not map ring read ptr\n"); return GL_FALSE; } fprintf(stderr, "[pci] Ring read ptr mapped at 0x%08lx\n", (unsigned long)info->ringReadPtr); fprintf(stderr, "[pci] Ring read ptr contents 0x%08lx\n", *(unsigned long *)info->ringReadPtr); if (drmAddMap(ctx->drmFD, info->bufStart, info->bufMapSize, DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) { fprintf(stderr, "[pci] Could not add vertex/indirect buffers mapping\n"); return GL_FALSE; } fprintf(stderr, "[pci] vertex/indirect buffers handle = 0x%08lx\n", info->bufHandle); if (drmMap(ctx->drmFD, info->bufHandle, info->bufMapSize, (drmAddressPtr)&info->buf) < 0) { fprintf(stderr, "[pci] Could not map vertex/indirect buffers\n"); return GL_FALSE; } fprintf(stderr, "[pci] Vertex/indirect buffers mapped at 0x%08lx\n", (unsigned long)info->buf); fprintf(stderr, "[pci] Vertex/indirect buffers contents 0x%08lx\n", *(unsigned long *)info->buf); if (!info->IsPCI) { /* This is really an AGP card, force PCI GART mode */ chunk = INREG(R128_BM_CHUNK_0_VAL); chunk |= (R128_BM_PTR_FORCE_TO_PCI | R128_BM_PM4_RD_FORCE_TO_PCI | R128_BM_GLOBAL_FORCE_TO_PCI); OUTREG(R128_BM_CHUNK_0_VAL, chunk); OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */ } return GL_TRUE; } /* Add a map for the MMIO registers that will be accessed by any DRI-based clients. */ static GLboolean R128DRIMapInit(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; int flags; if (info->CCESecure) flags = DRM_READ_ONLY; else flags = 0; /* Map registers */ if (drmAddMap(ctx->drmFD, ctx->MMIOStart, ctx->MMIOSize, DRM_REGISTERS, flags, &info->registerHandle) < 0) { return GL_FALSE; } fprintf(stderr, "[drm] register handle = 0x%08x\n", info->registerHandle); return GL_TRUE; } /* Initialize the kernel data structures. */ static int R128DRIKernelInit(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; drm_r128_init_t drmInfo; memset( &drmInfo, 0, sizeof(&drmInfo) ); drmInfo.func = R128_INIT_CCE; drmInfo.sarea_priv_offset = sizeof(drm_sarea_t); drmInfo.is_pci = info->IsPCI; drmInfo.cce_mode = info->CCEMode; drmInfo.cce_secure = info->CCESecure; drmInfo.ring_size = info->ringSize*1024*1024; drmInfo.usec_timeout = info->CCEusecTimeout; drmInfo.fb_bpp = ctx->bpp; drmInfo.depth_bpp = ctx->bpp; drmInfo.front_offset = info->frontOffset; drmInfo.front_pitch = info->frontPitch; drmInfo.back_offset = info->backOffset; drmInfo.back_pitch = info->backPitch; drmInfo.depth_offset = info->depthOffset; drmInfo.depth_pitch = info->depthPitch; drmInfo.span_offset = info->spanOffset; drmInfo.fb_offset = info->LinearAddr; drmInfo.mmio_offset = info->registerHandle; drmInfo.ring_offset = info->ringHandle; drmInfo.ring_rptr_offset = info->ringReadPtrHandle; drmInfo.buffers_offset = info->bufHandle; drmInfo.agp_textures_offset = info->agpTexHandle; if (drmCommandWrite(ctx->drmFD, DRM_R128_INIT, &drmInfo, sizeof(drmInfo)) < 0) return GL_FALSE; return GL_TRUE; } /* Add a map for the vertex buffers that will be accessed by any DRI-based clients. */ static GLboolean R128DRIBufInit(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; /* Initialize vertex buffers */ if (info->IsPCI) { info->bufNumBufs = drmAddBufs(ctx->drmFD, info->bufMapSize / R128_BUFFER_SIZE, R128_BUFFER_SIZE, DRM_SG_BUFFER, info->bufStart); } else { info->bufNumBufs = drmAddBufs(ctx->drmFD, info->bufMapSize / R128_BUFFER_SIZE, R128_BUFFER_SIZE, DRM_AGP_BUFFER, info->bufStart); } if (info->bufNumBufs <= 0) { fprintf(stderr, "[drm] Could not create vertex/indirect buffers list\n"); return GL_FALSE; } fprintf(stderr, "[drm] Added %d %d byte vertex/indirect buffers\n", info->bufNumBufs, R128_BUFFER_SIZE); if (!(info->buffers = drmMapBufs(ctx->drmFD))) { fprintf(stderr, "[drm] Failed to map vertex/indirect buffers list\n"); return GL_FALSE; } fprintf(stderr, "[drm] Mapped %d vertex/indirect buffers\n", info->buffers->count); return GL_TRUE; } static void R128DRIIrqInit(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; unsigned char *R128MMIO = ctx->MMIOAddress; if (!info->irq) { info->irq = drmGetInterruptFromBusID( ctx->drmFD, ctx->pciBus, ctx->pciDevice, ctx->pciFunc); if((drmCtlInstHandler(ctx->drmFD, info->irq)) != 0) { fprintf(stderr, "[drm] failure adding irq handler, " "there is a device already using that irq\n" "[drm] falling back to irq-free operation\n"); info->irq = 0; } else { info->gen_int_cntl = INREG( R128_GEN_INT_CNTL ); } } if (info->irq) fprintf(stderr, "[drm] dma control initialized, using IRQ %d\n", info->irq); } static int R128CCEStop(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; drm_r128_cce_stop_t stop; int ret, i; stop.flush = 1; stop.idle = 1; ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, &stop, sizeof(stop) ); if ( ret == 0 ) { return 0; } else if ( errno != EBUSY ) { return -errno; } stop.flush = 0; i = 0; do { ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, &stop, sizeof(stop) ); } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); if ( ret == 0 ) { return 0; } else if ( errno != EBUSY ) { return -errno; } stop.idle = 0; if ( drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, &stop, sizeof(stop) )) { return -errno; } else { return 0; } } /* Initialize the CCE state, and start the CCE (if used by the X server) */ static void R128DRICCEInit(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; /* Turn on bus mastering */ info->BusCntl &= ~R128_BUS_MASTER_DIS; /* CCEMode is initialized in r128_driver.c */ switch (info->CCEMode) { case R128_PM4_NONPM4: info->CCEFifoSize = 0; break; case R128_PM4_192PIO: info->CCEFifoSize = 192; break; case R128_PM4_192BM: info->CCEFifoSize = 192; break; case R128_PM4_128PIO_64INDBM: info->CCEFifoSize = 128; break; case R128_PM4_128BM_64INDBM: info->CCEFifoSize = 128; break; case R128_PM4_64PIO_128INDBM: info->CCEFifoSize = 64; break; case R128_PM4_64BM_128INDBM: info->CCEFifoSize = 64; break; case R128_PM4_64PIO_64VCBM_64INDBM: info->CCEFifoSize = 64; break; case R128_PM4_64BM_64VCBM_64INDBM: info->CCEFifoSize = 64; break; case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64; break; } /* Make sure the CCE is on for the X server */ R128CCE_START(ctx, info); } static int R128MemoryInit(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; int width_bytes = ctx->shared.virtualWidth * ctx->cpp; int cpp = ctx->cpp; int bufferSize = ((ctx->shared.virtualHeight * width_bytes + R128_BUFFER_ALIGN) & ~R128_BUFFER_ALIGN); int depthSize = ((((ctx->shared.virtualHeight+15) & ~15) * width_bytes + R128_BUFFER_ALIGN) & ~R128_BUFFER_ALIGN); int l; info->frontOffset = 0; info->frontPitch = ctx->shared.virtualWidth; fprintf(stderr, "Using %d MB AGP aperture\n", info->agpSize); fprintf(stderr, "Using %d MB for the ring buffer\n", info->ringSize); fprintf(stderr, "Using %d MB for vertex/indirect buffers\n", info->bufSize); fprintf(stderr, "Using %d MB for AGP textures\n", info->agpTexSize); /* Front, back and depth buffers - everything else texture?? */ info->textureSize = ctx->shared.fbSize - 2 * bufferSize - depthSize; if (info->textureSize < 0) return 0; l = R128MinBits((info->textureSize-1) / R128_NR_TEX_REGIONS); if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; /* Round the texture size up to the nearest whole number of * texture regions. Again, be greedy about this, don't * round down. */ info->log2TexGran = l; info->textureSize = (info->textureSize >> l) << l; /* Set a minimum usable local texture heap size. This will fit * two 256x256x32bpp textures. */ if (info->textureSize < 512 * 1024) { info->textureOffset = 0; info->textureSize = 0; } /* Reserve space for textures */ info->textureOffset = ((ctx->shared.fbSize - info->textureSize + R128_BUFFER_ALIGN) & ~R128_BUFFER_ALIGN); /* Reserve space for the shared depth * buffer. */ info->depthOffset = ((info->textureOffset - depthSize + R128_BUFFER_ALIGN) & ~R128_BUFFER_ALIGN); info->depthPitch = ctx->shared.virtualWidth; info->backOffset = ((info->depthOffset - bufferSize + R128_BUFFER_ALIGN) & ~R128_BUFFER_ALIGN); info->backPitch = ctx->shared.virtualWidth; fprintf(stderr, "Will use back buffer at offset 0x%x\n", info->backOffset); fprintf(stderr, "Will use depth buffer at offset 0x%x\n", info->depthOffset); fprintf(stderr, "Will use %d kb for textures at offset 0x%x\n", info->textureSize/1024, info->textureOffset); return 1; } /* Initialize the screen-specific data structures for the DRI and the Rage 128. 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. */ static GLboolean R128DRIScreenInit(DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; R128DRIPtr pR128DRI; int err, major, minor, patch; drmVersionPtr version; drm_r128_sarea_t *pSAREAPriv; switch (ctx->bpp) { case 8: /* These modes are not supported (yet). */ case 15: case 24: fprintf(stderr, "[dri] R128DRIScreenInit failed (depth %d not supported). " "[dri] Disabling DRI.\n", ctx->bpp); return GL_FALSE; /* Only 16 and 32 color depths are supports currently. */ case 16: case 32: break; } r128_drm_page_size = getpagesize(); info->registerSize = ctx->MMIOSize; ctx->shared.SAREASize = SAREA_MAX; /* Note that drmOpen will try to load the kernel module, if needed. */ ctx->drmFD = drmOpen("r128", NULL ); if (ctx->drmFD < 0) { fprintf(stderr, "[drm] drmOpen failed\n"); return 0; } /* Check the r128 DRM version */ version = drmGetVersion(ctx->drmFD); if (version) { if (version->version_major != 2 || version->version_minor < 2) { /* incompatible drm version */ fprintf(stderr, "[dri] R128DRIScreenInit failed because of a version mismatch.\n" "[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n" "[dri] Disabling the DRI.\n", version->version_major, version->version_minor, version->version_patchlevel); drmFreeVersion(version); return GL_FALSE; } info->drmMinor = version->version_minor; drmFreeVersion(version); } if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) { fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n", ctx->drmFD, ctx->pciBusID, strerror(-err)); return 0; } if (drmAddMap( ctx->drmFD, 0, ctx->shared.SAREASize, DRM_SHM, DRM_CONTAINS_LOCK, &ctx->shared.hSAREA) < 0) { fprintf(stderr, "[drm] drmAddMap failed\n"); return 0; } fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n", ctx->shared.SAREASize, ctx->shared.hSAREA); if (drmMap( ctx->drmFD, ctx->shared.hSAREA, ctx->shared.SAREASize, (drmAddressPtr)(&ctx->pSAREA)) < 0) { fprintf(stderr, "[drm] drmMap failed\n"); return 0; } memset(ctx->pSAREA, 0, ctx->shared.SAREASize); fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n", ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize); /* Need to AddMap the framebuffer and mmio regions here: */ if (drmAddMap( ctx->drmFD, (drm_handle_t)ctx->FBStart, ctx->FBSize, DRM_FRAME_BUFFER, 0, &ctx->shared.hFrameBuffer) < 0) { fprintf(stderr, "[drm] drmAddMap framebuffer failed\n"); return 0; } fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n", ctx->shared.hFrameBuffer); if (!R128MemoryInit(ctx)) return GL_FALSE; /* Initialize AGP */ if (!info->IsPCI && !R128DRIAgpInit(ctx)) { info->IsPCI = GL_TRUE; fprintf(stderr, "[agp] AGP failed to initialize -- falling back to PCI mode.\n"); fprintf(stderr, "[agp] Make sure you have the agpgart kernel module loaded.\n"); } /* Initialize PCIGART */ if (info->IsPCI && !R128DRIPciInit(ctx)) { return GL_FALSE; } /* DRIScreenInit doesn't add all the common mappings. Add additional mappings here. */ if (!R128DRIMapInit(ctx)) { return GL_FALSE; } /* Create a 'server' context so we can grab the lock for * initialization ioctls. */ if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) { fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err); return 0; } DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0); /* Initialize the kernel data structures */ if (!R128DRIKernelInit(ctx)) { return GL_FALSE; } /* Initialize the vertex buffers list */ if (!R128DRIBufInit(ctx)) { return GL_FALSE; } /* Initialize IRQ */ R128DRIIrqInit(ctx); /* Initialize and start the CCE if required */ R128DRICCEInit(ctx); /* Quick hack to clear the front & back buffers. Could also use * the clear ioctl to do this, but would need to setup hw state * first. */ drimemsetio((char *)ctx->FBAddress + info->frontOffset, 0, info->frontPitch * ctx->cpp * ctx->shared.virtualHeight ); drimemsetio((char *)ctx->FBAddress + info->backOffset, 0, info->backPitch * ctx->cpp * ctx->shared.virtualHeight ); pSAREAPriv = (drm_r128_sarea_t *)(((char*)ctx->pSAREA) + sizeof(drm_sarea_t)); memset(pSAREAPriv, 0, sizeof(*pSAREAPriv)); /* This is the struct passed to radeon_dri.so for its initialization */ ctx->driverClientMsg = malloc(sizeof(R128DRIRec)); ctx->driverClientMsgSize = sizeof(R128DRIRec); pR128DRI = (R128DRIPtr)ctx->driverClientMsg; pR128DRI->deviceID = info->Chipset; pR128DRI->width = ctx->shared.virtualWidth; pR128DRI->height = ctx->shared.virtualHeight; pR128DRI->depth = ctx->bpp; pR128DRI->bpp = ctx->bpp; pR128DRI->IsPCI = info->IsPCI; pR128DRI->AGPMode = info->agpMode; pR128DRI->frontOffset = info->frontOffset; pR128DRI->frontPitch = info->frontPitch; pR128DRI->backOffset = info->backOffset; pR128DRI->backPitch = info->backPitch; pR128DRI->depthOffset = info->depthOffset; pR128DRI->depthPitch = info->depthPitch; pR128DRI->spanOffset = info->spanOffset; pR128DRI->textureOffset = info->textureOffset; pR128DRI->textureSize = info->textureSize; pR128DRI->log2TexGran = info->log2TexGran; pR128DRI->registerHandle = info->registerHandle; pR128DRI->registerSize = info->registerSize; pR128DRI->agpTexHandle = info->agpTexHandle; pR128DRI->agpTexMapSize = info->agpTexMapSize; pR128DRI->log2AGPTexGran = info->log2AGPTexGran; pR128DRI->agpTexOffset = info->agpTexStart; pR128DRI->sarea_priv_offset = sizeof(drm_sarea_t); return GL_TRUE; } /* The screen is being closed, so clean up any state and free any resources used by the DRI. */ void R128DRICloseScreen(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; drm_r128_init_t drmInfo; /* Stop the CCE if it is still in use */ R128CCE_STOP(ctx, info); if (info->irq) { drmCtlUninstHandler(ctx->drmFD); info->irq = 0; } /* De-allocate vertex buffers */ if (info->buffers) { drmUnmapBufs(info->buffers); info->buffers = NULL; } /* De-allocate all kernel resources */ memset(&drmInfo, 0, sizeof(drmInfo)); drmInfo.func = R128_CLEANUP_CCE; drmCommandWrite(ctx->drmFD, DRM_R128_INIT, &drmInfo, sizeof(drmInfo)); /* De-allocate all AGP resources */ if (info->agpTex) { drmUnmap(info->agpTex, info->agpTexMapSize); info->agpTex = NULL; } if (info->buf) { drmUnmap(info->buf, info->bufMapSize); info->buf = NULL; } if (info->ringReadPtr) { drmUnmap(info->ringReadPtr, info->ringReadMapSize); info->ringReadPtr = NULL; } if (info->ring) { drmUnmap(info->ring, info->ringMapSize); info->ring = NULL; } if (info->agpMemHandle != DRM_AGP_NO_HANDLE) { drmAgpUnbind(ctx->drmFD, info->agpMemHandle); drmAgpFree(ctx->drmFD, info->agpMemHandle); info->agpMemHandle = 0; drmAgpRelease(ctx->drmFD); } if (info->pciMemHandle) { drmScatterGatherFree(ctx->drmFD, info->pciMemHandle); info->pciMemHandle = 0; } } static GLboolean R128PreInitDRI(const DRIDriverContext *ctx) { R128InfoPtr info = ctx->driverPrivate; /*info->CCEMode = R128_DEFAULT_CCE_PIO_MODE;*/ info->CCEMode = R128_DEFAULT_CCE_BM_MODE; info->CCESecure = GL_TRUE; info->agpMode = R128_DEFAULT_AGP_MODE; info->agpSize = R128_DEFAULT_AGP_SIZE; info->ringSize = R128_DEFAULT_RING_SIZE; info->bufSize = R128_DEFAULT_BUFFER_SIZE; info->agpTexSize = R128_DEFAULT_AGP_TEX_SIZE; info->CCEusecTimeout = R128_DEFAULT_CCE_TIMEOUT; return GL_TRUE; } /** * \brief Initialize the framebuffer device mode * * \param ctx display handle. * * \return one on success, or zero on failure. * * Fills in \p info with some default values and some information from \p ctx * and then calls R128ScreenInit() for the screen initialization. * * Before exiting clears the framebuffer memory accessing it directly. */ static int R128InitFBDev( DRIDriverContext *ctx ) { R128InfoPtr info = calloc(1, sizeof(*info)); { int dummy = ctx->shared.virtualWidth; switch (ctx->bpp / 8) { case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break; case 2: dummy = (ctx->shared.virtualWidth + 31) & ~31; break; case 3: case 4: dummy = (ctx->shared.virtualWidth + 15) & ~15; break; } ctx->shared.virtualWidth = dummy; } ctx->driverPrivate = (void *)info; info->Chipset = ctx->chipset; switch (info->Chipset) { case PCI_DEVICE_ID_ATI_RAGE128_LE: case PCI_DEVICE_ID_ATI_RAGE128_RE: case PCI_DEVICE_ID_ATI_RAGE128_RK: case PCI_DEVICE_ID_ATI_RAGE128_PD: case PCI_DEVICE_ID_ATI_RAGE128_PP: case PCI_DEVICE_ID_ATI_RAGE128_PR: /* This is a PCI card */ info->IsPCI = GL_TRUE; break; default: /* This is an AGP card */ info->IsPCI = GL_FALSE; break; } info->frontPitch = ctx->shared.virtualWidth; info->LinearAddr = ctx->FBStart & 0xfc000000; if (!R128PreInitDRI(ctx)) return 0; if (!R128DRIScreenInit(ctx)) return 0; return 1; } /** * \brief The screen is being closed, so clean up any state and free any * resources used by the DRI. * * \param ctx display handle. * * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver * private data. */ static void R128HaltFBDev( DRIDriverContext *ctx ) { drmUnmap( ctx->pSAREA, ctx->shared.SAREASize ); drmClose(ctx->drmFD); if (ctx->driverPrivate) { free(ctx->driverPrivate); ctx->driverPrivate = 0; } } /** * \brief Validate the fbdev mode. * * \param ctx display handle. * * \return one on success, or zero on failure. * * Saves some registers and returns 1. * * \sa R128PostValidateMode(). */ static int R128ValidateMode( const DRIDriverContext *ctx ) { return 1; } /** * \brief Examine mode returned by fbdev. * * \param ctx display handle. * * \return one on success, or zero on failure. * * Restores registers that fbdev has clobbered and returns 1. * * \sa R128ValidateMode(). */ static int R128PostValidateMode( const DRIDriverContext *ctx ) { return 1; } /** * \brief Shutdown the drawing engine. * * \param ctx display handle * * Turns off the command processor engine & restores the graphics card * to a state that fbdev understands. */ static int R128EngineShutdown( const DRIDriverContext *ctx ) { return 1; } /** * \brief Restore the drawing engine. * * \param ctx display handle * * Resets the graphics card and sets initial values for several registers of * the card's drawing engine. * * Turns on the R128 command processor engine (i.e., the ringbuffer). */ static int R128EngineRestore( const DRIDriverContext *ctx ) { return 1; } /** * \brief Exported driver interface for Mini GLX. * * \sa DRIDriverRec. */ const struct DRIDriverRec __driDriver = { R128ValidateMode, R128PostValidateMode, R128InitFBDev, R128HaltFBDev, R128EngineShutdown, R128EngineRestore, 0, };