diff options
author | alan <alan> | 2004-06-24 16:34:25 +0000 |
---|---|---|
committer | alan <alan> | 2004-06-24 16:34:25 +0000 |
commit | 65f9bc5c20ca203f4789421399f1f06b3c628816 (patch) | |
tree | d3922688310c04dcfffc92bb26d579e1cb125108 |
Check in the voodoo driver subtree
-rw-r--r-- | README | 56 | ||||
-rw-r--r-- | TODO | 35 | ||||
-rw-r--r-- | man/voodoo.man | 72 | ||||
-rw-r--r-- | src/voodoo.h | 109 | ||||
-rw-r--r-- | src/voodoo_dga.c | 184 | ||||
-rw-r--r-- | src/voodoo_driver.c | 969 | ||||
-rw-r--r-- | src/voodoo_hardware.c | 1432 |
7 files changed, 2857 insertions, 0 deletions
@@ -0,0 +1,56 @@ +Quick Voodoo/Voodoo2 Crash Course (mostly Alan's notes to save looking +stuff up in the docs all the time) + +Voodoo and Voodoo 2 appear as multimedia devices. They may be on a "dual +function" board in which case we should not 'borrow' the Voodoo as we will +blank the main video card. That is reported in the PCI config space. +Voodoo/Voodoo2 hardware may not always be initialized by the host OS because +it is not video. + +The voodoo memory is split into two pools. A 1-4Mb pool holds the frame +buffer, an optional second buffer, zbuffers, and alpha. A second 2-8Mb +memory area holds all the textures. + +Texture ram is directly writable but not important for the current 2D +driver. Video RAM is 16bit depth and tiled. The view of the video memory +area is "magic", it doesn't contain a mapping of the video RAM into PCI +space but contains pixel poking functionality. + +The frame buffer always appears untiled and 1024 pixels wide. For write +there are some 16 different write modes including 24/32bit. The hardware +does not support 24/32bit - these are provided for software rendering +fallback. Read back is always 16bit. Endian conversion is hardware. Byte +aligned access is not supported, only word aligned. Also watch how you +access data - you can't access out of frame buffer space and if you get +the control bits wrong you also get zbuffered, fogged and other fun. +LFB writes have depth and alpha if you want. + +The real hardware is RGB565, how it sets stuff up internally is out of +our hands - which means X memory alloc/pixmap cache is a little +constrained. + +[IDEA: Should we put the mouse and framebuffer at different Z values so + that we don't have to erase it to draw under it - less flicker] + +Acceleration: + +All Voodoo + Fast Fill - Solid 2D rectangle fill + (Also depth buffer clear for 3D) + Supports a constant alpha option + Requires a running 3D engine + +Voodoo2 and later + Screen to screen blit + CPU to screen blit + Ultra fast fill to some alignments + Monochrome to colour expansion (cpu to screen only) + (and they finally made the 2D and 3D state independant + if someone ever gets drunk enough to do DRI...) + Colour conversion on blit + Dither + Chroma testing (src/dst) and selection of op by colour + raster ops are the usual 16 suspects + +Other bits supported + CLUT Gamma correction @@ -0,0 +1,35 @@ +DONE + +Basic video setup +ShadowFB buffering +DGA +Voodoo2 2D accelerations +Render acceleration +Debugged 24bpp shadowFB + +TODO + +Rotation +FIFO level handling code maybe needed for heavy 2D +Hardware Gamma correction +Proper DPMS for Voodoo2 +DRI + +DRI thoughts: +Figure out out to use YAB textures for Xv +X runs on the front buffer +DRI draws on the backbuffer +2D engine can do the screen to screen blits +Backbuffer allocation is problematic as memory is short. One way + might be to allocate those rectangles that are visible only ? +For voodoo1 DRI is somewhat harder but Voodoo2like with software fallback + except fullscreen would work 8) + + +Random Ramblings: +The right way to write a Voodoo1 X server is to use shadow buffers for +each visible window area and dump them into texture buffers then composite +the textures using the 3D engine. XFree86 alas doesn't think that way. +Maybe Keith's server can be persuaded to do so some day. Maybe I should +just buy a better video card. + diff --git a/man/voodoo.man b/man/voodoo.man new file mode 100644 index 0000000..1c974ce --- /dev/null +++ b/man/voodoo.man @@ -0,0 +1,72 @@ +.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/voodoo/voodoo.man,v 1.0 2004/02/11 23:10:13 alan Exp $ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH VOODOO __drivermansuffix__ __vendorversion__ +.SH NAME +voodoo \- Voodoo video driver +.SH SYNOPSIS +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qvoodoo\*q" +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B voodoo +is an XFree86 driver for Voodoo 1 and Voodoo 2 series video adapters. +On the Voodoo 1 the driver uses a shadow buffer in system memory as +the video adapter has only 3D acceleration. Selected portions of the shadow +framebuffer are copied out to the Voodoo board at the right time. Because +of this, the speed of the driver is very dependent on the CPU. Processors +nowdays are actually rather fast at moving data so we get very good speed +anyway as the shadow framebuffer is in cached RAM. +.PP +The Voodoo2 has 16bpp acceleration and the driver provides accelerated +versions of most operations except angled lines and stipples. Accelerated +alpha blending with the Render extension is also supported as is DGA. +.PP +This driver supports 16bpp modes currently. The video hardware supports +image conversion from 24bpp to 16bpp but the hardware is 16bpp only. +.PP +The Voodoo 1 series cards can go up to 800x600 resolution while the +Voodoo 2 can reach 1024x768 providing it has at least 2Mb of frame +buffer memory. 1024x768 2D mode does not require two cards configured in +scan-line interleave mode (SLI). +.PP +Multihead and Xinerama configurations are supported. SLI configurations will +be treated as multiple video cards. +.PP +Limited support for DPMS screen saving is available. The "standby" and +"suspend" modes are just painting the screen black. The "off" mode turns +the Voodoo board off and thus works correctly. +.PP +This driver does not support a virtual screen size different from the +display size. This is a hardware limitation. 3D rendering is also not +supported. +.SH CONFIGURATION DETAILS +Please refer to XF86Config(__filemansuffix__) for general configuration +details. This section only covers configuration details specific to this +driver. +.PP +The following driver +.B Options +are supported: +.TP +.BI "Option \*qShadowFB\*q \*q" boolean \*q +Enables a shadow buffer in main memory. This turns off acceleration but for +otherwise unaccelerated operations can improve performance materially. +Default: off for voodoo2, on for voodoo1. +.TP +.BI "Option \*qNoAccel\*q \*q" boolean \*q +Disables acceleration if set. Unless debugging this option should only +be set if ShadowFB is enabled. +Default: off for voodoo2, on for voodoo1. +.SH "BUGS" +The driver interacts badly with the +sstfb frame buffer driver as there is insufficient information to restore +the chip to its previous state. +.SH "SEE ALSO" +XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__) +.SH AUTHORS +Authors: Alan Cox, Ghozlane Toumi, Henrik Harmsen. diff --git a/src/voodoo.h b/src/voodoo.h new file mode 100644 index 0000000..3a99aca --- /dev/null +++ b/src/voodoo.h @@ -0,0 +1,109 @@ +typedef struct { + CARD32 m; + CARD32 n; + CARD32 p; +} PLLClock; + +typedef struct { + CARD8 * ShadowPtr; /* Shadow buffer */ + CARD32 ShadowPitch; + CloseScreenProcPtr CloseScreen; /* Wrapped Close */ + XAAInfoRecPtr AccelInfoRec; /* Cached Accel rec for close */ + Bool Blanked; + Bool OnAtExit; + EntityInfoPtr pEnt; + OptionInfoPtr Options; + + Bool Voodoo2; /* Set if Voodoo2 */ + pciVideoPtr PciInfo; /* PCI data */ + PCITAG PciTag; + CARD32 PhysBase; + + CARD32 Width; /* Current width */ + CARD32 Height; /* Current height */ + CARD32 FullHeight; /* Height including pixmap cache */ + CARD32 Tiles; /* 32 tile count */ + + int BlitDirX; /* Cache blitter direction */ + int BlitDirY; /* Cache blitter direction */ + + CARD32 lfbMode; /* Cached lfbMode value */ + + CARD32 alpha; /* Cached alpha reg for sw blit */ + CARD32 alphaPitch; /* Software render blit state */ + int alphaType; + CARD8 *alphaPtr; + CARD32 alphaC; + CARD32 alphaW; + CARD32 alphaH; + + CARD32 texPitch; + int texType; + CARD8 *texPtr; + CARD32 texW; + CARD32 texH; + + int ShadowFB; /* Using shadow FB */ + int Accel; /* Using acceleration */ + + CARD8 * MMIO; /* MMIO base */ + CARD8 * FBBase; /* Virtual FB base */ + CARD32 Pitch; /* Pitch of FB */ + + DGAModePtr pDGAMode; /* DGA mode */ + int nDGAMode; + + int DAC; +#define DAC_ID_ATT 1 +#define DAC_ID_TI 2 +#define DAC_ID_ICS 3 +#define DAC_UNKNOWN 0 + CARD32 MaxClock; + + PLLClock vClock; + PLLClock gClock; + + unsigned char LineBuffer[1028]; /* Draw buffer */ + unsigned char *LinePtr; /* To keep XAA amused */ +} VoodooRec, *VoodooPtr; + +#define TRUE 1 +#define FALSE 0 + +/* Card-specific driver information */ + +#define VoodooPTR(p) ((VoodooPtr)((p)->driverPrivate)) + +#define VERSION 4000 +#define VOODOO_NAME "Voodoo" +#define VOODOO_DRIVER_NAME "voodoo" +#define VOODOO_MAJOR_VERSION 1 +#define VOODOO_MINOR_VERSION 0 +#define VOODOO_PATCHLEVEL 0 + +#define PCI_CHIP_VOODOO1 0x0001 +#define PCI_CHIP_VOODOO2 0x0002 + +/* + * Hardware functions + */ + +extern void VoodooClear(VoodooPtr pVoo); +extern void VoodooCopy16(VoodooPtr pVoo, CARD32 x1, CARD32 y1, CARD32 w, CARD32 h, CARD32 spitch, unsigned char *src); +extern void VoodooCopy24(VoodooPtr pVoo, CARD32 x1, CARD32 y1, CARD32 w, CARD32 h, CARD32 spitch, unsigned char *src); +extern int VoodooHardwareInit(VoodooPtr pVoo); +extern int VoodooMode(ScrnInfoPtr pScrn, DisplayModePtr mode); +extern void VoodooBlank(VoodooPtr pVoo); +extern int VoodooMemorySize(VoodooPtr pVoo); +extern void Voodoo2XAAInit(ScreenPtr pScreen); +extern void VoodooSync(ScrnInfoPtr pScrn); +extern void VoodooReadBank(ScreenPtr pScreen, int bank); +extern void VoodooWriteBank(ScreenPtr pScreen, int bank); +extern void VoodooReadBank(ScreenPtr pScreen, int bank); + +/* + * DGA + */ + +extern Bool VoodooDGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen); + diff --git a/src/voodoo_dga.c b/src/voodoo_dga.c new file mode 100644 index 0000000..668545a --- /dev/null +++ b/src/voodoo_dga.c @@ -0,0 +1,184 @@ +/* + * XFree86 driver for the Voodoo 2 using native X support and no + * Glide2. This is done for two reasons, firstly Glide2 is not portable + * to other than x86_32 which is becoming an issue, and secondly to get + * accelerations that Glide does not expose. The Voodoo 2 hardware has + * bit blit (screen->screen, cpu->screen), some colour expansion and + * also alpha (so could do hw render even!). Also can in theory use + * texture ram and engine to do arbitary Xv support as we have + * colour match on the 2D blit (ie 3D blit to back, 2D blit to front) + * along with alpha on the Xv 8) and with some care rotation of Xv. + * + * Alan Cox <alan@redhat.com> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of Red Hat, Alan Cox and Henrik Harmsen + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Th authors make no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL RICHARD HECKER BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * THIS SOFTWARE IS NOT DESIGNED FOR USE IN SAFETY CRITICAL SYSTEMS OF + * ANY KIND OR FORM. + */ + +#include "fb.h" +#include "mibank.h" +#include "micmap.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Version.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86cmap.h" +#include "shadowfb.h" +#include "vgaHW.h" +#include "xf86DDC.h" +#include "xf86RAC.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "xaa.h" +#include "dgaproc.h" + +#include "voodoo.h" + +#define _XF86DGA_SERVER_ +#include "extensions/xf86dgastr.h" + +#include "opaque.h" +#define DPMS_SERVER +#include "extensions/dpms.h" + + + /*********************************************************************** + * DGA stuff + ***********************************************************************/ +static Bool VoodooDGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName, + unsigned char **ApertureBase, + int *ApertureSize, int *ApertureOffset, + int *flags); +static Bool VoodooDGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode); + +static Bool VoodooDGAOpenFramebuffer(ScrnInfoPtr pScrn, char **DeviceName, + unsigned char **ApertureBase, int *ApertureSize, + int *ApertureOffset, int *flags) +{ + *DeviceName = NULL; /* No special device */ + *ApertureBase = (unsigned char *)(pScrn->memPhysBase); + *ApertureSize = pScrn->videoRam; + *ApertureOffset = pScrn->fbOffset; + *flags = 0; + + return TRUE; +} + +static Bool VoodooDGASetMode(ScrnInfoPtr pScrn, DGAModePtr pDGAMode) +{ + DisplayModePtr pMode; + int scrnIdx = pScrn->pScreen->myNum; + int frameX0, frameY0; + + if (pDGAMode) { + pMode = pDGAMode->mode; + frameX0 = frameY0 = 0; + } + else { + if (!(pMode = pScrn->currentMode)) + return TRUE; + + frameX0 = pScrn->frameX0; + frameY0 = pScrn->frameY0; + } + + if (!(*pScrn->SwitchMode)(scrnIdx, pMode, 0)) + return FALSE; + return TRUE; +} + +static int VoodooDGAGetViewport(ScrnInfoPtr pScrn) +{ + return (0); +} + +static DGAFunctionRec VoodooDGAFunctions = +{ + VoodooDGAOpenFramebuffer, + NULL, /* CloseFramebuffer */ + VoodooDGASetMode, + NULL, + VoodooDGAGetViewport, + /* TODO - can do Sync/blit/fill on Voodoo2 */ + NULL, /* Sync */ + NULL, /* FillRect */ + NULL, /* BlitRect */ + NULL, /* BlitTransRect */ +}; + +static void VoodooDGAAddModes(ScrnInfoPtr pScrn) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + DisplayModePtr pMode = pScrn->modes; + DGAModePtr pDGAMode; + + do { + pDGAMode = xrealloc(pVoo->pDGAMode, + (pVoo->nDGAMode + 1) * sizeof(DGAModeRec)); + if (!pDGAMode) + break; + + pVoo->pDGAMode = pDGAMode; + pDGAMode += pVoo->nDGAMode; + (void)memset(pDGAMode, 0, sizeof(DGAModeRec)); + + ++pVoo->nDGAMode; + pDGAMode->mode = pMode; + pDGAMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE; + pDGAMode->byteOrder = pScrn->imageByteOrder; + pDGAMode->depth = pScrn->depth; + pDGAMode->bitsPerPixel = pScrn->bitsPerPixel; + pDGAMode->red_mask = pScrn->mask.red; + pDGAMode->green_mask = pScrn->mask.green; + pDGAMode->blue_mask = pScrn->mask.blue; + pDGAMode->visualClass = TrueColor; + pDGAMode->xViewportStep = 1; + pDGAMode->yViewportStep = 1; + pDGAMode->viewportWidth = pMode->HDisplay; + pDGAMode->viewportHeight = pMode->VDisplay; + + pDGAMode->bytesPerScanline = 2048; + + pDGAMode->imageWidth = pMode->HDisplay; + pDGAMode->imageHeight = pMode->VDisplay; + pDGAMode->pixmapWidth = pDGAMode->imageWidth; + pDGAMode->pixmapHeight = pDGAMode->imageHeight; + pDGAMode->maxViewportX = pScrn->virtualX - + pDGAMode->viewportWidth; + pDGAMode->maxViewportY = pScrn->virtualY - + pDGAMode->viewportHeight; + + pDGAMode->address = pVoo->FBBase; + + pMode = pMode->next; + } while (pMode != pScrn->modes); +} + +Bool VoodooDGAInit(ScrnInfoPtr pScrn, ScreenPtr pScreen) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + if (!pVoo->nDGAMode) + VoodooDGAAddModes(pScrn); + return (DGAInit(pScreen, &VoodooDGAFunctions, + pVoo->pDGAMode, pVoo->nDGAMode)); +} diff --git a/src/voodoo_driver.c b/src/voodoo_driver.c new file mode 100644 index 0000000..a38435c --- /dev/null +++ b/src/voodoo_driver.c @@ -0,0 +1,969 @@ +/* + * XFree86 driver for the Voodoo 2 using native X support and no + * Glide2. This is done for two reasons, firstly Glide2 is not portable + * to other than x86_32 which is becoming an issue, and secondly to get + * accelerations that Glide does not expose. The Voodoo 2 hardware has + * bit blit (screen->screen, cpu->screen), some colour expansion and + * also alpha (so could do hw render even!). Also can in theory use + * texture ram and engine to do arbitary Xv support as we have + * colour match on the 2D blit (ie 3D blit to back, 2D blit to front) + * along with alpha on the Xv 8) and with some care rotation of Xv. + * + * Alan Cox <alan@redhat.com> + * + * Derived from: + * + * XFree86 driver for Glide(tm). (Mainly for Voodoo 1 and 2 cards) + * Author: + * Henrik Harmsen (hch@cd.chalmers.se or Henrik.Harmsen@erv.ericsson.se) + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of Red Hat, Alan Cox and Henrik Harmsen + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Th authors make no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL RICHARD HECKER BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * THIS SOFTWARE IS NOT DESIGNED FOR USE IN SAFETY CRITICAL SYSTEMS OF + * ANY KIND OR FORM. + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/voodoo/voodoo_driver.c,v 1.27 2001/08/07 07:04:46 keithp Exp $ */ + +#include "fb.h" +#include "mibank.h" +#include "micmap.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Version.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86cmap.h" +#include "shadowfb.h" +#include "vgaHW.h" +#include "xf86DDC.h" +#include "xf86RAC.h" +#include "xf86Resources.h" +#include "compiler.h" +#include "xaa.h" + +#include "voodoo.h" + +#define _XF86DGA_SERVER_ +#include "extensions/xf86dgastr.h" + +#include "opaque.h" +#define DPMS_SERVER +#include "extensions/dpms.h" + +static const OptionInfoRec * VoodooAvailableOptions(int chipid, int busid); +static void VoodooIdentify(int flags); +static Bool VoodooProbe(DriverPtr drv, int flags); +static Bool VoodooPreInit(ScrnInfoPtr pScrn, int flags); +static Bool VoodooScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); +static Bool VoodooEnterVT(int scrnIndex, int flags); +static void VoodooLeaveVT(int scrnIndex, int flags); +static Bool VoodooCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool VoodooSaveScreen(ScreenPtr pScreen, int mode); +static void VoodooFreeScreen(int scrnIndex, int flags); +static void VoodooRefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox); +static void VoodooRefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox); +static Bool VoodooSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); +static Bool VoodooModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); +static void VoodooRestore(ScrnInfoPtr pScrn, Bool Closing); + +static void VoodooDisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, + int flags); + +/* + * This contains the functions needed by the server after loading the + * driver module. It must be supplied, and gets added the driver list by + * the Module Setup funtion in the dynamic case. In the static case a + * reference to this is compiled in, and this requires that the name of + * this DriverRec be an upper-case version of the driver name. + */ + +DriverRec VOODOO = { + VERSION, + VOODOO_DRIVER_NAME, + VoodooIdentify, + VoodooProbe, + VoodooAvailableOptions, + NULL, + 0 +}; + +typedef enum { + OPTION_NOACCEL, + OPTION_SHADOW_FB +} VoodooOpts; + +static const OptionInfoRec VoodooOptions[] = { + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +/* Supported chipsets */ +static SymTabRec VoodooChipsets[] = { + { PCI_CHIP_VOODOO1, "Voodoo 1" }, + { PCI_CHIP_VOODOO2, "Voodoo 2" }, + {-1, NULL } +}; + + +/* + * List of symbols from other modules that this module references. This + * list is used to tell the loader that it is OK for symbols here to be + * unresolved providing that it hasn't been told that they haven't been + * told that they are essential via a call to xf86LoaderReqSymbols() or + * xf86LoaderReqSymLists(). The purpose is this is to avoid warnings about + * unresolved symbols that are not required. + */ + +static const char *fbSymbols[] = { + "fbScreenInit", + "fbPictureInit", + NULL +}; + +static const char *xaaSymbols[] = { + "XAACreateInfoRec", + "XAAInit", + "XAADestroyInfoRec", + NULL +}; + +static const char *shadowSymbols[] = { + "ShadowFBInit", + NULL +}; + +#ifdef XFree86LOADER + +static XF86ModuleVersionInfo voodooVersRec = +{ + "voodoo", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + VOODOO_MAJOR_VERSION, VOODOO_MINOR_VERSION, VOODOO_PATCHLEVEL, + ABI_CLASS_VIDEODRV, /* This is a video driver */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0,0,0,0} +}; + +static pointer voodooSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static int setupDone = FALSE; + if(errmaj) + *errmaj = LDR_ONCEONLY; + if(setupDone == FALSE) + { + setupDone = TRUE; + xf86AddDriver(&VOODOO, module, 0); + LoaderRefSymLists(fbSymbols, shadowSymbols, xaaSymbols,NULL); + return (pointer)1; + } + return NULL; +} + +XF86ModuleData voodooModuleData = { &voodooVersRec, voodooSetup, NULL }; + + +#endif /* XFree86LOADER */ + +static Bool +VoodooGetRec(ScrnInfoPtr pScrn) +{ + /* + * Allocate an VoodooRec, and hook it into pScrn->driverPrivate. + * pScrn->driverPrivate is initialised to NULL, so we can check if + * the allocation has already been done. + */ + if (pScrn->driverPrivate != NULL) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(VoodooRec), 1); + + /* Initialize it */ + /* No init here yet */ + return TRUE; +} + +static void +VoodooFreeRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate == NULL) + return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + + +static const OptionInfoRec * +VoodooAvailableOptions(int chipid, int busid) +{ + return VoodooOptions; +} + +/* Mandatory */ +static void +VoodooIdentify(int flags) +{ + xf86PrintChipsets(VOODOO_NAME, "driver for Voodoo1/Voodoo2", VoodooChipsets); +} + +static PciChipsets VoodooPCIChipsets[] = { + { PCI_CHIP_VOODOO1, PCI_CHIP_VOODOO1, 0 }, + { PCI_CHIP_VOODOO2, PCI_CHIP_VOODOO2, 0 }, + { -1, -1, RES_UNDEFINED } +}; + +/* Mandatory */ +static Bool +VoodooProbe(DriverPtr drv, int flags) +{ + int i, numDevSections, numUsed, *usedChips; + GDevPtr *devSections; + Bool foundScreen = FALSE; + + /* + * Look for config file Device sections with this driver specified. + */ + if ((numDevSections = xf86MatchDevice(VOODOO_DRIVER_NAME, + &devSections)) <= 0) { +#ifdef DEBUG + xf86ErrorFVerb(3,"%s: No Device section found.\n",VOODOO_NAME); +#endif + /* + * There's no matching device section in the config file, so quit + * now. + */ + return FALSE; + } + + /* PCI BUS */ + if (xf86GetPciVideoInfo() ) { + numUsed = xf86MatchPciInstances(VOODOO_NAME, PCI_VENDOR_3DFX, + VoodooChipsets, VoodooPCIChipsets, + devSections,numDevSections, + drv, &usedChips); + + if (numUsed > 0) { + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i = 0; i < numUsed; i++) { + ScrnInfoPtr pScrn = NULL; + EntityInfoPtr pEnt; + + /* Allocate a ScrnInfoRec and claim the slot */ + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], + VoodooPCIChipsets,NULL, + NULL, NULL, NULL, + NULL))) { + pScrn->driverVersion = VERSION; + pScrn->driverName = VOODOO_DRIVER_NAME; + pScrn->name = VOODOO_NAME; + pScrn->Probe = VoodooProbe; + pScrn->PreInit = VoodooPreInit; + pScrn->ScreenInit = VoodooScreenInit; + pScrn->SwitchMode = VoodooSwitchMode; + pScrn->EnterVT = VoodooEnterVT; + pScrn->LeaveVT = VoodooLeaveVT; + pScrn->FreeScreen = VoodooFreeScreen; + foundScreen = TRUE; + } + pEnt = xf86GetEntityInfo(usedChips[i]); + } + xfree(usedChips); + } + } + xfree(devSections); + return foundScreen; +} + + + + +/* Mandatory */ +static Bool +VoodooPreInit(ScrnInfoPtr pScrn, int flags) +{ + VoodooPtr pVoo; + int i; + ClockRangePtr clockRanges; + MessageType from; + int maxwidth; + + if (flags & PROBE_DETECT) + return FALSE; + + /* Check the number of entities, and fail if it isn't one. */ + if (pScrn->numEntities != 1) + return FALSE; + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + if (!xf86SetDepthBpp(pScrn, 16, 0, 0, Support32bppFb)) { + return FALSE; + } + + /* Check that the returned depth is one we support */ + switch (pScrn->depth) { + case 16: + case 24: + case 32: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by this driver\n", + pScrn->depth); + return FALSE; + } + xf86PrintDepthBpp(pScrn); + + if(pScrn->depth == 32) + pScrn->depth = 24; + + /* + * This must happen after pScrn->display has been set because + * xf86SetWeight references it. + */ + + if (pScrn->depth > 8) { + /* The defaults are OK for us */ + rgb zeros = {0, 0, 0}; + + if (!xf86SetWeight(pScrn, zeros, zeros)) { + return FALSE; + } else { + /* XXX check that weight returned is supported */ + ; + } + } + + /* Set the default visual. */ + if (!xf86SetDefaultVisual(pScrn, -1)) { + return FALSE; + } + /* We don't support DirectColor at > 8bpp */ + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" + " (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + return FALSE; + } + + /* Set default gamma */ + { + Gamma zeros = {0.0, 0.0, 0.0}; + + if (!xf86SetGamma(pScrn, zeros)) { + return FALSE; + } + } + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + /* Allocate the VoodooRec driverPrivate */ + if (!VoodooGetRec(pScrn)) { + return FALSE; + } + + pVoo = VoodooPTR(pScrn); + + /* Get the entity */ + pVoo->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + pVoo->PciInfo = xf86GetPciInfoForEntity(pVoo->pEnt->index); + pVoo->PciTag = pciTag(pVoo->PciInfo->bus, pVoo->PciInfo->device, pVoo->PciInfo->func); + + + /* Collect all of the relevant option flags (fill in pScrn->options) */ + xf86CollectOptions(pScrn, NULL); + + /* Process the options */ + if (!(pVoo->Options = xalloc(sizeof(VoodooOptions)))) + return FALSE; + memcpy(pVoo->Options, VoodooOptions, sizeof(VoodooOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pVoo->Options); + + /* Need to do rotation some day */ + + if(pVoo->pEnt->chipset == PCI_CHIP_VOODOO2) + { + pVoo->Voodoo2 = 1; /* We have 2D accel, interlace, double */ + pVoo->Accel = 1; + } + else + { + pVoo->Voodoo2 = 0; + pVoo->ShadowFB = 1; + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Using shadowFB with Voodoo1 hardware.\n"); + } + + from = X_DEFAULT; + + if (xf86ReturnOptValBool(pVoo->Options, OPTION_SHADOW_FB, FALSE)) { + pVoo->ShadowFB = 1; + pVoo->Accel = 0; + } + + if (xf86ReturnOptValBool(pVoo->Options, OPTION_NOACCEL, FALSE)) { + pVoo->ShadowFB = 1; + pVoo->Accel = 0; + } + + if(pScrn->depth == 24 && !pVoo->ShadowFB) + { + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "ShadowFB is required for 24/32bit modes.\n"); + pVoo->ShadowFB = 1; + pVoo->Accel = 0; + } + + /* MMIO at 0 , FB at 4Mb, Texture at 8Mb */ + pVoo->MMIO = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVoo->PciTag, + pVoo->PciInfo->memBase[0], 0x400000); + pVoo->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pVoo->PciTag, + pVoo->PciInfo->memBase[0] + 0x400000, 0x400000); + + pVoo->PhysBase = pVoo->PciInfo->memBase[0] + 0x400000; + + VoodooHardwareInit(pVoo); + + /* + * If the user has specified the amount of memory in the XF86Config + * file, we respect that setting. + */ + if (pVoo->pEnt->device->videoRam != 0) { + pScrn->videoRam = pVoo->pEnt->device->videoRam; + from = X_CONFIG; + } else { + pScrn->videoRam = VoodooMemorySize(pVoo) * 1024 ; /* Sizer reports Mbytes */ + from = X_PROBED; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Video RAM: %d kB\n", + pScrn->videoRam); + + /* Set up clock ranges so that the xf86ValidateModes() function will not fail a mode because of the clock + requirement (because we don't use the clock value anyway) */ + clockRanges = xnfcalloc(sizeof(ClockRange), 1); + clockRanges->next = NULL; + clockRanges->minClock = 10000; + clockRanges->maxClock = 250000; /* 250MHz DAC */ + clockRanges->clockIndex = -1; /* programmable */ + + if(pVoo->Voodoo2) + { + clockRanges->interlaceAllowed = TRUE; + clockRanges->doubleScanAllowed = TRUE; + maxwidth = min(1024, pScrn->display->virtualX); + } + else + { + clockRanges->interlaceAllowed = FALSE; + clockRanges->doubleScanAllowed = FALSE; + maxwidth = min(800, pScrn->display->virtualX); + } + + /* Select valid modes from those available */ + i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, + pScrn->display->modes, clockRanges, + NULL, 256, 2048, + pScrn->bitsPerPixel, 128, 768, + pScrn->display->virtualX, + pScrn->display->virtualY, + pScrn->videoRam * 1024, + LOOKUP_BEST_REFRESH); + + if (i == -1) { + VoodooFreeRec(pScrn); + return FALSE; + } + + /* Prune the modes marked as invalid */ + xf86PruneDriverModes(pScrn); + + /* If no valid modes, return */ + if (i == 0 || pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + VoodooFreeRec(pScrn); + return FALSE; + } + + /* Set the current mode to the first in the list */ + pScrn->currentMode = pScrn->modes; + + /* Do some checking, we will not support a virtual framebuffer larger than + the visible screen. */ + if (pScrn->currentMode->HDisplay != pScrn->virtualX || + pScrn->currentMode->VDisplay != pScrn->virtualY || + pScrn->displayWidth != pScrn->virtualX) + { + /* FIXME: In this case we could use shadowfb and clip the drawing into + the physical buffer */ + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Virtual size doesn't equal display size. Forcing virtual size to equal display size.\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "(Virtual size: %dx%d, Display size: %dx%d)\n", pScrn->virtualX, pScrn->virtualY, + pScrn->currentMode->HDisplay, pScrn->currentMode->VDisplay); + /* I'm not entirely sure this is "legal" but I hope so. */ + pScrn->virtualX = pScrn->currentMode->HDisplay; + pScrn->virtualY = pScrn->currentMode->VDisplay; + pScrn->displayWidth = pScrn->virtualX; + } + + /* Print the list of modes being used */ + xf86PrintModes(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load fb */ + if (xf86LoadSubModule(pScrn, "fb") == NULL) { + VoodooFreeRec(pScrn); + return FALSE; + } + + xf86LoaderReqSymLists(fbSymbols, NULL); + + if (!xf86LoadSubModule(pScrn, "xaa")) { + VoodooFreeRec(pScrn); + return FALSE; + } + + xf86LoaderReqSymLists(xaaSymbols, NULL); + + if(pVoo->ShadowFB) + { + /* Load the shadow framebuffer */ + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + VoodooFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(shadowSymbols, NULL); + } + return TRUE; +} + + +/* Mandatory */ +/* This gets called at the start of each server generation */ +static Bool +VoodooScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn; + VoodooPtr pVoo; + int ret; + VisualPtr visual; + void *FBStart; + CARD32 displayWidth; + + /* + * First get the ScrnInfoRec + */ + pScrn = xf86Screens[pScreen->myNum]; + + pVoo = VoodooPTR(pScrn); + + if (!VoodooModeInit(pScrn, pScrn->currentMode)) + return FALSE; + + VoodooClear(pVoo); + + /* + * The next step is to setup the screen's visuals, and initialise the + * framebuffer code. In cases where the framebuffer's default + * choices for things like visual layouts and bits per RGB are OK, + * this may be as simple as calling the framebuffer's ScreenInit() + * function. If not, the visuals will need to be setup before calling + * a fb ScreenInit() function and fixed up after. + * + * For most PC hardware at depths >= 8, the defaults that fb uses + * are not appropriate. In this driver, we fixup the visuals after. + */ + + /* + * Reset the visual list. + */ + miClearVisualTypes(); + + /* Setup the visuals we support. Only TrueColor. */ + if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + miSetPixmapDepths (); + + if(pVoo->ShadowFB) + { + pVoo->ShadowPitch = ((pScrn->virtualX * pScrn->bitsPerPixel >> 3) + 3) & ~3L; + pVoo->ShadowPtr = xnfalloc(pVoo->ShadowPitch * pScrn->virtualY); + FBStart = pVoo->ShadowPtr; + displayWidth = pScrn->virtualX; + } + else + { + FBStart = pVoo->FBBase; + displayWidth = 1024; + } + + if(pScrn->depth == 16) + pVoo->Pitch = 2048; + else + pVoo->Pitch = 4096; + + /* + * Call the framebuffer layer's ScreenInit function, and fill in other + * pScreen fields. + */ + ret = fbScreenInit(pScreen, FBStart, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + displayWidth, + pScrn->bitsPerPixel); + + if (!ret) + return FALSE; + + xf86SetBlackWhitePixels(pScreen); + + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + + /* must be after RGB ordering fixed */ + fbPictureInit (pScreen, 0, 0); + if(!pVoo->ShadowFB) + VoodooDGAInit(pScrn, pScreen); + + /* Activate accelerations */ + if(pVoo->Accel) + Voodoo2XAAInit(pScreen); + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + + + /* Initialize software cursor. + Must precede creation of the default colormap */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Initialise default colourmap */ + if (!miCreateDefColormap(pScreen)) + return FALSE; + + if(pVoo->ShadowFB) + { + if(pScrn->depth == 16) + ShadowFBInit(pScreen, VoodooRefreshArea16); + else + ShadowFBInit(pScreen, VoodooRefreshArea24); + } + + xf86DPMSInit(pScreen, VoodooDisplayPowerManagementSet, 0); + + pScrn->memPhysBase = pVoo->PhysBase; + pScrn->fbOffset = 0; + + pScreen->SaveScreen = VoodooSaveScreen; + + /* Wrap the current CloseScreen function */ + pVoo->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = VoodooCloseScreen; + + /* Report any unused options (only for the first generation) */ + if (serverGeneration == 1) { + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + } + + /* Done */ + return TRUE; +} + + + +/* + * This is called when VT switching back to the X server. Its job is + * to reinitialise the video mode. + * + * We may wish to unmap video/MMIO memory too. + */ + +/* Mandatory */ +static Bool +VoodooEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + return VoodooModeInit(pScrn, pScrn->currentMode); +} + +/* + * This is called when VT switching away from the X server. Its job is + * to restore the previous (text) mode. + * + * We may wish to remap video/MMIO memory too. + */ + +/* Mandatory */ +static void +VoodooLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + VoodooRestore(pScrn, FALSE); +} + +/* + * This is called at the end of each server generation. It restores the + * original (text) mode. It should also unmap the video memory, and free + * any per-generation data allocated by the driver. It should finish + * by unwrapping and calling the saved CloseScreen function. + */ + +/* Mandatory */ +static Bool +VoodooCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + VoodooPtr pVoo = VoodooPTR(pScrn); + + if (pScrn->vtSema) + VoodooRestore(pScrn, TRUE); + if(pVoo->ShadowPtr) + xfree(pVoo->ShadowPtr); + if(pVoo->AccelInfoRec) + xfree(pVoo->AccelInfoRec); + if (pVoo->pDGAMode) { + xfree(pVoo->pDGAMode); + pVoo->pDGAMode = NULL; + pVoo->nDGAMode = 0; + } + + pScrn->vtSema = FALSE; + + pScreen->CloseScreen = pVoo->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + + +/* Free up any persistent data structures */ + +/* Optional */ +static void +VoodooFreeScreen(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + VoodooPtr pVoo = VoodooPTR(pScrn); + /* + * This only gets called when a screen is being deleted. It does not + * get called routinely at the end of a server generation. + */ + if (pVoo && pVoo->ShadowPtr) + xfree(pVoo->ShadowPtr); + VoodooFreeRec(xf86Screens[scrnIndex]); +} + + +/* Do screen blanking */ +/* Mandatory */ +static Bool +VoodooSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn; + VoodooPtr pVoo; + Bool unblank; + + unblank = xf86IsUnblank(mode); + if(pScreen != NULL) + { + pScrn = xf86Screens[pScreen->myNum]; + pVoo = VoodooPTR(pScrn); + + if(pScrn->vtSema && (unblank == pVoo->Blanked)) + { + if (unblank) + VoodooModeInit(pScrn, pScrn->currentMode); + else + VoodooBlank(pVoo); + pVoo->Blanked = !unblank; + } + } + return TRUE; +} + +static Bool +VoodooModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + VoodooPtr pVoo; + int width, height; + + pVoo = VoodooPTR(pScrn); + + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Clock : %x\n", mode->Clock); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Display : %x\n", mode->CrtcHDisplay); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank Start : %x\n", mode->CrtcHBlankStart); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync Start : %x\n", mode->CrtcHSyncStart); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Sync End : %x\n", mode->CrtcHSyncEnd); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Blank End : %x\n", mode->CrtcHBlankEnd); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Total : %x\n", mode->CrtcHTotal); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz Skew : %x\n", mode->CrtcHSkew); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Hz HAdjusted : %x\n", mode->CrtcHAdjusted); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Display : %x\n", mode->CrtcVDisplay); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank Start : %x\n", mode->CrtcVBlankStart); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync Start : %x\n", mode->CrtcVSyncStart); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Sync End : %x\n", mode->CrtcVSyncEnd); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Blank End : %x\n", mode->CrtcVBlankEnd); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt Total : %x\n", mode->CrtcVTotal); + xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Vt VAdjusted : %x\n", mode->CrtcVAdjusted); + if ((mode->Flags & (V_INTERLACE|V_DBLSCAN)) && !pVoo->Voodoo2) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Interlaced/doublescan modes not supported\n"); + return FALSE; + } + + width = mode->HDisplay; + height = mode->VDisplay; + + /* Initialize the video card */ + if(VoodooMode(pScrn, mode)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot set chosen mode.\n"); + return FALSE; + } + + pVoo->Blanked = FALSE; + return TRUE; +} + +/* + * Sync engine on mode switches. The docs are not clear if + * this is needed but it does no harm. + */ + +static Bool VoodooSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + VoodooSync(pScrn); + return VoodooModeInit(xf86Screens[scrnIndex], mode); +} + +static void +VoodooRestore(ScrnInfoPtr pScrn, Bool Closing) +{ + VoodooPtr pVoo; + + pVoo = VoodooPTR(pScrn); + pVoo->Blanked = TRUE; + if (!Closing || !(pVoo->OnAtExit)) + VoodooBlank(pVoo); +} + +static void +VoodooRefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + int Bpp; + unsigned char *src; + signed int x1, x2; + + if (pVoo->Blanked) + return; + + /* + * Voodoo 1 lacks host to CPU blit so we must use the LFB port + */ + + Bpp = pScrn->bitsPerPixel >> 3; + while(num--) { + /* We align to an even number of pixels so we won't have to copy + half-words over the PCI bus */ + x1 = (pbox->x1) & ~1; + x2 = (pbox->x2 + 1) & ~1; + src = pVoo->ShadowPtr + (pbox->y1 * pVoo->ShadowPitch) + + (x1 * Bpp); + VoodooCopy16(pVoo, x1, pbox->y1, x2-x1, pbox->y2-pbox->y1, pVoo->ShadowPitch, src); + pbox++; + } +} + +static void +VoodooRefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + int Bpp; + unsigned char *src; + + if (pVoo->Blanked) + return; + + /* + * Voodoo 1 lacks host to CPU blit so we must use the LFB port + */ + + Bpp = pScrn->bitsPerPixel >> 3; + while(num--) { + src = pVoo->ShadowPtr + (pbox->y1 * pVoo->ShadowPitch) + + (pbox->x1 * Bpp); + VoodooCopy24(pVoo, pbox->x1, pbox->y1, pbox->x2-pbox->x1, pbox->y2-pbox->y1, pVoo->ShadowPitch, src); + pbox++; + } +} + +/* + * VoodooDisplayPowerManagementSet -- + * + * Sets VESA Display Power Management Signaling (DPMS) Mode. + */ +static void +VoodooDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + int old = -1; + + + switch (PowerManagementMode) + { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + if(old != DPMSModeOn && old != -1) + { + VoodooModeInit(pScrn, pScrn->currentMode); + } + pVoo->Blanked = FALSE; + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + pVoo->Blanked = TRUE; + VoodooBlank(pVoo); + break; + } + old = PowerManagementMode; +} diff --git a/src/voodoo_hardware.c b/src/voodoo_hardware.c new file mode 100644 index 0000000..73b6c88 --- /dev/null +++ b/src/voodoo_hardware.c @@ -0,0 +1,1432 @@ +/* + * Portions derived from linux/drivers/video/sstfb.c + * -- voodoo graphics frame buffer + * Copyright (c) 2000-2002 Ghozlane Toumi <gtoumi@laposte.net> + * + * Relicensed from GPL to the X license by consent of the author + * + * Other code Alan Cox (c) Copyright 2004 Red Hat Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of Red Hat, Alan Cox and Ghozlane Toumi + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Th authors make no + * representations about the suitability of this software for any purpose. + * It is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL RICHARD HECKER BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * THIS SOFTWARE IS NOT DESIGNED FOR USE IN SAFETY CRITICAL SYSTEMS OF + * ANY KIND OR FORM. + * + * Freely reviewably music for this hacking supplied by + * http://www.hoerstreich.de + * http://www.machinaesupremacy.com + * http://www.magnatune.com + */ + +#include "fb.h" +#include "mibank.h" +#include "micmap.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Version.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86cmap.h" +#include "shadowfb.h" +#include "vgaHW.h" +#include "xf86DDC.h" +#include "xf86RAC.h" +#include "xf86Resources.h" +#include "xaa.h" +#include "compiler.h" + +#include "voodoo.h" + +#include "extensions/xf86dgastr.h" + +#include "opaque.h" +#define DPMS_SERVER +#include "extensions/dpms.h" +#include "mipict.h" +#include "dixstruct.h" + +static int debug = 0; + +/* + * Big endian might need to byteswap these ? + */ + +/* + * Write to chuck and bruce + */ + +static CARD32 mmio32_r(VoodooPtr pVoo, int reg) +{ + volatile CARD32 *ptr = (CARD32 *)(pVoo->MMIO + reg); + CARD32 val = *ptr; + return val; +} + +static void mmio32_w(VoodooPtr pVoo, int reg, CARD32 val) +{ + volatile CARD32 *ptr = (CARD32 *)(pVoo->MMIO + reg); + *ptr = val; +} + +/* + * Write to chuck only + */ + +static void mmio32_w_chuck(VoodooPtr pVoo, int reg, CARD32 val) +{ + volatile CARD32 *ptr = (CARD32 *)(pVoo->MMIO + (reg |(1<<10))); + *ptr = val; +} + +/* + * Size the video RAM. Texture ram sizing is different and seperate + * but we don't use the texture ram for 2D anyway. + */ + +int VoodooMemorySize(VoodooPtr pVoo) +{ + volatile CARD32 *fp = (volatile CARD32 *)pVoo->FBBase; + fp[0] = 0xA5A5A5A5; + fp[1<<18] = 0xA5A5A5A5; + fp[1<<19] = 0xA5A5A5A5; + + fp[0] = 0x5A5A5A5A; + + if(fp[1<<19] == 0xA5A5A5A5) + return 4; /* 4Mb Card */ + if(fp[1<<18] == 0xA5A5A5A5) + return 2; /* 2Mb Card */ + return 1; +} + +/* + * FIXME: If we are also doing 3D or DRI paths do we need + * to fix this path to issue a NOP command as per the chip errata? + */ + +static void wait_idle(VoodooPtr pVoo) +{ + int i = 0; + + while(i < 5) + { + if((mmio32_r(pVoo,0) & 0x80) == 0) + i++; + } +} + +/* + * PCI control registers + */ + +/* + * PCI enables. Used for setup, mode switch etc + */ + +static void pci_enable(VoodooPtr pVoo, int wr, int dac, int fifo) +{ + CARD32 x = pciReadLong(pVoo->PciTag, 0x40); + x &= ~7; + x |= wr; + x |= fifo<<1; + x |= dac<<2; + pciWriteLong(pVoo->PciTag, 0x40, x); +} + +/* + * VClock control + */ + +static void vclock_enable(VoodooPtr pVoo, int enable) +{ + if(enable) + pciWriteLong(pVoo->PciTag, 0xC0, 0); + else + pciWriteLong(pVoo->PciTag, 0xE0, 0); +} + +/* + * DPMS + */ + +void VoodooBlank(VoodooPtr pVoo) +{ + vclock_enable(pVoo, 0); + pci_enable(pVoo, 1, 0, 0); + + mmio32_w(pVoo, 0x214, mmio32_r(pVoo, 0x214) | 0x100); + wait_idle(pVoo); + + mmio32_w(pVoo, 0x210, mmio32_r(pVoo, 0x210) | 6); + wait_idle(pVoo); + + mmio32_w(pVoo, 0x218, mmio32_r(pVoo, 0x218) & ~(1<<22)); + wait_idle(pVoo); +} + +/* + * Read and write the DAC registers + */ + +static void dac_out(VoodooPtr pVoo, CARD32 reg, CARD32 val) +{ + mmio32_w(pVoo, 0x22C, (reg << 8) | val); + wait_idle(pVoo); +} + +static CARD32 dac_in(VoodooPtr pVoo, CARD32 reg) +{ + CARD32 r; + mmio32_w(pVoo, 0x22C, (1<<11)|(reg<< 8)); + wait_idle(pVoo); + r = mmio32_r(pVoo, 0x218) & 0xFF; + return r; +} + +/* + * Indexed (or should that be "demented") mode on the TI + * and AT&T DAC's + */ + +static void dac_out_idx(VoodooPtr pVoo, CARD32 reg, CARD32 val) +{ + dac_out(pVoo, 0, reg); + dac_out(pVoo, 2, val); +} + +static CARD32 dac_in_idx(VoodooPtr pVoo, CARD32 reg) +{ + dac_out(pVoo, 0, reg); + return dac_in(pVoo, 2); +} + +/* + * We have generic ics5432 code we perhaps ought to use instead. + * This is based on the sstfb and Glide logic. + */ + +#define ICS_PLL_CLK0_1_INI 0x55 /* Frequencies for detecting ICS */ +#define ICS_PLL_CLK0_7_INI 0x71 +#define ICS_PLL_CLK1_B_INI 0x79 + +static int probe_ics5432(VoodooPtr pVoo) +{ + int i; + CARD32 m01, m07, m11; + + for(i = 0; i < 5; i++) + { + dac_out(pVoo, 7, 1); + m01 = dac_in(pVoo,5); + dac_in(pVoo,5); + dac_out(pVoo,7, 7); + m07 = dac_in(pVoo, 5); + dac_in(pVoo,5); + dac_out(pVoo,7, 11); + m11 = dac_in(pVoo, 5); + dac_in(pVoo, 5); + + if(m01 == ICS_PLL_CLK0_1_INI && + m07 == ICS_PLL_CLK0_7_INI && + m11 == ICS_PLL_CLK1_B_INI) + return 1; + } + return 0; +} + +/* + * Activate backdoor on DACs + */ + +static void dacdoor(VoodooPtr pVoo) +{ + dac_out(pVoo,0, 0); + dac_in(pVoo,2); + dac_in(pVoo,2); + dac_in(pVoo,2); + dac_in(pVoo,2); +} + +/* + * Set a PLL on the DAC. Either vClock (0) or gClock (1) + */ + +static void voodoo_set_pll(VoodooPtr pVoo, int pllnum) +{ + CARD32 cr0; + if(pVoo->DAC == DAC_ID_ATT || pVoo->DAC == DAC_ID_TI) + { + CARD32 cc; + dacdoor(pVoo); + cr0 = dac_in(pVoo, 2); + + dacdoor(pVoo); + dac_out(pVoo, 2, (cr0 & 0xF0) | 0xB); /* Switch to index mode */ + + /* Sleep a bit */ + usleep(300); + + cc = dac_in_idx(pVoo, 6); + if(pllnum == 0) + { + dac_out_idx(pVoo, 0x48, pVoo->vClock.m); + dac_out_idx(pVoo, 0x49, (pVoo->vClock.p << 6) | pVoo->vClock.n); + dac_out_idx(pVoo, 6, (cc & 0x0F) | 0xA0 ); + } + else + { + dac_out_idx(pVoo, 0x6C, pVoo->gClock.m); + dac_out_idx(pVoo, 0x6D, (pVoo->gClock.p << 6) | pVoo->vClock.n); + dac_out_idx(pVoo, 6, (cc & 0x0F) | 0x0B); + } + return; + } + /* ICS5432 */ + dac_out(pVoo, 7, 14); + cr0 = dac_in(pVoo, 5); + if(pllnum == 0) + { + dac_out(pVoo, 4, 0); + dac_out(pVoo, 5, pVoo->vClock.m); + dac_out(pVoo, 5, pVoo->vClock.p << 5 | pVoo->vClock.n); + dac_out(pVoo, 4, 14); + dac_out(pVoo, 5, (cr0 & 0xD8) | (1<<5)); + } + else + { + dac_out(pVoo, 4, 10); + dac_out(pVoo, 5, pVoo->gClock.m); + dac_out(pVoo, 5, pVoo->gClock.p << 5 | pVoo->gClock.n); + dac_out(pVoo, 4, 14); + dac_out(pVoo, 5, (cr0 & 0xEF)); + } +} + +/* + * Set the depth in the DAC. This must match the frame + * buffer format. Right now we could hard code 16, in fact + * it may be correct to always do so.. ? + */ + +static void voodoo_set_depth(VoodooPtr pVoo, int depth) +{ + CARD32 cr0; + + if(pVoo->DAC == DAC_ID_ATT || pVoo->DAC == DAC_ID_TI) + { + dacdoor(pVoo); + cr0 = dac_in(pVoo, 2); + + dacdoor(pVoo); + + if(depth == 16) + dac_out(pVoo, 2, (cr0 & 0x0F) | 0x50); + else if(depth ==24 || depth == 32) + dac_out(pVoo, 2, (cr0 & 0x0F) | 0x70); + } + else if(pVoo->DAC == DAC_ID_ICS) + { + if(depth == 16) + dac_out(pVoo, 6, 0x50); + else + dac_out(pVoo, 6, 0x70); + } +} + +static int voodoo_find_dac(VoodooPtr pVoo) +{ + CARD32 vendor_id, device_id; + +#define DAC_VENDOR_ATT 0x84 +#define DAC_DEVICE_ATT20C409 0x09 +#define DAC_VENDOR_TI 0x97 +#define DAC_DEVICE_TITVP3409 0x09 + + dacdoor(pVoo); + dac_in(pVoo, 2); + vendor_id = dac_in(pVoo, 2); + device_id = dac_in(pVoo, 2); + + /* AT&T 20C409 and clones */ + if(vendor_id == DAC_VENDOR_ATT && DAC_DEVICE_ATT20C409) + return DAC_ID_ATT; + + if(vendor_id == DAC_VENDOR_TI && DAC_DEVICE_TITVP3409) + return DAC_ID_TI; + + /* ICS5432 doesn't implement the back door. Glide does some + quick tests to see if it is an ICS5432 just in case. */ + + if(probe_ics5432(pVoo)) + return DAC_ID_ICS; + + /* Shouldn't be any boards that get this far */ + ErrorF("Voodoo card with unknown DAC. Not supported.\n"); + return DAC_UNKNOWN; +} + +/* + * Compute the PLL clock values. This is directly based on the + * technique used by sstfb. + */ + +/* compute the m,n,p , returns the real freq + * (ics datasheet : N <-> N1 , P <-> N2) + * + * Fout= Fref * (M+2)/( 2^P * (N+2)) + * we try to get close to the asked freq + * with P as high, and M as low as possible + * range: + * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63 + * ics : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31 + * + * We will use the lowest limitation, should be precise enough + */ + +static int iabs(int a) +{ + if(a >= 0) + return a; + return -a; +} + +static int sst_calc_pll(const int freq, PLLClock *t) +{ + int m, m2, n, p, best_err, fout; + int best_n=-1; + int best_m=-1; + + best_err = freq; + p=3; + /* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics */ + while (((1 << p) * freq > 260000) && (p >= 0)) + p--; + if (p == -1) + return 0; + for (n = 1; n < 32; n++) { + /* Calc 2 * m so we can round it later */ + m2 = (2 * freq * (1 << p) * (n + 2) ) / 14318 - 4 ; + + m = (m2 % 2) ? m2/2+1 : m2/2 ; + if (m >= 128) + break; + fout = (14318 * (m + 2)) / ((1 << p) * (n + 2)); + if (iabs(fout - freq) < best_err && m > 0) { + best_n = n; + best_m = m; + best_err = iabs(fout - freq); + /* We get the lowest m , allowing 0.5% error in freq */ + if (200*best_err < freq) + break; + } + } + if (best_n == -1) /* Unlikely, but who knows ? */ + return 0; + t->p=p; + t->n=best_n; + t->m=best_m; + return (14318 * (t->m + 2)) / ((1 << t->p) * (t->n + 2)); +} + + +/* + * Here endeth the DAC code + */ + + +/* + * Higher level mode management + */ + +static void voodoo_set_mode(VoodooPtr pVoo, DisplayModePtr mode) +{ + CARD32 hbporch = mode->CrtcHTotal - mode->CrtcHSyncEnd; + CARD32 vbporch = mode->CrtcVTotal - mode->CrtcVSyncEnd; + CARD32 hsyncstart = mode->CrtcHSyncEnd - mode->CrtcHSyncStart; + CARD32 hsyncend = mode->CrtcHTotal - hsyncstart; + CARD32 vsyncstart = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + CARD32 vsyncend = mode->CrtcVTotal - vsyncstart; + CARD32 width = mode->CrtcHDisplay; + CARD32 height = mode->CrtcVDisplay; + + /* Even numbers of lines for interlace */ + if((mode->Flags & V_INTERLACE) && (vbporch & 1)) + vbporch += 1; + /* Doublescan does what you expect */ + if(mode->Flags & V_DBLSCAN) + { + /* Not sure if we need to do all of these */ + vbporch <<= 1; + hbporch <<= 1; + hsyncend <<= 1; + hsyncstart <<= 1; + vsyncend <<= 1; + vsyncstart <<= 1; + width <<= 1; + height <<= 1; + } + + /* Write back porch values */ + mmio32_w(pVoo, 0x208, (vbporch << 16) | (hbporch - 2)); + /* Write displayed area */ + mmio32_w(pVoo, 0x20C, (height << 16) | (width - 1)); + mmio32_w(pVoo, 0x220, (hsyncend - 1 ) << 16 | (hsyncstart - 1)); + mmio32_w(pVoo, 0x224, (vsyncend << 16) | vsyncstart); +} + +/* + * Set up a Voodoo video mode. Note that we do need to have + * save/restore functions here too because the user might be + * using sstfb... Eventually.. + */ + +int VoodooMode(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + CARD32 f1, f2, f3; + VoodooPtr pVoo = VoodooPTR(pScrn); + int tiles; + + /* FIXME: Compute PLL and check */ + + sst_calc_pll(mode->SynthClock, &pVoo->vClock); + + mmio32_w(pVoo, 0x120, 0); /* NOP */ + wait_idle(pVoo); + pci_enable(pVoo, 1, 0, 0); + mmio32_w(pVoo, 0x214, mmio32_r(pVoo,0x214)|(1<<8)); + mmio32_w(pVoo, 0x210, mmio32_r(pVoo,0x210)|6); + mmio32_w(pVoo, 0x218, mmio32_r(pVoo,0x218) & ~(1<<22)); + wait_idle(pVoo); + + voodoo_set_mode(pVoo, mode); + + f2 = mmio32_r(pVoo,0x218); + f3 = mmio32_r(pVoo,0x21c); + + pci_enable(pVoo, 1, 1, 0); + + voodoo_set_depth(pVoo, 16); /* Hardware output is always 16bpp */ + voodoo_set_pll(pVoo, 0); + + pci_enable(pVoo, 1, 0, 0); + + mmio32_w(pVoo, 0x218, f2); + mmio32_w(pVoo, 0x21C, f3); + + f1 = mmio32_r(pVoo,0x214); + + f1 &= 0x8080010F; /* Mask off video bits */ + f1 |= 0x21E000; /* Enable blanking, data, vsync, dclock 2x sel */ + + /* Number of 64 pixel tiles */ + tiles = (mode->CrtcHDisplay + 63) / 64; + + if(pVoo->Voodoo2) + f1|= ((tiles & 0x10) ? 1<<24 : 0) | (tiles & 0x0f) << 4; + else + f1|= tiles << 4; + + pVoo->Tiles = tiles * 2; + pVoo->Width = mode->CrtcHDisplay; + pVoo->Height = mode->CrtcVDisplay; + if(!pVoo->Accel) + pVoo->FullHeight = mode->CrtcVDisplay; + + mmio32_w(pVoo, 0x214, f1); + + /* Voodoo 2 support */ + if(pVoo->Voodoo2) + { + CARD32 f5 = mmio32_r(pVoo, 0x244); + mmio32_w(pVoo, 0x248, 0); + + f5 &= ~0x05BF0000; + + f5 &= ~(1<<22); /* For now */ + + if(mode->Flags & V_INTERLACE) + f5 |= 1<<26; + /* FIXME: is this H, V or both doublescan ?? */ + if(mode->Flags & V_DBLSCAN) + f5 |= (1<<21) | (1<<20); + if(mode->Flags & V_PHSYNC) + f5 |= (1<<23); + if(mode->Flags & V_PVSYNC) + f5 |= (1<<24); + mmio32_w(pVoo, 0x244, f5); + } + wait_idle(pVoo); + mmio32_w(pVoo, 0x214, mmio32_r(pVoo,0x214) & ~0x100); + mmio32_w(pVoo, 0x210, 1 | (mmio32_r(pVoo,0x210) & ~6)); + mmio32_w(pVoo, 0x218, mmio32_r(pVoo,0x218) | (1<<22)); + + pci_enable(pVoo, 0, 0, 1); + + mmio32_w(pVoo, 0x114, 0x100); + pVoo->lfbMode = 0x100; /* Cached LFB mode, front, front, on */ + + /* + * Set a clipping rectangle. We really deeply emphatically + * don't want to write off screen otherwise. + */ + mmio32_w(pVoo, 0x118, mode->CrtcHDisplay); + mmio32_w(pVoo, 0x11C, mode->CrtcVDisplay); + mmio32_w(pVoo, 0x110, /*mmio32_r(pVoo, 0x110) | */0x201); + + /* + * Set up the 2D engine drawing logic + */ + + if(pVoo->Voodoo2) + { + mmio32_w_chuck(pVoo, 0x2C0, 0); /* Zero source */ + mmio32_w_chuck(pVoo, 0x2C4, 0); /* Zero destination */ + /* Use screen sized tiles for src/dst */ + mmio32_w_chuck(pVoo, 0x2C8, (pVoo->Tiles << 16) | pVoo->Tiles); + mmio32_w_chuck(pVoo, 0x2D4, pVoo->Width); + mmio32_w_chuck(pVoo, 0x2D8, pVoo->FullHeight); + } + return 0; +} + +/* + * Probe and initialize a Voodoo 1 or Voodoo 2 that we found. + * We don't set up any video mode at this point. + */ + +int VoodooHardwareInit(VoodooPtr pVoo) +{ + vclock_enable(pVoo, 0); + pci_enable(pVoo, 1, 0, 0); + + mmio32_w(pVoo, 0x214, mmio32_r(pVoo, 0x214) | 0x100); + wait_idle(pVoo); + + mmio32_w(pVoo, 0x210, mmio32_r(pVoo, 0x210) | 7); + wait_idle(pVoo); + + mmio32_w(pVoo, 0x218, mmio32_r(pVoo, 0x218) & ~(1<<22)); + wait_idle(pVoo); + + /* At this point we are basically shut down */ + + pci_enable(pVoo, 1, 1, 0); + + pVoo->DAC = voodoo_find_dac(pVoo); + + /* Graphics clock depends on the board */ + pVoo->MaxClock = 50000; + if(pVoo->Voodoo2) + pVoo->MaxClock = 75000; + + sst_calc_pll(pVoo->MaxClock, &pVoo->gClock); + voodoo_set_pll(pVoo, 1); + + pci_enable(pVoo, 1, 0, 1); + + mmio32_w(pVoo, 0x210, 0); /* 1 for VGA pass through */ + wait_idle(pVoo); + mmio32_w(pVoo, 0x214, 0x1A8 | (1<<21) ); + wait_idle(pVoo); + mmio32_w(pVoo, 0x218, 0x186000E0); /* RAM setup with fast ras, oe, fifo, refresh on and a 16mS refresh */ + wait_idle(pVoo); + mmio32_w(pVoo, 0x21C, 0x40); /* Need to review with DRI */ + wait_idle(pVoo); + mmio32_w(pVoo, 0x200, 2); + wait_idle(pVoo); + + if(pVoo->Voodoo2) + { + mmio32_w(pVoo, 0x248, 0); + wait_idle(pVoo); + } + + pci_enable(pVoo, 0, 0, 1); + vclock_enable(pVoo, 1); + + return 0; +} + +/* + * Copiers for Voodoo1 + * + * Voodoo1 has no CPU to screen blit, and also lacks SGRAM fill + */ + +void VoodooCopy16(VoodooPtr pVoo, CARD32 x1, CARD32 y1, CARD32 w, CARD32 h, CARD32 spitch, unsigned char *src) +{ + /* DWord copy pointer */ + CARD32 *out = (CARD32 *)(pVoo->FBBase + y1 * pVoo->Pitch + x1 *2); + CARD32 *in = (CARD32 *)src; + /* DWords to skip */ + CARD32 skipo = (pVoo->Pitch - w*2)>>2; + CARD32 skipi = (pVoo->ShadowPitch - w*2)>>2; + int ct; + + /* LFB will do all our work for us */ + + mmio32_w(pVoo, 0x10C, 0); + mmio32_w(pVoo, 0x110, (1<<9)|1); + mmio32_w(pVoo, 0x114, (1<<8)); + while(h > 0) + { + for(ct = 0; ct < w; ct+=2) + *out++=*in++; + in += skipi; + out += skipo; + h--; + } +} + +/* + * Copiers for Voodoo 1 and Voodoo 2 24bit + * + * Voodoo1 has no CPU to screen blit, and also lacks SGRAM fill + * Voodoo2 has no read side 24bit, nor 24bit accelerator + */ + +void VoodooCopy24(VoodooPtr pVoo, CARD32 x1, CARD32 y1, CARD32 w, CARD32 h, CARD32 spitch, unsigned char *src) +{ + /* DWord copy pointer */ + CARD32 *out = (CARD32 *)(pVoo->FBBase + y1 * pVoo->Pitch + x1 * 4); + CARD32 *in = (CARD32 *)src; + /* DWords to skip */ + CARD32 skipo = (pVoo->Pitch - w*4)>>2; + CARD32 skipi = (pVoo->ShadowPitch - w*4)>>2; + int ct; + + /* LFB will do all our work for us */ + /* FIXME: Should we allow dither options ? */ + + mmio32_w(pVoo, 0x10C, 0); + mmio32_w(pVoo, 0x110, (1<<9)|1); + mmio32_w(pVoo, 0x114, (1<<8)|4); + while(h > 0) + { + for(ct = 0; ct < w; ct++) + *out++=*in++; + in += skipi; + out += skipo; + h--; + } +} + +/* + * Use hardware clear. For Voodoo2 we want to use the SGRAM fill + * really. fbzMode bits 9/10 write to depth buffer, bit 14/15 to select + * the right buffer, bit 9 off for no dither, depth in zacolor, bits in + * colour1. + * + * load cliplr/lyhy and then fire. + */ + +void VoodooClear(VoodooPtr pVoo) +{ + memset(pVoo->FBBase,0, 0x400000); +#if 0 + /* + * We can't do this as the 3D engine setup is not + * done by this driver.. + */ + mmio32_w(pVoo, 0x130, 0); /* No Alpha ! */ + + mmio32_w(pVoo, 0x118, pVoo->Width); + mmio32_w(pVoo, 0x11C, pVoo->Height << 16); + /* On entry we know Clip is set correctly so we wil clear the lot */ + mmio32_w(pVoo, 0x148, 0xC0C0C0); /* RGB888 black */ + mmio32_w(pVoo, 0x130, 0xFFFF); /* I think ?? */ + /* We want to write to screen and depth, front buffer, and no dither */ + mmio32_w(pVoo, 0x110, (mmio32_r(pVoo, 0x110) | 0x601) & 0xFFE00EE1); + /* Fire */ + mmio32_w(pVoo, 0x124, 1); + wait_idle(pVoo); + /* In case X decides to read the LFB before clear finishes */ +#endif +} + +/* + * Voodoo banking. The voodoo isn't exactly banked in the conventional + * sense but claiming to be banked allows us to use the back buffer + * as the pixcache, providing we are careful with our acceleration + * ops + * + * There are two banks. Bank 0 is the front buffer, bank 1 is the + * back buffer. We don't use the aux buffer. Additionally the + * back bufer in 1024x768 with 2Mbyte cards is only a partial buffer. + * (No SLI yet) + * + * Not yet used (TODO: figure out the offsets for the backbuffer layout) + * For now we work the screen as one deep display instead + */ + +void VoodooReadBank(ScreenPtr pScreen, int bank) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + VoodooPtr pVoo = VoodooPTR(pScrn); + if(bank) + { + mmio32_w(pVoo, 0x2C0, pVoo->Height); + pVoo->lfbMode |= (1<<6); + } + else + { + mmio32_w(pVoo, 0x2C0, 0); + pVoo->lfbMode &= ~(1<<6); + } + mmio32_w(pVoo, 0x114, pVoo->lfbMode); +} + +void VoodooWriteBank(ScreenPtr pScreen, int bank) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + VoodooPtr pVoo = VoodooPTR(pScrn); + if(bank) + { + mmio32_w(pVoo, 0x2C4, pVoo->Height); + pVoo->lfbMode |= (1<<4); + } + else + { + mmio32_w(pVoo, 0x2C4, 0); + pVoo->lfbMode &= ~(1<<4); + } + mmio32_w(pVoo, 0x114, pVoo->lfbMode); +} + +void VoodooReadWriteBank(ScreenPtr pScreen, int bank) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + VoodooPtr pVoo = VoodooPTR(pScrn); + if(bank) + { + mmio32_w(pVoo, 0x2C0, pVoo->Height); + mmio32_w(pVoo, 0x2C4, pVoo->Height); + pVoo->lfbMode |= (1<<4) | (1<<6); + } + else + { + mmio32_w(pVoo, 0x2C0, 0); + mmio32_w(pVoo, 0x2C4, 0); + pVoo->lfbMode &= ~((1<<4) | (1<<6)); + } + mmio32_w(pVoo, 0x114, pVoo->lfbMode); +} + +/* + * We normally want to load all four rop variants at once so + * the table is the 16bits for the lot equal. + */ + +static CARD16 ropxlate[16] = { + 0x0000, /* GXclear */ + 0x8888, /* GXand */ + 0x4444, /* GXandReverse */ + 0xCCCC, /* GXcopy */ + 0x2222, /* GXandInverted */ + 0xAAAA, /* GXnop */ + 0x6666, /* GXxor */ + 0xEEEE, /* GXor */ + 0x1111, /* GXnor */ + 0x9999, /* GXequiv */ + 0x5555, /* GXinvert */ + 0xDDDD, /* GXorReverse */ + 0x3333, /* GXcopyInverted */ + 0xBBBB, /* GXorInverted */ + 0x7777, /* GXnand */ + 0xFFFF /* GXset */ +}; + +/* + * Transparent mask rops + */ + +static CARD16 tropxlate[16] = { + 0xAA00, /* GXclear */ + 0xAA88, /* GXand */ + 0xAA44, /* GXandReverse */ + 0xAACC, /* GXcopy */ + 0xAA22, /* GXandInverted */ + 0xAAAA, /* GXnop */ + 0xAA66, /* GXxor */ + 0xAAEE, /* GXor */ + 0xAA11, /* GXnor */ + 0xAA99, /* GXequiv */ + 0xAA55, /* GXinvert */ + 0xAADD, /* GXorReverse */ + 0xAA33, /* GXcopyInverted */ + 0xAABB, /* GXorInverted */ + 0xAA77, /* GXnand */ + 0xAAFF /* GXset */ +}; + + +void VoodooSync(ScrnInfoPtr pScrn) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + /* FIXME: Check if cliprect dirty if so rewrite */ + wait_idle(pVoo); + mmio32_w(pVoo, 0x10C, 0); /* Maybe flag this */ +} + +static void Voodoo2Setup2D(VoodooPtr pVoo) +{ + wait_idle(pVoo); +} + +static void Voodoo2SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, + int xdir, int ydir, int rop, + unsigned int planemask, + int trans_color) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + Voodoo2Setup2D(pVoo); + pVoo->BlitDirX = xdir; + pVoo->BlitDirY = ydir; + + if(trans_color == -1) + { + mmio32_w_chuck(pVoo, 0x2EC, ropxlate[rop]); /* Set the rop */ + mmio32_w_chuck(pVoo, 0x2F8, 0 | (1<<14) | (1<<15) | (1<<16)); /* 16bpp no color compare */ + } + else + { + mmio32_w_chuck(pVoo, 0x2EC, tropxlate[rop]); /* Transparent src rop */ + mmio32_w_chuck(pVoo, 0x2CC, (trans_color << 16) | trans_color); /* Match transparent colour */ + mmio32_w_chuck(pVoo, 0x2F8, 0 | (1<<10) | (1<<14) | (1<<15) | (1<<16)); /* 16bpp color compare */ + } +} + +static void Voodoo2SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, + int x1, int y1, + int x2, int y2, + int width, int height) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + wait_idle(pVoo); + /* Adjust co-ordinates for backward blits */ + height --; /* Adjust for fenceposting in the hardware */ + width --; + if(pVoo->BlitDirY < 0) + { + y1 += height; + y2 += height; + height = -height; + } + if(pVoo->BlitDirY < 0) + { + x1 += width; + x2 += width; + width = -width; + } + mmio32_w_chuck(pVoo, 0x2E0, (y1 << 16) | x1); /* Src x/y */ + mmio32_w_chuck(pVoo, 0x2E4, (y2 << 16) | x2); /* Dst x/y */ + /* Set size and fire */ + height &= 0xFFF; + width &= 0xFFF; + mmio32_w_chuck(pVoo, 0x2E8, (height << 16) | width | (1<<31)); +} + +static void Voodoo2SetupForSolidFill(ScrnInfoPtr pScrn, int color, + int rop, unsigned int planemask) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + Voodoo2Setup2D(pVoo); + mmio32_w_chuck(pVoo, 0x2EC, ropxlate[rop]); /* rop */ + mmio32_w_chuck(pVoo, 0x2F0, color); /* fg color */ + mmio32_w_chuck(pVoo, 0x2F8, 2 | (1<<14) | (1<<15) | (0/*1*/<<16)); /* Solid fill 16bpp front */ +} + +static void Voodoo2SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, + int w, int h) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + wait_idle(pVoo); + mmio32_w_chuck(pVoo, 0x2E4, (y<<16) | x); /* Dst x,y */ + /* Set size and fire */ + mmio32_w_chuck(pVoo, 0x2E8, ((h-1) << 16) | (w-1) | (1<<31)); +} + + +/* + * Colour expand fills are standard hardware goodies + */ + +static void Voodoo2SetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int planemask) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + Voodoo2Setup2D(pVoo); + mmio32_w_chuck(pVoo, 0x2EC, ropxlate[rop]); /* Pattern op */ + mmio32_w_chuck(pVoo, 0x2F0, fg | (bg << 16)); /* colors */ + if(bg != -1) /* Set transparent if needed */ + mmio32_w_chuck(pVoo, 0x2F8, 1 | (1<<14) | (1<<15) | (1<<16)); + else + mmio32_w_chuck(pVoo, 0x2F8, 1 | (1<<14) | (1<<15) | (1<<16) | (1<<17)); +} + +static void Voodoo2SubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int x, int y, int w, int h, + int skipleft) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + wait_idle(pVoo); + mmio32_w_chuck(pVoo, 0x2E4, x | (y<<16)); /* destination */ + mmio32_w_chuck(pVoo, 0x2E8, (w-1) | ((h-1)<<16) | (1<<31)); /* fire */ + pVoo->texW = w; +} + +static void Voodoo2SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + CARD32 *data = (CARD32 *)pVoo->LineBuffer; + int w = pVoo->texW; + int i; + + wait_idle(pVoo); + for(i = 0; i < w; i += 32) /* Each dword is 32 pixels mask */ + mmio32_w(pVoo, 0x2FC, *data++); +} + +static void Voodoo2SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty, + int fg, int bg, int rop, unsigned int planemask) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + Voodoo2Setup2D(pVoo); + mmio32_w_chuck(pVoo, 0x2EC, ropxlate[rop]); + mmio32_w_chuck(pVoo, 0x2F0, fg | (bg << 16)); + if(bg != -1) + mmio32_w_chuck(pVoo, 0x2F8, 1 | (1<<14) | (1<<15) | (1<<16)); + else + mmio32_w_chuck(pVoo, 0x2F8, 1 | (1<<14) | (1<<15) | (1<<16) | (1<<17)); +} + +/* + * We don't have pattern fill hardware but for any operation that + * references dst it is going to be faster to use the hardware + * and simply upload the pattern a lot as we avoid reading + * video memory. GXcopy ought to be the same either way. + */ + +static __inline__ CARD32 spread(CARD32 v) +{ + return v * 16843009; +} + +static void Voodoo2SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int patx, int paty, + int x, int y, int w, int h) +{ + int ln = 0; + CARD32 l[8]; + VoodooPtr pVoo = VoodooPTR(pScrn); + + wait_idle(pVoo); + + if( w <3) + return; + + mmio32_w_chuck(pVoo, 0x2E4, x | (y<<16)); + mmio32_w_chuck(pVoo, 0x2E8, (w - 1) | ((h - 1)<<16) | (1<<31)); + + /* Turn the pattern into 32x8 for the expansion engine */ + l[0] = spread((patx >> 24) & 0xFF); + l[1] = spread((patx >> 16) & 0xFF); + l[2] = spread((patx >> 8) & 0xFF); + l[3] = spread(patx & 0xFF); + + l[4] = spread((paty >> 24) & 0xFF); + l[5] = spread((paty >> 16) & 0xFF); + l[6] = spread((paty >> 8) & 0xFF); + l[7] = spread(paty & 0xFF); + + while(h > 0) + { + int i; + for(i = 0; i < w; i += 32) /* DWORD pad */ + mmio32_w_chuck(pVoo, 0x2FC, l[ln]); + wait_idle(pVoo); + ln = (ln + 1) & 7; + h--; + } +} + +/* + * The XAA layer uses video memory as the basis for colour pattern + * fill, so we can't usefully perform it. + */ + +static void Voodoo2SetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + Voodoo2Setup2D(pVoo); + mmio32_w_chuck(pVoo, 0x2CC, color); + mmio32_w_chuck(pVoo, 0x2EC, ropxlate[rop]); + mmio32_w_chuck(pVoo, 0x2F8, 2 | (1<<14) | (1<<15) | (1<<16)); /* Solid fill 16 bpp front */ +} + +static void Voodoo2SubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len, int dir) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + wait_idle(pVoo); + mmio32_w_chuck(pVoo, 0x2E4, (y<<16) | x); /* Dst x,y */ + if(dir == DEGREES_0) + mmio32_w_chuck(pVoo, 0x2E8, (len - 1) | (1<<31)); + else + mmio32_w_chuck(pVoo, 0x2E8, ((len - 1) << 16) | (1<<31)); +} + +static void Voodoo2SetupForScanlineImageWrite(ScrnInfoPtr pScrn, int rop, + unsigned int planemask, int trans_color, + int bpp, int depth) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + Voodoo2Setup2D(pVoo); + if(trans_color != -1) + { + mmio32_w_chuck(pVoo, 0x2CC, (trans_color << 16) | trans_color); + mmio32_w_chuck(pVoo, 0x2EC, tropxlate[rop]); + mmio32_w_chuck(pVoo, 0x2F8, 1 | (2<<3) | (1<<10) | (1<<14) | (1<<15) | (1<<16)); + } + else + { + mmio32_w_chuck(pVoo, 0x2EC, ropxlate[rop]); + mmio32_w_chuck(pVoo, 0x2F8, 1 | (2<<3) | (1<<14) | (1<<15) | (1<<16)); + } + if(debug) + ErrorF("Setup for image write rop %d col %d bpp %d depth %d\n", + rop, trans_color, bpp, depth); +} + +static void Voodoo2SubsequentImageWriteRect(ScrnInfoPtr pScrn, + int x, int y, + int w, int h, + int skipleft) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + wait_idle(pVoo); + mmio32_w_chuck(pVoo, 0x2E4, x | (y<<16)); + mmio32_w_chuck(pVoo, 0x2E8, (w - 1) | ((h - 1)<<16) | (1<<31)); + if(debug) + ErrorF("Image Write (%d,%d) [%d,%d]\n", x,y,w,h); + pVoo->texW = w; +} + +static void Voodoo2SubsequentImageWriteScanline(ScrnInfoPtr pScrn, int bufno) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + CARD32 *data = (CARD32 *)pVoo->LineBuffer; + int w = pVoo->texW; + int i; + + wait_idle(pVoo); + for(i = 0; i < w; i += 2) + mmio32_w(pVoo, 0x2FC, *data++); +} + +static void Voodoo2SetClippingRectangle(ScrnInfoPtr pScrn, + int left, int top, int right, int bottom) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + if(debug) + ErrorF("Clip to (%d,%d)-(%d,%d)\n", left,top,right,bottom); + mmio32_w_chuck(pVoo, 0x2D4, (left << 16) | right); + mmio32_w_chuck(pVoo, 0x2D8, (top << 16 ) | bottom); +} + +static void Voodoo2DisableClipping(ScrnInfoPtr pScrn) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + /* FIXME: pVoo->FullHeight for the cache ! */ + if(debug) + ErrorF("Clip to (0,0)-(%d,%d)\n", (int)pVoo->Width, (int)pVoo->Height); + mmio32_w_chuck(pVoo, 0x2D4, pVoo->Width); + mmio32_w_chuck(pVoo, 0x2D8, pVoo->FullHeight); +} + +/* + * TODO: Implement 2D line acceleration using the 3D engines + */ + +#ifdef RENDER + +/* + * Render acceleration. All Voodoo chips support cpu driver alpha + * composite to the frame buffer. This is presumably meant for software + * fallbacks on rendering 3D but happens to be very useful to avoid + * some render operations reading from the frame buffer as much + * + * Possibly we could the 3D engine for this once we get it working. + * We can't however use the 2D engine much as it lacks Alpha + */ + + +Bool VoodooSetupForCPUToScreenAlphaTexture(ScrnInfoPtr pScrn, int op, CARD16 red, + CARD16 green, CARD16 blue, CARD16 alpha, int alphaType, CARD8 *alphaPtr, + int alphaPitch, int width, int height, int flags) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + + pVoo->alphaType = alphaType; + pVoo->alphaPitch = alphaPitch; + pVoo->alphaPtr = alphaPtr; + pVoo->alphaW = width; + pVoo->alphaH = height; + pVoo->alphaC = (red & 0xFF00) << 8 | (green & 0xFF00) | blue >> 8; + + if(op != PictOpOver && op != PictOpSrc) + return FALSE; + + if(debug) + ErrorF("Supported CPU To Screen Alpha Texture (%d) -> %d,%d\n", op, width, height); + wait_idle(pVoo); + if(op == PictOpSrc) + pVoo->alpha = 0; + else /* dst = src * srcalpha + (1-a) * dst */ + pVoo->alpha = (1<<4) | (1<<8) | (5<<12); + + return TRUE; +} + +void VoodooSubsequentCPUToScreenAlphaTexture(ScrnInfoPtr pScrn, int dstx, int dsty, int srcx, int srcy, int width, int height) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + /* 32bit LFB write mode */ + CARD32 *fb = (CARD32 *)(pVoo->FBBase + 4096 * dsty + 4 * dstx); + CARD8 *db = pVoo->alphaPtr + pVoo->alphaW * srcy + srcx; + int x, y; + CARD32 *fdb; + CARD8 *cdb; + CARD32 colour = pVoo->alphaC; + int dw, dh; + int w, h; + + mmio32_w(pVoo, 0x10C, pVoo->alpha); + mmio32_w(pVoo, 0x110, 1 | (1<<9)); + mmio32_w(pVoo, 0x114, (1<<8) | 5); /* ARGB888 */ + + dh = srcy; + w = pVoo->alphaW; + h = pVoo->alphaH; + + for(y = 0; y < height; y++) + { + cdb = db; + fdb = fb; + + dw = srcx; + for(x = 0; x < width; x++) + { + *fdb++ = (*cdb++<< 24) | colour; + if(++dw == w) + { + dw = 0; + cdb -= pVoo->alphaW; + } + } + db += pVoo->alphaW; + fb += 1024; + if(++dh == h) + { + db = pVoo->alphaPtr + srcx; + dh = 0; + } + } + mmio32_w(pVoo, 114, pVoo->lfbMode); + mmio32_w(pVoo, 0x10C, 0); +} + +Bool VoodooSetupForCPUToScreenTexture(ScrnInfoPtr pScrn, int op, int texType, + CARD8 *texPtr, int texPitch, int width, int height, int flags) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + + if(op != PictOpOver && op != PictOpSrc) + return FALSE; /* For now */ + + if(debug) + ErrorF("Supported CPU TO Screen Texture (%d) -> %d,%d\n", op, width, height); + pVoo->texType = texType; + pVoo->texPitch = texPitch; + pVoo->texPtr = texPtr; + pVoo->texW = width; + pVoo->texH = height; + + wait_idle(pVoo); + if(op == PictOpSrc || texType == PICT_x8r8g8b8) + pVoo->alpha = 0; + else + pVoo->alpha = (1<<4) | (1<<8) | (5<<12); + + return TRUE; +} + +void VoodooSubsequentCPUToScreenTexture(ScrnInfoPtr pScrn, int dstx, int dsty, int srcx, int srcy, int width, int height) +{ + VoodooPtr pVoo = VoodooPTR(pScrn); + /* 32bit LFB write mode */ + CARD32 *fb = (CARD32 *)(pVoo->FBBase + 4096 * dsty + 4 * dstx); + CARD32 *db = ((CARD32 *)(pVoo->texPtr)) + pVoo->texW * srcy + srcx; + int x, y; + CARD32 *cdb, *fdb; + int dw, dh; + int w, h; + + mmio32_w(pVoo, 0x10C, pVoo->alpha); + mmio32_w(pVoo, 0x110, 1 | (1<<9)); + + if(pVoo->texType == PICT_a8r8g8b8) + mmio32_w(pVoo, 0x114, (1<<8) | 5); /* ARGB888 */ + else if(pVoo->texType == PICT_x8r8g8b8) + mmio32_w(pVoo, 0x114, (1<<8) | 4); /* xRGB888 */ + else ErrorF("BOGOFORMAT\n"); + + dh = srcy; + w = pVoo->texW; + h = pVoo->texH; + + if(debug) + ErrorF("CPUToScreenTexture (%d,%d)->(%d,%d)[%d,%d]\n", + srcx,srcy,dstx,dsty,width,height); + /* + * Tiled software render letting hardware do the read merge + * that we don't want the CPU to do. + */ + + for(y = 0; y < height; y++) + { + cdb = db; + fdb = fb; + dw = srcx; + for(x = 0; x < width; x++) + { + *fdb++ = *cdb++; + + if(++dw == w) + { + dw = 0; + cdb -= pVoo->texW; + } + } + db += pVoo->texW; + fb += 1024; + dh ++; + if(dh == h) + { + db = ((CARD32 *)pVoo->texPtr) + srcx; + dh = 0; + } + } + mmio32_w(pVoo, 0x114, pVoo->lfbMode); + mmio32_w(pVoo, 0x10C, 0); +} + +CARD32 VoodooAlphaTextureFormats[2] = {PICT_a8, 0}; +CARD32 VoodooTextureFormats[3] = {PICT_a8r8g8b8, PICT_x8r8g8b8, 0}; + +#endif + +void Voodoo2XAAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + VoodooPtr pVoo = VoodooPTR(pScrn); + XAAInfoRecPtr pAccel = XAACreateInfoRec(); + BoxRec cacheArea; + + pAccel->Flags = OFFSCREEN_PIXMAPS|LINEAR_FRAMEBUFFER; + pAccel->Sync = VoodooSync; + + pAccel->ScreenToScreenCopyFlags = NO_PLANEMASK; + pAccel->SetupForScreenToScreenCopy = Voodoo2SetupForScreenToScreenCopy; + pAccel->SubsequentScreenToScreenCopy = Voodoo2SubsequentScreenToScreenCopy; + + pAccel->SolidFillFlags = NO_PLANEMASK; + pAccel->SetupForSolidFill = Voodoo2SetupForSolidFill; + pAccel->SubsequentSolidFillRect = Voodoo2SubsequentSolidFillRect; + + pAccel->ScanlineCPUToScreenColorExpandFillFlags = + BIT_ORDER_IN_BYTE_MSBFIRST | NO_PLANEMASK | + SCANLINE_PAD_DWORD | CPU_TRANSFER_BASE_FIXED; + pAccel->SetupForScanlineCPUToScreenColorExpandFill = + Voodoo2SetupForScanlineCPUToScreenColorExpandFill; + pAccel->SubsequentScanlineCPUToScreenColorExpandFill = + Voodoo2SubsequentScanlineCPUToScreenColorExpandFill; + pAccel->SubsequentColorExpandScanline = + Voodoo2SubsequentColorExpandScanline; + + pAccel->NumScanlineColorExpandBuffers = 1; + pVoo->LinePtr = pVoo->LineBuffer; + pAccel->ScanlineColorExpandBuffers = &pVoo->LinePtr; + + pAccel->SetupForSolidLine = Voodoo2SetupForSolidLine; + pAccel->SubsequentSolidHorVertLine = Voodoo2SubsequentSolidHorVertLine; + pAccel->SolidLineFlags = NO_PLANEMASK; + + pAccel->Mono8x8PatternFillFlags = HARDWARE_PATTERN_PROGRAMMED_BITS; + pAccel->SetupForMono8x8PatternFill = Voodoo2SetupForMono8x8PatternFill; + pAccel->SubsequentMono8x8PatternFillRect = Voodoo2SubsequentMono8x8PatternFillRect; + + pAccel->ScanlineImageWriteFlags = NO_PLANEMASK; + pAccel->SetupForScanlineImageWrite = Voodoo2SetupForScanlineImageWrite; + pAccel->SubsequentImageWriteRect = Voodoo2SubsequentImageWriteRect; + pAccel->SubsequentImageWriteScanline = Voodoo2SubsequentImageWriteScanline; + + pAccel->ClippingFlags = + HARDWARE_CLIP_SCREEN_TO_SCREEN_COLOR_EXPAND | + HARDWARE_CLIP_SCREEN_TO_SCREEN_COPY | + HARDWARE_CLIP_MONO_8x8_FILL | + HARDWARE_CLIP_SOLID_FILL; + + pAccel->SetClippingRectangle = Voodoo2SetClippingRectangle; + pAccel->DisableClipping = Voodoo2DisableClipping; + +#ifdef RENDER + pAccel->CPUToScreenAlphaTextureFlags = 0; + pAccel->SetupForCPUToScreenAlphaTexture = VoodooSetupForCPUToScreenAlphaTexture; + pAccel->SubsequentCPUToScreenAlphaTexture = VoodooSubsequentCPUToScreenAlphaTexture; + + pAccel->CPUToScreenTextureFlags = 0; + pAccel->SetupForCPUToScreenTexture = VoodooSetupForCPUToScreenTexture; + pAccel->SubsequentCPUToScreenTexture = VoodooSubsequentCPUToScreenTexture; + + pAccel->CPUToScreenTextureFormats = VoodooTextureFormats; + pAccel->CPUToScreenAlphaTextureFormats = VoodooAlphaTextureFormats; +#endif + + cacheArea.x1 = 0; + cacheArea.x2 = pScrn->displayWidth; + cacheArea.y1 = pVoo->Height; + cacheArea.y2 = (pScrn->videoRam * 1024) / (pVoo->Tiles * 64); + if(cacheArea.y2 > 2047) + cacheArea.y2 = 2047; + + if(cacheArea.y2 > cacheArea.y1) + { + xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Using %d lines of pixmap cache.\n", cacheArea.y2-cacheArea.y1); + pAccel->Flags |= PIXMAP_CACHE; + pVoo->FullHeight = cacheArea.y2; + xf86InitFBManager(pScreen, &cacheArea); + } + if( XAAInit(pScreen, pAccel) == FALSE) + ErrorF("Unable to set up acceleration.\n"); + + Voodoo2DisableClipping(pScrn); +} |