diff options
-rw-r--r-- | man/savage.man | 127 | ||||
-rw-r--r-- | src/savage_accel.c | 1242 | ||||
-rw-r--r-- | src/savage_bci.h | 97 | ||||
-rw-r--r-- | src/savage_cursor.c | 299 | ||||
-rw-r--r-- | src/savage_dga.c | 397 | ||||
-rw-r--r-- | src/savage_driver.c | 3282 | ||||
-rw-r--r-- | src/savage_driver.h | 278 | ||||
-rw-r--r-- | src/savage_i2c.c | 93 | ||||
-rw-r--r-- | src/savage_image.c | 194 | ||||
-rw-r--r-- | src/savage_regs.h | 222 | ||||
-rw-r--r-- | src/savage_shadow.c | 244 | ||||
-rw-r--r-- | src/savage_vbe.c | 302 | ||||
-rw-r--r-- | src/savage_vbe.h | 113 | ||||
-rw-r--r-- | src/savage_video.c | 1982 |
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 */ |