| /* $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 <martin@valinux.com> |
| * Rickard E. Faith <faith@valinux.com> |
| * Daryll Strauss <daryll@valinux.com> |
| * Gareth Hughes <gareth@valinux.com> |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| // 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, |
| }; |