diff options
-rw-r--r-- | README.sgml | 155 | ||||
-rw-r--r-- | man/i740.man | 30 | ||||
-rw-r--r-- | src/i740.h | 157 | ||||
-rw-r--r-- | src/i740_accel.c | 396 | ||||
-rw-r--r-- | src/i740_cursor.c | 220 | ||||
-rw-r--r-- | src/i740_dga.c | 252 | ||||
-rw-r--r-- | src/i740_dga.h | 26 | ||||
-rw-r--r-- | src/i740_driver.c | 1921 | ||||
-rw-r--r-- | src/i740_i2c.c | 105 | ||||
-rw-r--r-- | src/i740_io.c | 93 | ||||
-rw-r--r-- | src/i740_macros.h | 61 | ||||
-rw-r--r-- | src/i740_reg.h | 327 | ||||
-rw-r--r-- | src/i740_video.c | 1323 |
13 files changed, 5066 insertions, 0 deletions
diff --git a/README.sgml b/README.sgml new file mode 100644 index 0000000..3c978ae --- /dev/null +++ b/README.sgml @@ -0,0 +1,155 @@ +<!DOCTYPE linuxdoc PUBLIC "-//XFree86//DTD linuxdoc//EN" [ +<!ENTITY % defs SYSTEM "defs.ent"> %defs; +]> + +<article> +<title>Information for i740 Users +<author>Precision Insight, Inc. +<date>18 February 1999 +<ident> +$XFree86: xc/programs/Xserver/hw/xfree86/doc/sgml/i740.sgml,v 1.3 2000/03/04 00:26:30 dawes Exp $ +</ident> +<toc> + +<sect>Supported Hardware +<p> +<itemize> + <item>Intel 740 based cards. +</itemize> + + +<sect>Features +<p> +<itemize> + <item>Full support for 8, 15, 16, and 24 bit pixel depths. + <item>Hardware cursor support to reduce sprite flicker. + <item>Hardware accelerated 2D drawing engine support for 8, 15, 16 and + 24 bit pixel depths. + <item>Support for high resolution video modes up to 1600x1200. + <item>Support for doublescan video modes (e.g., 320x200 and 320x240). + <item>Support for gamma correction at all pixel depths. + <item>Fully programmable clock supported. + <item>Robust text mode restore for VT switching. +</itemize> + + +<sect>Technical Notes +<p> +<itemize> + <item>Hardware acceleration is not possible when using the framebuffer + in 32 bit per pixel format. + <item>Interlace modes cannot be supported. +</itemize> + + +<sect>Reported Working Video Cards +<p> +<itemize> + <item>Real3D Starfighter AGP + <item>Real3D Starfighter PCI + <item>Diamond Stealth II/G460 AGP + <item>3DVision-i740 AGP + <item>ABIT G740 8MB SDRAM + <item>Acorp AGP i740 + <item>AGP 2D/3D V. 1N, AGP-740D + <item>AOpen AGP 2X 3D Navigator PA740 + <item>ARISTO i740 AGP (ART-i740-G) + <item>ASUS AGP-V2740 + <item>Atrend (Speedy) 3DIO740 AGP (ATC-2740) + <item>Chaintech AGP-740D + <item>EliteGroup(ECS) 3DVision-i740 AGP + <item>EONtronics Picasso 740 + <item>EONtronics Van Gogh + <item>Everex MVGA i740/AG + <item>Flagpoint Shocker i740 8MB + <item>Gainward CardExpert 740 8MB + <item>Genoa Systems Phantom 740 + <item>Gigabyte Predator i740 8MB AGP + <item>Hercules Terminator 128 2X/i AGP + <item>HOT-158 (Shuttle) + <item>Intel Express 3D AGP + <item>Jaton Video-740 AGP 3D + <item>Jetway J-740-3D 8MB AGP, i740 AGP 3D + <item>Joymedia Apollo 7400 + <item>Leadtek Winfast S900 + <item>Machspeed Raptor i740 AGP 4600 + <item>Magic-Pro MP-740DVD + <item>MAXI Gamer AGP 8 MB + <item>Palit Daytona AGP740 + <item>PowerColor C740 (SG/SD) AGP + <item>QDI Amazing I + <item>Soyo AGP (SY-740 AGP) + <item>Spacewalker Hot-158 + <item>VideoExcel AGP 740 + <item>ViewTop ZeusL 8MB + <item>Winfast S900 i740 AGP 8MB +</itemize> + + +<sect>Configuration +<p> +The driver auto-detects all device information necessary to +initialize the card. The only lines you need in the "Device" +section of your XF86Config file are: +<verb> + Section "Device" + Identifier "Intel i740" + Driver "i740" + EndSection +</verb> +or let <tt>xf86config</tt> do this for you. + +However, if you have problems with auto-detection, you can specify: +<itemize> + <item>VideoRam - in kilobytes + <item>DacSpeed - in MHz + <item>MemBase - physical address of the linear framebuffer + <item>IOBase - physical address of the memory mapped IO registers +</itemize> + + +<sect>Driver Options +<p> +<itemize> + <item>"NoAccel" - Turn off hardware acceleration + <item>"SWCursor" - Request a software cursor (hardware is default) + <item>"SDRAM" - Force the use of SDRAM timings + <item>"SGRAM" - Force the use of SGRAM timings + <item>"SlowRam" - Force the use of slower ram timings + <item>"Dac6Bit" - Force the use of a 6 Bit Dac (8 Bit is the default) + <item>"UsePIO - Force the use of programmed IO (Memory mapped is the default) +</itemize> + +Note: the i740 X server should automatically detect whether your +card has SGRAM or SDRAM. Use the "sgram" and "sdram" options +if it is incorrectly detected. + + +<sect>Known Limitations +<p> +<itemize> + <item>Certain drawing operations are very slow when using 24 bit + pixel depth mode. +</itemize> + + +<sect>Author +<p> +<itemize> + <item>Original version by Kevin E Martin + <email>kevin@precisioninsight.com</email> + <item>Daryll Strauss <email>daryll@precisioninsight.com</email> +</itemize> + +This driver was donated to The XFree86 Project by: +<verb> + Precision Insight, Inc. + Cedar Park, TX + USA +</verb> + +<htmlurl name="http://www.precisioninsight.com" + url="http://www.precisioninsight.com"> + + +</article> diff --git a/man/i740.man b/man/i740.man new file mode 100644 index 0000000..9db6041 --- /dev/null +++ b/man/i740.man @@ -0,0 +1,30 @@ +.\" $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740.man,v 1.2 2001/01/27 18:20:48 dawes Exp $ +.\" shorthand for double quote that works everywhere. +.ds q \N'34' +.TH I740 __drivermansuffix__ __vendorversion__ +.SH NAME +i740 \- Intel i740 video driver +.SH SYNOPSIS +.nf +.B "Section \*qDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qi740\*q" +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B i740 +is an XFree86 driver for Intel i740 video cards. +THIS MAN PAGE NEEDS TO BE FILLED IN. +.SH SUPPORTED HARDWARE +The +.B i740 +driver supports... +.SH CONFIGURATION DETAILS +Please refer to XF86Config(__filemansuffix__) for general configuration +details. This section only covers configuration details specific to this +driver. +.SH "SEE ALSO" +XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__) +.SH AUTHORS +Authors include: ... diff --git a/src/i740.h b/src/i740.h new file mode 100644 index 0000000..63f78f2 --- /dev/null +++ b/src/i740.h @@ -0,0 +1,157 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740.h,v 1.7 2002/10/23 16:08:36 tsi Exp $ */ + +/* + * Authors: + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + +#ifndef _I740_H_ +#define _I740_H_ + +#include "xf86PciInfo.h" +#include "xf86Pci.h" + +#include "i740_reg.h" +#include "i740_macros.h" + +#include "xaa.h" +#include "xf86Cursor.h" + +/* Globals */ +/* Memory mapped register access macros */ +#define INREG8(addr) *(volatile CARD8 *)(pI740->MMIOBase + (addr)) +#define INREG16(addr) *(volatile CARD16 *)(pI740->MMIOBase + (addr)) +#define INREG(addr) *(volatile CARD32 *)(pI740->MMIOBase + (addr)) +#define OUTREG8(addr, val) *(volatile CARD8 *)(pI740->MMIOBase + (addr)) = (val) +#define OUTREG16(addr, val) *(volatile CARD16 *)(pI740->MMIOBase + (addr)) = (val) +#define OUTREG(addr, val) *(volatile CARD32 *)(pI740->MMIOBase + (addr)) = (val) + +typedef struct _I740Rec *I740Ptr; + +typedef void (*I740WriteIndexedByteFunc)(I740Ptr pI740, int addr, + unsigned char index, char value); +typedef char (*I740ReadIndexedByteFunc)(I740Ptr pI740, int addr, + unsigned char index); +typedef void (*I740WriteByteFunc)(I740Ptr pI740, int addr, unsigned char value); +typedef char (*I740ReadByteFunc)(I740Ptr pI740, int addr); + +typedef struct { + unsigned char DisplayControl; + unsigned char PixelPipeCfg0; + unsigned char PixelPipeCfg1; + unsigned char PixelPipeCfg2; + unsigned char VideoClk2_M; + unsigned char VideoClk2_N; + unsigned char VideoClk2_MN_MSBs; + unsigned char VideoClk2_DivisorSel; + unsigned char PLLControl; + unsigned char AddressMapping; + unsigned char IOControl; + unsigned char BitBLTControl; + unsigned char ExtVertTotal; + unsigned char ExtVertDispEnd; + unsigned char ExtVertSyncStart; + unsigned char ExtVertBlankStart; + unsigned char ExtHorizTotal; + unsigned char ExtHorizBlank; + unsigned char ExtOffset; + unsigned char InterlaceControl; + unsigned int LMI_FIFO_Watermark; +} I740RegRec, *I740RegPtr; + +typedef struct _I740Rec { + unsigned char *MMIOBase; + unsigned char *FbBase; + long FbMapSize; + int cpp; + int MaxClock; + int CursorStart; + int Chipset; + unsigned long LinearAddr; + unsigned long MMIOAddr; + EntityInfoPtr pEnt; + pciVideoPtr PciInfo; + PCITAG PciTag; + int HasSGRAM; + I740RegRec SavedReg; + I740RegRec ModeReg; + XAAInfoRecPtr AccelInfoRec; + xf86CursorInfoPtr CursorInfoRec; + FBAreaPtr CursorData; + CloseScreenProcPtr CloseScreen; + GFX2DOPREG_BLTER_FULL_LOAD bltcmd; + Bool usePIO; + I740WriteIndexedByteFunc writeControl; + I740ReadIndexedByteFunc readControl; + I740WriteByteFunc writeStandard; + I740ReadByteFunc readStandard; + OptionInfoPtr Options; + + /*DGA*/ + DGAModePtr DGAModes; + int numDGAModes; + Bool DGAactive; + int DGAViewportStatus; + BoxRec FbMemBox; + /*-*/ + + /*I2C*/ + I2CBusPtr rc_i2c; + /*-*/ + + /*-*/ /*Overlay*/ + XF86VideoAdaptorPtr adaptor; + unsigned long OverlayStart; + unsigned long OverlayPhysical; + int colorKey; + ScreenBlockHandlerProcPtr BlockHandler; + int ov_offset_x,ov_offset_y; + /*-*/ + + Bool usevgacompat; +} I740Rec; + +#define I740PTR(p) ((I740Ptr)((p)->driverPrivate)) + +extern Bool I740CursorInit(ScreenPtr pScreen); +extern Bool I740AccelInit(ScreenPtr pScreen); +void I740SetPIOAccess(I740Ptr pI740); +void I740SetMMIOAccess(I740Ptr pI740); +void I740InitVideo(ScreenPtr pScreen); + +Bool I740SwitchMode(int scrnIndex, DisplayModePtr mode, int flags); +void I740AdjustFrame(int scrnIndex, int x, int y, int flags); + + +#define minb(p) MMIO_IN8(pI740->MMIOBase, (p)) +#define moutb(p,v) MMIO_OUT8(pI740->MMIOBase, (p),(v)) + +#endif diff --git a/src/i740_accel.c b/src/i740_accel.c new file mode 100644 index 0000000..78c9644 --- /dev/null +++ b/src/i740_accel.c @@ -0,0 +1,396 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_accel.c,v 1.7 2002/10/21 13:32:58 alanh Exp $ */ + +/* + * Authors: + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" + +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "xaa.h" +#include "vgaHW.h" + +#include "xf86xv.h" +#include "i740.h" + +static unsigned int i740Rop[16] = { + 0x00, /* GXclear */ + 0x88, /* GXand */ + 0x44, /* GXandReverse */ + 0xCC, /* GXcopy */ + 0x22, /* GXandInvert */ + 0xAA, /* GXnoop */ + 0x66, /* GXxor */ + 0xEE, /* GXor */ + 0x11, /* GXnor */ + 0x99, /* GXequiv */ + 0x55, /* GXinvert */ + 0xDD, /* GXorReverse */ + 0x33, /* GXcopyInvert */ + 0xBB, /* GXorInverted */ + 0x77, /* GXnand */ + 0xFF /* GXset */ +}; + +static unsigned int i740PatternRop[16] = { + 0x00, /* GXclear */ + 0xA0, /* GXand */ + 0x50, /* GXandReverse */ + 0xF0, /* GXcopy */ + 0x0A, /* GXandInvert */ + 0xAA, /* GXnoop */ + 0x5A, /* GXxor */ + 0xFA, /* GXor */ + 0x05, /* GXnor */ + 0xA5, /* GXequiv */ + 0x55, /* GXinvert */ + 0xF5, /* GXorReverse */ + 0x0F, /* GXcopyInvert */ + 0xAF, /* GXorInverted */ + 0x5F, /* GXnand */ + 0xFF /* GXset */ +}; + +static void I740SyncPIO(ScrnInfoPtr pScrn); +static void I740SyncMMIO(ScrnInfoPtr pScrn); +static void I740SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask); +static void I740SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, + int w, int h); +static void I740SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, + int ydir, int rop, + unsigned int planemask, + int transparency_color); +static void I740SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, + int x2, int y2, int w, int h); +static void I740SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, + int pattx, int patty, + int fg, int bg, int rop, + unsigned int planemask); +static void I740SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, + int pattx, int patty, + int x, int y, int w, int h); +#if 0 +static void I740SetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int bg, int fg, int rop, + unsigned int planemask); +static void I740SubsequentCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int x, int y, int w, int h, + int skipleft); +#endif +/* + * The following function sets up the supported acceleration. Call it + * from the FbInit() function in the SVGA driver, or before ScreenInit + * in a monolithic server. + */ +Bool +I740AccelInit(ScreenPtr pScreen) { + XAAInfoRecPtr infoPtr; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I740Ptr pI740 = I740PTR(pScrn); + + pI740->AccelInfoRec = infoPtr = XAACreateInfoRec(); + if (!infoPtr) return FALSE; + + if (pScrn->bitsPerPixel == 32) { + infoPtr->Flags = 0; /* Disables all acceleration */ + return TRUE;; + } + + infoPtr->Flags = PIXMAP_CACHE | OFFSCREEN_PIXMAPS | LINEAR_FRAMEBUFFER; + + /* Sync */ + if (pI740->usePIO) + infoPtr->Sync = I740SyncPIO; + else + infoPtr->Sync = I740SyncMMIO; + + infoPtr->CachePixelGranularity=8/pI740->cpp; + + /* Solid filled rectangles */ + infoPtr->SolidFillFlags = NO_PLANEMASK; + infoPtr->SetupForSolidFill = I740SetupForSolidFill; + infoPtr->SubsequentSolidFillRect = I740SubsequentSolidFillRect; + + /* Screen to screen copy */ + infoPtr->ScreenToScreenCopyFlags = (NO_PLANEMASK | NO_TRANSPARENCY); + infoPtr->SetupForScreenToScreenCopy = I740SetupForScreenToScreenCopy; + infoPtr->SubsequentScreenToScreenCopy = I740SubsequentScreenToScreenCopy; + + /* 8x8 pattern fills */ + infoPtr->SetupForMono8x8PatternFill = I740SetupForMono8x8PatternFill; + infoPtr->SubsequentMono8x8PatternFillRect = I740SubsequentMono8x8PatternFillRect; + infoPtr->Mono8x8PatternFillFlags = NO_PLANEMASK | HARDWARE_PATTERN_SCREEN_ORIGIN | + BIT_ORDER_IN_BYTE_MSBFIRST; + + /* CPU to screen color expansion */ + /* Currently XAA is limited to only DWORD padding. The 3.3 driver + * uses NO_PAD scanlines b/c of problems with using the chip in + * DWORD mode. Once other padding modes are available in XAA this + * Code can be turned back on. + */ +#if 0 +#ifndef ALLOW_PCI_COLOR_EXP + if (pI740->Chipset != PCI_CHIP_I740_PCI) { +#endif + /* + * Currently, we are not properly able to read the bitblt engine + * busy bit on the PCI i740 card. When we are able to do so, we + * can re-enable color expansion. + */ + infoPtr->CPUToScreenColorExpandFillFlags = + NO_PLANEMASK | +#ifdef USE_DWORD_COLOR_EXP + SCANLINE_PAD_DWORD | +#endif + CPU_TRANSFER_PAD_QWORD | + SYNC_AFTER_COLOR_EXPAND | + BIT_ORDER_IN_BYTE_MSBFIRST; + infoPtr->ColorExpandBase = (unsigned char *)(pI740->MMIOBase + BLTDATA); + infoPtr->ColorExpandRange = 0x10000; + infoPtr->SetupForCPUToScreenColorExpandFill = I740SetupForCPUToScreenColorExpandFill; + infoPtr->SubsequentCPUToScreenColorExpandFill = I740SubsequentCPUToScreenColorExpandFill; +#ifndef ALLOW_PCI_COLOR_EXP + } +#endif +#endif + return XAAInit(pScreen, infoPtr); +} + +static void +I740SyncPIO(ScrnInfoPtr pScrn) { + WAIT_ENGINE_IDLE_PIO(); +} + +static void +I740SyncMMIO(ScrnInfoPtr pScrn) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + WAIT_ENGINE_IDLE_MMIO(); +} + +static void +I740SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, + unsigned int planemask) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + + pI740->bltcmd.BR00 = ((pScrn->displayWidth * pI740->cpp) << 16) | + (pScrn->displayWidth * pI740->cpp); + pI740->bltcmd.BR01 = color; + pI740->bltcmd.BR04 = SOLID_PAT_SELECT | PAT_IS_MONO | i740PatternRop[rop]; +} + +static void +I740SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + WAIT_LP_FIFO(12); + OUTREG(LP_FIFO, 0x6000000A); + OUTREG(LP_FIFO, pI740->bltcmd.BR00); + OUTREG(LP_FIFO, pI740->bltcmd.BR01); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, pI740->bltcmd.BR04); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, (y * pScrn->displayWidth + x) * pI740->cpp); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, (h << 16) | (w * pI740->cpp)); +} + +static void +I740SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, + unsigned int planemask, int transparency_color) +{ + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + pI740->bltcmd.BR00 = (((pScrn->displayWidth * pI740->cpp) << 16) | + (pScrn->displayWidth * pI740->cpp)); + + pI740->bltcmd.BR04 = SRC_IS_IN_COLOR | SRC_USE_SRC_ADDR | i740Rop[rop]; + if (xdir == -1) + pI740->bltcmd.BR04 |= BLT_RIGHT_TO_LEFT; + else + pI740->bltcmd.BR04 |= BLT_LEFT_TO_RIGHT; + + if (ydir == -1) + pI740->bltcmd.BR04 |= BLT_BOT_TO_TOP; + else + pI740->bltcmd.BR04 |= BLT_TOP_TO_BOT; + + pI740->bltcmd.BR01 = 0x00000000; + +} + +static void +I740SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int x1, int y1, + int x2, int y2, int w, int h) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + if (pI740->bltcmd.BR04 & BLT_BOT_TO_TOP) { + pI740->bltcmd.BR06 = (y1 + h - 1) * + pScrn->displayWidth * pI740->cpp; + pI740->bltcmd.BR07 = (y2 + h - 1) * + pScrn->displayWidth * pI740->cpp; + } else { + pI740->bltcmd.BR06 = y1 * pScrn->displayWidth * pI740->cpp; + pI740->bltcmd.BR07 = y2 * pScrn->displayWidth * pI740->cpp; + } + + if (pI740->bltcmd.BR04 & BLT_RIGHT_TO_LEFT) { + pI740->bltcmd.BR06 += (x1 + w - 1) * pI740->cpp + pI740->cpp - 1; + pI740->bltcmd.BR07 += (x2 + w - 1) * pI740->cpp + pI740->cpp - 1; + } else { + pI740->bltcmd.BR06 += x1 * pI740->cpp; + pI740->bltcmd.BR07 += x2 * pI740->cpp; + } + + WAIT_LP_FIFO(12); + OUTREG(LP_FIFO, 0x6000000A); + OUTREG(LP_FIFO, pI740->bltcmd.BR00); + OUTREG(LP_FIFO, pI740->bltcmd.BR01); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, pI740->bltcmd.BR04); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, pI740->bltcmd.BR06); + OUTREG(LP_FIFO, pI740->bltcmd.BR07); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, (h << 16) | (w * pI740->cpp)); +} + +static void +I740SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int pattx, int patty, + int fg, int bg, int rop, + unsigned int planemask) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + pI740->bltcmd.BR00 = ((pScrn->displayWidth * pI740->cpp) << 16) | + (pScrn->displayWidth * pI740->cpp); + + pI740->bltcmd.BR01 = bg; + pI740->bltcmd.BR02 = fg; + + pI740->bltcmd.BR04 = PAT_IS_MONO | i740PatternRop[rop]; + if (bg == -1) pI740->bltcmd.BR04 |= MONO_PAT_TRANSP; + + pI740->bltcmd.BR05 = (pattx + patty * pScrn->displayWidth) * pI740->cpp; +} + +static void +I740SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int pattx, int patty, + int x, int y, int w, int h) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + WAIT_LP_FIFO(12); + OUTREG(LP_FIFO, 0x6000000A); + OUTREG(LP_FIFO, pI740->bltcmd.BR00); + OUTREG(LP_FIFO, pI740->bltcmd.BR01); + OUTREG(LP_FIFO, pI740->bltcmd.BR02); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, pI740->bltcmd.BR04 | ((y<<20) & PAT_VERT_ALIGN)); + OUTREG(LP_FIFO, pI740->bltcmd.BR05); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, (y * pScrn->displayWidth + x) * pI740->cpp); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, (h << 16) | (w * pI740->cpp)); +} +#if 0 +static void +I740SetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int bg, int fg, + int rop, unsigned int planemask) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + pI740->bltcmd.BR00 = (pScrn->displayWidth * pI740->cpp) << 16; + pI740->bltcmd.BR01 = bg; + pI740->bltcmd.BR02 = fg; +#ifdef USE_DWORD_COLOR_EXP + pI740->bltcmd.BR03 = MONO_DWORD_ALIGN | MONO_USE_COLEXP; +#else + pI740->bltcmd.BR03 = MONO_BIT_ALIGN | MONO_USE_COLEXP; +#endif + pI740->bltcmd.BR04 = SRC_IS_MONO | SRC_USE_BLTDATA | i740Rop[rop]; + if (bg == -1) pI740->bltcmd.BR04 |= MONO_SRC_TRANSP; +} + +static void +I740SubsequentCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int x, int y, + int w, int h, int skipleft) { + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + pI740->AccelInfoRec->Sync(pScrn); + OUTREG(LP_FIFO, 0x6000000A); + OUTREG(LP_FIFO, pI740->bltcmd.BR00); + OUTREG(LP_FIFO, pI740->bltcmd.BR01); + OUTREG(LP_FIFO, pI740->bltcmd.BR02); + OUTREG(LP_FIFO, pI740->bltcmd.BR03 | (skipleft & MONO_SRC_LEFT_CLIP)); + OUTREG(LP_FIFO, pI740->bltcmd.BR04); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, (y * pScrn->displayWidth + x) * pI740->cpp); + OUTREG(LP_FIFO, 0x00000000); + OUTREG(LP_FIFO, 0x00000000); +#ifdef USE_DWORD_COLOR_EXP + /* + * This extra wait is necessary to keep the bitblt engine from + * locking up, but I am not sure why it is needed. If we take it + * out, "x11perf -copyplane10" will lock the bitblt engine. When + * the bitblt engine is locked, it is waiting for mono data to be + * written to the BLTDATA region, which seems to imply that some of + * the data that was written was lost. This might be fixed by + * BLT_SKEW changes. Update: The engine still locks up with this + * extra wait. More investigation (and time) is needed. + */ + WAIT_BLT_IDLE(); +#endif + OUTREG(LP_FIFO, (h << 16) | (w * pI740->cpp)); +} +#endif diff --git a/src/i740_cursor.c b/src/i740_cursor.c new file mode 100644 index 0000000..6f62660 --- /dev/null +++ b/src/i740_cursor.c @@ -0,0 +1,220 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_cursor.c,v 1.5 2002/10/21 13:32:58 alanh Exp $ */ + +/* + * Authors: + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86fbman.h" + +#include "vgaHW.h" +#include "xf86xv.h" +#include "i740.h" + +static void I740LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src); +static void I740ShowCursor(ScrnInfoPtr pScrn); +static void I740HideCursor(ScrnInfoPtr pScrn); +static void I740SetCursorPosition(ScrnInfoPtr pScrn, int x, int y); +static void I740SetCursorColors(ScrnInfoPtr pScrn, int bg, int fb); +static Bool I740UseHWCursor(ScreenPtr pScrn, CursorPtr pCurs); + +Bool +I740CursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn; + I740Ptr pI740; + xf86CursorInfoPtr infoPtr; + FBAreaPtr fbarea; + + pScrn = xf86Screens[pScreen->myNum]; + pI740 = I740PTR(pScrn); + pI740->CursorInfoRec = infoPtr = xf86CreateCursorInfoRec(); + if (!infoPtr) return FALSE; + + infoPtr->MaxWidth = 64; + infoPtr->MaxHeight = 64; + infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | + HARDWARE_CURSOR_INVERT_MASK | + HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64; + + infoPtr->SetCursorColors = I740SetCursorColors; + infoPtr->SetCursorPosition = I740SetCursorPosition; + infoPtr->LoadCursorImage = I740LoadCursorImage; + infoPtr->HideCursor = I740HideCursor; + infoPtr->ShowCursor = I740ShowCursor; + infoPtr->UseHWCursor = I740UseHWCursor; + +/* + * Allocate a region the full width and tall enough + * that at least 6K of video memory is consumed. + * Then use a 1 kilobyte piece that is 4K byte aligned + * within that region. KAO. + */ + fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->displayWidth, + ((6*1024)/(pScrn->displayWidth*pI740->cpp))+1, + 0,0,0,0); + if (fbarea == NULL) { + pI740->CursorStart=0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Hardware cursor disabled due to failure allocating offscreen memory.\n"); + } + else { + pI740->CursorStart = ((((fbarea->box.x1 + pScrn->displayWidth * fbarea->box.y1) * pI740->cpp)+4096)&0xfff000); + } + /* + * Perhaps move the cursor to the beginning of the frame buffer + * so that it never fails? + */ + if (pI740->CursorStart>4*1024*1024) { + pI740->CursorStart=0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling hardware cursor due to large framebuffer\n"); + } + return xf86InitCursor(pScreen, infoPtr); +} + +static Bool +I740UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) { + ScrnInfoPtr pScrn; + I740Ptr pI740; + + pScrn = xf86Screens[pScreen->myNum]; + pI740 = I740PTR(pScrn); + if (pScrn->currentMode->Flags&V_DBLSCAN) + return FALSE; + if (!pI740->CursorStart) return FALSE; + return TRUE; +} + +static void +I740LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *src) { + I740Ptr pI740; + int x, y; + CARD8 *pcurs; + + pI740 = I740PTR(pScrn); + pcurs = (CARD8 *)(pI740->FbBase + pI740->CursorStart); + for (y = 0; y < 64; y++) { + for (x = 0; x < 64 / 4; x++) { + *pcurs++ = *src++; + } + } +} + +static void +I740SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) { + I740Ptr pI740; + int flag; + + pI740 = I740PTR(pScrn); + if (x >= 0) flag = CURSOR_X_POS; + else { + flag = CURSOR_X_NEG; + x=-x; + } + pI740->writeControl(pI740, XRX, CURSOR_X_LO, x&0xFF); + pI740->writeControl(pI740, XRX, CURSOR_X_HI, (((x >> 8) & 0x07) | flag)); + + if (y >= 0) flag = CURSOR_Y_POS; + else { + flag = CURSOR_Y_NEG; + y=-y; + } + pI740->writeControl(pI740, XRX, CURSOR_Y_LO, y&0xFF); + pI740->writeControl(pI740, XRX, CURSOR_Y_HI, (((y >> 8) & 0x07) | flag)); +} + +static void +I740ShowCursor(ScrnInfoPtr pScrn) { + I740Ptr pI740; + unsigned char tmp; + + pI740 = I740PTR(pScrn); + pI740->writeControl(pI740, XRX, CURSOR_BASEADDR_LO, + (pI740->CursorStart & 0x0000F000) >> 8); + pI740->writeControl(pI740, XRX, CURSOR_BASEADDR_HI, + (pI740->CursorStart & 0x003F0000) >> 16); + pI740->writeControl(pI740, XRX, CURSOR_CONTROL, + CURSOR_ORIGIN_DISPLAY | CURSOR_MODE_64_3C); + + tmp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); + tmp |= HW_CURSOR_ENABLE; + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, tmp); +} + +static void +I740HideCursor(ScrnInfoPtr pScrn) { + unsigned char tmp; + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + tmp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); + tmp &= ~HW_CURSOR_ENABLE; + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, tmp); +} + +static void +I740SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) { + int tmp; + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + tmp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); + tmp |= EXTENDED_PALETTE; + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, tmp); + + pI740->writeStandard(pI740, DACMASK, 0xFF); + pI740->writeStandard(pI740, DACWX, 0x04); + + pI740->writeStandard(pI740, DACDATA, (bg & 0x00FF0000) >> 16); + pI740->writeStandard(pI740, DACDATA, (bg & 0x0000FF00) >> 8); + pI740->writeStandard(pI740, DACDATA, (bg & 0x000000FF)); + + pI740->writeStandard(pI740, DACDATA, (fg & 0x00FF0000) >> 16); + pI740->writeStandard(pI740, DACDATA, (fg & 0x0000FF00) >> 8); + pI740->writeStandard(pI740, DACDATA, (fg & 0x000000FF)); + + tmp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); + tmp &= ~EXTENDED_PALETTE; + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, tmp); +} + + + diff --git a/src/i740_dga.c b/src/i740_dga.c new file mode 100644 index 0000000..0edc0b9 --- /dev/null +++ b/src/i740_dga.c @@ -0,0 +1,252 @@ +/* + * Copyright 2001 by Patrick LERDA + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Patrick LERDA not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Patrick LERDA makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * PATRICK LERDA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL PATRICK LERDA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Patrick LERDA + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_dga.c,v 1.2 2003/02/12 21:46:42 tsi Exp $ */ + + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "xf86Pci.h" +#include "xf86PciInfo.h" +#include "xaa.h" +#include "xaalocal.h" +#include "vgaHW.h" +#include "xf86xv.h" +#include "i740.h" +#include "dgaproc.h" +#include "i740_dga.h" + +static Bool I740_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, int *, int *, int *); +static Bool I740_SetMode(ScrnInfoPtr, DGAModePtr); +static void I740_Sync(ScrnInfoPtr); +static int I740_GetViewport(ScrnInfoPtr); +static void I740_SetViewport(ScrnInfoPtr, int, int, int); +static void I740_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); +static void I740_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); +#if 0 +static void I740_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, unsigned long); +#endif + +static DGAFunctionRec I740DGAFuncs = { + I740_OpenFramebuffer, + NULL, + I740_SetMode, + I740_SetViewport, + I740_GetViewport, + I740_Sync, + I740_FillRect, + I740_BlitRect, +#if 0 + I740_BlitTransRect +#else + NULL +#endif +}; + +Bool I740DGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I740Ptr pI740 = I740PTR(pScrn); + DGAModePtr modes = NULL, newmodes = NULL, currentMode; + DisplayModePtr pMode, firstMode; + int Bpp = pScrn->bitsPerPixel >> 3; + int num = 0; + + pMode = firstMode = pScrn->modes; + + while(pMode) { + + newmodes = xrealloc(modes, (num + 1) * sizeof(DGAModeRec)); + + if(!newmodes) { + xfree(modes); + return FALSE; + } + modes = newmodes; + + currentMode = modes + num; + num++; + + currentMode->mode = pMode; + currentMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE; + if(pI740->AccelInfoRec) + currentMode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT; + if(pMode->Flags & V_DBLSCAN) + currentMode->flags |= DGA_DOUBLESCAN; + if(pMode->Flags & V_INTERLACE) + currentMode->flags |= DGA_INTERLACED; + currentMode->byteOrder = pScrn->imageByteOrder; + currentMode->depth = pScrn->depth; + currentMode->bitsPerPixel = pScrn->bitsPerPixel; + currentMode->red_mask = pScrn->mask.red; + currentMode->green_mask = pScrn->mask.green; + currentMode->blue_mask = pScrn->mask.blue; + currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor; + currentMode->viewportWidth = pMode->HDisplay; + currentMode->viewportHeight = pMode->VDisplay; + currentMode->xViewportStep = (Bpp == 3) ? 2 : 1; + currentMode->yViewportStep = 1; + currentMode->viewportFlags = DGA_FLIP_RETRACE; + currentMode->offset = 0; + currentMode->address = pI740->FbBase; + + currentMode->bytesPerScanline = + ((pScrn->displayWidth * Bpp) + 3) & ~3L; + currentMode->imageWidth = pI740->FbMemBox.x2; + currentMode->imageHeight = pI740->FbMemBox.y2; + currentMode->pixmapWidth = currentMode->imageWidth; + currentMode->pixmapHeight = currentMode->imageHeight; + currentMode->maxViewportX = currentMode->imageWidth - + currentMode->viewportWidth; + /* this might need to get clamped to some maximum */ + currentMode->maxViewportY = currentMode->imageHeight - + currentMode->viewportHeight; + + pMode = pMode->next; + if(pMode == firstMode) + break; + } + + pI740->numDGAModes = num; + pI740->DGAModes = modes; + + return DGAInit(pScreen, &I740DGAFuncs, modes, num); +} + +static DisplayModePtr I740SavedDGAModes[MAXSCREENS]; + +static Bool I740_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode) +{ + int index = pScrn->pScreen->myNum; + I740Ptr pI740 = I740PTR(pScrn); + + if(!pMode) { /* restore the original mode */ + if(pI740->DGAactive) { + pScrn->currentMode = I740SavedDGAModes[index]; + I740SwitchMode(index, pScrn->currentMode, 0); + I740AdjustFrame(index, 0, 0, 0); + pI740->DGAactive = FALSE; + } + } else { + if(!pI740->DGAactive) { + I740SavedDGAModes[index] = pScrn->currentMode; + pI740->DGAactive = TRUE; + } + + I740SwitchMode(index, pMode->mode, 0); + } + + return TRUE; +} + +static int I740_GetViewport(ScrnInfoPtr pScrn) +{ + I740Ptr pI740 = I740PTR(pScrn); + + return pI740->DGAViewportStatus; +} + +static void I740_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + I740Ptr pI740 = I740PTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + + I740AdjustFrame(pScrn->pScreen->myNum, x, y, flags); + + /* wait for retrace */ + while((hwp->readST01(hwp) & 0x08)); + while(!(hwp->readST01(hwp) & 0x08)); + + pI740->DGAViewportStatus = 0; +} + +static void I740_FillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h, unsigned long color) +{ + I740Ptr pI740 = I740PTR(pScrn); + + if(pI740->AccelInfoRec) { + (*pI740->AccelInfoRec->SetupForSolidFill)(pScrn, color, GXcopy, ~0); + (*pI740->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h); + SET_SYNC_FLAG(pI740->AccelInfoRec); + } +} + +static void I740_Sync(ScrnInfoPtr pScrn) +{ + I740Ptr pI740 = I740PTR(pScrn); + + if(pI740->AccelInfoRec) { + (*pI740->AccelInfoRec->Sync)(pScrn); + } +} + +static void I740_BlitRect( + ScrnInfoPtr pScrn, + int srcx, int srcy, + int w, int h, + int dstx, int dsty + ){ + I740Ptr pI740 = I740PTR(pScrn); + + if(pI740->AccelInfoRec) { + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*pI740->AccelInfoRec->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, GXcopy, ~0, -1); + (*pI740->AccelInfoRec->SubsequentScreenToScreenCopy)(pScrn, srcx, srcy, dstx, dsty, w, h); + SET_SYNC_FLAG(pI740->AccelInfoRec); + } +} + +#if 0 +static void I740_BlitTransRect(ScrnInfoPtr pScrn, + int srcx, int srcy, + int w, int h, + int dstx, int dsty, + unsigned long color + ) +{ + /* this one should be separate since the XAA function would + prohibit usage of ~0 as the key */ +} +#endif + +static Bool I740_OpenFramebuffer( + ScrnInfoPtr pScrn, + char **name, + unsigned char **mem, + int *size, + int *offset, + int *flags + ){ + I740Ptr pI740 = I740PTR(pScrn); + + *name = NULL; /* no special device */ + *mem = (unsigned char*)pI740->LinearAddr; + *size = pI740->FbMapSize; + *offset = 0; + *flags = DGA_NEED_ROOT; + + return TRUE; +} diff --git a/src/i740_dga.h b/src/i740_dga.h new file mode 100644 index 0000000..ea00de2 --- /dev/null +++ b/src/i740_dga.h @@ -0,0 +1,26 @@ +/* + * Copyright 2001 by Patrick LERDA + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Patrick LERDA not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Patrick LERDA makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * PATRICK LERDA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL PATRICK LERDA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Patrick LERDA + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_dga.h,v 1.1 2002/10/21 13:32:58 alanh Exp $ */ + +Bool I740DGAInit(ScreenPtr pScreen); diff --git a/src/i740_driver.c b/src/i740_driver.c new file mode 100644 index 0000000..51e8b61 --- /dev/null +++ b/src/i740_driver.c @@ -0,0 +1,1921 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_driver.c,v 1.41 2003/02/17 16:59:02 dawes Exp $ */ + +/* + * Authors: + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + +/* + * This server does not support these XFree86 4.0 features yet + * DDC1 & DDC2 (requires I2C) + * shadowFb (if requested or acceleration is off) + * Overlay planes + * DGA + */ + +/* + * These are X and server generic header files. + */ +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86cmap.h" + +/* If the driver uses port I/O directly, it needs: */ + +#include "compiler.h" + +/* Drivers using the mi implementation of backing store need: */ + +#include "mibstore.h" + +/* All drivers using the vgahw module need this */ +/* This driver needs to be modified to not use vgaHW for multihead operation */ +#include "vgaHW.h" + +/* Drivers using the mi SW cursor need: */ + +#include "mipointer.h" + +/* Drivers using the mi colourmap code need: */ + +#include "micmap.h" + +#define USE_FB + +#ifdef USE_FB +#include "fb.h" +#else +/* Drivers using cfb need: */ + +#define PSZ 8 +#include "cfb.h" +#undef PSZ + +/* Drivers supporting bpp 16, 24 or 32 with cfb need one or more of: */ + +#include "cfb16.h" +#include "cfb24.h" +#include "cfb32.h" +#endif + +/* The driver's own header file: */ + + +#include "miscstruct.h" + +#include "xf86xv.h" +#include "Xv.h" + +#include "vbe.h" +#include "i740_dga.h" +#include "i740.h" + + +/* Required Functions: */ +static const OptionInfoRec * I740AvailableOptions(int chipid, int busid); + +/* Print a driver identifying message. */ +static void I740Identify(int flags); + +/* Identify if there is any hardware present that I know how to drive. */ +static Bool I740Probe(DriverPtr drv, int flags); + +/* Process the config file and see if we have a valid configuration */ +static Bool I740PreInit(ScrnInfoPtr pScrn, int flags); + +/* Initialize a screen */ +static Bool I740ScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); + +/* Enter from a virtual terminal */ +static Bool I740EnterVT(int scrnIndex, int flags); + +/* Leave to a virtual terminal */ +static void I740LeaveVT(int scrnIndex, int flags); + +/* Close down each screen we initialized */ +static Bool I740CloseScreen(int scrnIndex, ScreenPtr pScreen); + +/* Change screensaver state */ +static Bool I740SaveScreen(ScreenPtr pScreen, int mode); + +/* Cleanup server private data */ +static void I740FreeScreen(int scrnIndex, int flags); + +/* Check if a mode is valid on the hardware */ +static int I740ValidMode(int scrnIndex, DisplayModePtr mode, Bool + verbose, int flags); + +/* Switch to various Display Power Management System levels */ +static void I740DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagermentMode, int flags); + +static void I740ProbeDDC(ScrnInfoPtr pScrn, int index); + +static Bool I740MapMem(ScrnInfoPtr pScrn); +static Bool I740UnmapMem(ScrnInfoPtr pScrn); + + +#define VERSION 4000 +#define I740_NAME "I740" +#define I740_DRIVER_NAME "i740" +#define I740_MAJOR_VERSION 1 +#define I740_MINOR_VERSION 0 +#define I740_PATCHLEVEL 0 + +DriverRec I740 = { + VERSION, + I740_DRIVER_NAME, + I740Identify, + I740Probe, + I740AvailableOptions, + NULL, + 0 +}; + +/* Chipsets */ +static SymTabRec I740Chipsets[] = { + { PCI_CHIP_I740_AGP, "i740 (agp)"}, + { PCI_CHIP_I740_PCI, "i740 (pci)"}, + { -1, NULL } +}; + +static PciChipsets I740PciChipsets[] = { + { PCI_CHIP_I740_AGP, PCI_CHIP_I740_AGP, RES_SHARED_VGA }, + { PCI_CHIP_I740_PCI, PCI_CHIP_I740_PCI, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED } +}; + +typedef enum { + OPTION_NOACCEL, + OPTION_SW_CURSOR, + OPTION_SDRAM, + OPTION_SGRAM, + OPTION_SLOW_RAM, + OPTION_DAC_6BIT, + OPTION_USE_PIO, + OPTION_VGACOMPAT +} I740Opts; + +static const OptionInfoRec I740Options[] = { + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SDRAM, "SDRAM", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_SGRAM, "SGRAM", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_SLOW_RAM, "SlowRam", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_USE_PIO, "UsePIO", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_VGACOMPAT, "VGACompat", OPTV_BOOLEAN, {0}, FALSE}, + { -1, NULL, OPTV_NONE, {0}, FALSE} +}; + +static const char *vgahwSymbols[] = { + "vgaHWGetHWRec", + "vgaHWSave", /* Added */ + "vgaHWRestore", /* Added */ + "vgaHWProtect", + "vgaHWInit", + "vgaHWMapMem", + "vgaHWSetMmioFuncs", + "vgaHWGetIOBase", + "vgaHWLock", + "vgaHWUnlock", + "vgaHWFreeHWRec", + "vgaHWSaveScreen", + "vgaHWHandleColormaps", + 0 +}; + +static const char *fbSymbols[] = { +#ifdef USE_FB + "fbScreenInit", + "fbPictureInit", +#else + "cfbScreenInit", + "cfb16ScreenInit", + "cfb24ScreenInit", + "cfb32ScreenInit", +#endif + "cfb8_32ScreenInit", + "cfb24_32ScreenInit", + NULL +}; + +static const char *xf8_32bppSymbols[] = { + "xf86Overlay8Plus32Init", + NULL +}; + +static const char *xaaSymbols[] = { + "XAADestroyInfoRec", + "XAACreateInfoRec", + "XAAInit", + "XAAStippleScanlineFuncLSBFirst", + "XAAOverlayFBfuncs", + "XAACachePlanarMonoStipple", + "XAAScreenIndex", + NULL +}; + +static const char *ramdacSymbols[] = { + "xf86InitCursor", + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + NULL +}; + +static const char *vbeSymbols[] = { + "VBEInit", + "vbeDoEDID", + NULL +}; + +static const char *ddcSymbols[] = { + "xf86PrintEDID", + "xf86DoEDID_DDC1", + "xf86DoEDID_DDC2", + NULL +}; + +static const char *i2cSymbols[] = { + "xf86CreateI2CBusRec", + "xf86I2CBusInit", + NULL +}; + + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(i740Setup); + +static XF86ModuleVersionInfo i740VersRec = +{ + "i740", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + I740_MAJOR_VERSION, I740_MINOR_VERSION, I740_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0,0,0,0} +}; + +XF86ModuleData i740ModuleData = {&i740VersRec, i740Setup, 0}; + +static pointer +i740Setup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + /* This module should be loaded only once, but check to be sure. */ + + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&I740, module, 0); + + /* + * Modules that this driver always requires may be loaded here + * by calling LoadSubModule(). + */ + + /* + * Tell the loader about symbols from other modules that this module + * might refer to. + */ + LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, + xf8_32bppSymbols, ramdacSymbols, vbeSymbols, + ddcSymbols, i2cSymbols, NULL /* shadowSymbols */, + NULL /* fbdevsymbols */, NULL); + + /* + * The return value must be non-NULL on success even though there + * is no TearDownProc. + */ + return (pointer)1; + } else { + if (errmaj) *errmaj = LDR_ONCEONLY; + return NULL; + } +} + +#endif + +/* + * I740GetRec and I740FreeRec -- + * + * Private data for the driver is stored in the screen structure. + * These two functions create and destroy that private data. + * + */ +static Bool +I740GetRec(ScrnInfoPtr pScrn) { + if (pScrn->driverPrivate) return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(I740Rec), 1); + return TRUE; +} + +static void +I740FreeRec(ScrnInfoPtr pScrn) { + if (!pScrn) return; + if (!pScrn->driverPrivate) return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate=0; +} + +static const OptionInfoRec * +I740AvailableOptions(int chipid, int busid) +{ + return I740Options; +} + +/* + * I740Identify -- + * + * Returns the string name for the driver based on the chipset. In this + * case it will always be an I740, so we can return a static string. + * + */ +static void +I740Identify(int flags) { + xf86PrintChipsets(I740_NAME, "Driver for Intel i740 chipset", I740Chipsets); +} + +/* + * I740Probe -- + * + * Look through the PCI bus to find cards that are I740 boards. + * Setup the dispatch table for the rest of the driver functions. + * + */ +static Bool +I740Probe(DriverPtr drv, int flags) { + int i, numUsed, numDevSections, *usedChips; + GDevPtr *devSections; + Bool foundScreen = FALSE; + + /* + Find the config file Device sections that match this + driver, and return if there are none. + */ + if ((numDevSections = xf86MatchDevice(I740_DRIVER_NAME, &devSections))<=0) { + return FALSE; + } + + /* + Since these Probing is just checking the PCI data the server already + collected. + */ + if (!xf86GetPciVideoInfo()) return FALSE; + + /* Look for Intel based chips */ + numUsed = xf86MatchPciInstances(I740_NAME, PCI_VENDOR_INTEL, + I740Chipsets, I740PciChipsets, + devSections, numDevSections, + drv, &usedChips); + + if (numUsed > 0) { + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i=0; i<numUsed; i++) { + ScrnInfoPtr pScrn = NULL; + /* Allocate new ScrnInfoRec and claim the slot */ + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], + I740PciChipsets, 0, 0, 0, 0, 0))) { + pScrn->driverVersion = VERSION; + pScrn->driverName = I740_DRIVER_NAME; + pScrn->name = I740_NAME; + pScrn->Probe = I740Probe; + pScrn->PreInit = I740PreInit; + pScrn->ScreenInit = I740ScreenInit; + pScrn->SwitchMode = I740SwitchMode; + pScrn->AdjustFrame = I740AdjustFrame; + pScrn->EnterVT = I740EnterVT; + pScrn->LeaveVT = I740LeaveVT; + pScrn->FreeScreen = I740FreeScreen; + pScrn->ValidMode = I740ValidMode; + foundScreen = TRUE; + + } + } + } + + + /* Look for Real3D based chips */ + numUsed = xf86MatchPciInstances(I740_NAME, PCI_VENDOR_REAL3D, + I740Chipsets, I740PciChipsets, + devSections, numDevSections, + drv, &usedChips); + + if (numUsed > 0) { + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i=0; i<numUsed; i++) { + ScrnInfoPtr pScrn = NULL; + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], + I740PciChipsets, 0, 0, 0, 0, 0))) { + pScrn->driverVersion = VERSION; + pScrn->driverName = I740_DRIVER_NAME; + pScrn->name = I740_NAME; + pScrn->Probe = I740Probe; + pScrn->PreInit = I740PreInit; + pScrn->ScreenInit = I740ScreenInit; + pScrn->SwitchMode = I740SwitchMode; + pScrn->AdjustFrame = I740AdjustFrame; + pScrn->EnterVT = I740EnterVT; + pScrn->LeaveVT = I740LeaveVT; + pScrn->FreeScreen = I740FreeScreen; + pScrn->ValidMode = I740ValidMode; + foundScreen = TRUE; + } + } + } + + xfree(devSections); + xfree(usedChips); + + return foundScreen; +} + +static void +I740ProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + if (xf86LoadSubModule(pScrn, "vbe")) { + pVbe = VBEInit(NULL,index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +/* + * I740PreInit -- + * + * Do initial setup of the board before we know what resolution we will + * be running at. + * + */ +static Bool +I740PreInit(ScrnInfoPtr pScrn, int flags) { + vgaHWPtr hwp; + I740Ptr pI740; + ClockRangePtr clockRanges; + int i; + MessageType from; + int temp; +#ifndef USE_FB + char *mod=0, *reqSym=0; +#endif + int flags24; + rgb defaultWeight = {0, 0, 0}; + + if (pScrn->numEntities != 1) return FALSE; + + /* Allocate driverPrivate */ + if (!I740GetRec(pScrn)) { + return FALSE; + } + + pI740 = I740PTR(pScrn); + + pI740->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if (pI740->pEnt->location.type != BUS_PCI) return FALSE; + + /*I740ProbeDDC(pScrn, pI740->pEnt->index);*/ + if (flags & PROBE_DETECT) { + I740ProbeDDC(pScrn, pI740->pEnt->index); + return TRUE; + } + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE; + + xf86LoaderReqSymLists(vgahwSymbols, NULL); + + /* Allocate a vgaHWRec */ + if (!vgaHWGetHWRec(pScrn)) return FALSE; + + pI740->PciInfo = xf86GetPciInfoForEntity(pI740->pEnt->index); + pI740->PciTag = pciTag(pI740->PciInfo->bus, pI740->PciInfo->device, + pI740->PciInfo->func); + + if (xf86RegisterResources(pI740->pEnt->index, 0, ResNone)) + return FALSE; + if (pI740->usePIO) + pScrn->racIoFlags = RAC_FB | RAC_COLORMAP; + else + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + + flags24=Support24bppFb | Support32bppFb | SupportConvert32to24; + if (!xf86SetDepthBpp(pScrn, 8, 8, 8, flags24)) { + return FALSE; + } else { + switch (pScrn->depth) { + case 8: + case 15: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by i740 driver\n", + pScrn->depth); + return FALSE; + } + } + /*xf86PrintDepthBpp(pScrn);*/ + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + + if (!xf86SetDefaultVisual(pScrn, -1)) { + return FALSE; + } else { + /* We don't currently support DirectColor at > 8bpp */ + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" + " (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + return FALSE; + } + } + + /* We use a programamble clock */ + pScrn->progClock = TRUE; + + hwp = VGAHWPTR(pScrn); + pI740->cpp = pScrn->bitsPerPixel/8; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(pI740->Options = xalloc(sizeof(I740Options)))) + return FALSE; + memcpy(pI740->Options, I740Options, sizeof(I740Options)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI740->Options); + + /* 6-BIT dac isn't reasonable for modes with > 8bpp */ + if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE) && + pScrn->bitsPerPixel>8) { + OptionInfoPtr ptr; + ptr=xf86TokenToOptinfo(pI740->Options, OPTION_DAC_6BIT); + ptr->found=FALSE; + } + + if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE)) + pScrn->rgbBits=8; + else + pScrn->rgbBits=6; + + /* We have to use PIO to probe, because we haven't mappend yet */ + I740SetPIOAccess(pI740); + + /* + * Set the Chipset and ChipRev, allowing config file entries to + * override. + */ + if (pI740->pEnt->device->chipset && *pI740->pEnt->device->chipset) { + pScrn->chipset = pI740->pEnt->device->chipset; + from = X_CONFIG; + } else if (pI740->pEnt->device->chipID >= 0) { + pScrn->chipset = (char *)xf86TokenToString(I740Chipsets, pI740->pEnt->device->chipID); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + pI740->pEnt->device->chipID); + } else { + from = X_PROBED; + pScrn->chipset = (char *)xf86TokenToString(I740Chipsets, pI740->PciInfo->chipType); + } + if (pI740->pEnt->device->chipRev >= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pI740->pEnt->device->chipRev); + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", (pScrn->chipset!=NULL)?pScrn->chipset:"Unknown i740"); + + if (pI740->pEnt->device->MemBase != 0) { + pI740->LinearAddr = pI740->pEnt->device->MemBase; + from = X_CONFIG; + } else { + if (pI740->PciInfo->memBase[1] != 0) { + pI740->LinearAddr = pI740->PciInfo->memBase[0]&0xFF000000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid FB address in PCI config space\n"); + I740FreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", + pI740->LinearAddr); + + if (pI740->pEnt->device->IOBase != 0) { + pI740->MMIOAddr = pI740->pEnt->device->IOBase; + from = X_CONFIG; + } else { + if (pI740->PciInfo->memBase[1]) { + pI740->MMIOAddr = pI740->PciInfo->memBase[1]&0xFFF80000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid MMIO address in PCI config space\n"); + I740FreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n", + pI740->MMIOAddr); + + /* Calculate memory */ + if (pI740->pEnt->device->videoRam) { + pScrn->videoRam = pI740->pEnt->device->videoRam; + from = X_CONFIG; + } else { + if ((pI740->readControl(pI740, XRX, DRAM_ROW_TYPE)&DRAM_ROW_1)==DRAM_ROW_1_SDRAM) + pScrn->videoRam=pI740->readControl(pI740, XRX, DRAM_ROW_BNDRY_1); + else + pScrn->videoRam=pI740->readControl(pI740, XRX, DRAM_ROW_BNDRY_0); + pScrn->videoRam = (pScrn->videoRam&0x0F)*1024; + from = X_PROBED; + } + + temp=pI740->readControl(pI740, XRX, DRAM_ROW_CNTL_LO); + pI740->HasSGRAM = !((temp&DRAM_RAS_TIMING)||(temp&DRAM_RAS_PRECHARGE)); + if (xf86IsOptionSet(pI740->Options, OPTION_SDRAM)) { + if (xf86IsOptionSet(pI740->Options, OPTION_SGRAM)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "It is nonsensical to set both SDRAM and SGRAM options\n"); + return FALSE; + } + if (xf86ReturnOptValBool(pI740->Options, OPTION_SDRAM, FALSE)) { + pI740->HasSGRAM = FALSE; + } else { + pI740->HasSGRAM = TRUE; + } + } else { + if (xf86IsOptionSet(pI740->Options, OPTION_SDRAM)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "It is nonsensical to set both SDRAM and SGRAM options\n"); + return FALSE; + } + if (xf86ReturnOptValBool(pI740->Options, OPTION_SGRAM, FALSE)) { + pI740->HasSGRAM = TRUE; + } else { + pI740->HasSGRAM = FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Steve was here! VideoRAM: %d kByte %s\n", + pScrn->videoRam, (pI740->HasSGRAM)?"SGRAM":"SDRAM"); + pI740->FbMapSize = pScrn->videoRam*1024; + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() + * here. + */ + + { + Gamma zeros = {0.0, 0.0, 0.0}; + + if (!xf86SetGamma(pScrn, zeros)) { + return FALSE; + } + } + + pI740->MaxClock = 0; + if (pI740->pEnt->device->dacSpeeds[0]) { + switch (pScrn->bitsPerPixel) { + case 8: + pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP8]; + break; + case 16: + pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP16]; + break; + case 24: + pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP24]; + break; + case 32: + pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP32]; + break; + } + if (!pI740->MaxClock) + pI740->MaxClock = pI740->pEnt->device->dacSpeeds[0]; + from = X_CONFIG; + } else { + switch (pScrn->bitsPerPixel) { + case 8: + pI740->MaxClock = 203000; + break; + case 16: + pI740->MaxClock = 163000; + break; + case 24: + if (pI740->HasSGRAM) + pI740->MaxClock = 136000; + else + pI740->MaxClock = 128000; + break; + case 32: + pI740->MaxClock = 86000; + } + } + clockRanges = xnfcalloc(sizeof(ClockRange), 1); + clockRanges->next=NULL; + clockRanges->minClock= 12000; /* !!! What's the min clock? !!! */ + clockRanges->maxClock=pI740->MaxClock; + clockRanges->clockIndex = -1; + clockRanges->interlaceAllowed = FALSE; /*PL*/ + clockRanges->doubleScanAllowed = TRUE; /*PL*/ + + i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, + pScrn->display->modes, clockRanges, + 0, 320, 1600, + 8, 200, 1200, + pScrn->display->virtualX, pScrn->display->virtualY, + pI740->FbMapSize, LOOKUP_BEST_REFRESH); + + if (i==-1) { + I740FreeRec(pScrn); + return FALSE; + } + + xf86PruneDriverModes(pScrn); + + if (!i || !pScrn->modes) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + I740FreeRec(pScrn); + return FALSE; + } + + xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); + + pScrn->currentMode = pScrn->modes; + + xf86PrintModes(pScrn); + + xf86SetDpi(pScrn, 0, 0); + +#ifdef USE_FB + if (!xf86LoadSubModule(pScrn, "fb")) { + I740FreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymbols("fbScreenInit","fbPictureInit", NULL); +#else + switch (pScrn->bitsPerPixel) { + case 8: + mod = "cfb"; + reqSym = "cfbScreenInit"; + break; + case 16: + mod = "cfb16"; + reqSym = "cfb16ScreenInit"; + break; + case 24: + mod = "cfb24"; + reqSym = "cfb24ScreenInit"; + break; + case 32: + mod = "cfb32"; + reqSym = "cfb32ScreenInit"; + break; + } + if (mod && !xf86LoadSubModule(pScrn, mod)) { + I740FreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymbols(reqSym, NULL); +#endif + + if (!xf86ReturnOptValBool(pI740->Options, OPTION_NOACCEL, FALSE)) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + I740FreeRec(pScrn); + return FALSE; + } + } + + if (!xf86ReturnOptValBool(pI740->Options, OPTION_SW_CURSOR, FALSE)) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + I740FreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + + /* We wont be using the VGA access after the probe */ + if (!xf86ReturnOptValBool(pI740->Options, OPTION_USE_PIO, FALSE)) { + resRange vgaio[] = { {ResShrIoBlock,0x3B0,0x3BB}, + {ResShrIoBlock,0x3C0,0x3DF}, + _END }; + resRange vgamem[] = {{ResShrMemBlock,0xA0000,0xAFFFF}, + {ResShrMemBlock,0xB8000,0xBFFFF}, + {ResShrMemBlock,0xB0000,0xB7FFF}, + _END }; + + pI740->usePIO=FALSE; + I740SetMMIOAccess(pI740); + xf86SetOperatingState(vgaio, pI740->pEnt->index, ResUnusedOpr); + xf86SetOperatingState(vgamem, pI740->pEnt->index, ResDisableOpr); + } else { + pI740->usePIO=TRUE; + } + + if(xf86IsOptionSet(pI740->Options, OPTION_VGACOMPAT)) + pI740->usevgacompat=TRUE; + else + pI740->usevgacompat=FALSE; + + +#if 0 /*DDC2*/ + { /*PL*/ + + if (xf86LoadSubModule(pScrn, "ddc")) { + xf86LoaderReqSymLists(ddcSymbols, NULL); + if ( xf86LoadSubModule(pScrn, "i2c") ) { + xf86LoaderReqSymLists(i2cSymbols,NULL); + + if (I740MapMem(pScrn)) + { + if (I740_I2CInit(pScrn)) + { + xf86MonPtr MonInfo; + + if ((MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,pI740->rc_i2c))) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DDC Monitor info: %p\n", + MonInfo); + xf86PrintEDID( MonInfo ); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "end of DDC Monitor " + "info\n\n"); + xf86SetDDCproperties(pScrn,MonInfo); + } + + //xf86SetDDCproperties(pScrn,xf86PrintEDID( xf86DoEDID_DDC2(pScrn->scrnIndex,pI740->rc_i2c))); + } + else + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n"); + + I740UnmapMem(pScrn); + } + } + } + } +#endif /*DDC2*/ + + { /* Overlay */ + pI740->colorKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) | + (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue); + + pI740->colorKey &= ((1 << pScrn->depth) - 1); + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video overlay key set to 0x%x\n", pI740->colorKey); + } + + + return TRUE; +} + +static Bool I740MapMem(ScrnInfoPtr pScrn) +{ + int mmioFlags; + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; + + pI740->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, + pI740->PciTag, + pI740->MMIOAddr, + 0x80000); + if (!pI740->MMIOBase) return FALSE; + + pI740->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + pI740->PciTag, + pI740->LinearAddr, + pI740->FbMapSize); + if (!pI740->FbBase) return FALSE; + + return TRUE; +} + +static Bool I740UnmapMem(ScrnInfoPtr pScrn) +{ + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pI740->MMIOBase, 0x80000); + pI740->MMIOBase=0; + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pI740->FbBase, pI740->FbMapSize); + pI740->FbBase = 0; + return TRUE; +} + +/* + * I740Save -- + * + * This function saves the video state. It reads all of the SVGA registers + * into the vgaI740Rec data structure. There is in general no need to + * mask out bits here - just read the registers. + */ +static void +DoSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I740RegPtr i740Reg, Bool saveFonts) +{ + I740Ptr pI740; + vgaHWPtr hwp; + + pI740 = I740PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + /* + * This function will handle creating the data structure and filling + * in the generic VGA portion. + */ + if (saveFonts) + vgaHWSave(pScrn, vgaReg, VGA_SR_MODE|VGA_SR_FONTS); + else + vgaHWSave(pScrn, vgaReg, VGA_SR_MODE); + + /* + * The port I/O code necessary to read in the extended registers + * into the fields of the vgaI740Rec structure goes here. + */ + + i740Reg->IOControl = pI740->readControl(pI740, XRX, IO_CTNL); + i740Reg->AddressMapping = pI740->readControl(pI740, XRX, ADDRESS_MAPPING); + i740Reg->BitBLTControl = pI740->readControl(pI740, XRX, BITBLT_CNTL); + i740Reg->VideoClk2_M = pI740->readControl(pI740, XRX, VCLK2_VCO_M); + i740Reg->VideoClk2_N = pI740->readControl(pI740, XRX, VCLK2_VCO_N); + i740Reg->VideoClk2_MN_MSBs = pI740->readControl(pI740, XRX, VCLK2_VCO_MN_MSBS); + i740Reg->VideoClk2_DivisorSel = pI740->readControl(pI740, XRX, VCLK2_VCO_DIV_SEL); + i740Reg->PLLControl = pI740->readControl(pI740, XRX, PLL_CNTL); + + i740Reg->ExtVertTotal=hwp->readCrtc(hwp, EXT_VERT_TOTAL); + i740Reg->ExtVertDispEnd=hwp->readCrtc(hwp, EXT_VERT_DISPLAY); + i740Reg->ExtVertSyncStart=hwp->readCrtc(hwp, EXT_VERT_SYNC_START); + i740Reg->ExtVertBlankStart=hwp->readCrtc(hwp, EXT_VERT_BLANK_START); + i740Reg->ExtHorizTotal=hwp->readCrtc(hwp, EXT_HORIZ_TOTAL); + i740Reg->ExtHorizBlank=hwp->readCrtc(hwp, EXT_HORIZ_BLANK); + i740Reg->ExtOffset=hwp->readCrtc(hwp, EXT_OFFSET); + i740Reg->InterlaceControl=hwp->readCrtc(hwp, INTERLACE_CNTL); + + i740Reg->PixelPipeCfg0 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); + i740Reg->PixelPipeCfg1 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_1); + i740Reg->PixelPipeCfg2 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_2); + i740Reg->DisplayControl = pI740->readControl(pI740, XRX, DISPLAY_CNTL); + + i740Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC); +} + +static void +I740Save(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + I740Ptr pI740; + + hwp = VGAHWPTR(pScrn); + pI740 = I740PTR(pScrn); + DoSave(pScrn, &hwp->SavedReg, &pI740->SavedReg, TRUE); +} + +static void +DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I740RegPtr i740Reg, + Bool restoreFonts) { + I740Ptr pI740; + vgaHWPtr hwp; + unsigned char temp; + unsigned int itemp; + + pI740 = I740PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + vgaHWProtect(pScrn, TRUE); +#if 0 + temp=hwp->readCrtc(hwp, VERT_SYNC_END); + hwp->writeCrtc(hwp, VERT_SYNC_END, temp&0x7F); +#endif + + temp = pI740->readControl(pI740, MRX, ACQ_CNTL_2); + if ((temp & FRAME_CAP_MODE) == SINGLE_CAP_MODE) { + temp=pI740->readControl(pI740, MRX, COL_KEY_CNTL_1); + temp |= BLANK_DISP_OVERLAY; /* Disable the overlay */ + pI740->writeControl(pI740, MRX, COL_KEY_CNTL_1, temp); + } else { + temp &= ~FRAME_CAP_MODE; + pI740->writeControl(pI740, MRX, ACQ_CNTL_2, temp); + } + usleep(50000); + + /* Turn off DRAM Refresh */ + pI740->writeControl(pI740, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE); + + usleep(1000); /* Wait 1 ms */ + + /* Write the M, N and P values */ + pI740->writeControl(pI740, XRX, VCLK2_VCO_M, i740Reg->VideoClk2_M); + pI740->writeControl(pI740, XRX, VCLK2_VCO_N, i740Reg->VideoClk2_N); + pI740->writeControl(pI740, XRX, VCLK2_VCO_MN_MSBS, i740Reg->VideoClk2_MN_MSBs); + pI740->writeControl(pI740, XRX, VCLK2_VCO_DIV_SEL, i740Reg->VideoClk2_DivisorSel); + + /* + * Turn on 8 bit dac mode, if requested. This is needed to make + * sure that vgaHWRestore writes the values into the DAC properly. + * The problem occurs if 8 bit dac mode is requested and the HW is + * in 6 bit dac mode. If this happens, all the values are + * automatically shifted left twice by the HW and incorrect colors + * will be displayed on the screen. The only time this can happen + * is at server startup time and when switching back from a VT. + */ + temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); + temp &= 0x7F; /* Save all but the 8 bit dac mode bit */ + temp |= (i740Reg->PixelPipeCfg0 & DAC_8_BIT); + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, temp); + + /* + * Code to restore any SVGA registers that have been saved/modified + * goes here. Note that it is allowable, and often correct, to + * only modify certain bits in a register by a read/modify/write cycle. + * + * A special case - when using an external clock-setting program, + * this function must not change bits associated with the clock + * selection. This condition can be checked by the condition: + * + * if (restore->std.NoClock >= 0) + * restore clock-select bits. + */ + if (restoreFonts) + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS|VGA_SR_MODE); + else + vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE); + + hwp->writeCrtc(hwp, EXT_VERT_TOTAL, i740Reg->ExtVertTotal); + hwp->writeCrtc(hwp, EXT_VERT_DISPLAY, i740Reg->ExtVertDispEnd); + hwp->writeCrtc(hwp, EXT_VERT_SYNC_START, i740Reg->ExtVertSyncStart); + hwp->writeCrtc(hwp, EXT_VERT_BLANK_START, i740Reg->ExtVertBlankStart); + hwp->writeCrtc(hwp, EXT_HORIZ_TOTAL, i740Reg->ExtHorizTotal); + hwp->writeCrtc(hwp, EXT_HORIZ_BLANK, i740Reg->ExtHorizBlank); + hwp->writeCrtc(hwp, EXT_OFFSET, i740Reg->ExtOffset); + + temp=hwp->readCrtc(hwp, INTERLACE_CNTL); + temp &= ~INTERLACE_ENABLE; + temp |= i740Reg->InterlaceControl; + hwp->writeCrtc(hwp, INTERLACE_CNTL, temp); + + temp=pI740->readControl(pI740, XRX, ADDRESS_MAPPING); + temp &= 0xE0; /* Save reserved bits 7:5 */ + temp |= i740Reg->AddressMapping; + pI740->writeControl(pI740, XRX, ADDRESS_MAPPING, temp); + + temp=pI740->readControl(pI740, XRX, BITBLT_CNTL); + temp &= ~COLEXP_MODE; + temp |= i740Reg->BitBLTControl; + pI740->writeControl(pI740, XRX, BITBLT_CNTL, temp); + + temp=pI740->readControl(pI740, XRX, DISPLAY_CNTL); + temp &= ~(VGA_WRAP_MODE | GUI_MODE); + temp |= i740Reg->DisplayControl; + pI740->writeControl(pI740, XRX, DISPLAY_CNTL, temp); + + temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); + temp &= 0x64; /* Save reserved bits 6:5,2 */ + temp |= i740Reg->PixelPipeCfg0; + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, temp); + + temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_2); + temp &= 0xF3; /* Save reserved bits 7:4,1:0 */ + temp |= i740Reg->PixelPipeCfg2; + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_2, temp); + + temp=pI740->readControl(pI740, XRX, PLL_CNTL); + temp = i740Reg->PLLControl; /* To fix the 2.3X BIOS problem */ + pI740->writeControl(pI740, XRX, PLL_CNTL, temp); + + temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_1); + temp &= ~DISPLAY_COLOR_MODE; + temp |= i740Reg->PixelPipeCfg1; + pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_1, temp); + + itemp = INREG(FWATER_BLC); + itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK); + itemp |= i740Reg->LMI_FIFO_Watermark; + OUTREG(FWATER_BLC, itemp); + + /* Turn on DRAM Refresh */ + pI740->writeControl(pI740, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ); + + temp=pI740->readControl(pI740, MRX, COL_KEY_CNTL_1); + temp &= ~BLANK_DISP_OVERLAY; /* Re-enable the overlay */ + pI740->writeControl(pI740, MRX, COL_KEY_CNTL_1, temp); + + if (!(vgaReg->Attribute[0x10] & 0x1)) { + usleep(50000); + if (restoreFonts) + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS|VGA_SR_MODE); + else + vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE); + } + + vgaHWProtect(pScrn, FALSE); + temp=pI740->readControl(pI740, XRX, IO_CTNL); + temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL); + temp |= i740Reg->IOControl; + pI740->writeControl(pI740, XRX, IO_CTNL, temp); +#if 0 + temp=hwp->readCrtc(hwp, VERT_SYNC_END); + hwp->writeCrtc(hwp, VERT_SYNC_END, temp|0x80); +#endif +} + +static void +I740Restore(ScrnInfoPtr pScrn) { + vgaHWPtr hwp; + I740Ptr pI740; + + hwp = VGAHWPTR(pScrn); + pI740 = I740PTR(pScrn); + + DoRestore(pScrn, &hwp->SavedReg, &pI740->SavedReg, TRUE); +} + +/* + * I740CalcFIFO -- + * + * Calculate burst length and FIFO watermark. + */ + +static unsigned int +I740CalcFIFO(ScrnInfoPtr pScrn, double freq) +{ + unsigned int wm = 0x18120000; + I740Ptr pI740; + + pI740 = I740PTR(pScrn); + + /* + * Would like to calculate these values automatically, but a generic + * algorithm does not seem possible. Note: These FIFO water mark + * values were tested on several cards and seem to eliminate the + * all of the snow and vertical banding, but fine adjustments will + * probably be required for other cards. + */ + + switch (pScrn->bitsPerPixel) { + case 8: + if (pI740->HasSGRAM) { + if (freq > 200) wm = 0x18120000; + else if (freq > 175) wm = 0x16110000; + else if (freq > 135) wm = 0x120E0000; + else wm = 0x100D0000; + } else { + if (freq > 200) wm = 0x18120000; + else if (freq > 175) wm = 0x16110000; + else if (freq > 135) wm = 0x120E0000; + else wm = 0x100D0000; + } + break; + case 16: + if (pI740->HasSGRAM) { + if (freq > 140) wm = 0x2C1D0000; + else if (freq > 120) wm = 0x2C180000; + else if (freq > 100) wm = 0x24160000; + else if (freq > 90) wm = 0x18120000; + else if (freq > 50) wm = 0x16110000; + else if (freq > 32) wm = 0x13100000; + else wm = 0x120E0000; + } else { + if (freq > 160) wm = 0x28200000; + else if (freq > 140) wm = 0x2A1E0000; + else if (freq > 130) wm = 0x2B1A0000; + else if (freq > 120) wm = 0x2C180000; + else if (freq > 100) wm = 0x24180000; + else if (freq > 90) wm = 0x18120000; + else if (freq > 50) wm = 0x16110000; + else if (freq > 32) wm = 0x13100000; + else wm = 0x120E0000; + } + break; + case 24: + if (pI740->HasSGRAM) { + if (freq > 130) wm = 0x31200000; + else if (freq > 120) wm = 0x2E200000; + else if (freq > 100) wm = 0x2C1D0000; + else if (freq > 80) wm = 0x25180000; + else if (freq > 64) wm = 0x24160000; + else if (freq > 49) wm = 0x18120000; + else if (freq > 32) wm = 0x16110000; + else wm = 0x13100000; + } else { + if (freq > 120) wm = 0x311F0000; + else if (freq > 100) wm = 0x2C1D0000; + else if (freq > 80) wm = 0x25180000; + else if (freq > 64) wm = 0x24160000; + else if (freq > 49) wm = 0x18120000; + else if (freq > 32) wm = 0x16110000; + else wm = 0x13100000; + } + break; + case 32: + if (pI740->HasSGRAM) { + if (freq > 80) wm = 0x2A200000; + else if (freq > 60) wm = 0x281A0000; + else if (freq > 49) wm = 0x25180000; + else if (freq > 32) wm = 0x18120000; + else wm = 0x16110000; + } else { + if (freq > 80) wm = 0x29200000; + else if (freq > 60) wm = 0x281A0000; + else if (freq > 49) wm = 0x25180000; + else if (freq > 32) wm = 0x18120000; + else wm = 0x16110000; + } + break; + } + + return wm; +} + +/* + * I740CalcVCLK -- + * + * Determine the closest clock frequency to the one requested. + */ + +#define MAX_VCO_FREQ 450.0 +#define TARGET_MAX_N 30 +#define REF_FREQ 66.66666666667 + +#define CALC_VCLK(m,n,p,d) \ + (double)m / ((double)n * (1 << p)) * (4 << (d << 1)) * REF_FREQ + +static void +I740CalcVCLK(ScrnInfoPtr pScrn, double freq) +{ + I740Ptr pI740; + I740RegPtr i740Reg; + int m, n, p, d; + double f_out; + double f_err; + double f_vco; + int m_best = 0, n_best = 0, p_best = 0, d_best = 0; + double f_target = freq; + double err_max = 0.005; + double err_target = 0.001; + double err_best = 999999.0; + + pI740 = I740PTR(pScrn); + i740Reg = &pI740->ModeReg; + + p_best = p = log(MAX_VCO_FREQ/f_target)/log((double)2); + d_best = d = 0; + + f_vco = f_target * (1 << p); + + n = 2; + do { + n++; + m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5; + if (m < 3) m = 3; + f_out = CALC_VCLK(m,n,p,d); + f_err = 1.0 - (f_target/f_out); + if (fabs(f_err) < err_max) { + m_best = m; + n_best = n; + err_best = f_err; + } + } while ((fabs(f_err) >= err_target) && + ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max))); + + if (fabs(f_err) < err_target) { + m_best = m; + n_best = n; + } + + i740Reg->VideoClk2_M = (m_best-2) & 0xFF; + i740Reg->VideoClk2_N = (n_best-2) & 0xFF; + i740Reg->VideoClk2_MN_MSBs = ((((n_best-2) >> 4) & VCO_N_MSBS) | + (((m_best-2) >> 8) & VCO_M_MSBS)); + i740Reg->VideoClk2_DivisorSel = ((p_best << 4) | + (d_best ? 4 : 0) | + REF_DIV_1); +} + +static Bool +I740SetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) { + I740Ptr pI740; + I740RegPtr i740Reg; + vgaRegPtr pVga; + double dclk = mode->Clock/1000.0; + + pI740 = I740PTR(pScrn); + i740Reg = &pI740->ModeReg; + pVga = &VGAHWPTR(pScrn)->ModeReg; + + switch (pScrn->bitsPerPixel) { + case 8: + pVga->CRTC[0x13] = pScrn->displayWidth >> 3; + i740Reg->ExtOffset = pScrn->displayWidth >> 11; + i740Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE; + i740Reg->BitBLTControl = COLEXP_8BPP; + break; + case 16: + if (pScrn->weight.green == 5) { + i740Reg->PixelPipeCfg1 = DISPLAY_15BPP_MODE; + } else { + i740Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE; + } + pVga->CRTC[0x13] = pScrn->displayWidth >> 2; + i740Reg->ExtOffset = pScrn->displayWidth >> 10; + i740Reg->BitBLTControl = COLEXP_16BPP; + break; + case 24: + pVga->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3; + i740Reg->ExtOffset = (pScrn->displayWidth * 3) >> 11; + i740Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE; + i740Reg->BitBLTControl = COLEXP_24BPP; + break; + case 32: + pVga->CRTC[0x13] = pScrn->displayWidth >> 1; + i740Reg->ExtOffset = pScrn->displayWidth >> 9; + i740Reg->PixelPipeCfg1 = DISPLAY_32BPP_MODE; + i740Reg->BitBLTControl = COLEXP_RESERVED; /* Not implemented on i740 */ + break; + default: + break; + } + + /* Turn on 8 bit dac if requested */ + if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE)) + i740Reg->PixelPipeCfg0 = DAC_6_BIT; + else + i740Reg->PixelPipeCfg0 = DAC_8_BIT; + + i740Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE /*| OVERLAY_GAMMA_ENABLE*/; + + /* Turn on Extended VGA Interpretation */ + i740Reg->IOControl = EXTENDED_CRTC_CNTL; + + /* Turn on linear and page mapping */ + i740Reg->AddressMapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE; + + /* Turn on GUI mode */ + i740Reg->DisplayControl = HIRES_MODE; + + /* Set the MCLK freq */ + if (xf86ReturnOptValBool(pI740->Options, OPTION_SLOW_RAM, FALSE)) + i740Reg->PLLControl = PLL_MEMCLK__66667KHZ; /* 66 MHz */ + else + i740Reg->PLLControl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */ + + /* Calculate the extended CRTC regs */ + i740Reg->ExtVertTotal = (mode->CrtcVTotal - 2) >> 8; + i740Reg->ExtVertDispEnd = (mode->CrtcVDisplay - 1) >> 8; + i740Reg->ExtVertSyncStart = mode->CrtcVSyncStart >> 8; + i740Reg->ExtVertBlankStart = mode->CrtcVBlankStart >> 8; + i740Reg->ExtHorizTotal = ((mode->CrtcHTotal >> 3) - 5) >> 8; + /* + * the KGA fix in vgaHW.c results in the first + * scanline and the first character clock (8 pixels) + * of each scanline thereafter on display with an i740 + * to be blank. Restoring CRTC 3, 5, & 22 to their + * "theoretical" values corrects the problem. KAO. + */ + i740Reg->ExtHorizBlank = vgaHWHBlankKGA(mode, pVga, 7, 0) << 6; + vgaHWVBlankKGA(mode, pVga, 8, 0); + + /* Turn on interlaced mode if necessary */ + if (mode->Flags & V_INTERLACE) + i740Reg->InterlaceControl = INTERLACE_ENABLE; + else + i740Reg->InterlaceControl = INTERLACE_DISABLE; + + /* + * Set the overscan color to 0. + * NOTE: This only affects >8bpp mode. + */ + pVga->Attribute[0x11] = 0; + + /* + * Calculate the VCLK that most closely matches the requested dot + * clock. + */ + I740CalcVCLK(pScrn, dclk); + + /* Since we program the clocks ourselves, always use VCLK2. */ + pVga->MiscOutReg |= 0x0C; + + /* Calculate the FIFO Watermark and Burst Length. */ + i740Reg->LMI_FIFO_Watermark = I740CalcFIFO(pScrn, dclk); + + /*-Overlay-*/ + pI740->ov_offset_x=((mode->CrtcHTotal-mode->CrtcHDisplay) & ~7)-9; + pI740->ov_offset_y=mode->CrtcVTotal-mode->CrtcVSyncEnd-2; + /*-*/ + + return TRUE; +} + +static Bool +I740ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode_src) +{ + vgaHWPtr hwp; + I740Ptr pI740; + struct _DisplayModeRec mode_dst; + DisplayModePtr mode=&mode_dst; + + *mode=*mode_src; + + hwp = VGAHWPTR(pScrn); + pI740 = I740PTR(pScrn); + + vgaHWUnlock(hwp); + + + if(pI740->usevgacompat) + { /* Try to get the same visual aspect as a S3 board */ + mode->CrtcHSyncStart+=16; + mode->CrtcHSyncEnd +=16; + } + + if (!vgaHWInit(pScrn, mode)) return FALSE; + + pScrn->vtSema = TRUE; + + if (!I740SetMode(pScrn, mode)) return FALSE; + + DoRestore(pScrn, &hwp->ModeReg, &pI740->ModeReg, FALSE); + + return TRUE; +} + +static void I740LoadPalette15(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) +{ + I740Ptr pI740; + vgaHWPtr hwp; + int i, index; + unsigned char r, g, b; + + pI740 = I740PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + for (i=0; i<numColors; i++) + { + index=indices[i/2]; + r=colors[index].red; + b=colors[index].blue; + g=colors[index].green; + + hwp->writeDacWriteAddr(hwp, index<<2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + + i++; + hwp->writeDacWriteAddr(hwp, index<<2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + } +} + +static void I740LoadPalette16(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) +{ + I740Ptr pI740; + vgaHWPtr hwp; + int i, index; + unsigned char r, g, b; + + pI740 = I740PTR(pScrn); + hwp = VGAHWPTR(pScrn); + for (i=0; i<numColors; i++) { + index=indices[i/2]; + r=colors[index].red; + b=colors[index].blue; + index=indices[i]; + g=colors[index].green; + hwp->writeDacWriteAddr(hwp, index<<2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + i++; + index=indices[i]; + g=colors[index].green; + hwp->writeDacWriteAddr(hwp, index<<2); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + } +} + +static void +I740LoadPalette24(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, + VisualPtr pVisual) { + I740Ptr pI740; + vgaHWPtr hwp; + int i, index; + unsigned char r, g, b; + + pI740 = I740PTR(pScrn); + hwp = VGAHWPTR(pScrn); + for (i=0; i<numColors; i++) { + index=indices[i]; + r=colors[index].red; + b=colors[index].blue; + index=indices[i]; + g=colors[index].green; + hwp->writeDacWriteAddr(hwp, index); + hwp->writeDacData(hwp, r); + hwp->writeDacData(hwp, g); + hwp->writeDacData(hwp, b); + } +} + +static Bool +I740ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + I740Ptr pI740; + VisualPtr visual; + + pScrn = xf86Screens[pScreen->myNum]; + pI740 = I740PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + if (!I740MapMem(pScrn)) return FALSE; + pScrn->memPhysBase = pI740->LinearAddr; + pScrn->fbOffset = 0; + + if (!pI740->usePIO) + vgaHWSetMmioFuncs(hwp, pI740->MMIOBase, 0); + vgaHWGetIOBase(hwp); + if (!vgaHWMapMem(pScrn)) return FALSE; + + I740Save(pScrn); + if (!I740ModeInit(pScrn, pScrn->currentMode)) return FALSE; + + I740SaveScreen(pScreen, SCREEN_SAVER_ON); + I740AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + miClearVisualTypes(); + + if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; +#ifdef USE_FB + if (!miSetPixmapDepths ()) return FALSE; +#endif + + switch (pScrn->bitsPerPixel) { +#ifdef USE_FB + case 8: + case 16: + case 24: + case 32: + if (!fbScreenInit(pScreen, pI740->FbBase, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth,pScrn->bitsPerPixel)) + return FALSE; + break; +#else + case 8: + if (!cfbScreenInit(pScreen, pI740->FbBase, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth)) + return FALSE; + break; + case 16: + if (!cfb16ScreenInit(pScreen, pI740->FbBase, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth)) + return FALSE; + break; + case 24: + if (!cfb24ScreenInit(pScreen, pI740->FbBase, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth)) + return FALSE; + break; + case 32: + if (!cfb32ScreenInit(pScreen, pI740->FbBase, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth)) + return FALSE; + break; +#endif + default: + xf86DrvMsg(scrnIndex, X_ERROR, + "Internal error: invalid bpp (%d) in I740ScrnInit\n", + pScrn->bitsPerPixel); + return FALSE; + } +#ifdef USE_FB + fbPictureInit(pScreen,0,0); +#endif + + xf86SetBlackWhitePixels(pScreen); + + if (pScrn->bitsPerPixel>8) { + 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; + } + } + } + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (!miCreateDefColormap(pScreen)) return FALSE; + + if (pScrn->bitsPerPixel==16) + { + if (pScrn->weight.green == 5) + { + if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette15, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } + else + { + if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette16, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } + } + else + { + if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette24, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } + + xf86DPMSInit(pScreen, I740DisplayPowerManagementSet, 0); + +#if 0 /*def XvExtension*/ + { + XF86VideoAdaptorPtr *ptr; + int n; + + n = xf86XVListGenericAdaptors(pScrn,&ptr); + if (n) { + xf86XVScreenInit(pScreen, ptr, n); + } + } +#endif + + memset(&(pI740->FbMemBox), 0, sizeof(BoxRec)); + pI740->FbMemBox.x1=0; + pI740->FbMemBox.x2=pScrn->displayWidth; + pI740->FbMemBox.y1=0; + pI740->FbMemBox.y2=pI740->FbMapSize/(pScrn->displayWidth*pI740->cpp); + + I740DGAInit(pScreen); + + if (!xf86InitFBManager(pScreen, &pI740->FbMemBox)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to init memory manager\n"); + return FALSE; + } + + if (!xf86ReturnOptValBool(pI740->Options, OPTION_NOACCEL, FALSE)) { + if (!I740AccelInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware acceleration initialization failed\n"); + } + } + + if (!xf86ReturnOptValBool(pI740->Options, OPTION_SW_CURSOR, FALSE)) { + if (!I740CursorInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + } + } + + pScreen->SaveScreen = I740SaveScreen; + pI740->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = I740CloseScreen; + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + +#ifdef XvExtension + { /* Overlay */ + I740InitVideo(pScreen); pI740->OverlayStart = pI740->CursorStart + 1024; + } +#endif /*XvExtension*/ + + return TRUE; +} + +Bool +I740SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { + ScrnInfoPtr pScrn; + + pScrn=xf86Screens[scrnIndex]; + return I740ModeInit(pScrn, mode); +} + +void +I740AdjustFrame(int scrnIndex, int x, int y, int flags) { + ScrnInfoPtr pScrn; + I740Ptr pI740; + int Base; + vgaHWPtr hwp; + + pScrn = xf86Screens[scrnIndex]; + pI740 = I740PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + Base = (y * pScrn->displayWidth + x) >> 2; + switch (pScrn->bitsPerPixel) { + case 8: + break; + case 16: + Base *= 2; + break; + case 24: + /* + * The last bit does not seem to have any effect on the start + * address register in 24bpp mode, so... + */ + Base &= 0xFFFFFFFE; /* ...ignore the last bit. */ + Base *= 3; + break; + case 32: + Base *= 4; + break; + } + + hwp->writeCrtc(hwp, START_ADDR_LO, Base&0xFF); + hwp->writeCrtc(hwp, START_ADDR_HI, (Base&0xFF00)>>8); + hwp->writeCrtc(hwp, EXT_START_ADDR_HI, (Base&0x3FC00000)>>22); + hwp->writeCrtc(hwp, EXT_START_ADDR, + ((Base&0x00eF0000)>>16|EXT_START_ADDR_ENABLE)); +} + +static Bool +I740EnterVT(int scrnIndex, int flags) { + ScrnInfoPtr pScrn; + + pScrn = xf86Screens[scrnIndex]; + if (!I740ModeInit(pScrn, pScrn->currentMode)) return FALSE; + I740AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + return TRUE; +} + +static void +I740LeaveVT(int scrnIndex, int flags) { + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + + pScrn = xf86Screens[scrnIndex]; + hwp=VGAHWPTR(pScrn); + I740Restore(pScrn); + vgaHWLock(hwp); +} + +static Bool +I740CloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + I740Ptr pI740; + + pScrn = xf86Screens[scrnIndex]; + hwp = VGAHWPTR(pScrn); + pI740 = I740PTR(pScrn); + + if (pScrn->vtSema) { + I740Restore(pScrn); + vgaHWLock(hwp); + } + + I740UnmapMem(pScrn); + vgaHWUnmapMem(pScrn); + if (pI740->AccelInfoRec) + XAADestroyInfoRec(pI740->AccelInfoRec); + pI740->AccelInfoRec=0; + if (pI740->CursorInfoRec) + xf86DestroyCursorInfoRec(pI740->CursorInfoRec); + pI740->CursorInfoRec=0; + pScrn->vtSema=FALSE; + + pScreen->CloseScreen = pI740->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + +static void +I740FreeScreen(int scrnIndex, int flags) { + I740FreeRec(xf86Screens[scrnIndex]); + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); +} + +static int +I740ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) { + if (mode->Flags & V_INTERLACE) { + if (verbose) { + xf86DrvMsg(scrnIndex, X_PROBED, + "Removing interlaced mode \"%s\"\n", + mode->name); + } + return MODE_BAD; + } + return MODE_OK; +} + +static Bool +I740SaveScreen(ScreenPtr pScreen, int mode) +{ +#if 0 + Bool unblack = xf86IsUnblank(mode); + if (unblack) outw(SRX, 0x0300); + else outw(SRX, 0x0100); +#endif + return vgaHWSaveScreen(pScreen, mode); +} + +static void +I740DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) { + I740Ptr pI740; + unsigned char SEQ01=0; + int DPMSSyncSelect=0; + + pI740 = I740PTR(pScrn); + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + SEQ01 = 0x00; + DPMSSyncSelect = HSYNC_ON | VSYNC_ON; + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_ON; + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_ON | VSYNC_OFF; + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + SEQ01 = 0x20; + DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF; + break; + } + + /* Turn the screen on/off */ + SEQ01 |= pI740->readControl(pI740, SRX, 0x01) & ~0x20; + pI740->writeControl(pI740, SRX, 0x01, SEQ01); + + /* Set the DPMS mode */ + pI740->writeControl(pI740, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect); +} diff --git a/src/i740_i2c.c b/src/i740_i2c.c new file mode 100644 index 0000000..174a578 --- /dev/null +++ b/src/i740_i2c.c @@ -0,0 +1,105 @@ +/* + * Copyright 2001 by Patrick LERDA + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Patrick LERDA not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Patrick LERDA makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * PATRICK LERDA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL PATRICK LERDA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Patrick LERDA + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_i2c.c,v 1.1 2002/10/21 13:32:58 alanh Exp $ */ + +/* not working at this time */ + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86_ansic.h" +#include "compiler.h" + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "vgaHW.h" + +#include "xf86xv.h" +#include "i740.h" + + +static void i740_I2CPutBits(I2CBusPtr b, int clk, int dat) +{ + I740Ptr pI740=I740PTR(xf86Screens[b->scrnIndex]); + unsigned char val; + + val=pI740->readControl(pI740, XRX, 0x1C); + + if(clk) val&=~0x40; else val|=0x40; if(dat) val&=~0x08; else val|=0x08; + + /*if ( clk && dat) val&=0xBF; else if( clk && !dat) val&=0xF7; else if(!clk && dat) val|=0x40; else val|=0x08;*/ + + val|=0x90; + + pI740->writeControl(pI740, XRX, 0x1C, val); + + ErrorF("i740_I2CPutBits: clk=%d dat=%d [<1c>=0x%02x] [<63>=0x%02x] clk=%d dat=%d\n", clk, dat,val,pI740->readControl(pI740, XRX, 0x63), + !!(pI740->readControl(pI740, XRX, 0x63) & 0x02), !!(pI740->readControl(pI740, XRX, 0x63) & 0x01) ); +} + +static void i740_I2CGetBits(I2CBusPtr b, int *clk, int *dat) +{ + I740Ptr pI740=I740PTR(xf86Screens[b->scrnIndex]); + unsigned char val; + + { + val=pI740->readControl(pI740, XRX, 0x1C); + val|=0x90; + pI740->writeControl(pI740, XRX, 0x1C, val); + } + + { + val=pI740->readControl(pI740, XRX, 0x63); + *clk=!!(val & 0x02); + *dat=!!(val & 0x01); + } + + ErrorF("i740_I2CGetBits: clk=%d dat=%d [<1c>=0x%02x] [<63>=0x%02x]\n", *clk, *dat,pI740->readControl(pI740, XRX, 0x1c) & 0xff,pI740->readControl(pI740, XRX, 0x63)); +} + +Bool I740_I2CInit(ScrnInfoPtr pScrn) +{ + I740Ptr pI740=I740PTR(pScrn); + I2CBusPtr I2CPtr; + + { unsigned char val; val=pI740->readControl(pI740, XRX, 0x63); val&=0xFC; pI740->writeControl(pI740, XRX, 0x63, val); } + { unsigned char val; val=pI740->readControl(pI740, XRX, 0x1C); val|=0x90; pI740->writeControl(pI740, XRX, 0x1C, val); } + { unsigned char val; val=pI740->readControl(pI740, XRX, 0x63); val&=0xFC; pI740->writeControl(pI740, XRX, 0x63, val); } + + + I2CPtr = xf86CreateI2CBusRec(); + if(!I2CPtr) return FALSE; + + pI740->rc_i2c = I2CPtr; + + I2CPtr->BusName = "I2C bus"; + I2CPtr->scrnIndex = pScrn->scrnIndex; + I2CPtr->I2CPutBits = i740_I2CPutBits; + I2CPtr->I2CGetBits = i740_I2CGetBits; + + if (!xf86I2CBusInit(I2CPtr)) + return FALSE; + + return TRUE; +} diff --git a/src/i740_io.c b/src/i740_io.c new file mode 100644 index 0000000..0195862 --- /dev/null +++ b/src/i740_io.c @@ -0,0 +1,93 @@ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_io.c,v 1.5 2002/10/21 13:32:58 alanh Exp $ */ + +/* + * Authors: + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "vgaHW.h" + +#include "xf86xv.h" +#include "i740.h" + +static void I740WriteControlPIO(I740Ptr pI740, int addr, unsigned char index, char val) { + outb(addr, index); + outb(addr+1, val); +} + +static char I740ReadControlPIO(I740Ptr pI740, int addr, unsigned char index) { + outb(addr, index); + return inb(addr+1); +} + +static void I740WriteStandardPIO(I740Ptr pI740, int addr, unsigned char val) { + outb(addr, val); +} + +static char I740ReadStandardPIO(I740Ptr pI740, int addr) { + return inb(addr); +} + +void I740SetPIOAccess(I740Ptr pI740) { + pI740->writeControl=I740WriteControlPIO; + pI740->readControl=I740ReadControlPIO; + pI740->writeStandard=I740WriteStandardPIO; + pI740->readStandard=I740ReadStandardPIO; +} + +static void I740WriteControlMMIO(I740Ptr pI740, int addr, unsigned char index, char val) { + moutb(addr, index); + moutb(addr+1, val); +} + +static char I740ReadControlMMIO(I740Ptr pI740, int addr, unsigned char index) { + moutb(addr, index); + return minb(addr+1); +} + +static void I740WriteStandardMMIO(I740Ptr pI740, int addr, unsigned char val) { + moutb(addr, val); +} + +static char I740ReadStandardMMIO(I740Ptr pI740, int addr) { + return minb(addr); +} + +void I740SetMMIOAccess(I740Ptr pI740) { + pI740->writeControl=I740WriteControlMMIO; + pI740->readControl=I740ReadControlMMIO; + pI740->writeStandard=I740WriteStandardMMIO; + pI740->readStandard=I740ReadStandardMMIO; +} + diff --git a/src/i740_macros.h b/src/i740_macros.h new file mode 100644 index 0000000..797b89f --- /dev/null +++ b/src/i740_macros.h @@ -0,0 +1,61 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_macros.h,v 1.4 2002/10/21 13:32:58 alanh Exp $ */ + +/* + * Authors: + * Kevin E. Martin <kevin@precisioninsight.com> + * + */ + +#include "xf86fbman.h" + + +#define WAIT_ENGINE_IDLE_PIO() { \ + outb(XRX, BITBLT_CNTL); \ + while (inb(XRX+1) & BITBLT_STATUS) \ + outb(XRX, BITBLT_CNTL); \ + } + +#define WAIT_ENGINE_IDLE_MMIO() { \ + moutb(XRX, BITBLT_CNTL); \ + while (minb(XRX+1) & BITBLT_STATUS) \ + moutb(XRX, BITBLT_CNTL); \ + } + +#define WAIT_BLT_IDLE() { \ + while (INREG(BITBLT_CONTROL) & BLTR_STATUS); \ + } + +#define WAIT_LP_FIFO(n) { \ + while (INREG8(LP_FIFO_COUNT) > 15-(n)); \ + } + +#define WAIT_HP_FIFO(n) { \ + while (INREG8(HP_FIFO_COUNT) > 15-(n)); \ + } diff --git a/src/i740_reg.h b/src/i740_reg.h new file mode 100644 index 0000000..0366d7e --- /dev/null +++ b/src/i740_reg.h @@ -0,0 +1,327 @@ + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_reg.h,v 1.2 2000/02/23 04:47:14 martin Exp $ */ + +/* + * Authors: + * Kevin E. Martin <kevin@precisioninsight.com> + * + */ + +/* I/O register offsets */ +#define SRX 0x3C4 +#define GRX 0x3CE +#define ARX 0x3C0 +#define XRX 0x3D6 +#define MRX 0x3D2 + +/* VGA Color Palette Registers */ +#define DACMASK 0x3C6 +#define DACSTATE 0x3C7 +#define DACRX 0x3C7 +#define DACWX 0x3C8 +#define DACDATA 0x3C9 + +/* CRT Controller Registers (CRX) */ +#define START_ADDR_HI 0x0C +#define START_ADDR_LO 0x0D +#define VERT_SYNC_END 0x11 +#define EXT_VERT_TOTAL 0x30 +#define EXT_VERT_DISPLAY 0x31 +#define EXT_VERT_SYNC_START 0x32 +#define EXT_VERT_BLANK_START 0x33 +#define EXT_HORIZ_TOTAL 0x35 +#define EXT_HORIZ_BLANK 0x39 +#define EXT_START_ADDR 0x40 +#define EXT_START_ADDR_ENABLE 0x80 +#define EXT_OFFSET 0x41 +#define EXT_START_ADDR_HI 0x42 +#define INTERLACE_CNTL 0x70 +#define INTERLACE_ENABLE 0x80 +#define INTERLACE_DISABLE 0x00 + +/* Miscellaneous Output Register */ +#define MSR_R 0x3CC +#define MSR_W 0x3C2 +#define IO_ADDR_SELECT 0x01 + +#define MDA_BASE 0x3B0 +#define CGA_BASE 0x3D0 + +/* System Configuration Extension Registers (XRX) */ +#define IO_CTNL 0x09 +#define EXTENDED_ATTR_CNTL 0x02 +#define EXTENDED_CRTC_CNTL 0x01 + +#define ADDRESS_MAPPING 0x0A +#define PACKED_MODE_ENABLE 0x04 +#define LINEAR_MODE_ENABLE 0x02 +#define PAGE_MAPPING_ENABLE 0x01 + +#define BITBLT_CNTL 0x20 +#define COLEXP_MODE 0x30 +#define COLEXP_8BPP 0x00 +#define COLEXP_16BPP 0x10 +#define COLEXP_24BPP 0x20 +#define COLEXP_RESERVED 0x30 +#define CHIP_RESET 0x02 +#define BITBLT_STATUS 0x01 + +#define DISPLAY_CNTL 0x40 +#define VGA_WRAP_MODE 0x02 +#define VGA_WRAP_AT_256KB 0x00 +#define VGA_NO_WRAP 0x02 +#define GUI_MODE 0x01 +#define STANDARD_VGA_MODE 0x00 +#define HIRES_MODE 0x01 + +#define DRAM_ROW_TYPE 0x50 +#define DRAM_ROW_0 0x07 +#define DRAM_ROW_0_SDRAM 0x00 +#define DRAM_ROW_0_EMPTY 0x07 +#define DRAM_ROW_1 0x38 +#define DRAM_ROW_1_SDRAM 0x00 +#define DRAM_ROW_1_EMPTY 0x38 +#define DRAM_ROW_CNTL_LO 0x51 +#define DRAM_CAS_LATENCY 0x10 +#define DRAM_RAS_TIMING 0x08 +#define DRAM_RAS_PRECHARGE 0x04 +#define DRAM_ROW_CNTL_HI 0x52 +#define DRAM_EXT_CNTL 0x53 +#define DRAM_REFRESH_RATE 0x03 +#define DRAM_REFRESH_DISABLE 0x00 +#define DRAM_REFRESH_60HZ 0x01 +#define DRAM_REFRESH_FAST_TEST 0x02 +#define DRAM_REFRESH_RESERVED 0x03 +#define DRAM_TIMING 0x54 +#define DRAM_ROW_BNDRY_0 0x55 +#define DRAM_ROW_BNDRY_1 0x56 + +#define DPMS_SYNC_SELECT 0x61 +#define VSYNC_CNTL 0x08 +#define VSYNC_ON 0x00 +#define VSYNC_OFF 0x08 +#define HSYNC_CNTL 0x02 +#define HSYNC_ON 0x00 +#define HSYNC_OFF 0x02 + +#define PIXPIPE_CONFIG_0 0x80 +#define DAC_8_BIT 0x80 +#define DAC_6_BIT 0x00 +#define HW_CURSOR_ENABLE 0x10 +#define EXTENDED_PALETTE 0x01 + +#define PIXPIPE_CONFIG_1 0x81 +#define DISPLAY_COLOR_MODE 0x0F +#define DISPLAY_VGA_MODE 0x00 +#define DISPLAY_8BPP_MODE 0x02 +#define DISPLAY_15BPP_MODE 0x04 +#define DISPLAY_16BPP_MODE 0x05 +#define DISPLAY_24BPP_MODE 0x06 +#define DISPLAY_32BPP_MODE 0x07 + +#define PIXPIPE_CONFIG_2 0x82 +#define DISPLAY_GAMMA_ENABLE 0x08 +#define DISPLAY_GAMMA_DISABLE 0x00 +#define OVERLAY_GAMMA_ENABLE 0x04 +#define OVERLAY_GAMMA_DISABLE 0x00 + +#define CURSOR_CONTROL 0xA0 +#define CURSOR_ORIGIN_SCREEN 0x00 +#define CURSOR_ORIGIN_DISPLAY 0x10 +#define CURSOR_MODE 0x07 +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_32_4C_AX 0x01 +#define CURSOR_MODE_128_2C 0x02 +#define CURSOR_MODE_128_1C 0x03 +#define CURSOR_MODE_64_3C 0x04 +#define CURSOR_MODE_64_4C_AX 0x05 +#define CURSOR_MODE_64_4C 0x06 +#define CURSOR_MODE_RESERVED 0x07 +#define CURSOR_BASEADDR_LO 0xA2 +#define CURSOR_BASEADDR_HI 0xA3 +#define CURSOR_X_LO 0xA4 +#define CURSOR_X_HI 0xA5 +#define CURSOR_X_POS 0x00 +#define CURSOR_X_NEG 0x80 +#define CURSOR_Y_LO 0xA6 +#define CURSOR_Y_HI 0xA7 +#define CURSOR_Y_POS 0x00 +#define CURSOR_Y_NEG 0x80 + +#define VCLK2_VCO_M 0xC8 +#define VCLK2_VCO_N 0xC9 +#define VCLK2_VCO_MN_MSBS 0xCA +#define VCO_N_MSBS 0x30 +#define VCO_M_MSBS 0x03 +#define VCLK2_VCO_DIV_SEL 0xCB +#define POST_DIV_SELECT 0x70 +#define POST_DIV_1 0x00 +#define POST_DIV_2 0x10 +#define POST_DIV_4 0x20 +#define POST_DIV_8 0x30 +#define POST_DIV_16 0x40 +#define POST_DIV_32 0x50 +#define VCO_LOOP_DIV_BY_4M 0x00 +#define VCO_LOOP_DIV_BY_16M 0x04 +#define REF_CLK_DIV_BY_5 0x02 +#define REF_DIV_4 0x00 +#define REF_DIV_1 0x01 + +#define PLL_CNTL 0xCE +#define PLL_MEMCLK_SEL 0x03 +#define PLL_MEMCLK__66667KHZ 0x00 +#define PLL_MEMCLK__75000KHZ 0x01 +#define PLL_MEMCLK__88889KHZ 0x02 +#define PLL_MEMCLK_100000KHZ 0x03 + +/* Multimedia Extension Registers (MRX) */ +#define ACQ_CNTL_1 0x02 +#define ACQ_CNTL_2 0x03 +#define FRAME_CAP_MODE 0x01 +#define CONT_CAP_MODE 0x00 +#define SINGLE_CAP_MODE 0x01 +#define ACQ_CNTL_3 0x04 +#define COL_KEY_CNTL_1 0x3C +#define BLANK_DISP_OVERLAY 0x20 + +/* FIFOs */ +#define LP_FIFO 0x1000 +#define HP_FIFO 0x2000 +#define INSTPNT 0x3040 +#define LP_FIFO_COUNT 0x3040 +#define HP_FIFO_COUNT 0x3041 + +/* FIFO Commands */ +#define CLIENT 0xE0000000 +#define CLIENT_2D 0x60000000 + +/* Command Parser Mode Register */ +#define COMPARS 0x3038 +#define TWO_D_INST_DISABLE 0x08 +#define THREE_D_INST_DISABLE 0x04 +#define STATE_VAR_UPDATE_DISABLE 0x02 +#define PAL_STIP_DISABLE 0x01 + +/* Interrupt Control Registers */ +#define IER 0x3030 +#define IIR 0x3032 +#define IMR 0x3034 +#define ISR 0x3036 +#define VMIINTB_EVENT 0x2000 +#define GPIO4_INT 0x1000 +#define DISP_FLIP_EVENT 0x0800 +#define DVD_PORT_DMA 0x0400 +#define DISP_VBLANK 0x0200 +#define FIFO_EMPTY_DMA_DONE 0x0100 +#define INST_PARSER_ERROR 0x0080 +#define USER_DEFINED 0x0040 +#define BREAKPOINT 0x0020 +#define DISP_HORIZ_COUNT 0x0010 +#define DISP_VSYNC 0x0008 +#define CAPTURE_HORIZ_COUNT 0x0004 +#define CAPTURE_VSYNC 0x0002 +#define THREE_D_PIPE_FLUSHED 0x0001 + +/* FIFO Watermark and Burst Length Control Register */ +#define FWATER_BLC 0x00006000 +#define LMI_BURST_LENGTH 0x7F000000 +#define LMI_FIFO_WATERMARK 0x003F0000 +#define AGP_BURST_LENGTH 0x00007F00 +#define AGP_FIFO_WATERMARK 0x0000003F + +/* BitBLT Registers */ +#define SRC_DST_PITCH 0x00040000 +#define DST_PITCH 0x1FFF0000 +#define SRC_PITCH 0x00001FFF +#define COLEXP_BG_COLOR 0x00040004 +#define COLEXP_FG_COLOR 0x00040008 +#define MONO_SRC_CNTL 0x0004000C +#define MONO_USE_COLEXP 0x00000000 +#define MONO_USE_SRCEXP 0x08000000 +#define MONO_DATA_ALIGN 0x07000000 +#define MONO_BIT_ALIGN 0x01000000 +#define MONO_BYTE_ALIGN 0x02000000 +#define MONO_WORD_ALIGN 0x03000000 +#define MONO_DWORD_ALIGN 0x04000000 +#define MONO_QWORD_ALIGN 0x05000000 +#define MONO_SRC_INIT_DSCRD 0x003F0000 +#define MONO_SRC_RIGHT_CLIP 0x00003F00 +#define MONO_SRC_LEFT_CLIP 0x0000003F +#define BITBLT_CONTROL 0x00040010 +#define BLTR_STATUS 0x80000000 +#define DYN_DEPTH 0x03000000 +#define DYN_DEPTH_8BPP 0x00000000 +#define DYN_DEPTH_16BPP 0x01000000 +#define DYN_DEPTH_24BPP 0x02000000 +#define DYN_DEPTH_32BPP 0x03000000 /* Not implemented on the i740 */ +#define DYN_DEPTH_ENABLE 0x00800000 +#define PAT_VERT_ALIGN 0x00700000 +#define SOLID_PAT_SELECT 0x00080000 +#define PAT_IS_IN_COLOR 0x00000000 +#define PAT_IS_MONO 0x00040000 +#define MONO_PAT_TRANSP 0x00020000 +#define COLOR_TRANSP_ROP 0x00000000 +#define COLOR_TRANSP_DST 0x00008000 +#define COLOR_TRANSP_EQ 0x00000000 +#define COLOR_TRANSP_NOT_EQ 0x00010000 +#define COLOR_TRANSP_ENABLE 0x00004000 +#define MONO_SRC_TRANSP 0x00002000 +#define SRC_IS_IN_COLOR 0x00000000 +#define SRC_IS_MONO 0x00001000 +#define SRC_USE_SRC_ADDR 0x00000000 +#define SRC_USE_BLTDATA 0x00000400 +#define BLT_TOP_TO_BOT 0x00000000 +#define BLT_BOT_TO_TOP 0x00000200 +#define BLT_LEFT_TO_RIGHT 0x00000000 +#define BLT_RIGHT_TO_LEFT 0x00000100 +#define BLT_ROP 0x000000FF +#define BLT_PAT_ADDR 0x00040014 +#define BLT_SRC_ADDR 0x00040018 +#define BLT_DST_ADDR 0x0004001C +#define BLT_DST_H_W 0x00040020 +#define BLT_DST_HEIGHT 0x1FFF0000 +#define BLT_DST_WIDTH 0x00001FFF +#define SRCEXP_BG_COLOR 0x00040024 +#define SRCEXP_FG_COLOR 0x00040028 +#define BLTDATA 0x00050000 + +typedef struct { + unsigned int cmd; + unsigned int BR00; + unsigned int BR01; + unsigned int BR02; + unsigned int BR03; + unsigned int BR04; + unsigned int BR05; + unsigned int BR06; + unsigned int BR07; + unsigned int BR09; + unsigned int BR0A; + unsigned int BR08; +} GFX2DOPREG_BLTER_FULL_LOAD; diff --git a/src/i740_video.c b/src/i740_video.c new file mode 100644 index 0000000..7ce7dfb --- /dev/null +++ b/src/i740_video.c @@ -0,0 +1,1323 @@ +/* + * Copyright 2001 by Patrick LERDA + * Portions Copyright by Stephen Blackheath + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Patrick LERDA not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Patrick LERDA makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * PATRICK LERDA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL PATRICK LERDA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Patrick LERDA + * with modifications by Stephen Blackheath (Aug 2002) + * + * REVISION HISTORY: + * December 2001 - Patrick LERDA's original (http://sourceforge.net/projects/i740fb). + * 27 August 2002 - Patrick's version would run for an hour or two on my machine, + * then the screen would go blank (no signal to monitor) and for some reason I + * sometimes couldn't even log in through the network. I had to re-boot my machine. + * This version fixes that and makes a few other unnecessary tweaks. I am not + * certain, but I think the problem is that Patrick's code was reading a value from + * XRX register 0xD0, and or'ing with 0x10. When I removed this from the main + * loop, it became reliable. I suspect the hardware (whether just my cheap + * clone board only I'm not sure) was sometimes returning bogus values, which were + * then programmed back in - but I never checked this. This register is related to + * powering on or off certain subsystems of the i740 chip, so that might explain + * the blank screen. - Stephen Blackheath + * 3 September 2002 - Added software scaling in the situation where the screen size is + * smaller than the original video size, since scaling down is not supported by + * the hardware. The implementation of this is not quite complete. + * 12 September 2002 - Better software scaling with some averaging, giving a nicer + * picture. + * 13 January 2003 - Fixed a minor bug where the video would occasionally stop updating, + * which was worked around just by re-sizing the window. + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i740/i740_video.c,v 1.3 2003/01/17 22:22:52 tsi Exp $ */ + +/* + * i740_video.c: i740 Xv driver. Based on the mga Xv driver by Mark Vojkovich. + */ + +#ifdef XvExtension +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86_ansic.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86fbman.h" +#include "regionstr.h" + +#include "xf86xv.h" +#include "Xv.h" +#include "xaa.h" +#include "xaalocal.h" +#include "dixstruct.h" +#include "fourcc.h" + +#include "vgaHW.h" +#include "i740.h" + + +#define FOURCC_RV15 0x35315652 +#define FOURCC_RV16 0x36315652 + +/*-*/ +#define i740_wc(fb,z,r,v) (pI740->writeControl(pI740,(z),(r),(v))) +#define i740_rc(fb,z,r) (pI740->readControl(pI740,(z),(r))) +/*-*/ + +#define OFF_DELAY 250 /* milliseconds */ +#define FREE_DELAY 15000 + +#define OFF_TIMER 0x01 +#define FREE_TIMER 0x02 +#define CLIENT_VIDEO_ON 0x04 + +#define TIMER_MASK (OFF_TIMER | FREE_TIMER) + + + + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvContrast, xvColorKey; + + + +#define IMAGE_MAX_PHY_WIDTH 1024 /*720*/ +#define IMAGE_MAX_PHY_HEIGHT 1024 /*576*/ + + +#define IMAGE_MAX_LOG_WIDTH 1024 /*720*/ +#define IMAGE_MAX_LOG_HEIGHT 1024 /*576*/ + + +typedef struct { + CARD32 YBuf0offset; + CARD32 YBuf1offset; + + unsigned char currentBuf; + + int brightness; + int contrast; + + RegionRec clip; + CARD32 colorKey; + + CARD32 videoStatus; + Time offTime; + Time freeTime; + FBLinearPtr linear; + +} I740PortPrivRec, *I740PortPrivPtr; + +typedef struct { + CARD32 OBUF_0Y; + CARD32 OBUF_1Y; + CARD32 OBUF_0U; + CARD32 OBUF_0V; + CARD32 OBUF_1U; + CARD32 OBUF_1V; + CARD32 OV0STRIDE; + CARD32 YRGB_VPH; + CARD32 UV_VPH; + CARD32 HORZ_PH; + CARD32 INIT_PH; + CARD32 DWINPOS; + CARD32 DWINSZ; + CARD32 SWID; + CARD32 SWIDQW; + CARD32 SHEIGHT; + CARD32 YRGBSCALE; + CARD32 UVSCALE; + CARD32 OV0CLRC0; + CARD32 OV0CLRC1; + CARD32 DCLRKV; + CARD32 DCLRKM; + CARD32 SCLRKVH; + CARD32 SCLRKVL; + CARD32 SCLRKM; + CARD32 OV0CONF; + CARD32 OV0CMD; +} I740OverlayRegRec, *I740OverlayRegPtr; + +#define GET_PORT_PRIVATE(pScrn) \ + (I740PortPrivPtr)((I740PTR(pScrn))->adaptor->pPortPrivates[0].ptr) + + +/*-----------------------------------------------------------------------------------------*/ +__inline__ static void i740fb_overlay_off(ScrnInfoPtr pScrn) +{ + I740Ptr pI740 = I740PTR(pScrn); + + /* 0x3C = COL_KEY_CNTL_1 */ + i740_wc(fb_p, MRX, 0x3C, (i740_rc(fb_p, MRX, 0x3C) | 0x02)); + usleep(50000); + /*i740_wc(fb_p, XRX, 0xD0, (i740_rc(fb_p, XRX, 0xD0) & ~0x10)); + usleep(50000);*/ + i740_wc(fb_p, XRX, 0xD0, 0x2F); +} + +__inline__ static void i740fb_overlay_set(ScrnInfoPtr pScrn, I740PortPrivPtr pPriv, unsigned long mem1,unsigned long mem2, + unsigned long isrc_w,unsigned long isrc_h, /* source image size */ + unsigned long idst_w,unsigned long idst_h, /* destination image size */ + unsigned long ddst_x,unsigned long ddst_y, /* destination image pos to display */ + unsigned long ddst_w,unsigned long ddst_h, /* destination image size to display allows trunc... */ + unsigned long pitch,int flip, + unsigned char vd_mod) +{ + I740Ptr pI740 = I740PTR(pScrn); + const int f_dbl=pScrn->currentMode->Flags & V_DBLSCAN; + + if(f_dbl) { idst_h*=2; ddst_y*=2; ddst_h*=2; } + + ddst_x+=pI740->ov_offset_x; + ddst_y+=pI740->ov_offset_y; + + /* Program the i740 overlay to use the new image dimensions. */ + + i740_wc(fb_p, MRX, 0x24, mem1>>16); + i740_wc(fb_p, MRX, 0x23, mem1>> 8); + i740_wc(fb_p, MRX, 0x22, mem1>> 0); + + i740_wc(fb_p, MRX, 0x27, mem2>>16); + i740_wc(fb_p, MRX, 0x26, mem2>> 8); + i740_wc(fb_p, MRX, 0x25, mem2>> 0); + + i740_wc(fb_p, MRX, 0x28, (( pitch >>3)-1) ); + + { unsigned short v=ddst_x; i740_wc(fb_p, MRX, 0x2B, v>> 8); i740_wc(fb_p, MRX, 0x2A, v>> 0); } + { unsigned short v=ddst_x+ddst_w-1; i740_wc(fb_p, MRX, 0x2D, v>> 8); i740_wc(fb_p, MRX, 0x2C, v>> 0); } + { unsigned short v=ddst_y; i740_wc(fb_p, MRX, 0x2F, v>> 8); i740_wc(fb_p, MRX, 0x2E, v>> 0); } + { unsigned short v=ddst_y+ddst_h-1; i740_wc(fb_p, MRX, 0x31, v>> 8); i740_wc(fb_p, MRX, 0x30, v>> 0); } + + i740_wc(fb_p, MRX, 0x32, (isrc_w<<8)/(idst_w)); + i740_wc(fb_p, MRX, 0x33, (isrc_h<<8)/(idst_h)); + + i740_wc(fb_p, MRX, 0x50, 0); + i740_wc(fb_p, MRX, 0x51, 0); + + i740_wc(fb_p, MRX, 0x1E, ( idst_w > isrc_w ? 0x04 : 0x00 ) | ( idst_h > isrc_h ? 0x08 : 0x00 )); + i740_wc(fb_p, MRX, 0x1F, ( idst_w > isrc_w ? 0x20 : 0x00 ) | ( (idst_h > isrc_h) && (pitch <= 720*2) ? 0xC0 : 0x00 ) | (vd_mod & 0x1F)); + + /*i740_wc(fb_p, MRX, 0x20, 0);*/ + + i740_wc(fb_p, MRX, 0x19, 0x00); + + /*i740_wc(fb_p, XRX, 0xD0, i740_rc(fb_p, XRX, 0xD0) | 0x10 );*/ + i740_wc(fb_p, XRX, 0xD0, 0x3F); + /* 0x3C = COL_KEY_CNTL_1 */ + i740_wc(fb_p, MRX, 0x3C, 0x05 | 0x02); + + /*i740_wc(fb_p, MRX, 0x20, (flip ? 0x14 : 0x04));*/ + /*i740_wc(fb_p, MRX, 0x20, 0);*/ + /*i740_wc(fb_p, XRX, 0xD0, i740_rc(fb_p, XRX, 0xD0) | 0x10 );*/ + /*i740_wc(fb_p, MRX, 0x19, 0x00);*/ + i740_wc(fb_p, MRX, 0x20, (flip ? 0x34 : 0x24)); /*SB*/ +} + +__inline__ static void i740fb_colorkey(ScrnInfoPtr pScrn,unsigned long key) +{ + I740Ptr pI740 = I740PTR(pScrn); + unsigned char r,g,b,rm,gm,bm; + + /*//xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,"colorkey=%04x depth=%d\n",key,pScrn->depth);*/ + + switch(pScrn->depth) + { + case 4: r=0x00; g=0x00; b=key; rm=0xFF; gm=0xFF; bm=0xF0; break; + case 8: r=0x00; g=0x00; b=key; rm=0xFF; gm=0xFF; bm=0x00; break; + case 15: r=(key&0x7C00)>>7; g=(key&0x03E0)>>2; b=(key&0x001F)<<3; rm=0x07; gm=0x07; bm=0x07; break; + case 16: r=(key&0xF800)>>8; g=(key&0x07E0)>>3; b=(key&0x001F)<<3; rm=0x07; gm=0x03; bm=0x07; break; + default: /*24*/ r=(key&0xFF00)>>8; g=(key&0xFF00)>>3; b=(key&0xFF00)<<3; rm=0x00; gm=0x00; bm=0x00; break; + } + + i740_wc(fb_p, MRX, 0x3D, r); + i740_wc(fb_p, MRX, 0x3E, g); + i740_wc(fb_p, MRX, 0x3F, b); + + i740_wc(fb_p, MRX, 0x40, rm); + i740_wc(fb_p, MRX, 0x41, gm); + i740_wc(fb_p, MRX, 0x42, bm); +} + +/*-----------------------------------------------------------------------------------------*/ + + + +static void I740ResetVideo(ScrnInfoPtr pScrn) +{ + I740Ptr pI740 = I740PTR(pScrn); + I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr; + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740ResetVideo entered\n"); /* ### */ + + /* + * Enable destination color keying + */ + + i740fb_colorkey(pScrn,pPriv->colorKey); +} + + + + +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; +} + + +/* I740ClipVideo - + + 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 I740ClipVideo( + 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 I740StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit) +{ + I740PortPrivPtr pPriv = (I740PortPrivPtr)data; + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740StopVideo entered %p %d\n", (void*)data, (int)exit);*/ /* ### */ + + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + + if(exit) + { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) + i740fb_overlay_off(pScrn); + + if(pPriv->linear) + { + xf86FreeOffscreenLinear(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } + else + { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) + { + pPriv->videoStatus |= OFF_TIMER; + pPriv->offTime = currentTime.milliseconds + OFF_DELAY; + } + } + +} + +static int I740SetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value, pointer data) +{ + I740PortPrivPtr pPriv = (I740PortPrivPtr)data; + I740Ptr pI740 = I740PTR(pScrn); + I740OverlayRegPtr overlay = (I740OverlayRegPtr) (pI740->FbBase + pI740->OverlayStart); + + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740SetPortAttribute entered %d\n", (int) value);*/ /* ### */ + + if(attribute == xvBrightness) + { + if((value < -128) || (value > 127)) + return BadValue; + pPriv->brightness = value; + overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff); + /*//OVERLAY_UPDATE(pI740->OverlayPhysical);*/ + } + else + if(attribute == xvContrast) + { + if((value < 0) || (value > 255)) + return BadValue; + pPriv->contrast = value; + overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff); + /*//OVERLAY_UPDATE(pI740->OverlayPhysical);*/ + } + else + if(attribute == xvColorKey) + { + pPriv->colorKey = value; + + i740fb_colorkey(pScrn,pPriv->colorKey); + + /*//OVERLAY_UPDATE(pI740->OverlayPhysical);*/ + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + } + else + return BadMatch; + + return Success; +} + +static int I740GetPortAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data +){ + I740PortPrivPtr pPriv = (I740PortPrivPtr)data; + + if(attribute == xvBrightness) { + *value = pPriv->brightness; + } else + if(attribute == xvContrast) { + *value = pPriv->contrast; + } else + if(attribute == xvColorKey) { + *value = pPriv->colorKey; + } else return BadMatch; + + return Success; +} + +static void I740QueryBestSize( + 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 +){ + if(vid_w > (drw_w << 1)) drw_w = vid_w >> 1; + if(vid_h > (drw_h << 1)) drw_h = vid_h >> 1; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740QueryBestSize entered %d %d %d %d\n", (int) vid_w, (int) vid_h, (int) drw_w, (int) drw_h); /* ### */ + fprintf(stderr, "fprintf - I740QueryBestSize entered %d %d %d %d\n", (int) vid_w, (int) vid_h, (int) drw_w, (int) drw_h); /* ### */ + + *p_w = drw_w; + *p_h = drw_h; +} + +static void I740CopyMungedData(ScrnInfoPtr pScrn, + unsigned char *src1, unsigned char *src2, unsigned char *src3, + int srcPitch, + int srcPitch2, + int dstPitch, + int h, + int w, + long scalex, + long scaley) +{ + I740Ptr pI740 = I740PTR(pScrn); + I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr; + CARD32 *dst; + int i, j; + + if (pPriv->currentBuf == 0) + dst = (CARD32 *)(pI740->FbBase + pPriv->YBuf0offset); + else + dst = (CARD32 *)(pI740->FbBase + pPriv->YBuf1offset); + + dstPitch >>= 2; + w >>= 1; + + /* If the space on the screen is smaller than the source image, then we use + * software scaling to make it smaller. */ + if (scalex > 0x10000 || scaley > 0x10000) { + int dsth = ((long) h * 0x10000L + scaley - 1) / scaley; + long halfx = scalex/2; + long dstj = 0; + for(j = 0; j < dsth; j++) { + int dstj_rnd = dstj >> 16; + unsigned char* src1_ = src1 + (dstj_rnd * srcPitch); + unsigned char* src2_ = src2 + ((dstj_rnd/2) * srcPitch2); + unsigned char* src3_ = src3 + ((dstj_rnd/2) * srcPitch2); + int dstw = ((long) w * 0x10000L + halfx - 1) / scalex; + long srci = 0; + for(i = 0; i < dstw; i++) { + long srci_rnd = srci >> 16; + long srci2_rnd = (srci + halfx) >> 16; + dst[i] = + (((src1_[srci_rnd << 1] | (src1_[(srci_rnd << 1) + 1] << 16) | + (src3_[srci_rnd] << 8) | (src2_[srci_rnd] << 24))) >> 1 & 0x7F7F7F7FL) + + + (((src1_[srci2_rnd << 1] | (src1_[(srci2_rnd << 1) + 1] << 16) | + (src3_[srci2_rnd] << 8) | (src2_[srci2_rnd] << 24))) >> 1 & 0x7F7F7F7FL); + srci += scalex; + } + dst += dstPitch; + dstj += scaley; + } + } + else { + for(j = 0; j < h; j++) { + for(i = 0; i < w; i++) { + dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) | + (src3[i] << 8) | (src2[i] << 24); + } + dst += dstPitch; + src1 += srcPitch; + if(j & 1) { + src2 += srcPitch2; + src3 += srcPitch2; + } + } + } +} + + +__inline__ static void I740CopyPackedData(ScrnInfoPtr pScrn, + unsigned char *buf, + int srcPitch, + int dstPitch, + int top, + int left, + int h, + int w + ) +{ + I740Ptr pI740 = I740PTR(pScrn); + I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr; + unsigned char *src, *dst; + + src = buf + (top*srcPitch) + (left<<1); + + if (pPriv->currentBuf == 0) + dst = pI740->FbBase + pPriv->YBuf0offset; + else + dst = pI740->FbBase + pPriv->YBuf1offset; + + w <<= 1; + while(h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} + + +__inline__ static void I740DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height, + int dstPitch, /* of chroma for 4:2:0 */ + int x1, int y1, int x2, int y2, + BoxPtr dstBox, + short src_w, short src_h, short drw_w, short drw_h, + unsigned char vd_mod + ) +{ + I740Ptr pI740 = I740PTR(pScrn); + I740PortPrivPtr pPriv = pI740->adaptor->pPortPrivates[0].ptr; + + i740fb_overlay_set(pScrn,pPriv,pPriv->YBuf0offset,pPriv->YBuf1offset, + src_w,src_h, /* source image size */ + drw_w,drw_h, /* destination image size */ + dstBox->x1,dstBox->y1, /* destination image pos to display */ + dstBox->x2 - dstBox->x1,dstBox->y2 - dstBox->y1, /* destination image size to display allows trunc... */ + dstPitch,(pPriv->currentBuf != 0), + vd_mod); + + i740fb_colorkey(pScrn,pPriv->colorKey); /* needed to reset properly the i740 board after switching from framebuffer */ +} + +static FBLinearPtr I740AllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size) +{ + ScreenPtr pScreen; + FBLinearPtr new_linear; + + if(linear) + { + if(linear->size >= size) + return linear; + + if(xf86ResizeOffscreenLinear(linear, size)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory resized to %d - %p\n", (int) size, linear); /* ### */ + return linear; + } + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory free %p - %d < %d\n", linear, (int) linear->size, (int) size); /* ### */ + xf86FreeOffscreenLinear(linear); + } + + pScreen = screenInfo.screens[pScrn->scrnIndex]; + + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL); + + if(!new_linear) + { + int max_size; + + xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4, PRIORITY_EXTREME); + + if(max_size < size) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory can't purge %d < %d\n", (int) max_size, (int) size); /* ### */ + return NULL; + } + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory purged %d\n", (int) max_size); /* ### */ + xf86PurgeUnlockedOffscreenAreas(pScreen); + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, + NULL, NULL, NULL); + } + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateMemory allocated %d - %p\n", (int) size, new_linear); /* ### */ + + return new_linear; +} + +static int I740PutImage(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 + ) +{ + I740Ptr pI740 = I740PTR(pScrn); + I740PortPrivPtr pPriv = (I740PortPrivPtr)data; + INT32 x1, x2, y1, y2; + int srcPitch, dstPitch, srcPitch2=0; + int top, left, npixels, nlines, size; + BoxRec dstBox; + int offset2=0, offset3=0; + + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740PutImage entered %d %d\n", (int) width, (int) height, id);*/ /* ### */ + + /* 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; + + I740ClipVideo(&dstBox, &x1, &x2, &y1, &y2, + REGION_EXTENTS(pScreen, clipBoxes), width, height); + + if((x1 >= x2) || (y1 >= y2)) { + return Success; + } + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + switch(id) + { + case FOURCC_YV12: + case FOURCC_I420: + srcPitch = (width + 3) & ~3; + offset2 = srcPitch * height; + srcPitch2 = ((width >> 1) + 3) & ~3; + offset3 = (srcPitch2 * (height >> 1)) + offset2; + dstPitch = ((width << 1) + 15) & ~15; + size = dstPitch * height; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + srcPitch = (width << 1); + dstPitch = (srcPitch + 7) & ~7; + size = dstPitch * height; + break; + } + + { + FBLinearPtr new_linear = I740AllocateMemory(pScrn, pPriv->linear, size); + if (new_linear != pPriv->linear) { + pPriv->linear = new_linear; + } + } + if(!pPriv->linear) + return BadAlloc; + + /* fixup pointers */ + pPriv->YBuf0offset = pPriv->linear->offset*pI740->cpp; + pPriv->YBuf1offset = (pPriv->linear->offset*pI740->cpp) + size; + + +#if 0 /*???*/ + /* wait for the last rendered buffer to be flipped in */ + while (((INREG(DOV0STA)&0x00100000)>>20) != pPriv->currentBuf); +#endif + + /* buffer swap */ + pPriv->currentBuf ^= 1; + + /* copy data */ + top = y1 >> 16; + left = (x1 >> 16) & ~1; + npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + { + CARD32 tmp; + + top &= ~1; + tmp = ((top >> 1) * srcPitch2) + (left >> 1); + offset2 += tmp; + offset3 += tmp; + + if(id == FOURCC_I420) + { + tmp = offset2; + offset2 = offset3; + offset3 = tmp; + } + + nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; + + /* If the screen image size is smaller than the video image size, then + * we use software scaling to make it smaller. The hardware takes care + * of scaling up - see i740fb_overlay_set. + */ + { + long scalex = 0x10000, scaley = 0x10000; + if (drw_w < src_w) + scalex = (0x10000L * (long) src_w) / (long) drw_w; + if (drw_h < src_h) + scaley = (0x10000L * (long) src_h) / (long) drw_h; + + I740CopyMungedData(pScrn, buf + (top * srcPitch) + left, + buf + offset2, buf + offset3, + srcPitch, srcPitch2, dstPitch, nlines, npixels, scalex, scaley); + } + } + break; + + case FOURCC_UYVY: case FOURCC_YUY2: default: + { + nlines = ((y2 + 0xffff) >> 16) - top; + /* Add software scaling as above. */ + I740CopyPackedData(pScrn, buf, srcPitch, dstPitch, top, left, 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)); + } + + { + unsigned char vd_mod; + + switch(id) + { + case FOURCC_RV15: vd_mod=0x09; break; + case FOURCC_RV16: vd_mod=0x08; break; + default: vd_mod=0x00; break; + } + + I740DisplayVideo(pScrn, id, width, height, dstPitch, + x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, + vd_mod); + } + + pPriv->videoStatus = CLIENT_VIDEO_ON; + + return Success; +} + + +static int I740QueryImageAttributes(ScrnInfoPtr pScrn, int id, unsigned short *w, unsigned short *h, int *pitches, int *offsets ) +{ + int size,tmp; + + if(*w > IMAGE_MAX_PHY_WIDTH) *w = IMAGE_MAX_PHY_WIDTH; + if(*h > IMAGE_MAX_PHY_HEIGHT) *h = IMAGE_MAX_PHY_HEIGHT; + + *w = (*w + 1) & ~1; + if(offsets) offsets[0] = 0; + + switch(id) + { + 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_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if(pitches) pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +static void I740BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + I740Ptr pI740 = I740PTR(pScrn); + I740PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); + + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740BlockHandler entered\n"); */ /* ### */ + + pScreen->BlockHandler = pI740->BlockHandler; + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + pScreen->BlockHandler = I740BlockHandler; + + if(pPriv->videoStatus & TIMER_MASK) + { + UpdateCurrentTime(); + if(pPriv->videoStatus & OFF_TIMER) + { + if(pPriv->offTime < currentTime.milliseconds) + { + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740BlockHandler: OFF_TIMER expired\n");*/ /* ### */ + /* Turn off the overlay */ + i740fb_overlay_off(pScrn); + + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = currentTime.milliseconds + FREE_DELAY; + } + } + else + { /* FREE_TIMER */ + if(pPriv->freeTime < currentTime.milliseconds) + { + if(pPriv->linear) + { + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740BlockHandler: FREE_TIMER expired\n");*/ /* ### */ + xf86FreeOffscreenLinear(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + } + } + } +} + + +/*************************************************************************** + * Offscreen Images + ***************************************************************************/ + +typedef struct { + FBLinearPtr linear; + Bool isOn; +} OffscreenPrivRec, * OffscreenPrivPtr; + +static int I740AllocateSurface( + ScrnInfoPtr pScrn, + int id, + unsigned short w, + unsigned short h, + XF86SurfacePtr surface +){ + FBLinearPtr linear; + int pitch, size; + OffscreenPrivPtr pPriv; + I740Ptr pI740 = I740PTR(pScrn); + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740AllocateSurface entered %d %d\n", (int) w, (int) h); /* ### */ + + if((w > IMAGE_MAX_LOG_WIDTH) || (h > IMAGE_MAX_LOG_HEIGHT)) + return BadAlloc; + + w = (w + 1) & ~1; + pitch = ((w << 1) + 15) & ~15; + size = pitch * h; + + if(!(linear = I740AllocateMemory(pScrn, NULL, size))) + return BadAlloc; + + surface->width = w; + surface->height = h; + + if(!(surface->pitches = xalloc(sizeof(int)))) { + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + if(!(surface->offsets = xalloc(sizeof(int)))) { + xfree(surface->pitches); + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) { + xfree(surface->pitches); + xfree(surface->offsets); + xf86FreeOffscreenLinear(linear); + return BadAlloc; + } + + pPriv->linear = linear; + pPriv->isOn = FALSE; + + surface->pScrn = pScrn; + surface->id = id; + surface->pitches[0] = pitch; + surface->offsets[0] = linear->offset*pI740->cpp; + surface->devPrivate.ptr = (pointer)pPriv; + + /*//memset(pI740->FbBase + surface->offsets[0],0,size);*/ + + return Success; +} + +static int I740StopSurface(XF86SurfacePtr surface) +{ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; + + if(pPriv->isOn) + { + /*//i740fb_overlay_off(pScrn);*/ + + pPriv->isOn = FALSE; + } + + return Success; +} + + +static int I740FreeSurface(XF86SurfacePtr surface) +{ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; + + if(pPriv->isOn) + { + I740StopSurface(surface); + } + + xf86FreeOffscreenLinear(pPriv->linear); + xfree(surface->pitches); + xfree(surface->offsets); + xfree(surface->devPrivate.ptr); + + return Success; +} + +static int I740GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value) +{ + return I740GetPortAttribute(pScrn, attribute, value, 0); +} + +static int I740SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value) +{ + return I740SetPortAttribute(pScrn, attribute, value, 0); +} + + +static int I740DisplaySurface(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; + I740PortPrivPtr pI740Priv = GET_PORT_PRIVATE(pScrn); + + INT32 x1, y1, x2, y2; + BoxRec dstBox; + + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740DisplaySurface entered\n"); /* ### */ + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,"I740DisplaySurface-----------------------------------\n");*/ + /*//fprintf(stderr, "I740DisplaySurface-----------------------------------\n");*/ + + + 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; + + I740ClipVideo(&dstBox, &x1, &x2, &y1, &y2, + REGION_EXTENTS(screenInfo.screens[0], clipBoxes), + surface->width, surface->height); + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + /* fixup pointers */ + pI740Priv->YBuf0offset = surface->offsets[0]; + pI740Priv->YBuf1offset = pI740Priv->YBuf0offset; + +#if 0 /*???*/ + /* wait for the last rendered buffer to be flipped in */ + while (((INREG(DOV0STA)&0x00100000)>>20) != pI740Priv->currentBuf) { + if(loops == 200000) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Overlay Lockup\n"); + break; + } + loops++; + } +#endif + + /* buffer swap */ + if (pI740Priv->currentBuf == 0) + pI740Priv->currentBuf = 1; + else + pI740Priv->currentBuf = 0; + + I740ResetVideo(pScrn); + + I740DisplayVideo(pScrn, surface->id, surface->width, surface->height, + surface->pitches[0], x1, y1, x2, y2, &dstBox, + src_w, src_h, drw_w, drw_h, + 0x00); + + XAAFillSolidRects(pScrn, pI740Priv->colorKey, GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), + REGION_RECTS(clipBoxes)); + + pPriv->isOn = TRUE; + /* we've prempted the XvImage stream so set its free timer */ + if(pI740Priv->videoStatus & CLIENT_VIDEO_ON) { + REGION_EMPTY(pScrn->pScreen, & pI740Priv->clip); + UpdateCurrentTime(); + pI740Priv->videoStatus = FREE_TIMER; + pI740Priv->freeTime = currentTime.milliseconds + FREE_DELAY; + pScrn->pScreen->BlockHandler = I740BlockHandler; + } + + return Success; +} + +/*-------------------------------------------------------------------------------------------*/ +#define NUM_IMAGES (sizeof(i740vid_Images)/sizeof(XF86ImageRec)) +static XF86ImageRec i740vid_Images[] = +{ + XVIMAGE_YUY2, + XVIMAGE_UYVY, + XVIMAGE_YV12, /* converted to YUV2 while copying */ + XVIMAGE_I420, /* converted to YUV2 while copying */ + { + 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 + }, +}; + +#define NUM_ATTRIBUTES (sizeof(i740vid_Attributes)/sizeof(XF86AttributeRec)) + +static XF86AttributeRec i740vid_Attributes[] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} +}; + + +static void I740InitOffscreenImages(ScreenPtr pScreen) +{ + XF86OffscreenImagePtr offscreenImages; + { + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740InitOffscreenImages entered\n"); /* ### */ + } + + /* need to free this someplace */ + if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)))) + { + return; + } + + offscreenImages[0].image = &i740vid_Images[0]; + offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + offscreenImages[0].alloc_surface = I740AllocateSurface; + offscreenImages[0].free_surface = I740FreeSurface; + offscreenImages[0].display = I740DisplaySurface; + offscreenImages[0].stop = I740StopSurface; + offscreenImages[0].setAttribute = I740SetSurfaceAttribute; + offscreenImages[0].getAttribute = I740GetSurfaceAttribute; + offscreenImages[0].max_width = IMAGE_MAX_LOG_WIDTH; + offscreenImages[0].max_height = IMAGE_MAX_LOG_HEIGHT; + offscreenImages[0].num_attributes = NUM_ATTRIBUTES; + offscreenImages[0].attributes = i740vid_Attributes; + + xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1); +} + + + +static XF86VideoAdaptorPtr I740SetupImageVideo(ScreenPtr pScreen) +{ + /* client libraries expect an encoding */ + static XF86VideoEncodingRec DummyEncoding[1] = + { + { + 0, + "XV_IMAGE", + IMAGE_MAX_PHY_WIDTH, IMAGE_MAX_PHY_HEIGHT, + {1, 1} + } + }; + +#define NUM_FORMATS (sizeof(i740vid_Formats)/sizeof(XF86VideoFormatRec)) + static XF86VideoFormatRec i740vid_Formats[] = + { + {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, {8, PseudoColor} + }; + + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I740Ptr pI740 = I740PTR(pScrn); + XF86VideoAdaptorPtr adapt; + I740PortPrivPtr pPriv; + + /*xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740SetupImageVideo entered\n");*/ /* ### */ + { + const int n=sizeof(XF86VideoAdaptorRec)+sizeof(I740PortPrivRec)+sizeof(DevUnion); + + if(!(adapt = xcalloc(1, n))) + return NULL; + + /*//memset(adapt,0,n);*/ + } + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "I740 Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = i740vid_Formats; + adapt->nPorts = 1; + adapt->pPortPrivates = (DevUnion*)(&adapt[1]); + + pPriv = (I740PortPrivPtr)((unsigned char *)(&adapt[1])+sizeof(sizeof(DevUnion))); + + adapt->pPortPrivates[0].ptr = (pointer)(pPriv); + adapt->pAttributes = i740vid_Attributes; + adapt->nImages = NUM_IMAGES; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pImages = i740vid_Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = I740StopVideo; + adapt->SetPortAttribute = I740SetPortAttribute; + adapt->GetPortAttribute = I740GetPortAttribute; + adapt->QueryBestSize = I740QueryBestSize; + adapt->PutImage = I740PutImage; + adapt->QueryImageAttributes = I740QueryImageAttributes; + + pPriv->colorKey = pI740->colorKey & ((1 << pScrn->depth) - 1); + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->contrast = 64; + pPriv->linear = NULL; + pPriv->currentBuf = 0; + + /* gotta uninit this someplace */ + REGION_INIT(pScreen, &pPriv->clip, NullBox, 0); + + pI740->adaptor = adapt; + + pI740->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = I740BlockHandler; + + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + + I740ResetVideo(pScrn); + + return adapt; +} + +void I740InitVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr newAdaptor = NULL; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "I740InitVideo entered\n"); /* ### */ + +#if 0 /*disable!*/ + { + XF86VideoAdaptorPtr *ptr; + int n; + + n = xf86XVListGenericAdaptors(pScrn,&ptr); + if (n) { + xf86XVScreenInit(pScreen, ptr, n); + } + + return; + } +#endif + + { + newAdaptor = I740SetupImageVideo(pScreen); + I740InitOffscreenImages(pScreen); + } + + { + XF86VideoAdaptorPtr *adaptors_oldptrs, *adaptors_newptrs = NULL; + int num_adaptors; + + num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors_oldptrs); + + if(newAdaptor) + { + if(!num_adaptors) + { + xf86XVScreenInit(pScreen, &newAdaptor, 1); + } + else + { + if((adaptors_newptrs = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr)))) + { + memcpy(adaptors_newptrs, adaptors_oldptrs, num_adaptors * sizeof(XF86VideoAdaptorPtr)); + adaptors_newptrs[num_adaptors] = newAdaptor; + + /*//xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,"num--- %d [%d] %08x %08x\n",num_adaptors,num_adaptors * sizeof(XF86VideoAdaptorPtr),*/ + /*// adaptors_newptrs[0],adaptors_newptrs[1]);*/ + + + xf86XVScreenInit(pScreen, adaptors_newptrs, num_adaptors+1); + xfree(adaptors_newptrs); + } + } + } + + } +} +#endif /*XvExtension*/ |