/* * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2003 S3 Graphics, Inc. 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, sub license, * 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 * VIA, S3 GRAPHICS, AND/OR ITS 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. */ #include #include #include #include #include #include "driver.h" #include "drm.h" #include "imports.h" #include "dri_util.h" #include "via_context.h" #include "via_dri.h" #include "via_driver.h" #include "xf86drm.h" static void VIAEnableMMIO(DRIDriverContext * ctx); static void VIADisableMMIO(DRIDriverContext * ctx); static void VIADisableExtendedFIFO(DRIDriverContext *ctx); static void VIAEnableExtendedFIFO(DRIDriverContext *ctx); static void VIAInitialize2DEngine(DRIDriverContext *ctx); static void VIAInitialize3DEngine(DRIDriverContext *ctx); static int VIADRIScreenInit(DRIDriverContext * ctx); static void VIADRICloseScreen(DRIDriverContext * ctx); static int VIADRIFinishScreenInit(DRIDriverContext * ctx); /* _SOLO : missing macros normally defined by X code */ #define xf86DrvMsg(a, b, ...) fprintf(stderr, __VA_ARGS__) #define MMIO_IN8(base, addr) ((*(((volatile uint8_t*)base)+(addr)))+0) #define MMIO_OUT8(base, addr, val) ((*(((volatile uint8_t*)base)+(addr)))=((uint8_t)val)) #define MMIO_OUT16(base, addr, val) ((*(volatile uint16_t*)(((uint8_t*)base)+(addr)))=((uint16_t)val)) #define VIDEO 0 #define AGP 1 #define AGP_PAGE_SIZE 4096 #define AGP_PAGES 8192 #define AGP_SIZE (AGP_PAGE_SIZE * AGP_PAGES) #define AGP_CMDBUF_PAGES 512 #define AGP_CMDBUF_SIZE (AGP_PAGE_SIZE * AGP_CMDBUF_PAGES) static char VIAKernelDriverName[] = "via"; static char VIAClientDriverName[] = "unichrome"; static int VIADRIAgpInit(const DRIDriverContext *ctx, VIAPtr pVia); static int VIADRIPciInit(DRIDriverContext * ctx, VIAPtr pVia); static int VIADRIFBInit(DRIDriverContext * ctx, VIAPtr pVia); static int VIADRIKernelInit(DRIDriverContext * ctx, VIAPtr pVia); static int VIADRIMapInit(DRIDriverContext * ctx, VIAPtr pVia); static void VIADRIIrqInit( DRIDriverContext *ctx ) { VIAPtr pVia = VIAPTR(ctx); VIADRIPtr pVIADRI = pVia->devPrivate; pVIADRI->irqEnabled = drmGetInterruptFromBusID(pVia->drmFD, ctx->pciBus, ctx->pciDevice, ctx->pciFunc); if ((drmCtlInstHandler(pVia->drmFD, pVIADRI->irqEnabled))) { xf86DrvMsg(pScreen->myNum, X_WARNING, "[drm] Failure adding irq handler. " "Falling back to irq-free operation.\n"); pVIADRI->irqEnabled = 0; } if (pVIADRI->irqEnabled) xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Irq handler installed, using IRQ %d.\n", pVIADRI->irqEnabled); } static void VIADRIIrqExit( DRIDriverContext *ctx ) { VIAPtr pVia = VIAPTR(ctx); VIADRIPtr pVIADRI = pVia->devPrivate; if (pVIADRI->irqEnabled) { if (drmCtlUninstHandler(pVia->drmFD)) { xf86DrvMsg(pScreen-myNum, X_INFO,"[drm] Irq handler uninstalled.\n"); } else { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] Could not uninstall irq handler.\n"); } } } static void VIADRIRingBufferCleanup(DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); VIADRIPtr pVIADRI = pVia->devPrivate; drm_via_dma_init_t ringBufInit; if (pVIADRI->ringBufActive) { xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Cleaning up DMA ring-buffer.\n"); ringBufInit.func = VIA_CLEANUP_DMA; if (drmCommandWrite(pVia->drmFD, DRM_VIA_DMA_INIT, &ringBufInit, sizeof(ringBufInit))) { xf86DrvMsg(pScreen->myNum, X_WARNING, "[drm] Failed to clean up DMA ring-buffer: %d\n", errno); } pVIADRI->ringBufActive = 0; } } static int VIADRIRingBufferInit(DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); VIADRIPtr pVIADRI = pVia->devPrivate; drm_via_dma_init_t ringBufInit; drmVersionPtr drmVer; pVIADRI->ringBufActive = 0; if (NULL == (drmVer = drmGetVersion(pVia->drmFD))) { return GL_FALSE; } if (((drmVer->version_major <= 1) && (drmVer->version_minor <= 3))) { return GL_FALSE; } /* * Info frome code-snippet on DRI-DEVEL list; Erdi Chen. */ switch (pVia->ChipId) { case PCI_CHIP_VT3259: ringBufInit.reg_pause_addr = 0x40c; break; default: ringBufInit.reg_pause_addr = 0x418; break; } ringBufInit.offset = pVia->agpSize; ringBufInit.size = AGP_CMDBUF_SIZE; ringBufInit.func = VIA_INIT_DMA; if (drmCommandWrite(pVia->drmFD, DRM_VIA_DMA_INIT, &ringBufInit, sizeof(ringBufInit))) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] Failed to initialize DMA ring-buffer: %d\n", errno); return GL_FALSE; } xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Initialized AGP ring-buffer, size 0x%lx at AGP offset 0x%lx.\n", ringBufInit.size, ringBufInit.offset); pVIADRI->ringBufActive = 1; return GL_TRUE; } static int VIADRIAgpInit(const DRIDriverContext *ctx, VIAPtr pVia) { unsigned long agp_phys; drmAddress agpaddr; VIADRIPtr pVIADRI; pVIADRI = pVia->devPrivate; pVia->agpSize = 0; if (drmAgpAcquire(pVia->drmFD) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAgpAcquire failed %d\n", errno); return GL_FALSE; } if (drmAgpEnable(pVia->drmFD, drmAgpGetMode(pVia->drmFD)&~0x0) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAgpEnable failed\n"); return GL_FALSE; } xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] drmAgpEnabled succeeded\n"); if (drmAgpAlloc(pVia->drmFD, AGP_SIZE, 0, &agp_phys, &pVia->agpHandle) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAgpAlloc failed\n"); drmAgpRelease(pVia->drmFD); return GL_FALSE; } if (drmAgpBind(pVia->drmFD, pVia->agpHandle, 0) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAgpBind failed\n"); drmAgpFree(pVia->drmFD, pVia->agpHandle); drmAgpRelease(pVia->drmFD); return GL_FALSE; } /* * Place the ring-buffer last in the AGP region, and restrict the * public map not to include the buffer for security reasons. */ pVia->agpSize = AGP_SIZE - AGP_CMDBUF_SIZE; pVia->agpAddr = drmAgpBase(pVia->drmFD); xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] agpAddr = 0x%08lx\n",pVia->agpAddr); pVIADRI->agp.size = pVia->agpSize; if (drmAddMap(pVia->drmFD, (drm_handle_t)0, pVIADRI->agp.size, DRM_AGP, 0, &pVIADRI->agp.handle) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] Failed to map public agp area\n"); pVIADRI->agp.size = 0; return GL_FALSE; } /* Map AGP from kernel to Xserver - Not really needed */ drmMap(pVia->drmFD, pVIADRI->agp.handle,pVIADRI->agp.size, &agpaddr); xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] agpAddr = 0x%08lx\n", pVia->agpAddr); xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] agpSize = 0x%08lx\n", pVia->agpSize); xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] agp physical addr = 0x%08lx\n", agp_phys); { drm_via_agp_t agp; agp.offset = 0; agp.size = AGP_SIZE-AGP_CMDBUF_SIZE; if (drmCommandWrite(pVia->drmFD, DRM_VIA_AGP_INIT, &agp, sizeof(drm_via_agp_t)) < 0) { drmUnmap(&agpaddr,pVia->agpSize); drmRmMap(pVia->drmFD,pVIADRI->agp.handle); drmAgpUnbind(pVia->drmFD, pVia->agpHandle); drmAgpFree(pVia->drmFD, pVia->agpHandle); drmAgpRelease(pVia->drmFD); return GL_FALSE; } } return GL_TRUE; } static int VIADRIFBInit(DRIDriverContext * ctx, VIAPtr pVia) { int FBSize = pVia->FBFreeEnd-pVia->FBFreeStart; int FBOffset = pVia->FBFreeStart; VIADRIPtr pVIADRI = pVia->devPrivate; pVIADRI->fbOffset = FBOffset; pVIADRI->fbSize = pVia->videoRambytes; { drm_via_fb_t fb; fb.offset = FBOffset; fb.size = FBSize; if (drmCommandWrite(pVia->drmFD, DRM_VIA_FB_INIT, &fb, sizeof(drm_via_fb_t)) < 0) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] failed to init frame buffer area\n"); return GL_FALSE; } else { xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] FBFreeStart= 0x%08x FBFreeEnd= 0x%08x " "FBSize= 0x%08x\n", pVia->FBFreeStart, pVia->FBFreeEnd, FBSize); return GL_TRUE; } } } static int VIADRIPciInit(DRIDriverContext * ctx, VIAPtr pVia) { return GL_TRUE; } static int VIADRIScreenInit(DRIDriverContext * ctx) { VIAPtr pVia = VIAPTR(ctx); VIADRIPtr pVIADRI; int err; #if 0 ctx->shared.SAREASize = ((sizeof(drm_sarea_t) + 0xfff) & 0x1000); #else if (sizeof(drm_sarea_t)+sizeof(drm_via_sarea_t) > SAREA_MAX) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Data does not fit in SAREA\n"); return GL_FALSE; } ctx->shared.SAREASize = SAREA_MAX; #endif ctx->drmFD = drmOpen(VIAKernelDriverName, NULL); if (ctx->drmFD < 0) { fprintf(stderr, "[drm] drmOpen failed\n"); return 0; } pVia->drmFD = ctx->drmFD; err = drmSetBusid(ctx->drmFD, ctx->pciBusID); if (err < 0) { fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n", ctx->drmFD, ctx->pciBusID, strerror(-err)); return 0; } err = drmAddMap(ctx->drmFD, 0, ctx->shared.SAREASize, DRM_SHM, DRM_CONTAINS_LOCK, &ctx->shared.hSAREA); if (err < 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, #ifndef _EMBEDDED 0, #else DRM_READ_ONLY, #endif &ctx->shared.hFrameBuffer) < 0) { fprintf(stderr, "[drm] drmAddMap framebuffer failed\n"); return 0; } fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n", ctx->shared.hFrameBuffer); pVIADRI = (VIADRIPtr) CALLOC(sizeof(VIADRIRec)); if (!pVIADRI) { drmClose(ctx->drmFD); return GL_FALSE; } pVia->devPrivate = pVIADRI; ctx->driverClientMsg = pVIADRI; ctx->driverClientMsgSize = sizeof(*pVIADRI); /* DRIScreenInit doesn't add all the common mappings. Add additional mappings here. */ if (!VIADRIMapInit(ctx, pVia)) { VIADRICloseScreen(ctx); return GL_FALSE; } pVIADRI->regs.size = VIA_MMIO_REGSIZE; pVIADRI->regs.handle = pVia->registerHandle; xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] mmio Registers = 0x%08lx\n", pVIADRI->regs.handle); if (drmMap(pVia->drmFD, pVIADRI->regs.handle, pVIADRI->regs.size, (drmAddress *)&pVia->MapBase) != 0) { VIADRICloseScreen(ctx); return GL_FALSE; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] mmio mapped.\n" ); VIAEnableMMIO(ctx); /* Get video memory clock. */ VGAOUT8(0x3D4, 0x3D); pVia->MemClk = (VGAIN8(0x3D5) & 0xF0) >> 4; xf86DrvMsg(0, X_INFO, "[dri] MemClk (0x%x)\n", pVia->MemClk); /* 3D rendering has noise if not enabled. */ VIAEnableExtendedFIFO(ctx); VIAInitialize2DEngine(ctx); /* Must disable MMIO or 3D won't work. */ VIADisableMMIO(ctx); VIAInitialize3DEngine(ctx); pVia->IsPCI = !VIADRIAgpInit(ctx, pVia); if (pVia->IsPCI) { VIADRIPciInit(ctx, pVia); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] use pci.\n" ); } else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] use agp.\n" ); if (!(VIADRIFBInit(ctx, pVia))) { VIADRICloseScreen(ctx); xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[dri] frame buffer initialize fail .\n" ); return GL_FALSE; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] frame buffer initialized.\n" ); return VIADRIFinishScreenInit(ctx); } static void VIADRICloseScreen(DRIDriverContext * ctx) { VIAPtr pVia = VIAPTR(ctx); VIADRIPtr pVIADRI=(VIADRIPtr)pVia->devPrivate; VIADRIRingBufferCleanup(ctx); if (pVia->MapBase) { xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Unmapping MMIO registers\n"); drmUnmap(pVia->MapBase, pVIADRI->regs.size); } if (pVia->agpSize) { xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Freeing agp memory\n"); drmAgpFree(pVia->drmFD, pVia->agpHandle); xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Releasing agp module\n"); drmAgpRelease(pVia->drmFD); } #if 0 if (pVia->DRIIrqEnable) #endif VIADRIIrqExit(ctx); } static int VIADRIFinishScreenInit(DRIDriverContext * ctx) { VIAPtr pVia = VIAPTR(ctx); VIADRIPtr pVIADRI; int err; err = drmCreateContext(ctx->drmFD, &ctx->serverContext); if (err != 0) { fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err); return GL_FALSE; } DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0); if (!VIADRIKernelInit(ctx, pVia)) { VIADRICloseScreen(ctx); return GL_FALSE; } xf86DrvMsg(pScreen->myNum, X_INFO, "[dri] kernel data initialized.\n"); /* set SAREA value */ { drm_via_sarea_t *saPriv; saPriv=(drm_via_sarea_t*)(((char*)ctx->pSAREA) + sizeof(drm_sarea_t)); assert(saPriv); memset(saPriv, 0, sizeof(*saPriv)); saPriv->ctxOwner = -1; } pVIADRI=(VIADRIPtr)pVia->devPrivate; pVIADRI->deviceID=pVia->Chipset; pVIADRI->width=ctx->shared.virtualWidth; pVIADRI->height=ctx->shared.virtualHeight; pVIADRI->mem=ctx->shared.fbSize; pVIADRI->bytesPerPixel= (ctx->bpp+7) / 8; pVIADRI->sarea_priv_offset = sizeof(drm_sarea_t); /* TODO */ pVIADRI->scrnX=pVIADRI->width; pVIADRI->scrnY=pVIADRI->height; /* Initialize IRQ */ #if 0 if (pVia->DRIIrqEnable) #endif VIADRIIrqInit(ctx); pVIADRI->ringBufActive = 0; VIADRIRingBufferInit(ctx); return GL_TRUE; } /* Initialize the kernel data structures. */ static int VIADRIKernelInit(DRIDriverContext * ctx, VIAPtr pVia) { drm_via_init_t drmInfo; memset(&drmInfo, 0, sizeof(drm_via_init_t)); drmInfo.sarea_priv_offset = sizeof(drm_sarea_t); drmInfo.func = VIA_INIT_MAP; drmInfo.fb_offset = pVia->FrameBufferBase; drmInfo.mmio_offset = pVia->registerHandle; if (pVia->IsPCI) drmInfo.agpAddr = (uint32_t)NULL; else drmInfo.agpAddr = (uint32_t)pVia->agpAddr; if ((drmCommandWrite(pVia->drmFD, DRM_VIA_MAP_INIT,&drmInfo, sizeof(drm_via_init_t))) < 0) return GL_FALSE; return GL_TRUE; } /* Add a map for the MMIO registers */ static int VIADRIMapInit(DRIDriverContext * ctx, VIAPtr pVia) { int flags = 0; if (drmAddMap(pVia->drmFD, pVia->MmioBase, VIA_MMIO_REGSIZE, DRM_REGISTERS, flags, &pVia->registerHandle) < 0) { return GL_FALSE; } xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] register handle = 0x%08lx\n", pVia->registerHandle); return GL_TRUE; } static int viaValidateMode(const DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); return 1; } static int viaPostValidateMode(const DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); return 1; } static void VIAEnableMMIO(DRIDriverContext * ctx) { /*vgaHWPtr hwp = VGAHWPTR(ctx);*/ VIAPtr pVia = VIAPTR(ctx); unsigned char val; #if 0 if (xf86IsPrimaryPci(pVia->PciInfo)) { /* If we are primary card, we still use std vga port. If we use * MMIO, system will hang in vgaHWSave when our card used in * PLE and KLE (integrated Trident MVP4) */ vgaHWSetStdFuncs(hwp); } else { vgaHWSetMmioFuncs(hwp, pVia->MapBase, 0x8000); } #endif val = VGAIN8(0x3c3); VGAOUT8(0x3c3, val | 0x01); val = VGAIN8(0x3cc); VGAOUT8(0x3c2, val | 0x01); /* Unlock Extended IO Space */ VGAOUT8(0x3c4, 0x10); VGAOUT8(0x3c5, 0x01); /* Enable MMIO */ if(!pVia->IsSecondary) { VGAOUT8(0x3c4, 0x1a); val = VGAIN8(0x3c5); #ifdef DEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "primary val = %x\n", val); #endif VGAOUT8(0x3c5, val | 0x68); } else { VGAOUT8(0x3c4, 0x1a); val = VGAIN8(0x3c5); #ifdef DEBUG xf86DrvMsg(pScrn->scrnIndex, X_INFO, "secondary val = %x\n", val); #endif VGAOUT8(0x3c5, val | 0x38); } /* Unlock CRTC registers */ VGAOUT8(0x3d4, 0x47); VGAOUT8(0x3d5, 0x00); return; } static void VIADisableMMIO(DRIDriverContext * ctx) { VIAPtr pVia = VIAPTR(ctx); unsigned char val; VGAOUT8(0x3c4, 0x1a); val = VGAIN8(0x3c5); VGAOUT8(0x3c5, val & 0x97); return; } static void VIADisableExtendedFIFO(DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); uint32_t dwGE230, dwGE298; /* Cause of exit XWindow will dump back register value, others chipset no * need to set extended fifo value */ if (pVia->Chipset == VIA_CLE266 && pVia->ChipRev < 15 && (ctx->shared.virtualWidth > 1024 || pVia->HasSecondary)) { /* Turn off Extend FIFO */ /* 0x298[29] */ dwGE298 = VIAGETREG(0x298); VIASETREG(0x298, dwGE298 | 0x20000000); /* 0x230[21] */ dwGE230 = VIAGETREG(0x230); VIASETREG(0x230, dwGE230 & ~0x00200000); /* 0x298[29] */ dwGE298 = VIAGETREG(0x298); VIASETREG(0x298, dwGE298 & ~0x20000000); } } static void VIAEnableExtendedFIFO(DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); uint8_t bRegTemp; uint32_t dwGE230, dwGE298; switch (pVia->Chipset) { case VIA_CLE266: if (pVia->ChipRev > 14) { /* For 3123Cx */ if (pVia->HasSecondary) { /* SAMM or DuoView case */ if (ctx->shared.virtualWidth >= 1024) { /* 3c5.16[0:5] */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp |= 0x1C; VGAOUT8(0x3C5, bRegTemp); /* 3c5.17[0:6] */ VGAOUT8(0x3C4, 0x17); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x7F; bRegTemp |= 0x3F; VGAOUT8(0x3C5, bRegTemp); pVia->EnableExtendedFIFO = GL_TRUE; } } else /* Single view or Simultaneoue case */ { if (ctx->shared.virtualWidth > 1024) { /* 3c5.16[0:5] */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp |= 0x17; VGAOUT8(0x3C5, bRegTemp); /* 3c5.17[0:6] */ VGAOUT8(0x3C4, 0x17); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x7F; bRegTemp |= 0x2F; VGAOUT8(0x3C5, bRegTemp); pVia->EnableExtendedFIFO = GL_TRUE; } } /* 3c5.18[0:5] */ VGAOUT8(0x3C4, 0x18); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp |= 0x17; bRegTemp |= 0x40; /* force the preq always higher than treq */ VGAOUT8(0x3C5, bRegTemp); } else { /* for 3123Ax */ if (ctx->shared.virtualWidth > 1024 || pVia->HasSecondary) { /* Turn on Extend FIFO */ /* 0x298[29] */ dwGE298 = VIAGETREG(0x298); VIASETREG(0x298, dwGE298 | 0x20000000); /* 0x230[21] */ dwGE230 = VIAGETREG(0x230); VIASETREG(0x230, dwGE230 | 0x00200000); /* 0x298[29] */ dwGE298 = VIAGETREG(0x298); VIASETREG(0x298, dwGE298 & ~0x20000000); /* 3c5.16[0:5] */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp |= 0x17; /* bRegTemp |= 0x10; */ VGAOUT8(0x3C5, bRegTemp); /* 3c5.17[0:6] */ VGAOUT8(0x3C4, 0x17); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x7F; bRegTemp |= 0x2F; /*bRegTemp |= 0x1F;*/ VGAOUT8(0x3C5, bRegTemp); /* 3c5.18[0:5] */ VGAOUT8(0x3C4, 0x18); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp |= 0x17; bRegTemp |= 0x40; /* force the preq always higher than treq */ VGAOUT8(0x3C5, bRegTemp); pVia->EnableExtendedFIFO = GL_TRUE; } } break; case VIA_KM400: if (pVia->HasSecondary) { /* SAMM or DuoView case */ if ((ctx->shared.virtualWidth >= 1600) && (pVia->MemClk <= VIA_MEM_DDR200)) { /* enable CRT extendded FIFO */ VGAOUT8(0x3C4, 0x17); VGAOUT8(0x3C5, 0x1C); /* revise second display queue depth and read threshold */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp = (bRegTemp) | (0x09); VGAOUT8(0x3C5, bRegTemp); } else { /* enable CRT extendded FIFO */ VGAOUT8(0x3C4, 0x17); VGAOUT8(0x3C5,0x3F); /* revise second display queue depth and read threshold */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp = (bRegTemp) | (0x1C); VGAOUT8(0x3C5, bRegTemp); } /* 3c5.18[0:5] */ VGAOUT8(0x3C4, 0x18); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp |= 0x17; bRegTemp |= 0x40; /* force the preq always higher than treq */ VGAOUT8(0x3C5, bRegTemp); pVia->EnableExtendedFIFO = GL_TRUE; } else { if ( (ctx->shared.virtualWidth > 1024) && (ctx->shared.virtualWidth <= 1280) ) { /* enable CRT extendded FIFO */ VGAOUT8(0x3C4, 0x17); VGAOUT8(0x3C5, 0x3F); /* revise second display queue depth and read threshold */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp = (bRegTemp) | (0x17); VGAOUT8(0x3C5, bRegTemp); pVia->EnableExtendedFIFO = GL_TRUE; } else if ((ctx->shared.virtualWidth > 1280)) { /* enable CRT extendded FIFO */ VGAOUT8(0x3C4, 0x17); VGAOUT8(0x3C5, 0x3F); /* revise second display queue depth and read threshold */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp = (bRegTemp) | (0x1C); VGAOUT8(0x3C5, bRegTemp); pVia->EnableExtendedFIFO = GL_TRUE; } else { /* enable CRT extendded FIFO */ VGAOUT8(0x3C4, 0x17); VGAOUT8(0x3C5, 0x3F); /* revise second display queue depth and read threshold */ VGAOUT8(0x3C4, 0x16); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp = (bRegTemp) | (0x10); VGAOUT8(0x3C5, bRegTemp); } /* 3c5.18[0:5] */ VGAOUT8(0x3C4, 0x18); bRegTemp = VGAIN8(0x3C5); bRegTemp &= ~0x3F; bRegTemp |= 0x17; bRegTemp |= 0x40; /* force the preq always higher than treq */ VGAOUT8(0x3C5, bRegTemp); } break; case VIA_K8M800: /*=* R1 Display FIFO depth (384 /8 -1 -> 0xbf) SR17[7:0] (8bits) *=*/ VGAOUT8(0x3c4, 0x17); VGAOUT8(0x3c5, 0xbf); /*=* R2 Display fetch datum threshold value (328/4 -> 0x52) SR16[5:0], SR16[7] (7bits) *=*/ VGAOUT8(0x3c4, 0x16); bRegTemp = VGAIN8(0x3c5) & ~0xBF; bRegTemp |= (0x52 & 0x3F); bRegTemp |= ((0x52 & 0x40) << 1); VGAOUT8(0x3c5, bRegTemp); /*=* R3 Switch to the highest agent threshold value (74 -> 0x4a) SR18[5:0], SR18[7] (7bits) *=*/ VGAOUT8(0x3c4, 0x18); bRegTemp = VGAIN8(0x3c5) & ~0xBF; bRegTemp |= (0x4a & 0x3F); bRegTemp |= ((0x4a & 0x40) << 1); VGAOUT8(0x3c5, bRegTemp); #if 0 /*=* R4 Fetch Number for a scan line (unit: 8 bytes) SR1C[7:0], SR1D[1:0] (10bits) *=*/ wRegTemp = (pBIOSInfo->offsetWidthByQWord >> 1) + 4; VGAOUT8(0x3c4, 0x1c); VGAOUT8(0x3c5, (uint8_t)(wRegTemp & 0xFF)); VGAOUT8(0x3c4, 0x1d); bRegTemp = VGAIN8(0x3c5) & ~0x03; VGAOUT8(0x3c5, bRegTemp | ((wRegTemp & 0x300) >> 8)); #endif if (ctx->shared.virtualWidth >= 1400 && ctx->bpp == 32) { /*=* Max. length for a request SR22[4:0] (64/4 -> 0x10) *=*/ VGAOUT8(0x3c4, 0x22); bRegTemp = VGAIN8(0x3c5) & ~0x1F; VGAOUT8(0x3c5, bRegTemp | 0x10); } else { /*=* Max. length for a request SR22[4:0] (128/4 -> over flow 0x0) *=*/ VGAOUT8(0x3c4, 0x22); bRegTemp = VGAIN8(0x3c5) & ~0x1F; VGAOUT8(0x3c5, bRegTemp); } break; case VIA_PM800: /*=* R1 Display FIFO depth (96-1 -> 0x5f) SR17[7:0] (8bits) *=*/ VGAOUT8(0x3c4, 0x17); VGAOUT8(0x3c5, 0x5f); /*=* R2 Display fetch datum threshold value (32 -> 0x20) SR16[5:0], SR16[7] (7bits) *=*/ VGAOUT8(0x3c4, 0x16); bRegTemp = VGAIN8(0x3c5) & ~0xBF; bRegTemp |= (0x20 & 0x3F); bRegTemp |= ((0x20 & 0x40) << 1); VGAOUT8(0x3c5, bRegTemp); /*=* R3 Switch to the highest agent threshold value (16 -> 0x10) SR18[5:0], SR18[7] (7bits) *=*/ VGAOUT8(0x3c4, 0x18); bRegTemp = VGAIN8(0x3c5) & ~0xBF; bRegTemp |= (0x10 & 0x3F); bRegTemp |= ((0x10 & 0x40) << 1); VGAOUT8(0x3c5, bRegTemp); #if 0 /*=* R4 Fetch Number for a scan line (unit: 8 bytes) SR1C[7:0], SR1D[1:0] (10bits) *=*/ wRegTemp = (pBIOSInfo->offsetWidthByQWord >> 1) + 4; VGAOUT8(0x3c4, 0x1c); VGAOUT8(0x3c5, (uint8_t)(wRegTemp & 0xFF)); VGAOUT8(0x3c4, 0x1d); bRegTemp = VGAIN8(0x3c5) & ~0x03; VGAOUT8(0x3c5, bRegTemp | ((wRegTemp & 0x300) >> 8)); #endif if (ctx->shared.virtualWidth >= 1400 && ctx->bpp == 32) { /*=* Max. length for a request SR22[4:0] (64/4 -> 0x10) *=*/ VGAOUT8(0x3c4, 0x22); bRegTemp = VGAIN8(0x3c5) & ~0x1F; VGAOUT8(0x3c5, bRegTemp | 0x10); } else { /*=* Max. length for a request SR22[4:0] (0x1F) *=*/ VGAOUT8(0x3c4, 0x22); bRegTemp = VGAIN8(0x3c5) & ~0x1F; VGAOUT8(0x3c5, bRegTemp | 0x1F); } break; default: break; } } static void VIAInitialize2DEngine(DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); uint32_t dwVQStartAddr, dwVQEndAddr; uint32_t dwVQLen, dwVQStartL, dwVQEndL, dwVQStartEndH; uint32_t dwGEMode; /* init 2D engine regs to reset 2D engine */ VIASETREG(0x04, 0x0); VIASETREG(0x08, 0x0); VIASETREG(0x0c, 0x0); VIASETREG(0x10, 0x0); VIASETREG(0x14, 0x0); VIASETREG(0x18, 0x0); VIASETREG(0x1c, 0x0); VIASETREG(0x20, 0x0); VIASETREG(0x24, 0x0); VIASETREG(0x28, 0x0); VIASETREG(0x2c, 0x0); VIASETREG(0x30, 0x0); VIASETREG(0x34, 0x0); VIASETREG(0x38, 0x0); VIASETREG(0x3c, 0x0); VIASETREG(0x40, 0x0); VIADisableMMIO(ctx); /* Init AGP and VQ regs */ VIASETREG(0x43c, 0x00100000); VIASETREG(0x440, 0x00000000); VIASETREG(0x440, 0x00333004); VIASETREG(0x440, 0x60000000); VIASETREG(0x440, 0x61000000); VIASETREG(0x440, 0x62000000); VIASETREG(0x440, 0x63000000); VIASETREG(0x440, 0x64000000); VIASETREG(0x440, 0x7D000000); VIASETREG(0x43c, 0xfe020000); VIASETREG(0x440, 0x00000000); if (pVia->VQStart != 0) { /* Enable VQ */ dwVQStartAddr = pVia->VQStart; dwVQEndAddr = pVia->VQEnd; dwVQStartL = 0x50000000 | (dwVQStartAddr & 0xFFFFFF); dwVQEndL = 0x51000000 | (dwVQEndAddr & 0xFFFFFF); dwVQStartEndH = 0x52000000 | ((dwVQStartAddr & 0xFF000000) >> 24) | ((dwVQEndAddr & 0xFF000000) >> 16); dwVQLen = 0x53000000 | (VIA_VQ_SIZE >> 3); VIASETREG(0x43c, 0x00fe0000); VIASETREG(0x440, 0x080003fe); VIASETREG(0x440, 0x0a00027c); VIASETREG(0x440, 0x0b000260); VIASETREG(0x440, 0x0c000274); VIASETREG(0x440, 0x0d000264); VIASETREG(0x440, 0x0e000000); VIASETREG(0x440, 0x0f000020); VIASETREG(0x440, 0x1000027e); VIASETREG(0x440, 0x110002fe); VIASETREG(0x440, 0x200f0060); VIASETREG(0x440, 0x00000006); VIASETREG(0x440, 0x40008c0f); VIASETREG(0x440, 0x44000000); VIASETREG(0x440, 0x45080c04); VIASETREG(0x440, 0x46800408); VIASETREG(0x440, dwVQStartEndH); VIASETREG(0x440, dwVQStartL); VIASETREG(0x440, dwVQEndL); VIASETREG(0x440, dwVQLen); } else { /* Diable VQ */ VIASETREG(0x43c, 0x00fe0000); VIASETREG(0x440, 0x00000004); VIASETREG(0x440, 0x40008c0f); VIASETREG(0x440, 0x44000000); VIASETREG(0x440, 0x45080c04); VIASETREG(0x440, 0x46800408); } dwGEMode = 0; switch (ctx->bpp) { case 16: dwGEMode |= VIA_GEM_16bpp; break; case 32: dwGEMode |= VIA_GEM_32bpp; break; default: dwGEMode |= VIA_GEM_8bpp; break; } #if 0 switch (ctx->shared.virtualWidth) { case 800: dwGEMode |= VIA_GEM_800; break; case 1024: dwGEMode |= VIA_GEM_1024; break; case 1280: dwGEMode |= VIA_GEM_1280; break; case 1600: dwGEMode |= VIA_GEM_1600; break; case 2048: dwGEMode |= VIA_GEM_2048; break; default: dwGEMode |= VIA_GEM_640; break; } #endif VIAEnableMMIO(ctx); /* Set BPP and Pitch */ VIASETREG(VIA_REG_GEMODE, dwGEMode); /* Set Src and Dst base address and pitch, pitch is qword */ VIASETREG(VIA_REG_SRCBASE, 0x0); VIASETREG(VIA_REG_DSTBASE, 0x0); VIASETREG(VIA_REG_PITCH, VIA_PITCH_ENABLE | ((ctx->shared.virtualWidth * ctx->bpp >> 3) >> 3) | (((ctx->shared.virtualWidth * ctx->bpp >> 3) >> 3) << 16)); } static int b3DRegsInitialized = 0; static void VIAInitialize3DEngine(DRIDriverContext *ctx) { VIAPtr pVia = VIAPTR(ctx); int i; if (!b3DRegsInitialized) { VIASETREG(0x43C, 0x00010000); for (i = 0; i <= 0x7D; i++) { VIASETREG(0x440, (uint32_t) i << 24); } VIASETREG(0x43C, 0x00020000); for (i = 0; i <= 0x94; i++) { VIASETREG(0x440, (uint32_t) i << 24); } VIASETREG(0x440, 0x82400000); VIASETREG(0x43C, 0x01020000); for (i = 0; i <= 0x94; i++) { VIASETREG(0x440, (uint32_t) i << 24); } VIASETREG(0x440, 0x82400000); VIASETREG(0x43C, 0xfe020000); for (i = 0; i <= 0x03; i++) { VIASETREG(0x440, (uint32_t) i << 24); } VIASETREG(0x43C, 0x00030000); for (i = 0; i <= 0xff; i++) { VIASETREG(0x440, 0); } VIASETREG(0x43C, 0x00100000); VIASETREG(0x440, 0x00333004); VIASETREG(0x440, 0x10000002); VIASETREG(0x440, 0x60000000); VIASETREG(0x440, 0x61000000); VIASETREG(0x440, 0x62000000); VIASETREG(0x440, 0x63000000); VIASETREG(0x440, 0x64000000); VIASETREG(0x43C, 0x00fe0000); if (pVia->ChipRev >= 3 ) VIASETREG(0x440,0x40008c0f); else VIASETREG(0x440,0x4000800f); VIASETREG(0x440,0x44000000); VIASETREG(0x440,0x45080C04); VIASETREG(0x440,0x46800408); VIASETREG(0x440,0x50000000); VIASETREG(0x440,0x51000000); VIASETREG(0x440,0x52000000); VIASETREG(0x440,0x53000000); b3DRegsInitialized = 1; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Engine has been initialized.\n"); } VIASETREG(0x43C,0x00fe0000); VIASETREG(0x440,0x08000001); VIASETREG(0x440,0x0A000183); VIASETREG(0x440,0x0B00019F); VIASETREG(0x440,0x0C00018B); VIASETREG(0x440,0x0D00019B); VIASETREG(0x440,0x0E000000); VIASETREG(0x440,0x0F000000); VIASETREG(0x440,0x10000000); VIASETREG(0x440,0x11000000); VIASETREG(0x440,0x20000000); } static int WaitIdleCLE266(VIAPtr pVia) { int loop = 0; /*mem_barrier();*/ while (!(VIAGETREG(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP)) ; while ((VIAGETREG(VIA_REG_STATUS) & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) && (loop++ < MAXLOOP)) ; return loop >= MAXLOOP; } static int viaInitFBDev(DRIDriverContext *ctx) { VIAPtr pVia = CALLOC(sizeof(*pVia)); ctx->driverPrivate = (void *)pVia; switch (ctx->chipset) { case PCI_CHIP_CLE3122: case PCI_CHIP_CLE3022: pVia->Chipset = VIA_CLE266; break; case PCI_CHIP_VT7205: case PCI_CHIP_VT3205: pVia->Chipset = VIA_KM400; break; case PCI_CHIP_VT3204: case PCI_CHIP_VT3344: pVia->Chipset = VIA_K8M800; break; case PCI_CHIP_VT3259: pVia->Chipset = VIA_PM800; break; default: xf86DrvMsg(0, X_ERROR, "VIA: Unknown device ID (0x%x)\n", ctx->chipset); } /* _SOLO TODO XXX need to read ChipRev too */ pVia->ChipRev = 0; pVia->videoRambytes = ctx->shared.fbSize; pVia->MmioBase = ctx->MMIOStart; pVia->FrameBufferBase = ctx->FBStart & 0xfc000000; pVia->FBFreeStart = ctx->shared.virtualWidth * ctx->cpp * ctx->shared.virtualHeight; #if 1 /* Alloc a second framebuffer for the second head */ pVia->FBFreeStart += ctx->shared.virtualWidth * ctx->cpp * ctx->shared.virtualHeight; #endif pVia->VQStart = pVia->FBFreeStart; pVia->VQEnd = pVia->FBFreeStart + VIA_VQ_SIZE - 1; pVia->FBFreeStart += VIA_VQ_SIZE; pVia->FBFreeEnd = pVia->videoRambytes; if (!VIADRIScreenInit(ctx)) return 0; return 1; } static void viaHaltFBDev(DRIDriverContext *ctx) { drmUnmap( ctx->pSAREA, ctx->shared.SAREASize ); drmClose(ctx->drmFD); if (ctx->driverPrivate) { free(ctx->driverPrivate); ctx->driverPrivate = 0; } } static int viaEngineShutdown(const DRIDriverContext *ctx) { return 1; } static int viaEngineRestore(const DRIDriverContext *ctx) { return 1; } const struct DRIDriverRec __driDriver = { viaValidateMode, viaPostValidateMode, viaInitFBDev, viaHaltFBDev, viaEngineShutdown, viaEngineRestore, 0, };