summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralan <alan>2004-06-24 16:34:25 +0000
committeralan <alan>2004-06-24 16:34:25 +0000
commit65f9bc5c20ca203f4789421399f1f06b3c628816 (patch)
treed3922688310c04dcfffc92bb26d579e1cb125108
Check in the voodoo driver subtree
-rw-r--r--README56
-rw-r--r--TODO35
-rw-r--r--man/voodoo.man72
-rw-r--r--src/voodoo.h109
-rw-r--r--src/voodoo_dga.c184
-rw-r--r--src/voodoo_driver.c969
-rw-r--r--src/voodoo_hardware.c1432
7 files changed, 2857 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..0eb0b90
--- /dev/null
+++ b/README
@@ -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
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..41f644e
--- /dev/null
+++ b/TODO
@@ -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);
+}