summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/savage.man127
-rw-r--r--src/savage_accel.c1242
-rw-r--r--src/savage_bci.h97
-rw-r--r--src/savage_cursor.c299
-rw-r--r--src/savage_dga.c397
-rw-r--r--src/savage_driver.c3282
-rw-r--r--src/savage_driver.h278
-rw-r--r--src/savage_i2c.c93
-rw-r--r--src/savage_image.c194
-rw-r--r--src/savage_regs.h222
-rw-r--r--src/savage_shadow.c244
-rw-r--r--src/savage_vbe.c302
-rw-r--r--src/savage_vbe.h113
-rw-r--r--src/savage_video.c1982
14 files changed, 8872 insertions, 0 deletions
diff --git a/man/savage.man b/man/savage.man
new file mode 100644
index 0000000..cfd00ae
--- /dev/null
+++ b/man/savage.man
@@ -0,0 +1,127 @@
+.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage.man,v 1.6 2002/05/14 20:19:51 alanh Exp $
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH SAVAGE __drivermansuffix__ __vendorversion__
+.SH NAME
+savage \- S3 Savage video driver
+.SH SYNOPSIS
+.nf
+.B "Section \*qDevice\*q"
+.BI " Identifier \*q" devname \*q
+.B " Driver \*qsavage\*q"
+\ \ ...
+.B EndSection
+.fi
+.SH DESCRIPTION
+.B savage
+is an XFree86 driver for the S3 Savage family video accelerator chips. The
+.B savage
+driver supports PCI and AGP boards with the following chips:
+.TP 16
+.BI Savage3D
+(8a20 and 8a21)
+.TP 16
+.B Savage4
+(8a22)
+.TP 16
+.B Savage2000
+(9102)
+.TP 16
+.B Savage/MX
+(8c10 and 8c11)
+.TP 16
+.B Savage/IX
+(8c12 and 8c13)
+.TP 16
+.B ProSavage PM133
+(8a25)
+.TP 16
+.B ProSavage KM133
+(8a26)
+.TP 16
+.B Twister (ProSavage PN133)
+(8d01)
+.TP 16
+.B TwisterK (ProSavage KN133)
+(8d02)
+.TP 16
+.B ProSavage DDR
+(8d03)
+.TP 16
+.B ProSavage DDR-K
+(8d04)
+.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 \*qHWCursor\*q \*q" boolean \*q
+.TP
+.BI "Option \*qSWCursor\*q \*q" boolean \*q
+These two options interact to specify hardware or software cursor. If the
+SWCursor option is specified, any HWCursor setting is ignored. Thus, either
+\*qHWCursor off\*q or \*qSWCursor on\*q will force the use of the software
+cursor. On Savage/MX and Savage/IX chips which are connected to LCDs, a
+software cursor will be forced, because the Savage hardware cursor does not
+correctly track the automatic panel expansion feature.
+Default: hardware cursor.
+.TP
+.BI "Option \*qNoAccel\*q \*q" boolean \*q
+Disable or enable acceleration. Default: acceleration is enabled.
+.TP
+.BI "Option \*qRotate\*q \*qCW\*q"
+.TP
+.BI "Option \*qRotate\*q \*qCCW\*q"
+Rotate the desktop 90 degrees clockwise or counterclockwise. This option
+forces the ShadowFB option on, and disables acceleration.
+Default: no rotation.
+.TP
+.BI "Option \*qShadowFB\*q \*q" boolean \*q
+Enable or disable use of the shadow framebuffer layer. See
+shadowfb(__drivermansuffix__) for further information. This option
+disables acceleration. Default: off.
+.TP
+.BI "Option \*qLCDClock\*q \*q" frequency \*q
+Override the maximum dot clock. Some LCD panels produce incorrect results if
+they are driven at too fast of a frequency. If UseBIOS is on, the BIOS will
+usually restrict the clock to the correct range. If not, it might be
+necessary to override it here. The
+.B frequency
+parameter may be specified as an integer in Hz (135750000), or with
+standard suffixes like "k", "kHz", "M", or "MHz" (as in 135.75MHz).
+.TP
+.BI "Option \*qUseBIOS\*q \*q" boolean \*q
+Enable or disable use of the video BIOS to change modes. Ordinarily, the
+.B savage
+driver tries to use the video BIOS to do mode switches. This generally
+produces the best results with the mobile chips (/MX and /IX), since the BIOS
+knows how to handle the critical but unusual timing requirements of the
+various LCD panels supported by the chip. To do this, the driver searches
+through the BIOS mode list, looking for the mode which most closely matches
+the XF86Config mode line. Some purists find this scheme objectionable. If
+you would rather have the
+.B savage
+driver use your mode line timing exactly, turn off the UseBios option.
+Default: on (use the BIOS).
+.TP
+.BI "Option \*qShadowStatus\*q \q*" boolean \*q
+Enables the use of a shadow status register. There is a chip bug in the
+Savage graphics engine that can cause a bus lock when reading the engine
+status register under heavy load, such as when scrolling text or dragging
+windows. The bug affects about 4% of all Savage users. If your system
+hangs regularly while scrolling text or dragging windows, try turning this
+option on. This uses an alternate method of reading the engine status
+which is slightly more expensive, but avoids the problem. Default: off
+(use normal status register).
+.SH FILES
+savage_drv.o
+.SH "SEE ALSO"
+XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__)
+.SH AUTHORS
+Authors include Tim Roberts (timr@probo.com) and Ani Joshi (ajoshi@unixbox.com)
+for the 4.0 version, and Tim Roberts and S. Marineau for the 3.3 driver from
+which this was derived.
diff --git a/src/savage_accel.c b/src/savage_accel.c
new file mode 100644
index 0000000..0ffc863
--- /dev/null
+++ b/src/savage_accel.c
@@ -0,0 +1,1242 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_accel.c,v 1.18 2002/11/08 18:03:32 alanh Exp $ */
+
+/*
+ *
+ * Copyright 1995-1997 The XFree86 Project, Inc.
+ *
+ */
+
+/*
+ * The accel file for the Savage driver.
+ *
+ * Created 20/03/97 by Sebastien Marineau for 3.3.6
+ * Modified 17-Nov-2000 by Tim Roberts for 4.0.1
+ * Revision:
+ *
+ */
+
+#include "Xarch.h"
+#include "xaalocal.h"
+#include "xaarop.h"
+#include "miline.h"
+
+#include "savage_driver.h"
+#include "savage_regs.h"
+#include "savage_bci.h"
+
+/* Forward declaration of functions used in the driver */
+
+static void SavageSetupForScreenToScreenCopy(
+ ScrnInfoPtr pScrn,
+ int xdir,
+ int ydir,
+ int rop,
+ unsigned planemask,
+ int transparency_color);
+
+static void SavageSubsequentScreenToScreenCopy(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int w,
+ int h);
+
+static void SavageSetupForSolidFill(
+ ScrnInfoPtr pScrn,
+ int color,
+ int rop,
+ unsigned planemask);
+
+static void SavageSubsequentSolidFillRect(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h);
+
+static void SavageSubsequentSolidBresenhamLine(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int e1,
+ int e2,
+ int err,
+ int length,
+ int octant);
+
+static void SavageSubsequentSolidTwoPointLine(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int bias);
+
+#if 0
+static void SavageSetupForScreenToScreenColorExpand(
+ ScrnInfoPtr pScrn,
+ int bg,
+ int fg,
+ int rop,
+ unsigned planemask);
+
+static void SavageSubsequentScreenToScreenColorExpand(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ int skipleft);
+#endif
+
+static void SavageSetupForCPUToScreenColorExpandFill(
+ ScrnInfoPtr pScrn,
+ int fg,
+ int bg,
+ int rop,
+ unsigned planemask);
+
+static void SavageSubsequentScanlineCPUToScreenColorExpandFill(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ int skipleft);
+
+static void SavageSubsequentColorExpandScanline(
+ ScrnInfoPtr pScrn,
+ int buffer_no);
+
+static void SavageSetupForMono8x8PatternFill(
+ ScrnInfoPtr pScrn,
+ int patternx,
+ int patterny,
+ int fg,
+ int bg,
+ int rop,
+ unsigned planemask);
+
+static void SavageSubsequentMono8x8PatternFillRect(
+ ScrnInfoPtr pScrn,
+ int pattern0,
+ int pattern1,
+ int x,
+ int y,
+ int w,
+ int h);
+
+static void SavageSetupForColor8x8PatternFill(
+ ScrnInfoPtr pScrn,
+ int patternx,
+ int patterny,
+ int rop,
+ unsigned planemask,
+ int trans_col);
+
+static void SavageSubsequentColor8x8PatternFillRect(
+ ScrnInfoPtr pScrn,
+ int pattern0,
+ int pattern1,
+ int x,
+ int y,
+ int w,
+ int h);
+
+static void SavageSetClippingRectangle(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int x2,
+ int y2);
+
+static void SavageDisableClipping( ScrnInfoPtr );
+
+#if 0
+static void SavageSubsequentSolidFillTrap(
+ ScrnInfoPtr pScrn,
+ int y,
+ int h,
+ int left,
+ int dxl,
+ int dyl,
+ int el,
+ int right,
+ int dxr,
+ int dyr,
+ int er);
+#endif
+
+/* from savage_image.c: */
+
+void SavageSetupForImageWrite(
+ ScrnInfoPtr pScrn,
+ int rop,
+ unsigned int planemask,
+ int transparency_color,
+ int bpp,
+ int depth);
+
+void SavageSubsequentImageWriteRect(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ int skipleft);
+
+void SavageWriteBitmapCPUToScreenColorExpand (
+ ScrnInfoPtr pScrn,
+ int x, int y, int w, int h,
+ unsigned char * src,
+ int srcwidth,
+ int skipleft,
+ int fg, int bg,
+ int rop,
+ unsigned int planemask
+);
+
+unsigned long writedw( unsigned long addr, unsigned long value );
+unsigned long readdw( unsigned long addr );
+unsigned long readfb( unsigned long addr );
+unsigned long writefb( unsigned long addr, unsigned long value );
+void writescan( unsigned long scan, unsigned long color );
+
+
+/*
+ * This is used to cache the last known value for routines we want to
+ * call from the debugger.
+ */
+
+ScrnInfoPtr gpScrn = 0;
+
+
+
+
+void
+SavageInitialize2DEngine(ScrnInfoPtr pScrn)
+{
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned int vgaCRIndex = hwp->IOBase + 4;
+ unsigned int vgaCRReg = hwp->IOBase + 5;
+
+ gpScrn = pScrn;
+
+ VGAOUT16(vgaCRIndex, 0x0140);
+ VGAOUT8(vgaCRIndex, 0x31);
+ VGAOUT8(vgaCRReg, 0x0c);
+
+ /* Setup plane masks */
+ OUTREG(0x8128, ~0); /* enable all write planes */
+ OUTREG(0x812C, ~0); /* enable all read planes */
+ OUTREG16(0x8134, 0x27);
+ OUTREG16(0x8136, 0x07);
+
+ switch( psav->Chipset ) {
+
+ case S3_SAVAGE3D:
+ case S3_SAVAGE_MX:
+ /* Disable BCI */
+ OUTREG(0x48C18, INREG(0x48C18) & 0x3FF0);
+ /* Setup BCI command overflow buffer */
+ OUTREG(0x48C14, (psav->cobOffset >> 11) | (psav->cobIndex << 29));
+ /* Program shadow status update. */
+ OUTREG(0x48C10, 0x78207220);
+ if( psav->ShadowStatus )
+ {
+ OUTREG(0x48C0C, psav->ShadowPhysical | 1 );
+ /* Enable BCI and command overflow buffer */
+ OUTREG(0x48C18, INREG(0x48C18) | 0x0E);
+ }
+ else
+ {
+ OUTREG(0x48C0C, 0);
+ /* Enable BCI and command overflow buffer */
+ OUTREG(0x48C18, INREG(0x48C18) | 0x0C);
+ }
+ break;
+
+ case S3_SAVAGE4:
+ case S3_PROSAVAGE:
+ case S3_SUPERSAVAGE:
+ /* Disable BCI */
+ OUTREG(0x48C18, INREG(0x48C18) & 0x3FF0);
+ /* Program shadow status update */
+ OUTREG(0x48C10, 0x00700040);
+ if( psav->ShadowStatus )
+ {
+ OUTREG(0x48C0C, psav->ShadowPhysical | 1 );
+ /* Enable BCI without the COB */
+ OUTREG(0x48C18, INREG(0x48C18) | 0x0a);
+ }
+ else
+ {
+ OUTREG(0x48C0C, 0);
+ /* Enable BCI without the COB */
+ OUTREG(0x48C18, INREG(0x48C18) | 0x08);
+ }
+ break;
+
+ case S3_SAVAGE2000:
+ /* Disable BCI */
+ OUTREG(0x48C18, 0);
+ /* Setup BCI command overflow buffer */
+ OUTREG(0x48C18, (psav->cobOffset >> 7) | (psav->cobIndex));
+ if( psav->ShadowStatus )
+ {
+ /* Set shadow update threshholds. */
+ OUTREG(0x48C10, 0x6090 );
+ OUTREG(0x48C14, 0x70A8 );
+ /* Enable shadow status update */
+ OUTREG(0x48A30, psav->ShadowPhysical );
+ /* Enable BCI, command overflow buffer and shadow status. */
+ OUTREG(0x48C18, INREG(0x48C18) | 0x00380000 );
+ }
+ else
+ {
+ /* Disable shadow status update */
+ OUTREG(0x48A30, 0);
+ /* Enable BCI and command overflow buffer */
+ OUTREG(0x48C18, INREG(0x48C18) | 0x00280000 );
+ }
+ break;
+ }
+
+ /* Use and set global bitmap descriptor. */
+
+ /* For reasons I do not fully understand yet, on the Savage4, the */
+ /* write to the GBD register, MM816C, does not "take" at this time. */
+ /* Only the low-order byte is acknowledged, resulting in an incorrect */
+ /* stride. Writing the register later, after the mode switch, works */
+ /* correctly. This needs to get resolved. */
+
+ SavageSetGBD(pScrn);
+}
+
+
+void
+SavageSetGBD( ScrnInfoPtr pScrn )
+{
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned int vgaCRIndex = hwp->IOBase + 4;
+ unsigned int vgaCRReg = hwp->IOBase + 5;
+ unsigned long GlobalBitmapDescriptor;
+
+ GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
+ BCI_BD_SET_BPP(GlobalBitmapDescriptor, pScrn->bitsPerPixel);
+ BCI_BD_SET_STRIDE(GlobalBitmapDescriptor, pScrn->displayWidth);
+
+ /* Turn on 16-bit register access. */
+
+ VGAOUT8(vgaCRIndex, 0x31);
+ VGAOUT8(vgaCRReg, 0x0c);
+
+ /* Set stride to use GBD. */
+
+ VGAOUT8(vgaCRIndex, 0x50);
+ VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
+
+ /* Enable 2D engine. */
+
+ VGAOUT16(vgaCRIndex, 0x0140);
+
+ /* Now set the GBD and SBDs. */
+
+ OUTREG(0x8168, 0);
+ OUTREG(0x816C, GlobalBitmapDescriptor);
+ OUTREG(0x8170, 0);
+ OUTREG(0x8174, GlobalBitmapDescriptor);
+ OUTREG(0x8178, 0);
+ OUTREG(0x817C, GlobalBitmapDescriptor);
+
+ OUTREG(PRI_STREAM_STRIDE, pScrn->displayWidth * pScrn->bitsPerPixel >> 3);
+ OUTREG(SEC_STREAM_STRIDE, pScrn->displayWidth * pScrn->bitsPerPixel >> 3);
+}
+
+
+/* Acceleration init function, sets up pointers to our accelerated functions */
+
+Bool
+SavageInitAccel(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ SavagePtr psav = SAVPTR(pScrn);
+ XAAInfoRecPtr xaaptr;
+ BoxRec AvailFBArea;
+
+ /* Set-up our GE command primitive */
+
+ if (pScrn->depth == 8) {
+ psav->PlaneMask = 0xFF;
+ }
+ else if (pScrn->depth == 15) {
+ psav->PlaneMask = 0x7FFF;
+ }
+ else if (pScrn->depth == 16) {
+ psav->PlaneMask = 0xFFFF;
+ }
+ else if (pScrn->depth == 24) {
+ psav->PlaneMask = 0xFFFFFF;
+ }
+
+ /* General acceleration flags */
+
+ if (!(xaaptr = psav->AccelInfoRec = XAACreateInfoRec()))
+ return FALSE;
+
+ xaaptr->Flags = 0
+ | PIXMAP_CACHE
+ | OFFSCREEN_PIXMAPS
+ | LINEAR_FRAMEBUFFER
+ ;
+
+ /* Clipping */
+
+ xaaptr->SetClippingRectangle = SavageSetClippingRectangle;
+ xaaptr->DisableClipping = SavageDisableClipping;
+ xaaptr->ClippingFlags = 0
+#if 0
+ | HARDWARE_CLIP_SOLID_FILL
+ | HARDWARE_CLIP_SOLID_LINE
+ | HARDWARE_CLIP_DASHED_LINE
+#endif
+ | HARDWARE_CLIP_SCREEN_TO_SCREEN_COPY
+ | HARDWARE_CLIP_MONO_8x8_FILL
+ | HARDWARE_CLIP_COLOR_8x8_FILL
+ ;
+
+ xaaptr->Sync = SavageAccelSync;
+
+
+ /* ScreenToScreen copies */
+
+#if 1
+ xaaptr->SetupForScreenToScreenCopy = SavageSetupForScreenToScreenCopy;
+ xaaptr->SubsequentScreenToScreenCopy = SavageSubsequentScreenToScreenCopy;
+ xaaptr->ScreenToScreenCopyFlags = NO_TRANSPARENCY | NO_PLANEMASK | ROP_NEEDS_SOURCE;
+#endif
+
+
+ /* Solid filled rectangles */
+
+#if 1
+ xaaptr->SetupForSolidFill = SavageSetupForSolidFill;
+ xaaptr->SubsequentSolidFillRect = SavageSubsequentSolidFillRect;
+ xaaptr->SolidFillFlags = NO_PLANEMASK | ROP_NEEDS_SOURCE;
+#endif
+
+ /* Mono 8x8 pattern fills */
+
+#if 1
+ xaaptr->SetupForMono8x8PatternFill = SavageSetupForMono8x8PatternFill;
+ xaaptr->SubsequentMono8x8PatternFillRect
+ = SavageSubsequentMono8x8PatternFillRect;
+ xaaptr->Mono8x8PatternFillFlags = 0
+ | HARDWARE_PATTERN_PROGRAMMED_BITS
+ | HARDWARE_PATTERN_SCREEN_ORIGIN
+ | ROP_NEEDS_SOURCE
+ | BIT_ORDER_IN_BYTE_MSBFIRST
+ ;
+ if( psav->Chipset == S3_SAVAGE4 )
+ xaaptr->Mono8x8PatternFillFlags |= NO_TRANSPARENCY;
+#endif
+
+ /* Color 8x8 pattern fills */
+
+ /*
+ * With the exception of the Savage3D and Savage4, all of the Savage
+ * chips require that bitmap descriptors have a stride that is a
+ * multiple of 16 pixels. This includes any descriptor used for
+ * color pattern fills, which COMPLETELY screws the XAA 8x8 color
+ * pattern support.
+ *
+ * We could double the width ourselves into a reserved frame buffer
+ * section, but since I went 18 months with only ONE report of this
+ * error, it seems hardly worth the trouble.
+ */
+
+#if 1
+ if( (psav->Chipset == S3_SAVAGE3D) || (psav->Chipset == S3_SAVAGE4) )
+ {
+ xaaptr->SetupForColor8x8PatternFill =
+ SavageSetupForColor8x8PatternFill;
+ xaaptr->SubsequentColor8x8PatternFillRect =
+ SavageSubsequentColor8x8PatternFillRect;
+ xaaptr->Color8x8PatternFillFlags = 0
+ | NO_TRANSPARENCY
+ | HARDWARE_PATTERN_PROGRAMMED_BITS
+ | HARDWARE_PATTERN_PROGRAMMED_ORIGIN
+ ;
+ }
+#endif
+
+ /* Solid lines */
+
+#if 1
+ xaaptr->SolidLineFlags = NO_PLANEMASK;
+ xaaptr->SetupForSolidLine = SavageSetupForSolidFill;
+ xaaptr->SubsequentSolidBresenhamLine = SavageSubsequentSolidBresenhamLine;
+ xaaptr->SubsequentSolidTwoPointLine = SavageSubsequentSolidTwoPointLine;
+#if 0
+ xaaptr->SubsequentSolidFillTrap = SavageSubsequentSolidFillTrap;
+#endif
+
+ xaaptr->SolidBresenhamLineErrorTermBits = 14;
+#endif
+
+ /* ImageWrite */
+
+ xaaptr->ImageWriteFlags = 0
+ | NO_PLANEMASK
+ | CPU_TRANSFER_PAD_DWORD
+ | SCANLINE_PAD_DWORD
+ | BIT_ORDER_IN_BYTE_MSBFIRST
+ | LEFT_EDGE_CLIPPING
+ ;
+ xaaptr->SetupForImageWrite = SavageSetupForImageWrite;
+ xaaptr->SubsequentImageWriteRect = SavageSubsequentImageWriteRect;
+ xaaptr->NumScanlineImageWriteBuffers = 1;
+ xaaptr->ImageWriteBase = psav->BciMem;
+ xaaptr->ImageWriteRange = 120 * 1024;
+
+ /* WriteBitmap color expand */
+
+#if 0
+ xaaptr->WriteBitmapFlags = NO_PLANEMASK;
+ xaaptr->WriteBitmap = SavageWriteBitmapCPUToScreenColorExpand;
+#endif
+
+ /* Screen to Screen color expansion. Not implemented. */
+
+#if 0
+ xaaptr->SetupForScreenToScreenColorExpand =
+ SavageSetupForScreenToScreenColorExpand;
+ xaaptr->SubsequentScreenToScreenColorExpand =
+ SavageSubsequentCPUToScreenColorExpand;
+#endif
+
+ /* CPU to Screen color expansion */
+
+ xaaptr->ScanlineCPUToScreenColorExpandFillFlags = 0
+ | NO_PLANEMASK
+ | CPU_TRANSFER_PAD_DWORD
+ | SCANLINE_PAD_DWORD
+ | BIT_ORDER_IN_BYTE_MSBFIRST
+ | LEFT_EDGE_CLIPPING
+ | ROP_NEEDS_SOURCE
+ ;
+
+ xaaptr->SetupForScanlineCPUToScreenColorExpandFill =
+ SavageSetupForCPUToScreenColorExpandFill;
+ xaaptr->SubsequentScanlineCPUToScreenColorExpandFill =
+ SavageSubsequentScanlineCPUToScreenColorExpandFill;
+ xaaptr->SubsequentColorExpandScanline =
+ SavageSubsequentColorExpandScanline;
+ xaaptr->ColorExpandBase = psav->BciMem;
+ xaaptr->ScanlineColorExpandBuffers = &xaaptr->ColorExpandBase;
+ xaaptr->NumScanlineColorExpandBuffers = 1;
+
+ /* Set up screen parameters. */
+
+ psav->Bpp = pScrn->bitsPerPixel / 8;
+ psav->Bpl = pScrn->displayWidth * psav->Bpp;
+ psav->ScissB = (psav->CursorKByte << 10) / psav->Bpl;
+ if (psav->ScissB > 2047)
+ psav->ScissB = 2047;
+
+ /*
+ * Finally, we set up the video memory space available to the pixmap
+ * cache. In this case, all memory from the end of the virtual screen
+ * to the end of the command overflow buffer can be used. If you haven't
+ * enabled the PIXMAP_CACHE flag, then these lines can be omitted.
+ */
+
+ AvailFBArea.x1 = 0;
+ AvailFBArea.y1 = 0;
+ AvailFBArea.x2 = pScrn->displayWidth;
+ AvailFBArea.y2 = psav->ScissB;
+ xf86InitFBManager(pScreen, &AvailFBArea);
+ xf86DrvMsg( pScrn->scrnIndex, X_INFO,
+ "Using %d lines for offscreen memory.\n",
+ psav->ScissB - pScrn->virtualY );
+
+ return XAAInit(pScreen, xaaptr);
+}
+
+
+
+
+/* The sync function for the GE */
+void
+SavageAccelSync(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ psav->WaitIdleEmpty(psav);
+}
+
+
+/*
+ * The XAA ROP helper routines all assume that a solid color is a
+ * "pattern". The Savage chips, however, apply a non-stippled solid
+ * color as "source". Thus, we use a slightly customized version.
+ */
+
+static int
+SavageHelpPatternROP(ScrnInfoPtr pScrn, int *fg, int *bg, int pm, int *rop)
+{
+ XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
+ int ret = 0;
+
+ pm &= infoRec->FullPlanemask;
+
+ if(pm == infoRec->FullPlanemask) {
+ if(!NO_SRC_ROP(*rop))
+ ret |= ROP_PAT;
+ *rop = XAACopyROP[*rop];
+ } else {
+ switch(*rop) {
+ case GXnoop:
+ break;
+ case GXset:
+ case GXclear:
+ case GXinvert:
+ ret |= ROP_PAT;
+ *fg = pm;
+ if(*bg != -1)
+ *bg = pm;
+ break;
+ default:
+ ret |= ROP_PAT | ROP_SRC;
+ break;
+ }
+ *rop = XAACopyROP_PM[*rop];
+ }
+
+ return ret;
+}
+
+
+static int
+SavageHelpSolidROP(ScrnInfoPtr pScrn, int *fg, int pm, int *rop)
+{
+ XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
+ int ret = 0;
+
+ pm &= infoRec->FullPlanemask;
+
+ if(pm == infoRec->FullPlanemask) {
+ if(!NO_SRC_ROP(*rop))
+ ret |= ROP_PAT;
+ *rop = XAACopyROP[*rop];
+ } else {
+ switch(*rop) {
+ case GXnoop:
+ break;
+ case GXset:
+ case GXclear:
+ case GXinvert:
+ ret |= ROP_PAT;
+ *fg = pm;
+ break;
+ default:
+ ret |= ROP_PAT | ROP_SRC;
+ break;
+ }
+ *rop = XAACopyROP_PM[*rop];
+ }
+
+ return ret;
+}
+
+
+
+/* These are the ScreenToScreen bitblt functions. We support all ROPs, all
+ * directions, and a planemask by adjusting the ROP and using the mono pattern
+ * registers.
+ *
+ * (That's a lie; we don't really support planemask.)
+ */
+
+static void
+SavageSetupForScreenToScreenCopy(
+ ScrnInfoPtr pScrn,
+ int xdir,
+ int ydir,
+ int rop,
+ unsigned planemask,
+ int transparency_color)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int cmd;
+
+ cmd = BCI_CMD_RECT | BCI_CMD_DEST_GBD | BCI_CMD_SRC_GBD;
+ BCI_CMD_SET_ROP( cmd, XAACopyROP[rop] );
+ if (transparency_color != -1)
+ cmd |= BCI_CMD_SEND_COLOR | BCI_CMD_SRC_TRANSPARENT;
+
+ if (xdir == 1 ) cmd |= BCI_CMD_RECT_XP;
+ if (ydir == 1 ) cmd |= BCI_CMD_RECT_YP;
+
+ psav->SavedBciCmd = cmd;
+ psav->SavedBgColor = transparency_color;
+}
+
+static void
+SavageSubsequentScreenToScreenCopy(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int w,
+ int h)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+
+ if (!w || !h) return;
+ if (!(psav->SavedBciCmd & BCI_CMD_RECT_XP)) {
+ w --;
+ x1 += w;
+ x2 += w;
+ w ++;
+ }
+ if (!(psav->SavedBciCmd & BCI_CMD_RECT_YP)) {
+ h --;
+ y1 += h;
+ y2 += h;
+ h ++;
+ }
+
+ psav->WaitQueue(psav,6);
+ BCI_SEND(psav->SavedBciCmd);
+ if (psav->SavedBgColor != -1)
+ BCI_SEND(psav->SavedBgColor);
+ BCI_SEND(BCI_X_Y(x1, y1));
+ BCI_SEND(BCI_X_Y(x2, y2));
+ BCI_SEND(BCI_W_H(w, h));
+}
+
+
+/*
+ * SetupForSolidFill is also called to set up for lines.
+ */
+
+static void
+SavageSetupForSolidFill(
+ ScrnInfoPtr pScrn,
+ int color,
+ int rop,
+ unsigned planemask)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ XAAInfoRecPtr xaaptr = GET_XAAINFORECPTR_FROM_SCRNINFOPTR( pScrn );
+ int cmd;
+ int mix;
+
+ cmd = BCI_CMD_RECT
+ | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+ | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID;
+
+ /* Don't send a color if we don't have to. */
+
+ if( rop == GXcopy )
+ {
+ if( color == 0 )
+ rop = GXclear;
+ else if( color == xaaptr->FullPlanemask )
+ rop = GXset;
+ }
+
+ mix = SavageHelpSolidROP( pScrn, &color, planemask, &rop );
+
+ if( mix & ROP_PAT )
+ cmd |= BCI_CMD_SEND_COLOR;
+
+ BCI_CMD_SET_ROP( cmd, rop );
+
+ psav->SavedBciCmd = cmd;
+ psav->SavedFgColor = color;
+}
+
+
+static void
+SavageSubsequentSolidFillRect(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+
+ if( !w || !h )
+ return;
+
+ psav->WaitQueue(psav,5);
+
+ BCI_SEND(psav->SavedBciCmd);
+ if( psav->SavedBciCmd & BCI_CMD_SEND_COLOR )
+ BCI_SEND(psav->SavedFgColor);
+ BCI_SEND(BCI_X_Y(x, y));
+ BCI_SEND(BCI_W_H(w, h));
+}
+
+#if 0
+static void
+SavageSetupForScreenToScreenColorExpand(
+ ScrnInfoPtr pScrn,
+ int bg,
+ int fg,
+ int rop,
+ unsigned planemask)
+{
+/* SavagePtr psav = SAVPTR(pScrn); */
+}
+
+static void
+SavageSubsequentScreenToScreenColorExpand(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ int skipleft)
+{
+/* SavagePtr psav = SAVPTR(pScrn); */
+}
+#endif
+
+
+static void
+SavageSetupForCPUToScreenColorExpandFill(
+ ScrnInfoPtr pScrn,
+ int fg,
+ int bg,
+ int rop,
+ unsigned planemask)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int cmd;
+ int mix;
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+ | BCI_CMD_CLIP_LR
+ | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO;
+
+ mix = SavageHelpPatternROP( pScrn, &fg, &bg, planemask, &rop );
+
+ if( mix & ROP_PAT )
+ cmd |= BCI_CMD_SEND_COLOR;
+
+ BCI_CMD_SET_ROP( cmd, rop );
+
+ if (bg != -1)
+ cmd |= BCI_CMD_SEND_COLOR;
+ else
+ cmd |= BCI_CMD_SRC_TRANSPARENT;
+
+ psav->SavedBciCmd = cmd;
+ psav->SavedFgColor = fg;
+ psav->SavedBgColor = bg;
+}
+
+
+static void
+SavageSubsequentScanlineCPUToScreenColorExpandFill(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ int skipleft)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+
+ /* XAA will be sending bitmap data next. */
+ /* We should probably wait for empty/idle here. */
+
+ psav->WaitQueue(psav,20);
+
+ BCI_SEND(psav->SavedBciCmd);
+ BCI_SEND(BCI_CLIP_LR(x+skipleft, x+w-1));
+ w = (w + 31) & ~31;
+ if( psav->SavedBciCmd & BCI_CMD_SEND_COLOR )
+ BCI_SEND(psav->SavedFgColor);
+ if( psav->SavedBgColor != -1 )
+ BCI_SEND(psav->SavedBgColor);
+ BCI_SEND(BCI_X_Y(x, y));
+ BCI_SEND(BCI_W_H(w, 1));
+
+ psav->Rect.x = x;
+ psav->Rect.y = y + 1;
+ psav->Rect.width = w;
+ psav->Rect.height = h - 1;
+}
+
+static void
+SavageSubsequentColorExpandScanline(
+ ScrnInfoPtr pScrn,
+ int buffer_no)
+{
+ /* This gets call after each scanline's image data has been sent. */
+ SavagePtr psav = SAVPTR(pScrn);
+ xRectangle xr = psav->Rect;
+ BCI_GET_PTR;
+
+ if( xr.height )
+ {
+ psav->WaitQueue(psav,20);
+ BCI_SEND(BCI_X_Y( xr.x, xr.y));
+ BCI_SEND(BCI_W_H( xr.width, 1 ));
+ psav->Rect.height--;
+ psav->Rect.y++;
+ }
+}
+
+
+/*
+ * The meaning of the two pattern paremeters to Setup & Subsequent for
+ * Mono8x8Patterns varies depending on the flag bits. We specify
+ * HW_PROGRAMMED_BITS, which means our hardware can handle 8x8 patterns
+ * without caching in the frame buffer. Thus, Setup gets the pattern bits.
+ * There is no way with BCI to rotate an 8x8 pattern, so we do NOT specify
+ * HW_PROGRAMMED_ORIGIN. XAA wil rotate it for us and pass the rotated
+ * pattern to both Setup and Subsequent. If we DID specify PROGRAMMED_ORIGIN,
+ * then Setup would get the unrotated pattern, and Subsequent gets the
+ * origin values.
+ */
+
+static void
+SavageSetupForMono8x8PatternFill(
+ ScrnInfoPtr pScrn,
+ int patternx,
+ int patterny,
+ int fg,
+ int bg,
+ int rop,
+ unsigned planemask)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int cmd;
+ int mix;
+
+ mix = XAAHelpPatternROP( pScrn, &fg, &bg, planemask, &rop );
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+ | BCI_CMD_DEST_GBD;
+
+ if( mix & ROP_PAT )
+ cmd |= BCI_CMD_SEND_COLOR | BCI_CMD_PAT_MONO;
+
+ if (bg == -1)
+ cmd |= BCI_CMD_PAT_TRANSPARENT;
+
+ BCI_CMD_SET_ROP(cmd, rop);
+
+ psav->SavedBciCmd = cmd;
+ psav->SavedFgColor = fg;
+ psav->SavedBgColor = bg;
+}
+
+
+static void
+SavageSubsequentMono8x8PatternFillRect(
+ ScrnInfoPtr pScrn,
+ int pattern0,
+ int pattern1,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+
+ /*
+ * I didn't think it was my job to do trivial rejection, but
+ * miFillGeneralPolygon definitely generates null spans, and XAA
+ * just passes them through.
+ */
+
+ if( !w || !h )
+ return;
+
+ psav->WaitQueue(psav,7);
+ BCI_SEND(psav->SavedBciCmd);
+ if( psav->SavedBciCmd & BCI_CMD_SEND_COLOR )
+ BCI_SEND(psav->SavedFgColor);
+ if( psav->SavedBgColor != -1 )
+ BCI_SEND(psav->SavedBgColor);
+ BCI_SEND(BCI_X_Y(x, y));
+ BCI_SEND(BCI_W_H(w, h));
+ if( psav->SavedBciCmd & BCI_CMD_PAT_MONO )
+ {
+ BCI_SEND(pattern0);
+ BCI_SEND(pattern1);
+ }
+}
+
+
+static void
+SavageSetupForColor8x8PatternFill(
+ ScrnInfoPtr pScrn,
+ int patternx,
+ int patterny,
+ int rop,
+ unsigned planemask,
+ int trans_col)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+
+ int cmd;
+ int mix;
+ unsigned int bd;
+ int pat_offset;
+
+ /* ViRGEs and Savages do not support transparent color patterns. */
+ /* We set the NO_TRANSPARENCY bit, so we should never receive one. */
+
+ pat_offset = (int) (patternx * psav->Bpp + patterny * psav->Bpl);
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+ | BCI_CMD_DEST_GBD | BCI_CMD_PAT_PBD_COLOR_NEW;
+
+ mix = XAAHelpSolidROP( pScrn, &trans_col, planemask, &rop );
+
+ BCI_CMD_SET_ROP(cmd, rop);
+ bd = BCI_BD_BW_DISABLE;
+ BCI_BD_SET_BPP(bd, pScrn->bitsPerPixel);
+ BCI_BD_SET_STRIDE(bd, 8);
+
+ psav->SavedBciCmd = cmd;
+ psav->SavedSbdOffset = pat_offset;
+ psav->SavedSbd = bd;
+ psav->SavedBgColor = trans_col;
+}
+
+
+static void
+SavageSubsequentColor8x8PatternFillRect(
+ ScrnInfoPtr pScrn,
+ int patternx,
+ int patterny,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+
+ if( !w || !h )
+ return;
+
+ psav->WaitQueue(psav,6);
+ BCI_SEND(psav->SavedBciCmd);
+ BCI_SEND(psav->SavedSbdOffset);
+ BCI_SEND(psav->SavedSbd);
+ BCI_SEND(BCI_X_Y(patternx,patterny));
+ BCI_SEND(BCI_X_Y(x, y));
+ BCI_SEND(BCI_W_H(w, h));
+}
+
+
+static void
+SavageSubsequentSolidBresenhamLine(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int e1,
+ int e2,
+ int err,
+ int length,
+ int octant)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+ int cmd;
+
+ cmd = (psav->SavedBciCmd & 0x00ffffff);
+ cmd |= BCI_CMD_LINE_LAST_PIXEL;
+
+#ifdef DEBUG_EXTRA
+ ErrorF("BresenhamLine, (%4d,%4d), len %4d, oct %d, err %4d,%4d,%4d clr %08x\n",
+ x1, y1, length, octant, e1, e2, err, psav->SavedFgColor );
+#endif
+
+ psav->WaitQueue(psav, 5 );
+ BCI_SEND(cmd);
+ if( cmd & BCI_CMD_SEND_COLOR )
+ BCI_SEND( psav->SavedFgColor );
+ BCI_SEND(BCI_LINE_X_Y(x1, y1));
+ BCI_SEND(BCI_LINE_STEPS(e2-e1, e2));
+ BCI_SEND(BCI_LINE_MISC(length,
+ (octant & YMAJOR),
+ !(octant & XDECREASING),
+ !(octant & YDECREASING),
+ e2+err));
+}
+
+
+static void
+SavageSubsequentSolidTwoPointLine(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int bias)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+
+ int cmd;
+ int dx, dy;
+ int min, max, xp, yp, ym;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+#ifdef DEBUG_EXTRA
+ ErrorF("TwoPointLine, (%4d,%4d)-(%4d,%4d), clr %08x, last pt %s\n",
+ x1, y1, x2, y2, psav->SavedFgColor, (bias & 0x100)?"NO ":"YES");
+#endif
+
+ xp = (dx >= 0);
+ if( !xp ) {
+ dx = -dx;
+ }
+
+ yp = (dy >= 0);
+ if( !yp ) {
+ dy = -dy;
+ }
+
+ ym = (dy > dx);
+ if( ym ) {
+ max = dy;
+ min = dx;
+ }
+ else {
+ max = dx;
+ min = dy;
+ }
+
+ if( !(bias & 0x100) ) {
+ max++;
+ }
+
+ cmd = (psav->SavedBciCmd & 0x00ffffff);
+ cmd |= BCI_CMD_LINE_LAST_PIXEL;
+
+ psav->WaitQueue(psav,5);
+ BCI_SEND( cmd );
+ if( cmd & BCI_CMD_SEND_COLOR )
+ BCI_SEND( psav->SavedFgColor );
+ BCI_SEND( BCI_LINE_X_Y( x1, y1 ) );
+ BCI_SEND( BCI_LINE_STEPS( 2 * (min - max), 2 * min ) );
+ BCI_SEND( BCI_LINE_MISC( max, ym, xp, yp, 2 * min - max ) );
+}
+
+
+
+static void
+SavageSetClippingRectangle(
+ ScrnInfoPtr pScrn,
+ int x1,
+ int y1,
+ int x2,
+ int y2)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+ int cmd;
+
+#ifdef DEBUG_EXTRA
+ ErrorF("ClipRect, (%4d,%4d)-(%4d,%4d) \n", x1, y1, x2, y2 );
+#endif
+
+ cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
+ psav->WaitQueue(psav,3);
+ BCI_SEND(cmd);
+ BCI_SEND(BCI_CLIP_TL(y1, x1));
+ BCI_SEND(BCI_CLIP_BR(y2, x2));
+ psav->SavedBciCmd |= BCI_CMD_CLIP_CURRENT;
+}
+
+
+static void SavageDisableClipping( ScrnInfoPtr pScrn )
+{
+ SavagePtr psav = SAVPTR(pScrn);
+#ifdef DEBUG_EXTRA
+ ErrorF("Kill ClipRect\n");
+#endif
+ psav->SavedBciCmd &= ~BCI_CMD_CLIP_CURRENT;
+}
+
+
+/* Routines for debugging. */
+
+
+unsigned long
+writedw( unsigned long addr, unsigned long value )
+{
+ SavagePtr psav = SAVPTR(gpScrn);
+ OUTREG( addr, value );
+ return INREG( addr );
+}
+
+unsigned long
+readdw( unsigned long addr )
+{
+ SavagePtr psav = SAVPTR(gpScrn);
+ return INREG( addr );
+}
+
+unsigned long
+readfb( unsigned long addr )
+{
+ SavagePtr psav = SAVPTR(gpScrn);
+ char * videobuffer = (char *) psav->FBBase;
+ return *(volatile unsigned long*)(videobuffer + (addr & ~3) );
+}
+
+unsigned long
+writefb( unsigned long addr, unsigned long value )
+{
+ SavagePtr psav = SAVPTR(gpScrn);
+ char * videobuffer = (char *) psav->FBBase;
+ *(unsigned long*)(videobuffer + (addr & ~3)) = value;
+ return *(volatile unsigned long*)(videobuffer + (addr & ~3) );
+}
+
+void
+writescan( unsigned long scan, unsigned long color )
+{
+ SavagePtr psav = SAVPTR(gpScrn);
+ int i;
+ char * videobuffer = (char *)psav->FBBase;
+ videobuffer += scan * gpScrn->displayWidth * gpScrn->bitsPerPixel >> 3;
+ for( i = gpScrn->displayWidth; --i; ) {
+ switch( gpScrn->bitsPerPixel ) {
+ case 8:
+ *videobuffer++ = color;
+ break;
+ case 16:
+ *(CARD16 *)videobuffer = color;
+ videobuffer += 2;
+ break;
+ case 32:
+ *(CARD32 *)videobuffer = color;
+ videobuffer += 4;
+ break;
+ }
+ }
+}
diff --git a/src/savage_bci.h b/src/savage_bci.h
new file mode 100644
index 0000000..0d7c489
--- /dev/null
+++ b/src/savage_bci.h
@@ -0,0 +1,97 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_bci.h,v 1.4 2002/10/02 20:39:54 alanh Exp $ */
+
+#ifndef _S3BCI_H_
+#define _S3BCI_H_
+
+#define REVERSE_BYTE_ORDER32(dword) {\
+ unsigned int temp; \
+ dword = (temp & 0xFF) << 24; \
+ dword |= (temp & 0xFF00) << 8; \
+ dword |= (temp & 0xFF0000) >> 8; \
+ dword |= (temp & 0xFF000000) >> 24; }
+
+#define BCI_GET_PTR volatile unsigned int * bci_ptr = (unsigned int *) psav->BciMem
+#define BCI_RESET bci_ptr = (unsigned int *) psav->BciMem
+
+#define BCI_SEND(dw) (*bci_ptr++ = (unsigned int)(dw))
+
+#define BCI_CMD_NOP 0x40000000
+#define BCI_CMD_RECT 0x48000000
+#define BCI_CMD_RECT_XP 0x01000000
+#define BCI_CMD_RECT_YP 0x02000000
+#define BCI_CMD_SCANLINE 0x50000000
+#define BCI_CMD_LINE 0x5C000000
+#define BCI_CMD_LINE_LAST_PIXEL 0x58000000
+#define BCI_CMD_BYTE_TEXT 0x63000000
+#define BCI_CMD_NT_BYTE_TEXT 0x67000000
+#define BCI_CMD_BIT_TEXT 0x6C000000
+#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF)
+#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16))
+#define BCI_CMD_SEND_COLOR 0x00008000
+
+#define BCI_CMD_CLIP_NONE 0x00000000
+#define BCI_CMD_CLIP_CURRENT 0x00002000
+#define BCI_CMD_CLIP_LR 0x00004000
+#define BCI_CMD_CLIP_NEW 0x00006000
+
+#define BCI_CMD_DEST_GBD 0x00000000
+#define BCI_CMD_DEST_PBD 0x00000800
+#define BCI_CMD_DEST_PBD_NEW 0x00000C00
+#define BCI_CMD_DEST_SBD 0x00001000
+#define BCI_CMD_DEST_SBD_NEW 0x00001400
+
+#define BCI_CMD_SRC_TRANSPARENT 0x00000200
+#define BCI_CMD_SRC_SOLID 0x00000000
+#define BCI_CMD_SRC_GBD 0x00000020
+#define BCI_CMD_SRC_COLOR 0x00000040
+#define BCI_CMD_SRC_MONO 0x00000060
+#define BCI_CMD_SRC_PBD_COLOR 0x00000080
+#define BCI_CMD_SRC_PBD_MONO 0x000000A0
+#define BCI_CMD_SRC_PBD_COLOR_NEW 0x000000C0
+#define BCI_CMD_SRC_PBD_MONO_NEW 0x000000E0
+#define BCI_CMD_SRC_SBD_COLOR 0x00000100
+#define BCI_CMD_SRC_SBD_MONO 0x00000120
+#define BCI_CMD_SRC_SBD_COLOR_NEW 0x00000140
+#define BCI_CMD_SRC_SBD_MONO_NEW 0x00000160
+
+#define BCI_CMD_PAT_TRANSPARENT 0x00000010
+#define BCI_CMD_PAT_NONE 0x00000000
+#define BCI_CMD_PAT_COLOR 0x00000002
+#define BCI_CMD_PAT_MONO 0x00000003
+#define BCI_CMD_PAT_PBD_COLOR 0x00000004
+#define BCI_CMD_PAT_PBD_MONO 0x00000005
+#define BCI_CMD_PAT_PBD_COLOR_NEW 0x00000006
+#define BCI_CMD_PAT_PBD_MONO_NEW 0x00000007
+#define BCI_CMD_PAT_SBD_COLOR 0x00000008
+#define BCI_CMD_PAT_SBD_MONO 0x00000009
+#define BCI_CMD_PAT_SBD_COLOR_NEW 0x0000000A
+#define BCI_CMD_PAT_SBD_MONO_NEW 0x0000000B
+
+#define BCI_BD_BW_DISABLE 0x10000000
+#define BCI_BD_TILE_MASK 0x03000000
+#define BCI_BD_TILE_NONE 0x00000000
+#define BCI_BD_TILE_16 0x02000000
+#define BCI_BD_TILE_32 0x04000000
+#define BCI_BD_GET_BPP(bd) (((bd) >> 16) & 0xFF)
+#define BCI_BD_SET_BPP(bd, bpp) ((bd) |= (((bpp) & 0xFF) << 16))
+#define BCI_BD_GET_STRIDE(bd) ((bd) & 0xFFFF)
+#define BCI_BD_SET_STRIDE(bd, st) ((bd) |= ((st) & 0xFFFF))
+
+#define BCI_W_H(w, h) ((((h) << 16) | (w)) & 0x0FFF0FFF)
+#define BCI_X_Y(x, y) ((((y) << 16) | (x)) & 0x0FFF0FFF)
+#define BCI_X_W(x, y) ((((w) << 16) | (x)) & 0x0FFF0FFF)
+#define BCI_CLIP_LR(l, r) ((((r) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_TL(t, l) ((((t) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_BR(b, r) ((((b) << 16) | (r)) & 0x0FFF0FFF)
+
+#define BCI_LINE_X_Y(x, y) (((y) << 16) | ((x) & 0xFFFF))
+#define BCI_LINE_STEPS(diag, axi) (((axi) << 16) | ((diag) & 0xFFFF))
+#define BCI_LINE_MISC(maj, ym, xp, yp, err) \
+ (((maj) & 0x1FFF) | \
+ ((ym) ? 1<<13 : 0) | \
+ ((xp) ? 1<<14 : 0) | \
+ ((yp) ? 1<<15 : 0) | \
+ ((err) << 16))
+
+
+#endif /* _S3BCI_H_ */
diff --git a/src/savage_cursor.c b/src/savage_cursor.c
new file mode 100644
index 0000000..16aaabf
--- /dev/null
+++ b/src/savage_cursor.c
@@ -0,0 +1,299 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_cursor.c,v 1.9 2003/01/18 15:22:29 eich Exp $ */
+
+/*
+ * Hardware cursor support for S3 Savage 4.0 driver. Taken with
+ * very few changes from the s3virge cursor file.
+ *
+ * S. Marineau, 19/04/97.
+ * Modified by Amancio Hasty and Jon Tombs
+ * Ported to 4.0 by Tim Roberts.
+ */
+
+#include "savage_driver.h"
+
+static void SavageLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src);
+static void SavageSetCursorPosition(ScrnInfoPtr pScrn, int x, int y);
+static void SavageSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg);
+
+
+/*
+ * Read/write to the DAC via MMIO
+ */
+
+#define inCRReg(reg) (VGAHWPTR(pScrn))->readCrtc( VGAHWPTR(pScrn), reg )
+#define outCRReg(reg, val) (VGAHWPTR(pScrn))->writeCrtc( VGAHWPTR(pScrn), reg, val )
+#define inSRReg(reg) (VGAHWPTR(pScrn))->readSeq( VGAHWPTR(pScrn), reg )
+#define outSRReg(reg, val) (VGAHWPTR(pScrn))->writeSeq( VGAHWPTR(pScrn), reg, val )
+#define inStatus1() (VGAHWPTR(pScrn))->readST01( VGAHWPTR(pScrn) )
+
+/*
+ * certain HW cursor operations seem
+ * to require a delay to prevent lockups.
+ */
+#define waitHSync(n) { \
+ int num = n; \
+ while (num--) { \
+ while ((inStatus1()) & 0x01){};\
+ while (!(inStatus1()) & 0x01){};\
+ } \
+ }
+#define MAX_CURS 64
+
+/*
+ * Disable HW Cursor on stretched LCDs. We don't know how to
+ * detect if display is stretched. Therefore we cannot rescale
+ * the HW cursor position.
+ */
+
+static Bool
+SavageUseHWCursor(ScreenPtr pScr, CursorPtr pCurs)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScr->myNum];
+ SavagePtr psav = SAVPTR(pScrn);
+
+ if (psav->PanelX != pScrn->currentMode->HDisplay
+ || psav->PanelY != pScrn->currentMode->VDisplay) {
+ /* BIT 1 : CRT is active, BIT 2 : LCD is active */
+ unsigned char cr6d = inCRReg( 0x6d );
+ if (cr6d & 0x02)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+Bool
+SavageHWCursorInit(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ SavagePtr psav = SAVPTR(pScrn);
+ xf86CursorInfoPtr infoPtr;
+
+ infoPtr = xf86CreateCursorInfoRec();
+ if(!infoPtr)
+ return FALSE;
+
+ psav->CursorInfoRec = infoPtr;
+
+ infoPtr->MaxWidth = MAX_CURS;
+ infoPtr->MaxHeight = MAX_CURS;
+ infoPtr->Flags = HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
+ HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
+ HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
+ HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
+ HARDWARE_CURSOR_INVERT_MASK;
+
+ /*
+ * The /MX family is apparently unique among the Savages, in that
+ * the cursor color is always straight RGB. The rest of the Savages
+ * use palettized values at 8-bit when not clock doubled.
+ */
+
+ if(
+ ((psav->Chipset != S3_SAVAGE4)
+ && (inSRReg(0x18) & 0x80) && (inSRReg(0x15) & 0x50) )
+ ||
+ S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
+ )
+ infoPtr->Flags |= HARDWARE_CURSOR_TRUECOLOR_AT_8BPP;
+
+ infoPtr->SetCursorColors = SavageSetCursorColors;
+ infoPtr->SetCursorPosition = SavageSetCursorPosition;
+ infoPtr->LoadCursorImage = SavageLoadCursorImage;
+ infoPtr->HideCursor = SavageHideCursor;
+ infoPtr->ShowCursor = SavageShowCursor;
+
+ if ((S3_SAVAGE_MOBILE_SERIES(psav->Chipset)
+ || (psav->Chipset == S3_PROSAVAGE)) && !psav->CrtOnly)
+ infoPtr->UseHWCursor = SavageUseHWCursor;
+ else
+ infoPtr->UseHWCursor = NULL;
+ if( !psav->CursorKByte )
+ psav->CursorKByte = pScrn->videoRam - 4;
+
+ return xf86InitCursor(pScreen, infoPtr);
+}
+
+
+
+void
+SavageShowCursor(ScrnInfoPtr pScrn)
+{
+ /* Turn cursor on. */
+ outCRReg( 0x45, inCRReg(0x45) | 0x01 );
+ SAVPTR(pScrn)->hwc_on = TRUE;
+}
+
+
+void
+SavageHideCursor(ScrnInfoPtr pScrn)
+{
+ /* Turn cursor off. */
+ if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) )
+ {
+ waitHSync(5);
+ }
+ outCRReg( 0x45, inCRReg(0x45) & 0xfe );
+ SAVPTR(pScrn)->hwc_on = FALSE;
+}
+
+static void
+SavageLoadCursorImage(
+ ScrnInfoPtr pScrn,
+ unsigned char* src)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+
+ /* Set cursor location in frame buffer. */
+ outCRReg( 0x4d, (0xff & psav->CursorKByte));
+ outCRReg( 0x4c, (0xff00 & psav->CursorKByte) >> 8);
+
+ /* Upload the cursor image to the frame buffer. */
+ memcpy(psav->FBBase + psav->CursorKByte * 1024, src, 1024);
+
+ if( S3_SAVAGE4_SERIES( psav->Chipset ) ) {
+ /*
+ * Bug in Savage4 Rev B requires us to do an MMIO read after
+ * loading the cursor.
+ */
+ volatile unsigned int i = ALT_STATUS_WORD0;
+ (void)i; /* Not to be optimised out */
+ }
+}
+
+static void
+SavageSetCursorPosition(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y)
+{
+ unsigned char xoff, yoff;
+
+ if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) )
+ {
+ waitHSync(5);
+ }
+ /* adjust for frame buffer base address granularity */
+ if (pScrn->bitsPerPixel == 8)
+ x += ((pScrn->frameX0) & 3);
+ else if (pScrn->bitsPerPixel == 16)
+ x += ((pScrn->frameX0) & 1);
+ else if (pScrn->bitsPerPixel == 32)
+ x += ((pScrn->frameX0+2) & 3) - 2;
+
+ /*
+ * Make these even when used. There is a bug/feature on at least
+ * some chipsets that causes a "shadow" of the cursor in interlaced
+ * mode. Making this even seems to have no visible effect, so just
+ * do it for the generic case.
+ */
+
+ if (x < 0) {
+ xoff = ((-x) & 0xFE);
+ x = 0;
+ } else {
+ xoff = 0;
+ }
+
+ if (y < 0) {
+ yoff = ((-y) & 0xFE);
+ y = 0;
+ } else {
+ yoff = 0;
+ }
+
+ /* This is the recomended order to move the cursor */
+ outCRReg( 0x46, (x & 0xff00)>>8 );
+ outCRReg( 0x47, (x & 0xff) );
+ outCRReg( 0x49, (y & 0xff) );
+ outCRReg( 0x4e, xoff );
+ outCRReg( 0x4f, yoff );
+ outCRReg( 0x48, (y & 0xff00)>>8 );
+}
+
+
+static void
+SavageSetCursorColors(
+ ScrnInfoPtr pScrn,
+ int bg,
+ int fg)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ Bool bNeedExtra = FALSE;
+
+ /* Clock doubled modes need an extra cursor stack write. */
+
+ bNeedExtra =
+ (psav->CursorInfoRec->Flags & HARDWARE_CURSOR_TRUECOLOR_AT_8BPP);
+
+ if(
+ S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+ (pScrn->depth == 24) ||
+ ((pScrn->depth == 8) && bNeedExtra)
+ )
+ {
+ /* Do it straight, full 24 bit color. */
+
+ /* Reset the cursor color stack pointer */
+ inCRReg(0x45);
+ /* Write low, mid, high bytes - foreground */
+ outCRReg(0x4a, fg);
+ outCRReg(0x4a, fg >> 8);
+ outCRReg(0x4a, fg >> 16);
+ /* Reset the cursor color stack pointer */
+ inCRReg(0x45);
+ /* Write low, mid, high bytes - background */
+ outCRReg(0x4b, bg);
+ outCRReg(0x4b, bg >> 8);
+ outCRReg(0x4b, bg >> 16);
+ return;
+ }
+ else if( (pScrn->depth == 15) || (pScrn->depth == 16) )
+ {
+ if (pScrn->depth == 15) {
+ fg = ((fg & 0xf80000) >> 9) |
+ ((fg & 0xf800) >> 6) |
+ ((fg & 0xf8) >> 3);
+ bg = ((bg & 0xf80000) >> 9) |
+ ((bg & 0xf800) >> 6) |
+ ((bg & 0xf8) >> 3);
+ } else {
+ fg = ((fg & 0xf80000) >> 8) |
+ ((fg & 0xfc00) >> 5) |
+ ((fg & 0xf8) >> 3);
+ bg = ((bg & 0xf80000) >> 8) |
+ ((bg & 0xfc00) >> 5) |
+ ((bg & 0xf8) >> 3);
+ }
+ /* Reset the cursor color stack pointer */
+ inCRReg( 0x45 );
+ outCRReg( 0x4a, fg );
+ outCRReg( 0x4a, fg>>8 );
+ if( bNeedExtra )
+ {
+ outCRReg( 0x4a, fg );
+ outCRReg( 0x4a, fg>>8 );
+ }
+ /* Reset the cursor color stack pointer */
+ inCRReg( 0x45 );
+ outCRReg( 0x4b, bg );
+ outCRReg( 0x4b, bg>>8 );
+ if( bNeedExtra )
+ {
+ outCRReg( 0x4b, bg );
+ outCRReg( 0x4b, bg>>8 );
+ }
+ }
+ else if( pScrn->depth == 8 )
+ {
+ /* Reset the cursor color stack pointer */
+ inCRReg(0x45);
+ /* Write foreground */
+ outCRReg(0x4a, fg);
+ outCRReg(0x4a, fg);
+ /* Reset the cursor color stack pointer */
+ inCRReg(0x45);
+ /* Write background */
+ outCRReg(0x4b, bg);
+ outCRReg(0x4b, bg);
+ }
+}
diff --git a/src/savage_dga.c b/src/savage_dga.c
new file mode 100644
index 0000000..55f057e
--- /dev/null
+++ b/src/savage_dga.c
@@ -0,0 +1,397 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_dga.c,v 1.6 2003/01/18 15:22:29 eich Exp $ */
+
+/*
+Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the XFree86 Project shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the XFree86 Project.
+*/
+
+
+/*
+ * file: savage_dga.c
+ * ported from s3v, which was ported from mga
+ *
+ */
+
+
+#include "xaalocal.h"
+#include "savage_driver.h"
+#include "dgaproc.h"
+
+
+Bool SavageDGAInit(ScreenPtr pScreen);
+static Bool Savage_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **,
+ int *, int *, int *);
+static Bool Savage_SetMode(ScrnInfoPtr, DGAModePtr);
+static int Savage_GetViewport(ScrnInfoPtr);
+static void Savage_SetViewport(ScrnInfoPtr, int, int, int);
+static void Savage_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
+static void Savage_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
+
+
+static
+DGAFunctionRec Savage_DGAFuncs = {
+ Savage_OpenFramebuffer,
+ NULL, /* CloseFrameBuffer */
+ Savage_SetMode,
+ Savage_SetViewport,
+ Savage_GetViewport,
+ SavageAccelSync,
+ Savage_FillRect,
+ Savage_BlitRect,
+ NULL /* BlitTransRect */
+};
+
+#define DGATRACE 4
+
+/*
+ * I don't understand the thinking here. As near as I can tell, we are
+ * never asked to change into a depth other than the frame buffer depth.
+ * So why create modes to do so?
+ */
+
+static DGAModePtr
+SavageSetupDGAMode(
+ ScrnInfoPtr pScrn,
+ DGAModePtr modes,
+ int *num,
+ int bitsPerPixel,
+ int depth,
+ Bool pixmap,
+ int secondPitch,
+ unsigned long red,
+ unsigned long green,
+ unsigned long blue,
+ short visualClass
+)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ DGAModePtr mode, newmodes = NULL;
+ DisplayModePtr pMode, firstMode;
+ int otherPitch, Bpp = bitsPerPixel >> 3;
+ Bool oneMore;
+
+ xf86ErrorFVerb(DGATRACE, " SavageSetupDGAMode\n");
+
+ pMode = firstMode = pScrn->modes;
+
+ /*
+ * DGA 1.0 would only provide modes where the depth and stride
+ * matched the current desktop. Some DGA apps might still expect
+ * this, so we provide them, too.
+ */
+
+ while(pMode) {
+
+ otherPitch = secondPitch ? secondPitch : pMode->HDisplay;
+
+ if(pMode->HDisplay != otherPitch) {
+ newmodes = xrealloc(modes, (*num + 2) * sizeof(DGAModeRec));
+ oneMore = TRUE;
+ } else {
+ newmodes = xrealloc(modes, (*num + 1) * sizeof(DGAModeRec));
+ oneMore = FALSE;
+ }
+
+ if(!newmodes) {
+ xfree(modes);
+ return NULL;
+ }
+ modes = newmodes;
+
+SECOND_PASS:
+
+ mode = modes + *num;
+ (*num)++;
+
+ mode->mode = pMode;
+ mode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
+ if(!psav->NoAccel)
+ mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
+ if(pMode->Flags & V_DBLSCAN)
+ mode->flags |= DGA_DOUBLESCAN;
+ if(pMode->Flags & V_INTERLACE)
+ mode->flags |= DGA_INTERLACED;
+ mode->byteOrder = pScrn->imageByteOrder;
+ mode->depth = depth;
+ mode->bitsPerPixel = bitsPerPixel;
+ mode->red_mask = red;
+ mode->green_mask = green;
+ mode->blue_mask = blue;
+ mode->visualClass = visualClass;
+ mode->viewportWidth = pMode->HDisplay;
+ mode->viewportHeight = pMode->VDisplay;
+ mode->xViewportStep = 2;
+ mode->yViewportStep = 1;
+ mode->viewportFlags = DGA_FLIP_RETRACE;
+ mode->offset = 0;
+ mode->address = psav->FBBase;
+
+ xf86ErrorFVerb(DGATRACE,
+ "SavageDGAInit vpWid=%d, vpHgt=%d, Bpp=%d, mdbitsPP=%d\n",
+ mode->viewportWidth,
+ mode->viewportHeight,
+ Bpp,
+ mode->bitsPerPixel
+ );
+
+ if(oneMore) { /* first one is narrow width */
+ /* Force stride to multiple of 16 pixels. */
+ mode->bytesPerScanline = ((pMode->HDisplay + 15) & ~15) * Bpp;
+ mode->imageWidth = pMode->HDisplay;
+ mode->imageHeight = pMode->VDisplay;
+ mode->pixmapWidth = mode->imageWidth;
+ mode->pixmapHeight = mode->imageHeight;
+ mode->maxViewportX = mode->imageWidth - mode->viewportWidth;
+ /* this might need to get clamped to some maximum */
+ mode->maxViewportY = mode->imageHeight - mode->viewportHeight;
+ oneMore = FALSE;
+
+ xf86ErrorFVerb(DGATRACE,
+ "SavageDGAInit 1 imgHgt=%d, stride=%d\n",
+ mode->imageHeight,
+ mode->bytesPerScanline );
+
+ goto SECOND_PASS;
+ } else {
+ mode->bytesPerScanline = ((pScrn->displayWidth + 15) & ~15) * Bpp;
+ mode->imageWidth = pScrn->displayWidth;
+ mode->imageHeight = psav->videoRambytes / mode->bytesPerScanline;
+ mode->pixmapWidth = mode->imageWidth;
+ mode->pixmapHeight = mode->imageHeight;
+ mode->maxViewportX = mode->imageWidth - mode->viewportWidth;
+ /* this might need to get clamped to some maximum */
+ mode->maxViewportY = mode->imageHeight - mode->viewportHeight;
+
+ xf86ErrorFVerb(DGATRACE,
+ "SavageDGAInit 2 imgHgt=%d, stride=%d\n",
+ mode->imageHeight,
+ mode->bytesPerScanline );
+ }
+
+ pMode = pMode->next;
+ if(pMode == firstMode)
+ break;
+ }
+
+ return modes;
+}
+
+
+Bool
+SavageDGAInit(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ SavagePtr psav = SAVPTR(pScrn);
+ DGAModePtr modes = NULL;
+ int num = 0;
+
+ xf86ErrorFVerb(DGATRACE, " SavageDGAInit\n");
+
+ /* 8 */
+ modes = SavageSetupDGAMode (pScrn, modes, &num, 8, 8,
+ (pScrn->bitsPerPixel == 8),
+ (pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth,
+ 0, 0, 0, PseudoColor);
+
+ /* 15 */
+ modes = SavageSetupDGAMode (pScrn, modes, &num, 16, 15,
+ (pScrn->bitsPerPixel == 16),
+ (pScrn->depth != 15) ? 0 : pScrn->displayWidth,
+ 0x7c00, 0x03e0, 0x001f, TrueColor);
+
+ modes = SavageSetupDGAMode (pScrn, modes, &num, 16, 15,
+ (pScrn->bitsPerPixel == 16),
+ (pScrn->depth != 15) ? 0 : pScrn->displayWidth,
+ 0x7c00, 0x03e0, 0x001f, DirectColor);
+
+ /* 16 */
+ modes = SavageSetupDGAMode (pScrn, modes, &num, 16, 16,
+ (pScrn->bitsPerPixel == 16),
+ (pScrn->depth != 16) ? 0 : pScrn->displayWidth,
+ 0xf800, 0x07e0, 0x001f, TrueColor);
+
+ modes = SavageSetupDGAMode (pScrn, modes, &num, 16, 16,
+ (pScrn->bitsPerPixel == 16),
+ (pScrn->depth != 16) ? 0 : pScrn->displayWidth,
+ 0xf800, 0x07e0, 0x001f, DirectColor);
+
+ /* 24-in-32 */
+ modes = SavageSetupDGAMode (pScrn, modes, &num, 32, 24,
+ (pScrn->bitsPerPixel == 32),
+ (pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
+ 0xff0000, 0x00ff00, 0x0000ff, TrueColor);
+
+ modes = SavageSetupDGAMode (pScrn, modes, &num, 32, 24,
+ (pScrn->bitsPerPixel == 32),
+ (pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
+ 0xff0000, 0x00ff00, 0x0000ff, DirectColor);
+
+ psav->numDGAModes = num;
+ psav->DGAModes = modes;
+
+ return DGAInit(pScreen, &Savage_DGAFuncs, modes, num);
+}
+
+
+static Bool
+Savage_SetMode(
+ ScrnInfoPtr pScrn,
+ DGAModePtr pMode
+){
+ static int OldDisplayWidth[MAXSCREENS];
+ static int OldBitsPerPixel[MAXSCREENS];
+ static int OldDepth[MAXSCREENS];
+ static DisplayModePtr OldMode[MAXSCREENS];
+ int index = pScrn->pScreen->myNum;
+ SavagePtr psav = SAVPTR(pScrn);
+
+ if(!pMode) { /* restore the original mode */
+ /* put the ScreenParameters back */
+
+ pScrn->displayWidth = OldDisplayWidth[index];
+ pScrn->bitsPerPixel = OldBitsPerPixel[index];
+ pScrn->depth = OldDepth[index];
+ pScrn->currentMode = OldMode[index];
+
+ psav->DGAactive = FALSE;
+ SavageSwitchMode(index, pScrn->currentMode, 0);
+ if( psav->hwcursor && psav->hwc_on )
+ SavageShowCursor(pScrn);
+ } else {
+ Bool holdBIOS = psav->UseBIOS;
+
+#if 0
+ ErrorF(
+ "pScrn->bitsPerPixel %d, pScrn->depth %d\n",
+ pScrn->bitsPerPixel, pScrn->depth);
+ ErrorF(
+ " want bitsPerPixel %d, want depth %d\n",
+ pMode->bitsPerPixel, pMode->depth);
+#endif
+
+ if( psav->hwcursor && psav->hwc_on) {
+ SavageHideCursor(pScrn);
+ psav->hwc_on = TRUE; /* save for later restauration */
+ }
+
+
+ if(!psav->DGAactive) { /* save the old parameters */
+ OldDisplayWidth[index] = pScrn->displayWidth;
+ OldBitsPerPixel[index] = pScrn->bitsPerPixel;
+ OldDepth[index] = pScrn->depth;
+ OldMode[index] = pScrn->currentMode;
+
+ psav->DGAactive = TRUE;
+ }
+
+ pScrn->bitsPerPixel = pMode->bitsPerPixel;
+ pScrn->depth = pMode->depth;
+ pScrn->displayWidth = pMode->bytesPerScanline /
+ (pMode->bitsPerPixel >> 3);
+
+/* psav->UseBIOS = FALSE; */
+ SavageSwitchMode(index, pMode->mode, 0);
+ psav->UseBIOS = holdBIOS;
+ }
+
+ return TRUE;
+}
+
+
+static int
+Savage_GetViewport(
+ ScrnInfoPtr pScrn
+){
+ SavagePtr psav = SAVPTR(pScrn);
+ return psav->DGAViewportStatus;
+}
+
+
+static void
+Savage_SetViewport(
+ ScrnInfoPtr pScrn,
+ int x, int y,
+ int flags
+){
+ SavagePtr psav = SAVPTR(pScrn);
+
+ SavageAdjustFrame(pScrn->pScreen->myNum, x, y, flags);
+ psav->DGAViewportStatus = 0; /* MGAAdjustFrame loops until finished */
+}
+
+static void
+Savage_FillRect (
+ ScrnInfoPtr pScrn,
+ int x, int y, int w, int h,
+ unsigned long color
+){
+ SavagePtr psav = SAVPTR(pScrn);
+
+ if(psav->AccelInfoRec) {
+ (*psav->AccelInfoRec->SetupForSolidFill)(pScrn, color, GXcopy, ~0);
+ (*psav->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h);
+ SET_SYNC_FLAG(psav->AccelInfoRec);
+ }
+}
+
+static void
+Savage_BlitRect(
+ ScrnInfoPtr pScrn,
+ int srcx, int srcy,
+ int w, int h,
+ int dstx, int dsty
+){
+ SavagePtr psav = SAVPTR(pScrn);
+
+ if(psav->AccelInfoRec) {
+ int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
+ int ydir = (srcy < dsty) ? -1 : 1;
+
+ (*psav->AccelInfoRec->SetupForScreenToScreenCopy)(
+ pScrn, xdir, ydir, GXcopy, ~0, -1);
+ (*psav->AccelInfoRec->SubsequentScreenToScreenCopy)(
+ pScrn, srcx, srcy, dstx, dsty, w, h);
+ SET_SYNC_FLAG(psav->AccelInfoRec);
+ }
+}
+
+
+static Bool
+Savage_OpenFramebuffer(
+ ScrnInfoPtr pScrn,
+ char **name,
+ unsigned char **mem,
+ int *size,
+ int *offset,
+ int *flags
+){
+ SavagePtr psav = SAVPTR(pScrn);
+
+ *name = NULL; /* no special device */
+ *mem = (unsigned char*)psav->FrameBufferBase;
+ *size = psav->videoRambytes;
+ *offset = 0;
+ *flags = DGA_NEED_ROOT;
+
+ return TRUE;
+}
diff --git a/src/savage_driver.c b/src/savage_driver.c
new file mode 100644
index 0000000..cdfe256
--- /dev/null
+++ b/src/savage_driver.c
@@ -0,0 +1,3282 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_driver.c,v 1.34 2003/02/25 04:08:21 dawes Exp $ */
+/*
+ * vim: sw=4 ts=8 ai ic:
+ *
+ * XFree86 4.0 S3 Savage driver
+ *
+ * Tim Roberts <timr@probo.com>
+ * Ani Joshi <ajoshi@unixbox.com>
+ *
+ * TODO: add credits for the 3.3.x authors...
+ *
+ */
+
+
+#include "xf86RAC.h"
+#include "shadowfb.h"
+
+#include "globals.h"
+#define DPMS_SERVER
+#include "extensions/dpms.h"
+
+#ifdef XvExtension
+#include "xf86xv.h"
+#endif
+
+#include "savage_driver.h"
+#include "savage_bci.h"
+
+
+
+
+/*
+ * prototypes
+ */
+static void SavageEnableMMIO(ScrnInfoPtr pScrn);
+static void SavageDisableMMIO(ScrnInfoPtr pScrn);
+
+static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid);
+static void SavageIdentify(int flags);
+static Bool SavageProbe(DriverPtr drv, int flags);
+static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags);
+
+static Bool SavageEnterVT(int scrnIndex, int flags);
+static void SavageLeaveVT(int scrnIndex, int flags);
+static void SavageSave(ScrnInfoPtr pScrn);
+static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr, SavageRegPtr, Bool);
+
+static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
+ char **argv);
+static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen);
+static ModeStatus SavageValidMode(int index, DisplayModePtr mode,
+ Bool verbose, int flags);
+
+void SavageDGAInit(ScreenPtr);
+static Bool SavageMapMMIO(ScrnInfoPtr pScrn);
+static Bool SavageMapFB(ScrnInfoPtr pScrn);
+static void SavageUnmapMem(ScrnInfoPtr pScrn, int All);
+static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
+static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen);
+static Bool SavageSaveScreen(ScreenPtr pScreen, int mode);
+static void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors,
+ int *indicies, LOCO *colors,
+ VisualPtr pVisual);
+static void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors,
+ int *indicies, LOCO *colors,
+ VisualPtr pVisual);
+static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
+ int min_n2, int max_n2, long freq_min,
+ long freq_max, unsigned int *mdiv,
+ unsigned int *ndiv, unsigned int *r);
+void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file);
+void SavagePrintRegs(ScrnInfoPtr pScrn);
+static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags);
+static Bool SavageDDC1(int scrnIndex);
+static unsigned int SavageDDC1Read(ScrnInfoPtr pScrn);
+static void SavageProbeDDC(ScrnInfoPtr pScrn, int index);
+static void SavageGetTvMaxSize(SavagePtr psav);
+static Bool SavagePanningCheck(ScrnInfoPtr pScrn);
+
+extern ScrnInfoPtr gpScrn;
+
+#define iabs(a) ((int)(a)>0?(a):(-(a)))
+
+#define DRIVER_NAME "savage"
+#define DRIVER_VERSION "1.1.26"
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 1
+#define PATCHLEVEL 26
+#define SAVAGE_VERSION ((VERSION_MAJOR << 24) | \
+ (VERSION_MINOR << 16) | \
+ PATCHLEVEL)
+
+
+/*#define TRACEON*/
+#ifdef TRACEON
+#define TRACE(prms) ErrorF prms
+#else
+#define TRACE(prms)
+#endif
+
+DriverRec SAVAGE =
+{
+ SAVAGE_VERSION,
+ DRIVER_NAME,
+ SavageIdentify,
+ SavageProbe,
+ SavageAvailableOptions,
+ NULL,
+ 0
+};
+
+
+/* Supported chipsets */
+
+static SymTabRec SavageChips[] = {
+ { PCI_CHIP_SAVAGE4, "Savage4" },
+ { PCI_CHIP_SAVAGE3D, "Savage3D" },
+ { PCI_CHIP_SAVAGE3D_MV, "Savage3D-MV" },
+ { PCI_CHIP_SAVAGE2000, "Savage2000" },
+ { PCI_CHIP_SAVAGE_MX_MV, "Savage/MX-MV" },
+ { PCI_CHIP_SAVAGE_MX, "Savage/MX" },
+ { PCI_CHIP_SAVAGE_IX_MV, "Savage/IX-MV" },
+ { PCI_CHIP_SAVAGE_IX, "Savage/IX" },
+ { PCI_CHIP_PROSAVAGE_PM, "ProSavage PM133" },
+ { PCI_CHIP_PROSAVAGE_KM, "ProSavage KM133" },
+ { PCI_CHIP_S3TWISTER_P, "ProSavage PN133" },
+ { PCI_CHIP_S3TWISTER_K, "ProSavage KN133" },
+ { PCI_CHIP_SUPSAV_MX128, "SuperSavage/MX 128" },
+ { PCI_CHIP_SUPSAV_MX64, "SuperSavage/MX 64" },
+ { PCI_CHIP_SUPSAV_MX64C, "SuperSavage/MX 64C" },
+ { PCI_CHIP_SUPSAV_IX128SDR, "SuperSavage/IX 128" },
+ { PCI_CHIP_SUPSAV_IX128DDR, "SuperSavage/IX 128" },
+ { PCI_CHIP_SUPSAV_IX64SDR, "SuperSavage/IX 64" },
+ { PCI_CHIP_SUPSAV_IX64DDR, "SuperSavage/IX 64" },
+ { PCI_CHIP_SUPSAV_IXCSDR, "SuperSavage/IXC 64" },
+ { PCI_CHIP_SUPSAV_IXCDDR, "SuperSavage/IXC 64" },
+ { PCI_CHIP_PROSAVAGE_DDR, "ProSavage DDR" },
+ { PCI_CHIP_PROSAVAGE_DDRK, "ProSavage DDR-K" },
+ { -1, NULL }
+};
+
+static SymTabRec SavageChipsets[] = {
+ { S3_SAVAGE3D, "Savage3D" },
+ { S3_SAVAGE4, "Savage4" },
+ { S3_SAVAGE2000, "Savage2000" },
+ { S3_SAVAGE_MX, "MobileSavage" },
+ { S3_PROSAVAGE, "ProSavage" },
+ { S3_SUPERSAVAGE, "SuperSavage" },
+ { -1, NULL }
+};
+
+/* This table maps a PCI device ID to a chipset family identifier. */
+
+static PciChipsets SavagePciChipsets[] = {
+ { S3_SAVAGE3D, PCI_CHIP_SAVAGE3D, RES_SHARED_VGA },
+ { S3_SAVAGE3D, PCI_CHIP_SAVAGE3D_MV, RES_SHARED_VGA },
+ { S3_SAVAGE4, PCI_CHIP_SAVAGE4, RES_SHARED_VGA },
+ { S3_SAVAGE2000, PCI_CHIP_SAVAGE2000, RES_SHARED_VGA },
+ { S3_SAVAGE_MX, PCI_CHIP_SAVAGE_MX_MV, RES_SHARED_VGA },
+ { S3_SAVAGE_MX, PCI_CHIP_SAVAGE_MX, RES_SHARED_VGA },
+ { S3_SAVAGE_MX, PCI_CHIP_SAVAGE_IX_MV, RES_SHARED_VGA },
+ { S3_SAVAGE_MX, PCI_CHIP_SAVAGE_IX, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_PROSAVAGE_PM, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_PROSAVAGE_KM, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_S3TWISTER_P, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_S3TWISTER_K, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_PROSAVAGE_DDR, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_PROSAVAGE_DDRK, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_MX128, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_MX64, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_MX64C, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX128SDR, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX128DDR, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX64SDR, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX64DDR, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IXCSDR, RES_SHARED_VGA },
+ { S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IXCDDR, RES_SHARED_VGA },
+ { -1, -1, RES_UNDEFINED }
+};
+
+typedef enum {
+ OPTION_PCI_BURST
+ ,OPTION_PCI_RETRY
+ ,OPTION_NOACCEL
+ ,OPTION_LCD_CENTER
+ ,OPTION_LCDCLOCK
+ ,OPTION_MCLK
+ ,OPTION_REFCLK
+ ,OPTION_SHOWCACHE
+ ,OPTION_SWCURSOR
+ ,OPTION_HWCURSOR
+ ,OPTION_SHADOW_FB
+ ,OPTION_ROTATE
+ ,OPTION_USEBIOS
+ ,OPTION_SHADOW_STATUS
+ ,OPTION_CRT_ONLY
+ ,OPTION_TV_ON
+ ,OPTION_TV_PAL
+ ,OPTION_FORCE_INIT
+} SavageOpts;
+
+
+static const OptionInfoRec SavageOptions[] =
+{
+ { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_HWCURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE },
+ { OPTION_USEBIOS, "UseBIOS", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_LCDCLOCK, "LCDClock", OPTV_FREQ, {0}, FALSE },
+ { OPTION_SHADOW_STATUS, "ShadowStatus", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_CRT_ONLY, "CrtOnly", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_TV_ON, "TvOn", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_TV_PAL, "PAL", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_FORCE_INIT,"ForceInit", OPTV_BOOLEAN, {0}, FALSE },
+ { -1, NULL, OPTV_NONE, {0}, FALSE }
+};
+
+
+static const char *vgaHWSymbols[] = {
+ "vgaHWBlankScreen",
+ "vgaHWCopyReg",
+ "vgaHWGetHWRec",
+ "vgaHWGetIOBase",
+ "vgaHWGetIndex",
+ "vgaHWInit",
+ "vgaHWLock",
+ "vgaHWProtect",
+ "vgaHWRestore",
+ "vgaHWSave",
+ "vgaHWSaveScreen",
+ "vgaHWSetMmioFuncs",
+ "vgaHWSetStdFuncs",
+ "vgaHWUnmapMem",
+ "vgaHWddc1SetSpeed",
+#if 0
+ "vgaHWFreeHWRec",
+ "vgaHWMapMem",
+ "vgaHWUnlock",
+#endif
+ NULL
+};
+
+static const char *ramdacSymbols[] = {
+ "xf86CreateCursorInfoRec",
+#if 0
+ "xf86DestroyCursorInfoRec",
+#endif
+ "xf86InitCursor",
+ NULL
+};
+
+static const char *vbeSymbols[] = {
+ "VBEInit",
+ "vbeDoEDID",
+#if 0
+ "vbeFree",
+#endif
+ NULL
+};
+
+static const char *vbeOptSymbols[] = {
+ "vbeModeInit",
+ "VBESetVBEMode",
+ "VBEGetVBEInfo",
+ "VBEFreeVBEInfo",
+ NULL
+};
+
+static const char *ddcSymbols[] = {
+ "xf86DoEDID_DDC1",
+ "xf86DoEDID_DDC2",
+ "xf86PrintEDID",
+ "xf86SetDDCproperties",
+ NULL
+};
+
+static const char *i2cSymbols[] = {
+ "xf86CreateI2CBusRec",
+ "xf86I2CBusInit",
+ NULL
+};
+
+static const char *xaaSymbols[] = {
+ "XAACopyROP",
+ "XAACopyROP_PM",
+ "XAACreateInfoRec",
+ "XAADestroyInfoRec",
+ "XAAFillSolidRects",
+ "XAAHelpPatternROP",
+ "XAAHelpSolidROP",
+ "XAAInit",
+ "XAAScreenIndex",
+ NULL
+};
+
+static const char *shadowSymbols[] = {
+ "ShadowFBInit",
+ NULL
+};
+
+static const char *int10Symbols[] = {
+ "xf86ExecX86int10",
+#if 0
+ "xf86FreeInt10",
+#endif
+ "xf86InitInt10",
+ "xf86Int10AllocPages",
+ "xf86Int10FreePages",
+ "xf86int10Addr",
+ NULL
+};
+
+static const char *fbSymbols[] = {
+ "fbPictureInit",
+ "fbScreenInit",
+ NULL
+};
+
+#ifdef XFree86LOADER
+
+static MODULESETUPPROTO(SavageSetup);
+
+static XF86ModuleVersionInfo SavageVersRec = {
+ "savage",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XF86_VERSION_CURRENT,
+ VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_VIDEODRV,
+ {0, 0, 0, 0}
+};
+
+XF86ModuleData savageModuleData = { &SavageVersRec, SavageSetup, NULL };
+
+static pointer SavageSetup(pointer module, pointer opts, int *errmaj,
+ int *errmin)
+{
+ static Bool setupDone = FALSE;
+
+ if (!setupDone) {
+ setupDone = TRUE;
+ xf86AddDriver(&SAVAGE, module, 0);
+ LoaderRefSymLists(vgaHWSymbols, fbSymbols, ramdacSymbols,
+ xaaSymbols, shadowSymbols, vbeSymbols, vbeOptSymbols,
+ int10Symbols, i2cSymbols, ddcSymbols, NULL);
+ return (pointer) 1;
+ } else {
+ if (errmaj)
+ *errmaj = LDR_ONCEONLY;
+ return NULL;
+ }
+}
+
+#endif /* XFree86LOADER */
+
+
+/*
+ * I'd rather have these wait macros be inline, but S3 has made it
+ * darned near impossible. The bit fields are in a different place in
+ * all three families, the status register has a different address in the
+ * three families, and even the idle vs busy sense flipped in the Sav2K.
+ */
+
+static void
+ResetBCI2K( SavagePtr psav )
+{
+ CARD32 cob = INREG( 0x48c18 );
+ /* if BCI is enabled and BCI is busy... */
+
+ if(
+ (cob & 0x00000008) &&
+ ! (ALT_STATUS_WORD0 & 0x00200000)
+ )
+ {
+ ErrorF( "Resetting BCI, stat = %08x...\n", ALT_STATUS_WORD0);
+ /* Turn off BCI */
+ OUTREG( 0x48c18, cob & ~8 );
+ usleep(10000);
+ /* Turn it back on */
+ OUTREG( 0x48c18, cob );
+ usleep(10000);
+ }
+}
+
+static Bool
+ShadowWait( SavagePtr psav )
+{
+ BCI_GET_PTR;
+ int loop = 0;
+
+ if( !psav->NoPCIRetry )
+ return 0;
+
+ psav->ShadowCounter = (psav->ShadowCounter + 1) & 0x7fff;
+ BCI_SEND( psav->dwBCIWait2DIdle );
+ BCI_SEND( 0x98000000 + psav->ShadowCounter );
+
+ while(
+ (psav->ShadowVirtual[1] & 0x7fff) != psav->ShadowCounter &&
+ (loop++ < MAXLOOP)
+ )
+ ;
+
+ return loop >= MAXLOOP;
+}
+
+static Bool
+ShadowWait1( SavagePtr psav, int v )
+{
+ return ShadowWait( psav );
+}
+
+
+/* Wait until "v" queue entries are free */
+
+static int
+WaitQueue3D( SavagePtr psav, int v )
+{
+ int loop = 0;
+ int slots = MAXFIFO - v;
+
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitQueue = ShadowWait1;
+ return ShadowWait(psav);
+ }
+ else
+ {
+ loop &= STATUS_WORD0;
+ while( ((STATUS_WORD0 & 0x0000ffff) > slots) && (loop++ < MAXLOOP))
+ ;
+ }
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitQueue4( SavagePtr psav, int v )
+{
+ int loop = 0;
+ int slots = MAXFIFO - v;
+
+ if( !psav->NoPCIRetry )
+ return 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitQueue = ShadowWait1;
+ return ShadowWait(psav);
+ }
+ else
+ while( ((ALT_STATUS_WORD0 & 0x001fffff) > slots) && (loop++ < MAXLOOP))
+ ;
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitQueue2K( SavagePtr psav, int v )
+{
+ int loop = 0;
+ int slots = MAXFIFO - v;
+
+ if( !psav->NoPCIRetry )
+ return 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitQueue = ShadowWait1;
+ return ShadowWait(psav);
+ }
+ else
+ while( ((ALT_STATUS_WORD0 & 0x000fffff) > slots) && (loop++ < MAXLOOP))
+ ;
+ if( loop >= MAXLOOP )
+ ResetBCI2K(psav);
+ return loop >= MAXLOOP;
+}
+
+/* Wait until GP is idle and queue is empty */
+
+static int
+WaitIdleEmpty3D(SavagePtr psav)
+{
+ int loop = 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitIdleEmpty = ShadowWait;
+ return ShadowWait(psav);
+ }
+ loop &= STATUS_WORD0;
+ while( ((STATUS_WORD0 & 0x0008ffff) != 0x80000) && (loop++ < MAXLOOP) )
+ ;
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitIdleEmpty4(SavagePtr psav)
+{
+ int loop = 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitIdleEmpty = ShadowWait;
+ return ShadowWait(psav);
+ }
+ while( ((ALT_STATUS_WORD0 & 0x00a1ffff) != 0x00a00000) && (loop++ < MAXLOOP) )
+ ;
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitIdleEmpty2K(SavagePtr psav)
+{
+ int loop = 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitIdleEmpty = ShadowWait;
+ return ShadowWait(psav);
+ }
+ loop &= ALT_STATUS_WORD0;
+ while( ((ALT_STATUS_WORD0 & 0x009fffff) != 0) && (loop++ < MAXLOOP) )
+ ;
+ if( loop >= MAXLOOP )
+ ResetBCI2K(psav);
+ return loop >= MAXLOOP;
+}
+
+/* Wait until GP is idle */
+
+static int
+WaitIdle3D(SavagePtr psav)
+{
+ int loop = 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitIdle = ShadowWait;
+ return ShadowWait(psav);
+ }
+ while( (!(STATUS_WORD0 & 0x00080000)) && (loop++ < MAXLOOP) )
+ ;
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitIdle4(SavagePtr psav)
+{
+ int loop = 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitIdle = ShadowWait;
+ return ShadowWait(psav);
+ }
+ while( (!(ALT_STATUS_WORD0 & 0x00800000)) && (loop++ < MAXLOOP) )
+ ;
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitIdle2K(SavagePtr psav)
+{
+ int loop = 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitIdle = ShadowWait;
+ return ShadowWait(psav);
+ }
+ loop &= ALT_STATUS_WORD0;
+ while( (ALT_STATUS_WORD0 & 0x00900000) && (loop++ < MAXLOOP) )
+ ;
+ return loop >= MAXLOOP;
+}
+
+
+static Bool SavageGetRec(ScrnInfoPtr pScrn)
+{
+ if (pScrn->driverPrivate)
+ return TRUE;
+
+ pScrn->driverPrivate = xnfcalloc(sizeof(SavageRec), 1);
+ return TRUE;
+}
+
+
+static void SavageFreeRec(ScrnInfoPtr pScrn)
+{
+ TRACE(( "SavageFreeRec(%x)\n", pScrn->driverPrivate ));
+ if (!pScrn->driverPrivate)
+ return;
+ xfree(pScrn->driverPrivate);
+ pScrn->driverPrivate = NULL;
+ SavageUnmapMem(pScrn, 1);
+}
+
+
+static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid)
+{
+ return SavageOptions;
+}
+
+
+static void SavageIdentify(int flags)
+{
+ xf86PrintChipsets("SAVAGE",
+ "driver (version " DRIVER_VERSION ") for S3 Savage chipsets",
+ SavageChips);
+}
+
+
+static Bool SavageProbe(DriverPtr drv, int flags)
+{
+ int i;
+ GDevPtr *devSections = NULL;
+ int *usedChips;
+ int numDevSections;
+ int numUsed;
+ Bool foundScreen = FALSE;
+
+ /* sanity checks */
+ if ((numDevSections = xf86MatchDevice("savage", &devSections)) <= 0)
+ return FALSE;
+ if (xf86GetPciVideoInfo() == NULL)
+ return FALSE;
+
+ numUsed = xf86MatchPciInstances("SAVAGE", PCI_VENDOR_S3,
+ SavageChipsets, SavagePciChipsets,
+ devSections, numDevSections, drv,
+ &usedChips);
+ if (devSections)
+ xfree(devSections);
+ devSections = NULL;
+ if (numUsed <= 0)
+ return FALSE;
+
+ if (flags & PROBE_DETECT)
+ foundScreen = TRUE;
+ else
+ for (i=0; i<numUsed; i++) {
+ ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
+
+ pScrn->driverVersion = (int)DRIVER_VERSION;
+ pScrn->driverName = DRIVER_NAME;
+ pScrn->name = "SAVAGE";
+ pScrn->Probe = SavageProbe;
+ pScrn->PreInit = SavagePreInit;
+ pScrn->ScreenInit = SavageScreenInit;
+ pScrn->SwitchMode = SavageSwitchMode;
+ pScrn->AdjustFrame = SavageAdjustFrame;
+ pScrn->EnterVT = SavageEnterVT;
+ pScrn->LeaveVT = SavageLeaveVT;
+ pScrn->FreeScreen = NULL;
+ pScrn->ValidMode = SavageValidMode;
+ foundScreen = TRUE;
+ xf86ConfigActivePciEntity(pScrn, usedChips[i], SavagePciChipsets,
+ NULL, NULL, NULL, NULL, NULL);
+ }
+
+ xfree(usedChips);
+ return foundScreen;
+}
+
+static int LookupChipID( PciChipsets* pset, int ChipID )
+{
+ /* Is there a function to do this for me? */
+ while( pset->numChipset >= 0 )
+ {
+ if( pset->PCIid == ChipID )
+ return pset->numChipset;
+ pset++;
+ }
+
+ return -1;
+}
+
+static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags)
+{
+ EntityInfoPtr pEnt;
+ SavagePtr psav;
+ MessageType from = X_DEFAULT;
+ int i;
+ ClockRangePtr clockRanges;
+ char *s = NULL;
+ unsigned char config1, m, n, n1, n2, sr8, cr66 = 0, tmp;
+ int mclk;
+ vgaHWPtr hwp;
+ int vgaCRIndex, vgaCRReg;
+ pointer ddc;
+
+ TRACE(("SavagePreInit(%d)\n", flags));
+
+ gpScrn = pScrn;
+
+ if (flags & PROBE_DETECT) {
+ SavageProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
+ return TRUE;
+ }
+
+ if (!xf86LoadSubModule(pScrn, "vgahw"))
+ return FALSE;
+
+ xf86LoaderReqSymLists(vgaHWSymbols, NULL);
+ if (!vgaHWGetHWRec(pScrn))
+ return FALSE;
+
+#if 0
+ /* Here we can alter the number of registers saved and restored by the
+ * standard vgaHWSave and Restore routines.
+ */
+ vgaHWSetRegCounts( pScrn, VGA_NUM_CRTC, VGA_NUM_SEQ, VGA_NUM_GFX, VGA_NUM_ATTR );
+#endif
+
+ pScrn->monitor = pScrn->confScreen->monitor;
+
+ /*
+ * We support depths of 8, 15, 16 and 24.
+ * We support bpp of 8, 16, and 32.
+ */
+
+ if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support32bppFb))
+ return FALSE;
+ else {
+ int requiredBpp;
+ int altBpp = 0;
+
+ switch (pScrn->depth) {
+ case 8:
+ case 16:
+ requiredBpp = pScrn->depth;
+ break;
+ case 15:
+ requiredBpp = 16;
+ break;
+ case 24:
+ requiredBpp = 32;
+ altBpp = 24;
+ break;
+
+ default:
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by this driver\n",
+ pScrn->depth);
+ return FALSE;
+ }
+
+ if(
+ (pScrn->bitsPerPixel != requiredBpp) &&
+ (pScrn->bitsPerPixel != altBpp)
+ ) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Depth %d must specify %d bpp; %d was given\n",
+ pScrn->depth, requiredBpp, pScrn->bitsPerPixel );
+ return FALSE;
+ }
+ }
+
+ xf86PrintDepthBpp(pScrn);
+
+ if (pScrn->depth > 8) {
+ rgb zeros = {0, 0, 0};
+
+ if (!xf86SetWeight(pScrn, zeros, zeros))
+ return FALSE;
+ else {
+ /* TODO check weight returned is supported */
+ ;
+ }
+ }
+
+ if (!xf86SetDefaultVisual(pScrn, -1)) {
+ return FALSE;
+ } else {
+ /* We don't currently support DirectColor at 16bpp */
+ if (pScrn->bitsPerPixel == 16 && 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;
+ }
+ }
+
+ pScrn->progClock = TRUE;
+
+ if (!SavageGetRec(pScrn))
+ return FALSE;
+ psav = SAVPTR(pScrn);
+
+ hwp = VGAHWPTR(pScrn);
+ vgaHWGetIOBase(hwp);
+ psav->vgaIOBase = hwp->IOBase;
+
+ xf86CollectOptions(pScrn, NULL);
+
+ if (pScrn->depth == 8)
+ pScrn->rgbBits = 8/*6*/;
+
+ if (!(psav->Options = xalloc(sizeof(SavageOptions))))
+ return FALSE;
+ memcpy(psav->Options, SavageOptions, sizeof(SavageOptions));
+ xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, psav->Options);
+
+ xf86GetOptValBool(psav->Options, OPTION_PCI_BURST, &psav->pci_burst);
+
+ if (psav->pci_burst) {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Option: pci_burst - PCI burst read enabled\n");
+ }
+
+ psav->NoPCIRetry = 1; /* default */
+ if (xf86ReturnOptValBool(psav->Options, OPTION_PCI_RETRY, FALSE)) {
+ if (xf86ReturnOptValBool(psav->Options, OPTION_PCI_BURST, FALSE)) {
+ psav->NoPCIRetry = 0;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
+ } else
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires \"pci_burst\"\n");
+ }
+
+ xf86GetOptValBool( psav->Options, OPTION_SHADOW_FB, &psav->shadowFB );
+ if (psav->shadowFB) {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: shadow FB enabled\n");
+ }
+
+ if ((s = xf86GetOptValString(psav->Options, OPTION_ROTATE))) {
+ if(!xf86NameCmp(s, "CW")) {
+ /* accel is disabled below for shadowFB */
+ psav->shadowFB = TRUE;
+ psav->rotate = 1;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Rotating screen clockwise - acceleration disabled\n");
+ } else if(!xf86NameCmp(s, "CCW")) {
+ psav->shadowFB = TRUE;
+ psav->rotate = -1;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen"
+ "counter clockwise - acceleration disabled\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
+ "value for Option \"Rotate\"\n", s);
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Valid options are \"CW\" or \"CCW\"\n");
+ }
+ }
+
+ if (xf86GetOptValBool(psav->Options, OPTION_NOACCEL, &psav->NoAccel))
+ xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+ "Option: NoAccel - Acceleration Disabled\n");
+
+ if (psav->shadowFB && !psav->NoAccel) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "HW acceleration not supported with \"shadowFB\".\n");
+ psav->NoAccel = TRUE;
+ }
+
+ if (pScrn->bitsPerPixel == 24 && !psav->NoAccel) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "HW acceleration not possible with depth 32 and bpp 24.\n");
+ psav->NoAccel = TRUE;
+ }
+
+
+ /*
+ * The SWCursor setting takes priority over HWCursor. The default
+ * if neither is specified is HW, unless ShadowFB is specified,
+ * then SW.
+ */
+
+ from = X_DEFAULT;
+ psav->hwcursor = psav->shadowFB ? FALSE : TRUE;
+ if (xf86GetOptValBool(psav->Options, OPTION_HWCURSOR, &psav->hwcursor))
+ from = X_CONFIG;
+ if (xf86ReturnOptValBool(psav->Options, OPTION_SWCURSOR, FALSE)) {
+ psav->hwcursor = FALSE;
+ from = X_CONFIG;
+ }
+ xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
+ psav->hwcursor ? "HW" : "SW");
+
+ from = X_DEFAULT;
+ psav->UseBIOS = TRUE;
+ if (xf86GetOptValBool(psav->Options, OPTION_USEBIOS, &psav->UseBIOS) )
+ from = X_CONFIG;
+ xf86DrvMsg(pScrn->scrnIndex, from, "%ssing video BIOS to set modes\n",
+ psav->UseBIOS ? "U" : "Not u" );
+
+ psav->LCDClock = 0.0;
+ if( xf86GetOptValFreq( psav->Options, OPTION_LCDCLOCK, OPTUNITS_MHZ, &psav->LCDClock ) )
+ xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+ "Option: LCDClock %1.2f MHz\n", psav->LCDClock );
+
+ if( xf86GetOptValBool( psav->Options, OPTION_SHADOW_STATUS, &psav->ShadowStatus))
+ xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+ "Option: ShadowStatus enabled\n" );
+
+
+ if( xf86GetOptValBool( psav->Options, OPTION_CRT_ONLY, &psav->CrtOnly))
+ xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+ "Option: CrtOnly enabled\n" );
+
+ if( xf86GetOptValBool( psav->Options, OPTION_TV_ON, &psav->TvOn)) {
+ psav->PAL = FALSE;
+ SavageGetTvMaxSize(psav);
+ }
+
+ if( xf86GetOptValBool( psav->Options, OPTION_TV_PAL, &psav->PAL)) {
+ SavageGetTvMaxSize(psav);
+ psav->TvOn = TRUE;
+ }
+
+ if( psav->TvOn )
+ xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+ "TV enabled in %s format\n",
+ psav->PAL ? "PAL" : "NTSC" );
+
+ psav->ForceInit = 0;
+ if( xf86GetOptValBool( psav->Options, OPTION_FORCE_INIT, &psav->ForceInit))
+ xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+ "Option: ForceInit enabled\n" );
+
+ /* Add more options here. */
+
+ if (pScrn->numEntities > 1) {
+ SavageFreeRec(pScrn);
+ return FALSE;
+ }
+
+ pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+ if (pEnt->resources) {
+ xfree(pEnt);
+ SavageFreeRec(pScrn);
+ return FALSE;
+ }
+ psav->EntityIndex = pEnt->index;
+
+ if (xf86LoadSubModule(pScrn, "int10")) {
+ xf86LoaderReqSymLists(int10Symbols, NULL);
+ psav->pInt10 = xf86InitInt10(pEnt->index);
+ }
+
+ if (xf86LoadSubModule(pScrn, "vbe")) {
+ xf86LoaderReqSymLists(vbeSymbols, NULL);
+ psav->pVbe = VBEInit(psav->pInt10, pEnt->index);
+ }
+
+
+ psav->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
+ xf86RegisterResources(pEnt->index, NULL, ResNone);
+ xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
+ xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
+
+ from = X_DEFAULT;
+ if (pEnt->device->chipset && *pEnt->device->chipset) {
+ pScrn->chipset = pEnt->device->chipset;
+ psav->ChipId = pEnt->device->chipID;
+ psav->Chipset = xf86StringToToken(SavageChipsets, pScrn->chipset);
+ from = X_CONFIG;
+ } else if (pEnt->device->chipID >= 0) {
+ psav->ChipId = pEnt->device->chipID;
+ psav->Chipset = LookupChipID(SavagePciChipsets, psav->ChipId);
+ pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
+ psav->Chipset);
+ from = X_CONFIG;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
+ pEnt->device->chipID);
+ } else {
+ from = X_PROBED;
+ psav->ChipId = psav->PciInfo->chipType;
+ psav->Chipset = LookupChipID(SavagePciChipsets, psav->ChipId);
+ pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
+ psav->Chipset);
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chip: id %04x, \"%s\"\n",
+ psav->ChipId, xf86TokenToString( SavageChips, psav->ChipId ) );
+
+ if (pEnt->device->chipRev >= 0) {
+ psav->ChipRev = pEnt->device->chipRev;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
+ psav->ChipRev);
+ } else
+ psav->ChipRev = psav->PciInfo->chipRev;
+
+ if (pEnt->device->videoRam != 0)
+ pScrn->videoRam = pEnt->device->videoRam;
+
+ xfree(pEnt);
+
+ /* maybe throw in some more sanity checks here */
+
+ xf86DrvMsg(pScrn->scrnIndex, from, "Engine: \"%s\"\n", pScrn->chipset);
+
+ psav->PciTag = pciTag(psav->PciInfo->bus, psav->PciInfo->device,
+ psav->PciInfo->func);
+
+
+ if (!SavageMapMMIO(pScrn)) {
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+
+ vgaCRIndex = psav->vgaIOBase + 4;
+ vgaCRReg = psav->vgaIOBase + 5;
+
+ xf86EnableIO();
+ /* unprotect CRTC[0-7] */
+ VGAOUT8(vgaCRIndex, 0x11);
+ tmp = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, tmp & 0x7f);
+
+ /* unlock extended regs */
+ VGAOUT16(vgaCRIndex, 0x4838);
+ VGAOUT16(vgaCRIndex, 0xa039);
+ VGAOUT16(0x3c4, 0x0608);
+
+ VGAOUT8(vgaCRIndex, 0x40);
+ tmp = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, tmp & ~0x01);
+
+ /* unlock sys regs */
+ VGAOUT8(vgaCRIndex, 0x38);
+ VGAOUT8(vgaCRReg, 0x48);
+
+ {
+ Gamma zeros = {0.0, 0.0, 0.0};
+
+ if (!xf86SetGamma(pScrn, zeros)) {
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+ }
+
+ /* Unlock system registers. */
+ VGAOUT16(vgaCRIndex, 0x4838);
+
+ /* Next go on to detect amount of installed ram */
+
+ VGAOUT8(vgaCRIndex, 0x36); /* for register CR36 (CONFG_REG1), */
+ config1 = VGAIN8(vgaCRReg); /* get amount of vram installed */
+
+ /* Compute the amount of video memory and offscreen memory. */
+
+ if (!pScrn->videoRam) {
+ static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
+ static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 };
+ static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
+ static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
+
+ switch( psav->Chipset ) {
+ case S3_SAVAGE3D:
+ pScrn->videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
+ break;
+
+ case S3_SAVAGE4:
+ /*
+ * The Savage4 has one ugly special case to consider. On
+ * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
+ * when it really means 8MB. Why do it the same when you
+ * can do it different...
+ */
+ VGAOUT8(vgaCRIndex, 0x68); /* memory control 1 */
+ if( (VGAIN8(vgaCRReg) & 0xC0) == (0x01 << 6) )
+ RamSavage4[1] = 8;
+
+ /*FALLTHROUGH*/
+
+ case S3_SAVAGE2000:
+ pScrn->videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
+ break;
+
+ case S3_SAVAGE_MX:
+ case S3_SUPERSAVAGE:
+ pScrn->videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
+ break;
+
+ case S3_PROSAVAGE:
+ pScrn->videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
+ break;
+
+ default:
+ /* How did we get here? */
+ pScrn->videoRam = 0;
+ break;
+ }
+
+ psav->videoRambytes = pScrn->videoRam * 1024;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "probed videoram: %dk\n",
+ pScrn->videoRam);
+ } else {
+ psav->videoRambytes = pScrn->videoRam * 1024;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "videoram = %dk\n",
+ pScrn->videoRam);
+ }
+
+ if( !pScrn->videoRam && psav->pVbe )
+ {
+ /* If VBE is available, ask it about onboard memory. */
+
+ VbeInfoBlock* vib;
+
+ vib = VBEGetVBEInfo( psav->pVbe );
+ pScrn->videoRam = vib->TotalMemory * 64;
+ VBEFreeVBEInfo( vib );
+
+ /* VBE often cuts 64k off of the RAM total. */
+
+ if( pScrn->videoRam & 64 )
+ pScrn->videoRam += 64;
+
+ psav->videoRambytes = pScrn->videoRam * 1024;
+ }
+
+ /*
+ * If we're running with acceleration, compute the command overflow
+ * buffer location. The command overflow buffer must END at a
+ * 4MB boundary; for all practical purposes, that means the very
+ * end of the frame buffer.
+ */
+
+ if( psav->NoAccel ) {
+ psav->CursorKByte = pScrn->videoRam - 4;
+ psav->cobIndex = 0;
+ psav->cobSize = 0;
+ psav->cobOffset = psav->videoRambytes;
+ }
+ else if( (S3_SAVAGE4_SERIES(psav->Chipset)) ||
+ (S3_SUPERSAVAGE == psav->Chipset) ) {
+ /*
+ * The Savage4 and ProSavage have COB coherency bugs which render
+ * the buffer useless. COB seems to make the SuperSavage slower.
+ * We disable it.
+ */
+ psav->CursorKByte = pScrn->videoRam - 4;
+ psav->cobIndex = 2;
+ psav->cobSize = 0x8000 << psav->cobIndex;
+ psav->cobOffset = psav->videoRambytes;
+ }
+ else
+ {
+ /* We use 128kB for the COB on all other chips. */
+
+ psav->cobSize = 1 << 17;
+ if (psav->Chipset == S3_SUPERSAVAGE) {
+ psav->cobIndex = 2;
+ }
+ else {
+ psav->cobIndex = 7;
+ }
+ psav->cobOffset = psav->videoRambytes - psav->cobSize;
+ }
+
+ /*
+ * We place the cursor in high memory, just before the command overflow
+ * buffer. The cursor must be aligned on a 4k boundary.
+ */
+
+ psav->CursorKByte = (psav->cobOffset >> 10) - 4;
+
+ /* reset graphics engine to avoid memory corruption */
+ VGAOUT8(vgaCRIndex, 0x66);
+ cr66 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr66 | 0x02);
+ usleep(10000);
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ VGAOUT8(vgaCRReg, cr66 & ~0x02); /* clear reset flag */
+ usleep(10000);
+
+ /* Set status word positions based on chip type. */
+
+ switch( psav->Chipset ) {
+ case S3_SAVAGE3D:
+ case S3_SAVAGE_MX:
+ psav->WaitQueue = WaitQueue3D;
+ psav->WaitIdle = WaitIdle3D;
+ psav->WaitIdleEmpty = WaitIdleEmpty3D;
+ break;
+
+ case S3_SAVAGE4:
+ case S3_PROSAVAGE:
+ case S3_SUPERSAVAGE:
+ psav->WaitQueue = WaitQueue4;
+ psav->WaitIdle = WaitIdle4;
+ psav->WaitIdleEmpty = WaitIdleEmpty4;
+ break;
+
+ case S3_SAVAGE2000:
+ psav->WaitQueue = WaitQueue2K;
+ psav->WaitIdle = WaitIdle2K;
+ psav->WaitIdleEmpty = WaitIdleEmpty2K;
+ break;
+ }
+
+ /* Do the DDC dance. */
+
+ if( psav->Chipset != S3_PROSAVAGE ) {
+ ddc = xf86LoadSubModule(pScrn, "ddc");
+ if (ddc) {
+#if 0
+ xf86MonPtr pMon = NULL;
+#endif
+
+ xf86LoaderReqSymLists(ddcSymbols, NULL);
+#if 0
+/*
+ * On many machines, the attempt to read DDC information via VBE puts the
+ * BIOS access into a state which prevents me from reading mode information.
+ * This is a complete mystery to me.
+ */
+ if ((psav->pVbe)
+ && ((pMon = xf86PrintEDID(vbeDoEDID(psav->pVbe, ddc))) != NULL))
+ xf86SetDDCproperties(pScrn,pMon);
+ else
+#endif
+ if (!SavageDDC1(pScrn->scrnIndex)) {
+ if ( xf86LoadSubModule(pScrn, "i2c") ) {
+ xf86LoaderReqSymLists(i2cSymbols,NULL);
+ if (SavageI2CInit(pScrn)) {
+ unsigned char tmp;
+
+ InI2CREG(psav,tmp);
+ OutI2CREG(psav,tmp | 0x13);
+ xf86SetDDCproperties(pScrn,xf86PrintEDID(
+ xf86DoEDID_DDC2(pScrn->scrnIndex,psav->I2C)));
+ OutI2CREG(psav,tmp);
+ }
+ }
+ }
+ }
+ }
+
+ /* Savage ramdac speeds */
+ pScrn->numClocks = 4;
+ pScrn->clock[0] = 250000;
+ pScrn->clock[1] = 250000;
+ pScrn->clock[2] = 220000;
+ pScrn->clock[3] = 220000;
+
+ if (psav->dacSpeedBpp <= 0) {
+ if (pScrn->bitsPerPixel > 24)
+ psav->dacSpeedBpp = pScrn->clock[3];
+ else if (pScrn->bitsPerPixel >= 24)
+ psav->dacSpeedBpp = pScrn->clock[2];
+ else if ((pScrn->bitsPerPixel > 8) && (pScrn->bitsPerPixel < 24))
+ psav->dacSpeedBpp = pScrn->clock[1];
+ else if (pScrn->bitsPerPixel <= 8)
+ psav->dacSpeedBpp = pScrn->clock[0];
+ }
+
+ /* Set ramdac limits */
+ psav->maxClock = psav->dacSpeedBpp;
+
+ /* detect current mclk */
+ VGAOUT8(0x3c4, 0x08);
+ sr8 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c5, 0x06);
+ VGAOUT8(0x3c4, 0x10);
+ n = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x11);
+ m = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x08);
+ VGAOUT8(0x3c5, sr8);
+ m &= 0x7f;
+ n1 = n & 0x1f;
+ n2 = (n >> 5) & 0x03;
+ mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of %1.3f MHz\n",
+ mclk / 1000.0);
+
+ psav->minClock = 10000;
+
+ pScrn->maxHValue = 2048 << 3; /* 11 bits of h_total 8-pixel units */
+ pScrn->maxVValue = 2048; /* 11 bits of v_total */
+ pScrn->virtualX = pScrn->display->virtualX;
+ pScrn->virtualY = pScrn->display->virtualY;
+
+ /* Check LCD panel information */
+
+ if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) && !psav->CrtOnly )
+ {
+ unsigned char cr6b = hwp->readCrtc( hwp, 0x6b );
+
+ int panelX = (hwp->readSeq(hwp, 0x61) +
+ ((hwp->readSeq(hwp, 0x66) & 0x02) << 7) + 1) * 8;
+ int panelY = hwp->readSeq(hwp, 0x69) +
+ ((hwp->readSeq(hwp, 0x6e) & 0x70) << 4) + 1;
+
+ char * sTechnology = "Unknown";
+
+ /* OK, I admit it. I don't know how to limit the max dot clock
+ * for LCD panels of various sizes. I thought I copied the formula
+ * from the BIOS, but many users have informed me of my folly.
+ *
+ * Instead, I'll abandon any attempt to automatically limit the
+ * clock, and add an LCDClock option to XF86Config. Some day,
+ * I should come back to this.
+ */
+
+ enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
+ ActiveCRT = 0x01,
+ ActiveLCD = 0x02,
+ ActiveTV = 0x04,
+ ActiveCRT2 = 0x20,
+ ActiveDUO = 0x80
+ };
+
+ if( (hwp->readSeq( hwp, 0x39 ) & 0x03) == 0 )
+ {
+ sTechnology = "TFT";
+ }
+ else if( (hwp->readSeq( hwp, 0x30 ) & 0x01) == 0 )
+ {
+ sTechnology = "DSTN";
+ }
+ else
+ {
+ sTechnology = "STN";
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "%dx%d %s LCD panel detected %s\n",
+ panelX, panelY, sTechnology,
+ cr6b & ActiveLCD ? "and active" : "but not active");
+
+ if( cr6b & ActiveLCD ) {
+ /* If the LCD is active and panel expansion is enabled, */
+ /* we probably want to kill the HW cursor. */
+
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "- Limiting video mode to %dx%d\n",
+ panelX, panelY );
+
+ psav->PanelX = panelX;
+ psav->PanelY = panelY;
+
+ if( psav->LCDClock > 0.0 )
+ {
+ psav->maxClock = psav->LCDClock * 1000.0;
+ xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+ "- Limiting dot clock to %1.2f MHz\n",
+ psav->LCDClock );
+ }
+ }
+ }
+
+ clockRanges = xnfcalloc(sizeof(ClockRange),1);
+ clockRanges->next = NULL;
+ clockRanges->minClock = psav->minClock;
+ clockRanges->maxClock = psav->maxClock;
+ clockRanges->clockIndex = -1;
+ clockRanges->interlaceAllowed = TRUE;
+ clockRanges->doubleScanAllowed = TRUE;
+ clockRanges->ClockDivFactor = 1.0;
+ clockRanges->ClockMulFactor = 1.0;
+
+ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+ pScrn->display->modes, clockRanges, NULL,
+ 256, 2048, 16 * pScrn->bitsPerPixel,
+ 128, 2048,
+ pScrn->virtualX, pScrn->virtualY,
+ psav->videoRambytes, LOOKUP_BEST_REFRESH);
+
+ if (i == -1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes failure\n");
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+
+ xf86PruneDriverModes(pScrn);
+
+ if (i == 0 || pScrn->modes == NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+
+ if( psav->UseBIOS )
+ {
+ /* Go probe the BIOS for all the modes and refreshes at this depth. */
+
+ if( psav->ModeTable )
+ {
+ SavageFreeBIOSModeTable( psav, &psav->ModeTable );
+ }
+
+ psav->ModeTable = SavageGetBIOSModeTable( psav, pScrn->bitsPerPixel );
+
+ if( !psav->ModeTable || !psav->ModeTable->NumModes ) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to fetch any BIOS modes. Disabling BIOS.\n");
+ psav->UseBIOS = FALSE;
+ }
+ else
+ /*if( xf86Verbose )*/
+ {
+ SavageModeEntryPtr pmt;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "Found %d modes at this depth:\n",
+ psav->ModeTable->NumModes);
+
+ for(
+ i = 0, pmt = psav->ModeTable->Modes;
+ i < psav->ModeTable->NumModes;
+ i++, pmt++ )
+ {
+ int j;
+ ErrorF( " [%03x] %d x %d",
+ pmt->VesaMode, pmt->Width, pmt->Height );
+ for( j = 0; j < pmt->RefreshCount; j++ )
+ {
+ ErrorF( ", %dHz", pmt->RefreshRate[j] );
+ }
+ ErrorF( "\n");
+ }
+ }
+ }
+
+ xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
+ pScrn->currentMode = pScrn->modes;
+ xf86PrintModes(pScrn);
+ xf86SetDpi(pScrn, 0, 0);
+
+ if (xf86LoadSubModule(pScrn, "fb") == NULL) {
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+
+ xf86LoaderReqSymLists(fbSymbols, NULL);
+
+ if( !psav->NoAccel ) {
+ if( !xf86LoadSubModule(pScrn, "xaa") ) {
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(xaaSymbols, NULL );
+ }
+
+ if (psav->hwcursor) {
+ if (!xf86LoadSubModule(pScrn, "ramdac")) {
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(ramdacSymbols, NULL);
+ }
+
+ if (psav->shadowFB) {
+ if (!xf86LoadSubModule(pScrn, "shadowfb")) {
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(shadowSymbols, NULL);
+ }
+ vbeFree(psav->pVbe);
+
+ return TRUE;
+}
+
+
+static Bool SavageEnterVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ TRACE(("SavageEnterVT(%d)\n", flags));
+
+ gpScrn = pScrn;
+ SavageEnableMMIO(pScrn);
+ SavageSave(pScrn);
+ return SavageModeInit(pScrn, pScrn->currentMode);
+}
+
+
+static void SavageLeaveVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ vgaRegPtr vgaSavePtr = &hwp->SavedReg;
+ SavageRegPtr SavageSavePtr = &psav->SavedReg;
+
+ TRACE(("SavageLeaveVT(%d)\n", flags));
+ gpScrn = pScrn;
+ SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
+ SavageDisableMMIO(pScrn);
+}
+
+
+static void SavageSave(ScrnInfoPtr pScrn)
+{
+ unsigned char cr3a, cr53, cr66;
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ vgaRegPtr vgaSavePtr = &hwp->SavedReg;
+ SavagePtr psav = SAVPTR(pScrn);
+ SavageRegPtr save = &psav->SavedReg;
+ unsigned short vgaCRReg = psav->vgaIOBase + 5;
+ unsigned short vgaCRIndex = psav->vgaIOBase + 4;
+
+ TRACE(("SavageSave()\n"));
+
+ VGAOUT16(vgaCRIndex, 0x4838);
+ VGAOUT16(vgaCRIndex, 0xa039);
+ VGAOUT16(0x3c4, 0x0608);
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ cr66 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr66 | 0x80);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ cr3a = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr3a | 0x80);
+ VGAOUT8(vgaCRIndex, 0x53);
+ cr53 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr53 & 0x7f);
+
+ if (xf86IsPrimaryPci(psav->PciInfo))
+ vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
+ else
+ vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ VGAOUT8(vgaCRReg, cr66);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ VGAOUT8(vgaCRReg, cr3a);
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ VGAOUT8(vgaCRReg, cr66);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ VGAOUT8(vgaCRReg, cr3a);
+
+ /* unlock extended seq regs */
+ VGAOUT8(0x3c4, 0x08);
+ save->SR08 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c5, 0x06);
+
+ /* now save all the extended regs we need */
+ VGAOUT8(vgaCRIndex, 0x31);
+ save->CR31 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x32);
+ save->CR32 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x34);
+ save->CR34 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x36);
+ save->CR36 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ save->CR3A = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x40);
+ save->CR40 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x42);
+ save->CR42 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x45);
+ save->CR45 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x50);
+ save->CR50 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x51);
+ save->CR51 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x53);
+ save->CR53 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x58);
+ save->CR58 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x60);
+ save->CR60 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x66);
+ save->CR66 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x67);
+ save->CR67 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x68);
+ save->CR68 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x69);
+ save->CR69 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x6f);
+ save->CR6F = VGAIN8(vgaCRReg);
+
+ VGAOUT8(vgaCRIndex, 0x33);
+ save->CR33 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x86);
+ save->CR86 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x88);
+ save->CR88 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x90);
+ save->CR90 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x91);
+ save->CR91 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0xb0);
+ save->CRB0 = VGAIN8(vgaCRReg) | 0x80;
+
+ /* extended mode timing regs */
+ VGAOUT8(vgaCRIndex, 0x3b);
+ save->CR3B = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x3c);
+ save->CR3C = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x43);
+ save->CR43 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x5d);
+ save->CR5D = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x5e);
+ save->CR5E = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x65);
+ save->CR65 = VGAIN8(vgaCRReg);
+
+ /* save seq extended regs for DCLK PLL programming */
+ VGAOUT8(0x3c4, 0x0e);
+ save->SR0E = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x0f);
+ save->SR0F = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x10);
+ save->SR10 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x11);
+ save->SR11 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x12);
+ save->SR12 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x13);
+ save->SR13 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x29);
+ save->SR29 = VGAIN8(0x3c5);
+
+ VGAOUT8(0x3c4, 0x15);
+ save->SR15 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x30);
+ save->SR30 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x18);
+ save->SR18 = VGAIN8(0x3c5);
+ VGAOUT8(0x3c4, 0x1b);
+ save->SR1B = VGAIN8(0x3c5);
+
+ /* Save flat panel expansion regsters. */
+
+ if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
+ int i;
+ for( i = 0; i < 8; i++ ) {
+ VGAOUT8(0x3c4, 0x54+i);
+ save->SR54[i] = VGAIN8(0x3c5);
+ }
+ }
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ cr66 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr66 | 0x80);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ cr3a = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr3a | 0x80);
+
+ /* now save MIU regs */
+ if( ! S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
+ save->MMPR0 = INREG(FIFO_CONTROL_REG);
+ save->MMPR1 = INREG(MIU_CONTROL_REG);
+ save->MMPR2 = INREG(STREAMS_TIMEOUT_REG);
+ save->MMPR3 = INREG(MISC_TIMEOUT_REG);
+ }
+
+ VGAOUT8(vgaCRIndex, 0x3a);
+ VGAOUT8(vgaCRReg, cr3a);
+ VGAOUT8(vgaCRIndex, 0x66);
+ VGAOUT8(vgaCRReg, cr66);
+
+ if (!psav->ModeStructInit) {
+ vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
+ memcpy(&psav->ModeReg, save, sizeof(SavageRegRec));
+ psav->ModeStructInit = TRUE;
+ }
+
+#if 0
+ if (xf86GetVerbosity() > 1)
+ SavagePrintRegs(pScrn);
+#endif
+
+ return;
+}
+
+
+static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr,
+ SavageRegPtr restore, Bool Entering)
+{
+ unsigned char tmp, cr3a, cr66, cr67;
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+
+
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+
+ TRACE(("SavageWriteMode(%x)\n", restore->mode));
+
+ if( Entering &&
+ (!S3_SAVAGE_MOBILE_SERIES(psav->Chipset) || (psav->ForceInit))
+ )
+ SavageInitialize2DEngine(pScrn);
+
+ /*
+ * If we figured out a VESA mode number for this timing, just use
+ * the S3 BIOS to do the switching, with a few additional tweaks.
+ */
+
+ if( psav->UseBIOS && restore->mode > 0x13 )
+ {
+ int width;
+ unsigned short cr6d;
+ unsigned short cr79 = 0;
+
+ /* Set up the mode. Don't clear video RAM. */
+ SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
+
+ /* Restore the DAC. */
+ vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP);
+
+ /* Unlock the extended registers. */
+
+#if 0
+ /* Which way is better? */
+ hwp->writeCrtc( hwp, 0x38, 0x48 );
+ hwp->writeCrtc( hwp, 0x39, 0xa0 );
+ hwp->writeSeq( hwp, 0x08, 0x06 );
+#endif
+
+ VGAOUT16(vgaCRIndex, 0x4838);
+ VGAOUT16(vgaCRIndex, 0xA039);
+ VGAOUT16(0x3c4, 0x0608);
+
+ /* Enable linear addressing. */
+
+ VGAOUT16(vgaCRIndex, 0x1358);
+
+ /* Disable old MMIO. */
+
+ VGAOUT8(vgaCRIndex, 0x53);
+ VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & ~0x10);
+
+ /* Set the color mode. */
+
+ VGAOUT8(vgaCRIndex, 0x67);
+ VGAOUT8(vgaCRReg, restore->CR67);
+
+ /* Enable gamma correction. */
+
+ VGAOUT8(0x3c4, 0x1b);
+ if( (pScrn->bitsPerPixel == 32) && !psav->DGAactive )
+ VGAOUT8(0x3c5, 0x28 );
+ else
+ VGAOUT8(0x3c5, 0x00 );
+
+ /* We may need TV/panel fixups here. See s3bios.c line 2904. */
+
+ /* Set FIFO fetch delay. */
+ VGAOUT8(vgaCRIndex, 0x85);
+ VGAOUT8(vgaCRReg, (VGAIN8(vgaCRReg) & 0xf8) | 0x03);
+
+ /* Patch CR79. These values are magical. */
+
+ if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
+ {
+ VGAOUT8(vgaCRIndex, 0x6d);
+ cr6d = VGAIN8(vgaCRReg);
+
+ cr79 = 0x04;
+
+ if( pScrn->displayWidth >= 1024 )
+ {
+ if(pScrn->bitsPerPixel == 32 )
+ {
+ if( restore->refresh >= 130 )
+ cr79 = 0x03;
+ else if( pScrn->displayWidth >= 1280 )
+ cr79 = 0x02;
+ else if(
+ (pScrn->displayWidth == 1024) &&
+ (restore->refresh >= 75)
+ )
+ {
+ if( cr6d && LCD_ACTIVE )
+ cr79 = 0x05;
+ else
+ cr79 = 0x08;
+ }
+ }
+ else if( pScrn->bitsPerPixel == 16)
+ {
+
+/* The windows driver uses 0x13 for 16-bit 130Hz, but I see terrible
+ * screen artifacts with that value. Let's keep it low for now.
+ * if( restore->refresh >= 130 )
+ * cr79 = 0x13;
+ * else
+ */
+ if( pScrn->displayWidth == 1024 )
+ {
+ if( cr6d && LCD_ACTIVE )
+ cr79 = 0x08;
+ else
+ cr79 = 0x0e;
+ }
+ }
+ }
+ }
+
+ if( (psav->Chipset != S3_SAVAGE2000) &&
+ !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
+ VGAOUT16(vgaCRIndex, (cr79 << 8) | 0x79);
+
+ /* Make sure 16-bit memory access is enabled. */
+
+ VGAOUT16(vgaCRIndex, 0x0c31);
+
+ /* Enable the graphics engine. */
+
+ VGAOUT16(vgaCRIndex, 0x0140);
+
+ /* Handle the pitch. */
+
+ VGAOUT8(vgaCRIndex, 0x50);
+ VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
+
+ width = (pScrn->displayWidth * (pScrn->bitsPerPixel / 8)) >> 3;
+ VGAOUT16(vgaCRIndex, ((width & 0xff) << 8) | 0x13 );
+ VGAOUT16(vgaCRIndex, ((width & 0x300) << 4) | 0x51 );
+
+ /* Some non-S3 BIOSes enable block write even on non-SGRAM devices. */
+
+ switch( psav->Chipset )
+ {
+ case S3_SAVAGE2000:
+ VGAOUT8(vgaCRIndex, 0x73);
+ VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & 0xdf );
+ break;
+
+ case S3_SAVAGE3D:
+ case S3_SAVAGE4:
+ VGAOUT8(vgaCRIndex, 0x68);
+ if( !(VGAIN8(vgaCRReg) & 0x80) )
+ {
+ /* Not SGRAM; disable block write. */
+ VGAOUT8(vgaCRIndex, 0x88);
+ VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0x10);
+ }
+ break;
+ }
+
+ SavageInitialize2DEngine(pScrn);
+ SavageSetGBD(pScrn);
+
+ VGAOUT16(vgaCRIndex, 0x0140);
+
+ SavageSetGBD(pScrn);
+
+ return;
+ }
+
+ VGAOUT8(0x3c2, 0x23);
+ VGAOUT16(vgaCRIndex, 0x4838);
+ VGAOUT16(vgaCRIndex, 0xa039);
+ VGAOUT16(0x3c4, 0x0608);
+
+ vgaHWProtect(pScrn, TRUE);
+
+ /* will we be reenabling STREAMS for the new mode? */
+ psav->STREAMSRunning = 0;
+
+ /* reset GE to make sure nothing is going on */
+ VGAOUT8(vgaCRIndex, 0x66);
+ if(VGAIN8(vgaCRReg) & 0x01)
+ SavageGEReset(pScrn,0,__LINE__,__FILE__);
+
+ /*
+ * Some Savage/MX and /IX systems go nuts when trying to exit the
+ * server after WindowMaker has displayed a gradient background. I
+ * haven't been able to find what causes it, but a non-destructive
+ * switch to mode 3 here seems to eliminate the issue.
+ */
+
+ if( ((restore->CR31 & 0x0a) == 0) && psav->pInt10 ) {
+ SavageSetTextMode( psav );
+ }
+
+ VGAOUT8(vgaCRIndex, 0x67);
+ cr67 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c); /* no STREAMS yet */
+
+ /* restore extended regs */
+ VGAOUT8(vgaCRIndex, 0x66);
+ VGAOUT8(vgaCRReg, restore->CR66);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ VGAOUT8(vgaCRReg, restore->CR3A);
+ VGAOUT8(vgaCRIndex, 0x31);
+ VGAOUT8(vgaCRReg, restore->CR31);
+ VGAOUT8(vgaCRIndex, 0x32);
+ VGAOUT8(vgaCRReg, restore->CR32);
+ VGAOUT8(vgaCRIndex, 0x58);
+ VGAOUT8(vgaCRReg, restore->CR58);
+ VGAOUT8(vgaCRIndex, 0x53);
+ VGAOUT8(vgaCRReg, restore->CR53 & 0x7f);
+
+ VGAOUT16(0x3c4, 0x0608);
+
+ /* Restore DCLK registers. */
+
+ VGAOUT8(0x3c4, 0x0e);
+ VGAOUT8(0x3c5, restore->SR0E);
+ VGAOUT8(0x3c4, 0x0f);
+ VGAOUT8(0x3c5, restore->SR0F);
+ VGAOUT8(0x3c4, 0x29);
+ VGAOUT8(0x3c5, restore->SR29);
+ VGAOUT8(0x3c4, 0x15);
+ VGAOUT8(0x3c5, restore->SR15);
+
+ /* Restore flat panel expansion regsters. */
+ if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
+ int i;
+ for( i = 0; i < 8; i++ ) {
+ VGAOUT8(0x3c4, 0x54+i);
+ VGAOUT8(0x3c5, restore->SR54[i]);
+ }
+ }
+
+ /* restore the standard vga regs */
+ if (xf86IsPrimaryPci(psav->PciInfo))
+ vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
+ else
+ vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
+
+ /* extended mode timing registers */
+ VGAOUT8(vgaCRIndex, 0x53);
+ VGAOUT8(vgaCRReg, restore->CR53);
+ VGAOUT8(vgaCRIndex, 0x5d);
+ VGAOUT8(vgaCRReg, restore->CR5D);
+ VGAOUT8(vgaCRIndex, 0x5e);
+ VGAOUT8(vgaCRReg, restore->CR5E);
+ VGAOUT8(vgaCRIndex, 0x3b);
+ VGAOUT8(vgaCRReg, restore->CR3B);
+ VGAOUT8(vgaCRIndex, 0x3c);
+ VGAOUT8(vgaCRReg, restore->CR3C);
+ VGAOUT8(vgaCRIndex, 0x43);
+ VGAOUT8(vgaCRReg, restore->CR43);
+ VGAOUT8(vgaCRIndex, 0x65);
+ VGAOUT8(vgaCRReg, restore->CR65);
+
+ /* restore the desired video mode with cr67 */
+ VGAOUT8(vgaCRIndex, 0x67);
+ VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c); /* no STREAMS yet */
+
+ /* other mode timing and extended regs */
+ VGAOUT8(vgaCRIndex, 0x34);
+ VGAOUT8(vgaCRReg, restore->CR34);
+ VGAOUT8(vgaCRIndex, 0x40);
+ VGAOUT8(vgaCRReg, restore->CR40);
+ VGAOUT8(vgaCRIndex, 0x42);
+ VGAOUT8(vgaCRReg, restore->CR42);
+ VGAOUT8(vgaCRIndex, 0x45);
+ VGAOUT8(vgaCRReg, restore->CR45);
+ VGAOUT8(vgaCRIndex, 0x50);
+ VGAOUT8(vgaCRReg, restore->CR50);
+ VGAOUT8(vgaCRIndex, 0x51);
+ VGAOUT8(vgaCRReg, restore->CR51);
+
+ /* memory timings */
+ VGAOUT8(vgaCRIndex, 0x36);
+ VGAOUT8(vgaCRReg, restore->CR36);
+ VGAOUT8(vgaCRIndex, 0x60);
+ VGAOUT8(vgaCRReg, restore->CR60);
+ VGAOUT8(vgaCRIndex, 0x68);
+ VGAOUT8(vgaCRReg, restore->CR68);
+ VGAOUT8(vgaCRIndex, 0x69);
+ VGAOUT8(vgaCRReg, restore->CR69);
+ VGAOUT8(vgaCRIndex, 0x6f);
+ VGAOUT8(vgaCRReg, restore->CR6F);
+
+ VGAOUT8(vgaCRIndex, 0x33);
+ VGAOUT8(vgaCRReg, restore->CR33);
+ VGAOUT8(vgaCRIndex, 0x86);
+ VGAOUT8(vgaCRReg, restore->CR86);
+ VGAOUT8(vgaCRIndex, 0x88);
+ VGAOUT8(vgaCRReg, restore->CR88);
+ VGAOUT8(vgaCRIndex, 0x90);
+ VGAOUT8(vgaCRReg, restore->CR90);
+ VGAOUT8(vgaCRIndex, 0x91);
+ VGAOUT8(vgaCRReg, restore->CR91);
+ if( psav->Chipset == S3_SAVAGE4 )
+ {
+ VGAOUT8(vgaCRIndex, 0xb0);
+ VGAOUT8(vgaCRReg, restore->CRB0);
+ }
+
+ VGAOUT8(vgaCRIndex, 0x32);
+ VGAOUT8(vgaCRReg, restore->CR32);
+
+ /* unlock extended seq regs */
+ VGAOUT8(0x3c4, 0x08);
+ VGAOUT8(0x3c5, 0x06);
+
+ /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that
+ * we should leave the default SR10 and SR11 values there.
+ */
+ if (restore->SR10 != 255) {
+ VGAOUT8(0x3c4, 0x10);
+ VGAOUT8(0x3c5, restore->SR10);
+ VGAOUT8(0x3c4, 0x11);
+ VGAOUT8(0x3c5, restore->SR11);
+ }
+
+ /* restore extended seq regs for dclk */
+ VGAOUT8(0x3c4, 0x0e);
+ VGAOUT8(0x3c5, restore->SR0E);
+ VGAOUT8(0x3c4, 0x0f);
+ VGAOUT8(0x3c5, restore->SR0F);
+ VGAOUT8(0x3c4, 0x12);
+ VGAOUT8(0x3c5, restore->SR12);
+ VGAOUT8(0x3c4, 0x13);
+ VGAOUT8(0x3c5, restore->SR13);
+ VGAOUT8(0x3c4, 0x29);
+ VGAOUT8(0x3c5, restore->SR29);
+
+ VGAOUT8(0x3c4, 0x18);
+ VGAOUT8(0x3c5, restore->SR18);
+ VGAOUT8(0x3c4, 0x1b);
+ if( psav->DGAactive )
+ VGAOUT8(0x3c5, restore->SR1B & ~0x28);
+ else
+ VGAOUT8(0x3c5, restore->SR1B);
+
+ /* load new m, n pll values for dclk & mclk */
+ VGAOUT8(0x3c4, 0x15);
+ tmp = VGAIN8(0x3c5) & ~0x21;
+
+ VGAOUT8(0x3c5, tmp | 0x03);
+ VGAOUT8(0x3c5, tmp | 0x23);
+ VGAOUT8(0x3c5, tmp | 0x03);
+ VGAOUT8(0x3c5, restore->SR15);
+ usleep( 100 );
+
+ VGAOUT8(0x3c4, 0x30);
+ VGAOUT8(0x3c5, restore->SR30);
+ VGAOUT8(0x3c4, 0x08);
+ VGAOUT8(0x3c5, restore->SR08);
+
+ /* now write out cr67 in full, possibly starting STREAMS */
+ VerticalRetraceWait(psav);
+ VGAOUT8(vgaCRIndex, 0x67);
+#if 0
+ VGAOUT8(vgaCRReg, 0x50);
+ usleep(10000);
+ VGAOUT8(vgaCRIndex, 0x67);
+#endif
+ VGAOUT8(vgaCRReg, restore->CR67);
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ cr66 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr66 | 0x80);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ cr3a = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, cr3a | 0x80);
+
+ if (Entering)
+ SavageGEReset(pScrn,0,__LINE__,__FILE__);
+
+ if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
+ {
+ VerticalRetraceWait(psav);
+ OUTREG(FIFO_CONTROL_REG, restore->MMPR0);
+ OUTREG(MIU_CONTROL_REG, restore->MMPR1);
+ OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2);
+ OUTREG(MISC_TIMEOUT_REG, restore->MMPR3);
+ }
+
+ /* If we're going into graphics mode and acceleration was enabled, */
+ /* go set up the BCI buffer and the global bitmap descriptor. */
+
+#if 0
+ if( Entering && (!psav->NoAccel) )
+ {
+ VGAOUT8(vgaCRIndex, 0x50);
+ VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
+ SavageInitialize2DEngine(pScrn);
+ }
+#endif
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ VGAOUT8(vgaCRReg, cr66);
+ VGAOUT8(vgaCRIndex, 0x3a);
+ VGAOUT8(vgaCRReg, cr3a);
+
+ if( Entering )
+ SavageSetGBD(pScrn);
+
+ vgaHWProtect(pScrn, FALSE);
+
+ return;
+}
+
+
+static Bool SavageMapMMIO(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav;
+
+ TRACE(("SavageMapMMIO()\n"));
+
+ psav = SAVPTR(pScrn);
+
+ if( S3_SAVAGE3D_SERIES(psav->Chipset) ) {
+ psav->MmioBase = psav->PciInfo->memBase[0] + SAVAGE_NEWMMIO_REGBASE_S3;
+ psav->FrameBufferBase = psav->PciInfo->memBase[0];
+ }
+ else {
+ psav->MmioBase = psav->PciInfo->memBase[0] + SAVAGE_NEWMMIO_REGBASE_S4;
+ psav->FrameBufferBase = psav->PciInfo->memBase[1];
+ }
+
+ xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
+ "mapping MMIO @ 0x%x with size 0x%x\n",
+ psav->MmioBase, SAVAGE_NEWMMIO_REGSIZE);
+
+ psav->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, psav->PciTag,
+ psav->MmioBase,
+ SAVAGE_NEWMMIO_REGSIZE);
+#if 0
+ psav->MapBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO_32BIT,
+ psav->PciTag,
+ psav->PciInfo->memBase[0],
+ 0x8000);
+#endif
+ if (!psav->MapBase) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Internal error: cound not map registers\n");
+ return FALSE;
+ }
+
+ psav->BciMem = psav->MapBase + 0x10000;
+
+ SavageEnableMMIO(pScrn);
+
+ return TRUE;
+}
+
+
+
+static Bool SavageMapFB(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+
+ TRACE(("SavageMapFB()\n"));
+
+ xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
+ "mapping framebuffer @ 0x%x with size 0x%x\n",
+ psav->FrameBufferBase, psav->videoRambytes);
+
+ if (psav->videoRambytes) {
+ psav->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+ psav->PciTag, psav->FrameBufferBase,
+ psav->videoRambytes);
+ if (!psav->FBBase) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Internal error: could not map framebuffer\n");
+ return FALSE;
+ }
+ psav->FBStart = psav->FBBase;
+ }
+ pScrn->memPhysBase = psav->PciInfo->memBase[0];
+ pScrn->fbOffset = 0;
+
+ return TRUE;
+}
+
+
+static void SavageUnmapMem(ScrnInfoPtr pScrn, int All)
+{
+ SavagePtr psav;
+
+ psav = SAVPTR(pScrn);
+
+ TRACE(("SavageUnmapMem(%x,%x)\n", psav->MapBase, psav->FBBase));
+
+ if (psav->PrimaryVidMapped) {
+ vgaHWUnmapMem(pScrn);
+ psav->PrimaryVidMapped = FALSE;
+ }
+
+ SavageDisableMMIO(pScrn);
+
+ if (All && psav->MapBase) {
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->MapBase,
+ SAVAGE_NEWMMIO_REGSIZE);
+ psav->MapBase = 0;
+ }
+
+ if (psav->FBBase) {
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->FBBase,
+ psav->videoRambytes);
+ psav->FBBase = 0;
+ }
+
+#if 0
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->MapBaseDense,
+ 0x8000);
+#endif
+
+ return;
+}
+
+
+static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen,
+ int argc, char **argv)
+{
+ ScrnInfoPtr pScrn;
+ SavagePtr psav;
+ EntityInfoPtr pEnt;
+ int ret;
+
+ TRACE(("SavageScreenInit()\n"));
+
+ pScrn = xf86Screens[pScreen->myNum];
+ psav = SAVPTR(pScrn);
+
+ pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+ psav->pVbe = VBEInit(NULL, pEnt->index);
+
+ SavageEnableMMIO(pScrn);
+
+ if (!SavageMapFB(pScrn))
+ return FALSE;
+
+ if( psav->ShadowStatus ) {
+ psav->ShadowPhysical =
+ psav->FrameBufferBase + psav->CursorKByte*1024 + 4096 - 32;
+
+ psav->ShadowVirtual = (CARD32 *)
+ (psav->FBBase + psav->CursorKByte*1024 + 4096 - 32);
+
+ xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
+ "Shadow area physical %08x, linear %08x\n",
+ psav->ShadowPhysical, psav->ShadowVirtual );
+
+ psav->WaitQueue = ShadowWait1;
+ psav->WaitIdle = ShadowWait;
+ psav->WaitIdleEmpty = ShadowWait;
+
+ if( psav->Chipset == S3_SAVAGE2000 )
+ psav->dwBCIWait2DIdle = 0xc0040000;
+ else
+ psav->dwBCIWait2DIdle = 0xc0020000;
+ }
+ psav->ShadowCounter = 0;
+
+ SavageSave(pScrn);
+
+ vgaHWBlankScreen(pScrn, TRUE);
+
+ if (!SavageModeInit(pScrn, pScrn->currentMode))
+ return FALSE;
+
+ miClearVisualTypes();
+
+ if (pScrn->bitsPerPixel == 16) {
+ if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
+ pScrn->rgbBits, pScrn->defaultVisual))
+ return FALSE;
+ if (!miSetPixmapDepths ())
+ return FALSE;
+ } else {
+ if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
+ pScrn->rgbBits, pScrn->defaultVisual))
+ return FALSE;
+ if (!miSetPixmapDepths ())
+ return FALSE;
+ }
+
+ ret = SavageInternalScreenInit(scrnIndex, pScreen);
+ if (!ret)
+ return FALSE;
+
+ xf86SetBlackWhitePixels(pScreen);
+
+ if (pScrn->bitsPerPixel > 8) {
+ VisualPtr visual;
+
+ 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( !psav->NoAccel ) {
+ SavageInitAccel(pScreen);
+ }
+
+ miInitializeBackingStore(pScreen);
+ xf86SetBackingStore(pScreen);
+
+ if( !psav->shadowFB )
+ SavageDGAInit(pScreen);
+
+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+ if (psav->hwcursor)
+ if (!SavageHWCursorInit(pScreen))
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Hardware cursor initialization failed\n");
+
+ if (psav->shadowFB) {
+ RefreshAreaFuncPtr refreshArea = SavageRefreshArea;
+
+ if(psav->rotate) {
+ if (!psav->PointerMoved) {
+ psav->PointerMoved = pScrn->PointerMoved;
+ pScrn->PointerMoved = SavagePointerMoved;
+ }
+
+ switch(pScrn->bitsPerPixel) {
+ case 8: refreshArea = SavageRefreshArea8; break;
+ case 16: refreshArea = SavageRefreshArea16; break;
+ case 24: refreshArea = SavageRefreshArea24; break;
+ case 32: refreshArea = SavageRefreshArea32; break;
+ }
+ }
+
+ ShadowFBInit(pScreen, refreshArea);
+ }
+
+ if (!miCreateDefColormap(pScreen))
+ return FALSE;
+
+ if (psav->Chipset == S3_SAVAGE4) {
+ if (!xf86HandleColormaps(pScreen, 256, 6, SavageLoadPaletteSavage4,
+ NULL,
+ CMAP_RELOAD_ON_MODE_SWITCH
+ | CMAP_PALETTED_TRUECOLOR
+ ))
+ return FALSE;
+ } else {
+ if (!xf86HandleColormaps(pScreen, 256, 6, SavageLoadPalette, NULL,
+ CMAP_RELOAD_ON_MODE_SWITCH
+ | CMAP_PALETTED_TRUECOLOR
+ ))
+ return FALSE;
+ }
+
+ vgaHWBlankScreen(pScrn, FALSE);
+
+ psav->CloseScreen = pScreen->CloseScreen;
+ pScreen->SaveScreen = SavageSaveScreen;
+ pScreen->CloseScreen = SavageCloseScreen;
+
+ if (xf86DPMSInit(pScreen, SavageDPMS, 0) == FALSE)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed\n");
+
+#ifdef XvExtension
+ if( !psav->NoAccel && !SavagePanningCheck(pScrn) )
+ SavageInitVideo( pScreen );
+#endif
+
+ if (serverGeneration == 1)
+ xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+
+ return TRUE;
+}
+
+
+static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen)
+{
+ int ret = TRUE;
+ ScrnInfoPtr pScrn;
+ SavagePtr psav;
+ int width, height, displayWidth;
+ unsigned char *FBStart;
+
+ TRACE(("SavageInternalScreenInit()\n"));
+
+ pScrn = xf86Screens[pScreen->myNum];
+ psav = SAVPTR(pScrn);
+
+ displayWidth = pScrn->displayWidth;
+
+ if (psav->rotate) {
+ height = pScrn->virtualX;
+ width = pScrn->virtualY;
+ } else {
+ width = pScrn->virtualX;
+ height = pScrn->virtualY;
+ }
+
+
+ if(psav->shadowFB) {
+ psav->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
+ psav->ShadowPtr = xalloc(psav->ShadowPitch * height);
+ displayWidth = psav->ShadowPitch / (pScrn->bitsPerPixel >> 3);
+ FBStart = psav->ShadowPtr;
+ } else {
+ psav->ShadowPtr = NULL;
+ FBStart = psav->FBStart;
+ }
+
+ ret = fbScreenInit(pScreen, FBStart, width, height,
+ pScrn->xDpi, pScrn->yDpi,
+ displayWidth,
+ pScrn->bitsPerPixel);
+ return ret;
+}
+
+
+static ModeStatus SavageValidMode(int index, DisplayModePtr pMode,
+ Bool verbose, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[index];
+ SavagePtr psav = SAVPTR(pScrn);
+
+ TRACE(("SavageValidMode\n"));
+
+ /* We prohibit modes bigger than the LCD panel. */
+ /* TODO We should do this only if the panel is active. */
+
+ if( psav->TvOn )
+ {
+ if( pMode->HDisplay > psav->TVSizeX )
+ return MODE_VIRTUAL_X;
+
+ if( pMode->VDisplay > psav->TVSizeY )
+ return MODE_VIRTUAL_Y;
+
+ }
+ if(
+ !psav->CrtOnly &&
+ psav->PanelX &&
+ (
+ (pMode->HDisplay > psav->PanelX) ||
+ (pMode->VDisplay > psav->PanelY)
+ )
+ )
+ return MODE_PANEL;
+
+ return MODE_OK;
+}
+
+static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
+{
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ int width, dclk, i, j; /*, refresh; */
+ unsigned int m, n, r;
+ unsigned char tmp = 0;
+ SavageRegPtr new = &psav->ModeReg;
+ vgaRegPtr vganew = &hwp->ModeReg;
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+
+ TRACE(("SavageModeInit(%dx%d, %dHz)\n",
+ mode->HDisplay, mode->VDisplay, mode->Clock));
+
+#if 0
+ ErrorF("Clock = %d, HDisplay = %d, HSStart = %d\n",
+ mode->Clock, mode->HDisplay, mode->HSyncStart);
+ ErrorF("HSEnd = %d, HSkew = %d\n",
+ mode->HSyncEnd, mode->HSkew);
+ ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
+ mode->VDisplay, mode->VSyncStart, mode->VSyncEnd);
+ ErrorF("VTotal = %d\n",
+ mode->VTotal);
+ ErrorF("HDisplay = %d, HSStart = %d\n",
+ mode->CrtcHDisplay, mode->CrtcHSyncStart);
+ ErrorF("HSEnd = %d, HSkey = %d\n",
+ mode->CrtcHSyncEnd, mode->CrtcHSkew);
+ ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
+ mode->CrtcVDisplay, mode->CrtcVSyncStart, mode->CrtcVSyncEnd);
+ ErrorF("VTotal = %d\n",
+ mode->CrtcVTotal);
+#endif
+
+
+
+ if (pScrn->bitsPerPixel == 8)
+ psav->HorizScaleFactor = 1;
+ else if (pScrn->bitsPerPixel == 16)
+ psav->HorizScaleFactor = 1; /* I don't think we ever want 2 */
+ else
+ psav->HorizScaleFactor = 1;
+
+ if (psav->HorizScaleFactor == 2)
+ if (!mode->CrtcHAdjusted) {
+ mode->CrtcHDisplay *= 2;
+ mode->CrtcHSyncStart *= 2;
+ mode->CrtcHSyncEnd *= 2;
+ mode->CrtcHTotal *= 2;
+ mode->CrtcHSkew *= 2;
+ mode->CrtcHAdjusted = TRUE;
+ }
+
+ if (!vgaHWInit(pScrn, mode))
+ return FALSE;
+
+ new->mode = 0;
+
+ /* We need to set CR67 whether or not we use the BIOS. */
+
+ dclk = mode->Clock;
+ new->CR67 = 0x00;
+
+ switch( pScrn->depth ) {
+ case 8:
+ if( (psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000) )
+ new->CR67 = 0x10; /* 8bpp, 2 pixels/clock */
+ else
+ new->CR67 = 0x00; /* 8bpp, 1 pixel/clock */
+ break;
+ case 15:
+ if(
+ S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+ ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
+ )
+ new->CR67 = 0x30; /* 15bpp, 2 pixel/clock */
+ else
+ new->CR67 = 0x20; /* 15bpp, 1 pixels/clock */
+ break;
+ case 16:
+ if(
+ S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+ ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
+ )
+ new->CR67 = 0x50; /* 16bpp, 2 pixel/clock */
+ else
+ new->CR67 = 0x40; /* 16bpp, 1 pixels/clock */
+ break;
+ case 24:
+ if (pScrn->bitsPerPixel == 24 )
+ new->CR67 = 0x70;
+ else
+ new->CR67 = 0xd0;
+ break;
+ }
+
+ if( psav->UseBIOS ) {
+ int refresh;
+ SavageModeEntryPtr pmt;
+
+ /* Scan through our BIOS list to locate the closest valid mode. */
+
+ /* If we ever break 4GHz clocks on video boards, we'll need to
+ * change this.
+ */
+
+ refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
+
+#ifdef EXTENDED_DEBUG
+ ErrorF( "Desired refresh rate = %dHz\n", refresh );
+#endif
+
+ for( i = 0, pmt = psav->ModeTable->Modes;
+ i < psav->ModeTable->NumModes;
+ i++, pmt++ )
+ {
+ if( (pmt->Width == mode->HDisplay) &&
+ (pmt->Height == mode->VDisplay) )
+ {
+ int jDelta = 99;
+ int jBest = 0;
+
+ /* We have an acceptable mode. Find a refresh rate. */
+
+ new->mode = pmt->VesaMode;
+ for( j = 0; j < pmt->RefreshCount; j++ )
+ {
+ if( pmt->RefreshRate[j] == refresh )
+ {
+ /* Exact match. */
+ jBest = j;
+ break;
+ }
+ else if( iabs(pmt->RefreshRate[j] - refresh) < jDelta )
+ {
+ jDelta = iabs(pmt->RefreshRate[j] - refresh);
+ jBest = j;
+ }
+ }
+
+ new->refresh = pmt->RefreshRate[jBest];
+ break;
+ }
+ }
+
+ if( new->mode ) {
+ /* Success: we found a match in the BIOS. */
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "Chose mode %x at %dHz.\n", new->mode, new->refresh );
+ }
+ else {
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "No suitable BIOS mode found for %dx%d %dMHz.\n",
+ mode->HDisplay, mode->VDisplay, mode->Clock/1000 );
+ }
+ }
+
+ if( !new->mode ) {
+ /*
+ * Either BIOS use is disabled, or we failed to find a suitable
+ * match. Fall back to traditional register-crunching.
+ */
+
+ VGAOUT8(vgaCRIndex, 0x3a);
+ tmp = VGAIN8(vgaCRReg);
+ if (psav->pci_burst)
+ new->CR3A = (tmp & 0x7f) | 0x15;
+ else
+ new->CR3A = tmp | 0x95;
+
+ new->CR53 = 0x00;
+ new->CR31 = 0x8c;
+ new->CR66 = 0x89;
+
+ VGAOUT8(vgaCRIndex, 0x58);
+ new->CR58 = VGAIN8(vgaCRReg) & 0x80;
+ new->CR58 |= 0x13;
+
+#if 0
+ VGAOUT8(vgaCRIndex, 0x55);
+ new->CR55 = VGAIN8(vgaCRReg);
+ if (psav->hwcursor)
+ new->CR55 |= 0x10;
+#endif
+
+ new->SR15 = 0x03 | 0x80;
+ new->SR18 = 0x00;
+
+/* VGAOUT8(0x3c4, 0x1b);
+ new->SR1B = VGAIN8(0x3c5);
+ if( pScrn->depth == 24 )
+ new->SR1B |= 0x28;
+*/
+ if( pScrn->depth == 24 )
+ new->SR1B = 0x28;
+ else
+ new->SR1B = 0x00;
+
+
+ new->CR43 = new->CR45 = new->CR65 = 0x00;
+
+ VGAOUT8(vgaCRIndex, 0x40);
+ new->CR40 = VGAIN8(vgaCRReg) & ~0x01;
+
+ new->MMPR0 = 0x010400;
+ new->MMPR1 = 0x00;
+ new->MMPR2 = 0x0808;
+ new->MMPR3 = 0x08080810;
+
+ if (psav->fifo_aggressive || psav->fifo_moderate ||
+ psav->fifo_conservative) {
+ new->MMPR1 = 0x0200;
+ new->MMPR2 = 0x1808;
+ new->MMPR3 = 0x08081810;
+ }
+
+ if (psav->MCLK <= 0) {
+ new->SR10 = 255;
+ new->SR11 = 255;
+ }
+
+ psav->NeedSTREAMS = FALSE;
+
+ SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000,
+ &m, &n, &r);
+ new->SR12 = (r << 6) | (n & 0x3f);
+ new->SR13 = m & 0xff;
+ new->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
+
+ if (psav->fifo_moderate) {
+ if (pScrn->bitsPerPixel < 24)
+ new->MMPR0 -= 0x8000;
+ else
+ new->MMPR0 -= 0x4000;
+ } else if (psav->fifo_aggressive) {
+ if (pScrn->bitsPerPixel < 24)
+ new->MMPR0 -= 0xc000;
+ else
+ new->MMPR0 -= 0x6000;
+ }
+
+ if (mode->Flags & V_INTERLACE)
+ new->CR42 = 0x20;
+ else
+ new->CR42 = 0x00;
+
+ new->CR34 = 0x10;
+
+ i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
+ ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
+ ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
+ ((mode->CrtcHSyncStart & 0x800) >> 7);
+
+ if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
+ i |= 0x08;
+ if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
+ i |= 0x20;
+ j = (vganew->CRTC[0] + ((i & 0x01) << 8) +
+ vganew->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
+ if (j - (vganew->CRTC[4] + ((i & 0x10) << 4)) < 4) {
+ if (vganew->CRTC[4] + ((i & 0x10) << 4) + 4 <=
+ vganew->CRTC[0] + ((i & 0x01) << 8))
+ j = vganew->CRTC[4] + ((i & 0x10) << 4) + 4;
+ else
+ j = vganew->CRTC[0] + ((i & 0x01) << 8) + 1;
+ }
+
+ new->CR3B = j & 0xff;
+ i |= (j & 0x100) >> 2;
+ new->CR3C = (vganew->CRTC[0] + ((i & 0x01) << 8)) / 2;
+ new->CR5D = i;
+ new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10) |
+ (((mode->CrtcVDisplay - 1) & 0x400) >> 9) |
+ (((mode->CrtcVSyncStart) & 0x400) >> 8) |
+ (((mode->CrtcVSyncStart) & 0x400) >> 6) | 0x40;
+ width = (pScrn->displayWidth * (pScrn->bitsPerPixel / 8)) >> 3;
+ new->CR91 = vganew->CRTC[19] = 0xff & width;
+ new->CR51 = (0x300 & width) >> 4;
+ new->CR90 = 0x80 | (width >> 8);
+ vganew->MiscOutReg |= 0x0c;
+
+ /* Set frame buffer description. */
+
+ if (pScrn->bitsPerPixel <= 8)
+ new->CR50 = 0;
+ else if (pScrn->bitsPerPixel <= 16)
+ new->CR50 = 0x10;
+ else
+ new->CR50 = 0x30;
+
+ if (pScrn->displayWidth == 640)
+ new->CR50 |= 0x40;
+ else if (pScrn->displayWidth == 800)
+ new->CR50 |= 0x80;
+ else if (pScrn->displayWidth == 1024)
+ new->CR50 |= 0x00;
+ else if (pScrn->displayWidth == 1152)
+ new->CR50 |= 0x01;
+ else if (pScrn->displayWidth == 1280)
+ new->CR50 |= 0xc0;
+ else if (pScrn->displayWidth == 1600)
+ new->CR50 |= 0x81;
+ else
+ new->CR50 |= 0xc1; /* Use GBD */
+
+ if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
+ new->CR33 = 0x00;
+ else
+ new->CR33 = 0x08;
+
+ vganew->CRTC[0x17] = 0xeb;
+
+ new->CR67 |= 1;
+
+ VGAOUT8(vgaCRIndex, 0x36);
+ new->CR36 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x68);
+ new->CR68 = VGAIN8(vgaCRReg);
+ new->CR69 = 0;
+ VGAOUT8(vgaCRIndex, 0x6f);
+ new->CR6F = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRIndex, 0x88);
+ new->CR86 = VGAIN8(vgaCRReg) | 0x08;
+ VGAOUT8(vgaCRIndex, 0xb0);
+ new->CRB0 = VGAIN8(vgaCRReg) | 0x80;
+ }
+
+ pScrn->vtSema = TRUE;
+
+ /* do it! */
+ SavageWriteMode(pScrn, vganew, new, TRUE);
+ SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+ return TRUE;
+}
+
+
+static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ vgaRegPtr vgaSavePtr = &hwp->SavedReg;
+ SavageRegPtr SavageSavePtr = &psav->SavedReg;
+
+ TRACE(("SavageCloseScreen\n"));
+
+ if (psav->pVbe)
+ vbeFree(psav->pVbe);
+ psav->pVbe = NULL;
+
+ if( psav->AccelInfoRec ) {
+ XAADestroyInfoRec( psav->AccelInfoRec );
+ psav->AccelInfoRec = NULL;
+ }
+
+ if( psav->DGAModes ) {
+ xfree( psav->DGAModes );
+ psav->DGAModes = NULL;
+ psav->numDGAModes = 0;
+ }
+
+ if (pScrn->vtSema) {
+ SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
+ vgaHWLock(hwp);
+ SavageUnmapMem(pScrn, 0);
+ }
+
+ pScrn->vtSema = FALSE;
+ pScreen->CloseScreen = psav->CloseScreen;
+
+ return (*pScreen->CloseScreen)(scrnIndex, pScreen);
+}
+
+
+static Bool SavageSaveScreen(ScreenPtr pScreen, int mode)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ TRACE(("SavageSaveScreen(0x%x)\n", mode));
+
+ if( pScrn->vtSema && SAVPTR(pScrn)->hwcursor && SAVPTR(pScrn)->hwc_on) {
+
+ if( xf86IsUnblank(mode) )
+ SavageShowCursor( pScrn );
+ else
+ SavageHideCursor( pScrn );
+ SAVPTR(pScrn)->hwc_on = TRUE;
+ }
+
+ return vgaHWSaveScreen(pScreen, mode);
+}
+
+
+void SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ int Base;
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+
+ TRACE(("SavageAdjustFrame(%d,%d,%x)\n", x, y, flags));
+
+ if (psav->ShowCache && y)
+ y += pScrn->virtualY - 1;
+
+ Base = ((y * pScrn->displayWidth + (x&~1)) *
+ (pScrn->bitsPerPixel / 8)) >> 2;
+ /* now program the start address registers */
+ VGAOUT16(vgaCRIndex, (Base & 0x00ff00) | 0x0c);
+ VGAOUT16(vgaCRIndex, ((Base & 0x00ff) << 8) | 0x0d);
+ VGAOUT8(vgaCRIndex, 0x69);
+ VGAOUT8(vgaCRReg, (Base & 0x7f0000) >> 16);
+
+ return;
+}
+
+
+Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ TRACE(("SavageSwitchMode\n"));
+ return SavageModeInit(xf86Screens[scrnIndex], mode);
+}
+
+
+void SavageEnableMMIO(ScrnInfoPtr pScrn)
+{
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ int vgaCRIndex, vgaCRReg;
+ unsigned char val;
+
+ TRACE(("SavageEnableMMIO\n"));
+
+ vgaHWSetStdFuncs(hwp);
+ vgaHWSetMmioFuncs(hwp, psav->MapBase, 0x8000);
+ val = VGAIN8(0x3c3);
+ VGAOUT8(0x3c3, val | 0x01);
+ val = VGAIN8(VGA_MISC_OUT_R);
+ VGAOUT8(VGA_MISC_OUT_W, val | 0x01);
+ vgaCRIndex = psav->vgaIOBase + 4;
+ vgaCRReg = psav->vgaIOBase + 5;
+
+ if( psav->Chipset >= S3_SAVAGE4 )
+ {
+ VGAOUT8(vgaCRIndex, 0x40);
+ val = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, val | 1);
+ }
+
+ return;
+}
+
+
+void SavageDisableMMIO(ScrnInfoPtr pScrn)
+{
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ int vgaCRIndex, vgaCRReg;
+ unsigned char val;
+
+ TRACE(("SavageDisableMMIO\n"));
+
+ vgaCRIndex = psav->vgaIOBase + 4;
+ vgaCRReg = psav->vgaIOBase + 5;
+
+ if( psav->Chipset >= S3_SAVAGE4 )
+ {
+ VGAOUT8(vgaCRIndex, 0x40);
+ val = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, val | 1);
+ }
+
+ vgaHWSetStdFuncs(hwp);
+
+ return;
+}
+
+void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
+ LOCO *colors, VisualPtr pVisual)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int i, index;
+
+ for (i=0; i<numColors; i++) {
+ index = indicies[i];
+ VGAOUT8(0x3c8, index);
+ VGAOUT8(0x3c9, colors[index].red);
+ VGAOUT8(0x3c9, colors[index].green);
+ VGAOUT8(0x3c9, colors[index].blue);
+ }
+}
+
+#define inStatus1() (hwp->readST01( hwp ))
+
+void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors, int *indicies,
+ LOCO *colors, VisualPtr pVisual)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int i, index;
+
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+ VerticalRetraceWait(psav);
+
+ for (i=0; i<numColors; i++) {
+ if (!(inStatus1()) & 0x08)
+ VerticalRetraceWait(psav);
+ index = indicies[i];
+ VGAOUT8(0x3c8, index);
+ VGAOUT8(0x3c9, colors[index].red);
+ VGAOUT8(0x3c9, colors[index].green);
+ VGAOUT8(0x3c9, colors[index].blue);
+ }
+}
+
+
+
+static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
+
+ /* Make sure linear addressing is enabled after the BIOS call. */
+ /* Note that we must use an I/O port to do this. */
+ int min_n2, int max_n2, long freq_min,
+ long freq_max, unsigned int *mdiv,
+ unsigned int *ndiv, unsigned int *r)
+{
+ double ffreq, ffreq_min, ffreq_max;
+ double div, diff, best_diff;
+ unsigned int m;
+ unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
+
+ ffreq = freq / 1000.0 / BASE_FREQ;
+ ffreq_max = freq_max / 1000.0 / BASE_FREQ;
+ ffreq_min = freq_min / 1000.0 / BASE_FREQ;
+
+ if (ffreq < ffreq_min / (1 << max_n2)) {
+ ErrorF("invalid frequency %1.3f Mhz\n",
+ ffreq*BASE_FREQ);
+ ffreq = ffreq_min / (1 << max_n2);
+ }
+ if (ffreq > ffreq_max / (1 << min_n2)) {
+ ErrorF("invalid frequency %1.3f Mhz\n",
+ ffreq*BASE_FREQ);
+ ffreq = ffreq_max / (1 << min_n2);
+ }
+
+ /* work out suitable timings */
+
+ best_diff = ffreq;
+
+ for (n2=min_n2; n2<=max_n2; n2++) {
+ for (n1=min_n1+2; n1<=max_n1+2; n1++) {
+ m = (int)(ffreq * n1 * (1 << n2) + 0.5);
+ if (m < min_m+2 || m > 127+2)
+ continue;
+ div = (double)(m) / (double)(n1);
+ if ((div >= ffreq_min) &&
+ (div <= ffreq_max)) {
+ diff = ffreq - div / (1 << n2);
+ if (diff < 0.0)
+ diff = -diff;
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_m = m;
+ best_n1 = n1;
+ best_n2 = n2;
+ }
+ }
+ }
+ }
+
+ *ndiv = best_n1 - 2;
+ *r = best_n2;
+ *mdiv = best_m - 2;
+}
+
+
+void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file)
+{
+ unsigned char cr66;
+ int r, success = 0;
+ CARD32 fifo_control = 0, miu_control = 0;
+ CARD32 streams_timeout = 0, misc_timeout = 0;
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+
+ TRACE(("SavageGEReset(%d,%s)\n", line, file));
+
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+
+ if (from_timeout) {
+ if (psav->GEResetCnt++ < 10 || xf86GetVerbosity() > 1)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "SavageGEReset called from %s line %d\n", file, line);
+ } else
+ psav->WaitIdleEmpty(psav);
+
+ if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
+ fifo_control = INREG(FIFO_CONTROL_REG);
+ miu_control = INREG(MIU_CONTROL_REG);
+ streams_timeout = INREG(STREAMS_TIMEOUT_REG);
+ misc_timeout = INREG(MISC_TIMEOUT_REG);
+ }
+
+ VGAOUT8(vgaCRIndex, 0x66);
+ cr66 = VGAIN8(vgaCRReg);
+
+ usleep(10000);
+ for (r=1; r<10; r++) {
+ VGAOUT8(vgaCRReg, cr66 | 0x02);
+ usleep(10000);
+ VGAOUT8(vgaCRReg, cr66 & ~0x02);
+ usleep(10000);
+
+ if (!from_timeout)
+ psav->WaitIdleEmpty(psav);
+ OUTREG(DEST_SRC_STR, psav->Bpl << 16 | psav->Bpl);
+
+ usleep(10000);
+ switch(psav->Chipset) {
+ case S3_SAVAGE3D:
+ case S3_SAVAGE_MX:
+ success = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
+ break;
+ case S3_SAVAGE4:
+ case S3_PROSAVAGE:
+ case S3_SUPERSAVAGE:
+ success = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
+ break;
+ case S3_SAVAGE2000:
+ success = (ALT_STATUS_WORD0 & 0x008fffff) == 0;
+ break;
+ }
+ if(!success) {
+ usleep(10000);
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "restarting S3 graphics engine reset %2d ...\n", r);
+ }
+ else
+ break;
+ }
+
+ /* At this point, the FIFO is empty and the engine is idle. */
+
+ if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
+ OUTREG(FIFO_CONTROL_REG, fifo_control);
+ OUTREG(MIU_CONTROL_REG, miu_control);
+ OUTREG(STREAMS_TIMEOUT_REG, streams_timeout);
+ OUTREG(MISC_TIMEOUT_REG, misc_timeout);
+ }
+
+ OUTREG(SRC_BASE, 0);
+ OUTREG(DEST_BASE, 0);
+ OUTREG(CLIP_L_R, ((0) << 16) | pScrn->displayWidth);
+ OUTREG(CLIP_T_B, ((0) << 16) | psav->ScissB);
+ OUTREG(MONO_PAT_0, ~0);
+ OUTREG(MONO_PAT_1, ~0);
+
+ SavageSetGBD(pScrn);
+}
+
+
+
+/* This function is used to debug, it prints out the contents of s3 regs */
+
+void
+SavagePrintRegs(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char i;
+ int vgaCRIndex = 0x3d4;
+ int vgaCRReg = 0x3d5;
+
+ ErrorF( "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
+
+ for( i = 0; i < 0x70; i++ ) {
+ if( !(i % 16) )
+ ErrorF( "\nSR%xx ", i >> 4 );
+ VGAOUT8( 0x3c4, i );
+ ErrorF( " %02x", VGAIN8(0x3c5) );
+ }
+
+ ErrorF( "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
+
+ for( i = 0; i < 0xB7; i++ ) {
+ if( !(i % 16) )
+ ErrorF( "\nCR%xx ", i >> 4 );
+ VGAOUT8( vgaCRIndex, i );
+ ErrorF( " %02x", VGAIN8(vgaCRReg) );
+ }
+
+ ErrorF("\n\n");
+}
+
+
+static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char sr8 = 0x00, srd = 0x00;
+
+ TRACE(("SavageDPMS(%d,%x)\n", mode, flags));
+
+ VGAOUT8(0x3c4, 0x08);
+ sr8 = VGAIN8(0x3c5);
+ sr8 |= 0x06;
+ VGAOUT8(0x3c5, sr8);
+
+ VGAOUT8(0x3c4, 0x0d);
+ srd = VGAIN8(0x3c5);
+
+ srd &= 0x03;
+
+ switch (mode) {
+ case DPMSModeOn:
+ break;
+ case DPMSModeStandby:
+ srd |= 0x10;
+ break;
+ case DPMSModeSuspend:
+ srd |= 0x40;
+ break;
+ case DPMSModeOff:
+ srd |= 0x50;
+ break;
+ default:
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
+ break;
+ }
+
+ VGAOUT8(0x3c4, 0x0d);
+ VGAOUT8(0x3c5, srd);
+
+ return;
+}
+
+
+static unsigned int
+SavageDDC1Read(ScrnInfoPtr pScrn)
+{
+ register vgaHWPtr hwp = VGAHWPTR(pScrn);
+ register unsigned char tmp;
+ SavagePtr psav = SAVPTR(pScrn);
+
+ VerticalRetraceWait(psav);
+
+ InI2CREG(psav,tmp);
+ while (hwp->readST01(hwp)&0x8) {};
+ while (!(hwp->readST01(hwp)&0x8)) {};
+
+ return ((unsigned int) (tmp & 0x08));
+}
+
+static Bool
+SavageDDC1(int scrnIndex)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char tmp;
+ Bool success = FALSE;
+ xf86MonPtr pMon;
+
+ /* initialize chipset */
+ InI2CREG(psav,tmp);
+ OutI2CREG(psav,tmp | 0x12);
+
+ if ((pMon = xf86PrintEDID(
+ xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeed,SavageDDC1Read))) != NULL)
+ success = TRUE;
+ xf86SetDDCproperties(pScrn,pMon);
+
+ /* undo initialization */
+ OutI2CREG(psav,tmp);
+ return success;
+}
+
+
+static void
+SavageProbeDDC(ScrnInfoPtr pScrn, int index)
+{
+ vbeInfoPtr pVbe;
+ if (xf86LoadSubModule(pScrn, "vbe")) {
+ pVbe = VBEInit(NULL,index);
+ ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
+ vbeFree(pVbe);
+ }
+}
+
+
+static void
+SavageGetTvMaxSize(SavagePtr psav)
+{
+ if( psav->PAL ) {
+ psav->TVSizeX = 800;
+ psav->TVSizeY = 600;
+ }
+ else {
+ psav->TVSizeX = 640;
+ psav->TVSizeY = 480;
+ }
+}
+
+
+static Bool
+SavagePanningCheck(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ DisplayModePtr pMode;
+
+ pMode = pScrn->currentMode;
+ psav->iResX = pMode->CrtcHDisplay;
+ psav->iResY = pMode->CrtcVDisplay;
+ if( psav->iResX < pScrn->virtualX || psav->iResY < pScrn->virtualY )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
diff --git a/src/savage_driver.h b/src/savage_driver.h
new file mode 100644
index 0000000..2311396
--- /dev/null
+++ b/src/savage_driver.h
@@ -0,0 +1,278 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_driver.h,v 1.16 2003/01/18 15:22:30 eich Exp $ */
+
+#ifndef SAVAGE_VGAHWMMIO_H
+#define SAVAGE_VGAHWMMIO_H
+
+#include "xf86_ansic.h"
+#include "compiler.h"
+#include "vgaHW.h"
+#include "xf86.h"
+#include "xf86Resources.h"
+#include "xf86Pci.h"
+#include "xf86PciInfo.h"
+#include "xf86_OSproc.h"
+#include "xf86Cursor.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include "fb.h"
+#include "xf86cmap.h"
+#include "vbe.h"
+#include "xaa.h"
+#include "xf86xv.h"
+
+#include "savage_regs.h"
+
+#define VGAIN8(addr) MMIO_IN8(psav->MapBase+0x8000, addr)
+#define VGAIN16(addr) MMIO_IN16(psav->MapBase+0x8000, addr)
+#define VGAIN(addr) MMIO_IN32(psav->MapBase+0x8000, addr)
+
+#define VGAOUT8(addr,val) MMIO_OUT8(psav->MapBase+0x8000, addr, val)
+#define VGAOUT16(addr,val) MMIO_OUT16(psav->MapBase+0x8000, addr, val)
+#define VGAOUT(addr,val) MMIO_OUT32(psav->MapBase+0x8000, addr, val)
+
+#define INREG(addr) MMIO_IN32(psav->MapBase, addr)
+#define OUTREG(addr,val) MMIO_OUT32(psav->MapBase, addr, val)
+#define INREG16(addr) MMIO_IN16(psav->MapBase, addr)
+#define OUTREG16(addr,val) MMIO_OUT16(psav->MapBase, addr, val)
+
+#define SAVAGE_CRT_ON 1
+#define SAVAGE_LCD_ON 2
+#define SAVAGE_TV_ON 4
+
+typedef struct _S3VMODEENTRY {
+ unsigned short Width;
+ unsigned short Height;
+ unsigned short VesaMode;
+ unsigned char RefreshCount;
+ unsigned char * RefreshRate;
+} SavageModeEntry, *SavageModeEntryPtr;
+
+
+typedef struct _S3VMODETABLE {
+ unsigned short NumModes;
+ SavageModeEntry Modes[1];
+} SavageModeTableRec, *SavageModeTablePtr;
+
+
+typedef struct {
+ unsigned int mode, refresh;
+ unsigned char SR08, SR0E, SR0F;
+ unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR1B, SR29, SR30;
+ unsigned char SR54[8];
+ unsigned char Clock;
+ unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C;
+ unsigned char CR40, CR41, CR42, CR43, CR45;
+ unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E;
+ unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F;
+ unsigned char CR86, CR88;
+ unsigned char CR90, CR91, CRB0;
+ unsigned int STREAMS[22]; /* yuck, streams regs */
+ unsigned int MMPR0, MMPR1, MMPR2, MMPR3;
+} SavageRegRec, *SavageRegPtr;
+
+
+typedef struct _Savage {
+ SavageRegRec SavedReg;
+ SavageRegRec ModeReg;
+ xf86CursorInfoPtr CursorInfoRec;
+ Bool ModeStructInit;
+ Bool NeedSTREAMS;
+ Bool STREAMSRunning;
+ int Bpp, Bpl, ScissB;
+ unsigned PlaneMask;
+ I2CBusPtr I2C;
+
+ int videoRambytes;
+ int videoRamKbytes;
+ int MemOffScreen;
+ CARD32 CursorKByte;
+
+ /* These are physical addresses. */
+ unsigned long FrameBufferBase;
+ unsigned long MmioBase;
+ unsigned long ShadowPhysical;
+
+ /* These are linear addresses. */
+ unsigned char* MapBase;
+ unsigned char* BciMem;
+ unsigned char* MapBaseDense;
+ unsigned char* FBBase;
+ unsigned char* FBStart;
+ CARD32 volatile * ShadowVirtual;
+
+ Bool PrimaryVidMapped;
+ int dacSpeedBpp;
+ int minClock, maxClock;
+ int HorizScaleFactor;
+ int MCLK, REFCLK, LCDclk;
+ double refclk_fact;
+ int GEResetCnt;
+
+ /* Here are all the Options */
+
+ OptionInfoPtr Options;
+ Bool ShowCache;
+ Bool pci_burst;
+ Bool NoPCIRetry;
+ Bool fifo_conservative;
+ Bool fifo_moderate;
+ Bool fifo_aggressive;
+ Bool hwcursor;
+ Bool hwc_on;
+ Bool NoAccel;
+ Bool shadowFB;
+ Bool UseBIOS;
+ int rotate;
+ double LCDClock;
+ Bool ShadowStatus;
+ Bool CrtOnly;
+ Bool TvOn;
+ Bool PAL;
+ Bool ForceInit;
+ int iDevInfo;
+ int iDevInfoPrim;
+
+ int PanelX; /* panel width */
+ int PanelY; /* panel height */
+ int iResX; /* crtc X display */
+ int iResY; /* crtc Y display */
+ int XFactor; /* overlay X factor */
+ int YFactor; /* overlay Y factor */
+ int displayXoffset; /* overlay X offset */
+ int displayYoffset; /* overlay Y offset */
+ int XExpansion; /* expansion factor in x */
+ int XExp1;
+ int XExp2;
+ int YExpansion; /* expansion factor in x */
+ int YExp1;
+ int YExp2;
+ int cxScreen;
+ int TVSizeX;
+ int TVSizeY;
+
+ CloseScreenProcPtr CloseScreen;
+ pciVideoPtr PciInfo;
+ PCITAG PciTag;
+ int Chipset;
+ int ChipId;
+ int ChipRev;
+ vbeInfoPtr pVbe;
+ int EntityIndex;
+ int ShadowCounter;
+ int vgaIOBase; /* 3b0 or 3d0 */
+
+ /* The various Savage wait handlers. */
+ int (*WaitQueue)(struct _Savage *, int);
+ int (*WaitIdle)(struct _Savage *);
+ int (*WaitIdleEmpty)(struct _Savage *);
+
+ /* Support for shadowFB and rotation */
+ unsigned char * ShadowPtr;
+ int ShadowPitch;
+ void (*PointerMoved)(int index, int x, int y);
+
+ /* Support for XAA acceleration */
+ XAAInfoRecPtr AccelInfoRec;
+ xRectangle Rect;
+ unsigned int SavedBciCmd;
+ unsigned int SavedFgColor;
+ unsigned int SavedBgColor;
+ unsigned int SavedSbdOffset;
+ unsigned int SavedSbd;
+
+ /* Support for Int10 processing */
+ xf86Int10InfoPtr pInt10;
+ SavageModeTablePtr ModeTable;
+
+ /* Support for the Savage command overflow buffer. */
+ unsigned long cobIndex; /* size index */
+ unsigned long cobSize; /* size in bytes */
+ unsigned long cobOffset; /* offset in frame buffer */
+
+ /* Support for DGA */
+ int numDGAModes;
+ DGAModePtr DGAModes;
+ Bool DGAactive;
+ int DGAViewportStatus;
+
+ /* Support for XVideo */
+
+ unsigned int videoFlags;
+ unsigned int blendBase;
+ int videoFourCC;
+ XF86VideoAdaptorPtr adaptor;
+ int VideoZoomMax;
+ int dwBCIWait2DIdle;
+ XF86OffscreenImagePtr offscreenImages;
+
+} SavageRec, *SavagePtr;
+
+/* Video flags. */
+
+#define VF_STREAMS_ON 0x0001
+
+#define SAVPTR(p) ((SavagePtr)((p)->driverPrivate))
+
+/* Make the names of these externals driver-unique */
+#define gpScrn savagegpScrn
+#define myOUTREG savageOUTREG
+#define readdw savagereaddw
+#define readfb savagereadfb
+#define writedw savagewritedw
+#define writefb savagewritefb
+#define writescan savagewritescan
+
+/* Prototypes. */
+
+extern void SavageCommonCalcClock(long freq, int min_m, int min_n1,
+ int max_n1, int min_n2, int max_n2,
+ long freq_min, long freq_max,
+ unsigned char *mdiv, unsigned char *ndiv);
+void SavageAdjustFrame(int scrnIndex, int y, int x, int flags);
+Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
+
+/* In savage_cursor.c. */
+
+Bool SavageHWCursorInit(ScreenPtr pScreen);
+void SavageShowCursor(ScrnInfoPtr);
+void SavageHideCursor(ScrnInfoPtr);
+
+/* In savage_accel.c. */
+
+Bool SavageInitAccel(ScreenPtr);
+void SavageInitialize2DEngine(ScrnInfoPtr);
+void SavageSetGBD(ScrnInfoPtr);
+void SavageAccelSync(ScrnInfoPtr);
+
+/* In savage_i2c.c. */
+
+Bool SavageI2CInit(ScrnInfoPtr pScrn);
+
+/* In savage_shadow.c */
+
+void SavagePointerMoved(int index, int x, int y);
+void SavageRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
+void SavageRefreshArea8(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
+void SavageRefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
+void SavageRefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
+void SavageRefreshArea32(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
+
+/* In savage_vbe.c */
+
+void SavageSetTextMode( SavagePtr psav );
+void SavageSetVESAMode( SavagePtr psav, int n, int Refresh );
+void SavageFreeBIOSModeTable( SavagePtr psav, SavageModeTablePtr* ppTable );
+SavageModeTablePtr SavageGetBIOSModeTable( SavagePtr psav, int iDepth );
+
+unsigned short SavageGetBIOSModes(
+ SavagePtr psav,
+ int iDepth,
+ SavageModeEntryPtr s3vModeTable );
+
+
+/* In savage_video.c */
+
+void SavageInitVideo( ScreenPtr pScreen );
+
+#endif /* SAVAGE_VGAHWMMIO_H */
+
diff --git a/src/savage_i2c.c b/src/savage_i2c.c
new file mode 100644
index 0000000..01ac3e2
--- /dev/null
+++ b/src/savage_i2c.c
@@ -0,0 +1,93 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_i2c.c,v 1.3 2002/10/02 20:39:55 alanh Exp $ */
+
+/*
+Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the XFree86 Project shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the XFree86 Project.
+*/
+
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86_ansic.h"
+#include "compiler.h"
+
+#include "xf86Pci.h"
+#include "xf86PciInfo.h"
+
+#include "vgaHW.h"
+
+#include "savage_driver.h"
+
+static void
+SavageI2CPutBits(I2CBusPtr b, int clock, int data)
+{
+ ScrnInfoPtr pScrn = (ScrnInfoPtr)(xf86Screens[b->scrnIndex]);
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char reg = 0x10;
+
+ if(clock) reg |= 0x1;
+ if(data) reg |= 0x2;
+
+ OutI2CREG(psav,reg);
+ /*ErrorF("SavageI2CPutBits: %d %d\n", clock, data); */
+}
+
+static void
+SavageI2CGetBits(I2CBusPtr b, int *clock, int *data)
+{
+ ScrnInfoPtr pScrn = (ScrnInfoPtr)(xf86Screens[b->scrnIndex]);
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char reg = 0x10;
+
+ InI2CREG(psav,reg);
+
+ *clock = reg & 0x4;
+ *data = reg & 0x8;
+
+ /*ErrorF("SavageI2CGetBits: %d %d\n", *clock, *data); */
+}
+
+Bool
+SavageI2CInit(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ I2CBusPtr I2CPtr;
+
+ I2CPtr = xf86CreateI2CBusRec();
+ if(!I2CPtr) return FALSE;
+
+ psav->I2C = I2CPtr;
+
+ I2CPtr->BusName = "I2C bus";
+ I2CPtr->scrnIndex = pScrn->scrnIndex;
+ I2CPtr->I2CPutBits = SavageI2CPutBits;
+ I2CPtr->I2CGetBits = SavageI2CGetBits;
+
+ if (!xf86I2CBusInit(I2CPtr))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+
diff --git a/src/savage_image.c b/src/savage_image.c
new file mode 100644
index 0000000..8354622
--- /dev/null
+++ b/src/savage_image.c
@@ -0,0 +1,194 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_image.c,v 1.6 2002/05/14 20:19:52 alanh Exp $ */
+
+#include "savage_driver.h"
+#include "xaarop.h"
+#include "savage_bci.h"
+
+void SavageSubsequentImageWriteRect (
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ int skipleft);
+
+void SavageSetupForImageWrite (
+ ScrnInfoPtr pScrn,
+ int rop,
+ unsigned planemask,
+ int transparency_color,
+ int bpp,
+ int depth);
+
+void SavageWriteBitmapCPUToScreenColorExpand (
+ ScrnInfoPtr pScrn,
+ int x, int y, int w, int h,
+ unsigned char * src,
+ int srcwidth,
+ int skipleft,
+ int fg, int bg,
+ int rop,
+ unsigned int planemask);
+
+#if 0
+void SavageWriteBitmapScreenToScreenColorExpand(
+ ScrnPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ unsigned char * src,
+ int srcwidth,
+ int srcx,
+ int srcy,
+ int bg,
+ int fg,
+ int rop,
+ unsigned int planemask
+)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+ unsigned int cmd;
+ unsigned char * bd_offset;
+ unsigned int bd;
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+ | BCI_CMD_SEND_COLOR
+ | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SBD_MONO_NEW;
+ cmd |= (bg != -1) ? BCI_CMD_SEND_COLOR : BCI_CMD_SRC_TRANSPARENT;
+ cmd |= s3vAlu[rop];
+
+ bd |= BCI_BD_BW_DISABLE;
+ BCI_BD_SET_BPP(bd, 1);
+ BCI_BD_SET_STRIDE(bd, srcwidth);
+ bd_offset = srcwidth * srcy + (srcx >> 3) + src;
+
+ psav->WaitQueue(psav,10);
+ BCI_SEND(cmd);
+ BCI_SEND((unsigned int)bd_offset);
+ BCI_SEND(bd);
+ BCI_SEND(fg);
+ BCI_SEND((bg != -1) ? bg : 0);
+ BCI_SEND(BCI_X_Y(srcx, srcy));
+ BCI_SEND(BCI_X_Y(x, y));
+ BCI_SEND(BCI_W_H(w, h));
+}
+#endif
+
+void
+SavageWriteBitmapCPUToScreenColorExpand (
+ ScrnInfoPtr pScrn,
+ int x, int y, int w, int h,
+ unsigned char * src,
+ int srcwidth,
+ int skipleft,
+ int fg, int bg,
+ int rop,
+ unsigned int planemask
+)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+ int i, j, count, reset;
+ unsigned int cmd;
+ CARD32 * srcp;
+
+/* We aren't using planemask at all here... */
+
+ if( !srcwidth )
+ return;
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+ | BCI_CMD_SEND_COLOR | BCI_CMD_CLIP_LR
+ | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO;
+ cmd |= XAACopyROP[rop] << 16;
+
+ if( bg == -1 )
+ cmd |= BCI_CMD_SRC_TRANSPARENT;
+
+ BCI_SEND(cmd);
+ BCI_SEND(BCI_CLIP_LR(x+skipleft, x+w-1));
+ BCI_SEND(fg);
+ if( bg != -1 )
+ BCI_SEND(bg);
+
+ /* Bitmaps come in in units of DWORDS, LSBFirst. This is exactly */
+ /* reversed of what we expect. */
+
+ count = (w + 31) / 32;
+/* src += ((srcx & ~31) / 8); */
+
+ /* The BCI region is 128k bytes. A screen-sized mono bitmap can */
+ /* exceed that. */
+
+ reset = 65536 / count;
+
+ for (j = 0; j < h; j ++) {
+ BCI_SEND(BCI_X_Y(x, y+j));
+ BCI_SEND(BCI_W_H(w, 1));
+ srcp = (CARD32 *) src;
+ for (i = count; i > 0; srcp ++, i --) {
+ /* We have to invert the bits in each byte. */
+ CARD32 u = *srcp;
+ u = ((u & 0x0f0f0f0f) << 4) | ((u & 0xf0f0f0f0) >> 4);
+ u = ((u & 0x33333333) << 2) | ((u & 0xcccccccc) >> 2);
+ u = ((u & 0x55555555) << 1) | ((u & 0xaaaaaaaa) >> 1);
+ BCI_SEND(u);
+ }
+ src += srcwidth;
+ if( !--reset ) {
+ BCI_RESET;
+ reset = 65536 / count;
+ }
+ }
+}
+
+void
+SavageSetupForImageWrite(
+ ScrnInfoPtr pScrn,
+ int rop,
+ unsigned planemask,
+ int transparency_color,
+ int bpp,
+ int depth)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int cmd;
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
+ | BCI_CMD_CLIP_LR
+ | BCI_CMD_DEST_GBD | BCI_CMD_SRC_COLOR;
+
+ cmd |= XAACopyROP[rop] << 16;
+
+ if( transparency_color != -1 )
+ cmd |= BCI_CMD_SRC_TRANSPARENT;
+
+ psav->SavedBciCmd = cmd;
+ psav->SavedBgColor = transparency_color;
+}
+
+
+void SavageSubsequentImageWriteRect
+(
+ ScrnInfoPtr pScrn,
+ int x,
+ int y,
+ int w,
+ int h,
+ int skipleft)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ BCI_GET_PTR;
+ int count;
+
+ count = ((w * pScrn->bitsPerPixel + 31) / 32) * h;
+ psav->WaitQueue( psav, count );
+ BCI_SEND(psav->SavedBciCmd);
+ BCI_SEND(BCI_CLIP_LR(x+skipleft, x+w-1));
+ if( psav->SavedBgColor != -1 )
+ BCI_SEND(psav->SavedBgColor);
+ BCI_SEND(BCI_X_Y(x, y));
+ BCI_SEND(BCI_W_H(w, h));
+}
diff --git a/src/savage_regs.h b/src/savage_regs.h
new file mode 100644
index 0000000..602d2bc
--- /dev/null
+++ b/src/savage_regs.h
@@ -0,0 +1,222 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_regs.h,v 1.12 2002/10/02 20:39:55 alanh Exp $ */
+
+#ifndef _SAVAGE_REGS_H
+#define _SAVAGE_REGS_H
+
+/* These are here until xf86PciInfo.h is updated. */
+
+#ifndef PCI_CHIP_S3TWISTER_P
+#define PCI_CHIP_S3TWISTER_P 0x8d01
+#endif
+#ifndef PCI_CHIP_S3TWISTER_K
+#define PCI_CHIP_S3TWISTER_K 0x8d02
+#endif
+#ifndef PCI_CHIP_SUPSAV_MX128
+#define PCI_CHIP_SUPSAV_MX128 0x8c22
+#define PCI_CHIP_SUPSAV_MX64 0x8c24
+#define PCI_CHIP_SUPSAV_MX64C 0x8c26
+#define PCI_CHIP_SUPSAV_IX128SDR 0x8c2a
+#define PCI_CHIP_SUPSAV_IX128DDR 0x8c2b
+#define PCI_CHIP_SUPSAV_IX64SDR 0x8c2c
+#define PCI_CHIP_SUPSAV_IX64DDR 0x8c2d
+#define PCI_CHIP_SUPSAV_IXCSDR 0x8c2e
+#define PCI_CHIP_SUPSAV_IXCDDR 0x8c2f
+#endif
+#ifndef PCI_CHIP_PROSAVAGE_DDR
+#define PCI_CHIP_PROSAVAGE_DDR 0x8d03
+#define PCI_CHIP_PROSAVAGE_DDRK 0x8d04
+#endif
+
+#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE4_SERIES(chip) ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE))
+
+#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
+
+#define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+
+
+/* Chip tags. These are used to group the adapters into
+ * related families.
+ */
+
+enum S3CHIPTAGS {
+ S3_UNKNOWN = 0,
+ S3_SAVAGE3D,
+ S3_SAVAGE_MX,
+ S3_SAVAGE4,
+ S3_PROSAVAGE,
+ S3_SUPERSAVAGE,
+ S3_SAVAGE2000,
+ S3_LAST
+};
+
+#define BIOS_BSIZE 1024
+#define BIOS_BASE 0xc0000
+
+#define SAVAGE_NEWMMIO_REGBASE_S3 0x1000000 /* 16MB */
+#define SAVAGE_NEWMMIO_REGBASE_S4 0x0000000
+#define SAVAGE_NEWMMIO_REGSIZE 0x0080000 /* 512kb */
+#define SAVAGE_NEWMMIO_VGABASE 0x8000
+
+#define BASE_FREQ 14.31818
+
+#define FIFO_CONTROL_REG 0x8200
+#define MIU_CONTROL_REG 0x8204
+#define STREAMS_TIMEOUT_REG 0x8208
+#define MISC_TIMEOUT_REG 0x820c
+
+/* Stream Processor 1 */
+
+/* Primary Stream 1 Frame Buffer Address 0 */
+#define PRI_STREAM_FBUF_ADDR0 0x81c0
+/* Primary Stream 1 Frame Buffer Address 0 */
+#define PRI_STREAM_FBUF_ADDR1 0x81c4
+/* Primary Stream 1 Stride */
+#define PRI_STREAM_STRIDE 0x81c8
+/* Primary Stream 1 Frame Buffer Size */
+#define PRI_STREAM_BUFFERSIZE 0x8214
+
+/* Secondary stream 1 Color/Chroma Key Control */
+#define SEC_STREAM_CKEY_LOW 0x8184
+/* Secondary stream 1 Chroma Key Upper Bound */
+#define SEC_STREAM_CKEY_UPPER 0x8194
+/* Blend Control of Secondary Stream 1 & 2 */
+#define BLEND_CONTROL 0x8190
+/* Secondary Stream 1 Color conversion/Adjustment 1 */
+#define SEC_STREAM_COLOR_CONVERT1 0x8198
+/* Secondary Stream 1 Color conversion/Adjustment 2 */
+#define SEC_STREAM_COLOR_CONVERT2 0x819c
+/* Secondary Stream 1 Color conversion/Adjustment 3 */
+#define SEC_STREAM_COLOR_CONVERT3 0x81e4
+/* Secondary Stream 1 Horizontal Scaling */
+#define SEC_STREAM_HSCALING 0x81a0
+/* Secondary Stream 1 Frame Buffer Size */
+#define SEC_STREAM_BUFFERSIZE 0x81a8
+/* Secondary Stream 1 Horizontal Scaling Normalization (2K only) */
+#define SEC_STREAM_HSCALE_NORMALIZE 0x81ac
+/* Secondary Stream 1 Horizontal Scaling */
+#define SEC_STREAM_VSCALING 0x81e8
+/* Secondary Stream 1 Frame Buffer Address 0 */
+#define SEC_STREAM_FBUF_ADDR0 0x81d0
+/* Secondary Stream 1 Frame Buffer Address 1 */
+#define SEC_STREAM_FBUF_ADDR1 0x81d4
+/* Secondary Stream 1 Frame Buffer Address 2 */
+#define SEC_STREAM_FBUF_ADDR2 0x81ec
+/* Secondary Stream 1 Stride */
+#define SEC_STREAM_STRIDE 0x81d8
+/* Secondary Stream 1 Window Start Coordinates */
+#define SEC_STREAM_WINDOW_START 0x81f8
+/* Secondary Stream 1 Window Size */
+#define SEC_STREAM_WINDOW_SZ 0x81fc
+/* Secondary Streams Tile Offset */
+#define SEC_STREAM_TILE_OFF 0x821c
+/* Secondary Stream 1 Opaque Overlay Control */
+#define SEC_STREAM_OPAQUE_OVERLAY 0x81dc
+
+
+/* Stream Processor 2 */
+
+/* Primary Stream 2 Frame Buffer Address 0 */
+#define PRI_STREAM2_FBUF_ADDR0 0x81b0
+/* Primary Stream 2 Frame Buffer Address 1 */
+#define PRI_STREAM2_FBUF_ADDR1 0x81b4
+/* Primary Stream 2 Stride */
+#define PRI_STREAM2_STRIDE 0x81b8
+/* Primary Stream 2 Frame Buffer Size */
+#define PRI_STREAM2_BUFFERSIZE 0x8218
+
+/* Secondary Stream 2 Color/Chroma Key Control */
+#define SEC_STREAM2_CKEY_LOW 0x8188
+/* Secondary Stream 2 Chroma Key Upper Bound */
+#define SEC_STREAM2_CKEY_UPPER 0x818c
+/* Secondary Stream 2 Horizontal Scaling */
+#define SEC_STREAM2_HSCALING 0x81a4
+/* Secondary Stream 2 Horizontal Scaling */
+#define SEC_STREAM2_VSCALING 0x8204
+/* Secondary Stream 2 Frame Buffer Size */
+#define SEC_STREAM2_BUFFERSIZE 0x81ac
+/* Secondary Stream 2 Frame Buffer Address 0 */
+#define SEC_STREAM2_FBUF_ADDR0 0x81bc
+/* Secondary Stream 2 Frame Buffer Address 1 */
+#define SEC_STREAM2_FBUF_ADDR1 0x81e0
+/* Secondary Stream 2 Frame Buffer Address 2 */
+#define SEC_STREAM2_FBUF_ADDR2 0x8208
+/* Multiple Buffer/LPB and Secondary Stream 2 Stride */
+#define SEC_STREAM2_STRIDE_LPB 0x81cc
+/* Secondary Stream 2 Color conversion/Adjustment 1 */
+#define SEC_STREAM2_COLOR_CONVERT1 0x81f0
+/* Secondary Stream 2 Color conversion/Adjustment 2 */
+#define SEC_STREAM2_COLOR_CONVERT2 0x81f4
+/* Secondary Stream 2 Color conversion/Adjustment 3 */
+#define SEC_STREAM2_COLOR_CONVERT3 0x8200
+/* Secondary Stream 2 Window Start Coordinates */
+#define SEC_STREAM2_WINDOW_START 0x820c
+/* Secondary Stream 2 Window Size */
+#define SEC_STREAM2_WINDOW_SZ 0x8210
+/* Secondary Stream 2 Opaque Overlay Control */
+#define SEC_STREAM2_OPAQUE_OVERLAY 0x8180
+
+
+#define SUBSYS_STAT_REG 0x8504
+
+#define SRC_BASE 0xa4d4
+#define DEST_BASE 0xa4d8
+#define CLIP_L_R 0xa4dc
+#define CLIP_T_B 0xa4e0
+#define DEST_SRC_STR 0xa4e4
+#define MONO_PAT_0 0xa4e8
+#define MONO_PAT_1 0xa4ec
+
+/* Constants for CR69. */
+
+#define CRT_ACTIVE 0x01
+#define LCD_ACTIVE 0x02
+#define TV_ACTIVE 0x04
+#define CRT_ATTACHED 0x10
+#define LCD_ATTACHED 0x20
+#define TV_ATTACHED 0x40
+
+
+/*
+ * reads from SUBSYS_STAT
+ */
+#define STATUS_WORD0 (INREG(0x48C00))
+#define ALT_STATUS_WORD0 (INREG(0x48C60))
+#define MAXLOOP 0xffffff
+#define IN_SUBSYS_STAT() (INREG(SUBSYS_STAT_REG))
+
+#define MAXFIFO 0x7f00
+
+/*
+ * NOTE: don't remove 'VGAIN8(vgaCRIndex);'.
+ * If not present it will cause lockups on Savage4.
+ * Ask S3, why.
+ */
+#define VerticalRetraceWait(psav) \
+{ \
+ VGAIN8(psav->vgaIOBase+4); \
+ VGAOUT8(psav->vgaIOBase+4, 0x17); \
+ if (VGAIN8(psav->vgaIOBase+5) & 0x80) { \
+ while ((VGAIN8(psav->vgaIOBase + 0x0a) & 0x08) == 0x08) ; \
+ while ((VGAIN8(psav->vgaIOBase + 0x0a) & 0x08) == 0x00) ; \
+ } \
+}
+
+#define I2C_REG 0xa0
+#define InI2CREG(psav,a) \
+{ \
+ VGAOUT8(psav->vgaIOBase + 4, I2C_REG); \
+ a = VGAIN8(psav->vgaIOBase + 5); \
+}
+
+#define OutI2CREG(psav,a) \
+{ \
+ VGAOUT8(psav->vgaIOBase + 4, I2C_REG); \
+ VGAOUT8(psav->vgaIOBase + 5, a); \
+}
+
+#define HZEXP_FACTOR_IGA1 0x59
+#define VTEXP_FACTOR_IGA1 0x5b
+
+#endif /* _SAVAGE_REGS_H */
diff --git a/src/savage_shadow.c b/src/savage_shadow.c
new file mode 100644
index 0000000..00a5120
--- /dev/null
+++ b/src/savage_shadow.c
@@ -0,0 +1,244 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_shadow.c,v 1.2 2002/05/14 20:19:52 alanh Exp $ */
+
+/*
+ Copyright (c) 1999,2000 The XFree86 Project Inc.
+ based on code written by Mark Vojkovich <markv@valinux.com>
+*/
+
+#include "savage_driver.h"
+#include "shadowfb.h"
+#include "servermd.h"
+
+
+void
+SavageRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int width, height, Bpp, FBPitch;
+ unsigned char *src, *dst;
+
+ Bpp = pScrn->bitsPerPixel >> 3;
+ FBPitch = BitmapBytePad(pScrn->displayWidth * pScrn->bitsPerPixel);
+
+ while(num--) {
+ width = (pbox->x2 - pbox->x1) * Bpp;
+ height = pbox->y2 - pbox->y1;
+ src = psav->ShadowPtr + (pbox->y1 * psav->ShadowPitch) +
+ (pbox->x1 * Bpp);
+ dst = psav->FBStart + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp);
+
+ while(height--) {
+ memcpy(dst, src, width);
+ dst += FBPitch;
+ src += psav->ShadowPitch;
+ }
+
+ pbox++;
+ }
+}
+
+
+void
+SavagePointerMoved(int index, int x, int y)
+{
+ ScrnInfoPtr pScrn = xf86Screens[index];
+ SavagePtr psav = SAVPTR(pScrn);
+ int newX, newY;
+
+ if(psav->rotate == 1) {
+ newX = pScrn->pScreen->height - y - 1;
+ newY = x;
+ } else {
+ newX = y;
+ newY = pScrn->pScreen->width - x - 1;
+ }
+
+ (*psav->PointerMoved)(index, newX, newY);
+}
+
+void
+SavageRefreshArea8(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int count, width, height, y1, y2, dstPitch, srcPitch;
+ CARD8 *dstPtr, *srcPtr, *src;
+ CARD32 *dst;
+
+ dstPitch = pScrn->displayWidth;
+ srcPitch = -psav->rotate * psav->ShadowPitch;
+
+ while(num--) {
+ width = pbox->x2 - pbox->x1;
+ y1 = pbox->y1 & ~3;
+ y2 = (pbox->y2 + 3) & ~3;
+ height = (y2 - y1) >> 2; /* in dwords */
+
+ if(psav->rotate == 1) {
+ dstPtr = psav->FBStart +
+ (pbox->x1 * dstPitch) + pScrn->virtualX - y2;
+ srcPtr = psav->ShadowPtr + ((1 - y2) * srcPitch) + pbox->x1;
+ } else {
+ dstPtr = psav->FBStart +
+ ((pScrn->virtualY - pbox->x2) * dstPitch) + y1;
+ srcPtr = psav->ShadowPtr + (y1 * srcPitch) + pbox->x2 - 1;
+ }
+
+ while(width--) {
+ src = srcPtr;
+ dst = (CARD32*)dstPtr;
+ count = height;
+ while(count--) {
+ *(dst++) = src[0] | (src[srcPitch] << 8) |
+ (src[srcPitch * 2] << 16) |
+ (src[srcPitch * 3] << 24);
+ src += srcPitch * 4;
+ }
+ srcPtr += psav->rotate;
+ dstPtr += dstPitch;
+ }
+
+ pbox++;
+ }
+}
+
+
+void
+SavageRefreshArea16(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int count, width, height, y1, y2, dstPitch, srcPitch;
+ CARD16 *dstPtr, *srcPtr, *src;
+ CARD32 *dst;
+
+ dstPitch = pScrn->displayWidth;
+ srcPitch = -psav->rotate * psav->ShadowPitch >> 1;
+
+ while(num--) {
+ width = pbox->x2 - pbox->x1;
+ y1 = pbox->y1 & ~1;
+ y2 = (pbox->y2 + 1) & ~1;
+ height = (y2 - y1) >> 1; /* in dwords */
+
+ if(psav->rotate == 1) {
+ dstPtr = (CARD16*)psav->FBStart +
+ (pbox->x1 * dstPitch) + pScrn->virtualX - y2;
+ srcPtr = (CARD16*)psav->ShadowPtr +
+ ((1 - y2) * srcPitch) + pbox->x1;
+ } else {
+ dstPtr = (CARD16*)psav->FBStart +
+ ((pScrn->virtualY - pbox->x2) * dstPitch) + y1;
+ srcPtr = (CARD16*)psav->ShadowPtr +
+ (y1 * srcPitch) + pbox->x2 - 1;
+ }
+
+ while(width--) {
+ src = srcPtr;
+ dst = (CARD32*)dstPtr;
+ count = height;
+ while(count--) {
+ *(dst++) = src[0] | (src[srcPitch] << 16);
+ src += srcPitch * 2;
+ }
+ srcPtr += psav->rotate;
+ dstPtr += dstPitch;
+ }
+
+ pbox++;
+ }
+}
+
+
+/* this one could be faster */
+void
+SavageRefreshArea24(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int count, width, height, y1, y2, dstPitch, srcPitch;
+ CARD8 *dstPtr, *srcPtr, *src;
+ CARD32 *dst;
+
+ dstPitch = BitmapBytePad(pScrn->displayWidth * 24);
+ srcPitch = -psav->rotate * psav->ShadowPitch;
+
+ while(num--) {
+ width = pbox->x2 - pbox->x1;
+ y1 = pbox->y1 & ~3;
+ y2 = (pbox->y2 + 3) & ~3;
+ height = (y2 - y1) >> 2; /* blocks of 3 dwords */
+
+ if(psav->rotate == 1) {
+ dstPtr = psav->FBStart +
+ (pbox->x1 * dstPitch) + ((pScrn->virtualX - y2) * 3);
+ srcPtr = psav->ShadowPtr + ((1 - y2) * srcPitch) + (pbox->x1 * 3);
+ } else {
+ dstPtr = psav->FBStart +
+ ((pScrn->virtualY - pbox->x2) * dstPitch) + (y1 * 3);
+ srcPtr = psav->ShadowPtr + (y1 * srcPitch) + (pbox->x2 * 3) - 3;
+ }
+
+ while(width--) {
+ src = srcPtr;
+ dst = (CARD32*)dstPtr;
+ count = height;
+ while(count--) {
+ dst[0] = src[0] | (src[1] << 8) | (src[2] << 16) |
+ (src[srcPitch] << 24);
+ dst[1] = src[srcPitch + 1] | (src[srcPitch + 2] << 8) |
+ (src[srcPitch * 2] << 16) |
+ (src[(srcPitch * 2) + 1] << 24);
+ dst[2] = src[(srcPitch * 2) + 2] | (src[srcPitch * 3] << 8) |
+ (src[(srcPitch * 3) + 1] << 16) |
+ (src[(srcPitch * 3) + 2] << 24);
+ dst += 3;
+ src += srcPitch * 4;
+ }
+ srcPtr += psav->rotate * 3;
+ dstPtr += dstPitch;
+ }
+
+ pbox++;
+ }
+}
+
+void
+SavageRefreshArea32(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int count, width, height, dstPitch, srcPitch;
+ CARD32 *dstPtr, *srcPtr, *src, *dst;
+
+ dstPitch = pScrn->displayWidth;
+ srcPitch = -psav->rotate * psav->ShadowPitch >> 2;
+
+ while(num--) {
+ width = pbox->x2 - pbox->x1;
+ height = pbox->y2 - pbox->y1;
+
+ if(psav->rotate == 1) {
+ dstPtr = (CARD32*)psav->FBStart +
+ (pbox->x1 * dstPitch) + pScrn->virtualX - pbox->y2;
+ srcPtr = (CARD32*)psav->ShadowPtr +
+ ((1 - pbox->y2) * srcPitch) + pbox->x1;
+ } else {
+ dstPtr = (CARD32*)psav->FBStart +
+ ((pScrn->virtualY - pbox->x2) * dstPitch) + pbox->y1;
+ srcPtr = (CARD32*)psav->ShadowPtr +
+ (pbox->y1 * srcPitch) + pbox->x2 - 1;
+ }
+
+ while(width--) {
+ src = srcPtr;
+ dst = dstPtr;
+ count = height;
+ while(count--) {
+ *(dst++) = *src;
+ src += srcPitch;
+ }
+ srcPtr += psav->rotate;
+ dstPtr += dstPitch;
+ }
+
+ pbox++;
+ }
+}
+
diff --git a/src/savage_vbe.c b/src/savage_vbe.c
new file mode 100644
index 0000000..f0a0edc
--- /dev/null
+++ b/src/savage_vbe.c
@@ -0,0 +1,302 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_vbe.c,v 1.12 2002/10/02 20:39:55 alanh Exp $ */
+
+#include "savage_driver.h"
+#include "savage_vbe.h"
+
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+#define B_O16(x) (x)
+#define B_O32(x) (x)
+#else
+#define B_O16(x) ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8))
+#define B_O32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \
+ | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24))
+#endif
+#define L_ADD(x) (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00)
+
+Bool vbeModeInit( vbeInfoPtr, int );
+static int SavageGetDevice( SavagePtr psav );
+/*static int SavageGetTVType( SavagePtr psav );*/
+
+static void
+SavageClearVM86Regs( xf86Int10InfoPtr pInt )
+{
+ pInt->ax = 0;
+ pInt->bx = 0;
+ pInt->cx = 0;
+ pInt->dx = 0;
+ pInt->si = 0;
+ pInt->di = 0;
+ pInt->es = 0xc000;
+ pInt->num = 0x10;
+}
+
+void
+SavageSetTextMode( SavagePtr psav )
+{
+ /* Restore display device if changed. */
+ if( psav->iDevInfo != psav->iDevInfoPrim ) {
+ SavageClearVM86Regs( psav->pInt10 );
+ psav->pInt10->ax = 0x4f14;
+ psav->pInt10->bx = 0x0003;
+ psav->pInt10->cx = psav->iDevInfoPrim;
+ xf86ExecX86int10( psav->pInt10 );
+ }
+
+ SavageClearVM86Regs( psav->pInt10 );
+
+ psav->pInt10->ax = 0x83;
+
+ xf86ExecX86int10( psav->pInt10 );
+}
+
+
+void
+SavageSetVESAMode( SavagePtr psav, int n, int Refresh )
+{
+ int iDevInfo;
+ static int iCount = 0;
+
+ /* Get current display device status. */
+
+ iDevInfo = SavageGetDevice(psav);
+ psav->iDevInfo = iDevInfo;
+ if( !iCount++ )
+ psav->iDevInfoPrim = psav->iDevInfo;
+ if( psav->CrtOnly )
+ psav->iDevInfo = CRT_ACTIVE;
+ if( psav->TvOn )
+ psav->iDevInfo = TV_ACTIVE;
+
+ /* Establish the refresh rate for this mode. */
+
+ SavageClearVM86Regs( psav->pInt10 );
+ psav->pInt10->ax = 0x4f14; /* S3 extensions */
+ psav->pInt10->bx = 0x0001; /* Set default refresh rate */
+ psav->pInt10->cx = n;
+ psav->pInt10->di = Refresh & 0xffff;
+
+ xf86ExecX86int10( psav->pInt10 );
+
+ /* Set TV type if TV is on. */
+ if( psav->TvOn ) {
+ SavageClearVM86Regs( psav->pInt10 );
+ psav->pInt10->ax = 0x4f14; /* S3 extensions */
+ psav->pInt10->bx = 0x0007; /* TV extensions */
+ psav->pInt10->cx = psav->PAL ? 0x08 : 0x04;
+ psav->pInt10->dx = 0x0c;
+ xf86ExecX86int10( psav->pInt10 );
+ }
+
+ /* Manipulate output device set. */
+ if( psav->iDevInfo != iDevInfo ) {
+ SavageClearVM86Regs( psav->pInt10 );
+ psav->pInt10->ax = 0x4f14; /* S3 extensions */
+ psav->pInt10->bx = 0x0003; /* set active devices */
+ psav->pInt10->cx = psav->PAL ? 0x08 : 0x04;
+ xf86ExecX86int10( psav->pInt10 );
+
+ /* Re-fetch actual device set. */
+ psav->iDevInfo = SavageGetDevice( psav );
+ iDevInfo = psav->iDevInfo;
+ psav->CrtOnly = (iDevInfo == 1);
+ psav->TvOn = !!(iDevInfo & 4);
+ }
+
+ /* Now, make this mode current. */
+
+ if( xf86LoaderCheckSymbol( "VBESetVBEMode" ) )
+ {
+ if( !VBESetVBEMode( psav->pVbe, n, NULL ) )
+ {
+ ErrorF("Set video mode failed\n");
+ }
+ }
+#ifdef XFree86LOADER
+ else
+ {
+ if( !vbeModeInit( psav->pVbe, n ) )
+ {
+ ErrorF("Set video mode failed\n");
+ }
+ }
+#endif
+}
+
+
+/* Function to get supported device list. */
+
+static int SavageGetDevice( SavagePtr psav )
+{
+ SavageClearVM86Regs( psav->pInt10 );
+ psav->pInt10->ax = 0x4f14; /* S3 extensions */
+ psav->pInt10->bx = 0x0103; /* get active devices */
+
+ xf86ExecX86int10( psav->pInt10 );
+
+ return ((psav->pInt10->cx) & 0xf);
+}
+
+
+void
+SavageFreeBIOSModeTable( SavagePtr psav, SavageModeTablePtr* ppTable )
+{
+ int i;
+ SavageModeEntryPtr pMode = (*ppTable)->Modes;
+
+ for( i = (*ppTable)->NumModes; i--; )
+ {
+ if( pMode->RefreshRate )
+ {
+ xfree( pMode->RefreshRate );
+ pMode->RefreshRate = NULL;
+ }
+ }
+
+ xfree( *ppTable );
+}
+
+
+SavageModeTablePtr
+SavageGetBIOSModeTable( SavagePtr psav, int iDepth )
+{
+ int nModes = SavageGetBIOSModes( psav, iDepth, NULL );
+ SavageModeTablePtr pTable;
+
+ pTable = (SavageModeTablePtr)
+ xcalloc( 1, sizeof(SavageModeTableRec) +
+ (nModes-1) * sizeof(SavageModeEntry) );
+ if( pTable ) {
+ pTable->NumModes = nModes;
+ SavageGetBIOSModes( psav, iDepth, pTable->Modes );
+ }
+
+ return pTable;
+}
+
+
+unsigned short
+SavageGetBIOSModes(
+ SavagePtr psav,
+ int iDepth,
+ SavageModeEntryPtr s3vModeTable )
+{
+ unsigned short iModeCount = 0;
+ unsigned short int *mode_list;
+ pointer vbeLinear = NULL;
+ vbeControllerInfoPtr vbe = NULL;
+ int vbeReal;
+ struct vbe_mode_info_block * vmib;
+
+ if( !psav->pVbe )
+ return 0;
+
+ vbe = (vbeControllerInfoPtr) psav->pVbe->memory;
+ vbeLinear = xf86Int10AllocPages( psav->pInt10, 1, &vbeReal );
+ if( !vbeLinear )
+ {
+ ErrorF( "Cannot allocate scratch page in real mode memory." );
+ return 0;
+ }
+ vmib = (struct vbe_mode_info_block *) vbeLinear;
+
+ for (
+ mode_list = xf86int10Addr( psav->pInt10, L_ADD(vbe->VideoModePtr) );
+ *mode_list != 0xffff;
+ mode_list++
+ )
+ {
+ /*
+ * This is a HACK to work around what I believe is a BUG in the
+ * Toshiba Satellite BIOSes in 08/2000 and 09/2000. The BIOS
+ * table for 1024x600 says it has six refresh rates, when in fact
+ * it only has 3. When I ask for rate #4, the BIOS goes into an
+ * infinite loop until the user interrupts it, usually by pressing
+ * Ctrl-Alt-F1. For now, we'll just punt everything with a VESA
+ * number greater than or equal to 0200.
+ *
+ * This also prevents some strange and unusual results seen with
+ * the later ProSavage/PM133 BIOSes directly from S3/VIA.
+ */
+ if( *mode_list >= 0x0200 )
+ continue;
+
+ SavageClearVM86Regs( psav->pInt10 );
+
+ psav->pInt10->ax = 0x4f01;
+ psav->pInt10->cx = *mode_list;
+ psav->pInt10->es = SEG_ADDR(vbeReal);
+ psav->pInt10->di = SEG_OFF(vbeReal);
+ psav->pInt10->num = 0x10;
+
+ xf86ExecX86int10( psav->pInt10 );
+
+ if(
+ (vmib->bits_per_pixel == iDepth) &&
+ (
+ (vmib->memory_model == VBE_MODEL_256) ||
+ (vmib->memory_model == VBE_MODEL_PACKED) ||
+ (vmib->memory_model == VBE_MODEL_RGB)
+ )
+ )
+ {
+ /* This mode is a match. */
+
+ iModeCount++;
+
+ /* If we're supposed to fetch information, do it now. */
+
+ if( s3vModeTable )
+ {
+ int iRefresh = 0;
+
+ s3vModeTable->Width = vmib->x_resolution;
+ s3vModeTable->Height = vmib->y_resolution;
+ s3vModeTable->VesaMode = *mode_list;
+
+ /* Query the refresh rates at this mode. */
+
+ psav->pInt10->cx = *mode_list;
+ psav->pInt10->dx = 0;
+
+ do
+ {
+ if( (iRefresh % 8) == 0 )
+ {
+ if( s3vModeTable->RefreshRate )
+ {
+ s3vModeTable->RefreshRate = (unsigned char *)
+ xrealloc(
+ s3vModeTable->RefreshRate,
+ (iRefresh+8) * sizeof(unsigned char)
+ );
+ }
+ else
+ {
+ s3vModeTable->RefreshRate = (unsigned char *)
+ xcalloc(
+ sizeof(unsigned char),
+ (iRefresh+8)
+ );
+ }
+ }
+
+ psav->pInt10->ax = 0x4f14; /* S3 extended functions */
+ psav->pInt10->bx = 0x0201; /* query refresh rates */
+ psav->pInt10->num = 0x10;
+ xf86ExecX86int10( psav->pInt10 );
+
+ s3vModeTable->RefreshRate[iRefresh++] = psav->pInt10->di;
+ }
+ while( psav->pInt10->dx );
+
+ s3vModeTable->RefreshCount = iRefresh;
+
+ s3vModeTable++;
+ }
+ }
+ }
+
+ xf86Int10FreePages( psav->pInt10, vbeLinear, 1 );
+
+ return iModeCount;
+}
diff --git a/src/savage_vbe.h b/src/savage_vbe.h
new file mode 100644
index 0000000..ba77773
--- /dev/null
+++ b/src/savage_vbe.h
@@ -0,0 +1,113 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_vbe.h,v 1.3 2002/05/14 20:19:52 alanh Exp $ */
+
+/*
+This file was originally part of the Linux Real-Mode Interface, or LRMI.
+There is nothing LRMI-specific here; this is all good, general VBE info.
+
+Copyright (C) 1996 by Josh Vanderhoof
+
+You are free to distribute and modify this file, as long as you
+do not remove this copyright notice and clearly label modified
+versions as being modified.
+
+This software has NO WARRANTY. Use it at your own risk.
+*/
+
+#ifndef _SAVAGEVBE_H
+#define _SAVAGEVBE_H
+
+/* structures for vbe 2.0 */
+
+#ifndef __GNUC__
+#define __attribute__(a)
+#endif
+
+struct vbe_info_block
+ {
+ char vbe_signature[4];
+ short vbe_version;
+ unsigned short oem_string_off;
+ unsigned short oem_string_seg;
+ int capabilities;
+ unsigned short video_mode_list_off;
+ unsigned short video_mode_list_seg;
+ short total_memory;
+ short oem_software_rev;
+ unsigned short oem_vendor_name_off;
+ unsigned short oem_vendor_name_seg;
+ unsigned short oem_product_name_off;
+ unsigned short oem_product_name_seg;
+ unsigned short oem_product_rev_off;
+ unsigned short oem_product_rev_seg;
+ char reserved[222];
+ char oem_data[256];
+ } __attribute__ ((packed));
+
+#define VBE_ATTR_MODE_SUPPORTED (1 << 0)
+#define VBE_ATTR_TTY (1 << 2)
+#define VBE_ATTR_COLOR (1 << 3)
+#define VBE_ATTR_GRAPHICS (1 << 4)
+#define VBE_ATTR_NOT_VGA (1 << 5)
+#define VBE_ATTR_NOT_WINDOWED (1 << 6)
+#define VBE_ATTR_LINEAR (1 << 7)
+
+#define VBE_WIN_RELOCATABLE (1 << 0)
+#define VBE_WIN_READABLE (1 << 1)
+#define VBE_WIN_WRITEABLE (1 << 2)
+
+#define VBE_MODEL_TEXT 0
+#define VBE_MODEL_CGA 1
+#define VBE_MODEL_HERCULES 2
+#define VBE_MODEL_PLANAR 3
+#define VBE_MODEL_PACKED 4
+#define VBE_MODEL_256 5
+#define VBE_MODEL_RGB 6
+#define VBE_MODEL_YUV 7
+
+struct vbe_mode_info_block
+ {
+ unsigned short mode_attributes;
+ unsigned char win_a_attributes;
+ unsigned char win_b_attributes;
+ unsigned short win_granularity;
+ unsigned short win_size;
+ unsigned short win_a_segment;
+ unsigned short win_b_segment;
+ unsigned short win_func_ptr_off;
+ unsigned short win_func_ptr_seg;
+ unsigned short bytes_per_scanline;
+ unsigned short x_resolution;
+ unsigned short y_resolution;
+ unsigned char x_char_size;
+ unsigned char y_char_size;
+ unsigned char number_of_planes;
+ unsigned char bits_per_pixel;
+ unsigned char number_of_banks;
+ unsigned char memory_model;
+ unsigned char bank_size;
+ unsigned char number_of_image_pages;
+ unsigned char res1;
+ unsigned char red_mask_size;
+ unsigned char red_field_position;
+ unsigned char green_mask_size;
+ unsigned char green_field_position;
+ unsigned char blue_mask_size;
+ unsigned char blue_field_position;
+ unsigned char rsvd_mask_size;
+ unsigned char rsvd_field_position;
+ unsigned char direct_color_mode_info;
+ unsigned int phys_base_ptr;
+ unsigned int offscreen_mem_offset;
+ unsigned short offscreen_mem_size;
+ unsigned char res2[206];
+ } __attribute__ ((packed));
+
+struct vbe_palette_entry
+ {
+ unsigned char blue;
+ unsigned char green;
+ unsigned char red;
+ unsigned char align;
+ } __attribute__ ((packed));
+
+#endif
diff --git a/src/savage_video.c b/src/savage_video.c
new file mode 100644
index 0000000..38c2cc3
--- /dev/null
+++ b/src/savage_video.c
@@ -0,0 +1,1982 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_video.c,v 1.11 2003/01/12 03:55:49 tsi Exp $ */
+
+#include "Xv.h"
+#include "dix.h"
+#include "dixstruct.h"
+#include "fourcc.h"
+#include "xaalocal.h"
+
+#include "savage_driver.h"
+
+#define OFF_DELAY 200 /* milliseconds */
+#define FREE_DELAY 60000
+
+#define OFF_TIMER 0x01
+#define FREE_TIMER 0x02
+#define CLIENT_VIDEO_ON 0x04
+
+#define TIMER_MASK (OFF_TIMER | FREE_TIMER)
+
+#ifndef XvExtension
+void SavageInitVideo(ScreenPtr pScreen) {}
+void SavageResetVideo(ScrnInfoPtr pScrn) {}
+#else
+
+void myOUTREG( SavagePtr psav, unsigned long offset, unsigned long value );
+
+static XF86VideoAdaptorPtr SavageSetupImageVideo(ScreenPtr);
+static void SavageInitOffscreenImages(ScreenPtr);
+static void SavageStopVideo(ScrnInfoPtr, pointer, Bool);
+static int SavageSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
+static int SavageGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
+static void SavageQueryBestSize(ScrnInfoPtr, Bool,
+ short, short, short, short, unsigned int *, unsigned int *, pointer);
+static int SavagePutImage( ScrnInfoPtr,
+ short, short, short, short, short, short, short, short,
+ int, unsigned char*, short, short, Bool, RegionPtr, pointer);
+static int SavageQueryImageAttributes(ScrnInfoPtr,
+ int, unsigned short *, unsigned short *, int *, int *);
+
+void SavageStreamsOn(ScrnInfoPtr pScrn, int id);
+void SavageStreamsOff(ScrnInfoPtr pScrn);
+void SavageResetVideo(ScrnInfoPtr pScrn);
+
+static void SavageInitStreamsOld(ScrnInfoPtr pScrn);
+static void SavageInitStreamsNew(ScrnInfoPtr pScrn);
+static void (*SavageInitStreams)(ScrnInfoPtr pScrn) = NULL;
+
+static void SavageSetColorKeyOld(ScrnInfoPtr pScrn);
+static void SavageSetColorKeyNew(ScrnInfoPtr pScrn);
+static void (*SavageSetColorKey)(ScrnInfoPtr pScrn) = NULL;
+
+static void SavageSetColorOld(ScrnInfoPtr pScrn );
+static void SavageSetColorNew(ScrnInfoPtr pScrn );
+static void (*SavageSetColor)(ScrnInfoPtr pScrn ) = NULL;
+
+static void SavageDisplayVideoOld(
+ ScrnInfoPtr pScrn, int id, int offset,
+ short width, short height, int pitch,
+ int x1, int y1, int x2, int y2,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+);
+static void SavageDisplayVideoNew(
+ ScrnInfoPtr pScrn, int id, int offset,
+ short width, short height, int pitch,
+ int x1, int y1, int x2, int y2,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+);
+static void (*SavageDisplayVideo)(
+ ScrnInfoPtr pScrn, int id, int offset,
+ short width, short height, int pitch,
+ int x1, int y1, int x2, int y2,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+) = NULL;
+
+static void OverlayParamInit(ScrnInfoPtr pScrn);
+static void InitStreamsForExpansion(SavagePtr psav);
+
+/*static void SavageBlockHandler(int, pointer, pointer, pointer);*/
+
+#define XVTRACE 4
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static Atom xvColorKey, xvBrightness, xvContrast, xvSaturation, xvHue;
+
+/* client libraries expect an encoding */
+static XF86VideoEncodingRec DummyEncoding[1] =
+{
+ {
+ 0,
+ "XV_IMAGE",
+ 1024, 1024,
+ {1, 1}
+ }
+};
+
+#define NUM_FORMATS 4
+
+static XF86VideoFormatRec Formats[NUM_FORMATS] =
+{
+ {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
+};
+
+#define NUM_ATTRIBUTES 5
+
+static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
+{
+ {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
+ {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
+ {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
+ {XvSettable | XvGettable, 0, 255, "XV_SATURATION"},
+ {XvSettable | XvGettable, -180, 180, "XV_HUE"}
+};
+
+#define FOURCC_RV16 0x36315652
+#define FOURCC_RV15 0x35315652
+#define FOURCC_Y211 0x31313259
+
+/*
+ * For completeness sake, here is a cracking of the fourcc's I support.
+ *
+ * YUY2, packed 4:2:2, byte order: Y0 U0 Y1 V0 Y2 U2 Y3 V2
+ * Y211, packed 2:1:1, byte order: Y0 U0 Y2 V0 Y4 U2 Y6 V2
+ * YV12, planar 4:1:1, Y plane HxW, V plane H/2xW/2, U plane H/2xW/2
+ * I420, planar 4:1:1, Y plane HxW, U plane H/2xW/2, V plane H/2xW/2
+ * (I420 is also known as IYUV)
+ */
+
+
+static XF86ImageRec Images[] =
+{
+ XVIMAGE_YUY2,
+ XVIMAGE_YV12,
+ XVIMAGE_I420,
+ {
+ FOURCC_RV15,
+ XvRGB,
+ LSBFirst,
+ {'R','V','1','5',
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ 16,
+ XvPacked,
+ 1,
+ 15, 0x001F, 0x03E0, 0x7C00,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ {'R','V','B',0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ XvTopToBottom
+ },
+ {
+ FOURCC_RV16,
+ XvRGB,
+ LSBFirst,
+ {'R','V','1','6',
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+ 16,
+ XvPacked,
+ 1,
+ 16, 0x001F, 0x07E0, 0xF800,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ {'R','V','B',0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ XvTopToBottom
+ },
+ {
+ FOURCC_Y211,
+ XvYUV,
+ LSBFirst,
+ {'Y','2','1','1',
+ 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71},
+ 6,
+ XvPacked,
+ 3,
+ 0, 0, 0, 0 ,
+ 8, 8, 8,
+ 2, 4, 4,
+ 1, 1, 1,
+ {'Y','U','Y','V',
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ XvTopToBottom
+ }
+};
+
+#define NUM_IMAGES (sizeof(Images)/sizeof(Images[0]))
+
+typedef struct {
+ int brightness; /* -128 .. 127 */
+ CARD32 contrast; /* 0 .. 255 */
+ CARD32 saturation; /* 0 .. 255 */
+ int hue; /* -128 .. 127 */
+
+ FBAreaPtr area;
+ RegionRec clip;
+ CARD32 colorKey;
+ CARD32 videoStatus;
+ Time offTime;
+ Time freeTime;
+ int lastKnownPitch;
+} SavagePortPrivRec, *SavagePortPrivPtr;
+
+
+#define GET_PORT_PRIVATE(pScrn) \
+ (SavagePortPrivPtr)((SAVPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
+
+/**************************************
+ S3 streams processor
+**************************************/
+
+#define EXT_MISC_CTRL2 0x67
+
+/* New streams */
+
+/* CR67[2] = 1 : enable stream 1 */
+#define ENABLE_STREAM1 0x04
+/* CR67[1] = 1 : enable stream 2 */
+#define ENABLE_STREAM2 0x02
+/* mask to clear CR67[2,1] */
+#define NO_STREAMS 0xF9
+/* CR67[3] = 1 : Mem-mapped regs */
+#define USE_MM_FOR_PRI_STREAM 0x08
+
+#define HDM_SHIFT 16
+#define HDSCALE_4 (2 << HDM_SHIFT)
+#define HDSCALE_8 (3 << HDM_SHIFT)
+#define HDSCALE_16 (4 << HDM_SHIFT)
+#define HDSCALE_32 (5 << HDM_SHIFT)
+#define HDSCALE_64 (6 << HDM_SHIFT)
+
+/* Old Streams */
+
+#define ENABLE_STREAMS_OLD 0x0c
+#define NO_STREAMS_OLD 0xf3
+/* CR69[0] = 1 : Mem-mapped regs */
+#define USE_MM_FOR_PRI_STREAM_OLD 0x01
+
+
+/*
+ * There are two different streams engines used in the Savage line.
+ * The old engine is in the 3D, 4, Pro, and Twister.
+ * The new engine is in the 2000, MX, IX, and Super.
+ */
+
+
+/* streams registers for old engine */
+#define PSTREAM_CONTROL_REG 0x8180
+#define COL_CHROMA_KEY_CONTROL_REG 0x8184
+#define SSTREAM_CONTROL_REG 0x8190
+#define CHROMA_KEY_UPPER_BOUND_REG 0x8194
+#define SSTREAM_STRETCH_REG 0x8198
+#define COLOR_ADJUSTMENT_REG 0x819C
+#define BLEND_CONTROL_REG 0x81A0
+#define PSTREAM_FBADDR0_REG 0x81C0
+#define PSTREAM_FBADDR1_REG 0x81C4
+#define PSTREAM_STRIDE_REG 0x81C8
+#define DOUBLE_BUFFER_REG 0x81CC
+#define SSTREAM_FBADDR0_REG 0x81D0
+#define SSTREAM_FBADDR1_REG 0x81D4
+#define SSTREAM_STRIDE_REG 0x81D8
+#define SSTREAM_VSCALE_REG 0x81E0
+#define SSTREAM_VINITIAL_REG 0x81E4
+#define SSTREAM_LINES_REG 0x81E8
+#define STREAMS_FIFO_REG 0x81EC
+#define PSTREAM_WINDOW_START_REG 0x81F0
+#define PSTREAM_WINDOW_SIZE_REG 0x81F4
+#define SSTREAM_WINDOW_START_REG 0x81F8
+#define SSTREAM_WINDOW_SIZE_REG 0x81FC
+#define FIFO_CONTROL 0x8200
+#define PSTREAM_FBSIZE_REG 0x8300
+#define SSTREAM_FBSIZE_REG 0x8304
+#define SSTREAM_FBADDR2_REG 0x8308
+
+#define OS_XY(x,y) (((x+1)<<16)|(y+1))
+#define OS_WH(x,y) (((x-1)<<16)|(y))
+
+static
+unsigned int GetBlendForFourCC( int id )
+{
+ switch( id ) {
+ case FOURCC_YUY2:
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ return 1;
+ case FOURCC_Y211:
+ return 4;
+ case FOURCC_RV15:
+ return 3;
+ case FOURCC_RV16:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+void myOUTREG( SavagePtr psav, unsigned long offset, unsigned long value )
+{
+ ErrorF( "MMIO %04x, was %08x, want %08x,",
+ offset, MMIO_IN32( psav->MapBase, offset ), value );
+ MMIO_OUT32( psav->MapBase, offset, value );
+ ErrorF( " now %08x\n", MMIO_IN32( psav->MapBase, offset ) );
+}
+
+void SavageInitStreamsOld(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned long jDelta;
+ unsigned long format = 0;
+
+ /*
+ * For the OLD streams engine, several of these registers
+ * cannot be touched unless streams are on. Seems backwards to me;
+ * I'd want to set 'em up, then cut 'em loose.
+ */
+
+ xf86ErrorFVerb(XVTRACE, "SavageInitStreams\n" );
+
+ /* Primary stream reflects the frame buffer. */
+
+ switch( pScrn->depth ) {
+ case 8: format = 0 << 24; break;
+ case 15: format = 3 << 24; break;
+ case 16: format = 5 << 24; break;
+ case 24: format = 7 << 24; break;
+ }
+
+ jDelta = pScrn->displayWidth * pScrn->bitsPerPixel / 8;
+ OUTREG( PSTREAM_WINDOW_START_REG, OS_XY(0,0) );
+ OUTREG( PSTREAM_WINDOW_SIZE_REG, OS_WH(pScrn->displayWidth, pScrn->virtualY) );
+ OUTREG( PSTREAM_FBADDR0_REG, pScrn->fbOffset );
+ OUTREG( PSTREAM_FBADDR1_REG, 0 );
+ OUTREG( PSTREAM_STRIDE_REG, jDelta );
+ OUTREG( PSTREAM_CONTROL_REG, format );
+ OUTREG( PSTREAM_FBSIZE_REG, jDelta * pScrn->virtualY >> 3 );
+
+ OUTREG( COL_CHROMA_KEY_CONTROL_REG, 0 );
+ OUTREG( SSTREAM_CONTROL_REG, 0 );
+ OUTREG( CHROMA_KEY_UPPER_BOUND_REG, 0 );
+ OUTREG( SSTREAM_STRETCH_REG, 0 );
+ OUTREG( COLOR_ADJUSTMENT_REG, 0 );
+ OUTREG( BLEND_CONTROL_REG, 1 << 24 );
+ OUTREG( DOUBLE_BUFFER_REG, 0 );
+ OUTREG( SSTREAM_FBADDR0_REG, 0 );
+ OUTREG( SSTREAM_FBADDR1_REG, 0 );
+ OUTREG( SSTREAM_FBADDR2_REG, 0 );
+/* OUTREG( SSTREAM_FBSIZE_REG, 0 ); */
+ OUTREG( SSTREAM_STRIDE_REG, 0 );
+ OUTREG( SSTREAM_VSCALE_REG, 0 );
+ OUTREG( SSTREAM_LINES_REG, 0 );
+ OUTREG( SSTREAM_VINITIAL_REG, 0 );
+ OUTREG( SSTREAM_WINDOW_START_REG, OS_XY(0xfffe, 0xfffe) );
+ OUTREG( SSTREAM_WINDOW_SIZE_REG, OS_WH(10,2) );
+}
+
+#undef OUTREG
+#if 0
+#define OUTREG(a,v) myOUTREG(psav,a,v)
+#else
+#define OUTREG(addr,val) MMIO_OUT32(psav->MapBase, addr, val)
+#endif
+
+void SavageInitStreamsNew(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned long jDelta;
+
+ xf86ErrorFVerb(XVTRACE, "SavageInitStreams\n" );
+
+ if(
+ S3_SAVAGE_MOBILE_SERIES(psav->Chipset) &&
+ !psav->CrtOnly &&
+ !psav->TvOn
+ ) {
+ OverlayParamInit( pScrn );
+ }
+
+ /* Primary stream reflects the frame buffer. */
+
+ jDelta = pScrn->displayWidth * pScrn->bitsPerPixel / 8;
+ OUTREG( PRI_STREAM_BUFFERSIZE, jDelta * pScrn->virtualY >> 3 );
+ OUTREG( PRI_STREAM_FBUF_ADDR0, pScrn->fbOffset );
+ OUTREG( PRI_STREAM_STRIDE, jDelta );
+
+ OUTREG( SEC_STREAM_CKEY_LOW, 0 );
+ OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
+ OUTREG( SEC_STREAM_HSCALING, 0 );
+ OUTREG( SEC_STREAM_VSCALING, 0 );
+ OUTREG( BLEND_CONTROL, 0 );
+ OUTREG( SEC_STREAM_FBUF_ADDR0, 0 );
+ OUTREG( SEC_STREAM_FBUF_ADDR1, 0 );
+ OUTREG( SEC_STREAM_FBUF_ADDR2, 0 );
+ OUTREG( SEC_STREAM_WINDOW_START, 0 );
+ OUTREG( SEC_STREAM_WINDOW_SZ, 0 );
+/* OUTREG( SEC_STREAM_BUFFERSIZE, 0 ); */
+ OUTREG( SEC_STREAM_TILE_OFF, 0 );
+ OUTREG( SEC_STREAM_OPAQUE_OVERLAY, 0 );
+ OUTREG( SEC_STREAM_STRIDE, 0 );
+
+ /* These values specify brightness, contrast, saturation and hue. */
+ OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
+ OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
+ OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
+}
+
+void SavageStreamsOn(ScrnInfoPtr pScrn, int id)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char jStreamsControl;
+ unsigned short vgaCRIndex = psav->vgaIOBase + 4;
+ unsigned short vgaCRReg = psav->vgaIOBase + 5;
+
+ xf86ErrorFVerb(XVTRACE, "SavageStreamsOn\n" );
+
+ /* Sequence stolen from streams.c in M7 NT driver */
+
+
+ xf86EnableIO();
+
+ /* Unlock extended registers. */
+
+ VGAOUT16(vgaCRIndex, 0x4838);
+ VGAOUT16(vgaCRIndex, 0xa039);
+ VGAOUT16(0x3c4, 0x0608);
+
+ VGAOUT8( vgaCRIndex, EXT_MISC_CTRL2 );
+
+ if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+ (psav->Chipset == S3_SUPERSAVAGE) ||
+ (psav->Chipset == S3_SAVAGE2000) )
+ {
+ jStreamsControl = VGAIN8( vgaCRReg ) | ENABLE_STREAM1;
+
+ /* Wait for VBLANK. */
+
+ VerticalRetraceWait(psav);
+
+ /* Fire up streams! */
+
+ VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+
+ psav->blendBase = GetBlendForFourCC( id ) << 9;
+ xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", &id, psav->blendBase );
+ OUTREG( BLEND_CONTROL, psav->blendBase | 0x08 );
+
+ /* These values specify brightness, contrast, saturation and hue. */
+ OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
+ OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
+ OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
+ }
+ else
+ {
+ jStreamsControl = VGAIN8( vgaCRReg ) | ENABLE_STREAMS_OLD;
+
+ /* Wait for VBLANK. */
+
+ VerticalRetraceWait(psav);
+
+ /* Fire up streams! */
+
+ VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+
+ SavageInitStreamsOld( pScrn );
+ }
+
+ /* Wait for VBLANK. */
+
+ VerticalRetraceWait(psav);
+
+ /* Turn on secondary stream TV flicker filter, once we support TV. */
+
+ /* SR70 |= 0x10 */
+
+ psav->videoFlags |= VF_STREAMS_ON;
+ psav->videoFourCC = id;
+}
+
+
+void SavageStreamsOff(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char jStreamsControl;
+ unsigned short vgaCRIndex = psav->vgaIOBase + 4;
+ unsigned short vgaCRReg = psav->vgaIOBase + 5;
+
+ xf86ErrorFVerb(XVTRACE, "SavageStreamsOff\n" );
+
+ xf86EnableIO();
+
+ /* Unlock extended registers. */
+
+ VGAOUT16(vgaCRIndex, 0x4838);
+ VGAOUT16(vgaCRIndex, 0xa039);
+ VGAOUT16(0x3c4, 0x0608);
+
+ VGAOUT8( vgaCRIndex, EXT_MISC_CTRL2 );
+ if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+ (psav->Chipset == S3_SUPERSAVAGE) ||
+ (psav->Chipset == S3_SAVAGE2000) )
+ jStreamsControl = VGAIN8( vgaCRReg ) & NO_STREAMS;
+ else
+ jStreamsControl = VGAIN8( vgaCRReg ) & NO_STREAMS_OLD;
+
+ /* Wait for VBLANK. */
+
+ VerticalRetraceWait(psav);
+
+ /* Kill streams. */
+
+ VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+
+ VGAOUT16( vgaCRIndex, 0x0093 );
+ VGAOUT8( vgaCRIndex, 0x92 );
+ VGAOUT8( vgaCRReg, VGAIN8(vgaCRReg) & 0x40 );
+
+ psav->videoFlags &= ~VF_STREAMS_ON;
+}
+
+
+void SavageInitVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
+ XF86VideoAdaptorPtr newAdaptor = NULL;
+ SavagePtr psav = SAVPTR(pScrn);
+ int num_adaptors;
+
+ xf86ErrorFVerb(XVTRACE,"SavageInitVideo\n");
+ if(
+ S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+ (psav->Chipset == S3_SUPERSAVAGE) ||
+ (psav->Chipset == S3_SAVAGE2000)
+ )
+ {
+ newAdaptor = SavageSetupImageVideo(pScreen);
+ SavageInitOffscreenImages(pScreen);
+
+ SavageInitStreams = SavageInitStreamsNew;
+ SavageSetColor = SavageSetColorNew;
+ SavageSetColorKey = SavageSetColorKeyNew;
+ SavageDisplayVideo = SavageDisplayVideoNew;
+ }
+ else
+ {
+ newAdaptor = SavageSetupImageVideo(pScreen);
+ SavageInitOffscreenImages(pScreen);
+ /*DELETENEXTLINE*/
+ /* Since newAdaptor is still NULL, these are still disabled for now. */
+ SavageInitStreams = SavageInitStreamsOld;
+ SavageSetColor = SavageSetColorOld;
+ SavageSetColorKey = SavageSetColorKeyOld;
+ SavageDisplayVideo = SavageDisplayVideoOld;
+ }
+
+ num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
+
+ if(newAdaptor) {
+ if(!num_adaptors) {
+ num_adaptors = 1;
+ adaptors = &newAdaptor;
+ } else {
+ newAdaptors = /* need to free this someplace */
+ xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
+ if(newAdaptors) {
+ memcpy(newAdaptors, adaptors, num_adaptors *
+ sizeof(XF86VideoAdaptorPtr));
+ newAdaptors[num_adaptors] = newAdaptor;
+ adaptors = newAdaptors;
+ num_adaptors++;
+ }
+ }
+ }
+
+ if(num_adaptors)
+ xf86XVScreenInit(pScreen, adaptors, num_adaptors);
+
+ if(newAdaptors)
+ xfree(newAdaptors);
+
+ if( newAdaptor )
+ {
+ if( SavageInitStreams == SavageInitStreamsNew )
+ SavageInitStreams(pScrn);
+ psav->videoFlags = 0;
+ psav->videoFourCC = 0;
+ }
+}
+
+
+void SavageSetColorKeyOld(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
+ int red, green, blue;
+
+ /* Here, we reset the colorkey and all the controls. */
+
+ red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
+ green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
+ blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
+
+ if( !pPriv->colorKey ) {
+ OUTREG( COL_CHROMA_KEY_CONTROL_REG, 0 );
+ OUTREG( CHROMA_KEY_UPPER_BOUND_REG, 0 );
+ OUTREG( BLEND_CONTROL_REG, 0 );
+ }
+ else {
+ switch (pScrn->depth) {
+ case 8:
+ OUTREG( COL_CHROMA_KEY_CONTROL_REG,
+ 0x37000000 | (pPriv->colorKey & 0xFF) );
+ OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
+ 0x00000000 | (pPriv->colorKey & 0xFF) );
+ break;
+ case 15:
+ OUTREG( COL_CHROMA_KEY_CONTROL_REG,
+ 0x05000000 | (red<<19) | (green<<11) | (blue<<3) );
+ OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
+ 0x00000000 | (red<<19) | (green<<11) | (blue<<3) );
+ break;
+ case 16:
+ OUTREG( COL_CHROMA_KEY_CONTROL_REG,
+ 0x16000000 | (red<<19) | (green<<10) | (blue<<3) );
+ OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
+ 0x00020002 | (red<<19) | (green<<10) | (blue<<3) );
+ break;
+ case 24:
+ OUTREG( COL_CHROMA_KEY_CONTROL_REG,
+ 0x17000000 | (red<<16) | (green<<8) | (blue) );
+ OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
+ 0x00000000 | (red<<16) | (green<<8) | (blue) );
+ break;
+ }
+
+ /* We use destination colorkey */
+ OUTREG( BLEND_CONTROL_REG, 0x05000000 );
+ }
+}
+
+void SavageSetColorKeyNew(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
+ int red, green, blue;
+
+ /* Here, we reset the colorkey and all the controls. */
+
+ red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
+ green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
+ blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
+
+ if( !pPriv->colorKey ) {
+ OUTREG( SEC_STREAM_CKEY_LOW, 0 );
+ OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
+ OUTREG( BLEND_CONTROL, psav->blendBase | 0x08 );
+ }
+ else {
+ switch (pScrn->depth) {
+ case 8:
+ OUTREG( SEC_STREAM_CKEY_LOW,
+ 0x47000000 | (pPriv->colorKey & 0xFF) );
+ OUTREG( SEC_STREAM_CKEY_UPPER,
+ 0x47000000 | (pPriv->colorKey & 0xFF) );
+ break;
+ case 15:
+ OUTREG( SEC_STREAM_CKEY_LOW,
+ 0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+ OUTREG( SEC_STREAM_CKEY_UPPER,
+ 0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+ break;
+ case 16:
+ OUTREG( SEC_STREAM_CKEY_LOW,
+ 0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
+ OUTREG( SEC_STREAM_CKEY_UPPER,
+ 0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
+ break;
+ case 24:
+ OUTREG( SEC_STREAM_CKEY_LOW,
+ 0x47000000 | (red<<16) | (green<<8) | (blue) );
+ OUTREG( SEC_STREAM_CKEY_UPPER,
+ 0x47000000 | (red<<16) | (green<<8) | (blue) );
+ break;
+ }
+
+ /* We assume destination colorkey */
+ OUTREG( BLEND_CONTROL, psav->blendBase | 0x08 );
+ }
+}
+
+
+void SavageSetColorOld( ScrnInfoPtr pScrn )
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
+
+ xf86ErrorFVerb(XVTRACE, "bright %d, contrast %d, saturation %d, hue %d\n",
+ pPriv->brightness, pPriv->contrast, pPriv->saturation, pPriv->hue );
+
+ if(
+ (psav->videoFourCC == FOURCC_RV15) ||
+ (psav->videoFourCC == FOURCC_RV16)
+ )
+ {
+ OUTREG( COLOR_ADJUSTMENT_REG, 0 );
+ }
+ else
+ {
+ /* Change 0..255 into 0..15 */
+ long sat = pPriv->saturation * 16 / 256;
+ double hue = pPriv->hue * 0.017453292;
+ unsigned long hs1 = ((long)(sat * cos(hue))) & 0x1f;
+ unsigned long hs2 = ((long)(sat * sin(hue))) & 0x1f;
+
+ OUTREG( COLOR_ADJUSTMENT_REG,
+ 0x80008000 |
+ (pPriv->brightness + 128) |
+ ((pPriv->contrast & 0xf8) << (12-7)) |
+ (hs1 << 16) |
+ (hs2 << 24)
+ );
+
+ }
+}
+
+void SavageSetColorNew( ScrnInfoPtr pScrn )
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
+
+ /* Brightness/contrast/saturation/hue computations. */
+
+ double k, dk1, dk2, dk3, dk4, dk5, dk6, dk7, dkb;
+ int k1, k2, k3, k4, k5, k6, k7, kb;
+ double s = pPriv->saturation / 128.0;
+ double h = pPriv->hue * 0.017453292;
+ unsigned long assembly;
+
+ xf86ErrorFVerb(XVTRACE, "bright %d, contrast %d, saturation %d, hue %d\n",
+ pPriv->brightness, pPriv->contrast, pPriv->saturation, pPriv->hue );
+
+ if( psav->videoFourCC == FOURCC_Y211 )
+ k = 1.0; /* YUV */
+ else
+ k = 1.14; /* YCrCb */
+
+ /*
+ * The S3 documentation must be wrong for k4 and k5. Their default
+ * values, which they hardcode in their Windows driver, have the
+ * opposite sign from the results in the register spec.
+ */
+
+ dk1 = k * pPriv->contrast;
+ dk2 = 64.0 * 1.371 * k * s * cos(h);
+ dk3 = -64.0 * 1.371 * k * s * sin(h);
+ dk4 = -128.0 * k * s * (0.698 * cos(h) - 0.336 * sin(h));
+ dk5 = -128.0 * k * s * (0.698 * sin(h) + 0.336 * cos(h));
+ dk6 = 64.0 * 1.732 * k * s * sin(h); /* == k3 / 1.26331, right? */
+ dk7 = 64.0 * 1.732 * k * s * cos(h); /* == k2 / -1.26331, right? */
+ dkb = 128.0 * pPriv->brightness + 64.0;
+ if( psav->videoFourCC != FOURCC_Y211 )
+ dkb -= dk1 * 14.0;
+
+ k1 = (int)(dk1+0.5) & 0x1ff;
+ k2 = (int)(dk2+0.5) & 0x1ff;
+ k3 = (int)(dk3+0.5) & 0x1ff;
+ assembly = (k3<<18) | (k2<<9) | k1;
+ xf86ErrorFVerb(XVTRACE+1, "CC1 = %08x ", assembly );
+ OUTREG( SEC_STREAM_COLOR_CONVERT1, assembly );
+
+ k4 = (int)(dk4+0.5) & 0x1ff;
+ k5 = (int)(dk5+0.5) & 0x1ff;
+ k6 = (int)(dk6+0.5) & 0x1ff;
+ assembly = (k6<<18) | (k5<<9) | k4;
+ xf86ErrorFVerb(XVTRACE+1, "CC2 = %08x ", assembly );
+ OUTREG( SEC_STREAM_COLOR_CONVERT2, assembly );
+
+ k7 = (int)(dk7+0.5) & 0x1ff;
+ kb = (int)(dkb+0.5) & 0xffff;
+ assembly = (kb<<9) | k7;
+ xf86ErrorFVerb(XVTRACE+1, "CC3 = %08x\n", assembly );
+ OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly );
+}
+
+
+void SavageResetVideo(ScrnInfoPtr pScrn)
+{
+ xf86ErrorFVerb(XVTRACE,"SavageResetVideo\n");
+ SavageSetColor( pScrn );
+ SavageSetColorKey( pScrn );
+}
+
+
+static XF86VideoAdaptorPtr
+SavageSetupImageVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ SavagePtr psav = SAVPTR(pScrn);
+ XF86VideoAdaptorPtr adapt;
+ SavagePortPrivPtr pPriv;
+
+ xf86ErrorFVerb(XVTRACE,"SavageSetupImageVideo\n");
+
+ if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
+ sizeof(SavagePortPrivRec) +
+ sizeof(DevUnion))))
+ return NULL;
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+ adapt->name = "Savage Streams Engine";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = DummyEncoding;
+ adapt->nFormats = NUM_FORMATS;
+ adapt->pFormats = Formats;
+ adapt->nPorts = 1;
+ adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
+ pPriv = (SavagePortPrivPtr)(&adapt->pPortPrivates[1]);
+ adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
+ adapt->pAttributes = Attributes;
+ adapt->nImages = NUM_IMAGES;
+ adapt->nAttributes = NUM_ATTRIBUTES;
+ adapt->pImages = Images;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+ adapt->GetVideo = NULL;
+ adapt->GetStill = NULL;
+ adapt->StopVideo = SavageStopVideo;
+ adapt->SetPortAttribute = SavageSetPortAttribute;
+ adapt->GetPortAttribute = SavageGetPortAttribute;
+ adapt->QueryBestSize = SavageQueryBestSize;
+ adapt->PutImage = SavagePutImage;
+ adapt->QueryImageAttributes = SavageQueryImageAttributes;
+
+ xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+ xvContrast = MAKE_ATOM("XV_CONTRAST");
+ xvColorKey = MAKE_ATOM("XV_COLORKEY");
+ xvHue = MAKE_ATOM("XV_HUE");
+ xvSaturation = MAKE_ATOM("XV_SATURATION");
+
+ pPriv->colorKey =
+ (1 << pScrn->offset.red) |
+ (1 << pScrn->offset.green) |
+ (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
+ pPriv->videoStatus = 0;
+ pPriv->brightness = 0;
+ pPriv->contrast = 128;
+ pPriv->saturation = 128;
+#if 0
+ /*
+ * The S3 driver has these values for some of the chips. I have yet
+ * to find any Savage where these make sense.
+ */
+ pPriv->brightness = 64;
+ pPriv->contrast = 16;
+ pPriv->saturation = 128;
+#endif
+ pPriv->hue = 0;
+ pPriv->lastKnownPitch = 0;
+
+ /* gotta uninit this someplace */
+ REGION_INIT(pScreen, &pPriv->clip, NullBox, 0);
+
+ psav->adaptor = adapt;
+
+#if 0
+ psav->BlockHandler = pScreen->BlockHandler;
+ pScreen->BlockHandler = SavageBlockHandler;
+#endif
+
+ return adapt;
+}
+
+
+static Bool
+RegionsEqual(RegionPtr A, RegionPtr B)
+{
+ int *dataA, *dataB;
+ int num;
+
+ num = REGION_NUM_RECTS(A);
+ if(num != REGION_NUM_RECTS(B))
+ return FALSE;
+
+ if((A->extents.x1 != B->extents.x1) ||
+ (A->extents.x2 != B->extents.x2) ||
+ (A->extents.y1 != B->extents.y1) ||
+ (A->extents.y2 != B->extents.y2))
+ return FALSE;
+
+ dataA = (int*)REGION_RECTS(A);
+ dataB = (int*)REGION_RECTS(B);
+
+ while(num--) {
+ if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
+ return FALSE;
+ dataA += 2;
+ dataB += 2;
+ }
+
+ return TRUE;
+}
+
+
+/* SavageClipVideo -
+
+ Takes the dst box in standard X BoxRec form (top and left
+ edges inclusive, bottom and right exclusive). The new dst
+ box is returned. The source boundaries are given (x1, y1
+ inclusive, x2, y2 exclusive) and returned are the new source
+ boundaries in 16.16 fixed point.
+*/
+
+static void
+SavageClipVideo(
+ BoxPtr dst,
+ INT32 *x1,
+ INT32 *x2,
+ INT32 *y1,
+ INT32 *y2,
+ BoxPtr extents, /* extents of the clip region */
+ INT32 width,
+ INT32 height
+){
+ INT32 vscale, hscale, delta;
+ int diff;
+
+ hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
+ vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
+
+ *x1 <<= 16; *x2 <<= 16;
+ *y1 <<= 16; *y2 <<= 16;
+
+ diff = extents->x1 - dst->x1;
+ if(diff > 0) {
+ dst->x1 = extents->x1;
+ *x1 += diff * hscale;
+ }
+ diff = dst->x2 - extents->x2;
+ if(diff > 0) {
+ dst->x2 = extents->x2;
+ *x2 -= diff * hscale;
+ }
+ diff = extents->y1 - dst->y1;
+ if(diff > 0) {
+ dst->y1 = extents->y1;
+ *y1 += diff * vscale;
+ }
+ diff = dst->y2 - extents->y2;
+ if(diff > 0) {
+ dst->y2 = extents->y2;
+ *y2 -= diff * vscale;
+ }
+
+ if(*x1 < 0) {
+ diff = (- *x1 + hscale - 1)/ hscale;
+ dst->x1 += diff;
+ *x1 += diff * hscale;
+ }
+ delta = *x2 - (width << 16);
+ if(delta > 0) {
+ diff = (delta + hscale - 1)/ hscale;
+ dst->x2 -= diff;
+ *x2 -= diff * hscale;
+ }
+ if(*y1 < 0) {
+ diff = (- *y1 + vscale - 1)/ vscale;
+ dst->y1 += diff;
+ *y1 += diff * vscale;
+ }
+ delta = *y2 - (height << 16);
+ if(delta > 0) {
+ diff = (delta + vscale - 1)/ vscale;
+ dst->y2 -= diff;
+ *y2 -= diff * vscale;
+ }
+}
+
+static void
+SavageStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
+{
+ SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
+ /*SavagePtr psav = SAVPTR(pScrn); */
+
+ xf86ErrorFVerb(XVTRACE,"SavageStopVideo\n");
+
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+
+ SavageStreamsOff( pScrn );
+
+ if(shutdown) {
+ if(pPriv->area) {
+ xf86FreeOffscreenArea(pPriv->area);
+ pPriv->area = NULL;
+ }
+ pPriv->videoStatus = 0;
+ } else {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ pPriv->videoStatus |= OFF_TIMER;
+ pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
+ }
+ }
+}
+
+
+static int
+SavageSetPortAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value,
+ pointer data
+){
+ SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
+ SavagePtr psav = SAVPTR(pScrn);
+
+ if(attribute == xvColorKey) {
+ pPriv->colorKey = value;
+ if( psav->videoFlags & VF_STREAMS_ON)
+ SavageSetColorKey( pScrn );
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+ }
+ else if( attribute == xvBrightness) {
+ if((value < -128) || (value > 127))
+ return BadValue;
+ pPriv->brightness = value;
+ if( psav->videoFlags & VF_STREAMS_ON)
+ SavageSetColor( pScrn );
+ }
+ else if( attribute == xvContrast) {
+ if((value < 0) || (value > 255))
+ return BadValue;
+ pPriv->contrast = value;
+ if( psav->videoFlags & VF_STREAMS_ON)
+ SavageSetColor( pScrn );
+ }
+ else if( attribute == xvSaturation) {
+ if((value < 0) || (value > 255))
+ return BadValue;
+ pPriv->saturation = value;
+ if( psav->videoFlags & VF_STREAMS_ON)
+ SavageSetColor( pScrn );
+ }
+ else if( attribute == xvHue) {
+ if((value < -180) || (value > 180))
+ return BadValue;
+ pPriv->hue = value;
+ if( psav->videoFlags & VF_STREAMS_ON)
+ SavageSetColor( pScrn );
+ }
+ else
+ return BadMatch;
+
+ return Success;
+}
+
+
+static int
+SavageGetPortAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value,
+ pointer data
+){
+ SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
+
+ if(attribute == xvColorKey) {
+ *value = pPriv->colorKey;
+ }
+ else if( attribute == xvBrightness ) {
+ *value = pPriv->brightness;
+ }
+ else if( attribute == xvContrast ) {
+ *value = pPriv->contrast;
+ }
+ else if( attribute == xvHue ) {
+ *value = pPriv->hue;
+ }
+ else if( attribute == xvSaturation ) {
+ *value = pPriv->saturation;
+ }
+ else return BadMatch;
+
+ return Success;
+}
+
+static void
+SavageQueryBestSize(
+ ScrnInfoPtr pScrn,
+ Bool motion,
+ short vid_w, short vid_h,
+ short drw_w, short drw_h,
+ unsigned int *p_w, unsigned int *p_h,
+ pointer data
+){
+ /* What are the real limits for the Savage? */
+
+ *p_w = drw_w;
+ *p_h = drw_h;
+
+ if(*p_w > 16384) *p_w = 16384;
+}
+
+
+static void
+SavageCopyData(
+ unsigned char *src,
+ unsigned char *dst,
+ int srcPitch,
+ int dstPitch,
+ int h,
+ int w
+){
+ w <<= 1;
+ while(h--) {
+ memcpy(dst, src, w);
+ src += srcPitch;
+ dst += dstPitch;
+ }
+}
+
+static void
+SavageCopyPlanarData(
+ unsigned char *src1, /* Y */
+ unsigned char *src2, /* V */
+ unsigned char *src3, /* U */
+ unsigned char *dst1,
+ int srcPitch,
+ int srcPitch2,
+ int dstPitch,
+ int h,
+ int w
+){
+ CARD32 *dst = (CARD32*)dst1;
+ int i, j;
+
+ dstPitch >>= 2;
+ w >>= 1;
+
+ for(j = 0; j < h; j++) {
+ for(i = 0; i < w; i++) {
+/* Shouldn't this be 'if LITTLEENDIAN'? */
+#if 1
+ dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
+ (src3[i] << 8) | (src2[i] << 24);
+#else
+ dst[i] = (src1[i << 1] << 24) | (src1[(i << 1) + 1] << 8) |
+ (src3[i] << 0) | (src2[i] << 16);
+#endif
+ }
+ dst += dstPitch;
+ src1 += srcPitch;
+ if(j & 1) {
+ src2 += srcPitch2;
+ src3 += srcPitch2;
+ }
+ }
+}
+
+static FBAreaPtr
+SavageAllocateMemory(
+ ScrnInfoPtr pScrn,
+ FBAreaPtr area,
+ int numlines
+){
+ ScreenPtr pScreen;
+ FBAreaPtr new_area;
+
+ if(area) {
+ if((area->box.y2 - area->box.y1) >= numlines)
+ return area;
+
+ if(xf86ResizeOffscreenArea(area, pScrn->displayWidth, numlines))
+ return area;
+
+ xf86FreeOffscreenArea(area);
+ }
+
+ pScreen = screenInfo.screens[pScrn->scrnIndex];
+
+ xf86PurgeUnlockedOffscreenAreas(pScreen);
+ new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
+ numlines, 0, NULL, NULL, NULL);
+
+ if(!new_area) {
+ int max_w, max_h;
+
+ xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
+ FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);
+
+ if((max_w < pScrn->displayWidth) || (max_h < numlines))
+ return NULL;
+
+ xf86PurgeUnlockedOffscreenAreas(pScreen);
+ new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
+ numlines, 0, NULL, NULL, NULL);
+ }
+
+ return new_area;
+}
+
+static void
+SavageDisplayVideoOld(
+ ScrnInfoPtr pScrn,
+ int id,
+ int offset,
+ short width, short height,
+ int pitch,
+ int x1, int y1, int x2, int y2,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+){
+ SavagePtr psav = SAVPTR(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
+ /*DisplayModePtr mode = pScrn->currentMode;*/
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+ unsigned int ssControl;
+
+
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+
+ if( psav->videoFourCC != id )
+ SavageStreamsOff(pScrn);
+
+ if( !psav->videoFlags & VF_STREAMS_ON )
+ {
+ SavageStreamsOn(pScrn, id);
+ SavageResetVideo(pScrn);
+ }
+
+ /* Set surface format. */
+
+ OUTREG(SSTREAM_CONTROL_REG,
+ (GetBlendForFourCC(psav->videoFourCC) << 24) + src_w );
+
+ /* Calculate horizontal scale factor. */
+
+ OUTREG(SSTREAM_STRETCH_REG, (src_w << 15) / drw_w );
+
+ /* Calculate vertical scale factor. */
+
+ OUTREG(SSTREAM_LINES_REG, src_h );
+ OUTREG(SSTREAM_VINITIAL_REG, 0 );
+ OUTREG(SSTREAM_VSCALE_REG, (src_h << 15) / drw_h );
+
+ /* Set surface location and stride. */
+
+ OUTREG(SSTREAM_FBADDR0_REG, (offset + (x1>>15)) & 0x3ffff0 );
+ OUTREG(SSTREAM_FBADDR1_REG, 0 );
+
+ OUTREG(SSTREAM_STRIDE_REG, pitch & 0xfff );
+
+ OUTREG(SSTREAM_WINDOW_START_REG, OS_XY(dstBox->x1, dstBox->y1) );
+ OUTREG(SSTREAM_WINDOW_SIZE_REG, OS_WH(drw_w, drw_h) );
+
+ ssControl = 0;
+
+ if( src_w > (drw_w << 1) )
+ {
+ /* BUGBUG shouldn't this be >=? */
+ if( src_w <= (drw_w << 2) )
+ ssControl |= HDSCALE_4;
+ else if( src_w > (drw_w << 3) )
+ ssControl |= HDSCALE_8;
+ else if( src_w > (drw_w << 4) )
+ ssControl |= HDSCALE_16;
+ else if( src_w > (drw_w << 5) )
+ ssControl |= HDSCALE_32;
+ else if( src_w > (drw_w << 6) )
+ ssControl |= HDSCALE_64;
+ }
+
+ ssControl |= src_w;
+ ssControl |= (1 << 24);
+ OUTREG(SSTREAM_CONTROL_REG, ssControl);
+
+ /* Set color key on primary. */
+
+ SavageSetColorKey( pScrn );
+
+ /* Set FIFO L2 on second stream. */
+
+ if( pPriv->lastKnownPitch != pitch )
+ {
+ unsigned char cr92;
+
+ pPriv->lastKnownPitch = pitch;
+
+ pitch = (pitch + 7) / 8;
+ VGAOUT8(vgaCRIndex, 0x92);
+ cr92 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
+ VGAOUT8(vgaCRIndex, 0x93);
+ VGAOUT8(vgaCRReg, pitch);
+ }
+
+}
+
+static void
+SavageDisplayVideoNew(
+ ScrnInfoPtr pScrn,
+ int id,
+ int offset,
+ short width, short height,
+ int pitch,
+ int x1, int y1, int x2, int y2,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+){
+ SavagePtr psav = SAVPTR(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ /*DisplayModePtr mode = pScrn->currentMode;*/
+ SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+
+
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+
+ if( psav->videoFourCC != id )
+ SavageStreamsOff(pScrn);
+
+ if( !psav->videoFlags & VF_STREAMS_ON )
+ {
+ SavageStreamsOn(pScrn, id);
+ SavageResetVideo(pScrn);
+ }
+
+ /* Calculate horizontal and vertical scale factors. */
+
+ if( psav->Chipset == S3_SAVAGE2000 )
+ {
+ OUTREG(SEC_STREAM_HSCALING,
+ (65536 * src_w / drw_w) & 0x1FFFFF );
+ if( src_w < drw_w )
+ OUTREG(SEC_STREAM_HSCALE_NORMALIZE,
+ ((2048 * src_w / drw_w) & 0x7ff) << 16 );
+ else
+ OUTREG(SEC_STREAM_HSCALE_NORMALIZE, 2048 << 16 );
+ OUTREG(SEC_STREAM_VSCALING,
+ (65536 * src_h / drw_h) & 0x1FFFFF );
+ }
+ else
+ {
+ if(
+ S3_SAVAGE_MOBILE_SERIES(psav->Chipset) &&
+ !psav->CrtOnly &&
+ !psav->TvOn
+ ) {
+ drw_w = (float)(drw_w * psav->XExp1)/(float)psav->XExp2 + 1;
+ drw_h = (float)(drw_h * psav->YExp1)/(float)psav->YExp2 + 1;
+ dstBox->x1 = (float)(dstBox->x1 * psav->XExp1)/(float)psav->XExp2;
+ dstBox->y1 = (float)(dstBox->y1 * psav->YExp1)/(float)psav->YExp2;
+ dstBox->x1 += psav->displayXoffset;
+ dstBox->y1 += psav->displayYoffset;
+ }
+
+ OUTREG(SEC_STREAM_HSCALING,
+ ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
+ /* BUGBUG need to add 00040000 if src stride > 2048 */
+ OUTREG(SEC_STREAM_VSCALING,
+ ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
+ }
+
+ /*
+ * Set surface location and stride. We use x1>>15 because all surfaces
+ * are 2 bytes/pixel.
+ */
+
+ OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15)) & 0x3ffff0 );
+ OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
+ OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
+ OUTREG(SEC_STREAM_WINDOW_SZ, ((drw_w) << 16) | drw_h );
+
+ /* Set color key on primary. */
+
+ SavageSetColorKey( pScrn );
+
+ /* Set FIFO L2 on second stream. */
+
+ if( pPriv->lastKnownPitch != pitch )
+ {
+ unsigned char cr92;
+
+ pPriv->lastKnownPitch = pitch;
+ pitch = (pitch + 7) / 8 - 4;
+ VGAOUT8(vgaCRIndex, 0x92);
+ cr92 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
+ VGAOUT8(vgaCRIndex, 0x93);
+ VGAOUT8(vgaCRReg, pitch);
+ }
+}
+
+static int
+SavagePutImage(
+ ScrnInfoPtr pScrn,
+ short src_x, short src_y,
+ short drw_x, short drw_y,
+ short src_w, short src_h,
+ short drw_w, short drw_h,
+ int id, unsigned char* buf,
+ short width, short height,
+ Bool sync,
+ RegionPtr clipBoxes, pointer data
+){
+ SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
+ SavagePtr psav = SAVPTR(pScrn);
+ INT32 x1, x2, y1, y2;
+ unsigned char *dst_start;
+ int pitch, new_h, offset, offsetV=0, offsetU=0;
+ int srcPitch, srcPitch2=0, dstPitch;
+ int top, left, npixels, nlines;
+ BoxRec dstBox;
+ CARD32 tmp;
+
+ if(drw_w > 16384) drw_w = 16384;
+
+ /* Clip */
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
+
+ dstBox.x1 = drw_x;
+ dstBox.x2 = drw_x + drw_w;
+ dstBox.y1 = drw_y;
+ dstBox.y2 = drw_y + drw_h;
+
+ SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
+ REGION_EXTENTS(pScreen, clipBoxes), width, height);
+
+ drw_w = dstBox.x2 - dstBox.x1;
+ drw_h = dstBox.y2 - dstBox.y1;
+ src_w = ( x2 - x1 ) >> 16;
+ src_h = ( y2 - y1 ) >> 16;
+
+ if((x1 >= x2) || (y1 >= y2))
+ return Success;
+
+ dstBox.x1 -= pScrn->frameX0;
+ dstBox.x2 -= pScrn->frameX0;
+ dstBox.y1 -= pScrn->frameY0;
+ dstBox.y2 -= pScrn->frameY0;
+
+ pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
+
+ dstPitch = ((width << 1) + 15) & ~15;
+ new_h = ((dstPitch * height) + pitch - 1) / pitch;
+
+ switch(id) {
+ case FOURCC_Y211: /* Y211 */
+ srcPitch = width;
+ break;
+ case FOURCC_YV12: /* YV12 */
+ srcPitch = (width + 3) & ~3;
+ offsetV = srcPitch * height;
+ srcPitch2 = ((width >> 1) + 3) & ~3;
+ offsetU = (srcPitch2 * (height >> 1)) + offsetV;
+ break;
+ case FOURCC_I420:
+ srcPitch = (width + 3) & ~3;
+ offsetU = srcPitch * height;
+ srcPitch2 = ((width >> 1) + 3) & ~3;
+ offsetV = (srcPitch2 * (height >> 1)) + offsetU;
+ break;
+ case FOURCC_RV15: /* RGB15 */
+ case FOURCC_RV16: /* RGB16 */
+ case FOURCC_YUY2: /* YUY2 */
+ default:
+ srcPitch = (width << 1);
+ break;
+ }
+
+ if(!(pPriv->area = SavageAllocateMemory(pScrn, pPriv->area, new_h)))
+ return BadAlloc;
+
+ /* copy data */
+ top = y1 >> 16;
+ left = (x1 >> 16) & ~1;
+ npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
+ left <<= 1;
+
+ offset = (pPriv->area->box.y1 * pitch) + (top * dstPitch);
+ dst_start = psav->FBBase + offset + left;
+
+ switch(id) {
+ case FOURCC_YV12: /* YV12 */
+ case FOURCC_I420:
+ top &= ~1;
+ tmp = ((top >> 1) * srcPitch2) + (left >> 2);
+ offsetU += tmp;
+ offsetV += tmp;
+ nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
+ SavageCopyPlanarData(
+ buf + (top * srcPitch) + (left >> 1),
+ buf + offsetV,
+ buf + offsetU,
+ dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
+ break;
+ case FOURCC_Y211: /* Y211 */
+ case FOURCC_RV15: /* RGB15 */
+ case FOURCC_RV16: /* RGB16 */
+ case FOURCC_YUY2: /* YUY2 */
+ default:
+ buf += (top * srcPitch) + left;
+ nlines = ((y2 + 0xffff) >> 16) - top;
+ SavageCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
+ break;
+ }
+
+ /* update cliplist */
+ if(!RegionsEqual(&pPriv->clip, clipBoxes)) {
+ REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
+ /* draw these */
+ XAAFillSolidRects(pScrn, pPriv->colorKey, GXcopy, ~0,
+ REGION_NUM_RECTS(clipBoxes),
+ REGION_RECTS(clipBoxes));
+ }
+
+ SavageDisplayVideo(pScrn, id, offset, width, height, dstPitch,
+ x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
+
+ pPriv->videoStatus = CLIENT_VIDEO_ON;
+
+ return Success;
+}
+
+static int
+SavageQueryImageAttributes(
+ ScrnInfoPtr pScrn,
+ int id,
+ unsigned short *w, unsigned short *h,
+ int *pitches, int *offsets
+){
+ int size, tmp;
+
+ if(*w > 1024) *w = 1024;
+ if(*h > 1024) *h = 1024;
+
+ *w = (*w + 1) & ~1;
+ if(offsets) offsets[0] = 0;
+
+ switch(id) {
+ case FOURCC_Y211:
+ size = *w << 2;
+ if(pitches) pitches[0] = size;
+ size *= *h;
+ break;
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ *h = (*h + 1) & ~1;
+ size = (*w + 3) & ~3;
+ if(pitches) pitches[0] = size;
+ size *= *h;
+ if(offsets) offsets[1] = size;
+ tmp = ((*w >> 1) + 3) & ~3;
+ if(pitches) pitches[1] = pitches[2] = tmp;
+ tmp *= (*h >> 1);
+ size += tmp;
+ if(offsets) offsets[2] = size;
+ size += tmp;
+ break;
+ case FOURCC_RV15: /* RGB15 */
+ case FOURCC_RV16: /* RGB16 */
+ case FOURCC_YUY2:
+ default:
+ size = *w << 1;
+ if(pitches) pitches[0] = size;
+ size *= *h;
+ break;
+ }
+
+ return size;
+}
+
+#if 0
+
+static void
+CHIPSBlockHandler (
+ int i,
+ pointer blockData,
+ pointer pTimeout,
+ pointer pReadmask
+){
+ ScreenPtr pScreen = screenInfo.screens[i];
+ ScrnInfoPtr pScrn = xf86Screens[i];
+ CHIPSPtr cPtr = CHIPSPTR(pScrn);
+ CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
+ unsigned char mr3c;
+
+ pScreen->BlockHandler = cPtr->BlockHandler;
+
+ (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+
+ pScreen->BlockHandler = CHIPSBlockHandler;
+
+ CHIPSHiQVSync(pScrn);
+ if(pPriv->videoStatus & TIMER_MASK) {
+ UpdateCurrentTime();
+ if(pPriv->videoStatus & OFF_TIMER) {
+ if(pPriv->offTime < currentTime.milliseconds) {
+ mr3c = cPtr->readMR(cPtr, 0x3C);
+ cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
+ pPriv->videoStatus = FREE_TIMER;
+ pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
+ }
+ } else { /* FREE_TIMER */
+ if(pPriv->freeTime < currentTime.milliseconds) {
+ if(pPriv->area) {
+ xf86FreeOffscreenArea(pPriv->area);
+ pPriv->area = NULL;
+ }
+ pPriv->videoStatus = 0;
+ }
+ }
+ }
+}
+
+#endif
+
+/****************** Offscreen stuff ***************/
+
+typedef struct {
+ FBAreaPtr area;
+ Bool isOn;
+} OffscreenPrivRec, * OffscreenPrivPtr;
+
+static int
+SavageAllocateSurface(
+ ScrnInfoPtr pScrn,
+ int id,
+ unsigned short w,
+ unsigned short h,
+ XF86SurfacePtr surface
+){
+ FBAreaPtr area;
+ int pitch, fbpitch, numlines;
+ OffscreenPrivPtr pPriv;
+
+ if((w > 1024) || (h > 1024))
+ return BadAlloc;
+
+ w = (w + 1) & ~1;
+ pitch = ((w << 1) + 15) & ~15;
+ fbpitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
+ numlines = ((pitch * h) + fbpitch - 1) / fbpitch;
+
+ if(!(area = SavageAllocateMemory(pScrn, NULL, numlines)))
+ return BadAlloc;
+
+ surface->width = w;
+ surface->height = h;
+
+ if(!(surface->pitches = xalloc(sizeof(int))))
+ return BadAlloc;
+ if(!(surface->offsets = xalloc(sizeof(int)))) {
+ xfree(surface->pitches);
+ return BadAlloc;
+ }
+ if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
+ xfree(surface->pitches);
+ xfree(surface->offsets);
+ return BadAlloc;
+ }
+
+ pPriv->area = area;
+ pPriv->isOn = FALSE;
+
+ surface->pScrn = pScrn;
+ surface->id = id;
+ surface->pitches[0] = pitch;
+ surface->offsets[0] = area->box.y1 * fbpitch;
+ surface->devPrivate.ptr = (pointer)pPriv;
+
+ return Success;
+}
+
+static int
+SavageStopSurface(
+ XF86SurfacePtr surface
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+
+ if(pPriv->isOn) {
+ /*SavagePtr psav = SAVPTR(surface->pScrn);*/
+ SavageStreamsOff( surface->pScrn );
+ pPriv->isOn = FALSE;
+ }
+
+ return Success;
+}
+
+
+static int
+SavageFreeSurface(
+ XF86SurfacePtr surface
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+
+ if(pPriv->isOn)
+ SavageStopSurface(surface);
+ xf86FreeOffscreenArea(pPriv->area);
+ xfree(surface->pitches);
+ xfree(surface->offsets);
+ xfree(surface->devPrivate.ptr);
+
+ return Success;
+}
+
+static int
+SavageGetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value
+){
+ return SavageGetPortAttribute(pScrn, attribute, value,
+ (pointer)(GET_PORT_PRIVATE(pScrn)));
+}
+
+static int
+SavageSetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value
+){
+ return SavageSetPortAttribute(pScrn, attribute, value,
+ (pointer)(GET_PORT_PRIVATE(pScrn)));
+}
+
+
+static int
+SavageDisplaySurface(
+ XF86SurfacePtr surface,
+ short src_x, short src_y,
+ short drw_x, short drw_y,
+ short src_w, short src_h,
+ short drw_w, short drw_h,
+ RegionPtr clipBoxes
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+ ScrnInfoPtr pScrn = surface->pScrn;
+ SavagePortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
+ INT32 x1, y1, x2, y2;
+ BoxRec dstBox;
+
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
+
+ dstBox.x1 = drw_x;
+ dstBox.x2 = drw_x + drw_w;
+ dstBox.y1 = drw_y;
+ dstBox.y2 = drw_y + drw_h;
+
+ SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
+ REGION_EXTENTS(pScreen, clipBoxes),
+ surface->width, surface->height);
+
+ if((x1 >= x2) || (y1 >= y2))
+ return Success;
+
+ dstBox.x1 -= pScrn->frameX0;
+ dstBox.x2 -= pScrn->frameX0;
+ dstBox.y1 -= pScrn->frameY0;
+ dstBox.y2 -= pScrn->frameY0;
+
+ XAAFillSolidRects(pScrn, portPriv->colorKey, GXcopy, ~0,
+ REGION_NUM_RECTS(clipBoxes),
+ REGION_RECTS(clipBoxes));
+
+ SavageDisplayVideo(pScrn, surface->id, surface->offsets[0],
+ surface->width, surface->height, surface->pitches[0],
+ x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
+
+ pPriv->isOn = TRUE;
+#if 0
+ if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
+ REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
+ UpdateCurrentTime();
+ portPriv->videoStatus = FREE_TIMER;
+ portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
+ }
+#endif
+
+ return Success;
+}
+
+
+static void
+SavageInitOffscreenImages(ScreenPtr pScreen)
+{
+ XF86OffscreenImagePtr offscreenImages;
+ SavagePtr psav = SAVPTR(xf86Screens[pScreen->myNum]);
+
+ /* need to free this someplace */
+ if (!psav->offscreenImages) {
+ if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
+ return;
+ psav->offscreenImages = offscreenImages;
+ } else {
+ offscreenImages = psav->offscreenImages;
+ }
+
+ offscreenImages[0].image = &Images[0];
+ offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
+ VIDEO_CLIP_TO_VIEWPORT;
+ offscreenImages[0].alloc_surface = SavageAllocateSurface;
+ offscreenImages[0].free_surface = SavageFreeSurface;
+ offscreenImages[0].display = SavageDisplaySurface;
+ offscreenImages[0].stop = SavageStopSurface;
+ offscreenImages[0].setAttribute = SavageSetSurfaceAttribute;
+ offscreenImages[0].getAttribute = SavageGetSurfaceAttribute;
+ offscreenImages[0].max_width = 1024;
+ offscreenImages[0].max_height = 1024;
+ offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
+ offscreenImages[0].attributes = Attributes;
+
+ xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
+}
+
+/* Function to get lcd factor, display offset for overlay use
+ * Input: pScrn; Output: x,yfactor, displayoffset in pScrn
+ */
+static void OverlayParamInit(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+
+ psav = SAVPTR(pScrn);
+ psav->cxScreen = psav->iResX;
+ InitStreamsForExpansion(psav);
+}
+
+/* Function to calculate lcd expansion x,yfactor and offset for overlay
+ */
+static void InitStreamsForExpansion(SavagePtr psav)
+{
+ int PanelSizeX,PanelSizeY;
+ int ViewPortWidth,ViewPortHeight;
+ int XFactor, YFactor;
+
+ PanelSizeX = psav->PanelX;
+ PanelSizeY = psav->PanelY;
+ ViewPortWidth = psav->iResX;
+ ViewPortHeight = psav->iResY;
+ if( PanelSizeX == 1408 )
+ PanelSizeX = 1400;
+ psav->XExpansion = 0x00010001;
+ psav->YExpansion = 0x00010001;
+ psav->displayXoffset = 0;
+ psav->displayYoffset = 0;
+
+ VGAOUT8(0x3C4, HZEXP_FACTOR_IGA1);
+ XFactor = VGAIN8(0x3C5) >> 4;
+ VGAOUT8(0x3C4, VTEXP_FACTOR_IGA1);
+ YFactor = VGAIN8(0x3C5) >> 4;
+
+ switch( XFactor )
+ {
+ case 1:
+ psav->XExpansion = 0x00010001;
+ psav->displayXoffset =
+ (((PanelSizeX - ViewPortWidth) / 2) + 0x7) & 0xFFF8;
+ break;
+
+ case 3:
+ psav->XExpansion = 0x00090008;
+ psav->displayXoffset =
+ (((PanelSizeX - ((9 * ViewPortWidth)/8)) / 2) + 0x7) & 0xFFF8;
+ break;
+
+ case 4:
+ psav->XExpansion = 0x00050004;
+
+ if ((psav->cxScreen == 800) && (PanelSizeX !=1400))
+ {
+ psav->displayXoffset =
+ (((PanelSizeX - ((5 * ViewPortWidth)/4)) / 2) ) & 0xFFF8;
+ }
+ else
+ {
+ psav->displayXoffset =
+ (((PanelSizeX - ((5 * ViewPortWidth)/4)) / 2) +0x7) & 0xFFF8;
+ }
+ break;
+
+ case 6:
+ psav->XExpansion = 0x00030002;
+ psav->displayXoffset =
+ (((PanelSizeX - ((3 * ViewPortWidth)/2)) / 2) + 0x7) & 0xFFF8;
+ break;
+
+ case 7:
+ psav->XExpansion = 0x00020001;
+ psav->displayXoffset =
+ (((PanelSizeX - (2 * ViewPortWidth)) / 2) + 0x7) & 0xFFF8;
+ break;
+ }
+
+ switch( YFactor )
+ {
+ case 0:
+ psav->YExpansion = 0x00010001;
+ psav->displayYoffset = (PanelSizeY - ViewPortHeight) / 2;
+ break;
+ case 1:
+ psav->YExpansion = 0x00010001;
+ psav->displayYoffset = (PanelSizeY - ViewPortHeight) / 2;
+ break;
+ case 2:
+ psav->YExpansion = 0x00040003;
+ psav->displayYoffset = (PanelSizeY - ((4 * ViewPortHeight)/3)) / 2;
+ break;
+ case 4:
+ psav->YExpansion = 0x00050004;
+ psav->displayYoffset = (PanelSizeY - ((5 * ViewPortHeight)/4)) / 2;
+ break;
+ case 5:
+ psav->YExpansion = 0x00040003;
+
+ if((psav->cxScreen == 1024)&&(PanelSizeX ==1400))
+ {
+ psav->displayYoffset =
+ ((PanelSizeY - ((4 * ViewPortHeight)/3)) / 2) - 0x1 ;
+ }
+ else
+ {
+ psav->displayYoffset = (PanelSizeY - ((4 * ViewPortHeight)/3)) / 2;
+ }
+ break;
+ case 6:
+ psav->YExpansion = 0x00050004;
+ psav->displayYoffset = (PanelSizeY - ((5 * ViewPortHeight)/4)) / 2;
+ break;
+ case 7:
+ psav->YExpansion = 0x00030002;
+ psav->displayYoffset = (PanelSizeY - ((3 * ViewPortHeight)/2)) / 2;
+ break;
+ case 8:
+ psav->YExpansion = 0x00020001;
+ psav->displayYoffset = (PanelSizeY - (2 * ViewPortHeight)) /2;
+ break;
+ case 9:
+ psav->YExpansion = 0x00090004;
+ psav->displayYoffset = (PanelSizeY - ((9 * ViewPortHeight)/4)) /2;
+ break;
+ case 11:
+ psav->YExpansion = 0x00110005;
+ psav->displayYoffset = (PanelSizeY - ((11 * ViewPortHeight)/5)) /2;
+ break;
+ case 12:
+ psav->YExpansion = 0x00070003;
+ psav->displayYoffset = (PanelSizeY - ((7 * ViewPortHeight)/3)) /2;
+ break;
+ case 14:
+ psav->YExpansion = 0x00050002;
+ psav->displayYoffset = (PanelSizeY - ((5 * ViewPortHeight)/2)) /2;
+ break;
+ case 15:
+ psav->YExpansion = 0x00040001;
+ psav->displayYoffset = (PanelSizeY - (4 * ViewPortHeight)) /2;
+ break;
+ }
+ psav->XExp1 = psav->XExpansion >> 16;
+ psav->XExp2 = psav->XExpansion & 0xFFFF;
+ psav->YExp1 = psav->YExpansion >> 16;
+ psav->YExp2 = psav->YExpansion & 0xFFFF;
+} /* InitStreamsForExpansionPM */
+
+#endif /* XvExtension */