diff options
Diffstat (limited to 'src')
150 files changed, 67693 insertions, 0 deletions
diff --git a/src/ati.c b/src/ati.c new file mode 100644 index 0000000..1163a81 --- /dev/null +++ b/src/ati.c @@ -0,0 +1,72 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ati.c,v 1.23 2003/04/25 14:37:35 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +/*************************************************************************/ + +/* + * Author: Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * This is the ATI driver for XFree86. + * + * John Donne once said "No man is an island", and I am most certainly not an + * exception. Contributions, intentional or not, to this and previous versions + * of this driver by the following are hereby acknowledged: + * + * Thomas Roell, Per Lindqvist, Doug Evans, Rik Faith, Arthur Tateishi, + * Alain Hebert, Ton van Rosmalen, David Chambers, William Shubert, + * ATI Technologies Incorporated, Robert Wolff, David Dawes, Mark Weaver, + * Hans Nasten, Kevin Martin, Frederic Rienthaler, Marc Bolduc, Reuben Sumner, + * Benjamin T. Yang, James Fast Kane, Randall Hopper, W. Marcus Miller, + * Henrik Harmsen, Christian Lupien, Precision Insight Incorporated, + * Mark Vojkovich, Huw D M Davies, Andrew C Aitchison, Ani Joshi, + * Kostas Gewrgiou, Jakub Jelinek, David S. Miller, A E Lawrence, + * Linus Torvalds, William Blew, Ignacio Garcia Etxebarria, Patrick Chase, + * Vladimir Dergachev, Egbert Eich, Mike A. Harris + * + * ... and, many, many others from around the world. + * + * In addition, this work would not have been possible without the active + * support, both moral and otherwise, of the staff and management of Computing + * and Network Services at the University of Alberta, in Edmonton, Alberta, + * Canada. + * + * The driver is intended to support all ATI adapters since their VGA Wonder + * V3, including OEM counterparts. + */ + +#include "atiident.h" +#include "atioption.h" +#include "atiprobe.h" +#include "ativersion.h" + +/* The root of all evil... */ +DriverRec ATI = +{ + ATI_VERSION_CURRENT, + "ati", + ATIIdentify, + ATIProbe, + ATIAvailableOptions, + NULL, + 0 +}; diff --git a/src/ati.h b/src/ati.h new file mode 100644 index 0000000..38e2715 --- /dev/null +++ b/src/ati.h @@ -0,0 +1,37 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ati.h,v 1.9 2003/01/01 19:16:30 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATI_H___ +#define ___ATI_H___ 1 + +#include "xf86Pci.h" +#include "xf86PciInfo.h" + +#include "xf86.h" + +#include "xf86_ansic.h" +#include "xf86_OSproc.h" + +extern DriverRec ATI; + +#endif /* ___ATI_H___ */ diff --git a/src/atiaccel.c b/src/atiaccel.c new file mode 100644 index 0000000..3c358cf --- /dev/null +++ b/src/atiaccel.c @@ -0,0 +1,133 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiaccel.c,v 1.13 2003/04/24 21:19:22 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiaccel.h" +#include "atiadapter.h" +#include "atimach64accel.h" +#include "atistruct.h" + +/* + * ATIInitializeAcceleration -- + * + * This function is called to initialise both the framebuffer manager and XAA + * on a screen. + */ +Bool +ATIInitializeAcceleration +( + ScreenPtr pScreen, + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + int maxScanlines = 32767, maxPixelArea, PixelArea; + + if (pATI->OptionAccel) + { + if (!(pATI->pXAAInfo = XAACreateInfoRec())) + return FALSE; + + switch (pATI->Adapter) + { + case ATI_ADAPTER_MACH64: + maxScanlines = ATIMach64AccelInit(pATI, pATI->pXAAInfo); + break; + + default: + break; + } + } + +#ifndef AVOID_CPIO + + if (!pATI->BankInfo.BankSize) + +#endif /* AVOID_CPIO */ + + { + /* + * Note: If PixelArea exceeds the engine's maximum, the excess is + * never used, even though it would be useful for such things + * as XVideo buffers. + */ + maxPixelArea = maxScanlines * pScreenInfo->displayWidth; + PixelArea = pScreenInfo->videoRam * 1024 * 8 / pATI->bitsPerPixel; + if (PixelArea > maxPixelArea) + PixelArea = maxPixelArea; + xf86InitFBManagerArea(pScreen, PixelArea, 2); + } + + if (!pATI->OptionAccel || XAAInit(pScreen, pATI->pXAAInfo)) + return TRUE; + + XAADestroyInfoRec(pATI->pXAAInfo); + pATI->pXAAInfo = NULL; + return FALSE; +} + +FBLinearPtr +ATIResizeOffscreenLinear +( + ScreenPtr pScreen, + FBLinearPtr pLinear, + int Size +) +{ + if (Size <= 0) + { + xf86FreeOffscreenLinear(pLinear); + return NULL; + } + + if (pLinear) + { + if ((pLinear->size >= Size) || + xf86ResizeOffscreenLinear(pLinear, Size)) + { + pLinear->MoveLinearCallback = NULL; + pLinear->RemoveLinearCallback = NULL; + return pLinear; + } + + xf86FreeOffscreenLinear(pLinear); + } + + pLinear = xf86AllocateOffscreenLinear(pScreen, Size, 16, NULL, NULL, NULL); + + if (!pLinear) + { + int maxSize; + + xf86QueryLargestOffscreenLinear(pScreen, &maxSize, 16, + PRIORITY_EXTREME); + + if (maxSize < Size) + return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + pLinear = + xf86AllocateOffscreenLinear(pScreen, Size, 16, NULL, NULL, NULL); + } + + return pLinear; +} diff --git a/src/atiaccel.h b/src/atiaccel.h new file mode 100644 index 0000000..e9faa33 --- /dev/null +++ b/src/atiaccel.h @@ -0,0 +1,41 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiaccel.h,v 1.5 2003/04/23 21:51:27 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIACCEL_H___ +#define ___ATIACCEL_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" +#include "xf86fbman.h" + +extern Bool ATIInitializeAcceleration FunctionPrototype((ScreenPtr, + ScrnInfoPtr, + ATIPtr)); + +extern FBLinearPtr ATIResizeOffscreenLinear FunctionPrototype((ScreenPtr, + FBLinearPtr, + int)); + +#endif /* ___ATIACCEL_H___ */ diff --git a/src/atiadapter.c b/src/atiadapter.c new file mode 100644 index 0000000..15f91bb --- /dev/null +++ b/src/atiadapter.c @@ -0,0 +1,54 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiadapter.c,v 1.17 2003/01/01 19:16:30 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiadapter.h" + +/* + * Adapter-related definitions. + */ +const char *ATIAdapterNames[] = +{ + "Unknown", + +#ifndef AVOID_CPIO + + "ATI EGA Wonder800", + "ATI EGA Wonder800+", + "IBM VGA or compatible", + "ATI VGA Basic16", + "ATI VGA Wonder V3", + "ATI VGA Wonder V4", + "ATI VGA Wonder V5", + "ATI VGA Wonder+", + "ATI VGA Wonder XL or XL24", + "ATI VGA Wonder VLB or PCI", + "IBM 8514/A or compatible", + "ATI Mach8", + "ATI Mach32", + +#endif /* AVOID_CPIO */ + + "ATI Mach64", + "ATI Rage128", + "ATI Radeon" +}; diff --git a/src/atiadapter.h b/src/atiadapter.h new file mode 100644 index 0000000..5cfb79c --- /dev/null +++ b/src/atiadapter.h @@ -0,0 +1,60 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiadapter.h,v 1.10 2003/01/01 19:16:30 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIADAPTER_H___ +#define ___ATIADAPTER_H___ 1 + +/* + * Adapter-related definitions. + */ +typedef enum +{ + ATI_ADAPTER_NONE = 0, + +#ifndef AVOID_CPIO + + ATI_ADAPTER_EGA, + ATI_ADAPTER_EGA_PLUS, + ATI_ADAPTER_VGA, + ATI_ADAPTER_BASIC, + ATI_ADAPTER_V3, + ATI_ADAPTER_V4, + ATI_ADAPTER_V5, + ATI_ADAPTER_PLUS, + ATI_ADAPTER_XL, + ATI_ADAPTER_NONISA, + ATI_ADAPTER_8514A, + ATI_ADAPTER_MACH8, + ATI_ADAPTER_MACH32, + +#endif /* AVOID_CPIO */ + + ATI_ADAPTER_MACH64, + ATI_ADAPTER_RAGE128, + ATI_ADAPTER_RADEON, + ATI_ADAPTER_MAX /* Must be last */ +} ATIAdapterType; + +extern const char *ATIAdapterNames[]; + +#endif /* ___ATIADAPTER_H___ */ diff --git a/src/atiadjust.c b/src/atiadjust.c new file mode 100644 index 0000000..097c21d --- /dev/null +++ b/src/atiadjust.c @@ -0,0 +1,230 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiadjust.c,v 1.15 2003/04/23 21:51:27 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadjust.h" +#include "atichip.h" +#include "aticrtc.h" +#include "atilock.h" +#include "atimach64io.h" +#include "atiwonderio.h" + +/* + * The display start address is expressed in units of 32-bit (VGA) or 64-bit + * (accelerator) words where all planar modes are considered as 4bpp modes. + * These functions ensure the start address does not exceed architectural + * limits. Also, to avoid colour changes while panning, these 32-bit or 64-bit + * boundaries may not fall within a pixel. + */ + +/* + * ATIAjustPreInit -- + * + * This function calculates values needed to speed up the setting of the + * display start address. + */ +void +ATIAdjustPreInit +( + ATIPtr pATI +) +{ + unsigned long MaxBase; + +#ifndef AVOID_CPIO + + if ((pATI->CPIO_VGAWonder) && + (pATI->Chip <= ATI_CHIP_18800_1) && + (pATI->VideoRAM == 256) && + (pATI->depth >= 8)) + { + /* Strange, to say the least ... */ + pATI->AdjustDepth = (pATI->bitsPerPixel + 3) >> 2; + pATI->AdjustMask = (unsigned long)(-32); + } + else + +#endif /* AVOID_CPIO */ + + { + pATI->AdjustDepth = (pATI->bitsPerPixel + 7) >> 3; + + pATI->AdjustMask = 64; + while (pATI->AdjustMask % (unsigned long)(pATI->AdjustDepth)) + pATI->AdjustMask += 64; + pATI->AdjustMask = + ~(((pATI->AdjustMask / (unsigned long)(pATI->AdjustDepth)) >> 3) - + 1); + } + + switch (pATI->NewHW.crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + if (pATI->Chip >= ATI_CHIP_264CT) + { + pATI->AdjustMaxBase = MaxBits(CRTC_OFFSET_VGA) << 2; + if (pATI->depth <= 4) + pATI->AdjustMaxBase <<= 1; + } + else if (!pATI->CPIO_VGAWonder) + { + pATI->AdjustMaxBase = 0xFFFFU << 3; + } + else if (pATI->Chip <= ATI_CHIP_28800_6) + { + pATI->AdjustMaxBase = 0x03FFFFU << 3; + } + else /* Mach32 & Mach64 */ + { + pATI->AdjustMaxBase = 0x0FFFFFU << 3; + } + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + pATI->AdjustMaxBase = MaxBits(CRTC_OFFSET) << 3; + break; + + default: + pATI->AdjustMaxBase = 0; + break; + } + + MaxBase = (pATI->AdjustMaxBase / (unsigned long)pATI->AdjustDepth) | + ~pATI->AdjustMask; + + pATI->AdjustMaxX = MaxBase % pATI->displayWidth; + pATI->AdjustMaxY = MaxBase / pATI->displayWidth; +} + +/* + * ATIAdjustFrame -- + * + * This function is used to initialise the SVGA Start Address - the first + * displayed location in video memory. This is used to implement the virtual + * window. + */ +void +ATIAdjustFrame +( + int scrnIndex, + int x, + int y, + int flags +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[scrnIndex]; + ATIPtr pATI = ATIPTR(pScreenInfo); + int Base, xy; + + /* + * Assume the caller has already done its homework in ensuring the physical + * screen is still contained in the virtual resolution. + */ + if (y >= pATI->AdjustMaxY) + { + y = pATI->AdjustMaxY; + if (x > pATI->AdjustMaxX) + y--; + } + + Base = ((((y * pATI->displayWidth) + x) & pATI->AdjustMask) * + pATI->AdjustDepth) >> 3; + + if (!pATI->currentMode) + { + /* + * Not in DGA. This reverse-calculates pScreenInfo->frame[XY][01] so + * that the cursor does not move on mode switches. + */ + xy = (Base << 3) / pATI->AdjustDepth; + pScreenInfo->frameX0 = xy % pATI->displayWidth; + pScreenInfo->frameY0 = xy / pATI->displayWidth; + pScreenInfo->frameX1 = + pScreenInfo->frameX0 + pScreenInfo->currentMode->HDisplay - 1; + pScreenInfo->frameY1 = + pScreenInfo->frameY0 + pScreenInfo->currentMode->VDisplay - 1; + } + + /* Unlock registers */ + ATIUnlock(pATI); + +#ifndef AVOID_CPIO + + if ((pATI->NewHW.crtc == ATI_CRTC_VGA) && (pATI->Chip < ATI_CHIP_264CT)) + { + PutReg(CRTX(pATI->CPIO_VGABase), 0x0CU, GetByte(Base, 1)); + PutReg(CRTX(pATI->CPIO_VGABase), 0x0DU, GetByte(Base, 0)); + + if (pATI->CPIO_VGAWonder) + { + if (pATI->Chip <= ATI_CHIP_18800_1) + ATIModifyExtReg(pATI, 0xB0U, -1, 0x3FU, Base >> 10); + else + { + ATIModifyExtReg(pATI, 0xB0U, -1, 0xBFU, Base >> 10); + ATIModifyExtReg(pATI, 0xA3U, -1, 0xEFU, Base >> 13); + + /* + * I don't know if this also applies to Mach64's, but give it a + * shot... + */ + if (pATI->Chip >= ATI_CHIP_68800) + ATIModifyExtReg(pATI, 0xADU, -1, 0xF3U, Base >> 16); + } + } + } + else + /* + * On integrated controllers, there is only one set of CRTC control bits, + * many of which are simultaneously accessible through both VGA and + * accelerator I/O ports. Given VGA's architectural limitations, setting + * the CRTC's offset register to more than 256k needs to be done through + * the accelerator port. + */ + if (pATI->depth <= 4) + { + outr(CRTC_OFF_PITCH, SetBits(pATI->displayWidth >> 4, CRTC_PITCH) | + SetBits(Base, CRTC_OFFSET)); + } + else + +#endif /* AVOID_CPIO */ + + { + +#ifndef AVOID_CPIO + + if (pATI->NewHW.crtc == ATI_CRTC_VGA) + Base <<= 1; /* LSBit must be zero */ + +#endif /* AVOID_CPIO */ + + outr(CRTC_OFF_PITCH, SetBits(pATI->displayWidth >> 3, CRTC_PITCH) | + SetBits(Base, CRTC_OFFSET)); + } +} diff --git a/src/atiadjust.h b/src/atiadjust.h new file mode 100644 index 0000000..b5cddf0 --- /dev/null +++ b/src/atiadjust.h @@ -0,0 +1,33 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiadjust.h,v 1.8 2003/01/01 19:16:30 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIADJUST_H___ +#define ___ATIADJUST_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +extern void ATIAdjustPreInit FunctionPrototype((ATIPtr)); +extern void ATIAdjustFrame FunctionPrototype((int, int, int, int)); + +#endif /* ___ATIADJUST_H___ */ diff --git a/src/atiaudio.c b/src/atiaudio.c new file mode 100644 index 0000000..a154098 --- /dev/null +++ b/src/atiaudio.c @@ -0,0 +1,47 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiaudio.c,v 1.1 2003/07/24 22:08:27 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiaudio.h" + +/* + * Audio chip definitions. + */ +const char *ATIAudioNames[] = +{ + "Philips TEA5582", + "Mono with audio mux", + "Philips TDA9850", + "Sony CXA2020S", + "ITT MSP3410D", + "Crystal CS4236B", + "Philips TDA9851", + "ITT MSP3415", + "ITT MSP3430", + "Unknown type (9)", + "Unknown type (10)", + "Unknown type (11)", + "Unknown type (12)", + "Unknown type (13)", + "Unknown type (14)", + "No audio" +}; diff --git a/src/atiaudio.h b/src/atiaudio.h new file mode 100644 index 0000000..f2eb94c --- /dev/null +++ b/src/atiaudio.h @@ -0,0 +1,52 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiaudio.h,v 1.1 2003/07/24 22:08:27 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIAUDIO_H___ +#define ___ATIAUDIO_H___ 1 + +/* + * Audio chip definitions. + */ +typedef enum +{ + ATI_AUDIO_TEA5582, + ATI_AUDIO_MONO, + ATI_AUDIO_TDA9850, + ATI_AUDIO_CXA2020S, + ATI_AUDIO_MSP3410D, + ATI_AUDIO_CS4236B, + ATI_AUDIO_TDA9851, + ATI_AUDIO_MSP3415, + ATI_AUDIO_MSP3430, + ATI_AUDIO_9, + ATI_AUDIO_10, + ATI_AUDIO_11, + ATI_AUDIO_12, + ATI_AUDIO_13, + ATI_AUDIO_14, + ATI_AUDIO_NONE +} ATIAudioType; + +extern const char *ATIAudioNames[]; + +#endif /* ___ATIAUDIO_H___ */ diff --git a/src/atibank.c b/src/atibank.c new file mode 100644 index 0000000..cd94824 --- /dev/null +++ b/src/atibank.c @@ -0,0 +1,409 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atibank.c,v 1.12 2003/01/01 19:16:30 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atibank.h" +#include "atimach64io.h" +#include "atiwonderio.h" + +#ifndef AVOID_CPIO + +/* + * ATI VGA Wonder V3 adapters use an ATI 18800 chip and are single-banked. + * Bank selection is done with bits 0x1E of ATI extended VGA register index + * 0xB2. + */ + +/* + * ATIV3SetBank -- + * + * Set an ATI 18800's bank number. + */ +void +ATIV3SetBank +( + ATIPtr pATI, + unsigned int iBank +) +{ + ATIModifyExtReg(pATI, 0xB2U, -1, (CARD8)(~0x1EU), SetBits(iBank, 0x1EU)); +} + +/* + * ATIV3SetReadWrite -- + * + * Set an ATI 18800's bank number. + */ +int +ATIV3SetReadWrite +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIPtr pATI = ATIPTR(XF86SCRNINFO(pScreen)); + + ATIModifyExtReg(pATI, 0xB2U, -1, (CARD8)(~0x1EU), SetBits(iBank, 0x1EU)); + return 0; +} + +/* + * ATI VGA Wonder V4 and V5 adapters use an ATI 18800-1 chip. Bank selection + * is done with ATI extended VGA register index 0xB2. The format is: + * + * 0xE0 - Read bank select bits 0x07 + * 0x1E - Write bank select bits 0x0F + * 0x01 - Read bank select bit 0x08. + */ + +/* + * ATIV4V5SetBank -- + * + * Set an ATI 18800-1's read and write bank numbers. + */ +void +ATIV4V5SetBank +( + ATIPtr pATI, + unsigned int iBank +) +{ + pATI->B2Reg = SetBits(iBank, 0x1EU) | SetBits(iBank, 0xE0U) | + SetBits(GetBits(iBank, 0x08U), 0x01U); + ATIPutExtReg(0xB2U, pATI->B2Reg); +} + +/* + * ATIV4V5SetRead -- + * + * Set an ATI 18800-1's read bank number. + */ +int +ATIV4V5SetRead +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIPtr pATI = ATIPTR(XF86SCRNINFO(pScreen)); + CARD8 B2Reg = (pATI->B2Reg & 0x1EU) | SetBits(iBank, 0xE0U) | + SetBits(GetBits(iBank, 0x08U), 0x01U); + + if (B2Reg != pATI->B2Reg) + { + ATIPutExtReg(0xB2U, B2Reg); + pATI->B2Reg = B2Reg; + } + + return 0; +} + +/* + * ATIV4V5SetWrite -- + * + * Set an ATI 18800-1's write bank number. + */ +int +ATIV4V5SetWrite +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIPtr pATI = ATIPTR(XF86SCRNINFO(pScreen)); + CARD8 B2Reg = (pATI->B2Reg & 0xE1U) | SetBits(iBank, 0x1EU); + + if (B2Reg != pATI->B2Reg) + { + ATIPutExtReg(0xB2U, B2Reg); + pATI->B2Reg = B2Reg; + } + return 0; +} + +/* + * ATIV4V5SetReadWrite -- + * + * Set an ATI 18800-1's read and write bank numbers. + */ +int +ATIV4V5SetReadWrite +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIV4V5SetBank(ATIPTR(XF86SCRNINFO(pScreen)), iBank); + return 0; +} + +/* + * In addition to ATI extended register index 0xB2, 28800's, 68800's and + * 88800's define banking bits in bits 0x0F of ATI extended VGA register index + * 0xAE. These are only needed for adapters with more than 1MB of video + * memory, and it is questionable whether or not they are actually implemented + * by 28800's and 88800's. ATI extended VGA register index 0xAE is defined as + * follows: + * + * 0xF0 - reserved + * 0x0C - read bank select bits 0x30 + * 0x03 - write bank select bits 0x30 + */ + +/* + * ATIx8800SetBank -- + * + * Set an ATI 28800's, 68800's or 88800's read and write bank numbers. + */ +void +ATIx8800SetBank +( + ATIPtr pATI, + unsigned int iBank +) +{ + ATIV4V5SetBank(pATI, iBank); + iBank = GetBits(iBank, 0x30U); + ATIModifyExtReg(pATI, 0xAEU, -1, (CARD8)(~0x0FU), + SetBits(iBank, 0x03U) | SetBits(iBank, 0x0CU)); +} + +/* + * ATIx8800SetRead -- + * + * Set an ATI 28800's, 68800's or 88800's read bank numbers. + */ +int +ATIx8800SetRead +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + (void)ATIV4V5SetRead(pScreen, iBank); + ATIModifyExtReg(ATIPTR(XF86SCRNINFO(pScreen)), 0xAEU, -1, (CARD8)(~0x0CU), + SetBits(GetBits(iBank, 0x30U), 0x0CU)); + return 0; +} + +/* + * ATIx8800SetWrite -- + * + * Set an ATI 28800's, 68800's or 88800's write bank numbers. + */ +int +ATIx8800SetWrite +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + (void)ATIV4V5SetWrite(pScreen, iBank); + ATIModifyExtReg(ATIPTR(XF86SCRNINFO(pScreen)), 0xAEU, -1, (CARD8)(~0x03U), + SetBits(GetBits(iBank, 0x30U), 0x03U)); + return 0; +} + +/* + * ATIx8800SetReadWrite -- + * + * Set an ATI 28800's, 68800's or 88800's read and write bank numbers. + */ +int +ATIx8800SetReadWrite +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIx8800SetBank(ATIPTR(XF86SCRNINFO(pScreen)), iBank); + return 0; +} + +/* + * Functions to simulate a banked VGA aperture using a Mach64's small dual + * paged apertures. There are two sets of these: one for packed modes, the + * other for planar modes. + */ + +static CARD32 +ATIMach64MassagePackedBankNumber +( + CARD8 iBank +) +{ + iBank <<= 1; + return ((iBank + 1) << 16) | iBank; +} + +/* + * ATIMach64SetBankPacked -- + * + * Set read and write bank numbers for small dual paged apertures. + */ +void +ATIMach64SetBankPacked +( + ATIPtr pATI, + unsigned int iBank +) +{ + CARD32 tmp = ATIMach64MassagePackedBankNumber(iBank); + + outr(MEM_VGA_RP_SEL, tmp); + outr(MEM_VGA_WP_SEL, tmp); +} + +/* + * ATIMach64SetReadPacked -- + * + * Set read bank number for small dual paged apertures. + */ +int +ATIMach64SetReadPacked +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIPtr pATI = ATIPTR(XF86SCRNINFO(pScreen)); + + outr(MEM_VGA_RP_SEL, ATIMach64MassagePackedBankNumber(iBank)); + return 0; +} + +/* + * ATIMach64SetWritePacked -- + * + * Set write bank number for small dual paged apertures. + */ +int +ATIMach64SetWritePacked +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIPtr pATI = ATIPTR(XF86SCRNINFO(pScreen)); + + outr(MEM_VGA_WP_SEL, ATIMach64MassagePackedBankNumber(iBank)); + return 0; +} + +/* + * ATIMach64SetReadWritePacked -- + * + * Set read and write bank numbers for small dual paged apertures. + */ +int +ATIMach64SetReadWritePacked +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIMach64SetBankPacked(ATIPTR(XF86SCRNINFO(pScreen)), iBank); + return 0; +} + +static CARD32 +ATIMach64MassagePlanarBankNumber +( + CARD8 iBank +) +{ + iBank <<= 3; + return ((iBank + 4) << 16) | iBank; +} + +/* + * ATIMach64SetBankPlanar -- + * + * Set read and write bank numbers for small dual paged apertures. + */ +void +ATIMach64SetBankPlanar +( + ATIPtr pATI, + unsigned int iBank +) +{ + CARD32 tmp = ATIMach64MassagePlanarBankNumber(iBank); + + outr(MEM_VGA_RP_SEL, tmp); + outr(MEM_VGA_WP_SEL, tmp); +} + +/* + * ATIMach64SetReadPlanar -- + * + * Set read bank number for small dual paged apertures. + */ +int +ATIMach64SetReadPlanar +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIPtr pATI = ATIPTR(XF86SCRNINFO(pScreen)); + + outr(MEM_VGA_RP_SEL, ATIMach64MassagePlanarBankNumber(iBank)); + return 0; +} + +/* + * ATIMach64SetWritePlanar -- + * + * Set write bank number for small dual paged apertures. + */ +int +ATIMach64SetWritePlanar +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIPtr pATI = ATIPTR(XF86SCRNINFO(pScreen)); + + outr(MEM_VGA_WP_SEL, ATIMach64MassagePlanarBankNumber(iBank)); + return 0; +} + +/* + * ATIMach64SetReadWritePlanar -- + * + * Set read and write bank numbers for small dual paged apertures. + */ +int +ATIMach64SetReadWritePlanar +( + ScreenPtr pScreen, + unsigned int iBank +) +{ + ATIMach64SetBankPlanar(ATIPTR(XF86SCRNINFO(pScreen)), iBank); + return 0; +} + +#endif /* AVOID_CPIO */ diff --git a/src/atibank.h b/src/atibank.h new file mode 100644 index 0000000..071dc22 --- /dev/null +++ b/src/atibank.h @@ -0,0 +1,88 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atibank.h,v 1.8 2003/01/01 19:16:30 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIBANK_H___ +#define ___ATIBANK_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "mibank.h" + +#ifndef AVOID_CPIO + +/* + * Banking definitions. + */ + +/* + * Bank selection function for VGA Wonder V3 adapters (which are + * single-banked). + */ +#define ATIV3SetRead ATIV3SetReadWrite +#define ATIV3SetWrite ATIV3SetReadWrite +extern miBankProc ATIV3SetReadWrite; + +/* + * Bank selection functions for VGA Wonder V4 and V5 adapters. + */ +extern miBankProc ATIV4V5SetRead, + ATIV4V5SetWrite, + ATIV4V5SetReadWrite; + +/* + * Bank selection functions for 28800-x, 68800-x and 88800 based adapters. + */ +extern miBankProc ATIx8800SetRead, + ATIx8800SetWrite, + ATIx8800SetReadWrite; + +/* + * Bank selection functions used to simulate a banked VGA aperture with a + * Mach64's small dual paged apertures. There are two sets of these: one for + * packed modes, and one for planar modes. + */ +extern miBankProc ATIMach64SetReadPacked, + ATIMach64SetWritePacked, + ATIMach64SetReadWritePacked; +extern miBankProc ATIMach64SetReadPlanar, + ATIMach64SetWritePlanar, + ATIMach64SetReadWritePlanar; + +/* + * The CRT save/restore code also needs a separate banking interface that can + * used before ATIScreenInit() is called. + */ + +typedef void ATIBankProc FunctionPrototype((ATIPtr, unsigned int)); +typedef ATIBankProc *ATIBankProcPtr; + +extern ATIBankProc ATIV3SetBank, + ATIV4V5SetBank, + ATIx8800SetBank, + ATIMach64SetBankPacked, + ATIMach64SetBankPlanar; + +#endif /* AVOID_CPIO */ + +#endif /* ___ATIBANK_H___ */ diff --git a/src/atibus.c b/src/atibus.c new file mode 100644 index 0000000..9eb099c --- /dev/null +++ b/src/atibus.c @@ -0,0 +1,183 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atibus.c,v 1.18 2003/01/22 21:44:10 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atibus.h" +#include "atichip.h" +#include "atiio.h" +#include "atistruct.h" +#include "ativersion.h" + +/* + * Definitions related to an adapter's system bus interface. + */ + +const char *ATIBusNames[] = +{ + "16-Bit ISA", + "EISA", + "16-Bit MicroChannel", + "32-Bit MicroChannel", + "386SX Local Bus", + "386DX Local Bus", + "VESA Local Bus", + "PCI", + "AGP" +}; + +/* + * ATIClaimResources -- + * + * This function registers most of the bus resources used by an adapter. The + * exceptions are PCI-configured resources and non-PCI non-AGP linear + * apertures, both of which are registered by ATIPreInit(). This function also + * attempts to register unshareable resources for inactive PCI adapters, + * whether or not they are relocatable. + */ +static void +ATIClaimResources +( + ATIPtr pATI, + Bool Active +) +{ + resPtr pResources; + +#ifndef AVOID_CPIO + + resRange Resources[2] = {{0, 0, 0}, _END}; + + /* Claim VGA and VGAWonder resources */ + if ((pATI->VGAAdapter != ATI_ADAPTER_NONE) && (Active || !pATI->SharedVGA)) + { + /* + * 18800-x's are the only ATI controllers that decode all ISA aliases + * of VGA and VGA Wonder I/O ports. Other x8800's do not decode >any< + * VGA aliases, but do decode VGA Wonder aliases whose most significant + * nibble is zero. + */ + xf86ClaimFixedResources( + (pATI->Chip <= ATI_CHIP_18800_1) ? + (pATI->SharedVGA ? resVgaSparseShared : resVgaSparseExclusive) : + (pATI->SharedVGA ? resVgaShared : resVgaExclusive), + pATI->iEntity); + + if (pATI->CPIO_VGAWonder) + { + if (pATI->SharedVGA) + Resources[0].type = ResShrIoSparse | ResBus; + else + Resources[0].type = ResExcIoSparse | ResBus; + Resources[0].rBase = pATI->CPIO_VGAWonder; + if (pATI->Chip <= ATI_CHIP_18800_1) + Resources[0].rMask = 0x03FEU; + else + Resources[0].rMask = 0xF3FEU; + + xf86ClaimFixedResources(Resources, pATI->iEntity); + + (void)memcpy(pATI->VGAWonderResources, + Resources, SizeOf(Resources)); + } + } + + if (!Active && pATI->SharedAccelerator) + return; + + /* Claim 8514/A resources */ + if (pATI->ChipHasSUBSYS_CNTL) + xf86ClaimFixedResources( + pATI->SharedAccelerator ? res8514Shared : res8514Exclusive, + pATI->iEntity); + + /* Claim Mach64 sparse I/O resources */ + if ((pATI->Adapter == ATI_ADAPTER_MACH64) && + (pATI->CPIODecoding == SPARSE_IO)) + { + if (pATI->SharedAccelerator) + Resources[0].type = ResShrIoSparse | ResBus; + else + Resources[0].type = ResExcIoSparse | ResBus; + Resources[0].rBase = pATI->CPIOBase; + Resources[0].rMask = 0x03FCU; + + xf86ClaimFixedResources(Resources, pATI->iEntity); + } + + if (Active) + return; + +#else /* AVOID_CPIO */ + + if (pATI->SharedAccelerator) + return; + +#endif /* AVOID_CPIO */ + + /* Register unshared relocatable resources for inactive adapters */ + do + { + pResources = xf86RegisterResources(pATI->iEntity, NULL, ResExclusive); + if (!pResources) + return; + + pResources = xf86ReallocatePciResources(pATI->iEntity, pResources); + } while (!pResources); + + xf86Msg(X_WARNING, + ATI_NAME ": Unable to register the following resources for inactive" + " adapter:\n"); + xf86PrintResList(1, pResources); + xf86FreeResList(pResources); +} + +/* + * ATIClaimBusSlot -- + * + * Claim an adapter and register its resources. + */ +int +ATIClaimBusSlot +( + DriverPtr pDriver, + int Chipset, + GDevPtr pGDev, + Bool Active, + ATIPtr pATI +) +{ + pciVideoPtr pVideo = pATI->PCIInfo; + + if (pVideo) + pATI->iEntity = + xf86ClaimPciSlot(pVideo->bus, pVideo->device, pVideo->func, + pDriver, Chipset, pGDev, Active); + else + pATI->iEntity = xf86ClaimIsaSlot(pDriver, Chipset, pGDev, Active); + + if (pATI->iEntity >= 0) + ATIClaimResources(pATI, Active); + + return pATI->iEntity; +} diff --git a/src/atibus.h b/src/atibus.h new file mode 100644 index 0000000..44dcc72 --- /dev/null +++ b/src/atibus.h @@ -0,0 +1,59 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atibus.h,v 1.11 2003/01/01 19:16:30 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIBUS_H___ + +#if !defined(___ATI_H___) && defined(XFree86Module) +# error missing #include "ati.h" before #include "atibus.h" +# undef XFree86Module +#endif + +#define ___ATIBUS_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +/* + * Definitions related to an adapter's system bus interface. + */ +typedef enum +{ + ATI_BUS_ISA = 0, + ATI_BUS_EISA, + ATI_BUS_MCA16, + ATI_BUS_MCA32, + ATI_BUS_SXLB, + ATI_BUS_DXLB, + ATI_BUS_VLB, + ATI_BUS_PCI, + ATI_BUS_AGP +} ATIBusType; + +extern const char *ATIBusNames[]; + +extern int ATIClaimBusSlot FunctionPrototype((DriverPtr, int, GDevPtr, Bool, + ATIPtr)); + +#endif /* ___ATIBUS_H___ */ diff --git a/src/atichip.c b/src/atichip.c new file mode 100644 index 0000000..4d4861b --- /dev/null +++ b/src/atichip.c @@ -0,0 +1,747 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atichip.c,v 1.38tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atibus.h" +#include "atichip.h" +#include "atimach64io.h" +#include "ativersion.h" + +/* + * Chip-related definitions. + */ +const char *ATIChipNames[] = +{ + "Unknown", + +#ifndef AVOID_CPIO + + "IBM VGA or compatible", + "ATI 18800", + "ATI 18800-1", + "ATI 28800-2", + "ATI 28800-4", + "ATI 28800-5", + "ATI 28800-6", + "IBM 8514/A", + "Chips & Technologies 82C480", + "ATI 38800-1", + "ATI 68800", + "ATI 68800-3", + "ATI 68800-6", + "ATI 68800LX", + "ATI 68800AX", + +#endif /* AVOID_CPIO */ + + "ATI 88800GX-C", + "ATI 88800GX-D", + "ATI 88800GX-E", + "ATI 88800GX-F", + "ATI 88800GX", + "ATI 88800CX", + "ATI 264CT", + "ATI 264ET", + "ATI 264VT", + "ATI 3D Rage", + "ATI 264VT-B", + "ATI 3D Rage II", + "ATI 264VT3", + "ATI 3D Rage II+DVD", + "ATI 3D Rage LT", + "ATI 264VT4", + "ATI 3D Rage IIc", + "ATI 3D Rage Pro", + "ATI 3D Rage LT Pro", + "ATI 3D Rage XL or XC", + "ATI 3D Rage Mobility", + "ATI unknown Mach64", + "ATI Rage 128 GL", + "ATI Rage 128 VR", + "ATI Rage 128 Pro GL", + "ATI Rage 128 Pro VR", + "ATI Rage 128 Pro ULTRA", + "ATI Rage 128 Mobility M3", + "ATI Rage 128 Mobility M4", + "ATI unknown Rage 128" + "ATI Radeon 7200", + "ATI Radeon 7000 (VE)", + "ATI Radeon Mobility M6", + "ATI Radeon IGP320", + "ATI Radeon IGP330/340/350", + "ATI Radeon 7000 IGP", + "ATI Radeon 7500", + "ATI Radeon Mobility M7", + "ATI Radeon 8500/9100", + "ATI Radeon 9000", + "ATI Radeon Mobility M9", + "ATI Radeon 9000 IGP", + "ATI Radeon 9200", + "ATI Radeon Mobility M9+", + "ATI Radeon 9700/9500", + "ATI Radeon 9600", + "ATI Radeon 9800", + "ATI Radeon 9800XT", + "ATI unknown Radeon", + "ATI Rage HDTV" +}; + +const char *ATIFoundryNames[] = + { "SGS", "NEC", "KCS", "UMC", "TSMC", "5", "6", "UMC" }; + +#ifndef AVOID_CPIO + +/* + * ATIMach32ChipID -- + * + * Set variables whose value is dependent upon an 68800's CHIP_ID register. + */ +void +ATIMach32ChipID +( + ATIPtr pATI +) +{ + CARD16 IOValue = inw(CHIP_ID); + pATI->ChipType = GetBits(IOValue, CHIP_CODE_0 | CHIP_CODE_1); + pATI->ChipClass = GetBits(IOValue, CHIP_CLASS); + pATI->ChipRevision = GetBits(IOValue, CHIP_REV); + pATI->ChipRev = pATI->ChipRevision; + if (IOValue == 0xFFFFU) + IOValue = 0; + switch (GetBits(IOValue, CHIP_CODE_0 | CHIP_CODE_1)) + { + case OldChipID('A', 'A'): + pATI->Chip = ATI_CHIP_68800_3; + break; + + case OldChipID('X', 'X'): + pATI->Chip = ATI_CHIP_68800_6; + break; + + case OldChipID('L', 'X'): + pATI->Chip = ATI_CHIP_68800LX; + break; + + case OldChipID('A', 'X'): + pATI->Chip = ATI_CHIP_68800AX; + break; + + default: + pATI->Chip = ATI_CHIP_68800; + break; + } +} + +#endif /* AVOID_CPIO */ + +/* + * ATIMach64ChipID -- + * + * Set variables whose value is dependent upon a Mach64's CONFIG_CHIP_ID + * register. + */ +void +ATIMach64ChipID +( + ATIPtr pATI, + const CARD16 ExpectedChipType +) +{ + pATI->config_chip_id = inr(CONFIG_CHIP_ID); + pATI->ChipType = GetBits(pATI->config_chip_id, 0xFFFFU); + pATI->ChipClass = GetBits(pATI->config_chip_id, CFG_CHIP_CLASS); + pATI->ChipRevision = GetBits(pATI->config_chip_id, CFG_CHIP_REV); + pATI->ChipVersion = GetBits(pATI->config_chip_id, CFG_CHIP_VERSION); + pATI->ChipFoundry = GetBits(pATI->config_chip_id, CFG_CHIP_FOUNDRY); + pATI->ChipRev = pATI->ChipRevision; + switch (pATI->ChipType) + { + case OldChipID('G', 'X'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'X'): + switch (pATI->ChipRevision) + { + case 0x00U: + pATI->Chip = ATI_CHIP_88800GXC; + break; + + case 0x01U: + pATI->Chip = ATI_CHIP_88800GXD; + break; + + case 0x02U: + pATI->Chip = ATI_CHIP_88800GXE; + break; + + case 0x03U: + pATI->Chip = ATI_CHIP_88800GXF; + break; + + default: + pATI->Chip = ATI_CHIP_88800GX; + break; + } + break; + + case OldChipID('C', 'X'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('C', 'X'): + pATI->Chip = ATI_CHIP_88800CX; + break; + + case OldChipID('C', 'T'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('C', 'T'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264CT; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('E', 'T'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('E', 'T'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264ET; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('V', 'T'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('V', 'T'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264VT; + pATI->BusType = ATI_BUS_PCI; + /* Some early GT's are detected as VT's */ + if (ExpectedChipType && (pATI->ChipType != ExpectedChipType)) + { + if (ExpectedChipType == NewChipID('G', 'T')) + pATI->Chip = ATI_CHIP_264GT; + else + xf86Msg(X_WARNING, + ATI_NAME ": Mach64 chip type probe discrepancy" + " detected: PCI=0x%04X; CHIP_ID=0x%04X.\n", + ExpectedChipType, pATI->ChipType); + } + else if (pATI->ChipVersion) + pATI->Chip = ATI_CHIP_264VTB; + break; + + case OldChipID('G', 'T'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'T'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->BusType = ATI_BUS_PCI; + if (!pATI->ChipVersion) + pATI->Chip = ATI_CHIP_264GT; + else + pATI->Chip = ATI_CHIP_264GTB; + break; + + case OldChipID('V', 'U'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('V', 'U'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264VT3; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('G', 'U'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'U'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264GTDVD; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('L', 'G'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('L', 'G'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264LT; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('V', 'V'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('V', 'V'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264VT4; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('G', 'V'): + case OldChipID('G', 'Y'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'V'): + case NewChipID('G', 'Y'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264GT2C; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('G', 'W'): + case OldChipID('G', 'Z'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'W'): + case NewChipID('G', 'Z'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264GT2C; + pATI->BusType = ATI_BUS_AGP; + break; + + case OldChipID('G', 'I'): + case OldChipID('G', 'P'): + case OldChipID('G', 'Q'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'I'): + case NewChipID('G', 'P'): + case NewChipID('G', 'Q'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264GTPRO; + pATI->BusType = ATI_BUS_PCI; + break; + + case OldChipID('G', 'B'): + case OldChipID('G', 'D'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'B'): + case NewChipID('G', 'D'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264GTPRO; + pATI->BusType = ATI_BUS_AGP; + break; + + case OldChipID('L', 'I'): + case OldChipID('L', 'P'): + case OldChipID('L', 'Q'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('L', 'I'): + case NewChipID('L', 'P'): + case NewChipID('L', 'Q'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264LTPRO; + pATI->BusType = ATI_BUS_PCI; + pATI->LCDVBlendFIFOSize = 800; + break; + + case OldChipID('L', 'B'): + case OldChipID('L', 'D'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('L', 'B'): + case NewChipID('L', 'D'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264LTPRO; + pATI->BusType = ATI_BUS_AGP; + pATI->LCDVBlendFIFOSize = 800; + break; + + case OldChipID('G', 'L'): + case OldChipID('G', 'O'): + case OldChipID('G', 'R'): + case OldChipID('G', 'S'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'L'): + case NewChipID('G', 'O'): + case NewChipID('G', 'R'): + case NewChipID('G', 'S'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264XL; + pATI->BusType = ATI_BUS_PCI; + pATI->LCDVBlendFIFOSize = 1024; + break; + + case OldChipID('G', 'M'): + case OldChipID('G', 'N'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('G', 'M'): + case NewChipID('G', 'N'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_264XL; + pATI->BusType = ATI_BUS_AGP; + pATI->LCDVBlendFIFOSize = 1024; + break; + + case OldChipID('L', 'R'): + case OldChipID('L', 'S'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('L', 'R'): + case NewChipID('L', 'S'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_MOBILITY; + pATI->BusType = ATI_BUS_PCI; + pATI->LCDVBlendFIFOSize = 1024; + break; + + case OldChipID('L', 'M'): + case OldChipID('L', 'N'): + pATI->ChipType = OldToNewChipID(pATI->ChipType); + case NewChipID('L', 'M'): + case NewChipID('L', 'N'): + pATI->ChipRevision = + GetBits(pATI->config_chip_id, CFG_CHIP_REVISION); + pATI->Chip = ATI_CHIP_MOBILITY; + pATI->BusType = ATI_BUS_AGP; + pATI->LCDVBlendFIFOSize = 1024; + break; + + default: + pATI->Chip = ATI_CHIP_Mach64; + break; + } +} + +/* + * ATIChipID -- + * + * This returns the ATI_CHIP_* value (generally) associated with a particular + * ChipID/ChipRev combination. + */ +ATIChipType +ATIChipID +( + const CARD16 ChipID, + const CARD8 ChipRev +) +{ + switch (ChipID) + { + +#ifndef AVOID_CPIO + + case OldChipID('A', 'A'): case NewChipID('A', 'A'): + return ATI_CHIP_68800_3; + + case OldChipID('X', 'X'): case NewChipID('X', 'X'): + return ATI_CHIP_68800_6; + + case OldChipID('L', 'X'): + return ATI_CHIP_68800LX; + + case OldChipID('A', 'X'): case NewChipID('A', 'X'): + return ATI_CHIP_68800AX; + +#endif /* AVOID_CPIO */ + + case OldChipID('G', 'X'): case NewChipID('G', 'X'): + switch (ChipRev) + { + case 0x00U: + return ATI_CHIP_88800GXC; + + case 0x01U: + return ATI_CHIP_88800GXD; + + case 0x02U: + return ATI_CHIP_88800GXE; + + case 0x03U: + return ATI_CHIP_88800GXF; + + default: + return ATI_CHIP_88800GX; + } + + case OldChipID('C', 'X'): case NewChipID('C', 'X'): + return ATI_CHIP_88800CX; + + case OldChipID('C', 'T'): case NewChipID('C', 'T'): + return ATI_CHIP_264CT; + + case OldChipID('E', 'T'): case NewChipID('E', 'T'): + return ATI_CHIP_264ET; + + case OldChipID('V', 'T'): case NewChipID('V', 'T'): + /* For simplicity, ignore ChipID discrepancy that can occur here */ + if (!(ChipRev & GetBits(CFG_CHIP_VERSION, CFG_CHIP_REV))) + return ATI_CHIP_264VT; + return ATI_CHIP_264VTB; + + case OldChipID('G', 'T'): case NewChipID('G', 'T'): + if (!(ChipRev & GetBits(CFG_CHIP_VERSION, CFG_CHIP_REV))) + return ATI_CHIP_264GT; + return ATI_CHIP_264GTB; + + case OldChipID('V', 'U'): case NewChipID('V', 'U'): + return ATI_CHIP_264VT3; + + case OldChipID('G', 'U'): case NewChipID('G', 'U'): + return ATI_CHIP_264GTDVD; + + case OldChipID('L', 'G'): case NewChipID('L', 'G'): + return ATI_CHIP_264LT; + + case OldChipID('V', 'V'): case NewChipID('V', 'V'): + return ATI_CHIP_264VT4; + + case OldChipID('G', 'V'): case NewChipID('G', 'V'): + case OldChipID('G', 'W'): case NewChipID('G', 'W'): + case OldChipID('G', 'Y'): case NewChipID('G', 'Y'): + case OldChipID('G', 'Z'): case NewChipID('G', 'Z'): + return ATI_CHIP_264GT2C; + + case OldChipID('G', 'B'): case NewChipID('G', 'B'): + case OldChipID('G', 'D'): case NewChipID('G', 'D'): + case OldChipID('G', 'I'): case NewChipID('G', 'I'): + case OldChipID('G', 'P'): case NewChipID('G', 'P'): + case OldChipID('G', 'Q'): case NewChipID('G', 'Q'): + return ATI_CHIP_264GTPRO; + + case OldChipID('L', 'B'): case NewChipID('L', 'B'): + case OldChipID('L', 'D'): case NewChipID('L', 'D'): + case OldChipID('L', 'I'): case NewChipID('L', 'I'): + case OldChipID('L', 'P'): case NewChipID('L', 'P'): + case OldChipID('L', 'Q'): case NewChipID('L', 'Q'): + return ATI_CHIP_264LTPRO; + + case OldChipID('G', 'L'): case NewChipID('G', 'L'): + case OldChipID('G', 'M'): case NewChipID('G', 'M'): + case OldChipID('G', 'N'): case NewChipID('G', 'N'): + case OldChipID('G', 'O'): case NewChipID('G', 'O'): + case OldChipID('G', 'R'): case NewChipID('G', 'R'): + case OldChipID('G', 'S'): case NewChipID('G', 'S'): + return ATI_CHIP_264XL; + + case OldChipID('L', 'M'): case NewChipID('L', 'M'): + case OldChipID('L', 'N'): case NewChipID('L', 'N'): + case OldChipID('L', 'R'): case NewChipID('L', 'R'): + case OldChipID('L', 'S'): case NewChipID('L', 'S'): + return ATI_CHIP_MOBILITY; + + case NewChipID('R', 'E'): + case NewChipID('R', 'F'): + case NewChipID('R', 'G'): + case NewChipID('S', 'K'): + case NewChipID('S', 'L'): + case NewChipID('S', 'M'): + /* "SN" is listed as ATI_CHIP_RAGE128_4X in ATI docs */ + case NewChipID('S', 'N'): + return ATI_CHIP_RAGE128GL; + + case NewChipID('R', 'K'): + case NewChipID('R', 'L'): + /* + * ATI documentation lists SE/SF/SG under both ATI_CHIP_RAGE128VR + * and ATI_CHIP_RAGE128_4X, and lists SH/SK/SL under Rage 128 4X only. + * I'm stuffing them here for now until this can be clarified as ATI + * documentation doesn't mention their details. <mharris@redhat.com> + */ + case NewChipID('S', 'E'): + case NewChipID('S', 'F'): + case NewChipID('S', 'G'): + case NewChipID('S', 'H'): + return ATI_CHIP_RAGE128VR; + + /* case NewChipID('S', 'H'): */ + /* case NewChipID('S', 'K'): */ + /* case NewChipID('S', 'L'): */ + /* case NewChipID('S', 'N'): */ + /* return ATI_CHIP_RAGE128_4X; */ + + case NewChipID('P', 'A'): + case NewChipID('P', 'B'): + case NewChipID('P', 'C'): + case NewChipID('P', 'D'): + case NewChipID('P', 'E'): + case NewChipID('P', 'F'): + return ATI_CHIP_RAGE128PROGL; + + case NewChipID('P', 'G'): + case NewChipID('P', 'H'): + case NewChipID('P', 'I'): + case NewChipID('P', 'J'): + case NewChipID('P', 'K'): + case NewChipID('P', 'L'): + case NewChipID('P', 'M'): + case NewChipID('P', 'N'): + case NewChipID('P', 'O'): + case NewChipID('P', 'P'): + case NewChipID('P', 'Q'): + case NewChipID('P', 'R'): + case NewChipID('P', 'S'): + case NewChipID('P', 'T'): + case NewChipID('P', 'U'): + case NewChipID('P', 'V'): + case NewChipID('P', 'W'): + case NewChipID('P', 'X'): + return ATI_CHIP_RAGE128PROVR; + + case NewChipID('T', 'F'): + case NewChipID('T', 'L'): + case NewChipID('T', 'R'): + case NewChipID('T', 'S'): + case NewChipID('T', 'T'): + case NewChipID('T', 'U'): + return ATI_CHIP_RAGE128PROULTRA; + + case NewChipID('L', 'E'): + case NewChipID('L', 'F'): + /* + * "LK" and "LL" are not in any ATI documentation I can find + * - mharris + */ + case NewChipID('L', 'K'): + case NewChipID('L', 'L'): + return ATI_CHIP_RAGE128MOBILITY3; + + case NewChipID('M', 'F'): + case NewChipID('M', 'L'): + return ATI_CHIP_RAGE128MOBILITY4; + + case NewChipID('Q', 'D'): + case NewChipID('Q', 'E'): + case NewChipID('Q', 'F'): + case NewChipID('Q', 'G'): + return ATI_CHIP_RADEON; + + case NewChipID('Q', 'Y'): + case NewChipID('Q', 'Z'): + return ATI_CHIP_RADEONVE; + + case NewChipID('L', 'Y'): + case NewChipID('L', 'Z'): + return ATI_CHIP_RADEONMOBILITY6; + + case NewChipID('A', '6'): + case NewChipID('C', '6'): + return ATI_CHIP_RS100; + + case NewChipID('A', '7'): + case NewChipID('C', '7'): + return ATI_CHIP_RS200; + + case NewChipID('D', '7'): + case NewChipID('B', '7'): + return ATI_CHIP_RS250; + + case NewChipID('L', 'W'): + case NewChipID('L', 'X'): + return ATI_CHIP_RADEONMOBILITY7; + + case NewChipID('Q', 'H'): + case NewChipID('Q', 'I'): + case NewChipID('Q', 'J'): + case NewChipID('Q', 'K'): + case NewChipID('Q', 'L'): + case NewChipID('Q', 'M'): + case NewChipID('Q', 'N'): + case NewChipID('Q', 'O'): + case NewChipID('Q', 'h'): + case NewChipID('Q', 'i'): + case NewChipID('Q', 'j'): + case NewChipID('Q', 'k'): + case NewChipID('Q', 'l'): + case NewChipID('B', 'B'): + return ATI_CHIP_R200; + + case NewChipID('Q', 'W'): + case NewChipID('Q', 'X'): + return ATI_CHIP_RV200; + + case NewChipID('I', 'f'): + case NewChipID('I', 'g'): + return ATI_CHIP_RV250; + + case NewChipID('L', 'd'): + case NewChipID('L', 'f'): + case NewChipID('L', 'g'): + return ATI_CHIP_RADEONMOBILITY9; + + case NewChipID('X', '4'): + case NewChipID('X', '5'): + return ATI_CHIP_RS300; + + case NewChipID('Y', '\''): + case NewChipID('Y', 'a'): + case NewChipID('Y', 'b'): + case NewChipID('Y', 'd'): + return ATI_CHIP_RV280; + + case NewChipID('\\', 'a'): + case NewChipID('\\', 'c'): + return ATI_CHIP_RADEONMOBILITY9PLUS; + + case NewChipID('A', 'D'): + case NewChipID('A', 'E'): + case NewChipID('A', 'F'): + case NewChipID('A', 'G'): + case NewChipID('N', 'D'): + case NewChipID('N', 'E'): + case NewChipID('N', 'F'): + case NewChipID('N', 'G'): + return ATI_CHIP_R300; + + case NewChipID('A', 'H'): + case NewChipID('A', 'I'): + case NewChipID('A', 'J'): + case NewChipID('A', 'K'): + case NewChipID('N', 'H'): + case NewChipID('N', 'I'): + case NewChipID('N', 'K'): + return ATI_CHIP_R350; + + case NewChipID('A', 'P'): + case NewChipID('A', 'Q'): + case NewChipID('A', 'R'): + case NewChipID('A', 'S'): + case NewChipID('A', 'T'): + case NewChipID('A', 'V'): + case NewChipID('N', 'P'): + case NewChipID('N', 'Q'): + case NewChipID('N', 'R'): + case NewChipID('N', 'S'): + case NewChipID('N', 'T'): + case NewChipID('N', 'V'): + return ATI_CHIP_RV350; + + case NewChipID('N', 'J'): + return ATI_CHIP_R360; + + case NewChipID('H', 'D'): + return ATI_CHIP_HDTV; + + default: + /* + * Treat anything else as an unknown Radeon. Please keep the above + * up-to-date however, as it serves as a central chip list. + */ + return ATI_CHIP_Radeon; + } +} diff --git a/src/atichip.h b/src/atichip.h new file mode 100644 index 0000000..e47947d --- /dev/null +++ b/src/atichip.h @@ -0,0 +1,154 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atichip.h,v 1.26tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATICHIP_H___ +#define ___ATICHIP_H___ 1 + +#include "atipriv.h" +#include "atiregs.h" + +#include "Xmd.h" + +/* + * Chip-related definitions. + */ +typedef enum +{ + ATI_CHIP_NONE = 0, + +#ifndef AVOID_CPIO + + ATI_CHIP_VGA, /* Generic VGA */ + ATI_CHIP_18800, + ATI_CHIP_18800_1, + ATI_CHIP_28800_2, + ATI_CHIP_28800_4, + ATI_CHIP_28800_5, + ATI_CHIP_28800_6, + ATI_CHIP_8514A, /* 8514/A */ + ATI_CHIP_CT480, /* 8514/A clone */ + ATI_CHIP_38800_1, /* Mach8 */ + ATI_CHIP_68800, /* Mach32 */ + ATI_CHIP_68800_3, /* Mach32 */ + ATI_CHIP_68800_6, /* Mach32 */ + ATI_CHIP_68800LX, /* Mach32 */ + ATI_CHIP_68800AX, /* Mach32 */ + +#endif /* AVOID_CPIO */ + + ATI_CHIP_88800GXC, /* Mach64 */ + ATI_CHIP_88800GXD, /* Mach64 */ + ATI_CHIP_88800GXE, /* Mach64 */ + ATI_CHIP_88800GXF, /* Mach64 */ + ATI_CHIP_88800GX, /* Mach64 */ + ATI_CHIP_88800CX, /* Mach64 */ + ATI_CHIP_264CT, /* Mach64 */ + ATI_CHIP_264ET, /* Mach64 */ + ATI_CHIP_264VT, /* Mach64 */ + ATI_CHIP_264GT, /* Mach64 */ + ATI_CHIP_264VTB, /* Mach64 */ + ATI_CHIP_264GTB, /* Mach64 */ + ATI_CHIP_264VT3, /* Mach64 */ + ATI_CHIP_264GTDVD, /* Mach64 */ + ATI_CHIP_264LT, /* Mach64 */ + ATI_CHIP_264VT4, /* Mach64 */ + ATI_CHIP_264GT2C, /* Mach64 */ + ATI_CHIP_264GTPRO, /* Mach64 */ + ATI_CHIP_264LTPRO, /* Mach64 */ + ATI_CHIP_264XL, /* Mach64 */ + ATI_CHIP_MOBILITY, /* Mach64 */ + ATI_CHIP_Mach64, /* Last among Mach64's */ + ATI_CHIP_RAGE128GL, /* Rage128 */ + ATI_CHIP_RAGE128VR, /* Rage128 */ + ATI_CHIP_RAGE128PROGL, /* Rage128 */ + ATI_CHIP_RAGE128PROVR, /* Rage128 */ + ATI_CHIP_RAGE128PROULTRA, /* Rage128 */ + ATI_CHIP_RAGE128MOBILITY3, /* Rage128 */ + ATI_CHIP_RAGE128MOBILITY4, /* Rage128 */ + ATI_CHIP_Rage128, /* Last among Rage128's */ + ATI_CHIP_RADEON, /* Radeon */ + ATI_CHIP_RADEONVE, /* Radeon VE */ + ATI_CHIP_RADEONMOBILITY6, /* Radeon M6 */ + ATI_CHIP_RS100, /* IGP320 */ + ATI_CHIP_RS200, /* IGP340 */ + ATI_CHIP_RS250, /* Radoen 7000 IGP */ + ATI_CHIP_RV200, /* RV200 */ + ATI_CHIP_RADEONMOBILITY7, /* Radeon M7 */ + ATI_CHIP_R200, /* R200 */ + ATI_CHIP_RV250, /* RV250 */ + ATI_CHIP_RADEONMOBILITY9, /* Radeon M9 */ + ATI_CHIP_RS300, /* Radoen 9000 IGP */ + ATI_CHIP_RV280, /* RV250 */ + ATI_CHIP_RADEONMOBILITY9PLUS, /* Radeon M9+ */ + ATI_CHIP_R300, /* R300 */ + ATI_CHIP_RV350, /* RV350 */ + ATI_CHIP_R350, /* R350 */ + ATI_CHIP_R360, /* R360 */ + ATI_CHIP_Radeon, /* Last among Radeon's */ + ATI_CHIP_HDTV /* HDTV */ +} ATIChipType; + +extern const char *ATIChipNames[]; + +/* + * Foundry codes for 264xT's. + */ +typedef enum +{ + ATI_FOUNDRY_SGS, /* SGS-Thompson */ + ATI_FOUNDRY_NEC, /* NEC */ + ATI_FOUNDRY_KSC, /* KSC (?) */ + ATI_FOUNDRY_UMC, /* United Microelectronics Corporation */ + ATI_FOUNDRY_TSMC, /* Taiwan Semiconductor Manufacturing Company */ + ATI_FOUNDRY_5, + ATI_FOUNDRY_6, + ATI_FOUNDRY_UMCA /* UMC alternate */ +} ATIFoundryType; + +extern const char *ATIFoundryNames[]; + +#ifndef AVOID_CPIO + +extern void ATIMach32ChipID FunctionPrototype((ATIPtr)); + +#endif /* AVOID_CPIO */ + +extern void ATIMach64ChipID FunctionPrototype((ATIPtr, const CARD16)); +extern ATIChipType ATIChipID FunctionPrototype((const CARD16, + const CARD8)); + +#define OldChipID(_1, _0) \ + (SetBits(_0 - 'A', CHIP_CODE_0) | SetBits(_1 - 'A', CHIP_CODE_1)) + +#define NewChipID(_1, _0) \ + (SetBits(_0, CFG_CHIP_TYPE0) | SetBits(_1, CFG_CHIP_TYPE1)) + +#define OldToNewChipID(_ChipID) \ + (SetBits(GetBits(_ChipID, CHIP_CODE_0) + 'A', CFG_CHIP_TYPE0) | \ + SetBits(GetBits(_ChipID, CHIP_CODE_1) + 'A', CFG_CHIP_TYPE1)) + +#define NewToOldChipID(_ChipID) \ + (SetBits(GetBits(_ChipID, CFG_CHIP_TYPE0) - 'A', CHIP_CODE_0) | \ + (SetBits(GetBits(_ChipID, CFG_CHIP_TYPE1) - 'A', CHIP_CODE_1)) + +#endif /* ___ATICHIP_H___ */ diff --git a/src/aticlock.c b/src/aticlock.c new file mode 100644 index 0000000..89a4180 --- /dev/null +++ b/src/aticlock.c @@ -0,0 +1,1608 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticlock.c,v 1.21 2003/04/23 21:51:27 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +/* + * Adapters prior to V5 use 4 crystals. Adapters V5 and later use a clock + * generator chip. V3 and V4 adapters differ when it comes to choosing clock + * frequencies. + * + * VGA Wonder V3/V4 Adapter Clock Frequencies + * R E G I S T E R S + * 1CE(*) 3C2 3C2 Frequency + * B2h/BEh + * Bit 6/4 Bit 3 Bit 2 (MHz) + * ------- ------- ------- ------- + * 0 0 0 50.000 + * 0 0 1 56.644 + * 0 1 0 Spare 1 + * 0 1 1 44.900 + * 1 0 0 44.900 + * 1 0 1 50.000 + * 1 1 0 Spare 2 + * 1 1 1 36.000 + * + * (*): V3 uses index B2h, bit 6; V4 uses index BEh, bit 4 + * + * V5, PLUS, XL and XL24 usually have an ATI 18810 clock generator chip, but + * some have an ATI 18811-0, and it's quite conceivable that some exist with + * ATI 18811-1's or ATI 18811-2's. Mach32 adapters are known to use any one of + * these clock generators. Mach32 adapters also use a different dot clock + * ordering. ATI says there is no reliable way for the driver to determine + * which clock generator is on the adapter, but this driver will do its best to + * do so anyway. + * + * VGA Wonder V5/PLUS/XL/XL24 Clock Frequencies + * R E G I S T E R S + * 1CE 1CE 3C2 3C2 Frequency + * B9h BEh (MHz) 18811-0 18811-1 + * Bit 1 Bit 4 Bit 3 Bit 2 18810 18812-0 18811-2 (*5) + * ------- ------- ------- ------- ------- ------- ------- ------- + * 0 0 0 0 30.240 30.240 135.000 75.000 + * 0 0 0 1 32.000 32.000 32.000 77.500 + * 0 0 1 0 37.500 110.000 110.000 80.000 + * 0 0 1 1 39.000 80.000 80.000 90.000 + * 0 1 0 0 42.954 42.954 100.000 25.175 + * 0 1 0 1 48.771 48.771 126.000 28.322 + * 0 1 1 0 (*1) 92.400 92.400 31.500 + * 0 1 1 1 36.000 36.000 36.000 36.000 + * 1 0 0 0 40.000 39.910 39.910 100.000 + * 1 0 0 1 (*4) 44.900 44.900 110.000 + * 1 0 1 0 75.000 75.000 75.000 126.000 + * 1 0 1 1 65.000 65.000 65.000 135.000 + * 1 1 0 0 50.350 50.350 50.350 40.000 + * 1 1 0 1 56.640 56.640 56.640 44.900 + * 1 1 1 0 (*2) (*3) (*3) 50.000 + * 1 1 1 1 44.900 44.900 44.900 65.000 + * + * (*1) External 0 (supposedly 16.657 Mhz) + * (*2) External 1 (supposedly 28.322 MHz) + * (*3) This setting doesn't seem to generate anything + * (*4) This setting is documented to be 56.644 MHz, but something close to 82 + * MHz has also been encountered. + * (*5) This setting is for Dell OmniPlex 590 systems, with a 68800AX on the + * motherboard, along with an AT&T21C498 DAC (which is reported as an + * STG1700) and ICS2494AM clock generator (a.k.a. ATI 18811-?). + * + * Mach32 Clock Frequencies + * R E G I S T E R S + * 1CE 1CE 3C2 3C2 Frequency + * B9h BEh (MHz) 18811-0 18811-1 + * Bit 1 Bit 4 Bit 3 Bit 2 18810 18812-0 18811-2 (*5) + * ------- ------- ------- ------- ------- ------- ------- ------- + * 0 0 0 0 42.954 42.954 100.000 25.175 + * 0 0 0 1 48.771 48.771 126.000 28.322 + * 0 0 1 0 (*1) 92.400 92.400 31.500 + * 0 0 1 1 36.000 36.000 36.000 36.000 + * 0 1 0 0 30.240 30.240 135.000 75.000 + * 0 1 0 1 32.000 32.000 32.000 77.500 + * 0 1 1 0 37.500 110.000 110.000 80.000 + * 0 1 1 1 39.000 80.000 80.000 90.000 + * 1 0 0 0 50.350 50.350 50.350 40.000 + * 1 0 0 1 56.640 56.640 56.640 44.900 + * 1 0 1 0 (*2) (*3) (*3) 50.000 + * 1 0 1 1 44.900 44.900 44.900 65.000 + * 1 1 0 0 40.000 39.910 39.910 100.000 + * 1 1 0 1 (*4) 44.900 44.900 110.000 + * 1 1 1 0 75.000 75.000 75.000 126.000 + * 1 1 1 1 65.000 65.000 65.000 135.000 + * + * (*1) External 0 (supposedly 16.657 Mhz) + * (*2) External 1 (supposedly 28.322 MHz) + * (*3) This setting doesn't seem to generate anything + * (*4) This setting is documented to be 56.644 MHz, but something close to 82 + * MHz has also been encountered. + * (*5) This setting is for Dell OmniPlex 590 systems, with a 68800AX on the + * motherboard, along with an AT&T21C498 DAC (which is reported as an + * STG1700) and ICS2494AM clock generator (a.k.a. ATI 18811-?). + * + * Note that, to reduce confusion, this driver masks out the different clock + * ordering. + * + * For all adapters, these frequencies can be divided by 1 or 2. For all + * adapters, except Mach32's and Mach64's, frequencies can also be divided by 3 + * or 4. + * + * Register 1CE, index B8h + * Bit 7 Bit 6 + * ------- ------- + * 0 0 Divide by 1 + * 0 1 Divide by 2 + * 1 0 Divide by 3 + * 1 1 Divide by 4 + * + * With respect to clocks, Mach64's are entirely different animals. + * + * The oldest Mach64's use one of the non-programmable clock generators + * described above. In this case, the driver will handle clocks in much the + * same way as it would for a Mach32. + * + * All other Mach64 adapters use a programmable clock generator. BIOS + * initialisation programmes an initial set of frequencies. Two of these are + * reserved to allow for the setting of modes that do not use a frequency from + * this initial set. One of these reserved slots is used by the BIOS mode set + * routine, the other by the particular accelerated driver used (MS-Windows, + * AutoCAD, etc.). The slots reserved in this way are dependent on the + * particular clock generator used by the adapter. + * + * If the driver does not support the adapter's clock generator, it will try to + * match the (probed or specified) clocks to one of the following sets. + * + * Mach64 Clock Frequencies for unsupported programmable clock generators + * R E G I S T E R S + * 1CE 1CE 3C2 3C2 Frequency + * B9h BEh (MHz) + * Bit 1 Bit 4 Bit 3 Bit 2 Set 1 Set 2 Set 3 + * ------- ------- ------- ------- ------- ------- ------- + * 0 0 0 0 50.350 25.180 25.180 + * 0 0 0 1 56.640 28.320 28.320 + * 0 0 1 0 63.000 31.500 0.000 + * 0 0 1 1 72.000 36.000 0.000 + * 0 1 0 0 0.000 0.000 0.000 + * 0 1 0 1 110.000 110.000 0.000 + * 0 1 1 0 126.000 126.000 0.000 + * 0 1 1 1 135.000 135.000 0.000 + * 1 0 0 0 40.000 40.000 0.000 + * 1 0 0 1 44.900 44.900 0.000 + * 1 0 1 0 49.500 49.500 0.000 + * 1 0 1 1 50.000 50.000 0.000 + * 1 1 0 0 0.000 0.000 0.000 + * 1 1 0 1 80.000 80.000 0.000 + * 1 1 1 0 75.000 75.000 0.000 + * 1 1 1 1 65.000 65.000 0.000 + * + * The driver will never select a setting of 0.000 MHz. The above comments on + * clock ordering and clock divider apply here also. + * + * For all supported programmable clock generators, the driver will ignore any + * XF86Config clock line and programme, as needed, the clock number reserved by + * the BIOS for accelerated drivers. The driver's mode initialisation routine + * finds integers N, M and D such that + * + * N + * R * ------- MHz + * M * D + * + * best approximates the mode's clock frequency, where R is the crystal- + * generated reference frequency (usually 14.318 MHz). D is a power of 2 + * except for those integrated controllers that also offer odd dividers. + * Different clock generators have different restrictions on the value N, M and + * D can assume. The driver contains an internal table to record these + * restrictions (among other things). The resulting values of N, M and D are + * then encoded in a generator-specific way and used to programme the clock. + * The Mach64's clock divider is not used in this case. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atichip.h" +#include "atidac.h" +#include "atidsp.h" +#include "atimach64io.h" +#include "atimode.h" +#include "atiwonderio.h" + +/* + * Definitions related to non-programmable clock generators. + */ +const char *ATIClockNames[] = +{ + "unknown", + "IBM VGA compatible", + "crystals", + "ATI 18810 or similar", + "ATI 18811-0 or similar", + "ATI 18811-1 or similar", + "ICS 2494-AM or similar", + "Programmable (BIOS setting 1)", + "Programmable (BIOS setting 2)", + "Programmable (BIOS setting 3)" +}; + +/* + * Definitions related to programmable clock generators. + */ +static CARD16 ATIPostDividers[] = {1, 2, 4, 8, 16, 32, 64, 128}, + ATI264xTPostDividers[] = {1, 2, 4, 8, 3, 0, 6, 12}; +ClockRec ATIClockDescriptors[] = +{ + { + 0, 0, 0, 1, 1, + 1, 1, 0, + 0, NULL, + "Non-programmable" + }, + { + 257, 512, 257, 1, 1, + 46, 46, 0, + 4, ATIPostDividers, + "ATI 18818 or ICS 2595 or similar" + }, + { + 2, 129, 2, 1, 1, + 8, 14, 2, + 8, ATIPostDividers, + "SGS-Thompson 1703 or similar" + }, + { + 16, 263, 8, 8, 9, + 4, 12, 2, + 4, ATIPostDividers, + "Chrontel 8398 or similar" + }, + { + 2, 255, 0, 1, 1, + 45, 45, 0, + 4, ATI264xTPostDividers, + "Internal" + }, + { + 2, 257, 2, 1, 1, + 2, 32, 2, + 4, ATIPostDividers, + "AT&T 20C408 or similar" + }, + { + 65, 128, 65, 1, 1, + 2, 14, 0, + 4, ATIPostDividers, + "IBM RGB 514 or similar" + } +}; + +/* + * XF86Config clocks line that start with the following will either be rejected + * for ATI adapters, or accepted for non-ATI adapters. + */ +static const int +ATIVGAClocks[] = +{ + 25175, 28322, + -1 +}; + +/* + * The driver will attempt to match fixed clocks to one of the following + * specifications. + */ +static const int +ATICrystalFrequencies[] = +{ + 50000, 56644, 0, 44900, 44900, 50000, 0, 36000, + -1 +}, +ATI18810Frequencies[] = +{ + 30240, 32000, 37500, 39000, 42954, 48771, 0, 36000, + 40000, 0, 75000, 65000, 50350, 56640, 0, 44900 +}, +ATI188110Frequencies[] = +{ + 30240, 32000, 110000, 80000, 42954, 48771, 92400, 36000, + 39910, 44900, 75000, 65000, 50350, 56640, 0, 44900 +}, +ATI188111Frequencies[] = +{ + 135000, 32000, 110000, 80000, 100000, 126000, 92400, 36000, + 39910, 44900, 75000, 65000, 50350, 56640, 0, 44900 +}, +ATI2494AMFrequencies[] = +{ + 75000, 77500, 80000, 90000, 25175, 28322, 31500, 36000, + 100000, 110000, 126000, 135000, 40000, 44900, 50000, 65000 +}, +ATIMach64AFrequencies[] = +{ + 0, 110000, 126000, 135000, 50350, 56640, 63000, 72000, + 0, 80000, 75000, 65000, 40000, 44900, 49500, 50000 +}, +ATIMach64BFrequencies[] = +{ + 0, 110000, 126000, 135000, 25180, 28320, 31500, 36000, + 0, 80000, 75000, 65000, 40000, 44900, 49500, 50000 +}, +ATIMach64CFrequencies[] = +{ + 0, 0, 0, 0, 25180, 28320, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}, +*SpecificationClockLine[] = +{ + NULL, + ATIVGAClocks, + ATICrystalFrequencies, + ATI18810Frequencies, + ATI188110Frequencies, + ATI188111Frequencies, + ATI2494AMFrequencies, + ATIMach64AFrequencies, + ATIMach64BFrequencies, + ATIMach64CFrequencies, + NULL +}; + +/* + * The driver will reject XF86Config clocks lines that start with, or are an + * initial subset of, one of the following. + */ +static const int +ATIPre_2_1_1_Clocks_A[] = /* Based on 18810 */ +{ + 18000, 22450, 25175, 28320, 36000, 44900, 50350, 56640, + 30240, 32000, 37500, 39000, 40000, 0, 75000, 65000, + -1 +}, +ATIPre_2_1_1_Clocks_B[] = /* Based on 18811-0 */ +{ + 18000, 22450, 25175, 28320, 36000, 44900, 50350, 56640, + 30240, 32000, 110000, 80000, 39910, 44900, 75000, 65000, + -1 +}, +ATIPre_2_1_1_Clocks_C[] = /* Based on 18811-1 (or -2) */ +{ + 18000, 22450, 25175, 28320, 36000, 44900, 50350, 56640, + 135000, 32000, 110000, 80000, 39910, 44900, 75000, 65000, + -1 +}, +ATIPre_2_1_1_Clocks_D[] = /* Based on ICS 2494AM */ +{ + 18000, 32500, 20000, 22450, 36000, 65000, 40000, 44900, + 75000, 77500, 80000, 90000, 100000, 110000, 126000, 135000, + -1 +}, +ATIPre_2_1_1_Clocks_E[] = /* Based on programmable setting 1 */ +{ + 36000, 25000, 20000, 22450, 72000, 50000, 40000, 44900, + 0, 110000, 126000, 135000, 0, 80000, 75000, 65000, + -1 +}, +ATIPre_2_1_1_Clocks_F[] = /* Based on programmable setting 2 */ +{ + 18000, 25000, 20000, 22450, 36000, 50000, 40000, 44900, + 0, 110000, 126000, 135000, 0, 80000, 75000, 65000, + -1 +}, +*InvalidClockLine[] = +{ + NULL, + ATIVGAClocks, + ATIPre_2_1_1_Clocks_A, + ATIPre_2_1_1_Clocks_B, + ATIPre_2_1_1_Clocks_C, + ATIPre_2_1_1_Clocks_D, + ATIPre_2_1_1_Clocks_E, + ATIPre_2_1_1_Clocks_F, + NULL +}; + +/* + * Clock maps. + */ +static const CARD8 ClockMaps[][4] = +{ + /* Null map */ + { 0, 1, 2, 3}, + /* VGA Wonder map <-> Mach{8,32,64} */ + { 1, 0, 3, 2}, + /* VGA Wonder map <-> Accelerator */ + { 0, 2, 1, 3}, + /* VGA -> Accelerator map */ + { 2, 0, 3, 1}, + /* Accelerator -> VGA map */ + { 1, 3, 0, 2} +}; +#define ATIVGAWonderClockMap ClockMaps[0] +#define ATIVGAWonderClockUnmap ATIVGAWonderClockMap +#define ATIMachVGAClockMap ClockMaps[1] +#define ATIMachVGAClockUnmap ATIMachVGAClockMap +#define ATIVGAProgrammableClockMap ClockMaps[2] +#define ATIVGAProgrammableClockUnmap ATIVGAProgrammableClockMap +#define ATIAcceleratorClockMap ClockMaps[3] +#define ATIAcceleratorClockUnmap ClockMaps[4] +#define ATIProgrammableClockMap ClockMaps[0] +#define ATIProgrammableClockUnmap ATIProgrammableClockMap +#define MapClockIndex(_ClockMap, _Index) \ + (SetBits((_ClockMap)[GetBits(_Index, 0x0CU)], 0x0CU) | \ + ((_Index) & ~0x0CU)) + +/* + * ATIMatchClockLine -- + * + * This function tries to match the XF86Config clocks to one of an array of + * clock lines. It returns a clock line number or 0. + */ +static int +ATIMatchClockLine +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + const int **ClockLine, + const unsigned short int NumberOfClocks, + const int CalibrationClockNumber, + const int ClockMap +) +{ + int ClockChip = 0, ClockChipIndex = 0; + int NumberOfMatchingClocks = 0; + int MinimumGap = CLOCK_TOLERANCE + 1; + + /* For ATI adapters, reject generic VGA clocks */ + +#ifndef AVOID_CPIO + + if (pATI->Adapter != ATI_ADAPTER_VGA) + +#endif /* AVOID_CPIO */ + + { + if (ClockLine == SpecificationClockLine) + ClockChipIndex++; + } + + /* If checking for XF86Config clock order, skip crystals */ + if (ClockMap) + ClockChipIndex++; + + for (; ClockLine[++ClockChipIndex]; ) + { + int MaximumGap = 0, ClockCount = 0, ClockIndex = 0; + +#ifndef AVOID_CPIO + + /* Only Mach64's and later can have programmable clocks */ + if ((ClockChipIndex >= ATI_CLOCK_MACH64A) && + (pATI->Adapter < ATI_ADAPTER_MACH64)) + break; + +#endif /* AVOID_CPIO */ + + for (; ClockIndex < NumberOfClocks; ClockIndex++) + { + int Gap, XF86ConfigClock, SpecificationClock; + + SpecificationClock = ClockLine[ClockChipIndex] + [MapClockIndex(ClockMaps[ClockMap], ClockIndex)]; + if (SpecificationClock < 0) + break; + if (!SpecificationClock) + continue; + + XF86ConfigClock = pScreenInfo->clock[ClockIndex]; + if (!XF86ConfigClock) + continue; + + Gap = abs(XF86ConfigClock - SpecificationClock); + if (Gap >= MinimumGap) + goto SkipThisClockGenerator; + if (!Gap) + { + if (ClockIndex == CalibrationClockNumber) + continue; + } + else if (Gap > MaximumGap) + { + MaximumGap = Gap; + } + ClockCount++; + } + + if (ClockCount <= NumberOfMatchingClocks) + continue; + NumberOfMatchingClocks = ClockCount; + ClockChip = ClockChipIndex; + if (!(MinimumGap = MaximumGap)) + break; + +SkipThisClockGenerator:; + +#ifndef AVOID_CPIO + + /* For non-ATI adapters, only normalise standard VGA clocks */ + if (pATI->Adapter == ATI_ADAPTER_VGA) + break; + +#endif /* AVOID_CPIO */ + + } + + return ClockChip; +} + +/* + * ATIClockPreInit -- + * + * This function is called by ATIPreInit() and handles the XF86Config clocks + * line (or lack thereof). + */ +void +ATIClockPreInit +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + GDevPtr pGDev, + ClockRangePtr pRange +) +{ + double ScaleFactor; + unsigned short int NumberOfUndividedClocks; + unsigned short int NumberOfDividers, NumberOfClocks; + int CalibrationClockNumber, CalibrationClockValue; + int ClockIndex, SpecificationClock, ClockMap = 0, Index; + CARD8 CanDisableInterrupts; + +#ifndef AVOID_CPIO + + CARD8 genmo; + +#endif /* AVOID_CPIO */ + + /* + * Decide what to do about the XF86Config clocks for programmable clock + * generators. + */ + if (pATI->ProgrammableClock != ATI_CLOCK_FIXED) + { + /* Check for those that are not (yet) handled */ + if ((pATI->ProgrammableClock == ATI_CLOCK_UNKNOWN) || + (pATI->ProgrammableClock > NumberOf(ATIClockDescriptors))) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0, + "Unknown programmable clock generator type (0x%02X)" + " detected.\n", pATI->ProgrammableClock); + } + else if (pATI->ClockDescriptor.MaxN <= 0) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0, + "Unsupported programmable clock generator detected: %s.\n", + pATI->ClockDescriptor.ClockName); + } + else + { + /* + * Recognise supported clock generators. This involves telling the + * rest of the server about it and (re-)initializing the XF86Config + * clocks line. + */ + pRange->clockIndex = -1; + pScreenInfo->progClock = TRUE; + + /* Set internal clock ordering */ + +#ifndef AVOID_CPIO + + if (pATI->NewHW.crtc == ATI_CRTC_VGA) + { + pATI->NewHW.ClockMap = ATIVGAProgrammableClockMap; + pATI->NewHW.ClockUnmap = ATIVGAProgrammableClockUnmap; + } + else + +#endif /* AVOID_CPIO */ + + { + pATI->NewHW.ClockMap = ATIProgrammableClockMap; + pATI->NewHW.ClockUnmap = ATIProgrammableClockUnmap; + } + + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s programmable clock generator detected.\n", + pATI->ClockDescriptor.ClockName); + if (pATI->ReferenceDenominator == 1) + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "Reference clock %.3f MHz.\n", + (double)pATI->ReferenceNumerator / 1000.0); + else + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "Reference clock %.6g/%d (%.3f) MHz.\n", + (double)pATI->ReferenceNumerator / 1000.0, + pATI->ReferenceDenominator, + (double)pATI->ReferenceNumerator / + ((double)pATI->ReferenceDenominator * 1000.0)); + + /* Clobber XF86Config clocks line */ + if (pGDev->numclocks) + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "XF86Config clocks specification ignored.\n"); + + if (pATI->ProgrammableClock == ATI_CLOCK_CH8398) + { /* First two are fixed */ + pScreenInfo->numClocks = 2; + pScreenInfo->clock[0] = 25175; + pScreenInfo->clock[1] = 28322; + } + else if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL) + { + /* + * The integrated PLL generates clocks as if the reference + * frequency were doubled. + */ + pATI->ReferenceNumerator <<= 1; + } + + return; /* ... to ATIPreInit() */ + } + } + +#ifndef AVOID_CPIO + + /* Set default clock maps */ + pATI->NewHW.ClockMap = ATIVGAWonderClockMap; + pATI->NewHW.ClockUnmap = ATIVGAWonderClockUnmap; + +#endif /* AVOID_CPIO */ + + /* + * Determine the number of clock values the adapter should be able to + * generate and the dot clock to use for probe calibration. + */ +ProbeClocks: + +#ifndef AVOID_CPIO + + if (pATI->Adapter == ATI_ADAPTER_VGA) + { + NumberOfDividers = 1; + NumberOfUndividedClocks = 4; + CalibrationClockNumber = 1; + CalibrationClockValue = 28322; + } + else + +#endif /* AVOID_CPIO */ + + { + +#ifndef AVOID_CPIO + + NumberOfDividers = 4; + if ((pATI->Chip <= ATI_CHIP_18800) || + (pATI->Adapter == ATI_ADAPTER_V4)) + { + NumberOfUndividedClocks = 8; + /* Actually, any undivided clock will do */ + CalibrationClockNumber = 1; + CalibrationClockValue = 56644; + } + else + +#endif /* AVOID_CPIO */ + + { + NumberOfUndividedClocks = 16; + +#ifndef AVOID_CPIO + + CalibrationClockNumber = 7; + CalibrationClockValue = 36000; + if (pATI->Chip >= ATI_CHIP_68800) + +#endif /* AVOID_CPIO */ + + { + NumberOfDividers = 2; + if (pATI->Chip >= ATI_CHIP_264CT) + { + NumberOfDividers = 1; + NumberOfUndividedClocks = 4; + CalibrationClockNumber = 1; + CalibrationClockValue = 28322; + } + else + +#ifndef AVOID_CPIO + + if (pATI->Adapter >= ATI_ADAPTER_MACH64) + +#endif /* AVOID_CPIO */ + + { + CalibrationClockNumber = 10 /* or 11 */; + CalibrationClockValue = 75000 /* or 65000 */; + } + + /* + * When selecting clocks, all ATI accelerators use a different + * clock ordering. + */ + +#ifndef AVOID_CPIO + + if (pATI->NewHW.crtc == ATI_CRTC_VGA) + { + pATI->NewHW.ClockMap = ATIMachVGAClockMap; + pATI->NewHW.ClockUnmap = ATIMachVGAClockUnmap; + } + else + +#endif /* AVOID_CPIO */ + + { + pATI->NewHW.ClockMap = ATIAcceleratorClockMap; + pATI->NewHW.ClockUnmap = ATIAcceleratorClockUnmap; + } + } + } + } + + pATI->OldHW.ClockMap = pATI->NewHW.ClockMap; + pATI->OldHW.ClockUnmap = pATI->NewHW.ClockUnmap; + + NumberOfClocks = NumberOfUndividedClocks * NumberOfDividers; + + /* + * Respect any XF86Config clocks line. Well, that's the theory, anyway. + * In practice, however, the regular use of probed values is widespread, at + * times causing otherwise inexplicable results. So, attempt to normalise + * the clocks to known (i.e. specification) values. + */ + if (!pGDev->numclocks || pATI->OptionProbeClocks || + xf86ServerIsOnlyProbing()) + { + if (pATI->ProgrammableClock != ATI_CLOCK_FIXED) + { + /* + * For unsupported programmable clock generators, pick the highest + * frequency set by BIOS initialisation for clock calibration. + */ + CalibrationClockNumber = CalibrationClockValue = 0; + for (ClockIndex = 0; + ClockIndex < NumberOfUndividedClocks; + ClockIndex++) + { + if (CalibrationClockValue < pATI->BIOSClocks[ClockIndex]) + { + CalibrationClockNumber = ClockIndex; + CalibrationClockValue = pATI->BIOSClocks[ClockIndex]; + } + } + CalibrationClockNumber = + MapClockIndex(pATI->NewHW.ClockUnmap, CalibrationClockNumber); + CalibrationClockValue *= 10; + } + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + /* + * The current video state needs to be saved before the clock + * probe, and restored after. Video memory corruption and other + * effects occur because, at this early stage, the clock probe + * cannot reliably be prevented from enabling frequencies that are + * greater than what the adapter can handle. + */ + ATIModeSave(pScreenInfo, pATI, &pATI->OldHW); + + /* Ensure clock select pins are not OR'ed with anything */ + if (pATI->CPIO_VGAWonder && (pATI->OldHW.crtc == ATI_CRTC_VGA)) + ATIModifyExtReg(pATI, 0xB5U, pATI->OldHW.b5, 0x7FU, 0x00U); + } + +#endif /* AVOID_CPIO */ + + /* + * Probe the adapter for clock values. The following is essentially + * the common layer's xf86GetClocks() reworked to fit. One difference + * is the ability to monitor a VSync bit in MMIO space. + */ + CanDisableInterrupts = TRUE; /* An assumption verified below */ + + for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++) + { + pScreenInfo->clock[ClockIndex] = 0; + + /* Remap clock number */ + Index = MapClockIndex(pATI->OldHW.ClockMap, ClockIndex); + + /* Select the clock */ + switch (pATI->OldHW.crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + /* Get generic two low-order bits */ + genmo = (inb(R_GENMO) & 0xF3U) | ((Index << 2) & 0x0CU); + + if (pATI->CPIO_VGAWonder) + { + /* + * On adapters with crystals, switching to one of the + * spare assignments doesn't do anything (i.e. the + * previous setting remains in effect). So, disable + * their selection. + */ + if (((Index & 0x03U) == 0x02U) && + ((pATI->Chip <= ATI_CHIP_18800) || + (pATI->Adapter == ATI_ADAPTER_V4))) + continue; + + /* Start sequencer reset */ + PutReg(SEQX, 0x00U, 0x00U); + + /* Set high-order bits */ + if (pATI->Chip <= ATI_CHIP_18800) + { + ATIModifyExtReg(pATI, 0xB2U, -1, 0xBFU, + Index << 4); + } + else + { + ATIModifyExtReg(pATI, 0xBEU, -1, 0xEFU, + Index << 2); + if (pATI->Adapter != ATI_ADAPTER_V4) + { + Index >>= 1; + ATIModifyExtReg(pATI, 0xB9U, -1, 0xFDU, + Index >> 1); + } + } + + /* Set clock divider bits */ + ATIModifyExtReg(pATI, 0xB8U, -1, 0x00U, + (Index << 3) & 0xC0U); + } + else + { + /* + * Reject clocks that cannot be selected. + */ + if (Index & ~0x03U) + continue; + + /* Start sequencer reset */ + PutReg(SEQX, 0x00U, 0x00U); + } + + /* Must set miscellaneous output register last */ + outb(GENMO, genmo); + + /* End sequencer reset */ + PutReg(SEQX, 0x00U, 0x03U); + + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + out8(CLOCK_CNTL, CLOCK_STROBE | + SetBits(Index, CLOCK_SELECT | CLOCK_DIVIDER)); + break; + + default: + continue; + } + + usleep(50000); /* Let clock stabilise */ + + xf86SetPriority(TRUE); + + /* Try to disable interrupts */ + if (CanDisableInterrupts && !xf86DisableInterrupts()) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to disable interrupts; Clock probe will not be as" + " accurate.\n"); + CanDisableInterrupts = FALSE; + } + + /* + * Generate a count while monitoring the vertical sync or blanking + * pulse. This is dependent on the CRTC used by the mode on server + * entry. + */ + switch (pATI->OldHW.crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + /* Verify vertical sync pulses are in fact occurring */ + Index = 1 << 19; + while (!(inb(GENS1(pATI->CPIO_VGABase)) & 0x08U)) + if (Index-- <= 0) + goto EnableInterrupts; + Index = 1 << 19; + while (inb(GENS1(pATI->CPIO_VGABase)) & 0x08U) + if (Index-- <= 0) + goto EnableInterrupts; + Index = 1 << 19; + while (!(inb(GENS1(pATI->CPIO_VGABase)) & 0x08U)) + if (Index-- <= 0) + goto EnableInterrupts; + + /* Generate the count */ + for (Index = 0; Index < 8; Index++) + { + while (inb(GENS1(pATI->CPIO_VGABase)) & 0x08U) + pScreenInfo->clock[ClockIndex]++; + while (!(inb(GENS1(pATI->CPIO_VGABase)) & 0x08U)) + pScreenInfo->clock[ClockIndex]++; + } + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + /* Verify vertical blanking pulses are in fact occurring */ + Index = 1 << 19; + while (!(inr(CRTC_INT_CNTL) & CRTC_VBLANK)) + if (Index-- <= 0) + goto EnableInterrupts; + Index = 1 << 19; + while (inr(CRTC_INT_CNTL) & CRTC_VBLANK) + if (Index-- <= 0) + goto EnableInterrupts; + Index = 1 << 19; + while (!(inr(CRTC_INT_CNTL) & CRTC_VBLANK)) + if (Index-- <= 0) + goto EnableInterrupts; + + /* Generate the count */ + for (Index = 0; Index < 4; Index++) + { + while (inr(CRTC_INT_CNTL) & CRTC_VBLANK) + pScreenInfo->clock[ClockIndex]++; + while (!(inr(CRTC_INT_CNTL) & CRTC_VBLANK)) + pScreenInfo->clock[ClockIndex]++; + } + break; + + default: + break; + } + + EnableInterrupts: + if (CanDisableInterrupts) + xf86EnableInterrupts(); + + xf86SetPriority(FALSE); + } + + ScaleFactor = (double)CalibrationClockValue * + (double)pScreenInfo->clock[CalibrationClockNumber]; + + /* Scale the clocks from counts to kHz */ + for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++) + { + if (ClockIndex == CalibrationClockNumber) + pScreenInfo->clock[ClockIndex] = CalibrationClockValue; + else if (pScreenInfo->clock[ClockIndex]) + /* Round to the nearest 10 kHz */ + pScreenInfo->clock[ClockIndex] = + (int)(((ScaleFactor / + (double)pScreenInfo->clock[ClockIndex]) + + 5) / 10) * 10; + } + + pScreenInfo->numClocks = NumberOfClocks; + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + /* Restore video state */ + ATIModeSet(pScreenInfo, pATI, &pATI->OldHW); + xfree(pATI->OldHW.frame_buffer); + pATI->OldHW.frame_buffer = NULL; + } + +#endif /* AVOID_CPIO */ + + /* Tell user clocks were probed, instead of supplied */ + pATI->OptionProbeClocks = TRUE; + + /* Attempt to match probed clocks to a known specification */ + pATI->Clock = ATIMatchClockLine(pScreenInfo, pATI, + SpecificationClockLine, NumberOfUndividedClocks, + CalibrationClockNumber, 0); + +#ifndef AVOID_CPIO + + if ((pATI->Chip <= ATI_CHIP_18800) || + (pATI->Adapter == ATI_ADAPTER_V4)) + { + /* V3 and V4 adapters don't have clock chips */ + if (pATI->Clock > ATI_CLOCK_CRYSTALS) + pATI->Clock = ATI_CLOCK_NONE; + } + else + +#endif /* AVOID_CPIO */ + + { + /* All others don't have crystals */ + if (pATI->Clock == ATI_CLOCK_CRYSTALS) + pATI->Clock = ATI_CLOCK_NONE; + } + } + else + { + /* + * Allow for an initial subset of specification clocks. Can't allow + * for any more than that though... + */ + if (NumberOfClocks > pGDev->numclocks) + { + NumberOfClocks = pGDev->numclocks; + if (NumberOfUndividedClocks > NumberOfClocks) + NumberOfUndividedClocks = NumberOfClocks; + } + + /* Move XF86Config clocks into the ScrnInfoRec */ + for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++) + pScreenInfo->clock[ClockIndex] = pGDev->clock[ClockIndex]; + pScreenInfo->numClocks = NumberOfClocks; + + /* Attempt to match clocks to a known specification */ + pATI->Clock = ATIMatchClockLine(pScreenInfo, pATI, + SpecificationClockLine, NumberOfUndividedClocks, -1, 0); + +#ifndef AVOID_CPIO + + if (pATI->Adapter != ATI_ADAPTER_VGA) + +#endif /* AVOID_CPIO */ + + { + if (pATI->Clock == ATI_CLOCK_NONE) + { + /* + * Reject certain clock lines that are obviously wrong. This + * includes the standard VGA clocks for ATI adapters, and clock + * lines that could have been used with the pre-2.1.1 driver. + */ + if (ATIMatchClockLine(pScreenInfo, pATI, InvalidClockLine, + NumberOfClocks, -1, 0)) + { + pATI->OptionProbeClocks = TRUE; + } + else + +#ifndef AVOID_CPIO + + if ((pATI->Chip >= ATI_CHIP_18800) && + (pATI->Adapter != ATI_ADAPTER_V4)) + +#endif /* AVOID_CPIO */ + + { + /* + * Check for clocks that are specified in the wrong order. + * This is meant to catch those who are trying to use the + * clock order intended for the old accelerated servers. + */ + while ((++ClockMap, ClockMap %= NumberOf(ClockMaps))) + { + pATI->Clock = ATIMatchClockLine(pScreenInfo, pATI, + SpecificationClockLine, NumberOfUndividedClocks, + -1, ClockMap); + if (pATI->Clock != ATI_CLOCK_NONE) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, + X_WARNING, 0, + "XF86Config clock ordering incorrect. Clocks" + " will be reordered.\n"); + break; + } + } + } + } + else + /* Ensure crystals are not matched to clock chips, and vice versa */ + +#ifndef AVOID_CPIO + + if ((pATI->Chip <= ATI_CHIP_18800) || + (pATI->Adapter == ATI_ADAPTER_V4)) + { + if (pATI->Clock > ATI_CLOCK_CRYSTALS) + pATI->OptionProbeClocks = TRUE; + } + else + +#endif /* AVOID_CPIO */ + + { + if (pATI->Clock == ATI_CLOCK_CRYSTALS) + pATI->OptionProbeClocks = TRUE; + } + + if (pATI->OptionProbeClocks) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0, + "Invalid or obsolete XF86Config clocks line rejected.\n" + " Clocks will be probed.\n"); + goto ProbeClocks; + } + } + } + + if (pATI->ProgrammableClock != ATI_CLOCK_FIXED) + { + pATI->ProgrammableClock = ATI_CLOCK_FIXED; + } + else if (pATI->Clock == ATI_CLOCK_NONE) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0, + "Unknown clock generator detected.\n"); + } + else + +#ifndef AVOID_CPIO + + if (pATI->Clock == ATI_CLOCK_CRYSTALS) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "This adapter uses crystals to generate clock frequencies.\n"); + } + else if (pATI->Clock != ATI_CLOCK_VGA) + +#endif /* AVOID_CPIO */ + + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s clock chip detected.\n", ATIClockNames[pATI->Clock]); + } + + if (pATI->Clock != ATI_CLOCK_NONE) + { + /* Replace undivided clocks with specification values */ + for (ClockIndex = 0; + ClockIndex < NumberOfUndividedClocks; + ClockIndex++) + { + /* + * Don't replace clocks that are probed, documented, or set by the + * user to zero. One exception is that we need to override the + * user's value for the spare settings on a crystal-based adapter. + * Another exception is when the user specifies the clock ordering + * intended for the old accelerated servers. + */ + SpecificationClock = + SpecificationClockLine[pATI->Clock][ClockIndex]; + if (SpecificationClock < 0) + break; + if (!ClockMap) + { + if (!pScreenInfo->clock[ClockIndex]) + continue; + if (!SpecificationClock) + { + if (pATI->Clock != ATI_CLOCK_CRYSTALS) + continue; + } + else + { + /* + * Due to the way clock lines are matched, the following + * can prevent the override if the clock is probed, + * documented or set by the user to a value greater than + * maxClock. + */ + if (abs(SpecificationClock - + pScreenInfo->clock[ClockIndex]) > CLOCK_TOLERANCE) + continue; + } + } + pScreenInfo->clock[ClockIndex] = SpecificationClock; + } + + /* Adjust divided clocks */ + for (ClockIndex = NumberOfUndividedClocks; + ClockIndex < NumberOfClocks; + ClockIndex++) + pScreenInfo->clock[ClockIndex] = ATIDivide( + pScreenInfo->clock[ClockIndex % NumberOfUndividedClocks], + (ClockIndex / NumberOfUndividedClocks) + 1, 0, 0); + } + + /* Tell user about fixed clocks */ + xf86ShowClocks(pScreenInfo, pATI->OptionProbeClocks ? X_PROBED : X_CONFIG); + + /* Prevent selection of high clocks, even by V_CLKDIV2 modes */ + for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++) + if (pScreenInfo->clock[ClockIndex] > pRange->maxClock) + pScreenInfo->clock[ClockIndex] = 0; +} + +/* + * ATIClockSave -- + * + * This function saves that part of an ATIHWRec that relates to clocks. + */ +void +ATIClockSave +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + if (pScreenInfo->vtSema && (pATI->ProgrammableClock > ATI_CLOCK_FIXED)) + { + +#ifndef AVOID_CPIO + + if (pATIHW->crtc == ATI_CRTC_VGA) + { + pATIHW->ClockMap = ATIVGAProgrammableClockMap; + pATIHW->ClockUnmap = ATIVGAProgrammableClockUnmap; + } + else + +#endif /* AVOID_CPIO */ + + { + pATIHW->ClockMap = ATIProgrammableClockMap; + pATIHW->ClockUnmap = ATIProgrammableClockUnmap; + } + } + else + { + +#ifndef AVOID_CPIO + + if (pATIHW->crtc != ATI_CRTC_VGA) + +#endif /* AVOID_CPIO */ + + { + pATIHW->ClockMap = ATIAcceleratorClockMap; + pATIHW->ClockUnmap = ATIAcceleratorClockUnmap; + } + +#ifndef AVOID_CPIO + + else if (pATI->Chip < ATI_CHIP_68800) + { + pATIHW->ClockMap = ATIVGAWonderClockMap; + pATIHW->ClockUnmap = ATIVGAWonderClockUnmap; + } + else + { + pATIHW->ClockMap = ATIMachVGAClockMap; + pATIHW->ClockUnmap = ATIMachVGAClockUnmap; + } + +#endif /* AVOID_CPIO */ + + } +} + +/* + * ATIClockCalculate -- + * + * This function is called to generate, if necessary, the data needed for clock + * programming, and set clock select bits in various register values. + */ +Bool +ATIClockCalculate +( + int iScreen, + ATIPtr pATI, + ATIHWPtr pATIHW, + DisplayModePtr pMode +) +{ + int N, M, D; + int ClockSelect, N1, MinimumGap; + int Frequency, Multiple; /* Used as temporaries */ + + /* Set default values */ + pATIHW->FeedbackDivider = pATIHW->ReferenceDivider = pATIHW->PostDivider = 0; + + if ((pATI->ProgrammableClock <= ATI_CLOCK_FIXED) || + ((pATI->ProgrammableClock == ATI_CLOCK_CH8398) && + (pMode->ClockIndex < 2))) + { + /* Use a fixed clock */ + ClockSelect = pMode->ClockIndex; + } + else + { + /* Generate clock programme word, using units of kHz */ + MinimumGap = ((unsigned int)(-1)) >> 1; + + /* Loop through reference dividers */ + for (M = pATI->ClockDescriptor.MinM; + M <= pATI->ClockDescriptor.MaxM; + M++) + { + /* Loop through post-dividers */ + for (D = 0; D < pATI->ClockDescriptor.NumD; D++) + { + if (!pATI->ClockDescriptor.PostDividers[D]) + continue; + + /* Limit undivided VCO to maxClock */ + if (pATI->maxClock && + ((pATI->maxClock / pATI->ClockDescriptor.PostDividers[D]) < + pMode->Clock)) + continue; + + /* + * Calculate closest feedback divider and apply its + * restrictions. + */ + Multiple = M * pATI->ReferenceDenominator * + pATI->ClockDescriptor.PostDividers[D]; + N = ATIDivide(pMode->Clock * Multiple, + pATI->ReferenceNumerator, 0, 0); + if (N < pATI->ClockDescriptor.MinN) + N = pATI->ClockDescriptor.MinN; + else if (N > pATI->ClockDescriptor.MaxN) + N = pATI->ClockDescriptor.MaxN; + N -= pATI->ClockDescriptor.NAdjust; + N1 = (N / pATI->ClockDescriptor.N1) * pATI->ClockDescriptor.N2; + if (N > N1) + N = ATIDivide(N1 + 1, pATI->ClockDescriptor.N1, 0, 1); + N += pATI->ClockDescriptor.NAdjust; + N1 += pATI->ClockDescriptor.NAdjust; + + for (; ; N = N1) + { + /* Pick the closest setting */ + Frequency = abs(ATIDivide(N * pATI->ReferenceNumerator, + Multiple, 0, 0) - pMode->Clock); + if ((Frequency < MinimumGap) || + ((Frequency == MinimumGap) && + (pATIHW->FeedbackDivider < N))) + { + /* Save settings */ + pATIHW->FeedbackDivider = N; + pATIHW->ReferenceDivider = M; + pATIHW->PostDivider = D; + MinimumGap = Frequency; + } + + if (N <= N1) + break; + } + } + } + + Multiple = pATIHW->ReferenceDivider * pATI->ReferenceDenominator * + pATI->ClockDescriptor.PostDividers[pATIHW->PostDivider]; + Frequency = pATIHW->FeedbackDivider * pATI->ReferenceNumerator; + Frequency = ATIDivide(Frequency, Multiple, 0, 0); + if (abs(Frequency - pMode->Clock) > CLOCK_TOLERANCE) + { + xf86DrvMsg(iScreen, X_ERROR, + "Unable to programme clock %.3fMHz for mode %s.\n", + (double)(pMode->Clock) / 1000.0, pMode->name); + return FALSE; + } + pMode->SynthClock = Frequency; + ClockSelect = pATI->ClockNumberToProgramme; + + xf86ErrorFVerb(4, + "\n Programming clock %d to %.3fMHz for mode %s." + " N=%d, M=%d, D=%d.\n", + ClockSelect, (double)Frequency / 1000.0, pMode->name, + pATIHW->FeedbackDivider, pATIHW->ReferenceDivider, + pATIHW->PostDivider); + + if (pATI->Chip >= ATI_CHIP_264VTB) + ATIDSPCalculate(pATI, pATIHW, pMode); + } + + /* Set clock select bits, after remapping them */ + pATIHW->clock = ClockSelect; /* Save pre-map clock number */ + ClockSelect = MapClockIndex(pATIHW->ClockMap, ClockSelect); + + switch (pATIHW->crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + pATIHW->genmo = (pATIHW->genmo & 0xF3U) | + ((ClockSelect << 2) & 0x0CU); + + if (pATI->CPIO_VGAWonder) + { + /* Set ATI clock select bits */ + if (pATI->Chip <= ATI_CHIP_18800) + { + pATIHW->b2 = (pATIHW->b2 & 0xBFU) | + ((ClockSelect << 4) & 0x40U); + } + else + { + pATIHW->be = (pATIHW->be & 0xEFU) | + ((ClockSelect << 2) & 0x10U); + if (pATI->Adapter != ATI_ADAPTER_V4) + { + ClockSelect >>= 1; + pATIHW->b9 = (pATIHW->b9 & 0xFDU) | + ((ClockSelect >> 1) & 0x02U); + } + } + + /* Set clock divider bits */ + pATIHW->b8 = (pATIHW->b8 & 0x3FU) | + ((ClockSelect << 3) & 0xC0U); + } + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + pATIHW->clock_cntl = CLOCK_STROBE | + SetBits(ClockSelect, CLOCK_SELECT | CLOCK_DIVIDER); + break; + + default: + break; + } + + return TRUE; +} + +/* + * ATIClockSet -- + * + * This function is called to programme a clock for the mode being set. + */ +void +ATIClockSet +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + CARD32 crtc_gen_cntl, tmp; + CARD8 clock_cntl0; + CARD8 tmp2; + unsigned int Programme; + int N = pATIHW->FeedbackDivider - pATI->ClockDescriptor.NAdjust; + int M = pATIHW->ReferenceDivider - pATI->ClockDescriptor.MAdjust; + int D = pATIHW->PostDivider; + + /* Temporarily switch to accelerator mode */ + crtc_gen_cntl = inr(CRTC_GEN_CNTL); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN); + + switch (pATI->ProgrammableClock) + { + case ATI_CLOCK_ICS2595: + clock_cntl0 = in8(CLOCK_CNTL); + + Programme = (SetBits(pATIHW->clock, ICS2595_CLOCK) | + SetBits(N, ICS2595_FB_DIV) | SetBits(D, ICS2595_POST_DIV)) ^ + ICS2595_TOGGLE; + + ATIDelay(50000); /* 50 milliseconds */ + + (void)xf86DisableInterrupts(); + + /* Send all 20 bits of programme word */ + while (Programme >= CLOCK_BIT) + { + tmp = (Programme & CLOCK_BIT) | CLOCK_STROBE; + out8(CLOCK_CNTL, tmp); + ATIDelay(26); /* 26 microseconds */ + out8(CLOCK_CNTL, tmp | CLOCK_PULSE); + ATIDelay(26); /* 26 microseconds */ + Programme >>= 1; + } + + xf86EnableInterrupts(); + + /* Restore register */ + out8(CLOCK_CNTL, clock_cntl0 | CLOCK_STROBE); + break; + + case ATI_CLOCK_STG1703: + (void)ATIGetDACCmdReg(pATI); + (void)in8(M64_DAC_MASK); + out8(M64_DAC_MASK, (pATIHW->clock << 1) + 0x20U); + out8(M64_DAC_MASK, 0); + out8(M64_DAC_MASK, SetBits(N, 0xFFU)); + out8(M64_DAC_MASK, SetBits(M, 0x1FU) | SetBits(D, 0xE0U)); + break; + + case ATI_CLOCK_CH8398: + tmp = inr(DAC_CNTL) | (DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3); + outr(DAC_CNTL, tmp); + out8(M64_DAC_WRITE, pATIHW->clock); + out8(M64_DAC_DATA, SetBits(N, 0xFFU)); + out8(M64_DAC_DATA, SetBits(M, 0x3FU) | SetBits(D, 0xC0U)); + out8(M64_DAC_MASK, 0x04U); + outr(DAC_CNTL, tmp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)); + tmp2 = in8(M64_DAC_WRITE); + out8(M64_DAC_WRITE, (tmp2 & 0x70U) | 0x80U); + outr(DAC_CNTL, tmp & ~DAC_EXT_SEL_RS2); + break; + + case ATI_CLOCK_INTERNAL: + /* Reset VCLK generator */ + ATIMach64PutPLLReg(PLL_VCLK_CNTL, pATIHW->pll_vclk_cntl); + + /* Set post-divider */ + tmp2 = pATIHW->clock << 1; + tmp = ATIMach64GetPLLReg(PLL_VCLK_POST_DIV); + tmp &= ~(0x03U << tmp2); + tmp |= SetBits(D, 0x03U) << tmp2; + ATIMach64PutPLLReg(PLL_VCLK_POST_DIV, tmp); + + /* Set extended post-divider */ + tmp = ATIMach64GetPLLReg(PLL_XCLK_CNTL); + tmp &= ~(SetBits(1, PLL_VCLK0_XDIV) << pATIHW->clock); + tmp |= SetBits(D >> 2, PLL_VCLK0_XDIV) << pATIHW->clock; + ATIMach64PutPLLReg(PLL_XCLK_CNTL, tmp); + + /* Set feedback divider */ + tmp = PLL_VCLK0_FB_DIV + pATIHW->clock; + ATIMach64PutPLLReg(tmp, SetBits(N, 0xFFU)); + + /* End VCLK generator reset */ + ATIMach64PutPLLReg(PLL_VCLK_CNTL, + pATIHW->pll_vclk_cntl & ~PLL_VCLK_RESET); + + /* Reset write bit */ + ATIMach64AccessPLLReg(pATI, 0, FALSE); + break; + + case ATI_CLOCK_ATT20C408: + (void)ATIGetDACCmdReg(pATI); + tmp = in8(M64_DAC_MASK); + (void)ATIGetDACCmdReg(pATI); + out8(M64_DAC_MASK, tmp | 1); + out8(M64_DAC_WRITE, 1); + out8(M64_DAC_MASK, tmp | 9); + ATIDelay(400); /* 400 microseconds */ + tmp2 = (pATIHW->clock << 2) + 0x40U; + out8(M64_DAC_WRITE, tmp2); + out8(M64_DAC_MASK, SetBits(N, 0xFFU)); + out8(M64_DAC_WRITE, ++tmp2); + out8(M64_DAC_MASK, SetBits(M, 0x3FU) | SetBits(D, 0xC0U)); + out8(M64_DAC_WRITE, ++tmp2); + out8(M64_DAC_MASK, 0x77U); + ATIDelay(400); /* 400 microseconds */ + out8(M64_DAC_WRITE, 1); + out8(M64_DAC_MASK, tmp); + break; + + case ATI_CLOCK_IBMRGB514: + /* + * Here, only update in-core data. It will be written out later by + * ATIRGB514Set(). + */ + tmp = (pATIHW->clock << 1) + 0x20U; + pATIHW->ibmrgb514[tmp] = + (SetBits(N, 0x3FU) | SetBits(D, 0xC0U)) ^ 0xC0U; + pATIHW->ibmrgb514[tmp + 1] = SetBits(M, 0x3FU); + break; + + default: + break; + } + + (void)in8(M64_DAC_WRITE); /* Clear DAC counter */ + + /* Restore register */ + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl); +} diff --git a/src/aticlock.h b/src/aticlock.h new file mode 100644 index 0000000..20e646d --- /dev/null +++ b/src/aticlock.h @@ -0,0 +1,86 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticlock.h,v 1.8 2003/01/01 19:16:31 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATICLOCK_H___ +#define ___ATICLOCK_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +/* + * Definitions related to non-programmable clock generators. + */ +typedef enum +{ + ATI_CLOCK_NONE = 0, + ATI_CLOCK_VGA = 1, + ATI_CLOCK_CRYSTALS = 2, + ATI_CLOCK_18810, + ATI_CLOCK_18811_0, + ATI_CLOCK_18811_1, + ATI_CLOCK_2494AM, + ATI_CLOCK_MACH64A, + ATI_CLOCK_MACH64B, + ATI_CLOCK_MACH64C +} ATIClockType; +extern const char *ATIClockNames[]; + +/* + * Definitions related to programmable clock generators. + */ +typedef enum +{ + ATI_CLOCK_UNKNOWN = -1, + ATI_CLOCK_FIXED = 0, /* Further described by ATIClockType */ + ATI_CLOCK_ICS2595, + ATI_CLOCK_STG1703, + ATI_CLOCK_CH8398, + ATI_CLOCK_INTERNAL, + ATI_CLOCK_ATT20C408, + ATI_CLOCK_IBMRGB514, + ATI_CLOCK_MAX /* Must be last */ +} ATIProgrammableClockType; + +typedef struct +{ + CARD16 MinN, MaxN; /* Feedback divider and ... */ + CARD16 NAdjust; /* ... its adjustment and ... */ + CARD16 N1, N2; /* ... its restrictions */ + CARD16 MinM, MaxM; /* Reference divider and ... */ + CARD16 MAdjust; /* ... its adjustment */ + CARD16 NumD, *PostDividers; /* Post-dividers */ + const char *ClockName; +} ClockRec, *ClockPtr; +extern ClockRec ATIClockDescriptors[]; + +extern void ATIClockPreInit FunctionPrototype((ScrnInfoPtr, ATIPtr, GDevPtr, + ClockRangePtr)); +extern void ATIClockSave FunctionPrototype((ScrnInfoPtr, ATIPtr, + ATIHWPtr)); +extern Bool ATIClockCalculate FunctionPrototype((int, ATIPtr, ATIHWPtr, + DisplayModePtr)); +extern void ATIClockSet FunctionPrototype((ATIPtr, ATIHWPtr)); + +#endif /* ___ATICLOCK_H___ */ diff --git a/src/aticonfig.c b/src/aticonfig.c new file mode 100644 index 0000000..cee9e18 --- /dev/null +++ b/src/aticonfig.c @@ -0,0 +1,256 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticonfig.c,v 1.15tsi Exp $*/ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atichip.h" +#include "aticonfig.h" +#include "aticursor.h" +#include "atioption.h" +#include "atistruct.h" + +/* + * Non-publicised XF86Config options. + */ +typedef enum +{ + ATI_OPTION_BIOS_DISPLAY, /* Allow BIOS interference */ + ATI_OPTION_CRT_SCREEN, /* Legacy negation of "PanelDisplay" */ + ATI_OPTION_DEVEL, /* Intentionally undocumented */ + ATI_OPTION_BLEND, /* Force horizontal blending of small modes */ + ATI_OPTION_LCDSYNC /* Use XF86Config panel mode porches */ +} ATIPrivateOptionType; + +/* + * ATIProcessOptions -- + * + * This function extracts options from what was parsed out of the XF86Config + * file. + */ +void +ATIProcessOptions +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + OptionInfoPtr PublicOption = xnfalloc(ATIPublicOptionSize); + OptionInfoRec PrivateOption[] = + { + { /* ON: Let BIOS change display(s) */ + ATI_OPTION_BIOS_DISPLAY, /* OFF: Don't */ + "biosdisplay", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { /* Negation of "PanelDisplay" public option */ + ATI_OPTION_CRT_SCREEN, + "crtscreen", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { /* ON: Ease exploration of loose ends */ + ATI_OPTION_DEVEL, /* OFF: Fit for public consumption */ + "tsi", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { /* ON: Horizontally blend most modes */ + ATI_OPTION_BLEND, /* OFF: Use pixel replication more often */ + "lcdblend", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { /* ON: Use XF86Config porch timings */ + ATI_OPTION_LCDSYNC, /* OFF: Use porches from mode on entry */ + "lcdsync", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + -1, + NULL, + OPTV_NONE, + {0, }, + FALSE + } + }; + + (void)memcpy(PublicOption, ATIPublicOptions, ATIPublicOptionSize); + +# define Accel PublicOption[ATI_OPTION_ACCEL].value.bool +# define BIOSDisplay PrivateOption[ATI_OPTION_BIOS_DISPLAY].value.bool +# define Blend PrivateOption[ATI_OPTION_BLEND].value.bool +# define CRTDisplay PublicOption[ATI_OPTION_CRT_DISPLAY].value.bool +# define CRTScreen PrivateOption[ATI_OPTION_CRT_SCREEN].value.bool +# define CSync PublicOption[ATI_OPTION_CSYNC].value.bool +# define Devel PrivateOption[ATI_OPTION_DEVEL].value.bool +# define HWCursor PublicOption[ATI_OPTION_HWCURSOR].value.bool + +#ifndef AVOID_CPIO + +# define Linear PublicOption[ATI_OPTION_LINEAR].value.bool + +#endif /* AVOID_CPIO */ + +# define CacheMMIO PublicOption[ATI_OPTION_MMIO_CACHE].value.bool +# define TestCacheMMIO PublicOption[ATI_OPTION_TEST_MMIO_CACHE].value.bool +# define PanelDisplay PublicOption[ATI_OPTION_PANEL_DISPLAY].value.bool +# define ProbeClocks PublicOption[ATI_OPTION_PROBE_CLOCKS].value.bool +# define ShadowFB PublicOption[ATI_OPTION_SHADOW_FB].value.bool +# define SWCursor PublicOption[ATI_OPTION_SWCURSOR].value.bool +# define LCDSync PrivateOption[ATI_OPTION_LCDSYNC].value.bool + +# define ReferenceClock \ + PublicOption[ATI_OPTION_REFERENCE_CLOCK].value.freq.freq + + /* Pick up XF86Config options */ + xf86CollectOptions(pScreenInfo, NULL); + + /* Set non-zero defaults */ + +#ifndef AVOID_CPIO + + if (pATI->Adapter >= ATI_ADAPTER_MACH64) + +#endif /* AVOID_CPIO */ + + { + Accel = CacheMMIO = HWCursor = TRUE; + +#ifndef AVOID_CPIO + + Linear = TRUE; + +#endif /* AVOID_CPIO */ + + } + + ReferenceClock = ((double)157500000.0) / ((double)11.0); + +#ifndef AVOID_CPIO + + if (pATI->PCIInfo) + +#endif /* AVOID_CPIO */ + + { + ShadowFB = TRUE; + } + + Blend = PanelDisplay = TRUE; + + xf86ProcessOptions(pScreenInfo->scrnIndex, pScreenInfo->options, + PublicOption); + xf86ProcessOptions(pScreenInfo->scrnIndex, pScreenInfo->options, + PrivateOption); + +#ifndef AVOID_CPIO + + /* Disable linear apertures if the OS doesn't support them */ + if (!xf86LinearVidMem() && Linear) + { + if (PublicOption[ATI_OPTION_LINEAR].found) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "OS does not support linear apertures.\n"); + Linear = FALSE; + } + +#endif /* AVOID_CPIO */ + + /* Move option values into driver private structure */ + pATI->OptionAccel = Accel; + pATI->OptionBIOSDisplay = BIOSDisplay; + pATI->OptionBlend = Blend; + pATI->OptionCRTDisplay = CRTDisplay; + pATI->OptionCSync = CSync; + pATI->OptionDevel = Devel; + +#ifndef AVOID_CPIO + + pATI->OptionLinear = Linear; + +#endif /* AVOID_CPIO */ + + pATI->OptionMMIOCache = CacheMMIO; + pATI->OptionTestMMIOCache = TestCacheMMIO; + pATI->OptionProbeClocks = ProbeClocks; + pATI->OptionShadowFB = ShadowFB; + pATI->OptionLCDSync = LCDSync; + + /* "CRTScreen" is now "NoPanelDisplay" */ + if ((PanelDisplay != CRTScreen) || + PublicOption[ATI_OPTION_PANEL_DISPLAY].found) + pATI->OptionPanelDisplay = PanelDisplay; + else + pATI->OptionPanelDisplay = !CRTScreen; + + /* Validate and set cursor options */ + pATI->Cursor = ATI_CURSOR_SOFTWARE; + if (SWCursor || !HWCursor) + { + if (HWCursor && PublicOption[ATI_OPTION_HWCURSOR].found) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Option \"sw_cursor\" overrides Option \"hw_cursor\".\n"); + } + else if (pATI->Chip < ATI_CHIP_264CT) + { + if (HWCursor && PublicOption[ATI_OPTION_HWCURSOR].found) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Option \"hw_cursor\" not supported in this configuration.\n"); + } + else + { + pATI->Cursor = ATI_CURSOR_HARDWARE; + } + + /* Only set the reference clock if it hasn't already been determined */ + if (!pATI->ReferenceNumerator || !pATI->ReferenceDenominator) + { + switch ((int)(ReferenceClock / ((double)100000.0))) + { + case 143: + pATI->ReferenceNumerator = 157500; + pATI->ReferenceDenominator = 11; + break; + + case 286: + pATI->ReferenceNumerator = 315000; + pATI->ReferenceDenominator = 11; + break; + + default: + pATI->ReferenceNumerator = + (int)(ReferenceClock / ((double)1000.0)); + pATI->ReferenceDenominator = 1; + break; + } + } + + xfree(PublicOption); +} diff --git a/src/aticonfig.h b/src/aticonfig.h new file mode 100644 index 0000000..242ecef --- /dev/null +++ b/src/aticonfig.h @@ -0,0 +1,34 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticonfig.h,v 1.5 2003/01/01 19:16:31 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATICONFIG_H___ +#define ___ATICONFIG_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern void ATIProcessOptions FunctionPrototype((ScrnInfoPtr, ATIPtr)); + +#endif /* ___ATICONFIG_H___ */ diff --git a/src/aticonsole.c b/src/aticonsole.c new file mode 100644 index 0000000..80062d4 --- /dev/null +++ b/src/aticonsole.c @@ -0,0 +1,364 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticonsole.c,v 1.22 2003/11/13 18:42:47 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiadapter.h" +#include "aticonsole.h" +#include "aticrtc.h" +#include "atii2c.h" +#include "atilock.h" +#include "atimach64.h" +#include "atimode.h" +#include "atistruct.h" +#include "ativga.h" +#include "atividmem.h" + +#include "xf86.h" + +/* + * ATISaveScreen -- + * + * This function is a screen saver hook for DIX. + */ +Bool +ATISaveScreen +( + ScreenPtr pScreen, + int Mode +) +{ + ScrnInfoPtr pScreenInfo; + ATIPtr pATI; + + if ((Mode != SCREEN_SAVER_ON) && (Mode != SCREEN_SAVER_CYCLE)) + SetTimeSinceLastInputEvent(); + + if (!pScreen) + return TRUE; + + pScreenInfo = xf86Screens[pScreen->myNum]; + if (!pScreenInfo->vtSema) + return TRUE; + + pATI = ATIPTR(pScreenInfo); + switch (pATI->NewHW.crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + ATIVGASaveScreen(pATI, Mode); + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + ATIMach64SaveScreen(pATI, Mode); + break; + + default: + break; + } + + return TRUE; +} + +/* + * ATISetDPMSMode -- + * + * This function sets the adapter's VESA Display Power Management Signaling + * mode. + */ +void +ATISetDPMSMode +( + ScrnInfoPtr pScreenInfo, + int DPMSMode, + int flags +) +{ + ATIPtr pATI; + + if (!pScreenInfo || !pScreenInfo->vtSema) + return; + + pATI = ATIPTR(pScreenInfo); + + switch (pATI->Adapter) + { + case ATI_ADAPTER_MACH64: + ATIMach64SetDPMSMode(pScreenInfo, pATI, DPMSMode); + break; + + default: + +#ifndef AVOID_CPIO + + /* Assume EGA/VGA */ + ATIVGASetDPMSMode(pATI, DPMSMode); + break; + + case ATI_ADAPTER_NONE: + case ATI_ADAPTER_8514A: + case ATI_ADAPTER_MACH8: + +#endif /* AVOID_CPIO */ + + break; + } +} + +/* + * ATIEnterGraphics -- + * + * This function sets the hardware to a graphics video state. + */ +Bool +ATIEnterGraphics +( + ScreenPtr pScreen, + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + /* Map apertures */ + if (!ATIMapApertures(pScreenInfo->scrnIndex, pATI)) + return FALSE; + + /* Unlock device */ + ATIUnlock(pATI); + + /* Calculate hardware data */ + if (pScreen && + !ATIModeCalculate(pScreenInfo->scrnIndex, pATI, &pATI->NewHW, + pScreenInfo->currentMode)) + return FALSE; + + pScreenInfo->vtSema = TRUE; + + /* Save current state */ + ATIModeSave(pScreenInfo, pATI, &pATI->OldHW); + + /* Set graphics state */ + ATIModeSet(pScreenInfo, pATI, &pATI->NewHW); + + /* Possibly blank the screen */ + if (pScreen) + (void)ATISaveScreen(pScreen, SCREEN_SAVER_ON); + + /* Position the screen */ + (*pScreenInfo->AdjustFrame)(pScreenInfo->scrnIndex, + pScreenInfo->frameX0, pScreenInfo->frameY0, 0); + + SetTimeSinceLastInputEvent(); + + return TRUE; +} + +/* + * ATILeaveGraphics -- + * + * This function restores the hardware to its previous state. + */ +void +ATILeaveGraphics +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + if (pScreenInfo->vtSema) + { + /* If not exiting, save graphics video state */ + if (!xf86ServerIsExiting()) + ATIModeSave(pScreenInfo, pATI, &pATI->NewHW); + + /* Restore mode in effect on server entry */ + ATIModeSet(pScreenInfo, pATI, &pATI->OldHW); + + pScreenInfo->vtSema = FALSE; + } + + /* Lock device */ + ATILock(pATI); + + /* Unmap apertures */ + +#ifdef AVOID_DGA + + if (!pATI->Closeable) + +#else /* AVOID_DGA */ + + if (!pATI->Closeable || !pATI->nDGAMode) + +#endif /* AVOID_DGA */ + + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + + SetTimeSinceLastInputEvent(); +} + +/* + * ATISwitchMode -- + * + * This function switches to another graphics video state. + */ +Bool +ATISwitchMode +( + int iScreen, + DisplayModePtr pMode, + int flags +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + /* Calculate new hardware data */ + if (!ATIModeCalculate(iScreen, pATI, &pATI->NewHW, pMode)) + return FALSE; + + /* Set new hardware state */ + if (pScreenInfo->vtSema) + { + pScreenInfo->currentMode = pMode; + ATIModeSet(pScreenInfo, pATI, &pATI->NewHW); + } + + SetTimeSinceLastInputEvent(); + + return TRUE; +} + +/* + * ATIEnterVT -- + * + * This function sets the server's virtual console to a graphics video state. + */ +Bool +ATIEnterVT +( + int iScreen, + int flags +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; + ScreenPtr pScreen = pScreenInfo->pScreen; + ATIPtr pATI = ATIPTR(pScreenInfo); + PixmapPtr pScreenPixmap; + DevUnion PixmapPrivate; + Bool Entered; + + if (!ATIEnterGraphics(NULL, pScreenInfo, pATI)) + return FALSE; + + /* The rest of this isn't needed for shadowfb */ + if (pATI->OptionShadowFB) + return TRUE; + +#ifndef AVOID_CPIO + + /* If used, modify banking interface */ + if (!miModifyBanking(pScreen, &pATI->BankInfo)) + return FALSE; + +#endif /* AVOID_CPIO */ + + pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen); + PixmapPrivate = pScreenPixmap->devPrivate; + if (!PixmapPrivate.ptr) + pScreenPixmap->devPrivate = pScreenInfo->pixmapPrivate; + + /* Tell framebuffer about remapped aperture */ + Entered = (*pScreen->ModifyPixmapHeader)(pScreenPixmap, + -1, -1, -1, -1, -1, pATI->pMemory); + + if (!PixmapPrivate.ptr) + { + pScreenInfo->pixmapPrivate = pScreenPixmap->devPrivate; + pScreenPixmap->devPrivate.ptr = NULL; + } + + return Entered; +} + +/* + * ATILeaveVT -- + * + * This function restores the server's virtual console to its state on server + * entry. + */ +void +ATILeaveVT +( + int iScreen, + int flags +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; + + ATILeaveGraphics(pScreenInfo, ATIPTR(pScreenInfo)); +} + +/* + * ATIFreeScreen -- + * + * This function frees all driver data related to a screen. + */ +void +ATIFreeScreen +( + int iScreen, + int flags +) +{ + ScreenPtr pScreen = screenInfo.screens[iScreen]; + ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->Closeable || (serverGeneration > 1)) + ATII2CFreeScreen(iScreen); + + if (pATI->Closeable) + (void)(*pScreen->CloseScreen)(iScreen, pScreen); + + ATILeaveGraphics(pScreenInfo, pATI); + +#ifndef AVOID_CPIO + + xfree(pATI->OldHW.frame_buffer); + xfree(pATI->NewHW.frame_buffer); + +#endif /* AVOID_CPIO */ + + xfree(pATI->pShadow); + +#ifndef AVOID_DGA + + xfree(pATI->pDGAMode); + +#endif /* AVOID_DGA */ + + xfree(pATI); + pScreenInfo->driverPrivate = NULL; +} diff --git a/src/aticonsole.h b/src/aticonsole.h new file mode 100644 index 0000000..da71c65 --- /dev/null +++ b/src/aticonsole.h @@ -0,0 +1,46 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticonsole.h,v 1.9 2003/01/01 19:16:31 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATICONSOLE_H___ +#define ___ATICONSOLE_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern Bool ATISaveScreen FunctionPrototype((ScreenPtr, int)); +extern void ATISetDPMSMode FunctionPrototype((ScrnInfoPtr, int, int)); + +extern Bool ATIEnterGraphics FunctionPrototype((ScreenPtr, ScrnInfoPtr, + ATIPtr)); +extern void ATILeaveGraphics FunctionPrototype((ScrnInfoPtr, ATIPtr)); + +extern Bool ATISwitchMode FunctionPrototype((int, DisplayModePtr, int)); + +extern Bool ATIEnterVT FunctionPrototype((int, int)); +extern void ATILeaveVT FunctionPrototype((int, int)); + +extern void ATIFreeScreen FunctionPrototype((int, int)); + +#endif /* ___ATICONSOLE_H___ */ diff --git a/src/aticrtc.h b/src/aticrtc.h new file mode 100644 index 0000000..ba2a7a1 --- /dev/null +++ b/src/aticrtc.h @@ -0,0 +1,43 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticrtc.h,v 1.8 2003/01/01 19:16:31 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATICRTC_H___ +#define ___ATICRTC_H___ 1 + +/* + * CRTC related definitions. + */ +typedef enum +{ + +#ifndef AVOID_CPIO + + ATI_CRTC_VGA, /* Use VGA CRTC */ + ATI_CRTC_8514, /* Use 8514/Mach8/Mach32 accelerator CRTC */ + +#endif /* AVOID_CPIO */ + + ATI_CRTC_MACH64 /* Use Mach64 accelerator CRTC */ +} ATICRTCType; + +#endif /* ___ATICRTC_H___ */ diff --git a/src/aticursor.c b/src/aticursor.c new file mode 100644 index 0000000..9846f22 --- /dev/null +++ b/src/aticursor.c @@ -0,0 +1,75 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticursor.c,v 1.4 2003/04/23 21:51:27 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiadapter.h" +#include "aticursor.h" +#include "atimach64cursor.h" +#include "atistruct.h" + +#include "xf86.h" + +/* + * ATIInitializeCursor -- + * + * This function initialises the screen cursor. + */ +Bool +ATIInitializeCursor +( + ScreenPtr pScreen, + ATIPtr pATI +) +{ + /* Initialise software cursor */ + if (!miDCInitialize(pScreen, xf86GetPointerScreenFuncs())) + return FALSE; + + if (pATI->Cursor == ATI_CURSOR_SOFTWARE) + return TRUE; + + if (!(pATI->pCursorInfo = xf86CreateCursorInfoRec())) + return FALSE; + + switch (pATI->Adapter) + { + case ATI_ADAPTER_MACH64: + if (ATIMach64CursorInit(pATI->pCursorInfo)) + break; + /* Fall through */ + + default: + xf86DestroyCursorInfoRec(pATI->pCursorInfo); + pATI->pCursorInfo = NULL; + return FALSE; + } + + if (xf86InitCursor(pScreen, pATI->pCursorInfo)) + { + xf86SetSilkenMouse(pScreen); + return TRUE; + } + + xf86DestroyCursorInfoRec(pATI->pCursorInfo); + pATI->pCursorInfo = NULL; + return FALSE; +} diff --git a/src/aticursor.h b/src/aticursor.h new file mode 100644 index 0000000..71d0a9a --- /dev/null +++ b/src/aticursor.h @@ -0,0 +1,44 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/aticursor.h,v 1.3 2003/01/01 19:16:31 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATICURSOR_H___ +#define ___ATICURSOR_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "screenint.h" + +/* + * Cursor related definitions. + */ +typedef enum +{ + ATI_CURSOR_SOFTWARE, /* Software cursor */ + ATI_CURSOR_HARDWARE, /* Hardware cursor provided by CRTC */ + ATI_CURSOR_DAC /* Hardware cursor provided by RAMDAC */ +} ATICursorType; + +extern Bool ATIInitializeCursor FunctionPrototype((ScreenPtr, ATIPtr)); + +#endif /* ___ATICURSOR_H___ */ diff --git a/src/atidac.c b/src/atidac.c new file mode 100644 index 0000000..cf59556 --- /dev/null +++ b/src/atidac.c @@ -0,0 +1,522 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidac.c,v 1.18 2003/02/25 17:58:13 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atidac.h" +#include "atimach64io.h" +#include "atimono.h" + +/* + * RAMDAC-related definitions. + */ +const SymTabRec ATIDACDescriptors[] = +{ /* Keep this table in ascending DACType order */ + {ATI_DAC_ATI68830, "ATI 68830 or similar"}, + {ATI_DAC_SC11483, "Sierra 11483 or similar"}, + {ATI_DAC_ATI68875, "ATI 68875 or similar"}, + {ATI_DAC_TVP3026_A, "TI ViewPoint3026 or similar"}, + {ATI_DAC_GENERIC, "Brooktree 476 or similar"}, + {ATI_DAC_BT481, "Brooktree 481 or similar"}, + {ATI_DAC_ATT20C491, "AT&T 20C491 or similar"}, + {ATI_DAC_SC15026, "Sierra 15026 or similar"}, + {ATI_DAC_MU9C1880, "Music 9C1880 or similar"}, + {ATI_DAC_IMSG174, "Inmos G174 or similar"}, + {ATI_DAC_ATI68860_B, "ATI 68860 (Revision B) or similar"}, + {ATI_DAC_ATI68860_C, "ATI 68860 (Revision C) or similar"}, + {ATI_DAC_TVP3026_B, "TI ViewPoint3026 or similar"}, + {ATI_DAC_STG1700, "SGS-Thompson 1700 or similar"}, + {ATI_DAC_ATT20C498, "AT&T 20C498 or similar"}, + {ATI_DAC_STG1702, "SGS-Thompson 1702 or similar"}, + {ATI_DAC_SC15021, "Sierra 15021 or similar"}, + {ATI_DAC_ATT21C498, "AT&T 21C498 or similar"}, + {ATI_DAC_STG1703, "SGS-Thompson 1703 or similar"}, + {ATI_DAC_CH8398, "Chrontel 8398 or similar"}, + {ATI_DAC_ATT20C408, "AT&T 20C408 or similar"}, + {ATI_DAC_INTERNAL, "Internal"}, + {ATI_DAC_IBMRGB514, "IBM RGB 514 or similar"}, + {ATI_DAC_UNKNOWN, "Unknown"} /* Must be last */ +}; + +#ifndef AVOID_CPIO + +/* + * ATISetDACIOPorts -- + * + * This function sets up DAC access I/O port numbers. + */ +void +ATISetDACIOPorts +( + ATIPtr pATI, + ATICRTCType crtc +) +{ + switch (crtc) + { + case ATI_CRTC_VGA: + pATI->CPIO_DAC_DATA = VGA_DAC_DATA; + pATI->CPIO_DAC_MASK = VGA_DAC_MASK; + pATI->CPIO_DAC_READ = VGA_DAC_READ; + pATI->CPIO_DAC_WRITE = VGA_DAC_WRITE; + pATI->CPIO_DAC_WAIT = GENS1(pATI->CPIO_VGABase); + break; + + case ATI_CRTC_8514: + pATI->CPIO_DAC_DATA = IBM_DAC_DATA; + pATI->CPIO_DAC_MASK = IBM_DAC_MASK; + pATI->CPIO_DAC_READ = IBM_DAC_READ; + pATI->CPIO_DAC_WRITE = IBM_DAC_WRITE; + pATI->CPIO_DAC_WAIT = pATI->CPIO_DAC_MASK; + break; + + case ATI_CRTC_MACH64: + pATI->CPIO_DAC_DATA = ATIIOPort(DAC_REGS) + 1; + pATI->CPIO_DAC_MASK = ATIIOPort(DAC_REGS) + 2; + pATI->CPIO_DAC_READ = ATIIOPort(DAC_REGS) + 3; + pATI->CPIO_DAC_WRITE = ATIIOPort(DAC_REGS) + 0; + pATI->CPIO_DAC_WAIT = pATI->CPIOBase; + break; + + default: + break; + } +} + +#endif /* AVOID_CPIO */ + +/* + * ATIGetDACCmdReg -- + * + * Setup to access a RAMDAC's command register. + */ +CARD8 +ATIGetDACCmdReg +( + ATIPtr pATI +) +{ + +#ifdef AVOID_CPIO + + (void)in8(M64_DAC_WRITE); /* Reset to PEL mode */ + (void)in8(M64_DAC_MASK); + (void)in8(M64_DAC_MASK); + (void)in8(M64_DAC_MASK); + return in8(M64_DAC_MASK); + +#else /* AVOID_CPIO */ + + (void)inb(pATI->CPIO_DAC_WRITE); /* Reset to PEL mode */ + (void)inb(pATI->CPIO_DAC_MASK); + (void)inb(pATI->CPIO_DAC_MASK); + (void)inb(pATI->CPIO_DAC_MASK); + return inb(pATI->CPIO_DAC_MASK); + +#endif /* AVOID_CPIO */ + +} + +/* + * ATIDACPreInit -- + * + * This function initialises the fields in an ATIHWRec that relate to DACs. + */ +void +ATIDACPreInit +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + int Index, Index2; + CARD8 maxColour = (1 << pATI->rgbBits) - 1; + + pATIHW->dac_read = pATIHW->dac_write = 0x00U; + pATIHW->dac_mask = 0xFFU; + + /* + * Set colour lookup table. The first entry has already been zeroed out. + */ + if (pATI->depth > 8) + for (Index = 1; Index < (NumberOf(pATIHW->lut) / 3); Index++) + { + Index2 = Index * 3; + pATIHW->lut[Index2 + 0] = + pATIHW->lut[Index2 + 1] = + pATIHW->lut[Index2 + 2] = Index; + } + else + { + /* + * Initialise hardware colour map so that use of uninitialised + * software colour map entries can easily be seen. For 256-colour + * modes, this doesn't remain effective for very long... + */ + pATIHW->lut[3] = pATIHW->lut[4] = pATIHW->lut[5] = 0xFFU; + for (Index = 2; Index < (NumberOf(pATIHW->lut) / 3); Index++) + { + Index2 = Index * 3; + pATIHW->lut[Index2 + 0] = maxColour; + pATIHW->lut[Index2 + 1] = 0x00U; + pATIHW->lut[Index2 + 2] = maxColour; + } + +#ifndef AVOID_CPIO + + if (pATI->depth == 1) + { + rgb blackColour = pScreenInfo->display->blackColour, + whiteColour = pScreenInfo->display->whiteColour; + + if (blackColour.red > maxColour) + blackColour.red = maxColour; + if (blackColour.green > maxColour) + blackColour.green = maxColour; + if (blackColour.blue > maxColour) + blackColour.blue = maxColour; + if (whiteColour.red > maxColour) + whiteColour.red = maxColour; + if (whiteColour.green > maxColour) + whiteColour.green = maxColour; + if (whiteColour.blue > maxColour) + whiteColour.blue = maxColour; + + if ((blackColour.red == whiteColour.red) && + (blackColour.green == whiteColour.green) && + (blackColour.blue == whiteColour.blue)) + { + blackColour.red ^= maxColour; + blackColour.green ^= maxColour; + blackColour.blue ^= maxColour; + } + + pATIHW->lut[(MONO_BLACK * 3) + 0] = blackColour.red; + pATIHW->lut[(MONO_BLACK * 3) + 1] = blackColour.green; + pATIHW->lut[(MONO_BLACK * 3) + 2] = blackColour.blue; + pATIHW->lut[(MONO_WHITE * 3) + 0] = whiteColour.red; + pATIHW->lut[(MONO_WHITE * 3) + 1] = whiteColour.green; + pATIHW->lut[(MONO_WHITE * 3) + 2] = whiteColour.blue; + } + + if (pATIHW->crtc == ATI_CRTC_VGA) + { + /* Initialise overscan to black */ + Index = pATIHW->attr[17] * 3; + pATIHW->lut[Index + 0] = + pATIHW->lut[Index + 1] = + pATIHW->lut[Index + 2] = 0x00U; + } + +#endif /* AVOID_CPIO */ + + } +} + +/* + * ATIDACSave -- + * + * This function is called to save the current RAMDAC state into an ATIHWRec + * structure occurrence. + */ +void +ATIDACSave +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + int Index; + +#ifdef AVOID_CPIO + + pATIHW->dac_read = in8(M64_DAC_READ); + DACDelay; + pATIHW->dac_write = in8(M64_DAC_WRITE); + DACDelay; + pATIHW->dac_mask = in8(M64_DAC_MASK); + DACDelay; + + /* Save DAC's colour lookup table */ + out8(M64_DAC_MASK, 0xFFU); + DACDelay; + out8(M64_DAC_READ, 0x00U); + DACDelay; + for (Index = 0; Index < NumberOf(pATIHW->lut); Index++) + { + pATIHW->lut[Index] = in8(M64_DAC_DATA); + DACDelay; + } + + out8(M64_DAC_MASK, pATIHW->dac_mask); + DACDelay; + out8(M64_DAC_READ, pATIHW->dac_read); + DACDelay; + +#else /* AVOID_CPIO */ + + ATISetDACIOPorts(pATI, pATIHW->crtc); + + pATIHW->dac_read = inb(pATI->CPIO_DAC_READ); + DACDelay; + pATIHW->dac_write = inb(pATI->CPIO_DAC_WRITE); + DACDelay; + pATIHW->dac_mask = inb(pATI->CPIO_DAC_MASK); + DACDelay; + + /* Save DAC's colour lookup table */ + outb(pATI->CPIO_DAC_MASK, 0xFFU); + DACDelay; + outb(pATI->CPIO_DAC_READ, 0x00U); + DACDelay; + for (Index = 0; Index < NumberOf(pATIHW->lut); Index++) + { + pATIHW->lut[Index] = inb(pATI->CPIO_DAC_DATA); + DACDelay; + } + + outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask); + DACDelay; + outb(pATI->CPIO_DAC_READ, pATIHW->dac_read); + DACDelay; + +#endif /* AVOID_CPIO */ + +} + +/* + * ATIDACSet -- + * + * This function loads RAMDAC data from an ATIHWRec structure occurrence. + */ +void +ATIDACSet +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + int Index; + +#ifdef AVOID_CPIO + + /* Load DAC's colour lookup table */ + out8(M64_DAC_MASK, 0xFFU); + DACDelay; + out8(M64_DAC_WRITE, 0x00U); + DACDelay; + for (Index = 0; Index < NumberOf(pATIHW->lut); Index++) + { + out8(M64_DAC_DATA, pATIHW->lut[Index]); + DACDelay; + } + + out8(M64_DAC_MASK, pATIHW->dac_mask); + DACDelay; + out8(M64_DAC_READ, pATIHW->dac_read); + DACDelay; + out8(M64_DAC_WRITE, pATIHW->dac_write); + DACDelay; + +#else /* AVOID_CPIO */ + + ATISetDACIOPorts(pATI, pATIHW->crtc); + + /* Load DAC's colour lookup table */ + outb(pATI->CPIO_DAC_MASK, 0xFFU); + DACDelay; + outb(pATI->CPIO_DAC_WRITE, 0x00U); + DACDelay; + for (Index = 0; Index < NumberOf(pATIHW->lut); Index++) + { + outb(pATI->CPIO_DAC_DATA, pATIHW->lut[Index]); + DACDelay; + } + + outb(pATI->CPIO_DAC_MASK, pATIHW->dac_mask); + DACDelay; + outb(pATI->CPIO_DAC_READ, pATIHW->dac_read); + DACDelay; + outb(pATI->CPIO_DAC_WRITE, pATIHW->dac_write); + DACDelay; + +#endif /* AVOID_CPIO */ + +} + +/* + * ATILoadPalette -- + * + * This function updates the RAMDAC's LUT and the in-memory copy of it in + * NewHW. + */ +void +ATILoadPalette +( + ScrnInfoPtr pScreenInfo, + int nColours, + int *Indices, + LOCO *Colours, + VisualPtr pVisual +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + CARD8 *LUTEntry; + int i, j, Index; + + if (((pVisual->class | DynamicClass) == DirectColor) && + ((1 << pVisual->nplanes) > (SizeOf(pATI->NewHW.lut) / 3))) + { + int reds = pVisual->redMask >> pVisual->offsetRed; + int greens = pVisual->greenMask >> pVisual->offsetGreen; + int blues = pVisual->blueMask >> pVisual->offsetBlue; + + int redShift = 8 - pATI->weight.red; + int greenShift = 8 - pATI->weight.green; + int blueShift = 8 - pATI->weight.blue; + + int redMult = 3 << redShift; + int greenMult = 3 << greenShift; + int blueMult = 3 << blueShift; + + int minShift; + + CARD8 fChanged[SizeOf(pATI->NewHW.lut) / 3]; + + (void)memset(fChanged, SizeOf(fChanged), 0); + + minShift = redShift; + if (minShift > greenShift) + minShift = greenShift; + if (minShift > blueShift) + minShift = blueShift; + + for (i = 0; i < nColours; i++) + { + if((Index = Indices[i]) < 0) + continue; + + if (Index <= reds) + { + j = Index * redMult; + pATI->NewHW.lut[j + 0] = Colours[Index].red; + fChanged[j / 3] = TRUE; + } + if (Index <= greens) + { + j = Index * greenMult; + pATI->NewHW.lut[j + 1] = Colours[Index].green; + fChanged[j / 3] = TRUE; + } + if (Index <= blues) + { + j = Index * blueMult; + pATI->NewHW.lut[j + 2] = Colours[Index].blue; + fChanged[j / 3] = TRUE; + } + } + + if (pScreenInfo->vtSema || pATI->currentMode) + { + /* Rewrite LUT entries that could have been changed */ + i = 1 << minShift; + LUTEntry = pATI->NewHW.lut; + + for (Index = 0; + Index < (SizeOf(pATI->NewHW.lut) / 3); + Index += i, LUTEntry += i * 3) + { + if (!fChanged[Index]) + continue; + +#ifdef AVOID_CPIO + + out8(M64_DAC_WRITE, Index); + DACDelay; + out8(M64_DAC_DATA, LUTEntry[0]); + DACDelay; + out8(M64_DAC_DATA, LUTEntry[1]); + DACDelay; + out8(M64_DAC_DATA, LUTEntry[2]); + DACDelay; + +#else /* AVOID_CPIO */ + + outb(pATI->CPIO_DAC_WRITE, Index); + DACDelay; + outb(pATI->CPIO_DAC_DATA, LUTEntry[0]); + DACDelay; + outb(pATI->CPIO_DAC_DATA, LUTEntry[1]); + DACDelay; + outb(pATI->CPIO_DAC_DATA, LUTEntry[2]); + DACDelay; + +#endif /* AVOID_CPIO */ + + } + } + } + else + { + for (i = 0; i < nColours; i++) + { + Index = Indices[i]; + if ((Index < 0) || (Index >= (SizeOf(pATI->NewHW.lut) / 3))) + continue; + + LUTEntry = &pATI->NewHW.lut[Index * 3]; + LUTEntry[0] = Colours[Index].red; + LUTEntry[1] = Colours[Index].green; + LUTEntry[2] = Colours[Index].blue; + + if (pScreenInfo->vtSema || pATI->currentMode) + { + +#ifdef AVOID_CPIO + + out8(M64_DAC_WRITE, Index); + DACDelay; + out8(M64_DAC_DATA, LUTEntry[0]); + DACDelay; + out8(M64_DAC_DATA, LUTEntry[1]); + DACDelay; + out8(M64_DAC_DATA, LUTEntry[2]); + DACDelay; + +#else /* AVOID_CPIO */ + + outb(pATI->CPIO_DAC_WRITE, Index); + DACDelay; + outb(pATI->CPIO_DAC_DATA, LUTEntry[0]); + DACDelay; + outb(pATI->CPIO_DAC_DATA, LUTEntry[1]); + DACDelay; + outb(pATI->CPIO_DAC_DATA, LUTEntry[2]); + DACDelay; + +#endif /* AVOID_CPIO */ + + } + } + } +} diff --git a/src/atidac.h b/src/atidac.h new file mode 100644 index 0000000..097858e --- /dev/null +++ b/src/atidac.h @@ -0,0 +1,103 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidac.h,v 1.15 2003/01/01 19:16:31 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIDAC_H___ + +#if !defined(___ATI_H___) && defined(XFree86Module) +# error missing #include "ati.h" before #include "atidac.h" +# undef XFree86Module +#endif + +#define ___ATIDAC_H___ 1 + +#include "aticrtc.h" +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +#include "colormapst.h" + +/* + * RAMDAC-related definitions. + */ +#define ATI_DAC_MAX_TYPE MaxBits(DACTYPE) +#define ATI_DAC_MAX_SUBTYPE MaxBits(BIOS_INIT_DAC_SUBTYPE) + +#define ATI_DAC(_Type, _Subtype) (((_Type) << 4) | (_Subtype)) + +#define ATI_DAC_ATI68830 ATI_DAC(0x0U, 0x0U) +#define ATI_DAC_SC11483 ATI_DAC(0x1U, 0x0U) +#define ATI_DAC_ATI68875 ATI_DAC(0x2U, 0x0U) +#define ATI_DAC_TVP3026_A ATI_DAC(0x2U, 0x7U) +#define ATI_DAC_GENERIC ATI_DAC(0x3U, 0x0U) +#define ATI_DAC_BT481 ATI_DAC(0x4U, 0x0U) +#define ATI_DAC_ATT20C491 ATI_DAC(0x4U, 0x1U) +#define ATI_DAC_SC15026 ATI_DAC(0x4U, 0x2U) +#define ATI_DAC_MU9C1880 ATI_DAC(0x4U, 0x3U) +#define ATI_DAC_IMSG174 ATI_DAC(0x4U, 0x4U) +#define ATI_DAC_ATI68860_B ATI_DAC(0x5U, 0x0U) +#define ATI_DAC_ATI68860_C ATI_DAC(0x5U, 0x1U) +#define ATI_DAC_TVP3026_B ATI_DAC(0x5U, 0x7U) +#define ATI_DAC_STG1700 ATI_DAC(0x6U, 0x0U) +#define ATI_DAC_ATT20C498 ATI_DAC(0x6U, 0x1U) +#define ATI_DAC_STG1702 ATI_DAC(0x7U, 0x0U) +#define ATI_DAC_SC15021 ATI_DAC(0x7U, 0x1U) +#define ATI_DAC_ATT21C498 ATI_DAC(0x7U, 0x2U) +#define ATI_DAC_STG1703 ATI_DAC(0x7U, 0x3U) +#define ATI_DAC_CH8398 ATI_DAC(0x7U, 0x4U) +#define ATI_DAC_ATT20C408 ATI_DAC(0x7U, 0x5U) +#define ATI_DAC_INTERNAL ATI_DAC(0x8U, 0x0U) +#define ATI_DAC_IBMRGB514 ATI_DAC(0x9U, 0x0U) +#define ATI_DAC_UNKNOWN ATI_DAC((ATI_DAC_MAX_TYPE << 2) + 3, \ + ATI_DAC_MAX_SUBTYPE) +extern const SymTabRec ATIDACDescriptors[]; + +#ifdef AVOID_CPIO + +# define DACDelay /* Nothing */ + +#else /* AVOID_CPIO */ + +# define DACDelay \ + do \ + { \ + (void)inb(pATI->CPIO_DAC_WAIT); \ + (void)inb(pATI->CPIO_DAC_WAIT); \ + } while (0) + + extern void ATISetDACIOPorts FunctionPrototype((ATIPtr, ATICRTCType)); + +#endif /* AVOID_CPIO */ + +extern CARD8 ATIGetDACCmdReg FunctionPrototype((ATIPtr)); + +extern void ATIDACPreInit FunctionPrototype((ScrnInfoPtr, ATIPtr, + ATIHWPtr)); +extern void ATIDACSave FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIDACSet FunctionPrototype((ATIPtr, ATIHWPtr)); + +extern void ATILoadPalette FunctionPrototype((ScrnInfoPtr, int, int *, + LOCO *, VisualPtr)); + +#endif /* ___ATIDAC_H___ */ diff --git a/src/atidecoder.c b/src/atidecoder.c new file mode 100644 index 0000000..60d3f9d --- /dev/null +++ b/src/atidecoder.c @@ -0,0 +1,47 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidecoder.c,v 1.1 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atidecoder.h" + +/* + * Video decoder definitions. + */ +const char *ATIDecoderNames[] = +{ + "No decoder", + "BrookTree BT819", + "Brooktree BT829", + "Brooktree BT829A", + "Philips SA7111", + "Philips SA7112", + "ATI Rage Theater", + "Unknown type (7)", + "Unknown type (8)", + "Unknown type (9)", + "Unknown type (10)", + "Unknown type (11)", + "Unknown type (12)", + "Unknown type (13)", + "Unknown type (14)", + "Unknown type (15)" +}; diff --git a/src/atidecoder.h b/src/atidecoder.h new file mode 100644 index 0000000..0c3cc5c --- /dev/null +++ b/src/atidecoder.h @@ -0,0 +1,52 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidecoder.h,v 1.1 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIDECODER_H___ +#define ___ATIDECODER_H___ 1 + +/* + * Video decoder definitions. + */ +typedef enum +{ + ATI_DECODER_NONE, + ATI_DECODER_BT819, + ATI_DECODER_BT829, + ATI_DECODER_BT829A, + ATI_DECODER_SA7111, + ATI_DECODER_SA7112, + ATI_DECODER_THEATER, + ATI_DECODER_7, + ATI_DECODER_8, + ATI_DECODER_9, + ATI_DECODER_10, + ATI_DECODER_11, + ATI_DECODER_12, + ATI_DECODER_13, + ATI_DECODER_14, + ATI_DECODER_15 +} ATIDecoderType; + +extern const char *ATIDecoderNames[]; + +#endif /* ___ATIDECODER_H___ */ diff --git a/src/atidga.c b/src/atidga.c new file mode 100644 index 0000000..81da7c9 --- /dev/null +++ b/src/atidga.c @@ -0,0 +1,479 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidga.c,v 1.10 2003/04/23 21:51:27 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef AVOID_DGA + +#include "ati.h" +#include "atiadjust.h" +#include "atichip.h" +#include "atidac.h" +#include "atidga.h" +#include "atiident.h" +#include "atimode.h" +#include "atistruct.h" + +#include "dgaproc.h" + +/* + * ATIDGAOpenFramebuffer -- + * + * This function returns various framebuffer attributes to a DGA client. + */ +static Bool +ATIDGAOpenFramebuffer +( + ScrnInfoPtr pScreenInfo, + char **DeviceName, + unsigned char **ApertureBase, + int *ApertureSize, + int *ApertureOffset, + int *flags +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + *DeviceName = NULL; /* No special device */ + *ApertureBase = (unsigned char *)(pATI->LinearBase); + *ApertureSize = pScreenInfo->videoRam * 1024; + *ApertureOffset = 0; /* Always */ + *flags = 0; /* Root premissions OS-dependent */ + + return TRUE; +} + +static int +BitsSet +( + unsigned long data +) +{ + unsigned long mask = 1; + int set = 0; + + for (; mask; mask <<= 1) + if (data & mask) + set++; + + return set; +} + +/* + * ATIDGASetMode -- + * + * This function sets a graphics mode for a DGA client. + */ +static Bool +ATIDGASetMode +( + ScrnInfoPtr pScreenInfo, + DGAModePtr pDGAMode +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + DisplayModePtr pMode; + int iScreen = pScreenInfo->scrnIndex; + int frameX0, frameY0; + + if (pDGAMode) + { + pMode = pDGAMode->mode; + pATI->depth = pDGAMode->depth; + pATI->bitsPerPixel = pDGAMode->bitsPerPixel; + pATI->displayWidth = + pDGAMode->bytesPerScanline * 8 / pATI->bitsPerPixel; + pATI->weight.red = BitsSet(pDGAMode->red_mask); + pATI->weight.green = BitsSet(pDGAMode->green_mask); + pATI->weight.blue = BitsSet(pDGAMode->blue_mask); + frameX0 = frameY0 = 0; + if (!pATI->currentMode) + pATI->currentMode = pScreenInfo->currentMode; + } + else + { + if (!(pMode = pATI->currentMode)) + return TRUE; + + pATI->depth = pScreenInfo->depth; + pATI->bitsPerPixel = pScreenInfo->bitsPerPixel; + pATI->displayWidth = pScreenInfo->displayWidth; + pATI->weight = pScreenInfo->weight; + frameX0 = pScreenInfo->frameX0; + frameY0 = pScreenInfo->frameY0; + } + + pATI->XModifier = pATI->bitsPerPixel / UnitOf(pATI->bitsPerPixel); + ATIAdjustPreInit(pATI); + ATIModePreInit(pScreenInfo, pATI, &pATI->NewHW); + + if (!(*pScreenInfo->SwitchMode)(iScreen, pMode, 0)) + return FALSE; + if (!pDGAMode) + pATI->currentMode = NULL; + (*pScreenInfo->AdjustFrame)(iScreen, frameX0, frameY0, 0); + + return TRUE; +} + +/* + * ATIDGASetViewport -- + * + * This function sets the display start address for a DGA client. + */ +static void +ATIDGASetViewport +( + ScrnInfoPtr pScreenInfo, + int x, + int y, + int flags +) +{ + (*pScreenInfo->AdjustFrame)(pScreenInfo->pScreen->myNum, x, y, flags); +} + +/* + * ATIDGAGetViewport -- + * + * This function returns the current status of prior DGA requests to set the + * adapter's display start address. + */ +static int +ATIDGAGetViewport +( + ScrnInfoPtr pScreenInfo +) +{ + return 0; /* There are never any pending requests */ +} + +/* + * ATIDGAFillRect -- + * + * This function calls XAA solid fill primitives to fill a rectangle. + */ +static void +ATIDGAFillRect +( + ScrnInfoPtr pScreenInfo, + int x, + int y, + int w, + int h, + unsigned long colour +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; + + (*pXAAInfo->SetupForSolidFill)(pScreenInfo, (int)colour, GXcopy, + (CARD32)(~0)); + (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, x, y, w, h); + + if (pScreenInfo->bitsPerPixel == pATI->bitsPerPixel) + SET_SYNC_FLAG(pXAAInfo); +} + +/* + * ATIDGABlitRect -- + * + * This function calls XAA screen-to-screen copy primitives to copy a + * rectangle. + */ +static void +ATIDGABlitRect +( + ScrnInfoPtr pScreenInfo, + int xSrc, + int ySrc, + int w, + int h, + int xDst, + int yDst +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; + int xdir = ((xSrc < xDst) && (ySrc == yDst)) ? -1 : 1; + int ydir = (ySrc < yDst) ? -1 : 1; + + (*pXAAInfo->SetupForScreenToScreenCopy)(pScreenInfo, + xdir, ydir, GXcopy, (CARD32)(~0), -1); + (*pXAAInfo->SubsequentScreenToScreenCopy)(pScreenInfo, + xSrc, ySrc, xDst, yDst, w, h); + + if (pScreenInfo->bitsPerPixel == pATI->bitsPerPixel) + SET_SYNC_FLAG(pXAAInfo); +} + +/* + * ATIDGABlitTransRect -- + * + * This function calls XAA screen-to-screen copy primitives to transparently + * copy a rectangle. + */ +static void +ATIDGABlitTransRect +( + ScrnInfoPtr pScreenInfo, + int xSrc, + int ySrc, + int w, + int h, + int xDst, + int yDst, + unsigned long colour +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; + int xdir = ((xSrc < xDst) && (ySrc == yDst)) ? -1 : 1; + int ydir = (ySrc < yDst) ? -1 : 1; + + pATI->XAAForceTransBlit = TRUE; + + (*pXAAInfo->SetupForScreenToScreenCopy)(pScreenInfo, + xdir, ydir, GXcopy, (CARD32)(~0), (int)colour); + + pATI->XAAForceTransBlit = FALSE; + + (*pXAAInfo->SubsequentScreenToScreenCopy)(pScreenInfo, + xSrc, ySrc, xDst, yDst, w, h); + + if (pScreenInfo->bitsPerPixel == pATI->bitsPerPixel) + SET_SYNC_FLAG(pXAAInfo); +} + +/* + * ATIDGAAddModes -- + * + * This function translates DisplayModeRec's into DGAModeRec's. + */ +static void +ATIDGAAddModes +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + int flags, + int depth, + int bitsPerPixel, + int redMask, + int greenMask, + int blueMask, + int visualClass +) +{ + DisplayModePtr pMode = pScreenInfo->modes; + DGAModePtr pDGAMode; + int displayWidth = pScreenInfo->displayWidth; + int videoBits = pScreenInfo->videoRam * 1024 * 8; + int xViewportStep = 64 / UnitOf(bitsPerPixel); + int modePitch, bitsPerScanline, maxViewportY; + + if (bitsPerPixel != pScreenInfo->bitsPerPixel) + displayWidth = 0; + + while (1) + { + /* Weed out multiscanned modes */ + if ((pMode->VScan <= 1) || + ((pMode->VScan == 2) && !(pMode->Flags & V_DBLSCAN))) + { + /* + * For code simplicity, ensure DGA mode pitch is a multiple of 64 + * bytes. + */ + if (!(modePitch = displayWidth)) + { + modePitch = ((64 * 8) / UnitOf(bitsPerPixel)) - 1; + modePitch = (pMode->HDisplay + modePitch) & ~modePitch; + } + + /* Ensure the mode fits in video memory */ + if ((modePitch * bitsPerPixel * pMode->VDisplay) <= videoBits) + { + /* Stop generating modes on out-of-memory conditions */ + pDGAMode = xrealloc(pATI->pDGAMode, + (pATI->nDGAMode + 1) * SizeOf(DGAModeRec)); + if (!pDGAMode) + break; + + pATI->pDGAMode = pDGAMode; + pDGAMode += pATI->nDGAMode; + pATI->nDGAMode++; + (void)memset(pDGAMode, 0, SizeOf(DGAModeRec)); + + /* Fill in the mode structure */ + pDGAMode->mode = pMode; + pDGAMode->flags = flags; + if (bitsPerPixel == pScreenInfo->bitsPerPixel) + { + pDGAMode->flags |= DGA_PIXMAP_AVAILABLE; + pDGAMode->address = pATI->pMemory; + + if (pATI->pXAAInfo) + pDGAMode->flags &= ~DGA_CONCURRENT_ACCESS; + } + if ((pMode->Flags & V_DBLSCAN) || (pMode->VScan > 1)) + pDGAMode->flags |= DGA_DOUBLESCAN; + if (pMode->Flags & V_INTERLACE) + pDGAMode->flags |= DGA_INTERLACED; + + pDGAMode->byteOrder = pScreenInfo->imageByteOrder; + pDGAMode->depth = depth; + pDGAMode->bitsPerPixel = bitsPerPixel; + pDGAMode->red_mask = redMask; + pDGAMode->green_mask = greenMask; + pDGAMode->blue_mask = blueMask; + pDGAMode->visualClass = visualClass; + + pDGAMode->viewportWidth = pMode->HDisplay; + pDGAMode->viewportHeight = pMode->VDisplay; + pDGAMode->xViewportStep = xViewportStep; + pDGAMode->yViewportStep = 1; + + bitsPerScanline = modePitch * bitsPerPixel; + pDGAMode->bytesPerScanline = bitsPerScanline / 8; + pDGAMode->imageWidth = pDGAMode->pixmapWidth = modePitch; + pDGAMode->imageHeight = pDGAMode->pixmapHeight = + videoBits / bitsPerScanline; + + pDGAMode->maxViewportX = + pDGAMode->imageWidth - pDGAMode->viewportWidth; + pDGAMode->maxViewportY = + pDGAMode->imageHeight - pDGAMode->viewportHeight; + maxViewportY = + ((((pATI->AdjustMaxBase * 8) / bitsPerPixel) + + xViewportStep) / modePitch) - 1; + if (maxViewportY < pDGAMode->maxViewportY) + pDGAMode->maxViewportY = maxViewportY; + } + } + + if ((pMode = pMode->next) == pScreenInfo->modes) + { + if (!displayWidth) + break; + + displayWidth = 0; + } + } +} + +/* + * ATIDGAInit -- + * + * This function initialises the driver's support for the DGA extension. + */ +Bool +ATIDGAInit +( + ScreenPtr pScreen, + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + XAAInfoRecPtr pXAAInfo; + int flags; + + if (!pATI->nDGAMode) + { + +#ifndef AVOID_CPIO + + /* + * Contrary to previous extension versions, DGA 2 does not support + * banked framebuffers. Also, disable DGA when non-DGA server modes + * are planar. + */ + if (pATI->BankInfo.BankSize || (pScreenInfo->depth <= 4)) + return FALSE; + +#endif /* AVOID_CPIO */ + + /* Set up DGA callbacks */ + pATI->ATIDGAFunctions.OpenFramebuffer = ATIDGAOpenFramebuffer; + pATI->ATIDGAFunctions.SetMode = ATIDGASetMode; + pATI->ATIDGAFunctions.SetViewport = ATIDGASetViewport; + pATI->ATIDGAFunctions.GetViewport = ATIDGAGetViewport; + + flags = 0; + if ((pXAAInfo = pATI->pXAAInfo)) + { + pATI->ATIDGAFunctions.Sync = pXAAInfo->Sync; + if (pXAAInfo->SetupForSolidFill && + pXAAInfo->SubsequentSolidFillRect) + { + flags |= DGA_FILL_RECT; + pATI->ATIDGAFunctions.FillRect = ATIDGAFillRect; + } + if (pXAAInfo->SetupForScreenToScreenCopy && + pXAAInfo->SubsequentScreenToScreenCopy) + { + flags |= DGA_BLIT_RECT | DGA_BLIT_RECT_TRANS; + pATI->ATIDGAFunctions.BlitRect = ATIDGABlitRect; + pATI->ATIDGAFunctions.BlitTransRect = ATIDGABlitTransRect; + } + } + if (!flags) + flags = DGA_CONCURRENT_ACCESS; + + ATIDGAAddModes(pScreenInfo, pATI, flags, + 8, 8, 0, 0, 0, PseudoColor); + + if ((pATI->Chip >= ATI_CHIP_264CT) && + (pATI->Chipset == ATI_CHIPSET_ATI)) + { + ATIDGAAddModes(pScreenInfo, pATI, flags, + 15, 16, 0x7C00U, 0x03E0U, 0x001FU, TrueColor); + + ATIDGAAddModes(pScreenInfo, pATI, flags, + 16, 16, 0xF800U, 0x07E0U, 0x001FU, TrueColor); + + ATIDGAAddModes(pScreenInfo, pATI, flags, + 24, 24, 0x00FF0000U, 0x0000FF00U, 0x000000FFU, TrueColor); + + ATIDGAAddModes(pScreenInfo, pATI, flags, + 24, 32, 0x00FF0000U, 0x0000FF00U, 0x000000FFU, TrueColor); + + if (pATI->DAC != ATI_DAC_INTERNAL) /* Not first revision */ + { + ATIDGAAddModes(pScreenInfo, pATI, flags, + 15, 16, 0x7C00U, 0x03E0U, 0x001FU, DirectColor); + + ATIDGAAddModes(pScreenInfo, pATI, flags, + 16, 16, 0xF800U, 0x07E0U, 0x001FU, DirectColor); + + ATIDGAAddModes(pScreenInfo, pATI, flags, + 24, 24, 0x00FF0000U, 0x0000FF00U, 0x000000FFU, DirectColor); + + ATIDGAAddModes(pScreenInfo, pATI, flags, + 24, 32, 0x00FF0000U, 0x0000FF00U, 0x000000FFU, DirectColor); + } + } + } + + return DGAInit(pScreen, &pATI->ATIDGAFunctions, pATI->pDGAMode, + pATI->nDGAMode); +} + +#endif /* AVOID_DGA */ diff --git a/src/atidga.h b/src/atidga.h new file mode 100644 index 0000000..1a93879 --- /dev/null +++ b/src/atidga.h @@ -0,0 +1,38 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidga.h,v 1.7 2003/04/23 21:51:28 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIDGA_H___ +#define ___ATIDGA_H___ 1 + +#ifndef AVOID_DGA + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern Bool ATIDGAInit FunctionPrototype((ScreenPtr, ScrnInfoPtr, ATIPtr)); + +#endif /* AVOID_DGA */ + +#endif /* ___ATIDGA_H___ */ diff --git a/src/atidri.c b/src/atidri.c new file mode 100644 index 0000000..c3fd976 --- /dev/null +++ b/src/atidri.c @@ -0,0 +1,1547 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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. + */ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +/* Driver data structures */ +#include "ati.h" +#include "atibus.h" +#include "atidri.h" +#include "atiregs.h" +#include "atistruct.h" +#include "ativersion.h" + +#include "atimach64io.h" +#include "mach64_dri.h" +#include "mach64_common.h" +#include "mach64_sarea.h" + +/* X and server generic header files */ +#include "xf86.h" +#include "windowstr.h" + +/* GLX/DRI/DRM definitions */ +#define _XF86DRI_SERVER_ +#include "GL/glxtokens.h" +#include "sarea.h" + +static char ATIKernelDriverName[] = "mach64"; +static char ATIClientDriverName[] = "mach64"; + +/* Initialize the visual configs that are supported by the hardware. + * These are combined with the visual configs that the indirect + * rendering core supports, and the intersection is exported to the + * client. + */ +static Bool ATIInitVisualConfigs( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = NULL; + ATIConfigPrivPtr pATIConfigs = NULL; + ATIConfigPrivPtr *pATIConfigPtrs = NULL; + int i, accum, stencil, db; + + switch ( pATI->bitsPerPixel ) { + case 8: /* 8bpp mode is not support */ + case 15: /* FIXME */ + case 24: /* FIXME */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] ATIInitVisualConfigs failed (%d bpp not supported). " + "Disabling DRI.\n", pATI->bitsPerPixel); + return FALSE; + +#define ATI_USE_ACCUM 1 +#define ATI_USE_STENCIL 1 + + case 16: + + if ( pATI->depth != 16) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] ATIInitVisualConfigs failed (depth %d at 16 bpp not supported). " + "Disabling DRI.\n", pATI->depth); + return FALSE; + } + + numConfigs = 1; + if ( ATI_USE_ACCUM ) numConfigs *= 2; + if ( ATI_USE_STENCIL ) numConfigs *= 2; + numConfigs *= 2; /* single- and double-buffered */ + + pConfigs = (__GLXvisualConfig*) + xnfcalloc( sizeof(__GLXvisualConfig), numConfigs ); + if ( !pConfigs ) { + return FALSE; + } + pATIConfigs = (ATIConfigPrivPtr) + xnfcalloc( sizeof(ATIConfigPrivRec), numConfigs ); + if ( !pATIConfigs ) { + xfree( pConfigs ); + return FALSE; + } + pATIConfigPtrs = (ATIConfigPrivPtr*) + xnfcalloc( sizeof(ATIConfigPrivPtr), numConfigs ); + if ( !pATIConfigPtrs ) { + xfree( pConfigs ); + xfree( pATIConfigs ); + return FALSE; + } + + i = 0; + for (db = 0; db <= 1; db++) { + for ( accum = 0 ; accum <= ATI_USE_ACCUM ; accum++ ) { + for ( stencil = 0 ; stencil <= ATI_USE_STENCIL ; stencil++ ) { + pATIConfigPtrs[i] = &pATIConfigs[i]; + + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + pConfigs[i].alphaMask = 0x00000000; + if ( accum ) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = db ? TRUE : FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + pConfigs[i].depthSize = 16; + if ( stencil ) { /* Simulated in software */ + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if ( accum || stencil ) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + + case 32: + numConfigs = 1; + if ( ATI_USE_ACCUM ) numConfigs *= 2; + if ( ATI_USE_STENCIL ) numConfigs *= 2; + numConfigs *= 2; /* single- and double-buffered */ + + pConfigs = (__GLXvisualConfig*) + xnfcalloc( sizeof(__GLXvisualConfig), numConfigs ); + if ( !pConfigs ) { + return FALSE; + } + pATIConfigs = (ATIConfigPrivPtr) + xnfcalloc( sizeof(ATIConfigPrivRec), numConfigs ); + if ( !pATIConfigs ) { + xfree( pConfigs ); + return FALSE; + } + pATIConfigPtrs = (ATIConfigPrivPtr*) + xnfcalloc( sizeof(ATIConfigPrivPtr), numConfigs ); + if ( !pATIConfigPtrs ) { + xfree( pConfigs ); + xfree( pATIConfigs ); + return FALSE; + } + + i = 0; + for (db = 0; db <= 1; db++) { + for ( accum = 0 ; accum <= ATI_USE_ACCUM ; accum++ ) { + for ( stencil = 0 ; stencil <= ATI_USE_STENCIL ; stencil++ ) { + pATIConfigPtrs[i] = &pATIConfigs[i]; + + pConfigs[i].vid = -1; + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 8; + pConfigs[i].greenSize = 8; + pConfigs[i].blueSize = 8; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x00FF0000; + pConfigs[i].greenMask = 0x0000FF00; + pConfigs[i].blueMask = 0x000000FF; + pConfigs[i].alphaMask = 0x00000000; + if ( accum ) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + pConfigs[i].doubleBuffer = db ? TRUE : FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 24; + if ( stencil ) { /* Simulated in software */ + pConfigs[i].depthSize = 16; + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].depthSize = 16; + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if ( accum || stencil ) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + } + + pATI->numVisualConfigs = numConfigs; + pATI->pVisualConfigs = pConfigs; + pATI->pVisualConfigsPriv = pATIConfigs; + GlxSetVisualConfigs( numConfigs, pConfigs, (void**)pATIConfigPtrs ); + return TRUE; +} + +/* Create the ATI-specific context information */ +static Bool ATICreateContext( ScreenPtr pScreen, VisualPtr visual, + drm_context_t hwContext, void *pVisualConfigPriv, + DRIContextType contextStore ) +{ + /* Nothing yet */ + return TRUE; +} + +/* Destroy the ATI-specific context information */ +static void ATIDestroyContext( ScreenPtr pScreen, drm_context_t hwContext, + DRIContextType contextStore ) +{ + /* Nothing yet */ +} + +/* Called when the X server is woken up to allow the last client's + * context to be saved and the X server's context to be loaded. + * The client detects when it's context is not currently loaded and + * then loads it itself. The X server's context is loaded in the + * XAA Sync callback if NeedDRISync is set. + */ +static void ATIEnterServer( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if ( pATI->directRenderingEnabled && pATI->pXAAInfo ) { + pATI->pXAAInfo->NeedToSync = TRUE; + pATI->NeedDRISync = TRUE; + } +} + +/* Called when the X server goes to sleep to allow the X server's + * context to be saved and the last client's context to be loaded. + * The client detects when it's context is not currently loaded and + * then loads it itself. The X server keeps track of it's own state. + */ +static void ATILeaveServer( ScreenPtr pScreen ) +{ + /* Nothing yet */ +} + +/* Contexts can be swapped by the X server if necessary. This callback + * is currently only used to perform any functions necessary when + * entering or leaving the X server, and in the future might not be + * necessary. + */ +static void ATIDRISwapContext( ScreenPtr pScreen, + DRISyncType syncType, + DRIContextType oldContextType, + void *oldContext, + DRIContextType newContextType, + void *newContext ) +{ + if ( ( syncType == DRI_3D_SYNC ) && ( oldContextType == DRI_2D_CONTEXT ) && + ( newContextType == DRI_2D_CONTEXT ) ) { + /* Entering from Wakeup */ + ATIEnterServer( pScreen ); + } + if ( ( syncType == DRI_2D_SYNC ) && ( oldContextType == DRI_NO_CONTEXT ) && + ( newContextType == DRI_2D_CONTEXT ) ) { + /* Exiting from Block Handler */ + ATILeaveServer( pScreen ); + } +} + +static void ATIDRITransitionTo2d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->backArea) { + xf86FreeOffscreenArea(pATI->backArea); + pATI->backArea = NULL; + } + if (pATI->depthTexArea) { + xf86FreeOffscreenArea(pATI->depthTexArea); + pATI->depthTexArea = NULL; + } + pATI->have3DWindows = FALSE; +} + +static void ATIDRITransitionTo3d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + FBAreaPtr fbArea; + int width, height; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + + xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0); + + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + + fbArea = xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, + height - pATI->depthTexLines - + pATI->backLines, + pScreenInfo->displayWidth, NULL, NULL, NULL); + + if (!fbArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve placeholder " + "offscreen area, you might experience screen corruption\n"); + + if (!pATI->backArea) { + pATI->backArea = + xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, + pATI->backLines, + pScreenInfo->displayWidth, + NULL, NULL, NULL); + } + if (!pATI->backArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area " + "for back buffer, you might experience screen corruption\n"); + + if (!pATI->depthTexArea) { + pATI->depthTexArea = + xf86AllocateOffscreenArea(pScreen, pScreenInfo->displayWidth, + pATI->depthTexLines, + pScreenInfo->displayWidth, + NULL, NULL, NULL); + } + if (!pATI->depthTexArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen area " + "for depth buffer and textures, you might experience screen corruption\n"); + + if (fbArea) + xf86FreeOffscreenArea(fbArea); + + pATI->have3DWindows = TRUE; +} + +/* Initialize the state of the back and depth buffers. */ +static void ATIDRIInitBuffers( WindowPtr pWin, RegionPtr prgn, CARD32 indx ) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; + BoxPtr pbox, pboxSave; + int nbox, nboxSave; + int depth; + + depth = 0x0000ffff; + + if (!pXAAInfo) + return; + + if (!pXAAInfo->SetupForSolidFill) + return; + + /* FIXME: Only initialize the back and depth buffers for contexts + that request them */ + + /* FIXME: Use drm clear? (see Radeon driver) */ + + pboxSave = pbox = REGION_RECTS(prgn); + nboxSave = nbox = REGION_NUM_RECTS(prgn); + + (*pXAAInfo->SetupForSolidFill)(pScreenInfo, 0, GXcopy, (CARD32)(-1)); + for (; nbox; nbox--, pbox++) { + (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, + pbox->x1 + pATIDRIServer->fbX, + pbox->y1 + pATIDRIServer->fbY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, + pbox->x1 + pATIDRIServer->backX, + pbox->y1 + pATIDRIServer->backY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } + + pbox = pboxSave; + nbox = nboxSave; + + (*pXAAInfo->SetupForSolidFill)(pScreenInfo, depth, GXcopy, (CARD32)(-1)); + for (; nbox; nbox--, pbox++) + (*pXAAInfo->SubsequentSolidFillRect)(pScreenInfo, + pbox->x1 + pATIDRIServer->depthX, + pbox->y1 + pATIDRIServer->depthY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + + pXAAInfo->NeedToSync = TRUE; +} + +/* Copy the back and depth buffers when the X server moves a window. + * + * Note: this function was copied from the Radeon driver... + * + * This routine is a modified form of XAADoBitBlt with the calls to + * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source + * instead of destination. My origin is upside down so the ydir cases + * are reversed. + */ +static void ATIDRIMoveBuffers( WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 indx ) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + XAAInfoRecPtr pXAAInfo = pATI->pXAAInfo; + + int backOffsetPitch = (((pATI->pDRIServerInfo->backPitch/8) << 22) | + (pATI->pDRIServerInfo->backOffset >> 3)); +#if 0 + int depthOffsetPitch = (((pATI->pDRIServerInfo->depthPitch/8) << 22) | + (pATI->pDRIServerInfo->depthOffset >> 3)); +#endif + BoxPtr pboxTmp, pboxNext, pboxBase; + DDXPointPtr pptTmp; + int xdir, ydir; + + int screenwidth = pScreenInfo->virtualX; + int screenheight = pScreenInfo->virtualY; + + BoxPtr pbox = REGION_RECTS(prgnSrc); + int nbox = REGION_NUM_RECTS(prgnSrc); + + BoxPtr pboxNew1 = NULL; + BoxPtr pboxNew2 = NULL; + DDXPointPtr pptNew1 = NULL; + DDXPointPtr pptNew2 = NULL; + DDXPointPtr pptSrc = &ptOldOrg; + + int dx = pWin->drawable.x - ptOldOrg.x; + int dy = pWin->drawable.y - ptOldOrg.y; + + if (!pXAAInfo) + return; + + if (!pXAAInfo->SetupForScreenToScreenCopy) + return; + + /* FIXME: Only move the back and depth buffers for contexts + * that request them. + */ + + /* If the copy will overlap in Y, reverse the order */ + if (dy > 0) { + ydir = -1; + + if (nbox > 1) { + /* Keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); + if (!pboxNew1) return; + pptNew1 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); + if (!pptNew1) { + DEALLOCATE_LOCAL(pboxNew1); + return; + } + pboxBase = pboxNext = pbox+nbox-1; + while (pboxBase >= pbox) { + while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + pboxTmp = pboxNext+1; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp <= pboxBase) { + *pboxNew1++ = *pboxTmp++; + *pptNew1++ = *pptTmp++; + } + pboxBase = pboxNext; + } + pboxNew1 -= nbox; + pbox = pboxNew1; + pptNew1 -= nbox; + pptSrc = pptNew1; + } + } else { + /* No changes required */ + ydir = 1; + } + + /* If the regions will overlap in X, reverse the order */ + if (dx > 0) { + xdir = -1; + + if (nbox > 1) { + /* reverse order of rects in each band */ + pboxNew2 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); + pptNew2 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); + if (!pboxNew2 || !pptNew2) { + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + return; + } + pboxBase = pboxNext = pbox; + while (pboxBase < pbox+nbox) { + while ((pboxNext < pbox+nbox) + && (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + pboxTmp = pboxNext; + pptTmp = pptSrc + (pboxTmp - pbox); + while (pboxTmp != pboxBase) { + *pboxNew2++ = *--pboxTmp; + *pptNew2++ = *--pptTmp; + } + pboxBase = pboxNext; + } + pboxNew2 -= nbox; + pbox = pboxNew2; + pptNew2 -= nbox; + pptSrc = pptNew2; + } + } else { + /* No changes are needed */ + xdir = 1; + } + + (*pXAAInfo->SetupForScreenToScreenCopy)(pScreenInfo, xdir, ydir, GXcopy, + (CARD32)(-1), -1); + + for (; nbox-- ; pbox++) { + int xa = pbox->x1; + int ya = pbox->y1; + int destx = xa + dx; + int desty = ya + dy; + int w = pbox->x2 - xa + 1; + int h = pbox->y2 - ya + 1; + + if (destx < 0) xa -= destx, w += destx, destx = 0; + if (desty < 0) ya -= desty, h += desty, desty = 0; + if (destx + w > screenwidth) w = screenwidth - destx; + if (desty + h > screenheight) h = screenheight - desty; + + if (w <= 0) continue; + if (h <= 0) continue; + + ATIMach64WaitForFIFO(pATI, 2); + outf(SRC_OFF_PITCH, backOffsetPitch); + outf(DST_OFF_PITCH, backOffsetPitch); + + (*pXAAInfo->SubsequentScreenToScreenCopy)(pScreenInfo, + xa, ya, + destx, desty, + w, h); +#if 0 + /* FIXME: Move depth buffers? */ + ATIMach64WaitForFIFO(pATI, 2); + outf(SRC_OFF_PITCH, depthOffsetPitch); + outf(DST_OFF_PITCH, depthOffsetPitch); + + if (pATI->depthMoves) + ATIScreenToScreenCopyDepth(pScreenInfo, + xa, ya, + destx, desty, + w, h); +#endif + } + + ATIMach64WaitForFIFO(pATI, 2); + outf(SRC_OFF_PITCH, pATI->NewHW.dst_off_pitch); + outf(DST_OFF_PITCH, pATI->NewHW.src_off_pitch); + + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + + pXAAInfo->NeedToSync = TRUE; +} + +/* Compute log base 2 of val. */ +static int Mach64MinBits(int val) +{ + int bits; + + if (!val) return 1; + for (bits = 0; val; val >>= 1, ++bits); + return bits; +} + +static Bool ATIDRISetAgpMode( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + unsigned long mode = drmAgpGetMode( pATI->drmFD ); /* Default mode */ + unsigned int vendor = drmAgpVendorId( pATI->drmFD ); + unsigned int device = drmAgpDeviceId( pATI->drmFD ); + + if (pATI->OptionAGPMode > 0 && pATI->OptionAGPMode <= ATI_AGP_MAX_MODE) { + pATIDRIServer->agpMode = pATI->OptionAGPMode; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using AGP %dx Mode\n", + pATIDRIServer->agpMode ); + } else if (pATI->OptionAGPMode > 0) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal AGP Mode: %d\n", + pATI->OptionAGPMode ); + return FALSE; + } else { + /* If no mode configured, use the default mode obtained from agpgart */ + if ( mode & AGP_MODE_2X ) { + pATIDRIServer->agpMode = 2; + } else if ( mode & AGP_MODE_1X ) { + pATIDRIServer->agpMode = 1; + } + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using AGP %dx Mode\n", + pATIDRIServer->agpMode ); + } + + mode &= ~AGP_MODE_MASK; + switch ( pATIDRIServer->agpMode ) { + case 2: mode |= AGP_MODE_2X; + case 1: default: mode |= AGP_MODE_1X; + } + + if (pATI->OptionAGPSize) { + switch (pATI->OptionAGPSize) { + case 256: + case 128: + case 64: + case 32: + case 16: + case 8: + case 4: + pATIDRIServer->agpSize = pATI->OptionAGPSize; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using %d MB AGP aperture\n", + pATIDRIServer->agpSize ); + break; + default: + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Illegal aperture size %d MB\n", pATI->OptionAGPSize ); + return FALSE; + } + } else { + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using %d MB AGP aperture\n", + pATIDRIServer->agpSize ); + } + + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", + mode, vendor, device, + pATI->PCIInfo->vendor, + pATI->PCIInfo->chipType ); + + if ( drmAgpEnable( pATI->drmFD, mode ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n" ); + drmAgpRelease( pATI->drmFD ); + return FALSE; + } + + return TRUE; +} + +/* Initialize the AGP state. Request memory for use in AGP space, and + * initialize the Rage Pro registers to point to that memory. + */ +static Bool ATIDRIAgpInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + int ret; + unsigned long cntl; + int s, l; + + pATIDRIServer->agpSize = ATI_DEFAULT_AGP_SIZE; + pATIDRIServer->agpMode = ATI_DEFAULT_AGP_MODE; + pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE; + pATIDRIServer->ringSize = 16; /* 16 kB ring */ + + if ( drmAgpAcquire( pATI->drmFD ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP not available\n" ); + return FALSE; + } + + if (!ATIDRISetAgpMode( pScreen )) + return FALSE; + + pATIDRIServer->agpOffset = 0; + + ret = drmAgpAlloc( pATI->drmFD, pATIDRIServer->agpSize*1024*1024, + 0, NULL, &pATIDRIServer->agpHandle ); + if ( ret < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret ); + drmAgpRelease( pATI->drmFD ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] %d kB allocated with handle 0x%08x\n", + pATIDRIServer->agpSize*1024, pATIDRIServer->agpHandle ); + + if ( drmAgpBind( pATI->drmFD, pATIDRIServer->agpHandle, pATIDRIServer->agpOffset) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Could not bind\n" ); + drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle ); + drmAgpRelease( pATI->drmFD ); + return FALSE; + } + + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Using %d kB for DMA descriptor ring\n", pATIDRIServer->ringSize); + + if (pATI->OptionBufferSize) { + if (pATI->OptionBufferSize < 1 || pATI->OptionBufferSize > pATIDRIServer->agpSize ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + return FALSE; + } + if (pATI->OptionBufferSize > 2) { + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Clamping DMA buffers size to 2 MB\n", + pATI->OptionBufferSize ); + pATIDRIServer->bufferSize = 2; + } else { + pATIDRIServer->bufferSize = pATI->OptionBufferSize; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[agp] Using %d MB for DMA buffers\n", + pATIDRIServer->bufferSize ); + } + } else { + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[agp] Using %d MB for DMA buffers\n", + pATIDRIServer->bufferSize ); + } + + pATIDRIServer->agpTexSize = pATIDRIServer->agpSize - pATIDRIServer->bufferSize; + + /* Reserve space for the DMA descriptor ring */ + pATIDRIServer->ringStart = pATIDRIServer->agpOffset; + pATIDRIServer->ringMapSize = pATIDRIServer->ringSize*1024; /* ringSize is in kB */ + + /* Reserve space for the vertex buffer */ + pATIDRIServer->bufferStart = pATIDRIServer->ringStart + pATIDRIServer->ringMapSize; + pATIDRIServer->bufferMapSize = pATIDRIServer->bufferSize*1024*1024; + + /* Reserve the rest for AGP textures */ + pATIDRIServer->agpTexStart = pATIDRIServer->bufferStart + pATIDRIServer->bufferMapSize; + s = (pATIDRIServer->agpSize*1024*1024 - pATIDRIServer->agpTexStart); + l = Mach64MinBits((s-1) / MACH64_NR_TEX_REGIONS); + if (l < MACH64_LOG_TEX_GRANULARITY) l = MACH64_LOG_TEX_GRANULARITY; + pATIDRIServer->agpTexMapSize = (s >> l) << l; + pATIDRIServer->log2AGPTexGran = l; + + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Using %d kB for AGP textures\n", pATIDRIServer->agpTexMapSize/1024); + + /* Map DMA descriptor ring */ + if ( drmAddMap( pATI->drmFD, pATIDRIServer->ringStart, pATIDRIServer->ringMapSize, + DRM_AGP, DRM_RESTRICTED, &pATIDRIServer->ringHandle ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not add ring mapping\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] ring handle = 0x%08lx\n", + pATIDRIServer->ringHandle ); + + if ( drmMap( pATI->drmFD, pATIDRIServer->ringHandle, + pATIDRIServer->ringMapSize, &pATIDRIServer->ringMap ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not map ring\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] Ring mapped at 0x%08lx\n", + (unsigned long)pATIDRIServer->ringMap ); + + /* Map vertex buffers */ + if ( drmAddMap( pATI->drmFD, pATIDRIServer->bufferStart, pATIDRIServer->bufferMapSize, + DRM_AGP, 0, &pATIDRIServer->bufferHandle ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not add vertex buffers mapping\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] vertex buffers handle = 0x%08lx\n", + pATIDRIServer->bufferHandle ); + + if ( drmMap( pATI->drmFD, pATIDRIServer->bufferHandle, + pATIDRIServer->bufferMapSize, &pATIDRIServer->bufferMap ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Could not map vertex buffers\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[agp] Vertex buffers mapped at 0x%08lx\n", + (unsigned long)pATIDRIServer->bufferMap ); + + /* Map AGP Textures */ + if (drmAddMap(pATI->drmFD, pATIDRIServer->agpTexStart, pATIDRIServer->agpTexMapSize, + DRM_AGP, 0, &pATIDRIServer->agpTexHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add AGP texture region mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP texture region handle = 0x%08lx\n", + pATIDRIServer->agpTexHandle); + + if (drmMap(pATI->drmFD, pATIDRIServer->agpTexHandle, pATIDRIServer->agpTexMapSize, + &pATIDRIServer->agpTexMap) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map AGP texture region\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP Texture region mapped at 0x%08lx\n", + (unsigned long)pATIDRIServer->agpTexMap); + + /* Initialize Mach64's AGP registers */ + cntl = inm( AGP_CNTL ); + cntl &= ~AGP_APER_SIZE_MASK; + switch ( pATIDRIServer->agpSize ) { + case 256: cntl |= AGP_APER_SIZE_256MB; break; + case 128: cntl |= AGP_APER_SIZE_128MB; break; + case 64: cntl |= AGP_APER_SIZE_64MB; break; + case 32: cntl |= AGP_APER_SIZE_32MB; break; + case 16: cntl |= AGP_APER_SIZE_16MB; break; + case 8: cntl |= AGP_APER_SIZE_8MB; break; + case 4: cntl |= AGP_APER_SIZE_4MB; break; + default: + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[agp] Illegal aperture size %d kB\n", + pATIDRIServer->agpSize*1024 ); + return FALSE; + } + + /* 1 = DATA comes in clock in which TRDY sampled (default) */ + /* 0 = DATA comes in clock after TRDY sampled */ + cntl |= AGP_TRDY_MODE; + + /* 1 = generate all reads as high priority */ + /* 0 = generate all reads as their default priority (default) */ + /* Setting this only works for me at AGP 1x mode (LLD) */ + if (pATIDRIServer->agpMode == 1) { + cntl |= HIGH_PRIORITY_READ_EN; + } else { + cntl &= ~HIGH_PRIORITY_READ_EN; + } + + outm( AGP_BASE, drmAgpBase(pATI->drmFD) ); + outm( AGP_CNTL, cntl ); + + return TRUE; +} + +/* Add a map for the MMIO registers that will be accessed by any + * DRI-based clients. + */ +static Bool ATIDRIMapInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + pATIDRIServer->regsSize = getpagesize(); + if ( drmAddMap( pATI->drmFD, pATI->Block1Base, + pATIDRIServer->regsSize, + DRM_REGISTERS, DRM_READ_ONLY, + &pATIDRIServer->regsHandle ) < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[drm] failed to map registers\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[drm] register handle = 0x%08lx\n", + pATIDRIServer->regsHandle ); + + return TRUE; +} + +/* Initialize the kernel data structures. */ +static Bool ATIDRIKernelInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + drmMach64Init info; + + memset( &info, 0, sizeof(drmMach64Init) ); + + info.func = DRM_MACH64_INIT_DMA; + info.sarea_priv_offset = sizeof(XF86DRISAREARec); + info.is_pci = pATIDRIServer->IsPCI; + info.dma_mode = pATI->OptionDMAMode; + + info.fb_bpp = pATI->bitsPerPixel; + info.front_offset = pATIDRIServer->frontOffset; + info.front_pitch = pATIDRIServer->frontPitch; + info.back_offset = pATIDRIServer->backOffset; + info.back_pitch = pATIDRIServer->backPitch; + + info.depth_bpp = 16; + info.depth_offset = pATIDRIServer->depthOffset; + info.depth_pitch = pATIDRIServer->depthPitch; + + info.fb_offset = pATI->LinearBase; + info.mmio_offset = pATIDRIServer->regsHandle; + info.ring_offset = pATIDRIServer->ringHandle; + info.buffers_offset = pATIDRIServer->bufferHandle; + info.agp_textures_offset = pATIDRIServer->agpTexHandle; + + if ( drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT, + &info, sizeof(drmMach64Init) ) < 0 ) { + return FALSE; + } else { + return TRUE; + } +} + +/* Add a map for the DMA buffers that will be accessed by any + * DRI-based clients. + */ +static Bool ATIDRIAddBuffers( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + /* Initialize vertex buffers */ + if ( pATIDRIServer->IsPCI ) { + pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD, + (pATIDRIServer->bufferSize*1024*1024)/MACH64_BUFFER_SIZE, + MACH64_BUFFER_SIZE, + 0, + 0 ); + } else { + pATIDRIServer->numBuffers = drmAddBufs( pATI->drmFD, + pATIDRIServer->bufferMapSize/MACH64_BUFFER_SIZE, + MACH64_BUFFER_SIZE, + DRM_AGP_BUFFER, + pATIDRIServer->bufferStart ); + } + if ( pATIDRIServer->numBuffers <= 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[drm] Could not create DMA buffers list\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[drm] Added %d %d byte DMA buffers\n", + pATIDRIServer->numBuffers, MACH64_BUFFER_SIZE ); + + return TRUE; +} + +static Bool ATIDRIMapBuffers( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + pATIDRIServer->drmBuffers = drmMapBufs( pATI->drmFD ); + if ( !pATIDRIServer->drmBuffers ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[drm] Failed to map DMA buffers list\n" ); + return FALSE; + } + xf86DrvMsg( pScreen->myNum, X_INFO, + "[drm] Mapped %d DMA buffers at 0x%08lx\n", + pATIDRIServer->drmBuffers->count, + pATIDRIServer->drmBuffers->list->address ); + + return TRUE; +} + +static Bool ATIDRIIrqInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if ( pATI->irq <= 0 ) { + pATI->irq = drmGetInterruptFromBusID(pATI->drmFD, + ((pciConfigPtr)pATI->PCIInfo + ->thisCard)->busnum, + ((pciConfigPtr)pATI->PCIInfo + ->thisCard)->devnum, + ((pciConfigPtr)pATI->PCIInfo + ->thisCard)->funcnum); + if ( pATI->irq <= 0 ) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Couldn't find IRQ for bus id %d:%d:%d\n", + ((pciConfigPtr)pATI->PCIInfo->thisCard)->busnum, + ((pciConfigPtr)pATI->PCIInfo->thisCard)->devnum, + ((pciConfigPtr)pATI->PCIInfo->thisCard)->funcnum); + pATI->irq = 0; + } else if ((drmCtlInstHandler(pATI->drmFD, pATI->irq)) != 0) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Failed to initialize interrupt handler with IRQ %d\n", + pATI->irq); + pATI->irq = 0; + } + + if (pATI->irq) + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "[drm] Installed interrupt handler, using IRQ %d\n", + pATI->irq); + else { + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "[drm] Falling back to irq-free operation\n", + pATI->irq); + return FALSE; + } + } + + return TRUE; + +} + +/* Initialize the screen-specific data structures for the DRI and the + * Rage Pro. This is the main entry point to the device-specific + * initialization code. It calls device-independent DRI functions to + * create the DRI data structures and initialize the DRI state. + */ +Bool ATIDRIScreenInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + DRIInfoPtr pDRIInfo; + ATIDRIPtr pATIDRI; + ATIDRIServerInfoPtr pATIDRIServer; + drmVersionPtr version; + int major, minor, patch; + + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for known symbols in each module. + */ + if ( !xf86LoaderCheckSymbol("GlxSetVisualConfigs") ) return FALSE; + if ( !xf86LoaderCheckSymbol("DRIScreenInit") ) return FALSE; + if ( !xf86LoaderCheckSymbol("drmAvailable") ) return FALSE; + if ( !xf86LoaderCheckSymbol("DRIQueryVersion") ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed (libdri.a too old)\n" ); + return FALSE; + } + + /* Check the DRI version */ + DRIQueryVersion( &major, &minor, &patch ); + if ( major != 4 || minor < 0 ) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" + "[dri] libDRI version is %d.%d.%d but version 4.0.x is needed.\n" + "[dri] Disabling the DRI.\n", + major, minor, patch ); + return FALSE; + } + + switch ( pATI->bitsPerPixel ) { + case 8: + /* These modes are not supported (yet). */ + case 15: + case 24: + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] Direct rendering only supported in 16 and 32 bpp modes\n"); + return FALSE; + + /* Only 16 and 32 color depths are supported currently. */ + case 16: + if ( pATI->depth != 16) { + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] Direct rendering not supported for depth %d at fbbpp 16.\n", pATI->depth ); + return FALSE; + } + break; + case 32: + break; + } + + /* Create the DRI data structure, and fill it in before calling the + * DRIScreenInit(). + */ + pDRIInfo = DRICreateInfoRec(); + if ( !pDRIInfo ) return FALSE; + + pATI->pDRIInfo = pDRIInfo; + pDRIInfo->drmDriverName = ATIKernelDriverName; + pDRIInfo->clientDriverName = ATIClientDriverName; + if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) { + pDRIInfo->busIdString = DRICreatePCIBusID(pATI->PCIInfo); + } else { + pDRIInfo->busIdString = xalloc( 64 ); + sprintf( pDRIInfo->busIdString, + "PCI:%d:%d:%d", + pATI->PCIInfo->bus, + pATI->PCIInfo->device, + pATI->PCIInfo->func ); + } + pDRIInfo->ddxDriverMajorVersion = ATI_VERSION_MAJOR; + pDRIInfo->ddxDriverMinorVersion = ATI_VERSION_MINOR; + pDRIInfo->ddxDriverPatchVersion = ATI_VERSION_PATCH; + pDRIInfo->frameBufferPhysicalAddress = pATI->LinearBase; + pDRIInfo->frameBufferSize = pATI->LinearSize; + pDRIInfo->frameBufferStride = (pScreenInfo->displayWidth * + pATI->FBBytesPerPixel); + pDRIInfo->ddxDrawableTableEntry = ATI_MAX_DRAWABLES; + + if ( SAREA_MAX_DRAWABLES < ATI_MAX_DRAWABLES ) { + pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES; + } else { + pDRIInfo->maxDrawableTableEntry = ATI_MAX_DRAWABLES; + } + + /* For now the mapping works by using a fixed size defined + * in the SAREA header + */ + if ( sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec) > SAREA_MAX ) { + ErrorF( "[dri] Data does not fit in SAREA\n" ); + return FALSE; + } + xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, "[drm] SAREA %d+%d: %d\n", + sizeof(XF86DRISAREARec), sizeof(ATISAREAPrivRec), + sizeof(XF86DRISAREARec) + sizeof(ATISAREAPrivRec) ); + pDRIInfo->SAREASize = SAREA_MAX; + + pATIDRI = (ATIDRIPtr) xnfcalloc( sizeof(ATIDRIRec), 1 ); + if ( !pATIDRI ) { + DRIDestroyInfoRec( pATI->pDRIInfo ); + pATI->pDRIInfo = NULL; + xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR, + "[dri] Failed to allocate memory for private record\n" ); + return FALSE; + } + pATIDRIServer = (ATIDRIServerInfoPtr) + xnfcalloc( sizeof(ATIDRIServerInfoRec), 1 ); + if ( !pATIDRIServer ) { + xfree( pATIDRI ); + DRIDestroyInfoRec( pATI->pDRIInfo ); + pATI->pDRIInfo = NULL; + xf86DrvMsg( pScreenInfo->scrnIndex, X_ERROR, + "[dri] Failed to allocate memory for private record\n" ); + return FALSE; + } + + pATI->pDRIServerInfo = pATIDRIServer; + + pDRIInfo->devPrivate = pATIDRI; + pDRIInfo->devPrivateSize = sizeof(ATIDRIRec); + pDRIInfo->contextSize = sizeof(ATIDRIContextRec); + + pDRIInfo->CreateContext = ATICreateContext; + pDRIInfo->DestroyContext = ATIDestroyContext; + pDRIInfo->SwapContext = ATIDRISwapContext; + pDRIInfo->InitBuffers = ATIDRIInitBuffers; + pDRIInfo->MoveBuffers = ATIDRIMoveBuffers; + pDRIInfo->TransitionTo2d = ATIDRITransitionTo2d; + pDRIInfo->TransitionTo3d = ATIDRITransitionTo3d; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + + pDRIInfo->createDummyCtx = TRUE; + pDRIInfo->createDummyCtxPriv = FALSE; + + pATI->have3DWindows = FALSE; + + if ( !DRIScreenInit( pScreen, pDRIInfo, &pATI->drmFD ) ) { + xfree( pATIDRIServer ); + pATI->pDRIServerInfo = NULL; + xfree( pDRIInfo->devPrivate ); + pDRIInfo->devPrivate = NULL; + DRIDestroyInfoRec( pDRIInfo ); + pDRIInfo = NULL; + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] DRIScreenInit Failed\n" ); + return FALSE; + } + + /* Check the DRM lib version. + drmGetLibVersion was not supported in version 1.0, so check for + symbol first to avoid possible crash or hang. + */ + if (xf86LoaderCheckSymbol("drmGetLibVersion")) { + version = drmGetLibVersion(pATI->drmFD); + } else { + /* drmlib version 1.0.0 didn't have the drmGetLibVersion + entry point. Fake it by allocating a version record + via drmGetVersion and changing it to version 1.0.0 + */ + version = drmGetVersion(pATI->drmFD); + version->version_major = 1; + version->version_minor = 0; + version->version_patchlevel = 0; + } + + if (version) { + if (version->version_major != 1 || + version->version_minor < 1) { + /* incompatible drm library version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" + "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + ATIDRICloseScreen(pScreen); + return FALSE; + } + drmFreeVersion(version); + } + + /* Check the mach64 DRM version */ + version = drmGetVersion( pATI->drmFD ); + if ( version ) { + if ( version->version_major != 1 || + version->version_minor < 0 ) { + /* Incompatible DRM version */ + xf86DrvMsg( pScreen->myNum, X_ERROR, + "[dri] ATIDRIScreenInit failed because of a version mismatch.\n" + "[dri] mach64.o kernel module version is %d.%d.%d, but version 1.0 or greater is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel ); + drmFreeVersion( version ); + ATIDRICloseScreen( pScreen ); + return FALSE; + } + drmFreeVersion( version ); + } + + switch ( pATI->OptionDMAMode ) { + case MACH64_MODE_DMA_ASYNC: + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request asynchronous DMA mode\n"); + break; + case MACH64_MODE_DMA_SYNC: + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request synchronous DMA mode\n"); + break; + case MACH64_MODE_MMIO: + xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Will request pseudo-DMA (MMIO) mode\n"); + break; + default: + xf86DrvMsg(pScreen->myNum, X_WARNING, "[drm] Unknown DMA mode\n"); + } + + pATIDRIServer->IsPCI = (pATI->BusType == ATI_BUS_PCI || pATI->OptionIsPCI) ? TRUE : FALSE; + + if ( pATI->BusType != ATI_BUS_PCI && pATI->OptionIsPCI ) { + outm( AGP_BASE, 0 ); + outm( AGP_CNTL, 0 ); + xf86DrvMsg(pScreen->myNum, X_CONFIG, "[dri] Forcing PCI mode\n"); + } + + /* Check buffer size option for PCI, since it won't be done in ATIDRIAgpInit */ + if ( pATIDRIServer->IsPCI) { + pATIDRIServer->bufferSize = ATI_DEFAULT_BUFFER_SIZE; + if (pATI->OptionBufferSize) { + if (pATI->OptionBufferSize < 1) { + xf86DrvMsg( pScreen->myNum, X_ERROR, "[pci] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + ATIDRICloseScreen( pScreen ); + return FALSE; + } + if (pATI->OptionBufferSize > 2) { + xf86DrvMsg( pScreen->myNum, X_WARNING, "[pci] Illegal DMA buffers size: %d MB\n", + pATI->OptionBufferSize ); + xf86DrvMsg( pScreen->myNum, X_WARNING, "[pci] Clamping DMA buffers size to 2 MB\n", + pATI->OptionBufferSize ); + pATIDRIServer->bufferSize = 2; + } else { + pATIDRIServer->bufferSize = pATI->OptionBufferSize; + xf86DrvMsg( pScreen->myNum, X_CONFIG, "[pci] Using %d MB DMA buffer size\n", + pATIDRIServer->bufferSize ); + } + } else { + xf86DrvMsg( pScreen->myNum, X_DEFAULT, "[pci] Using %d MB DMA buffer size\n", + pATIDRIServer->bufferSize ); + } + } + + /* Initialize AGP */ + if ( !pATIDRIServer->IsPCI && !ATIDRIAgpInit( pScreen ) ) { + pATIDRIServer->IsPCI = TRUE; + if ( pATI->BusType != ATI_BUS_PCI ) { + outm( AGP_BASE, 0 ); + outm( AGP_CNTL, 0 ); + } + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] AGP failed to initialize -- falling back to PCI mode.\n" ); + xf86DrvMsg( pScreen->myNum, X_WARNING, "[agp] Make sure you have the agpgart kernel module loaded.\n" ); + } + + if ( !ATIDRIMapInit( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + if ( !ATIInitVisualConfigs( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, + "[dri] Visual configs initialized\n" ); + + xf86DrvMsg( pScreenInfo->scrnIndex, X_INFO, + "[dri] Block 0 base at 0x%08lx\n", pATI->Block0Base ); + + return TRUE; +} + +/* Finish initializing the device-dependent DRI state, and call + * DRIFinishScreenInit() to complete the device-independent DRI + * initialization. + */ +Bool ATIDRIFinishScreenInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATISAREAPrivPtr pSAREAPriv; + ATIDRIPtr pATIDRI; + ATIDRIServerInfoPtr pATIDRIServer; + + pATI->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + + /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit + * because *DRIKernelInit requires that the hardware lock is held by + * the X server, and the first time the hardware lock is grabbed is + * in DRIFinishScreenInit. + */ + if ( !DRIFinishScreenInit( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + /* Initialize the DMA buffer list */ + /* Need to do this before ATIDRIKernelInit so we can init the freelist */ + if ( !ATIDRIAddBuffers( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + /* Initialize the kernel data structures */ + if ( !ATIDRIKernelInit( pScreen ) ) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Failed to initialize the mach64.o kernel module\n"); + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Check the system log for more information.\n"); + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + if ( !ATIDRIMapBuffers( pScreen ) ) { + ATIDRICloseScreen( pScreen ); + return FALSE; + } + + /* Initialize IRQ */ + ATIDRIIrqInit( pScreen ); + + pSAREAPriv = (ATISAREAPrivPtr) DRIGetSAREAPrivate( pScreen ); + memset( pSAREAPriv, 0, sizeof(*pSAREAPriv) ); + + pATIDRI = (ATIDRIPtr)pATI->pDRIInfo->devPrivate; + pATIDRIServer = pATI->pDRIServerInfo; + + pATIDRI->width = pScreenInfo->virtualX; + pATIDRI->height = pScreenInfo->virtualY; + pATIDRI->mem = pScreenInfo->videoRam * 1024; + pATIDRI->cpp = pScreenInfo->bitsPerPixel / 8; + + pATIDRI->IsPCI = pATIDRIServer->IsPCI; + pATIDRI->AGPMode = pATIDRIServer->agpMode; + + pATIDRI->frontOffset = pATIDRIServer->frontOffset; + pATIDRI->frontPitch = pATIDRIServer->frontPitch; + + pATIDRI->backOffset = pATIDRIServer->backOffset; + pATIDRI->backPitch = pATIDRIServer->backPitch; + + pATIDRI->depthOffset = pATIDRIServer->depthOffset; + pATIDRI->depthPitch = pATIDRIServer->depthPitch; + + pATIDRI->textureOffset = pATIDRIServer->textureOffset; + pATIDRI->textureSize = pATIDRIServer->textureSize; + pATIDRI->logTextureGranularity = pATIDRIServer->logTextureGranularity; + + pATIDRI->regs = pATIDRIServer->regsHandle; + pATIDRI->regsSize = pATIDRIServer->regsSize; + + pATIDRI->agp = pATIDRIServer->agpTexHandle; + pATIDRI->agpSize = pATIDRIServer->agpTexMapSize; + pATIDRI->logAgpTextureGranularity = pATIDRIServer->log2AGPTexGran; + pATIDRI->agpTextureOffset = pATIDRIServer->agpTexStart; + + return TRUE; +} + +/* + * This function will attempt to get the Mach64 hardware back into shape + * after a resume from disc. Its an extract from ATIDRIAgpInit and ATIDRIFinishScreenInit + * This also calls a new ioctl in the mach64 DRM that in its turn is + * an extraction of the hardware-affecting bits from mach64_do_init_drm() + * (see atidrm.c) + * I am assuming here that pATI->pDRIServerInfo doesn't change + * elsewhere in incomaptible ways. + * How will this code react to resuming after a failed resumeor pci based dri ? + */ +void ATIDRIResume( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + + int ret; + + xf86DrvMsg( pScreen->myNum, X_INFO, + "[RESUME] Attempting to re-init Mach64 hardware.\n"); + + if (!pATIDRIServer->IsPCI) { + if (!ATIDRISetAgpMode(pScreen)) + return; + + outm( AGP_BASE, drmAgpBase(pATI->drmFD) ); + } +} + +/* The screen is being closed, so clean up any state and free any + * resources used by the DRI. + */ +void ATIDRICloseScreen( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + ATIDRIServerInfoPtr pATIDRIServer = pATI->pDRIServerInfo; + drmMach64Init info; + + /* Stop interrupt generation and handling if used */ + if ( pATI->irq > 0 ) { + if ( drmCtlUninstHandler(pATI->drmFD) != 0 ) { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "[drm] Error uninstalling interrupt handler for IRQ %d\n", pATI->irq); + } else { + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "[drm] Uninstalled interrupt handler for IRQ %d\n", pATI->irq); + } + pATI->irq = 0; + } + + /* De-allocate DMA buffers */ + if ( pATIDRIServer->drmBuffers ) { + drmUnmapBufs( pATIDRIServer->drmBuffers ); + pATIDRIServer->drmBuffers = NULL; + } + + /* De-allocate all kernel resources */ + memset(&info, 0, sizeof(drmMach64Init)); + info.func = DRM_MACH64_CLEANUP_DMA; + drmCommandWrite( pATI->drmFD, DRM_MACH64_INIT, + &info, sizeof(drmMach64Init) ); + + /* De-allocate all AGP resources */ + if ( pATIDRIServer->agpTexMap ) { + drmUnmap( pATIDRIServer->agpTexMap, pATIDRIServer->agpTexMapSize ); + pATIDRIServer->agpTexMap = NULL; + } + if ( pATIDRIServer->bufferMap ) { + drmUnmap( pATIDRIServer->bufferMap, pATIDRIServer->bufferMapSize ); + pATIDRIServer->bufferMap = NULL; + } + if ( pATIDRIServer->agpHandle ) { + drmAgpUnbind( pATI->drmFD, pATIDRIServer->agpHandle ); + drmAgpFree( pATI->drmFD, pATIDRIServer->agpHandle ); + pATIDRIServer->agpHandle = 0; + drmAgpRelease( pATI->drmFD ); + } + + /* De-allocate all DRI resources */ + DRICloseScreen( pScreen ); + + /* De-allocate all DRI data structures */ + if ( pATI->pDRIInfo ) { + if ( pATI->pDRIInfo->devPrivate ) { + xfree( pATI->pDRIInfo->devPrivate ); + pATI->pDRIInfo->devPrivate = NULL; + } + DRIDestroyInfoRec( pATI->pDRIInfo ); + pATI->pDRIInfo = NULL; + } + if ( pATI->pDRIServerInfo ) { + xfree( pATI->pDRIServerInfo ); + pATI->pDRIServerInfo = NULL; + } + if ( pATI->pVisualConfigs ) { + xfree( pATI->pVisualConfigs ); + pATI->pVisualConfigs = NULL; + } + if ( pATI->pVisualConfigsPriv ) { + xfree( pATI->pVisualConfigsPriv ); + pATI->pVisualConfigsPriv = NULL; + } +} diff --git a/src/atidri.h b/src/atidri.h new file mode 100644 index 0000000..3df07ec --- /dev/null +++ b/src/atidri.h @@ -0,0 +1,49 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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. + */ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __ATIDRI_H__ +#define __ATIDRI_H__ 1 + +/* DRI driver defaults */ +#define ATI_DEFAULT_AGP_SIZE 8 /* MB (must be a power of 2 and > 4MB) */ +#define ATI_DEFAULT_AGP_MODE 1 +#define ATI_DEFAULT_BUFFER_SIZE 2 /* MB (must be page aligned) */ + +#define ATI_AGP_MAX_MODE 2 + +/* Imported from the radeon suspend code writen by cpbotha@ieee.org + * to enable suspend/resume support for the mach64 card. + */ +extern void ATIDRIResume(ScreenPtr pScreen); +extern Bool ATIDRIScreenInit(ScreenPtr); +extern Bool ATIDRIFinishScreenInit(ScreenPtr); +extern void ATIDRICloseScreen(ScreenPtr); + +#endif /* __ATIDRI_H__ */ diff --git a/src/atidripriv.h b/src/atidripriv.h new file mode 100644 index 0000000..af42d6e --- /dev/null +++ b/src/atidripriv.h @@ -0,0 +1,57 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __ATIDRIPRIV_H__ +#define __ATIDRIPRIV_H__ 1 + +#include "GL/glxint.h" +#include "GL/glxtokens.h" + +#define ATI_MAX_DRAWABLES 256 + +typedef struct { + /* Nothing here yet */ + int dummy; +} ATIConfigPrivRec, *ATIConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} ATIDRIContextRec, *ATIDRIContextPtr; + +extern void GlxSetVisualConfigs(int, __GLXvisualConfig *, void **); + +#endif /* __ATIDRIPRIV_H__ */ diff --git a/src/atidsp.c b/src/atidsp.c new file mode 100644 index 0000000..bbab3e5 --- /dev/null +++ b/src/atidsp.c @@ -0,0 +1,329 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidsp.c,v 1.21 2003/09/24 02:43:18 dawes Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atichip.h" +#include "aticrtc.h" +#include "atidsp.h" +#include "atimach64io.h" +#include "atividmem.h" + +/* + * ATIDSPPreInit -- + * + * This function initialises global variables used to set DSP registers on a + * VT-B or later. + */ +Bool +ATIDSPPreInit +( + int iScreen, + ATIPtr pATI +) +{ + CARD32 IOValue, dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off; + int trp; + + /* + * VT-B's and later have additional post-dividers that are not powers of + * two. + */ + pATI->ClockDescriptor.NumD = 8; + + /* Retrieve XCLK settings */ + IOValue = ATIMach64GetPLLReg(PLL_XCLK_CNTL); + pATI->XCLKPostDivider = GetBits(IOValue, PLL_XCLK_SRC_SEL); + pATI->XCLKReferenceDivider = 1; + switch (pATI->XCLKPostDivider) + { + case 0: case 1: case 2: case 3: + break; + + case 4: + pATI->XCLKReferenceDivider = 3; + pATI->XCLKPostDivider = 0; + break; + + default: + xf86DrvMsg(iScreen, X_ERROR, + "Unsupported XCLK source: %d.\n", pATI->XCLKPostDivider); + return FALSE; + } + + pATI->XCLKPostDivider -= GetBits(IOValue, PLL_MFB_TIMES_4_2B); + pATI->XCLKFeedbackDivider = ATIMach64GetPLLReg(PLL_MCLK_FB_DIV); + + xf86DrvMsgVerb(iScreen, X_INFO, 2, + "Engine XCLK %.3f MHz; Refresh rate code %ld.\n", + ATIDivide(pATI->XCLKFeedbackDivider * pATI->ReferenceNumerator, + pATI->XCLKReferenceDivider * pATI->ClockDescriptor.MaxM * + pATI->ReferenceDenominator, 1 - pATI->XCLKPostDivider, 0) / + (double)1000.0, + GetBits(pATI->LockData.mem_cntl, CTL_MEM_REFRESH_RATE_B)); + + /* Compute maximum RAS delay and friends */ + trp = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRP); + pATI->XCLKPageFaultDelay = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRCD) + + GetBits(pATI->LockData.mem_cntl, CTL_MEM_TCRD) + trp + 2; + pATI->XCLKMaxRASDelay = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRAS) + + trp + 2; + pATI->DisplayFIFODepth = 32; + + if (pATI->Chip < ATI_CHIP_264VT4) + { + pATI->XCLKPageFaultDelay += 2; + pATI->XCLKMaxRASDelay += 3; + pATI->DisplayFIFODepth = 24; + } + + switch (pATI->MemoryType) + { + case MEM_264_DRAM: + if (pATI->VideoRAM <= 1024) + { + pATI->DisplayLoopLatency = 10; + } + else + { + pATI->DisplayLoopLatency = 8; + pATI->XCLKPageFaultDelay += 2; + } + break; + + case MEM_264_EDO: + case MEM_264_PSEUDO_EDO: + if (pATI->VideoRAM <= 1024) + { + pATI->DisplayLoopLatency = 9; + } + else + { + pATI->DisplayLoopLatency = 8; + pATI->XCLKPageFaultDelay++; + } + break; + + case MEM_264_SDRAM: + if (pATI->VideoRAM <= 1024) + { + pATI->DisplayLoopLatency = 11; + } + else + { + pATI->DisplayLoopLatency = 10; + pATI->XCLKPageFaultDelay++; + } + break; + + case MEM_264_SGRAM: + pATI->DisplayLoopLatency = 8; + pATI->XCLKPageFaultDelay += 3; + break; + + default: /* Set maximums */ + pATI->DisplayLoopLatency = 11; + pATI->XCLKPageFaultDelay += 3; + break; + } + + if (pATI->XCLKMaxRASDelay <= pATI->XCLKPageFaultDelay) + pATI->XCLKMaxRASDelay = pATI->XCLKPageFaultDelay + 1; + + /* Allow BIOS to override */ + dsp_config = inr(DSP_CONFIG); + dsp_on_off = inr(DSP_ON_OFF); + vga_dsp_config = inr(VGA_DSP_CONFIG); + vga_dsp_on_off = inr(VGA_DSP_ON_OFF); + + if (dsp_config) + pATI->DisplayLoopLatency = GetBits(dsp_config, DSP_LOOP_LATENCY); + + if ((!dsp_on_off && (pATI->Chip < ATI_CHIP_264GTPRO)) || + ((dsp_on_off == vga_dsp_on_off) && + (!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW)))) + { + if (ATIDivide(GetBits(vga_dsp_on_off, VGA_DSP_OFF), + GetBits(vga_dsp_config, VGA_DSP_XCLKS_PER_QW), 5, 1) > 24) + pATI->DisplayFIFODepth = 32; + else + pATI->DisplayFIFODepth = 24; + } + + return TRUE; +} + +/* + * ATIDSPSave -- + * + * This function is called to remember DSP register values on VT-B and later + * controllers. + */ +void +ATIDSPSave +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + pATIHW->dsp_on_off = inr(DSP_ON_OFF); + pATIHW->dsp_config = inr(DSP_CONFIG); +} + + +/* + * ATIDSPCalculate -- + * + * This function sets up DSP register values for a VTB or later. Note that + * this would be slightly different if VCLK 0 or 1 were used for the mode + * instead. In that case, this function would set VGA_DSP_CONFIG and + * VGA_DSP_ON_OFF, would have to zero out DSP_CONFIG and DSP_ON_OFF, and would + * have to consider that VGA_DSP_CONFIG is partitioned slightly differently + * than DSP_CONFIG. + */ +void +ATIDSPCalculate +( + ATIPtr pATI, + ATIHWPtr pATIHW, + DisplayModePtr pMode +) +{ + int Multiplier, Divider; + int RASMultiplier = pATI->XCLKMaxRASDelay, RASDivider = 1; + int dsp_precision, dsp_on, dsp_off, dsp_xclks; + int tmp, vshift, xshift; + +# define Maximum_DSP_PRECISION ((int)MaxBits(DSP_PRECISION)) + + /* Compute a memory-to-screen bandwidth ratio */ + Multiplier = pATI->XCLKFeedbackDivider * + pATI->ClockDescriptor.PostDividers[pATIHW->PostDivider]; + Divider = pATIHW->FeedbackDivider * pATI->XCLKReferenceDivider; + +#ifndef AVOID_CPIO + + if (pATI->depth >= 8) + +#endif /* AVOID_CPIO */ + + { + Divider *= pATI->bitsPerPixel / 4; + } + + /* Start by assuming a display FIFO width of 64 bits */ + vshift = (6 - 2) - pATI->XCLKPostDivider; + +#ifndef AVOID_CPIO + + if (pATIHW->crtc == ATI_CRTC_VGA) + vshift--; /* Nope, it's 32 bits wide */ + +#endif /* AVOID_CPIO */ + + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) + { + /* Compensate for horizontal stretching */ + Multiplier *= pATI->LCDHorizontal; + Divider *= pMode->HDisplay & ~7; + + RASMultiplier *= pATI->LCDHorizontal; + RASDivider *= pMode->HDisplay & ~7; + } + + /* Determine dsp_precision first */ + tmp = ATIDivide(Multiplier * pATI->DisplayFIFODepth, Divider, vshift, -1); + for (dsp_precision = -5; tmp; dsp_precision++) + tmp >>= 1; + if (dsp_precision < 0) + dsp_precision = 0; + else if (dsp_precision > Maximum_DSP_PRECISION) + dsp_precision = Maximum_DSP_PRECISION; + + xshift = 6 - dsp_precision; + vshift += xshift; + + /* Move on to dsp_off */ + dsp_off = ATIDivide(Multiplier * (pATI->DisplayFIFODepth - 1), Divider, + vshift, -1) - ATIDivide(1, 1, vshift - xshift, 1); + + /* Next is dsp_on */ + +#ifndef AVOID_CPIO + + if ((pATIHW->crtc == ATI_CRTC_VGA) /* && (dsp_precision < 3) */) + { + /* + * TODO: I don't yet know why something like this appears necessary. + * But I don't have time to explore this right now. + */ + dsp_on = ATIDivide(Multiplier * 5, Divider, vshift + 2, 1); + } + else + +#endif /* AVOID_CPIO */ + + { + dsp_on = ATIDivide(Multiplier, Divider, vshift, 1); + tmp = ATIDivide(RASMultiplier, RASDivider, xshift, 1); + if (dsp_on < tmp) + dsp_on = tmp; + dsp_on += (tmp * 2) + + ATIDivide(pATI->XCLKPageFaultDelay, 1, xshift, 1); + } + + /* Calculate rounding factor and apply it to dsp_on */ + tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1; + dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1); + + if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) + { + dsp_on = dsp_off - ATIDivide(Multiplier, Divider, vshift, -1); + dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1); + } + + /* Last but not least: dsp_xclks */ + dsp_xclks = ATIDivide(Multiplier, Divider, vshift + 5, 1); + + /* Build DSP register contents */ + pATIHW->dsp_on_off = SetBits(dsp_on, DSP_ON) | + SetBits(dsp_off, DSP_OFF); + pATIHW->dsp_config = SetBits(dsp_precision, DSP_PRECISION) | + SetBits(dsp_xclks, DSP_XCLKS_PER_QW) | + SetBits(pATI->DisplayLoopLatency, DSP_LOOP_LATENCY); +} + +/* + * ATIDSPSet -- + * + * This function is called to set DSP registers on VT-B and later controllers. + */ +void +ATIDSPSet +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + outr(DSP_ON_OFF, pATIHW->dsp_on_off); + outr(DSP_CONFIG, pATIHW->dsp_config); +} diff --git a/src/atidsp.h b/src/atidsp.h new file mode 100644 index 0000000..91438cc --- /dev/null +++ b/src/atidsp.h @@ -0,0 +1,38 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atidsp.h,v 1.10 2003/01/01 19:16:32 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIDSP_H___ +#define ___ATIDSP_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern Bool ATIDSPPreInit FunctionPrototype((int, ATIPtr)); +extern void ATIDSPSave FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIDSPCalculate FunctionPrototype((ATIPtr, ATIHWPtr, + DisplayModePtr)); +extern void ATIDSPSet FunctionPrototype((ATIPtr, ATIHWPtr)); + +#endif /* ___ATIDSP_H___ */ diff --git a/src/atifillin.c b/src/atifillin.c new file mode 100644 index 0000000..76df755 --- /dev/null +++ b/src/atifillin.c @@ -0,0 +1,24 @@ +/* + * atifillin.c: fill in a ScrnInfoPtr with the relevant information for + * atimisc. + * + * (c) 2004 Adam Jackson. Standard MIT license applies. + */ + +#include "atifillin.h" + +void ATIFillInScreenInfo(ScrnInfoPtr pScreenInfo) +{ + pScreenInfo->driverVersion = ATI_VERSION_CURRENT; + pScreenInfo->driverName = ATI_DRIVER_NAME; + pScreenInfo->name = ATI_NAME; + pScreenInfo->Probe = ATIProbe; + pScreenInfo->PreInit = ATIPreInit; + pScreenInfo->ScreenInit = ATIScreenInit; + pScreenInfo->SwitchMode = ATISwitchMode; + pScreenInfo->AdjustFrame = ATIAdjustFrame; + pScreenInfo->EnterVT = ATIEnterVT; + pScreenInfo->LeaveVT = ATILeaveVT; + pScreenInfo->FreeScreen = ATIFreeScreen; + pScreenInfo->ValidMode = ATIValidMode; +} diff --git a/src/atifillin.h b/src/atifillin.h new file mode 100644 index 0000000..dafd458 --- /dev/null +++ b/src/atifillin.h @@ -0,0 +1,22 @@ +/* + * atifillin.h: header for atifillin.c. + * + * (c) 2004 Adam Jackson. Standard MIT license applies. + */ + +#ifndef ATI_FILLIN_H +#define ATI_FILLIN_H + +/* include headers corresponding to fields touched by ATIFillInScreenInfo() */ + +#include "ativersion.h" +#include "atiprobe.h" +#include "atipreinit.h" +#include "atiscreen.h" +#include "aticonsole.h" +#include "atiadjust.h" +#include "ativalid.h" + +extern void ATIFillInScreenInfo(ScrnInfoPtr); + +#endif diff --git a/src/atii2c.c b/src/atii2c.c new file mode 100644 index 0000000..331bd70 --- /dev/null +++ b/src/atii2c.c @@ -0,0 +1,387 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atii2c.c,v 1.3 2003/11/10 18:41:20 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiadapter.h" +#include "atii2c.h" +#include "atiload.h" +#include "atimach64i2c.h" +#include "atistruct.h" + +#include "xf86.h" + +/* This is derived from GATOS code, with a liberal sprinkling of bug fixes */ + +/* + * Some local macros for use by the mid-level I2C functions. + */ + +#define ATII2CDelay \ + (*pI2CBus->I2CUDelay)(pI2CBus, pI2CBus->HoldTime) + + +#define ATII2CSCLDirOff \ + if (pATII2C->SCLDir != 0) \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur & ~pATII2C->SCLDir) + +#define ATII2CSCLDirOn \ + if (pATII2C->SCLDir != 0) \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur | pATII2C->SCLDir) + +#define ATII2CSDADirOff \ + if (pATII2C->SDADir != 0) \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur & ~pATII2C->SDADir) + +#define ATII2CSDADirOn \ + if (pATII2C->SDADir != 0) \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur | pATII2C->SDADir) + + +#define ATII2CSCLBitGet \ + ((*pATII2C->I2CGetBits)(pATI) & pATII2C->SCLGet) + +#define ATII2CSCLBitOff \ + do \ + { \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur & ~pATII2C->SCLSet); \ + ATII2CDelay; \ + } while (0) + +#define ATII2CSCLBitOn \ + do \ + { \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur | pATII2C->SCLSet); \ + do /* Wait until all devices have released SCL */ \ + { \ + ATII2CDelay; \ + } while (ATII2CSCLBitGet == 0); \ + } while (0) + + +#define ATII2CSDABitGet \ + ((*pATII2C->I2CGetBits)(pATI) & pATII2C->SDAGet) + +#define ATII2CSDABitOff \ + do \ + { \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur & ~pATII2C->SDASet); \ + ATII2CDelay; \ + } while (0) + +#define ATII2CSDABitOn \ + do \ + { \ + (*pATII2C->I2CSetBits)(pATII2C, pATI, \ + pATII2C->I2CCur | pATII2C->SDASet); \ + ATII2CDelay; \ + } while (0) + +#define ATII2CSDABitSet(_flag) \ + do \ + { \ + if (_flag) \ + ATII2CSDABitOn; \ + else \ + ATII2CSDABitOff; \ + } while (0) + + +/* + * ATII2CAddress -- + * + * This function puts a Start bit and an 8-bit address on the I2C bus. + */ +static Bool +ATII2CAddress +( + I2CDevPtr pI2CDev, + I2CSlaveAddr Address +) +{ + I2CBusPtr pI2CBus = pI2CDev->pI2CBus; + ATII2CPtr pATII2C = pI2CBus->DriverPrivate.ptr; + ATIPtr pATI = pATII2C->pATI; + + /* + * Set I2C line directions to out-bound. SCL will remain out-bound until + * next I2C Stop. + */ + ATII2CSCLDirOn; + ATII2CSDADirOn; + + /* + * Send Start bit. This is a pull-down of the data line while the clock + * line is pulled up. + */ + ATII2CSDABitOn; + ATII2CSCLBitOn; + ATII2CSDABitOff; + ATII2CSCLBitOff; + + /* Send low byte of device address */ + if ((*pI2CBus->I2CPutByte)(pI2CDev, (I2CByte)Address)) + { + /* Send top byte of address, if appropriate */ + if (((Address & 0x00F8U) != 0x00F0U) && + ((Address & 0x00FEU) != 0x0000U)) + return TRUE; + + if ((*pI2CBus->I2CPutByte)(pI2CDev, (I2CByte)(Address >> 8))) + return TRUE; + } + + /* Kill I2C transaction on failure */ + (*pI2CBus->I2CStop)(pI2CDev); + return FALSE; +} + +/* + * ATII2CStop -- + * + * This function puts a stop signal on the I2C bus. + */ +static void +ATII2CStop +( + I2CDevPtr pI2CDev +) +{ + I2CBusPtr pI2CBus = pI2CDev->pI2CBus; + ATII2CPtr pATII2C = pI2CBus->DriverPrivate.ptr; + ATIPtr pATI = pATII2C->pATI; + + ATII2CSDADirOn; /* Set data line direction to out-bound */ + + /* + * Send Stop bit. This is a pull-up of the data line while the clock line + * is pulled up. + */ + ATII2CSDABitOff; + ATII2CSCLBitOn; + ATII2CSDABitOn; + ATII2CSCLBitOff; + + /* Reset I2C line directions to in-bound */ + ATII2CSCLDirOff; + ATII2CSDADirOff; +} + +/* + * ATII2CPutByte -- + * + * This function puts an 8-bit value on the I2C bus, starting with its MSB. + */ +static Bool +ATII2CPutByte +( + I2CDevPtr pI2CDev, + I2CByte Data +) +{ + I2CBusPtr pI2CBus = pI2CDev->pI2CBus; + ATII2CPtr pATII2C = pI2CBus->DriverPrivate.ptr; + ATIPtr pATI = pATII2C->pATI; + int i; + Bool Result; + + ATII2CSDADirOn; /* Set data line direction to out-bound */ + + /* Send data byte */ + for (i = 0; i < 8; i++) + { + ATII2CSDABitSet(Data & 0x80U); + ATII2CSCLBitOn; + ATII2CSCLBitOff; + + Data <<= 1; + } + + ATII2CSDABitOn; /* Release data line */ + + ATII2CSDADirOff; /* Set data line direction to in-bound */ + + ATII2CSCLBitOn; /* Start bit-read clock pulse */ + + /* Get [N]ACK bit */ + if (ATII2CSDABitGet) + Result = FALSE; + else + Result = TRUE; + + ATII2CSCLBitOff; /* End clock pulse */ + + return Result; +} + +/* + * ATII2CGetByte -- + * + * This function retrieves an 8-bit value from the I2C bus. + */ +static Bool +ATII2CGetByte +( + I2CDevPtr pI2CDev, + I2CByte *pData, + Bool Last +) +{ + I2CBusPtr pI2CBus = pI2CDev->pI2CBus; + ATII2CPtr pATII2C = pI2CBus->DriverPrivate.ptr; + ATIPtr pATI = pATII2C->pATI; + unsigned long Value = 1; + + do + { + ATII2CSCLBitOn; /* Start bit-read clock pulse */ + + /* Accumulate bit into byte value */ + Value <<= 1; + if (ATII2CSDABitGet) + Value++; + + ATII2CSCLBitOff; /* End clock pulse */ + } while (Value <= (unsigned long)((I2CByte)(-1))); + + *pData = (I2CByte)Value; + + ATII2CSDADirOn; /* Set data line direction to out-bound */ + + /* Send [N]ACK bit */ + ATII2CSDABitSet(Last); + ATII2CSCLBitOn; + ATII2CSCLBitOff; + + if (!Last) + ATII2CSDABitOn; /* Release data line */ + + ATII2CSDADirOff; /* Set data line direction to in-bound */ + + return TRUE; +} + +/* + * ATICreateI2CBusRec -- + * + * This function is called to initialise an I2CBusRec. + */ +I2CBusPtr +ATICreateI2CBusRec +( + int iScreen, + ATIPtr pATI, + char *BusName +) +{ + I2CBusPtr pI2CBus; + ATII2CPtr pATII2C = xnfcalloc(1, SizeOf(ATII2CRec)); + + if (!(pI2CBus = xf86CreateI2CBusRec())) + { + xf86DrvMsg(iScreen, X_WARNING, "Unable to allocate I2C Bus record.\n"); + xfree(pATII2C); + return NULL; + } + + /* Fill in generic structure fields */ + pI2CBus->BusName = BusName; + pI2CBus->scrnIndex = iScreen; + + pI2CBus->I2CAddress = ATII2CAddress; + pI2CBus->I2CStop = ATII2CStop; + pI2CBus->I2CPutByte = ATII2CPutByte; + pI2CBus->I2CGetByte = ATII2CGetByte; + + pI2CBus->DriverPrivate.ptr = pATII2C; + + pATII2C->pATI = pATI; + + if (xf86I2CBusInit(pI2CBus)) + return pI2CBus; + + xf86DrvMsg(iScreen, X_WARNING, + "I2C bus %s initialisation failure.\n", BusName); + xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE); + xfree(pATII2C); + return NULL; +} + +/* + * ATII2CPreInit -- + * + * This is called by ATIPreInit() to create I2C bus record(s) for the adapter. + */ +void +ATII2CPreInit +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + switch (pATI->Adapter) + { + case ATI_ADAPTER_MACH64: + if (!ATILoadModule(pScreenInfo, "i2c", ATIi2cSymbols)) + return; + + ATIMach64I2CPreInit(pScreenInfo, pATI); + break; + + default: + break; + } +} + +/* + * ATII2CFreeScreen -- + * + * This is called by ATIFreeScreen() to remove the driver's I2C interface. + */ +void +ATII2CFreeScreen +( + int iScreen +) +{ + I2CBusPtr pI2CBus, *ppI2CBus; + ATII2CPtr pATII2C; + int nI2CBus; + + nI2CBus = xf86I2CGetScreenBuses(iScreen, &ppI2CBus); + while (--nI2CBus >= 0) + { + pI2CBus = ppI2CBus[nI2CBus]; + pATII2C = pI2CBus->DriverPrivate.ptr; + + xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE); + xfree(pATII2C); + } + + xfree(ppI2CBus); +} diff --git a/src/atii2c.h b/src/atii2c.h new file mode 100644 index 0000000..d33ba23 --- /dev/null +++ b/src/atii2c.h @@ -0,0 +1,50 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atii2c.h,v 1.1 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATII2C_H___ +#define ___ATII2C_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +#include "xf86i2c.h" + +typedef struct _ATII2CRec ATII2CRec, *ATII2CPtr; + +struct _ATII2CRec +{ + ATIPtr pATI; + void (*I2CSetBits) FunctionPrototype((ATII2CPtr, ATIPtr, CARD32)); + CARD32 (*I2CGetBits) FunctionPrototype((ATIPtr)); + CARD32 SCLDir, SCLGet, SCLSet; + CARD32 SDADir, SDAGet, SDASet; + CARD32 I2CCur; +}; + +extern void ATII2CPreInit FunctionPrototype((ScrnInfoPtr, ATIPtr)); +extern I2CBusPtr ATICreateI2CBusRec FunctionPrototype((int, ATIPtr, char *)); +extern void ATII2CFreeScreen FunctionPrototype((int)); + +#endif /* ___ATII2C_H___ */ diff --git a/src/atiident.c b/src/atiident.c new file mode 100644 index 0000000..91dd114 --- /dev/null +++ b/src/atiident.c @@ -0,0 +1,134 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiident.c,v 1.11 2003/01/01 19:16:32 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiident.h" +#include "atiutil.h" +#include "ativersion.h" + +#include "r128_probe.h" +#include "radeon_probe.h" + +const char *ATIChipsetNames[] = +{ + "ati", + +#ifndef AVOID_CPIO + + "ativga", + "ibmvga", + "ibm8514", + "vgawonder", + "mach8", + "mach32", + +#endif /* AVOID_CPIO */ + + "mach64", + "rage128", + "radeon" +}; + +static SymTabRec ATIPublicChipsetNames[] = +{ + {ATI_CHIPSET_ATI, "ati"}, + +#ifndef AVOID_CPIO + + {ATI_CHIPSET_ATIVGA, "ativga"}, +#ifdef __MAYBE_NOT__ + {ATI_CHIPSET_IBMVGA, "ibmvga"}, +#endif +#ifdef __NOT_YET__ + {ATI_CHIPSET_IBM8514, "ibm8514"}, +#endif + +#endif /* AVOID_CPIO */ + + {-1, NULL} +}; + +/* + * ATIIdentify -- + * + * Print the driver's list of chipset names. + */ +void +ATIIdentify +( + int flags +) +{ + xf86PrintChipsets(ATI_NAME, + (NumberOf(ATIPublicChipsetNames) <= 2) ? + "ATI driver (version " ATI_VERSION_NAME ") for chipset" : + "ATI driver (version " ATI_VERSION_NAME ") for chipsets", + ATIPublicChipsetNames); + R128Identify(flags); + RADEONIdentify(flags); +} + +/* + * ATIIdentProbe -- + * + * This function determines if the user specified a chipset name acceptable to + * the driver. It returns an ATIChipsetType or -1. + */ +int +ATIIdentProbe +( + const char *ChipsetName +) +{ + int Chipset; + + static SymTabRec SpecificNames[] = + { + +#ifndef AVOID_CPIO + + {ATI_CHIPSET_VGAWONDER, "vgawonder"}, +#ifdef __NOT_YET__ + {ATI_CHIPSET_MACH8, "mach8"}, +#endif + {ATI_CHIPSET_MACH32, "mach32"}, + +#endif /* AVOID_CPIO */ + + {ATI_CHIPSET_MACH64, "mach64"}, + {ATI_CHIPSET_RAGE128, "rage128"}, + {ATI_CHIPSET_RADEON, "radeon"}, + {-1, NULL} + }; + + /* If no Chipset specification, default to "ati" */ + if (!ChipsetName || !*ChipsetName) + return ATI_CHIPSET_ATI; + + Chipset = xf86StringToToken(ATIPublicChipsetNames, ChipsetName); + if (Chipset != -1) + return Chipset; + + /* Check for some other chipset names */ + return xf86StringToToken(SpecificNames, ChipsetName); +} diff --git a/src/atiident.h b/src/atiident.h new file mode 100644 index 0000000..1c5969a --- /dev/null +++ b/src/atiident.h @@ -0,0 +1,55 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiident.h,v 1.10 2003/01/01 19:16:32 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIIDENT_H___ +#define ___ATIIDENT_H___ 1 + +#include "atiproto.h" + +typedef enum +{ + ATI_CHIPSET_ATI, + +#ifndef AVOID_CPIO + + ATI_CHIPSET_ATIVGA, + ATI_CHIPSET_IBMVGA, + ATI_CHIPSET_IBM8514, + ATI_CHIPSET_VGAWONDER, + ATI_CHIPSET_MACH8, + ATI_CHIPSET_MACH32, + +#endif /* AVOID_CPIO */ + + ATI_CHIPSET_MACH64, + ATI_CHIPSET_RAGE128, + ATI_CHIPSET_RADEON, + ATI_CHIPSET_MAX /* Must be last */ +} ATIChipsetType; + +extern const char *ATIChipsetNames[]; + +extern void ATIIdentify FunctionPrototype((int)); +extern int ATIIdentProbe FunctionPrototype((const char *)); + +#endif /* ___ATIIDENT_H___ */ diff --git a/src/atiio.h b/src/atiio.h new file mode 100644 index 0000000..9405033 --- /dev/null +++ b/src/atiio.h @@ -0,0 +1,83 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiio.h,v 1.14 2003/01/01 19:16:32 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIIO_H___ + +#if !defined(___ATI_H___) && defined(XFree86Module) +# error missing #include "ati.h" before #include "atiio.h" +# undef XFree86Module +#endif + +#define ___ATIIO_H___ 1 + +#include "atiregs.h" + +#include "compiler.h" + +/* I/O decoding definitions */ +typedef enum +{ + SPARSE_IO, + BLOCK_IO +} ATIIODecodingType; + +#ifndef AVOID_CPIO + +/* Wait until "n" queue entries are free */ +#define ibm8514WaitQueue(_n) \ + { \ + while (inw(GP_STAT) & (0x0100U >> (_n))); \ + } +#define ATIWaitQueue(_n) \ + { \ + while (inw(EXT_FIFO_STATUS) & (0x010000U >> (_n))); \ + } + +/* Wait until GP is idle and queue is empty */ +#define WaitIdleEmpty() \ + { \ + while (inw(GP_STAT) & (GPBUSY | 1)); \ + } +#define ProbeWaitIdleEmpty() \ + { \ + int _i; \ + CARD16 _value; \ + for (_i = 0; _i < 100000; _i++) \ + { \ + _value = inw(GP_STAT); \ + if (_value == (CARD16)(-1)) \ + break; \ + if (!(_value & (GPBUSY | 1))) \ + break; \ + } \ + } + +/* Wait until GP has data available */ +#define WaitDataReady() \ + { \ + while (!(inw(GP_STAT) & DATARDY)); \ + } + +#endif /* AVOID_CPIO */ + +#endif /* ___ATIIO_H___ */ diff --git a/src/atiload.c b/src/atiload.c new file mode 100644 index 0000000..e00f216 --- /dev/null +++ b/src/atiload.c @@ -0,0 +1,189 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiload.c,v 1.15 2003/08/29 21:07:57 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifdef XFree86LOADER + +#include "ati.h" +#include "aticursor.h" +#include "atiload.h" +#include "atistruct.h" + +/* + * All symbol lists belong here. They are externalised so that they can be + * referenced elsewhere. Note the naming convention for these things... + */ + +const char *ATIint10Symbols[] = +{ + "xf86FreeInt10", + "xf86InitInt10", + "xf86int10Addr", + NULL +}; + +const char *ATIddcSymbols[] = +{ + "xf86PrintEDID", + "xf86SetDDCProperties", + NULL +}; + +const char *ATIvbeSymbols[] = +{ + "VBEInit", + "vbeDoEDID", + "vbeFree", + NULL +}; + +#ifndef AVOID_CPIO + +const char *ATIxf1bppSymbols[] = +{ + "xf1bppScreenInit", + NULL +}; + +const char *ATIxf4bppSymbols[] = +{ + "xf4bppScreenInit", + NULL +}; + +#endif /* AVOID_CPIO */ + +const char *ATIfbSymbols[] = +{ + "fbPictureInit", + "fbScreenInit", + NULL +}; + +const char *ATIshadowfbSymbols[] = +{ + "ShadowFBInit", + NULL +}; + +const char *ATIxaaSymbols[] = +{ + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAInit", + NULL +}; + +const char *ATIramdacSymbols[] = +{ + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +const char *ATIi2cSymbols[] = +{ + "xf86CreateI2CBusRec", + "xf86DestroyI2CBusRec", + "xf86I2CBusInit", + "xf86I2CDevInit", + "xf86I2CFindDev", + "xf86I2CGetScreenBuses", + NULL +}; + +/* + * ATILoadModule -- + * + * Load a specific module and register with the loader those of its entry + * points that are referenced by this driver. + */ +pointer +ATILoadModule +( + ScrnInfoPtr pScreenInfo, + const char *Module, + const char **SymbolList +) +{ + pointer pModule = xf86LoadSubModule(pScreenInfo, Module); + + if (pModule) + xf86LoaderReqSymLists(SymbolList, NULL); + + return pModule; +} + +/* + * ATILoadModules -- + * + * This function loads other modules required for a screen. + */ +pointer +ATILoadModules +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + /* Load shadow frame buffer code if needed */ + if (pATI->OptionShadowFB && + !ATILoadModule(pScreenInfo, "shadowfb", ATIshadowfbSymbols)) + return NULL; + + /* Load XAA if needed */ + if (pATI->OptionAccel && + !ATILoadModule(pScreenInfo, "xaa", ATIxaaSymbols)) + return NULL; + + /* Load ramdac module if needed */ + if ((pATI->Cursor > ATI_CURSOR_SOFTWARE) && + !ATILoadModule(pScreenInfo, "ramdac", ATIramdacSymbols)) + return NULL; + + /* Load depth-specific entry points */ + switch (pATI->bitsPerPixel) + { + +#ifndef AVOID_CPIO + + case 1: + return ATILoadModule(pScreenInfo, "xf1bpp", ATIxf1bppSymbols); + + case 4: + return ATILoadModule(pScreenInfo, "xf4bpp", ATIxf4bppSymbols); + +#endif /* AVOID_CPIO */ + + case 8: + case 16: + case 24: + case 32: + return ATILoadModule(pScreenInfo, "fb", ATIfbSymbols); + + default: + return NULL; + } +} + +#endif /* XFree86LOADER */ diff --git a/src/atiload.h b/src/atiload.h new file mode 100644 index 0000000..a506f34 --- /dev/null +++ b/src/atiload.h @@ -0,0 +1,56 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiload.h,v 1.6 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATILOAD_H___ +#define ___ATILOAD_H___ 1 + +#ifdef XFree86LOADER + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern const char *ATIint10Symbols[], *ATIddcSymbols[], *ATIvbeSymbols[], + +#ifndef AVOID_CPIO + + *ATIxf1bppSymbols[], *ATIxf4bppSymbols[], + +#endif /* AVOID_CPIO */ + + *ATIfbSymbols[], *ATIshadowfbSymbols[], *ATIxaaSymbols[], + *ATIramdacSymbols[], *ATIi2cSymbols[]; + +extern pointer ATILoadModule FunctionPrototype((ScrnInfoPtr, const char *, + const char **)); +extern pointer ATILoadModules FunctionPrototype((ScrnInfoPtr, ATIPtr)); + +#else /* XFree86LOADER */ + +#define ATILoadModule(pScreenInfo, Module, SymboList) ((pointer)1) +#define ATILoadModules(pScreenInfo, pATI) ((pointer)1) + +#endif /* XFree86LOADER */ + +#endif /* ___ATILOAD_H___ */ diff --git a/src/atilock.c b/src/atilock.c new file mode 100644 index 0000000..a6d5cda --- /dev/null +++ b/src/atilock.c @@ -0,0 +1,588 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atilock.c,v 1.20tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atichip.h" +#include "atilock.h" +#include "atimach64io.h" +#include "atiwonderio.h" + +/* + * ATIUnlock -- + * + * This function is entered to unlock registers and disable unwanted + * emulations. It saves the current state for later restoration by ATILock(). + */ +void +ATIUnlock +( + ATIPtr pATI +) +{ + CARD32 tmp; + +#ifndef AVOID_CPIO + + CARD32 saved_lcd_gen_ctrl = 0, lcd_gen_ctrl = 0; + +#endif /* AVOID_CPIO */ + + if (pATI->Unlocked) + return; + pATI->Unlocked = TRUE; + +#ifndef AVOID_CPIO + + if (pATI->ChipHasSUBSYS_CNTL) + { + /* Save register values to be modified */ + pATI->LockData.clock_sel = inw(CLOCK_SEL); + if (pATI->Chip >= ATI_CHIP_68800) + { + pATI->LockData.misc_options = inw(MISC_OPTIONS); + pATI->LockData.mem_bndry = inw(MEM_BNDRY); + pATI->LockData.mem_cfg = inw(MEM_CFG); + } + + tmp = inw(SUBSYS_STAT) & _8PLANE; + + /* Reset the 8514/A and disable all interrupts */ + outw(SUBSYS_CNTL, tmp | (GPCTRL_RESET | CHPTEST_NORMAL)); + outw(SUBSYS_CNTL, tmp | (GPCTRL_ENAB | CHPTEST_NORMAL | RVBLNKFLG | + RPICKFLAG | RINVALIDIO | RGPIDLE)); + + /* Ensure VGA is enabled */ + outw(CLOCK_SEL, pATI->LockData.clock_sel &~DISABPASSTHRU); + if (pATI->Chip >= ATI_CHIP_68800) + { + outw(MISC_OPTIONS, pATI->LockData.misc_options & + ~(DISABLE_VGA | DISABLE_DAC)); + + /* Disable any video memory boundary */ + outw(MEM_BNDRY, pATI->LockData.mem_bndry & + ~(MEM_PAGE_BNDRY | MEM_BNDRY_ENA)); + + /* Disable direct video memory aperture */ + outw(MEM_CFG, pATI->LockData.mem_cfg & + ~(MEM_APERT_SEL | MEM_APERT_PAGE | MEM_APERT_LOC)); + } + + /* Wait for all activity to die down */ + ProbeWaitIdleEmpty(); + } + else if (pATI->Chip >= ATI_CHIP_88800GXC) + +#endif /* AVOID_CPIO */ + + { + /* Reset everything */ + pATI->LockData.bus_cntl = inr(BUS_CNTL); + if (pATI->Chip < ATI_CHIP_264VT4) + { + pATI->LockData.bus_cntl = + (pATI->LockData.bus_cntl & ~BUS_HOST_ERR_INT_EN) | + BUS_HOST_ERR_INT; + if (pATI->Chip < ATI_CHIP_264VTB) + pATI->LockData.bus_cntl = + (pATI->LockData.bus_cntl & ~BUS_FIFO_ERR_INT_EN) | + BUS_FIFO_ERR_INT; + } + tmp = pATI->LockData.bus_cntl & ~BUS_ROM_DIS; + if (pATI->Chip < ATI_CHIP_264VTB) + tmp |= SetBits(15, BUS_FIFO_WS); + else + tmp &= ~BUS_MASTER_DIS; + if (pATI->Chip >= ATI_CHIP_264VT) + tmp |= BUS_EXT_REG_EN; /* Enable Block 1 */ + outr(BUS_CNTL, tmp); + pATI->LockData.crtc_int_cntl = inr(CRTC_INT_CNTL); + outr(CRTC_INT_CNTL, (pATI->LockData.crtc_int_cntl & ~CRTC_INT_ENS) | + CRTC_INT_ACKS); + pATI->LockData.gen_test_cntl = inr(GEN_TEST_CNTL) & + (GEN_OVR_OUTPUT_EN | GEN_OVR_POLARITY | GEN_CUR_EN | + GEN_BLOCK_WR_EN); + tmp = pATI->LockData.gen_test_cntl & ~GEN_CUR_EN; + outr(GEN_TEST_CNTL, tmp | GEN_GUI_EN); + outr(GEN_TEST_CNTL, tmp); + outr(GEN_TEST_CNTL, tmp | GEN_GUI_EN); + tmp = pATI->LockData.crtc_gen_cntl = inr(CRTC_GEN_CNTL) & + ~(CRTC_EN | CRTC_LOCK_REGS); + if (pATI->Chip >= ATI_CHIP_264XL) + tmp = (tmp & ~CRTC_INT_ENS_X) | CRTC_INT_ACKS_X; + outr(CRTC_GEN_CNTL, tmp | CRTC_EN); + outr(CRTC_GEN_CNTL, tmp); + outr(CRTC_GEN_CNTL, tmp | CRTC_EN); + if ((pATI->LCDPanelID >= 0) && (pATI->Chip != ATI_CHIP_264LT)) + { + pATI->LockData.lcd_index = inr(LCD_INDEX); + if (pATI->Chip >= ATI_CHIP_264XL) + outr(LCD_INDEX, pATI->LockData.lcd_index & + ~(LCD_MONDET_INT_EN | LCD_MONDET_INT)); + + /* + * Prevent BIOS initiated display switches on dual-CRT controllers. + */ + if (!pATI->OptionBIOSDisplay && (pATI->Chip != ATI_CHIP_264XL)) + { + pATI->LockData.scratch_reg3 = inr(SCRATCH_REG3); + outr(SCRATCH_REG3, + pATI->LockData.scratch_reg3 | DISPLAY_SWITCH_DISABLE); + } + } + + pATI->LockData.mem_cntl = inr(MEM_CNTL); + if (pATI->Chip < ATI_CHIP_264CT) + outr(MEM_CNTL, pATI->LockData.mem_cntl & + ~(CTL_MEM_BNDRY | CTL_MEM_BNDRY_EN)); + + /* Disable feature connector on integrated controllers */ + tmp = pATI->LockData.dac_cntl = inr(DAC_CNTL); + if (pATI->Chip >= ATI_CHIP_264CT) + tmp &= ~DAC_FEA_CON_EN; + +#ifndef AVOID_CPIO + + /* Ensure VGA aperture is enabled */ + pATI->LockData.config_cntl = inr(CONFIG_CNTL); + tmp |= DAC_VGA_ADR_EN; + outr(CONFIG_CNTL, pATI->LockData.config_cntl & ~CFG_VGA_DIS); + +#endif /* AVOID_CPIO */ + + outr(DAC_CNTL, tmp); + + if (pATI->Chip >= ATI_CHIP_264VTB) + { + pATI->LockData.mpp_config = inr(MPP_CONFIG); + pATI->LockData.mpp_strobe_seq = inr(MPP_STROBE_SEQ); + pATI->LockData.tvo_cntl = inr(TVO_CNTL); + + if (pATI->Chip >= ATI_CHIP_264GT2C) + { + pATI->LockData.hw_debug = inr(HW_DEBUG); + + if (pATI->Chip >= ATI_CHIP_264GTPRO) + { + if (!(pATI->LockData.hw_debug & CMDFIFO_SIZE_EN)) + outr(HW_DEBUG, + pATI->LockData.hw_debug | CMDFIFO_SIZE_EN); + + pATI->LockData.i2c_cntl_0 = + inr(I2C_CNTL_0) | (I2C_CNTL_STAT | I2C_CNTL_HPTR_RST); + outr(I2C_CNTL_0, + pATI->LockData.i2c_cntl_0 & ~I2C_CNTL_INT_EN); + pATI->LockData.i2c_cntl_1 = inr(I2C_CNTL_1); + } + else + { + if (pATI->LockData.hw_debug & CMDFIFO_SIZE_DIS) + outr(HW_DEBUG, + pATI->LockData.hw_debug & ~CMDFIFO_SIZE_DIS); + } + } + } + +#ifndef AVOID_CPIO + + } + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + if (pATI->CPIO_VGAWonder) + { + /* + * Ensure all registers are read/write and disable all non-VGA + * emulations. + */ + pATI->LockData.b1 = ATIGetExtReg(0xB1U); + ATIModifyExtReg(pATI, 0xB1U, pATI->LockData.b1, 0xFCU, 0x00U); + pATI->LockData.b4 = ATIGetExtReg(0xB4U); + ATIModifyExtReg(pATI, 0xB4U, pATI->LockData.b4, 0x00U, 0x00U); + pATI->LockData.b5 = ATIGetExtReg(0xB5U); + ATIModifyExtReg(pATI, 0xB5U, pATI->LockData.b5, 0xBFU, 0x00U); + pATI->LockData.b6 = ATIGetExtReg(0xB6U); + ATIModifyExtReg(pATI, 0xB6U, pATI->LockData.b6, 0xDDU, 0x00U); + pATI->LockData.b8 = ATIGetExtReg(0xB8U); + ATIModifyExtReg(pATI, 0xB8U, pATI->LockData.b8, 0xC0U, 0x00U); + pATI->LockData.b9 = ATIGetExtReg(0xB9U); + ATIModifyExtReg(pATI, 0xB9U, pATI->LockData.b9, 0x7FU, 0x00U); + if (pATI->Chip > ATI_CHIP_18800) + { + pATI->LockData.be = ATIGetExtReg(0xBEU); + ATIModifyExtReg(pATI, 0xBEU, pATI->LockData.be, 0xFAU, 0x01U); + if (pATI->Chip >= ATI_CHIP_28800_2) + { + pATI->LockData.a6 = ATIGetExtReg(0xA6U); + ATIModifyExtReg(pATI, 0xA6U, pATI->LockData.a6, + 0x7FU, 0x00U); + pATI->LockData.ab = ATIGetExtReg(0xABU); + ATIModifyExtReg(pATI, 0xABU, pATI->LockData.ab, + 0xE7U, 0x00U); + } + } + } + + if (pATI->LCDPanelID >= 0) + { + if (pATI->Chip == ATI_CHIP_264LT) + { + saved_lcd_gen_ctrl = inr(LCD_GEN_CTRL); + + /* Setup to unlock non-shadow registers */ + lcd_gen_ctrl = saved_lcd_gen_ctrl & ~SHADOW_RW_EN; + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + saved_lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + + /* Setup to unlock non-shadow registers */ + lcd_gen_ctrl = saved_lcd_gen_ctrl & + ~(CRTC_RW_SELECT | SHADOW_RW_EN); + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + } + } + + ATISetVGAIOBase(pATI, inb(R_GENMO)); + + /* + * There's a bizarre interaction here. If bit 0x80 of CRTC[17] is on, + * then CRTC[3] is read-only. If bit 0x80 of CRTC[3] is off, then + * CRTC[17] is write-only (or a read attempt actually returns bits from + * C/EGA's light pen position). This means that if both conditions are + * met, CRTC[17]'s value on server entry cannot be retrieved. + */ + + pATI->LockData.crt03 = tmp = GetReg(CRTX(pATI->CPIO_VGABase), 0x03U); + if ((tmp & 0x80U) || + ((outb(CRTD(pATI->CPIO_VGABase), tmp | 0x80U), + tmp = inb(CRTD(pATI->CPIO_VGABase))) & 0x80U)) + { + /* CRTC[16-17] should be readable */ + pATI->LockData.crt11 = tmp = + GetReg(CRTX(pATI->CPIO_VGABase), 0x11U); + if (tmp & 0x80U) /* Unprotect CRTC[0-7] */ + outb(CRTD(pATI->CPIO_VGABase), tmp & 0x7FU); + } + else + { + /* + * Could not make CRTC[17] readable, so unprotect CRTC[0-7] + * replacing VSyncEnd with zero. This zero will be replaced after + * acquiring the needed access. + */ + unsigned int VSyncEnd, VBlankStart, VBlankEnd; + CARD8 crt07, crt09; + + PutReg(CRTX(pATI->CPIO_VGABase), 0x11U, 0x20U); + /* Make CRTC[16-17] readable */ + PutReg(CRTX(pATI->CPIO_VGABase), 0x03U, tmp | 0x80U); + /* Make vertical synch pulse as wide as possible */ + crt07 = GetReg(CRTX(pATI->CPIO_VGABase), 0x07U); + crt09 = GetReg(CRTX(pATI->CPIO_VGABase), 0x09U); + VBlankStart = (((crt09 & 0x20U) << 4) | ((crt07 & 0x08U) << 5) | + GetReg(CRTX(pATI->CPIO_VGABase), 0x15U)) + 1; + VBlankEnd = (VBlankStart & 0x0300U) | + GetReg(CRTX(pATI->CPIO_VGABase), 0x16U); + if (VBlankEnd <= VBlankStart) + VBlankEnd += 0x0100U; + VSyncEnd = (((crt07 & 0x80U) << 2) | ((crt07 & 0x04U) << 6) | + GetReg(CRTX(pATI->CPIO_VGABase), 0x10U)) + 0x0FU; + if (VSyncEnd >= VBlankEnd) + VSyncEnd = VBlankEnd - 1; + pATI->LockData.crt11 = (VSyncEnd & 0x0FU) | 0x20U; + PutReg(CRTX(pATI->CPIO_VGABase), 0x11U, pATI->LockData.crt11); + pATI->LockData.crt11 |= 0x80U; + } + + if (pATI->LCDPanelID >= 0) + { + /* Setup to unlock shadow registers */ + lcd_gen_ctrl |= SHADOW_RW_EN; + + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + + /* Unlock shadow registers */ + ATISetVGAIOBase(pATI, inb(R_GENMO)); + + pATI->LockData.shadow_crt03 = tmp = + GetReg(CRTX(pATI->CPIO_VGABase), 0x03U); + if ((tmp & 0x80U) || + ((outb(CRTD(pATI->CPIO_VGABase), tmp | 0x80U), + tmp = inb(CRTD(pATI->CPIO_VGABase))) & 0x80U)) + { + /* CRTC[16-17] should be readable */ + pATI->LockData.shadow_crt11 = tmp = + GetReg(CRTX(pATI->CPIO_VGABase), 0x11U); + if (tmp & 0x80U) /* Unprotect CRTC[0-7] */ + { + outb(CRTD(pATI->CPIO_VGABase), tmp & 0x7FU); + } + else if (!tmp && pATI->LockData.crt11) + { + pATI->LockData.shadow_crt11 = tmp = pATI->LockData.crt11; + outb(CRTD(pATI->CPIO_VGABase), tmp & 0x7FU); + } + } + else + { + /* + * Could not make CRTC[17] readable, so unprotect CRTC[0-7] + * replacing VSyncEnd with zero. This zero will be replaced + * after acquiring the needed access. + */ + unsigned int VSyncEnd, VBlankStart, VBlankEnd; + CARD8 crt07, crt09; + + PutReg(CRTX(pATI->CPIO_VGABase), 0x11U, 0x20U); + /* Make CRTC[16-17] readable */ + PutReg(CRTX(pATI->CPIO_VGABase), 0x03U, tmp | 0x80U); + /* Make vertical synch pulse as wide as possible */ + crt07 = GetReg(CRTX(pATI->CPIO_VGABase), 0x07U); + crt09 = GetReg(CRTX(pATI->CPIO_VGABase), 0x09U); + VBlankStart = (((crt09 & 0x20U) << 4) | + ((crt07 & 0x08U) << 5) | + GetReg(CRTX(pATI->CPIO_VGABase), 0x15U)) + 1; + VBlankEnd = (VBlankStart & 0x0300U) | + GetReg(CRTX(pATI->CPIO_VGABase), 0x16U); + if (VBlankEnd <= VBlankStart) + VBlankEnd += 0x0100U; + VSyncEnd = (((crt07 & 0x80U) << 2) | ((crt07 & 0x04U) << 6) | + GetReg(CRTX(pATI->CPIO_VGABase), 0x10U)) + 0x0FU; + if (VSyncEnd >= VBlankEnd) + VSyncEnd = VBlankEnd - 1; + pATI->LockData.shadow_crt11 = (VSyncEnd & 0x0FU) | 0x20U; + PutReg(CRTX(pATI->CPIO_VGABase), 0x11U, + pATI->LockData.shadow_crt11); + pATI->LockData.shadow_crt11 |= 0x80U; + } + + /* Restore selection */ + if (pATI->Chip == ATI_CHIP_264LT) + { + outr(LCD_GEN_CTRL, saved_lcd_gen_ctrl); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + ATIMach64PutLCDReg(LCD_GEN_CNTL, saved_lcd_gen_ctrl); + + /* Restore LCD index */ + out8(LCD_INDEX, GetByte(pATI->LockData.lcd_index, 0)); + } + } + +#endif /* AVOID_CPIO */ + + } +} + +/* + * ATILock -- + * + * This function restores the state saved by ATIUnlock() above. + */ +void +ATILock +( + ATIPtr pATI +) +{ + +#ifndef AVOID_CPIO + + CARD32 tmp, saved_lcd_gen_ctrl = 0, lcd_gen_ctrl = 0; + +#endif /* AVOID_CPIO */ + + if (!pATI->Unlocked) + return; + pATI->Unlocked = FALSE; + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + if (pATI->LCDPanelID >= 0) + { + if (pATI->Chip == ATI_CHIP_264LT) + { + saved_lcd_gen_ctrl = inr(LCD_GEN_CTRL); + + /* Setup to lock non-shadow registers */ + lcd_gen_ctrl = saved_lcd_gen_ctrl & ~SHADOW_RW_EN; + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + saved_lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + + /* Setup to lock non-shadow registers */ + lcd_gen_ctrl = saved_lcd_gen_ctrl & + ~(CRTC_RW_SELECT | SHADOW_RW_EN); + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + } + } + + ATISetVGAIOBase(pATI, inb(R_GENMO)); + + /* Restore VGA locks */ + PutReg(CRTX(pATI->CPIO_VGABase), 0x03U, pATI->LockData.crt03); + PutReg(CRTX(pATI->CPIO_VGABase), 0x11U, pATI->LockData.crt11); + + if (pATI->LCDPanelID >= 0) + { + /* Setup to lock shadow registers */ + lcd_gen_ctrl |= SHADOW_RW_EN; + + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + + /* Lock shadow registers */ + ATISetVGAIOBase(pATI, inb(R_GENMO)); + + PutReg(CRTX(pATI->CPIO_VGABase), 0x03U, + pATI->LockData.shadow_crt03); + PutReg(CRTX(pATI->CPIO_VGABase), 0x11U, + pATI->LockData.shadow_crt11); + + /* Restore selection */ + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, saved_lcd_gen_ctrl); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, saved_lcd_gen_ctrl); + } + + if (pATI->CPIO_VGAWonder) + { + /* + * Restore emulation and protection bits in ATI extended VGA + * registers. + */ + ATIModifyExtReg(pATI, 0xB1U, -1, 0xFCU, pATI->LockData.b1); + ATIModifyExtReg(pATI, 0xB4U, -1, 0x00U, pATI->LockData.b4); + ATIModifyExtReg(pATI, 0xB5U, -1, 0xBFU, pATI->LockData.b5); + ATIModifyExtReg(pATI, 0xB6U, -1, 0xDDU, pATI->LockData.b6); + ATIModifyExtReg(pATI, 0xB8U, -1, 0xC0U, pATI->LockData.b8 & 0x03U); + ATIModifyExtReg(pATI, 0xB9U, -1, 0x7FU, pATI->LockData.b9); + if (pATI->Chip > ATI_CHIP_18800) + { + ATIModifyExtReg(pATI, 0xBEU, -1, 0xFAU, pATI->LockData.be); + if (pATI->Chip >= ATI_CHIP_28800_2) + { + ATIModifyExtReg(pATI, 0xA6U, -1, 0x7FU, pATI->LockData.a6); + ATIModifyExtReg(pATI, 0xABU, -1, 0xE7U, pATI->LockData.ab); + } + } + ATIModifyExtReg(pATI, 0xB8U, -1, 0xC0U, pATI->LockData.b8); + } + } + + if (pATI->ChipHasSUBSYS_CNTL) + { + tmp = inw(SUBSYS_STAT) & _8PLANE; + + /* Reset the 8514/A and disable all interrupts */ + outw(SUBSYS_CNTL, tmp | (GPCTRL_RESET | CHPTEST_NORMAL)); + outw(SUBSYS_CNTL, tmp | (GPCTRL_ENAB | CHPTEST_NORMAL | RVBLNKFLG | + RPICKFLAG | RINVALIDIO | RGPIDLE)); + + /* Restore modified accelerator registers */ + outw(CLOCK_SEL, pATI->LockData.clock_sel); + if (pATI->Chip >= ATI_CHIP_68800) + { + outw(MISC_OPTIONS, pATI->LockData.misc_options); + outw(MEM_BNDRY, pATI->LockData.mem_bndry); + outw(MEM_CFG, pATI->LockData.mem_cfg); + } + + /* Wait for all activity to die down */ + ProbeWaitIdleEmpty(); + } + else if (pATI->Chip >= ATI_CHIP_88800GXC) + +#endif /* AVOID_CPIO */ + + { + /* Reset everything */ + outr(BUS_CNTL, pATI->LockData.bus_cntl); + + outr(CRTC_INT_CNTL, pATI->LockData.crtc_int_cntl); + + outr(GEN_TEST_CNTL, pATI->LockData.gen_test_cntl | GEN_GUI_EN); + outr(GEN_TEST_CNTL, pATI->LockData.gen_test_cntl); + outr(GEN_TEST_CNTL, pATI->LockData.gen_test_cntl | GEN_GUI_EN); + + outr(CRTC_GEN_CNTL, pATI->LockData.crtc_gen_cntl | CRTC_EN); + outr(CRTC_GEN_CNTL, pATI->LockData.crtc_gen_cntl); + outr(CRTC_GEN_CNTL, pATI->LockData.crtc_gen_cntl | CRTC_EN); + +#ifndef AVOID_CPIO + + outr(CONFIG_CNTL, pATI->LockData.config_cntl); + +#endif /* AVOID_CPIO */ + + outr(DAC_CNTL, pATI->LockData.dac_cntl); + if (pATI->Chip < ATI_CHIP_264CT) + outr(MEM_CNTL, pATI->LockData.mem_cntl); + if ((pATI->LCDPanelID >= 0) && (pATI->Chip != ATI_CHIP_264LT)) + { + outr(LCD_INDEX, pATI->LockData.lcd_index); + if (!pATI->OptionBIOSDisplay && (pATI->Chip != ATI_CHIP_264XL)) + outr(SCRATCH_REG3, pATI->LockData.scratch_reg3); + } + if (pATI->Chip >= ATI_CHIP_264VTB) + { + outr(MPP_CONFIG, pATI->LockData.mpp_config); + outr(MPP_STROBE_SEQ, pATI->LockData.mpp_strobe_seq); + outr(TVO_CNTL, pATI->LockData.tvo_cntl); + if (pATI->Chip >= ATI_CHIP_264GT2C) + { + outr(HW_DEBUG, pATI->LockData.hw_debug); + if (pATI->Chip >= ATI_CHIP_264GTPRO) + { + outr(I2C_CNTL_0, pATI->LockData.i2c_cntl_0); + outr(I2C_CNTL_1, pATI->LockData.i2c_cntl_1); + } + } + } + } +} diff --git a/src/atilock.h b/src/atilock.h new file mode 100644 index 0000000..70c6393 --- /dev/null +++ b/src/atilock.h @@ -0,0 +1,33 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atilock.h,v 1.5 2003/01/01 19:16:32 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATILOCK_H___ +#define ___ATILOCK_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +extern void ATIUnlock FunctionPrototype((ATIPtr)); +extern void ATILock FunctionPrototype((ATIPtr)); + +#endif /* ___ATILOCK_H___ */ diff --git a/src/atimach64.c b/src/atimach64.c new file mode 100644 index 0000000..f90f6f9 --- /dev/null +++ b/src/atimach64.c @@ -0,0 +1,1181 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64.c,v 1.52 2003/04/23 21:51:28 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atibus.h" +#include "atichip.h" +#include "atidac.h" +#include "atimach64.h" +#include "atimach64accel.h" +#include "atimach64io.h" +#include "atirgb514.h" + +#ifndef DPMS_SERVER +# define DPMS_SERVER +#endif +#include "extensions/dpms.h" + +/* + * ATIMach64PreInit -- + * + * This function fills in the Mach64 portion of an ATIHWRec that is common to + * all video modes generated by the driver. + */ +void +ATIMach64PreInit +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + CARD32 bus_cntl, config_cntl; + int tmp; + +#ifndef AVOID_CPIO + + if (pATI->depth <= 4) + { + pATIHW->crtc_off_pitch = SetBits(pATI->displayWidth >> 4, CRTC_PITCH); + } + else + +#endif /* AVOID_CPIO */ + + { + pATIHW->crtc_off_pitch = SetBits(pATI->displayWidth >> 3, CRTC_PITCH); + } + + if ((pATI->LockData.crtc_gen_cntl & CRTC_CSYNC_EN) && !pATI->OptionCSync) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "Using composite sync to match input timing.\n"); + pATI->OptionCSync = TRUE; + } + + pATIHW->bus_cntl = bus_cntl = inr(BUS_CNTL); + if (pATI->Chip < ATI_CHIP_264VT4) + pATIHW->bus_cntl = (pATIHW->bus_cntl & ~BUS_HOST_ERR_INT_EN) | + BUS_HOST_ERR_INT; + if (pATI->Chip < ATI_CHIP_264VTB) + { + pATIHW->bus_cntl &= ~(BUS_FIFO_ERR_INT_EN | BUS_ROM_DIS); + pATIHW->bus_cntl |= SetBits(15, BUS_FIFO_WS) | BUS_FIFO_ERR_INT; + } + else if (pATI->MMIOInLinear) + { + pATIHW->bus_cntl &= ~BUS_APER_REG_DIS; + } + else + { + pATIHW->bus_cntl |= BUS_APER_REG_DIS; + } + if (pATI->Chip >= ATI_CHIP_264VT) + pATIHW->bus_cntl |= BUS_EXT_REG_EN; /* Enable Block 1 */ + +#ifdef AVOID_CPIO + + pATIHW->mem_vga_wp_sel = SetBits(0, MEM_VGA_WPS0) | + SetBits(1, MEM_VGA_WPS1); + pATIHW->mem_vga_rp_sel = SetBits(0, MEM_VGA_RPS0) | + SetBits(1, MEM_VGA_RPS1); + +#else /* AVOID_CPIO */ + + pATIHW->mem_vga_wp_sel = SetBits(0, MEM_VGA_WPS0) | + SetBits(pATIHW->nPlane, MEM_VGA_WPS1); + pATIHW->mem_vga_rp_sel = SetBits(0, MEM_VGA_RPS0) | + SetBits(pATIHW->nPlane, MEM_VGA_RPS1); + +#endif /* AVOID_CPIO */ + + pATIHW->dac_cntl = inr(DAC_CNTL) & + ~(DAC1_CLK_SEL | DAC_PALETTE_ACCESS_CNTL | DAC_8BIT_EN); + if (pATI->Chip >= ATI_CHIP_264CT) + pATIHW->dac_cntl &= ~DAC_FEA_CON_EN; + if (pATI->rgbBits == 8) + pATIHW->dac_cntl |= DAC_8BIT_EN; + + pATIHW->gen_test_cntl = pATI->LockData.gen_test_cntl & ~GEN_CUR_EN; + if (pATI->DAC == ATI_DAC_IBMRGB514) + pATIHW->gen_test_cntl |= GEN_OVR_OUTPUT_EN; + + pATIHW->config_cntl = config_cntl = inr(CONFIG_CNTL); + +#ifndef AVOID_CPIO + + if (pATI->UseSmallApertures) + { + pATIHW->config_cntl |= CFG_MEM_VGA_AP_EN; + } + else + +#endif /* AVOID_CPIO */ + + { + pATIHW->config_cntl &= ~CFG_MEM_VGA_AP_EN; + } + + if (pATI->LinearBase && (pATI->Chip < ATI_CHIP_264CT)) + { + /* Replace linear aperture size and address */ + pATIHW->config_cntl &= ~(CFG_MEM_AP_LOC | CFG_MEM_AP_SIZE); + pATIHW->config_cntl |= SetBits(pATI->LinearBase >> 22, CFG_MEM_AP_LOC); + if ((pATI->Chip < ATI_CHIP_264CT) && (pATI->VideoRAM < 4096)) + pATIHW->config_cntl |= SetBits(1, CFG_MEM_AP_SIZE); + else + pATIHW->config_cntl |= SetBits(2, CFG_MEM_AP_SIZE); + } + + if (pATI->Chip >= ATI_CHIP_264VTB) + { + pATIHW->mem_cntl = (pATI->LockData.mem_cntl & + ~(CTL_MEM_LOWER_APER_ENDIAN | CTL_MEM_UPPER_APER_ENDIAN)) | + SetBits(CTL_MEM_APER_BYTE_ENDIAN, CTL_MEM_LOWER_APER_ENDIAN); + + switch (pATI->bitsPerPixel) + { + default: + pATIHW->mem_cntl |= SetBits(CTL_MEM_APER_BYTE_ENDIAN, + CTL_MEM_UPPER_APER_ENDIAN); + break; + + case 16: + pATIHW->mem_cntl |= SetBits(CTL_MEM_APER_WORD_ENDIAN, + CTL_MEM_UPPER_APER_ENDIAN); + break; + + case 32: + pATIHW->mem_cntl |= SetBits(CTL_MEM_APER_LONG_ENDIAN, + CTL_MEM_UPPER_APER_ENDIAN); + break; + } + + pATIHW->mpp_config = inr(MPP_CONFIG); + pATIHW->mpp_config &= + ~(MPP_PRESCALE | MPP_NSTATES | MPP_FORMAT | MPP_WAIT_STATE | + MPP_INSERT_WAIT | MPP_TRISTATE_ADDR | MPP_AUTO_INC_EN | + MPP_CHKREQ_EN | MPP_BUFFER_SIZE | MPP_BUFFER_MODE | MPP_BUSY); + pATIHW->mpp_config |= + (MPP_NSTATES_8 | MPP_FORMAT_DA8 | SetBits(4, MPP_WAIT_STATE) | + MPP_CHKRDY_EN | MPP_READ_EARLY | MPP_RW_MODE | MPP_EN); + pATIHW->mpp_strobe_seq = inr(MPP_STROBE_SEQ); + pATIHW->mpp_strobe_seq &= ~(MPP_STB0_SEQ | MPP_STB1_SEQ); + pATIHW->mpp_strobe_seq |= + SetBits(0x0087U, MPP_STB0_SEQ) | SetBits(0x0083U, MPP_STB1_SEQ); + pATIHW->tvo_cntl = 0; + } + + /* Draw engine setup */ + if (pATI->Block0Base) + { + /* Ensure apertures are enabled */ + outr(BUS_CNTL, pATIHW->bus_cntl); + outr(CONFIG_CNTL, pATIHW->config_cntl); + + /* + * When possible, max out command FIFO size. + */ + if (pATI->Chip >= ATI_CHIP_264VT4) + pATIHW->gui_cntl = inm(GUI_CNTL) & ~CMDFIFO_SIZE_MODE; + + /* Initialise destination registers */ + pATIHW->dst_off_pitch = + SetBits((pATI->displayWidth * pATI->XModifier) >> 3, DST_PITCH); + pATIHW->dst_cntl = DST_X_DIR | DST_Y_DIR | DST_LAST_PEL; + + /* Initialise source registers */ + pATIHW->src_off_pitch = pATIHW->dst_off_pitch; + pATIHW->src_width1 = pATIHW->src_height1 = + pATIHW->src_width2 = pATIHW->src_height2 = 1; + pATIHW->src_cntl = SRC_LINE_X_DIR; + + /* Initialise scissor, allowing for offscreen areas */ + pATIHW->sc_right = (pATI->displayWidth * pATI->XModifier) - 1; + tmp = pATI->displayWidth * pATI->bitsPerPixel; + tmp = (((pScreenInfo->videoRam * (1024 * 8)) + tmp - 1) / tmp) - 1; + if (tmp > ATIMach64MaxY) + tmp = ATIMach64MaxY; + pATIHW->sc_bottom = tmp; + pATI->sc_left_right = SetWord(pATI->NewHW.sc_right, 1) | + SetWord(pATI->NewHW.sc_left, 0); + pATI->sc_top_bottom = SetWord(pATI->NewHW.sc_bottom, 1) | + SetWord(pATI->NewHW.sc_top, 0); + + /* Initialise data path */ + pATIHW->dp_frgd_clr = (CARD32)(-1); + pATIHW->dp_write_mask = (CARD32)(-1); + + switch (pATI->depth) + { + case 8: + pATIHW->dp_chain_mask = DP_CHAIN_8BPP; + pATIHW->dp_pix_width = + SetBits(PIX_WIDTH_8BPP, DP_DST_PIX_WIDTH) | + SetBits(PIX_WIDTH_8BPP, DP_SRC_PIX_WIDTH) | + SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH); + break; + + case 15: + pATIHW->dp_chain_mask = DP_CHAIN_15BPP_1555; + pATIHW->dp_pix_width = + SetBits(PIX_WIDTH_15BPP, DP_DST_PIX_WIDTH) | + SetBits(PIX_WIDTH_15BPP, DP_SRC_PIX_WIDTH) | + SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH); + break; + + case 16: + pATIHW->dp_chain_mask = DP_CHAIN_16BPP_565; + pATIHW->dp_pix_width = + SetBits(PIX_WIDTH_16BPP, DP_DST_PIX_WIDTH) | + SetBits(PIX_WIDTH_16BPP, DP_SRC_PIX_WIDTH) | + SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH); + break; + + case 24: + if (pATI->bitsPerPixel == 24) + { + pATIHW->dp_chain_mask = DP_CHAIN_24BPP_888; + pATIHW->dp_pix_width = + SetBits(PIX_WIDTH_8BPP, DP_DST_PIX_WIDTH) | + SetBits(PIX_WIDTH_8BPP, DP_SRC_PIX_WIDTH) | + SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH); + } + else + { + pATIHW->dp_chain_mask = DP_CHAIN_32BPP_8888; + pATIHW->dp_pix_width = + SetBits(PIX_WIDTH_32BPP, DP_DST_PIX_WIDTH) | + SetBits(PIX_WIDTH_32BPP, DP_SRC_PIX_WIDTH) | + SetBits(PIX_WIDTH_1BPP, DP_HOST_PIX_WIDTH); + } + break; + + default: + break; + } + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + + pATIHW->dp_pix_width |= DP_BYTE_PIX_ORDER; + +#endif /* X_BYTE_ORDER */ + + pATIHW->dp_mix = SetBits(MIX_SRC, DP_FRGD_MIX) | + SetBits(MIX_DST, DP_BKGD_MIX); + pATIHW->dp_src = DP_MONO_SRC_ALLONES | + SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC); + + /* Initialise colour compare */ + pATIHW->clr_cmp_msk = (1 << pATI->depth) - 1; + + if (pATI->Block1Base) + { + pATIHW->overlay_y_x_start = SetBits(0, OVERLAY_Y_START) | + SetBits(0, OVERLAY_X_START) | OVERLAY_LOCK_START; + pATIHW->overlay_y_x_end = SetBits(0, OVERLAY_Y_END) | + SetBits(0, OVERLAY_X_END) | OVERLAY_LOCK_END; + + pATIHW->overlay_graphics_key_clr = + (3 << ((2 * pATI->depth) / 3)) | + (2 << ((1 * pATI->depth) / 3)) | + (1 << ((0 * pATI->depth) / 3)); + pATIHW->overlay_graphics_key_msk = (1 << pATI->depth) - 1; + + pATIHW->overlay_key_cntl = + SetBits(OVERLAY_MIX_FALSE, OVERLAY_VIDEO_FN) | + SetBits(OVERLAY_MIX_EQUAL, OVERLAY_GRAPHICS_FN); + + pATIHW->overlay_scale_cntl = SCALE_EN; + + pATIHW->video_format = VIDEO_IN_VYUY422 | SCALER_IN_VYUY422; + + if (pATI->Chip >= ATI_CHIP_264GTPRO) + { + /* These values are documented voodoo */ + pATIHW->scaler_h_coeff0 = SetByte(0x20U, 1); + pATIHW->scaler_h_coeff1 = SetByte(0x0DU, 0) | + SetByte(0x20U, 1) | SetByte(0x06U, 2) | SetByte(0x0DU, 3); + pATIHW->scaler_h_coeff2 = SetByte(0x0DU, 0) | + SetByte(0x1CU, 1) | SetByte(0x0AU, 2) | SetByte(0x0DU, 3); + pATIHW->scaler_h_coeff3 = SetByte(0x0CU, 0) | + SetByte(0x1AU, 1) | SetByte(0x0EU, 2) | SetByte(0x0CU, 3); + pATIHW->scaler_h_coeff4 = SetByte(0x0CU, 0) | + SetByte(0x14U, 1) | SetByte(0x14U, 2) | SetByte(0x0CU, 3); + } + } + + /* Restore aperture enablement */ + outr(BUS_CNTL, bus_cntl); + outr(CONFIG_CNTL, config_cntl); + } +} + +/* + * ATIMach64Save -- + * + * This function is called to save the Mach64 portion of the current video + * state. + */ +void +ATIMach64Save +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP); + pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); + pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP); + pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); + + pATIHW->crtc_off_pitch = inr(CRTC_OFF_PITCH); + + pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL); + + pATIHW->ovr_clr = inr(OVR_CLR); + pATIHW->ovr_wid_left_right = inr(OVR_WID_LEFT_RIGHT); + pATIHW->ovr_wid_top_bottom = inr(OVR_WID_TOP_BOTTOM); + + pATIHW->cur_clr0 = inr(CUR_CLR0); + pATIHW->cur_clr1 = inr(CUR_CLR1); + pATIHW->cur_offset = inr(CUR_OFFSET); + pATIHW->cur_horz_vert_posn = inr(CUR_HORZ_VERT_POSN); + pATIHW->cur_horz_vert_off = inr(CUR_HORZ_VERT_OFF); + + pATIHW->clock_cntl = inr(CLOCK_CNTL); + + pATIHW->bus_cntl = inr(BUS_CNTL); + + pATIHW->mem_vga_wp_sel = inr(MEM_VGA_WP_SEL); + pATIHW->mem_vga_rp_sel = inr(MEM_VGA_RP_SEL); + + pATIHW->dac_cntl = inr(DAC_CNTL); + + pATIHW->config_cntl = inr(CONFIG_CNTL); + + pATIHW->gen_test_cntl = inr(GEN_TEST_CNTL) & ~GEN_CUR_EN; + + if (pATI->Chip >= ATI_CHIP_264VTB) + { + pATIHW->mem_cntl = inr(MEM_CNTL); + pATIHW->mpp_config = inr(MPP_CONFIG); + pATIHW->mpp_strobe_seq = inr(MPP_STROBE_SEQ); + pATIHW->tvo_cntl = inr(TVO_CNTL); + } + + /* Save draw engine state */ + if (pATI->Block0Base && (pATIHW == &pATI->OldHW)) + { + /* Ensure apertures are enabled */ + outr(BUS_CNTL, pATI->NewHW.bus_cntl); + outr(CONFIG_CNTL, pATI->NewHW.config_cntl); + + ATIMach64WaitForIdle(pATI); + + /* Save FIFO size */ + if (pATI->Chip >= ATI_CHIP_264VT4) + pATIHW->gui_cntl = inm(GUI_CNTL); + + /* Save destination registers */ + pATIHW->dst_off_pitch = inm(DST_OFF_PITCH); + pATIHW->dst_x = inm(DST_X); + pATIHW->dst_y = inm(DST_Y); + pATIHW->dst_height = inm(DST_HEIGHT); + pATIHW->dst_bres_err = inm(DST_BRES_ERR); + pATIHW->dst_bres_inc = inm(DST_BRES_INC); + pATIHW->dst_bres_dec = inm(DST_BRES_DEC); + pATIHW->dst_cntl = inm(DST_CNTL); + + /* Save source registers */ + pATIHW->src_off_pitch = inm(SRC_OFF_PITCH); + pATIHW->src_x = inm(SRC_X); + pATIHW->src_y = inm(SRC_Y); + pATIHW->src_width1 = inm(SRC_WIDTH1); + pATIHW->src_height1 = inm(SRC_HEIGHT1); + pATIHW->src_x_start = inm(SRC_X_START); + pATIHW->src_y_start = inm(SRC_Y_START); + pATIHW->src_width2 = inm(SRC_WIDTH2); + pATIHW->src_height2 = inm(SRC_HEIGHT2); + pATIHW->src_cntl = inm(SRC_CNTL); + + /* Save host data register */ + pATIHW->host_cntl = inm(HOST_CNTL); + + /* Save pattern registers */ + pATIHW->pat_reg0 = inm(PAT_REG0); + pATIHW->pat_reg1 = inm(PAT_REG1); + pATIHW->pat_cntl = inm(PAT_CNTL); + + /* Save scissor registers */ + pATIHW->sc_left = pATI->sc_left = inm(SC_LEFT); + pATIHW->sc_right = pATI->sc_right = inm(SC_RIGHT); + pATIHW->sc_top = pATI->sc_top = inm(SC_TOP); + pATIHW->sc_bottom = pATI->sc_bottom = inm(SC_BOTTOM); + + /* Save data path registers */ + pATIHW->dp_bkgd_clr = inm(DP_BKGD_CLR); + pATIHW->dp_frgd_clr = inm(DP_FRGD_CLR); + pATIHW->dp_write_mask = inm(DP_WRITE_MASK); + pATIHW->dp_chain_mask = inm(DP_CHAIN_MASK); + pATIHW->dp_pix_width = inm(DP_PIX_WIDTH); + pATIHW->dp_mix = inm(DP_MIX); + pATIHW->dp_src = inm(DP_SRC); + + /* Save colour compare registers */ + pATIHW->clr_cmp_clr = inm(CLR_CMP_CLR); + pATIHW->clr_cmp_msk = inm(CLR_CMP_MSK); + pATIHW->clr_cmp_cntl = inm(CLR_CMP_CNTL); + + /* Save context */ + pATIHW->context_mask = inm(CONTEXT_MASK); + + if (pATI->Block1Base) + { + /* Save overlay & scaler registers */ + pATIHW->overlay_y_x_start = inm(OVERLAY_Y_X_START); + pATIHW->overlay_y_x_end = inm(OVERLAY_Y_X_END); + + pATIHW->overlay_graphics_key_clr = inm(OVERLAY_GRAPHICS_KEY_CLR); + pATIHW->overlay_graphics_key_msk = inm(OVERLAY_GRAPHICS_KEY_MSK); + + pATIHW->overlay_key_cntl = inm(OVERLAY_KEY_CNTL); + + pATIHW->overlay_scale_inc = inm(OVERLAY_SCALE_INC); + pATIHW->overlay_scale_cntl = inm(OVERLAY_SCALE_CNTL); + + pATIHW->scaler_height_width = inm(SCALER_HEIGHT_WIDTH); + + pATIHW->scaler_test = inm(SCALER_TEST); + + pATIHW->video_format = inm(VIDEO_FORMAT); + + if (pATI->Chip < ATI_CHIP_264VTB) + { + pATIHW->buf0_offset = inm(BUF0_OFFSET); + pATIHW->buf0_pitch = inm(BUF0_PITCH); + pATIHW->buf1_offset = inm(BUF1_OFFSET); + pATIHW->buf1_pitch = inm(BUF1_PITCH); + } + else + { + pATIHW->scaler_buf0_offset = inm(SCALER_BUF0_OFFSET); + pATIHW->scaler_buf1_offset = inm(SCALER_BUF1_OFFSET); + pATIHW->scaler_buf_pitch = inm(SCALER_BUF_PITCH); + + pATIHW->overlay_exclusive_horz = inm(OVERLAY_EXCLUSIVE_HORZ); + pATIHW->overlay_exclusive_vert = inm(OVERLAY_EXCLUSIVE_VERT); + + if (pATI->Chip >= ATI_CHIP_264GTPRO) + { + pATIHW->scaler_colour_cntl = inm(SCALER_COLOUR_CNTL); + + pATIHW->scaler_h_coeff0 = inm(SCALER_H_COEFF0); + pATIHW->scaler_h_coeff1 = inm(SCALER_H_COEFF1); + pATIHW->scaler_h_coeff2 = inm(SCALER_H_COEFF2); + pATIHW->scaler_h_coeff3 = inm(SCALER_H_COEFF3); + pATIHW->scaler_h_coeff4 = inm(SCALER_H_COEFF4); + + pATIHW->scaler_buf0_offset_u = inm(SCALER_BUF0_OFFSET_U); + pATIHW->scaler_buf0_offset_v = inm(SCALER_BUF0_OFFSET_V); + pATIHW->scaler_buf1_offset_u = inm(SCALER_BUF1_OFFSET_U); + pATIHW->scaler_buf1_offset_v = inm(SCALER_BUF1_OFFSET_V); + } + } + } + + /* Restore aperture enablement */ + outr(BUS_CNTL, pATIHW->bus_cntl); + outr(CONFIG_CNTL, pATIHW->config_cntl); + } +} + +/* + * ATIMach64Calculate -- + * + * This function is called to fill in the Mach64 portion of an ATIHWRec. + */ +void +ATIMach64Calculate +( + ATIPtr pATI, + ATIHWPtr pATIHW, + DisplayModePtr pMode +) +{ + int VDisplay; + + /* If not already done adjust horizontal timings */ + if (!pMode->CrtcHAdjusted) + { + pMode->CrtcHAdjusted = TRUE; + /* XXX Deal with Blank Start/End and overscan later */ + pMode->CrtcHDisplay = (pMode->HDisplay >> 3) - 1; + pMode->CrtcHSyncStart = (pMode->HSyncStart >> 3) - 1; + pMode->CrtcHSyncEnd = (pMode->HSyncEnd >> 3) - 1; + pMode->CrtcHTotal = (pMode->HTotal >> 3) - 1; + + /* Make adjustments if sync pulse width is out-of-bounds */ + if ((pMode->CrtcHSyncEnd - pMode->CrtcHSyncStart) > + (int)MaxBits(CRTC_H_SYNC_WID)) + { + pMode->CrtcHSyncEnd = + pMode->CrtcHSyncStart + MaxBits(CRTC_H_SYNC_WID); + } + else if (pMode->CrtcHSyncStart == pMode->CrtcHSyncEnd) + { + if (pMode->CrtcHDisplay < pMode->CrtcHSyncStart) + pMode->CrtcHSyncStart--; + else if (pMode->CrtcHSyncEnd < pMode->CrtcHTotal) + pMode->CrtcHSyncEnd++; + } + } + + /* + * Always re-do vertical adjustments. + */ + pMode->CrtcVDisplay = pMode->VDisplay; + pMode->CrtcVSyncStart = pMode->VSyncStart; + pMode->CrtcVSyncEnd = pMode->VSyncEnd; + pMode->CrtcVTotal = pMode->VTotal; + + if ((pATI->Chip >= ATI_CHIP_264CT) && + ((pMode->Flags & V_DBLSCAN) || (pMode->VScan > 1))) + { + pMode->CrtcVDisplay <<= 1; + pMode->CrtcVSyncStart <<= 1; + pMode->CrtcVSyncEnd <<= 1; + pMode->CrtcVTotal <<= 1; + } + + /* + * Might as well default to the same as VGA with respect to sync + * polarities. + */ + if ((!(pMode->Flags & (V_PHSYNC | V_NHSYNC))) || + (!(pMode->Flags & (V_PVSYNC | V_NVSYNC)))) + { + pMode->Flags &= ~(V_PHSYNC | V_NHSYNC | V_PVSYNC | V_NVSYNC); + + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) + VDisplay = pATI->LCDVertical; + else + VDisplay = pMode->CrtcVDisplay; + + if (VDisplay < 400) + pMode->Flags |= V_PHSYNC | V_NVSYNC; + else if (VDisplay < 480) + pMode->Flags |= V_NHSYNC | V_PVSYNC; + else if (VDisplay < 768) + pMode->Flags |= V_NHSYNC | V_NVSYNC; + else + pMode->Flags |= V_PHSYNC | V_PVSYNC; + } + + pMode->CrtcVDisplay--; + pMode->CrtcVSyncStart--; + pMode->CrtcVSyncEnd--; + pMode->CrtcVTotal--; + /* Make sure sync pulse is not too wide */ + if ((pMode->CrtcVSyncEnd - pMode->CrtcVSyncStart) > + (int)MaxBits(CRTC_V_SYNC_WID)) + pMode->CrtcVSyncEnd = pMode->CrtcVSyncStart + MaxBits(CRTC_V_SYNC_WID); + pMode->CrtcVAdjusted = TRUE; /* Redundant */ + + /* Build register contents */ + pATIHW->crtc_h_total_disp = + SetBits(pMode->CrtcHTotal, CRTC_H_TOTAL) | + SetBits(pMode->CrtcHDisplay, CRTC_H_DISP); + pATIHW->crtc_h_sync_strt_wid = + SetBits(pMode->CrtcHSyncStart, CRTC_H_SYNC_STRT) | + SetBits(pMode->CrtcHSkew, CRTC_H_SYNC_DLY) | /* ? */ + SetBits(GetBits(pMode->CrtcHSyncStart, 0x0100U), + CRTC_H_SYNC_STRT_HI) | + SetBits(pMode->CrtcHSyncEnd - pMode->CrtcHSyncStart, + CRTC_H_SYNC_WID); + if (pMode->Flags & V_NHSYNC) + pATIHW->crtc_h_sync_strt_wid |= CRTC_H_SYNC_POL; + + pATIHW->crtc_v_total_disp = + SetBits(pMode->CrtcVTotal, CRTC_V_TOTAL) | + SetBits(pMode->CrtcVDisplay, CRTC_V_DISP); + pATIHW->crtc_v_sync_strt_wid = + SetBits(pMode->CrtcVSyncStart, CRTC_V_SYNC_STRT) | + SetBits(pMode->CrtcVSyncEnd - pMode->CrtcVSyncStart, + CRTC_V_SYNC_WID); + if (pMode->Flags & V_NVSYNC) + pATIHW->crtc_v_sync_strt_wid |= CRTC_V_SYNC_POL; + + pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL) & + ~(CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN | + CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_CSYNC_EN | + CRTC_PIX_BY_2_EN | CRTC_DISPLAY_DIS | CRTC_VGA_XOVERSCAN | + CRTC_PIX_WIDTH | CRTC_BYTE_PIX_ORDER | + CRTC_VGA_128KAP_PAGING | CRTC_VFC_SYNC_TRISTATE | + CRTC_LOCK_REGS | /* Already off, but ... */ + CRTC_SYNC_TRISTATE | CRTC_DISP_REQ_EN | + CRTC_VGA_TEXT_132 | CRTC_CUR_B_TEST); + pATIHW->crtc_gen_cntl |= + CRTC_EXT_DISP_EN | CRTC_EN | CRTC_VGA_LINEAR | CRTC_CNT_EN; + switch (pATI->depth) + { + +#ifndef AVOID_CPIO + + case 1: + pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_1BPP, CRTC_PIX_WIDTH); + break; + + case 4: + pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_4BPP, CRTC_PIX_WIDTH); + break; + +#endif /* AVOID_CPIO */ + + case 8: + pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_8BPP, CRTC_PIX_WIDTH); + break; + + case 15: + pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_15BPP, CRTC_PIX_WIDTH); + break; + + case 16: + pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_16BPP, CRTC_PIX_WIDTH); + break; + + case 24: + if (pATI->bitsPerPixel == 24) + { + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_24BPP, CRTC_PIX_WIDTH); + break; + } + if (pATI->bitsPerPixel != 32) + break; + /* Fall through */ + + case 32: + pATIHW->crtc_gen_cntl |= SetBits(PIX_WIDTH_32BPP, CRTC_PIX_WIDTH); + break; + + default: + break; + } + if ((pMode->Flags & V_DBLSCAN) || (pMode->VScan > 1)) + pATIHW->crtc_gen_cntl |= CRTC_DBL_SCAN_EN; + if (pMode->Flags & V_INTERLACE) + pATIHW->crtc_gen_cntl |= CRTC_INTERLACE_EN; + if (pATI->OptionCSync || (pMode->Flags & (V_CSYNC | V_PCSYNC))) + pATIHW->crtc_gen_cntl |= CRTC_CSYNC_EN; + /* For now, set display FIFO low water mark as high as possible */ + if (pATI->Chip < ATI_CHIP_264VTB) + pATIHW->crtc_gen_cntl |= CRTC_FIFO_LWM; +} + +/* + * ATIMach64Set -- + * + * This function is called to load a Mach64's accelerator CRTC and draw engine. + */ +void +ATIMach64Set +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + +#ifndef AVOID_CPIO + + if (pATIHW->crtc == ATI_CRTC_MACH64) + +#endif /* AVOID_CPIO */ + + { + if ((pATIHW->FeedbackDivider > 0) && + (pATI->ProgrammableClock != ATI_CLOCK_NONE)) + ATIClockSet(pATI, pATIHW); /* Programme clock */ + + if (pATI->DAC == ATI_DAC_IBMRGB514) + ATIRGB514Set(pATI, pATIHW); + + /* Load Mach64 CRTC registers */ + outr(CRTC_H_TOTAL_DISP, pATIHW->crtc_h_total_disp); + outr(CRTC_H_SYNC_STRT_WID, pATIHW->crtc_h_sync_strt_wid); + outr(CRTC_V_TOTAL_DISP, pATIHW->crtc_v_total_disp); + outr(CRTC_V_SYNC_STRT_WID, pATIHW->crtc_v_sync_strt_wid); + + outr(CRTC_OFF_PITCH, pATIHW->crtc_off_pitch); + + /* Load overscan registers */ + outr(OVR_CLR, pATIHW->ovr_clr); + outr(OVR_WID_LEFT_RIGHT, pATIHW->ovr_wid_left_right); + outr(OVR_WID_TOP_BOTTOM, pATIHW->ovr_wid_top_bottom); + + /* Load hardware cursor registers */ + outr(CUR_CLR0, pATIHW->cur_clr0); + outr(CUR_CLR1, pATIHW->cur_clr1); + outr(CUR_OFFSET, pATIHW->cur_offset); + outr(CUR_HORZ_VERT_POSN, pATIHW->cur_horz_vert_posn); + outr(CUR_HORZ_VERT_OFF, pATIHW->cur_horz_vert_off); + + /* Set pixel clock */ + outr(CLOCK_CNTL, pATIHW->clock_cntl | CLOCK_STROBE); + + outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl | GEN_GUI_EN); + outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl); + outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl | GEN_GUI_EN); + + /* Finalise CRTC setup and turn on the screen */ + outr(CRTC_GEN_CNTL, pATIHW->crtc_gen_cntl); + } + + /* Load draw engine */ + if (pATI->Block0Base) + { + /* Clobber MMIO cache */ + (void)memset(pATI->MMIOCached, 0, SizeOf(pATI->MMIOCached)); + + /* Ensure apertures are enabled */ + outr(BUS_CNTL, pATI->NewHW.bus_cntl); + outr(CONFIG_CNTL, pATI->NewHW.config_cntl); + + pATI->EngineIsBusy = TRUE; /* Force engine poll */ + ATIMach64WaitForIdle(pATI); + + /* Load FIFO size */ + if (pATI->Chip >= ATI_CHIP_264VT4) + { + outm(GUI_CNTL, pATIHW->gui_cntl); + pATI->nAvailableFIFOEntries = 0; + ATIMach64PollEngineStatus(pATI); + } + + /* Set FIFO depth */ + pATI->nFIFOEntries = pATI->nAvailableFIFOEntries; + + /* Load destination registers */ + ATIMach64WaitForFIFO(pATI, 7); + outf(DST_OFF_PITCH, pATIHW->dst_off_pitch); + outf(DST_Y_X, SetWord(pATIHW->dst_x, 1) | SetWord(pATIHW->dst_y, 0)); + outf(DST_HEIGHT, pATIHW->dst_height); + outf(DST_BRES_ERR, pATIHW->dst_bres_err); + outf(DST_BRES_INC, pATIHW->dst_bres_inc); + outf(DST_BRES_DEC, pATIHW->dst_bres_dec); + outf(DST_CNTL, pATIHW->dst_cntl); + + /* Load source registers */ + ATIMach64WaitForFIFO(pATI, 6); + outf(SRC_OFF_PITCH, pATIHW->src_off_pitch); + outf(SRC_Y_X, SetWord(pATIHW->src_x, 1) | SetWord(pATIHW->src_y, 0)); + outf(SRC_HEIGHT1_WIDTH1, + SetWord(pATIHW->src_width1, 1) | SetWord(pATIHW->src_height1, 0)); + outf(SRC_Y_X_START, + SetWord(pATIHW->src_x_start, 1) | SetWord(pATIHW->src_y_start, 0)); + outf(SRC_HEIGHT2_WIDTH2, + SetWord(pATIHW->src_width2, 1) | SetWord(pATIHW->src_height2, 0)); + outf(SRC_CNTL, pATIHW->src_cntl); + + /* Load host data register */ + ATIMach64WaitForFIFO(pATI, 1); + outf(HOST_CNTL, pATIHW->host_cntl); + + /* Set host transfer window address and size clamp */ + pATI->pHOST_DATA = + (CARD8 *)pATI->pBlock[GetBits(HOST_DATA_0, BLOCK_SELECT)] + + (HOST_DATA_0 & MM_IO_SELECT); + pATI->nHostFIFOEntries = pATI->nFIFOEntries >> 1; + if (pATI->nHostFIFOEntries > 16) + pATI->nHostFIFOEntries = 16; + + /* Load pattern registers */ + ATIMach64WaitForFIFO(pATI, 3); + outf(PAT_REG0, pATIHW->pat_reg0); + outf(PAT_REG1, pATIHW->pat_reg1); + outf(PAT_CNTL, pATIHW->pat_cntl); + + /* Load scissor registers */ + ATIMach64WaitForFIFO(pATI, 2); + outf(SC_LEFT_RIGHT, + SetWord(pATIHW->sc_right, 1) | SetWord(pATIHW->sc_left, 0)); + outf(SC_TOP_BOTTOM, + SetWord(pATIHW->sc_bottom, 1) | SetWord(pATIHW->sc_top, 0)); + pATI->sc_left = pATIHW->sc_left; + pATI->sc_right = pATIHW->sc_right; + pATI->sc_top = pATIHW->sc_top; + pATI->sc_bottom = pATIHW->sc_bottom; + + /* Load data path registers */ + ATIMach64WaitForFIFO(pATI, 7); + outf(DP_BKGD_CLR, pATIHW->dp_bkgd_clr); + outf(DP_FRGD_CLR, pATIHW->dp_frgd_clr); + outf(DP_WRITE_MASK, pATIHW->dp_write_mask); + outf(DP_CHAIN_MASK, pATIHW->dp_chain_mask); + outf(DP_PIX_WIDTH, pATIHW->dp_pix_width); + outf(DP_MIX, pATIHW->dp_mix); + outf(DP_SRC, pATIHW->dp_src); + + /* Load colour compare registers */ + ATIMach64WaitForFIFO(pATI, 3); + outf(CLR_CMP_CLR, pATIHW->clr_cmp_clr); + outf(CLR_CMP_MSK, pATIHW->clr_cmp_msk); + outf(CLR_CMP_CNTL, pATIHW->clr_cmp_cntl); + + /* Load context mask */ + ATIMach64WaitForFIFO(pATI, 1); + outf(CONTEXT_MASK, pATIHW->context_mask); + + if (pATI->Block1Base) + { + /* Load overlay & scaler registers */ + ATIMach64WaitForFIFO(pATI, 10); + outf(OVERLAY_Y_X_START, pATIHW->overlay_y_x_start); + outf(OVERLAY_Y_X_END, pATIHW->overlay_y_x_end); + + outf(OVERLAY_GRAPHICS_KEY_CLR, pATIHW->overlay_graphics_key_clr); + outf(OVERLAY_GRAPHICS_KEY_MSK, pATIHW->overlay_graphics_key_msk); + + outf(OVERLAY_KEY_CNTL, pATIHW->overlay_key_cntl); + + outf(OVERLAY_SCALE_INC, pATIHW->overlay_scale_inc); + outf(OVERLAY_SCALE_CNTL, pATIHW->overlay_scale_cntl); + + outf(SCALER_HEIGHT_WIDTH, pATIHW->scaler_height_width); + + outf(SCALER_TEST, pATIHW->scaler_test); + + outf(VIDEO_FORMAT, pATIHW->video_format); + + if (pATI->Chip < ATI_CHIP_264VTB) + { + ATIMach64WaitForFIFO(pATI, 4); + outf(BUF0_OFFSET, pATIHW->buf0_offset); + outf(BUF0_PITCH, pATIHW->buf0_pitch); + outf(BUF1_OFFSET, pATIHW->buf1_offset); + outf(BUF1_PITCH, pATIHW->buf1_pitch); + } + else + { + ATIMach64WaitForFIFO(pATI, 5); + outf(SCALER_BUF0_OFFSET, pATIHW->scaler_buf0_offset); + outf(SCALER_BUF1_OFFSET, pATIHW->scaler_buf1_offset); + outf(SCALER_BUF_PITCH, pATIHW->scaler_buf_pitch); + + outf(OVERLAY_EXCLUSIVE_HORZ, pATIHW->overlay_exclusive_horz); + outf(OVERLAY_EXCLUSIVE_VERT, pATIHW->overlay_exclusive_vert); + + if (pATI->Chip >= ATI_CHIP_264GTPRO) + { + ATIMach64WaitForFIFO(pATI, 10); + outf(SCALER_COLOUR_CNTL, pATIHW->scaler_colour_cntl); + + outf(SCALER_H_COEFF0, pATIHW->scaler_h_coeff0); + outf(SCALER_H_COEFF1, pATIHW->scaler_h_coeff1); + outf(SCALER_H_COEFF2, pATIHW->scaler_h_coeff2); + outf(SCALER_H_COEFF3, pATIHW->scaler_h_coeff3); + outf(SCALER_H_COEFF4, pATIHW->scaler_h_coeff4); + + outf(SCALER_BUF0_OFFSET_U, pATIHW->scaler_buf0_offset_u); + outf(SCALER_BUF0_OFFSET_V, pATIHW->scaler_buf0_offset_v); + outf(SCALER_BUF1_OFFSET_U, pATIHW->scaler_buf1_offset_u); + outf(SCALER_BUF1_OFFSET_V, pATIHW->scaler_buf1_offset_v); + } + } + } + + ATIMach64WaitForIdle(pATI); + + if (pATI->OptionMMIOCache) + { + /* + * Enable write caching for selected MMIO registers. This can only + * be done for those registers whose value does not change without + * driver intervention. + */ + + CacheRegister(SRC_CNTL); + + CacheRegister(HOST_CNTL); + + CacheRegister(PAT_REG0); + CacheRegister(PAT_REG1); + CacheRegister(PAT_CNTL); + + CacheRegister(SC_LEFT_RIGHT); + CacheRegister(SC_TOP_BOTTOM); + + CacheRegister(DP_BKGD_CLR); + CacheRegister(DP_FRGD_CLR); + CacheRegister(DP_WRITE_MASK); + CacheRegister(DP_MIX); + + CacheRegister(CLR_CMP_CLR); + CacheRegister(CLR_CMP_MSK); + CacheRegister(CLR_CMP_CNTL); + + if (pATI->Block1Base) + { + CacheRegister(OVERLAY_Y_X_START); + CacheRegister(OVERLAY_Y_X_END); + + CacheRegister(OVERLAY_GRAPHICS_KEY_CLR); + CacheRegister(OVERLAY_GRAPHICS_KEY_MSK); + + CacheRegister(OVERLAY_KEY_CNTL); + + CacheRegister(OVERLAY_SCALE_INC); + CacheRegister(OVERLAY_SCALE_CNTL); + + CacheRegister(SCALER_HEIGHT_WIDTH); + + CacheRegister(SCALER_TEST); + + CacheRegister(VIDEO_FORMAT); + + if (pATI->Chip < ATI_CHIP_264VTB) + { + CacheRegister(BUF0_OFFSET); + CacheRegister(BUF0_PITCH); + CacheRegister(BUF1_OFFSET); + CacheRegister(BUF1_PITCH); + } + else + { + CacheRegister(SCALER_BUF0_OFFSET); + CacheRegister(SCALER_BUF1_OFFSET); + CacheRegister(SCALER_BUF_PITCH); + + CacheRegister(OVERLAY_EXCLUSIVE_HORZ); + CacheRegister(OVERLAY_EXCLUSIVE_VERT); + + if (pATI->Chip >= ATI_CHIP_264GTPRO) + { + CacheRegister(SCALER_COLOUR_CNTL); + + CacheRegister(SCALER_H_COEFF0); + CacheRegister(SCALER_H_COEFF1); + CacheRegister(SCALER_H_COEFF2); + CacheRegister(SCALER_H_COEFF3); + CacheRegister(SCALER_H_COEFF4); + + CacheRegister(SCALER_BUF0_OFFSET_U); + CacheRegister(SCALER_BUF0_OFFSET_V); + CacheRegister(SCALER_BUF1_OFFSET_U); + CacheRegister(SCALER_BUF1_OFFSET_V); + } + } + } + } + } + +#ifndef AVOID_CPIO + + if (pATIHW->crtc == ATI_CRTC_MACH64) + +#endif /* AVOID_CPIO */ + + { + /* Aperture setup */ + outr(MEM_VGA_WP_SEL, pATIHW->mem_vga_wp_sel); + outr(MEM_VGA_RP_SEL, pATIHW->mem_vga_rp_sel); + + outr(DAC_CNTL, pATIHW->dac_cntl); + + outr(CONFIG_CNTL, pATIHW->config_cntl); + outr(BUS_CNTL, pATIHW->bus_cntl); + + if (pATI->Chip >= ATI_CHIP_264VTB) + { + outr(MEM_CNTL, pATIHW->mem_cntl); + outr(MPP_CONFIG, pATIHW->mpp_config); + outr(MPP_STROBE_SEQ, pATIHW->mpp_strobe_seq); + outr(TVO_CNTL, pATIHW->tvo_cntl); + } + } +} + +/* + * ATIMach64SaveScreen -- + * + * This function blanks or unblanks a Mach64 screen. + */ +void +ATIMach64SaveScreen +( + ATIPtr pATI, + int Mode +) +{ + CARD32 crtc_gen_cntl = inr(CRTC_GEN_CNTL); + + switch (Mode) + { + case SCREEN_SAVER_OFF: + case SCREEN_SAVER_FORCER: + outr(CRTC_GEN_CNTL, crtc_gen_cntl & ~CRTC_DISPLAY_DIS); + break; + + case SCREEN_SAVER_ON: + case SCREEN_SAVER_CYCLE: + outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_DISPLAY_DIS); + break; + + default: + break; + } +} + +/* + * ATIMach64SetDPMSMode -- + * + * This function sets a Mach64's VESA Display Power Management Signaling mode. + */ +void +ATIMach64SetDPMSMode +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + int DPMSMode +) +{ + CARD32 crtc_gen_cntl = + inr(CRTC_GEN_CNTL) & ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS); + + switch (DPMSMode) + { + case DPMSModeOn: /* HSync on, VSync on */ + break; + + case DPMSModeStandby: /* HSync off, VSync on */ + crtc_gen_cntl |= CRTC_HSYNC_DIS; + break; + + case DPMSModeSuspend: /* HSync on, VSync off */ + crtc_gen_cntl |= CRTC_VSYNC_DIS; + break; + + case DPMSModeOff: /* HSync off, VSync off */ + crtc_gen_cntl |= CRTC_HSYNC_DIS | CRTC_VSYNC_DIS; + break; + + default: /* Muffle compiler */ + return; + } + + ATIMach64Sync(pScreenInfo); + + outr(CRTC_GEN_CNTL, crtc_gen_cntl); + + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) + { + CARD32 lcd_index = 0; + + /* + * ATI's BIOS simply turns the panel on and off, so do the same by + * default, but keep the previous behaviour around for reference. + */ + if (pATI->OptionDevel) + { + CARD32 power_management; + + if (pATI->Chip == ATI_CHIP_264LT) + { + power_management = inr(POWER_MANAGEMENT); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + lcd_index = inr(LCD_INDEX); + power_management = ATIMach64GetLCDReg(LCD_POWER_MANAGEMENT); + } + + power_management &= ~(STANDBY_NOW | SUSPEND_NOW); + + switch (DPMSMode) + { + case DPMSModeOn: + break; + + case DPMSModeStandby: + power_management |= STANDBY_NOW; + break; + + case DPMSModeSuspend: + power_management |= SUSPEND_NOW; + break; + + case DPMSModeOff: + power_management |= STANDBY_NOW | SUSPEND_NOW; /* ? */ + break; + + default: /* Muffle compiler */ + return; + } + + if (pATI->Chip == ATI_CHIP_264LT) + { + outr(POWER_MANAGEMENT, power_management); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + ATIMach64PutLCDReg(LCD_POWER_MANAGEMENT, power_management); + outr(LCD_INDEX, lcd_index); + } + } + else + { + CARD32 lcd_gen_ctrl; + + if (pATI->Chip == ATI_CHIP_264LT) + { + lcd_gen_ctrl = inr(LCD_GEN_CTRL); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + lcd_index = inr(LCD_INDEX); + lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + } + + if (DPMSMode == DPMSModeOn) + lcd_gen_ctrl |= LCD_ON; + else + lcd_gen_ctrl &= ~LCD_ON; + + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + outr(LCD_INDEX, lcd_index); + } + } + } +} diff --git a/src/atimach64.h b/src/atimach64.h new file mode 100644 index 0000000..34cea4a --- /dev/null +++ b/src/atimach64.h @@ -0,0 +1,40 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64.h,v 1.17 2003/04/23 21:51:28 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMACH64_H___ +#define ___ATIMACH64_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +extern void ATIMach64PreInit FunctionPrototype((ScrnInfoPtr, ATIPtr, + ATIHWPtr)); +extern void ATIMach64Save FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIMach64Calculate FunctionPrototype((ATIPtr, ATIHWPtr, + DisplayModePtr)); +extern void ATIMach64Set FunctionPrototype((ATIPtr, ATIHWPtr)); + +extern void ATIMach64SaveScreen FunctionPrototype((ATIPtr, int)); +extern void ATIMach64SetDPMSMode FunctionPrototype((ScrnInfoPtr, ATIPtr, int)); + +#endif /* ___ATIMACH64_H___ */ diff --git a/src/atimach64accel.c b/src/atimach64accel.c new file mode 100644 index 0000000..6f2dba7 --- /dev/null +++ b/src/atimach64accel.c @@ -0,0 +1,862 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64accel.c,v 1.1 2003/04/23 21:51:28 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ +/* + * Copyright 1999-2000 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, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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. + */ + +#include "ati.h" +#include "atichip.h" +#include "atimach64accel.h" +#include "atimach64io.h" +#include "atipriv.h" +#include "atiregs.h" + +#include "miline.h" + +/* Used to test MMIO cache integrity in ATIMach64Sync() */ +#define TestRegisterCaching(_Register) \ + if (RegisterIsCached(_Register) && \ + (CacheSlot(_Register) != inm(_Register))) \ + { \ + UncacheRegister(_Register); \ + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, \ + #_Register " MMIO write cache disabled!\n"); \ + } + +/* + * X-to-Mach64 mix translation table. + */ +static CARD8 ATIMach64ALU[16] = +{ + MIX_0, /* GXclear */ + MIX_AND, /* GXand */ + MIX_SRC_AND_NOT_DST, /* GXandReverse */ + MIX_SRC, /* GXcopy */ + MIX_NOT_SRC_AND_DST, /* GXandInverted */ + MIX_DST, /* GXnoop */ + MIX_XOR, /* GXxor */ + MIX_OR, /* GXor */ + MIX_NOR, /* GXnor */ + MIX_XNOR, /* GXequiv */ + MIX_NOT_DST, /* GXinvert */ + MIX_SRC_OR_NOT_DST, /* GXorReverse */ + MIX_NOT_SRC, /* GXcopyInverted */ + MIX_NOT_SRC_OR_DST, /* GXorInverted */ + MIX_NAND, /* GXnand */ + MIX_1 /* GXset */ +}; + +/* + * ATIMach64ValidateClip -- + * + * This function ensures the current scissor settings do not interfere with + * the current draw request. + */ +static void +ATIMach64ValidateClip +( + ATIPtr pATI, + int sc_left, + int sc_right, + int sc_top, + int sc_bottom +) +{ + if ((sc_left < (int)pATI->sc_left) || (sc_right > (int)pATI->sc_right)) + { + outf(SC_LEFT_RIGHT, pATI->sc_left_right); + pATI->sc_left = pATI->NewHW.sc_left; + pATI->sc_right = pATI->NewHW.sc_right; + } + + if ((sc_top < (int)pATI->sc_top) || (sc_bottom > (int)pATI->sc_bottom)) + { + outf(SC_TOP_BOTTOM, pATI->sc_top_bottom); + pATI->sc_top = pATI->NewHW.sc_top; + pATI->sc_bottom = pATI->NewHW.sc_bottom; + } +} + +/* + * ATIMach64Sync -- + * + * This is called to wait for the draw engine to become idle. + */ +void +ATIMach64Sync +( + ScrnInfoPtr pScreenInfo +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + ATIMach64WaitForIdle(pATI); + if (pATI->pXAAInfo) + pATI->pXAAInfo->NeedToSync = FALSE; + + if (pATI->OptionMMIOCache && pATI->OptionTestMMIOCache) + { + /* + * For debugging purposes, attempt to verify that each cached register + * should actually be cached. + */ + TestRegisterCaching(SRC_CNTL); + + TestRegisterCaching(HOST_CNTL); + + TestRegisterCaching(PAT_REG0); + TestRegisterCaching(PAT_REG1); + TestRegisterCaching(PAT_CNTL); + + if (RegisterIsCached(SC_LEFT_RIGHT) && /* Special case */ + (CacheSlot(SC_LEFT_RIGHT) != + (SetWord(inm(SC_RIGHT), 1) | SetWord(inm(SC_LEFT), 0)))) + { + UncacheRegister(SC_LEFT_RIGHT); + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "SC_LEFT_RIGHT write cache disabled!\n"); + } + + if (RegisterIsCached(SC_TOP_BOTTOM) && /* Special case */ + (CacheSlot(SC_TOP_BOTTOM) != + (SetWord(inm(SC_BOTTOM), 1) | SetWord(inm(SC_TOP), 0)))) + { + UncacheRegister(SC_TOP_BOTTOM); + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "SC_TOP_BOTTOM write cache disabled!\n"); + } + + TestRegisterCaching(DP_BKGD_CLR); + TestRegisterCaching(DP_FRGD_CLR); + TestRegisterCaching(DP_WRITE_MASK); + TestRegisterCaching(DP_MIX); + + TestRegisterCaching(CLR_CMP_CLR); + TestRegisterCaching(CLR_CMP_MSK); + TestRegisterCaching(CLR_CMP_CNTL); + + if (pATI->Block1Base) + { + TestRegisterCaching(OVERLAY_Y_X_START); + TestRegisterCaching(OVERLAY_Y_X_END); + + TestRegisterCaching(OVERLAY_GRAPHICS_KEY_CLR); + TestRegisterCaching(OVERLAY_GRAPHICS_KEY_MSK); + + TestRegisterCaching(OVERLAY_KEY_CNTL); + + TestRegisterCaching(OVERLAY_SCALE_INC); + TestRegisterCaching(OVERLAY_SCALE_CNTL); + + TestRegisterCaching(SCALER_HEIGHT_WIDTH); + + TestRegisterCaching(SCALER_TEST); + + TestRegisterCaching(VIDEO_FORMAT); + + if (pATI->Chip < ATI_CHIP_264VTB) + { + TestRegisterCaching(BUF0_OFFSET); + TestRegisterCaching(BUF0_PITCH); + TestRegisterCaching(BUF1_OFFSET); + TestRegisterCaching(BUF1_PITCH); + } + else + { + TestRegisterCaching(SCALER_BUF0_OFFSET); + TestRegisterCaching(SCALER_BUF1_OFFSET); + TestRegisterCaching(SCALER_BUF_PITCH); + + TestRegisterCaching(OVERLAY_EXCLUSIVE_HORZ); + TestRegisterCaching(OVERLAY_EXCLUSIVE_VERT); + + if (pATI->Chip >= ATI_CHIP_264GTPRO) + { + TestRegisterCaching(SCALER_COLOUR_CNTL); + + TestRegisterCaching(SCALER_H_COEFF0); + TestRegisterCaching(SCALER_H_COEFF1); + TestRegisterCaching(SCALER_H_COEFF2); + TestRegisterCaching(SCALER_H_COEFF3); + TestRegisterCaching(SCALER_H_COEFF4); + + TestRegisterCaching(SCALER_BUF0_OFFSET_U); + TestRegisterCaching(SCALER_BUF0_OFFSET_V); + TestRegisterCaching(SCALER_BUF1_OFFSET_U); + TestRegisterCaching(SCALER_BUF1_OFFSET_V); + } + } + } + } + + /* + * For VTB's and later, the first CPU read of the framebuffer will return + * zeroes, so do it here. This appears to be due to some kind of engine + * caching of framebuffer data I haven't found any way of disabling, or + * otherwise circumventing. Thanks to Mark Vojkovich for the suggestion. + */ + pATI = *(volatile ATIPtr *)pATI->pMemory; +} + +/* + * ATIMach64SetupForScreenToScreenCopy -- + * + * This function sets up the draw engine for a series of screen-to-screen copy + * operations. + */ +static void +ATIMach64SetupForScreenToScreenCopy +( + ScrnInfoPtr pScreenInfo, + int xdir, + int ydir, + int rop, + unsigned int planemask, + int TransparencyColour +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + ATIMach64WaitForFIFO(pATI, 3); + outf(DP_WRITE_MASK, planemask); + outf(DP_SRC, DP_MONO_SRC_ALLONES | + SetBits(SRC_BLIT, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC)); + outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX)); + +#ifdef AVOID_DGA + + if (TransparencyColour == -1) + +#else /* AVOID_DGA */ + + if (!pATI->XAAForceTransBlit && (TransparencyColour == -1)) + +#endif /* AVOID_DGA */ + + { + outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE); + } + else + { + ATIMach64WaitForFIFO(pATI, 2); + outf(CLR_CMP_CLR, TransparencyColour); + outf(CLR_CMP_CNTL, CLR_CMP_FN_EQUAL | CLR_CMP_SRC_2D); + } + + pATI->dst_cntl = 0; + + if (ydir > 0) + pATI->dst_cntl |= DST_Y_DIR; + if (xdir > 0) + pATI->dst_cntl |= DST_X_DIR; + + if (pATI->XModifier == 1) + outf(DST_CNTL, pATI->dst_cntl); + else + pATI->dst_cntl |= DST_24_ROT_EN; +} + +/* + * ATIMach64SubsequentScreenToScreenCopy -- + * + * This function performs a screen-to-screen copy operation. + */ +static void +ATIMach64SubsequentScreenToScreenCopy +( + ScrnInfoPtr pScreenInfo, + int xSrc, + int ySrc, + int xDst, + int yDst, + int w, + int h +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + xSrc *= pATI->XModifier; + xDst *= pATI->XModifier; + w *= pATI->XModifier; + + /* Disable clipping if it gets in the way */ + ATIMach64ValidateClip(pATI, xDst, xDst + w - 1, yDst, yDst + h - 1); + + if (!(pATI->dst_cntl & DST_X_DIR)) + { + xSrc += w - 1; + xDst += w - 1; + } + + if (!(pATI->dst_cntl & DST_Y_DIR)) + { + ySrc += h - 1; + yDst += h - 1; + } + + if (pATI->XModifier != 1) + outf(DST_CNTL, pATI->dst_cntl | SetBits((xDst / 4) % 6, DST_24_ROT)); + + ATIMach64WaitForFIFO(pATI, 4); + outf(SRC_Y_X, SetWord(xSrc, 1) | SetWord(ySrc, 0)); + outf(SRC_WIDTH1, w); + outf(DST_Y_X, SetWord(xDst, 1) | SetWord(yDst, 0)); + outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0)); +} + +/* + * ATIMach64SetupForSolidFill -- + * + * This function sets up the draw engine for a series of solid fills. + */ +static void +ATIMach64SetupForSolidFill +( + ScrnInfoPtr pScreenInfo, + int colour, + int rop, + unsigned int planemask +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + ATIMach64WaitForFIFO(pATI, 5); + outf(DP_WRITE_MASK, planemask); + outf(DP_SRC, DP_MONO_SRC_ALLONES | + SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC)); + outf(DP_FRGD_CLR, colour); + outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX)); + + outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE); + + if (pATI->XModifier == 1) + outf(DST_CNTL, DST_X_DIR | DST_Y_DIR); +} + +/* + * ATIMach64SubsequentSolidFillRect -- + * + * This function performs a solid rectangle fill. + */ +static void +ATIMach64SubsequentSolidFillRect +( + ScrnInfoPtr pScreenInfo, + int x, + int y, + int w, + int h +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->XModifier != 1) + { + x *= pATI->XModifier; + w *= pATI->XModifier; + + outf(DST_CNTL, SetBits((x / 4) % 6, DST_24_ROT) | + (DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)); + } + + /* Disable clipping if it gets in the way */ + ATIMach64ValidateClip(pATI, x, x + w - 1, y, y + h - 1); + + ATIMach64WaitForFIFO(pATI, 2); + outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0)); + outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0)); +} + +/* + * ATIMach64SetupForSolidLine -- + * + * This function sets up the draw engine for a series of solid lines. It is + * not used for 24bpp because the engine doesn't support it. + */ +static void +ATIMach64SetupForSolidLine +( + ScrnInfoPtr pScreenInfo, + int colour, + int rop, + unsigned int planemask +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + ATIMach64WaitForFIFO(pATI, 5); + outf(DP_WRITE_MASK, planemask); + outf(DP_SRC, DP_MONO_SRC_ALLONES | + SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC)); + outf(DP_FRGD_CLR, colour); + outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX)); + + outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE); + + ATIMach64ValidateClip(pATI, pATI->NewHW.sc_left, pATI->NewHW.sc_right, + pATI->NewHW.sc_top, pATI->NewHW.sc_bottom); +} + +/* + * ATIMach64SubsequentSolidHorVertLine -- + * + * This is called to draw a solid horizontal or vertical line. This does a + * one-pixel wide solid fill. + */ +static void +ATIMach64SubsequentSolidHorVertLine +( + ScrnInfoPtr pScreenInfo, + int x, + int y, + int len, + int dir +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + ATIMach64WaitForFIFO(pATI, 3); + outf(DST_CNTL, DST_X_DIR | DST_Y_DIR); + outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0)); + + if (dir == DEGREES_0) + outf(DST_HEIGHT_WIDTH, SetWord(len, 1) | SetWord(1, 0)); + else /* if (dir == DEGREES_270) */ + outf(DST_HEIGHT_WIDTH, SetWord(1, 1) | SetWord(len, 0)); +} + +/* + * ATIMach64SubsequentSolidBresenhamLine -- + * + * This function draws a line using the Bresenham line engine. + */ +static void +ATIMach64SubsequentSolidBresenhamLine +( + ScrnInfoPtr pScreenInfo, + int x, + int y, + int major, + int minor, + int err, + int len, + int octant +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + CARD32 dst_cntl = DST_LAST_PEL; + + if (octant & YMAJOR) + dst_cntl |= DST_Y_MAJOR; + + if (!(octant & XDECREASING)) + dst_cntl |= DST_X_DIR; + + if (!(octant & YDECREASING)) + dst_cntl |= DST_Y_DIR; + + ATIMach64WaitForFIFO(pATI, 6); + outf(DST_CNTL, dst_cntl); + outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0)); + outf(DST_BRES_ERR, minor + err); + outf(DST_BRES_INC, minor); + outf(DST_BRES_DEC, minor - major); + outf(DST_BRES_LNTH, len); +} + +/* + * ATIMach64SetupForMono8x8PatternFill -- + * + * This function sets up the draw engine for a series of 8x8 1bpp pattern + * fills. + */ +static void +ATIMach64SetupForMono8x8PatternFill +( + ScrnInfoPtr pScreenInfo, + int patx, + int paty, + int fg, + int bg, + int rop, + unsigned int planemask +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + ATIMach64WaitForFIFO(pATI, 3); + outf(DP_WRITE_MASK, planemask); + outf(DP_SRC, DP_MONO_SRC_PATTERN | + SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC)); + outf(DP_FRGD_CLR, fg); + + if (bg == -1) + { + outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) | + SetBits(MIX_DST, DP_BKGD_MIX)); + } + else + { + ATIMach64WaitForFIFO(pATI, 2); + outf(DP_BKGD_CLR, bg); + outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) | + SetBits(ATIMach64ALU[rop], DP_BKGD_MIX)); + } + + ATIMach64WaitForFIFO(pATI, 4); + outf(PAT_REG0, patx); + outf(PAT_REG1, paty); + outf(PAT_CNTL, PAT_MONO_EN); + + outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE); + + if (pATI->XModifier == 1) + outf(DST_CNTL, DST_X_DIR | DST_Y_DIR); +} + +/* + * ATIMach64SubsequentMono8x8PatternFillRect -- + * + * This function performs an 8x8 1bpp pattern fill. + */ +static void +ATIMach64SubsequentMono8x8PatternFillRect +( + ScrnInfoPtr pScreenInfo, + int patx, + int paty, + int x, + int y, + int w, + int h +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->XModifier != 1) + { + x *= pATI->XModifier; + w *= pATI->XModifier; + + outf(DST_CNTL, SetBits((x / 4) % 6, DST_24_ROT) | + (DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)); + } + + /* Disable clipping if it gets in the way */ + ATIMach64ValidateClip(pATI, x, x + w - 1, y, y + h - 1); + + ATIMach64WaitForFIFO(pATI, 2); + outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0)); + outf(DST_HEIGHT_WIDTH, SetWord(w, 1) | SetWord(h, 0)); +} + +/* + * ATIMach64SetupForScanlineCPUToScreenColorExpandFill -- + * + * This function sets up the engine for a series of colour expansion fills. + */ +static void +ATIMach64SetupForScanlineCPUToScreenColorExpandFill +( + ScrnInfoPtr pScreenInfo, + int fg, + int bg, + int rop, + unsigned int planemask +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + ATIMach64WaitForFIFO(pATI, 3); + outf(DP_WRITE_MASK, planemask); + outf(DP_SRC, DP_MONO_SRC_HOST | + SetBits(SRC_FRGD, DP_FRGD_SRC) | SetBits(SRC_BKGD, DP_BKGD_SRC)); + outf(DP_FRGD_CLR, fg); + + if (bg == -1) + { + outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) | + SetBits(MIX_DST, DP_BKGD_MIX)); + } + else + { + ATIMach64WaitForFIFO(pATI, 2); + outf(DP_BKGD_CLR, bg); + outf(DP_MIX, SetBits(ATIMach64ALU[rop], DP_FRGD_MIX) | + SetBits(ATIMach64ALU[rop], DP_BKGD_MIX)); + } + + outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE); + + if (pATI->XModifier == 1) + outf(DST_CNTL, DST_X_DIR | DST_Y_DIR); +} + +/* + * ATIMach64SubsequentScanlineCPUToScreenColorExpandFill -- + * + * This function sets up the engine for a single colour expansion fill. + */ +static void +ATIMach64SubsequentScanlineCPUToScreenColorExpandFill +( + ScrnInfoPtr pScreenInfo, + int x, + int y, + int w, + int h, + int skipleft +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->XModifier != 1) + { + x *= pATI->XModifier; + w *= pATI->XModifier; + skipleft *= pATI->XModifier; + + outf(DST_CNTL, SetBits((x / 4) % 6, DST_24_ROT) | + (DST_X_DIR | DST_Y_DIR | DST_24_ROT_EN)); + } + + pATI->ExpansionBitmapWidth = (w + 31) / 32; + + ATIMach64WaitForFIFO(pATI, 3); + pATI->sc_left = x + skipleft; + pATI->sc_right = x + w - 1; + outf(SC_LEFT_RIGHT, + SetWord(pATI->sc_right, 1) | SetWord(pATI->sc_left, 0)); + outf(DST_Y_X, SetWord(x, 1) | SetWord(y, 0)); + outf(DST_HEIGHT_WIDTH, + SetWord(pATI->ExpansionBitmapWidth * 32, 1) | SetWord(h, 0)); +} + +/* + * ATIMach64SubsequentColorExpandScanline -- + * + * This function feeds a bitmap scanline to the engine for a colour expansion + * fill. This is written to do burst transfers for those platforms that can do + * them, and to improve CPU/engine concurrency. + */ +static void +ATIMach64SubsequentColorExpandScanline +( + ScrnInfoPtr pScreenInfo, + int iBuffer +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + CARD32 *pBitmapData = pATI->ExpansionBitmapScanlinePtr[iBuffer]; + int w = pATI->ExpansionBitmapWidth; + int nDWord; + + while (w > 0) + { + /* + * Transfers are done in chunks of up to 64 bytes in length (32 on + * earlier controllers). + */ + nDWord = w; + if (nDWord > pATI->nHostFIFOEntries) + nDWord = pATI->nHostFIFOEntries; + + /* Make enough FIFO slots available */ + ATIMach64WaitForFIFO(pATI, nDWord); + + /* + * Always start transfers on a chuck-sized boundary. Note that + * HOST_DATA_0 is actually on a 512-byte boundary, but *pBitmapData can + * only be guaranteed to be on a chunk-sized boundary. + * + * Transfer current chunk. With any luck, the compiler won't mangle + * this too badly... + */ + +# if defined(ATIMove32) + + { + ATIMove32(pATI->pHOST_DATA, pBitmapData, nDWord); + } + +# else + + { + volatile CARD32 *pDst; + CARD32 *pSrc; + unsigned int iDWord; + + iDWord = 16 - nDWord; + pDst = (volatile CARD32 *)pATI->pHOST_DATA - iDWord; + pSrc = pBitmapData - iDWord; + + switch (iDWord) + { + case 0: MMIO_MOVE32(pDst + 0, 0, *(pSrc + 0)); + case 1: MMIO_MOVE32(pDst + 1, 0, *(pSrc + 1)); + case 2: MMIO_MOVE32(pDst + 2, 0, *(pSrc + 2)); + case 3: MMIO_MOVE32(pDst + 3, 0, *(pSrc + 3)); + case 4: MMIO_MOVE32(pDst + 4, 0, *(pSrc + 4)); + case 5: MMIO_MOVE32(pDst + 5, 0, *(pSrc + 5)); + case 6: MMIO_MOVE32(pDst + 6, 0, *(pSrc + 6)); + case 7: MMIO_MOVE32(pDst + 7, 0, *(pSrc + 7)); + case 8: MMIO_MOVE32(pDst + 8, 0, *(pSrc + 8)); + case 9: MMIO_MOVE32(pDst + 9, 0, *(pSrc + 9)); + case 10: MMIO_MOVE32(pDst + 10, 0, *(pSrc + 10)); + case 11: MMIO_MOVE32(pDst + 11, 0, *(pSrc + 11)); + case 12: MMIO_MOVE32(pDst + 12, 0, *(pSrc + 12)); + case 13: MMIO_MOVE32(pDst + 13, 0, *(pSrc + 13)); + case 14: MMIO_MOVE32(pDst + 14, 0, *(pSrc + 14)); + case 15: MMIO_MOVE32(pDst + 15, 0, *(pSrc + 15)); + + default: /* Muffle compiler */ + break; + } + } + +# endif + + /* Step to next chunk */ + pBitmapData += nDWord; + w -= nDWord; + pATI->nAvailableFIFOEntries -= nDWord; + } + + pATI->EngineIsBusy = TRUE; +} + +/* + * ATIMach64AccelInit -- + * + * This function fills in structure fields needed for acceleration on Mach64 + * variants. + */ +int +ATIMach64AccelInit +( + ATIPtr pATI, + XAAInfoRecPtr pXAAInfo +) +{ + /* This doesn't seem quite right... */ + if (pATI->XModifier == 1) + { + pXAAInfo->Flags = PIXMAP_CACHE | OFFSCREEN_PIXMAPS; + +#ifndef AVOID_CPIO + + if (!pATI->BankInfo.BankSize) + +#endif /* AVOID_CPIO */ + + { + pXAAInfo->Flags |= LINEAR_FRAMEBUFFER; + } + } + + /* Sync */ + pXAAInfo->Sync = ATIMach64Sync; + + /* Screen-to-screen copy */ + pXAAInfo->SetupForScreenToScreenCopy = ATIMach64SetupForScreenToScreenCopy; + pXAAInfo->SubsequentScreenToScreenCopy = + ATIMach64SubsequentScreenToScreenCopy; + + /* Solid fills */ + pXAAInfo->SetupForSolidFill = ATIMach64SetupForSolidFill; + pXAAInfo->SubsequentSolidFillRect = ATIMach64SubsequentSolidFillRect; + + /* 8x8 mono pattern fills */ + pXAAInfo->Mono8x8PatternFillFlags = + +#if X_BYTE_ORDER != X_LITTLE_ENDIAN + + BIT_ORDER_IN_BYTE_MSBFIRST | + +#endif /* X_BYTE_ORDER */ + + HARDWARE_PATTERN_PROGRAMMED_BITS | HARDWARE_PATTERN_SCREEN_ORIGIN; + pXAAInfo->SetupForMono8x8PatternFill = ATIMach64SetupForMono8x8PatternFill; + pXAAInfo->SubsequentMono8x8PatternFillRect = + ATIMach64SubsequentMono8x8PatternFillRect; + + /* + * Use scanline version of colour expansion, not only for the non-ix86 + * case, but also to avoid PCI retries. + */ + pXAAInfo->ScanlineCPUToScreenColorExpandFillFlags = + LEFT_EDGE_CLIPPING | LEFT_EDGE_CLIPPING_NEGATIVE_X | + CPU_TRANSFER_PAD_DWORD | SCANLINE_PAD_DWORD; + if (pATI->XModifier != 1) + pXAAInfo->ScanlineCPUToScreenColorExpandFillFlags |= TRIPLE_BITS_24BPP; + pXAAInfo->NumScanlineColorExpandBuffers = 1; + + /* Align bitmap data on a 64-byte boundary */ + pATI->ExpansionBitmapWidth = /* DWord size in bits */ + ((pATI->displayWidth * pATI->XModifier) + 31) & ~31U; + pATI->ExpansionBitmapScanlinePtr[1] = + (CARD32 *)xnfalloc((pATI->ExpansionBitmapWidth >> 3) + 63); + pATI->ExpansionBitmapScanlinePtr[0] = + (pointer)(((unsigned long)pATI->ExpansionBitmapScanlinePtr[1] + 63) & + ~63UL); + pXAAInfo->ScanlineColorExpandBuffers = + (CARD8 **)pATI->ExpansionBitmapScanlinePtr; + pXAAInfo->SetupForScanlineCPUToScreenColorExpandFill = + ATIMach64SetupForScanlineCPUToScreenColorExpandFill; + pXAAInfo->SubsequentScanlineCPUToScreenColorExpandFill = + ATIMach64SubsequentScanlineCPUToScreenColorExpandFill; + pXAAInfo->SubsequentColorExpandScanline = + ATIMach64SubsequentColorExpandScanline; + + /* The engine does not support the following primitives for 24bpp */ + if (pATI->XModifier != 1) + return ATIMach64MaxY; + + /* Solid lines */ + pXAAInfo->SetupForSolidLine = ATIMach64SetupForSolidLine; + pXAAInfo->SubsequentSolidHorVertLine = ATIMach64SubsequentSolidHorVertLine; + pXAAInfo->SubsequentSolidBresenhamLine = + ATIMach64SubsequentSolidBresenhamLine; + + return ATIMach64MaxY; +} diff --git a/src/atimach64accel.h b/src/atimach64accel.h new file mode 100644 index 0000000..ff24b17 --- /dev/null +++ b/src/atimach64accel.h @@ -0,0 +1,38 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64accel.h,v 1.1 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMACH64ACCEL_H___ +#define ___ATIMACH64ACCEL_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xaa.h" + +#define ATIMach64MaxX 8191 +#define ATIMach64MaxY 32767 + +extern int ATIMach64AccelInit FunctionPrototype((ATIPtr, XAAInfoRecPtr)); +extern void ATIMach64Sync FunctionPrototype((ScrnInfoPtr)); + +#endif /* ___ATIMACH64ACCEL_H___ */ diff --git a/src/atimach64cursor.c b/src/atimach64cursor.c new file mode 100644 index 0000000..9d8816b --- /dev/null +++ b/src/atimach64cursor.c @@ -0,0 +1,400 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64cursor.c,v 1.1 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "aticrtc.h" +#include "atimach64accel.h" +#include "atimach64cursor.h" +#include "atimach64io.h" + +/* + * ATIMach64SetCursorColours -- + * + * Set hardware cursor foreground and background colours. + */ +static void +ATIMach64SetCursorColours +( + ScrnInfoPtr pScreenInfo, + int fg, + int bg +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + outr(CUR_CLR0, SetBits(fg, CUR_CLR)); + outr(CUR_CLR1, SetBits(bg, CUR_CLR)); +} + +/* + * ATIMach64SetCursorPosition -- + * + * Set position of hardware cursor. + */ +static void +ATIMach64SetCursorPosition +( + ScrnInfoPtr pScreenInfo, + int x, + int y +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + CARD16 CursorXOffset, CursorYOffset; + + /* Adjust x & y when the cursor is partially obscured */ + if (x < 0) + { + if ((CursorXOffset = -x) > 63) + CursorXOffset = 63; + x = 0; + } + else + { + CursorXOffset = pScreenInfo->frameX1 - pScreenInfo->frameX0; + if (x > CursorXOffset) + x = CursorXOffset; + CursorXOffset = 0; + } + + if (y < 0) + { + if ((CursorYOffset = -y) > 63) + CursorYOffset = 63; + y = 0; + } + else + { + CursorYOffset = pScreenInfo->frameY1 - pScreenInfo->frameY0; + if (y > CursorYOffset) + y = CursorYOffset; + CursorYOffset = 0; + } + + /* Adjust for multiscanned modes */ + if (pScreenInfo->currentMode->Flags & V_DBLSCAN) + y *= 2; + if (pScreenInfo->currentMode->VScan > 1) + y *= pScreenInfo->currentMode->VScan; + + do + { + if (CursorYOffset != pATI->CursorYOffset) + { + pATI->CursorYOffset = CursorYOffset; + outr(CUR_OFFSET, ((CursorYOffset << 4) + pATI->CursorOffset) >> 3); + } + else if (CursorXOffset == pATI->CursorXOffset) + break; + + pATI->CursorXOffset = CursorXOffset; + outr(CUR_HORZ_VERT_OFF, SetBits(CursorXOffset, CUR_HORZ_OFF) | + SetBits(CursorYOffset, CUR_VERT_OFF)); + } while (0); + + outr(CUR_HORZ_VERT_POSN, + SetBits(x, CUR_HORZ_POSN) | SetBits(y, CUR_VERT_POSN)); +} + +/* + * ATIMach64LoadCursorImage -- + * + * Copy hardware cursor image into offscreen video memory. + */ +static void +ATIMach64LoadCursorImage +( + ScrnInfoPtr pScreenInfo, + CARD8 *pImage +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + CARD32 *pSrc = (pointer)pImage; + volatile CARD32 *pDst = pATI->pCursorImage; + + /* Synchronise video memory accesses */ + ATIMach64Sync(pScreenInfo); + +# if defined(ATIMove32) + + { + ATIMove32(pDst, pSrc, 256); + } + +# else + + { + /* This is lengthy, but it does maximise burst modes */ + pDst[ 0] = pSrc[ 0]; pDst[ 1] = pSrc[ 1]; + pDst[ 2] = pSrc[ 2]; pDst[ 3] = pSrc[ 3]; + pDst[ 4] = pSrc[ 4]; pDst[ 5] = pSrc[ 5]; + pDst[ 6] = pSrc[ 6]; pDst[ 7] = pSrc[ 7]; + pDst[ 8] = pSrc[ 8]; pDst[ 9] = pSrc[ 9]; + pDst[ 10] = pSrc[ 10]; pDst[ 11] = pSrc[ 11]; + pDst[ 12] = pSrc[ 12]; pDst[ 13] = pSrc[ 13]; + pDst[ 14] = pSrc[ 14]; pDst[ 15] = pSrc[ 15]; + pDst[ 16] = pSrc[ 16]; pDst[ 17] = pSrc[ 17]; + pDst[ 18] = pSrc[ 18]; pDst[ 19] = pSrc[ 19]; + pDst[ 20] = pSrc[ 20]; pDst[ 21] = pSrc[ 21]; + pDst[ 22] = pSrc[ 22]; pDst[ 23] = pSrc[ 23]; + pDst[ 24] = pSrc[ 24]; pDst[ 25] = pSrc[ 25]; + pDst[ 26] = pSrc[ 26]; pDst[ 27] = pSrc[ 27]; + pDst[ 28] = pSrc[ 28]; pDst[ 29] = pSrc[ 29]; + pDst[ 30] = pSrc[ 30]; pDst[ 31] = pSrc[ 31]; + pDst[ 32] = pSrc[ 32]; pDst[ 33] = pSrc[ 33]; + pDst[ 34] = pSrc[ 34]; pDst[ 35] = pSrc[ 35]; + pDst[ 36] = pSrc[ 36]; pDst[ 37] = pSrc[ 37]; + pDst[ 38] = pSrc[ 38]; pDst[ 39] = pSrc[ 39]; + pDst[ 40] = pSrc[ 40]; pDst[ 41] = pSrc[ 41]; + pDst[ 42] = pSrc[ 42]; pDst[ 43] = pSrc[ 43]; + pDst[ 44] = pSrc[ 44]; pDst[ 45] = pSrc[ 45]; + pDst[ 46] = pSrc[ 46]; pDst[ 47] = pSrc[ 47]; + pDst[ 48] = pSrc[ 48]; pDst[ 49] = pSrc[ 49]; + pDst[ 50] = pSrc[ 50]; pDst[ 51] = pSrc[ 51]; + pDst[ 52] = pSrc[ 52]; pDst[ 53] = pSrc[ 53]; + pDst[ 54] = pSrc[ 54]; pDst[ 55] = pSrc[ 55]; + pDst[ 56] = pSrc[ 56]; pDst[ 57] = pSrc[ 57]; + pDst[ 58] = pSrc[ 58]; pDst[ 59] = pSrc[ 59]; + pDst[ 60] = pSrc[ 60]; pDst[ 61] = pSrc[ 61]; + pDst[ 62] = pSrc[ 62]; pDst[ 63] = pSrc[ 63]; + pDst[ 64] = pSrc[ 64]; pDst[ 65] = pSrc[ 65]; + pDst[ 66] = pSrc[ 66]; pDst[ 67] = pSrc[ 67]; + pDst[ 68] = pSrc[ 68]; pDst[ 69] = pSrc[ 69]; + pDst[ 70] = pSrc[ 70]; pDst[ 71] = pSrc[ 71]; + pDst[ 72] = pSrc[ 72]; pDst[ 73] = pSrc[ 73]; + pDst[ 74] = pSrc[ 74]; pDst[ 75] = pSrc[ 75]; + pDst[ 76] = pSrc[ 76]; pDst[ 77] = pSrc[ 77]; + pDst[ 78] = pSrc[ 78]; pDst[ 79] = pSrc[ 79]; + pDst[ 80] = pSrc[ 80]; pDst[ 81] = pSrc[ 81]; + pDst[ 82] = pSrc[ 82]; pDst[ 83] = pSrc[ 83]; + pDst[ 84] = pSrc[ 84]; pDst[ 85] = pSrc[ 85]; + pDst[ 86] = pSrc[ 86]; pDst[ 87] = pSrc[ 87]; + pDst[ 88] = pSrc[ 88]; pDst[ 89] = pSrc[ 89]; + pDst[ 90] = pSrc[ 90]; pDst[ 91] = pSrc[ 91]; + pDst[ 92] = pSrc[ 92]; pDst[ 93] = pSrc[ 93]; + pDst[ 94] = pSrc[ 94]; pDst[ 95] = pSrc[ 95]; + pDst[ 96] = pSrc[ 96]; pDst[ 97] = pSrc[ 97]; + pDst[ 98] = pSrc[ 98]; pDst[ 99] = pSrc[ 99]; + pDst[100] = pSrc[100]; pDst[101] = pSrc[101]; + pDst[102] = pSrc[102]; pDst[103] = pSrc[103]; + pDst[104] = pSrc[104]; pDst[105] = pSrc[105]; + pDst[106] = pSrc[106]; pDst[107] = pSrc[107]; + pDst[108] = pSrc[108]; pDst[109] = pSrc[109]; + pDst[110] = pSrc[110]; pDst[111] = pSrc[111]; + pDst[112] = pSrc[112]; pDst[113] = pSrc[113]; + pDst[114] = pSrc[114]; pDst[115] = pSrc[115]; + pDst[116] = pSrc[116]; pDst[117] = pSrc[117]; + pDst[118] = pSrc[118]; pDst[119] = pSrc[119]; + pDst[120] = pSrc[120]; pDst[121] = pSrc[121]; + pDst[122] = pSrc[122]; pDst[123] = pSrc[123]; + pDst[124] = pSrc[124]; pDst[125] = pSrc[125]; + pDst[126] = pSrc[126]; pDst[127] = pSrc[127]; + pDst[128] = pSrc[128]; pDst[129] = pSrc[129]; + pDst[130] = pSrc[130]; pDst[131] = pSrc[131]; + pDst[132] = pSrc[132]; pDst[133] = pSrc[133]; + pDst[134] = pSrc[134]; pDst[135] = pSrc[135]; + pDst[136] = pSrc[136]; pDst[137] = pSrc[137]; + pDst[138] = pSrc[138]; pDst[139] = pSrc[139]; + pDst[140] = pSrc[140]; pDst[141] = pSrc[141]; + pDst[142] = pSrc[142]; pDst[143] = pSrc[143]; + pDst[144] = pSrc[144]; pDst[145] = pSrc[145]; + pDst[146] = pSrc[146]; pDst[147] = pSrc[147]; + pDst[148] = pSrc[148]; pDst[149] = pSrc[149]; + pDst[150] = pSrc[150]; pDst[151] = pSrc[151]; + pDst[152] = pSrc[152]; pDst[153] = pSrc[153]; + pDst[154] = pSrc[154]; pDst[155] = pSrc[155]; + pDst[156] = pSrc[156]; pDst[157] = pSrc[157]; + pDst[158] = pSrc[158]; pDst[159] = pSrc[159]; + pDst[160] = pSrc[160]; pDst[161] = pSrc[161]; + pDst[162] = pSrc[162]; pDst[163] = pSrc[163]; + pDst[164] = pSrc[164]; pDst[165] = pSrc[165]; + pDst[166] = pSrc[166]; pDst[167] = pSrc[167]; + pDst[168] = pSrc[168]; pDst[169] = pSrc[169]; + pDst[170] = pSrc[170]; pDst[171] = pSrc[171]; + pDst[172] = pSrc[172]; pDst[173] = pSrc[173]; + pDst[174] = pSrc[174]; pDst[175] = pSrc[175]; + pDst[176] = pSrc[176]; pDst[177] = pSrc[177]; + pDst[178] = pSrc[178]; pDst[179] = pSrc[179]; + pDst[180] = pSrc[180]; pDst[181] = pSrc[181]; + pDst[182] = pSrc[182]; pDst[183] = pSrc[183]; + pDst[184] = pSrc[184]; pDst[185] = pSrc[185]; + pDst[186] = pSrc[186]; pDst[187] = pSrc[187]; + pDst[188] = pSrc[188]; pDst[189] = pSrc[189]; + pDst[190] = pSrc[190]; pDst[191] = pSrc[191]; + pDst[192] = pSrc[192]; pDst[193] = pSrc[193]; + pDst[194] = pSrc[194]; pDst[195] = pSrc[195]; + pDst[196] = pSrc[196]; pDst[197] = pSrc[197]; + pDst[198] = pSrc[198]; pDst[199] = pSrc[199]; + pDst[200] = pSrc[200]; pDst[201] = pSrc[201]; + pDst[202] = pSrc[202]; pDst[203] = pSrc[203]; + pDst[204] = pSrc[204]; pDst[205] = pSrc[205]; + pDst[206] = pSrc[206]; pDst[207] = pSrc[207]; + pDst[208] = pSrc[208]; pDst[209] = pSrc[209]; + pDst[210] = pSrc[210]; pDst[211] = pSrc[211]; + pDst[212] = pSrc[212]; pDst[213] = pSrc[213]; + pDst[214] = pSrc[214]; pDst[215] = pSrc[215]; + pDst[216] = pSrc[216]; pDst[217] = pSrc[217]; + pDst[218] = pSrc[218]; pDst[219] = pSrc[219]; + pDst[220] = pSrc[220]; pDst[221] = pSrc[221]; + pDst[222] = pSrc[222]; pDst[223] = pSrc[223]; + pDst[224] = pSrc[224]; pDst[225] = pSrc[225]; + pDst[226] = pSrc[226]; pDst[227] = pSrc[227]; + pDst[228] = pSrc[228]; pDst[229] = pSrc[229]; + pDst[230] = pSrc[230]; pDst[231] = pSrc[231]; + pDst[232] = pSrc[232]; pDst[233] = pSrc[233]; + pDst[234] = pSrc[234]; pDst[235] = pSrc[235]; + pDst[236] = pSrc[236]; pDst[237] = pSrc[237]; + pDst[238] = pSrc[238]; pDst[239] = pSrc[239]; + pDst[240] = pSrc[240]; pDst[241] = pSrc[241]; + pDst[242] = pSrc[242]; pDst[243] = pSrc[243]; + pDst[244] = pSrc[244]; pDst[245] = pSrc[245]; + pDst[246] = pSrc[246]; pDst[247] = pSrc[247]; + pDst[248] = pSrc[248]; pDst[249] = pSrc[249]; + pDst[250] = pSrc[250]; pDst[251] = pSrc[251]; + pDst[252] = pSrc[252]; pDst[253] = pSrc[253]; + pDst[254] = pSrc[254]; pDst[255] = pSrc[255]; + } + +#endif + +} + +/* + * ATIMach64HideCursor -- + * + * Turn off hardware cursor. + */ +static void +ATIMach64HideCursor +( + ScrnInfoPtr pScreenInfo +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (!(pATI->NewHW.gen_test_cntl & GEN_CUR_EN)) + return; + + pATI->NewHW.gen_test_cntl &= ~GEN_CUR_EN; + out8(GEN_TEST_CNTL, GetByte(pATI->NewHW.gen_test_cntl, 0)); +} + +/* + * ATIMach64ShowCursor -- + * + * Turn on hardware cursor. + */ +static void +ATIMach64ShowCursor +( + ScrnInfoPtr pScreenInfo +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->NewHW.gen_test_cntl & GEN_CUR_EN) + return; + + pATI->NewHW.gen_test_cntl |= GEN_CUR_EN; + out8(GEN_TEST_CNTL, GetByte(pATI->NewHW.gen_test_cntl, 0)); +} + +/* + * ATIMach64UseHWCursor -- + * + * Notify cursor layer whether a hardware cursor is configured. + */ +static Bool +ATIMach64UseHWCursor +( + ScreenPtr pScreen, + CursorPtr pCursor +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[pScreen->myNum]; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (!pATI->CursorBase) + return FALSE; + +#ifndef AVOID_CPIO + + /* + * For some reason, the hardware cursor isn't vertically scaled when a VGA + * doublescanned or multiscanned mode is in effect. + */ + if (pATI->NewHW.crtc == ATI_CRTC_MACH64) + return TRUE; + if ((pScreenInfo->currentMode->Flags & V_DBLSCAN) || + (pScreenInfo->currentMode->VScan > 1)) + return FALSE; + +#endif /* AVOID_CPIO */ + + return TRUE; +} + +/* + * ATIMach64CursorInit -- + * + * Initialise xf86CursorInfoRec fields with information specific to Mach64 + * variants. + */ +Bool +ATIMach64CursorInit +( + xf86CursorInfoPtr pCursorInfo +) +{ + /* + * For Mach64 variants, toggling hardware cursors off and on causes display + * artifacts. Ask the cursor support layers to always paint the cursor + * (whether or not it is entirely transparent) and to not hide the cursor + * when reloading its image. The two remaining reasons for turning off the + * hardware cursor are when it moves to a different screen or on a switch + * to a different virtual console. + */ + pCursorInfo->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_INVERT_MASK | + HARDWARE_CURSOR_SHOW_TRANSPARENT | + HARDWARE_CURSOR_UPDATE_UNHIDDEN | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + +#if X_BYTE_ORDER != X_LITTLE_ENDIAN + + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | + +#endif /* X_BYTE_ORDER */ + + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1; + pCursorInfo->MaxWidth = pCursorInfo->MaxHeight = 64; + + pCursorInfo->SetCursorColors = ATIMach64SetCursorColours; + pCursorInfo->SetCursorPosition = ATIMach64SetCursorPosition; + pCursorInfo->LoadCursorImage = ATIMach64LoadCursorImage; + pCursorInfo->HideCursor = ATIMach64HideCursor; + pCursorInfo->ShowCursor = ATIMach64ShowCursor; + pCursorInfo->UseHWCursor = ATIMach64UseHWCursor; + + return TRUE; +} diff --git a/src/atimach64cursor.h b/src/atimach64cursor.h new file mode 100644 index 0000000..b861f15 --- /dev/null +++ b/src/atimach64cursor.h @@ -0,0 +1,33 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64cursor.h,v 1.1 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMACH64CURSOR_H___ +#define ___ATIMACH64CURSOR_H___ 1 + +#include "atiproto.h" + +#include "xf86Cursor.h" + +extern Bool ATIMach64CursorInit FunctionPrototype((xf86CursorInfoPtr)); + +#endif /* ___ATIMACH64CURSOR_H___ */ diff --git a/src/atimach64i2c.c b/src/atimach64i2c.c new file mode 100644 index 0000000..10df61f --- /dev/null +++ b/src/atimach64i2c.c @@ -0,0 +1,466 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64i2c.c,v 1.1 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atichip.h" +#include "atii2c.h" +#include "atimach64i2c.h" +#include "atimach64io.h" +#include "atituner.h" + +/* MPP_CONFIG register values */ +#define MPP_INIT pATI->NewHW.mpp_config + +#define MPP_WRITE (MPP_INIT ) +#define MPP_WRITEINC (MPP_INIT | (MPP_AUTO_INC_EN )) +#define MPP_READ (MPP_INIT | ( MPP_BUFFER_MODE_PREFETCH)) +#define MPP_READINC (MPP_INIT | (MPP_AUTO_INC_EN | MPP_BUFFER_MODE_PREFETCH)) + +/* + * ATIMach64MPPWaitForIdle -- + * + * Support function to wait for the Multimedia Peripheral Port to become idle. + * Currently, this function's return value indicates whether or not the port + * became idle within 512 polling iterations. For now, this value is ignored + * by the rest of the code, but might be used in the future. + */ +static Bool +ATIMach64MPPWaitForIdle +( + ATIPtr pATI +) +{ + CARD32 Count = 0x0200; + + while (in8(MPP_CONFIG + 3) & GetByte(MPP_BUSY, 3)) + { + if (!--Count) + return FALSE; + usleep(1); /* XXX Excessive? */ + } + + return TRUE; +} + +/* + * ATIMach64MPPSetAddress -- + * + * Sets a 16-bit ImpacTV address on the Multimedia Peripheral Port. + */ +static void +ATIMach64MPPSetAddress +( + ATIPtr pATI, + CARD16 Address +) +{ + ATIMach64MPPWaitForIdle(pATI); + outr(MPP_CONFIG, MPP_WRITEINC); + outr(MPP_ADDR, 0x00000008U); + out8(MPP_DATA, (CARD8)Address); + ATIMach64MPPWaitForIdle(pATI); + out8(MPP_DATA, (CARD8)(Address >> 8)); + ATIMach64MPPWaitForIdle(pATI); + outr(MPP_CONFIG, MPP_WRITE); + outr(MPP_ADDR, 0x00000018U); + ATIMach64MPPWaitForIdle(pATI); +} + +/* + * ATIMach64ImpacTVProbe -- + * + * This probes for an ImpacTV chip and returns its chip ID, or 0. + */ +static int +ATIMach64ImpacTVProbe +( + int iScreen, + ATIPtr pATI +) +{ + CARD8 ChipID = 0; + + /* Assume ATIModePreInit() has already been called */ + outr(MPP_STROBE_SEQ, pATI->NewHW.mpp_strobe_seq); + outr(TVO_CNTL, pATI->NewHW.tvo_cntl); + + outr(MPP_CONFIG, MPP_READ); + ATIMach64MPPWaitForIdle(pATI); + outr(MPP_ADDR, 0x0000000AU); + if (!(ChipID = in8(MPP_DATA))) + { + ATIMach64MPPWaitForIdle(pATI); + outr(MPP_ADDR, 0x00000023U); + if ((ChipID = in8(MPP_DATA)) != 0x54U) + { + ATIMach64MPPWaitForIdle(pATI); + outr(MPP_ADDR, 0x0000000BU); + ChipID = in8(MPP_DATA); + } + } + ATIMach64MPPWaitForIdle(pATI); + outr(MPP_CONFIG, MPP_WRITE); + + if (ChipID) + xf86DrvMsg(iScreen, X_PROBED, "ImpacTV chip ID 0x%02X detected.\n", + ChipID); + + return (int)(CARD16)ChipID; +} + +/* + * ATIMach64ImpacTVSetBits -- + * + * Controls I2C SDA and SCL lines through ImpacTV. + */ +static void +ATIMach64ImpacTVSetBits +( + ATII2CPtr pATII2C, + ATIPtr pATI, + CARD32 Bits +) +{ + pATII2C->I2CCur = Bits; + + ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL); + + outr(MPP_CONFIG, MPP_WRITE); + + out8(MPP_DATA, (CARD8)Bits); + + ATIMach64MPPWaitForIdle(pATI); +} + +/* + * ATIMach64ImpacTVGetBits -- + * + * Returns the status of an ImpacTV's I2C control lines. + */ +static CARD32 +ATIMach64ImpacTVGetBits +( + ATIPtr pATI +) +{ + ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL); + + outr(MPP_CONFIG, MPP_READ); + + ATIMach64MPPWaitForIdle(pATI); + + return in8(MPP_DATA); +} + +/* + * ATIMach64I2C_CNTLSetBits -- + * + * Controls SDA and SCL lines through a 3D Rage Pro's hardware assisted I2C. + */ +static void +ATIMach64I2C_CNTLSetBits +( + ATII2CPtr pATII2C, + ATIPtr pATI, + CARD32 Bits +) +{ + pATII2C->I2CCur = Bits; + + out8(I2C_CNTL_0 + 1, (CARD8)Bits); +} + +/* + * ATIMach64I2C_CNTLGetBits -- + * + * Returns the status of a 3D Rage Pro's hardware assisted I2C control lines. + */ +static CARD32 +ATIMach64I2C_CNTLGetBits +( + ATIPtr pATI +) +{ + return in8(I2C_CNTL_0 + 1); +} + +/* + * ATIMach64GP_IOSetBits -- + * + * Controls SDA and SCL control lines through a Mach64's GP_IO register. + */ +static void +ATIMach64GP_IOSetBits +( + ATII2CPtr pATII2C, + ATIPtr pATI, + CARD32 Bits +) +{ + pATII2C->I2CCur = Bits; + + outr(GP_IO, Bits); +} + +/* + * ATIMach64GP_IOGetBits -- + * + * Returns the status of I2C control lines through a Mach64's GP_IO register. + */ +static CARD32 +ATIMach64GP_IOGetBits +( + ATIPtr pATI +) +{ + return inr(GP_IO); +} + +#define GPIO1_MASK \ + (DAC_GIO_STATE_1 | DAC_GIO_DIR_1) +#define GPIO2_MASK \ + (GEN_GIO2_DATA_OUT | GEN_GIO2_DATA_IN | GEN_GIO2_WRITE) + +/* + * ATIMach64DAC_GENSetBits -- + * + * Controls SDA and SCL control lines through a Mach64's GEN_TEST_CNTL and + * DAC_CNTL registers. + */ +static void +ATIMach64DAC_GENSetBits +( + ATII2CPtr pATII2C, + ATIPtr pATI, + CARD32 Bits +) +{ + CARD32 tmp; + + pATII2C->I2CCur = Bits; + + tmp = inr(DAC_CNTL) & ~GPIO1_MASK; + outr(DAC_CNTL, tmp | (Bits & GPIO1_MASK)); + tmp = inr(GEN_TEST_CNTL) & ~GPIO2_MASK; + outr(GEN_TEST_CNTL, tmp | (Bits & GPIO2_MASK)); +} + +/* + * ATIMach64DAC_GENGetBits -- + * + * Returns the status of I2C control lines through a Mach64's GEN_TEST_CNTL and + * DAC_CNTL registers. + */ +static CARD32 +ATIMach64DAC_GENGetBits +( + ATIPtr pATI +) +{ + return (inr(DAC_CNTL) & GPIO1_MASK) | (inr(GEN_TEST_CNTL) & GPIO2_MASK); +} + +/* + * ATITVAddOnProbe -- + * + * Probe for an ATI-TV add-on card at specific addresses on an I2C bus. + */ +static Bool +ATITVAddOnProbe +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + I2CBusPtr pI2CBus +) +{ + I2CDevPtr pI2CDev = xnfcalloc(1, SizeOf(I2CDevRec)); + int Index; + I2CByte tmp; + + static const CARD8 ATITVAddOnAddresses[] = {0x70, 0x40, 0x78, 0x72, 0x42}; + + pI2CDev->DevName = "ATI-TV Add-on"; + pI2CDev->pI2CBus = pI2CBus; + pI2CDev->StartTimeout = pI2CBus->StartTimeout; + pI2CDev->BitTimeout = pI2CBus->BitTimeout; + pI2CDev->AcknTimeout = pI2CBus->AcknTimeout; + pI2CDev->ByteTimeout = pI2CBus->ByteTimeout; + + for (Index = 0; Index < NumberOf(ATITVAddOnAddresses); Index++) + { + pI2CDev->SlaveAddr = ATITVAddOnAddresses[Index]; + + if (xf86I2CFindDev(pI2CBus, pI2CDev->SlaveAddr)) + continue; + + tmp = 0xFFU; + + if (!(*pI2CBus->I2CWriteRead)(pI2CDev, &tmp, 1, NULL, 0) || + !(*pI2CBus->I2CWriteRead)(pI2CDev, NULL, 0, &tmp, 1) || + (tmp == 0xFFU) || ((tmp = tmp & 0x1FU) == /*ATI_TUNER_NONE*/0)) + continue; + + if (!xf86I2CDevInit(pI2CDev)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Failed to register I2C device for ATI-TV add-on.\n"); + break; + } + + if (pATI->Tuner != tmp) + { + if (pATI->Tuner != ATI_TUNER_NONE) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Tuner type mismatch: BIOS 0x%x, ATI-TV 0x%x.\n", + pATI->Tuner, tmp); + + pATI->Tuner = tmp; + } + + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s tuner detected on ATI-TV add-on adapter at I2C bus address" + " 0x%2x.\n", ATITuners[pATI->Tuner].name, pI2CDev->SlaveAddr); + + return TRUE; + } + + xfree(pI2CDev); + return FALSE; +} + +/* + * ATIMach64I2CPreInit -- + * + * This function potentially allocates an I2CBusRec and initialises it with + * ATI-specific and Mach64-specific information. + */ +void +ATIMach64I2CPreInit +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + I2CBusPtr pI2CBus; + ATII2CPtr pATII2C; + + if ((pATI->Chip < ATI_CHIP_264CT) || (pATI->Chip >= ATI_CHIP_Mach64)) + return; + + /* Create an I2CBusRec and generically prime it */ + if (!(pI2CBus = ATICreateI2CBusRec(pScreenInfo->scrnIndex, pATI, "Mach64"))) + return; + + pATII2C = pI2CBus->DriverPrivate.ptr; + + switch (pATI->Chip) + { + case ATI_CHIP_264GTPRO: + case ATI_CHIP_264LTPRO: + case ATI_CHIP_264XL: + case ATI_CHIP_MOBILITY: + /* + * These have I2C-specific registers. Assume older I2C access + * mechanisms are inoperative. + */ + pATII2C->I2CSetBits = ATIMach64I2C_CNTLSetBits; + pATII2C->I2CGetBits = ATIMach64I2C_CNTLGetBits; + pATII2C->SCLDir = pATII2C->SDADir = 0; + pATII2C->SCLGet = pATII2C->SCLSet = GetByte(I2C_CNTL_SCL, 1); + pATII2C->SDAGet = pATII2C->SDASet = GetByte(I2C_CNTL_SDA, 1); + + out8(I2C_CNTL_1 + 2, GetByte(I2C_SEL, 2)); + out8(I2C_CNTL_0 + 0, + GetByte(I2C_CNTL_STAT | I2C_CNTL_HPTR_RST, 0)); + break; + + case ATI_CHIP_264VTB: + case ATI_CHIP_264GTB: + case ATI_CHIP_264VT3: + case ATI_CHIP_264GTDVD: + case ATI_CHIP_264LT: + case ATI_CHIP_264VT4: + case ATI_CHIP_264GT2C: + /* If an ImpacTV chip is found, use it to provide I2C access */ + if (ATIMach64ImpacTVProbe(pScreenInfo->scrnIndex, pATI)) + { + pATII2C->I2CSetBits = ATIMach64ImpacTVSetBits; + pATII2C->I2CGetBits = ATIMach64ImpacTVGetBits; + pATII2C->SCLDir = IT_SCL_DIR; + pATII2C->SCLGet = IT_SCL_GET; + pATII2C->SCLSet = IT_SCL_SET; + pATII2C->SDADir = IT_SDA_DIR; + pATII2C->SDAGet = IT_SDA_GET; + pATII2C->SDASet = IT_SDA_SET; + + ATIMach64MPPSetAddress(pATI, IT_I2C_CNTL); + outr(MPP_CONFIG, MPP_WRITEINC); + out8(MPP_DATA, 0x00U); + out8(MPP_DATA, 0x55U); + out8(MPP_DATA, 0x00U); + out8(MPP_DATA, 0x00U); + ATIMach64MPPWaitForIdle(pATI); + break; + } + /* Otherwise, fall through to the older case */ + + case ATI_CHIP_264VT: + case ATI_CHIP_264GT: + /* First try GIO pins 11 (clock) and 4 (data) */ + pATII2C->I2CSetBits = ATIMach64GP_IOSetBits; + pATII2C->I2CGetBits = ATIMach64GP_IOGetBits; + pATII2C->SCLDir = GP_IO_DIR_B; + pATII2C->SCLGet = pATII2C->SCLSet = GP_IO_B; + pATII2C->SDADir = GP_IO_DIR_4; + pATII2C->SDAGet = pATII2C->SDASet = GP_IO_4; + + if (ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus)) + break; + + /* Next, try pins 10 (clock) and 12 (data) */ + pATII2C->SCLDir = GP_IO_DIR_A; + pATII2C->SCLGet = pATII2C->SCLSet = GP_IO_A; + pATII2C->SDADir = GP_IO_DIR_C; + pATII2C->SDAGet = pATII2C->SDASet = GP_IO_C; + + if (ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus)) + break; + /* Otherwise, fall back to ATI's first I2C implementation */ + + default: + /* + * First generation integrated controllers access GIO pin 1 (clock) + * though DAC_CNTL, and pin 2 (data) through GEN_TEST_CNTL. + */ + pATII2C->I2CSetBits = ATIMach64DAC_GENSetBits; + pATII2C->I2CGetBits = ATIMach64DAC_GENGetBits; + pATII2C->SCLDir = DAC_GIO_DIR_1; + pATII2C->SCLGet = pATII2C->SCLSet = DAC_GIO_STATE_1; + pATII2C->SDADir = GEN_GIO2_WRITE; + pATII2C->SDAGet = GEN_GIO2_DATA_IN; + pATII2C->SDASet = GEN_GIO2_DATA_OUT; + + (void)ATITVAddOnProbe(pScreenInfo, pATI, pI2CBus); + break; + } +} diff --git a/src/atimach64i2c.h b/src/atimach64i2c.h new file mode 100644 index 0000000..aa05af9 --- /dev/null +++ b/src/atimach64i2c.h @@ -0,0 +1,34 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64i2c.h,v 1.1 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMACH64I2C_H___ +#define ___ATIMACH64I2C_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern void ATIMach64I2CPreInit FunctionPrototype((ScrnInfoPtr, ATIPtr)); + +#endif /* ___ATIMACH64I2C_H___ */ diff --git a/src/atimach64io.c b/src/atimach64io.c new file mode 100644 index 0000000..5628ce7 --- /dev/null +++ b/src/atimach64io.c @@ -0,0 +1,100 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64io.c,v 1.6 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atichip.h" +#include "atimach64io.h" + +/* + * ATIMach64AccessPLLReg -- + * + * This function sets up the addressing required to access, for read or write, + * a 264xT's PLL registers. + */ +void +ATIMach64AccessPLLReg +( + ATIPtr pATI, + const CARD8 Index, + const Bool Write +) +{ + CARD8 clock_cntl1 = in8(CLOCK_CNTL + 1) & + ~GetByte(PLL_WR_EN | PLL_ADDR, 1); + + /* Set PLL register to be read or written */ + out8(CLOCK_CNTL + 1, clock_cntl1 | + GetByte(SetBits(Index, PLL_ADDR) | SetBits(Write, PLL_WR_EN), 1)); +} + +/* + * ATIMach64PollEngineStatus -- + * + * This function refreshes the driver's view of the draw engine's status. This + * has been moved into a separate compilation unit to prevent inlining. + */ +void +ATIMach64PollEngineStatus +( + ATIPtr pATI +) +{ + CARD32 IOValue; + int Count; + + if (pATI->Chip < ATI_CHIP_264VTB) + { + /* + * TODO: Deal with locked engines. + */ + IOValue = inm(FIFO_STAT); + pATI->EngineIsLocked = GetBits(IOValue, FIFO_ERR); + + /* + * The following counts the number of bits in FIFO_STAT_BITS, and is + * derived from miSetVisualTypes() (formerly cfbSetVisualTypes()). + */ + IOValue = GetBits(IOValue, FIFO_STAT_BITS); + Count = (IOValue >> 1) & 0x36DBU; + Count = IOValue - Count - ((Count >> 1) & 0x36DBU); + Count = ((Count + (Count >> 3)) & 0x71C7U) % 0x3FU; + Count = pATI->nFIFOEntries - Count; + if (Count > pATI->nAvailableFIFOEntries) + pATI->nAvailableFIFOEntries = Count; + + /* + * If the command FIFO is non-empty, then the engine isn't idle. + */ + if (pATI->nAvailableFIFOEntries < pATI->nFIFOEntries) + { + pATI->EngineIsBusy = TRUE; + return; + } + } + + IOValue = inm(GUI_STAT); + pATI->EngineIsBusy = GetBits(IOValue, GUI_ACTIVE); + Count = GetBits(IOValue, GUI_FIFO); + if (Count > pATI->nAvailableFIFOEntries) + pATI->nAvailableFIFOEntries = Count; +} diff --git a/src/atimach64io.h b/src/atimach64io.h new file mode 100644 index 0000000..a1c07b8 --- /dev/null +++ b/src/atimach64io.h @@ -0,0 +1,304 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64io.h,v 1.15 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMACH64IO_H___ + +#if !defined(___ATI_H___) && defined(XFree86Module) +# error Missing #include "ati.h" before #include "atimach64io.h" +# undef XFree86Module +#endif + +#define ___ATIMACH64IO_H___ 1 + +#include "atiio.h" +#include "atistruct.h" + +/* + * A few important notes on some of the I/O statements provided: + * + * inl/outl 32-bit R/W through PIO space. The register is specified as the + * actual PIO address. These are actually defined in compiler.h. + * + * inw/outw 16-bit counterparts to inl/outl. Not used for Mach64 support. + * + * inb/outb 8-bit counterparts to inl/outl. + * + * inm/outm 32-bit R/W through MMIO space. The register is specified as + * the actual MMIO offset (with Block 1 following Block 0), which, + * in this case, is equivalent to the register's IOPortTag from + * atiregs.h. Can be used for those few non-FIFO'ed registers + * outside of Block 0's first 256 bytes. inm() can also be used + * for FIFO'ed registers if, and only if, it can be guaranteed to + * not have been previously FIFO'ed (e.g. when the engine is + * idle). pATI->pBlock array elements must have been previously + * set up by ATIMapApertures(). + * + * outf 32-bit write through MMIO cache. Identical to outm() but + * intended for FIFO'ed registers. There is no inf() provided. + * + * inr/outr 32-bit R/W through PIO or MMIO. Which one depends on the + * machine architecture. The register is specified as a IOPortTag + * from atiregs.h. Can only be used for registers in the first + * 256 bytes of MMIO space (in Block 0). Note that all of these + * registers are non-FIFO'ed. + * + * in8/out8 8-bit counterparts to inr/outr. + * + * For portability reasons, inr/outr/in8/out8 should be used in preference to + * inl/outl/inb/outb to/from any register space starting with CRTC_H_TOTAL_DISP + * but before DST_OFF_PITCH (in the order defined by atiregs.h). None of + * inm/outm/outf should ever be used for these registers. + * + * outf()'s should be grouped together as much as possible, while respecting + * any ordering constraints the engine might impose. Groups larger than 16 + * outf()'s should be split up into two or more groups as needed (but not + * necessarily wanted). The outf() groups that result should be immediately + * preceeded by an ATIMach64WaitForFIFO(n) call, where "n" is the number of + * outf()'s in the group with the exception that groups containing a single + * outf() should not be thus preceeded. This means "n" should not be less than + * 2, nor larger than 16. + */ + +/* + * Cave canem (or it WILL bite you): All Mach64 non-VGA registers are + * ================================ little-endian, no matter how they are + * accessed (nor by what). + */ + +#define inm(_Register) \ + MMIO_IN32(pATI->pBlock[GetBits(_Register, BLOCK_SELECT)], \ + (_Register) & MM_IO_SELECT) +#define outm(_Register, _Value) \ + MMIO_OUT32(pATI->pBlock[GetBits(_Register, BLOCK_SELECT)], \ + (_Register) & MM_IO_SELECT, _Value) + +#ifdef AVOID_CPIO + +# define inr(_Register) \ + MMIO_IN32(pATI->pBlock[0], (_Register) & MM_IO_SELECT) +# define outr(_Register, _Value) \ + MMIO_OUT32(pATI->pBlock[0], (_Register) & MM_IO_SELECT, _Value) + +# define in8(_Register) \ + MMIO_IN8(pATI->pBlock[0], \ + (_Register) & (MM_IO_SELECT | IO_BYTE_SELECT)) +# define out8(_Register, _Value) \ + MMIO_OUT8(pATI->pBlock[0], \ + (_Register) & (MM_IO_SELECT | IO_BYTE_SELECT), _Value) + +/* Cause a cpp syntax error if any of these are used */ +#undef inb +#undef inw +#undef inl +#undef outb +#undef outw +#undef outl + +#define inb() /* Nothing */ +#define inw() /* Nothing */ +#define inl() /* Nothing */ +#define outb() /* Nothing */ +#define outw() /* Nothing */ +#define outl() /* Nothing */ + +#else /* AVOID_CPIO */ + +# define ATIIOPort(_PortTag) \ + (((pATI->CPIODecoding == SPARSE_IO) ? \ + ((_PortTag) & (SPARSE_IO_SELECT | IO_BYTE_SELECT)) : \ + ((_PortTag) & (BLOCK_IO_SELECT | IO_BYTE_SELECT))) | \ + pATI->CPIOBase) + +# define inr(_Register) \ + inl(ATIIOPort(_Register)) +# define outr(_Register, _Value) \ + outl(ATIIOPort(_Register), _Value) + +# define in8(_Register) \ + inb(ATIIOPort(_Register)) +# define out8(_Register, _Value) \ + outb(ATIIOPort(_Register), _Value) + +#endif /* AVOID_CPIO */ + +extern void ATIMach64PollEngineStatus FunctionPrototype((ATIPtr)); + +/* + * MMIO cache definitions. + * + * Many FIFO'ed registers can be cached by the driver. Registers that qualify + * for caching must not contain values that can change without driver + * intervention. Thus registers that contain hardware counters, strobe lines, + * etc., cannot be cached. This caching is intended to minimise FIFO use. + * There is therefore not much point to enable it for non-FIFO'ed registers. + * + * The cache for a particular 32-bit register is enabled by coding a + * CacheRegister() line for that register in the ATIMach64Set() function. The + * integrity of the cache for a particular register should be verified by the + * ATIMach64Sync() function. This code should be kept in register order, as + * defined in atiregs.h. + */ +#define CacheByte(___Register) pATI->MMIOCached[CacheSlotOf(___Register) >> 3] +#define CacheBit(___Register) (0x80U >> (CacheSlotOf(___Register) & 0x07U)) + +#define RegisterIsCached(__Register) \ + (CacheByte(__Register) & CacheBit(__Register)) +#define CacheSlot(__Register) pATI->MMIOCache[CacheSlotOf(__Register)] + +#define CacheRegister(__Register) \ + CacheByte(__Register) |= CacheBit(__Register) +#define UncacheRegister(__Register) \ + CacheByte(__Register) &= ~CacheBit(__Register) + +/* This would be quite a bit slower as a function */ +#define outf(_Register, _Value) \ + do \ + { \ + CARD32 _IOValue = (_Value); \ + \ + if (!RegisterIsCached(_Register) || \ + (_IOValue != CacheSlot(_Register))) \ + { \ + while (!pATI->nAvailableFIFOEntries--) \ + ATIMach64PollEngineStatus(pATI); \ + MMIO_OUT32(pATI->pBlock[GetBits(_Register, BLOCK_SELECT)], \ + (_Register) & MM_IO_SELECT, _IOValue); \ + CacheSlot(_Register) = _IOValue; \ + pATI->EngineIsBusy = TRUE; \ + } \ + } while (0) + +/* + * This is no longer as critical, especially for _n == 1. However, + * there is still a need to ensure _n <= pATI->nFIFOEntries. + */ +#define ATIMach64WaitForFIFO(_pATI, _n) \ + while ((_pATI)->nAvailableFIFOEntries < (_n)) \ + ATIMach64PollEngineStatus(_pATI) + +#define ATIMach64WaitForIdle(_pATI) \ + while ((_pATI)->EngineIsBusy) \ + ATIMach64PollEngineStatus(_pATI) + +/* + * An outf() variant to write two registers such that the second register is + * is always written whenever either is to be changed. + */ +#define outq(_Register1, _Register2, _Value1, _Value2) \ + do \ + { \ + CARD32 _IOValue1 = (_Value1), \ + _IOValue2 = (_Value2); \ + \ + if (!RegisterIsCached(_Register1) || \ + (_IOValue1 != CacheSlot(_Register1))) \ + { \ + ATIMach64WaitForFIFO(pATI, 2); \ + pATI->nAvailableFIFOEntries -= 2; \ + MMIO_OUT32(pATI->pBlock[GetBits(_Register1, BLOCK_SELECT)], \ + (_Register1) & MM_IO_SELECT, _IOValue1); \ + MMIO_OUT32(pATI->pBlock[GetBits(_Register2, BLOCK_SELECT)], \ + (_Register2) & MM_IO_SELECT, _IOValue2); \ + CacheSlot(_Register1) = _IOValue1; \ + CacheSlot(_Register2) = _IOValue2; \ + pATI->EngineIsBusy = TRUE; \ + } \ + else if (!RegisterIsCached(_Register2) || \ + (_IOValue2 != CacheSlot(_Register2))) \ + { \ + while (!pATI->nAvailableFIFOEntries--) \ + ATIMach64PollEngineStatus(pATI); \ + MMIO_OUT32(pATI->pBlock[GetBits(_Register2, BLOCK_SELECT)], \ + (_Register2) & MM_IO_SELECT, _IOValue2); \ + CacheSlot(_Register2) = _IOValue2; \ + pATI->EngineIsBusy = TRUE; \ + } \ + } while (0) + +extern void ATIMach64AccessPLLReg FunctionPrototype((ATIPtr, const CARD8, + const Bool)); + +#define ATIMach64GetPLLReg(_Index) \ + ( \ + ATIMach64AccessPLLReg(pATI, _Index, FALSE), \ + in8(CLOCK_CNTL + 2) \ + ) +#define ATIMach64PutPLLReg(_Index, _Value) \ + do \ + { \ + ATIMach64AccessPLLReg(pATI, _Index, TRUE); \ + out8(CLOCK_CNTL + 2, _Value); \ + } while (0) + +#define ATIMach64GetLCDReg(_Index) \ + ( \ + out8(LCD_INDEX, SetBits(_Index, LCD_REG_INDEX)), \ + inr(LCD_DATA) \ + ) +#define ATIMach64PutLCDReg(_Index, _Value) \ + do \ + { \ + out8(LCD_INDEX, SetBits(_Index, LCD_REG_INDEX)); \ + outr(LCD_DATA, _Value); \ + } while (0) + +#define ATIMach64GetTVReg(_Index) \ + ( \ + out8(TV_OUT_INDEX, SetBits(_Index, TV_REG_INDEX)), \ + inr(TV_OUT_DATA) \ + ) +#define ATIMach64PutTVReg(_Index, _Value) \ + do \ + { \ + out8(TV_OUT_INDEX, SetBits(_Index, TV_REG_INDEX)); \ + outr(TV_OUT_DATA, _Value); \ + } while (0) + +/* + * Block transfer definitions. + */ + +#if defined(GCCUSESGAS) && \ + (defined(i386) || defined(__i386) || defined(__i386__)) + +#define ATIMove32(_pDst, _pSrc, _nCount) \ + do \ + { \ + long d0, d1, d2; \ + __asm__ __volatile__ \ + ( \ + "cld\n\t" \ + "rep ; movsl" \ + : "=&c" (d0), \ + "=&D" (d1), \ + "=&S" (d2) \ + : "0" (_nCount), \ + "1" (_pDst), \ + "2" (_pSrc) \ + : "memory" \ + ); \ + } while (0) + +#endif + +#endif /* ___ATIMACH64IO_H___ */ diff --git a/src/atimach64xv.c b/src/atimach64xv.c new file mode 100644 index 0000000..2923134 --- /dev/null +++ b/src/atimach64xv.c @@ -0,0 +1,1493 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64xv.c,v 1.7 2003/11/10 18:22:18 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiaccel.h" +#include "atichip.h" +#include "atimach64accel.h" +#include "atimach64io.h" +#include "atimach64xv.h" + +#include "Xv.h" +#include "fourcc.h" + +#define MAKE_ATOM(string) MakeAtom(string, strlen(string), TRUE) +#define MaxScale (CARD32)(CARD16)(-1) + +static unsigned long ATIMach64XVAtomGeneration = (unsigned long)(-1); + +static XF86VideoEncodingRec ATIMach64VideoEncoding_A[] = +{ + { 0, "XV_IMAGE", 384, 2048, {1, 1} } +}; +#define nATIMach64VideoEncoding_A NumberOf(ATIMach64VideoEncoding_A) + +static XF86VideoEncodingRec ATIMach64VideoEncoding_B[] = +{ + { 0, "XV_IMAGE", 720, 2048, {1, 1} } +}; +#define nATIMach64VideoEncoding_B NumberOf(ATIMach64VideoEncoding_B) + +/* nATIMach64VideoEncoding_[AB] should be equal */ +#define nATIMach64VideoEncoding nATIMach64VideoEncoding_A + +static XF86VideoFormatRec ATIMach64VideoFormat[] = +{ + { 8, TrueColor}, + { 8, DirectColor}, + { 8, PseudoColor}, + { 8, GrayScale}, + { 8, StaticGray}, + { 8, StaticColor}, + {15, TrueColor}, + {16, TrueColor}, + {24, TrueColor}, + {15, DirectColor}, + {16, DirectColor}, + {24, DirectColor} +}; +#define nATIMach64VideoFormat NumberOf(ATIMach64VideoFormat) + +static XF86AttributeRec ATIMach64Attribute[] = +{ + /* These are only supported on the Rage Pro and later ... */ + { + XvSettable | XvGettable, + -1000, 1000, + "XV_SATURATION" + }, + { + XvSettable | XvGettable, + -1000, 1000, + "XV_BRIGHTNESS" + }, + { + XvSettable | XvGettable, + -1000, 1000, + "XV_COLOUR" + }, + { + XvSettable | XvGettable, + -1000, 1000, + "XV_COLOR" + }, + + /* Local attributes, odds and ends for compatibility, etc... */ + { + XvSettable | XvGettable, + 0, 1, + "XV_AUTOPAINT_COLOURKEY" + }, + { + XvSettable | XvGettable, + 0, 1, + "XV_AUTOPAINT_COLORKEY" + }, + { + XvSettable | XvGettable, + 0, (1 << 24) - 1, + "XV_COLOURKEY" + }, + { + XvSettable | XvGettable, + 0, (1 << 24) - 1, + "XV_COLORKEY" + }, + { + XvSettable | XvGettable, + 0, (1 << 24) - 1, + "XV_COLOURKEY_MASK" + }, + { + XvSettable | XvGettable, + 0, (1 << 24) - 1, + "XV_COLORKEY_MASK" + }, + { + XvSettable, + 0, 0, + "XV_SET_DEFAULTS" + }, + { /* Keep last */ + XvSettable | XvGettable, + 0, 1, + "XV_DOUBLE_BUFFER" + } +}; +#define nATIMach64Attribute NumberOf(ATIMach64Attribute) + +static XF86ImageRec ATIMach64Image[] = +{ + XVIMAGE_YUY2, + XVIMAGE_UYVY, + XVIMAGE_YV12, + XVIMAGE_I420 +}; +#define nATIMach64Image NumberOf(ATIMach64Image) + +/* A local XVideo adaptor attribute record */ +typedef struct _ATIMach64Attribute +{ + Atom AttributeID; + INT32 MaxValue; /* ... for the hardware */ + void (*SetAttribute) NestedPrototype((ATIPtr, INT32)); + INT32 (*GetAttribute) NestedPrototype((ATIPtr)); +} ATIMach64AttributeRec, *ATIMach64AttributePtr; + +/* Functions to get/set XVideo adaptor attributes */ + +static void +ATIMach64SetSaturationAttribute +( + ATIPtr pATI, + INT32 Value +) +{ + /* Set the register */ + pATI->NewHW.scaler_colour_cntl &= + ~(SCALE_SATURATION_U | SCALE_SATURATION_V); + pATI->NewHW.scaler_colour_cntl |= SetBits(Value, SCALE_SATURATION_U) | + SetBits(Value, SCALE_SATURATION_V); + outf(SCALER_COLOUR_CNTL, pATI->NewHW.scaler_colour_cntl); +} + +static INT32 +ATIMach64GetSaturationAttribute +( + ATIPtr pATI +) +{ + return (INT32)GetBits(pATI->NewHW.scaler_colour_cntl, SCALE_SATURATION_U); +} + +static void +ATIMach64SetBrightnessAttribute +( + ATIPtr pATI, + INT32 Value +) +{ + /* Set the register */ + pATI->NewHW.scaler_colour_cntl &= ~SCALE_BRIGHTNESS; + pATI->NewHW.scaler_colour_cntl |= SetBits(Value, SCALE_BRIGHTNESS); + outf(SCALER_COLOUR_CNTL, pATI->NewHW.scaler_colour_cntl); +} + +static INT32 +ATIMach64GetBrightnessAttribute +( + ATIPtr pATI +) +{ + return (INT32)GetBits(pATI->NewHW.scaler_colour_cntl, SCALE_BRIGHTNESS); +} + +static void +ATIMach64SetDoubleBufferAttribute +( + ATIPtr pATI, + INT32 Value +) +{ + pATI->DoubleBuffer = Value; +} + +static INT32 +ATIMach64GetDoubleBufferAttribute +( + ATIPtr pATI +) +{ + return (int)pATI->DoubleBuffer; +} + +static void +ATIMach64SetAutoPaintAttribute +( + ATIPtr pATI, + INT32 Value +) +{ + pATI->AutoPaint = Value; +} + +static INT32 +ATIMach64GetAutoPaintAttribute +( + ATIPtr pATI +) +{ + return (int)pATI->AutoPaint; +} + +static void +ATIMach64SetColourKeyAttribute +( + ATIPtr pATI, + INT32 Value +) +{ + pATI->NewHW.overlay_graphics_key_clr = + (CARD32)(Value & ((1 << pATI->depth) - 1)); + outf(OVERLAY_GRAPHICS_KEY_CLR, pATI->NewHW.overlay_graphics_key_clr); +} + +static INT32 +ATIMach64GetColourKeyAttribute +( + ATIPtr pATI +) +{ + return (INT32)pATI->NewHW.overlay_graphics_key_clr; +} + +static void +ATIMach64SetColourKeyMaskAttribute +( + ATIPtr pATI, + INT32 Value +) +{ + pATI->NewHW.overlay_graphics_key_msk = + (CARD32)(Value & ((1 << pATI->depth) - 1)); + outf(OVERLAY_GRAPHICS_KEY_MSK, pATI->NewHW.overlay_graphics_key_msk); +} + +static INT32 +ATIMach64GetColourKeyMaskAttribute +( + ATIPtr pATI +) +{ + return (INT32)pATI->NewHW.overlay_graphics_key_msk; +} + +/* + * ATIMach64SetDefaultAttributes -- + * + * This function calls other functions to set default values for the various + * attributes of an XVideo port. + */ +static void +ATIMach64SetDefaultAttributes +( + ATIPtr pATI, + INT32 Value +) +{ + ATIMach64SetAutoPaintAttribute(pATI, TRUE); + ATIMach64SetDoubleBufferAttribute(pATI, FALSE); + ATIMach64SetColourKeyMaskAttribute(pATI, (1 << pATI->depth) - 1); + ATIMach64SetColourKeyAttribute(pATI, (3 << ((2 * pATI->depth) / 3)) | + (2 << ((1 * pATI->depth) / 3)) | + (1 << ((0 * pATI->depth) / 3))); + + if (pATI->Chip < ATI_CHIP_264GTPRO) + return; + + ATIMach64SetBrightnessAttribute(pATI, 32); + ATIMach64SetSaturationAttribute(pATI, 16); +} + +/* + * There is a one-to-one correspondance between elements of the following array + * and those of ATIMach64Attribute. + */ +static ATIMach64AttributeRec ATIMach64AttributeInfo[nATIMach64Attribute] = +{ + { /* SATURATION */ + 0, 23, + ATIMach64SetSaturationAttribute, + ATIMach64GetSaturationAttribute + }, + { /* BRIGHTNESS */ + 0, 63, + ATIMach64SetBrightnessAttribute, + ATIMach64GetBrightnessAttribute + }, + { /* COLOUR */ + 0, 23, + ATIMach64SetSaturationAttribute, + ATIMach64GetSaturationAttribute + }, + { /* COLOR */ + 0, 23, + ATIMach64SetSaturationAttribute, + ATIMach64GetSaturationAttribute + }, + { /* AUTOPAINT_COLOURKEY */ + 0, 1, + ATIMach64SetAutoPaintAttribute, + ATIMach64GetAutoPaintAttribute + }, + { /* AUTOPAINT_COLORKEY */ + 0, 1, + ATIMach64SetAutoPaintAttribute, + ATIMach64GetAutoPaintAttribute + }, + { /* COLOURKEY */ + 0, (1 << 24) - 1, + ATIMach64SetColourKeyAttribute, + ATIMach64GetColourKeyAttribute + }, + { /* COLORKEY */ + 0, (1 << 24) - 1, + ATIMach64SetColourKeyAttribute, + ATIMach64GetColourKeyAttribute + }, + { /* COLOURKEY_MASK */ + 0, (1 << 24) - 1, + ATIMach64SetColourKeyMaskAttribute, + ATIMach64GetColourKeyMaskAttribute + }, + { /* COLORKEY_MASK */ + 0, (1 << 24) - 1, + ATIMach64SetColourKeyMaskAttribute, + ATIMach64GetColourKeyMaskAttribute + }, + { /* SET_DEFAULTS */ + 0, 0, + ATIMach64SetDefaultAttributes, + NULL + }, + { /* DOUBLE_BUFFER */ + 0, 1, + ATIMach64SetDoubleBufferAttribute, + ATIMach64GetDoubleBufferAttribute + } +}; + +/* + * ATIMach64FindAttribute -- + * + * This function is called to locate an Xv attribute's table entry. + */ +static int +ATIMach64FindPortAttribute +( + ATIPtr pATI, + Atom AttributeID +) +{ + int iAttribute; + + if (pATI->Chip < ATI_CHIP_264GTPRO) + iAttribute = 4; + else + iAttribute = 0; + + for (; iAttribute < nATIMach64Attribute; iAttribute++) + if (AttributeID == ATIMach64AttributeInfo[iAttribute].AttributeID) + return iAttribute; + + return -1; +} + +/* + * ATIMach64SetPortAttribute -- + * + * This function sets the value of a particular port's attribute. + */ +static int +ATIMach64SetPortAttribute +( + ScrnInfoPtr pScreenInfo, + Atom AttributeID, + INT32 Value, + pointer pATI +) +{ + INT32 Range; + int iAttribute; + + if (((iAttribute = ATIMach64FindPortAttribute(pATI, AttributeID)) < 0) || + !ATIMach64AttributeInfo[iAttribute].SetAttribute) + return BadMatch; + + Range = ATIMach64Attribute[iAttribute].max_value - + ATIMach64Attribute[iAttribute].min_value; + + if (Range >= 0) + { + /* Limit and scale the value */ + Value -= ATIMach64Attribute[iAttribute].min_value; + + if (Value < 0) + Value = 0; + else if (Value > Range) + Value = Range; + + if (Range != ATIMach64AttributeInfo[iAttribute].MaxValue) + { + if (ATIMach64AttributeInfo[iAttribute].MaxValue > 0) + Value *= ATIMach64AttributeInfo[iAttribute].MaxValue; + if (Range > 0) + Value /= Range; + } + } + + (*ATIMach64AttributeInfo[iAttribute].SetAttribute)(pATI, Value); + + return Success; +} + +/* + * ATIMach64SetPortAttribute -- + * + * This function retrieves the value of a particular port's attribute. + */ +static int +ATIMach64GetPortAttribute +( + ScrnInfoPtr pScreenInfo, + Atom AttributeID, + INT32 *Value, + pointer pATI +) +{ + INT32 Range; + int iAttribute; + + if (!Value || + ((iAttribute = ATIMach64FindPortAttribute(pATI, AttributeID)) < 0) || + !ATIMach64AttributeInfo[iAttribute].GetAttribute) + return BadMatch; + + *Value = (*ATIMach64AttributeInfo[iAttribute].GetAttribute)(pATI); + + Range = ATIMach64Attribute[iAttribute].max_value - + ATIMach64Attribute[iAttribute].min_value; + + if (Range >= 0) + { + if (Range != ATIMach64AttributeInfo[iAttribute].MaxValue) + { + /* (Un-)scale the value */ + if (Range > 0) + *Value *= Range; + if (ATIMach64AttributeInfo[iAttribute].MaxValue > 0) + *Value /= ATIMach64AttributeInfo[iAttribute].MaxValue; + } + + *Value += ATIMach64Attribute[iAttribute].min_value; + } + + return Success; +} + +/* + * ATIMach64RemoveLinearCallback -- + * + * This is called by the framebuffer manager to release the offscreen XVideo + * buffer after the video has been temporarily disabled due to its window being + * iconified or completely occluded. + */ +static void +ATIMach64RemoveLinearCallback +( + FBLinearPtr pLinear +) +{ + ATIPtr pATI = ATIPTR(xf86Screens[pLinear->pScreen->myNum]); + + pATI->pXVBuffer = NULL; + outf(OVERLAY_SCALE_CNTL, SCALE_EN); +} + +/* + * ATIMach64StopVideo -- + * + * This is called to stop displaying a video. Note that, to prevent jittering + * this doesn't actually turn off the overlay unless 'Cleanup' is TRUE, i.e. + * when the video is to be actually stopped rather than temporarily disabled. + */ +static void +ATIMach64StopVideo +( + ScrnInfoPtr pScreenInfo, + pointer Data, + Bool Cleanup +) +{ + ScreenPtr pScreen = pScreenInfo->pScreen; + ATIPtr pATI = Data; + + if (pATI->ActiveSurface) + return; + + REGION_EMPTY(pScreen, &pATI->VideoClip); + + if (!Cleanup) + { + /* + * Free offscreen buffer if/when its allocation is needed by XAA's + * pixmap cache. + */ + if (pATI->pXVBuffer) + pATI->pXVBuffer->RemoveLinearCallback = + ATIMach64RemoveLinearCallback; + return; + } + + pATI->pXVBuffer = ATIResizeOffscreenLinear(pScreen, pATI->pXVBuffer, 0); + outf(OVERLAY_SCALE_CNTL, SCALE_EN); +} + +/* + * ATIMach64QueryBestSize -- + * + * Quoting XVideo docs: + * + * This function provides the client with a way to query what the destination + * dimensions would end up being if they were to request that an area + * VideoWidth by VideoHeight from the video stream be scaled to rectangle of + * DrawableWidth by DrawableHeight on the screen. Since it is not expected + * that all hardware will be able to get the target dimensions exactly, it is + * important that the driver provide this function. + */ +static void +ATIMach64QueryBestSize +( + ScrnInfoPtr pScreenInfo, + Bool Motion, + short VideoWidth, + short VideoHeight, + short DrawableWidth, + short DrawableHeight, + unsigned int *Width, + unsigned int *Height, + pointer pATI +) +{ + *Width = DrawableWidth; + *Height = DrawableHeight; +} + +/* + * ATIMach64QueryImageAttributes -- + * + * Quoting XVideo docs: + * + * This function is called to let the driver specify how data for a particular + * image of size Width by Height should be stored. Sometimes only the size and + * corrected width and height are needed. In that case pitches and offsets are + * NULL. The size of the memory required for the image is returned by this + * function. The width and height of the requested image can be altered by the + * driver to reflect format limitations (such as component sampling periods + * that are larger than one). If pPitch and pOffset are not NULL, these will + * be arrays with as many elements in them as there are planes in the image + * format. The driver should specify the pitch (in bytes) of each scanline in + * the particular plane as well as the offset to that plane (in bytes) from the + * beginning of the image. + */ +static int +ATIMach64QueryImageAttributes +( + ScrnInfoPtr pScreenInfo, + int ImageID, + unsigned short *Width, + unsigned short *Height, + int *pPitch, + int *pOffset +) +{ + int Size, tmp; + + if (!Width || !Height) + return 0; + + if (*Width > 2048) + *Width = 2048; + else + *Width = (*Width + 1) & ~1; + + if (*Height > 2048) + *Height = 2048; + + if (pOffset) + pOffset[0] = 0; + + switch (ImageID) + { + case FOURCC_YV12: + case FOURCC_I420: + *Height = (*Height + 1) & ~1; + Size = (*Width + 3) & ~3; + if (pPitch) + pPitch[0] = Size; + Size *= *Height; + if (pOffset) + pOffset[1] = Size; + tmp = ((*Width >> 1) + 3) & ~3; + if (pPitch) + pPitch[1] = pPitch[2] = tmp; + tmp *= (*Height >> 1); + Size += tmp; + if (pOffset) + pOffset[2] = Size; + Size += tmp; + break; + + case FOURCC_UYVY: + case FOURCC_YUY2: + Size = *Width << 1; + if (pPitch) + pPitch[0] = Size; + Size *= *Height; + break; + + default: + Size = 0; + break; + } + + return Size; +} + +/* + * ATIMach64ScaleVideo -- + * + * This function is called to calculate overlay scaling factors. + */ +static void +ATIMach64ScaleVideo +( + ATIPtr pATI, + DisplayModePtr pMode, + int SrcW, + int SrcH, + int DstW, + int DstH, + CARD32 *pHScale, + CARD32 *pVScale +) +{ + int Shift; + + *pHScale = ATIDivide(SrcW, DstW, + GetBits(pATI->NewHW.pll_vclk_cntl, PLL_ECP_DIV) + 12, 0); + + Shift = 12; + if (pMode->Flags & V_INTERLACE) + Shift++; + + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) + { + if (pMode->VDisplay < pATI->LCDVertical) + { + SrcH *= pMode->VDisplay; + DstH *= pATI->LCDVertical; + } + } + else + { + if (pMode->Flags & V_DBLSCAN) + Shift--; + if (pMode->VScan > 1) + DstH *= pMode->VScan; + } + + *pVScale = ATIDivide(SrcH, DstH, Shift, 0); +} + +/* + * ATIMach64ClipVideo -- + * + * Clip the video (both source and destination) and make various other + * adjustments. + */ +static Bool +ATIMach64ClipVideo +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + int ImageID, + short SrcX, + short SrcY, + short SrcW, + short SrcH, + short DstX, + short DstY, + short *DstW, + short *DstH, + short Width, + short Height, + RegionPtr pClip, + BoxPtr pDstBox, + INT32 *SrcX1, + INT32 *SrcX2, + INT32 *SrcY1, + INT32 *SrcY2, + int *SrcLeft, + int *SrcTop +) +{ + CARD32 HScale, VScale; + + /* Check hardware limits */ + if ((Height <= 0) || (Height > 2048) || (Width <= 0) || (Width > 720) || + ((Width > 384) && (pATI->Chip < ATI_CHIP_264VTB))) + return FALSE; + + ATIMach64ScaleVideo(pATI, pScreenInfo->currentMode, + SrcW, SrcH, *DstW, *DstH, &HScale, &VScale); + if (!HScale || !VScale) + return FALSE; + if (HScale > MaxScale) + *DstW = (*DstW * HScale) / MaxScale; + if (VScale > MaxScale) + *DstH = (*DstH * HScale) / MaxScale; + + /* Clip both the source and the destination */ + *SrcX1 = SrcX; + *SrcX2 = SrcX + SrcW; + *SrcY1 = SrcY; + *SrcY2 = SrcY + SrcH; + + pDstBox->x1 = DstX; + pDstBox->x2 = DstX + *DstW; + pDstBox->y1 = DstY; + pDstBox->y2 = DstY + *DstH; + + if (!xf86XVClipVideoHelper(pDstBox, SrcX1, SrcX2, SrcY1, SrcY2, + pClip, Width, Height)) + return FALSE; + + /* + * Reset overlay scaler origin. This prevents jittering during + * viewport panning or while the video is being moved or gradually + * obscured/unobscured. + */ + pDstBox->x1 = DstX; + pDstBox->y1 = DstY; + + /* Translate to the current viewport */ + pDstBox->x1 -= pScreenInfo->frameX0; + pDstBox->x2 -= pScreenInfo->frameX0; + pDstBox->y1 -= pScreenInfo->frameY0; + pDstBox->y2 -= pScreenInfo->frameY0; + + *SrcLeft = *SrcTop = 0; + + /* + * If the overlay scaler origin ends up outside the current viewport, move + * it to the viewport's top left corner. This unavoidably causes a slight + * jittering in the image (even with double-buffering). + */ + if (pDstBox->x1 < 0) + { + *SrcLeft = ((-pDstBox->x1 * SrcW) / *DstW) & ~1; + pDstBox->x1 = 0; + } + + if (pDstBox->y1 < 0) + { + *SrcTop = (-pDstBox->y1 * SrcH) / *DstH; + pDstBox->y1 = 0; + + switch (ImageID) + { + case FOURCC_YV12: + case FOURCC_I420: + *SrcTop = (*SrcTop + 1) & ~1; + break; + + default: + break; + } + } + + return TRUE; +} + +#ifdef ATIMove32 + +/* A faster intercept */ +#undef xf86XVCopyPacked +#define xf86XVCopyPacked ATIMach64XVCopyPacked + +static void +ATIMach64XVCopyPacked +( + const CARD8 *pSrc, + CARD8 *pDst, + int SrcPitch, + int DstPitch, + int Height, + int Width +) +{ + Width >>= 1; + while (--Height >= 0) + { + ATIMove32(pDst, pSrc, Width); + pSrc += SrcPitch; + pDst += DstPitch; + } +} + +#endif + +/* + * ATIMach64DisplayVideo -- + * + * This function programmes Mach64 registers needed to display a video. + */ +static void +ATIMach64DisplayVideo +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + BoxPtr pDstBox, + int ImageID, + int Offset, + int Pitch, + short SrcW, + short SrcH, + short DstW, + short DstH, + short Width, + short Height +) +{ + DisplayModePtr pMode = pScreenInfo->currentMode; + CARD32 HScale, VScale; + + if (pMode->VScan > 1) + { + pDstBox->y1 *= pMode->VScan; + pDstBox->y2 *= pMode->VScan; + } + if (pMode->Flags & V_DBLSCAN) + { + pDstBox->y1 <<= 1; + pDstBox->y2 <<= 1; + } + + /* Recalculate overlay scale factors */ + ATIMach64ScaleVideo(pATI, pMode, SrcW, SrcH, DstW, DstH, &HScale, &VScale); + + pATI->NewHW.video_format &= ~SCALER_IN; + if (ImageID == FOURCC_UYVY) + pATI->NewHW.video_format |= SCALER_IN_YVYU422; + else + pATI->NewHW.video_format |= SCALER_IN_VYUY422; + + ATIMach64WaitForFIFO(pATI, 8); + outq(OVERLAY_Y_X_START, OVERLAY_Y_X_END, OVERLAY_LOCK_START | + SetWord(pDstBox->x1, 1) | SetWord(pDstBox->y1, 0), + SetWord(pDstBox->x2 - 1, 1) | SetWord(pDstBox->y2 - 1, 0)); + outf(OVERLAY_SCALE_INC, SetWord(HScale, 1) | SetWord(VScale, 0)); + outf(SCALER_HEIGHT_WIDTH, SetWord(Width, 1) | SetWord(Height, 0)); + outf(VIDEO_FORMAT, pATI->NewHW.video_format); + + if (pATI->Chip < ATI_CHIP_264VTB) + { + outf(BUF0_OFFSET, Offset); + outf(BUF0_PITCH, Pitch); + } + else + { + outf(SCALER_BUF0_OFFSET, Offset); + outf(SCALER_BUF_PITCH, Pitch); + } + + outf(OVERLAY_SCALE_CNTL, SCALE_PIX_EXPAND | OVERLAY_EN | SCALE_EN); +} + +/* + * ATIMach64PutImage -- + * + * This function is called to put a video image on the screen. + */ +static int +ATIMach64PutImage +( + ScrnInfoPtr pScreenInfo, + short SrcX, + short SrcY, + short DstX, + short DstY, + short SrcW, + short SrcH, + short DstW, + short DstH, + int ImageID, + unsigned char *Buffer, + short Width, + short Height, + Bool Synchronise, + RegionPtr pClip, + pointer Data +) +{ + ATIPtr pATI = Data; + ScreenPtr pScreen; + INT32 SrcX1, SrcX2, SrcY1, SrcY2; + BoxRec DstBox; + int SrcPitch, SrcPitchUV, DstPitch, DstSize; + int SrcTop, SrcLeft, DstWidth, DstHeight; + int Top, Bottom, Left, Right, nLine, nPixel, Offset; + int OffsetV, OffsetU; + int tmp; + CARD8 *pDst; + + if (pATI->ActiveSurface) + return Success; + + if (!ATIMach64ClipVideo(pScreenInfo, pATI, ImageID, + SrcX, SrcY, SrcW, SrcH, + DstX, DstY, &DstW, &DstH, + Width, Height, pClip, &DstBox, + &SrcX1, &SrcX2, &SrcY1, &SrcY2, + &SrcLeft, &SrcTop)) + return Success; + + pScreen = pScreenInfo->pScreen; + + DstWidth = Width - SrcLeft; + DstHeight = Height - SrcTop; + + /* + * Allocate an offscreen buffer for the entire source, even though only a + * subset of the source will be copied into it. + */ + DstPitch = /* bytes */ + (DstWidth + DstWidth + 15) & ~15; + DstSize = /* pixels */ + ((DstPitch * DstHeight) + pATI->AdjustDepth - 1) / pATI->AdjustDepth; + + pATI->pXVBuffer = ATIResizeOffscreenLinear(pScreen, pATI->pXVBuffer, + (pATI->DoubleBuffer + 1) * DstSize); + + if (!pATI->pXVBuffer) + { + if (!pATI->DoubleBuffer) + return BadAlloc; + + pATI->pXVBuffer = + ATIResizeOffscreenLinear(pScreen, pATI->pXVBuffer, DstSize); + + if (!pATI->pXVBuffer) + return BadAlloc; + + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Video image double-buffering downgraded to single-buffering\n due" + " to insufficient video memory.\n"); + pATI->DoubleBuffer = pATI->CurrentBuffer = 0; + } + else + { + /* Possibly switch buffers */ + pATI->CurrentBuffer = pATI->DoubleBuffer - pATI->CurrentBuffer; + } + + /* Synchronise video memory accesses */ + ATIMach64Sync(pScreenInfo); + + Offset = (pATI->pXVBuffer->offset * pATI->AdjustDepth) + + (pATI->CurrentBuffer * DstSize * pATI->AdjustDepth); + pDst = pATI->pMemoryLE; + pDst += Offset; + + switch (ImageID) + { + case FOURCC_YV12: + case FOURCC_I420: + Left = (SrcX1 >> 16) & ~1; + Right = ((SrcX2 + 0x1FFFF) >> 16) & ~1; + Top = (SrcY1 >> 16) & ~1; + Bottom = ((SrcY2 + 0x1FFFF) >> 16) & ~1; + + if ((Right < Width) && ((SrcX1 & 0x1FFFF) <= (SrcX2 & 0x1FFFF))) + Right += 2; + if ((Bottom < Height) && ((SrcY1 & 0x1FFFF) <= (SrcY2 & 0x1FFFF))) + Bottom += 2; + + nPixel = Right - Left; + nLine = Bottom - Top; + + SrcPitch = (Width + 3) & ~3; + OffsetV = SrcPitch * Height; + SrcPitchUV = ((Width >> 1) + 3) & ~3; + OffsetU = ((Height >> 1) * SrcPitchUV) + OffsetV; + + tmp = ((Top >> 1) * SrcPitchUV) + (Left >> 1); + OffsetV += tmp; + OffsetU += tmp; + + if (ImageID == FOURCC_I420) + { + tmp = OffsetV; + OffsetV = OffsetU; + OffsetU = tmp; + } + + pDst += ((Top - SrcTop) * DstPitch) + ((Left - SrcLeft) << 1); + + xf86XVCopyYUV12ToPacked(Buffer + (Top * SrcPitch) + Left, + Buffer + OffsetV, Buffer + OffsetU, pDst, SrcPitch, SrcPitchUV, + DstPitch, nLine, nPixel); + break; + + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + Left = (SrcX1 >> 16) & ~1; + Right = ((SrcX2 + 0x1FFFF) >> 16) & ~1; + Top = SrcY1 >> 16; + Bottom = (SrcY2 + 0x0FFFF) >> 16; + + if ((Right < Width) && ((SrcX1 & 0x1FFFF) <= (SrcX2 & 0x1FFFF))) + Right += 2; + if ((Bottom < Height) && ((SrcY1 & 0x0FFFF) <= (SrcY2 & 0x0FFFF))) + Bottom++; + + nPixel = Right - Left; + nLine = Bottom - Top; + + SrcPitch = Width << 1; + Buffer += (Top * SrcPitch) + (Left << 1); + pDst += ((Top - SrcTop) * DstPitch) + ((Left - SrcLeft) << 1); + + xf86XVCopyPacked(Buffer, pDst, SrcPitch, DstPitch, nLine, nPixel); + break; + } + + if (!REGION_EQUAL(pScreen, &pATI->VideoClip, pClip)) + { + REGION_COPY(pScreen, &pATI->VideoClip, pClip); + if (pATI->AutoPaint) + xf86XVFillKeyHelper(pScreen, pATI->NewHW.overlay_graphics_key_clr, + pClip); + } + + ATIMach64DisplayVideo(pScreenInfo, pATI, &DstBox, ImageID, + Offset, DstPitch / 2, SrcW, SrcH, DstW, DstH, DstWidth, DstHeight); + + return Success; +} + +/* + * ATIMach64AllocateSurface -- + * + * This function allocates an offscreen buffer (called a "surface") for use by + * an external driver such as 'v4l'. + */ +static int +ATIMach64AllocateSurface +( + ScrnInfoPtr pScreenInfo, + int ImageID, + unsigned short Width, + unsigned short Height, + XF86SurfacePtr pSurface +) +{ + ScreenPtr pScreen; + ATIPtr pATI = ATIPTR(pScreenInfo); + + if (pATI->ActiveSurface) + return BadAlloc; + + if ((Height <= 0) || (Height > 2048) || (Width <= 0) || (Width > 720) || + ((Width > 384) && (pATI->Chip < ATI_CHIP_264VTB))) + return BadValue; + + Width = (Width + 1) & ~1; + pATI->SurfacePitch = ((Width << 1) + 15) & ~15; + + pScreen = pScreenInfo->pScreen; + + pATI->pXVBuffer = ATIResizeOffscreenLinear(pScreen, pATI->pXVBuffer, + ((Height * pATI->SurfacePitch) + pATI->AdjustDepth - 1) / + pATI->AdjustDepth); + if (!pATI->pXVBuffer) + return BadAlloc; + + pATI->SurfaceOffset = pATI->pXVBuffer->offset * pATI->AdjustDepth; + + pSurface->pScrn = pScreenInfo; + pSurface->id = ImageID; + pSurface->width = Width; + pSurface->height = Height; + pSurface->pitches = &pATI->SurfacePitch; + pSurface->offsets = &pATI->SurfaceOffset; + pSurface->devPrivate.ptr = pATI; + + /* Stop the video */ + outf(OVERLAY_SCALE_CNTL, SCALE_EN); + REGION_EMPTY(pScreen, &pATI->VideoClip); + pATI->ActiveSurface = TRUE; + + return Success; +} + +/* + * ATIMach64FreeSurface -- + * + * This function called to free a surface's offscreen buffer. + */ +static int +ATIMach64FreeSurface +( + XF86SurfacePtr pSurface +) +{ + ATIPtr pATI = pSurface->devPrivate.ptr; + + if (!pATI->ActiveSurface) + return Success; + + outf(OVERLAY_SCALE_CNTL, SCALE_EN); + pATI->pXVBuffer = ATIResizeOffscreenLinear(pSurface->pScrn->pScreen, + pATI->pXVBuffer, 0); + pATI->ActiveSurface = FALSE; + + return Success; +} + +/* + * ATIMach64DisplaySurface -- + * + * This function is called to display a video surface. + */ +static int +ATIMach64DisplaySurface +( + XF86SurfacePtr pSurface, + short SrcX, + short SrcY, + short DstX, + short DstY, + short SrcW, + short SrcH, + short DstW, + short DstH, + RegionPtr pClip +) +{ + ATIPtr pATI = pSurface->devPrivate.ptr; + ScrnInfoPtr pScreenInfo; + int ImageID; + short Width, Height; + BoxRec DstBox; + INT32 SrcX1, SrcX2, SrcY1, SrcY2; + int SrcLeft, SrcTop, SrcPitch, Offset; + + if (!pATI->ActiveSurface) + return Success; + + pScreenInfo = pSurface->pScrn; + ImageID = pSurface->id; + Width = pSurface->width; + Height = pSurface->height; + + if (!ATIMach64ClipVideo(pScreenInfo, pATI, ImageID, + SrcX, SrcY, SrcW, SrcH, + DstX, DstY, &DstW, &DstH, + Width, Height, pClip, &DstBox, + &SrcX1, &SrcX2, &SrcY1, &SrcY2, + &SrcLeft, &SrcTop)) + return Success; + + xf86XVFillKeyHelper(pScreenInfo->pScreen, + pATI->NewHW.overlay_graphics_key_clr, pClip); + + SrcPitch = pSurface->pitches[0]; + Offset = pSurface->offsets[0] + (SrcTop * SrcPitch) + (SrcLeft << 1); + ATIMach64DisplayVideo(pScreenInfo, pATI, &DstBox, ImageID, + Offset, SrcPitch, SrcW, SrcH, DstW, DstH, Width, Height); + + return Success; +} + +/* + * ATIMach64StopSurface -- + * + * This function is called to stop the overlaid display of a video surface. + */ +static int +ATIMach64StopSurface +( + XF86SurfacePtr pSurface +) +{ + ATIPtr pATI = pSurface->devPrivate.ptr; + + if (pATI->ActiveSurface) + outf(OVERLAY_SCALE_CNTL, SCALE_EN); + + return Success; +} + +/* + * ATIMach64GetSurfaceAttribute -- + * + * Retrieve the value of an XVideo attribute. + */ +static int +ATIMach64GetSurfaceAttribute +( + ScrnInfoPtr pScreenInfo, + Atom AttributeID, + INT32 *Value +) +{ + return ATIMach64GetPortAttribute(pScreenInfo, AttributeID, Value, + ATIPTR(pScreenInfo)); +} + +/* + * ATIMach64SetSurfaceAttribute + * + * Set the value of an XVideo attribute. + */ +static int +ATIMach64SetSurfaceAttribute +( + ScrnInfoPtr pScreenInfo, + Atom AttributeID, + INT32 Value +) +{ + return ATIMach64SetPortAttribute(pScreenInfo, AttributeID, Value, + ATIPTR(pScreenInfo)); +} + +/* XVideo surface registration data */ +static XF86OffscreenImageRec ATIMach64Surface_A[] = +{ + { + &ATIMach64Image[0], /* YUY2 */ + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, + ATIMach64AllocateSurface, + ATIMach64FreeSurface, + ATIMach64DisplaySurface, + ATIMach64StopSurface, + ATIMach64GetSurfaceAttribute, + ATIMach64SetSurfaceAttribute, + 384, 2048, + nATIMach64Attribute - 5, /* No double-buffering */ + ATIMach64Attribute + 4 /* No saturation nor brightness */ + }, + { + &ATIMach64Image[1], /* UYVY */ + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, + ATIMach64AllocateSurface, + ATIMach64FreeSurface, + ATIMach64DisplaySurface, + ATIMach64StopSurface, + ATIMach64GetSurfaceAttribute, + ATIMach64SetSurfaceAttribute, + 384, 2048, + nATIMach64Attribute - 5, /* No double-buffering */ + ATIMach64Attribute + 4 /* No saturation nor brightness */ + } +}; +#define nATIMach64Surface_A NumberOf(ATIMach64Surface_A) + +static XF86OffscreenImageRec ATIMach64Surface_B[] = +{ + { + &ATIMach64Image[0], /* YUY2 */ + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, + ATIMach64AllocateSurface, + ATIMach64FreeSurface, + ATIMach64DisplaySurface, + ATIMach64StopSurface, + ATIMach64GetSurfaceAttribute, + ATIMach64SetSurfaceAttribute, + 720, 2048, + nATIMach64Attribute - 5, /* No double-buffering */ + ATIMach64Attribute + 4 /* No saturation nor brightness */ + }, + { + &ATIMach64Image[1], /* UYVY */ + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, + ATIMach64AllocateSurface, + ATIMach64FreeSurface, + ATIMach64DisplaySurface, + ATIMach64StopSurface, + ATIMach64GetSurfaceAttribute, + ATIMach64SetSurfaceAttribute, + 720, 2048, + nATIMach64Attribute - 5, /* No double-buffering */ + ATIMach64Attribute + 4 /* No saturation nor brightness */ + } +}; +#define nATIMach64Surface_B NumberOf(ATIMach64Surface_B) + +static XF86OffscreenImageRec ATIMach64Surface_C[] = +{ + { + &ATIMach64Image[0], /* YUY2 */ + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, + ATIMach64AllocateSurface, + ATIMach64FreeSurface, + ATIMach64DisplaySurface, + ATIMach64StopSurface, + ATIMach64GetSurfaceAttribute, + ATIMach64SetSurfaceAttribute, + 720, 2048, + nATIMach64Attribute - 1, /* No double-buffering */ + ATIMach64Attribute + }, + { + &ATIMach64Image[1], /* UYVY */ + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, + ATIMach64AllocateSurface, + ATIMach64FreeSurface, + ATIMach64DisplaySurface, + ATIMach64StopSurface, + ATIMach64GetSurfaceAttribute, + ATIMach64SetSurfaceAttribute, + 720, 2048, + nATIMach64Attribute - 1, /* No double-buffering */ + ATIMach64Attribute + } +}; +#define nATIMach64Surface_C NumberOf(ATIMach64Surface_C) + +/* + * ATIMach64XVInitialiseAdaptor -- + * + * This function is called to make a Mach64's hardware overlay support + * available as an XVideo adaptor. + */ +int +ATIMach64XVInitialiseAdaptor +( + ScreenPtr pScreen, + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + XF86VideoAdaptorPtr **pppAdaptor +) +{ + XF86VideoAdaptorPtr pAdaptor; + int Index; + + if (!pATI->Block1Base) + return 0; + + if (!(pAdaptor = xf86XVAllocateVideoAdaptorRec(pScreenInfo))) + return 0; + + *pppAdaptor = xnfalloc(sizeof(pAdaptor)); + **pppAdaptor = pAdaptor; + + pAdaptor->nPorts = 1; + pAdaptor->pPortPrivates = pATI->XVPortPrivate; + pATI->XVPortPrivate[0].ptr = pATI; + + pAdaptor->type = XvInputMask | XvImageMask | XvWindowMask; + pAdaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + pAdaptor->name = "ATI Mach64 Back-end Overlay Scaler"; + + if (pATI->Chip < ATI_CHIP_264VTB) + { + pAdaptor->nEncodings = nATIMach64VideoEncoding_A; + pAdaptor->pEncodings = ATIMach64VideoEncoding_A; + } + else + { + pAdaptor->nEncodings = nATIMach64VideoEncoding_B; + pAdaptor->pEncodings = ATIMach64VideoEncoding_B; + } + + pAdaptor->nFormats = nATIMach64VideoFormat; + pAdaptor->pFormats = ATIMach64VideoFormat; + + pAdaptor->nAttributes = nATIMach64Attribute; + pAdaptor->pAttributes = ATIMach64Attribute; + + if (pATI->Chip < ATI_CHIP_264GTPRO) + { + /* Older controllers don't have brightness or saturation controls */ + pAdaptor->nAttributes -= 4; + pAdaptor->pAttributes += 4; + } + + pAdaptor->nImages = nATIMach64Image; + pAdaptor->pImages = ATIMach64Image; + + pAdaptor->StopVideo = ATIMach64StopVideo; + pAdaptor->SetPortAttribute = ATIMach64SetPortAttribute; + pAdaptor->GetPortAttribute = ATIMach64GetPortAttribute; + pAdaptor->QueryBestSize = ATIMach64QueryBestSize; + pAdaptor->PutImage = ATIMach64PutImage; + pAdaptor->QueryImageAttributes = ATIMach64QueryImageAttributes; + + REGION_NULL(pScreen, &pATI->VideoClip); + pATI->ActiveSurface = FALSE; + + if (ATIMach64XVAtomGeneration != serverGeneration) + { + /* Refresh static data */ + ATIMach64XVAtomGeneration = serverGeneration; + + Index = nATIMach64Attribute - pAdaptor->nAttributes; + for (; Index < nATIMach64Attribute; Index++) + ATIMach64AttributeInfo[Index].AttributeID = + MAKE_ATOM(ATIMach64Attribute[Index].name); + } + + ATIMach64SetDefaultAttributes(pATI, 0); + + if (pATI->Chip < ATI_CHIP_264VTB) + { + xf86XVRegisterOffscreenImages(pScreen, + ATIMach64Surface_A, nATIMach64Surface_A); + } + else if (pATI->Chip < ATI_CHIP_264GTPRO) + { + xf86XVRegisterOffscreenImages(pScreen, + ATIMach64Surface_B, nATIMach64Surface_B); + } + else + { + xf86XVRegisterOffscreenImages(pScreen, + ATIMach64Surface_C, nATIMach64Surface_C); + } + + return 1; +} + +/* + * ATIMach64CloseXVideo -- + * + * This function is called during screen termination to clean up after + * initialisation of Mach64 XVideo support. + */ +void +ATIMach64CloseXVideo +( + ScreenPtr pScreen, + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + ATIMach64StopVideo(pScreenInfo, pATI, TRUE); + + REGION_UNINIT(pScreen, &pATI->VideoClip); +} diff --git a/src/atimach64xv.h b/src/atimach64xv.h new file mode 100644 index 0000000..9204942 --- /dev/null +++ b/src/atimach64xv.h @@ -0,0 +1,40 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimach64xv.h,v 1.1 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMACH64XV_H___ +#define ___ATIMACH64XV_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" +#include "xf86xv.h" + +extern int ATIMach64XVInitialiseAdaptor + FunctionPrototype((ScreenPtr, ScrnInfoPtr, ATIPtr, + XF86VideoAdaptorPtr **)); + +extern void ATIMach64CloseXVideo + FunctionPrototype((ScreenPtr, ScrnInfoPtr, ATIPtr)); + +#endif /* ___ATIMACH64XV_H___ */ diff --git a/src/atimisc.c b/src/atimisc.c new file mode 100644 index 0000000..53c97b5 --- /dev/null +++ b/src/atimisc.c @@ -0,0 +1,135 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimisc.c,v 1.8tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifdef XFree86LOADER + +#include "ati.h" +#include "atiload.h" +#include "ativersion.h" + +/* Module loader interface for subsidiary driver module */ + +static XF86ModuleVersionInfo ATIVersionRec = +{ + "atimisc", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + ATI_VERSION_MAJOR, ATI_VERSION_MINOR, ATI_VERSION_PATCH, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +/* + * ATISetup -- + * + * This function is called every time the module is loaded. + */ +static pointer +ATISetup +( + pointer Module, + pointer Options, + int *ErrorMajor, + int *ErrorMinor +) +{ + static Bool Inited = FALSE; + + if (!Inited) + { + /* Ensure main driver module is loaded, but not as a submodule */ + if (!xf86ServerIsOnlyDetecting()) + { + if (!LoaderSymbol(ATI_NAME)) + xf86LoadOneModule(ATI_DRIVER_NAME, Options); + + /* ati & atimisc module versions must match */ + do + { + XF86ModuleData *pModuleData = LoaderSymbol("atiModuleData"); + + if (pModuleData) + { + XF86ModuleVersionInfo *pModuleInfo = pModuleData->vers; + + if ((pModuleInfo->majorversion == ATI_VERSION_MAJOR) && + (pModuleInfo->minorversion == ATI_VERSION_MINOR) && + (pModuleInfo->patchlevel == ATI_VERSION_PATCH)) + break; + } + + xf86Msg(X_ERROR, + "\"ati\" and \"atimisc\" module versions must" + " match.\n"); + + if (ErrorMajor) + *ErrorMajor = (int)LDR_MISMATCH; + if (ErrorMinor) + *ErrorMinor = (int)LDR_MISMATCH; + + return NULL; + } while (0); + } + + /* + * Tell loader about symbols from other modules that this module might + * refer to. + */ + xf86LoaderRefSymLists( + ATIint10Symbols, + ATIddcSymbols, + ATIvbeSymbols, + +#ifndef AVOID_CPIO + + ATIxf1bppSymbols, + ATIxf4bppSymbols, + +#endif /* AVOID_CPIO */ + + ATIfbSymbols, + ATIshadowfbSymbols, + ATIxaaSymbols, + ATIramdacSymbols, + ATIi2cSymbols, + NULL); + + Inited = TRUE; + } + + return (pointer)TRUE; +} + +/* The following record must be called atimiscModuleData */ +XF86ModuleData atimiscModuleData = +{ + &ATIVersionRec, + ATISetup, + NULL +}; + +#endif /* XFree86LOADER */ diff --git a/src/atimode.c b/src/atimode.c new file mode 100644 index 0000000..a723de9 --- /dev/null +++ b/src/atimode.c @@ -0,0 +1,1184 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimode.c,v 1.18 2004/01/05 16:42:03 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atichip.h" +#include "atidac.h" +#include "atidsp.h" +#include "atimach64.h" +#include "atimach64io.h" +#include "atimode.h" +#include "atiprint.h" +#include "atirgb514.h" +#include "ativga.h" +#include "atiwonder.h" +#include "atiwonderio.h" + +#ifndef AVOID_CPIO + +/* + * ATICopyVGAMemory -- + * + * This function is called to copy one or all banks of a VGA plane. + */ +static void +ATICopyVGAMemory +( + ATIPtr pATI, + ATIHWPtr pATIHW, + pointer *saveptr, + pointer *from, + pointer *to +) +{ + unsigned int iBank; + + for (iBank = 0; iBank < pATIHW->nBank; iBank++) + { + (*pATIHW->SetBank)(pATI, iBank); + (void)memcpy(*to, *from, 0x00010000U); + *saveptr = (char *)(*saveptr) + 0x00010000U; + } +} + +/* + * ATISwap -- + * + * This function saves/restores video memory contents during video mode + * switches. + */ +static void +ATISwap +( + int iScreen, + ATIPtr pATI, + ATIHWPtr pATIHW, + Bool ToFB +) +{ + pointer save, *from, *to; + unsigned int iPlane = 0, PlaneMask = 1; + CARD8 seq2, seq4, gra1, gra3, gra4, gra5, gra6, gra8; + + /* + * This is only done for non-accelerator modes. If the video state on + * server entry was an accelerator mode, the application that relinquished + * the console had better do the Right Thing (tm) anyway by saving and + * restoring its own video memory contents. + */ + if (pATIHW->crtc != ATI_CRTC_VGA) + return; + + if (ToFB) + { + if (!pATIHW->frame_buffer) + return; + + from = &save; + to = &pATI->pBank; + } + else + { + /* Allocate the memory */ + if (!pATIHW->frame_buffer) + { + pATIHW->frame_buffer = + (pointer)xalloc(pATIHW->nBank * pATIHW->nPlane * 0x00010000U); + if (!pATIHW->frame_buffer) + { + xf86DrvMsg(iScreen, X_WARNING, + "Temporary frame buffer could not be allocated.\n"); + return; + } + } + + from = &pATI->pBank; + to = &save; + } + + /* Turn off screen */ + ATIVGASaveScreen(pATI, SCREEN_SAVER_ON); + + /* Save register values to be modified */ + seq2 = GetReg(SEQX, 0x02U); + seq4 = GetReg(SEQX, 0x04U); + gra1 = GetReg(GRAX, 0x01U); + gra3 = GetReg(GRAX, 0x03U); + gra5 = GetReg(GRAX, 0x05U); + gra6 = GetReg(GRAX, 0x06U); + gra8 = GetReg(GRAX, 0x08U); + + save = pATIHW->frame_buffer; + + /* Temporarily normalise the mode */ + if (gra1 != 0x00U) + PutReg(GRAX, 0x01U, 0x00U); + if (gra3 != 0x00U) + PutReg(GRAX, 0x03U, 0x00U); + if (gra6 != 0x05U) + PutReg(GRAX, 0x06U, 0x05U); + if (gra8 != 0xFFU) + PutReg(GRAX, 0x08U, 0xFFU); + + if (seq4 & 0x08U) + { + /* Setup packed mode memory */ + if (seq2 != 0x0FU) + PutReg(SEQX, 0x02U, 0x0FU); + if (seq4 != 0x0AU) + PutReg(SEQX, 0x04U, 0x0AU); + if (pATI->Chip < ATI_CHIP_264CT) + { + if (gra5 != 0x00U) + PutReg(GRAX, 0x05U, 0x00U); + } + else + { + if (gra5 != 0x40U) + PutReg(GRAX, 0x05U, 0x40U); + } + + ATICopyVGAMemory(pATI, pATIHW, &save, from, to); + + if (seq2 != 0x0FU) + PutReg(SEQX, 0x02U, seq2); + if (seq4 != 0x0AU) + PutReg(SEQX, 0x04U, seq4); + if (pATI->Chip < ATI_CHIP_264CT) + { + if (gra5 != 0x00U) + PutReg(GRAX, 0x05U, gra5); + } + else + { + if (gra5 != 0x40U) + PutReg(GRAX, 0x05U, gra5); + } + } + else + { + gra4 = GetReg(GRAX, 0x04U); + + /* Setup planar mode memory */ + if (seq4 != 0x06U) + PutReg(SEQX, 0x04U, 0x06U); + if (gra5 != 0x00U) + PutReg(GRAX, 0x05U, 0x00U); + + for (; iPlane < pATIHW->nPlane; iPlane++) + { + PutReg(SEQX, 0x02U, PlaneMask); + PutReg(GRAX, 0x04U, iPlane); + ATICopyVGAMemory(pATI, pATIHW, &save, from, to); + PlaneMask <<= 1; + } + + PutReg(SEQX, 0x02U, seq2); + if (seq4 != 0x06U) + PutReg(SEQX, 0x04U, seq4); + PutReg(GRAX, 0x04U, gra4); + if (gra5 != 0x00U) + PutReg(GRAX, 0x05U, gra5); + } + + /* Restore registers */ + if (gra1 != 0x00U) + PutReg(GRAX, 0x01U, gra1); + if (gra3 != 0x00U) + PutReg(GRAX, 0x03U, gra3); + if (gra6 != 0x05U) + PutReg(GRAX, 0x06U, gra6); + if (gra8 != 0xFFU) + PutReg(GRAX, 0x08U, gra8); + + /* Back to bank 0 */ + (*pATIHW->SetBank)(pATI, 0); + + /* + * If restoring video memory for a server video mode, free the frame buffer + * save area. + */ + if (ToFB && (pATIHW == &pATI->NewHW)) + { + xfree(pATIHW->frame_buffer); + pATIHW->frame_buffer = NULL; + } +} + +#endif /* AVOID_CPIO */ + +/* + * ATIModePreInit -- + * + * This function initialises an ATIHWRec with information common to all video + * states generated by the driver. + */ +void +ATIModePreInit +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + CARD32 lcd_index; + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + /* Fill in VGA data */ + ATIVGAPreInit(pATI, pATIHW); + + /* Fill in VGA Wonder data */ + if (pATI->CPIO_VGAWonder) + ATIVGAWonderPreInit(pATI, pATIHW); + } + + if (pATI->Chip >= ATI_CHIP_88800GXC) + +#endif /* AVOID_CPIO */ + + { + /* Fill in Mach64 data */ + ATIMach64PreInit(pScreenInfo, pATI, pATIHW); + + if (pATI->Chip >= ATI_CHIP_264CT) + { + /* Ensure proper VCLK source */ + pATIHW->pll_vclk_cntl = ATIMach64GetPLLReg(PLL_VCLK_CNTL) | + (PLL_VCLK_SRC_SEL | PLL_VCLK_RESET); + + /* Set provisional values for other PLL registers */ + pATIHW->pll_vclk_post_div = ATIMach64GetPLLReg(PLL_VCLK_POST_DIV); + pATIHW->pll_vclk0_fb_div = ATIMach64GetPLLReg(PLL_VCLK0_FB_DIV); + pATIHW->pll_vclk1_fb_div = ATIMach64GetPLLReg(PLL_VCLK1_FB_DIV); + pATIHW->pll_vclk2_fb_div = ATIMach64GetPLLReg(PLL_VCLK2_FB_DIV); + pATIHW->pll_vclk3_fb_div = ATIMach64GetPLLReg(PLL_VCLK3_FB_DIV); + pATIHW->pll_xclk_cntl = ATIMach64GetPLLReg(PLL_XCLK_CNTL); + + /* For now disable extended reference and feedback dividers */ + if (pATI->Chip >= ATI_CHIP_264LT) + pATIHW->pll_ext_vpll_cntl = + ATIMach64GetPLLReg(PLL_EXT_VPLL_CNTL) & + ~(PLL_EXT_VPLL_EN | PLL_EXT_VPLL_VGA_EN | + PLL_EXT_VPLL_INSYNC); + + /* Initialise CRTC data for LCD panels */ + if (pATI->LCDPanelID >= 0) + { + if (pATI->Chip == ATI_CHIP_264LT) + { + pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + lcd_index = inr(LCD_INDEX); + pATIHW->lcd_index = lcd_index & + ~(LCD_REG_INDEX | LCD_DISPLAY_DIS | LCD_SRC_SEL | + LCD_CRTC2_DISPLAY_DIS); + if (pATI->Chip != ATI_CHIP_264XL) + pATIHW->lcd_index |= LCD_CRTC2_DISPLAY_DIS; + pATIHW->config_panel = + ATIMach64GetLCDReg(LCD_CONFIG_PANEL) | + DONT_SHADOW_HEND; + pATIHW->lcd_gen_ctrl = + ATIMach64GetLCDReg(LCD_GEN_CNTL) & ~CRTC_RW_SELECT; + outr(LCD_INDEX, lcd_index); + } + + pATIHW->lcd_gen_ctrl &= + ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | MCLK_PM_EN | + VCLK_DAC_PM_EN | USE_SHADOWED_VEND | + USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN); + pATIHW->lcd_gen_ctrl |= DONT_SHADOW_VPAR | LOCK_8DOT; + + if (!pATI->OptionPanelDisplay) + { + /* + * Use primary CRTC to drive the CRT. Turn off panel + * interface. + */ + pATIHW->lcd_gen_ctrl &= ~LCD_ON; + pATIHW->lcd_gen_ctrl |= CRT_ON; + } + else + { + /* Use primary CRTC to drive the panel */ + pATIHW->lcd_gen_ctrl |= LCD_ON; + + /* If requested, also force CRT on */ + if (pATI->OptionCRTDisplay) + pATIHW->lcd_gen_ctrl |= CRT_ON; + } + } + } + else if (pATI->DAC == ATI_DAC_IBMRGB514) + { + ATIRGB514PreInit(pATI, pATIHW); + } + } + + /* Set RAMDAC data */ + ATIDACPreInit(pScreenInfo, pATI, pATIHW); +} + +/* + * ATIModeSave -- + * + * This function saves the current video state. + */ +void +ATIModeSave +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + +#ifndef AVOID_CPIO + + int Index; + + /* Get back to bank 0 */ + (*pATIHW->SetBank)(pATI, 0); + +#endif /* AVOID_CPIO */ + + /* Save clock data */ + ATIClockSave(pScreenInfo, pATI, pATIHW); + + if (pATI->Chip >= ATI_CHIP_264CT) + { + pATIHW->pll_vclk_cntl = ATIMach64GetPLLReg(PLL_VCLK_CNTL) | + PLL_VCLK_RESET; + pATIHW->pll_vclk_post_div = ATIMach64GetPLLReg(PLL_VCLK_POST_DIV); + pATIHW->pll_vclk0_fb_div = ATIMach64GetPLLReg(PLL_VCLK0_FB_DIV); + pATIHW->pll_vclk1_fb_div = ATIMach64GetPLLReg(PLL_VCLK1_FB_DIV); + pATIHW->pll_vclk2_fb_div = ATIMach64GetPLLReg(PLL_VCLK2_FB_DIV); + pATIHW->pll_vclk3_fb_div = ATIMach64GetPLLReg(PLL_VCLK3_FB_DIV); + pATIHW->pll_xclk_cntl = ATIMach64GetPLLReg(PLL_XCLK_CNTL); + if (pATI->Chip >= ATI_CHIP_264LT) + pATIHW->pll_ext_vpll_cntl = ATIMach64GetPLLReg(PLL_EXT_VPLL_CNTL); + + /* Save LCD registers */ + if (pATI->LCDPanelID >= 0) + { + if (pATI->Chip == ATI_CHIP_264LT) + { + pATIHW->horz_stretching = inr(HORZ_STRETCHING); + pATIHW->vert_stretching = inr(VERT_STRETCHING); + pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL); + + /* Set up to save non-shadow registers */ + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + pATIHW->lcd_index = inr(LCD_INDEX); + pATIHW->config_panel = ATIMach64GetLCDReg(LCD_CONFIG_PANEL); + pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + pATIHW->horz_stretching = + ATIMach64GetLCDReg(LCD_HORZ_STRETCHING); + pATIHW->vert_stretching = + ATIMach64GetLCDReg(LCD_VERT_STRETCHING); + pATIHW->ext_vert_stretch = + ATIMach64GetLCDReg(LCD_EXT_VERT_STRETCH); + + /* Set up to save non-shadow registers */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, + pATIHW->lcd_gen_ctrl & ~(CRTC_RW_SELECT | SHADOW_RW_EN)); + } + } + } + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + /* Save VGA data */ + ATIVGASave(pATI, pATIHW); + + /* Save VGA Wonder data */ + if (pATI->CPIO_VGAWonder) + ATIVGAWonderSave(pATI, pATIHW); + } + + if (pATI->Chip >= ATI_CHIP_88800GXC) + +#endif /* AVOID_CPIO */ + + { + /* Save Mach64 data */ + ATIMach64Save(pATI, pATIHW); + + if (pATI->Chip >= ATI_CHIP_264VTB) + { + /* Save DSP data */ + ATIDSPSave(pATI, pATIHW); + + if (pATI->LCDPanelID >= 0) + { + /* Switch to shadow registers */ + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, + (pATIHW->lcd_gen_ctrl & ~CRTC_RW_SELECT) | + SHADOW_RW_EN); + +#ifndef AVOID_CPIO + + /* Save shadow VGA CRTC registers */ + for (Index = 0; + Index < NumberOf(pATIHW->shadow_vga); + Index++) + pATIHW->shadow_vga[Index] = + GetReg(CRTX(pATI->CPIO_VGABase), Index); + +#endif /* AVOID_CPIO */ + + /* Save shadow Mach64 CRTC registers */ + pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP); + pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); + pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP); + pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); + + /* Restore CRTC selection and shadow state */ + if (pATI->Chip == ATI_CHIP_264LT) + { + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl); + outr(LCD_INDEX, pATIHW->lcd_index); + } + } + } + else if (pATI->DAC == ATI_DAC_IBMRGB514) + ATIRGB514Save(pATI, pATIHW); + } + +#ifndef AVOID_CPIO + + /* + * For some unknown reason, CLKDIV2 needs to be turned off to save the + * DAC's LUT reliably on VGA Wonder VLB adapters. + */ + if ((pATI->Adapter == ATI_ADAPTER_NONISA) && (pATIHW->seq[1] & 0x08U)) + PutReg(SEQX, 0x01U, pATIHW->seq[1] & ~0x08U); + +#endif /* AVOID_CPIO */ + + /* Save RAMDAC state */ + ATIDACSave(pATI, pATIHW); + +#ifndef AVOID_CPIO + + if ((pATI->Adapter == ATI_ADAPTER_NONISA) && (pATIHW->seq[1] & 0x08U)) + PutReg(SEQX, 0x01U, pATIHW->seq[1]); + +#endif /* AVOID_CPIO */ + + /* + * The server has already saved video memory contents when switching out of + * its virtual console, so don't do it again. + */ + if (pATIHW != &pATI->NewHW) + { + pATIHW->FeedbackDivider = 0; /* Don't programme clock */ + +#ifndef AVOID_CPIO + + /* Save video memory */ + ATISwap(pScreenInfo->scrnIndex, pATI, pATIHW, FALSE); + +#endif /* AVOID_CPIO */ + + } + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + ATIVGASaveScreen(pATI, SCREEN_SAVER_OFF); /* Turn on screen */ + +#endif /* AVOID_CPIO */ + +} + +/* + * ATIModeCalculate -- + * + * This function fills in an ATIHWRec with all register values needed to enable + * a video state. It's important that this be done without modifying the + * current video state. + */ +Bool +ATIModeCalculate +( + int iScreen, + ATIPtr pATI, + ATIHWPtr pATIHW, + DisplayModePtr pMode +) +{ + CARD32 lcd_index; + int Index, ECPClock, MaxScalerClock; + + /* Clobber mode timings */ + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0) && + !pMode->CrtcHAdjusted && !pMode->CrtcVAdjusted && + (!pATI->OptionLCDSync || (pMode->type & M_T_BUILTIN))) + { + int VScan; + + pMode->Clock = pATI->LCDClock; + pMode->Flags &= ~(V_DBLSCAN | V_INTERLACE | V_CLKDIV2); + + /* + * Use doublescanning or multiscanning to get around vertical blending + * limitations. + */ + VScan = pATI->LCDVertical / pMode->VDisplay; + switch (pATIHW->crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + if (VScan > 64) + VScan = 64; + pMode->VScan = VScan; + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + pMode->VScan = 0; + if (VScan <= 1) + break; + VScan = 2; + pMode->Flags |= V_DBLSCAN; + break; + + default: + break; + } + + pMode->HSyncStart = pMode->HDisplay + pATI->LCDHSyncStart; + pMode->HSyncEnd = pMode->HSyncStart + pATI->LCDHSyncWidth; + pMode->HTotal = pMode->HDisplay + pATI->LCDHBlankWidth; + + pMode->VSyncStart = pMode->VDisplay + + ATIDivide(pATI->LCDVSyncStart, VScan, 0, 0); + pMode->VSyncEnd = pMode->VSyncStart + + ATIDivide(pATI->LCDVSyncWidth, VScan, 0, 1); + pMode->VTotal = pMode->VDisplay + + ATIDivide(pATI->LCDVBlankWidth, VScan, 0, 0); + } + + switch (pATIHW->crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + /* Fill in VGA data */ + ATIVGACalculate(pATI, pATIHW, pMode); + + /* Fill in VGA Wonder data */ + if (pATI->CPIO_VGAWonder) + ATIVGAWonderCalculate(pATI, pATIHW, pMode); + + if (pATI->Chip >= ATI_CHIP_88800GXC) + { + if (pATI->Chip >= ATI_CHIP_264CT) + { + /* + * Selected bits of accelerator & VGA CRTC registers are + * actually copies of each other. + */ + pATIHW->crtc_h_total_disp = + SetBits(pMode->CrtcHTotal, CRTC_H_TOTAL) | + SetBits(pMode->CrtcHDisplay, CRTC_H_DISP); + pATIHW->crtc_h_sync_strt_wid = + SetBits(pMode->CrtcHSyncStart, CRTC_H_SYNC_STRT) | + SetBits(pMode->CrtcHSkew, CRTC_H_SYNC_DLY) | /* ? */ + SetBits(GetBits(pMode->CrtcHSyncStart, 0x0100U), + CRTC_H_SYNC_STRT_HI) | + SetBits(pMode->CrtcHSyncEnd, CRTC_H_SYNC_WID); + if (pMode->Flags & V_NHSYNC) + pATIHW->crtc_h_sync_strt_wid |= CRTC_H_SYNC_POL; + + pATIHW->crtc_v_total_disp = + SetBits(pMode->CrtcVTotal, CRTC_V_TOTAL) | + SetBits(pMode->CrtcVDisplay, CRTC_V_DISP); + pATIHW->crtc_v_sync_strt_wid = + SetBits(pMode->CrtcVSyncStart, CRTC_V_SYNC_STRT) | + SetBits(pMode->CrtcVSyncEnd, CRTC_V_SYNC_WID); + if (pMode->Flags & V_NVSYNC) + pATIHW->crtc_v_sync_strt_wid |= CRTC_V_SYNC_POL; + } + + pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL) & + ~(CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN | + CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_CSYNC_EN | + CRTC_PIX_BY_2_EN | CRTC_DISPLAY_DIS | + CRTC_VGA_XOVERSCAN | CRTC_PIX_WIDTH | + CRTC_BYTE_PIX_ORDER | CRTC_VGA_128KAP_PAGING | + CRTC_VFC_SYNC_TRISTATE | + CRTC_LOCK_REGS | /* Already off, but ... */ + CRTC_SYNC_TRISTATE | CRTC_EXT_DISP_EN | + CRTC_DISP_REQ_EN | CRTC_VGA_LINEAR | CRTC_VGA_TEXT_132 | + CRTC_CUR_B_TEST); + /* Some of these are not relevent, but that doesn't matter */ + switch (pATI->depth) + { + case 1: + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_1BPP, CRTC_PIX_WIDTH); + break; + + case 4: + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_4BPP, CRTC_PIX_WIDTH); + break; + + case 8: + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_8BPP, CRTC_PIX_WIDTH); + break; + + case 15: + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_15BPP, CRTC_PIX_WIDTH); + break; + + case 16: + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_16BPP, CRTC_PIX_WIDTH); + break; + + case 24: + if (pATI->bitsPerPixel == 24) + { + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_24BPP, CRTC_PIX_WIDTH); + break; + } + if (pATI->bitsPerPixel != 32) + break; + /* Fall through */ + + case 32: + pATIHW->crtc_gen_cntl |= + SetBits(PIX_WIDTH_32BPP, CRTC_PIX_WIDTH); + break; + + default: + break; + } +#if 0 /* This isn't needed, but is kept for reference */ + if (pMode->Flags & V_DBLSCAN) + pATIHW->crtc_gen_cntl |= CRTC_DBL_SCAN_EN; +#endif + if (pMode->Flags & V_INTERLACE) + pATIHW->crtc_gen_cntl |= CRTC_INTERLACE_EN; + if ((pMode->Flags & (V_CSYNC | V_PCSYNC)) || pATI->OptionCSync) + pATIHW->crtc_gen_cntl |= CRTC_CSYNC_EN; + if (pATI->depth <= 4) + pATIHW->crtc_gen_cntl |= CRTC_EN | CRTC_CNT_EN; + else + pATIHW->crtc_gen_cntl |= + CRTC_EN | CRTC_VGA_LINEAR | CRTC_CNT_EN; + } + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + /* Fill in Mach64 data */ + ATIMach64Calculate(pATI, pATIHW, pMode); + break; + + default: + break; + } + + /* Set up LCD register values */ + if (pATI->LCDPanelID >= 0) + { + int VDisplay = pMode->VDisplay; + + if (pMode->Flags & V_DBLSCAN) + VDisplay <<= 1; + if (pMode->VScan > 1) + VDisplay *= pMode->VScan; + if (pMode->Flags & V_INTERLACE) + VDisplay >>= 1; + + /* Ensure secondary CRTC is completely disabled */ + pATIHW->crtc_gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH); + + if (pATI->Chip == ATI_CHIP_264LT) + { + pATIHW->horz_stretching = inr(HORZ_STRETCHING); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + lcd_index = inr(LCD_INDEX); + pATIHW->horz_stretching = ATIMach64GetLCDReg(LCD_HORZ_STRETCHING); + pATIHW->ext_vert_stretch = + ATIMach64GetLCDReg(LCD_EXT_VERT_STRETCH) & + ~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3); + + /* + * Don't use vertical blending if the mode is too wide or not + * vertically stretched. + */ + if (pATI->OptionPanelDisplay && + (pMode->HDisplay <= pATI->LCDVBlendFIFOSize) && + (VDisplay < pATI->LCDVertical)) + pATIHW->ext_vert_stretch |= VERT_STRETCH_MODE; + + outr(LCD_INDEX, lcd_index); + } + + pATIHW->horz_stretching &= + ~(HORZ_STRETCH_RATIO | HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO | + HORZ_STRETCH_MODE | HORZ_STRETCH_EN); + if (pATI->OptionPanelDisplay && + (pMode->HDisplay < pATI->LCDHorizontal)) + do + { + /* + * The horizontal blender misbehaves when HDisplay is less than a + * a certain threshold (440 for a 1024-wide panel). It doesn't + * stretch such modes enough. Use pixel replication instead of + * blending to stretch modes that can be made to exactly fit the + * panel width. The undocumented "NoLCDBlend" option allows the + * pixel-replicated mode to be slightly wider or narrower than the + * panel width. It also causes a mode that is exactly half as wide + * as the panel to be pixel-replicated, rather than blended. + */ + int HDisplay = pMode->HDisplay & ~7; + int nStretch = pATI->LCDHorizontal / HDisplay; + int Remainder = pATI->LCDHorizontal % HDisplay; + + if ((!Remainder && ((nStretch > 2) || !pATI->OptionBlend)) || + (((HDisplay * 16) / pATI->LCDHorizontal) < 7)) + { + static const char StretchLoops[] = {10, 12, 13, 15, 16}; + int horz_stretch_loop = -1, BestRemainder; + int Numerator = HDisplay, Denominator = pATI->LCDHorizontal; + + ATIReduceRatio(&Numerator, &Denominator); + + BestRemainder = (Numerator * 16) / Denominator; + Index = NumberOf(StretchLoops); + while (--Index >= 0) + { + Remainder = + ((Denominator - Numerator) * StretchLoops[Index]) % + Denominator; + if (Remainder < BestRemainder) + { + horz_stretch_loop = Index; + if (!(BestRemainder = Remainder)) + break; + } +#if 0 + /* + * Enabling this code allows the pixel-replicated mode to + * be slightly wider than the panel width. + */ + Remainder = Denominator - Remainder; + if (Remainder < BestRemainder) + { + horz_stretch_loop = Index; + BestRemainder = Remainder; + } +#endif + } + + if ((horz_stretch_loop >= 0) && + (!BestRemainder || !pATI->OptionBlend)) + { + int horz_stretch_ratio = 0, Accumulator = 0; + int reuse_previous = 1; + + Index = StretchLoops[horz_stretch_loop]; + + while (--Index >= 0) + { + if (Accumulator > 0) + horz_stretch_ratio |= reuse_previous; + else + Accumulator += Denominator; + Accumulator -= Numerator; + reuse_previous <<= 1; + } + + pATIHW->horz_stretching |= HORZ_STRETCH_EN | + SetBits(horz_stretch_loop, HORZ_STRETCH_LOOP) | + SetBits(horz_stretch_ratio, HORZ_STRETCH_RATIO); + break; /* Out of the do { ... } while (0) */ + } + } + + pATIHW->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN) | + SetBits((HDisplay * (MaxBits(HORZ_STRETCH_BLEND) + 1)) / + pATI->LCDHorizontal, HORZ_STRETCH_BLEND); + } while (0); + + if (!pATI->OptionPanelDisplay || (VDisplay >= pATI->LCDVertical)) + { + pATIHW->vert_stretching = 0; + } + else + { + pATIHW->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN) | + SetBits((VDisplay * (MaxBits(VERT_STRETCH_RATIO0) + 1)) / + pATI->LCDVertical, VERT_STRETCH_RATIO0); + } + +#ifndef AVOID_CPIO + + /* Copy non-shadow CRTC register values to the shadow set */ + for (Index = 0; Index < NumberOf(pATIHW->shadow_vga); Index++) + pATIHW->shadow_vga[Index] = pATIHW->crt[Index]; + +#endif /* AVOID_CPIO */ + + pATIHW->shadow_h_total_disp = pATIHW->crtc_h_total_disp; + pATIHW->shadow_h_sync_strt_wid = pATIHW->crtc_h_sync_strt_wid; + pATIHW->shadow_v_total_disp = pATIHW->crtc_v_total_disp; + pATIHW->shadow_v_sync_strt_wid = pATIHW->crtc_v_sync_strt_wid; + } + + /* Fill in clock data */ + if (!ATIClockCalculate(iScreen, pATI, pATIHW, pMode)) + return FALSE; + + /* Setup ECP clock divider */ + if (pATI->Chip >= ATI_CHIP_264VT) + { + if (pATI->Chip <= ATI_CHIP_264VT3) + MaxScalerClock = 80000; + else if (pATI->Chip <= ATI_CHIP_264GT2C) + MaxScalerClock = 100000; + else if (pATI->Chip == ATI_CHIP_264GTPRO) + MaxScalerClock = 125000; + else if (pATI->Chip <= ATI_CHIP_MOBILITY) + MaxScalerClock = 135000; + else + MaxScalerClock = 80000; /* Conservative */ + pATIHW->pll_vclk_cntl &= ~PLL_ECP_DIV; + /* XXX Don't do this for TVOut! */ + ECPClock = pMode->SynthClock; + for (Index = 0; (ECPClock > MaxScalerClock) && (Index < 2); Index++) + ECPClock >>= 1; + pATIHW->pll_vclk_cntl |= SetBits(Index, PLL_ECP_DIV); + } + else if (pATI->DAC == ATI_DAC_IBMRGB514) + { + ATIRGB514Calculate(pATI, pATIHW, pMode); + } + + return TRUE; +} + +/* + * ATIModeSet -- + * + * This function sets a video mode. It writes out all video state data that + * has been previously calculated or saved. + */ +void +ATIModeSet +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + +#ifndef AVOID_CPIO + + int Index; + + /* Get back to bank 0 */ + (*pATIHW->SetBank)(pATI, 0); + +#endif /* AVOID_CPIO */ + + if (pATI->Chip >= ATI_CHIP_88800GXC) + { + /* Stop CRTC */ + outr(CRTC_GEN_CNTL, + pATIHW->crtc_gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN)); + + if (pATI->Chip >= ATI_CHIP_264CT) + { + ATIMach64PutPLLReg(PLL_VCLK_CNTL, pATIHW->pll_vclk_cntl); + ATIMach64PutPLLReg(PLL_VCLK_POST_DIV, pATIHW->pll_vclk_post_div); + ATIMach64PutPLLReg(PLL_VCLK0_FB_DIV, pATIHW->pll_vclk0_fb_div); + ATIMach64PutPLLReg(PLL_VCLK1_FB_DIV, pATIHW->pll_vclk1_fb_div); + ATIMach64PutPLLReg(PLL_VCLK2_FB_DIV, pATIHW->pll_vclk2_fb_div); + ATIMach64PutPLLReg(PLL_VCLK3_FB_DIV, pATIHW->pll_vclk3_fb_div); + ATIMach64PutPLLReg(PLL_XCLK_CNTL, pATIHW->pll_xclk_cntl); + if (pATI->Chip >= ATI_CHIP_264LT) + ATIMach64PutPLLReg(PLL_EXT_VPLL_CNTL, + pATIHW->pll_ext_vpll_cntl); + ATIMach64PutPLLReg(PLL_VCLK_CNTL, + pATIHW->pll_vclk_cntl & ~PLL_VCLK_RESET); + + /* Load LCD registers */ + if (pATI->LCDPanelID >= 0) + { + if (pATI->Chip == ATI_CHIP_264LT) + { + /* Update non-shadow registers first */ + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN); + + /* Temporarily disable stretching */ + outr(HORZ_STRETCHING, pATIHW->horz_stretching & + ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN)); + outr(VERT_STRETCHING, pATIHW->vert_stretching & + ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 | + VERT_STRETCH_USE0 | VERT_STRETCH_EN)); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + /* Update non-shadow registers first */ + ATIMach64PutLCDReg(LCD_CONFIG_PANEL, pATIHW->config_panel); + ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl & + ~(CRTC_RW_SELECT | SHADOW_RW_EN)); + + /* Temporarily disable stretching */ + ATIMach64PutLCDReg(LCD_HORZ_STRETCHING, + pATIHW->horz_stretching & + ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN)); + ATIMach64PutLCDReg(LCD_VERT_STRETCHING, + pATIHW->vert_stretching & + ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 | + VERT_STRETCH_USE0 | VERT_STRETCH_EN)); + } + } + } + } + + switch (pATIHW->crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + /* Start sequencer reset */ + PutReg(SEQX, 0x00U, 0x00U); + + /* Set pixel clock */ + if ((pATIHW->FeedbackDivider > 0) && + (pATI->ProgrammableClock > ATI_CLOCK_FIXED)) + ATIClockSet(pATI, pATIHW); + + /* Set up RAMDAC */ + if (pATI->DAC == ATI_DAC_IBMRGB514) + ATIRGB514Set(pATI, pATIHW); + + /* Load VGA Wonder */ + if (pATI->CPIO_VGAWonder) + ATIVGAWonderSet(pATI, pATIHW); + + /* Load VGA device */ + ATIVGASet(pATI, pATIHW); + + /* Load Mach64 registers */ + if (pATI->Chip >= ATI_CHIP_88800GXC) + { + /* Load MMIO registers */ + if (pATI->Block0Base) + ATIMach64Set(pATI, pATIHW); + + outr(CRTC_GEN_CNTL, pATIHW->crtc_gen_cntl); + outr(CUR_CLR0, pATIHW->cur_clr0); + outr(CUR_CLR1, pATIHW->cur_clr1); + outr(CUR_OFFSET, pATIHW->cur_offset); + outr(CUR_HORZ_VERT_POSN, pATIHW->cur_horz_vert_posn); + outr(CUR_HORZ_VERT_OFF, pATIHW->cur_horz_vert_off); + outr(BUS_CNTL, pATIHW->bus_cntl); + outr(MEM_VGA_WP_SEL, pATIHW->mem_vga_wp_sel); + outr(MEM_VGA_RP_SEL, pATIHW->mem_vga_rp_sel); + outr(DAC_CNTL, pATIHW->dac_cntl); + outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl | GEN_GUI_EN); + outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl); + outr(GEN_TEST_CNTL, pATIHW->gen_test_cntl | GEN_GUI_EN); + outr(CONFIG_CNTL, pATIHW->config_cntl); + if (pATI->Chip >= ATI_CHIP_264CT) + { + outr(CRTC_H_TOTAL_DISP, pATIHW->crtc_h_total_disp); + outr(CRTC_H_SYNC_STRT_WID, pATIHW->crtc_h_sync_strt_wid); + outr(CRTC_V_TOTAL_DISP, pATIHW->crtc_v_total_disp); + outr(CRTC_V_SYNC_STRT_WID, pATIHW->crtc_v_sync_strt_wid); + outr(CRTC_OFF_PITCH, pATIHW->crtc_off_pitch); + if (pATI->Chip >= ATI_CHIP_264VTB) + { + outr(MEM_CNTL, pATIHW->mem_cntl); + outr(MPP_CONFIG, pATIHW->mpp_config); + outr(MPP_STROBE_SEQ, pATIHW->mpp_strobe_seq); + outr(TVO_CNTL, pATIHW->tvo_cntl); + } + } + } + + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + /* Load Mach64 CRTC registers */ + ATIMach64Set(pATI, pATIHW); + +#ifndef AVOID_CPIO + + if (pATI->UseSmallApertures) + { + /* Oddly enough, these need to be set also, maybe others */ + PutReg(SEQX, 0x02U, pATIHW->seq[2]); + PutReg(SEQX, 0x04U, pATIHW->seq[4]); + PutReg(GRAX, 0x06U, pATIHW->gra[6]); + if (pATI->CPIO_VGAWonder) + ATIModifyExtReg(pATI, 0xB6U, -1, 0x00U, pATIHW->b6); + } + +#endif /* AVOID_CPIO */ + + break; + + default: + break; + } + + if (pATI->LCDPanelID >= 0) + { + /* Switch to shadow registers */ + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, + (pATIHW->lcd_gen_ctrl & ~CRTC_RW_SELECT) | SHADOW_RW_EN); + + /* Restore shadow registers */ + switch (pATIHW->crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + for (Index = 0; + Index < NumberOf(pATIHW->shadow_vga); + Index++) + PutReg(CRTX(pATI->CPIO_VGABase), Index, + pATIHW->shadow_vga[Index]); + /* Fall through */ + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + outr(CRTC_H_TOTAL_DISP, pATIHW->shadow_h_total_disp); + outr(CRTC_H_SYNC_STRT_WID, pATIHW->shadow_h_sync_strt_wid); + outr(CRTC_V_TOTAL_DISP, pATIHW->shadow_v_total_disp); + outr(CRTC_V_SYNC_STRT_WID, pATIHW->shadow_v_sync_strt_wid); + break; + + default: + break; + } + + /* Restore CRTC selection & shadow state and enable stretching */ + if (pATI->Chip == ATI_CHIP_264LT) + { + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl); + outr(HORZ_STRETCHING, pATIHW->horz_stretching); + outr(VERT_STRETCHING, pATIHW->vert_stretching); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl); + ATIMach64PutLCDReg(LCD_HORZ_STRETCHING, pATIHW->horz_stretching); + ATIMach64PutLCDReg(LCD_VERT_STRETCHING, pATIHW->vert_stretching); + ATIMach64PutLCDReg(LCD_EXT_VERT_STRETCH, pATIHW->ext_vert_stretch); + outr(LCD_INDEX, pATIHW->lcd_index); + } + } + + /* + * Set DSP registers. Note that, for some reason, sequencer resets clear + * the DSP_CONFIG register on early integrated controllers. + */ + if (pATI->Chip >= ATI_CHIP_264VTB) + ATIDSPSet(pATI, pATIHW); + + /* Load RAMDAC */ + ATIDACSet(pATI, pATIHW); + + /* Reset hardware cursor caching */ + pATI->CursorXOffset = pATI->CursorYOffset = (CARD16)(-1); + +#ifndef AVOID_CPIO + + /* Restore video memory */ + ATISwap(pScreenInfo->scrnIndex, pATI, pATIHW, TRUE); + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + ATIVGASaveScreen(pATI, SCREEN_SAVER_OFF); /* Turn on screen */ + +#endif /* AVOID_CPIO */ + + if ((xf86GetVerbosity() > 3) && (pATIHW == &pATI->NewHW)) + { + xf86ErrorFVerb(4, "\n After setting mode \"%s\":\n\n", + pScreenInfo->currentMode->name); + ATIPrintMode(pScreenInfo->currentMode); + ATIPrintRegisters(pATI); + } +} diff --git a/src/atimode.h b/src/atimode.h new file mode 100644 index 0000000..2cbc1db --- /dev/null +++ b/src/atimode.h @@ -0,0 +1,41 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimode.h,v 1.5 2003/01/01 19:16:32 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMODE_H___ +#define ___ATIMODE_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern void ATIModePreInit FunctionPrototype((ScrnInfoPtr, ATIPtr, + ATIHWPtr)); +extern void ATIModeSave FunctionPrototype((ScrnInfoPtr, ATIPtr, + ATIHWPtr)); +extern Bool ATIModeCalculate FunctionPrototype((int, ATIPtr, ATIHWPtr, + DisplayModePtr)); +extern void ATIModeSet FunctionPrototype((ScrnInfoPtr, ATIPtr, + ATIHWPtr)); + +#endif /* ___ATIMODE_H___ */ diff --git a/src/atimodule.c b/src/atimodule.c new file mode 100644 index 0000000..206e281 --- /dev/null +++ b/src/atimodule.c @@ -0,0 +1,127 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimodule.c,v 1.16 2003/05/28 14:08:03 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifdef XFree86LOADER + +#include "ati.h" +#include "atimodule.h" +#include "ativersion.h" + +/* Module loader interface */ + +const char *ATISymbols[] = +{ + "ATIPreInit", + "ATIScreenInit", + "ATISwitchMode", + "ATIAdjustFrame", + "ATIEnterVT", + "ATILeaveVT", + "ATIFreeScreen", + "ATIValidMode", + NULL +}; + +const char *R128Symbols[] = +{ + "R128PreInit", + "R128ScreenInit", + "R128SwitchMode", + "R128AdjustFrame", + "R128EnterVT", + "R128LeaveVT", + "R128FreeScreen", + "R128ValidMode", + "R128Options", + NULL +}; + +const char *RADEONSymbols[] = +{ + "RADEONPreInit", + "RADEONScreenInit", + "RADEONSwitchMode", + "RADEONAdjustFrame", + "RADEONEnterVT", + "RADEONLeaveVT", + "RADEONFreeScreen", + "RADEONValidMode", + "RADEONOptions", + "RADEONHandleMessage", + NULL +}; + +static XF86ModuleVersionInfo ATIVersionRec = +{ + ATI_DRIVER_NAME, + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + ATI_VERSION_MAJOR, ATI_VERSION_MINOR, ATI_VERSION_PATCH, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +/* + * ATISetup -- + * + * This function is called every time the module is loaded. + */ +static pointer +ATISetup +( + pointer Module, + pointer Options, + int *ErrorMajor, + int *ErrorMinor +) +{ + static Bool Inited = FALSE; + + if (!Inited) + { + Inited = TRUE; + xf86AddDriver(&ATI, Module, 0); + + xf86LoaderRefSymLists( + ATISymbols, + R128Symbols, + RADEONSymbols, + NULL); + } + + return (pointer)1; +} + +/* The following record must be called atiModuleData */ +XF86ModuleData atiModuleData = +{ + &ATIVersionRec, + ATISetup, + NULL +}; + +#endif /* XFree86LOADER */ diff --git a/src/atimodule.h b/src/atimodule.h new file mode 100644 index 0000000..1a203ae --- /dev/null +++ b/src/atimodule.h @@ -0,0 +1,31 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimodule.h,v 1.9 2003/01/01 19:16:32 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#if defined(XFree86LOADER) && !defined(___ATIMODULE_H___) +#define ___ATIMODULE_H___ 1 + +extern const char *ATISymbols[]; +extern const char *R128Symbols[]; +extern const char *RADEONSymbols[]; + +#endif /* ___ATIMODULE_H___ */ diff --git a/src/atimono.h b/src/atimono.h new file mode 100644 index 0000000..f050ceb --- /dev/null +++ b/src/atimono.h @@ -0,0 +1,43 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atimono.h,v 1.7 2003/01/01 19:16:33 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIMONO_H___ +#define ___ATIMONO_H___ 1 + +#ifndef BIT_PLANE +# define BIT_PLANE 3 +#endif + +#ifndef MONO_BLACK +# define MONO_BLACK 0x00U +#endif + +#ifndef MONO_WHITE +# define MONO_WHITE 0x3FU +#endif + +#ifndef MONO_OVERSCAN +# define MONO_OVERSCAN 0x01U +#endif + +#endif /* ___ATIMONO_H___ */ diff --git a/src/atioption.c b/src/atioption.c new file mode 100644 index 0000000..81b6d3b --- /dev/null +++ b/src/atioption.c @@ -0,0 +1,157 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atioption.c,v 1.22 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atioption.h" +#include "atiutil.h" + +#include "radeon_probe.h" +#include "r128_probe.h" + +/* + * Recognised XF86Config options. + */ +const OptionInfoRec ATIPublicOptions[] = +{ + { + ATI_OPTION_ACCEL, + "accel", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_CRT_DISPLAY, + "crt_display", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_CSYNC, + "composite_sync", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_HWCURSOR, + "hw_cursor", + OPTV_BOOLEAN, + {0, }, + FALSE, + }, + +#ifndef AVOID_CPIO + + { + ATI_OPTION_LINEAR, + "linear", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + +#endif /* AVOID_CPIO */ + + { + ATI_OPTION_MMIO_CACHE, + "mmio_cache", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_TEST_MMIO_CACHE, + "test_mmio_cache", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_PANEL_DISPLAY, + "panel_display", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_PROBE_CLOCKS, + "probe_clocks", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_REFERENCE_CLOCK, + "reference_clock", + OPTV_FREQ, + {0, }, + FALSE + }, + { + ATI_OPTION_SHADOW_FB, + "shadow_fb", + OPTV_BOOLEAN, + {0, }, + FALSE + }, + { + ATI_OPTION_SWCURSOR, + "sw_cursor", + OPTV_BOOLEAN, + {0, }, + FALSE, + }, + { + -1, + NULL, + OPTV_NONE, + {0, }, + FALSE + } +}; + +const unsigned long ATIPublicOptionSize = SizeOf(ATIPublicOptions); + +/* + * ATIAvailableOptions -- + * + * Return recognised options that are intended for public consumption. + */ +const OptionInfoRec * +ATIAvailableOptions +( + int ChipId, + int BusId +) +{ + const OptionInfoRec *pOptions; + + if ((pOptions = R128AvailableOptions(ChipId, BusId))) + return pOptions; + + if ((pOptions = RADEONAvailableOptions(ChipId, BusId))) + return pOptions; + + return ATIPublicOptions; +} diff --git a/src/atioption.h b/src/atioption.h new file mode 100644 index 0000000..53e2be4 --- /dev/null +++ b/src/atioption.h @@ -0,0 +1,61 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atioption.h,v 1.12 2003/04/23 21:51:29 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIOPTION_H___ +#define ___ATIOPTION_H___ 1 + +#include "atiproto.h" + +#include "xf86str.h" + +/* + * Documented XF86Config options. + */ +typedef enum +{ + ATI_OPTION_ACCEL, + ATI_OPTION_CRT_DISPLAY, + ATI_OPTION_CSYNC, + ATI_OPTION_HWCURSOR, + +#ifndef AVOID_CPIO + + ATI_OPTION_LINEAR, + +#endif /* AVOID_CPIO */ + + ATI_OPTION_MMIO_CACHE, + ATI_OPTION_TEST_MMIO_CACHE, + ATI_OPTION_PANEL_DISPLAY, + ATI_OPTION_PROBE_CLOCKS, + ATI_OPTION_REFERENCE_CLOCK, + ATI_OPTION_SHADOW_FB, + ATI_OPTION_SWCURSOR +} ATIPublicOptionType; + +extern const OptionInfoRec ATIPublicOptions[]; +extern const unsigned long ATIPublicOptionSize; + +extern const OptionInfoRec * ATIAvailableOptions FunctionPrototype((int, int)); + +#endif /* ___ATIOPTION_H___ */ diff --git a/src/atipreinit.c b/src/atipreinit.c new file mode 100644 index 0000000..a3523da --- /dev/null +++ b/src/atipreinit.c @@ -0,0 +1,3484 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atipreinit.c,v 1.74 2003/12/22 17:48:09 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atiadjust.h" +#include "atiaudio.h" +#include "atibus.h" +#include "atichip.h" +#include "aticonfig.h" +#include "aticursor.h" +#include "atidac.h" +#include "atidsp.h" +#include "atii2c.h" +#include "atiident.h" +#include "atiload.h" +#include "atilock.h" +#include "atimach64.h" +#include "atimach64accel.h" +#include "atimach64io.h" +#include "atimode.h" +#include "atipreinit.h" +#include "atiprint.h" +#include "atividmem.h" +#include "atiwonderio.h" +#include "atixv.h" + +#include "vbe.h" +#include "xf86RAC.h" + +#ifndef AVOID_CPIO + +typedef CARD16 Colour; /* The correct spelling should be OK :-) */ + +/* + * Bit patterns which are extremely unlikely to show up when reading from + * nonexistant memory (which normally shows up as either all bits set or all + * bits clear). + */ +static const Colour Test_Pixel[] = {0x5AA5U, 0x55AAU, 0xA55AU, 0xCA53U}; + +static const struct +{ + int videoRamSize; + int Miscellaneous_Options_Setting; + struct + { + short int x, y; + } + Coordinates[NumberOf(Test_Pixel) + 1]; +} +Test_Case[] = +{ + /* + * Given the engine settings used, only a 4M card will have enough memory + * to back up the 1025th line of the display. Since the pixel coordinates + * are zero-based, line 1024 will be the first one which is only backed on + * 4M cards. + * + * <Mark_Weaver@brown.edu>: + * In case memory is being wrapped, (0,0) and (0,1024) to make sure they + * can each hold a unique value. + */ + {4096, MEM_SIZE_4M, {{0,0}, {0,1024}, {-1,-1}}}, + + /* + * This card has 2M or less. On a 1M card, the first 2M of the card's + * memory will have even doublewords backed by physical memory and odd + * doublewords unbacked. + * + * Pixels 0 and 1 of a row will be in the zeroth doubleword, while pixels 2 + * and 3 will be in the first. Check both pixels 2 and 3 in case this is a + * pseudo-1M card (one chip pulled to turn a 2M card into a 1M card). + * + * <Mark_Weaver@brown.edu>: + * I don't have a 1M card, so I'm taking a stab in the dark. Maybe memory + * wraps every 512 lines, or maybe odd doublewords are aliases of their + * even doubleword counterparts. I try everything here. + */ + {2048, MEM_SIZE_2M, {{0,0}, {0,512}, {2,0}, {3,0}, {-1,-1}}}, + + /* + * This is a either a 1M card or a 512k card. Test pixel 1, since it is an + * odd word in an even doubleword. + * + * <Mark_Weaver@brown.edu>: + * This is the same idea as the test above. + */ + {1024, MEM_SIZE_1M, {{0,0}, {0,256}, {1,0}, {-1,-1}}}, + + /* + * Assume it is a 512k card by default, since that is the minimum + * configuration. + */ + {512, MEM_SIZE_512K, {{-1,-1}}} +}; + +/* + * ATIMach32ReadPixel -- + * + * Return the colour of the specified screen location. Called from + * ATIMach32videoRam function below. + */ +static Colour +ATIMach32ReadPixel +( + const short int X, + const short int Y +) +{ + Colour Pixel_Colour; + + /* Wait for idle engine */ + ProbeWaitIdleEmpty(); + + /* Set up engine for pixel read */ + ATIWaitQueue(7); + outw(RD_MASK, (CARD16)(~0)); + outw(DP_CONFIG, FG_COLOR_SRC_BLIT | DATA_WIDTH | DRAW | DATA_ORDER); + outw(CUR_X, X); + outw(CUR_Y, Y); + outw(DEST_X_START, X); + outw(DEST_X_END, X + 1); + outw(DEST_Y_END, Y + 1); + + /* Wait for data to become ready */ + ATIWaitQueue(16); + WaitDataReady(); + + /* Read pixel colour */ + Pixel_Colour = inw(PIX_TRANS); + ProbeWaitIdleEmpty(); + return Pixel_Colour; +} + +/* + * ATIMach32WritePixel -- + * + * Set the colour of the specified screen location. Called from + * ATIMach32videoRam function below. + */ +static void +ATIMach32WritePixel +( + const short int X, + const short int Y, + const Colour Pixel_Colour +) +{ + /* Set up engine for pixel write */ + ATIWaitQueue(9); + outw(WRT_MASK, (CARD16)(~0)); + outw(DP_CONFIG, FG_COLOR_SRC_FG | DRAW | READ_WRITE); + outw(ALU_FG_FN, MIX_FN_PAINT); + outw(FRGD_COLOR, Pixel_Colour); + outw(CUR_X, X); + outw(CUR_Y, Y); + outw(DEST_X_START, X); + outw(DEST_X_END, X + 1); + outw(DEST_Y_END, Y + 1); +} + +/* + * ATIMach32videoRam -- + * + * Determine the amount of video memory installed on an 68800-6 based adapter. + * This is done because these chips exhibit a bug that causes their + * MISC_OPTIONS register to report 1M rather than the true amount of memory. + * + * This function is adapted from a similar function in mach32mem.c written by + * Robert Wolff, David Dawes and Mark Weaver. + */ +static int +ATIMach32videoRam +( + void +) +{ + CARD16 clock_sel, mem_bndry, misc_options, ext_ge_config; + Colour saved_Pixel[NumberOf(Test_Pixel)]; + unsigned int Case_Number, Pixel_Number; + Bool AllPixelsOK; + + /* Save register values to be modified */ + clock_sel = inw(CLOCK_SEL); + mem_bndry = inw(MEM_BNDRY); + misc_options = inw(MISC_OPTIONS) & ~MEM_SIZE_ALIAS; + ext_ge_config = inw(R_EXT_GE_CONFIG); + + /* Wait for enough FIFO entries */ + ATIWaitQueue(7); + + /* Enable accelerator */ + outw(CLOCK_SEL, clock_sel | DISABPASSTHRU); + + /* Make accelerator and VGA share video memory */ + outw(MEM_BNDRY, mem_bndry & ~(MEM_PAGE_BNDRY | MEM_BNDRY_ENA)); + + /* Prevent video memory wrap */ + outw(MISC_OPTIONS, misc_options | MEM_SIZE_4M); + + /* + * Set up the drawing engine for a pitch of 1024 at 16 bits per pixel. No + * need to mess with the CRT because the results of this test are not + * intended to be seen. + */ + outw(EXT_GE_CONFIG, PIXEL_WIDTH_16 | ORDER_16BPP_565 | MONITOR_8514 | + ALIAS_ENA); + outw(GE_PITCH, 1024 >> 3); + outw(GE_OFFSET_HI, 0); + outw(GE_OFFSET_LO, 0); + + for (Case_Number = 0; + Case_Number < (NumberOf(Test_Case) - 1); + Case_Number++) + { + /* Reduce redundancy as per Mark_Weaver@brown.edu */ +# define TestPixel Test_Case[Case_Number].Coordinates[Pixel_Number] +# define ForEachTestPixel \ + for (Pixel_Number = 0; TestPixel.x >= 0; Pixel_Number++) + + /* Save pixel colours that will be clobbered */ + ForEachTestPixel + saved_Pixel[Pixel_Number] = + ATIMach32ReadPixel(TestPixel.x, TestPixel.y); + + /* Write test patterns */ + ForEachTestPixel + ATIMach32WritePixel(TestPixel.x, TestPixel.y, + Test_Pixel[Pixel_Number]); + + /* Test for lost pixels */ + AllPixelsOK = TRUE; + ForEachTestPixel + { + if (ATIMach32ReadPixel(TestPixel.x, TestPixel.y) != + Test_Pixel[Pixel_Number]) + { + AllPixelsOK = FALSE; + break; + } + } + + /* Restore clobbered pixels */ + ForEachTestPixel + ATIMach32WritePixel(TestPixel.x, TestPixel.y, + saved_Pixel[Pixel_Number]); + + /* End test on success */ + if (AllPixelsOK) + break; + + /* Completeness */ +# undef ForEachTestPixel +# undef TestPixel + } + + /* Restore what was changed and correct MISC_OPTIONS register */ + ATIWaitQueue(4); + outw(EXT_GE_CONFIG, ext_ge_config); + misc_options |= Test_Case[Case_Number].Miscellaneous_Options_Setting; + outw(MISC_OPTIONS, misc_options); + outw(MEM_BNDRY, mem_bndry); + outw(CLOCK_SEL, clock_sel); + + /* Wait for activity to die down */ + ProbeWaitIdleEmpty(); + + /* Tell ATIPreInit the REAL story */ + return Test_Case[Case_Number].videoRamSize; +} + +#endif /* AVOID_CPIO */ + +/* + * ATIReportMemory -- + * + * This function reports on the amount and type of video memory found. + */ +static void +ATIReportMemory +( + ScrnInfoPtr pScreenInfo, + ATIPtr pATI, + const char *MemoryTypeName +) +{ + char Buffer[128], *Message; + + Message = Buffer + + snprintf(Buffer, SizeOf(Buffer), "%d kB of %s detected", + pATI->VideoRAM, MemoryTypeName); + +#ifndef AVOID_CPIO + + if (pATI->depth == 1) + { + /* 1bpp only uses one plane of four */ + pScreenInfo->videoRam /= 4; + Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, + " (using %d kB)", pScreenInfo->videoRam); + } + else + +#endif /* AVOID_CPIO */ + + if (pATI->VideoRAM > pScreenInfo->videoRam) + { + Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, + " (using %d kB)", pScreenInfo->videoRam); + } + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s.\n", Buffer); +} + +static const int videoRamSizes[] = + {0, 256, 512, 1024, 2*1024, 4*1024, 6*1024, 8*1024, 12*1024, 16*1024, 0}; +static const rgb defaultWeight = {0, 0, 0}; +static const Gamma defaultGamma = {0.0, 0.0, 0.0}; + +/* + * ATIMach64Map -- + * + * This function attempts to mmap() a Mach64's MMIO aperture. + */ +static void +ATIMach64Map +( + int iScreen, + ATIPtr pATI +) +{ + (void)ATIMapApertures(iScreen, pATI); + if (!pATI->pBlock[0] || + (pATI->config_chip_id != inr(CONFIG_CHIP_ID))) + ATIUnmapApertures(iScreen, pATI); +} + +/* + * ATIPrintNoiseIfRequested -- + * + * This function formats debugging information on the server's stderr when + * requested by the user through the server's verbosity setting. + */ +static void +ATIPrintNoiseIfRequested +( + ATIPtr pATI, + CARD8 *BIOS, + unsigned int BIOSSize +) +{ + if (xf86GetVerbosity() <= 3) + return; + + if (BIOSSize > 0) + ATIPrintBIOS(BIOS, BIOSSize); + xf86ErrorFVerb(4, "\n On server entry:\n"); + ATIPrintRegisters(pATI); +} + +/* + * ATIPreInit -- + * + * This function is only called once per screen at the start of the first + * server generation. + */ +Bool +ATIPreInit +( + ScrnInfoPtr pScreenInfo, + int flags +) +{ +# define BIOS_SIZE 0x00010000U /* 64kB */ + CARD8 BIOS[BIOS_SIZE]; +# define BIOSByte(_n) ((CARD8)(BIOS[_n])) +# define BIOSWord(_n) ((CARD16)(BIOS[_n] | \ + (BIOS[(_n) + 1] << 8))) +# define BIOSLong(_n) ((CARD32)(BIOS[_n] | \ + (BIOS[(_n) + 1] << 8) | \ + (BIOS[(_n) + 2] << 16) | \ + (BIOS[(_n) + 3] << 24))) + unsigned int BIOSSize = 0; + unsigned int ROMTable = 0, ClockTable = 0, FrequencyTable = 0; + unsigned int LCDTable = 0, LCDPanelInfo = 0, VideoTable = 0; + unsigned int HardwareTable = 0; + + char Buffer[128], *Message; + ATIPtr pATI; + GDevPtr pGDev; + EntityInfoPtr pEntity; + resPtr pResources; + pciVideoPtr pVideo; + DisplayModePtr pMode; + unsigned long Block0Base; + CARD32 IOValue; + int i, j, AcceleratorVideoRAM = 0, ServerVideoRAM; + int Numerator, Denominator; + int MinX, MinY; + ClockRange ATIClockRange = {NULL, 0, 80000, 0, TRUE, TRUE, 1, 1, 0}; + int DefaultmaxClock = 0; + int minPitch, maxPitch = 0xFFU, maxHeight = 0; + int ApertureSize = 0x00010000U; + int ModeType = M_T_BUILTIN; + LookupModeFlags Strategy = LOOKUP_CLOSEST_CLOCK; + int DefaultDepth; + +# define pATIHW (&pATI->OldHW) + +#ifndef AVOID_CPIO + + xf86Int10InfoPtr pInt10Info = NULL; + vbeInfoPtr pVBE; + pointer pInt10Module, pDDCModule = NULL, pVBEModule = NULL; + int VGAVideoRAM = 0; + resRange Resources[2] = {{0, 0, 0}, _END}; + +#endif /* AVOID_CPIO */ + + if (pScreenInfo->numEntities != 1) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Logic error: Number of attached entities not 1.\n"); + return FALSE; + } + + pATI = ATIPTR(pScreenInfo); + + if (pATI->iEntity != pScreenInfo->entityList[0]) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Logic error: Entity mismatch.\n"); + return FALSE; + } + + /* Register resources */ + pEntity = xf86GetEntityInfo(pATI->iEntity); + pGDev = pEntity->device; + pResources = pEntity->resources; + xfree(pEntity); + if (!pResources) + pResources = xf86RegisterResources(pATI->iEntity, NULL, + pATI->SharedAccelerator ? ResShared : ResExclusive); + if (pResources) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Unable to register the following bus resources:\n"); + xf86PrintResList(0, pResources); + xf86FreeResList(pResources); + return FALSE; + } + + ConfiguredMonitor = NULL; + (void)memset(BIOS, 0, SizeOf(BIOS)); + + if (!(flags & PROBE_DETECT)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, + pATI->Chipset ? X_CONFIG : X_DEFAULT, + "Chipset: \"%s\".\n", ATIChipsetNames[pATI->Chipset]); + + /* Promote chipset specification */ + switch (pATI->Chipset) + { + +#ifndef AVOID_CPIO + + case ATI_CHIPSET_IBMVGA: + if (pATI->Adapter == ATI_ADAPTER_VGA) + break; /* XXX */ + /* Fall through */ + + case ATI_CHIPSET_VGAWONDER: + pATI->Chipset = ATI_CHIPSET_ATIVGA; + break; + + case ATI_CHIPSET_IBM8514: + if (pATI->Adapter == ATI_ADAPTER_8514A) + break; /* XXX */ + /* Fall through */ + + case ATI_CHIPSET_MACH8: + case ATI_CHIPSET_MACH32: + +#endif /* AVOID_CPIO */ + + case ATI_CHIPSET_MACH64: + case ATI_CHIPSET_RAGE128: + case ATI_CHIPSET_RADEON: + pATI->Chipset = ATI_CHIPSET_ATI; + break; + + default: + break; + } + + /* Set monitor */ + pScreenInfo->monitor = pScreenInfo->confScreen->monitor; + + /* Set depth, bpp, etc. */ + if ((pATI->Chipset != ATI_CHIPSET_ATI) || + (pATI->Chip < ATI_CHIP_264CT)) + { + i = NoDepth24Support; /* No support for >8bpp either */ + DefaultDepth = 8; + } + else + { + i = Support24bppFb | Support32bppFb; + DefaultDepth = 0; + } + + if (!xf86SetDepthBpp(pScreenInfo, DefaultDepth, 0, 0, i)) + return FALSE; + + for (j = 0; ; j++) + { + static const CARD8 AllowedDepthBpp[][2] = + { + +#ifndef AVOID_CPIO + + { 1, 1}, + { 4, 4}, + { 4, 8}, + +#endif /* AVOID_CPIO */ + + { 8, 8}, + {15, 16}, + {16, 16}, + {24, 24}, + {24, 32} + }; + + if (j < NumberOf(AllowedDepthBpp)) + { + if (pScreenInfo->depth > AllowedDepthBpp[j][0]) + continue; + + if (pScreenInfo->depth == AllowedDepthBpp[j][0]) + { + if (pScreenInfo->bitsPerPixel > AllowedDepthBpp[j][1]) + continue; + + if (pScreenInfo->bitsPerPixel == AllowedDepthBpp[j][1]) + break; + } + } + + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Driver does not support depth %d at fbbpp %d.\n", + pScreenInfo->depth, pScreenInfo->bitsPerPixel); + return FALSE; + } + + xf86PrintDepthBpp(pScreenInfo); + + if ((i == NoDepth24Support) && (pScreenInfo->depth > 8)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Depth %d is not supported through this adapter.\n", + pScreenInfo->depth); + return FALSE; + } + + /* Pick up XF86Config options */ + ATIProcessOptions(pScreenInfo, pATI); + } + +#ifdef AVOID_CPIO + + else /* if (flags & PROBE_DETECT) */ + { + return TRUE; + } + +#else /* AVOID_CPIO */ + + /* + * If there is an ix86-style BIOS, ensure its initialisation entry point + * has been executed, and retrieve DDC and VBE information from it. + */ + if (!(pInt10Module = ATILoadModule(pScreenInfo, "int10", ATIint10Symbols))) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to load int10 module.\n"); + } + else if (!(pInt10Info = xf86InitInt10(pATI->iEntity))) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to initialise int10 interface.\n"); + } + else + { + if (!(pDDCModule = ATILoadModule(pScreenInfo, "ddc", ATIddcSymbols))) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to load ddc module.\n"); + } + else + if (!(pVBEModule = ATILoadModule(pScreenInfo, "vbe", ATIvbeSymbols))) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to load vbe module.\n"); + } + else + { + if ((pVBE = VBEInit(pInt10Info, pATI->iEntity))) + { + ConfiguredMonitor = vbeDoEDID(pVBE, pDDCModule); + vbeFree(pVBE); + } + xf86UnloadSubModule(pVBEModule); + } + + if (!(flags & PROBE_DETECT)) + { + /* Validate, then make a private copy of, the initialised BIOS */ + CARD8 *pBIOS = xf86int10Addr(pInt10Info, pInt10Info->BIOSseg << 4); + + if ((pBIOS[0] != 0x55U) || (pBIOS[1] != 0xAAU) || !pBIOS[2]) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to correctly retrieve adapter BIOS.\n"); + } + else + { + BIOSSize = pBIOS[2] << 9; + if (BIOSSize > BIOS_SIZE) + BIOSSize = BIOS_SIZE; + (void)memcpy(BIOS, pBIOS, BIOSSize); + } + } + } + + /* De-activate int10 */ + xf86FreeInt10(pInt10Info); + xf86UnloadSubModule(pInt10Module); + + if (flags & PROBE_DETECT) + { + xf86UnloadSubModule(pDDCModule); + return TRUE; + } + + if (ConfiguredMonitor) + { + xf86PrintEDID(ConfiguredMonitor); + xf86SetDDCproperties(pScreenInfo, ConfiguredMonitor); + } + + /* DDC module is no longer needed at this point */ + xf86UnloadSubModule(pDDCModule); + +#endif /* AVOID_CPIO */ + + pATI->Block0Base = 0; /* Might no longer be valid */ + if ((pVideo = pATI->PCIInfo)) + { + if (pATI->CPIODecoding == BLOCK_IO) + pATI->CPIOBase = pVideo->ioBase[1]; + + /* Set MMIO address from PCI configuration space, if available */ + if ((pATI->Block0Base = pVideo->memBase[2])) + { + if (pATI->Block0Base >= (CARD32)(-1 << pVideo->size[2])) + pATI->Block0Base = 0; + else + pATI->Block0Base += 0x0400U; + } + } + +#ifdef AVOID_CPIO + + pScreenInfo->racMemFlags = + RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; + +#else /* AVOID_CPIO */ + + pScreenInfo->racIoFlags = + RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; + pScreenInfo->racMemFlags = RAC_FB | RAC_CURSOR; + +#endif /* AVOID_CPIO */ + + /* Deal with ChipID & ChipRev overrides */ + if (pGDev->chipID >= 0) + { + ATIChipType Chip; + + Chip = ATIChipID(pGDev->chipID, + (pGDev->chipRev < 0) ? pATI->ChipRev : pGDev->chipRev); + if (Chip != pATI->Chip) + { + pATI->Chip = Chip; + pATI->ChipType = pGDev->chipID; + if (pGDev->chipRev < 0) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, + "Driver messages reflect ChipID 0x%04X override.\n", + pATI->ChipType); + } + else + { + pATI->ChipRev = pGDev->chipRev; + pATI->ChipVersion = GetBits(pATI->ChipRev, + GetBits(CFG_CHIP_VERSION, CFG_CHIP_REV)); + pATI->ChipFoundry = GetBits(pATI->ChipRev, + GetBits(CFG_CHIP_FOUNDRY, CFG_CHIP_REV)); + pATI->ChipRevision = GetBits(pATI->ChipRev, + GetBits(CFG_CHIP_REVISION, CFG_CHIP_REV)); + xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, + "Driver messages reflect ChipID 0x%04X and ChipRev 0x%02X" + " overrides.\n", pATI->ChipType, pATI->ChipRev); + } + } + } + + /* Finish private area initialisation */ + pATI->DAC = ATI_DAC_GENERIC; + +#ifndef AVOID_CPIO + + pATI->NewHW.SetBank = ATIx8800SetBank; + pATI->BankInfo.SetSourceBank = ATIx8800SetRead; + pATI->BankInfo.SetDestinationBank = ATIx8800SetWrite; + pATI->BankInfo.SetSourceAndDestinationBanks = ATIx8800SetReadWrite; + pATI->BankInfo.BankSize = 0x00010000U; /* 64kB */ + +#endif /* AVOID_CPIO */ + + pATI->LCDPanelID = -1; + pATI->nFIFOEntries = 16; /* For now */ + pATI->Audio = ATI_AUDIO_NONE; + + /* Finish probing the adapter */ + switch (pATI->Adapter) + { + +#ifndef AVOID_CPIO + + case ATI_ADAPTER_NONE: + case ATI_ADAPTER_EGA: + case ATI_ADAPTER_EGA_PLUS: + case ATI_ADAPTER_VGA: + case ATI_ADAPTER_BASIC: + pATI->NewHW.SetBank = (ATIBankProcPtr)NoopDDA; + pATI->BankInfo.SetSourceBank = + pATI->BankInfo.SetDestinationBank = + pATI->BankInfo.SetSourceAndDestinationBanks = + (miBankProcPtr)NoopDDA; + break; + + case ATI_ADAPTER_V3: + pATI->NewHW.SetBank = ATIV3SetBank; + pATI->BankInfo.SetSourceBank = ATIV3SetRead; + pATI->BankInfo.SetDestinationBank = ATIV3SetWrite; + pATI->BankInfo.SetSourceAndDestinationBanks = ATIV3SetReadWrite; + break; + + case ATI_ADAPTER_V4: + case ATI_ADAPTER_V5: + pATI->NewHW.SetBank = ATIV4V5SetBank; + pATI->BankInfo.SetSourceBank = ATIV4V5SetRead; + pATI->BankInfo.SetDestinationBank = ATIV4V5SetWrite; + pATI->BankInfo.SetSourceAndDestinationBanks = ATIV4V5SetReadWrite; + break; + + case ATI_ADAPTER_XL: + pATI->DAC = ATI_DAC_SC11483; + break; + + case ATI_ADAPTER_8514A: + pATI->VideoRAM = + videoRamSizes[GetBits(inw(SUBSYS_STAT), _8PLANE) + 2]; + break; + + case ATI_ADAPTER_MACH8: + pATI->VideoRAM = + videoRamSizes[GetBits(inw(CONFIG_STATUS_1), MEM_INSTALLED) + 2]; + break; + + case ATI_ADAPTER_MACH32: + IOValue = inw(CONFIG_STATUS_1); + pATI->DAC = ATI_DAC(GetBits(IOValue, DACTYPE), 0); + pATI->MemoryType = GetBits(IOValue, MEM_TYPE); + + IOValue = inw(MISC_OPTIONS); + pATI->VideoRAM = + videoRamSizes[GetBits(IOValue, MEM_SIZE_ALIAS) + 2]; + + /* + * The 68800-6 doesn't necessarily report the correct video memory + * size. + */ + if ((pATI->Chip == ATI_CHIP_68800_6) && (pATI->VideoRAM == 1024)) + pATI->VideoRAM = ATIMach32videoRam(); + + break; + +#endif /* AVOID_CPIO */ + + case ATI_ADAPTER_MACH64: + do + { + /* + * Find and mmap() MMIO area. Allow only auxiliary aperture if + * it exists. + */ + if (!(Block0Base = pATI->Block0Base)) + { + if (pVideo) + { + /* Check tail end of linear (8MB or 4MB) aperture */ + if ((pATI->Block0Base = pVideo->memBase[0])) + { + pATI->Block0Base += 0x007FFC00U; + ATIMach64Map(pScreenInfo->scrnIndex, pATI); + if (pATI->pBlock[0]) + break; + + pATI->Block0Base -= 0x00400000U; + ATIMach64Map(pScreenInfo->scrnIndex, pATI); + if (pATI->pBlock[0]) + break; + } + } + + /* Check VGA MMIO aperture */ + pATI->Block0Base = 0x000BFC00U; + } + + ATIMach64Map(pScreenInfo->scrnIndex, pATI); + } while (0); + pATI->Block0Base = Block0Base; + +#ifdef AVOID_CPIO + + if (!pATI->pBlock[0]) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Unable to mmap() adapter registers.\n"); + return FALSE; + } + +#endif /* AVOID_CPIO */ + + pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL); + if (!(pATIHW->crtc_gen_cntl & CRTC_EN) && + (pATI->Chip >= ATI_CHIP_264CT)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Adapter has not been initialised.\n"); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + +#ifdef AVOID_CPIO + + if (!(pATIHW->crtc_gen_cntl & CRTC_EXT_DISP_EN)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Adapters found to be in VGA mode on server entry are not" + " supported by the MMIO-only version of this driver.\n"); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + +#endif /* AVOID_CPIO */ + + pATIHW->mem_cntl = inr(MEM_CNTL); + if (pATI->Chip < ATI_CHIP_264VTB) + { + pATI->VideoRAM = + videoRamSizes[GetBits(pATIHW->mem_cntl, CTL_MEM_SIZE) + 2]; + } + else + { + pATI->nFIFOEntries = /* Don't care */ + (unsigned int)(-1) >> 1; + + IOValue = GetBits(pATIHW->mem_cntl, CTL_MEM_SIZEB); + if (IOValue < 8) + pATI->VideoRAM = (IOValue + 1) * 512; + else if (IOValue < 12) + pATI->VideoRAM = (IOValue - 3) * 1024; + else + pATI->VideoRAM = (IOValue - 7) * 2048; + } + + pATI->DAC = GetBits(inr(DAC_CNTL), DAC_TYPE); + + IOValue = inr(CONFIG_STATUS64_0); + if (pATI->Chip >= ATI_CHIP_264CT) + { + pATI->MemoryType = GetBits(IOValue, CFG_MEM_TYPE_T); + + /* Get LCD panel id */ + if (pATI->Chip == ATI_CHIP_264LT) + { + pATI->LCDPanelID = GetBits(IOValue, CFG_PANEL_ID); + + pATIHW->horz_stretching = inr(HORZ_STRETCHING); + pATIHW->vert_stretching = inr(VERT_STRETCHING); + pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL); + } + else if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) + { + pATI->LCDPanelID = GetBits(IOValue, CFG_PANEL_ID); + + pATIHW->lcd_index = inr(LCD_INDEX); + pATIHW->horz_stretching = + ATIMach64GetLCDReg(LCD_HORZ_STRETCHING); + pATI->LCDHorizontal = + GetBits(pATIHW->horz_stretching, HORZ_PANEL_SIZE); + if (pATI->LCDHorizontal) + { + if (pATI->LCDHorizontal == MaxBits(HORZ_PANEL_SIZE)) + pATI->LCDHorizontal = 0; + else + pATI->LCDHorizontal = + (pATI->LCDHorizontal + 1) << 3; + } + pATIHW->ext_vert_stretch = + ATIMach64GetLCDReg(LCD_EXT_VERT_STRETCH); + pATI->LCDVertical = + GetBits(pATIHW->ext_vert_stretch, VERT_PANEL_SIZE); + if (pATI->LCDVertical) + { + if (pATI->LCDVertical == MaxBits(VERT_PANEL_SIZE)) + pATI->LCDVertical = 0; + else + pATI->LCDVertical++; + } + pATIHW->vert_stretching = + ATIMach64GetLCDReg(LCD_VERT_STRETCHING); + pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + outr(LCD_INDEX, pATIHW->lcd_index); + } + + /* + * Don't bother with panel support if it hasn't been previously + * enabled. + */ + if ((pATI->LCDPanelID >= 0) && + !(pATIHW->horz_stretching & HORZ_STRETCH_EN) && + !(pATIHW->vert_stretching & VERT_STRETCH_EN) && + !(pATIHW->lcd_gen_ctrl & LCD_ON)) + { + /* + * At this point, if an XL or Mobility BIOS hasn't set + * panel dimensions, then there is no panel. Otherwise, + * keep any panel disabled to allow for modes greater than + * the panel's dimensions. + */ + if ((pATI->Chip >= ATI_CHIP_264XL) && + (!pATI->LCDHorizontal || !pATI->LCDVertical)) + pATI->LCDPanelID = -1; + else + pATI->OptionPanelDisplay = FALSE; + } + } + else + { + pATI->MemoryType = GetBits(IOValue, CFG_MEM_TYPE); + + /* Factor in what the BIOS says the DAC is */ + pATI->DAC = ATI_DAC(pATI->DAC, + GetBits(inr(SCRATCH_REG1), BIOS_INIT_DAC_SUBTYPE)); + } + + /* + * RAMDAC types 0 & 1 for Mach64's are different than those for + * Mach32's. + */ + if (pATI->DAC < ATI_DAC_ATI68875) + pATI->DAC += ATI_DAC_INTERNAL; + + break; + + default: + break; + } + + /* + * For Mach64 adapters, pick up, from the BIOS, the type of programmable + * clock generator (if any), and various information about it. + */ + +#ifndef AVOID_CPIO + + if (pATI->Chip >= ATI_CHIP_88800GXC) + +#endif /* AVOID_CPIO */ + + { + CARD16 ClockDac; + + /* Set up non-zero defaults */ + pATI->ClockDescriptor = ATIClockDescriptors[ATI_CLOCK_FIXED]; + pATI->ClockNumberToProgramme = -1; + + ROMTable = BIOSWord(0x48U); + if ((ROMTable < 0x0002U) || + (BIOSWord(ROMTable - 0x02U) < 0x0012U) || + ((ROMTable + BIOSWord(ROMTable - 0x02U)) > BIOSSize)) + ROMTable = 0; + + if (ROMTable > 0) + { + ClockTable = BIOSWord(ROMTable + 0x10U); + if ((ClockTable + 0x20U) > BIOSSize) + ClockTable = 0; + + if (BIOSWord(ROMTable - 0x02U) >= 0x0048U) + { + VideoTable = BIOSWord(ROMTable + 0x46U); + if ((VideoTable < 0x08U) || + (BIOSByte(VideoTable - 0x01U) < 0x08U) || + (BIOSByte(VideoTable - 0x02U) > 0x01U) || + ((VideoTable + BIOSByte(VideoTable - 0x01U)) > BIOSSize)) + VideoTable = 0; + } + + if (BIOSWord(ROMTable - 0x02U) >= 0x004AU) + { + HardwareTable = BIOSWord(ROMTable + 0x48U); + if (((HardwareTable + 0x08U) <= BIOSSize) && + !memcmp(BIOS + HardwareTable, "$ATI", 4)) + pATI->I2CType = BIOSByte(HardwareTable + 0x06U) & 0x0FU; + else + HardwareTable = 0; + } + } + + if (ClockTable > 0) + { + FrequencyTable = BIOSWord(ClockTable - 0x02U); + if ((FrequencyTable > 0) && + ((FrequencyTable + 0x20U) <= BIOSSize)) + { + for (i = 0; i < 16; i++) + { + pATI->BIOSClocks[i] = BIOSWord(FrequencyTable); + FrequencyTable += 2; + } + } + pATI->ProgrammableClock = BIOSByte(ClockTable); + pATI->ClockNumberToProgramme = BIOSByte(ClockTable + 0x06U); + switch (BIOSWord(ClockTable + 0x08U) / 10) + { + case 143: + pATI->ReferenceNumerator = 157500; + pATI->ReferenceDenominator = 11; + break; + + case 286: + pATI->ReferenceNumerator = 315000; + pATI->ReferenceDenominator = 11; + break; + + default: + pATI->ReferenceNumerator = + BIOSWord(ClockTable + 0x08U) * 10; + pATI->ReferenceDenominator = 1; + break; + } + } + else + { + /* + * Compensate for BIOS absence. Note that the reference + * frequency has already been set by option processing. + */ + if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL) + { + pATI->ProgrammableClock = ATI_CLOCK_INTERNAL; + } + else switch (pATI->DAC) + { + case ATI_DAC_STG1703: + pATI->ProgrammableClock = ATI_CLOCK_STG1703; + break; + + case ATI_DAC_CH8398: + pATI->ProgrammableClock = ATI_CLOCK_CH8398; + break; + + case ATI_DAC_ATT20C408: + pATI->ProgrammableClock = ATI_CLOCK_ATT20C408; + break; + + case ATI_DAC_IBMRGB514: + pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514; + break; + + default: /* Provisional */ + pATI->ProgrammableClock = ATI_CLOCK_ICS2595; + break; + } + + /* This should be safe for all generators except IBM's RGB514 */ + pATI->ClockNumberToProgramme = 3; + } + + if ((pATI->ProgrammableClock > ATI_CLOCK_FIXED) && + (pATI->ProgrammableClock < ATI_CLOCK_MAX)) + { + /* + * Graphics PRO TURBO 1600's are unusual in that an ICS2595 is used + * to generate clocks for VGA modes, and an IBM RGB514 is used for + * accelerator modes. + */ + if ((pATI->ProgrammableClock == ATI_CLOCK_ICS2595) && + (pATI->DAC == ATI_DAC_IBMRGB514) && + (pScreenInfo->depth >= 8) && + (pATI->Chipset == ATI_CHIPSET_ATI)) + pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514; + + pATI->ClockDescriptor = + ATIClockDescriptors[pATI->ProgrammableClock]; + } + + ClockDac = pATI->DAC; + switch (pATI->ProgrammableClock) + { + case ATI_CLOCK_ICS2595: + /* + * Pick up reference divider (43 or 46) appropriate to the chip + * revision level. + */ + if (ClockTable > 0) + pATI->ClockDescriptor.MinM = + pATI->ClockDescriptor.MaxM = + BIOSWord(ClockTable + 0x0AU); + else if (!xf86NameCmp(pGDev->clockchip, "ATI 18818-0")) + pATI->ClockDescriptor.MinM = + pATI->ClockDescriptor.MaxM = 43; + else if (!xf86NameCmp(pGDev->clockchip, "ATI 18818-1")) + pATI->ClockDescriptor.MinM = + pATI->ClockDescriptor.MaxM = 46; + else + pATI->ProgrammableClock = ATI_CLOCK_UNKNOWN; + break; + + case ATI_CLOCK_STG1703: + /* This one's also a RAMDAC */ + ClockDac = ATI_DAC_STG1703; + break; + + case ATI_CLOCK_CH8398: + /* This one's also a RAMDAC */ + ClockDac = ATI_DAC_CH8398; + break; + + case ATI_CLOCK_INTERNAL: + /* + * The reference divider has already been programmed by BIOS + * initialisation. Because, there is only one reference + * divider for all generated frequencies (including MCLK), it + * cannot be changed without reprogramming all clocks every + * time one of them needs a different reference divider. + * + * Besides, it's not a good idea to change the reference + * divider. BIOS initialisation sets it to a value that + * effectively prevents generating frequencies beyond the + * graphics controller's tolerance. + */ + pATI->ClockDescriptor.MinM = pATI->ClockDescriptor.MaxM = + ATIMach64GetPLLReg(PLL_REF_DIV); + + /* The DAC is also integrated */ + if ((pATI->DAC & ~0x0FU) != ATI_DAC_INTERNAL) + ClockDac = ATI_DAC_INTERNAL; + + break; + + case ATI_CLOCK_ATT20C408: + /* This one's also a RAMDAC */ + ClockDac = ATI_DAC_ATT20C408; + break; + + case ATI_CLOCK_IBMRGB514: + /* This one's also a RAMDAC */ + ClockDac = ATI_DAC_IBMRGB514; + pATI->ClockNumberToProgramme = 7; + break; + + default: + break; + } + + /* + * We now have up to two indications of what RAMDAC the adapter uses. + * They should be the same. The following test and corresponding + * action are under construction. + */ + if (pATI->DAC != ClockDac) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Mach64 RAMDAC probe discrepancy detected:\n" + " DAC=0x%02X; ClockDac=0x%02X.\n", + pATI->DAC, ClockDac); + + if (pATI->DAC == ATI_DAC_IBMRGB514) + { + pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514; + pATI->ClockDescriptor = + ATIClockDescriptors[ATI_CLOCK_IBMRGB514]; + pATI->ClockNumberToProgramme = 7; + } + else + { + pATI->DAC = ClockDac; /* For now */ + } + } + + /* + * Pick up multimedia information, which will be at different + * displacements depending on table revision. + */ + if (VideoTable > 0) + { + switch (BIOSByte(VideoTable - 0x02U)) + { + case 0x00U: + pATI->Tuner = BIOSByte(VideoTable) & 0x1FU; + + /* + * XXX The VideoTable[1] byte is known to have been + * omitted in LTPro and Mobility BIOS'es. Any others? + */ + switch (pATI->Chip) + { + case ATI_CHIP_264LTPRO: + case ATI_CHIP_MOBILITY: + pATI->Decoder = + BIOSByte(VideoTable + 0x01U) & 0x07U; + pATI->Audio = + BIOSByte(VideoTable + 0x02U) & 0x0FU; + break; + + default: + pATI->Decoder = + BIOSByte(VideoTable + 0x02U) & 0x07U; + pATI->Audio = + BIOSByte(VideoTable + 0x03U) & 0x0FU; + break; + } + + break; + + case 0x01U: + pATI->Tuner = BIOSByte(VideoTable) & 0x1FU; + pATI->Audio = BIOSByte(VideoTable + 0x01U) & 0x0FU; + pATI->Decoder = BIOSByte(VideoTable + 0x05U) & 0x0FU; + break; + + default: + break; + } + } + + /* Determine panel dimensions */ + if (pATI->LCDPanelID >= 0) + { + LCDTable = BIOSWord(0x78U); + if ((LCDTable + BIOSByte(LCDTable + 5)) > BIOSSize) + LCDTable = 0; + + if (LCDTable > 0) + { + LCDPanelInfo = BIOSWord(LCDTable + 0x0AU); + if (((LCDPanelInfo + 0x1DU) > BIOSSize) || + ((BIOSByte(LCDPanelInfo) != pATI->LCDPanelID) && + (pATI->LCDPanelID || (BIOSByte(LCDPanelInfo) > 0x1FU) || + (pATI->Chip <= ATI_CHIP_264LTPRO)))) + LCDPanelInfo = 0; + } + + if (!LCDPanelInfo) + { + /* + * Scan BIOS for panel info table. + */ + for (i = 0; i <= (int)(BIOSSize - 0x1DU); i++) + { + /* Look for panel ID ... */ + if ((BIOSByte(i) != pATI->LCDPanelID) && + (pATI->LCDPanelID || (BIOSByte(i) > 0x1FU) || + (pATI->Chip <= ATI_CHIP_264LTPRO))) + continue; + + /* ... followed by 24-byte panel model name ... */ + for (j = 0; j < 24; j++) + { + if ((CARD8)(BIOSByte(i + j + 1) - 0x20U) > 0x5FU) + { + i += j; + goto NextBIOSByte; + } + } + + /* ... verify panel width ... */ + if (pATI->LCDHorizontal && + (pATI->LCDHorizontal != BIOSWord(i + 0x19U))) + continue; + + /* ... and verify panel height */ + if (pATI->LCDVertical && + (pATI->LCDVertical != BIOSWord(i + 0x1BU))) + continue; + + if (LCDPanelInfo) + { + /* + * More than one possibility, but don't care if all + * tables describe panels of the same size. + */ + if ((BIOSByte(LCDPanelInfo + 0x19U) == + BIOSByte(i + 0x19U)) && + (BIOSByte(LCDPanelInfo + 0x1AU) == + BIOSByte(i + 0x1AU)) && + (BIOSByte(LCDPanelInfo + 0x1BU) == + BIOSByte(i + 0x1BU)) && + (BIOSByte(LCDPanelInfo + 0x1CU) == + BIOSByte(i + 0x1CU))) + continue; + + LCDPanelInfo = 0; + break; + } + + LCDPanelInfo = i; + + NextBIOSByte: ; + } + } + + if (LCDPanelInfo > 0) + { + pATI->LCDPanelID = BIOSByte(LCDPanelInfo); + pATI->LCDHorizontal = BIOSWord(LCDPanelInfo + 0x19U); + pATI->LCDVertical = BIOSWord(LCDPanelInfo + 0x1BU); + } + } + + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, + "BIOS Data: BIOSSize=0x%04X, ROMTable=0x%04X.\n", + BIOSSize, ROMTable); + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, + "BIOS Data: ClockTable=0x%04X, FrequencyTable=0x%04X.\n", + ClockTable, FrequencyTable); + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, + "BIOS Data: LCDTable=0x%04X, LCDPanelInfo=0x%04X.\n", + LCDTable, LCDPanelInfo); + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, + "BIOS Data: VideoTable=0x%04X, HardwareTable=0x%04X.\n", + VideoTable, HardwareTable); + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, + "BIOS Data: I2CType=0x%02X, Tuner=0x%02X, Decoder=0x%02X," + " Audio=0x%02X.\n", + pATI->I2CType, pATI->Tuner, pATI->Decoder, pATI->Audio); + } + + ATIUnlock(pATI); /* Unlock registers */ + +#ifndef AVOID_CPIO + + /* Sometimes, the BIOS lies about the chip */ + if ((pATI->Chip >= ATI_CHIP_28800_4) && (pATI->Chip <= ATI_CHIP_28800_6)) + { + IOValue = GetBits(ATIGetExtReg(0xAAU), 0x0FU) + + (ATI_CHIP_28800_4 - 4); + if ((IOValue <= ATI_CHIP_28800_6) && (IOValue > pATI->Chip)) + pATI->Chip = IOValue; + } + +#endif /* AVOID_CPIO */ + + /* Report what was found */ + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s graphics controller detected.\n", ATIChipNames[pATI->Chip]); + +#ifndef AVOID_CPIO + + if ((pATI->Chip >= ATI_CHIP_68800) && (pATI->Chip != ATI_CHIP_68800_3)) + +#endif /* AVOID_CPIO */ + + { + Message = Buffer + snprintf(Buffer, SizeOf(Buffer), "Chip type %04X", + pATI->ChipType); + if (!(pATI->ChipType & ~(CHIP_CODE_0 | CHIP_CODE_1))) + Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, + " (%c%c)", + GetBits(pATI->ChipType, CHIP_CODE_1) + 0x41U, + GetBits(pATI->ChipType, CHIP_CODE_0) + 0x41U); + else if ((pATI->ChipType & 0x4040U) == 0x4040U) + Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, + " \"%c%c\"", + GetByte(pATI->ChipType, 1), GetByte(pATI->ChipType, 0)); + if ((pATI->Chip >= ATI_CHIP_264CT) && (pATI->Chip != ATI_CHIP_Mach64)) + Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, + ", version %d, foundry %s", + pATI->ChipVersion, ATIFoundryNames[pATI->ChipFoundry]); + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s, class %d, revision 0x%02X.\n", + Buffer, pATI->ChipClass, pATI->ChipRevision); + } + +#ifndef AVOID_CPIO + + if (pATI->Adapter >= ATI_ADAPTER_MACH8) + +#endif /* AVOID_CPIO */ + + { + Message = Buffer + snprintf(Buffer, SizeOf(Buffer), + "%s bus interface detected", ATIBusNames[pATI->BusType]); + +#ifndef AVOID_CPIO + + if (pATI->Adapter >= ATI_ADAPTER_MACH64) + { + Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, + "; %s I/O base is 0x%04lX", + (pATI->CPIODecoding == SPARSE_IO) ? "sparse" : "block", + pATI->CPIOBase); + } + +#endif /* AVOID_CPIO */ + + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s.\n", Buffer); + } + +#ifndef AVOID_CPIO + + if (pATI->CPIO_VGAWonder) + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "VGA Wonder registers at I/O port 0x%04lX.\n", + pATI->CPIO_VGAWonder); + + if (pATI->Coprocessor != ATI_CHIP_NONE) + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s graphics accelerator detected,\n with %d kB of coprocessor" + " memory.\n", + ATIChipNames[pATI->Coprocessor], pATI->VideoRAM); + +#endif /* AVOID_CPIO */ + + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s adapter detected.\n", ATIAdapterNames[pATI->Adapter]); + + if (pATI->Chip >= ATI_CHIP_264GT) + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "For information on using the multimedia capabilities\n of this" + " adapter, please see http://gatos.sf.net.\n"); + + if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "Internal RAMDAC (subtype %d) detected.\n", pATI->DAC & 0x0FU); + } + else + { + const SymTabRec *DAC; + + for (DAC = ATIDACDescriptors; ; DAC++) + { + if (pATI->DAC == DAC->token) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%s RAMDAC detected.\n", DAC->name); + break; + } + + if (pATI->DAC < DAC->token) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0, + "Unknown RAMDAC type 0x%02X detected.\n", pATI->DAC); + break; + } + } + } + +#ifdef AVOID_CPIO + + if (!xf86LinearVidMem()) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "A linear aperture is not available.\n"); + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + +#endif /* AVOID_CPIO */ + + /* + * Set colour weights. + */ + + if (pATI->Chip < ATI_CHIP_264CT) + pScreenInfo->rgbBits = 6; + else + pScreenInfo->rgbBits = 8; + pATI->rgbBits = pScreenInfo->rgbBits; + if (!xf86SetWeight(pScreenInfo, defaultWeight, defaultWeight)) + { + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + if ((pScreenInfo->depth > 8) && + ((pScreenInfo->weight.red != pScreenInfo->weight.blue) || + (pScreenInfo->weight.red != (CARD32)(pScreenInfo->depth / 3)) || + ((CARD32)pScreenInfo->depth != (pScreenInfo->weight.red + + pScreenInfo->weight.green + + pScreenInfo->weight.blue)))) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Driver does not support weight %d%d%d for depth %d.\n", + (int)pScreenInfo->weight.red, (int)pScreenInfo->weight.green, + (int)pScreenInfo->weight.blue, pScreenInfo->depth); + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + /* + * Set default visual. + */ + + if (!xf86SetDefaultVisual(pScreenInfo, -1)) + { + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + if ((pScreenInfo->depth > 8) && + (((pScreenInfo->defaultVisual | DynamicClass) != DirectColor) || + ((pScreenInfo->defaultVisual == DirectColor) && + (pATI->DAC == ATI_DAC_INTERNAL)))) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Driver does not support default visual %s for depth %d.\n", + xf86GetVisualName(pScreenInfo->defaultVisual), + pScreenInfo->depth); + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + /* + * Set colour gamma. + */ + +#ifndef AVOID_CPIO + + if (pScreenInfo->depth > 1) + +#endif /* AVOID_CPIO */ + + { + if (!xf86SetGamma(pScreenInfo, defaultGamma)) + { + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + } + + pATI->depth = pScreenInfo->depth; + pATI->bitsPerPixel = pScreenInfo->bitsPerPixel; + pATI->weight = pScreenInfo->weight; + pATI->XModifier = pATI->bitsPerPixel / UnitOf(pATI->bitsPerPixel); + + /* + * Determine which CRT controller to use for video modes. + */ + +#ifndef AVOID_CPIO + + if ((pATI->Chip >= ATI_CHIP_88800GXC) && + (pATI->depth >= 8) && + (pATI->Chipset == ATI_CHIPSET_ATI)) + +#endif /* AVOID_CPIO */ + + { + pATI->NewHW.crtc = ATI_CRTC_MACH64; + + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Using Mach64 accelerator CRTC.\n"); + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + /* + * No need for VGA I/O resources during operating state (but they + * are still decoded). + */ + pResources = + xf86SetOperatingState(resVgaIo, pATI->iEntity, ResUnusedOpr); + if (pResources) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Logic error setting operating state for VGA I/O.\n"); + xf86FreeResList(pResources); + } + + if (pATI->CPIO_VGAWonder) + { + pResources = xf86SetOperatingState(pATI->VGAWonderResources, + pATI->iEntity, ResUnusedOpr); + if (pResources) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Logic error setting operating state for" + " VGAWonder I/O.\n"); + xf86FreeResList(pResources); + } + } + } + +#endif /* AVOID_CPIO */ + + } + +#ifndef AVOID_CPIO + + else + { + pATI->NewHW.crtc = ATI_CRTC_VGA; + + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Using VGA CRTC.\n"); + } + + /* Complain if VGA is needed but not there */ + if ((pATI->NewHW.crtc == ATI_CRTC_VGA) || !pATI->OptionLinear) + { + /* VGA is required at this point */ + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "VGA is not available through this adapter.\n"); + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + if (pATI->Coprocessor != ATI_CHIP_NONE) + { + /* Ignore any 8514/A or Mach8 accelerator from this point on */ + pATI->Adapter = pATI->VGAAdapter; + + /* Accelerator and VGA cannot share memory */ + pATI->VideoRAM = 0; + } + } + +#endif /* AVOID_CPIO */ + + /* + * Decide between the CRT and the panel. + */ + if (pATI->LCDPanelID >= 0) + { + if (!pATI->OptionPanelDisplay) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, + "Using CRT interface and disabling digital flat panel.\n"); + } + else + { + unsigned HDisplay, VDisplay; + CARD8 ClockMask, PostMask; + + /* + * Determine porch data. This groks the mode on entry to extract + * the width and position of its sync and blanking pulses, and + * considers any overscan as part of the displayed area, given that + * the overscan is also stretched. + * + * This also attempts to determine panel dimensions but cannot do + * so for one that is "auto-stretched". + */ + + if (pATI->Chip == ATI_CHIP_264LT) + { + pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL); + + /* Set up to read non-shadow registers */ + if (pATIHW->lcd_gen_ctrl & SHADOW_RW_EN) + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + pATIHW->lcd_index = inr(LCD_INDEX); + pATIHW->config_panel = ATIMach64GetLCDReg(LCD_CONFIG_PANEL); + pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + + /* Set up to read non-shadow registers */ + if (pATIHW->lcd_gen_ctrl & SHADOW_RW_EN) + ATIMach64PutLCDReg(LCD_GEN_CNTL, + pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN); + } + +#ifndef AVOID_CPIO + + if (!(pATIHW->crtc_gen_cntl & CRTC_EXT_DISP_EN)) + { + unsigned HBlankStart, HSyncStart, HSyncEnd, HBlankEnd, HTotal; + unsigned VBlankStart, VSyncStart, VSyncEnd, VBlankEnd, VTotal; + + pATIHW->clock = (inb(R_GENMO) & 0x0CU) >> 2; + + pATIHW->crt[2] = GetReg(CRTX(pATI->CPIO_VGABase), 0x02U); + pATIHW->crt[3] = GetReg(CRTX(pATI->CPIO_VGABase), 0x03U); + pATIHW->crt[5] = GetReg(CRTX(pATI->CPIO_VGABase), 0x05U); + pATIHW->crt[7] = GetReg(CRTX(pATI->CPIO_VGABase), 0x07U); + pATIHW->crt[9] = GetReg(CRTX(pATI->CPIO_VGABase), 0x09U); + pATIHW->crt[21] = GetReg(CRTX(pATI->CPIO_VGABase), 0x15U); + pATIHW->crt[22] = GetReg(CRTX(pATI->CPIO_VGABase), 0x16U); + + pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP); + pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); + pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP); + pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); + + /* Switch to shadow registers */ + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, + pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); + + pATIHW->shadow_vga[2] = + GetReg(CRTX(pATI->CPIO_VGABase), 0x02U); + pATIHW->shadow_vga[3] = + GetReg(CRTX(pATI->CPIO_VGABase), 0x03U); + pATIHW->shadow_vga[5] = + GetReg(CRTX(pATI->CPIO_VGABase), 0x05U); + pATIHW->shadow_vga[7] = + GetReg(CRTX(pATI->CPIO_VGABase), 0x07U); + pATIHW->shadow_vga[9] = + GetReg(CRTX(pATI->CPIO_VGABase), 0x09U); + pATIHW->shadow_vga[21] = + GetReg(CRTX(pATI->CPIO_VGABase), 0x15U); + pATIHW->shadow_vga[22] = + GetReg(CRTX(pATI->CPIO_VGABase), 0x16U); + + pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP); + pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); + pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP); + pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); + + /* + * HSyncStart and HSyncEnd should equal their shadow + * counterparts. Otherwise, due to a chip bug, the panel might + * not sync, regardless of which register set is used to drive + * the panel. There are certain combinations of register + * values where the panel does in fact sync, but it remains + * impossible to accurately determine the horizontal sync pulse + * timing actually seen by the panel. + * + * Note that this hardware bug does not affect the CRT output. + */ + if (((pATIHW->crtc_h_sync_strt_wid ^ + pATIHW->shadow_h_sync_strt_wid) & + (CRTC_H_SYNC_STRT | CRTC_H_SYNC_STRT_HI | + CRTC_H_SYNC_WID))) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_NOTICE, 0, + "Invalid horizontal sync pulse timing detected in mode" + " on server entry.\n"); + + /* Don't trust input timing */ + pATI->OptionLCDSync = TRUE; + ModeType = 0; + } + + /* Merge in shadow registers as appropriate */ + if (pATIHW->lcd_gen_ctrl & SHADOW_EN) + { + pATIHW->crt[2] = pATIHW->shadow_vga[2]; + pATIHW->crt[3] = pATIHW->shadow_vga[3]; + pATIHW->crt[5] = pATIHW->shadow_vga[5]; + + /* XXX Does this apply to VGA? If so, what about the LT? */ + if ((pATI->Chip < ATI_CHIP_264LTPRO) || + !(pATIHW->config_panel & DONT_SHADOW_HEND)) + { + pATIHW->crtc_h_total_disp &= ~CRTC_H_DISP; + pATIHW->crtc_h_total_disp |= + pATIHW->shadow_h_total_disp & CRTC_H_DISP; + } + + pATIHW->crtc_h_total_disp &= ~CRTC_H_TOTAL; + pATIHW->crtc_h_total_disp |= + pATIHW->shadow_h_total_disp & CRTC_H_TOTAL; + pATIHW->crtc_h_sync_strt_wid = + pATIHW->shadow_h_sync_strt_wid; + + /* XXX Does this apply to VGA? */ + if (pATIHW->lcd_gen_ctrl & USE_SHADOWED_VEND) + { + pATIHW->crtc_v_total_disp &= ~CRTC_V_DISP; + pATIHW->crtc_v_total_disp |= + pATIHW->shadow_v_total_disp & CRTC_V_DISP; + } + + if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) + { + pATIHW->crt[7] = pATIHW->shadow_vga[7]; + pATIHW->crt[9] = pATIHW->shadow_vga[9]; + pATIHW->crt[21] = pATIHW->shadow_vga[21]; + pATIHW->crt[22] = pATIHW->shadow_vga[22]; + + pATIHW->crtc_v_total_disp &= ~CRTC_V_TOTAL; + pATIHW->crtc_v_total_disp |= + pATIHW->shadow_v_total_disp & CRTC_V_TOTAL; + } + } + + if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) + pATIHW->crtc_v_sync_strt_wid = + pATIHW->shadow_v_sync_strt_wid; + + /* + * Decipher input timing. This is complicated by the fact that + * the full width of all timing parameters, except for the + * blanking pulses, is only available through the accelerator + * registers, not the VGA ones. Blanking pulse boundaries must + * then be interpolated. + * + * Note that, in VGA mode, the accelerator's sync width fields + * are actually end positions, not widths. + */ + HDisplay = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_DISP); + HSyncStart = + (GetBits(pATIHW->crtc_h_sync_strt_wid, + CRTC_H_SYNC_STRT_HI) * + (MaxBits(CRTC_H_SYNC_STRT) + 1)) | + GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT); + HSyncEnd = (HSyncStart & ~MaxBits(CRTC_H_SYNC_WID)) | + GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_WID); + if (HSyncStart >= HSyncEnd) + HSyncEnd += MaxBits(CRTC_H_SYNC_WID) + 1; + HTotal = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_TOTAL); + + HBlankStart = (HDisplay & ~0xFFU) | pATIHW->crt[2]; + if (HDisplay > HBlankStart) + HBlankStart += 0x0100U; + HBlankEnd = (HSyncEnd & ~0x3FU) | + ((pATIHW->crt[5] >> 2) & 0x20U) | + (pATIHW->crt[3] & 0x1FU); + if (HSyncEnd > (HBlankEnd + 1)) + HBlankEnd += 0x40U; + + VDisplay = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_DISP); + VSyncStart = + GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_STRT); + VSyncEnd = (VSyncStart & ~MaxBits(CRTC_V_SYNC_WID)) | + GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_WID); + if (VSyncStart > VSyncEnd) + VSyncEnd += MaxBits(CRTC_V_SYNC_WID) + 1; + VTotal = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_TOTAL); + + VBlankStart = (VDisplay & ~0x03FFU) | + ((pATIHW->crt[9] << 4) & 0x0200U) | + ((pATIHW->crt[7] << 5) & 0x0100U) | pATIHW->crt[21]; + if (VDisplay > VBlankStart) + VBlankStart += 0x0400U; + VBlankEnd = (VSyncEnd & ~0x00FFU) | pATIHW->crt[22]; + if (VSyncEnd > (VBlankEnd + 1)) + VBlankEnd += 0x0100U; + + pATI->LCDHBlankWidth = HBlankEnd - HBlankStart; + pATI->LCDHSyncStart = HSyncStart - HBlankStart - 1; + pATI->LCDHSyncWidth = HSyncEnd - HSyncStart; + + pATI->LCDVBlankWidth = VBlankEnd - VBlankStart; + pATI->LCDVSyncStart = VSyncStart - VBlankStart - 1; + pATI->LCDVSyncWidth = VSyncEnd - VSyncStart; + + HDisplay = HTotal + 5 - pATI->LCDHBlankWidth; + VDisplay = VTotal + 2 - pATI->LCDVBlankWidth; + } + else + +#endif /* AVOID_CPIO */ + + { + pATIHW->clock = inr(CLOCK_CNTL) & 0x03U; + + pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP); + pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); + pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP); + pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); + pATIHW->ovr_wid_left_right = inr(OVR_WID_LEFT_RIGHT); + pATIHW->ovr_wid_top_bottom = inr(OVR_WID_TOP_BOTTOM); + + /* Switch to shadow registers */ + if (pATI->Chip == ATI_CHIP_264LT) + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + ATIMach64PutLCDReg(LCD_GEN_CNTL, + pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); + + /* Oddly enough, there are no shadow overscan registers */ + pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP); + pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); + pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP); + pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); + + /* + * HSyncStart and HSyncEnd should equal their shadow + * counterparts. Otherwise, due to a chip bug, the panel might + * not sync, regardless of which register set is used to drive + * the panel. There are certain combinations of register + * values where the panel does in fact sync, but it remains + * impossible to accurately determine the horizontal sync pulse + * timing actually seen by the panel. + * + * Note that this hardware bug does not affect the CRT output. + */ + if (((pATIHW->crtc_h_sync_strt_wid ^ + pATIHW->shadow_h_sync_strt_wid) & + (CRTC_H_SYNC_STRT | CRTC_H_SYNC_STRT_HI | + CRTC_H_SYNC_WID))) + { + xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_NOTICE, 0, + "Invalid horizontal sync pulse timing detected in mode" + " on server entry.\n"); + + /* Don't trust input timing */ + pATI->OptionLCDSync = TRUE; + ModeType = 0; + } + + /* Merge in shadow registers as appropriate */ + if (pATIHW->lcd_gen_ctrl & SHADOW_EN) + { + /* XXX What about the LT? */ + if ((pATI->Chip < ATI_CHIP_264LTPRO) || + !(pATIHW->config_panel & DONT_SHADOW_HEND)) + { + pATIHW->crtc_h_total_disp &= ~CRTC_H_DISP; + pATIHW->crtc_h_total_disp |= + pATIHW->shadow_h_total_disp & CRTC_H_DISP; + } + + pATIHW->crtc_h_total_disp &= ~CRTC_H_TOTAL; + pATIHW->crtc_h_total_disp |= + pATIHW->shadow_h_total_disp & CRTC_H_TOTAL; + pATIHW->crtc_h_sync_strt_wid = + pATIHW->shadow_h_sync_strt_wid; + + if (pATIHW->lcd_gen_ctrl & USE_SHADOWED_VEND) + { + pATIHW->crtc_v_total_disp &= ~CRTC_V_DISP; + pATIHW->crtc_v_total_disp |= + pATIHW->shadow_v_total_disp & CRTC_V_DISP; + } + + if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) + { + pATIHW->crtc_v_total_disp &= ~CRTC_V_TOTAL; + pATIHW->crtc_v_total_disp |= + pATIHW->shadow_v_total_disp & CRTC_V_TOTAL; + } + } + + if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) + pATIHW->crtc_v_sync_strt_wid = + pATIHW->shadow_v_sync_strt_wid; + + /* Decipher input timing */ + HDisplay = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_DISP) + + GetBits(pATIHW->ovr_wid_left_right, OVR_WID_LEFT) + + GetBits(pATIHW->ovr_wid_left_right, OVR_WID_RIGHT); + VDisplay = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_DISP) + + GetBits(pATIHW->ovr_wid_top_bottom, OVR_WID_TOP) + + GetBits(pATIHW->ovr_wid_top_bottom, OVR_WID_BOTTOM); + + pATI->LCDHSyncStart = + (GetBits(pATIHW->crtc_h_sync_strt_wid, + CRTC_H_SYNC_STRT_HI) * + (MaxBits(CRTC_H_SYNC_STRT) + 1)) + + GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT) - + HDisplay; + pATI->LCDHSyncWidth = + GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_WID); + pATI->LCDHBlankWidth = + GetBits(pATIHW->crtc_h_total_disp, CRTC_H_TOTAL) - + HDisplay; + pATI->LCDVSyncStart = + GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_STRT) - + VDisplay; + pATI->LCDVSyncWidth = + GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_WID); + pATI->LCDVBlankWidth = + GetBits(pATIHW->crtc_v_total_disp, CRTC_V_TOTAL) - + VDisplay; + + HDisplay++; + VDisplay++; + } + + /* Restore LCD registers */ + if (pATI->Chip == ATI_CHIP_264LT) + { + outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl); + } + else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) */ + { + ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl); + outr(LCD_INDEX, pATIHW->lcd_index); + } + + HDisplay <<= 3; + pATI->LCDHSyncStart <<= 3; + pATI->LCDHSyncWidth <<= 3; + pATI->LCDHBlankWidth <<= 3; + + /* Calculate panel dimensions implied by the input timing */ + if ((pATIHW->horz_stretching & + (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) == + HORZ_STRETCH_EN) + { + if (pATIHW->horz_stretching & HORZ_STRETCH_MODE) + { + if (pATIHW->horz_stretching & HORZ_STRETCH_BLEND) + { + HDisplay = + (HDisplay * (MaxBits(HORZ_STRETCH_BLEND) + 1)) / + GetBits(pATIHW->horz_stretching, + HORZ_STRETCH_BLEND); + } + } + else if (((pATIHW->horz_stretching & HORZ_STRETCH_LOOP) > + HORZ_STRETCH_LOOP15) || + (pATIHW->horz_stretching & + SetBits(1, HORZ_STRETCH_RATIO))) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Ignoring invalid horizontal stretch ratio in mode on" + " server entry.\n"); + } + else + { + IOValue = + GetBits(pATIHW->horz_stretching, HORZ_STRETCH_RATIO); + + switch (GetBits(pATIHW->horz_stretching, + HORZ_STRETCH_LOOP)) + { + case GetBits(HORZ_STRETCH_LOOP09, HORZ_STRETCH_LOOP): + i = 9; + IOValue &= (1 << 9) - 1; + break; + + case GetBits(HORZ_STRETCH_LOOP11, HORZ_STRETCH_LOOP): + i = 11; + IOValue &= (1 << 11) - 1; + break; + + case GetBits(HORZ_STRETCH_LOOP12, HORZ_STRETCH_LOOP): + i = 12; + IOValue &= (1 << 12) - 1; + break; + + case GetBits(HORZ_STRETCH_LOOP14, HORZ_STRETCH_LOOP): + i = 14; + IOValue &= (1 << 14) - 1; + break; + + case GetBits(HORZ_STRETCH_LOOP15, HORZ_STRETCH_LOOP): + default: /* Muffle compiler */ + i = 15; + IOValue &= (1 << 15) - 1; + break; + } + + if (IOValue) + { + /* Count the number of bits in IOValue */ + j = (IOValue >> 1) & 0x36DBU; + j = IOValue - j - ((j >> 1) & 0x36DBU); + j = ((j + (j >> 3)) & 0x71C7U) % 0x3FU; + + HDisplay = (HDisplay * i) / j; + } + } + } + + if ((pATIHW->vert_stretching & VERT_STRETCH_EN) && + !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO)) + { + if ((pATIHW->vert_stretching & VERT_STRETCH_USE0) || + (VDisplay <= 350)) + IOValue = + GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO0); + else if (VDisplay <= 400) + IOValue = + GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO1); + else if ((VDisplay <= 480) || + !(pATIHW->ext_vert_stretch & VERT_STRETCH_RATIO3)) + IOValue = + GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO2); + else + IOValue = + GetBits(pATIHW->ext_vert_stretch, VERT_STRETCH_RATIO3); + + if (IOValue) + VDisplay = + (VDisplay * (MaxBits(VERT_STRETCH_RATIO0) + 1)) / + IOValue; + } + + /* Match calculated dimensions to probed dimensions */ + if (!pATI->LCDHorizontal) + { + if ((pATIHW->horz_stretching & + (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) != + (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) + pATI->LCDHorizontal = HDisplay; + } + else if (pATI->LCDHorizontal != (int)HDisplay) + { + if ((pATIHW->horz_stretching & + (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) != + (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Inconsistent panel horizontal dimension:" + " %d and %d.\n", pATI->LCDHorizontal, HDisplay); + HDisplay = pATI->LCDHorizontal; + } + + if (!pATI->LCDVertical) + { + if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) || + !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO)) + pATI->LCDVertical = VDisplay; + } + else if (pATI->LCDVertical != (int)VDisplay) + { + if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) || + !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO)) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Inconsistent panel vertical dimension: %d and %d.\n", + pATI->LCDVertical, VDisplay); + VDisplay = pATI->LCDVertical; + } + + if (!pATI->LCDHorizontal || !pATI->LCDVertical) + { + if (pATI->LCDPanelID || (pATI->Chip <= ATI_CHIP_264LTPRO)) + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Unable to determine dimensions of panel (ID %d).\n", + pATI->LCDPanelID); + else + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Unable to determine dimensions of panel.\n"); + + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + /* If the mode on entry wasn't stretched, adjust timings */ + if (!(pATIHW->horz_stretching & HORZ_STRETCH_EN) && + (pATI->LCDHorizontal > (int)HDisplay)) + { + HDisplay = pATI->LCDHorizontal - HDisplay; + if (pATI->LCDHSyncStart >= HDisplay) + pATI->LCDHSyncStart -= HDisplay; + else + pATI->LCDHSyncStart = 0; + pATI->LCDHBlankWidth -= HDisplay; + HDisplay = pATI->LCDHSyncStart + pATI->LCDHSyncWidth; + if (pATI->LCDHBlankWidth < HDisplay) + pATI->LCDHBlankWidth = HDisplay; + } + + if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) && + (pATI->LCDVertical > (int)VDisplay)) + { + VDisplay = pATI->LCDVertical - VDisplay; + if (pATI->LCDVSyncStart >= VDisplay) + pATI->LCDVSyncStart -= VDisplay; + else + pATI->LCDVSyncStart = 0; + pATI->LCDVBlankWidth -= VDisplay; + VDisplay = pATI->LCDVSyncStart + pATI->LCDVSyncWidth; + if (pATI->LCDVBlankWidth < VDisplay) + pATI->LCDVBlankWidth = VDisplay; + } + + if (pATI->LCDPanelID || (pATI->Chip <= ATI_CHIP_264LTPRO)) + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%dx%d panel (ID %d) detected.\n", + pATI->LCDHorizontal, pATI->LCDVertical, pATI->LCDPanelID); + else + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "%dx%d panel detected.\n", + pATI->LCDHorizontal, pATI->LCDVertical); + + if (LCDPanelInfo) + { + for (i = 0; i < 24; i++) + Buffer[i] = BIOSByte(LCDPanelInfo + 1 + i); + for (; --i >= 0; ) + if (Buffer[i] && Buffer[i] != ' ') + { + Buffer[i + 1] = '\0'; + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "Panel model %s.\n", Buffer); + break; + } + } + + /* + * Determine panel clock. This must be done after option + * processing so that the adapter's reference frequency is always + * available. + * + * Get post divider. A GCC bug has caused the following expression + * to be broken down into its individual components. + */ + ClockMask = PLL_VCLK0_XDIV << pATIHW->clock; + PostMask = PLL_VCLK0_POST_DIV << (pATIHW->clock * 2); + i = GetBits(ATIMach64GetPLLReg(PLL_XCLK_CNTL), ClockMask); + i *= MaxBits(PLL_VCLK0_POST_DIV) + 1; + i |= GetBits(ATIMach64GetPLLReg(PLL_VCLK_POST_DIV), PostMask); + + /* Calculate clock of mode on entry */ + Numerator = ATIMach64GetPLLReg(PLL_VCLK0_FB_DIV + pATIHW->clock) * + pATI->ReferenceNumerator; + Denominator = pATI->ClockDescriptor.MinM * + pATI->ReferenceDenominator * + pATI->ClockDescriptor.PostDividers[i]; + pATI->LCDClock = ATIDivide(Numerator, Denominator, 1, 0); + + xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, + "Panel clock is %.3f MHz.\n", + (double)(pATI->LCDClock) / 1000.0); + + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Using digital flat panel interface%s.\n", + pATI->OptionCRTDisplay ? + " to display on both CRT and panel" : ""); + } + } + + /* + * Finish detecting video RAM size. + */ + pScreenInfo->videoRam = pATI->VideoRAM; + +#ifndef AVOID_CPIO + + AcceleratorVideoRAM = pScreenInfo->videoRam; + if (pATI->Chip == ATI_CHIP_VGA) + { + if (pATI->depth <= 4) + VGAVideoRAM = 256; + else + VGAVideoRAM = 64; + + /* For VGA, allow a lower override */ + if ((pGDev->videoRam > 0) && (pGDev->videoRam < VGAVideoRAM)) + VGAVideoRAM = pGDev->videoRam; + } + else if (pATI->CPIO_VGAWonder) + { + /* + * XXX There's an assumption here that the values retrieved are those + * set by BIOS initialisation. + */ + if (pATI->Chip <= ATI_CHIP_18800_1) + { + VGAVideoRAM = + videoRamSizes[GetBits(ATIGetExtReg(0xBBU), 0x20U) + 1]; + if (AcceleratorVideoRAM > 512) + AcceleratorVideoRAM = 512; + } + else + { + IOValue = ATIGetExtReg(0xB0U); + if (IOValue & 0x08U) + VGAVideoRAM = 1024; + else if (IOValue & 0x10U) + VGAVideoRAM = 512; + else + VGAVideoRAM = 256; + if (AcceleratorVideoRAM > 1024) + AcceleratorVideoRAM = 1024; + } + } + + /* Check for hardware limitations */ + if (!AcceleratorVideoRAM) + { + pScreenInfo->videoRam = pATI->VideoRAM = VGAVideoRAM; + + /* + * VGA Wonder V3's, V4's and V5's don't appear to support banking in + * planar modes. + */ + if ((pATI->depth <= 4) && + (pATI->Chip <= ATI_CHIP_18800_1) && + (VGAVideoRAM > 256)) + { + if (pATI->OptionDevel) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "Virtual resolutions requiring more than %s kB\n of video" + " memory might not function properly.\n", + (pATI->depth == 1) ? "64" : "256"); + } + else + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "VideoRAM reduced to 256 kB due to hardware" + " limitations.\n"); + pScreenInfo->videoRam = 256; + } + } + } + else if ((pATI->NewHW.crtc == ATI_CRTC_MACH64) || + (pATI->Chip >= ATI_CHIP_264CT)) + +#endif /* AVOID_CPIO */ + + { + +#ifndef AVOID_CPIO + + if (pATI->depth >= 8) + +#endif /* AVOID_CPIO */ + + { + /* Get adapter's linear aperture configuration */ + pATIHW->config_cntl = inr(CONFIG_CNTL); + pATI->LinearBase = + GetBits(pATIHW->config_cntl, CFG_MEM_AP_LOC) << 22; + if ((pATIHW->config_cntl & CFG_MEM_AP_SIZE) != CFG_MEM_AP_SIZE) + { + pATI->LinearSize = + GetBits(pATIHW->config_cntl, CFG_MEM_AP_SIZE) << 22; + + /* + * Linear aperture could have been disabled (but still + * assigned) by BIOS initialisation. + */ + if (pATI->LinearBase && !pATI->LinearSize) + { + if ((pATI->Chip <= ATI_CHIP_88800GXD) && + (pATI->VideoRAM < 4096)) + pATI->LinearSize = 4 * 1024 * 1024; + else + pATI->LinearSize = 8 * 1024 * 1024; + } + } + +#ifndef AVOID_CPIO + + /* Except for PCI & AGP, allow for user override */ + if (!pVideo) + { + if (pATI->Chip == ATI_CHIP_88800CX) + IOValue = ~((CARD32)((1 << 23) - 1)); + else if (pATI->Chip >= ATI_CHIP_88800GXE) + IOValue = ~((CARD32)((1 << 24) - 1)); + else if (pATI->VideoRAM >= 4096) + IOValue = ~((CARD32)((1 << 23) - 1)); + else + IOValue = ~((CARD32)((1 << 22) - 1)); + + IOValue &= pGDev->MemBase; + if (IOValue && + (IOValue <= (CARD32)(MaxBits(CFG_MEM_AP_LOC) << 22))) + pATI->LinearBase = IOValue; + + if (!pATI->LinearBase) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Linear aperture not configured. Specify \"MemBase\"" + " override in XF86Config \"Device\" section.\n"); + } + else + { + if (!pATI->LinearSize) + { + if ((pATI->Chip <= ATI_CHIP_88800GXD) && + (pATI->VideoRAM < 4096)) + pATI->LinearSize = 4 * 1024 * 1024; + else + pATI->LinearSize = 8 * 1024 * 1024; + } + + Resources[0].type = ResExcMemBlock | ResBus; + Resources[0].rBegin = pATI->LinearBase; + Resources[0].rEnd = + pATI->LinearBase + pATI->LinearSize - 1; + if (xf86RegisterResources(pATI->iEntity, Resources, + ResNone)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to register %d MB linear aperture at" + " 0x%08lX.\n", pATI->LinearSize >> 10, + pATI->LinearBase); + + pATI->LinearSize = 0; + } + } + } + +#endif /* AVOID_CPIO */ + + if (pATI->LinearBase && pATI->LinearSize) + { + /* + * Unless specified in PCI configuration space, set MMIO + * address to tail end of linear aperture. + */ + if (!pATI->Block0Base) + { + pATI->Block0Base = + pATI->LinearBase + pATI->LinearSize - 0x00000400U; + pATI->MMIOInLinear = TRUE; + } + + AcceleratorVideoRAM = pATI->LinearSize >> 10; + + /* + * Account for MMIO area at the tail end of the linear + * aperture, if it is needed or if it cannot be disabled. + */ + if (pATI->MMIOInLinear || (pATI->Chip < ATI_CHIP_264VTB)) + AcceleratorVideoRAM -= 2; + + ServerVideoRAM = pATI->VideoRAM; + + if (pATI->Cursor > ATI_CURSOR_SOFTWARE) + { + /* + * Allocate a 1 kB cursor image area at the top of the + * little-endian aperture, just before any MMIO area that + * might also be there. + */ + if (ServerVideoRAM > AcceleratorVideoRAM) + ServerVideoRAM = AcceleratorVideoRAM; + + ServerVideoRAM--; + pATI->CursorOffset = ServerVideoRAM << 10; + pATI->CursorBase = pATI->LinearBase + pATI->CursorOffset; + + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Storing hardware cursor image at 0x%08lX.\n", + pATI->CursorBase); + } + +#ifndef AVOID_CPIO + + if (pATI->OptionLinear) + +#endif /* AVOID_CPIO */ + + { + CARD32 PageSize = getpagesize() >> 10; + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + + /* + * MMIO areas must be mmap()'ed separately to avoid write + * combining them. Thus, they might not end up still + * adjacent with the little-endian linear aperture after + * mmap()'ing. So, round down the linear aperture size to + * avoid an overlap. Any hardware cursor image area might + * not end up being write combined, but this seems + * preferable to further reducing the video memory size + * advertised to the server. + * + * XXX Ideally this should be dealt with in the os-support + * layer, i.e., it should be possible to reset a + * subarea's write combining after it has been + * mmap()'ed, but doing so currently causes the removal + * of write combining for the entire aperture. + */ + if (pATI->MMIOInLinear) + AcceleratorVideoRAM -= AcceleratorVideoRAM % PageSize; + +#else /* if X_BYTE_ORDER != X_LITTLE_ENDIAN */ + + /* + * Big-endian apertures are 8 MB higher and don't contain + * an MMIO area. + */ + pATI->LinearBase += 0x00800000U; + AcceleratorVideoRAM = pATI->LinearSize >> 10; + +#endif /* X_BYTE_ORDER */ + + if (ServerVideoRAM > AcceleratorVideoRAM) + ServerVideoRAM = AcceleratorVideoRAM; + else if (AcceleratorVideoRAM > pATI->VideoRAM) + AcceleratorVideoRAM = pATI->VideoRAM; + + PageSize--; + AcceleratorVideoRAM = + (AcceleratorVideoRAM + PageSize) & ~PageSize; + + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Using %d MB linear aperture at 0x%08lX.\n", + pATI->LinearSize >> 20, pATI->LinearBase); + + /* Only mmap what is needed */ + ApertureSize = pATI->LinearSize = + AcceleratorVideoRAM << 10; + } + + if (ServerVideoRAM < pATI->VideoRAM) + { + pScreenInfo->videoRam = ServerVideoRAM; + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "Virtual resolutions will be limited to %d kB\n due to" + " linear aperture size and/or placement of hardware" + " cursor image area.\n", + ServerVideoRAM); + } + } + } + +#ifndef AVOID_CPIO + + /* Set up for a banked aperture */ + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + pATI->UseSmallApertures = TRUE; + + /* Set banking functions */ + if (pATI->depth <= 4) + { + pATI->NewHW.SetBank = ATIMach64SetBankPlanar; + pATI->BankInfo.SetSourceBank = ATIMach64SetReadPlanar; + pATI->BankInfo.SetDestinationBank = ATIMach64SetWritePlanar; + pATI->BankInfo.SetSourceAndDestinationBanks = + ATIMach64SetReadWritePlanar; + } + else + { + pATI->NewHW.SetBank = ATIMach64SetBankPacked; + pATI->BankInfo.SetSourceBank = ATIMach64SetReadPacked; + pATI->BankInfo.SetDestinationBank = ATIMach64SetWritePacked; + pATI->BankInfo.SetSourceAndDestinationBanks = + ATIMach64SetReadWritePacked; + } + + /* + * Unless specified in PCI configuration space, or at the top of + * of a little-endian linear aperture, set MMIO address to the one + * just above the VGA aperture. This does not work on the CT + * (maybe others). + */ + if (!pATI->Block0Base && + ((pATI->Chip < ATI_CHIP_264CT) || + (pATI->Chip >= ATI_CHIP_264VT) || + pATI->OptionDevel)) + pATI->Block0Base = 0x000BFC00U; + } + + if (!pATI->OptionLinear) + pATI->LinearBase = 0; /* Not needed */ + +#endif /* AVOID_CPIO */ + + if (!pATI->LinearBase || !pATI->LinearSize) + { + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + +#endif /* AVOID_CPIO */ + + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, + "Linear aperture not available.\n"); + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + +#ifndef AVOID_CPIO + + /* Insurance */ + pATI->LinearBase = pATI->LinearSize = 0; + +#endif /* AVOID_CPIO */ + + } + + if (pATI->Block0Base) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Using Block 0 MMIO aperture at 0x%08lX.\n", pATI->Block0Base); + + /* Set Block1 MMIO address if supported */ + if (pATI->Chip >= ATI_CHIP_264VT) + { + pATI->Block1Base = pATI->Block0Base - 0x00000400U; + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Using Block 1 MMIO aperture at 0x%08lX.\n", + pATI->Block1Base); + } + } + } + +#ifndef AVOID_CPIO + + else + /* + * After BIOS initialisation, the accelerator (if any) and the VGA won't + * necessarily agree on the amount of video memory, depending on whether or + * where the memory boundary is configured. Any discrepancy will be + * resolved by ATIModePreInit(). + * + * However, it's possible that there is more video memory than VGA Wonder + * can architecturally handle. + */ + if (((pATI->Chip < ATI_CHIP_68800) || (pATI->Chip > ATI_CHIP_68800AX)) && + (AcceleratorVideoRAM < pScreenInfo->videoRam)) + { + if (pATI->OptionDevel) + { + if (pATI->depth == 1) + AcceleratorVideoRAM /= 4; + + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "Virtual resolutions requiring more than %d kB\n of video" + " memory might not function correctly.\n", + AcceleratorVideoRAM); + } + else + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "VideoRAM reduced to %d kB due to hardware limitations.\n", + AcceleratorVideoRAM); + + pScreenInfo->videoRam = AcceleratorVideoRAM; + } + } + + if (pATI->OptionLinear) + { + if (!pATI->LinearBase) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Linear aperture not supported in this configuration.\n"); + pATI->OptionLinear = FALSE; + } + else if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + /* + * Free VGA memory aperture during operating state (but it is still + * decoded). + */ + pResources = xf86SetOperatingState(resVgaMem, pATI->iEntity, + ResUnusedOpr); + if (pResources) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Logic error setting operating state for VGA memory" + " aperture.\n"); + xf86FreeResList(pResources); + } + } + } + +#endif /* AVOID_CPIO */ + + if ((pATI->Cursor > ATI_CURSOR_SOFTWARE) && !pATI->CursorBase) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Unable to store hardware cursor image. Reverting to software" + " cursor.\n"); + pATI->Cursor = ATI_CURSOR_SOFTWARE; + } + + /* + * Remap apertures. Must lock and re-unlock around this in case the + * remapping fails. + */ + ATILock(pATI); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + if (!ATIMapApertures(pScreenInfo->scrnIndex, pATI)) + return FALSE; + + ATIUnlock(pATI); + + if (pATI->OptionAccel) + { + +#ifndef AVOID_CPIO + + if (!pATI->Block0Base || (pATI->NewHW.crtc == ATI_CRTC_VGA)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Acceleration not supported in this configuration.\n"); + pATI->OptionAccel = FALSE; + } + else + +#endif /* AVOID_CPIO */ + + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "MMIO write caching %sabled.\n", + pATI->OptionMMIOCache ? "en" : "dis"); + } + } + +#ifndef AVOID_CPIO + + if (pATI->Adapter >= ATI_ADAPTER_MACH32) + +#endif /* AVOID_CPIO */ + + { + if (pATI->Chip >= ATI_CHIP_264CT) + ATIReportMemory(pScreenInfo, pATI, + ATIMemoryTypeNames_264xT[pATI->MemoryType]); + else if (pATI->Chip == ATI_CHIP_88800CX) + ATIReportMemory(pScreenInfo, pATI, + ATIMemoryTypeNames_88800CX[pATI->MemoryType]); + else + ATIReportMemory(pScreenInfo, pATI, + ATIMemoryTypeNames_Mach[pATI->MemoryType]); + } + +#ifndef AVOID_CPIO + + else if (pATI->Adapter >= ATI_ADAPTER_V3) + { + ATIReportMemory(pScreenInfo, pATI, + (ATIGetExtReg(0xB7U) & 0x04U) ? "DRAM" : "VRAM"); + } + else + { + ATIReportMemory(pScreenInfo, pATI, "video memory"); + } + +#endif /* AVOID_CPIO */ + + /* + * Finish banking setup. This needs to be fixed to not assume the mode on + * entry is a VGA mode. XXX + */ + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + +#endif /* AVOID_CPIO */ + + { + pATIHW->crtc = pATI->NewHW.crtc; + +#ifndef AVOID_CPIO + + pATIHW->SetBank = (ATIBankProcPtr)NoopDDA; + pATI->BankInfo.BankSize = 0; /* No banking */ + +#endif /* AVOID_CPIO */ + + } + +#ifndef AVOID_CPIO + + else + { + pATIHW->crtc = ATI_CRTC_VGA; +#if 0 /* ___NOT_YET___ */ + if (pATI->ChipHasSUBSYS_CNTL) + { + } + else +#endif + if ((pATI->Chip >= ATI_CHIP_88800GXC) && + (pATI->LockData.crtc_gen_cntl & CRTC_EXT_DISP_EN)) + { + pATIHW->crtc = ATI_CRTC_MACH64; + } + + if (pATI->depth <= 4) + { + pATI->BankInfo.nBankDepth = 1; + pATI->NewHW.nPlane = 4; + } + else + { + pATI->BankInfo.nBankDepth = pATI->depth; + pATI->NewHW.nPlane = 1; + } + + if ((pATIHW->crtc != ATI_CRTC_VGA) || (GetReg(SEQX, 0x04U) & 0x08U)) + pATIHW->nPlane = 1; + else + pATIHW->nPlane = 4; + + pATIHW->nBank = ATIDivide(pATI->VideoRAM, + pATIHW->nPlane * pATI->BankInfo.BankSize, 10, 1); + pATI->NewHW.nBank = ATIDivide(pATI->VideoRAM, + pATI->NewHW.nPlane * pATI->BankInfo.BankSize, 10, 1); + + if (pATI->VGAAdapter == ATI_ADAPTER_VGA) + { + pATIHW->SetBank = pATI->NewHW.SetBank = + (ATIBankProcPtr)NoopDDA; + pATIHW->nBank = pATI->NewHW.nBank = 1; + } + else if (!pATI->UseSmallApertures) + { + pATIHW->SetBank = pATI->NewHW.SetBank; + } + else if ((pATIHW->crtc == ATI_CRTC_VGA) && + !(pATI->LockData.config_cntl & CFG_MEM_VGA_AP_EN)) + { + pATIHW->SetBank = (ATIBankProcPtr)NoopDDA; + pATIHW->nBank = 1; + } + else if (pATIHW->nPlane == 1) + { + pATIHW->SetBank = ATIMach64SetBankPacked; + } + else + { + pATIHW->SetBank = ATIMach64SetBankPlanar; + } + + if (((ApertureSize * pATI->depth) / pATI->BankInfo.nBankDepth) >= + (unsigned)(pScreenInfo->videoRam * 1024)) + pATI->BankInfo.BankSize = 0; /* No banking */ + } + +#endif /* AVOID_CPIO */ + + if (pATI->OptionShadowFB) + { + /* Until ShadowFB becomes a true screen wrapper, if it ever does... */ + +#ifndef AVOID_CPIO + + if (pATI->BankInfo.BankSize) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Cannot shadow a banked frame buffer.\n"); + pATI->OptionShadowFB = FALSE; + } + else if (pATI->depth < 8) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Cannot shadow a planar frame buffer.\n"); + pATI->OptionShadowFB = FALSE; + } + else + +#endif /* AVOID_CPIO */ + + if (pATI->OptionAccel) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Cannot shadow an accelerated frame buffer.\n"); + pATI->OptionShadowFB = FALSE; + } + else + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Using shadow frame buffer.\n"); + } + } + + /* 264VT-B's and later have DSP registers */ + if ((pATI->Chip >= ATI_CHIP_264VTB) && + !ATIDSPPreInit(pScreenInfo->scrnIndex, pATI)) + { + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + /* + * Determine minClock and maxClock. For adapters with supported + * programmable clock generators, start with an absolute maximum. + */ + if (pATI->ClockDescriptor.MaxN > 0) + { + Numerator = pATI->ClockDescriptor.MaxN * pATI->ReferenceNumerator; + Denominator = pATI->ClockDescriptor.MinM * pATI->ReferenceDenominator * + pATI->ClockDescriptor.PostDividers[0]; + + /* + * An integrated PLL behaves as though the reference frequency were + * doubled. It also does not appear to care about the colour depth. + */ + if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL) + Numerator <<= 1; + else if (pATI->depth > 8) + Denominator *= (pATI->bitsPerPixel / 8); + + ATIClockRange.maxClock = (Numerator / (Denominator * 1000)) * 1000; + + Numerator = pATI->ClockDescriptor.MinN * pATI->ReferenceNumerator; + Denominator = pATI->ClockDescriptor.MaxM * pATI->ReferenceDenominator * + pATI->ClockDescriptor.PostDividers[pATI->ClockDescriptor.NumD - 1]; + + if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL) + Numerator <<= 1; + + ATIClockRange.minClock = (Numerator / (Denominator * 1000)) * 1000; + + if (pATI->XCLKFeedbackDivider) + { + /* Possibly reduce maxClock due to memory bandwidth */ + Numerator = pATI->XCLKFeedbackDivider * 2 * + pATI->ReferenceNumerator; + Denominator = pATI->ClockDescriptor.MinM * + pATI->XCLKReferenceDivider * pATI->ReferenceDenominator; + +#ifndef AVOID_CPIO + + if (pATI->depth >= 8) + +#endif /* AVOID_CPIO */ + + { + Denominator *= pATI->bitsPerPixel / 4; + } + + i = (6 - 2) - pATI->XCLKPostDivider; + +#ifndef AVOID_CPIO + + if (pATI->NewHW.crtc == ATI_CRTC_VGA) + i--; + +#endif /* AVOID_CPIO */ + + i = (ATIDivide(Numerator, Denominator, i, -1) / 1000) * 1000; + if (i < ATIClockRange.maxClock) + ATIClockRange.maxClock = i; + } + } + + /* + * Assume an internal DAC can handle whatever frequency the internal PLL + * can produce (with the reference divider set by BIOS initialisation), but + * default maxClock to a lower chip-specific default. + */ + if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL) + { + int DacSpeed; + switch (pATI->bitsPerPixel) + { + case 15: + case 16: + DacSpeed = pGDev->dacSpeeds[DAC_BPP16]; + break; + + case 24: + DacSpeed = pGDev->dacSpeeds[DAC_BPP24]; + break; + + case 32: + DacSpeed = pGDev->dacSpeeds[DAC_BPP32]; + break; + + default: + DacSpeed = 0; + break; + } + if (!DacSpeed) + DacSpeed = pGDev->dacSpeeds[DAC_BPP8]; + if (DacSpeed < ATIClockRange.maxClock) + { + DefaultmaxClock = 135000; + + if (pATI->depth > 8) + DefaultmaxClock = 80000; + + if ((pATI->Chip >= ATI_CHIP_264VTB) && + (pATI->Chip != ATI_CHIP_Mach64)) + { + if ((pATI->Chip >= ATI_CHIP_264VT4) && + (pATI->Chip != ATI_CHIP_264LTPRO)) + DefaultmaxClock = 230000; + else if (pATI->Chip >= ATI_CHIP_264VT3) + DefaultmaxClock = 200000; + else + DefaultmaxClock = 170000; + } + if (DacSpeed > DefaultmaxClock) + ATIClockRange.maxClock = DacSpeed; + else if (DefaultmaxClock < ATIClockRange.maxClock) + ATIClockRange.maxClock = DefaultmaxClock; + } + } + else + { + switch(pATI->DAC) + { + case ATI_DAC_STG1700: + case ATI_DAC_STG1702: + case ATI_DAC_STG1703: + DefaultmaxClock = 110000; + break; + + case ATI_DAC_IBMRGB514: + pATI->maxClock = 220000; + +#ifndef AVOID_CPIO + + if (pATI->NewHW.crtc == ATI_CRTC_VGA) + { + DefaultmaxClock = 100000; + } + else + +#endif /* AVOID_CPIO */ + + { + DefaultmaxClock = 220000; + } + break; + + default: + +#ifndef AVOID_CPIO + + /* + * 80 MHz is too high in some cases. Limit 18800-x's to 40 + * MHz. Don't exceed the memory clock on VGA Wonder capables + * with less than 1 MB, if using a packed mode. + */ + if ((pATI->Chip == ATI_CHIP_18800) || + (pATI->Chip == ATI_CHIP_18800_1)) + { + DefaultmaxClock = 40000; + } + else if (pATI->CPIO_VGAWonder && + (pATI->VideoRAM < 1024) && + (pATI->depth >= 8)) + { + DefaultmaxClock = + (GetBits(BIOSByte(0x44U), 0x04U) * 5000) + 40000; + } + else + +#endif /* AVOID_CPIO */ + + { + DefaultmaxClock = 80000; + } + + break; + } + + if (DefaultmaxClock < ATIClockRange.maxClock) + ATIClockRange.maxClock = DefaultmaxClock; + } + + if (pATI->ClockDescriptor.MaxN <= 0) + { + ATIClockRange.maxClock = DefaultmaxClock; + xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, + "Maximum pixel clock: %.3f MHz.\n", + (double)ATIClockRange.maxClock / 1000.0); + } + + /* + * Determine available pixel clock frequencies. + */ + + ATIClockPreInit(pScreenInfo, pATI, pGDev, &ATIClockRange); + if (pATI->ProgrammableClock > ATI_CLOCK_FIXED) + Strategy = LOOKUP_BEST_REFRESH; + + /* + * Mode validation. + */ + +#ifdef AVOID_CPIO + + if (pATI->Chip >= ATI_CHIP_264CT) + { + minPitch = 8; + } + +#else /* AVOID_CPIO */ + + if ((pATI->depth >= 8) && (pATI->Chip >= ATI_CHIP_264CT)) + { + minPitch = 8; + } + else if (pATI->CPIO_VGAWonder && + (pATI->Chip <= ATI_CHIP_18800_1) && + (pATI->VideoRAM == 256) && + (pATI->depth >= 8)) + { + minPitch = 32; /* Very strange, but true */ + maxPitch = 0x3FU; + } + +#endif /* AVOID_CPIO */ + + else + { + minPitch = 16; + } + + pATI->pitchInc = minPitch; + +#ifndef AVOID_CPIO + + if (pATI->depth >= 8) + +#endif /* AVOID_CPIO */ + + { + pATI->pitchInc *= pATI->bitsPerPixel; + } + + switch (pATI->NewHW.crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + /* + * IBM's VGA doesn't allow for interlaced modes. + */ + if (pATI->Adapter <= ATI_ADAPTER_VGA) + ATIClockRange.interlaceAllowed = FALSE; + + pScreenInfo->maxHValue = (0xFFU + 1) << 3; /* max HTotal */ + + /* + * The maximum VTotal value set here applies to all modes, + * including interlaced, doublescanned or multiscanned modes. + * Finer-grained checks are done in ATIValidateMode(). + */ + pScreenInfo->maxVValue = 0x03FFU + 1; + if (pATI->Adapter > ATI_ADAPTER_VGA) + { + pScreenInfo->maxVValue <<= 1; + if (ATIClockRange.interlaceAllowed && + (pATI->Chip < ATI_CHIP_264CT)) + pScreenInfo->maxVValue <<= 1; + } + + /* + * 18800-x and 28800-x do not support interlaced modes when the + * scanline pitch is 2048 pixels or more. For 18800-x's with 256 + * kB of video memory, the limit for 8bpp is 1024. + */ + if (ATIClockRange.interlaceAllowed && + (pATI->Chip <= ATI_CHIP_28800_6)) + { + if (minPitch == 32) + pATI->MaximumInterlacedPitch = 0x1FU * 32; + else + pATI->MaximumInterlacedPitch = 0x7FU * minPitch; + } + + Strategy |= LOOKUP_CLKDIV2; + + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + pScreenInfo->maxHValue = (MaxBits(CRTC_H_TOTAL) + 1) << 3; + + if (pATI->Chip < ATI_CHIP_264VT) + { + /* + * ATI finally fixed accelerated doublescanning in the 264VT + * and later. On 88800's, the bit is documented to exist, but + * only doubles the vertical timings. On the 264CT and 264ET, + * the bit is ignored. + */ + ATIClockRange.doubleScanAllowed = FALSE; + + /* CRTC_H_TOTAL is one bit narrower */ + pScreenInfo->maxHValue >>= 1; + } + + pScreenInfo->maxVValue = MaxBits(CRTC_V_TOTAL) + 1; + + maxPitch = MaxBits(CRTC_PITCH); + + break; + + default: + break; + } + + maxPitch *= minPitch; + + if (pATI->OptionAccel) + { + /* + * Set engine restrictions on coordinate space. Use maxPitch for the + * horizontal and maxHeight for the vertical. + */ + if (maxPitch > (ATIMach64MaxX / pATI->XModifier)) + maxPitch = ATIMach64MaxX / pATI->XModifier; + maxHeight = ATIMach64MaxY; + + /* + * For SGRAM & WRAM adapters, the display engine limits the pitch to + * multiples of 64 bytes. + */ + if ((pATI->Chip >= ATI_CHIP_264CT) && + ((pATI->Chip >= ATI_CHIP_264VTB) || + (pATI->MemoryType >= MEM_264_SGRAM))) + pATI->pitchInc = pATI->XModifier * (64 * 8); + } + + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) + { + /* + * Given LCD modes are more tightly controlled than CRT modes, allow + * the user the option of not specifying a panel's horizontal sync + * and/or vertical refresh tolerances. + */ + Strategy |= LOOKUP_OPTIONAL_TOLERANCES; + + if (ModeType == M_T_BUILTIN) + { + /* + * Add a mode to the end of the monitor's list for the panel's + * native resolution. + */ + pMode = (DisplayModePtr)xnfcalloc(1, SizeOf(DisplayModeRec)); + pMode->name = "Native panel mode"; + pMode->type = M_T_BUILTIN; + pMode->Clock = pATI->LCDClock; + pMode->HDisplay = pATI->LCDHorizontal; + pMode->VDisplay = pATI->LCDVertical; + + /* + * These timings are bogus, but enough to survive sync tolerance + * checks. + */ + pMode->HSyncStart = pMode->HDisplay; + pMode->HSyncEnd = pMode->HSyncStart + minPitch; + pMode->HTotal = pMode->HSyncEnd + minPitch; + pMode->VSyncStart = pMode->VDisplay; + pMode->VSyncEnd = pMode->VSyncStart + 1; + pMode->VTotal = pMode->VSyncEnd + 1; + + pMode->CrtcHDisplay = pMode->HDisplay; + pMode->CrtcHBlankStart = pMode->HDisplay; + pMode->CrtcHSyncStart = pMode->HSyncStart; + pMode->CrtcHSyncEnd = pMode->HSyncEnd; + pMode->CrtcHBlankEnd = pMode->HTotal; + pMode->CrtcHTotal = pMode->HTotal; + + pMode->CrtcVDisplay = pMode->VDisplay; + pMode->CrtcVBlankStart = pMode->VDisplay; + pMode->CrtcVSyncStart = pMode->VSyncStart; + pMode->CrtcVSyncEnd = pMode->VSyncEnd; + pMode->CrtcVBlankEnd = pMode->VTotal; + pMode->CrtcVTotal = pMode->VTotal; + + if (!pScreenInfo->monitor->Modes) + { + pScreenInfo->monitor->Modes = pMode; + } + else + { + pScreenInfo->monitor->Last->next = pMode; + pMode->prev = pScreenInfo->monitor->Last; + } + + pScreenInfo->monitor->Last = pMode; + } + + /* + * Defeat Xconfigurator brain damage. Ignore all HorizSync and + * VertRefresh specifications. For now, this does not take + * SYNC_TOLERANCE into account. + */ + if (pScreenInfo->monitor->nHsync > 0) + { + double hsync = (double)pATI->LCDClock / + (pATI->LCDHorizontal + pATI->LCDHBlankWidth); + + for (i = 0; ; i++) + { + if (i >= pScreenInfo->monitor->nHsync) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "Conflicting XF86Config HorizSync specification(s)" + " ignored.\n"); + break; + } + + if ((hsync >= pScreenInfo->monitor->hsync[i].lo) && + (hsync <= pScreenInfo->monitor->hsync[i].hi)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Extraneous XF86Config HorizSync specification(s)" + " ignored.\n"); + break; + } + } + + pScreenInfo->monitor->nHsync = 0; + } + + if (pScreenInfo->monitor->nVrefresh > 0) + { + double vrefresh = ((double)pATI->LCDClock * 1000.0) / + ((pATI->LCDHorizontal + pATI->LCDHBlankWidth) * + (pATI->LCDVertical + pATI->LCDVBlankWidth)); + + for (i = 0; ; i++) + { + if (i >= pScreenInfo->monitor->nVrefresh) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, + "Conflicting XF86Config VertRefresh specification(s)" + " ignored.\n"); + break; + } + + if ((vrefresh >= pScreenInfo->monitor->vrefresh[i].lo) && + (vrefresh <= pScreenInfo->monitor->vrefresh[i].hi)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Extraneous XF86Config VertRefresh specification(s)" + " ignored.\n"); + break; + } + } + + pScreenInfo->monitor->nVrefresh = 0; + } + } + + i = xf86ValidateModes(pScreenInfo, + pScreenInfo->monitor->Modes, pScreenInfo->display->modes, + &ATIClockRange, NULL, minPitch, maxPitch, + pATI->pitchInc, 0, maxHeight, + pScreenInfo->display->virtualX, pScreenInfo->display->virtualY, + ApertureSize, Strategy); + if (i <= 0) + { + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + /* Remove invalid modes */ + xf86PruneDriverModes(pScreenInfo); + + /* Set current mode to the first in the list */ + pScreenInfo->currentMode = pScreenInfo->modes; + + /* Print mode list */ + xf86PrintModes(pScreenInfo); + + /* Set display resolution */ + xf86SetDpi(pScreenInfo, 0, 0); + + /* Load required modules */ + if (!ATILoadModules(pScreenInfo, pATI)) + { + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + return FALSE; + } + + pATI->displayWidth = pScreenInfo->displayWidth; + + /* Initialise for panning */ + ATIAdjustPreInit(pATI); + + /* + * Warn about modes that are too small, or not aligned, to scroll to the + * bottom right corner of the virtual screen. + */ + MinX = pScreenInfo->virtualX - pATI->AdjustMaxX; + MinY = pScreenInfo->virtualY - pATI->AdjustMaxY; + + pMode = pScreenInfo->modes; + do + { + if ((pMode->VDisplay <= MinY) && + ((pMode->VDisplay < MinY) || (pMode->HDisplay < MinX))) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Mode \"%s\" too small to scroll to bottom right corner of" + " virtual resolution.\n", pMode->name); + else if ((pMode->HDisplay & ~pATI->AdjustMask) / pScreenInfo->xInc) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Mode \"%s\" cannot scroll to bottom right corner of virtual" + " resolution.\n Horizontal dimension not a multiple of %ld.\n", + pMode->name, ~pATI->AdjustMask + 1); + } while ((pMode = pMode->next) != pScreenInfo->modes); + + /* Initialise XVideo extension support */ + ATIXVPreInit(pATI); + + /* Initialise CRTC code */ + ATIModePreInit(pScreenInfo, pATI, &pATI->NewHW); + + /* Set up for I2C */ + ATII2CPreInit(pScreenInfo, pATI); + + if (!pScreenInfo->chipset || !*pScreenInfo->chipset) + pScreenInfo->chipset = (char *)ATIChipsetNames[0]; + + ATILock(pATI); + ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); + ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); + + return TRUE; +} diff --git a/src/atipreinit.h b/src/atipreinit.h new file mode 100644 index 0000000..f418a61 --- /dev/null +++ b/src/atipreinit.h @@ -0,0 +1,33 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atipreinit.h,v 1.6 2003/01/01 19:16:33 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIPREINIT_H___ +#define ___ATIPREINIT_H___ 1 + +#include "atiproto.h" + +#include "xf86str.h" + +extern Bool ATIPreInit FunctionPrototype((ScrnInfoPtr, int)); + +#endif /* ___ATIPREINIT_H___ */ diff --git a/src/atiprint.c b/src/atiprint.c new file mode 100644 index 0000000..31d7307 --- /dev/null +++ b/src/atiprint.c @@ -0,0 +1,831 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiprint.c,v 1.28 2003/11/07 13:45:26 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atichip.h" +#include "atidac.h" +#include "atimach64io.h" +#include "atiprint.h" +#include "atiwonderio.h" + +/* + * ATIPrintBIOS -- + * + * Display various parts of the BIOS when the server is invoked with -verbose. + */ +void +ATIPrintBIOS +( + const CARD8 *BIOS, + const unsigned int Length /* A multiple of 512 */ +) +{ + unsigned char *Char = NULL; + unsigned int Index; + unsigned char Printable[17]; + + if (xf86GetVerbosity() <= 4) + return; + + (void)memset(Printable, 0, SizeOf(Printable)); + + xf86ErrorFVerb(5, "\n BIOS image:"); + + for (Index = 0; Index < Length; Index++) + { + if (!(Index & (4U - 1U))) + { + if (!(Index & (16U - 1U))) + { + if (Printable[0]) + xf86ErrorFVerb(5, " |%s|", Printable); + Char = Printable; + xf86ErrorFVerb(5, "\n 0x%08X: ", Index); + } + xf86ErrorFVerb(5, " "); + } + xf86ErrorFVerb(5, "%02X", BIOS[Index]); + if (isprint(BIOS[Index])) + *Char++ = BIOS[Index]; + else + *Char++ = '.'; + } + + xf86ErrorFVerb(5, " |%s|\n", Printable); +} + +#ifndef AVOID_CPIO + +/* + * ATIPrintIndexedRegisters -- + * + * Display a set of indexed byte-size registers when the server is invoked with + * -verbose. + */ +static void +ATIPrintIndexedRegisters +( + const IOADDRESS Port, + const CARD8 StartIndex, + const CARD8 EndIndex, + const char *Name, + const IOADDRESS GenS1 +) +{ + int Index; + + xf86ErrorFVerb(4, "\n %s register values:", Name); + for (Index = StartIndex; Index < EndIndex; Index++) + { + if (!(Index & (4U - 1U))) + { + if (!(Index & (16U - 1U))) + xf86ErrorFVerb(4, "\n 0x%02X: ", Index); + xf86ErrorFVerb(4, " "); + } + if (Port == ATTRX) + (void)inb(GenS1); /* Reset flip-flop */ + xf86ErrorFVerb(4, "%02X", GetReg(Port, Index)); + } + + if (Port == ATTRX) + { + (void)inb(GenS1); /* Reset flip-flop */ + outb(ATTRX, 0x20U); /* Turn on PAS bit */ + } + + xf86ErrorFVerb(4, "\n"); +} + +#endif /* AVOID_CPIO */ + +/* + * ATIMach64PrintRegisters -- + * + * Display a Mach64's main register bank when the server is invoked with + * -verbose. + */ +static void +ATIMach64PrintRegisters +( + ATIPtr pATI, + CARD8 *crtc, + const char *Description +) +{ + CARD32 IOValue; + CARD8 dac_read, dac_mask, dac_data, dac_write; + int Index, Limit; + +#ifndef AVOID_CPIO + + int Step; + +#endif /* AVOID_CPIO */ + + xf86ErrorFVerb(4, "\n Mach64 %s register values:", Description); + +#ifdef AVOID_CPIO + + if (pATI->pBlock[1]) + Limit = DWORD_SELECT; + else + Limit = MM_IO_SELECT; + + for (Index = 0; Index <= Limit; Index += UnitOf(MM_IO_SELECT)) + { + if (!(Index & SetBits(3, MM_IO_SELECT))) + xf86ErrorFVerb(4, "\n 0x%04X: ", Index); + if (Index == (DAC_REGS & DWORD_SELECT)) + { + dac_read = in8(DAC_REGS + 3); + DACDelay; + dac_mask = in8(DAC_REGS + 2); + DACDelay; + dac_data = in8(DAC_REGS + 1); + DACDelay; + dac_write = in8(DAC_REGS + 0); + DACDelay; + + xf86ErrorFVerb(4, " %02X%02X%02X%02X", + dac_read, dac_mask, dac_data, dac_write); + + out8(DAC_REGS + 2, dac_mask); + DACDelay; + out8(DAC_REGS + 3, dac_read); + DACDelay; + } + else + { + IOValue = inm(Index); + + if ((Index == (CRTC_GEN_CNTL & DWORD_SELECT)) && + (IOValue & CRTC_EXT_DISP_EN)) + *crtc = ATI_CRTC_MACH64; + + xf86ErrorFVerb(4, " %08lX", (unsigned long)IOValue); + } + } + +#else /* AVOID_CPIO */ + + Limit = ATIIOPort(IOPortTag(0x1FU, 0x3FU)); + Step = ATIIOPort(IOPortTag(0x01U, 0x01U)) - pATI->CPIOBase; + for (Index = pATI->CPIOBase; Index <= Limit; Index += Step) + { + if (!(((Index - pATI->CPIOBase) / Step) & 0x03U)) + xf86ErrorFVerb(4, "\n 0x%04X: ", Index); + if (Index == (int)ATIIOPort(DAC_REGS)) + { + dac_read = in8(DAC_REGS + 3); + DACDelay; + dac_mask = in8(DAC_REGS + 2); + DACDelay; + dac_data = in8(DAC_REGS + 1); + DACDelay; + dac_write = in8(DAC_REGS + 0); + DACDelay; + + xf86ErrorFVerb(4, " %02X%02X%02X%02X", + dac_read, dac_mask, dac_data, dac_write); + + out8(DAC_REGS + 2, dac_mask); + DACDelay; + out8(DAC_REGS + 3, dac_read); + DACDelay; + } + else + { + IOValue = inl(Index); + + if ((Index == (int)ATIIOPort(CRTC_GEN_CNTL)) && + (IOValue & CRTC_EXT_DISP_EN)) + *crtc = ATI_CRTC_MACH64; + + xf86ErrorFVerb(4, " %08lX", (unsigned long)IOValue); + } + } + +#endif /* AVOID_CPIO */ + + xf86ErrorFVerb(4, "\n"); +} + +/* + * ATIMach64PrintPLLRegisters -- + * + * Display an integrated Mach64's PLL registers when the server is invoked with + * -verbose. + */ +static void +ATIMach64PrintPLLRegisters +( + ATIPtr pATI +) +{ + int Index, Limit; + CARD8 PLLReg[MaxBits(PLL_ADDR) + 1]; + + for (Limit = 0; Limit < SizeOf(PLLReg); Limit++) + PLLReg[Limit] = ATIMach64GetPLLReg(Limit); + + /* Determine how many PLL registers there really are */ + while ((Limit = Limit >> 1)) + for (Index = 0; Index < Limit; Index++) + if (PLLReg[Index] != PLLReg[Index + Limit]) + goto FoundLimit; +FoundLimit: + Limit <<= 1; + + xf86ErrorFVerb(4, "\n Mach64 PLL register values:"); + for (Index = 0; Index < Limit; Index++) + { + if (!(Index & 3)) + { + if (!(Index & 15)) + xf86ErrorFVerb(4, "\n 0x%02X: ", Index); + xf86ErrorFVerb(4, " "); + } + xf86ErrorFVerb(4, "%02X", PLLReg[Index]); + } + + xf86ErrorFVerb(4, "\n"); +} + +/* + * ATIRGB514PrintRegisters -- + * + * Display IBM RGB 514 registers when the server is invoked with -verbose. + */ +static void +ATIRGB514PrintRegisters +( + ATIPtr pATI +) +{ + CARD32 crtc_gen_cntl, dac_cntl; + CARD8 index_lo, index_hi, index_ctl; + int Index; + + /* Temporarily switch to Mach64 CRTC */ + crtc_gen_cntl = inr(CRTC_GEN_CNTL); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN); + + /* Temporarily switch to IBM RGB 514 registers */ + dac_cntl = inr(DAC_CNTL); + outr(DAC_CNTL, (dac_cntl & ~DAC_EXT_SEL_RS3) | DAC_EXT_SEL_RS2); + + index_lo = in8(M64_DAC_WRITE); + index_hi = in8(M64_DAC_DATA); + index_ctl = in8(M64_DAC_READ); + + out8(M64_DAC_WRITE, 0x00U); + out8(M64_DAC_DATA, 0x00U); + out8(M64_DAC_READ, 0x01U); /* Auto-increment */ + + xf86ErrorFVerb(4, "\n IBM RGB 514 registers:"); + for (Index = 0; Index < 0x0800; Index++) + { + if (!(Index & 3)) + { + if (!(Index & 15)) + { + xf86ErrorFVerb(4, "\n 0x%04X: ", Index); + + /* Need to rewrite index every so often... */ + if ((Index == 0x0100) || (Index == 0x0500)) + { + out8(M64_DAC_WRITE, 0x00U); + out8(M64_DAC_DATA, Index >> 8); + } + } + + xf86ErrorFVerb(4, " "); + } + + xf86ErrorFVerb(4, "%02X", in8(M64_DAC_MASK)); + } + + /* Restore registers */ + out8(M64_DAC_WRITE, index_lo); + out8(M64_DAC_DATA, index_hi); + out8(M64_DAC_READ, index_ctl); + outr(DAC_CNTL, dac_cntl); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl); + + xf86ErrorFVerb(4, "\n"); +} + +/* + * ATIPrintRegisters -- + * + * Display various registers when the server is invoked with -verbose. + */ +void +ATIPrintRegisters +( + ATIPtr pATI +) +{ + pciVideoPtr pVideo; + pciConfigPtr pPCI; + int Index; + CARD32 lcd_index, tv_out_index, lcd_gen_ctrl; + CARD8 dac_read, dac_mask, dac_write; + CARD8 crtc; + +#ifndef AVOID_CPIO + + CARD8 genmo, seq1 = 0; + + crtc = ATI_CRTC_VGA; + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + xf86ErrorFVerb(4, "\n Miscellaneous output register value: 0x%02X.\n", + genmo = inb(R_GENMO)); + + if (genmo & 0x01U) + { + if (pATI->Chip == ATI_CHIP_264LT) + { + lcd_gen_ctrl = inr(LCD_GEN_CTRL); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl & ~SHADOW_RW_EN); + ATIPrintIndexedRegisters(CRTX(ColourIOBase), 0, 64, + "Non-shadow colour CRT controller", 0); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl | SHADOW_RW_EN); + ATIPrintIndexedRegisters(CRTX(ColourIOBase), 0, 64, + "Shadow colour CRT controller", 0); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + } + else if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) + { + lcd_index = inr(LCD_INDEX); + lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, + lcd_gen_ctrl & ~(CRTC_RW_SELECT | SHADOW_RW_EN)); + ATIPrintIndexedRegisters(CRTX(ColourIOBase), 0, 64, + "Non-shadow colour CRT controller", 0); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, + (lcd_gen_ctrl & ~CRTC_RW_SELECT) | SHADOW_RW_EN); + ATIPrintIndexedRegisters(CRTX(ColourIOBase), 0, 64, + "Shadow colour CRT controller", 0); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + outr(LCD_INDEX, lcd_index); + } + else + { + ATIPrintIndexedRegisters(CRTX(ColourIOBase), 0, 64, + "Colour CRT controller", 0); + } + + ATIPrintIndexedRegisters(ATTRX, 0, 32, "Attribute controller", + GENS1(ColourIOBase)); + } + else + { + if (pATI->Chip == ATI_CHIP_264LT) + { + lcd_gen_ctrl = inr(LCD_GEN_CTRL); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl & ~SHADOW_RW_EN); + ATIPrintIndexedRegisters(CRTX(MonochromeIOBase), 0, 64, + "Non-shadow monochrome CRT controller", 0); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl | SHADOW_RW_EN); + ATIPrintIndexedRegisters(CRTX(MonochromeIOBase), 0, 64, + "Shadow monochrome CRT controller", 0); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + } + else if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) + { + lcd_index = inr(LCD_INDEX); + lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, + lcd_gen_ctrl & ~(CRTC_RW_SELECT | SHADOW_RW_EN)); + ATIPrintIndexedRegisters(CRTX(MonochromeIOBase), 0, 64, + "Non-shadow monochrome CRT controller", 0); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, + (lcd_gen_ctrl & ~CRTC_RW_SELECT) | SHADOW_RW_EN); + ATIPrintIndexedRegisters(CRTX(MonochromeIOBase), 0, 64, + "Shadow monochrome CRT controller", 0); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + outr(LCD_INDEX, lcd_index); + } + else + { + ATIPrintIndexedRegisters(CRTX(MonochromeIOBase), 0, 64, + "Monochrome CRT controller", 0); + } + + ATIPrintIndexedRegisters(ATTRX, 0, 32, "Attribute controller", + GENS1(MonochromeIOBase)); + } + + ATIPrintIndexedRegisters(GRAX, 0, 16, "Graphics controller", 0); + ATIPrintIndexedRegisters(SEQX, 0, 8, "Sequencer", 0); + + if (pATI->CPIO_VGAWonder) + ATIPrintIndexedRegisters(pATI->CPIO_VGAWonder, + xf86ServerIsOnlyProbing() ? 0x80U : pATI->VGAOffset, 0xC0U, + "ATI extended VGA", 0); + } + + if (pATI->ChipHasSUBSYS_CNTL) + { + xf86ErrorFVerb(4, "\n 8514/A register values:"); + for (Index = 0x02E8U; Index <= 0x0FEE8; Index += 0x0400U) + { + if (!((Index - 0x02E8U) & 0x0C00U)) + xf86ErrorFVerb(4, "\n 0x%04X: ", Index); + xf86ErrorFVerb(4, " %04X", inw(Index)); + } + + if (pATI->Adapter >= ATI_ADAPTER_MACH8) + { + xf86ErrorFVerb(4, "\n\n Mach8/Mach32 register values:"); + for (Index = 0x02EEU; Index <= 0x0FEEE; Index += 0x0400U) + { + if (!((Index - 0x02EEU) & 0x0C00U)) + xf86ErrorFVerb(4, "\n 0x%04X: ", Index); + xf86ErrorFVerb(4, " %04X", inw(Index)); + } + } + + xf86ErrorFVerb(4, "\n"); + } + else + +#endif /* AVOID_CPIO */ + + if (pATI->Chip == ATI_CHIP_264LT) + { + lcd_gen_ctrl = inr(LCD_GEN_CTRL); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl & ~SHADOW_RW_EN); + ATIMach64PrintRegisters(pATI, &crtc, "non-shadow"); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl | SHADOW_RW_EN); + ATIMach64PrintRegisters(pATI, &crtc, "shadow"); + + outr(LCD_GEN_CTRL, lcd_gen_ctrl); + + ATIMach64PrintPLLRegisters(pATI); + } + else if ((pATI->Chip == ATI_CHIP_264LTPRO) || + (pATI->Chip == ATI_CHIP_264XL) || + (pATI->Chip == ATI_CHIP_MOBILITY)) + { + lcd_index = inr(LCD_INDEX); + lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, + lcd_gen_ctrl & ~(CRTC_RW_SELECT | SHADOW_RW_EN)); + ATIMach64PrintRegisters(pATI, &crtc, "non-shadow"); + + ATIMach64PutLCDReg(LCD_GEN_CNTL, + (lcd_gen_ctrl & ~CRTC_RW_SELECT) | SHADOW_RW_EN); + ATIMach64PrintRegisters(pATI, &crtc, "shadow"); + + if (pATI->Chip != ATI_CHIP_264XL) + { + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl | CRTC_RW_SELECT); + ATIMach64PrintRegisters(pATI, &crtc, "secondary"); + } + + ATIMach64PutLCDReg(LCD_GEN_CNTL, lcd_gen_ctrl); + + ATIMach64PrintPLLRegisters(pATI); + + xf86ErrorFVerb(4, "\n LCD register values:"); + for (Index = 0; Index < 64; Index++) + { + if (!(Index & 3)) + xf86ErrorFVerb(4, "\n 0x%02X: ", Index); + xf86ErrorFVerb(4, " %08X", ATIMach64GetLCDReg(Index)); + } + + outr(LCD_INDEX, lcd_index); + + tv_out_index = inr(TV_OUT_INDEX); + + xf86ErrorFVerb(4, "\n\n TV_OUT register values:"); + for (Index = 0; Index < 256; Index++) + { + if (!(Index & 3)) + xf86ErrorFVerb(4, "\n 0x%02X: ", Index); + xf86ErrorFVerb(4, " %08X", ATIMach64GetTVReg(Index)); + } + + outr(TV_OUT_INDEX, tv_out_index); + + xf86ErrorFVerb(4, "\n"); + } + else + +#ifndef AVOID_CPIO + + if (pATI->Chip >= ATI_CHIP_88800GXC) + +#endif /* AVOID_CPIO */ + + { + +#ifdef AVOID_CPIO + + ATIMach64PrintRegisters(pATI, &crtc, "MMIO"); + +#else /* AVOID_CPIO */ + + ATIMach64PrintRegisters(pATI, &crtc, + (pATI->CPIODecoding == SPARSE_IO) ? "sparse" : "block"); + +#endif /* AVOID_CPIO */ + + if (pATI->Chip >= ATI_CHIP_264CT) + ATIMach64PrintPLLRegisters(pATI); + + if (pATI->DAC == ATI_DAC_IBMRGB514) + ATIRGB514PrintRegisters(pATI); + } + +#ifdef AVOID_CPIO + + dac_read = in8(M64_DAC_READ); + DACDelay; + dac_write = in8(M64_DAC_WRITE); + DACDelay; + dac_mask = in8(M64_DAC_MASK); + DACDelay; + + xf86ErrorFVerb(4, "\n" + " DAC read index: 0x%02X\n" + " DAC write index: 0x%02X\n" + " DAC mask: 0x%02X\n\n" + " DAC colour lookup table:", + dac_read, dac_write, dac_mask); + + out8(M64_DAC_MASK, 0xFFU); + DACDelay; + out8(M64_DAC_READ, 0x00U); + DACDelay; + + for (Index = 0; Index < 256; Index++) + { + if (!(Index & 3)) + xf86ErrorFVerb(4, "\n 0x%02X:", Index); + xf86ErrorFVerb(4, " %02X", in8(M64_DAC_DATA)); + DACDelay; + xf86ErrorFVerb(4, " %02X", in8(M64_DAC_DATA)); + DACDelay; + xf86ErrorFVerb(4, " %02X", in8(M64_DAC_DATA)); + DACDelay; + } + + out8(M64_DAC_MASK, dac_mask); + DACDelay; + out8(M64_DAC_READ, dac_read); + DACDelay; + +#else /* AVOID_CPIO */ + + ATISetDACIOPorts(pATI, crtc); + + /* Temporarily turn off CLKDIV2 while reading DAC's LUT */ + if (pATI->Adapter == ATI_ADAPTER_NONISA) + { + seq1 = GetReg(SEQX, 0x01U); + if (seq1 & 0x08U) + PutReg(SEQX, 0x01U, seq1 & ~0x08U); + } + + dac_read = inb(pATI->CPIO_DAC_READ); + DACDelay; + dac_write = inb(pATI->CPIO_DAC_WRITE); + DACDelay; + dac_mask = inb(pATI->CPIO_DAC_MASK); + DACDelay; + + xf86ErrorFVerb(4, "\n" + " DAC read index: 0x%02X\n" + " DAC write index: 0x%02X\n" + " DAC mask: 0x%02X\n\n" + " DAC colour lookup table:", + dac_read, dac_write, dac_mask); + + outb(pATI->CPIO_DAC_MASK, 0xFFU); + DACDelay; + outb(pATI->CPIO_DAC_READ, 0x00U); + DACDelay; + + for (Index = 0; Index < 256; Index++) + { + if (!(Index & 3)) + xf86ErrorFVerb(4, "\n 0x%02X:", Index); + xf86ErrorFVerb(4, " %02X", inb(pATI->CPIO_DAC_DATA)); + DACDelay; + xf86ErrorFVerb(4, " %02X", inb(pATI->CPIO_DAC_DATA)); + DACDelay; + xf86ErrorFVerb(4, " %02X", inb(pATI->CPIO_DAC_DATA)); + DACDelay; + } + + outb(pATI->CPIO_DAC_MASK, dac_mask); + DACDelay; + outb(pATI->CPIO_DAC_READ, dac_read); + DACDelay; + + if ((pATI->Adapter == ATI_ADAPTER_NONISA) && (seq1 & 0x08U)) + PutReg(SEQX, 0x01U, seq1); + +#endif /* AVOID_CPIO */ + + if ((pVideo = pATI->PCIInfo)) + { + pPCI = pVideo->thisCard; + xf86ErrorFVerb(4, "\n\n PCI configuration register values:"); + for (Index = 0; Index < 256; Index+= 4) + { + if (!(Index & 15)) + xf86ErrorFVerb(4, "\n 0x%02X: ", Index); + xf86ErrorFVerb(4, " 0x%08lX", + (unsigned long)pciReadLong(pPCI->tag, Index)); + } + } + + xf86ErrorFVerb(4, "\n"); + +#ifndef AVOID_CPIO + + if (pATI->pBank) + xf86ErrorFVerb(4, "\n Banked aperture at 0x%0lX.", + (unsigned long)pATI->pBank); + else + xf86ErrorFVerb(4, "\n No banked aperture."); + + if (pATI->pMemory == pATI->pBank) + { + xf86ErrorFVerb(4, "\n No linear aperture.\n"); + } + else + +#else /* AVOID_CPIO */ + + if (pATI->pMemory) + +#endif /* AVOID_CPIO */ + + { + xf86ErrorFVerb(4, "\n Linear aperture at %p.\n", pATI->pMemory); + } + + if (pATI->pBlock[0]) + { + xf86ErrorFVerb(4, " Block 0 aperture at %p.\n", pATI->pBlock[0]); + if (inr(CONFIG_CHIP_ID) == pATI->config_chip_id) + xf86ErrorFVerb(4, " MMIO registers are correctly mapped.\n"); + else + xf86ErrorFVerb(4, " MMIO mapping is in error!\n"); + if (pATI->pBlock[1]) + xf86ErrorFVerb(4, " Block 1 aperture at %p.\n", + pATI->pBlock[1]); + } + else + { + xf86ErrorFVerb(4, " No MMIO aperture.\n"); + } + + if (pATI->pCursorImage) + xf86ErrorFVerb(4, " Hardware cursor image aperture at %p.\n", + pATI->pCursorImage); + else + xf86ErrorFVerb(4, " No hardware cursor image aperture.\n"); + + xf86ErrorFVerb(4, "\n"); +} + +/* + * A table to associate mode attributes with character strings. + */ +static const SymTabRec ModeAttributeNames[] = +{ + {V_PHSYNC, "+hsync"}, + {V_NHSYNC, "-hsync"}, + {V_PVSYNC, "+vsync"}, + {V_NVSYNC, "-vsync"}, + {V_PCSYNC, "+csync"}, + {V_NCSYNC, "-csync"}, + {V_INTERLACE, "interlace"}, + {V_DBLSCAN, "doublescan"}, + {V_CSYNC, "composite"}, + {V_DBLCLK, "dblclk"}, + {V_CLKDIV2, "clkdiv2"}, + {0, NULL} +}; + +/* + * ATIPrintMode -- + * + * This function displays a mode's timing information. + */ +void +ATIPrintMode +( + DisplayModePtr pMode +) +{ + const SymTabRec *pSymbol = ModeAttributeNames; + int flags = pMode->Flags; + double mClock, hSync, vRefresh; + + mClock = (double)pMode->SynthClock; + if (pMode->HSync > 0.0) + hSync = pMode->HSync; + else + hSync = mClock / pMode->HTotal; + if (pMode->VRefresh > 0.0) + { + vRefresh = pMode->VRefresh; + } + else + { + vRefresh = (hSync * 1000.0) / pMode->VTotal; + if (flags & V_INTERLACE) + vRefresh *= 2.0; + if (flags & V_DBLSCAN) + vRefresh /= 2.0; + if (pMode->VScan > 1) + vRefresh /= pMode->VScan; + } + + xf86ErrorFVerb(4, " Dot clock: %7.3f MHz\n", mClock / 1000.0); + xf86ErrorFVerb(4, " Horizontal sync: %7.3f kHz\n", hSync); + xf86ErrorFVerb(4, " Vertical refresh: %7.3f Hz (%s)\n", vRefresh, + (flags & V_INTERLACE) ? "I" : "NI"); + if ((pMode->ClockIndex >= 0) && (pMode->ClockIndex < MAXCLOCKS)) + xf86ErrorFVerb(4, " Clock index: %d\n", pMode->ClockIndex); + xf86ErrorFVerb(4, " Horizontal timings: %4d %4d %4d %4d\n" + " Vertical timings: %4d %4d %4d %4d\n", + pMode->HDisplay, pMode->HSyncStart, pMode->HSyncEnd, pMode->HTotal, + pMode->VDisplay, pMode->VSyncStart, pMode->VSyncEnd, pMode->VTotal); + + if (flags & V_HSKEW) + { + flags &= ~V_HSKEW; + xf86ErrorFVerb(4, " Horizontal skew: %4d\n", pMode->HSkew); + } + + if (pMode->VScan >= 1) + xf86ErrorFVerb(4, " Vertical scan: %4d\n", pMode->VScan); + + xf86ErrorFVerb(4, " Flags: "); + for (; pSymbol->token; pSymbol++) + { + if (flags & pSymbol->token) + { + xf86ErrorFVerb(4, " %s", pSymbol->name); + flags &= ~pSymbol->token; + if (!flags) + break; + } + } + + xf86ErrorFVerb(4, "\n"); +} diff --git a/src/atiprint.h b/src/atiprint.h new file mode 100644 index 0000000..1aca516 --- /dev/null +++ b/src/atiprint.h @@ -0,0 +1,37 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiprint.h,v 1.10 2003/01/01 19:16:33 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIPRINT_H___ +#define ___ATIPRINT_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern void ATIPrintBIOS FunctionPrototype((const CARD8 *, + const unsigned int)); +extern void ATIPrintRegisters FunctionPrototype((ATIPtr)); +extern void ATIPrintMode FunctionPrototype((DisplayModePtr)); + +#endif /* ___ATIPRINT_H___ */ diff --git a/src/atipriv.h b/src/atipriv.h new file mode 100644 index 0000000..723bf9a --- /dev/null +++ b/src/atipriv.h @@ -0,0 +1,31 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atipriv.h,v 1.5 2003/01/01 19:16:33 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIPRIV_H___ +#define ___ATIPRIV_H___ 1 + +/* Forward pointer definitions */ +typedef struct _ATIHWRec *ATIHWPtr; +typedef struct _ATIRec *ATIPtr; + +#endif /* ___ATIPRIV_H___ */ diff --git a/src/atiprobe.c b/src/atiprobe.c new file mode 100644 index 0000000..ec86179 --- /dev/null +++ b/src/atiprobe.c @@ -0,0 +1,2356 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiprobe.c,v 1.62tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atiadjust.h" +#include "atibus.h" +#include "atichip.h" +#include "aticonsole.h" +#include "atiident.h" +#include "atimach64io.h" +#include "atimodule.h" +#include "atipreinit.h" +#include "atiprobe.h" +#include "atiscreen.h" +#include "ativalid.h" +#include "ativersion.h" +#include "atividmem.h" +#include "atiwonderio.h" + +#include "radeon_probe.h" +#include "radeon_version.h" +#include "r128_probe.h" +#include "r128_version.h" + +/* + * NOTES: + * + * - The driver private structures (ATIRec's) are allocated here, rather than + * in ATIPreInit(). This allows ATIProbe() to pass information to later + * stages. + * - A minor point, perhaps, is that XF86Config Chipset names denote functional + * levels, rather than specific graphics controller chips. + * - ATIProbe() does not call xf86MatchPciInstances(), because ATIProbe() + * should be able to match a mix of PCI and non-PCI devices to XF86Config + * Device sections. Also, PCI configuration space for Mach32's is to be + * largely ignored. + */ + +#ifdef XFree86LOADER + +/* + * The following exists to prevent the compiler from considering entry points + * defined in a separate module from being constants. + */ +static xf86PreInitProc * const volatile PreInitProc = ATIPreInit; +static xf86ScreenInitProc * const volatile ScreenInitProc = ATIScreenInit; +static xf86SwitchModeProc * const volatile SwitchModeProc = ATISwitchMode; +static xf86AdjustFrameProc * const volatile AdjustFrameProc = ATIAdjustFrame; +static xf86EnterVTProc * const volatile EnterVTProc = ATIEnterVT; +static xf86LeaveVTProc * const volatile LeaveVTProc = ATILeaveVT; +static xf86FreeScreenProc * const volatile FreeScreenProc = ATIFreeScreen; +static xf86ValidModeProc * const volatile ValidModeProc = ATIValidMode; + +#define ATIPreInit PreInitProc +#define ATIScreenInit ScreenInitProc +#define ATISwitchMode SwitchModeProc +#define ATIAdjustFrame AdjustFrameProc +#define ATIEnterVT EnterVTProc +#define ATILeaveVT LeaveVTProc +#define ATIFreeScreen FreeScreenProc +#define ATIValidMode ValidModeProc + +#endif + +/* Used as a temporary buffer */ +#define Identifier ((char *)(pATI->MMIOCache)) + +/* + * An internal structure definition to facilitate the matching of detected + * adapters to XF86Config Device sections. + */ +typedef struct _ATIGDev +{ + GDevPtr pGDev; + int iATIPtr; + CARD8 Chipset; +} ATIGDev, *ATIGDevPtr; + +#ifndef AVOID_CPIO + +/* + * Definitions for I/O conflict avoidance. + */ +#define LongPort(_Port) GetBits(_Port, PCIGETIO(SPARSE_IO_BASE)) +#define DetectedVGA (1 << 0) +#define Detected8514A (1 << 1) +#define DetectedMach64 (1 << 2) +#define Allowed (1 << 3) +#define DoProbe (1 << 4) +typedef struct +{ + IOADDRESS Base; + CARD8 Size; + CARD8 Flag; +} PortRec, *PortPtr; + +/* + * ATIScanPCIBases -- + * + * This function loops though a device's PCI registered bases and accumulates + * a list of block I/O bases in use in the system. + */ +static void +ATIScanPCIBases +( + PortPtr *PCIPorts, + int *nPCIPort, + const CARD32 *pBase, + const int *pSize, + const CARD8 ProbeFlag +) +{ + IOADDRESS Base; + int i, j; + + for (i = 6; --i >= 0; pBase++, pSize++) + { + if (*pBase & PCI_MAP_IO) + { + Base = *pBase & ~IO_BYTE_SELECT; + for (j = 0; ; j++) + { + if (j >= *nPCIPort) + { + (*nPCIPort)++; + *PCIPorts = (PortPtr)xnfrealloc(*PCIPorts, + *nPCIPort * SizeOf(PortRec)); + (*PCIPorts)[j].Base = Base; + (*PCIPorts)[j].Size = (CARD8)*pSize; + (*PCIPorts)[j].Flag = ProbeFlag; + break; + } + + if (Base == (*PCIPorts)[j].Base) + break; + } + + continue; + } + + /* Allow for 64-bit addresses */ + if (!PCI_MAP_IS64BITMEM(*pBase)) + continue; + + i--; + pBase++; + pSize++; + } +} + +/* + * ATICheckSparseIOBases -- + * + * This function checks whether a sparse I/O base can safely be probed. + */ +static CARD8 +ATICheckSparseIOBases +( + pciVideoPtr pVideo, + CARD8 *ProbeFlags, + const IOADDRESS IOBase, + const int Count, + const Bool Override +) +{ + CARD32 FirstPort, LastPort; + + if (!pVideo || !xf86IsPrimaryPci(pVideo)) + { + FirstPort = LongPort(IOBase); + LastPort = LongPort(IOBase + Count - 1); + + for (; FirstPort <= LastPort; FirstPort++) + { + CARD8 ProbeFlag = ProbeFlags[FirstPort]; + + if (ProbeFlag & DoProbe) + continue; + + if (!(ProbeFlag & Allowed)) + return ProbeFlag; + + if (Override) + continue; + + /* User might wish to override this decision */ + xf86Msg(X_WARNING, + ATI_NAME ": Sparse I/O base 0x%04lX not probed.\n", IOBase); + return Allowed; + } + } + + return DoProbe; +} + +#ifndef AVOID_NON_PCI + +/* + * ATIClaimSparseIOBases -- + * + * This function updates the sparse I/O base table with information from the + * hardware probes. + */ +static void +ATIClaimSparseIOBases +( + CARD8 *ProbeFlags, + const IOADDRESS IOBase, + const int Count, + const CARD8 ProbeFlag +) +{ + CARD32 FirstPort = LongPort(IOBase), + LastPort = LongPort(IOBase + Count - 1); + + for (; FirstPort <= LastPort; FirstPort++) + ProbeFlags[FirstPort] = ProbeFlag; +} + +#endif /* AVOID_NON_PCI */ + +/* + * ATIVGAProbe -- + * + * This function looks for an IBM standard VGA, or clone, and sets + * pATI->VGAAdapter if one is found. + */ +static ATIPtr +ATIVGAProbe +( + ATIPtr pVGA +) +{ + CARD8 IOValue1, IOValue2, IOValue3; + + if (!pVGA) + pVGA = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); + + /* + * VGA has one more attribute register than EGA. See if it can be read and + * written. Note that the CRTC registers are not used here, so there's no + * need to unlock them. + */ + ATISetVGAIOBase(pVGA, inb(R_GENMO)); + (void)inb(GENS1(pVGA->CPIO_VGABase)); + IOValue1 = inb(ATTRX); + (void)inb(GENS1(pVGA->CPIO_VGABase)); + IOValue2 = GetReg(ATTRX, 0x14U | 0x20U); + outb(ATTRX, IOValue2 ^ 0x0FU); + IOValue3 = GetReg(ATTRX, 0x14U | 0x20U); + outb(ATTRX, IOValue2); + outb(ATTRX, IOValue1); + (void)inb(GENS1(pVGA->CPIO_VGABase)); + if (IOValue3 == (IOValue2 ^ 0x0FU)) + { + /* VGA device detected */ + if (pVGA->Chip == ATI_CHIP_NONE) + pVGA->Chip = ATI_CHIP_VGA; + if (pVGA->VGAAdapter == ATI_ADAPTER_NONE) + pVGA->VGAAdapter = ATI_ADAPTER_VGA; + if (pVGA->Adapter == ATI_ADAPTER_NONE) + pVGA->Adapter = ATI_ADAPTER_VGA; + } + else + { + pVGA->VGAAdapter = ATI_ADAPTER_NONE; + } + + return pVGA; +} + +/* + * ATIVGAWonderProbe -- + * + * This function determines if ATI extended VGA registers can be accessed + * through the I/O port specified by pATI->CPIO_VGAWonder. If not, the + * function resets pATI->CPIO_VGAWonder to zero. + */ +static void +ATIVGAWonderProbe +( + pciVideoPtr pVideo, + ATIPtr pATI, + ATIPtr p8514, + CARD8 *ProbeFlags +) +{ + CARD8 IOValue1, IOValue2, IOValue3, IOValue4, IOValue5, IOValue6; + + switch (ATICheckSparseIOBases(pVideo, ProbeFlags, + pATI->CPIO_VGAWonder, 2, TRUE)) + { + case 0: + xf86Msg(X_WARNING, + ATI_NAME ": Expected VGA Wonder capability could not be" + " detected at I/O port 0x%04lX because it would conflict with" + " a non-video PCI/AGP device.\n", pATI->CPIO_VGAWonder); + pATI->CPIO_VGAWonder = 0; + break; + + case Detected8514A: + xf86Msg(X_WARNING, + ATI_NAME ": Expected VGA Wonder capability could not be" + " detected at I/O port 0x%04lX because it would conflict with" + " a %s %s.\n", pATI->CPIO_VGAWonder, + ATIBusNames[p8514->BusType], ATIAdapterNames[p8514->Adapter]); + pATI->CPIO_VGAWonder = 0; + break; + + case DetectedMach64: + xf86Msg(X_WARNING, + ATI_NAME ": Expected VGA Wonder capability could not be" + " detected at I/O port 0x%04lX because it would conflict with" + " a Mach64.\n", pATI->CPIO_VGAWonder); + pATI->CPIO_VGAWonder = 0; + break; + + case DetectedVGA: + default: /* Must be DoProbe */ + if (pVideo && !xf86IsPrimaryPci(pVideo) && + (pATI->Chip <= ATI_CHIP_88800GXD)) + { + /* Set up extended VGA register addressing */ + PutReg(GRAX, 0x50U, GetByte(pATI->CPIO_VGAWonder, 0)); + PutReg(GRAX, 0x51U, + GetByte(pATI->CPIO_VGAWonder, 1) | pATI->VGAOffset); + } + /* + * Register 0xBB is used by the BIOS to keep track of various + * things (monitor type, etc.). Except for 18800-x's, register + * 0xBC must be zero and causes the adapter to enter a test mode + * when written to with a non-zero value. + */ + IOValue1 = inb(pATI->CPIO_VGAWonder); + IOValue2 = ATIGetExtReg(IOValue1); + IOValue3 = ATIGetExtReg(0xBBU); + ATIPutExtReg(0xBBU, IOValue3 ^ 0xAAU); + IOValue4 = ATIGetExtReg(0xBBU); + ATIPutExtReg(0xBBU, IOValue3 ^ 0x55U); + IOValue5 = ATIGetExtReg(0xBBU); + ATIPutExtReg(0xBBU, IOValue3); + if (pATI->Chip <= ATI_CHIP_18800_1) + IOValue6 = 0; + else + IOValue6 = ATIGetExtReg(0xBCU); + ATIPutExtReg(IOValue1, IOValue2); + + if ((IOValue4 == (IOValue3 ^ 0xAAU)) && + (IOValue5 == (IOValue3 ^ 0x55U)) && + (IOValue6 == 0)) + { + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": VGA Wonder at I/O port 0x%04lX detected.\n", + pATI->CPIO_VGAWonder); + } + else + { + xf86Msg(X_WARNING, + ATI_NAME ": Expected VGA Wonder capability at I/O port" + " 0x%04lX was not detected.\n", pATI->CPIO_VGAWonder); + pATI->CPIO_VGAWonder = 0; + } + break; + } +} + +/* + * ATI8514Probe -- + * + * This function looks for an 8514/A compatible and returns an ATIRec if one is + * found. The function also determines whether or not the detected 8514/A + * compatible device is actually a Mach8 or Mach32, and sets pATI->Adapter + * accordingly. + */ +static ATIPtr +ATI8514Probe +( + pciVideoPtr pVideo +) +{ + ATIPtr pATI = NULL; + CARD16 IOValue1, IOValue2; + + /* + * Save register value to be modified, just in case there is no 8514/A + * compatible accelerator. Note that, in more ways than one, + * SUBSYS_STAT == SUBSYS_CNTL. + */ + IOValue1 = inw(SUBSYS_STAT); + IOValue2 = IOValue1 & _8PLANE; + + /* Reset any 8514/A compatible adapter that might be present */ + outw(SUBSYS_CNTL, IOValue2 | (GPCTRL_RESET | CHPTEST_NORMAL)); + outw(SUBSYS_CNTL, IOValue2 | (GPCTRL_ENAB | CHPTEST_NORMAL | + RVBLNKFLG | RPICKFLAG | RINVALIDIO | RGPIDLE)); + + /* Probe for an 8514/A compatible */ + IOValue2 = inw(ERR_TERM); + outw(ERR_TERM, 0x5A5AU); + ProbeWaitIdleEmpty(); + if (inw(ERR_TERM) == 0x5A5AU) + { + outw(ERR_TERM, 0x2525U); + if (inw(ERR_TERM) == 0x2525U) + { + pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); + pATI->Adapter = ATI_ADAPTER_8514A; + pATI->ChipHasSUBSYS_CNTL = TRUE; + pATI->PCIInfo = pVideo; + } + } + outw(ERR_TERM, IOValue2); + + /* Restore register value clobbered by 8514/A reset attempt */ + if (!pATI) + { + outw(SUBSYS_CNTL, IOValue1); + return NULL; + } + + /* Ensure any Mach8 or Mach32 is not in 8514/A emulation mode */ + IOValue1 = inw(CLOCK_SEL); + outw(CLOCK_SEL, IOValue1); + ProbeWaitIdleEmpty(); + + IOValue1 = IOValue2 = inw(ROM_ADDR_1); + outw(ROM_ADDR_1, 0x5555U); + ProbeWaitIdleEmpty(); + if (inw(ROM_ADDR_1) == 0x5555U) + { + outw(ROM_ADDR_1, 0x2A2AU); + ProbeWaitIdleEmpty(); + if (inw(ROM_ADDR_1) == 0x2A2AU) + pATI->Adapter = ATI_ADAPTER_MACH8; + } + outw(ROM_ADDR_1, IOValue1); + + if (pATI->Adapter == ATI_ADAPTER_MACH8) + { + /* A Mach8 or Mach32 has been detected */ + IOValue1 = inw(READ_SRC_X); + outw(DESTX_DIASTP, 0xAAAAU); + ProbeWaitIdleEmpty(); + if (inw(READ_SRC_X) == 0x02AAU) + pATI->Adapter = ATI_ADAPTER_MACH32; + + outw(DESTX_DIASTP, 0x5555U); + ProbeWaitIdleEmpty(); + if (inw(READ_SRC_X) == 0x0555U) + { + if (pATI->Adapter != ATI_ADAPTER_MACH32) + pATI->Adapter = ATI_ADAPTER_8514A; + } + else + { + if (pATI->Adapter != ATI_ADAPTER_MACH8) + pATI->Adapter = ATI_ADAPTER_8514A; + } + outw(DESTX_DIASTP, IOValue1); + } + + switch (pATI->Adapter) + { + case ATI_ADAPTER_8514A: + pATI->Coprocessor = ATI_CHIP_8514A; + IOValue1 = inb(EXT_CONFIG_3); + outb(EXT_CONFIG_3, IOValue1 & 0x0FU); + if (!(inb(EXT_CONFIG_3) & 0xF0U)) + { + outb(EXT_CONFIG_3, IOValue1 | 0xF0U); + if ((inb(EXT_CONFIG_3) & 0xF0U) == 0xF0U) + pATI->Coprocessor = ATI_CHIP_CT480; + } + outb(EXT_CONFIG_3, IOValue1); + break; + + case ATI_ADAPTER_MACH8: + pATI->Coprocessor = ATI_CHIP_38800_1; + if (inw(CONFIG_STATUS_1) & MC_BUS) + pATI->BusType = ATI_BUS_MCA16; + break; + + case ATI_ADAPTER_MACH32: + IOValue1 = inw(CONFIG_STATUS_1); + pATI->BusType = GetBits(IOValue1, BUS_TYPE); + pATI->BIOSBase = 0x000C0000U + + (GetBits(IOValue2, BIOS_BASE_SEGMENT) << 11); + if (!(IOValue1 & (_8514_ONLY | CHIP_DIS))) + { + pATI->VGAAdapter = ATI_ADAPTER_MACH32; + if ((xf86ReadBIOS(pATI->BIOSBase, 0x10U, + (pointer)(&pATI->CPIO_VGAWonder), + SizeOf(pATI->CPIO_VGAWonder)) < + SizeOf(pATI->CPIO_VGAWonder)) || + !(pATI->CPIO_VGAWonder &= SPARSE_IO_PORT)) + pATI->CPIO_VGAWonder = 0x01CEU; + pATI->VGAOffset = 0x80U; + } + + ATIMach32ChipID(pATI); + break; + + default: + break; + } + + return pATI; +} + +#endif /* AVOID_CPIO */ + +/* + * ATIMach64Detect -- + * + * This function determines if a Mach64 is detectable at a particular base + * address. + */ +static Bool +ATIMach64Detect +( + ATIPtr pATI, + const CARD16 ChipType, + const ATIChipType Chip +) +{ + CARD32 IOValue, bus_cntl, gen_test_cntl; + + (void)ATIMapApertures(-1, pATI); /* Ignore errors */ + +#ifdef AVOID_CPIO + + if (!pATI->pBlock[0]) + { + ATIUnmapApertures(-1, pATI); + return FALSE; + } + +#endif /* AVOID_CPIO */ + + /* Make sure any Mach64 is not in some weird state */ + bus_cntl = inr(BUS_CNTL); + if (Chip < ATI_CHIP_264VTB) + outr(BUS_CNTL, + (bus_cntl & ~(BUS_HOST_ERR_INT_EN | BUS_FIFO_ERR_INT_EN)) | + (BUS_HOST_ERR_INT | BUS_FIFO_ERR_INT)); + else if (Chip < ATI_CHIP_264VT4) + outr(BUS_CNTL, (bus_cntl & ~BUS_HOST_ERR_INT_EN) | BUS_HOST_ERR_INT); + + gen_test_cntl = inr(GEN_TEST_CNTL); + IOValue = gen_test_cntl & + (GEN_OVR_OUTPUT_EN | GEN_OVR_POLARITY | GEN_CUR_EN | GEN_BLOCK_WR_EN); + outr(GEN_TEST_CNTL, IOValue | GEN_GUI_EN); + outr(GEN_TEST_CNTL, IOValue); + outr(GEN_TEST_CNTL, IOValue | GEN_GUI_EN); + + /* See if a Mach64 answers */ + IOValue = inr(SCRATCH_REG0); + + /* Test odd bits */ + outr(SCRATCH_REG0, 0x55555555U); + if (inr(SCRATCH_REG0) == 0x55555555U) + { + /* Test even bits */ + outr(SCRATCH_REG0, 0xAAAAAAAAU); + if (inr(SCRATCH_REG0) == 0xAAAAAAAAU) + { + /* + * *Something* has a R/W 32-bit register at this address. Try to + * make sure it's a Mach64. The following assumes that ATI will + * not be producing any more adapters that do not register + * themselves in PCI configuration space. + */ + ATIMach64ChipID(pATI, ChipType); + if ((pATI->Chip != ATI_CHIP_Mach64) || + (pATI->CPIODecoding == BLOCK_IO)) + pATI->Adapter = ATI_ADAPTER_MACH64; + } + } + + /* Restore clobbered register value */ + outr(SCRATCH_REG0, IOValue); + + /* If no Mach64 was detected, return now */ + if (pATI->Adapter != ATI_ADAPTER_MACH64) + { + outr(GEN_TEST_CNTL, gen_test_cntl); + outr(BUS_CNTL, bus_cntl); + ATIUnmapApertures(-1, pATI); + return FALSE; + } + + /* Determine legacy BIOS address */ + pATI->BIOSBase = 0x000C0000U + + (GetBits(inr(SCRATCH_REG1), BIOS_BASE_SEGMENT) << 11); + + ATIUnmapApertures(-1, pATI); + pATI->PCIInfo = NULL; + return TRUE; +} + +#ifdef AVOID_CPIO + +/* + * ATIMach64Probe -- + * + * This function looks for a Mach64 at a particular MMIO address and returns an + * ATIRec if one is found. + */ +static ATIPtr +ATIMach64Probe +( + pciVideoPtr pVideo, + const IOADDRESS IOBase, + const CARD8 IODecoding, + const ATIChipType Chip +) +{ + ATIPtr pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); + CARD16 ChipType = 0; + + pATI->CPIOBase = IOBase; + pATI->CPIODecoding = IODecoding; + + if (pVideo) + { + pATI->PCIInfo = pVideo; + ChipType = pVideo->chipType; + + /* + * Probe through auxiliary MMIO aperture if one exists. Because such + * apertures can be enabled/disabled only through PCI, this probes no + * further. + */ + if ((pVideo->size[2] >= 12) && + (pATI->Block0Base = pVideo->memBase[2]) && + (pATI->Block0Base < (CARD32)(-1 << pVideo->size[2]))) + { + pATI->Block0Base += 0x00000400U; + goto LastProbe; + } + + /* + * Probe through the primary MMIO aperture that exists at the tail end + * of the linear aperture. Test for both 8MB and 4MB linear apertures. + */ + if ((pVideo->size[0] >= 22) && (pATI->Block0Base = pVideo->memBase[0])) + { + pATI->Block0Base += 0x007FFC00U; + if ((pVideo->size[0] >= 23) && + ATIMach64Detect(pATI, ChipType, Chip)) + return pATI; + + pATI->Block0Base -= 0x00400000U; + if (ATIMach64Detect(pATI, ChipType, Chip)) + return pATI; + } + } + + /* + * A last, perhaps desparate, probe attempt. Note that if this succeeds, + * there's a VGA in the system and it's likely the PIO version of the + * driver should be used instead (barring OS issues). + */ + pATI->Block0Base = 0x000BFC00U; + +LastProbe: + if (ATIMach64Detect(pATI, ChipType, Chip)) + return pATI; + + xfree(pATI); + return NULL; +} + +#else /* AVOID_CPIO */ + +/* + * ATIMach64Probe -- + * + * This function looks for a Mach64 at a particular PIO address and returns an + * ATIRec if one is found. + */ +static ATIPtr +ATIMach64Probe +( + pciVideoPtr pVideo, + const IOADDRESS IOBase, + const CARD8 IODecoding, + const ATIChipType Chip +) +{ + ATIPtr pATI; + CARD32 IOValue; + CARD16 ChipType = 0; + + if (!IOBase) + return NULL; + + if (pVideo) + { + if ((IODecoding == BLOCK_IO) && + ((pVideo->size[1] < 8) || + (IOBase >= (CARD32)(-1 << pVideo->size[1])))) + return NULL; + + ChipType = pVideo->chipType; + } + + pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); + pATI->CPIOBase = IOBase; + pATI->CPIODecoding = IODecoding; + pATI->PCIInfo = pVideo; + + if (!ATIMach64Detect(pATI, ChipType, Chip)) + { + xfree(pATI); + return NULL; + } + + /* + * Determine VGA capability. VGA can always be enabled on integrated + * controllers. For the GX/CX, it's a board strap. + */ + if (pATI->Chip >= ATI_CHIP_264CT) + { + pATI->VGAAdapter = ATI_ADAPTER_MACH64; + } + else + { + IOValue = inr(CONFIG_STATUS64_0); + pATI->BusType = GetBits(IOValue, CFG_BUS_TYPE); + IOValue &= (CFG_VGA_EN | CFG_CHIP_EN); + if (pATI->Chip == ATI_CHIP_88800CX) + IOValue |= CFG_VGA_EN; + if (IOValue == (CFG_VGA_EN | CFG_CHIP_EN)) + { + pATI->VGAAdapter = ATI_ADAPTER_MACH64; + pATI->CPIO_VGAWonder = 0x01CEU; + pATI->VGAOffset = 0x80U; + } + } + + return pATI; +} + +/* + * ATIAssignVGA -- + * + * This function is called to associate a VGA interface with an accelerator. + * This is done by temporarily configuring the accelerator to route VGA RAMDAC + * I/O through the accelerator's RAMDAC. A value is then written through the + * VGA DAC ports and a check is made to see if the same value shows up on the + * accelerator side. + */ +static void +ATIAssignVGA +( + pciVideoPtr pVideo, + ATIPtr *ppVGA, + ATIPtr pATI, + ATIPtr p8514, + CARD8 *ProbeFlags +) +{ + ATIPtr pVGA = *ppVGA; + CARD8 OldDACMask; + + /* Assume unassignable VGA */ + pATI->VGAAdapter = ATI_ADAPTER_NONE; + + /* If no assignable VGA, return now */ + if ((pATI != pVGA) && (!pVGA || (pVGA->Adapter > ATI_ADAPTER_VGA))) + return; + + switch (pATI->Adapter) + { + case ATI_ADAPTER_8514A: + { + /* + * Assumption: Bit DISABPASSTHRU in ADVFUNC_CNTL is already + * off. + */ + OldDACMask = inb(VGA_DAC_MASK); + + if (inb(IBM_DAC_MASK) == OldDACMask) + { + outb(VGA_DAC_MASK, 0xA5U); + if (inb(IBM_DAC_MASK) == 0xA5U) + pATI->VGAAdapter = ATI_ADAPTER_VGA; + outb(VGA_DAC_MASK, OldDACMask); + } + } + break; + + case ATI_ADAPTER_MACH8: + { + CARD16 ClockSel = inw(CLOCK_SEL); + + if (ClockSel & DISABPASSTHRU) + outw(CLOCK_SEL, ClockSel & ~DISABPASSTHRU); + + ProbeWaitIdleEmpty(); + + OldDACMask = inb(VGA_DAC_MASK); + + if (inb(IBM_DAC_MASK) == OldDACMask) + { + outb(VGA_DAC_MASK, 0xA5U); + if (inb(IBM_DAC_MASK) == 0xA5U) + pATI->VGAAdapter = ATI_ADAPTER_VGA; + outb(VGA_DAC_MASK, OldDACMask); + } + + if (ClockSel & DISABPASSTHRU) + outw(CLOCK_SEL, ClockSel); + } + break; + + case ATI_ADAPTER_MACH32: + { + CARD16 ClockSel = inw(CLOCK_SEL), + MiscOptions = inw(MISC_OPTIONS); + + if (ClockSel & DISABPASSTHRU) + outw(CLOCK_SEL, ClockSel & ~DISABPASSTHRU); + if (MiscOptions & (DISABLE_VGA | DISABLE_DAC)) + outw(MISC_OPTIONS, + MiscOptions & ~(DISABLE_VGA | DISABLE_DAC)); + + ProbeWaitIdleEmpty(); + + OldDACMask = inb(VGA_DAC_MASK); + + if (inb(IBM_DAC_MASK) == OldDACMask) + { + outb(VGA_DAC_MASK, 0xA5U); + if (inb(IBM_DAC_MASK) == 0xA5U) + pATI->VGAAdapter = ATI_ADAPTER_MACH32; + outb(VGA_DAC_MASK, OldDACMask); + } + + if (ClockSel & DISABPASSTHRU) + outw(CLOCK_SEL, ClockSel); + if (MiscOptions & (DISABLE_VGA | DISABLE_DAC)) + outw(MISC_OPTIONS, MiscOptions); + } + break; + + case ATI_ADAPTER_MACH64: + { + CARD32 DACCntl = inr(DAC_CNTL); + + if (!(DACCntl & DAC_VGA_ADR_EN)) + outr(DAC_CNTL, DACCntl | DAC_VGA_ADR_EN); + + OldDACMask = inb(VGA_DAC_MASK); + + if (in8(M64_DAC_MASK) == OldDACMask) + { + outb(VGA_DAC_MASK, 0xA5U); + if (in8(M64_DAC_MASK) == 0xA5U) + pATI->VGAAdapter = ATI_ADAPTER_MACH64; + outb(VGA_DAC_MASK, OldDACMask); + } + + if (!(DACCntl & DAC_VGA_ADR_EN)) + outr(DAC_CNTL, DACCntl); + } + break; + + default: + break; + } + + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + { + pATI->CPIO_VGAWonder = 0; + return; + } + + if (pATI->CPIO_VGAWonder) + { + ATIVGAWonderProbe(pVideo, pATI, p8514, ProbeFlags); + if (!pATI->CPIO_VGAWonder) + { + /* + * Some adapters are reputed to append ATI extended VGA registers + * to the VGA Graphics controller registers. In particular, 0x01CE + * cannot, in general, be used in a PCI environment due to routing + * of I/O through the bus tree. + */ + pATI->CPIO_VGAWonder = GRAX; + ATIVGAWonderProbe(pVideo, pATI, p8514, ProbeFlags); + } + } + + if (pATI == pVGA) + { + pATI->SharedVGA = TRUE; + return; + } + + /* Assign the VGA to this adapter */ + xfree(pVGA); + *ppVGA = pATI; + + xf86MsgVerb(X_INFO, 3, ATI_NAME ": VGA assigned to this adapter.\n"); +} + +#ifndef AVOID_NON_PCI + +/* + * ATIClaimVGA -- + * + * Attempt to assign a non-shareable VGA to an accelerator. If successful, + * update ProbeFlags array. + */ +static void +ATIClaimVGA +( + pciVideoPtr pVideo, + ATIPtr *ppVGA, + ATIPtr pATI, + ATIPtr p8514, + CARD8 *ProbeFlags, + int Detected +) +{ + ATIAssignVGA(pVideo, ppVGA, pATI, p8514, ProbeFlags); + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + return; + + ATIClaimSparseIOBases(ProbeFlags, MonochromeIOBase, 48, Detected); + if (!pATI->CPIO_VGAWonder) + return; + + ATIClaimSparseIOBases(ProbeFlags, pATI->CPIO_VGAWonder, 2, Detected); +} + +#endif /* AVOID_NON_PCI */ + +/* + * ATIFindVGA -- + * + * This function determines if a VGA associated with an ATI PCI adapter is + * shareable. + */ +static void +ATIFindVGA +( + pciVideoPtr pVideo, + ATIPtr *ppVGA, + ATIPtr *ppATI, + ATIPtr p8514, + CARD8 *ProbeFlags +) +{ + ATIPtr pATI = *ppATI; + + if (!*ppVGA) + { + /* + * An ATI PCI adapter has been detected at this point, and its VGA, if + * any, is shareable. Ensure the VGA isn't in sleep mode. + */ + outb(GENENA, 0x16U); + outb(GENVS, 0x01U); + outb(GENENA, 0x0EU); + + pATI = ATIVGAProbe(pATI); + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + return; + + ppVGA = ppATI; + } + + ATIAssignVGA(pVideo, ppVGA, pATI, p8514, ProbeFlags); +} + +#endif /* AVOID_CPIO */ + +/* + * ATIProbe -- + * + * This function is called once, at the start of the first server generation to + * do a minimal probe for supported hardware. + */ +Bool +ATIProbe +( + DriverPtr pDriver, + int flags +) +{ + ATIPtr pATI, *ATIPtrs = NULL; + GDevPtr *GDevs, pGDev; + pciVideoPtr pVideo, *xf86PciVideoInfo = xf86GetPciVideoInfo(); + pciConfigPtr pPCI; + ATIGDev *ATIGDevs = NULL, *pATIGDev; + ScrnInfoPtr pScreenInfo; + CARD32 PciReg; + Bool ProbeSuccess = FALSE; + Bool DoRage128 = FALSE, DoRadeon = FALSE; + int i, j, k; + int nGDev, nATIGDev = -1, nATIPtr = 0; + int Chipset; + ATIChipType Chip; + +#ifndef AVOID_CPIO + + ATIPtr pVGA = NULL, p8514 = NULL; + ATIPtr pMach64[3] = {NULL, NULL, NULL}; + pciConfigPtr *xf86PciInfo = xf86GetPciConfigInfo(); + PortPtr PCIPorts = NULL; + int nPCIPort = 0; + CARD8 fChipsets[ATI_CHIPSET_MAX]; + static const IOADDRESS Mach64SparseIOBases[] = {0x02ECU, 0x01CCU, 0x01C8U}; + CARD8 ProbeFlags[LongPort(SPARSE_IO_BASE) + 1]; + + unsigned long BIOSBase; + static const CARD8 ATISignature[] = " 761295520"; +# define SignatureSize 10 +# define PrefixSize 0x50U +# define BIOSSignature 0x30U + CARD8 BIOS[PrefixSize]; +# define BIOSWord(_n) (BIOS[_n] | (BIOS[(_n) + 1] << 8)) + +#endif /* AVOID_CPIO */ + +# define AddAdapter(_p) \ + do \ + { \ + nATIPtr++; \ + ATIPtrs = (ATIPtr *)xnfrealloc(ATIPtrs, SizeOf(ATIPtr) * nATIPtr); \ + ATIPtrs[nATIPtr - 1] = (_p); \ + (_p)->iEntity = -2; \ + } while (0) + +#ifndef AVOID_CPIO + + (void)memset(fChipsets, FALSE, SizeOf(fChipsets)); + +#endif /* AVOID_CPIO */ + + if (!(flags & PROBE_DETECT)) + { + /* + * Get a list of XF86Config device sections whose "Driver" is either + * not specified, or specified as this driver. From this list, + * eliminate those device sections that specify a "Chipset" or a + * "ChipID" not recognised by the driver. Those device sections that + * specify a "ChipRev" without a "ChipID" are also weeded out. + */ + nATIGDev = 0; + if ((nGDev = xf86MatchDevice(ATI_NAME, &GDevs)) > 0) + { + ATIGDevs = (ATIGDevPtr)xnfcalloc(nGDev, SizeOf(ATIGDev)); + + for (i = 0, pATIGDev = ATIGDevs; i < nGDev; i++) + { + pGDev = GDevs[i]; + Chipset = ATIIdentProbe(pGDev->chipset); + if (Chipset == -1) + continue; + + if ((pGDev->chipID > (int)((CARD16)(-1))) || + (pGDev->chipRev > (int)((CARD8)(-1)))) + continue; + + if (pGDev->chipID >= 0) + { + if (ATIChipID(pGDev->chipID, 0) == ATI_CHIP_Mach64) + continue; + } + else + { + if (pGDev->chipRev >= 0) + continue; + } + + pATIGDev->pGDev = pGDev; + pATIGDev->Chipset = Chipset; + nATIGDev++; + pATIGDev++; + + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": Candidate \"Device\" section \"%s\".\n", + pGDev->identifier); + +#ifndef AVOID_CPIO + + fChipsets[Chipset] = TRUE; + +#endif /* AVOID_CPIO */ + + } + + xfree(GDevs); + + if (!nATIGDev) + { + xfree(ATIGDevs); + ATIGDevs = NULL; + } + } + + if (xf86MatchDevice(R128_NAME, NULL) > 0) + DoRage128 = TRUE; + if (xf86MatchDevice(RADEON_NAME, NULL) > 0) + DoRadeon = TRUE; + } + +#ifndef AVOID_CPIO + + /* + * Collect hardware information. This must be done with care to avoid + * lockups due to overlapping I/O port assignments. + * + * First, scan PCI configuration space for registered I/O ports (which will + * be block I/O bases). Each such port is used to generate a list of + * sparse I/O bases it precludes. This list is then used to decide whether + * or not certain sparse I/O probes are done. Unfortunately, this assumes + * that any registered I/O base actually reserves upto the full 256 ports + * allowed by the PCI specification. This assumption holds true for PCI + * Mach64, but probably doesn't for other device types. For some things, + * such as video devices, the number of ports a base represents is + * determined by the server's PCI probe, but, for other devices, this + * cannot be done by a user-level process without jeopardizing system + * integrity. This information should ideally be retrieved from the OS's + * own PCI probe (if any), but there's currently no portable way of doing + * so. The following allows sparse I/O probes to be forced in certain + * circumstances when an appropriate chipset specification is used in any + * XF86Config Device section. + * + * Note that this is not bullet-proof. Lockups can still occur, but they + * will usually be due to devices that are misconfigured to respond to the + * same I/O ports as 8514/A's or ATI sparse I/O devices without registering + * them in PCI configuration space. + */ + if (nATIGDev) + { + if (xf86PciVideoInfo) + { + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor == PCI_VENDOR_ATI) || + !(pPCI = pVideo->thisCard)) + continue; + + ATIScanPCIBases(&PCIPorts, &nPCIPort, + &pPCI->pci_base0, pVideo->size, + (pciReadLong(pPCI->tag, PCI_CMD_STAT_REG) & + PCI_CMD_IO_ENABLE) ? 0 : Allowed); + } + } + + /* Check non-video PCI devices for I/O bases */ + if (xf86PciInfo) + { + for (i = 0; (pPCI = xf86PciInfo[i++]); ) + { + if ((pPCI->pci_vendor == PCI_VENDOR_ATI) || + (pPCI->pci_base_class == PCI_CLASS_BRIDGE) || + (pPCI->pci_header_type & + ~GetByte(PCI_HEADER_MULTIFUNCTION, 2))) + continue; + + ATIScanPCIBases(&PCIPorts, &nPCIPort, + &pPCI->pci_base0, pPCI->basesize, + (pciReadLong(pPCI->tag, PCI_CMD_STAT_REG) & + PCI_CMD_IO_ENABLE) ? 0 : Allowed); + } + } + + /* Generate ProbeFlags array from list of registered PCI I/O bases */ + (void)memset(ProbeFlags, Allowed | DoProbe, SizeOf(ProbeFlags)); + for (i = 0; i < nPCIPort; i++) + { + CARD32 Base = PCIPorts[i].Base; + CARD16 Count = (1 << PCIPorts[i].Size) - 1; + CARD8 ProbeFlag = PCIPorts[i].Flag; + + /* + * The following reduction of Count is based on the assumption that + * PCI-registered I/O port ranges do not overlap. + */ + for (j = 0; j < nPCIPort; j++) + { + CARD32 Base2 = PCIPorts[j].Base; + + if (Base < Base2) + while ((Base + Count) >= Base2) + Count >>= 1; + } + + Base = LongPort(Base); + Count = LongPort((Count | IO_BYTE_SELECT) + 1); + while (Count--) + ProbeFlags[Base++] &= ProbeFlag; + } + + xfree(PCIPorts); + +#ifndef AVOID_NON_PCI + + /* + * A note on probe strategy. I/O and memory response by certain PCI + * devices has been disabled by the common layer at this point, + * including any devices this driver might be interested in. The + * following does sparse I/O probes, followed by block I/O probes. + * Block I/O probes are dictated by what is found to be of interest in + * PCI configuration space. All this will detect ATI adapters that do + * not implement this disablement, pre-PCI or not. + * + * PCI configuration space is then scanned again for ATI devices that + * failed to be detected the first time around. Each such device is + * probed for again, this time with I/O temporarily enabled through + * PCI. + */ + if (ATICheckSparseIOBases(NULL, ProbeFlags, ATTRX, 16, TRUE) == + DoProbe) + { + pATI = ATIVGAProbe(NULL); + if (pATI->Adapter == ATI_ADAPTER_NONE) + { + xfree(pATI); + + xf86MsgVerb(X_INFO, 4, + ATI_NAME ": Unshared VGA not detected.\n"); + } + else + { + /* + * Claim all MDA/HGA/CGA/EGA/VGA I/O ports. This might need to + * be more selective. + */ + ATIClaimSparseIOBases(ProbeFlags, MonochromeIOBase, 48, + DetectedVGA); + + pVGA = pATI; + strcpy(Identifier, "Unshared VGA"); + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s detected.\n", Identifier); + } + } + else + { + xf86MsgVerb(X_INFO, 2, ATI_NAME ": Unshared VGA not probed.\n"); + } + + if (ATICheckSparseIOBases(NULL, ProbeFlags, 0x02E8U, 8, + fChipsets[ATI_CHIPSET_IBM8514] || + fChipsets[ATI_CHIPSET_MACH8] || + fChipsets[ATI_CHIPSET_MACH32]) == DoProbe) + { + if ((pATI = ATI8514Probe(NULL))) + { + strcpy(Identifier, "Unshared 8514/A"); + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s detected.\n", Identifier); + + AddAdapter(p8514 = pATI); + + if ((pATI->VGAAdapter != ATI_ADAPTER_NONE) || + (pATI->Coprocessor != ATI_CHIP_NONE)) + ATIClaimVGA(NULL, &pVGA, pATI, p8514, ProbeFlags, + Detected8514A); + + ATIClaimSparseIOBases(ProbeFlags, 0x02E8U, 8, Detected8514A); + } + else + { + xf86MsgVerb(X_INFO, 4, + ATI_NAME ": Unshared 8514/A not detected.\n"); + } + } + else + { + xf86MsgVerb(X_INFO, 2, + ATI_NAME ": Unshared 8514/A not probed.\n"); + } + + for (i = 0; i < NumberOf(Mach64SparseIOBases); i++) + { + if (ATICheckSparseIOBases(NULL, ProbeFlags, Mach64SparseIOBases[i], + 4, fChipsets[ATI_CHIPSET_MACH64]) != DoProbe) + { + xf86MsgVerb(X_INFO, 2, + ATI_NAME ": Unshared Mach64 at PIO base 0x%04lX not" + " probed.\n", + Mach64SparseIOBases[i]); + continue; + } + + pATI = ATIMach64Probe(NULL, Mach64SparseIOBases[i], SPARSE_IO, 0); + if (!pATI) + { + xf86MsgVerb(X_INFO, 4, + ATI_NAME ": Unshared Mach64 at PIO base 0x%04lX not" + " detected.\n", Mach64SparseIOBases[i]); + continue; + } + + sprintf(Identifier, "Unshared Mach64 at sparse PIO base 0x%04lX", + Mach64SparseIOBases[i]); + xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); + + AddAdapter(pMach64[i] = pATI); + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + ATIClaimVGA(NULL, &pVGA, pATI, p8514, ProbeFlags, + DetectedMach64); + + ATIClaimSparseIOBases(ProbeFlags, Mach64SparseIOBases[i], 4, + DetectedMach64); + } + +#endif /* AVOID_NON_PCI */ + + } + +#endif /* AVOID_CPIO */ + + if (xf86PciVideoInfo) + { + if (nATIGDev) + { + +#ifndef AVOID_NON_PCI + +#ifdef AVOID_CPIO + + /* PCI sparse I/O adapters can still be used through MMIO */ + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor != PCI_VENDOR_ATI) || + (pVideo->chipType == PCI_CHIP_MACH32) || + pVideo->size[1] || + !(pPCI = pVideo->thisCard)) + continue; + + PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG); + + /* Possibly fix block I/O indicator */ + if (PciReg & 0x00000004U) + pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG, + PciReg & ~0x00000004U); + + Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); + + /* + * The CPIO base used by the adapter is of little concern here. + */ + pATI = ATIMach64Probe(pVideo, 0, SPARSE_IO, Chip); + if (!pATI) + continue; + + sprintf(Identifier, + "Unshared PCI sparse I/O Mach64 in slot %d:%d:%d", + pVideo->bus, pVideo->device, pVideo->func); + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s detected through Block 0 at 0x%08lX.\n", + Identifier, pATI->Block0Base); + AddAdapter(pATI); + pATI->PCIInfo = pVideo; + } + +#endif /* AVOID_CPIO */ + + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor != PCI_VENDOR_ATI) || + (pVideo->chipType == PCI_CHIP_MACH32) || + !pVideo->size[1]) + continue; + + /* For now, ignore Rage128's and Radeon's */ + Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); + if ((Chip > ATI_CHIP_Mach64) || + !(pPCI = pVideo->thisCard)) + continue; + + /* + * Possibly fix block I/O indicator in PCI configuration space. + */ + PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG); + if (!(PciReg & 0x00000004U)) + pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG, + PciReg | 0x00000004U); + + pATI = + ATIMach64Probe(pVideo, pVideo->ioBase[1], BLOCK_IO, Chip); + if (!pATI) + continue; + + sprintf(Identifier, "Unshared PCI/AGP Mach64 in slot %d:%d:%d", + pVideo->bus, pVideo->device, pVideo->func); + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s detected.\n", Identifier); + AddAdapter(pATI); + +#ifndef AVOID_CPIO + + /* This is probably not necessary */ + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + ATIClaimVGA(pVideo, &pVGA, pATI, p8514, + ProbeFlags, DetectedMach64); + +#endif /* AVOID_CPIO */ + + } + +#endif /* AVOID_NON_PCI */ + +#ifndef AVOID_CPIO + + /* + * This is the second pass through PCI configuration space. Much + * of this is verbiage to deal with potential situations that are + * very unlikely to occur in practice. + * + * First, look for non-ATI shareable VGA's. For now, these must + * the primary device. + */ + if (ATICheckSparseIOBases(NULL, ProbeFlags, ATTRX, 16, TRUE) == + DoProbe) + { + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor == PCI_VENDOR_ATI) || + !xf86IsPrimaryPci(pVideo)) + continue; + + if (!xf86CheckPciSlot(pVideo->bus, + pVideo->device, + pVideo->func)) + continue; + + xf86SetPciVideo(pVideo, MEM_IO); + + pATI = ATIVGAProbe(NULL); + if (pATI->Adapter == ATI_ADAPTER_NONE) + { + xfree(pATI); + xf86Msg(X_WARNING, + ATI_NAME ": PCI/AGP VGA compatible in slot" + " %d:%d:%d could not be detected!\n", + pVideo->bus, pVideo->device, pVideo->func); + } + else + { + sprintf(Identifier, + "Shared non-ATI VGA in PCI/AGP slot %d:%d:%d", + pVideo->bus, pVideo->device, pVideo->func); + xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", + Identifier); + AddAdapter(pATI); + pATI->SharedVGA = TRUE; + pATI->BusType = ATI_BUS_PCI; + pATI->PCIInfo = pVideo; + } + + xf86SetPciVideo(NULL, NONE); + } + } + + /* Next, look for PCI Mach32's */ + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor != PCI_VENDOR_ATI) || + (pVideo->chipType != PCI_CHIP_MACH32)) + continue; + + switch (ATICheckSparseIOBases(pVideo, ProbeFlags, + 0x02E8U, 8, TRUE)) + { + case 0: + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach32 in slot %d:%d:%d will not" + " be enabled\n because it conflicts with a" + " non-video PCI/AGP device.\n", + pVideo->bus, pVideo->device, pVideo->func); + break; + +#ifndef AVOID_NON_PCI + + case Detected8514A: + if ((p8514->BusType >= ATI_BUS_PCI) && !p8514->PCIInfo) + p8514->PCIInfo = pVideo; + else + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach32 in slot %d:%d:%d will" + " not be enabled\n because it conflicts with" + " another %s %s.\n", + pVideo->bus, pVideo->device, pVideo->func, + ATIBusNames[p8514->BusType], + ATIAdapterNames[p8514->Adapter]); + break; + + case DetectedMach64: + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach32 in slot %d:%d:%d will not" + " be enabled\n because it conflicts with a Mach64" + " at I/O base 0x02EC.\n", + pVideo->bus, pVideo->device, pVideo->func); + break; + +#endif /* AVOID_NON_PCI */ + + default: /* Must be DoProbe */ + if (!xf86CheckPciSlot(pVideo->bus, + pVideo->device, + pVideo->func)) + continue; + + xf86SetPciVideo(pVideo, MEM_IO); + + if (!(pATI = ATI8514Probe(pVideo))) + { + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach32 in slot %d:%d:%d could" + " not be detected!\n", + pVideo->bus, pVideo->device, pVideo->func); + } + else + { + sprintf(Identifier, + "Shared 8514/A in PCI slot %d:%d:%d", + pVideo->bus, pVideo->device, pVideo->func); + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s detected.\n", Identifier); + if (pATI->Adapter != ATI_ADAPTER_MACH32) + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach32 in slot %d:%d:%d" + " could only be detected as an %s!\n", + pVideo->bus, pVideo->device, pVideo->func, + ATIAdapterNames[pATI->Adapter]); + + AddAdapter(pATI); + pATI->SharedAccelerator = TRUE; + + if ((pATI->VGAAdapter != ATI_ADAPTER_NONE) || + (pATI->Coprocessor != ATI_CHIP_NONE)) + ATIFindVGA(pVideo, &pVGA, &pATI, p8514, + ProbeFlags); + } + + xf86SetPciVideo(NULL, NONE); + break; + } + } + + /* Next, look for sparse I/O Mach64's */ + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor != PCI_VENDOR_ATI) || + (pVideo->chipType == PCI_CHIP_MACH32) || + pVideo->size[1]) + continue; + + pPCI = pVideo->thisCard; + PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG); + j = PciReg & 0x03U; + if (j == 0x03U) + { + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach64 in slot %d:%d:%d cannot be" + " enabled\n because it has neither a block, nor a" + " sparse, I/O base.\n", + pVideo->bus, pVideo->device, pVideo->func); + } + else switch(ATICheckSparseIOBases(pVideo, ProbeFlags, + Mach64SparseIOBases[j], 4, TRUE)) + { + case 0: + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach64 in slot %d:%d:%d will not" + " be enabled\n because it conflicts with another" + " non-video PCI device.\n", + pVideo->bus, pVideo->device, pVideo->func); + break; + +#ifndef AVOID_NON_PCI + + case Detected8514A: + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach64 in slot %d:%d:%d will not" + " be enabled\n because it conflicts with an %s.\n", + pVideo->bus, pVideo->device, pVideo->func, + ATIAdapterNames[p8514->Adapter]); + break; + + case DetectedMach64: + pATI = pMach64[j]; + if ((pATI->BusType >= ATI_BUS_PCI) && !pATI->PCIInfo) + pATI->PCIInfo = pVideo; + else + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach64 in slot %d:%d:%d will" + " not be enabled\n because it conflicts with" + " another %s Mach64 at sparse I/O base" + " 0x%04lX.\n", + pVideo->bus, pVideo->device, pVideo->func, + ATIBusNames[pATI->BusType], + Mach64SparseIOBases[j]); + break; + +#endif /* AVOID_NON_PCI */ + + default: /* Must be DoProbe */ + if (!xf86CheckPciSlot(pVideo->bus, + pVideo->device, + pVideo->func)) + continue; + + /* Possibly fix block I/O indicator */ + if (PciReg & 0x00000004U) + pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG, + PciReg & ~0x00000004U); + + xf86SetPciVideo(pVideo, MEM_IO); + + Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); + pATI = ATIMach64Probe(pVideo, Mach64SparseIOBases[j], + SPARSE_IO, Chip); + if (!pATI) + { + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach64 in slot %d:%d:%d could" + " not be detected!\n", + pVideo->bus, pVideo->device, pVideo->func); + } + else + { + sprintf(Identifier, + "Shared PCI Mach64 in slot %d:%d:%d", + pVideo->bus, pVideo->device, pVideo->func); + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s with sparse PIO base 0x%04lX" + " detected.\n", Identifier, + Mach64SparseIOBases[j]); + AddAdapter(pATI); + pATI->SharedAccelerator = TRUE; + pATI->PCIInfo = pVideo; + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + ATIFindVGA(pVideo, &pVGA, &pATI, p8514, + ProbeFlags); + } + + xf86SetPciVideo(NULL, NONE); + break; + } + } + +#else /* AVOID_CPIO */ + + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor != PCI_VENDOR_ATI) || + (pVideo->chipType == PCI_CHIP_MACH32) || + pVideo->size[1]) + continue; + + /* Check if this one has already been detected */ + for (j = 0; j < nATIPtr; j++) + { + pATI = ATIPtrs[j]; + if (pATI->PCIInfo == pVideo) + goto SkipThisSlot; + } + + if (!xf86CheckPciSlot(pVideo->bus, + pVideo->device, + pVideo->func)) + continue; + + xf86SetPciVideo(pVideo, MEM_IO); + + Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); + + /* The adapter's CPIO base is of little concern here */ + pATI = ATIMach64Probe(pVideo, 0, SPARSE_IO, Chip); + if (pATI) + { + sprintf(Identifier, "Shared PCI Mach64 in slot %d:%d:%d", + pVideo->bus, pVideo->device, pVideo->func); + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s with Block 0 base 0x%08lX detected.\n", + Identifier, pATI->Block0Base); + AddAdapter(pATI); + pATI->SharedAccelerator = TRUE; + pATI->PCIInfo = pVideo; + } + else + { + xf86Msg(X_WARNING, + ATI_NAME ": PCI Mach64 in slot %d:%d:%d could not be" + " detected!\n", + pVideo->bus, pVideo->device, pVideo->func); + } + + xf86SetPciVideo(NULL, NONE); + + SkipThisSlot:; + } + +#endif /* AVOID_CPIO */ + + } + + /* Lastly, look for block I/O devices */ + for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) + { + if ((pVideo->vendor != PCI_VENDOR_ATI) || + (pVideo->chipType == PCI_CHIP_MACH32) || + !pVideo->size[1]) + continue; + + /* Check for Rage128's, Radeon's and later adapters */ + Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); + if (Chip > ATI_CHIP_Mach64) + { + if (Chip <= ATI_CHIP_Rage128) + DoRage128 = TRUE; + else if (Chip <= ATI_CHIP_Radeon) + DoRadeon = TRUE; + + continue; + } + + if (!nATIGDev) + continue; + + /* Check if this one has already been detected */ + for (j = 0; j < nATIPtr; j++) + { + pATI = ATIPtrs[j]; + if (pATI->CPIOBase == pVideo->ioBase[1]) + goto SetPCIInfo; + } + + if (!xf86CheckPciSlot(pVideo->bus, pVideo->device, pVideo->func)) + continue; + + /* Probe for it */ + xf86SetPciVideo(pVideo, MEM_IO); + + pATI = ATIMach64Probe(pVideo, pVideo->ioBase[1], BLOCK_IO, Chip); + if (pATI) + { + sprintf(Identifier, "Shared PCI/AGP Mach64 in slot %d:%d:%d", + pVideo->bus, pVideo->device, pVideo->func); + xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", + Identifier); + AddAdapter(pATI); + pATI->SharedAccelerator = TRUE; + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + ATIFindVGA(pVideo, &pVGA, &pATI, p8514, ProbeFlags); + +#endif /* AVOID_CPIO */ + + } + + xf86SetPciVideo(NULL, NONE); + + if (!pATI) + { + xf86Msg(X_WARNING, + ATI_NAME ": PCI/AGP Mach64 in slot %d:%d:%d could not be" + " detected!\n", pVideo->bus, pVideo->device, pVideo->func); + continue; + } + + SetPCIInfo: + pATI->PCIInfo = pVideo; + } + } + +#ifndef AVOID_CPIO + + /* + * At this point, if there's a non-shareable VGA with its own framebuffer, + * find out if it's an ATI VGA Wonder. + */ + do + { + if (!nATIGDev || !pVGA || (pVGA->VGAAdapter > ATI_ADAPTER_VGA)) + break; + + /* If it has not been assigned to a coprocessor, keep track of it */ + if (pVGA->Coprocessor == ATI_CHIP_NONE) + AddAdapter(pVGA); + + /* + * A VGA should have installed its int 10 vector. Use that to find the + * VGA BIOS. If this fails, scan all legacy BIOS segments, in 512-byte + * increments. + */ + if (xf86ReadBIOS(0U, 0x42U, BIOS, 2) != 2) + goto NoVGAWonder; + + pATI = NULL; + BIOSBase = 0; + if (!(BIOS[0] & 0x1FU)) /* Otherwise there's no 512-byte alignment */ + BIOSBase = ((BIOS[1] << 8) | BIOS[0]) << 4; + + /* Look for its BIOS */ + for(; ; BIOSBase += 0x00000200U) + { + if (!BIOSBase) + goto SkipBiosSegment; + + if (BIOSBase >= 0x000F8000U) + goto NoVGAWonder; + + /* Skip over those that are already known */ + for (i = 0; i < nATIPtr; i++) + if (ATIPtrs[i]->BIOSBase == BIOSBase) + goto SkipBiosSegment; + + /* Get first 80 bytes of video BIOS */ + if (xf86ReadBIOS(BIOSBase, 0, BIOS, SizeOf(BIOS)) != + SizeOf(BIOS)) + goto NoVGAWonder; + + if ((BIOS[0x00U] != 0x55U) || (BIOS[0x01U] != 0xAAU)) + goto SkipBiosSegment; + + if ((BIOS[0x1EU] == 'I') && + (BIOS[0x1FU] == 'B') && + (BIOS[0x20U] == 'M')) + break; + + /* XXX Should PCI BIOS signature be checked for here ? */ + if ((BIOS[0x20U] == 'P') && + (BIOS[0x21U] == 'C') && + (BIOS[0x22U] == 'I')) + break; + + SkipBiosSegment: + if (pATI) + continue; + + pATI = pVGA; + BIOSBase = 0x000C0000U - 0x00000200U; + } + + pVGA->BIOSBase = BIOSBase; + + /* Look for the ATI signature string */ + if (memcmp(BIOS + BIOSSignature, ATISignature, SignatureSize)) + break; + + if (BIOS[0x40U] != '3') + break; + + switch (BIOS[0x41U]) + { + case '1': + /* This is a Mach8 or VGA Wonder adapter of some kind */ + if ((BIOS[0x43U] >= '1') && (BIOS[0x43U] <= '6')) + pVGA->Chip = BIOS[0x43U] - ('1' - ATI_CHIP_18800); + + switch (BIOS[0x43U]) + { + case '1': /* ATI_CHIP_18800 */ + pVGA->VGAOffset = 0xB0U; + pVGA->VGAAdapter = ATI_ADAPTER_V3; + break; + + case '2': /* ATI_CHIP_18800_1 */ + pVGA->VGAOffset = 0xB0U; + if (BIOS[0x42U] & 0x10U) + pVGA->VGAAdapter = ATI_ADAPTER_V5; + else + pVGA->VGAAdapter = ATI_ADAPTER_V4; + break; + + case '3': /* ATI_CHIP_28800_2 */ + case '4': /* ATI_CHIP_28800_4 */ + case '5': /* ATI_CHIP_28800_5 */ + case '6': /* ATI_CHIP_28800_6 */ + pVGA->VGAOffset = 0xA0U; + if (BIOS[0x44U] & 0x80U) + pVGA->VGAAdapter = ATI_ADAPTER_XL; + else + pVGA->VGAAdapter = ATI_ADAPTER_PLUS; + break; + + case 'a': /* A crippled Mach32 */ + case 'b': + case 'c': + pVGA->VGAOffset = 0x80U; + pVGA->VGAAdapter = ATI_ADAPTER_NONISA; + ATIMach32ChipID(pVGA); + ProbeWaitIdleEmpty(); + if (inw(SUBSYS_STAT) != (CARD16)(-1)) + pVGA->ChipHasSUBSYS_CNTL = TRUE; + break; +#if 0 + case ' ': /* A crippled Mach64 */ + pVGA->VGAOffset = 0x80U; + pVGA->VGAAdapter = ATI_ADAPTER_NONISA; + ATIMach64ChipID(pVGA, 0); + break; +#endif + default: + break; + } + + if (pVGA->VGAAdapter == ATI_ADAPTER_NONE) + break; + + /* Set VGA Wonder I/O port */ + pVGA->CPIO_VGAWonder = BIOSWord(0x10U) & SPARSE_IO_PORT; + if (!pVGA->CPIO_VGAWonder) + pVGA->CPIO_VGAWonder = 0x01CEU; + + ATIVGAWonderProbe(NULL, pVGA, p8514, ProbeFlags); + break; +#if 0 + case '2': + pVGA->VGAOffset = 0xB0U; /* Presumably */ + pVGA->VGAAdapter = ATI_ADAPTER_EGA_PLUS; + break; + + case '3': + pVGA->VGAOffset = 0xB0U; /* Presumably */ + pVGA->VGAAdapter = ATI_ADAPTER_BASIC; + break; + + case '?': /* A crippled Mach64 */ + pVGA->VGAAdapter = ATI_ADAPTER_NONISA; + ATIMach64ChipID(pVGA, 0); + break; +#endif + default: + break; + } + + if (pVGA->Adapter <= ATI_ADAPTER_VGA) + pVGA->Adapter = pVGA->VGAAdapter; + +NoVGAWonder:; + } while (0); + +#endif /* AVOID_CPIO */ + + /* + * Re-order list of detected devices so that the primary device is before + * any other PCI device. + */ + for (i = 0; i < nATIPtr; i++) + { + if (!ATIPtrs[i]->PCIInfo) + continue; + + for (j = i; j < nATIPtr; j++) + { + pATI = ATIPtrs[j]; + if (!xf86IsPrimaryPci(pATI->PCIInfo)) + continue; + + for (; j > i; j--) + ATIPtrs[j] = ATIPtrs[j - 1]; + ATIPtrs[j] = pATI; + break; + } + + break; + } + + if (flags & PROBE_DETECT) + { + /* + * No XF86Config information available, so use the default Chipset of + * "ati", and as many device sections as there are adapters. + */ + for (i = 0; i < nATIPtr; i++) + { + pATI = ATIPtrs[i]; + +#ifndef AVOID_CPIO + + if ((pATI->Adapter != ATI_ADAPTER_VGA) && + ((pATI->Adapter != ATI_ADAPTER_8514A) || + ((pATI->VGAAdapter != ATI_ADAPTER_VGA) && + (pATI->VGAAdapter != ATI_ADAPTER_NONE)))) + +#endif /* AVOID_CPIO */ + + { + ProbeSuccess = TRUE; + pGDev = xf86AddDeviceToConfigure(ATI_DRIVER_NAME, + pATI->PCIInfo, ATI_CHIPSET_ATI); + if (pGDev) + { + /* Fill in additional information */ + pGDev->vendor = ATI_NAME; + pGDev->chipset = (char *)ATIChipsetNames[ATI_CHIPSET_ATI]; + if (!pATI->PCIInfo) + pGDev->busID = NULL; + } + } + + xfree(pATI); + } + } + else + { + /* + * Assign detected devices to XF86Config Device sections. This is done + * by comparing certain Device section specifications against the + * corresponding adapter information. Begin with those specifications + * that are independent of the adapter's bus location. + */ + for (i = 0, pATIGDev = ATIGDevs; i < nATIGDev; i++, pATIGDev++) + { + pGDev = pATIGDev->pGDev; + + for (j = 0; j < nATIPtr; j++) + { + pATI = ATIPtrs[j]; + + /* + * First check the Chipset specification. The placement of + * "break" and "continue" statements here is carefully chosen + * to produce the intended behaviour for each Chipset value. + */ + switch (pATIGDev->Chipset) + { + case ATI_CHIPSET_ATI: + +#ifndef AVOID_CPIO + + if (pATI->Adapter == ATI_ADAPTER_VGA) + continue; + if (pATI->Adapter != ATI_ADAPTER_8514A) + break; + /* Fall through */ + + case ATI_CHIPSET_ATIVGA: + if (pATI->VGAAdapter == ATI_ADAPTER_VGA) + continue; + /* Fall through */ + + case ATI_CHIPSET_IBMVGA: + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + continue; + break; + + case ATI_CHIPSET_VGAWONDER: + if (!pATI->CPIO_VGAWonder) + continue; + break; + + case ATI_CHIPSET_IBM8514: + if (pATI->Adapter == ATI_ADAPTER_8514A) + break; + /* Fall through */ + + case ATI_CHIPSET_MACH8: + if (pATI->Adapter == ATI_ADAPTER_MACH8) + break; + /* Fall through */ + + case ATI_CHIPSET_MACH32: + if (pATI->Adapter == ATI_ADAPTER_MACH32) + break; + continue; + +#endif /* AVOID_CPIO */ + + case ATI_CHIPSET_MACH64: + if (pATI->Adapter == ATI_ADAPTER_MACH64) + break; + continue; + + default: + continue; + } + + /* + * The ChipID and ChipRev specifications are compared next. + * First, require these to be unspecified for anything other + * than Mach32 or Mach64 adapters. ChipRev is also required to + * be unspecified for Mach32's. ChipID is optional for + * Mach32's, and both specifications are optional for Mach64's. + * Lastly, allow both specifications to override their detected + * value in the case of Mach64 adapters whose ChipID is + * unrecognised. + */ + pVideo = pATI->PCIInfo; + if (pGDev->chipID >= 0) + { + if ((pATI->ChipType != pGDev->chipID) && + (!pVideo || (pGDev->chipID != pVideo->chipType))) + { + if ((pATI->Adapter != ATI_ADAPTER_MACH64) || + (pATI->Chip != ATI_CHIP_Mach64)) + continue; + + Chip = ATIChipID(pGDev->chipID, 0); + if ((Chip <= ATI_CHIP_264GTB) || + (Chip == ATI_CHIP_Mach64)) + continue; + } + if ((pGDev->chipRev >= 0) && + (pATI->ChipRev != pGDev->chipRev) && + (!pVideo || (pGDev->chipRev != pVideo->chipRev) || + (pGDev->chipID != pVideo->chipType))) + { + if (pATI->Chip < ATI_CHIP_264CT) + continue; + + if (pATI->Chip != ATI_CHIP_Mach64) + { + /* + * There are two foundry codes for UMC. Some + * adapters will advertise one in CONFIG_CHIP_ID + * and the other in PCI configuration space. For + * matching purposes, make both codes compare + * equal. + */ +# define UMC_IGNORE \ + (ATI_FOUNDRY_UMC ^ ATI_FOUNDRY_UMCA) +# define UMC_NOCARE \ + GetBits(SetBits(UMC_IGNORE, CFG_CHIP_FOUNDRY), \ + CFG_CHIP_REV) + + if ((pATI->ChipRev ^ pGDev->chipRev) & ~UMC_NOCARE) + continue; + + if ((pATI->ChipFoundry != ATI_FOUNDRY_UMC) && + (pATI->ChipFoundry != ATI_FOUNDRY_UMCA)) + continue; + + k = GetBits(pGDev->chipRev, + GetBits(CFG_CHIP_FOUNDRY, CFG_CHIP_REV)); + if ((k != ATI_FOUNDRY_UMC) && + (k != ATI_FOUNDRY_UMCA)) + continue; + } + } + } + + /* + * IOBase is next. This is the first specification that is + * potentially dependent on bus location. It is only allowed + * for Mach64 adapters, and is optional. + */ + if (pGDev->IOBase && (pATI->CPIOBase != pGDev->IOBase)) + continue; + + /* + * Compare BusID's. This specification is only allowed for PCI + * Mach32's or Mach64's and is optional. + */ + if (pGDev->busID && pGDev->busID[0]) + { + pVideo = pATI->PCIInfo; + +#ifndef AVOID_CPIO + + if (!pVideo) + continue; + +#endif /* AVOID_CPIO */ + + if (!xf86ComparePciBusString(pGDev->busID, + pVideo->bus, pVideo->device, pVideo->func)) + continue; + } + + /* + * Ensure no two adapters are assigned to the same XF86Config + * Device section. + */ + if (pATIGDev->iATIPtr) + { + if (pATIGDev->iATIPtr < 0) + break; + + xf86Msg(X_ERROR, + ATI_NAME ": XF86Config Device section \"%s\" may not" + " be assigned to more than one adapter.\n", + pGDev->identifier); + pATIGDev->iATIPtr = -1; + break; + } + + /* Assign adapter */ + pATIGDev->iATIPtr = j + 1; + + /* + * For compatibility with previous releases, assign the first + * applicable adapter if there is only one Device section. + */ + if (nATIGDev == 1) + break; + } + } + + /* + * Ensure no two XF86Config Device sections are assigned to the same + * adapter. Then, generate screens for any that are left. + */ + for (i = 0, pATIGDev = ATIGDevs; i < nATIGDev; i++, pATIGDev++) + { + pGDev = pATIGDev->pGDev; + + j = pATIGDev->iATIPtr; + if (j <= 0) + continue; + + for (k = i; ++k < nATIGDev; ) + { + if (j == ATIGDevs[k].iATIPtr) + { + xf86Msg(X_ERROR, + ATI_NAME ": XF86Config Device sections \"%s\" and" + " \"%s\" may not be assigned to the same adapter.\n", + pGDev->identifier, ATIGDevs[k].pGDev->identifier); + pATIGDev->iATIPtr = ATIGDevs[k].iATIPtr = -1; + } + } + + j = ATIGDevs[i].iATIPtr; + if (j <= 0) + continue; + + pATI = ATIPtrs[j - 1]; + + xf86MsgVerb(X_INFO, 3, + ATI_NAME ": %s assigned to %sactive \"Device\" section" + " \"%s\".\n", + Identifier, pGDev->active ? "" : "in", pGDev->identifier); + + /* + * Attach adapter to XF86Config Device section and register its + * resources. + */ + if (ATIClaimBusSlot(pDriver, pATIGDev->Chipset, + pGDev, pGDev->active, pATI) < 0) + { + xf86Msg(X_ERROR, + ATI_NAME ": Could not claim bus slot for %s.\n", + Identifier); + continue; + } + + if (!pGDev->active) + continue; + + /* Allocate screen */ + pScreenInfo = xf86AllocateScreen(pDriver, 0); + +#ifdef XFree86LOADER + + if (!xf86LoadSubModule(pScreenInfo, "atimisc")) + { + xf86Msg(X_ERROR, + ATI_NAME ": Failed to load \"atimisc\" module.\n"); + xf86DeleteScreen(pScreenInfo->scrnIndex, 0); + continue; + } + + xf86LoaderReqSymLists(ATISymbols, NULL); + +#endif + + /* Attach device to screen */ + xf86AddEntityToScreen(pScreenInfo, pATI->iEntity); + + ATIPtrs[j - 1] = NULL; + + /* Fill in probe data */ + pScreenInfo->driverVersion = ATI_VERSION_CURRENT; + pScreenInfo->driverName = ATI_DRIVER_NAME; + pScreenInfo->name = ATI_NAME; + pScreenInfo->Probe = ATIProbe; + pScreenInfo->PreInit = ATIPreInit; + pScreenInfo->ScreenInit = ATIScreenInit; + pScreenInfo->SwitchMode = ATISwitchMode; + pScreenInfo->AdjustFrame = ATIAdjustFrame; + pScreenInfo->EnterVT = ATIEnterVT; + pScreenInfo->LeaveVT = ATILeaveVT; + pScreenInfo->FreeScreen = ATIFreeScreen; + pScreenInfo->ValidMode = ATIValidMode; + + pScreenInfo->driverPrivate = pATI; + + pATI->Chipset = pATIGDev->Chipset; + + ProbeSuccess = TRUE; + } + + /* Deal with unassigned adapters */ + for (i = 0; i < nATIPtr; i++) + { + if (!(pATI = ATIPtrs[i])) + continue; + +#ifndef AVOID_CPIO + + if (pATI->Adapter > ATI_ADAPTER_VGA) + +#endif /* AVOID_CPIO */ + + { + if (pATI->iEntity < 0) + (void)ATIClaimBusSlot(pDriver, 0, NULL, FALSE, pATI); + } + + xfree(pATI); + } + + xfree(ATIGDevs); + } + + xfree(ATIPtrs); + + /* Call Rage 128 driver probe */ + if (DoRage128 && R128Probe(pDriver, flags)) + ProbeSuccess = TRUE; + + /* Call Radeon driver probe */ + if (DoRadeon && RADEONProbe(pDriver, flags)) + ProbeSuccess = TRUE; + + return ProbeSuccess; +} diff --git a/src/atiprobe.h b/src/atiprobe.h new file mode 100644 index 0000000..20f4f66 --- /dev/null +++ b/src/atiprobe.h @@ -0,0 +1,33 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiprobe.h,v 1.8 2003/01/01 19:16:33 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIPROBE_H___ +#define ___ATIPROBE_H___ 1 + +#include "atiproto.h" + +#include "xf86str.h" + +extern Bool ATIProbe FunctionPrototype((DriverPtr, int)); + +#endif /* ___ATIPROBE_H___ */ diff --git a/src/atiregs.h b/src/atiregs.h new file mode 100644 index 0000000..fd80e74 --- /dev/null +++ b/src/atiregs.h @@ -0,0 +1,2728 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiregs.h,v 1.24 2003/04/23 21:51:30 tsi Exp $ */ +/* + * Copyright 1994 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + * + * Acknowledgements: + * Jake Richter, Panacea Inc., Londonderry, New Hampshire, U.S.A. + * Kevin E. Martin, martin@cs.unc.edu + * Tiago Gons, tiago@comosjn.hobby.nl + * Rickard E. Faith, faith@cs.unc.edu + * Scott Laird, lair@kimbark.uchicago.edu + * + * The intent here is to list all I/O ports for VGA (and its predecessors), + * ATI VGA Wonder, 8514/A, ATI Mach8, ATI Mach32 and ATI Mach64 video adapters, + * not just the ones in use by the ATI driver. + */ + +#ifndef ___ATIREGS_H___ +#define ___ATIREGS_H___ 1 + +#include "atiutil.h" + +/* I/O decoding definitions */ +#define SPARSE_IO_BASE 0x03fcu +#define SPARSE_IO_SELECT 0xfc00u + +#define BLOCK_IO_BASE 0xff00u +#define BLOCK_IO_SELECT 0x00fcu + +#define MM_IO_SELECT 0x03fcu +#define BLOCK_SELECT 0x0400u +#define DWORD_SELECT (BLOCK_SELECT | MM_IO_SELECT) + +#define IO_BYTE_SELECT 0x0003u + +#define SPARSE_IO_PORT (SPARSE_IO_BASE | IO_BYTE_SELECT) +#define BLOCK_IO_PORT (BLOCK_IO_BASE | IO_BYTE_SELECT) + +#define IOPortTag(_SparseIOSelect, _BlockIOSelect) \ + (SetBits(_SparseIOSelect, SPARSE_IO_SELECT) | \ + SetBits(_BlockIOSelect, DWORD_SELECT)) +#define SparseIOTag(_IOSelect) IOPortTag(_IOSelect, 0) +#define BlockIOTag(_IOSelect) IOPortTag(0, _IOSelect) + +/* MDA/[M]CGA/EGA/VGA I/O ports */ +#define GENVS 0x0102u /* Write (and Read on uC only) */ + +#define R_GENLPS 0x03b9u /* Read */ + +#define GENHP 0x03bfu + +#define ATTRX 0x03c0u +#define ATTRD 0x03c1u +#define GENS0 0x03c2u /* Read */ +#define GENMO 0x03c2u /* Write */ +#define GENENB 0x03c3u /* Read */ +#define SEQX 0x03c4u +#define SEQD 0x03c5u +#define VGA_DAC_MASK 0x03c6u +#define VGA_DAC_READ 0x03c7u +#define VGA_DAC_WRITE 0x03c8u +#define VGA_DAC_DATA 0x03c9u +#define R_GENFC 0x03cau /* Read */ +/* ? 0x03cbu */ +#define R_GENMO 0x03ccu /* Read */ +/* ? 0x03cdu */ +#define GRAX 0x03ceu +#define GRAD 0x03cfu + +#define GENB 0x03d9u + +#define GENLPS 0x03dcu /* Write */ +#define KCX 0x03ddu +#define KCD 0x03deu + +#define GENENA 0x46e8u /* Write */ + +/* I/O port base numbers */ +#define MonochromeIOBase 0x03b0u +#define ColourIOBase 0x03d0u + +/* Other MDA/[M]CGA/EGA/VGA I/O ports */ +/* ?(_IOBase) ((_IOBase) + 0x00u) */ /* CRTX synonym */ +/* ?(_IOBase) ((_IOBase) + 0x01u) */ /* CRTD synonym */ +/* ?(_IOBase) ((_IOBase) + 0x02u) */ /* CRTX synonym */ +/* ?(_IOBase) ((_IOBase) + 0x03u) */ /* CRTD synonym */ +#define CRTX(_IOBase) ((_IOBase) + 0x04u) +#define CRTD(_IOBase) ((_IOBase) + 0x05u) +/* ?(_IOBase) ((_IOBase) + 0x06u) */ +/* ?(_IOBase) ((_IOBase) + 0x07u) */ +#define GENMC(_IOBase) ((_IOBase) + 0x08u) +/* ?(_IOBase) ((_IOBase) + 0x09u) */ /* R_GENLPS/GENB */ +#define GENS1(_IOBase) ((_IOBase) + 0x0au) /* Read */ +#define GENFC(_IOBase) ((_IOBase) + 0x0au) /* Write */ +#define GENLPC(_IOBase) ((_IOBase) + 0x0bu) +/* ?(_IOBase) ((_IOBase) + 0x0cu) */ /* /GENLPS */ +/* ?(_IOBase) ((_IOBase) + 0x0du) */ /* /KCX */ +/* ?(_IOBase) ((_IOBase) + 0x0eu) */ /* /KCD */ +/* ?(_IOBase) ((_IOBase) + 0x0fu) */ /* GENHP/ */ + +/* 8514/A VESA approved register definitions */ +#define DISP_STAT 0x02e8u /* Read */ +#define SENSE 0x0001u /* Presumably belong here */ +#define VBLANK 0x0002u +#define HORTOG 0x0004u +#define H_TOTAL 0x02e8u /* Write */ +#define IBM_DAC_MASK 0x02eau +#define IBM_DAC_READ 0x02ebu +#define IBM_DAC_WRITE 0x02ecu +#define IBM_DAC_DATA 0x02edu +#define H_DISP 0x06e8u /* Write */ +#define H_SYNC_STRT 0x0ae8u /* Write */ +#define H_SYNC_WID 0x0ee8u /* Write */ +#define HSYNCPOL_POS 0x0000u +#define HSYNCPOL_NEG 0x0020u +#define H_POLARITY_POS HSYNCPOL_POS /* Sigh */ +#define H_POLARITY_NEG HSYNCPOL_NEG /* Sigh */ +#define V_TOTAL 0x12e8u /* Write */ +#define V_DISP 0x16e8u /* Write */ +#define V_SYNC_STRT 0x1ae8u /* Write */ +#define V_SYNC_WID 0x1ee8u /* Write */ +#define VSYNCPOL_POS 0x0000u +#define VSYNCPOL_NEG 0x0020u +#define V_POLARITY_POS VSYNCPOL_POS /* Sigh */ +#define V_POLARITY_NEG VSYNCPOL_NEG /* Sigh */ +#define DISP_CNTL 0x22e8u /* Write */ +#define ODDBNKENAB 0x0001u +#define MEMCFG_2 0x0000u +#define MEMCFG_4 0x0002u +#define MEMCFG_6 0x0004u +#define MEMCFG_8 0x0006u +#define DBLSCAN 0x0008u +#define INTERLACE 0x0010u +#define DISPEN_NC 0x0000u +#define DISPEN_ENAB 0x0020u +#define DISPEN_DISAB 0x0040u +#define R_H_TOTAL 0x26e8u /* Read */ +/* ? 0x2ae8u */ +/* ? 0x2ee8u */ +/* ? 0x32e8u */ +/* ? 0x36e8u */ +/* ? 0x3ae8u */ +/* ? 0x3ee8u */ +#define SUBSYS_STAT 0x42e8u /* Read */ +#define VBLNKFLG 0x0001u +#define PICKFLAG 0x0002u +#define INVALIDIO 0x0004u +#define GPIDLE 0x0008u +#define MONITORID_MASK 0x0070u +/* MONITORID_? 0x0000u */ +#define MONITORID_8507 0x0010u +#define MONITORID_8514 0x0020u +/* MONITORID_? 0x0030u */ +/* MONITORID_? 0x0040u */ +#define MONITORID_8503 0x0050u +#define MONITORID_8512 0x0060u +#define MONITORID_8513 0x0060u +#define MONITORID_NONE 0x0070u +#define _8PLANE 0x0080u +#define SUBSYS_CNTL 0x42e8u /* Write */ +#define RVBLNKFLG 0x0001u +#define RPICKFLAG 0x0002u +#define RINVALIDIO 0x0004u +#define RGPIDLE 0x0008u +#define IVBLNKFLG 0x0100u +#define IPICKFLAG 0x0200u +#define IINVALIDIO 0x0400u +#define IGPIDLE 0x0800u +#define CHPTEST_NC 0x0000u +#define CHPTEST_NORMAL 0x1000u +#define CHPTEST_ENAB 0x2000u +#define GPCTRL_NC 0x0000u +#define GPCTRL_ENAB 0x4000u +#define GPCTRL_RESET 0x8000u +#define ROM_PAGE_SEL 0x46e8u /* Write */ +#define ADVFUNC_CNTL 0x4ae8u /* Write */ +#define DISABPASSTHRU 0x0001u +#define CLOKSEL 0x0004u +/* ? 0x4ee8u */ +#define EXT_CONFIG_0 0x52e8u /* C & T 82C480 */ +#define EXT_CONFIG_1 0x56e8u /* C & T 82C480 */ +#define EXT_CONFIG_2 0x5ae8u /* C & T 82C480 */ +#define EXT_CONFIG_3 0x5ee8u /* C & T 82C480 */ +/* ? 0x62e8u */ +/* ? 0x66e8u */ +/* ? 0x6ae8u */ +/* ? 0x6ee8u */ +/* ? 0x72e8u */ +/* ? 0x76e8u */ +/* ? 0x7ae8u */ +/* ? 0x7ee8u */ +#define CUR_Y 0x82e8u +#define CUR_X 0x86e8u +#define DESTY_AXSTP 0x8ae8u /* Write */ +#define DESTX_DIASTP 0x8ee8u /* Write */ +#define ERR_TERM 0x92e8u +#define MAJ_AXIS_PCNT 0x96e8u /* Write */ +#define GP_STAT 0x9ae8u /* Read */ +#define GE_STAT 0x9ae8u /* Alias */ +#define DATARDY 0x0100u +#define DATA_READY DATARDY /* Alias */ +#define GPBUSY 0x0200u +#define CMD 0x9ae8u /* Write */ +#define WRTDATA 0x0001u +#define PLANAR 0x0002u +#define LASTPIX 0x0004u +#define LINETYPE 0x0008u +#define DRAW 0x0010u +#define INC_X 0x0020u +#define YMAJAXIS 0x0040u +#define INC_Y 0x0080u +#define PCDATA 0x0100u +#define _16BIT 0x0200u +#define CMD_NOP 0x0000u +#define CMD_OP_MSK 0xf000u +#define BYTSEQ 0x1000u +#define CMD_LINE 0x2000u +#define CMD_RECT 0x4000u +#define CMD_RECTV1 0x6000u +#define CMD_RECTV2 0x8000u +#define CMD_LINEAF 0xa000u +#define CMD_BITBLT 0xc000u +#define SHORT_STROKE 0x9ee8u /* Write */ +#define SSVDRAW 0x0010u +#define VECDIR_000 0x0000u +#define VECDIR_045 0x0020u +#define VECDIR_090 0x0040u +#define VECDIR_135 0x0060u +#define VECDIR_180 0x0080u +#define VECDIR_225 0x00a0u +#define VECDIR_270 0x00c0u +#define VECDIR_315 0x00e0u +#define BKGD_COLOR 0xa2e8u /* Write */ +#define FRGD_COLOR 0xa6e8u /* Write */ +#define WRT_MASK 0xaae8u /* Write */ +#define RD_MASK 0xaee8u /* Write */ +#define COLOR_CMP 0xb2e8u /* Write */ +#define BKGD_MIX 0xb6e8u /* Write */ +/* 0x001fu See MIX_* definitions below */ +#define BSS_BKGDCOL 0x0000u +#define BSS_FRGDCOL 0x0020u +#define BSS_PCDATA 0x0040u +#define BSS_BITBLT 0x0060u +#define FRGD_MIX 0xbae8u /* Write */ +/* 0x001fu See MIX_* definitions below */ +#define FSS_BKGDCOL 0x0000u +#define FSS_FRGDCOL 0x0020u +#define FSS_PCDATA 0x0040u +#define FSS_BITBLT 0x0060u +#define MULTIFUNC_CNTL 0xbee8u /* Write */ +#define MIN_AXIS_PCNT 0x0000u +#define SCISSORS_T 0x1000u +#define SCISSORS_L 0x2000u +#define SCISSORS_B 0x3000u +#define SCISSORS_R 0x4000u +#define M32_MEM_CNTL 0x5000u +#define HORCFG_4 0x0000u +#define HORCFG_5 0x0001u +#define HORCFG_8 0x0002u +#define HORCFG_10 0x0003u +#define VRTCFG_2 0x0000u +#define VRTCFG_4 0x0004u +#define VRTCFG_6 0x0008u +#define VRTCFG_8 0x000cu +#define BUFSWP 0x0010u +#define PATTERN_L 0x8000u +#define PATTERN_H 0x9000u +#define PIX_CNTL 0xa000u +#define PLANEMODE 0x0004u +#define COLCMPOP_F 0x0000u +#define COLCMPOP_T 0x0008u +#define COLCMPOP_GE 0x0010u +#define COLCMPOP_LT 0x0018u +#define COLCMPOP_NE 0x0020u +#define COLCMPOP_EQ 0x0028u +#define COLCMPOP_LE 0x0030u +#define COLCMPOP_GT 0x0038u +#define MIXSEL_FRGDMIX 0x0000u +#define MIXSEL_PATT 0x0040u +#define MIXSEL_EXPPC 0x0080u +#define MIXSEL_EXPBLT 0x00c0u +/* ? 0xc2e8u */ +/* ? 0xc6e8u */ +/* ? 0xcae8u */ +/* ? 0xcee8u */ +/* ? 0xd2e8u */ +/* ? 0xd6e8u */ +/* ? 0xdae8u */ +/* ? 0xdee8u */ +#define PIX_TRANS 0xe2e8u +/* ? 0xe6e8u */ +/* ? 0xeae8u */ +/* ? 0xeee8u */ +/* ? 0xf2e8u */ +/* ? 0xf6e8u */ +/* ? 0xfae8u */ +/* ? 0xfee8u */ + +/* ATI Mach8 & Mach32 register definitions */ +#define OVERSCAN_COLOR_8 0x02eeu /* Write */ /* Mach32 */ +#define OVERSCAN_BLUE_24 0x02efu /* Write */ /* Mach32 */ +#define OVERSCAN_GREEN_24 0x06eeu /* Write */ /* Mach32 */ +#define OVERSCAN_RED_24 0x06efu /* Write */ /* Mach32 */ +#define CURSOR_OFFSET_LO 0x0aeeu /* Write */ /* Mach32 */ +#define CURSOR_OFFSET_HI 0x0eeeu /* Write */ /* Mach32 */ +#define CONFIG_STATUS_1 0x12eeu /* Read */ +#define CLK_MODE 0x0001u /* Mach8 */ +#define BUS_16 0x0002u /* Mach8 */ +#define MC_BUS 0x0004u /* Mach8 */ +#define EEPROM_ENA 0x0008u /* Mach8 */ +#define DRAM_ENA 0x0010u /* Mach8 */ +#define MEM_INSTALLED 0x0060u /* Mach8 */ +#define ROM_ENA 0x0080u /* Mach8 */ +#define ROM_PAGE_ENA 0x0100u /* Mach8 */ +#define ROM_LOCATION 0xfe00u /* Mach8 */ +#define _8514_ONLY 0x0001u /* Mach32 */ +#define BUS_TYPE 0x000eu /* Mach32 */ +#define ISA_16_BIT 0x0000u /* Mach32 */ +#define EISA 0x0002u /* Mach32 */ +#define MICRO_C_16_BIT 0x0004u /* Mach32 */ +#define MICRO_C_8_BIT 0x0006u /* Mach32 */ +#define LOCAL_386SX 0x0008u /* Mach32 */ +#define LOCAL_386DX 0x000au /* Mach32 */ +#define LOCAL_486 0x000cu /* Mach32 */ +#define PCI 0x000eu /* Mach32 */ +#define MEM_TYPE 0x0070u /* Mach32 */ +#define CHIP_DIS 0x0080u /* Mach32 */ +#define TST_VCTR_ENA 0x0100u /* Mach32 */ +#define DACTYPE 0x0e00u /* Mach32 */ +#define MC_ADR_DECODE 0x1000u /* Mach32 */ +#define CARD_ID 0xe000u /* Mach32 */ +#define HORZ_CURSOR_POSN 0x12eeu /* Write */ /* Mach32 */ +#define CONFIG_STATUS_2 0x16eeu /* Read */ +#define SHARE_CLOCK 0x0001u /* Mach8 */ +#define HIRES_BOOT 0x0002u /* Mach8 */ +#define EPROM_16_ENA 0x0004u /* Mach8 */ +#define WRITE_PER_BIT 0x0008u /* Mach8 */ +#define FLASH_ENA 0x0010u /* Mach8 */ +#define SLOW_SEQ_EN 0x0001u /* Mach32 */ +#define MEM_ADDR_DIS 0x0002u /* Mach32 */ +#define ISA_16_ENA 0x0004u /* Mach32 */ +#define KOR_TXT_MODE_ENA 0x0008u /* Mach32 */ +#define LOCAL_BUS_SUPPORT 0x0030u /* Mach32 */ +#define LOCAL_BUS_CONFIG_2 0x0040u /* Mach32 */ +#define LOCAL_BUS_RD_DLY_ENA 0x0080u /* Mach32 */ +#define LOCAL_DAC_EN 0x0100u /* Mach32 */ +#define LOCAL_RDY_EN 0x0200u /* Mach32 */ +#define EEPROM_ADR_SEL 0x0400u /* Mach32 */ +#define GE_STRAP_SEL 0x0800u /* Mach32 */ +#define VESA_RDY 0x1000u /* Mach32 */ +#define Z4GB 0x2000u /* Mach32 */ +#define LOC2_MDRAM 0x4000u /* Mach32 */ +#define VERT_CURSOR_POSN 0x16eeu /* Write */ /* Mach32 */ +#define FIFO_TEST_DATA 0x1aeeu /* Read */ /* Mach32 */ +#define CURSOR_COLOR_0 0x1aeeu /* Write */ /* Mach32 */ +#define CURSOR_COLOR_1 0x1aefu /* Write */ /* Mach32 */ +#define HORZ_CURSOR_OFFSET 0x1eeeu /* Write */ /* Mach32 */ +#define VERT_CURSOR_OFFSET 0x1eefu /* Write */ /* Mach32 */ +#define PCI_CNTL 0x22eeu /* Mach32-PCI */ +#define CRT_PITCH 0x26eeu /* Write */ +#define CRT_OFFSET_LO 0x2aeeu /* Write */ +#define CRT_OFFSET_HI 0x2eeeu /* Write */ +#define LOCAL_CNTL 0x32eeu /* Mach32 */ +#define FIFO_OPT 0x36eeu /* Write */ /* Mach8 */ +#define MISC_OPTIONS 0x36eeu /* Mach32 */ +#define W_STATE_ENA 0x0000u /* Mach32 */ +#define HOST_8_ENA 0x0001u /* Mach32 */ +#define MEM_SIZE_ALIAS 0x000cu /* Mach32 */ +#define MEM_SIZE_512K 0x0000u /* Mach32 */ +#define MEM_SIZE_1M 0x0004u /* Mach32 */ +#define MEM_SIZE_2M 0x0008u /* Mach32 */ +#define MEM_SIZE_4M 0x000cu /* Mach32 */ +#define DISABLE_VGA 0x0010u /* Mach32 */ +#define _16_BIT_IO 0x0020u /* Mach32 */ +#define DISABLE_DAC 0x0040u /* Mach32 */ +#define DLY_LATCH_ENA 0x0080u /* Mach32 */ +#define TEST_MODE 0x0100u /* Mach32 */ +#define BLK_WR_ENA 0x0400u /* Mach32 */ +#define _64_DRAW_ENA 0x0800u /* Mach32 */ +#define FIFO_TEST_TAG 0x3aeeu /* Read */ /* Mach32 */ +#define EXT_CURSOR_COLOR_0 0x3aeeu /* Write */ /* Mach32 */ +#define EXT_CURSOR_COLOR_1 0x3eeeu /* Write */ /* Mach32 */ +#define MEM_BNDRY 0x42eeu /* Mach32 */ +#define MEM_PAGE_BNDRY 0x000fu /* Mach32 */ +#define MEM_BNDRY_ENA 0x0010u /* Mach32 */ +#define SHADOW_CTL 0x46eeu /* Write */ +#define CLOCK_SEL 0x4aeeu +/* DISABPASSTHRU 0x0001u See ADVFUNC_CNTL */ +#define VFIFO_DEPTH_1 0x0100u /* Mach32 */ +#define VFIFO_DEPTH_2 0x0200u /* Mach32 */ +#define VFIFO_DEPTH_3 0x0300u /* Mach32 */ +#define VFIFO_DEPTH_4 0x0400u /* Mach32 */ +#define VFIFO_DEPTH_5 0x0500u /* Mach32 */ +#define VFIFO_DEPTH_6 0x0600u /* Mach32 */ +#define VFIFO_DEPTH_7 0x0700u /* Mach32 */ +#define VFIFO_DEPTH_8 0x0800u /* Mach32 */ +#define VFIFO_DEPTH_9 0x0900u /* Mach32 */ +#define VFIFO_DEPTH_A 0x0a00u /* Mach32 */ +#define VFIFO_DEPTH_B 0x0b00u /* Mach32 */ +#define VFIFO_DEPTH_C 0x0c00u /* Mach32 */ +#define VFIFO_DEPTH_D 0x0d00u /* Mach32 */ +#define VFIFO_DEPTH_E 0x0e00u /* Mach32 */ +#define VFIFO_DEPTH_F 0x0f00u /* Mach32 */ +#define COMPOSITE_SYNC 0x1000u +/* ? 0x4eeeu */ +#define ROM_ADDR_1 0x52eeu +#define BIOS_BASE_SEGMENT 0x007fu /* Mach32 */ +/* ? 0xff80u */ /* Mach32 */ +#define ROM_ADDR_2 0x56eeu /* Sick ... */ +#define SHADOW_SET 0x5aeeu /* Write */ +#define MEM_CFG 0x5eeeu /* Mach32 */ +#define MEM_APERT_SEL 0x0003u /* Mach32 */ +#define MEM_APERT_PAGE 0x000cu /* Mach32 */ +#define MEM_APERT_LOC 0xfff0u /* Mach32 */ +#define EXT_GE_STATUS 0x62eeu /* Read */ /* Mach32 */ +#define HORZ_OVERSCAN 0x62eeu /* Write */ /* Mach32 */ +#define VERT_OVERSCAN 0x66eeu /* Write */ /* Mach32 */ +#define MAX_WAITSTATES 0x6aeeu +#define GE_OFFSET_LO 0x6eeeu /* Write */ +#define BOUNDS_LEFT 0x72eeu /* Read */ +#define GE_OFFSET_HI 0x72eeu /* Write */ +#define BOUNDS_TOP 0x76eeu /* Read */ +#define GE_PITCH 0x76eeu /* Write */ +#define BOUNDS_RIGHT 0x7aeeu /* Read */ +#define EXT_GE_CONFIG 0x7aeeu /* Write */ /* Mach32 */ +#define MONITOR_ALIAS 0x0007u /* Mach32 */ +/* MONITOR_? 0x0000u */ /* Mach32 */ +#define MONITOR_8507 0x0001u /* Mach32 */ +#define MONITOR_8514 0x0002u /* Mach32 */ +/* MONITOR_? 0x0003u */ /* Mach32 */ +/* MONITOR_? 0x0004u */ /* Mach32 */ +#define MONITOR_8503 0x0005u /* Mach32 */ +#define MONITOR_8512 0x0006u /* Mach32 */ +#define MONITOR_8513 0x0006u /* Mach32 */ +#define MONITOR_NONE 0x0007u /* Mach32 */ +#define ALIAS_ENA 0x0008u /* Mach32 */ +#define PIXEL_WIDTH_4 0x0000u /* Mach32 */ +#define PIXEL_WIDTH_8 0x0010u /* Mach32 */ +#define PIXEL_WIDTH_16 0x0020u /* Mach32 */ +#define PIXEL_WIDTH_24 0x0030u /* Mach32 */ +#define RGB16_555 0x0000u /* Mach32 */ +#define RGB16_565 0x0040u /* Mach32 */ +#define RGB16_655 0x0080u /* Mach32 */ +#define RGB16_664 0x00c0u /* Mach32 */ +#define MULTIPLEX_PIXELS 0x0100u /* Mach32 */ +#define RGB24 0x0000u /* Mach32 */ +#define RGBx24 0x0200u /* Mach32 */ +#define BGR24 0x0400u /* Mach32 */ +#define xBGR24 0x0600u /* Mach32 */ +#define DAC_8_BIT_EN 0x4000u /* Mach32 */ +#define ORDER_16BPP_565 RGB16_565 /* Mach32 */ +#define BOUNDS_BOTTOM 0x7eeeu /* Read */ +#define MISC_CNTL 0x7eeeu /* Write */ /* Mach32 */ +#define PATT_DATA_INDEX 0x82eeu +/* ? 0x86eeu */ +/* ? 0x8aeeu */ +#define R_EXT_GE_CONFIG 0x8eeeu /* Read */ /* Mach32 */ +#define PATT_DATA 0x8eeeu /* Write */ +#define R_MISC_CNTL 0x92eeu /* Read */ /* Mach32 */ +#define BRES_COUNT 0x96eeu +#define EXT_FIFO_STATUS 0x9aeeu /* Read */ +#define LINEDRAW_INDEX 0x9aeeu /* Write */ +/* ? 0x9eeeu */ +#define LINEDRAW_OPT 0xa2eeu +#define BOUNDS_RESET 0x0100u +#define CLIP_MODE_0 0x0000u /* Clip exception disabled */ +#define CLIP_MODE_1 0x0200u /* Line segments */ +#define CLIP_MODE_2 0x0400u /* Polygon boundary lines */ +#define CLIP_MODE_3 0x0600u /* Patterned lines */ +#define DEST_X_START 0xa6eeu /* Write */ +#define DEST_X_END 0xaaeeu /* Write */ +#define DEST_Y_END 0xaeeeu /* Write */ +#define R_H_TOTAL_DISP 0xb2eeu /* Read */ /* Mach32 */ +#define SRC_X_STRT 0xb2eeu /* Write */ +#define R_H_SYNC_STRT 0xb6eeu /* Read */ /* Mach32 */ +#define ALU_BG_FN 0xb6eeu /* Write */ +#define R_H_SYNC_WID 0xbaeeu /* Read */ /* Mach32 */ +#define ALU_FG_FN 0xbaeeu /* Write */ +#define SRC_X_END 0xbeeeu /* Write */ +#define R_V_TOTAL 0xc2eeu /* Read */ +#define SRC_Y_DIR 0xc2eeu /* Write */ +#define R_V_DISP 0xc6eeu /* Read */ /* Mach32 */ +#define EXT_SHORT_STROKE 0xc6eeu /* Write */ +#define R_V_SYNC_STRT 0xcaeeu /* Read */ /* Mach32 */ +#define SCAN_X 0xcaeeu /* Write */ +#define VERT_LINE_CNTR 0xceeeu /* Read */ /* Mach32 */ +#define DP_CONFIG 0xceeeu /* Write */ +#define READ_WRITE 0x0001u +#define DATA_WIDTH 0x0200u +#define DATA_ORDER 0x1000u +#define FG_COLOR_SRC_FG 0x2000u +#define FG_COLOR_SRC_BLIT 0x6000u +#define R_V_SYNC_WID 0xd2eeu /* Read */ +#define PATT_LENGTH 0xd2eeu /* Write */ +#define PATT_INDEX 0xd6eeu /* Write */ +#define READ_SRC_X 0xdaeeu /* Read */ /* Mach32 */ +#define EXT_SCISSOR_L 0xdaeeu /* Write */ +#define READ_SRC_Y 0xdeeeu /* Read */ /* Mach32 */ +#define EXT_SCISSOR_T 0xdeeeu /* Write */ +#define EXT_SCISSOR_R 0xe2eeu /* Write */ +#define EXT_SCISSOR_B 0xe6eeu /* Write */ +/* ? 0xeaeeu */ +#define DEST_COMP_FN 0xeeeeu /* Write */ +#define DEST_COLOR_CMP_MASK 0xf2eeu /* Write */ /* Mach32 */ +/* ? 0xf6eeu */ +#define CHIP_ID 0xfaeeu /* Read */ /* Mach32 */ +#define CHIP_CODE_0 0x001fu /* Mach32 */ +#define CHIP_CODE_1 0x03e0u /* Mach32 */ +#define CHIP_CLASS 0x0c00u /* Mach32 */ +#define CHIP_REV 0xf000u /* Mach32 */ +#define LINEDRAW 0xfeeeu /* Write */ + +/* ATI Mach64 register definitions */ +#define CRTC_H_TOTAL_DISP IOPortTag(0x00u, 0x00u) +#define CRTC_H_TOTAL 0x000001fful +/* ? 0x0000fe00ul */ +#define CRTC_H_DISP 0x01ff0000ul +/* ? 0xfe000000ul */ +#define CRTC_H_SYNC_STRT_WID IOPortTag(0x01u, 0x01u) +#define CRTC_H_SYNC_STRT 0x000000fful +#define CRTC_H_SYNC_DLY 0x00000700ul +/* ? 0x00000800ul */ +#define CRTC_H_SYNC_STRT_HI 0x00001000ul +/* ? 0x0000e000ul */ +#define CRTC_H_SYNC_WID 0x001f0000ul +#define CRTC_H_SYNC_POL 0x00200000ul +/* ? 0xffc00000ul */ +#define CRTC_V_TOTAL_DISP IOPortTag(0x02u, 0x02u) +#define CRTC_V_TOTAL 0x000007fful +/* ? 0x0000f800ul */ +#define CRTC_V_DISP 0x07ff0000ul +/* ? 0xf8000000ul */ +#define CRTC_V_SYNC_STRT_WID IOPortTag(0x03u, 0x03u) +#define CRTC_V_SYNC_STRT 0x000007fful +/* ? 0x0000f800ul */ +#define CRTC_V_SYNC_WID 0x001f0000ul +#define CRTC_V_SYNC_POL 0x00200000ul +/* ? 0xffc00000ul */ +#define CRTC_VLINE_CRNT_VLINE IOPortTag(0x04u, 0x04u) +#define CRTC_VLINE 0x000007fful +/* ? 0x0000f800ul */ +#define CRTC_CRNT_VLINE 0x07ff0000ul +/* ? 0xf8000000ul */ +#define CRTC_OFF_PITCH IOPortTag(0x05u, 0x05u) +#define CRTC_OFFSET 0x000ffffful +#define CRTC_OFFSET_VGA 0x0003fffful +#define CRTC_OFFSET_LOCK 0x00100000ul /* XC/XL */ +/* ? 0x00200000ul */ +#define CRTC_PITCH 0xffc00000ul +#define CRTC_INT_CNTL IOPortTag(0x06u, 0x06u) +#define CRTC_VBLANK 0x00000001ul +#define CRTC_VBLANK_INT_EN 0x00000002ul +#define CRTC_VBLANK_INT 0x00000004ul +#define CRTC_VLINE_INT_EN 0x00000008ul +#define CRTC_VLINE_INT 0x00000010ul +#define CRTC_VLINE_SYNC 0x00000020ul +#define CRTC_FRAME 0x00000040ul +#define CRTC_SNAPSHOT_INT_EN 0x00000080ul /* GTPro */ +#define CRTC_SNAPSHOT_INT 0x00000100ul /* GTPro */ +#define CRTC_I2C_INT_EN 0x00000200ul /* GTPro */ +#define CRTC_I2C_INT 0x00000400ul /* GTPro */ +#define CRTC2_VBLANK 0x00000800ul /* LTPro */ +#define CRTC2_VBLANK_INT_EN 0x00001000ul /* LTPro */ +#define CRTC2_VBLANK_INT 0x00002000ul /* LTPro */ +#define CRTC2_VLINE_INT_EN 0x00004000ul /* LTPro */ +#define CRTC2_VLINE_INT 0x00008000ul /* LTPro */ +#define CRTC_CAPBUF0_INT_EN 0x00010000ul /* VT/GT */ +#define CRTC_CAPBUF0_INT 0x00020000ul /* VT/GT */ +#define CRTC_CAPBUF1_INT_EN 0x00040000ul /* VT/GT */ +#define CRTC_CAPBUF1_INT 0x00080000ul /* VT/GT */ +#define CRTC_OVERLAY_EOF_INT_EN 0x00100000ul /* VT/GT */ +#define CRTC_OVERLAY_EOF_INT 0x00200000ul /* VT/GT */ +#define CRTC_ONESHOT_CAP_INT_EN 0x00400000ul /* VT/GT */ +#define CRTC_ONESHOT_CAP_INT 0x00800000ul /* VT/GT */ +#define CRTC_BUSMASTER_EOL_INT_EN 0x01000000ul /* VTB/GTB/LT */ +#define CRTC_BUSMASTER_EOL_INT 0x02000000ul /* VTB/GTB/LT */ +#define CRTC_GP_INT_EN 0x04000000ul /* VTB/GTB/LT */ +#define CRTC_GP_INT 0x08000000ul /* VTB/GTB/LT */ +#define CRTC2_VLINE_SYNC 0x10000000ul /* LTPro */ +#define CRTC_SNAPSHOT2_INT_EN 0x20000000ul /* LTPro */ +#define CRTC_SNAPSHOT2_INT 0x40000000ul /* LTPro */ +#define CRTC_VBLANK_BIT2_INT 0x80000000ul /* GTPro */ +#define CRTC_INT_ENS /* *** UPDATE ME *** */ \ + ( \ + CRTC_VBLANK_INT_EN | \ + CRTC_VLINE_INT_EN | \ + CRTC_SNAPSHOT_INT_EN | \ + CRTC_I2C_INT_EN | \ + CRTC2_VBLANK_INT_EN | \ + CRTC2_VLINE_INT_EN | \ + CRTC_CAPBUF0_INT_EN | \ + CRTC_CAPBUF1_INT_EN | \ + CRTC_OVERLAY_EOF_INT_EN | \ + CRTC_ONESHOT_CAP_INT_EN | \ + CRTC_BUSMASTER_EOL_INT_EN | \ + CRTC_GP_INT_EN | \ + CRTC_SNAPSHOT2_INT_EN | \ + 0 \ + ) +#define CRTC_INT_ACKS /* *** UPDATE ME *** */ \ + ( \ + CRTC_VBLANK_INT | \ + CRTC_VLINE_INT | \ + CRTC_SNAPSHOT_INT | \ + CRTC_I2C_INT | \ + CRTC2_VBLANK_INT | \ + CRTC2_VLINE_INT | \ + CRTC_CAPBUF0_INT | \ + CRTC_CAPBUF1_INT | \ + CRTC_OVERLAY_EOF_INT | \ + CRTC_ONESHOT_CAP_INT | \ + CRTC_BUSMASTER_EOL_INT | \ + CRTC_GP_INT | \ + CRTC_SNAPSHOT2_INT | \ + CRTC_VBLANK_BIT2_INT | \ + 0 \ + ) +#define CRTC_GEN_CNTL IOPortTag(0x07u, 0x07u) +#define CRTC_DBL_SCAN_EN 0x00000001ul +#define CRTC_INTERLACE_EN 0x00000002ul +#define CRTC_HSYNC_DIS 0x00000004ul +#define CRTC_VSYNC_DIS 0x00000008ul +#define CRTC_CSYNC_EN 0x00000010ul +#define CRTC_PIX_BY_2_EN 0x00000020ul +#define CRTC2_DBL_SCAN_EN 0x00000020ul /* LTPro */ +#define CRTC_DISPLAY_DIS 0x00000040ul +#define CRTC_VGA_XOVERSCAN 0x00000080ul +#define CRTC_PIX_WIDTH 0x00000700ul +#define CRTC_BYTE_PIX_ORDER 0x00000800ul +#define CRTC_VSYNC_INT_EN 0x00001000ul /* XC/XL */ +#define CRTC_VSYNC_INT 0x00002000ul /* XC/XL */ +#define CRTC_FIFO_OVERFILL 0x0000c000ul /* VT/GT */ +#define CRTC2_VSYNC_INT_EN 0x00004000ul /* XC/XL */ +#define CRTC2_VSYNC_INT 0x00008000ul /* XC/XL */ +#define CRTC_FIFO_LWM 0x000f0000ul +#define CRTC_HVSYNC_IO_DRIVE 0x00010000ul /* XC/XL */ +#define CRTC2_PIX_WIDTH 0x000e0000ul /* LTPro */ +#define CRTC_VGA_128KAP_PAGING 0x00100000ul /* VT/GT */ +#define CRTC_DISPREQ_ONLY 0x00200000ul /* VT/GT */ +#define CRTC_VFC_SYNC_TRISTATE 0x00200000ul /* VTB/GTB/LT */ +#define CRTC2_EN 0x00200000ul /* LTPro */ +#define CRTC_LOCK_REGS 0x00400000ul /* VT/GT */ +#define CRTC_SYNC_TRISTATE 0x00800000ul /* VT/GT */ +#define CRTC_EXT_DISP_EN 0x01000000ul +#define CRTC_EN 0x02000000ul +#define CRTC_DISP_REQ_EN 0x04000000ul +#define CRTC_VGA_LINEAR 0x08000000ul +#define CRTC_VSYNC_FALL_EDGE 0x10000000ul +#define CRTC_VGA_TEXT_132 0x20000000ul +#define CRTC_CNT_EN 0x40000000ul +#define CRTC_CUR_B_TEST 0x80000000ul +#define CRTC_INT_ENS_X /* *** UPDATE ME *** */ \ + ( \ + CRTC_VSYNC_INT_EN | \ + CRTC2_VSYNC_INT_EN | \ + 0 \ + ) +#define CRTC_INT_ACKS_X /* *** UPDATE ME *** */ \ + ( \ + CRTC_VSYNC_INT | \ + CRTC2_VSYNC_INT | \ + 0 \ + ) +#define DSP_CONFIG BlockIOTag(0x08u) /* VTB/GTB/LT */ +#define DSP_XCLKS_PER_QW 0x00003ffful +/* ? 0x00004000ul */ +#define DSP_FLUSH_WB 0x00008000ul +#define DSP_LOOP_LATENCY 0x000f0000ul +#define DSP_PRECISION 0x00700000ul +/* ? 0xff800000ul */ +#define DSP_ON_OFF BlockIOTag(0x09u) /* VTB/GTB/LT */ +#define DSP_OFF 0x000007fful +/* ? 0x0000f800ul */ +#define DSP_ON 0x07ff0000ul +/* ? 0xf8000000ul */ +#define TIMER_CONFIG BlockIOTag(0x0au) /* VTB/GTB/LT */ +#define MEM_BUF_CNTL BlockIOTag(0x0bu) /* VTB/GTB/LT */ +#define SHARED_CNTL BlockIOTag(0x0cu) /* VTB/GTB/LT */ +#define SHARED_MEM_CONFIG BlockIOTag(0x0du) /* VTB/GTB/LT */ +#define MEM_ADDR_CONFIG BlockIOTag(0x0du) /* GTPro */ +#define SHARED_CNTL_CTD BlockIOTag(0x0eu) /* CTD */ +/* ? 0x00fffffful */ +#define CTD_FIFO5 0x01000000ul +/* ? 0xfe000000ul */ +#define CRT_TRAP BlockIOTag(0x0eu) /* VTB/GTB/LT */ +#define DSTN_CONTROL BlockIOTag(0x0fu) /* LT */ +#define I2C_CNTL_0 BlockIOTag(0x0fu) /* GTPro */ +#define I2C_CNTL_STAT 0x0000000ful +#define I2C_CNTL_DONE 0x00000001ul +#define I2C_CNTL_NACK 0x00000002ul +#define I2C_CNTL_HALT 0x00000004ul +#define I2C_CNTL_FULL 0x00000008ul +/* ? 0x00000010ul */ +#define I2C_CNTL_HPTR_RST 0x00000020ul +/* ? 0x000000c0ul */ +#define I2C_CNTL_START 0x00000100ul +#define I2C_CNTL_STOP 0x00000200ul +#define I2C_CNTL_GO 0x00000400ul +#define I2C_CNTL_RECEIVE 0x00000800ul +#define I2C_CNTL_ABORT 0x00001000ul +#define I2C_CNTL_INT_EN 0x00002000ul +#define I2C_CNTL_SCL 0x00004000ul +#define I2C_CNTL_SDA 0x00008000ul +#define I2C_CNTL_M_FACTOR 0x00ff0000ul +#define I2C_CNTL_N_FACTOR 0xff000000ul +#define OVR_CLR IOPortTag(0x08u, 0x10u) +#define OVR_CLR_8 0x000000fful +#define OVR_CLR_B 0x0000ff00ul +#define OVR_CLR_G 0x00ff0000ul +#define OVR_CLR_R 0xff000000ul +#define OVR_WID_LEFT_RIGHT IOPortTag(0x09u, 0x11u) +#define OVR_WID_LEFT 0x0000003ful /* 0x0f on <LT */ +/* ? 0x0000ffc0ul */ +#define OVR_WID_RIGHT 0x003f0000ul /* 0x0f0000 on <LT */ +/* ? 0xffc00000ul */ +#define OVR_WID_TOP_BOTTOM IOPortTag(0x0au, 0x12u) +#define OVR_WID_TOP 0x000001fful /* 0x00ff on <LT */ +/* ? 0x0000fe00ul */ +#define OVR_WID_BOTTOM 0x01ff0000ul /* 0x00ff0000 on <LT */ +/* ? 0xfe000000ul */ +#define VGA_DSP_CONFIG BlockIOTag(0x13u) /* VTB/GTB/LT */ +#define VGA_DSP_XCLKS_PER_QW DSP_XCLKS_PER_QW +/* ? 0x000fc000ul */ +#define VGA_DSP_PREC_PCLKBY2 0x00700000ul +/* ? 0x00800000ul */ +#define VGA_DSP_PREC_PCLK 0x07000000ul +/* ? 0xf8000000ul */ +#define VGA_DSP_ON_OFF BlockIOTag(0x14u) /* VTB/GTB/LT */ +#define VGA_DSP_OFF DSP_OFF +/* ? 0x0000f800ul */ +#define VGA_DSP_ON DSP_ON +/* ? 0xf8000000ul */ +#define DSP2_CONFIG BlockIOTag(0x15u) /* LTPro */ +#define DSP2_ON_OFF BlockIOTag(0x16u) /* LTPro */ +#define EXT_CRTC_GEN_CNTL BlockIOTag(0x17u) /* VT-A4 (W) */ +#define CRTC2_OFF_PITCH BlockIOTag(0x17u) /* LTPro */ +#define CUR_CLR0 IOPortTag(0x0bu, 0x18u) +#define CUR_CLR1 IOPortTag(0x0cu, 0x19u) +/* These are for both CUR_CLR0 and CUR_CLR1 */ +#define CUR_CLR_I 0x000000fful +#define CUR_CLR_B 0x0000ff00ul +#define CUR_CLR_G 0x00ff0000ul +#define CUR_CLR_R 0xff000000ul +#define CUR_CLR (CUR_CLR_R | CUR_CLR_G | CUR_CLR_B) +#define CUR_OFFSET IOPortTag(0x0du, 0x1au) +#define CUR_HORZ_VERT_POSN IOPortTag(0x0eu, 0x1bu) +#define CUR_HORZ_POSN 0x000007fful +/* ? 0x0000f800ul */ +#define CUR_VERT_POSN 0x07ff0000ul +/* ? 0xf8000000ul */ +#define CUR_HORZ_VERT_OFF IOPortTag(0x0fu, 0x1cu) +#define CUR_HORZ_OFF 0x0000007ful +/* ? 0x0000ff80ul */ +#define CUR_VERT_OFF 0x007f0000ul +/* ? 0xff800000ul */ +#define CONFIG_PANEL BlockIOTag(0x1du) /* LT */ +#define PANEL_FORMAT 0x00000007ul +/* ? 0x00000008ul */ +#define PANEL_TYPE 0x000000f0ul +#define NO_OF_GREY 0x00000700ul +#define MOD_GEN 0x00001800ul +#define EXT_LVDS_CLK 0x00001800ul /* LTPro */ +#define BLINK_RATE 0x00006000ul +#define BLINK_RATE_PRO 0x00002000ul /* LTPro */ +#define DONT_SHADOW_HEND 0x00004000ul /* LTPro */ +#define DONT_USE_F32KHZ 0x00008000ul +#define LCD_IO_DRIVE 0x00008000ul /* XC/XL */ +#define FP_POL 0x00010000ul +#define LP_POL 0x00020000ul +#define DTMG_POL 0x00040000ul +#define SCK_POL 0x00080000ul +#define DITHER_SEL 0x00300000ul +#define INVERSE_VIDEO_EN 0x00400000ul +#define BL_CLK_SEL 0x01800000ul +#define BL_LEVEL 0x0e000000ul +#define BL_CLK_SEL_PRO 0x00800000ul /* LTPro */ +#define BL_LEVEL_PRO 0x03000000ul /* LTPro */ +#define BIAS_LEVEL_PRO 0x0c000000ul /* LTPro */ +#define HSYNC_DELAY 0xf0000000ul +#define TV_OUT_INDEX BlockIOTag(0x1du) /* LTPro */ +#define TV_REG_INDEX 0x000000fful +#define TV_ON 0x00000100ul +/* ? 0xfffffe00ul */ +#define GP_IO IOPortTag(0x1eu, 0x1eu) /* VT/GT */ +#define GP_IO_0 0x00000001ul +#define GP_IO_1 0x00000002ul +#define GP_IO_2 0x00000004ul +#define GP_IO_3 0x00000008ul +#define GP_IO_4 0x00000010ul +#define GP_IO_5 0x00000020ul +#define GP_IO_6 0x00000040ul +#define GP_IO_7 0x00000080ul +#define GP_IO_8 0x00000100ul +#define GP_IO_9 0x00000200ul +#define GP_IO_A 0x00000400ul +#define GP_IO_B 0x00000800ul +#define GP_IO_C 0x00001000ul +#define GP_IO_D 0x00002000ul +#define GP_IO_E 0x00004000ul +#define GP_IO_F 0x00008000ul +#define GP_IO_DIR_0 0x00010000ul +#define GP_IO_DIR_1 0x00020000ul +#define GP_IO_DIR_2 0x00040000ul +#define GP_IO_DIR_3 0x00080000ul +#define GP_IO_DIR_4 0x00100000ul +#define GP_IO_DIR_5 0x00200000ul +#define GP_IO_DIR_6 0x00400000ul +#define GP_IO_DIR_7 0x00800000ul +#define GP_IO_DIR_8 0x01000000ul +#define GP_IO_DIR_9 0x02000000ul +#define GP_IO_DIR_A 0x04000000ul +#define GP_IO_DIR_B 0x08000000ul +#define GP_IO_DIR_C 0x10000000ul +#define GP_IO_DIR_D 0x20000000ul +#define GP_IO_DIR_E 0x40000000ul +#define GP_IO_DIR_F 0x80000000ul +#define GP_IO_CNTL BlockIOTag(0x1fu) /* VT/GT */ +#define GP_IO_MODE 0x0000000ful +/* ? 0x7ffffff0ul */ +#define GP_IO_EN 0x80000000ul +#define HW_DEBUG BlockIOTag(0x1fu) /* VTB/GTB/LT */ +#define FAST_SRCCOPY_DIS 0x00000001ul +#define BYPASS_SUBPIC_DBF 0x00000001ul /* XL/XC */ +#define SRC_AUTONA_FIX_DIS 0x00000002ul +#define SYNC_PD_EN 0x00000002ul /* Mobility */ +#define DISP_QW_FIX_DIS 0x00000004ul +#define GUIDST_WB_EXP_DIS 0x00000008ul +#define CYC_ALL_FIX_DIS 0x00000008ul /* GTPro */ +#define AGPPLL_FIX_EN 0x00000008ul /* Mobility */ +#define SRC_AUTONA_ALWAYS_EN 0x00000010ul +#define GUI_BEATS_HOST_P 0x00000010ul /* GTPro */ +#define DRV_CNTL_DQMB_WEB 0x00000020ul +#define FAST_FILL_SCISSOR_DIS 0x00000020ul /* GT2c/VT4 */ +#define INTER_BLIT_FIX_DIS 0x00000020ul /* GTPro */ +#define DRV_CNTL_MA 0x00000040ul +#define AUTO_BLKWRT_COLOR_DIS 0x00000040ul /* GT2c/VT4 */ +#define INTER_PRIM_DIS 0x00000040ul /* GTPro */ +#define DRV_CNTL_MD 0x00000080ul +#define CHG_DEV_ID 0x00000100ul +#define SRC_TRACK_DST_FIX_DIS 0x00000200ul +#define HCLK_FB_SKEW 0x00000380ul /* GT2c/VT4 */ +#define SRC_TRACK_DST_FIX_DIS_P 0x00000080ul /* GTPro */ +#define AUTO_BLKWRT_COLOR_DIS_P 0x00000100ul /* GTPro */ +#define INTER_LINE_OVERLAP_DIS 0x00000200ul /* GTPro */ +#define MEM_OE_PULLBACK 0x00000400ul +#define DBL_BUFFER_EN 0x00000400ul /* GTPro */ +#define MEM_WE_FIX_DIS 0x00000800ul +#define MEM_OE_PULLBACK_B 0x00000800ul /* GT2c/VT4 */ +#define CMDFIFO_SIZE_EN 0x00000800ul /* GTPro */ +#define RD_EN_FIX_DIS 0x00001000ul +#define MEM_WE_FIX_DIS_B 0x00001000ul +#define AUTO_FF_DIS 0x00001000ul /* GTPro */ +#define CMDFIFO_SIZE_DIS 0x00002000ul /* GT2c/VT4 */ +#define AUTO_BLKWRT_DIS 0x00002000ul /* GTPro */ +#define GUI_BEATS_HOST 0x00004000ul /* GT2c/VT4 */ +#define ORED_INVLD_RB_CACHE 0x00004000ul /* GTPro */ +#define BLOCK_DBL_BUF 0x00008000ul /* GTPro */ +#define R2W_TURNAROUND_DELAY 0x00020000ul /* GT2c/VT4 */ +#define ENA_32BIT_DATA_BUS 0x00040000ul /* GT2c/VT4 */ +#define HCLK_FB_SKEW_P 0x00070000ul /* GTPro */ +#define ENA_FLASH_ROM 0x00080000ul /* GT2c/VT4 */ +#define DISABLE_SWITCH_FIX 0x00080000ul /* GTPro */ +#define MCLK_START_EN 0x00080000ul /* LTPro */ +#define SEL_VBLANK_BDL_BUF 0x00100000ul /* GTPro */ +#define CMDFIFO_64EN 0x00200000ul /* GTPro */ +#define BM_FIX_DIS 0x00400000ul /* GTPro */ +#define Z_SWITCH_EN 0x00800000ul /* LTPro */ +#define FLUSH_HOST_WB 0x01000000ul /* GTPro */ +#define HW_DEBUG_WRITE_MSK_FIX_DIS 0x02000000ul /* LTPro */ +#define Z_NO_WRITE_EN 0x04000000ul /* LTPro */ +#define DISABLE_PCLK_RESET_P 0x08000000ul /* LTPro */ +#define PM_D3_SUPPORT_ENABLE_P 0x10000000ul /* LTPro */ +#define STARTCYCLE_FIX_ENABLE 0x20000000ul /* LTPro */ +#define DONT_RST_CHAREN 0x20000000ul /* XL/XC */ +#define C3_FIX_ENABLE 0x40000000ul /* LTPro */ +#define BM_HOSTRA_EN 0x40000000ul /* XL/XC */ +#define PKGBGAb 0x80000000ul /* XL/XC */ +#define AUTOEXP_HORZ_FIX 0x80000000ul /* Mobility */ +#define SCRATCH_REG0 IOPortTag(0x10u, 0x20u) +#define SCRATCH_REG1 IOPortTag(0x11u, 0x21u) +/* BIOS_BASE_SEGMENT 0x0000007ful */ /* As above */ +/* ? 0x00000f80ul */ +#define BIOS_INIT_DAC_SUBTYPE 0x0000f000ul +/* ? 0xffff0000ul */ +#define SCRATCH_REG2 BlockIOTag(0x22u) /* LT */ +#define SCRATCH_REG3 BlockIOTag(0x23u) /* GTPro */ +/* Not described here 0x07fffffful */ +#define DISPLAY_SWITCH_DISABLE 0x08000000ul +/* Not described here 0xf0000000ul */ +#define CLOCK_CNTL IOPortTag(0x12u, 0x24u) +#define CLOCK_BIT 0x00000004ul /* For ICS2595 */ +#define CLOCK_PULSE 0x00000008ul /* For ICS2595 */ +#define CLOCK_SELECT 0x0000000ful +#define CLOCK_DIVIDER 0x00000030ul +#define CLOCK_STROBE 0x00000040ul +#define CLOCK_DATA 0x00000080ul +/* ? 0x00000100ul */ +#define PLL_WR_EN 0x00000200ul /* For internal PLL */ +#define PLL_ADDR 0x0000fc00ul /* For internal PLL */ +#define PLL_DATA 0x00ff0000ul /* For internal PLL */ +/* ? 0xff000000ul */ +#define CONFIG_STAT64_1 BlockIOTag(0x25u) /* GTPro */ +#define CFG_SUBSYS_DEV_ID 0x000000fful +#define CFG_SUBSYS_VEN_ID 0x00ffff00ul +/* ? 0x1f000000ul */ +#define CFG_DIMM_TYPE 0xe0000000ul +#define CFG_PCI_SUBSYS_DEV_ID 0x0000fffful /* XC/XL */ +#define CFG_PCI_SUBSYS_VEN_ID 0xffff0000ul /* XC/XL */ +#define CONFIG_STAT64_2 BlockIOTag(0x26u) /* GTPro */ +#define CFG_DIMM_TYPE_3 0x00000001ul +/* ? 0x0000001eul */ +#define CFG_ROMWRTEN 0x00000020ul +#define CFG_AGPVCOGAIN 0x000000c0ul +#define CFG_PCI_TYPE 0x00000100ul +#define CFG_AGPSKEW 0x00000e00ul +#define CFG_X1CLKSKEW 0x00007000ul +#define CFG_PANEL_ID_P 0x000f8000ul /* LTPro */ +/* ? 0x00100000ul */ +#define CFG_PREFETCH_EN 0x00200000ul +#define CFG_ID_DISABLE 0x00400000ul +#define CFG_PRE_TESTEN 0x00800000ul +/* ? 0x01000000ul */ +#define CFG_PCI5VEN 0x02000000ul /* LTPro */ +#define CFG_VGA_DISABLE 0x04000000ul +#define CFG_ENINTB 0x08000000ul +/* ? 0x10000000ul */ +#define CFG_ROM_REMAP_2 0x20000000ul +#define CFG_IDSEL 0x40000000ul +/* ? 0x80000000ul */ +#define TV_OUT_DATA BlockIOTag(0x27u) /* LTPro */ +#define BUS_CNTL IOPortTag(0x13u, 0x28u) +#define BUS_WS 0x0000000ful +#define BUS_DBL_RESYNC 0x00000001ul /* VTB/GTB/LT */ +#define BUS_MSTR_RESET 0x00000002ul /* VTB/GTB/LT */ +#define BUS_FLUSH_BUF 0x00000004ul /* VTB/GTB/LT */ +#define BUS_STOP_REQ_DIS 0x00000008ul /* VTB/GTB/LT */ +#define BUS_ROM_WS 0x000000f0ul +#define BUS_APER_REG_DIS 0x00000010ul /* VTB/GTB/LT */ +#define BUS_EXTRA_PIPE_DIS 0x00000020ul /* VTB/GTB/LT */ +#define BUS_MASTER_DIS 0x00000040ul /* VTB/GTB/LT */ +#define BUS_ROM_WRT_EN 0x00000080ul /* GTPro */ +#define BUS_ROM_PAGE 0x00000f00ul +#define BUS_MINOR_REV_ID 0x00000700ul /* LTPro */ +/* First silicom - Prototype (A11) 0x00000000ul */ +/* Metal mask spin (A12 & A13) 0x00000100ul */ +/* All layer spin (A21) 0x00000200ul */ +/* Fast metal spin (A22) - Prod. 0x00000300ul */ +/* All layer spin (A31) 0x00000700ul */ +/* ? 0x00000800ul */ /* LTPro */ +#define BUS_CHIP_HIDDEN_REV 0x00000300ul /* XC/XL */ +/* ? 0x00001c00ul */ /* XC/XL */ +#define BUS_ROM_DIS 0x00001000ul +#define BUS_IO_16_EN 0x00002000ul /* GX */ +#define BUS_PCI_READ_RETRY_EN 0x00002000ul /* VTB/GTB/LT */ +#define BUS_DAC_SNOOP_EN 0x00004000ul +#define BUS_PCI_RETRY_EN 0x00008000ul /* VT/GT */ +#define BUS_PCI_WRT_RETRY_EN 0x00008000ul /* VTB/GTB/LT */ +#define BUS_FIFO_WS 0x000f0000ul +#define BUS_RETRY_WS 0x000f0000ul /* VTB/GTB/LT */ +#define BUS_FIFO_ERR_INT_EN 0x00100000ul +#define BUS_MSTR_RD_MULT 0x00100000ul /* VTB/GTB/LT */ +#define BUS_FIFO_ERR_INT 0x00200000ul +#define BUS_MSTR_RD_LINE 0x00200000ul /* VTB/GTB/LT */ +#define BUS_HOST_ERR_INT_EN 0x00400000ul +#define BUS_SUSPEND 0x00400000ul /* GTPro */ +#define BUS_HOST_ERR_INT 0x00800000ul +#define BUS_LAT16X 0x00800000ul /* GTPro */ +#define BUS_PCI_DAC_WS 0x07000000ul +#define BUS_RD_DISCARD_EN 0x01000000ul /* VTB/GTB/LT */ +#define BUS_RD_ABORT_EN 0x02000000ul /* VTB/GTB/LT */ +#define BUS_MSTR_WS 0x04000000ul /* VTB/GTB/LT */ +#define BUS_PCI_DAC_DLY 0x08000000ul +#define BUS_EXT_REG_EN 0x08000000ul /* VT/GT */ +#define BUS_PCI_MEMW_WS 0x10000000ul +#define BUS_MSTR_DISCONNECT_EN 0x10000000ul /* VTB/GTB/LT */ +#define BUS_PCI_BURST_DEC 0x20000000ul /* GX/CX */ +#define BUS_BURST 0x20000000ul /* 264xT */ +#define BUS_WRT_BURST 0x20000000ul /* VTB/GTB/LT */ +#define BUS_RDY_READ_DLY 0xc0000000ul +#define BUS_READ_BURST 0x40000000ul /* VTB/GTB/LT */ +#define BUS_RDY_READ_DLY_B 0x80000000ul /* VTB/GTB/LT */ +#define LCD_INDEX BlockIOTag(0x29u) /* LTPro */ +#define LCD_REG_INDEX 0x0000003ful +/* ? 0x000000c0ul */ +#define LCD_DISPLAY_DIS 0x00000100ul +#define LCD_SRC_SEL 0x00000200ul +#define LCD_SRC_SEL_CRTC1 0x00000000ul +#define LCD_SRC_SEL_CRTC2 0x00000200ul +#define LCD_CRTC2_DISPLAY_DIS 0x00000400ul +#define LCD_GUI_ACTIVE 0x00000800ul /* XC/XL */ +/* ? 0x00fff000ul */ +#define LCD_MONDET_SENSE 0x01000000ul /* XC/XL */ +#define LCD_MONDET_INT_POL 0x02000000ul /* XC/XL */ +#define LCD_MONDET_INT_EN 0x04000000ul /* XC/XL */ +#define LCD_MONDET_INT 0x08000000ul /* XC/XL */ +#define LCD_MONDET_EN 0x10000000ul /* XC/XL */ +#define LCD_EN_PL 0x20000000ul /* XC/XL */ +/* ? 0xc0000000ul */ +#define HFB_PITCH_ADDR BlockIOTag(0x2au) /* LT */ +#define LCD_DATA BlockIOTag(0x2au) /* LTPro */ +#define EXT_MEM_CNTL BlockIOTag(0x2bu) /* VTB/GTB/LT */ +#define MEM_CNTL IOPortTag(0x14u, 0x2cu) +#define CTL_MEM_SIZE 0x00000007ul +/* ? 0x00000008ul */ +#define CTL_MEM_REFRESH 0x00000078ul /* VT/GT */ +#define CTL_MEM_SIZEB 0x0000000ful /* VTB/GTB/LT */ +#define CTL_MEM_RD_LATCH_EN 0x00000010ul +#define CTL_MEM_RD_LATCH_DLY 0x00000020ul +#define CTL_MEM_LATENCY 0x00000030ul /* VTB/GTB/LT */ +#define CTL_MEM_SD_LATCH_EN 0x00000040ul +#define CTL_MEM_SD_LATCH_DLY 0x00000080ul +#define CTL_MEM_LATCH 0x000000c0ul /* VTB/GTB/LT */ +#define CTL_MEM_WDOE_CNTL 0x000000c0ul /* XC/XL */ +#define CTL_MEM_FULL_PLS 0x00000100ul +#define CTL_MEM_CYC_LNTH_AUX 0x00000180ul /* VT/GT */ +#define CTL_MEM_TRP 0x00000300ul /* VTB/GTB/LT */ +#define CTL_MEM_CYC_LNTH 0x00000600ul +#define CTL_MEM_REFRESH_RATE 0x00001800ul /* 264xT */ +#define CTL_MEM_TRCD 0x00000c00ul /* VTB/GTB/LT */ +#define CTL_MEM_WR_RDY_SEL 0x00000800ul /* GX/CX */ +#define CTL_MEM_EXT_RMW_CYC_EN 0x00001000ul /* GX/CX */ +#define CTL_MEM_TCRD 0x00001000ul /* VTB/GTB/LT */ +#define CTL_MEM_DLL_RESET 0x00002000ul /* VT/GT */ +#define CTL_MEM_TR2W 0x00002000ul /* GTPro */ +#define CTL_MEM_ACTV_PRE 0x0000c000ul /* VT/GT */ +#define CTL_MEM_CAS_PHASE 0x00004000ul /* GTPro */ +#define CTL_MEM_OE_PULLBACK 0x00008000ul /* GTPro */ +#define CTL_MEM_TWR 0x0000c000ul /* XC/XL */ +#define CTL_MEM_BNDRY 0x00030000ul +#define CTL_MEM_BNDRY_0K 0x00000000ul +#define CTL_MEM_BNDRY_256K 0x00010000ul +#define CTL_MEM_BNDRY_512K 0x00020000ul +#define CTL_MEM_BNDRY_1024K 0x00030000ul +#define CTL_MEM_DLL_GAIN_CNTL 0x00030000ul /* VT/GT */ +#define CTL_MEM_BNDRY_EN 0x00040000ul +#define CTL_MEM_SDRAM_RESET 0x00040000ul /* VT/GT */ +#define CTL_MEM_TRAS 0x00070000ul /* VTB/GTB/LT */ +#define CTL_MEM_TILE_SELECT 0x00180000ul /* VT/GT */ +#define CTL_MEM_REFRESH_DIS 0x00080000ul /* VTB/GTB/LT */ +#define CTL_MEM_LOW_LATENCY_MODE 0x00200000ul /* VT/GT */ +#define CTL_MEM_CDE_PULLBACK 0x00400000ul /* VT/GT */ +#define CTL_MEM_REFRESH_RATE_B 0x00f00000ul /* VTB/GTB/LT */ +#define CTL_MEM_PIX_WIDTH 0x07000000ul +#define CTL_MEM_LOWER_APER_ENDIAN 0x03000000ul /* VTB/GTB/LT */ +#define CTL_MEM_OE_SELECT 0x18000000ul /* VT/GT */ +#define CTL_MEM_UPPER_APER_ENDIAN 0x0c000000ul /* VTB/GTB/LT */ +/* ? 0xe0000000ul */ +#define CTL_MEM_PAGE_SIZE 0x30000000ul /* VTB/GTB/LT */ +#define MEM_VGA_WP_SEL IOPortTag(0x15u, 0x2du) +#define MEM_VGA_WPS0 0x0000fffful +#define MEM_VGA_WPS1 0xffff0000ul +#define MEM_VGA_RP_SEL IOPortTag(0x16u, 0x2eu) +#define MEM_VGA_RPS0 0x0000fffful +#define MEM_VGA_RPS1 0xffff0000ul +#define LT_GIO BlockIOTag(0x2fu) /* LT */ +#define I2C_CNTL_1 BlockIOTag(0x2fu) /* GTPro */ +#define I2C_DATA_PORT 0x000000fful +#define I2C_DATA_COUNT 0x0000ff00ul +#define I2C_ADDR_COUNT 0x00070000ul +/* ? 0x00380000ul */ +#define I2C_SEL 0x00400000ul +/* ? 0x00800000ul */ +#define I2C_TIME_LIMIT 0xff000000ul +#define DAC_REGS IOPortTag(0x17u, 0x30u) /* 4 separate bytes */ +#define M64_DAC_WRITE (DAC_REGS + 0) +#define M64_DAC_DATA (DAC_REGS + 1) +#define M64_DAC_MASK (DAC_REGS + 2) +#define M64_DAC_READ (DAC_REGS + 3) +#define DAC_CNTL IOPortTag(0x18u, 0x31u) +#define DAC_EXT_SEL 0x00000003ul +#define DAC_EXT_SEL_RS2 0x000000001ul +#define DAC_EXT_SEL_RS3 0x000000002ul +#define DAC_RANGE_CTL 0x00000003ul /* VTB/GTB/LT */ +#define DAC_BLANKING 0x00000004ul /* 264xT */ +#define DAC_CMP_DIS 0x00000008ul /* 264xT */ +#define DAC1_CLK_SEL 0x00000010ul /* LTPro */ +#define DAC_PALETTE_ACCESS_CNTL 0x00000020ul /* LTPro */ +#define DAC_PALETTE2_SNOOP_EN 0x00000040ul /* LTPro */ +#define DAC_CMP_OUTPUT 0x00000080ul /* 264xT */ +#define DAC_8BIT_EN 0x00000100ul +#define DAC_PIX_DLY 0x00000600ul +#define DAC_DIRECT 0x00000400ul /* VTB/GTB/LT */ +#define DAC_BLANK_ADJ 0x00001800ul +#define DAC_PAL_CLK_SEL 0x00000800ul /* VTB/GTB/LT */ +#define DAC_CRT_SENSE 0x00000800ul /* XC/XL */ +#define DAC_CRT_DETECTION_ON 0x00001000ul /* XC/XL */ +#define DAC_VGA_ADR_EN 0x00002000ul +#define DAC_FEA_CON_EN 0x00004000ul /* 264xT */ +#define DAC_PDMN 0x00008000ul /* 264xT */ +#define DAC_TYPE 0x00070000ul +/* ? 0x00f80000ul */ +#define DAC_MON_ID_STATE0 0x01000000ul /* GX-E+/CX */ +#define DAC_GIO_STATE_1 0x01000000ul /* 264xT */ +#define DAC_MON_ID_STATE1 0x02000000ul /* GX-E+/CX */ +#define DAC_GIO_STATE_0 0x02000000ul /* 264xT */ +#define DAC_MON_ID_STATE2 0x04000000ul /* GX-E+/CX */ +#define DAC_GIO_STATE_4 0x04000000ul /* 264xT */ +#define DAC_MON_ID_DIR0 0x08000000ul /* GX-E+/CX */ +#define DAC_GIO_DIR_1 0x08000000ul /* 264xT */ +#define DAC_MON_ID_DIR1 0x10000000ul /* GX-E+/CX */ +#define DAC_GIO_DIR_0 0x10000000ul /* 264xT */ +#define DAC_MON_ID_DIR2 0x20000000ul /* GX-E+/CX */ +#define DAC_GIO_DIR_4 0x20000000ul /* 264xT */ +#define DAC_MAN_CMP_STATE 0x40000000ul /* GX-E+ */ +#define DAC_RW_WS 0x80000000ul /* VT/GT */ +#define HORZ_STRETCHING BlockIOTag(0x32u) /* LT */ +#define HORZ_STRETCH_BLEND 0x00000ffful +#define HORZ_STRETCH_RATIO 0x0000fffful +#define HORZ_STRETCH_LOOP 0x00070000ul +#define HORZ_STRETCH_LOOP09 0x00000000ul +#define HORZ_STRETCH_LOOP11 0x00010000ul +#define HORZ_STRETCH_LOOP12 0x00020000ul +#define HORZ_STRETCH_LOOP14 0x00030000ul +#define HORZ_STRETCH_LOOP15 0x00040000ul +/* ? 0x00050000ul */ +/* ? 0x00060000ul */ +/* ? 0x00070000ul */ +/* ? 0x00080000ul */ +#define HORZ_PANEL_SIZE 0x0ff00000ul /* XC/XL */ +/* ? 0x10000000ul */ +#define AUTO_HORZ_RATIO 0x20000000ul /* XC/XL */ +#define HORZ_STRETCH_MODE 0x40000000ul +#define HORZ_STRETCH_EN 0x80000000ul +#define EXT_DAC_REGS BlockIOTag(0x32u) /* GTPro */ +#define EXT_DAC_REG_SEL 0x0000000ful +/* ? 0x000000f0ul */ +#define EXT_DAC_DATA 0x0000ff00ul +#define EXT_DAC_EN 0x00010000ul +#define EXT_DAC_WID 0x00020000ul +/* ? 0xfffc0000ul */ +#define VERT_STRETCHING BlockIOTag(0x33u) /* LT */ +#define VERT_STRETCH_RATIO0 0x000003fful +#define VERT_STRETCH_RATIO1 0x000ffc00ul +#define VERT_STRETCH_RATIO2 0x3ff00000ul +#define VERT_STRETCH_USE0 0x40000000ul +#define VERT_STRETCH_EN 0x80000000ul +#define GEN_TEST_CNTL IOPortTag(0x19u, 0x34u) +#define GEN_EE_DATA_OUT 0x00000001ul /* GX/CX */ +#define GEN_GIO2_DATA_OUT 0x00000001ul /* 264xT */ +#define GEN_EE_CLOCK 0x00000002ul /* GX/CX */ +/* ? 0x00000002ul */ /* 264xT */ +#define GEN_EE_CHIP_SEL 0x00000004ul /* GX/CX */ +#define GEN_GIO3_DATA_OUT 0x00000004ul /* 264xT */ +#define GEN_EE_DATA_IN 0x00000008ul /* GX/CX */ +#define GEN_GIO2_DATA_IN 0x00000008ul /* 264xT */ +#define GEN_EE_EN 0x00000010ul /* GX/CX */ +#define GEN_GIO2_ENABLE 0x00000010ul /* 264xT */ +#define GEN_ICON2_ENABLE 0x00000010ul /* XC/XL */ +#define GEN_OVR_OUTPUT_EN 0x00000020ul /* GX/CX */ +#define GEN_GIO2_WRITE 0x00000020ul /* 264xT */ +#define GEN_CUR2_ENABLE 0x00000020ul /* XC/XL */ +#define GEN_OVR_POLARITY 0x00000040ul /* GX/CX */ +#define GEN_ICON_ENABLE 0x00000040ul /* XC/XL */ +#define GEN_CUR_EN 0x00000080ul +#define GEN_GUI_EN 0x00000100ul /* GX/CX */ +#define GEN_GUI_RESETB 0x00000100ul /* 264xT */ +#define GEN_BLOCK_WR_EN 0x00000200ul /* GX */ +/* ? 0x00000200ul */ /* CX/264xT */ +#define GEN_SOFT_RESET 0x00000200ul /* VTB/GTB/LT */ +#define GEN_MEM_TRISTATE 0x00000400ul /* GTPro */ +/* ? 0x00000800ul */ +#define GEN_TEST_VECT_MODE 0x00003000ul /* VT/GT */ +/* ? 0x0000c000ul */ +#define GEN_TEST_FIFO_EN 0x00010000ul /* GX/CX */ +#define GEN_TEST_GUI_REGS_EN 0x00020000ul /* GX/CX */ +#define GEN_TEST_VECT_EN 0x00040000ul /* GX/CX */ +#define GEN_TEST_CRC_STR 0x00080000ul /* GX-C/-D */ +/* ? 0x00080000ul */ /* GX-E+/CX */ +#define GEN_TEST_MODE_T 0x000f0000ul /* 264xT */ +#define GEN_TEST_MODE 0x00700000ul /* GX/CX */ +#define GEN_TEST_CNT_EN 0x00100000ul /* 264xT */ +#define GEN_TEST_CRC_EN 0x00200000ul /* 264xT */ +/* ? 0x00400000ul */ /* 264xT */ +/* ? 0x00800000ul */ +#define GEN_TEST_MEM_WR 0x01000000ul /* GX-C/-D */ +#define GEN_TEST_MEM_STROBE 0x02000000ul /* GX-C/-D */ +#define GEN_TEST_DST_SS_EN 0x04000000ul /* GX/CX */ +#define GEN_TEST_DST_SS_STROBE 0x08000000ul /* GX/CX */ +#define GEN_TEST_SRC_SS_EN 0x10000000ul /* GX/CX */ +#define GEN_TEST_SRC_SS_STROBE 0x20000000ul /* GX/CX */ +#define GEN_TEST_CNT_VALUE 0x3f000000ul /* 264xT */ +#define GEN_TEST_CC_EN 0x40000000ul /* GX/CX */ +#define GEN_TEST_CC_STROBE 0x80000000ul /* GX/CX */ +/* ? 0xc0000000ul */ /* 264xT */ +#define GEN_DEBUG_MODE 0xff000000ul /* VTB/GTB/LT */ +#define LCD_GEN_CTRL BlockIOTag(0x35u) /* LT */ +#define CRT_ON 0x00000001ul +#define LCD_ON 0x00000002ul +#define HORZ_DIVBY2_EN 0x00000004ul +#define TRISTATE_MEM_EN 0x00000008ul +#define DONT_DS_ICON 0x00000008ul /* LTPro */ +#define LOCK_8DOT 0x00000010ul +#define ICON_ENABLE 0x00000020ul +#define DONT_SHADOW_VPAR 0x00000040ul +#define TOGGLE_EN 0x00000080ul +#define V2CLK_PM_EN 0x00000080ul /* LTPro */ +#define RST_FM 0x00000100ul +#define DISABLE_PCLK_RESET 0x00000200ul /* XC/XL */ +#define DIS_HOR_CRT_DIVBY2 0x00000400ul +#define SCLK_SEL 0x00000800ul +#define SCLK_DELAY 0x0000f000ul +#define MCLK_PM_EN 0x00010000ul +#define TVCLK_PM_EN 0x00010000ul /* LTPro */ +#define VCLK_DAC_PM_EN 0x00020000ul +#define VCLK_LCD_OFF 0x00040000ul +#define SLOWDOWN_XMCLK 0x00080000ul +#define SELECT_WAIT_4MS 0x00080000ul /* LTPro */ +#define XTALIN_PM_EN 0x00080000ul /* XC/XL */ +#define LCD_CLK_RATIO 0x00100000ul +#define V2CLK_DAC_PM_EN 0x00100000ul /* LTPro */ +#define LVDS_EN 0x00200000ul +#define LVDS_PLL_EN 0x00400000ul +#define LVDS_PLL_RESET 0x00800000ul +#define LVDS_RESERVED_BITS 0x07000000ul +#define CRTC_RW_SELECT 0x08000000ul /* LTPro */ +#define USE_SHADOWED_VEND 0x10000000ul +#define USE_SHADOWED_ROWCUR 0x20000000ul +#define SHADOW_EN 0x40000000ul +#define SHADOW_RW_EN 0x80000000ul +#define CUSTOM_MACRO_CNTL BlockIOTag(0x35u) /* GTPro */ +#define POWER_MANAGEMENT BlockIOTag(0x36u) /* LT */ +#define PWR_MGT_ON 0x00000001ul +#define PWR_MGT_MODE 0x00000006ul +#define AUTO_PWRUP_EN 0x00000008ul +#define ACTIVITY_PIN_ON 0x00000010ul +#define STANDBY_POL 0x00000020ul +#define SUSPEND_POL 0x00000040ul +#define SELF_REFRESH 0x00000080ul +#define ACTIVITY_PIN_EN 0x00000100ul +#define KEYBD_SNOOP 0x00000200ul +#define USE_F32KHZ 0x00000400ul /* LTPro */ +#define DONT_USE_XTALIN 0x00000400ul /* XC/XL */ +#define TRISTATE_MEM_EN_P 0x00000800ul /* LTPro */ +#define LCDENG_TEST_MODE 0x0000f000ul +#define STANDBY_COUNT 0x000f0000ul +#define SUSPEND_COUNT 0x00f00000ul +#define BAISON 0x01000000ul +#define BLON 0x02000000ul +#define DIGON 0x04000000ul +#define PM_D3_SUPPORT_ENABLE 0x08000000ul /* XC/XL */ +#define STANDBY_NOW 0x10000000ul +#define SUSPEND_NOW 0x20000000ul +#define PWR_MGT_STATUS 0xc0000000ul +#define CONFIG_CNTL IOPortTag(0x1au, 0x37u) +#define CFG_MEM_AP_SIZE 0x00000003ul +#define CFG_MEM_VGA_AP_EN 0x00000004ul +/* ? 0x00000008ul */ +#define CFG_MEM_AP_LOC 0x00003ff0ul +/* ? 0x0000c000ul */ +#define CFG_CARD_ID 0x00070000ul +#define CFG_VGA_DIS 0x00080000ul +/* ? 0x00f00000ul */ +#define CFG_CDE_WINDOW 0x3f000000ul /* VT/GT */ +/* ? 0xc0000000ul */ +#define CONFIG_CHIP_ID IOPortTag(0x1bu, 0x38u) /* Read */ +#define CFG_CHIP_TYPE0 0x000000fful +#define CFG_CHIP_TYPE1 0x0000ff00ul +#define CFG_CHIP_TYPE 0x0000fffful +#define CFG_CHIP_CLASS 0x00ff0000ul +#define CFG_CHIP_REV 0xff000000ul +#define CFG_CHIP_VERSION 0x07000000ul /* 264xT */ +#define CFG_CHIP_FOUNDRY 0x38000000ul /* 264xT */ +#define CFG_CHIP_REVISION 0xc0000000ul /* 264xT */ +#define CONFIG_STATUS64_0 IOPortTag(0x1cu, 0x39u) /* Read (R/W (264xT)) */ +#define CFG_BUS_TYPE 0x00000007ul /* GX/CX */ +#define CFG_MEM_TYPE_T 0x00000007ul /* 264xT */ +#define CFG_MEM_TYPE 0x00000038ul /* GX/CX */ +#define CFG_DUAL_CAS_EN_T 0x00000008ul /* 264xT */ +#define CFG_ROM_128K_EN 0x00000008ul /* VTB/GTB/LT */ +#define CFG_ROM_REMAP 0x00000008ul /* GTPro */ +#define CFG_VGA_EN_T 0x00000010ul /* VT/GT */ +#define CFG_CLOCK_EN 0x00000020ul /* 264xT */ +#define CFG_DUAL_CAS_EN 0x00000040ul /* GX/CX */ +#define CFG_VMC_SENSE 0x00000040ul /* VT/GT */ +#define CFG_SHARED_MEM_EN 0x00000040ul /* VTB/GTB/LT */ +#define CFG_LOCAL_BUS_OPTION 0x00000180ul /* GX/CX */ +#define CFG_VFC_SENSE 0x00000080ul /* VT/GT */ +#define CFG_INIT_DAC_TYPE 0x00000e00ul /* GX/CX */ +#define CFG_INIT_CARD_ID 0x00007000ul /* GX-C/-D */ +#define CFG_BLK_WR_SIZE 0x00001000ul /* GX-E+ */ +#define CFG_INT_QSF_EN 0x00002000ul /* GX-E+ */ +/* ? 0x00004000ul */ /* GX-E+ */ +/* ? 0x00007000ul */ /* CX */ +#define CFG_TRI_BUF_DIS 0x00008000ul /* GX/CX */ +#define CFG_BOARD_ID 0x0000ff00ul /* VT/GT */ +#define CFG_EXT_RAM_ADDR 0x003f0000ul /* GX/CX */ +#define CFG_PANEL_ID 0x001f0000ul /* LT */ +#define CFG_MACROVISION_EN 0x00200000ul /* GTPro */ +#define CFG_ROM_DIS 0x00400000ul /* GX/CX */ +#define CFG_PCI33EN 0x00400000ul /* GTPro */ +#define CFG_VGA_EN 0x00800000ul /* GX/CX */ +#define CFG_FULLAGP 0x00800000ul /* GTPro */ +#define CFG_ARITHMOS_ENABLE 0x00800000ul /* XC/XL */ +#define CFG_LOCAL_BUS_CFG 0x01000000ul /* GX/CX */ +#define CFG_CHIP_EN 0x02000000ul /* GX/CX */ +#define CFG_LOCAL_READ_DLY_DIS 0x04000000ul /* GX/CX */ +#define CFG_ROM_OPTION 0x08000000ul /* GX/CX */ +#define CFG_BUS_OPTION 0x10000000ul /* GX/CX */ +#define CFG_LOCAL_DAC_WR_EN 0x20000000ul /* GX/CX */ +#define CFG_VLB_RDY_DIS 0x40000000ul /* GX/CX */ +#define CFG_AP_4GBYTE_DIS 0x80000000ul /* GX/CX */ +#define CONFIG_STATUS64_1 IOPortTag(0x1du, 0x3au) /* Read */ +#define CFG_PCI_DAC_CFG 0x00000001ul /* GX/CX */ +/* ? 0x0000001eul */ /* GX/CX */ +#define CFG_1C8_IO_SEL 0x00000020ul /* GX/CX */ +/* ? 0xffffffc0ul */ /* GX/CX */ +#define CRC_SIG 0xfffffffful /* 264xT */ +#define MPP_CONFIG BlockIOTag(0x3bu) /* VTB/GTB/LT */ +#define MPP_PRESCALE 0x00000007ul +/* ? 0x00000008ul */ +#define MPP_NSTATES 0x00000030ul +/* ? 0x00000000ul */ +#define MPP_NSTATES_2 0x00000010ul +#define MPP_NSTATES_4 0x00000020ul +#define MPP_NSTATES_8 0x00000030ul +#define MPP_FORMAT 0x000000c0ul +#define MPP_FORMAT_DO8 0x00000000ul +#define MPP_FORMAT_DO16 0x00000040ul +#define MPP_FORMAT_DA8 0x00000080ul +#define MPP_FORMAT_DA16 0x000000c0ul +#define MPP_WAIT_STATE 0x00000700ul +#define MPP_CHKRDY_EN 0x00000800ul +#define MPP_INSERT_WAIT 0x00001000ul +#define MPP_TRISTATE_ADDR 0x00002000ul +/* ? 0x00004000ul */ +#define MPP_READ_EARLY 0x00008000ul +#define MPP_RW_MODE 0x00030000ul +#define MPP_INT_MASK 0x000c0000ul +#define MPP_AUTO_INC_EN 0x00300000ul +#define MPP_CHKREQ_EN 0x00400000ul +#define MPP_CHKREQ_MODE 0x00800000ul +#define MPP_BUFFER_SIZE 0x03000000ul +#define MPP_BUFFER_MODE 0x0c000000ul +#define MPP_BUFFER_MODE_NORMAL 0x00000000ul +#define MPP_BUFFER_MODE_PREFETCH 0x04000000ul +#define MPP_BUFFER_MODE_BUS_MASTER 0x08000000ul +/* ? 0x0c000000ul */ +/* ? 0x30000000ul */ +#define MPP_BUSY 0x40000000ul +#define MPP_EN 0x80000000ul +#define MPP_STROBE_SEQ BlockIOTag(0x3cu) /* VTB/GTB/LT */ +#define MPP_STB0_SEQ 0x000000fful +#define MPP_STB1_SEQ 0x0000ff00ul +/* ? 0xffff0000ul */ +#define MPP_ADDR BlockIOTag(0x3du) /* VTB/GTB/LT */ +#define MPP_DATA BlockIOTag(0x3eu) /* VTB/GTB/LT */ +#define TVO_CNTL BlockIOTag(0x3fu) /* VTB/GTB/LT */ +#define TVO_H_TOT_PIX 0x00000007ul +#define TVO_PC_OVR_DIS 0x00000008ul +#define TVO_H_TOT_EDGE 0x00000010ul +/* ? 0x00000060ul */ +#define TVO_VBLANK_ONLY 0x00000080ul +/* ? 0x0000ff00ul */ +#define TVO_MPEG_CLR_SRC 0x00030000ul +/* ? 0x1ffc0000ul */ +#define TVO_MPEG_CLK_EN 0x20000000ul +#define TVO_OVERRIDE_EN 0x40000000ul +#define TVO_EN 0x80000000ul +/* GP_IO IOPortTag(0x1eu, 0x1eu) */ /* See above */ +/* CRTC_H_TOTAL_DISP IOPortTag(0x1fu, 0x00u) */ /* Duplicate */ +#define DST_OFF_PITCH BlockIOTag(0x40u) +#define DST_OFFSET 0x000ffffful +/* ? 0x00300000ul */ +#define DST_PITCH 0xffc00000ul +#define DST_X BlockIOTag(0x41u) +#define DST_Y BlockIOTag(0x42u) +#define DST_Y_X BlockIOTag(0x43u) +#define DST_WIDTH BlockIOTag(0x44u) +#define DST_HEIGHT BlockIOTag(0x45u) +#define DST_HEIGHT_WIDTH BlockIOTag(0x46u) +#define DST_X_WIDTH BlockIOTag(0x47u) +#define DST_BRES_LNTH BlockIOTag(0x48u) +#define DST_BRES_ERR BlockIOTag(0x49u) +#define DST_BRES_INC BlockIOTag(0x4au) +#define DST_BRES_DEC BlockIOTag(0x4bu) +#define DST_CNTL BlockIOTag(0x4cu) +#define DST_X_DIR 0x00000001ul +#define DST_Y_DIR 0x00000002ul +#define DST_Y_MAJOR 0x00000004ul +#define DST_X_TILE 0x00000008ul +#define DST_Y_TILE 0x00000010ul +#define DST_LAST_PEL 0x00000020ul +#define DST_POLYGON_EN 0x00000040ul +#define DST_24_ROT_EN 0x00000080ul +#define DST_24_ROT 0x00000700ul +#define DST_BRES_SIGN 0x00000800ul /* GX/CX */ +#define DST_BRES_ZERO 0x00000800ul /* CT */ +#define DST_POLYGON_RTEDGE_DIS 0x00001000ul /* CT */ +#define TRAIL_X_DIR 0x00002000ul /* GT */ +#define TRAP_FILL_DIR 0x00004000ul /* GT */ +#define TRAIL_BRES_SIGN 0x00008000ul /* GT */ +/* ? 0x00010000ul */ +#define BRES_SIGN_AUTO 0x00020000ul /* GT */ +/* ? 0x00040000ul */ +#define ALPHA_OVERLAP_ENB 0x00080000ul /* GTPro */ +#define SUB_PIX_ON 0x00100000ul /* GTPro */ +/* ? 0xffe00000ul */ +/* DST_Y_X BlockIOTag(0x4du) */ /* Duplicate */ +#define TRAIL_BRES_ERR BlockIOTag(0x4eu) /* GT */ +#define TRAIL_BRES_INC BlockIOTag(0x4fu) /* GT */ +#define TRAIL_BRES_DEC BlockIOTag(0x50u) /* GT */ +#define LEAD_BRES_LNTH BlockIOTag(0x51u) /* GT */ +#define Z_OFF_PITCH BlockIOTag(0x52u) /* GT */ +#define Z_CNTL BlockIOTag(0x53u) /* GT */ +#define ALPHA_TST_CNTL BlockIOTag(0x54u) /* GTPro */ +/* ? BlockIOTag(0x55u) */ +#define SECONDARY_STW_EXP BlockIOTag(0x56u) /* GTPro */ +#define SECONDARY_S_X_INC BlockIOTag(0x57u) /* GTPro */ +#define SECONDARY_S_Y_INC BlockIOTag(0x58u) /* GTPro */ +#define SECONDARY_S_START BlockIOTag(0x59u) /* GTPro */ +#define SECONDARY_W_X_INC BlockIOTag(0x5au) /* GTPro */ +#define SECONDARY_W_Y_INC BlockIOTag(0x5bu) /* GTPro */ +#define SECONDARY_W_START BlockIOTag(0x5cu) /* GTPro */ +#define SECONDARY_T_X_INC BlockIOTag(0x5du) /* GTPro */ +#define SECONDARY_T_Y_INC BlockIOTag(0x5eu) /* GTPro */ +#define SECONDARY_T_START BlockIOTag(0x5fu) /* GTPro */ +#define SRC_OFF_PITCH BlockIOTag(0x60u) +#define SRC_OFFSET 0x000ffffful +/* ? 0x00300000ul */ +#define SRC_PITCH 0xffc00000ul +#define SRC_X BlockIOTag(0x61u) +#define SRC_Y BlockIOTag(0x62u) +#define SRC_Y_X BlockIOTag(0x63u) +#define SRC_WIDTH1 BlockIOTag(0x64u) +#define SRC_HEIGHT1 BlockIOTag(0x65u) +#define SRC_HEIGHT1_WIDTH1 BlockIOTag(0x66u) +#define SRC_X_START BlockIOTag(0x67u) +#define SRC_Y_START BlockIOTag(0x68u) +#define SRC_Y_X_START BlockIOTag(0x69u) +#define SRC_WIDTH2 BlockIOTag(0x6au) +#define SRC_HEIGHT2 BlockIOTag(0x6bu) +#define SRC_HEIGHT2_WIDTH2 BlockIOTag(0x6cu) +#define SRC_CNTL BlockIOTag(0x6du) +#define SRC_PATT_EN 0x00000001ul +#define SRC_PATT_ROT_EN 0x00000002ul +#define SRC_LINEAR_EN 0x00000004ul +#define SRC_BYTE_ALIGN 0x00000008ul +#define SRC_LINE_X_DIR 0x00000010ul +#define SRC_8X8X8_BRUSH 0x00000020ul /* VTB/GTB */ +#define FAST_FILL_EN 0x00000040ul /* VTB/GTB */ +#define SRC_TRACK_DST 0x00000080ul /* VTB/GTB */ +#define BUS_MASTER_EN 0x00000100ul /* VTB/GTB */ +#define BUS_MASTER_SYNC 0x00000200ul /* VTB/GTB */ +#define BUS_MASTER_OP 0x00000c00ul /* VTB/GTB */ +#define SRC_8X8X8_BRUSH_LOADED 0x00001000ul /* VTB/GTB */ +#define COLOR_REG_WRITE_EN 0x00002000ul /* VTB/GTB */ +#define BLOCK_WRITE_EN 0x00004000ul /* VTB/GTB */ +/* ? 0xffff8000ul */ +/* ? BlockIOTag(0x6eu) */ +/* ? BlockIOTag(0x6fu) */ +#define SCALE_Y_OFF BlockIOTag(0x70u) /* GT */ +#define SCALE_OFF BlockIOTag(0x70u) /* GTPro */ +#define SECONDARY_SCALE_OFF BlockIOTag(0x70u) /* GTPro */ +#define TEX_0_OFF BlockIOTag(0x70u) /* GT */ +#define TEX_1_OFF BlockIOTag(0x71u) /* GT */ +#define TEX_2_OFF BlockIOTag(0x72u) /* GT */ +#define TEX_3_OFF BlockIOTag(0x73u) /* GT */ +#define TEX_4_OFF BlockIOTag(0x74u) /* GT */ +#define TEX_5_OFF BlockIOTag(0x75u) /* GT */ +#define TEX_6_OFF BlockIOTag(0x76u) /* GT */ +#define SCALE_WIDTH BlockIOTag(0x77u) /* GT */ +#define TEX_7_OFF BlockIOTag(0x77u) /* GT */ +#define SCALE_HEIGHT BlockIOTag(0x78u) /* GT */ +#define TEX_8_OFF BlockIOTag(0x78u) /* GT */ +#define TEX_9_OFF BlockIOTag(0x79u) /* GT */ +#define TEX_10_OFF BlockIOTag(0x7au) /* GT */ +#define S_Y_INC BlockIOTag(0x7bu) /* GT */ +#define SCALE_Y_PITCH BlockIOTag(0x7bu) /* GT */ +#define SCALE_X_INC BlockIOTag(0x7cu) /* GT */ +#define RED_X_INC BlockIOTag(0x7cu) /* GT */ +#define GREEN_X_INC BlockIOTag(0x7du) /* GT */ +#define SCALE_Y_INC BlockIOTag(0x7du) /* GT */ +#define SCALE_VACC BlockIOTag(0x7eu) /* GT */ +#define SCALE_3D_CNTL BlockIOTag(0x7fu) /* GT */ +#define HOST_DATA_0 BlockIOTag(0x80u) +#define HOST_DATA_1 BlockIOTag(0x81u) +#define HOST_DATA_2 BlockIOTag(0x82u) +#define HOST_DATA_3 BlockIOTag(0x83u) +#define HOST_DATA_4 BlockIOTag(0x84u) +#define HOST_DATA_5 BlockIOTag(0x85u) +#define HOST_DATA_6 BlockIOTag(0x86u) +#define HOST_DATA_7 BlockIOTag(0x87u) +#define HOST_DATA_8 BlockIOTag(0x88u) +#define HOST_DATA_9 BlockIOTag(0x89u) +#define HOST_DATA_A BlockIOTag(0x8au) +#define HOST_DATA_B BlockIOTag(0x8bu) +#define HOST_DATA_C BlockIOTag(0x8cu) +#define HOST_DATA_D BlockIOTag(0x8du) +#define HOST_DATA_E BlockIOTag(0x8eu) +#define HOST_DATA_F BlockIOTag(0x8fu) +#define HOST_CNTL BlockIOTag(0x90u) +#define HOST_BYTE_ALIGN 0x00000001ul +#define HOST_BIG_ENDIAN_EN 0x00000002ul /* GX-E/CT */ +/* ? 0xfffffffcul */ +#define BM_HOSTDATA BlockIOTag(0x91u) /* VTB/GTB */ +#define BM_ADDR BlockIOTag(0x92u) /* VTB/GTB */ +#define BM_DATA BlockIOTag(0x92u) /* VTB/GTB */ +#define BM_GUI_TABLE_CMD BlockIOTag(0x93u) /* GTPro */ +/* ? BlockIOTag(0x94u) */ +/* ? BlockIOTag(0x95u) */ +/* ? BlockIOTag(0x96u) */ +/* ? BlockIOTag(0x97u) */ +/* ? BlockIOTag(0x98u) */ +/* ? BlockIOTag(0x99u) */ +/* ? BlockIOTag(0x9au) */ +/* ? BlockIOTag(0x9bu) */ +/* ? BlockIOTag(0x9cu) */ +/* ? BlockIOTag(0x9du) */ +/* ? BlockIOTag(0x9eu) */ +/* ? BlockIOTag(0x9fu) */ +#define PAT_REG0 BlockIOTag(0xa0u) +#define PAT_REG1 BlockIOTag(0xa1u) +#define PAT_CNTL BlockIOTag(0xa2u) +#define PAT_MONO_EN 0x00000001ul +#define PAT_CLR_4x2_EN 0x00000002ul +#define PAT_CLR_8x1_EN 0x00000004ul +/* ? 0xfffffff8ul */ +/* ? BlockIOTag(0xa3u) */ +/* ? BlockIOTag(0xa4u) */ +/* ? BlockIOTag(0xa5u) */ +/* ? BlockIOTag(0xa6u) */ +/* ? BlockIOTag(0xa7u) */ +#define SC_LEFT BlockIOTag(0xa8u) +#define SC_RIGHT BlockIOTag(0xa9u) +#define SC_LEFT_RIGHT BlockIOTag(0xaau) +#define SC_TOP BlockIOTag(0xabu) +#define SC_BOTTOM BlockIOTag(0xacu) +#define SC_TOP_BOTTOM BlockIOTag(0xadu) +#define USR1_DST_OFF_PITCH BlockIOTag(0xaeu) /* LTPro */ +#define USR2_DST_OFF_PITCH BlockIOTag(0xafu) /* LTPro */ +#define DP_BKGD_CLR BlockIOTag(0xb0u) +#define DP_FRGD_CLR BlockIOTag(0xb1u) +#define DP_WRITE_MASK BlockIOTag(0xb2u) +#define DP_CHAIN_MASK BlockIOTag(0xb3u) +#define DP_CHAIN_1BPP 0x00000000ul /* Irrelevant */ +#define DP_CHAIN_4BPP 0x00008888ul +#define DP_CHAIN_8BPP 0x00008080ul +#define DP_CHAIN_8BPP_332 0x00009292ul +#define DP_CHAIN_15BPP_1555 0x00004210ul +#define DP_CHAIN_16BPP_565 0x00008410ul +#define DP_CHAIN_24BPP_888 0x00008080ul +#define DP_CHAIN_32BPP_8888 0x00008080ul +/* ? 0xffff0000ul */ +#define DP_PIX_WIDTH BlockIOTag(0xb4u) +#define DP_DST_PIX_WIDTH 0x0000000ful +#define COMPOSITE_PIX_WIDTH 0x000000f0ul /* GTPro */ +#define DP_SRC_PIX_WIDTH 0x00000f00ul +/* ? 0x00001000ul */ +#define DP_HOST_TRIPLE_EN 0x00002000ul /* GT2c/VT4 */ +#define DP_SRC_AUTONA_FIX_DIS 0x00004000ul /* GTB */ +#define DP_FAST_SRCCOPY_DIS 0x00008000ul /* GTB */ +#define DP_HOST_PIX_WIDTH 0x000f0000ul +#define DP_CI4_RGB_INDEX 0x00f00000ul /* GTB */ +#define DP_BYTE_PIX_ORDER 0x01000000ul +#define DP_CONVERSION_TEMP 0x02000000ul /* GTB */ +#define DP_CI4_RGB_LOW_NIBBLE 0x04000000ul /* GTB */ +#define DP_C14_RGB_HIGH_NIBBLE 0x08000000ul /* GTB */ +#define DP_SCALE_PIX_WIDTH 0xf0000000ul /* GTB */ +#define DP_MIX BlockIOTag(0xb5u) +#define DP_BKGD_MIX 0x0000001ful +/* ? 0x0000ffe0ul */ +#define DP_FRGD_MIX 0x001f0000ul +/* ? 0xffe00000ul */ +#define DP_SRC BlockIOTag(0xb6u) +#define DP_BKGD_SRC 0x00000007ul +/* ? 0x000000feul */ +#define DP_FRGD_SRC 0x00000700ul +/* ? 0x0000fe00ul */ +#define DP_MONO_SRC 0x00030000ul +#define DP_MONO_SRC_ALLONES 0x00000000ul +#define DP_MONO_SRC_PATTERN 0x00010000ul +#define DP_MONO_SRC_HOST 0x00020000ul +#define DP_MONO_SRC_BLIT 0x00030000ul +/* ? 0xfffc0000ul */ +#define DP_FRGD_CLR_MIX BlockIOTag(0xb7u) /* VTB/GTB */ +#define DP_FRGD_BKGD_CLR BlockIOTag(0xb8u) /* VTB/GTB */ +/* ? BlockIOTag(0xb9u) */ +#define DST_X_Y BlockIOTag(0xbau) /* VTB/GTB */ +#define DST_WIDTH_HEIGHT BlockIOTag(0xbbu) /* VTB/GTB */ +#define USR_DST_PITCH BlockIOTag(0xbcu) /* GTPro */ +/* ? BlockIOTag(0xbdu) */ +#define DP_SET_GUI_ENGINE2 BlockIOTag(0xbeu) /* GTPro */ +#define DP_SET_GUI_ENGINE BlockIOTag(0xbfu) /* VTB/GTB */ +#define CLR_CMP_CLR BlockIOTag(0xc0u) +#define CLR_CMP_MSK BlockIOTag(0xc1u) +#define CLR_CMP_CNTL BlockIOTag(0xc2u) +#define CLR_CMP_FN 0x00000007ul +#define CLR_CMP_FN_FALSE 0x00000000ul +#define CLR_CMP_FN_TRUE 0x00000001ul +/* ? 0x00000002ul */ +/* ? 0x00000003ul */ +#define CLR_CMP_FN_NOT_EQUAL 0x00000004ul +#define CLR_CMP_FN_EQUAL 0x00000005ul +/* ? 0x00000006ul */ +/* ? 0x00000007ul */ +/* ? 0x00fffff8ul */ +#define CLR_CMP_SRC 0x03000000ul +#define CLR_CMP_SRC_DST 0x00000000ul +#define CLR_CMP_SRC_2D 0x01000000ul +#define CLR_CMP_SRC_TEXEL 0x02000000ul +/* ? 0x03000000ul */ +/* ? 0xfc000000ul */ +/* ? BlockIOTag(0xc3u) */ +#define FIFO_STAT BlockIOTag(0xc4u) +#define FIFO_STAT_BITS 0x0000fffful +/* ? 0x7fff0000ul */ +#define FIFO_ERR 0x80000000ul +/* ? BlockIOTag(0xc5u) */ +/* ? BlockIOTag(0xc6u) */ +/* ? BlockIOTag(0xc7u) */ +#define CONTEXT_MASK BlockIOTag(0xc8u) +/* ? BlockIOTag(0xc9u) */ +/* ? BlockIOTag(0xcau) */ +#define CONTEXT_LOAD_CNTL BlockIOTag(0xcbu) +#define CONTEXT_LOAD_PTR 0x00007ffful +/* ? 0x00008000ul */ +#define CONTEXT_LOAD_CMD 0x00030000ul +#define CONTEXT_LOAD_NONE 0x00000000ul +#define CONTEXT_LOAD_ONLY 0x00010000ul +#define CONTEXT_LOAD_FILL 0x00020000ul +#define CONTEXT_LOAD_LINE 0x00030000ul +/* ? 0x7ffc0000ul */ +#define CONTEXT_LOAD_DIS 0x80000000ul +#define GUI_TRAJ_CNTL BlockIOTag(0xccu) +/* ? BlockIOTag(0xcdu) */ +#define GUI_STAT BlockIOTag(0xceu) +#define GUI_ACTIVE 0x00000001ul +/* ? 0x000000feul */ +#define DSTX_LT_SCISSOR_LEFT 0x00000100ul +#define DSTX_GT_SCISSOR_RIGHT 0x00000200ul +#define DSTY_LT_SCISSOR_TOP 0x00000400ul +#define DSTY_GT_SCISSOR_BOTTOM 0x00000800ul +/* ? 0x0000f000ul */ +#define GUI_FIFO 0x03ff0000ul /* VTB/GTB */ +/* ? 0xfc000000ul */ +/* ? BlockIOTag(0xcfu) */ +#define S_X_INC2 BlockIOTag(0xd0u) /* GTB */ +#define TEX_PALETTE_INDEX BlockIOTag(0xd0u) /* GTPro */ +#define S_Y_INC2 BlockIOTag(0xd1u) /* GTB */ +#define STW_EXP BlockIOTag(0xd1u) /* GTPro */ +#define S_XY_INC2 BlockIOTag(0xd2u) /* GTB */ +#define LOG_MAX_INC BlockIOTag(0xd2u) /* GTPro */ +#define S_XINC_START BlockIOTag(0xd3u) /* GTB */ +/* S_Y_INC BlockIOTag(0xd4u) */ /* Duplicate */ +/* SCALE_Y_PITCH BlockIOTag(0xd4u) */ /* Duplicate */ +#define S_START BlockIOTag(0xd5u) /* GTB */ +#define T_X_INC2 BlockIOTag(0xd6u) /* GTB */ +#define W_X_INC BlockIOTag(0xd6u) /* GTPro */ +#define T_Y_INC2 BlockIOTag(0xd7u) /* GTB */ +#define W_Y_INC BlockIOTag(0xd7u) /* GTPro */ +#define T_XY_INC2 BlockIOTag(0xd8u) /* GTB */ +#define W_START BlockIOTag(0xd8u) /* GTPro */ +#define T_XINC_START BlockIOTag(0xd9u) /* GTB */ +#define T_Y_INC BlockIOTag(0xdau) /* GTB */ +#define SECONDARY_SCALE_PITCH BlockIOTag(0xdau) /* GTPro */ +#define T_START BlockIOTag(0xdbu) /* GTB */ +#define TEX_SIZE_PITCH BlockIOTag(0xdcu) /* GTB */ +#define TEX_CNTL BlockIOTag(0xddu) /* GTPro */ +#define SECONDARY_TEX_OFFSET BlockIOTag(0xdeu) /* GTPro */ +#define TEX_PAL_WR BlockIOTag(0xdfu) /* GTB */ +#define TEX_PALETTE BlockIOTag(0xdfu) /* GTPro */ +#define SCALE_PITCH_BOTH BlockIOTag(0xe0u) /* GTPro */ +#define SECONDARY_SCALE_OFF_ACC BlockIOTag(0xe1u) /* GTPro */ +#define SCALE_OFF_ACC BlockIOTag(0xe2u) /* GTPro */ +#define SCALE_DST_Y_X BlockIOTag(0xe3u) /* GTPro */ +/* ? BlockIOTag(0xe4u) */ +/* ? BlockIOTag(0xe5u) */ +#define COMPOSITE_SHADOW_ID BlockIOTag(0xe6u) /* GTPro */ +#define SECONDARY_SCALE_X_INC BlockIOTag(0xe7u) /* GTPro */ +#define SPECULAR_RED_X_INC BlockIOTag(0xe7u) /* GTPro */ +#define SPECULAR_RED_Y_INC BlockIOTag(0xe8u) /* GTPro */ +#define SPECULAR_RED_START BlockIOTag(0xe9u) /* GTPro */ +#define SECONDARY_SCALE_HACC BlockIOTag(0xe9u) /* GTPro */ +#define SPECULAR_GREEN_X_INC BlockIOTag(0xeau) /* GTPro */ +#define SPECULAR_GREEN_Y_INC BlockIOTag(0xebu) /* GTPro */ +#define SPECULAR_GREEN_START BlockIOTag(0xecu) /* GTPro */ +#define SPECULAR_BLUE_X_INC BlockIOTag(0xedu) /* GTPro */ +#define SPECULAR_BLUE_Y_INC BlockIOTag(0xeeu) /* GTPro */ +#define SPECULAR_BLUE_START BlockIOTag(0xefu) /* GTPro */ +/* SCALE_X_INC BlockIOTag(0xf0u) */ /* Duplicate */ +/* RED_X_INC BlockIOTag(0xf0u) */ /* Duplicate */ +#define RED_Y_INC BlockIOTag(0xf1u) /* GTB */ +#define SCALE_HACC BlockIOTag(0xf2u) /* GTB */ +#define RED_START BlockIOTag(0xf2u) /* GTB */ +/* GREEN_X_INC BlockIOTag(0xf3u) */ /* Duplicate */ +/* SCALE_Y_INC BlockIOTag(0xf3u) */ /* Duplicate */ +#define GREEN_Y_INC BlockIOTag(0xf4u) /* GTB */ +#define SECONDARY_SCALE_Y_INC BlockIOTag(0xf4u) /* GTPro */ +#define SECONDARY_SCALE_VACC BlockIOTag(0xf5u) /* GTPro */ +#define GREEN_START BlockIOTag(0xf5u) /* GTB */ +#define BLUE_X_INC BlockIOTag(0xf6u) /* GTB */ +#define SCALE_XUV_INC BlockIOTag(0xf6u) /* GTB */ +#define BLUE_Y_INC BlockIOTag(0xf7u) /* GTB */ +#define BLUE_START BlockIOTag(0xf8u) /* GTB */ +#define SCALE_UV_HACC BlockIOTag(0xf8u) /* GTB */ +#define Z_X_INC BlockIOTag(0xf9u) /* GTB */ +#define Z_Y_INC BlockIOTag(0xfau) /* GTB */ +#define Z_START BlockIOTag(0xfbu) /* GTB */ +#define ALPHA_FOG_X_INC BlockIOTag(0xfcu) /* GTB */ +#define ALPHA_FOG_Y_INC BlockIOTag(0xfdu) /* GTB */ +#define ALPHA_FOG_START BlockIOTag(0xfeu) /* GTB */ +/* ? BlockIOTag(0xffu) */ +#define OVERLAY_Y_X_START BlockIOTag(0x100u) +#define OVERLAY_Y_START 0x000003fful +/* ? 0x0000fc00ul */ +#define OVERLAY_X_START 0x03ff0000ul +/* ? 0x7c000000ul */ +#define OVERLAY_LOCK_START 0x80000000ul +#define OVERLAY_Y_X_END BlockIOTag(0x101u) +#define OVERLAY_Y_END 0x000003fful +/* ? 0x0000fc00ul */ +#define OVERLAY_X_END 0x03ff0000ul +/* ? 0x7c000000ul */ +#define OVERLAY_LOCK_END 0x80000000ul +#define OVERLAY_VIDEO_KEY_CLR BlockIOTag(0x102u) +#define OVERLAY_VIDEO_KEY_MSK BlockIOTag(0x103u) +#define OVERLAY_GRAPHICS_KEY_CLR BlockIOTag(0x104u) +#define OVERLAY_GRAPHICS_KEY_MSK BlockIOTag(0x105u) +#define OVERLAY_KEY_CNTL BlockIOTag(0x106u) +#define OVERLAY_VIDEO_FN 0x00000007ul +/* ? 0x00000008ul */ +#define OVERLAY_GRAPHICS_FN 0x00000070ul +/* ? 0x00000080ul */ +#define OVERLAY_CMP_MIX 0x00000100ul +/* ? 0xfffffe00ul */ +/* ? BlockIOTag(0x107u) */ +#define OVERLAY_SCALE_INC BlockIOTag(0x108u) +#define OVERLAY_SCALE_CNTL BlockIOTag(0x109u) +#define SCALE_PIX_EXPAND 0x00000001ul +#define SCALE_Y2R_TEMP 0x00000002ul +#define SCALE_HORZ_MODE 0x00000004ul +#define SCALE_VERT_MODE 0x00000008ul +#define SCALE_SIGNED_UV 0x00000010ul +#define SCALE_GAMMA_SEL 0x00000060ul +/* ? 0x03ffff80ul */ +#define SCALE_BANDWIDTH 0x04000000ul +#define SCALE_DIS_LIMIT 0x08000000ul +/* ? 0x10000000ul */ +#define SCALE_CLK_FORCE_ON 0x20000000ul +#define OVERLAY_EN 0x40000000ul +#define SCALE_EN 0x80000000ul +#define SCALER_HEIGHT_WIDTH BlockIOTag(0x10au) +#define SCALER_TEST BlockIOTag(0x10bu) +/* ? 0x00000001ul */ +#define SCALE_Y2R_DIS 0x00000002ul +/* ? 0xfffffffcul */ +#define SCALER_THRESHOLD BlockIOTag(0x10cu) +#define SCALER_BUF0_OFFSET BlockIOTag(0x10du) /* VTB/GTB */ +#define SCALER_BUF1_OFFSET BlockIOTag(0x10eu) /* VTB/GTB */ +#define SCALER_BUF_PITCH BlockIOTag(0x10fu) /* VTB/GTB */ +#define CAPTURE_Y_X BlockIOTag(0x110u) +#define CAPTURE_START_END BlockIOTag(0x110u) /* VTB/GTB */ +#define CAPTURE_HEIGHT_WIDTH BlockIOTag(0x111u) +#define CAPTURE_X_WIDTH BlockIOTag(0x111u) /* VTB/GTB */ +#define VIDEO_FORMAT BlockIOTag(0x112u) +#define VIDEO_IN 0x0000000ful +/* ? 0x00000000ul */ +/* ? 0x00000001ul */ +/* ? 0x00000002ul */ +/* ? 0x00000003ul */ +/* ? 0x00000004ul */ +/* ? 0x00000005ul */ +/* ? 0x00000006ul */ +/* ? 0x00000007ul */ +/* ? 0x00000008ul */ +/* ? 0x00000009ul */ +/* ? 0x0000000aul */ +#define VIDEO_IN_VYUY422 0x0000000bul +#define VIDEO_IN_YVYU422 0x0000000cul +/* ? 0x0000000dul */ +/* ? 0x0000000eul */ +/* ? 0x0000000ful */ +#define VIDEO_SIGNED_UV 0x00000010ul +/* ? 0x0000ffe0ul */ +#define SCALER_IN 0x000f0000ul +/* ? 0x00000000ul */ +/* ? 0x00010000ul */ +/* ? 0x00020000ul */ +#define SCALER_IN_15BPP 0x00030000ul +#define SCALER_IN_16BPP 0x00040000ul +/* ? 0x00050000ul */ +#define SCALER_IN_32BPP 0x00060000ul +/* ? 0x00070000ul */ +/* ? 0x00080000ul */ +#define SCALER_IN_YUV9 0x00090000ul +#define SCALER_IN_YUV12 0x000a0000ul +#define SCALER_IN_VYUY422 0x000b0000ul +#define SCALER_IN_YVYU422 0x000c0000ul +/* ? 0x000d0000ul */ +/* ? 0x000e0000ul */ +/* ? 0x000f0000ul */ +/* ? 0x0ff00000ul */ +#define HOST_BYTE_SHIFT_EN 0x10000000ul +#define HOST_YUV_APER 0x20000000ul +#define HOST_MEM_MODE 0xc0000000ul +#define HOST_MEM_MODE_NORMAL 0x00000000ul +#define HOST_MEM_MODE_Y 0x40000000ul +#define HOST_MEM_MODE_U 0x80000000ul +#define HOST_MEM_MODE_V 0xc0000000ul +#define VIDEO_CONFIG BlockIOTag(0x113u) +#define VBI_START_END BlockIOTag(0x113u) /* VTB/GTB */ +#define CAPTURE_CONFIG BlockIOTag(0x114u) +#define CAP_INPUT_MODE 0x00000001ul +#define CAP_START_FIELD 0x00000002ul +#define CAP_BUF_MODE 0x00000004ul +#define CAP_START_BUF 0x00000008ul +#define CAP_BUF_TYPE 0x00000030ul +#define CAP_BUF_FIELD 0x00000000ul +#define CAP_BUF_ALTERNATING 0x00000010ul +#define CAP_BUF_FRAME 0x00000020ul +/* ? 0x00000030ul */ +#define CAP_FIELD_FLIP 0x00000040ul +#define CAP_CCIR656_EN 0x00000080ul +/* ? 0x00000f00ul */ +#define CAP_MIRROR_EN 0x00001000ul +#define ONESHOT_MIRROR_EN 0x00002000ul +#define ONESHOT_MODE 0x00004000ul +/* ? 0x00008000ul */ +#define CAP_HORZ_DOWN 0x00030000ul +#define CAP_VERT_DOWN 0x000c0000ul +#define ONESHOT_HORZ_DOWN 0x00300000ul +#define ONESHOT_VERT_DOWN 0x00c00000ul +/* ? 0x0f000000ul */ +#define OVL_BUF_MODE 0x10000000ul +#define OVL_BUF_NEXT 0x20000000ul +/* ? 0xc0000000ul */ +#define TRIG_CNTL BlockIOTag(0x115u) +#define CAP_TRIGGER 0x00000003ul +#define CAP_TRIGGER_NEXT 0x00000001ul +/* ? 0x0000001cul */ +#define OVL_CUR_BUF 0x00000020ul +#define OVL_BUF_STATUS 0x00000040ul +#define CAP_BUF_STATUS 0x00000080ul +/* ? 0x7fffff00ul */ +#define CAPTURE_EN 0x80000000ul +#define VIDEO_SYNC_TEST BlockIOTag(0x116u) +#define OVERLAY_EXCLUSIVE_HORZ BlockIOTag(0x116u) /* VTB/GTB */ +#define EXCLUSIVE_HORZ_START 0x000000fful +#define EXCLUSIVE_HORZ_END 0x0000ff00ul +#define EXCLUSIVE_HORZ_PORCH 0x00ff0000ul +/* ? 0x7f000000ul */ +#define EXCLUSIVE_EN 0x80000000ul +#define EXT_CRTC_GEN_CNTL_R BlockIOTag(0x117u) /* VT-A4 (R) */ +#define OVERLAY_EXCLUSIVE_VERT BlockIOTag(0x117u) /* VTB/GTB */ +#define EXCLUSIVE_VERT_START 0x000003fful +/* ? 0x0000fc00ul */ +#define EXCLUSIVE_VERT_END 0x03ff0000ul +/* ? 0xfc000000ul */ +#define VMC_CONFIG BlockIOTag(0x118u) +#define VBI_WIDTH BlockIOTag(0x118u) /* VTB/GTB */ +#define VMC_STATUS BlockIOTag(0x119u) +#define CAPTURE_DEBUG BlockIOTag(0x119u) /* VTB/GTB */ +#define VMC_CMD BlockIOTag(0x11au) +#define VIDEO_SYNC_TEST_B BlockIOTag(0x11au) /* VTB/GTB */ +#define VMC_ARG0 BlockIOTag(0x11bu) +#define VMC_ARG1 BlockIOTag(0x11cu) +#define SNAPSHOT_VH_COUNTS BlockIOTag(0x11cu) /* GTPro */ +#define VMC_SNOOP_ARG0 BlockIOTag(0x11du) +#define SNAPSHOT_F_COUNT BlockIOTag(0x11du) /* GTPro */ +#define VMC_SNOOP_ARG1 BlockIOTag(0x11eu) +#define N_VIF_COUNT BlockIOTag(0x11eu) /* GTPro */ +#define SNAPSHOT_VIF_COUNT BlockIOTag(0x11fu) /* GTPro */ +#define BUF0_OFFSET BlockIOTag(0x120u) +#define CAPTURE_BUF0_OFFSET BlockIOTag(0x120u) /* VTB/GTB */ +#define CAPTURE_BUF1_OFFSET BlockIOTag(0x121u) /* VTB/GTB */ +#define ONESHOT_BUF_OFFSET BlockIOTag(0x122u) /* VTB/GTB */ +#define BUF0_PITCH BlockIOTag(0x123u) +/* ? BlockIOTag(0x124u) */ +/* ? BlockIOTag(0x125u) */ +#define BUF1_OFFSET BlockIOTag(0x126u) +/* ? BlockIOTag(0x127u) */ +/* ? BlockIOTag(0x128u) */ +#define BUF1_PITCH BlockIOTag(0x129u) +/* ? BlockIOTag(0x12au) */ +#define BUF0_CAP_ODD_OFFSET BlockIOTag(0x12bu) +#define BUF1_CAP_ODD_OFFSET BlockIOTag(0x12cu) +#define SNAPSHOT2_VH_COUNTS BlockIOTag(0x12cu) /* LTPro */ +#define SNAPSHOT2_F_COUNT BlockIOTag(0x12du) /* LTPro */ +#define N_VIF2_COUNT BlockIOTag(0x12eu) /* LTPro */ +#define SNAPSHOT2_VIF_COUNT BlockIOTag(0x12fu) /* LTPro */ +#define VMC_STRM_DATA_0 BlockIOTag(0x130u) +/* MPP_CONFIG BlockIOTag(0x130u) */ /* See 0x3bu */ +#define VMC_STRM_DATA_1 BlockIOTag(0x131u) +/* MPP_STROBE_SEQ BlockIOTag(0x131u) */ /* See 0x3cu */ +#define VMC_STRM_DATA_2 BlockIOTag(0x132u) +/* MPP_ADDR BlockIOTag(0x132u) */ /* See 0x3du */ +#define VMC_STRM_DATA_3 BlockIOTag(0x133u) +/* MPP_DATA BlockIOTag(0x133u) */ /* See 0x3eu */ +#define VMC_STRM_DATA_4 BlockIOTag(0x134u) +#define VMC_STRM_DATA_5 BlockIOTag(0x135u) +#define VMC_STRM_DATA_6 BlockIOTag(0x136u) +#define VMC_STRM_DATA_7 BlockIOTag(0x137u) +#define VMC_STRM_DATA_8 BlockIOTag(0x138u) +#define VMC_STRM_DATA_9 BlockIOTag(0x139u) +#define VMC_STRM_DATA_A BlockIOTag(0x13au) +#define VMC_STRM_DATA_B BlockIOTag(0x13bu) +#define VMC_STRM_DATA_C BlockIOTag(0x13cu) +#define VMC_STRM_DATA_D BlockIOTag(0x13du) +#define VMC_STRM_DATA_E BlockIOTag(0x13eu) +#define VMC_STRM_DATA_F BlockIOTag(0x13fu) +/* TVO_CNTL BlockIOTag(0x140u) */ /* See 0x3fu */ +/* ? BlockIOTag(0x141u) */ +/* ? BlockIOTag(0x142u) */ +/* ? BlockIOTag(0x143u) */ +/* ? BlockIOTag(0x144u) */ +/* ? BlockIOTag(0x145u) */ +/* ? BlockIOTag(0x146u) */ +/* ? BlockIOTag(0x147u) */ +/* ? BlockIOTag(0x148u) */ +/* ? BlockIOTag(0x149u) */ +/* ? BlockIOTag(0x14au) */ +/* ? BlockIOTag(0x14bu) */ +/* ? BlockIOTag(0x14cu) */ +/* ? BlockIOTag(0x14du) */ +/* ? BlockIOTag(0x14eu) */ +/* ? BlockIOTag(0x14fu) */ +/* ? BlockIOTag(0x150u) */ +#define CRT_HORZ_VERT_LOAD BlockIOTag(0x151u) /* VTB/GTB */ +#define AGP_BASE BlockIOTag(0x152u) /* GTPro */ +#define AGP_CNTL BlockIOTag(0x153u) /* GTPro */ +#define SCALER_COLOUR_CNTL BlockIOTag(0x154u) /* GTPro */ +#define SCALE_BRIGHTNESS 0x0000007ful +/* ? 0x00000080ul */ +#define SCALE_SATURATION_U 0x00001f00ul +/* ? 0x0000e000ul */ +#define SCALE_SATURATION_V 0x001f0000ul +#define SCALE_VERT_ADJ_UV 0x0fe00000ul +#define SCALE_HORZ_ADJ_UV 0xf0000000ul +#define SCALER_H_COEFF0 BlockIOTag(0x155u) /* GTPro */ +#define SCALER_H_COEFF1 BlockIOTag(0x156u) /* GTPro */ +#define SCALER_H_COEFF2 BlockIOTag(0x157u) /* GTPro */ +#define SCALER_H_COEFF3 BlockIOTag(0x158u) /* GTPro */ +#define SCALER_H_COEFF4 BlockIOTag(0x159u) /* GTPro */ +/* ? BlockIOTag(0x15au) */ +/* ? BlockIOTag(0x15bu) */ +#define GUI_CMDFIFO_DEBUG BlockIOTag(0x15cu) /* GT2c/VT4 */ +#define GUI_CMDFIFO_DATA BlockIOTag(0x15du) /* GT2c/VT4 */ +#define GUI_CNTL BlockIOTag(0x15eu) /* GT2c/VT4 */ +#define CMDFIFO_SIZE_MODE 0x00000003ul +/* ? 0x0000fffcul */ +#define IDCT_PRSR_MODE 0x00010000ul /* XL/XC */ +#define IDCT_BLOCK_GUI_INITIATOR 0x00020000ul /* XL/XC */ +/* ? 0xfffc0000ul */ +/* ? BlockIOTag(0x15fu) */ +#define BM_FRAME_BUF_OFFSET BlockIOTag(0x160u) /* VTB/GTB */ +#define BM_SYSTEM_MEM_ADDR BlockIOTag(0x161u) /* VTB/GTB */ +#define BM_COMMAND BlockIOTag(0x162u) /* VTB/GTB */ +#define BM_STATUS BlockIOTag(0x163u) /* VTB/GTB */ +/* ? BlockIOTag(0x164u) */ +/* ? BlockIOTag(0x165u) */ +/* ? BlockIOTag(0x166u) */ +/* ? BlockIOTag(0x167u) */ +/* ? BlockIOTag(0x168u) */ +/* ? BlockIOTag(0x169u) */ +/* ? BlockIOTag(0x16au) */ +/* ? BlockIOTag(0x16bu) */ +/* ? BlockIOTag(0x16cu) */ +/* ? BlockIOTag(0x16du) */ +#define BM_GUI_TABLE BlockIOTag(0x16eu) /* VTB/GTB */ +#define BM_SYSTEM_TABLE BlockIOTag(0x16fu) /* VTB/GTB */ +/* ? BlockIOTag(0x170u) */ +/* ? BlockIOTag(0x171u) */ +/* ? BlockIOTag(0x172u) */ +/* ? BlockIOTag(0x173u) */ +/* ? BlockIOTag(0x174u) */ +#define SCALER_BUF0_OFFSET_U BlockIOTag(0x175u) /* GTPro */ +#define SCALER_BUF0_OFFSET_V BlockIOTag(0x176u) /* GTPro */ +#define SCALER_BUF1_OFFSET_U BlockIOTag(0x177u) /* GTPro */ +#define SCALER_BUF1_OFFSET_V BlockIOTag(0x178u) /* GTPro */ +/* ? BlockIOTag(0x179u) */ +/* ? BlockIOTag(0x17au) */ +/* ? BlockIOTag(0x17bu) */ +/* ? BlockIOTag(0x17cu) */ +/* ? BlockIOTag(0x17du) */ +/* ? BlockIOTag(0x17eu) */ +/* ? BlockIOTag(0x17fu) */ +/* ? BlockIOTag(0x180u) */ +/* ? BlockIOTag(0x181u) */ +/* ? BlockIOTag(0x182u) */ +/* ? BlockIOTag(0x183u) */ +/* ? BlockIOTag(0x184u) */ +/* ? BlockIOTag(0x185u) */ +/* ? BlockIOTag(0x186u) */ +/* ? BlockIOTag(0x187u) */ +/* ? BlockIOTag(0x188u) */ +/* ? BlockIOTag(0x189u) */ +/* ? BlockIOTag(0x18au) */ +/* ? BlockIOTag(0x18bu) */ +/* ? BlockIOTag(0x18cu) */ +/* ? BlockIOTag(0x18du) */ +/* ? BlockIOTag(0x18eu) */ +/* ? BlockIOTag(0x18fu) */ +#define VERTEX_1_S BlockIOTag(0x190u) /* GTPro */ +#define VERTEX_1_T BlockIOTag(0x191u) /* GTPro */ +#define VERTEX_1_W BlockIOTag(0x192u) /* GTPro */ +#define VERTEX_1_SPEC_ARGB BlockIOTag(0x193u) /* GTPro */ +#define VERTEX_1_Z BlockIOTag(0x194u) /* GTPro */ +#define VERTEX_1_ARGB BlockIOTag(0x195u) /* GTPro */ +#define VERTEX_1_X_Y BlockIOTag(0x196u) /* GTPro */ +#define ONE_OVER_AREA BlockIOTag(0x197u) /* GTPro */ +#define VERTEX_2_S BlockIOTag(0x198u) /* GTPro */ +#define VERTEX_2_T BlockIOTag(0x199u) /* GTPro */ +#define VERTEX_2_W BlockIOTag(0x19au) /* GTPro */ +#define VERTEX_2_SPEC_ARGB BlockIOTag(0x19bu) /* GTPro */ +#define VERTEX_2_Z BlockIOTag(0x19cu) /* GTPro */ +#define VERTEX_2_ARGB BlockIOTag(0x19du) /* GTPro */ +#define VERTEX_2_X_Y BlockIOTag(0x19eu) /* GTPro */ +/* ONE_OVER_AREA BlockIOTag(0x19fu) */ /* Duplicate */ +#define VERTEX_3_S BlockIOTag(0x1a0u) /* GTPro */ +#define VERTEX_3_T BlockIOTag(0x1a1u) /* GTPro */ +#define VERTEX_3_W BlockIOTag(0x1a2u) /* GTPro */ +#define VERTEX_3_SPEC_ARGB BlockIOTag(0x1a3u) /* GTPro */ +#define VERTEX_3_Z BlockIOTag(0x1a4u) /* GTPro */ +#define VERTEX_3_ARGB BlockIOTag(0x1a5u) /* GTPro */ +#define VERTEX_3_X_Y BlockIOTag(0x1a6u) /* GTPro */ +/* ONE_OVER_AREA BlockIOTag(0x1a7u) */ /* Duplicate */ +#define VERTEX_3_SECONDARY_S BlockIOTag(0x1a8u) /* GTPro */ +#define VERTEX_3_SECONDARY_T BlockIOTag(0x1a9u) /* GTPro */ +#define VERTEX_3_SECONDARY_W BlockIOTag(0x1aau) /* GTPro */ +/* VERTEX_1_S BlockIOTag(0x1abu) */ /* Duplicate */ +/* VERTEX_1_T BlockIOTag(0x1acu) */ /* Duplicate */ +/* VERTEX_1_W BlockIOTag(0x1adu) */ /* Duplicate */ +/* VERTEX_2_S BlockIOTag(0x1aeu) */ /* Duplicate */ +/* VERTEX_2_T BlockIOTag(0x1afu) */ /* Duplicate */ +/* VERTEX_2_W BlockIOTag(0x1b0u) */ /* Duplicate */ +/* VERTEX_3_S BlockIOTag(0x1b1u) */ /* Duplicate */ +/* VERTEX_3_T BlockIOTag(0x1b2u) */ /* Duplicate */ +/* VERTEX_3_W BlockIOTag(0x1b3u) */ /* Duplicate */ +/* VERTEX_1_SPEC_ARGB BlockIOTag(0x1b4u) */ /* Duplicate */ +/* VERTEX_2_SPEC_ARGB BlockIOTag(0x1b5u) */ /* Duplicate */ +/* VERTEX_3_SPEC_ARGB BlockIOTag(0x1b6u) */ /* Duplicate */ +/* VERTEX_1_Z BlockIOTag(0x1b7u) */ /* Duplicate */ +/* VERTEX_2_Z BlockIOTag(0x1b8u) */ /* Duplicate */ +/* VERTEX_3_Z BlockIOTag(0x1b9u) */ /* Duplicate */ +/* VERTEX_1_ARGB BlockIOTag(0x1bau) */ /* Duplicate */ +/* VERTEX_2_ARGB BlockIOTag(0x1bbu) */ /* Duplicate */ +/* VERTEX_3_ARGB BlockIOTag(0x1bcu) */ /* Duplicate */ +/* VERTEX_1_X_Y BlockIOTag(0x1bdu) */ /* Duplicate */ +/* VERTEX_2_X_Y BlockIOTag(0x1beu) */ /* Duplicate */ +/* VERTEX_3_X_Y BlockIOTag(0x1bfu) */ /* Duplicate */ +#define ONE_OVER_AREA_UC BlockIOTag(0x1c0u) /* GTPro */ +#define SETUP_CNTL BlockIOTag(0x1c1u) /* GTPro */ +/* ? BlockIOTag(0x1c2u) */ +/* ? BlockIOTag(0x1c3u) */ +/* ? BlockIOTag(0x1c4u) */ +/* ? BlockIOTag(0x1c5u) */ +/* ? BlockIOTag(0x1c6u) */ +/* ? BlockIOTag(0x1c7u) */ +/* ? BlockIOTag(0x1c8u) */ +/* ? BlockIOTag(0x1c9u) */ +#define VERTEX_1_SECONDARY_S BlockIOTag(0x1cau) /* GTPro */ +#define VERTEX_1_SECONDARY_T BlockIOTag(0x1cbu) /* GTPro */ +#define VERTEX_1_SECONDARY_W BlockIOTag(0x1ccu) /* GTPro */ +#define VERTEX_2_SECONDARY_S BlockIOTag(0x1cdu) /* GTPro */ +#define VERTEX_2_SECONDARY_T BlockIOTag(0x1ceu) /* GTPro */ +#define VERTEX_2_SECONDARY_W BlockIOTag(0x1cfu) /* GTPro */ +/* ? BlockIOTag(0x1d0u) */ +/* ? BlockIOTag(0x1d1u) */ +/* ? BlockIOTag(0x1d2u) */ +/* ? BlockIOTag(0x1d3u) */ +/* ? BlockIOTag(0x1d4u) */ +/* ? BlockIOTag(0x1d5u) */ +/* ? BlockIOTag(0x1d6u) */ +/* ? BlockIOTag(0x1d7u) */ +/* ? BlockIOTag(0x1d8u) */ +/* ? BlockIOTag(0x1d9u) */ +/* ? BlockIOTag(0x1dau) */ +/* ? BlockIOTag(0x1dbu) */ +/* ? BlockIOTag(0x1dcu) */ +/* ? BlockIOTag(0x1ddu) */ +/* ? BlockIOTag(0x1deu) */ +/* ? BlockIOTag(0x1dfu) */ +/* ? BlockIOTag(0x1e0u) */ +/* ? BlockIOTag(0x1e1u) */ +/* ? BlockIOTag(0x1e2u) */ +/* ? BlockIOTag(0x1e3u) */ +/* ? BlockIOTag(0x1e4u) */ +/* ? BlockIOTag(0x1e5u) */ +/* ? BlockIOTag(0x1e6u) */ +/* ? BlockIOTag(0x1e7u) */ +/* ? BlockIOTag(0x1e8u) */ +/* ? BlockIOTag(0x1e9u) */ +/* ? BlockIOTag(0x1eau) */ +/* ? BlockIOTag(0x1ebu) */ +/* ? BlockIOTag(0x1ecu) */ +/* ? BlockIOTag(0x1edu) */ +/* ? BlockIOTag(0x1eeu) */ +/* ? BlockIOTag(0x1efu) */ +/* ? BlockIOTag(0x1f0u) */ +/* ? BlockIOTag(0x1f1u) */ +/* ? BlockIOTag(0x1f2u) */ +/* ? BlockIOTag(0x1f3u) */ +/* ? BlockIOTag(0x1f4u) */ +/* ? BlockIOTag(0x1f5u) */ +/* ? BlockIOTag(0x1f6u) */ +/* ? BlockIOTag(0x1f7u) */ +/* ? BlockIOTag(0x1f8u) */ +/* ? BlockIOTag(0x1f9u) */ +/* ? BlockIOTag(0x1fau) */ +/* ? BlockIOTag(0x1fbu) */ +/* ? BlockIOTag(0x1fcu) */ +/* ? BlockIOTag(0x1fdu) */ +/* ? BlockIOTag(0x1feu) */ +/* ? BlockIOTag(0x1ffu) */ + +/* Definitions for MEM_CNTL's CTL_MEM_?????_APER_ENDIAN fields */ +#define CTL_MEM_APER_BYTE_ENDIAN 0x00u +#define CTL_MEM_APER_WORD_ENDIAN 0x01u +#define CTL_MEM_APER_LONG_ENDIAN 0x02u +/* ? 0x03u */ + +/* Definitions for an ICS2595's programme word */ +#define ICS2595_CLOCK 0x000001f0ul +#define ICS2595_FB_DIV 0x0001fe00ul /* Feedback divider */ +#define ICS2595_POST_DIV 0x000c0000ul /* Post-divider */ +#define ICS2595_STOP 0x00300000ul /* Stop bits */ +#define ICS2595_TOGGLE (ICS2595_POST_DIV | ICS2595_STOP) + +/* Definitions for internal PLL registers on a 264xT */ +#define PLL_MPLL_CNTL 0x00u +#define MPLL_PC_GAIN 0x07u +#define MPLL_VC_GAIN 0x18u +#define MPLL_D_CYC 0x60u +#define MPLL_RANGE 0x80u +#define VPLL_CNTL 0x01u +#define VPLL_PC_GAIN 0x07u +#define VPLL_VC_GAIN 0x18u +#define VPLL_D_CYC 0x60u +#define VPLL_RANGE 0x80u +#define PLL_REF_DIV 0x02u +#define PLL_GEN_CNTL 0x03u +#define PLL_OVERRIDE 0x01u +#define PLL_SLEEP 0x01u /* GTPro */ +#define PLL_MCLK_RESET 0x02u +#define PLL_OSC_EN 0x04u +#define PLL_EXT_CLK_EN 0x08u +#define PLL_MCLK_SRC_SEL 0x70u +#define PLL_EXT_CLK_CNTL 0x80u /* CT/ET */ +#define PLL_DLL_PWDN 0x80u /* VTB/GTB/LT */ +#define PLL_MCLK_FB_DIV 0x04u +#define PLL_VCLK_CNTL 0x05u +#define PLL_VCLK_SRC_SEL 0x03u +#define PLL_VCLK_RESET 0x04u +#define PLL_VCLK_INVERT 0x08u +#define PLL_ECP_DIV 0x30u /* VT/GT */ +#define PLL_ERATE_GT_XRATE 0x40u /* VT/GT */ +#define PLL_SCALER_LOCK_EN 0x80u /* VT/GT */ +#define PLL_VCLK_POST_DIV 0x06u +#define PLL_VCLK0_POST_DIV 0x03u +#define PLL_VCLK1_POST_DIV 0x0cu +#define PLL_VCLK2_POST_DIV 0x30u +#define PLL_VCLK3_POST_DIV 0xc0u +#define PLL_VCLK0_FB_DIV 0x07u +#define PLL_VCLK1_FB_DIV 0x08u +#define PLL_VCLK2_FB_DIV 0x09u +#define PLL_VCLK3_FB_DIV 0x0au +#define PLL_XCLK_CNTL 0x0bu /* VT/GT */ +#define PLL_XCLK_MCLK_RATIO 0x03u +#define PLL_XCLK_SRC_SEL 0x07u /* VTB/GTB/LT */ +#define PLL_MFB_TIMES_4_2B 0x08u +#define PLL_VCLK0_XDIV 0x10u +#define PLL_VCLK1_XDIV 0x20u +#define PLL_VCLK2_XDIV 0x40u +#define PLL_VCLK3_XDIV 0x80u +#define PLL_FCP_CNTL 0x0cu /* VT/GT */ +#define PLL_FCP_POST_DIV 0x0fu +#define PLL_FCP_SRC_SEL 0x70u +#define PLL_DCLK_BY2_EN 0x80u +#define PLL_DLL_CNTL 0x0cu /* VTB/GTB/LT */ +#define PLL_DLL_REF_SRC 0x03u +#define PLL_DLL_FB_SRC 0x0cu +#define PLL_DLL_GAIN 0x30u +#define PLL_DLL_RESET 0x40u +#define PLL_DLL_HCLK_OUT_EN 0x80u +#define PLL_VFC_CNTL 0x0du /* VT/GT */ +#define PLL_DCLK_INVB 0x01u +#define PLL_DCLKBY2_EN 0x02u +#define PLL_VFC_2PHASE 0x04u +#define PLL_VFC_DELAY 0x18u +#define PLL_VFC_DCLKBY2_SHIFT 0x20u +/* ? 0x40u */ +#define PLL_TST_SRC_SEL_BIT5 0x80u /* VTB/GTB/LT */ +#define PLL_TEST_CNTL 0x0eu +#define PLL_TST_SRC_SEL 0x1fu +#define PLL_TST_DIVIDERS 0x20u +#define PLL_TST_MASK_READ 0x40u +#define PLL_TST_ANALOG_MON_EN 0x80u +#define PLL_TEST_COUNT 0x0fu +#define PLL_LVDSPLL_CNTL0 0x10u /* LT */ +#define PLL_FPDI_NS_TIMING 0x01u +#define PLL_CURR_LEVEL 0x0eu +#define PLL_LVDS_TEST_MODE 0xf0u +#define PLL_LVDSPLL_CNTL1 0x11u /* LT */ +#define PLL_LPPL_RANGE 0x01u +#define PLL_LPLL_DUTY 0x06u +#define PLL_LPLL_VC_GAIN 0x18u +#define PLL_LPLL_CP_GAIN 0xe0u +#define PLL_AGP1_CNTL 0x12u /* GTPro */ +#define PLL_AGP2_CNTL 0x13u /* GTPro */ +#define PLL_DLL2_CNTL 0x14u /* GTPro */ +#define PLL_SCLK_FB_DIV 0x15u /* GTPro */ +#define PLL_SPLL_CNTL1 0x16u /* GTPro */ +#define PLL_SPLL_CNTL2 0x17u /* GTPro */ +#define PLL_APLL_STRAPS 0x18u /* GTPro */ +#define PLL_EXT_VPLL_CNTL 0x19u /* GTPro */ +#define PLL_EXT_VPLL_REF_SRC 0x03u +#define PLL_EXT_VPLL_EN 0x04u +#define PLL_EXT_VPLL_VGA_EN 0x08u +#define PLL_EXT_VPLL_INSYNC 0x10u +/* ? 0x60u */ +#define PLL_EXT_V2PLL_EN 0x80u +#define PLL_EXT_VPLL_REF_DIV 0x1au /* GTPro */ +#define PLL_EXT_VPLL_FB_DIV 0x1bu /* GTPro */ +#define PLL_EXT_VPLL_MSB 0x1cu /* GTPro */ +#define PLL_HTOTAL_CNTL 0x1du /* GTPro */ +#define PLL_BYTE_CLK_CNTL 0x1eu /* GTPro */ +#define PLL_TV_REF_DIV 0x1fu /* LTPro */ +#define PLL_TV_FB_DIV 0x20u /* LTPro */ +#define PLL_TV_CNTL 0x21u /* LTPro */ +#define PLL_TV_GEN_CNTL 0x22u /* LTPro */ +#define PLL_V2_CNTL 0x23u /* LTPro */ +#define PLL_V2_GEN_CNTL 0x24u /* LTPro */ +#define PLL_V2_REF_DIV 0x25u /* LTPro */ +#define PLL_V2_FB_DIV 0x26u /* LTPro */ +#define PLL_V2_MSB 0x27u /* LTPro */ +#define PLL_HTOTAL2_CNTL 0x28u /* LTPro */ +#define PLL_YCLK_CNTL 0x29u /* XC/XL */ +#define PM_DYN_CLK_CNTL 0x2au /* XC/XL */ +/* ? 0x2bu */ +/* ? 0x2cu */ +/* ? 0x2du */ +/* ? 0x2eu */ +/* ? 0x2fu */ +/* ? 0x30u */ +/* ? 0x31u */ +/* ? 0x32u */ +/* ? 0x33u */ +/* ? 0x34u */ +/* ? 0x35u */ +/* ? 0x36u */ +/* ? 0x37u */ +/* ? 0x38u */ +/* ? 0x39u */ +/* ? 0x3au */ +/* ? 0x3bu */ +/* ? 0x3cu */ +/* ? 0x3du */ +/* ? 0x3eu */ +/* ? 0x3fu */ + +/* Definitions for an LTPro's 32-bit LCD registers */ +#define LCD_CONFIG_PANEL 0x00u /* See LT's CONFIG_PANEL (0x1d) */ +#define LCD_GEN_CNTL 0x01u /* See LT's LCD_GEN_CTRL (0x35) */ +#define LCD_DSTN_CONTROL 0x02u /* See LT's DSTN_CONTROL (0x1f) */ +#define LCD_HFB_PITCH_ADDR 0x03u /* See LT's HFB_PITCH_ADDR (0x2a) */ +#define LCD_HORZ_STRETCHING 0x04u /* See LT's HORZ_STRETCHING (0x32) */ +#define LCD_VERT_STRETCHING 0x05u /* See LT's VERT_STRETCHING (0x33) */ +#define LCD_EXT_VERT_STRETCH 0x06u +#define VERT_STRETCH_RATIO3 0x000003fful +#define FORCE_DAC_DATA 0x000000fful +#define FORCE_DAC_DATA_SEL 0x00000300ul +#define VERT_STRETCH_MODE 0x00000400ul +#define VERT_PANEL_SIZE 0x003ff800ul +#define AUTO_VERT_RATIO 0x00400000ul +#define USE_AUTO_FP_POS 0x00800000ul +#define USE_AUTO_LCD_VSYNC 0x01000000ul +/* ? 0xfe000000ul */ +#define LCD_LT_GIO 0x07u /* See LT's LT_GIO (0x2f) */ +#define LCD_POWER_MANAGEMENT 0x08u /* See LT's POWER_MANAGEMENT (0x36) */ +#define LCD_ZVGPIO 0x09u +#define LCD_ICON_CLR0 0x0au /* Mobility */ +#define LCD_ICON_CLR1 0x0bu /* Mobility */ +#define LCD_ICON_OFFSET 0x0cu /* Mobility */ +#define LCD_ICON_HORZ_VERT_POSN 0x0du /* Mobility */ +#define LCD_ICON_HORZ_VERT_OFF 0x0eu /* Mobility */ +#define LCD_ICON2_CLR0 0x0fu /* Mobility */ +#define LCD_ICON2_CLR1 0x10u /* Mobility */ +#define LCD_ICON2_OFFSET 0x11u /* Mobility */ +#define LCD_ICON2_HORZ_VERT_POSN 0x12u /* Mobility */ +#define LCD_ICON2_HORZ_VERT_OFF 0x13u /* Mobility */ +#define LCD_MISC_CNTL 0x14u /* XC/XL */ +#define BL_MOD_LEVEL 0x000000fful +#define BIAS_MOD_LEVEL 0x0000ff00ul +#define BLMOD_EN 0x00010000ul +#define BIASMOD_EN 0x00020000ul +/* ? 0x00040000ul */ +#define PWRSEQ_MODE 0x00080000ul +#define APC_EN 0x00100000ul +#define MONITOR_DET_EN 0x00200000ul +#define FORCE_DAC_DATA_SEL_X 0x00c00000ul +#define FORCE_DAC_DATA_X 0xff000000ul +#define LCD_TMDS_CNTL 0x15u /* XC/XL */ +#define LCD_SCRATCH_PAD_4M 0x15u /* Mobility */ +#define LCD_TMDS_SYNC_CHAR_SETA 0x16u /* XC/XL */ +#define LCD_SCRATCH_PAD_5M 0x16u /* Mobility */ +#define LCD_TMDS_SYNC_CHAR_SETB 0x17u /* XC/XL */ +#define LCD_SCRATCH_PAD_6M 0x17u /* Mobility */ +#define LCD_TMDS_SRC 0x18u /* XC/XL */ +#define LCD_SCRATCH_PAD_7M 0x18u /* Mobility */ +#define LCD_PLTSTBLK_CNTL 0x19u /* XC/XL */ +#define LCD_SCRATCH_PAD_8M 0x19u /* Mobility */ +#define LCD_SYNC_GEN_CNTL 0x1au /* XC/XL */ +#define LCD_PATTERN_GEN_SEED 0x1bu /* XC/XL */ +#define LCD_APC_CNTL 0x1cu /* XC/XL */ +#define LCD_POWER_MANAGEMENT_2 0x1du /* XC/XL */ +#define LCD_XCLK_DISP_PM_EN 0x00000001ul +#define LCD_XCLK_DISP2_PM_EN 0x00000002ul /* Mobility */ +#define LCD_XCLK_VID_PM_EN 0x00000004ul +#define LCD_XCLK_SCL_PM_EN 0x00000008ul +#define LCD_XCLK_GUI_PM_EN 0x00000010ul +#define LCD_XCLK_SUB_PM_EN 0x00000020ul +/* ? 0x000000c0ul */ +#define LCD_MCLK_PM_EN 0x00000100ul +#define LCD_SS_EN 0x00000200ul +#define LCD_BLON_DIGON_EN 0x00000400ul +/* ? 0x00000800ul */ +#define LCD_PM_DYN_XCLK_SYNC 0x00003000ul +#define LCD_SEL_W4MS 0x00004000ul +/* ? 0x00008000ul */ +#define LCD_PM_DYN_XCLK_EN 0x00010000ul +#define LCD_PM_XCLK_ALWAYS 0x00020000ul +#define LCD_PM_DYN_XCLK_STATUS 0x00040000ul +#define LCD_PCI_ACC_DIS 0x00080000ul +#define LCD_PM_DYN_XCLK_DISP 0x00100000ul +#define LCD_PM_DYN_XCLK_DISP2 0x00200000ul /* Mobility */ +#define LCD_PM_DYN_XCLK_VID 0x00400000ul +#define LCD_PM_DYN_XCLK_HFB 0x00800000ul +#define LCD_PM_DYN_XCLK_SCL 0x01000000ul +#define LCD_PM_DYN_XCLK_SUB 0x02000000ul +#define LCD_PM_DYN_XCLK_GUI 0x04000000ul +#define LCD_PM_DYN_XCLK_HOST 0x08000000ul +/* ? 0xf0000000ul */ +#define LCD_PRI_ERR_PATTERN 0x1eu /* XC/XL */ +#define LCD_CUR_ERR_PATTERN 0x1fu /* XC/XL */ +#define LCD_PLTSTBLK_RPT 0x20u /* XC/XL */ +#define LCD_SYNC_RPT 0x21u /* XC/XL */ +#define LCD_CRC_PATTERN_RPT 0x22u /* XC/XL */ +#define LCD_PL_TRANSMITTER_CNTL 0x23u /* XC/XL */ +#define LCD_PL_PLL_CNTL 0x24u /* XC/XL */ +#define LCD_ALPHA_BLENDING 0x25u /* Mobility */ +#define LCD_PORTRAIT_GEN_CNTL 0x26u /* Mobility */ +#define LCD_APC_CTRL_IO 0x27u /* Mobility */ +#define LCD_TEST_IO 0x28u /* XC/XL */ +/* ? 0x29u */ +#define LCD_DP1_MEM_ACCESS 0x2au /* XC/XL */ +#define LCD_DP0_MEM_ACCESS 0x2bu /* XC/XL */ +#define LCD_DP0_DEBUG_A 0x2cu /* XC/XL */ +#define LCD_DP0_DEBUG_B 0x2du /* XC/XL */ +#define LCD_DP1_DEBUG_A 0x2eu /* XC/XL */ +#define LCD_DP1_DEBUG_B 0x2fu /* XC/XL */ +#define LCD_DPCTRL_DEBUG_A 0x30u /* XC/XL */ +#define LCD_DPCTRL_DEBUG_B 0x31u /* XC/XL */ +#define LCD_MEMBLK_DEBUG 0x32u /* XC/XL */ +#define LCD_APC_LUT_AB 0x33u /* Mobility */ +#define LCD_SCRATCH_PAD_4X 0x33u /* XL/XC */ +#define LCD_APC_LUT_CD 0x34u /* Mobility */ +#define LCD_SCRATCH_PAD_5X 0x34u /* XL/XC */ +#define LCD_APC_LUT_EF 0x35u /* Mobility */ +#define LCD_SCRATCH_PAD_6X 0x35u /* XL/XC */ +#define LCD_APC_LUT_GH 0x36u /* Mobility */ +#define LCD_SCRATCH_PAD_7X 0x36u /* XL/XC */ +#define LCD_APC_LUT_IJ 0x37u /* Mobility */ +#define LCD_SCRATCH_PAD_8X 0x37u /* XL/XC */ +#define LCD_APC_LUT_KL 0x38u /* Mobility */ +#define LCD_APC_LUT_MN 0x39u /* Mobility */ +#define LCD_APC_LUT_OP 0x3au /* Mobility */ +/* ? 0x3bu */ +/* ? 0x3cu */ +/* ? 0x3du */ +/* ? 0x3eu */ +/* ? 0x3fu */ + +/* Definitions for an LTPro's TV registers */ +/* ? 0x00u */ +/* ? 0x01u */ +/* ? 0x02u */ +/* ? 0x03u */ +/* ? 0x04u */ +/* ? 0x05u */ +/* ? 0x06u */ +/* ? 0x07u */ +/* ? 0x08u */ +/* ? 0x09u */ +/* ? 0x0au */ +/* ? 0x0bu */ +/* ? 0x0cu */ +/* ? 0x0du */ +/* ? 0x0eu */ +/* ? 0x0fu */ +#define TV_MASTER_CNTL 0x10u +/* ? 0x11u */ +#define TV_RGB_CNTL 0x12u +/* ? 0x13u */ +#define TV_SYNC_CNTL 0x14u +/* ? 0x15u */ +/* ? 0x16u */ +/* ? 0x17u */ +/* ? 0x18u */ +/* ? 0x19u */ +/* ? 0x1au */ +/* ? 0x1bu */ +/* ? 0x1cu */ +/* ? 0x1du */ +/* ? 0x1eu */ +/* ? 0x1fu */ +#define TV_HTOTAL 0x20u +#define TV_HDISP 0x21u +#define TV_HSIZE 0x22u +#define TV_HSTART 0x23u +#define TV_HCOUNT 0x24u +#define TV_VTOTAL 0x25u +#define TV_VDISP 0x26u +#define TV_VCOUNT 0x27u +#define TV_FTOTAL 0x28u +#define TV_FCOUNT 0x29u +#define TV_FRESTART 0x2au +#define TV_HRESTART 0x2bu +#define TV_VRESTART 0x2cu +/* ? 0x2du */ +/* ? 0x2eu */ +/* ? 0x2fu */ +/* ? 0x30u */ +/* ? 0x31u */ +/* ? 0x32u */ +/* ? 0x33u */ +/* ? 0x34u */ +/* ? 0x35u */ +/* ? 0x36u */ +/* ? 0x37u */ +/* ? 0x38u */ +/* ? 0x39u */ +/* ? 0x3au */ +/* ? 0x3bu */ +/* ? 0x3cu */ +/* ? 0x3du */ +/* ? 0x3eu */ +/* ? 0x3fu */ +/* ? 0x40u */ +/* ? 0x41u */ +/* ? 0x42u */ +/* ? 0x43u */ +/* ? 0x44u */ +/* ? 0x45u */ +/* ? 0x46u */ +/* ? 0x47u */ +/* ? 0x48u */ +/* ? 0x49u */ +/* ? 0x4au */ +/* ? 0x4bu */ +/* ? 0x4cu */ +/* ? 0x4du */ +/* ? 0x4eu */ +/* ? 0x4fu */ +/* ? 0x50u */ +/* ? 0x51u */ +/* ? 0x52u */ +/* ? 0x53u */ +/* ? 0x54u */ +/* ? 0x55u */ +/* ? 0x56u */ +/* ? 0x57u */ +/* ? 0x58u */ +/* ? 0x59u */ +/* ? 0x5au */ +/* ? 0x5bu */ +/* ? 0x5cu */ +/* ? 0x5du */ +/* ? 0x5eu */ +/* ? 0x5fu */ +#define TV_HOST_READ_DATA 0x60u +#define TV_HOST_WRITE_DATA 0x61u +#define TV_HOST_RD_WT_CNTL 0x62u +/* ? 0x63u */ +/* ? 0x64u */ +/* ? 0x65u */ +/* ? 0x66u */ +/* ? 0x67u */ +/* ? 0x68u */ +/* ? 0x69u */ +/* ? 0x6au */ +/* ? 0x6bu */ +/* ? 0x6cu */ +/* ? 0x6du */ +/* ? 0x6eu */ +/* ? 0x6fu */ +#define TV_VSCALER_CNTL 0x70u +#define TV_TIMING_CNTL 0x71u +#define TV_GAMMA_CNTL 0x72u +#define TV_Y_FALL_CNTL 0x73u +#define TV_Y_RISE_CNTL 0x74u +#define TV_Y_SAW_TOOTH_CNTL 0x75u +/* ? 0x76u */ +/* ? 0x77u */ +/* ? 0x78u */ +/* ? 0x79u */ +/* ? 0x7au */ +/* ? 0x7bu */ +/* ? 0x7cu */ +/* ? 0x7du */ +/* ? 0x7eu */ +/* ? 0x7fu */ +#define TV_MODULATOR_CNTL1 0x80u +#define TV_MODULATOR_CNTL2 0x81u +/* ? 0x82u */ +/* ? 0x83u */ +/* ? 0x84u */ +/* ? 0x85u */ +/* ? 0x86u */ +/* ? 0x87u */ +/* ? 0x88u */ +/* ? 0x89u */ +/* ? 0x8au */ +/* ? 0x8bu */ +/* ? 0x8cu */ +/* ? 0x8du */ +/* ? 0x8eu */ +/* ? 0x8fu */ +#define TV_PRE_DAC_MUX_CNTL 0x90u +/* ? 0x91u */ +/* ? 0x92u */ +/* ? 0x93u */ +/* ? 0x94u */ +/* ? 0x95u */ +/* ? 0x96u */ +/* ? 0x97u */ +/* ? 0x98u */ +/* ? 0x99u */ +/* ? 0x9au */ +/* ? 0x9bu */ +/* ? 0x9cu */ +/* ? 0x9du */ +/* ? 0x9eu */ +/* ? 0x9fu */ +#define TV_DAC_CNTL 0xa0u +/* ? 0xa1u */ +/* ? 0xa2u */ +/* ? 0xa3u */ +/* ? 0xa4u */ +/* ? 0xa5u */ +/* ? 0xa6u */ +/* ? 0xa7u */ +/* ? 0xa8u */ +/* ? 0xa9u */ +/* ? 0xaau */ +/* ? 0xabu */ +/* ? 0xacu */ +/* ? 0xadu */ +/* ? 0xaeu */ +/* ? 0xafu */ +#define TV_CRC_CNTL 0xb0u +#define TV_VIDEO_PORT_SIG 0xb1u +/* ? 0xb2u */ +/* ? 0xb3u */ +/* ? 0xb4u */ +/* ? 0xb5u */ +/* ? 0xb6u */ +/* ? 0xb7u */ +#define TV_VBI_CC_CNTL 0xb8u +#define TV_VBI_EDS_CNTL 0xb9u +#define TV_VBI_20BIT_CNTL 0xbau +/* ? 0xbbu */ +/* ? 0xbcu */ +#define TV_VBI_DTO_CNTL 0xbdu +#define TV_VBI_LEVEL_CNTL 0xbeu +/* ? 0xbfu */ +#define TV_UV_ADR 0xc0u +#define TV_FIFO_TEST_CNTL 0xc1u +/* ? 0xc2u */ +/* ? 0xc3u */ +/* ? 0xc4u */ +/* ? 0xc5u */ +/* ? 0xc6u */ +/* ? 0xc7u */ +/* ? 0xc8u */ +/* ? 0xc9u */ +/* ? 0xcau */ +/* ? 0xcbu */ +/* ? 0xccu */ +/* ? 0xcdu */ +/* ? 0xceu */ +/* ? 0xcfu */ +/* ? 0xd0u */ +/* ? 0xd1u */ +/* ? 0xd2u */ +/* ? 0xd3u */ +/* ? 0xd4u */ +/* ? 0xd5u */ +/* ? 0xd6u */ +/* ? 0xd7u */ +/* ? 0xd8u */ +/* ? 0xd9u */ +/* ? 0xdau */ +/* ? 0xdbu */ +/* ? 0xdcu */ +/* ? 0xddu */ +/* ? 0xdeu */ +/* ? 0xdfu */ +/* ? 0xe0u */ +/* ? 0xe1u */ +/* ? 0xe2u */ +/* ? 0xe3u */ +/* ? 0xe4u */ +/* ? 0xe5u */ +/* ? 0xe6u */ +/* ? 0xe7u */ +/* ? 0xe8u */ +/* ? 0xe9u */ +/* ? 0xeau */ +/* ? 0xebu */ +/* ? 0xecu */ +/* ? 0xedu */ +/* ? 0xeeu */ +/* ? 0xefu */ +/* ? 0xf0u */ +/* ? 0xf1u */ +/* ? 0xf2u */ +/* ? 0xf3u */ +/* ? 0xf4u */ +/* ? 0xf5u */ +/* ? 0xf6u */ +/* ? 0xf7u */ +/* ? 0xf8u */ +/* ? 0xf9u */ +/* ? 0xfau */ +/* ? 0xfbu */ +/* ? 0xfcu */ +/* ? 0xfdu */ +/* ? 0xfeu */ +/* ? 0xffu */ + +/* Some ImpacTV definitions */ +#define IT_SDA_GET 0x40u +#define IT_SDA_SET 0x20u +#define IT_SDA_DIR 0x10u +#define IT_SCL_GET 0x04u +#define IT_SCL_SET 0x02u +#define IT_SCL_DIR 0x01u + +#define IT_I2C_CNTL 0x0015u + +/* Miscellaneous */ + +/* Current X, Y & Dest X, Y mask */ +#define COORD_MASK 0x07ffu + +/* Pixel widths */ +#define PIX_WIDTH_1BPP 0x00u +#define PIX_WIDTH_4BPP 0x01u /* CRTC2: 8bpp */ +#define PIX_WIDTH_8BPP 0x02u /* CRTC2: Undefined */ +#define PIX_WIDTH_15BPP 0x03u +#define PIX_WIDTH_16BPP 0x04u +#define PIX_WIDTH_24BPP 0x05u +#define PIX_WIDTH_32BPP 0x06u +#define PIX_WIDTH_YUV422 0x07u /* CRTC2 only */ + +/* Source definitions */ +#define SRC_BKGD 0x00u +#define SRC_FRGD 0x01u +#define SRC_HOST 0x02u +#define SRC_BLIT 0x03u +#define SRC_PATTERN 0x04u +#define SRC_SCALER_3D 0x05u +/* ? 0x06u */ +/* ? 0x07u */ + +/* The Mixes */ +#define MIX_MASK 0x001fu + +#define MIX_NOT_DST 0x0000u +#define MIX_0 0x0001u +#define MIX_1 0x0002u +#define MIX_DST 0x0003u +#define MIX_NOT_SRC 0x0004u +#define MIX_XOR 0x0005u +#define MIX_XNOR 0x0006u +#define MIX_SRC 0x0007u +#define MIX_NAND 0x0008u +#define MIX_NOT_SRC_OR_DST 0x0009u +#define MIX_SRC_OR_NOT_DST 0x000au +#define MIX_OR 0x000bu +#define MIX_AND 0x000cu +#define MIX_SRC_AND_NOT_DST 0x000du +#define MIX_NOT_SRC_AND_DST 0x000eu +#define MIX_NOR 0x000fu + +#define MIX_MIN 0x0010u +#define MIX_DST_MINUS_SRC 0x0011u +#define MIX_SRC_MINUS_DST 0x0012u +#define MIX_PLUS 0x0013u +#define MIX_MAX 0x0014u +#define MIX_HALF__DST_MINUS_SRC 0x0015u +#define MIX_HALF__SRC_MINUS_DST 0x0016u +#define MIX_AVERAGE 0x0017u +#define MIX_DST_MINUS_SRC_SAT 0x0018u +#define MIX_SRC_MINUS_DST_SAT 0x001au +#define MIX_HALF__DST_MINUS_SRC_SAT 0x001cu +#define MIX_HALF__SRC_MINUS_DST_SAT 0x001eu +#define MIX_AVERAGE_SAT 0x001fu +#define MIX_FN_PAINT MIX_SRC + +/* Video/Graphics mix functions for overlay */ +#define OVERLAY_MIX_FALSE 0x00u +#define OVERLAY_MIX_TRUE 0x01u +/* ? 0x02u */ +/* ? 0x03u */ +#define OVERLAY_MIX_NOT_EQUAL 0x04u +#define OVERLAY_MIX_EQUAL 0x05u +/* ? 0x06u */ +/* ? 0x07u */ + +#endif /* ___ATIREGS_H___ */ diff --git a/src/atirgb514.c b/src/atirgb514.c new file mode 100644 index 0000000..e0e215e --- /dev/null +++ b/src/atirgb514.c @@ -0,0 +1,280 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atirgb514.c,v 1.4 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "aticrtc.h" +#include "atimach64io.h" +#include "atirgb514.h" + +/* + * ATIRGB514PreInit -- + * + * This function fills in the IBM RGB 514 portion of an ATIHWRec that is common + * to all video modes generated by the server. + */ +void +ATIRGB514PreInit +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + /* Get a work copy of IBM RGB 514 registers */ + ATIRGB514Save(pATI, pATIHW); + + /* Miscellaneous Clock Control */ + pATIHW->ibmrgb514[0x0002U] = 0x01U; + + /* Sync Control */ + pATIHW->ibmrgb514[0x0003U] &= ~0x80U; + + /* Horizontal Sync Control */ + pATIHW->ibmrgb514[0x0004U] = 0x00U; + + /* Power Management */ + pATIHW->ibmrgb514[0x0005U] = 0x00U; + + /* DAC Operation */ + pATIHW->ibmrgb514[0x0006U] &= ~0x04U; + + /* Palette Control */ + pATIHW->ibmrgb514[0x0007U] = 0x00U; + + /* PLL Control */ + pATIHW->ibmrgb514[0x0010U] = 0x01U; + + /* Cursor control */ + pATIHW->ibmrgb514[0x0030U] &= ~0x03U; /* For now */ + + /* Border (i.e. overscan) */ + pATIHW->ibmrgb514[0x0060U] = 0x00U; + pATIHW->ibmrgb514[0x0061U] = 0x00U; + pATIHW->ibmrgb514[0x0062U] = 0x00U; + + /* Miscellaneous Control */ + pATIHW->ibmrgb514[0x0070U] &= ~0x20U; + pATIHW->ibmrgb514[0x0071U] = 0x41U; /* See workaround in ATIRGB514Set() */ + +#ifndef AVOID_CPIO + + if (pATIHW->crtc == ATI_CRTC_VGA) + { + /* Pixel Format */ + pATIHW->ibmrgb514[0x000AU] = 0x03U; + + /* Miscellaneous Control */ + pATIHW->ibmrgb514[0x0070U] |= 0x40U; + + /* VRAM Mask */ + pATIHW->ibmrgb514[0x0090U] = 0x03U; + } + else + +#endif /* AVOID_CPIO */ + + { + /* Miscellaneous Control */ + pATIHW->ibmrgb514[0x0070U] &= ~0x40U; + + /* VRAM Mask */ + pATIHW->ibmrgb514[0x0090U] = 0x00U; + pATIHW->ibmrgb514[0x0091U] = 0x00U; + + /* Pixel Format */ + switch (pATI->depth) + { + case 8: + pATIHW->ibmrgb514[0x000AU] = 0x03U; + pATIHW->ibmrgb514[0x000BU] = 0x00U; + break; + + case 15: + pATIHW->ibmrgb514[0x000AU] = 0x04U; + pATIHW->ibmrgb514[0x000CU] = 0xC4U; + break; + + case 16: + pATIHW->ibmrgb514[0x000AU] = 0x04U; + pATIHW->ibmrgb514[0x000CU] = 0xC6U; + break; + + case 24: + if (pATI->bitsPerPixel == 24) + { + pATIHW->ibmrgb514[0x000AU] = 0x05U; + pATIHW->ibmrgb514[0x000DU] = 0x01U; + } + else + { + pATIHW->ibmrgb514[0x000AU] = 0x06U; + pATIHW->ibmrgb514[0x000EU] = 0x03U; + } + break; + + default: + break; + } + } + + if (pATI->rgbBits == 8) + pATIHW->ibmrgb514[0x0071U] |= 0x04U; +} + +/* + * ATIRGB514Save -- + * + * This function saves IBM RGB514 related data into an ATIHWRec. + */ +void +ATIRGB514Save +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + CARD32 crtc_gen_cntl, dac_cntl; + CARD8 index_lo, index_hi, index_ctl; + int Index; + + /* Temporarily switch to Mach64 CRTC */ + crtc_gen_cntl = inr(CRTC_GEN_CNTL); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN); + + /* Temporarily switch to IBM RGB 514 registers */ + dac_cntl = inr(DAC_CNTL) & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3); + outr(DAC_CNTL, dac_cntl | DAC_EXT_SEL_RS2); + + index_lo = in8(M64_DAC_WRITE); + index_hi = in8(M64_DAC_DATA); + index_ctl = in8(M64_DAC_READ); + + out8(M64_DAC_WRITE, 0x00U); + out8(M64_DAC_DATA, 0x00U); + out8(M64_DAC_READ, 0x01U); /* Auto-increment */ + + /* Save IBM RGB 514 registers */ + for (Index = 0; Index < NumberOf(pATIHW->ibmrgb514); Index++) + { + /* Need to rewrite the index every so often... */ + if ((Index == 0x0100) || (Index == 0x0500)) + { + out8(M64_DAC_WRITE, 0); + out8(M64_DAC_DATA, Index >> 8); + } + pATIHW->ibmrgb514[Index] = in8(M64_DAC_MASK); + } + + /* Restore registers */ + out8(M64_DAC_WRITE, index_lo); + out8(M64_DAC_DATA, index_hi); + out8(M64_DAC_READ, index_ctl); + outr(DAC_CNTL, dac_cntl); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl); +} + +/* + * ATIRGB514Calculate -- + * + * This function fills in the IBM RGB 514 portion of an ATIHWRec that is + * specific to a display mode. pATIHW->ibmrgb514 has already been + * initialised by a previous call to ATIRGB514PreInit(). + */ +void +ATIRGB514Calculate +( + ATIPtr pATI, + ATIHWPtr pATIHW, + DisplayModePtr pMode +) +{ + if (pATI->OptionCSync || (pMode->Flags & (V_CSYNC | V_PCSYNC))) + pATIHW->ibmrgb514[0x0006U] |= 0x08U; + else + pATIHW->ibmrgb514[0x0006U] &= ~0x08U; + + if (pMode->Flags & V_INTERLACE) + pATIHW->ibmrgb514[0x0071U] |= 0x20U; + else + pATIHW->ibmrgb514[0x0071U] &= ~0x20U; +} + +/* + * ATIRGB514Set -- + * + * This function is called to set an IBM RGB514's registers. + */ +void +ATIRGB514Set +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + CARD32 crtc_gen_cntl, dac_cntl; + CARD8 index_lo, index_hi, index_ctl; + int Index; + + /* Temporarily switch to Mach64 CRTC */ + crtc_gen_cntl = inr(CRTC_GEN_CNTL); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN); + + /* Temporarily switch to IBM RGB 514 registers */ + dac_cntl = inr(DAC_CNTL) & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3); + outr(DAC_CNTL, dac_cntl | DAC_EXT_SEL_RS2); + + index_lo = in8(M64_DAC_WRITE); + index_hi = in8(M64_DAC_DATA); + index_ctl = in8(M64_DAC_READ); + + out8(M64_DAC_WRITE, 0x00U); + out8(M64_DAC_DATA, 0x00U); + out8(M64_DAC_READ, 0x01U); /* Auto-increment */ + + /* Load IBM RGB 514 registers */ + for (Index = 0; Index < NumberOf(pATIHW->ibmrgb514); Index++) + out8(M64_DAC_MASK, pATIHW->ibmrgb514[Index]); + +#ifndef AVOID_CPIO + + /* Deal with documented anomaly */ + if (pATIHW->crtc == ATI_CRTC_VGA) + { + /* Reset Miscellaneous Control 2 */ + out8(M64_DAC_WRITE, 0x71U); + out8(M64_DAC_DATA, 0x00U); + out8(M64_DAC_MASK, pATIHW->ibmrgb514[0x0071U] & ~0x41U); + } + +#endif /* AVOID_CPIO */ + + /* Restore registers */ + out8(M64_DAC_WRITE, index_lo); + out8(M64_DAC_DATA, index_hi); + out8(M64_DAC_READ, index_ctl); + outr(DAC_CNTL, dac_cntl); + if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) + outr(CRTC_GEN_CNTL, crtc_gen_cntl); +} diff --git a/src/atirgb514.h b/src/atirgb514.h new file mode 100644 index 0000000..9cc9b8b --- /dev/null +++ b/src/atirgb514.h @@ -0,0 +1,38 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atirgb514.h,v 1.3 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIRGB514_H___ +#define ___ATIRGB514_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern void ATIRGB514PreInit FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIRGB514Save FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIRGB514Calculate FunctionPrototype((ATIPtr, ATIHWPtr, + DisplayModePtr)); +extern void ATIRGB514Set FunctionPrototype((ATIPtr, ATIHWPtr)); + +#endif /* ___ATIRGB514_H___ */ diff --git a/src/atiscreen.c b/src/atiscreen.c new file mode 100644 index 0000000..822600d --- /dev/null +++ b/src/atiscreen.c @@ -0,0 +1,349 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiscreen.c,v 1.30 2003/04/23 21:51:30 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiaccel.h" +#include "aticonsole.h" +#include "aticursor.h" +#include "atidac.h" +#include "atidga.h" +#include "atiscreen.h" +#include "atistruct.h" +#include "atixv.h" + +#include "shadowfb.h" +#include "xf86cmap.h" + +#include "xf1bpp.h" +#include "xf4bpp.h" + +#include "fb.h" + +#include "mibank.h" +#include "micmap.h" +#include "mipointer.h" + +/* + * ATIRefreshArea -- + * + * This function is called by the shadow frame buffer code to refresh the + * hardware frame buffer. + */ +static void +ATIRefreshArea +( + ScrnInfoPtr pScreenInfo, + int nBox, + BoxPtr pBox +) +{ + ATIPtr pATI = ATIPTR(pScreenInfo); + pointer pSrc, pDst; + int offset, w, h; + + while (nBox-- > 0) + { + w = (pBox->x2 - pBox->x1) * pATI->AdjustDepth; + h = pBox->y2 - pBox->y1; + offset = (pBox->y1 * pATI->FBPitch) + (pBox->x1 * pATI->AdjustDepth); + pSrc = (char *)pATI->pShadow + offset; + pDst = (char *)pATI->pMemory + offset; + + while (h-- > 0) + { + (void)memcpy(pDst, pSrc, w); + pSrc = (char *)pSrc + pATI->FBPitch; + pDst = (char *)pDst + pATI->FBPitch; + } + + pBox++; + } +} + +/* + * ATIScreenInit -- + * + * This function is called by DIX to initialise the screen. + */ +Bool +ATIScreenInit +( + int iScreen, + ScreenPtr pScreen, + int argc, + char **argv +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; + ATIPtr pATI = ATIPTR(pScreenInfo); + pointer pFB; + int VisualMask; + + /* Set video hardware state */ + if (!ATIEnterGraphics(pScreen, pScreenInfo, pATI)) + return FALSE; + + /* Re-initialise mi's visual list */ + miClearVisualTypes(); + + if ((pATI->depth > 8) && (pATI->DAC == ATI_DAC_INTERNAL)) + VisualMask = TrueColorMask; + else + VisualMask = miGetDefaultVisualMask(pATI->depth); + + if (!miSetVisualTypes(pATI->depth, VisualMask, pATI->rgbBits, + pScreenInfo->defaultVisual)) + return FALSE; + + if (!miSetPixmapDepths()) + return FALSE; + + pFB = pATI->pMemory; + pATI->FBPitch = PixmapBytePad(pATI->displayWidth, pATI->depth); + if (pATI->OptionShadowFB) + { + if ((pATI->pShadow = xalloc(pATI->FBPitch * pScreenInfo->virtualY))) + { + pFB = pATI->pShadow; + } + else + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "Insufficient virtual memory for shadow frame buffer.\n"); + pATI->OptionShadowFB = FALSE; + } + } + + /* Initialise framebuffer layer */ + switch (pATI->bitsPerPixel) + { + +#ifndef AVOID_CPIO + + case 1: + pATI->Closeable = xf1bppScreenInit(pScreen, pFB, + pScreenInfo->virtualX, pScreenInfo->virtualY, + pScreenInfo->xDpi, pScreenInfo->yDpi, pATI->displayWidth); + break; + + case 4: + pATI->Closeable = xf4bppScreenInit(pScreen, pFB, + pScreenInfo->virtualX, pScreenInfo->virtualY, + pScreenInfo->xDpi, pScreenInfo->yDpi, pATI->displayWidth); + break; + +#endif /* AVOID_CPIO */ + + case 8: + case 16: + case 24: + case 32: + pATI->Closeable = fbScreenInit(pScreen, pFB, + pScreenInfo->virtualX, pScreenInfo->virtualY, + pScreenInfo->xDpi, pScreenInfo->yDpi, pATI->displayWidth, + pATI->bitsPerPixel); + break; + + default: + return FALSE; + } + + if (!pATI->Closeable) + return FALSE; + + /* Fixup RGB ordering */ + if (pATI->depth > 8) + { + VisualPtr pVisual = pScreen->visuals + pScreen->numVisuals; + + while (--pVisual >= pScreen->visuals) + { + if ((pVisual->class | DynamicClass) != DirectColor) + continue; + + pVisual->offsetRed = pScreenInfo->offset.red; + pVisual->offsetGreen = pScreenInfo->offset.green; + pVisual->offsetBlue = pScreenInfo->offset.blue; + + pVisual->redMask = pScreenInfo->mask.red; + pVisual->greenMask = pScreenInfo->mask.green; + pVisual->blueMask = pScreenInfo->mask.blue; + } + } + + /* If applicable, initialise RENDER extension */ + if (pATI->bitsPerPixel > 4) + { + if (pATI->OptionShadowFB) + { + if (serverGeneration == 1) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "RENDER extension not supported with a shadowed" + " framebuffer.\n"); + } + +#ifndef AVOID_CPIO + + else if (pATI->BankInfo.BankSize) + { + if (serverGeneration == 1) + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "RENDER extension not supported with a banked" + " framebuffer.\n"); + } + +#endif /* AVOID_CPIO */ + + else if (!fbPictureInit(pScreen, NULL, 0) && + (serverGeneration == 1)) + { + xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, + "RENDER extension initialisation failed.\n"); + } + } + + xf86SetBlackWhitePixels(pScreen); + +#ifndef AVOID_CPIO + + /* Initialise banking if needed */ + if (!miInitializeBanking(pScreen, + pScreenInfo->virtualX, pScreenInfo->virtualY, + pATI->displayWidth, &pATI->BankInfo)) + return FALSE; + +#endif /* AVOID_CPIO */ + + /* Setup acceleration */ + if (!ATIInitializeAcceleration(pScreen, pScreenInfo, pATI)) + return FALSE; + +#ifndef AVOID_DGA + + /* Initialise DGA support */ + (void)ATIDGAInit(pScreen, pScreenInfo, pATI); + +#endif /* AVOID_DGA */ + + /* Initialise backing store */ + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + + /* Initialise cursor */ + if (!ATIInitializeCursor(pScreen, pATI)) + return FALSE; + + /* Create default colourmap */ + if (!miCreateDefColormap(pScreen)) + return FALSE; + +#ifdef AVOID_CPIO + + if (!xf86HandleColormaps(pScreen, 256, pATI->rgbBits, ATILoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR | + CMAP_LOAD_EVEN_IF_OFFSCREEN)) + return FALSE; + +#else /* AVOID_CPIO */ + + if (pATI->depth > 1) + if (!xf86HandleColormaps(pScreen, (pATI->depth == 4) ? 16 : 256, + pATI->rgbBits, ATILoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR | + CMAP_LOAD_EVEN_IF_OFFSCREEN)) + return FALSE; + +#endif /* AVOID_CPIO */ + + /* Initialise shadow framebuffer */ + if (pATI->OptionShadowFB && + !ShadowFBInit(pScreen, ATIRefreshArea)) + return FALSE; + + /* Initialise DPMS support */ + (void)xf86DPMSInit(pScreen, ATISetDPMSMode, 0); + + /* Initialise XVideo support */ + (void)ATIInitializeXVideo(pScreen, pScreenInfo, pATI); + + /* Set pScreen->SaveScreen and wrap CloseScreen vector */ + pScreen->SaveScreen = ATISaveScreen; + pATI->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = ATICloseScreen; + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScreenInfo->scrnIndex, pScreenInfo->options); + + return TRUE; +} + +/* + * ATICloseScreen -- + * + * This function is called by DIX to close the screen. + */ +Bool +ATICloseScreen +( + int iScreen, + ScreenPtr pScreen +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; + ATIPtr pATI = ATIPTR(pScreenInfo); + Bool Closed = TRUE; + + ATICloseXVideo(pScreen, pScreenInfo, pATI); + + if (pATI->pXAAInfo) + { + XAADestroyInfoRec(pATI->pXAAInfo); + pATI->pXAAInfo = NULL; + } + + if ((pScreen->CloseScreen = pATI->CloseScreen)) + { + pATI->CloseScreen = NULL; + Closed = (*pScreen->CloseScreen)(iScreen, pScreen); + } + + pATI->Closeable = FALSE; + + if (pATI->pCursorInfo) + { + xf86DestroyCursorInfoRec(pATI->pCursorInfo); + pATI->pCursorInfo = NULL; + } + + ATILeaveGraphics(pScreenInfo, pATI); + + xfree(pATI->ExpansionBitmapScanlinePtr[1]); + pATI->ExpansionBitmapScanlinePtr[0] = + pATI->ExpansionBitmapScanlinePtr[1] = NULL; + + xfree(pATI->pShadow); + pATI->pShadow = NULL; + pScreenInfo->pScreen = NULL; + + return Closed; +} diff --git a/src/atiscreen.h b/src/atiscreen.h new file mode 100644 index 0000000..05954ec --- /dev/null +++ b/src/atiscreen.h @@ -0,0 +1,34 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiscreen.h,v 1.6 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATISCREEN_H___ +#define ___ATISCREEN_H___ 1 + +#include "atiproto.h" + +#include "screenint.h" + +extern Bool ATIScreenInit FunctionPrototype((int, ScreenPtr, int, char **)); +extern Bool ATICloseScreen FunctionPrototype((int, ScreenPtr)); + +#endif /* ___ATISCREEN_H___ */ diff --git a/src/atistruct.h b/src/atistruct.h new file mode 100644 index 0000000..a80c8b4 --- /dev/null +++ b/src/atistruct.h @@ -0,0 +1,443 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atistruct.h,v 1.41tsi Exp $ */ +/* + * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATISTRUCT_H___ +#define ___ATISTRUCT_H___ 1 + +#include "atibank.h" +#include "aticlock.h" +#include "atiregs.h" + +#include "xaa.h" +#include "xf86Cursor.h" +#include "xf86Pci.h" +#include "xf86Resources.h" + +#define CacheSlotOf(____Register) ((____Register) / UnitOf(DWORD_SELECT)) + +/* + * This is probably as good a place as any to put this note, as it applies to + * the entire driver, but especially here. CARD8's are used rather than the + * appropriate enum types because the latter would nearly quadruple storage + * requirements (they are stored as int's). This reduces the usefulness of + * enum types to their ability to declare index values. I've also elected to + * forgo the strong typing capabilities of enum types. C is not terribly adept + * at strong typing anyway. + */ + +/* A structure for local data related to video modes */ +typedef struct _ATIHWRec +{ + /* Clock number for mode */ + CARD8 clock; + + /* The CRTC used to drive the screen (VGA, 8514, Mach64) */ + CARD8 crtc; + + /* Colour lookup table */ + CARD8 lut[256 * 3]; + +#ifndef AVOID_CPIO + + /* VGA registers */ + CARD8 genmo, crt[25], seq[5], gra[9], attr[21]; + + /* VGA Wonder registers */ + CARD8 a3, a6, a7, ab, ac, ad, ae, + b0, b1, b2, b3, b5, b6, b8, b9, ba, bd, be, bf; + + /* Shadow VGA CRTC registers */ + CARD8 shadow_vga[25]; + +#endif /* AVOID_CPIO */ + + /* Generic DAC registers */ + CARD8 dac_read, dac_write, dac_mask; + + /* IBM RGB 514 registers */ + CARD8 ibmrgb514[0x0092U]; /* All that's needed for now */ + + /* Mach64 PLL registers */ + CARD8 pll_vclk_cntl, pll_vclk_post_div, + pll_vclk0_fb_div, pll_vclk1_fb_div, + pll_vclk2_fb_div, pll_vclk3_fb_div, + pll_xclk_cntl, pll_ext_vpll_cntl; + + /* Mach64 CPIO registers */ + CARD32 crtc_h_total_disp, crtc_h_sync_strt_wid, + crtc_v_total_disp, crtc_v_sync_strt_wid, + crtc_off_pitch, crtc_gen_cntl, dsp_config, dsp_on_off, + ovr_clr, ovr_wid_left_right, ovr_wid_top_bottom, + cur_clr0, cur_clr1, cur_offset, + cur_horz_vert_posn, cur_horz_vert_off, + clock_cntl, bus_cntl, mem_cntl, mem_vga_wp_sel, mem_vga_rp_sel, + dac_cntl, gen_test_cntl, config_cntl, mpp_config, mpp_strobe_seq, + tvo_cntl; + + /* LCD registers */ + CARD32 lcd_index, config_panel, lcd_gen_ctrl, + horz_stretching, vert_stretching, ext_vert_stretch; + + /* Shadow Mach64 CRTC registers */ + CARD32 shadow_h_total_disp, shadow_h_sync_strt_wid, + shadow_v_total_disp, shadow_v_sync_strt_wid; + + /* Mach64 MMIO Block 0 registers and related subfields */ + CARD32 dst_off_pitch; + CARD16 dst_x, dst_y, dst_height; + CARD32 dst_bres_err, dst_bres_inc, dst_bres_dec, dst_cntl; + CARD32 src_off_pitch; + CARD16 src_x, src_y, src_width1, src_height1, + src_x_start, src_y_start, src_width2, src_height2; + CARD32 src_cntl; + CARD32 host_cntl; + CARD32 pat_reg0, pat_reg1, pat_cntl; + CARD16 sc_left, sc_right, sc_top, sc_bottom; + CARD32 dp_bkgd_clr, dp_frgd_clr, dp_write_mask, dp_chain_mask, + dp_pix_width, dp_mix, dp_src; + CARD32 clr_cmp_clr, clr_cmp_msk, clr_cmp_cntl; + CARD32 context_mask, context_load_cntl; + + /* Mach64 MMIO Block 1 registers */ + CARD32 overlay_y_x_start, overlay_y_x_end, overlay_graphics_key_clr, + overlay_graphics_key_msk, overlay_key_cntl, overlay_scale_inc, + overlay_scale_cntl, scaler_height_width, scaler_test, + scaler_buf0_offset, scaler_buf1_offset, scaler_buf_pitch, + video_format, overlay_exclusive_horz, overlay_exclusive_vert, + buf0_offset, buf0_pitch, buf1_offset, buf1_pitch, + scaler_colour_cntl, scaler_h_coeff0, scaler_h_coeff1, + scaler_h_coeff2, scaler_h_coeff3, scaler_h_coeff4, gui_cntl, + scaler_buf0_offset_u, scaler_buf0_offset_v, scaler_buf1_offset_u, + scaler_buf1_offset_v; + + /* Clock map pointers */ + const CARD8 *ClockMap, *ClockUnmap; + + /* Clock programming data */ + int FeedbackDivider, ReferenceDivider, PostDivider; + +#ifndef AVOID_CPIO + + /* This is used by ATISwap() */ + pointer frame_buffer; + ATIBankProcPtr SetBank; + unsigned int nBank, nPlane; + +#endif /* AVOID_CPIO */ + +} ATIHWRec; + +/* + * This structure defines the driver's private area. + */ +typedef struct _ATIRec +{ + /* + * Definitions related to XF86Config "Chipset" specifications. + */ + CARD8 Chipset; + + /* + * Adapter-related definitions. + */ + CARD8 Adapter; + +#ifndef AVOID_CPIO + + CARD8 VGAAdapter; + +#endif /* AVOID_CPIO */ + + /* + * Chip-related definitions. + */ + CARD32 config_chip_id; + CARD16 ChipType; + CARD8 Chip; + CARD8 ChipClass, ChipRevision, ChipRev, ChipVersion, ChipFoundry; + +#ifndef AVOID_CPIO + + CARD8 Coprocessor, ChipHasSUBSYS_CNTL; + +#endif /* AVOID_CPIO */ + + /* + * Processor I/O decoding definitions. + */ + CARD8 CPIODecoding; + IOADDRESS CPIOBase; + +#ifndef AVOID_CPIO + + /* + * Processor I/O port definition for VGA. + */ + IOADDRESS CPIO_VGABase; + + /* + * Processor I/O port definitions for VGA Wonder. + */ + IOADDRESS CPIO_VGAWonder; + CARD8 B2Reg; /* The B2 mirror */ + CARD8 VGAOffset; /* Low index for CPIO_VGAWonder */ + +#endif /* AVOID_CPIO */ + + /* + * DAC-related definitions. + */ + +#ifndef AVOID_CPIO + + IOADDRESS CPIO_DAC_MASK, CPIO_DAC_DATA, CPIO_DAC_READ, CPIO_DAC_WRITE, + CPIO_DAC_WAIT; + +#endif /* AVOID_CPIO */ + + CARD16 DAC; + CARD8 rgbBits; + + /* + * Definitions related to system bus interface. + */ + pciVideoPtr PCIInfo; + CARD8 BusType; + CARD8 SharedAccelerator; + +#ifndef AVOID_CPIO + + CARD8 SharedVGA; + resRange VGAWonderResources[2]; + +#endif /* AVOID_CPIO */ + + /* + * Definitions related to video memory. + */ + CARD8 MemoryType; + int VideoRAM; + + /* + * BIOS-related definitions. + */ + unsigned long BIOSBase; + CARD8 I2CType, Tuner, Decoder, Audio; + + /* + * Definitions related to video memory apertures. + */ + pointer pMemory, pShadow; + pointer pMemoryLE; /* Always little-endian */ + unsigned long LinearBase; + int LinearSize, FBPitch; + +#ifndef AVOID_CPIO + + /* + * Banking interface. + */ + miBankInfoRec BankInfo; + pointer pBank; + CARD8 UseSmallApertures; + +#endif /* AVOID_CPIO */ + + /* + * Definitions related to MMIO register apertures. + */ + pointer pMMIO, pBlock[2]; + unsigned long Block0Base, Block1Base; + + /* + * XAA interface. + */ + XAAInfoRecPtr pXAAInfo; + int nAvailableFIFOEntries, nFIFOEntries, nHostFIFOEntries; + CARD8 EngineIsBusy, EngineIsLocked, XModifier; + CARD32 dst_cntl; /* For SetupFor/Subsequent communication */ + CARD32 sc_left_right, sc_top_bottom; + CARD16 sc_left, sc_right, sc_top, sc_bottom; /* Current scissors */ + pointer pHOST_DATA; /* Current HOST_DATA_* transfer window address */ + CARD32 *ExpansionBitmapScanlinePtr[2]; + int ExpansionBitmapWidth; + + /* + * Cursor-related definitions. + */ + xf86CursorInfoPtr pCursorInfo; + pointer pCursorPage, pCursorImage; + unsigned long CursorBase; + CARD32 CursorOffset; + CARD16 CursorXOffset, CursorYOffset; + CARD8 Cursor; + + /* + * MMIO cache. + */ + CARD32 MMIOCache[CacheSlotOf(DWORD_SELECT) + 1]; + CARD8 MMIOCached[(CacheSlotOf(DWORD_SELECT) + 8) >> 3]; + + /* + * Clock-related definitions. + */ + int ClockNumberToProgramme, ReferenceNumerator, ReferenceDenominator; + int ProgrammableClock, maxClock; + ClockRec ClockDescriptor; + CARD16 BIOSClocks[16]; + CARD8 Clock; + + /* + * DSP register data. + */ + int XCLKFeedbackDivider, XCLKReferenceDivider, XCLKPostDivider; + CARD16 XCLKMaxRASDelay, XCLKPageFaultDelay, + DisplayLoopLatency, DisplayFIFODepth; + + /* + * LCD panel data. + */ + int LCDPanelID, LCDClock, LCDHorizontal, LCDVertical; + unsigned LCDHSyncStart, LCDHSyncWidth, LCDHBlankWidth; + unsigned LCDVSyncStart, LCDVSyncWidth, LCDVBlankWidth; + int LCDVBlendFIFOSize; + + /* + * Data used by ATIAdjustFrame(). + */ + int AdjustDepth, AdjustMaxX, AdjustMaxY; + unsigned long AdjustMask, AdjustMaxBase; + + /* + * DGA and non-DGA common data. + */ + DisplayModePtr currentMode; + CARD8 depth, bitsPerPixel; + short int displayWidth; + int pitchInc; + rgb weight; + +#ifndef AVOID_DGA + + /* + * DGA-related data. + */ + DGAModePtr pDGAMode; + DGAFunctionRec ATIDGAFunctions; + int nDGAMode; + + /* + * XAAForceTransBlit alters the behavior of 'SetupForScreenToScreenCopy', + * such that ~0 is interpreted as a legitimate transparency key. + */ + CARD8 XAAForceTransBlit; + +#endif /* AVOID_DGA */ + + /* + * XVideo-related data. + */ + DevUnion XVPortPrivate[1]; + FBLinearPtr pXVBuffer; + RegionRec VideoClip; + int SurfacePitch, SurfaceOffset; + CARD8 AutoPaint, DoubleBuffer, CurrentBuffer, ActiveSurface; + + /* + * Data saved by ATIUnlock() and restored by ATILock(). + */ + struct + { + /* Mach64 registers */ + CARD32 crtc_int_cntl, crtc_gen_cntl, i2c_cntl_0, hw_debug, + scratch_reg3, bus_cntl, lcd_index, mem_cntl, i2c_cntl_1, + dac_cntl, gen_test_cntl, mpp_config, mpp_strobe_seq, tvo_cntl; + +#ifndef AVOID_CPIO + + CARD32 config_cntl; + + /* Mach8/Mach32 registers */ + CARD16 clock_sel, misc_options, mem_bndry, mem_cfg; + + /* VGA Wonder registers */ + CARD8 a6, ab, b1, b4, b5, b6, b8, b9, be; + + /* VGA registers */ + CARD8 crt03, crt11; + + /* VGA shadow registers */ + CARD8 shadow_crt03, shadow_crt11; + +#endif /* AVOID_CPIO */ + + } LockData; + + /* Mode data */ + ATIHWRec OldHW, NewHW; + int MaximumInterlacedPitch; + Bool InterlacedSeen; + + /* + * Resource Access Control entity index. + */ + int iEntity; + + /* + * Driver options. + */ + CARD8 OptionAccel:1; /* Use hardware draw engine */ + CARD8 OptionBIOSDisplay:1; /* Allow BIOS interference */ + CARD8 OptionBlend:1; /* Force horizontal blending */ + CARD8 OptionCRTDisplay:1; /* Display on both CRT and digital panel */ + CARD8 OptionCSync:1; /* Use composite sync */ + CARD8 OptionDevel:1; /* Intentionally undocumented */ + +#ifndef AVOID_CPIO + + CARD8 OptionLinear:1; /* Use linear fb aperture when available */ + +#endif /* AVOID_CPIO */ + + CARD8 OptionMMIOCache:1; /* Cache MMIO writes */ + CARD8 OptionTestMMIOCache:1;/* Test MMIO cache integrity */ + CARD8 OptionPanelDisplay:1; /* Prefer digital panel over CRT */ + CARD8 OptionProbeClocks:1; /* Force probe for fixed clocks */ + CARD8 OptionShadowFB:1; /* Use shadow frame buffer */ + CARD8 OptionLCDSync:1; /* Temporary */ + + /* + * State flags. + */ + CARD8 Unlocked, Mapped, Closeable; + CARD8 MMIOInLinear; + + /* + * Wrapped functions. + */ + CloseScreenProcPtr CloseScreen; +} ATIRec; + +#define ATIPTR(_p) ((ATIPtr)((_p)->driverPrivate)) + +#endif /* ___ATISTRUCT_H___ */ diff --git a/src/atituner.c b/src/atituner.c new file mode 100644 index 0000000..9e5eb12 --- /dev/null +++ b/src/atituner.c @@ -0,0 +1,174 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atituner.c,v 1.1 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atituner.h" + +/* Temporary interface glitch */ +#if 0 +# include "fi12x6.h" +#else + typedef enum { + FI12x6_TYPE_UNKNOWN = -1, + FI12x6_TYPE_FI1236 = 0, + FI12x6_TYPE_FI1216, + FI12x6_TYPE_FI1216MF, + FI12x6_TYPE_TEMIC_FN5AL, + FI12x6_TYPE_MT2032, + FI12x6_TYPE_MAX /* Must be last */ + } FI12x6TunerType; +#endif + +/* + * TV tuner definitions. + */ +const SymTabRec ATITuners[] = +{ + { + FI12x6_TYPE_UNKNOWN, + "No tuner" + }, + { + FI12x6_TYPE_FI1236, + "Philips FI1236 MK1 NTSC M/N North America" + }, + { + FI12x6_TYPE_FI1236, + "Philips FI1236 MK2 NTSC M/N Japan" + }, + { + FI12x6_TYPE_FI1216, + "Philips FI1216 MK2 PAL B/G" + }, + { + FI12x6_TYPE_UNKNOWN, + "Philips FI1246 MK2 PAL I" + }, + { + FI12x6_TYPE_FI1216MF, + "Philips FI1216 MF MK2 PAL B/G, SECAM L/L" + }, + { + FI12x6_TYPE_FI1236, + "Philips FI1236 MK2 NTSC M/N North America" + }, + { + FI12x6_TYPE_UNKNOWN, + "Philips FI1256 MK2 SECAM D/K" + }, + { + FI12x6_TYPE_FI1236, + "Philips FM1236 MK2 NTSC M/N North America" + }, + { + FI12x6_TYPE_FI1216, + "Philips FI1216 MK2 PAL B/G - External Tuner POD" + }, + { + FI12x6_TYPE_UNKNOWN, + "Philips FI1246 MK2 PAL I - External Tuner POD" + }, + { + FI12x6_TYPE_FI1216MF, + "Philips FI1216 MF MK2 PAL B/G, SECAM L/L - External Tuner POD" + }, + { + FI12x6_TYPE_FI1236, + "Philips FI1236 MK2 NTSC M/N North America - External Tuner POD" + }, + { + FI12x6_TYPE_TEMIC_FN5AL, + "Temic FN5AL.RF3X7595 PAL I/B/G/DK & SECAM DK" + }, + { + FI12x6_TYPE_FI1216MF, + "Philips FQ1216 ME/P" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (15)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Alps TSBH5 NTSC M/N North America" + }, + { + FI12x6_TYPE_UNKNOWN, + "Alps TSC?? NTSC M/N North America" + }, + { + FI12x6_TYPE_UNKNOWN, + "Alps TSCH5 NTSC M/N North America with FM" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (19)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (20)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (21)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (22)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (23)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (24)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (25)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (26)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (27)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (28)" + }, + { + FI12x6_TYPE_MT2032, + "Microtune MT2032" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (30)" + }, + { + FI12x6_TYPE_UNKNOWN, + "Unknown type (31)" + } +}; diff --git a/src/atituner.h b/src/atituner.h new file mode 100644 index 0000000..2b40d30 --- /dev/null +++ b/src/atituner.h @@ -0,0 +1,70 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atituner.h,v 1.1 2003/07/24 22:08:28 tsi Exp $ */ +/* + * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATITUNER_H___ +#define ___ATITUNER_H___ 1 + +#include "xf86str.h" + +/* + * TV Tuner definitions. Most of these are from Philips. + */ +typedef enum +{ + ATI_TUNER_NONE, + ATI_TUNER_FI1236MK1NA, + ATI_TUNER_FI1236MK2J, + ATI_TUNER_FI1216MK2BG, + ATI_TUNER_FI1246MK2I, + ATI_TUNER_FI1216MFMK2, + ATI_TUNER_FI1236MK2NA, + ATI_TUNER_FI1256MK2DK, + ATI_TUNER_FM1236MK2NA, + ATI_TUNER_FI1216MK2BGEXT, + ATI_TUNER_FI1246MK2IEXT, + ATI_TUNER_FI1216MFMK2EXT, + ATI_TUNER_FI1236MK2NAEXT, + ATI_TUNER_TEMIC_FN5AL, + ATI_TUNER_FQ1216MEP, + ATI_TUNER_15, + ATI_TUNER_ALPS_TSBH5, + ATI_TUNER_ALPS_TSCXX, + ATI_TUNER_ALPS_TSCH5, + ATI_TUNER_19, + ATI_TUNER_20, + ATI_TUNER_21, + ATI_TUNER_22, + ATI_TUNER_23, + ATI_TUNER_24, + ATI_TUNER_25, + ATI_TUNER_26, + ATI_TUNER_27, + ATI_TUNER_28, + ATI_TUNER_MT2032, + ATI_TUNER_30, + ATI_TUNER_31 +} ATITunerType; + +extern const SymTabRec ATITuners[]; + +#endif /* ___ATITUNER_H___ */ diff --git a/src/atiutil.c b/src/atiutil.c new file mode 100644 index 0000000..3ea2e8e --- /dev/null +++ b/src/atiutil.c @@ -0,0 +1,114 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiutil.c,v 1.8 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiutil.h" + +/* + * ATIReduceRatio -- + * + * Reduce a fraction by factoring out the largest common divider of the + * fraction's numerator and denominator. + */ +void +ATIReduceRatio +( + int *Numerator, + int *Denominator +) +{ + int Multiplier, Divider, Remainder; + + Multiplier = *Numerator; + Divider = *Denominator; + + while ((Remainder = Multiplier % Divider)) + { + Multiplier = Divider; + Divider = Remainder; + } + + *Numerator /= Divider; + *Denominator /= Divider; +} + +/* + * ATIDivide -- + * + * Using integer arithmetic and avoiding overflows, this function finds the + * rounded integer that best approximates + * + * Numerator Shift + * ----------- * 2 + * Denominator + * + * using the specified rounding (floor (<0), nearest (=0) or ceiling (>0)). + */ +int +ATIDivide +( + int Numerator, + int Denominator, + int Shift, + const int RoundingKind +) +{ + int Rounding = 0; /* Default to floor */ + +#define MaxInt ((int)((unsigned int)(-1) >> 2)) + + ATIReduceRatio(&Numerator, &Denominator); + + /* Deal with left shifts but try to keep the denominator even */ + if (Denominator & 1) + { + if (Denominator <= MaxInt) + { + Denominator <<= 1; + Shift++; + } + } + else while ((Shift > 0) && !(Denominator & 3)) + { + Denominator >>= 1; + Shift--; + } + + /* Deal with right shifts */ + while (Shift < 0) + { + if ((Numerator & 1) && (Denominator <= MaxInt)) + Denominator <<= 1; + else + Numerator >>= 1; + + Shift++; + } + + if (!RoundingKind) /* Nearest */ + Rounding = Denominator >> 1; + else if (RoundingKind > 0) /* Ceiling */ + Rounding = Denominator - 1; + + return ((Numerator / Denominator) << Shift) + + ((((Numerator % Denominator) << Shift) + Rounding) / Denominator); +} diff --git a/src/atiutil.h b/src/atiutil.h new file mode 100644 index 0000000..038102d --- /dev/null +++ b/src/atiutil.h @@ -0,0 +1,70 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiutil.h,v 1.8 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIUTIL_H___ +#define ___ATIUTIL_H___ 1 + +#include "atiproto.h" + +/* + * Prevent the C standard's insistence on unsigned long sizeof's from causing + * counter-intuitive results. + */ +#define SizeOf(_object) ((int)sizeof(_object)) +#define NumberOf(_what) (SizeOf(_what) / SizeOf(_what[0])) + +#define __ONE_MICROSECOND__ 100 /* This'll need calibration */ + +#define ATIDelay(_microseconds) \ + { \ + unsigned int _i, _j; \ + for (_i = 0; _i < _microseconds; _i++) \ + for (_j = 0; _j < __ONE_MICROSECOND__; _j++) \ + /* Nothing */; \ + } + +/* + * Macros to get/set a contiguous bit field. Arguments should not be + * self-modifying. + */ +#define UnitOf(___Value) \ + (((((___Value) ^ ((___Value) - 1)) + 1) >> 1) | \ + ((((___Value) ^ ((___Value) - 1)) >> 1) + 1)) + +#define GetBits(__Value, _Mask) (((__Value) & (_Mask)) / UnitOf(_Mask)) +#define SetBits(__Value, _Mask) (((__Value) * UnitOf(_Mask)) & (_Mask)) + +#define MaxBits(__Mask) GetBits(__Mask, __Mask) + +#define _ByteMask(__Byte) ((CARD8)(-1) << (8 * (__Byte))) +#define GetByte(_Value, _Byte) GetBits(_Value, _ByteMask(_Byte)) +#define SetByte(_Value, _Byte) SetBits(_Value, _ByteMask(_Byte)) + +#define _WordMask(__Word) ((CARD16)(-1) << (16 * (__Word))) +#define GetWord(_Value, _Word) GetBits(_Value, _WordMask(_Word)) +#define SetWord(_Value, _Word) SetBits(_Value, _WordMask(_Word)) + +extern void ATIReduceRatio FunctionPrototype((int *, int *)); +extern int ATIDivide FunctionPrototype((int, int, int, const int)); + +#endif /* ___ATIUTIL_H___ */ diff --git a/src/ativalid.c b/src/ativalid.c new file mode 100644 index 0000000..e3ada17 --- /dev/null +++ b/src/ativalid.c @@ -0,0 +1,235 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativalid.c,v 1.17 2003/10/30 17:36:58 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiadapter.h" +#include "atichip.h" +#include "aticrtc.h" +#include "atistruct.h" +#include "ativalid.h" + +#include "xf86.h" + +/* + * ATIValidMode -- + * + * This checks for hardware-related limits on mode timings. + */ +ModeStatus +ATIValidMode +( + int iScreen, + DisplayModePtr pMode, + Bool Verbose, + int flags +) +{ + ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; + ATIPtr pATI = ATIPTR(pScreenInfo); + Bool InterlacedSeen; + int HBlankWidth, HAdjust, VScan, VInterlace; + +#ifndef AVOID_CPIO + + int VDisplay, VTotal; + +#endif /* AVOID_CPIO */ + + if (flags & MODECHECK_FINAL) + { + /* + * This is the final check before the common layer accepts a mode. + * pScreenInfo->displayWidth is set to the proposed virtual pitch + * should the mode be accepted. The only check needed here is for + * 18800's and 28800's, which don't support interlaced modes if the + * pitch is over half the chipset's maximum pitch. + */ + if (pATI->MaximumInterlacedPitch) + { + /* + * Ensure no interlaced modes have a scanline pitch larger than the + * limit. + */ + if (pMode->Flags & V_INTERLACE) + InterlacedSeen = TRUE; + else + InterlacedSeen = pATI->InterlacedSeen; + + if (InterlacedSeen && + (pScreenInfo->displayWidth > pATI->MaximumInterlacedPitch)) + return MODE_INTERLACE_WIDTH; + + pATI->InterlacedSeen = InterlacedSeen; + } + + return MODE_OK; + } + + /* + * The following is done for every mode in the monitor section that + * survives the common layer's basic checks. + */ + if (pMode->VScan <= 1) + VScan = 1; + else + VScan = pMode->VScan; + + if (pMode->Flags & V_DBLSCAN) + VScan <<= 1; + + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) + { + if ((pMode->CrtcHDisplay > pATI->LCDHorizontal) || + (pMode->CrtcVDisplay > pATI->LCDVertical)) + return MODE_PANEL; + + if (!pATI->OptionLCDSync || (pMode->type & M_T_BUILTIN)) + { + if ((pMode->HDisplay > pATI->LCDHorizontal) || + (pMode->VDisplay > pATI->LCDVertical)) + return MODE_PANEL; + + return MODE_OK; + } + + /* + * Adjust effective timings for monitor checks. Here the modeline + * clock is ignored. Horizontal timings are scaled by the stretch + * ratio used for the displayed area. The vertical porch is scaled by + * the native resolution's aspect ratio. This seems rather arbitrary, + * and it is, but it does make all applicable VESA modes sync on a + * panel after stretching. This has the unfortunate, but necessary, + * side-effect of changing the mode's horizontal sync and vertical + * refresh rates. With some exceptions, this tends to increase the + * mode's horizontal sync rate, and decrease its vertical refresh rate. + */ + pMode->SynthClock = pATI->LCDClock; + + pMode->CrtcHTotal = pMode->CrtcHBlankEnd = + ATIDivide(pMode->CrtcHTotal * pATI->LCDHorizontal, + pMode->CrtcHDisplay, -3, 1) << 3; + pMode->CrtcHSyncEnd = + ATIDivide(pMode->CrtcHSyncEnd * pATI->LCDHorizontal, + pMode->CrtcHDisplay, -3, 1) << 3; + pMode->CrtcHSyncStart = + ATIDivide(pMode->CrtcHSyncStart * pATI->LCDHorizontal, + pMode->CrtcHDisplay, -3, -1) << 3; + pMode->CrtcHDisplay = pMode->CrtcHBlankStart = pATI->LCDHorizontal; + + pMode->CrtcVTotal = pMode->CrtcVBlankEnd = + ATIDivide((pMode->CrtcVTotal - pMode->CrtcVDisplay) * + pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + + pATI->LCDVertical; + pMode->CrtcVSyncEnd = + ATIDivide((pMode->CrtcVSyncEnd - pMode->CrtcVDisplay) * + pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + + pATI->LCDVertical; + pMode->CrtcVSyncStart = + ATIDivide((pMode->CrtcVSyncStart - pMode->CrtcVDisplay) * + pATI->LCDVertical, pATI->LCDHorizontal, 0, -1) + + pATI->LCDVertical; + pMode->CrtcVDisplay = pMode->CrtcVBlankStart = pATI->LCDVertical; + + /* + * The CRTC only stretches the mode's displayed area, not its porches. + * Reverse-engineer the mode's timings back into the user specified + * values so that the stretched mode is produced when the CRTC is + * eventually programmed. The reverse-engineered mode is then checked + * against CRTC limits below. + */ + pMode->Clock = pATI->LCDClock; + + HAdjust = pATI->LCDHorizontal - pMode->HDisplay; +# define ATIReverseHorizontal(_x) \ + (pMode->_x - HAdjust) + + pMode->HSyncStart = ATIReverseHorizontal(CrtcHSyncStart); + pMode->HSyncEnd = ATIReverseHorizontal(CrtcHSyncEnd); + pMode->HTotal = ATIReverseHorizontal(CrtcHTotal); + + VInterlace = GetBits(pMode->Flags, V_INTERLACE) + 1; +# define ATIReverseVertical(_y) \ + ((((pMode->_y - pATI->LCDVertical) * VInterlace) / VScan) + \ + pMode->VDisplay) + + pMode->VSyncStart = ATIReverseVertical(CrtcVSyncStart); + pMode->VSyncEnd = ATIReverseVertical(CrtcVSyncEnd); + pMode->VTotal = ATIReverseVertical(CrtcVTotal); + +# undef ATIReverseHorizontal +# undef ATIReverseVertical + } + + HBlankWidth = (pMode->HTotal >> 3) - (pMode->HDisplay >> 3); + if (!HBlankWidth) + return MODE_HBLANK_NARROW; + + switch (pATI->NewHW.crtc) + { + +#ifndef AVOID_CPIO + + case ATI_CRTC_VGA: + /* Prevent overscans */ + if (HBlankWidth > 63) + return MODE_HBLANK_WIDE; + + if (pMode->HDisplay > 2048) + return MODE_BAD_HVALUE; + + if (VScan > 64) + return MODE_BAD_VSCAN; + + VDisplay = pMode->VDisplay * VScan; + VTotal = pMode->VTotal * VScan; + + if ((pMode->Flags & V_INTERLACE) && (pATI->Chip < ATI_CHIP_264CT)) + { + VDisplay >>= 1; + VTotal >>= 1; + } + + if ((VDisplay > 2048) || (VTotal > 2050)) + return MODE_BAD_VVALUE; + + if (pATI->Adapter != ATI_ADAPTER_VGA) + break; + + if ((VDisplay > 1024) || (VTotal > 1025)) + return MODE_BAD_VVALUE; + + break; + +#endif /* AVOID_CPIO */ + + case ATI_CRTC_MACH64: + if (VScan > 2) + return MODE_NO_VSCAN; + + break; + + default: + break; + } + + return MODE_OK; +} diff --git a/src/ativalid.h b/src/ativalid.h new file mode 100644 index 0000000..bc16169 --- /dev/null +++ b/src/ativalid.h @@ -0,0 +1,34 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativalid.h,v 1.9 2003/10/30 17:36:58 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIVALID_H___ +#define ___ATIVALID_H___ 1 + +#include "atiproto.h" + +#include "xf86str.h" + +extern ModeStatus ATIValidMode FunctionPrototype((int, DisplayModePtr, Bool, + int)); + +#endif /* ___ATIVALID_H___ */ diff --git a/src/ativersion.h b/src/ativersion.h new file mode 100644 index 0000000..ae2929c --- /dev/null +++ b/src/ativersion.h @@ -0,0 +1,58 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativersion.h,v 1.65tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIVERSION_H___ +#define ___ATIVERSION_H___ 1 + +#undef ATI_NAME +#undef ATI_DRIVER_NAME +#undef ATI_VERSION_MAJOR +#undef ATI_VERSION_MINOR +#undef ATI_VERSION_PATCH +#undef ATI_VERSION_CURRENT +#undef ATI_VERSION_EVALUATE +#undef ATI_VERSION_STRINGIFY +#undef ATI_VERSION_NAME + +#define ATI_NAME "ATI" +#define ATI_DRIVER_NAME "ati" + +#define ATI_VERSION_MAJOR 6 +#define ATI_VERSION_MINOR 5 +#define ATI_VERSION_PATCH 6 + +#ifndef ATI_VERSION_EXTRA +#define ATI_VERSION_EXTRA "" +#endif + +#define ATI_VERSION_CURRENT \ + ((ATI_VERSION_MAJOR << 20) | (ATI_VERSION_MINOR << 10) | ATI_VERSION_PATCH) + +#define ATI_VERSION_EVALUATE(__x) #__x +#define ATI_VERSION_STRINGIFY(_x) ATI_VERSION_EVALUATE(_x) +#define ATI_VERSION_NAME \ + ATI_VERSION_STRINGIFY(ATI_VERSION_MAJOR) "." \ + ATI_VERSION_STRINGIFY(ATI_VERSION_MINOR) "." \ + ATI_VERSION_STRINGIFY(ATI_VERSION_PATCH) ATI_VERSION_EXTRA + +#endif /* ___ATIVERSION_H___ */ diff --git a/src/ativga.c b/src/ativga.c new file mode 100644 index 0000000..2ac97cd --- /dev/null +++ b/src/ativga.c @@ -0,0 +1,534 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativga.c,v 1.20 2003/04/23 21:51:31 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atichip.h" +#include "atimono.h" +#include "atistruct.h" +#include "ativga.h" +#include "ativgaio.h" + +#ifndef DPMS_SERVER +# define DPMS_SERVER +#endif +#include "extensions/dpms.h" + +#ifndef AVOID_CPIO + +/* + * ATIVGAPreInit -- + * + * This function is called to set up VGA-related data that is common to all + * video modes generated by the driver. + */ +void +ATIVGAPreInit +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + int Index; + + /* Initialise sequencer register values */ + pATIHW->seq[0] = 0x03U; + if (pATI->depth == 1) + pATIHW->seq[2] = 0x01U << BIT_PLANE; + else + pATIHW->seq[2] = 0x0FU; + if (pATI->depth <= 4) + pATIHW->seq[4] = 0x06U; + else if (pATI->Adapter == ATI_ADAPTER_VGA) + pATIHW->seq[4] = 0x0EU; + else + pATIHW->seq[4] = 0x0AU; + + /* Initialise CRTC register values */ + if ((pATI->depth >= 8) && + ((pATI->Chip >= ATI_CHIP_264CT) || + (pATI->CPIO_VGAWonder && + (pATI->Chip <= ATI_CHIP_18800_1) && + (pATI->VideoRAM == 256)))) + pATIHW->crt[19] = pATI->displayWidth >> 3; + else + pATIHW->crt[19] = pATI->displayWidth >> 4; + if ((pATI->depth >= 8) && (pATI->Adapter == ATI_ADAPTER_VGA)) + pATIHW->crt[23] = 0xC3U; + else + pATIHW->crt[23] = 0xE3U; + pATIHW->crt[24] = 0xFFU; + + /* Initialise attribute controller register values */ + if (pATI->depth == 1) + { + Bool FlipPixels = xf86GetFlipPixels(); + + for (Index = 0; Index < 16; Index++) + if (((Index & (0x01U << BIT_PLANE)) != 0) != FlipPixels) + pATIHW->attr[Index] = MONO_WHITE; + else + pATIHW->attr[Index] = MONO_BLACK; + pATIHW->attr[16] = 0x01U; + pATIHW->attr[17] = MONO_OVERSCAN; + } + else + { + for (Index = 0; Index < 16; Index++) + pATIHW->attr[Index] = Index; + if (pATI->depth <= 4) + pATIHW->attr[16] = 0x81U; + else if (pATI->Adapter == ATI_ADAPTER_VGA) + pATIHW->attr[16] = 0x41U; + else + pATIHW->attr[16] = 0x01U; + pATIHW->attr[17] = 0xFFU; + } + pATIHW->attr[18] = 0x0FU; + + /* Initialise graphics controller register values */ + if (pATI->depth == 1) + pATIHW->gra[4] = BIT_PLANE; + else if (pATI->depth <= 4) + pATIHW->gra[5] = 0x02U; + else if (pATI->Chip >= ATI_CHIP_264CT) + pATIHW->gra[5] = 0x40U; + if (pATI->UseSmallApertures && (pATI->Chip >= ATI_CHIP_264CT) && + ((pATI->Chip >= ATI_CHIP_264VT) || !pATI->LinearBase)) + pATIHW->gra[6] = 0x01U; /* 128kB aperture */ + else + pATIHW->gra[6] = 0x05U; /* 64kB aperture */ + pATIHW->gra[7] = 0x0FU; + pATIHW->gra[8] = 0xFFU; +} + +/* + * ATIVGASave -- + * + * This function is called to save the VGA portion of the current video state. + */ +void +ATIVGASave +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + int Index; + + /* Save miscellaneous output register */ + pATIHW->genmo = inb(R_GENMO); + ATISetVGAIOBase(pATI, pATIHW->genmo); + + /* Save sequencer registers */ + for (Index = 0; Index < NumberOf(pATIHW->seq); Index++) + pATIHW->seq[Index] = GetReg(SEQX, Index); + + /* Save CRTC registers */ + for (Index = 0; Index < NumberOf(pATIHW->crt); Index++) + pATIHW->crt[Index] = GetReg(CRTX(pATI->CPIO_VGABase), Index); + + /* Save attribute controller registers */ + for (Index = 0; Index < NumberOf(pATIHW->attr); Index++) + { + (void)inb(GENS1(pATI->CPIO_VGABase)); /* Reset flip-flop */ + pATIHW->attr[Index] = GetReg(ATTRX, Index); + } + + /* Save graphics controller registers */ + for (Index = 0; Index < NumberOf(pATIHW->gra); Index++) + pATIHW->gra[Index] = GetReg(GRAX, Index); +} + +/* + * ATIVGACalculate -- + * + * This function fills in the VGA portion of an ATIHWRec. + */ +void +ATIVGACalculate +( + ATIPtr pATI, + ATIHWPtr pATIHW, + DisplayModePtr pMode +) +{ + int Index, VDisplay; + + /* If not already done, adjust horizontal timings */ + if (!pMode->CrtcHAdjusted) + { + pMode->CrtcHAdjusted = TRUE; + pMode->CrtcHDisplay = (pMode->HDisplay >> 3) - 1; + pMode->CrtcHBlankStart = (pMode->HDisplay >> 3); + if ((pATI->Chip == ATI_CHIP_18800_1) || + (pATI->Chip >= ATI_CHIP_264CT)) + pMode->CrtcHBlankStart--; + pMode->CrtcHSyncStart = pMode->HSyncStart >> 3; + pMode->CrtcHSyncEnd = pMode->HSyncEnd >> 3; + pMode->CrtcHBlankEnd = (pMode->HTotal >> 3) - 1; + pMode->CrtcHTotal = (pMode->HTotal >> 3) - 5; + pMode->CrtcHSkew = pMode->HSkew; + + /* Check sync pulse width */ + Index = pMode->CrtcHSyncEnd - pMode->CrtcHSyncStart - 0x1F; + if (Index > 0) + { + pMode->CrtcHSyncStart += Index / 2; + pMode->CrtcHSyncEnd = pMode->CrtcHSyncStart + 0x1F; + } + + /* Check blank pulse width */ + Index = pMode->CrtcHBlankEnd - pMode->CrtcHBlankStart - 0x3F; + if (Index > 0) + { + if ((pMode->CrtcHBlankEnd - Index) > pMode->CrtcHSyncEnd) + { + pMode->CrtcHBlankStart += Index / 2; + if (pMode->CrtcHBlankStart >= pMode->CrtcHSyncStart) + pMode->CrtcHBlankStart = pMode->CrtcHSyncStart - 1; + pMode->CrtcHBlankEnd = pMode->CrtcHBlankStart + 0x3F; + } + else + { + Index -= 0x40; + if (Index > 0) + { + pMode->CrtcHBlankStart += Index / 2; + if (pMode->CrtcHBlankStart >= pMode->CrtcHSyncStart) + pMode->CrtcHBlankStart = pMode->CrtcHSyncStart - 1; + pMode->CrtcHBlankEnd = pMode->CrtcHBlankStart + 0x7F; + } + } + } + } + + /* + * Because of the use of CRTC[23] bit 0x04's for vertical doubling, it is + * necessary to always re-adjust vertical timings here. + */ + pMode->CrtcVDisplay = pMode->VDisplay; + pMode->CrtcVBlankStart = pMode->VDisplay; + pMode->CrtcVSyncStart = pMode->VSyncStart; + pMode->CrtcVSyncEnd = pMode->VSyncEnd; + pMode->CrtcVBlankEnd = pMode->VTotal; + pMode->CrtcVTotal = pMode->VTotal; + + /* Adjust for doublescanned modes */ + if (pMode->Flags & V_DBLSCAN) + { + pMode->CrtcVDisplay <<= 1; + pMode->CrtcVBlankStart <<= 1; + pMode->CrtcVSyncStart <<= 1; + pMode->CrtcVSyncEnd <<= 1; + pMode->CrtcVBlankEnd <<= 1; + pMode->CrtcVTotal <<= 1; + } + + /* Adjust for multiscanned modes */ + if (pMode->VScan > 1) + { + pMode->CrtcVDisplay *= pMode->VScan; + pMode->CrtcVBlankStart *= pMode->VScan; + pMode->CrtcVSyncStart *= pMode->VScan; + pMode->CrtcVSyncEnd *= pMode->VScan; + pMode->CrtcVBlankEnd *= pMode->VScan; + pMode->CrtcVTotal *= pMode->VScan; + } + + /* Set up miscellaneous output register value */ + pATIHW->genmo = 0x23U; + if ((pMode->Flags & (V_PHSYNC | V_NHSYNC)) && + (pMode->Flags & (V_PVSYNC | V_NVSYNC))) + { + if (pMode->Flags & V_NHSYNC) + pATIHW->genmo |= 0x40U; + if (pMode->Flags & V_NVSYNC) + pATIHW->genmo |= 0x80U; + } + else + { + pMode->Flags &= ~(V_PHSYNC | V_NHSYNC | V_PVSYNC | V_NVSYNC); + + if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) + VDisplay = pATI->LCDVertical; + else + VDisplay = pMode->CrtcVDisplay; + + if (VDisplay < 400) + { + pMode->Flags |= V_PHSYNC | V_NVSYNC; + pATIHW->genmo |= 0x80U; + } + else if (VDisplay < 480) + { + pMode->Flags |= V_NHSYNC | V_PVSYNC; + pATIHW->genmo |= 0x40U; + } + else if (VDisplay < 768) + { + pMode->Flags |= V_NHSYNC | V_NVSYNC; + pATIHW->genmo |= 0xC0U; + } + else + { + pMode->Flags |= V_PHSYNC | V_PVSYNC; + } + } + + /* Adjust for interlaced modes */ + if ((pMode->Flags & V_INTERLACE) && (pATI->Chip < ATI_CHIP_264CT)) + { + pMode->CrtcVDisplay >>= 1; + pMode->CrtcVBlankStart >>= 1; + pMode->CrtcVSyncStart >>= 1; + pMode->CrtcVSyncEnd >>= 1; + pMode->CrtcVBlankEnd >>= 1; + pMode->CrtcVTotal >>= 1; + } + + if (pMode->CrtcVTotal > 1024) + { + pATIHW->crt[23] |= 0x04U; + pMode->CrtcVDisplay >>= 1; + pMode->CrtcVBlankStart >>= 1; + pMode->CrtcVSyncStart >>= 1; + pMode->CrtcVSyncEnd >>= 1; + pMode->CrtcVBlankEnd >>= 1; + pMode->CrtcVTotal >>= 1; + } + else + { + pATIHW->crt[23] &= ~0x04U; + } + + pMode->CrtcVDisplay--; + if (pATI->Chip == ATI_CHIP_18800) + pMode->CrtcVBlankStart++; + else + pMode->CrtcVBlankStart--; + pMode->CrtcVBlankEnd--; + if (pATI->Chip < ATI_CHIP_264CT) + pMode->CrtcVBlankEnd--; + pMode->CrtcVTotal -= 2; + pMode->CrtcVAdjusted = TRUE; /* Redundant */ + + /* Check sync pulse width */ + Index = pMode->CrtcVSyncEnd - pMode->CrtcVSyncStart - 0x0F; + if (Index > 0) + { + pMode->CrtcVSyncStart += Index / 2; + pMode->CrtcVSyncEnd = pMode->CrtcVSyncStart + 0x0F; + } + + /* Check blank pulse width */ + Index = pMode->CrtcVBlankEnd - pMode->CrtcVBlankStart - 0x00FF; + if (Index > 0) + { + if ((pMode->CrtcVBlankEnd - Index) > pMode->CrtcVSyncEnd) + { + pMode->CrtcVBlankStart += Index / 2; + if (pMode->CrtcVBlankStart >= pMode->CrtcVSyncStart) + pMode->CrtcVBlankStart = pMode->CrtcVSyncStart - 1; + pMode->CrtcVBlankEnd = pMode->CrtcVBlankStart + 0x00FF; + } + else + { + Index -= 0x0100; + if (Index > 0) + { + pMode->CrtcVBlankStart += Index / 2; + if (pMode->CrtcVBlankStart >= pMode->CrtcVSyncStart) + pMode->CrtcVBlankStart = pMode->CrtcVSyncStart - 1; + pMode->CrtcVBlankEnd = pMode->CrtcVBlankStart + 0x01FF; + } + } + } + + /* Set up sequencer register values */ + if (pMode->Flags & V_CLKDIV2) + pATIHW->seq[1] = 0x09U; + else + pATIHW->seq[1] = 0x01U; + + /* Set up CRTC register values */ + pATIHW->crt[0] = pMode->CrtcHTotal; + pATIHW->crt[1] = pMode->CrtcHDisplay; + pATIHW->crt[2] = pMode->CrtcHBlankStart; + pATIHW->crt[3] = (pMode->CrtcHBlankEnd & 0x1FU) | 0x80U; + Index = ((pMode->CrtcHSkew << 2) + 0x10U) & ~0x1FU; + if (Index < 0x0080) + pATIHW->crt[3] |= Index; + pATIHW->crt[4] = pMode->CrtcHSyncStart; + pATIHW->crt[5] = ((pMode->CrtcHBlankEnd & 0x20U) << 2) | + ((pMode->CrtcHSyncEnd & 0x1FU) ); + pATIHW->crt[6] = pMode->CrtcVTotal & 0xFFU; + pATIHW->crt[7] = ((pMode->CrtcVTotal & 0x0100U) >> 8) | + ((pMode->CrtcVDisplay & 0x0100U) >> 7) | + ((pMode->CrtcVSyncStart & 0x0100U) >> 6) | + ((pMode->CrtcVBlankStart & 0x0100U) >> 5) | + 0x10U | + ((pMode->CrtcVTotal & 0x0200U) >> 4) | + ((pMode->CrtcVDisplay & 0x0200U) >> 3) | + ((pMode->CrtcVSyncStart & 0x0200U) >> 2); + pATIHW->crt[9] = ((pMode->CrtcVBlankStart & 0x0200U) >> 4) | 0x40U; + /* + * Doublescanned modes are missing the top scanline. Convert + * doublescanning to multiscanning, using the doublescan bit only as a last + * resort. + */ + if ((Index = pMode->VScan) <= 0) + Index = 1; + if (pMode->Flags & V_DBLSCAN) + Index <<= 1; + Index--; + pATIHW->crt[9] |= (Index & 0x1FU) | ((Index & 0x20U) << 2); + pATIHW->crt[16] = pMode->CrtcVSyncStart & 0xFFU; + pATIHW->crt[17] = (pMode->CrtcVSyncEnd & 0x0FU) | 0x20U; + pATIHW->crt[18] = pMode->CrtcVDisplay & 0xFFU; + pATIHW->crt[21] = pMode->CrtcVBlankStart & 0xFFU; + pATIHW->crt[22] = pMode->CrtcVBlankEnd & 0xFFU; +} + +/* + * ATIVGASet -- + * + * This function is called to load the VGA portion of a video state. + */ +void +ATIVGASet +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + int Index; + + /* Set VGA I/O base */ + ATISetVGAIOBase(pATI, pATIHW->genmo); + + /* Load miscellaneous output register */ + outb(GENMO, pATIHW->genmo); + + /* Load sequencer in reverse index order; this also ends its reset */ + for (Index = NumberOf(pATIHW->seq); --Index >= 0; ) + PutReg(SEQX, Index, pATIHW->seq[Index]); + + /* Load CRTC registers */ + for (Index = 0; Index < NumberOf(pATIHW->crt); Index++) + PutReg(CRTX(pATI->CPIO_VGABase), Index, pATIHW->crt[Index]); + + /* Load attribute controller registers */ + for (Index = 0; Index < NumberOf(pATIHW->attr); Index++) + { + (void)inb(GENS1(pATI->CPIO_VGABase)); /* Reset flip-flop & delay */ + outb(ATTRX, Index); + outb(ATTRX, pATIHW->attr[Index]); + } + + /* Load graphics controller registers */ + for (Index = 0; Index < NumberOf(pATIHW->gra); Index++) + PutReg(GRAX, Index, pATIHW->gra[Index]); +} + +/* + * ATIVGASaveScreen -- + * + * This function blanks or unblanks a VGA screen. + */ +void +ATIVGASaveScreen +( + ATIPtr pATI, + int Mode +) +{ + (void)inb(GENS1(pATI->CPIO_VGABase)); /* Reset flip-flop */ + + switch (Mode) + { + case SCREEN_SAVER_OFF: + case SCREEN_SAVER_FORCER: + outb(ATTRX, 0x20U); /* Turn PAS on */ + break; + + case SCREEN_SAVER_ON: + case SCREEN_SAVER_CYCLE: + outb(ATTRX, 0x00U); /* Turn PAS off */ + break; + + default: + break; + } +} + +/* + * ATIVGASetDPMSMode -- + * + * This function sets a VGA's VESA Display Power Management Signaling mode. + */ +void +ATIVGASetDPMSMode +( + ATIPtr pATI, + int DPMSMode +) +{ + CARD8 seq1, crt17; + + switch (DPMSMode) + { + case DPMSModeOn: /* HSync on, VSync on */ + seq1 = 0x00U; + crt17 = 0x80U; + break; + + case DPMSModeStandby: /* HSync off, VSync on -- unsupported */ + seq1 = 0x20U; + crt17 = 0x80U; + break; + + case DPMSModeSuspend: /* HSync on, VSync off -- unsupported */ + seq1 = 0x20U; + crt17 = 0x80U; + break; + + case DPMSModeOff: /* HSync off, VSync off */ + seq1 = 0x20U; + crt17 = 0x00U; + break; + + default: /* Muffle compiler */ + return; + } + + PutReg(SEQX, 0x00U, 0x01U); /* Start synchonous reset */ + seq1 |= GetReg(SEQX, 0x01U) & ~0x20U; + PutReg(SEQX, 0x01U, seq1); + crt17 |= GetReg(CRTX(pATI->CPIO_VGABase), 0x17U) & ~0x80U; + usleep(10000); + PutReg(CRTX(pATI->CPIO_VGABase), 0x17U, crt17); + PutReg(SEQX, 0x01U, 0x03U); /* End synchonous reset */ +} + +#endif /* AVOID_CPIO */ diff --git a/src/ativga.h b/src/ativga.h new file mode 100644 index 0000000..0f82294 --- /dev/null +++ b/src/ativga.h @@ -0,0 +1,45 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativga.h,v 1.10 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIVGA_H___ +#define ___ATIVGA_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +#ifndef AVOID_CPIO + +extern void ATIVGAPreInit FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIVGASave FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIVGACalculate FunctionPrototype((ATIPtr, ATIHWPtr, + DisplayModePtr)); +extern void ATIVGASet FunctionPrototype((ATIPtr, ATIHWPtr)); + +extern void ATIVGASaveScreen FunctionPrototype((ATIPtr, int)); +extern void ATIVGASetDPMSMode FunctionPrototype((ATIPtr, int)); + +#endif /* AVOID_CPIO */ + +#endif /* ___ATIVGA_H___ */ diff --git a/src/ativgaio.c b/src/ativgaio.c new file mode 100644 index 0000000..5e7d731 --- /dev/null +++ b/src/ativgaio.c @@ -0,0 +1,46 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativgaio.c,v 1.4 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atistruct.h" +#include "ativgaio.h" + +#ifndef AVOID_CPIO + +/* + * ATISetVGAIOBase -- + * + * This sets vgaIOBase according to the value of the passed value of the + * miscellaneous output register. + */ +void +ATISetVGAIOBase +( + ATIPtr pATI, + const CARD8 misc +) +{ + pATI->CPIO_VGABase = (misc & 0x01U) ? ColourIOBase : MonochromeIOBase; +} + +#endif /* AVOID_CPIO */ diff --git a/src/ativgaio.h b/src/ativgaio.h new file mode 100644 index 0000000..d3ce372 --- /dev/null +++ b/src/ativgaio.h @@ -0,0 +1,56 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/ativgaio.h,v 1.5 2003/01/01 19:16:34 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIVGAIO_H___ + +#if !defined(___ATI_H___) && defined(XFree86Module) +# error missing #include "ati.h" before #include "ativgaio.h" +# undef XFree86Module +#endif + +#define ___ATIVGAIO_H___ 1 + +#include "atiio.h" +#include "atipriv.h" +#include "atiproto.h" + +#ifndef AVOID_CPIO + +extern void ATISetVGAIOBase FunctionPrototype((ATIPtr, const CARD8)); + +/* Odds and ends to ease reading and writting of indexed registers */ +#define GetReg(_Register, _Index) \ + ( \ + outb(_Register, _Index), \ + inb((_Register) + 1) \ + ) +#define PutReg(_Register, _Index, _Value) \ + do \ + { \ + outb(_Register, _Index); \ + outb((_Register) + 1, _Value); \ + } while (0) + +#endif /* AVOID_CPIO */ + +#endif /* ___ATIVGAIO_H___ */ diff --git a/src/atividmem.c b/src/atividmem.c new file mode 100644 index 0000000..048b13a --- /dev/null +++ b/src/atividmem.c @@ -0,0 +1,417 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atividmem.c,v 1.15 2003/04/23 21:51:31 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atiadapter.h" +#include "atistruct.h" +#include "atividmem.h" + +/* Memory types for 68800's and 88800GX's */ +const char *ATIMemoryTypeNames_Mach[] = +{ + "DRAM (256Kx4)", + "VRAM (256Kx4, x8, x16)", + "VRAM (256Kx16 with short shift register)", + "DRAM (256Kx16)", + "Graphics DRAM (256Kx16)", + "Enhanced VRAM (256Kx4, x8, x16)", + "Enhanced VRAM (256Kx16 with short shift register)", + "Unknown video memory type" +}; + +/* Memory types for 88800CX's */ +const char *ATIMemoryTypeNames_88800CX[] = +{ + "DRAM (256Kx4, x8, x16)", + "EDO DRAM (256Kx4, x8, x16)", + "Unknown video memory type", + "DRAM (256Kx16 with assymetric RAS/CAS)", + "Unknown video memory type", + "Unknown video memory type", + "Unknown video memory type", + "Unknown video memory type" +}; + +/* Memory types for 264xT's */ +const char *ATIMemoryTypeNames_264xT[] = +{ + "Disabled video memory", + "DRAM", + "EDO DRAM", + "Pseudo-EDO DRAM", + "SDRAM (1:1)", + "SGRAM (1:1)", + "SGRAM (2:1) 32-bit", + "Unknown video memory type" +}; + +#ifndef AVOID_CPIO + +/* + * ATIUnmapVGA -- + * + * Unmap VGA aperture. + */ +static void +ATIUnmapVGA +( + int iScreen, + ATIPtr pATI +) +{ + if (!pATI->pBank) + return; + + xf86UnMapVidMem(iScreen, pATI->pBank, 0x00010000U); + + pATI->pBank = pATI->BankInfo.pBankA = pATI->BankInfo.pBankB = NULL; +} + +#endif /* AVOID_CPIO */ + +/* + * ATIUnmapLinear -- + * + * Unmap linear aperture. + */ +static void +ATIUnmapLinear +( + int iScreen, + ATIPtr pATI +) +{ + +#ifdef AVOID_CPIO + + if (!pATI->pMemory) + return; + +#else /* AVOID_CPIO */ + + if (pATI->pMemory != pATI->pBank) + +#endif /* AVOID_CPIO */ + + { + xf86UnMapVidMem(iScreen, pATI->pMemory, pATI->LinearSize); + +#if X_BYTE_ORDER != X_LITTLE_ENDIAN + + if (pATI->pMemoryLE) + xf86UnMapVidMem(iScreen, pATI->pMemoryLE, pATI->LinearSize); + +#endif /* X_BYTE_ORDER */ + + } + + pATI->pMemory = pATI->pMemoryLE = NULL; +} + +/* + * ATIUnmapMMIO -- + * + * Unmap MMIO registers. + */ +static void +ATIUnmapMMIO +( + int iScreen, + ATIPtr pATI +) +{ + if (pATI->pMMIO) + xf86UnMapVidMem(iScreen, pATI->pMMIO, getpagesize()); + + pATI->pMMIO = pATI->pBlock[0] = pATI->pBlock[1] = NULL; +} + +/* + * ATIUnmapCursor -- + * + * Unmap hardware cursor image area. + */ +static void +ATIUnmapCursor +( + int iScreen, + ATIPtr pATI +) +{ + if (pATI->pCursorPage) + xf86UnMapVidMem(iScreen, pATI->pCursorPage, getpagesize()); + + pATI->pCursorPage = pATI->pCursorImage = NULL; +} + +/* + * ATIMapApertures -- + * + * This function maps all apertures used by the driver. + */ +Bool +ATIMapApertures +( + int iScreen, + ATIPtr pATI +) +{ + pciVideoPtr pVideo; + PCITAG Tag; + unsigned long PageSize; + + if (pATI->Mapped) + return TRUE; + +#ifndef AVOID_CPIO + + if (pATI->VGAAdapter == ATI_ADAPTER_NONE) + +#endif /* AVOID_CPIO */ + + { + if (!pATI->LinearBase && !pATI->Block0Base) + return FALSE; + } + + PageSize = getpagesize(); + + if ((pVideo = pATI->PCIInfo)) + Tag = ((pciConfigPtr)(pVideo->thisCard))->tag; + else + Tag = 0; + +#ifndef AVOID_CPIO + + /* Map VGA aperture */ + if (pATI->VGAAdapter != ATI_ADAPTER_NONE) + { + /* + * No relocation, resizing, caching or write-combining of this + * aperture is supported. Hence, the hard-coded values here... + */ + if (pVideo) + pATI->pBank = xf86MapPciMem(iScreen, VIDMEM_MMIO, + Tag, 0x000A0000U, 0x00010000U); + else + pATI->pBank = xf86MapVidMem(iScreen, VIDMEM_MMIO, + 0x000A0000U, 0x00010000U); + + if (!pATI->pBank) + return FALSE; + + pATI->pMemory = + pATI->BankInfo.pBankA = + pATI->BankInfo.pBankB = pATI->pBank; + + pATI->Mapped = TRUE; + } + +#endif /* AVOID_CPIO */ + + /* Map linear aperture */ + if (pATI->LinearBase) + { + if (pVideo) + pATI->pMemory = xf86MapPciMem(iScreen, VIDMEM_FRAMEBUFFER, + Tag, pATI->LinearBase, pATI->LinearSize); + else + pATI->pMemory = xf86MapVidMem(iScreen, VIDMEM_FRAMEBUFFER, + pATI->LinearBase, pATI->LinearSize); + + if (!pATI->pMemory) + { + +#ifndef AVOID_CPIO + + ATIUnmapVGA(iScreen, pATI); + +#endif /* AVOID_CPIO */ + + pATI->Mapped = FALSE; + return FALSE; + } + + pATI->Mapped = TRUE; + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + + if ((pATI->CursorBase >= pATI->LinearBase) && + ((pATI->CursorOffset + 0x00000400UL) <= (CARD32)pATI->LinearSize)) + pATI->pCursorImage = (char *)pATI->pMemory + pATI->CursorOffset; + + pATI->pMemoryLE = pATI->pMemory; + +#else /* if X_BYTE_ORDER != X_LITTLE_ENDIAN */ + + /* + * Map the little-endian aperture (used for video, etc.). Note that + * caching of this area is _not_ wanted. + */ + if (pVideo) + { + pATI->pMemoryLE = xf86MapPciMem(iScreen, VIDMEM_MMIO, Tag, + pATI->LinearBase - 0x00800000U, pATI->LinearSize); + + if (!pATI->pMemoryLE) + { + ATIUnmapLinear(iScreen, pATI); + +#ifndef AVOID_CPIO + + ATIUnmapVGA(iScreen, pATI); + +#endif /* AVOID_CPIO */ + + pATI->Mapped = FALSE; + return FALSE; + } + } + +#endif /* X_BYTE_ORDER */ + + } + + /* Map MMIO aperture */ + if (pATI->Block0Base) + { + unsigned long MMIOBase = pATI->Block0Base & ~(PageSize - 1); + + if (pVideo) + pATI->pMMIO = xf86MapPciMem(iScreen, VIDMEM_MMIO, + Tag, MMIOBase, PageSize); + else + pATI->pMMIO = xf86MapVidMem(iScreen, VIDMEM_MMIO, + MMIOBase, PageSize); + + if (!pATI->pMMIO) + { + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + + ATIUnmapCursor(iScreen, pATI); + +#endif /* X_BYTE_ORDER */ + + ATIUnmapLinear(iScreen, pATI); + +#ifndef AVOID_CPIO + + ATIUnmapVGA(iScreen, pATI); + +#endif /* AVOID_CPIO */ + + pATI->Mapped = FALSE; + return FALSE; + } + + pATI->Mapped = TRUE; + + pATI->pBlock[0] = (char *)pATI->pMMIO + + (pATI->Block0Base - MMIOBase); + + if (pATI->Block1Base) + pATI->pBlock[1] = (char *)pATI->pBlock[0] - 0x00000400U; + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + + if (!pATI->pCursorImage) + +#endif /* X_BYTE_ORDER */ + + { + if ((pATI->CursorBase >= MMIOBase) && + ((pATI->CursorBase + 0x00000400UL) <= (MMIOBase + PageSize))) + pATI->pCursorImage = (char *)pATI->pMMIO + + (pATI->CursorBase - MMIOBase); + } + } + + /* Map hardware cursor image area */ + if (pATI->CursorBase && !pATI->pCursorImage) + { + unsigned long CursorBase = pATI->CursorBase & ~(PageSize - 1); + + if (pVideo) + pATI->pCursorPage = xf86MapPciMem(iScreen, VIDMEM_FRAMEBUFFER, + Tag, CursorBase, PageSize); + else + pATI->pCursorPage = xf86MapVidMem(iScreen, VIDMEM_FRAMEBUFFER, + CursorBase, PageSize); + + if (!pATI->pCursorPage) + { + ATIUnmapCursor(iScreen, pATI); + ATIUnmapMMIO(iScreen, pATI); + ATIUnmapLinear(iScreen, pATI); + +#ifndef AVOID_CPIO + + ATIUnmapVGA(iScreen, pATI); + +#endif /* AVOID_CPIO */ + + pATI->Mapped = FALSE; + return FALSE; + } + + pATI->pCursorImage = (char *)pATI->pCursorPage + + (pATI->CursorBase - CursorBase); + } + + return TRUE; +} + +/* + * ATIUnmapApertures -- + * + * This function unmaps all apertures used by the driver. + */ +void +ATIUnmapApertures +( + int iScreen, + ATIPtr pATI +) +{ + if (!pATI->Mapped) + return; + pATI->Mapped = FALSE; + + /* Unmap hardware cursor image area */ + ATIUnmapCursor(iScreen, pATI); + + /* Unmap MMIO area */ + ATIUnmapMMIO(iScreen, pATI); + + /* Unmap linear aperture */ + ATIUnmapLinear(iScreen, pATI); + +#ifndef AVOID_CPIO + + /* Unmap VGA aperture */ + ATIUnmapVGA(iScreen, pATI); + +#endif /* AVOID_CPIO */ + +} diff --git a/src/atividmem.h b/src/atividmem.h new file mode 100644 index 0000000..9c326c6 --- /dev/null +++ b/src/atividmem.h @@ -0,0 +1,75 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atividmem.h,v 1.9 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIVIDMEM_H___ +#define ___ATIVIDMEM_H___ 1 + +#include "atiproto.h" +#include "atipriv.h" + +/* Memory types for 68800's and 88800GX's */ +typedef enum +{ + MEM_MACH_DRAMx4, + MEM_MACH_VRAM, + MEM_MACH_VRAMssr, + MEM_MACH_DRAMx16, + MEM_MACH_GDRAM, + MEM_MACH_EVRAM, + MEM_MACH_EVRAMssr, + MEM_MACH_TYPE_7 +} ATIMachMemoryType; +extern const char *ATIMemoryTypeNames_Mach[]; + +/* Memory types for 88800CX's */ +typedef enum +{ + MEM_CX_DRAM, + MEM_CX_EDO, + MEM_CX_TYPE_2, + MEM_CX_DRAM_A, + MEM_CX_TYPE_4, + MEM_CX_TYPE_5, + MEM_CX_TYPE_6, + MEM_CX_TYPE_7 +} ATICXMemoryType; +extern const char *ATIMemoryTypeNames_88800CX[]; + +/* Memory types for 264xT's */ +typedef enum +{ + MEM_264_NONE, + MEM_264_DRAM, + MEM_264_EDO, + MEM_264_PSEUDO_EDO, + MEM_264_SDRAM, + MEM_264_SGRAM, + MEM_264_SGRAM32, + MEM_264_TYPE_7 +} ATI264MemoryType; +extern const char *ATIMemoryTypeNames_264xT[]; + +extern Bool ATIMapApertures FunctionPrototype((int, ATIPtr)); +extern void ATIUnmapApertures FunctionPrototype((int, ATIPtr)); + +#endif /* ___ATIVIDMEM_H___ */ diff --git a/src/atiwonder.c b/src/atiwonder.c new file mode 100644 index 0000000..7fb5fdb --- /dev/null +++ b/src/atiwonder.c @@ -0,0 +1,303 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiwonder.c,v 1.14 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +/* + * The ATI x8800 chips use special registers for their extended VGA features. + * These registers are accessible through an index I/O port and a data I/O + * port. BIOS initialisation stores the index port number in the Graphics + * register bank (0x03CE), indices 0x50 and 0x51. Unfortunately, for all but + * the 18800-x series of adapters, these registers are write-only (a.k.a. black + * holes). On all but 88800's, the index port number can be found in the short + * integer at offset 0x10 in the BIOS. For 88800's, this driver will use + * 0x01CE or 0x03CE as the index port number, depending on the I/O port + * decoding used. The data port number is one more than the index port number + * (i.e. 0x01CF). These ports differ slightly in their I/O behaviour from the + * normal VGA ones: + * + * write: outw(0x01CE, (data << 8) | index); (16-bit, not used) + * outb(0x01CE, index); outb(0x01CF, data); (8-bit) + * read: outb(0x01CE, index); data = inb(0x01CF); + * + * Two consecutive byte-writes to the data port will not work. Furthermore an + * index written to 0x01CE is usable only once. Note also that the setting of + * ATI extended registers (especially those with clock selection bits) should + * be bracketed by a sequencer reset. + * + * The number of these extended VGA registers varies by chipset. The 18800 + * series have 16, the 28800 series have 32, while 68800's and 88800's have 64. + * The last 16 on each have almost identical definitions. Thus, the BIOS sets + * up an indexing scheme whereby the last 16 extended VGA registers are + * accessed at indices 0xB0 through 0xBF on all chipsets. + */ + +#include "ati.h" +#include "atichip.h" +#include "atiwonder.h" +#include "atiwonderio.h" + +#ifndef AVOID_CPIO + +/* + * ATIVGAWonderPreInit -- + * + * This function is called to initialise the VGA Wonder part of an ATIHWRec + * that is common to all modes generated by the driver. + */ +void +ATIVGAWonderPreInit +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + pATIHW->b3 = ATIGetExtReg(0xB3U) & 0x20U; + if (pATI->depth <= 4) + pATIHW->b6 = 0x40U; + else + pATIHW->b6 = 0x04U; + if (pATI->Chip <= ATI_CHIP_18800) + pATIHW->ba = 0x08U; + else if (pATI->Chip >= ATI_CHIP_28800_2) + { + if (pATI->VideoRAM > 256) + pATIHW->b6 |= 0x01U; + pATIHW->bf = ATIGetExtReg(0xBFU) & 0x5FU; + pATIHW->a3 = ATIGetExtReg(0xA3U) & 0x67U; + pATIHW->ab = ATIGetExtReg(0xABU) & 0xE7U; + pATIHW->ae = ATIGetExtReg(0xAEU) & 0xE0U; + } +} + +/* + * ATIVGAWonderSave -- + * + * This function is called to save the VGA Wonder portion of the current video + * state. + */ +void +ATIVGAWonderSave +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + pATIHW->b0 = ATIGetExtReg(0xB0U); + pATIHW->b1 = ATIGetExtReg(0xB1U); + pATIHW->b2 = ATIGetExtReg(0xB2U); + pATIHW->b3 = ATIGetExtReg(0xB3U); + pATIHW->b5 = ATIGetExtReg(0xB5U); + pATIHW->b6 = ATIGetExtReg(0xB6U); + pATIHW->b8 = ATIGetExtReg(0xB8U); + pATIHW->b9 = ATIGetExtReg(0xB9U); + pATIHW->ba = ATIGetExtReg(0xBAU); + pATIHW->bd = ATIGetExtReg(0xBDU); + if (pATI->Chip > ATI_CHIP_18800) + { + pATIHW->be = ATIGetExtReg(0xBEU); + if (pATI->Chip >= ATI_CHIP_28800_2) + { + pATIHW->bf = ATIGetExtReg(0xBFU); + pATIHW->a3 = ATIGetExtReg(0xA3U); + pATIHW->a6 = ATIGetExtReg(0xA6U); + pATIHW->a7 = ATIGetExtReg(0xA7U); + pATIHW->ab = ATIGetExtReg(0xABU); + pATIHW->ac = ATIGetExtReg(0xACU); + pATIHW->ad = ATIGetExtReg(0xADU); + pATIHW->ae = ATIGetExtReg(0xAEU); + } + } +} + +/* + * ATIVGAWonderCalculate -- + * + * This function fills in the VGA Wonder portion of an ATIHWRec structure + * occurrence. + */ +void +ATIVGAWonderCalculate +( + ATIPtr pATI, + ATIHWPtr pATIHW, + DisplayModePtr pMode +) +{ + /* Set up the default horizontal display enable skew */ + if ((pATI->Chip >= ATI_CHIP_28800_2) && (pATI->Chip <= ATI_CHIP_28800_6) && + !(pMode->Flags & V_HSKEW)) + { + /* + * Modes using the higher clock frequencies need a non-zero Display + * Enable Skew. The following number has been empirically determined + * to be somewhere between 4.2 and 4.7 MHz. + */ +# define DisplayEnableSkewThreshold 4500 + + /* Set a reasonable default Display Enable Skew */ + pMode->HSkew = pMode->CrtcHSkew = + ATIDivide(pMode->SynthClock, DisplayEnableSkewThreshold, 0, 0); + } + pMode->Flags |= V_HSKEW; + + /* + * Fill in mode-specific VGA Wonder data. + */ + pATIHW->b0 = 0x00U; + if (pATI->depth >= 8) + pATIHW->b0 = 0x20U; + if (pATI->Chip >= ATI_CHIP_28800_2) + { + if (pATI->VideoRAM > 512) + pATIHW->b0 |= 0x08U; + else if (pATI->VideoRAM > 256) + pATIHW->b0 |= 0x10U; + } + else if (pATI->depth <= 4) + { + if (pATI->VideoRAM > 256) + pATIHW->b0 |= 0x08U; + } + else + { + if (pATI->VideoRAM > 256) + pATIHW->b0 |= 0x18U; + else + pATIHW->b0 |= 0x06U; + } + pATIHW->b1 = ATIGetExtReg(0xB1U) & 0x04U; + /* + * Setting the following bit causes hangs on return to text mode from + * packed modes on 18800-1's. The hang occurs because the adapter's I/O + * response is completely disabled when the register is rewritten. The + * adapter can then only be re-enabled with a powerdown. The bit, when on, + * blanks out the overscan. + */ + if ((pATI->Chip == ATI_CHIP_18800_1) && (pATI->depth >= 8)) + pATIHW->b5 = 0x00U; + else + pATIHW->b5 = 0x01U; + pATIHW->b8 = ATIGetExtReg(0xB8U) & 0xC0U; + pATIHW->b9 = ATIGetExtReg(0xB9U) & 0x7FU; + pATIHW->bd = ATIGetExtReg(0xBDU) & 0x02U; + if (pATI->Chip <= ATI_CHIP_18800) + pATIHW->b2 = ATIGetExtReg(0xB2U) & 0xC0U; + else + { + pATIHW->b2 = 0x00U; + pATIHW->be = (ATIGetExtReg(0xBEU) & 0x30U) | 0x09U; + if (pATI->Chip >= ATI_CHIP_28800_2) + { + pATIHW->a6 = (ATIGetExtReg(0xA6U) & 0x38U) | 0x04U; + pATIHW->a7 = (ATIGetExtReg(0xA7U) & 0xBEU) ; + pATIHW->ac = (ATIGetExtReg(0xACU) & 0x8EU) ; + } + } + if (pMode->Flags & V_INTERLACE) + { /* Enable interlace */ + if (pATI->Chip <= ATI_CHIP_18800) + pATIHW->b2 |= 0x01U; + else + pATIHW->be |= 0x02U; + } +#if 0 /* This is no longer needed but is left in for reference */ + if (pMode->Flags & V_DBLSCAN) /* Enable doublescan */ + pATIHW->b1 |= 0x08U; +#endif + if (pATI->OptionCSync || (pMode->Flags & (V_CSYNC | V_PCSYNC))) + pATIHW->bd |= 0x08U; /* Enable composite sync */ + if (pMode->Flags & V_NCSYNC) + pATIHW->bd |= 0x09U; /* Invert composite sync */ + if (pMode->HSkew > 0) + { + if (pMode->HSkew <= 3) + pATIHW->b5 |= 0x04U; + else if (pATI->Chip >= ATI_CHIP_28800_2) + switch ((pMode->HSkew + 4) >> 3) + { + case 1: /* Use ATI override */ + pATIHW->crt[3] &= ~0x60U; + pATIHW->b0 |= 0x01U; + break; + case 2: /* Use ATI override */ + pATIHW->crt[3] &= ~0x60U; + pATIHW->a6 |= 0x01U; + break; + case 3: + pATIHW->crt[3] |= 0x60U; + break; + case 4: + pATIHW->a7 |= 0x40U; + break; + case 5: + pATIHW->ac |= 0x10U; + break; + case 6: + pATIHW->ac |= 0x20U; + break; + default: + break; + } + } +} + +/* + * ATIVGAWonderSet -- + * + * This function loads the VGA Wonder portion of a video state. + */ +void +ATIVGAWonderSet +( + ATIPtr pATI, + ATIHWPtr pATIHW +) +{ + if (pATI->Chip <= ATI_CHIP_18800) + ATIModifyExtReg(pATI, 0xB2U, -1, 0x00U, pATIHW->b2); + else + { + ATIModifyExtReg(pATI, 0xBEU, -1, 0x00U, pATIHW->be); + if (pATI->Chip >= ATI_CHIP_28800_2) + { + ATIModifyExtReg(pATI, 0xBFU, -1, 0x00U, pATIHW->bf); + ATIModifyExtReg(pATI, 0xA3U, -1, 0x00U, pATIHW->a3); + ATIModifyExtReg(pATI, 0xA6U, -1, 0x00U, pATIHW->a6); + ATIModifyExtReg(pATI, 0xA7U, -1, 0x00U, pATIHW->a7); + ATIModifyExtReg(pATI, 0xABU, -1, 0x00U, pATIHW->ab); + ATIModifyExtReg(pATI, 0xACU, -1, 0x00U, pATIHW->ac); + ATIModifyExtReg(pATI, 0xADU, -1, 0x00U, pATIHW->ad); + ATIModifyExtReg(pATI, 0xAEU, -1, 0x00U, pATIHW->ae); + } + } + ATIModifyExtReg(pATI, 0xB0U, -1, 0x00U, pATIHW->b0); + ATIModifyExtReg(pATI, 0xB1U, -1, 0x00U, pATIHW->b1); + ATIModifyExtReg(pATI, 0xB3U, -1, 0x00U, pATIHW->b3); + ATIModifyExtReg(pATI, 0xB5U, -1, 0x00U, pATIHW->b5); + ATIModifyExtReg(pATI, 0xB6U, -1, 0x00U, pATIHW->b6); + ATIModifyExtReg(pATI, 0xB8U, -1, 0x00U, pATIHW->b8); + ATIModifyExtReg(pATI, 0xB9U, -1, 0x00U, pATIHW->b9); + ATIModifyExtReg(pATI, 0xBAU, -1, 0x00U, pATIHW->ba); + ATIModifyExtReg(pATI, 0xBDU, -1, 0x00U, pATIHW->bd); +} + +#endif /* AVOID_CPIO */ diff --git a/src/atiwonder.h b/src/atiwonder.h new file mode 100644 index 0000000..a3a1a34 --- /dev/null +++ b/src/atiwonder.h @@ -0,0 +1,42 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiwonder.h,v 1.9 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIWONDER_H___ +#define ___ATIWONDER_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +#ifndef AVOID_CPIO + +extern void ATIVGAWonderPreInit FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIVGAWonderSave FunctionPrototype((ATIPtr, ATIHWPtr)); +extern void ATIVGAWonderCalculate FunctionPrototype((ATIPtr, ATIHWPtr, + DisplayModePtr)); +extern void ATIVGAWonderSet FunctionPrototype((ATIPtr, ATIHWPtr)); + +#endif /* AVOID_CPIO */ + +#endif /* ___ATIWONDER_H___ */ diff --git a/src/atiwonderio.c b/src/atiwonderio.c new file mode 100644 index 0000000..53e0e8e --- /dev/null +++ b/src/atiwonderio.c @@ -0,0 +1,86 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiwonderio.c,v 1.4 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "ati.h" +#include "atichip.h" +#include "atiwonderio.h" + +#ifndef AVOID_CPIO + +/* + * ATIModifyExtReg -- + * + * This function is called to modify certain bits in an ATI extended VGA + * register while preserving its other bits. The function will not write the + * register if it turns out its value would not change. This helps prevent + * server hangs on older adapters. + */ +void +ATIModifyExtReg +( + ATIPtr pATI, + const CARD8 Index, + int CurrentValue, + const CARD8 CurrentMask, + CARD8 NewValue +) +{ + /* Possibly retrieve the current value */ + if (CurrentValue < 0) + CurrentValue = ATIGetExtReg(Index); + + /* Compute new value */ + NewValue &= (CARD8)(~CurrentMask); + NewValue |= CurrentValue & CurrentMask; + + /* Check if value will be changed */ + if (CurrentValue == NewValue) + return; + + /* + * The following is taken from ATI's VGA Wonder programmer's reference + * manual which says that this is needed to "ensure the proper state of the + * 8/16 bit ROM toggle". I suspect a timing glitch appeared in the 18800 + * after its die was cast. 18800-1 and later chips do not exhibit this + * problem. + */ + if ((pATI->Chip <= ATI_CHIP_18800) && (Index == 0xB2U) && + ((NewValue ^ 0x40U) & CurrentValue & 0x40U)) + { + CARD8 misc = inb(R_GENMO); + CARD8 bb = ATIGetExtReg(0xBBU); + + outb(GENMO, (misc & 0xF3U) | 0x04U | ((bb & 0x10U) >> 1)); + CurrentValue &= (CARD8)(~0x40U); + ATIPutExtReg(0xB2U, CurrentValue); + ATIDelay(5); + outb(GENMO, misc); + ATIDelay(5); + if (CurrentValue != NewValue) + ATIPutExtReg(0xB2U, NewValue); + } + else + ATIPutExtReg(Index, NewValue); +} + +#endif /* AVOID_CPIO */ diff --git a/src/atiwonderio.h b/src/atiwonderio.h new file mode 100644 index 0000000..c483dd7 --- /dev/null +++ b/src/atiwonderio.h @@ -0,0 +1,48 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiwonderio.h,v 1.4 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIWONDERIO_H___ + +#if !defined(___ATI_H___) && defined(XFree86Module) +# error missing #include "ati.h" before #include "atiwonderio.h" +# undef XFree86Module +#endif + +#define ___ATIWONDERIO_H___ 1 + +#include "atistruct.h" +#include "ativgaio.h" + +#ifndef AVOID_CPIO + +extern void ATIModifyExtReg FunctionPrototype((ATIPtr, const CARD8, int, + const CARD8, CARD8)); + +#define ATIGetExtReg(_Index) \ + GetReg(pATI->CPIO_VGAWonder, _Index) +#define ATIPutExtReg(_Index, _Value) \ + PutReg(pATI->CPIO_VGAWonder, _Index, _Value) + +#endif /* AVOID_CPIO */ + +#endif /* ___ATIWONDERIO_H___ */ diff --git a/src/atixv.c b/src/atixv.c new file mode 100644 index 0000000..10dce23 --- /dev/null +++ b/src/atixv.c @@ -0,0 +1,165 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atixv.c,v 1.5 2003/04/25 04:09:54 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#include "atiadapter.h" +#include "atimach64xv.h" +#include "atistruct.h" +#include "atixv.h" + +/* + * ATIXVFreeAdaptorInfo -- + * + * Free XVideo adaptor information. + */ +static void +ATIXVFreeAdaptorInfo +( + XF86VideoAdaptorPtr *ppAdaptor, + int nAdaptor +) +{ + if (!ppAdaptor) + return; + + while (nAdaptor > 0) + xfree(ppAdaptor[--nAdaptor]); + + xfree(ppAdaptor); +} + +/* + * ATIXVInitializeAdaptor -- + * + * This is called by the server's XVideo support layer to initialise an XVideo + * adapter. + */ +static int +ATIXVInitializeAdaptor +( + ScrnInfoPtr pScreenInfo, + XF86VideoAdaptorPtr **pppAdaptor +) +{ + ScreenPtr pScreen = screenInfo.screens[pScreenInfo->scrnIndex]; + ATIPtr pATI = ATIPTR(pScreenInfo); + XF86VideoAdaptorPtr *ppAdaptor = NULL; + int nAdaptor; + + switch (pATI->Adapter) + { + case ATI_ADAPTER_MACH64: + nAdaptor = ATIMach64XVInitialiseAdaptor(pScreen, pScreenInfo, pATI, + &ppAdaptor); + break; + + default: + nAdaptor = 0; + break; + } + + if (pppAdaptor) + *pppAdaptor = ppAdaptor; + else + ATIXVFreeAdaptorInfo(ppAdaptor, nAdaptor); + + return nAdaptor; +} + +/* + * ATIXVPreInit -- + * + * This function is called by ATIPreInit() to set up the environment required + * to support the XVideo extension. + */ +void +ATIXVPreInit +( + ATIPtr pATI +) +{ + +#ifndef AVOID_CPIO + + /* Currently a linear aperture is needed ... */ + if (!pATI->LinearBase) + return; + +#endif /* AVOID_CPIO */ + + (void)xf86XVRegisterGenericAdaptorDriver(ATIXVInitializeAdaptor); +} + +/* + * ATIInitializeXVideo -- + * + * This function is called to initialise XVideo extension support on a screen. + */ +Bool +ATIInitializeXVideo +( + ScreenPtr pScreen, + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + XF86VideoAdaptorPtr *ppAdaptor; + int nAdaptor; + Bool result; + + if (!(pScreenInfo->memPhysBase = pATI->LinearBase)) + return FALSE; + + pScreenInfo->fbOffset = 0; + + nAdaptor = xf86XVListGenericAdaptors(pScreenInfo, &ppAdaptor); + result = xf86XVScreenInit(pScreen, ppAdaptor, nAdaptor); + + ATIXVFreeAdaptorInfo(ppAdaptor, nAdaptor); + + return result; +} + +/* + * ATICloseXVideo -- + * + * This function is called during screen termination to clean up after XVideo + * initialisation. + */ +void +ATICloseXVideo +( + ScreenPtr pScreen, + ScrnInfoPtr pScreenInfo, + ATIPtr pATI +) +{ + switch (pATI->Adapter) + { + case ATI_ADAPTER_MACH64: + ATIMach64CloseXVideo(pScreen, pScreenInfo, pATI); + break; + + default: + break; + } +} diff --git a/src/atixv.h b/src/atixv.h new file mode 100644 index 0000000..50c4b3d --- /dev/null +++ b/src/atixv.h @@ -0,0 +1,38 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atixv.h,v 1.4 2003/04/23 21:51:31 tsi Exp $ */ +/* + * Copyright 2001 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef ___ATIXV_H___ +#define ___ATIXV_H___ 1 + +#include "atipriv.h" +#include "atiproto.h" + +#include "xf86str.h" + +extern void ATIXVPreInit FunctionPrototype((ATIPtr)); +extern Bool ATIInitializeXVideo FunctionPrototype((ScreenPtr, ScrnInfoPtr, + ATIPtr)); +extern void ATICloseXVideo FunctionPrototype((ScreenPtr, ScrnInfoPtr, + ATIPtr)); + +#endif /* ___ATIXV_H___ */ diff --git a/src/generic_bus.h b/src/generic_bus.h new file mode 100644 index 0000000..e7bc013 --- /dev/null +++ b/src/generic_bus.h @@ -0,0 +1,32 @@ +#ifndef __GENERIC_BUS_H__ +#define __GENERIC_BUS_H__ + +/* this is meant to be used for proprietary buses where abstraction is needed + but they don't occur often enough to warrant a separate helper library */ + + +#define GB_IOCTL_GET_NAME 1 + /* third argument is size of the buffer, fourth argument is pointer + to the buffer. Returns the name of the bus */ +#define GB_IOCTL_GET_TYPE 2 + /* third argument is size of the buffer, fourth argument is pointer + to the buffer. Returns the type of the bus, driver should check + this at initialization time to find out whether they are compatible + */ + + +typedef struct _GENERIC_BUS_Rec *GENERIC_BUS_Ptr; + +typedef struct _GENERIC_BUS_Rec{ + int scrnIndex; + DevUnion DriverPrivate; + Bool (*ioctl)(GENERIC_BUS_Ptr, long, long, char *); + Bool (*read)(GENERIC_BUS_Ptr, CARD32, CARD32, CARD8 *); + Bool (*write)(GENERIC_BUS_Ptr, CARD32, CARD32, CARD8 *); + } GENERIC_BUS_Rec; + + + + + +#endif diff --git a/src/mach64_common.h b/src/mach64_common.h new file mode 100644 index 0000000..00609e3 --- /dev/null +++ b/src/mach64_common.h @@ -0,0 +1,131 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* mach64_common.h -- common header definitions for Rage Pro 2D/3D/DRM suite + * Created: Sun Dec 03 11:34:16 2000 by gareth@valinux.com + * + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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. + * + * Author: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_COMMON_H__ +#define __MACH64_COMMON_H__ 1 + +/* WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (mach64_drm.h) + */ + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_MACH64_INIT 0x00 +#define DRM_MACH64_IDLE 0x01 +#define DRM_MACH64_RESET 0x02 +#define DRM_MACH64_SWAP 0x03 +#define DRM_MACH64_CLEAR 0x04 +#define DRM_MACH64_VERTEX 0x05 +#define DRM_MACH64_BLIT 0x06 +#define DRM_MACH64_FLUSH 0x07 +#define DRM_MACH64_GETPARAM 0x08 + +/* Buffer flags for clears + */ +#define MACH64_FRONT 0x1 +#define MACH64_BACK 0x2 +#define MACH64_DEPTH 0x4 + +/* Primitive types for vertex buffers + */ +#define MACH64_PRIM_POINTS 0x00000000 +#define MACH64_PRIM_LINES 0x00000001 +#define MACH64_PRIM_LINE_LOOP 0x00000002 +#define MACH64_PRIM_LINE_STRIP 0x00000003 +#define MACH64_PRIM_TRIANGLES 0x00000004 +#define MACH64_PRIM_TRIANGLE_STRIP 0x00000005 +#define MACH64_PRIM_TRIANGLE_FAN 0x00000006 +#define MACH64_PRIM_QUADS 0x00000007 +#define MACH64_PRIM_QUAD_STRIP 0x00000008 +#define MACH64_PRIM_POLYGON 0x00000009 + + +typedef enum _drmMach64DMAMode { + MACH64_MODE_DMA_ASYNC, + MACH64_MODE_DMA_SYNC, + MACH64_MODE_MMIO +} drmMach64DMAMode; + +typedef struct { + enum { + DRM_MACH64_INIT_DMA = 0x01, + DRM_MACH64_CLEANUP_DMA = 0x02 + } func; + unsigned long sarea_priv_offset; + int is_pci; + drmMach64DMAMode dma_mode; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; +} drmMach64Init; + +typedef struct { + unsigned int flags; + int x, y, w, h; + unsigned int clear_color; + unsigned int clear_depth; +} drmMach64Clear; + +typedef struct { + int prim; + void *buf; /* Address of vertex buffer */ + unsigned long used; /* Number of bytes in buffer */ + int discard; /* Client finished with buffer? */ +} drmMach64Vertex; + +typedef struct { + int idx; + int pitch; + int offset; + int format; + unsigned short x, y; + unsigned short width, height; +} drmMach64Blit; + +typedef struct { + int param; + int *value; +} drmMach64GetParam; + +#define MACH64_PARAM_FRAMES_QUEUED 1 +#define MACH64_PARAM_IRQ_NR 2 + +#endif /* __MACH64_COMMON_H__ */ diff --git a/src/mach64_dri.h b/src/mach64_dri.h new file mode 100644 index 0000000..139668e --- /dev/null +++ b/src/mach64_dri.h @@ -0,0 +1,126 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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. + */ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_DRI_H__ +#define __MACH64_DRI_H__ 1 + +#include "xf86drm.h" + +typedef struct { + drm_handle_t fbHandle; + + drm_handle_t regsHandle; + drmSize regsSize; + + int IsPCI; + + drm_handle_t agpHandle; /* Handle from drmAgpAlloc */ + unsigned long agpOffset; + drmSize agpSize; + int agpMode; + + /* DMA descriptor ring */ + unsigned long ringStart; /* Offset into AGP space */ + drm_handle_t ringHandle; /* Handle from drmAddMap */ + drmSize ringMapSize; /* Size of map */ + int ringSize; /* Size of ring (in kB) */ + drmAddress ringMap; /* Map */ + + /* vertex buffer data */ + unsigned long bufferStart; /* Offset into AGP space */ + drm_handle_t bufferHandle; /* Handle from drmAddMap */ + drmSize bufferMapSize; /* Size of map */ + int bufferSize; /* Size of buffers (in MB) */ + drmAddress bufferMap; /* Map */ + + drmBufMapPtr drmBuffers; /* Buffer map */ + int numBuffers; /* Number of buffers */ + + /* AGP Texture data */ + unsigned long agpTexStart; /* Offset into AGP space */ + drm_handle_t agpTexHandle; /* Handle from drmAddMap */ + drmSize agpTexMapSize; /* Size of map */ + int agpTexSize; /* Size of AGP tex space (in MB) */ + drmAddress agpTexMap; /* Map */ + int log2AGPTexGran; + + int fbX; + int fbY; + int backX; + int backY; + int depthX; + int depthY; + + int frontOffset; + int frontPitch; + int backOffset; + int backPitch; + int depthOffset; + int depthPitch; + + int textureOffset; + int textureSize; + int logTextureGranularity; +} ATIDRIServerInfoRec, *ATIDRIServerInfoPtr; + +typedef struct { + int chipset; + int width; + int height; + int mem; + int cpp; + + int IsPCI; + int AGPMode; + + unsigned int frontOffset; + unsigned int frontPitch; + + unsigned int backOffset; + unsigned int backPitch; + + unsigned int depthOffset; + unsigned int depthPitch; + + unsigned int textureOffset; + unsigned int textureSize; + int logTextureGranularity; + + drm_handle_t regs; + drmSize regsSize; + + drm_handle_t agp; + drmSize agpSize; + unsigned int agpTextureOffset; + unsigned int agpTextureSize; + int logAgpTextureGranularity; +} ATIDRIRec, *ATIDRIPtr; + +#endif /* __MACH64_DRI_H__ */ diff --git a/src/mach64_sarea.h b/src/mach64_sarea.h new file mode 100644 index 0000000..47a4bf9 --- /dev/null +++ b/src/mach64_sarea.h @@ -0,0 +1,163 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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. + */ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_SAREA_H__ +#define __MACH64_SAREA_H__ 1 + +#include "Xmd.h" + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the kernel file (mach64_drm.h) + */ +#ifndef __MACH64_SAREA_DEFINES__ +#define __MACH64_SAREA_DEFINES__ 1 + +/* What needs to be changed for the current vertex buffer? + * GH: We're going to be pedantic about this. We want the card to do as + * little as possible, so let's avoid having it fetch a whole bunch of + * register values that don't change all that often, if at all. + */ +#define MACH64_UPLOAD_DST_OFF_PITCH 0x0001 +#define MACH64_UPLOAD_Z_OFF_PITCH 0x0002 +#define MACH64_UPLOAD_Z_ALPHA_CNTL 0x0004 +#define MACH64_UPLOAD_SCALE_3D_CNTL 0x0008 +#define MACH64_UPLOAD_DP_FOG_CLR 0x0010 +#define MACH64_UPLOAD_DP_WRITE_MASK 0x0020 +#define MACH64_UPLOAD_DP_PIX_WIDTH 0x0040 +#define MACH64_UPLOAD_SETUP_CNTL 0x0080 +#define MACH64_UPLOAD_MISC 0x0100 +#define MACH64_UPLOAD_TEXTURE 0x0200 +#define MACH64_UPLOAD_TEX0IMAGE 0x0400 +#define MACH64_UPLOAD_TEX1IMAGE 0x0800 +#define MACH64_UPLOAD_CLIPRECTS 0x1000 /* handled client-side */ +#define MACH64_UPLOAD_CONTEXT 0x00ff +#define MACH64_UPLOAD_ALL 0x1fff + +/* DMA buffer size + */ +#define MACH64_BUFFER_SIZE 16384 + +/* Max number of swaps allowed on the ring + * before the client must wait + */ +#define MACH64_MAX_QUEUED_FRAMES 3 + +/* Byte offsets for host blit buffer data + */ +#define MACH64_HOSTDATA_BLIT_OFFSET 104 + +/* Keep these small for testing. + */ +#define MACH64_NR_SAREA_CLIPRECTS 8 + + +#define MACH64_CARD_HEAP 0 +#define MACH64_AGP_HEAP 1 +#define MACH64_NR_TEX_HEAPS 2 +#define MACH64_NR_TEX_REGIONS 64 +#define MACH64_LOG_TEX_GRANULARITY 16 + +#define MACH64_TEX_MAXLEVELS 1 + +#define MACH64_NR_CONTEXT_REGS 15 +#define MACH64_NR_TEXTURE_REGS 4 + +#endif /* __MACH64_SAREA_DEFINES__ */ + +typedef struct { + /* Context state */ + unsigned int dst_off_pitch; /* 0x500 */ + + unsigned int z_off_pitch; /* 0x548 */ /* ****** */ + unsigned int z_cntl; /* 0x54c */ + unsigned int alpha_tst_cntl; /* 0x550 */ + + unsigned int scale_3d_cntl; /* 0x5fc */ + + unsigned int sc_left_right; /* 0x6a8 */ + unsigned int sc_top_bottom; /* 0x6b4 */ + + unsigned int dp_fog_clr; /* 0x6c4 */ + unsigned int dp_write_mask; /* 0x6c8 */ + unsigned int dp_pix_width; /* 0x6d0 */ + unsigned int dp_mix; /* 0x6d4 */ /* ****** */ + unsigned int dp_src; /* 0x6d8 */ /* ****** */ + + unsigned int clr_cmp_cntl; /* 0x708 */ /* ****** */ + unsigned int gui_traj_cntl; /* 0x730 */ /* ****** */ + + unsigned int setup_cntl; /* 0x304 */ + + /* Texture state */ + unsigned int tex_size_pitch; /* 0x770 */ + unsigned int tex_cntl; /* 0x774 */ + unsigned int secondary_tex_off; /* 0x778 */ + unsigned int tex_offset; /* 0x5c0 */ +} mach64_context_regs_t; + +typedef struct { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + mach64_context_regs_t ContextState; + unsigned int dirty; + unsigned int vertsize; + +#ifdef XF86DRI + /* The current cliprects, or a subset thereof. + */ + drm_clip_rect_t boxes[MACH64_NR_SAREA_CLIPRECTS]; + unsigned int nbox; +#endif + /* Counter for throttling of rendering clients. + */ + unsigned int frames_queued; + + /* Maintain an LRU of contiguous regions of texture space. If you + * think you own a region of texture memory, and it has an age + * different to the one you set, then you are mistaken and it has + * been stolen by another client. If global texAge hasn't changed, + * there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained texture + * information of other clients - by maintaining them in the same + * lru which is used to age their own textures, clients have an + * approximate lru for the whole of global texture space, and can + * make informed decisions as to which areas to kick out. There is + * no need to choose whether to kick out your own texture or someone + * else's - simply eject them all in LRU order. + */ + drmTextureRegion texList[MACH64_NR_TEX_HEAPS][MACH64_NR_TEX_REGIONS+1]; + unsigned int texAge[MACH64_NR_TEX_HEAPS]; + + int ctxOwner; /* last context to upload state */ +} ATISAREAPrivRec, *ATISAREAPrivPtr; + +#endif /* __MACH64_SAREA_H__ */ diff --git a/src/r128.h b/src/r128.h new file mode 100644 index 0000000..3b47755 --- /dev/null +++ b/src/r128.h @@ -0,0 +1,558 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128.h,v 1.26 2003/11/06 18:37:58 tsi Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef _R128_H_ +#define _R128_H_ + +#include "xf86str.h" + + /* PCI support */ +#include "xf86Pci.h" + + /* XAA and Cursor Support */ +#include "xaa.h" +#include "xf86Cursor.h" + + /* DDC support */ +#include "xf86DDC.h" + + /* Xv support */ +#include "xf86xv.h" + + /* DRI support */ +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "r128_dripriv.h" +#include "dri.h" +#include "GL/glxint.h" +#endif + +#define R128_DEBUG 0 /* Turn off debugging output */ +#define R128_IDLE_RETRY 32 /* Fall out of idle loops after this count */ +#define R128_TIMEOUT 2000000 /* Fall out of wait loops after this count */ +#define R128_MMIOSIZE 0x4000 + +#define R128_VBIOS_SIZE 0x00010000 + +#if R128_DEBUG +#define R128TRACE(x) \ + do { \ + ErrorF("(**) %s(%d): ", R128_NAME, pScrn->scrnIndex); \ + ErrorF x; \ + } while (0); +#else +#define R128TRACE(x) +#endif + + +/* Other macros */ +#define R128_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define R128_ALIGN(x,bytes) (((x) + ((bytes) - 1)) & ~((bytes) - 1)) +#define R128PTR(pScrn) ((R128InfoPtr)(pScrn)->driverPrivate) + +typedef struct { /* All values in XCLKS */ + int ML; /* Memory Read Latency */ + int MB; /* Memory Burst Length */ + int Trcd; /* RAS to CAS delay */ + int Trp; /* RAS percentage */ + int Twr; /* Write Recovery */ + int CL; /* CAS Latency */ + int Tr2w; /* Read to Write Delay */ + int Rloop; /* Loop Latency */ + int Rloop_fudge; /* Add to ML to get Rloop */ + char *name; +} R128RAMRec, *R128RAMPtr; + +typedef struct { + /* Common registers */ + CARD32 ovr_clr; + CARD32 ovr_wid_left_right; + CARD32 ovr_wid_top_bottom; + CARD32 ov0_scale_cntl; + CARD32 mpp_tb_config; + CARD32 mpp_gp_config; + CARD32 subpic_cntl; + CARD32 viph_control; + CARD32 i2c_cntl_1; + CARD32 gen_int_cntl; + CARD32 cap0_trig_cntl; + CARD32 cap1_trig_cntl; + CARD32 bus_cntl; + CARD32 config_cntl; + + /* Other registers to save for VT switches */ + CARD32 dp_datatype; + CARD32 gen_reset_cntl; + CARD32 clock_cntl_index; + CARD32 amcgpio_en_reg; + CARD32 amcgpio_mask; + + /* CRTC registers */ + CARD32 crtc_gen_cntl; + CARD32 crtc_ext_cntl; + CARD32 dac_cntl; + CARD32 crtc_h_total_disp; + CARD32 crtc_h_sync_strt_wid; + CARD32 crtc_v_total_disp; + CARD32 crtc_v_sync_strt_wid; + CARD32 crtc_offset; + CARD32 crtc_offset_cntl; + CARD32 crtc_pitch; + + /* CRTC2 registers */ + CARD32 crtc2_gen_cntl; + + /* Flat panel registers */ + CARD32 fp_crtc_h_total_disp; + CARD32 fp_crtc_v_total_disp; + CARD32 fp_gen_cntl; + CARD32 fp_h_sync_strt_wid; + CARD32 fp_horz_stretch; + CARD32 fp_panel_cntl; + CARD32 fp_v_sync_strt_wid; + CARD32 fp_vert_stretch; + CARD32 lvds_gen_cntl; + CARD32 tmds_crc; + CARD32 tmds_transmitter_cntl; + + /* Computed values for PLL */ + CARD32 dot_clock_freq; + CARD32 pll_output_freq; + int feedback_div; + int post_div; + + /* PLL registers */ + CARD32 ppll_ref_div; + CARD32 ppll_div_3; + CARD32 htotal_cntl; + + /* DDA register */ + CARD32 dda_config; + CARD32 dda_on_off; + + /* Pallet */ + Bool palette_valid; + CARD32 palette[256]; +} R128SaveRec, *R128SavePtr; + +typedef struct { + CARD16 reference_freq; + CARD16 reference_div; + unsigned min_pll_freq; + unsigned max_pll_freq; + CARD16 xclk; +} R128PLLRec, *R128PLLPtr; + +typedef struct { + int bitsPerPixel; + int depth; + int displayWidth; + int pixel_code; + int pixel_bytes; + DisplayModePtr mode; +} R128FBLayout; + +typedef struct { + EntityInfoPtr pEnt; + pciVideoPtr PciInfo; + PCITAG PciTag; + int Chipset; + Bool Primary; + + Bool FBDev; + + unsigned long LinearAddr; /* Frame buffer physical address */ + unsigned long MMIOAddr; /* MMIO region physical address */ + unsigned long BIOSAddr; /* BIOS physical address */ + + unsigned char *MMIO; /* Map of MMIO region */ + unsigned char *FB; /* Map of frame buffer */ + + CARD32 MemCntl; + CARD32 BusCntl; + unsigned long FbMapSize; /* Size of frame buffer, in bytes */ + int Flags; /* Saved copy of mode flags */ + + CARD8 BIOSDisplay; /* Device the BIOS is set to display to */ + + Bool HasPanelRegs; /* Current chip can connect to a FP */ + CARD8 *VBIOS; /* Video BIOS for mode validation on FPs */ + int FPBIOSstart; /* Start of the flat panel info */ + + /* Computed values for FPs */ + int PanelXRes; + int PanelYRes; + int HOverPlus; + int HSyncWidth; + int HBlank; + int VOverPlus; + int VSyncWidth; + int VBlank; + int PanelPwrDly; + + R128PLLRec pll; + R128RAMPtr ram; + + R128SaveRec SavedReg; /* Original (text) mode */ + R128SaveRec ModeReg; /* Current mode */ + Bool (*CloseScreen)(int, ScreenPtr); + void (*BlockHandler)(int, pointer, pointer, pointer); + + Bool PaletteSavedOnVT; /* Palette saved on last VT switch */ + + XAAInfoRecPtr accel; + Bool accelOn; + xf86CursorInfoPtr cursor; + unsigned long cursor_start; + unsigned long cursor_end; + + /* + * XAAForceTransBlit is used to change the behavior of the XAA + * SetupForScreenToScreenCopy function, to make it DGA-friendly. + */ + Bool XAAForceTransBlit; + + int fifo_slots; /* Free slots in the FIFO (64 max) */ + int pix24bpp; /* Depth of pixmap for 24bpp framebuffer */ + Bool dac6bits; /* Use 6 bit DAC? */ + + /* Computed values for Rage 128 */ + int pitch; + int datatype; + CARD32 dp_gui_master_cntl; + + /* Saved values for ScreenToScreenCopy */ + int xdir; + int ydir; + + /* ScanlineScreenToScreenColorExpand support */ + unsigned char *scratch_buffer[1]; + unsigned char *scratch_save; + int scanline_x; + int scanline_y; + int scanline_w; + int scanline_h; +#ifdef XF86DRI + int scanline_hpass; + int scanline_x1clip; + int scanline_x2clip; + int scanline_rop; + int scanline_fg; + int scanline_bg; +#endif /* XF86DRI */ + int scanline_words; + int scanline_direct; + int scanline_bpp; /* Only used for ImageWrite */ + + DGAModePtr DGAModes; + int numDGAModes; + Bool DGAactive; + int DGAViewportStatus; + DGAFunctionRec DGAFuncs; + + R128FBLayout CurrentLayout; +#ifdef XF86DRI + Bool directRenderingEnabled; + DRIInfoPtr pDRIInfo; + int drmFD; + drmContext drmCtx; + int numVisualConfigs; + __GLXvisualConfig *pVisualConfigs; + R128ConfigPrivPtr pVisualConfigsPriv; + + drmHandle fbHandle; + + drmSize registerSize; + drmHandle registerHandle; + + Bool IsPCI; /* Current card is a PCI card */ + drmSize pciSize; + drmHandle pciMemHandle; + unsigned char *PCI; /* Map */ + + Bool allowPageFlip; /* Enable 3d page flipping */ + Bool have3DWindows; /* Are there any 3d clients? */ + int drmMinor; + + drmSize agpSize; + drmHandle agpMemHandle; /* Handle from drmAgpAlloc */ + unsigned long agpOffset; + unsigned char *AGP; /* Map */ + int agpMode; + + Bool CCEInUse; /* CCE is currently active */ + int CCEMode; /* CCE mode that server/clients use */ + int CCEFifoSize; /* Size of the CCE command FIFO */ + Bool CCESecure; /* CCE security enabled */ + int CCEusecTimeout; /* CCE timeout in usecs */ + + /* CCE ring buffer data */ + unsigned long ringStart; /* Offset into AGP space */ + drmHandle ringHandle; /* Handle from drmAddMap */ + drmSize ringMapSize; /* Size of map */ + int ringSize; /* Size of ring (in MB) */ + unsigned char *ring; /* Map */ + int ringSizeLog2QW; + + unsigned long ringReadOffset; /* Offset into AGP space */ + drmHandle ringReadPtrHandle; /* Handle from drmAddMap */ + drmSize ringReadMapSize; /* Size of map */ + unsigned char *ringReadPtr; /* Map */ + + /* CCE vertex/indirect buffer data */ + unsigned long bufStart; /* Offset into AGP space */ + drmHandle bufHandle; /* Handle from drmAddMap */ + drmSize bufMapSize; /* Size of map */ + int bufSize; /* Size of buffers (in MB) */ + unsigned char *buf; /* Map */ + int bufNumBufs; /* Number of buffers */ + drmBufMapPtr buffers; /* Buffer map */ + + /* CCE AGP Texture data */ + unsigned long agpTexStart; /* Offset into AGP space */ + drmHandle agpTexHandle; /* Handle from drmAddMap */ + drmSize agpTexMapSize; /* Size of map */ + int agpTexSize; /* Size of AGP tex space (in MB) */ + unsigned char *agpTex; /* Map */ + int log2AGPTexGran; + + /* CCE 2D accleration */ + drmBufPtr indirectBuffer; + int indirectStart; + + /* DRI screen private data */ + int fbX; + int fbY; + int backX; + int backY; + int depthX; + int depthY; + + int frontOffset; + int frontPitch; + int backOffset; + int backPitch; + int depthOffset; + int depthPitch; + int spanOffset; + int textureOffset; + int textureSize; + int log2TexGran; + + /* Saved scissor values */ + CARD32 sc_left; + CARD32 sc_right; + CARD32 sc_top; + CARD32 sc_bottom; + + CARD32 re_top_left; + CARD32 re_width_height; + + CARD32 aux_sc_cntl; + + int irq; + CARD32 gen_int_cntl; + + Bool DMAForXv; +#endif + + XF86VideoAdaptorPtr adaptor; + void (*VideoTimerCallback)(ScrnInfoPtr, Time); + int videoKey; + Bool showCache; + OptionInfoPtr Options; + + Bool isDFP; + Bool isPro2; + I2CBusPtr pI2CBus; + CARD32 DDCReg; + +} R128InfoRec, *R128InfoPtr; + +#define R128WaitForFifo(pScrn, entries) \ +do { \ + if (info->fifo_slots < entries) R128WaitForFifoFunction(pScrn, entries); \ + info->fifo_slots -= entries; \ +} while (0) + +extern void R128WaitForFifoFunction(ScrnInfoPtr pScrn, int entries); +extern void R128WaitForIdle(ScrnInfoPtr pScrn); +extern void R128EngineReset(ScrnInfoPtr pScrn); +extern void R128EngineFlush(ScrnInfoPtr pScrn); + +extern unsigned R128INPLL(ScrnInfoPtr pScrn, int addr); +extern void R128WaitForVerticalSync(ScrnInfoPtr pScrn); + +extern Bool R128AccelInit(ScreenPtr pScreen); +extern void R128EngineInit(ScrnInfoPtr pScrn); +extern Bool R128CursorInit(ScreenPtr pScreen); +extern Bool R128DGAInit(ScreenPtr pScreen); + +extern int R128MinBits(int val); + +extern void R128InitVideo(ScreenPtr pScreen); + +#ifdef XF86DRI +extern Bool R128DRIScreenInit(ScreenPtr pScreen); +extern void R128DRICloseScreen(ScreenPtr pScreen); +extern Bool R128DRIFinishScreenInit(ScreenPtr pScreen); + +#define R128CCE_START(pScrn, info) \ +do { \ + int _ret = drmCommandNone(info->drmFD, DRM_R128_CCE_START); \ + if (_ret) { \ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, \ + "%s: CCE start %d\n", __FUNCTION__, _ret); \ + } \ +} while (0) + +#define R128CCE_STOP(pScrn, info) \ +do { \ + int _ret = R128CCEStop(pScrn); \ + if (_ret) { \ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, \ + "%s: CCE stop %d\n", __FUNCTION__, _ret); \ + } \ +} while (0) + +#define R128CCE_RESET(pScrn, info) \ +do { \ + if (info->directRenderingEnabled \ + && R128CCE_USE_RING_BUFFER(info->CCEMode)) { \ + int _ret = drmCommandNone(info->drmFD, DRM_R128_CCE_RESET); \ + if (_ret) { \ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, \ + "%s: CCE reset %d\n", __FUNCTION__, _ret); \ + } \ + } \ +} while (0) + +extern drmBufPtr R128CCEGetBuffer(ScrnInfoPtr pScrn); +#endif + +extern void R128CCEFlushIndirect(ScrnInfoPtr pScrn, int discard); +extern void R128CCEReleaseIndirect(ScrnInfoPtr pScrn); +extern void R128CCEWaitForIdle(ScrnInfoPtr pScrn); +extern int R128CCEStop(ScrnInfoPtr pScrn); + + +#define CCE_PACKET0( reg, n ) \ + (R128_CCE_PACKET0 | ((n) << 16) | ((reg) >> 2)) +#define CCE_PACKET1( reg0, reg1 ) \ + (R128_CCE_PACKET1 | (((reg1) >> 2) << 11) | ((reg0) >> 2)) +#define CCE_PACKET2() \ + (R128_CCE_PACKET2) +#define CCE_PACKET3( pkt, n ) \ + (R128_CCE_PACKET3 | (pkt) | ((n) << 16)) + + +#define R128_VERBOSE 0 + +#define RING_LOCALS CARD32 *__head; int __count; + +#define R128CCE_REFRESH(pScrn, info) \ +do { \ + if ( R128_VERBOSE ) { \ + xf86DrvMsg( pScrn->scrnIndex, X_INFO, "REFRESH( %d ) in %s\n", \ + !info->CCEInUse , __FUNCTION__ ); \ + } \ + if ( !info->CCEInUse ) { \ + R128CCEWaitForIdle(pScrn); \ + BEGIN_RING( 6 ); \ + OUT_RING_REG( R128_RE_TOP_LEFT, info->re_top_left ); \ + OUT_RING_REG( R128_RE_WIDTH_HEIGHT, info->re_width_height ); \ + OUT_RING_REG( R128_AUX_SC_CNTL, info->aux_sc_cntl ); \ + ADVANCE_RING(); \ + info->CCEInUse = TRUE; \ + } \ +} while (0) + +#define BEGIN_RING( n ) do { \ + if ( R128_VERBOSE ) { \ + xf86DrvMsg( pScrn->scrnIndex, X_INFO, \ + "BEGIN_RING( %d ) in %s\n", n, __FUNCTION__ ); \ + } \ + if ( !info->indirectBuffer ) { \ + info->indirectBuffer = R128CCEGetBuffer( pScrn ); \ + info->indirectStart = 0; \ + } else if ( (info->indirectBuffer->used + 4*(n)) > \ + info->indirectBuffer->total ) { \ + R128CCEFlushIndirect( pScrn, 1 ); \ + } \ + __head = (pointer)((char *)info->indirectBuffer->address + \ + info->indirectBuffer->used); \ + __count = 0; \ +} while (0) + +#define ADVANCE_RING() do { \ + if ( R128_VERBOSE ) { \ + xf86DrvMsg( pScrn->scrnIndex, X_INFO, \ + "ADVANCE_RING() used: %d+%d=%d/%d\n", \ + info->indirectBuffer->used - info->indirectStart, \ + __count * (int)sizeof(CARD32), \ + info->indirectBuffer->used - info->indirectStart + \ + __count * (int)sizeof(CARD32), \ + info->indirectBuffer->total - info->indirectStart ); \ + } \ + info->indirectBuffer->used += __count * (int)sizeof(CARD32); \ +} while (0) + +#define OUT_RING( x ) do { \ + if ( R128_VERBOSE ) { \ + xf86DrvMsg( pScrn->scrnIndex, X_INFO, \ + " OUT_RING( 0x%08x )\n", (unsigned int)(x) ); \ + } \ + MMIO_OUT32(&__head[__count++], 0, (x)); \ +} while (0) + +#define OUT_RING_REG( reg, val ) \ +do { \ + OUT_RING( CCE_PACKET0( reg, 0 ) ); \ + OUT_RING( val ); \ +} while (0) + +#define FLUSH_RING() \ +do { \ + if ( R128_VERBOSE ) \ + xf86DrvMsg( pScrn->scrnIndex, X_INFO, \ + "FLUSH_RING in %s\n", __FUNCTION__ ); \ + if ( info->indirectBuffer ) { \ + R128CCEFlushIndirect( pScrn, 0 ); \ + } \ +} while (0) + +#endif diff --git a/src/r128_accel.c b/src/r128_accel.c new file mode 100644 index 0000000..44bc2d4 --- /dev/null +++ b/src/r128_accel.c @@ -0,0 +1,1805 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_accel.c,v 1.17 2003/10/03 20:11:11 herrb Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + * Credits: + * + * Thanks to Alan Hourihane <alanh@fairlite.demon..co.uk> and SuSE for + * providing source code to their 3.3.x Rage 128 driver. Portions of + * this file are based on the acceleration code for that driver. + * + * References: + * + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + * Notes on unimplemented XAA optimizations: + * + * SetClipping: The Rage128 doesn't support the full 16bit registers needed + * for XAA clip rect support. + * SolidFillTrap: This will probably work if we can compute the correct + * Bresenham error values. + * TwoPointLine: The Rage 128 supports Bresenham lines instead. + * DashedLine with non-power-of-two pattern length: Apparently, there is + * no way to set the length of the pattern -- it is always + * assumed to be 8 or 32 (or 1024?). + * ScreenToScreenColorExpandFill: See p. 4-17 of the Technical Reference + * Manual where it states that monochrome expansion of frame + * buffer data is not supported. + * CPUToScreenColorExpandFill, direct: The implementation here uses a hybrid + * direct/indirect method. If we had more data registers, + * then we could do better. If XAA supported a trigger write + * address, the code would be simpler. + * (Alan Hourihane) Update. We now use purely indirect and clip the full + * rectangle. Seems as the direct method has some problems + * with this, although this indirect method is much faster + * than the old method of setting up the engine per scanline. + * This code was the basis of the Radeon work we did. + * Color8x8PatternFill: Apparently, an 8x8 color brush cannot take an 8x8 + * pattern from frame buffer memory. + * ImageWrites: See CPUToScreenColorExpandFill. + * + */ + +#define R128_TRAPEZOIDS 0 /* Trapezoids don't work */ + + /* Driver data structures */ +#include "r128.h" +#include "r128_reg.h" +#ifdef XF86DRI +#include "r128_sarea.h" +#define _XF86DRI_SERVER_ +#include "r128_dri.h" +#endif + + /* Line support */ +#include "miline.h" + + /* X and server generic header files */ +#include "xf86.h" + +static struct { + int rop; + int pattern; +} R128_ROP[] = { + { R128_ROP3_ZERO, R128_ROP3_ZERO }, /* GXclear */ + { R128_ROP3_DSa, R128_ROP3_DPa }, /* Gxand */ + { R128_ROP3_SDna, R128_ROP3_PDna }, /* GXandReverse */ + { R128_ROP3_S, R128_ROP3_P }, /* GXcopy */ + { R128_ROP3_DSna, R128_ROP3_DPna }, /* GXandInverted */ + { R128_ROP3_D, R128_ROP3_D }, /* GXnoop */ + { R128_ROP3_DSx, R128_ROP3_DPx }, /* GXxor */ + { R128_ROP3_DSo, R128_ROP3_DPo }, /* GXor */ + { R128_ROP3_DSon, R128_ROP3_DPon }, /* GXnor */ + { R128_ROP3_DSxn, R128_ROP3_PDxn }, /* GXequiv */ + { R128_ROP3_Dn, R128_ROP3_Dn }, /* GXinvert */ + { R128_ROP3_SDno, R128_ROP3_PDno }, /* GXorReverse */ + { R128_ROP3_Sn, R128_ROP3_Pn }, /* GXcopyInverted */ + { R128_ROP3_DSno, R128_ROP3_DPno }, /* GXorInverted */ + { R128_ROP3_DSan, R128_ROP3_DPan }, /* GXnand */ + { R128_ROP3_ONE, R128_ROP3_ONE } /* GXset */ +}; + +/* Flush all dirty data in the Pixel Cache to memory. */ +void R128EngineFlush(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + OUTREGP(R128_PC_NGUI_CTLSTAT, R128_PC_FLUSH_ALL, ~R128_PC_FLUSH_ALL); + for (i = 0; i < R128_TIMEOUT; i++) { + if (!(INREG(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) break; + } +} + +/* Reset graphics card to known state. */ +void R128EngineReset(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + CARD32 clock_cntl_index; + CARD32 mclk_cntl; + CARD32 gen_reset_cntl; + + R128EngineFlush(pScrn); + + clock_cntl_index = INREG(R128_CLOCK_CNTL_INDEX); + mclk_cntl = INPLL(pScrn, R128_MCLK_CNTL); + + OUTPLL(R128_MCLK_CNTL, mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP); + + gen_reset_cntl = INREG(R128_GEN_RESET_CNTL); + + OUTREG(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI); + INREG(R128_GEN_RESET_CNTL); + OUTREG(R128_GEN_RESET_CNTL, + gen_reset_cntl & (CARD32)(~R128_SOFT_RESET_GUI)); + INREG(R128_GEN_RESET_CNTL); + + OUTPLL(R128_MCLK_CNTL, mclk_cntl); + OUTREG(R128_CLOCK_CNTL_INDEX, clock_cntl_index); + OUTREG(R128_GEN_RESET_CNTL, gen_reset_cntl); +} + +/* The FIFO has 64 slots. This routines waits until at least `entries' of + these slots are empty. */ +void R128WaitForFifoFunction(ScrnInfoPtr pScrn, int entries) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + for (;;) { + for (i = 0; i < R128_TIMEOUT; i++) { + info->fifo_slots = INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK; + if (info->fifo_slots >= entries) return; + } + R128TRACE(("FIFO timed out: %d entries, stat=0x%08x, probe=0x%08x\n", + INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK, + INREG(R128_GUI_STAT), + INREG(R128_GUI_PROBE))); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FIFO timed out, resetting engine...\n"); + R128EngineReset(pScrn); +#ifdef XF86DRI + R128CCE_RESET(pScrn, info); + if (info->directRenderingEnabled) { + R128CCE_START(pScrn, info); + } +#endif + } +} + +/* Wait for the graphics engine to be completely idle: the FIFO has + drained, the Pixel Cache is flushed, and the engine is idle. This is a + standard "sync" function that will make the hardware "quiescent". */ +void R128WaitForIdle(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + R128WaitForFifoFunction(pScrn, 64); + + for (;;) { + for (i = 0; i < R128_TIMEOUT; i++) { + if (!(INREG(R128_GUI_STAT) & R128_GUI_ACTIVE)) { + R128EngineFlush(pScrn); + return; + } + } + R128TRACE(("Idle timed out: %d entries, stat=0x%08x, probe=0x%08x\n", + INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK, + INREG(R128_GUI_STAT), + INREG(R128_GUI_PROBE))); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Idle timed out, resetting engine...\n"); + R128EngineReset(pScrn); +#ifdef XF86DRI + R128CCE_RESET(pScrn, info); + if (info->directRenderingEnabled) { + R128CCE_START(pScrn, info); + } +#endif + } +} + +#ifdef XF86DRI +/* Wait until the CCE is completely idle: the FIFO has drained and the + * CCE is idle. + */ +void R128CCEWaitForIdle(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + int ret, i; + + FLUSH_RING(); + + for (;;) { + i = 0; + do { + ret = drmCommandNone(info->drmFD, DRM_R128_CCE_IDLE); + } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); + + if (ret && ret != -EBUSY) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "%s: CCE idle %d\n", __FUNCTION__, ret); + } + + if (ret == 0) return; + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Idle timed out, resetting engine...\n"); + R128EngineReset(pScrn); + + /* Always restart the engine when doing CCE 2D acceleration */ + R128CCE_RESET(pScrn, info); + R128CCE_START(pScrn, info); + } +} + +int R128CCEStop(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + drmR128CCEStop stop; + int ret, i; + + stop.flush = 1; + stop.idle = 1; + + ret = drmCommandWrite( info->drmFD, DRM_R128_CCE_STOP, + &stop, sizeof(drmR128CCEStop) ); + + if ( ret == 0 ) { + return 0; + } else if ( errno != EBUSY ) { + return -errno; + } + + stop.flush = 0; + + i = 0; + do { + ret = drmCommandWrite( info->drmFD, DRM_R128_CCE_STOP, + &stop, sizeof(drmR128CCEStop) ); + } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); + + if ( ret == 0 ) { + return 0; + } else if ( errno != EBUSY ) { + return -errno; + } + + stop.idle = 0; + + if ( drmCommandWrite( info->drmFD, DRM_R128_CCE_STOP, + &stop, sizeof(drmR128CCEStop) )) { + return -errno; + } else { + return 0; + } +} + +#endif + +/* Setup for XAA SolidFill. */ +static void R128SetupForSolidFill(ScrnInfoPtr pScrn, + int color, int rop, unsigned int planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 4); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_BRUSH_SOLID_COLOR + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].pattern)); + OUTREG(R128_DP_BRUSH_FRGD_CLR, color); + OUTREG(R128_DP_WRITE_MASK, planemask); + OUTREG(R128_DP_CNTL, (R128_DST_X_LEFT_TO_RIGHT + | R128_DST_Y_TOP_TO_BOTTOM)); +} + +/* Subsequent XAA SolidFillRect. + + Tests: xtest CH06/fllrctngl, xterm +*/ +static void R128SubsequentSolidFillRect(ScrnInfoPtr pScrn, + int x, int y, int w, int h) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 2); + OUTREG(R128_DST_Y_X, (y << 16) | x); + OUTREG(R128_DST_WIDTH_HEIGHT, (w << 16) | h); +} + +/* Setup for XAA solid lines. */ +static void R128SetupForSolidLine(ScrnInfoPtr pScrn, + int color, int rop, unsigned int planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 3); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_BRUSH_SOLID_COLOR + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].pattern)); + OUTREG(R128_DP_BRUSH_FRGD_CLR, color); + OUTREG(R128_DP_WRITE_MASK, planemask); +} + + +/* Subsequent XAA solid Bresenham line. + + Tests: xtest CH06/drwln, ico, Mark Vojkovich's linetest program + + [See http://www.xfree86.org/devel/archives/devel/1999-Jun/0102.shtml for + Mark Vojkovich's linetest program, posted 2Jun99 to devel@xfree86.org.] + + x11perf -line500 + 1024x768@76Hz 1024x768@76Hz + 8bpp 32bpp + not used: 39700.0/sec 34100.0/sec + used: 47600.0/sec 36800.0/sec +*/ +static void R128SubsequentSolidBresenhamLine(ScrnInfoPtr pScrn, + int x, int y, + int major, int minor, + int err, int len, int octant) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int flags = 0; + + if (octant & YMAJOR) flags |= R128_DST_Y_MAJOR; + if (!(octant & XDECREASING)) flags |= R128_DST_X_DIR_LEFT_TO_RIGHT; + if (!(octant & YDECREASING)) flags |= R128_DST_Y_DIR_TOP_TO_BOTTOM; + + R128WaitForFifo(pScrn, 6); + OUTREG(R128_DP_CNTL_XDIR_YDIR_YMAJOR, flags); + OUTREG(R128_DST_Y_X, (y << 16) | x); + OUTREG(R128_DST_BRES_ERR, err); + OUTREG(R128_DST_BRES_INC, minor); + OUTREG(R128_DST_BRES_DEC, -major); + OUTREG(R128_DST_BRES_LNTH, len); +} + +/* Subsequent XAA solid horizontal and vertical lines + + 1024x768@76Hz 8bpp + Without With + x11perf -hseg500 87600.0/sec 798000.0/sec + x11perf -vseg500 38100.0/sec 38000.0/sec +*/ +static void R128SubsequentSolidHorVertLine(ScrnInfoPtr pScrn, + int x, int y, int len, int dir ) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 1); + OUTREG(R128_DP_CNTL, (R128_DST_X_LEFT_TO_RIGHT + | R128_DST_Y_TOP_TO_BOTTOM)); + + if (dir == DEGREES_0) { + R128SubsequentSolidFillRect(pScrn, x, y, len, 1); + } else { + R128SubsequentSolidFillRect(pScrn, x, y, 1, len); + } +} + +/* Setup for XAA dashed lines. + + Tests: xtest CH05/stdshs, XFree86/drwln + + NOTE: Since we can only accelerate lines with power-of-2 patterns of + length <= 32, these x11perf numbers are not representative of the + speed-up on appropriately-sized patterns. + + 1024x768@76Hz 8bpp + Without With + x11perf -dseg100 218000.0/sec 222000.0/sec + x11perf -dline100 215000.0/sec 221000.0/sec + x11perf -ddline100 178000.0/sec 180000.0/sec +*/ +static void R128SetupForDashedLine(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, unsigned int planemask, + int length, unsigned char *pattern) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + CARD32 pat = *(CARD32 *)(pointer)pattern; + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN +# define PAT_SHIFT(pat,n) pat << n +#else +# define PAT_SHIFT(pat,n) pat >> n +#endif + + switch (length) { + case 2: pat |= PAT_SHIFT(pat,2); /* fall through */ + case 4: pat |= PAT_SHIFT(pat,4); /* fall through */ + case 8: pat |= PAT_SHIFT(pat,8); /* fall through */ + case 16: pat |= PAT_SHIFT(pat,16); + } + + R128WaitForFifo(pScrn, 5); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | (bg == -1 + ? R128_GMC_BRUSH_32x1_MONO_FG_LA + : R128_GMC_BRUSH_32x1_MONO_FG_BG) + | R128_ROP[rop].pattern + | R128_GMC_BYTE_LSB_TO_MSB)); + OUTREG(R128_DP_WRITE_MASK, planemask); + OUTREG(R128_DP_BRUSH_FRGD_CLR, fg); + OUTREG(R128_DP_BRUSH_BKGD_CLR, bg); + OUTREG(R128_BRUSH_DATA0, pat); +} + +/* Subsequent XAA dashed line. */ +static void R128SubsequentDashedBresenhamLine(ScrnInfoPtr pScrn, + int x, int y, + int major, int minor, + int err, int len, int octant, + int phase) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int flags = 0; + + if (octant & YMAJOR) flags |= R128_DST_Y_MAJOR; + if (!(octant & XDECREASING)) flags |= R128_DST_X_DIR_LEFT_TO_RIGHT; + if (!(octant & YDECREASING)) flags |= R128_DST_Y_DIR_TOP_TO_BOTTOM; + + R128WaitForFifo(pScrn, 7); + OUTREG(R128_DP_CNTL_XDIR_YDIR_YMAJOR, flags); + OUTREG(R128_DST_Y_X, (y << 16) | x); + OUTREG(R128_BRUSH_Y_X, (phase << 16) | phase); + OUTREG(R128_DST_BRES_ERR, err); + OUTREG(R128_DST_BRES_INC, minor); + OUTREG(R128_DST_BRES_DEC, -major); + OUTREG(R128_DST_BRES_LNTH, len); +} + +#if R128_TRAPEZOIDS + /* This doesn't work. Except in the + lower-left quadrant, all of the pixel + errors appear to be because eL and eR + are not correct. Drawing from right to + left doesn't help. Be aware that the + non-_SUB registers set the sub-pixel + values to 0.5 (0x08), which isn't what + XAA wants. */ +/* Subsequent XAA SolidFillTrap. XAA always passes data that assumes we + fill from top to bottom, so dyL and dyR are always non-negative. */ +static void R128SubsequentSolidFillTrap(ScrnInfoPtr pScrn, int y, int h, + int left, int dxL, int dyL, int eL, + int right, int dxR, int dyR, int eR) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int flags = 0; + int Lymajor = 0; + int Rymajor = 0; + int origdxL = dxL; + int origdxR = dxR; + + R128TRACE(("Trap %d %d; L %d %d %d %d; R %d %d %d %d\n", + y, h, + left, dxL, dyL, eL, + right, dxR, dyR, eR)); + + if (dxL < 0) dxL = -dxL; else flags |= (1 << 0) /* | (1 << 8) */; + if (dxR < 0) dxR = -dxR; else flags |= (1 << 6); + + R128WaitForFifo(pScrn, 11); + +#if 1 + OUTREG(R128_DP_CNTL, flags | (1 << 1) | (1 << 7)); + OUTREG(R128_DST_Y_SUB, ((y) << 4) | 0x0 ); + OUTREG(R128_DST_X_SUB, ((left) << 4)|0x0); + OUTREG(R128_TRAIL_BRES_ERR, eR-dxR); + OUTREG(R128_TRAIL_BRES_INC, dxR); + OUTREG(R128_TRAIL_BRES_DEC, -dyR); + OUTREG(R128_TRAIL_X_SUB, ((right) << 4) | 0x0); + OUTREG(R128_LEAD_BRES_ERR, eL-dxL); + OUTREG(R128_LEAD_BRES_INC, dxL); + OUTREG(R128_LEAD_BRES_DEC, -dyL); + OUTREG(R128_LEAD_BRES_LNTH_SUB, ((h) << 4) | 0x00); +#else + OUTREG(R128_DP_CNTL, flags | (1 << 1) ); + OUTREG(R128_DST_Y_SUB, (y << 4)); + OUTREG(R128_DST_X_SUB, (right << 4)); + OUTREG(R128_TRAIL_BRES_ERR, eL); + OUTREG(R128_TRAIL_BRES_INC, dxL); + OUTREG(R128_TRAIL_BRES_DEC, -dyL); + OUTREG(R128_TRAIL_X_SUB, (left << 4) | 0); + OUTREG(R128_LEAD_BRES_ERR, eR); + OUTREG(R128_LEAD_BRES_INC, dxR); + OUTREG(R128_LEAD_BRES_DEC, -dyR); + OUTREG(R128_LEAD_BRES_LNTH_SUB, h << 4); +#endif +} +#endif + +/* Setup for XAA screen-to-screen copy. + + Tests: xtest CH06/fllrctngl (also tests transparency). +*/ +static void R128SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, + int xdir, int ydir, int rop, + unsigned int planemask, + int trans_color) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + info->xdir = xdir; + info->ydir = ydir; + R128WaitForFifo(pScrn, 3); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_BRUSH_SOLID_COLOR + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].rop + | R128_DP_SRC_SOURCE_MEMORY)); + OUTREG(R128_DP_WRITE_MASK, planemask); + OUTREG(R128_DP_CNTL, ((xdir >= 0 ? R128_DST_X_LEFT_TO_RIGHT : 0) + | (ydir >= 0 + ? R128_DST_Y_TOP_TO_BOTTOM + : 0))); + + if ((trans_color != -1) || (info->XAAForceTransBlit == TRUE)) { + /* Set up for transparency */ + R128WaitForFifo(pScrn, 3); + OUTREG(R128_CLR_CMP_CLR_SRC, trans_color); + OUTREG(R128_CLR_CMP_MASK, R128_CLR_CMP_MSK); + OUTREG(R128_CLR_CMP_CNTL, (R128_SRC_CMP_NEQ_COLOR + | R128_CLR_CMP_SRC_SOURCE)); + } +} + +/* Subsequent XAA screen-to-screen copy. */ +static void R128SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, + int xa, int ya, + int xb, int yb, + int w, int h) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + if (info->xdir < 0) xa += w - 1, xb += w - 1; + if (info->ydir < 0) ya += h - 1, yb += h - 1; + + R128WaitForFifo(pScrn, 3); + OUTREG(R128_SRC_Y_X, (ya << 16) | xa); + OUTREG(R128_DST_Y_X, (yb << 16) | xb); + OUTREG(R128_DST_HEIGHT_WIDTH, (h << 16) | w); +} + +/* Setup for XAA mono 8x8 pattern color expansion. Patterns with + transparency use `bg == -1'. This routine is only used if the XAA + pixmap cache is turned on. + + Tests: xtest XFree86/fllrctngl (no other test will test this routine with + both transparency and non-transparency) + + 1024x768@76Hz 8bpp + Without With + x11perf -srect100 38600.0/sec 85700.0/sec + x11perf -osrect100 38600.0/sec 85700.0/sec +*/ +static void R128SetupForMono8x8PatternFill(ScrnInfoPtr pScrn, + int patternx, int patterny, + int fg, int bg, int rop, + unsigned int planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 6); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | (bg == -1 + ? R128_GMC_BRUSH_8X8_MONO_FG_LA + : R128_GMC_BRUSH_8X8_MONO_FG_BG) + | R128_ROP[rop].pattern + | R128_GMC_BYTE_LSB_TO_MSB)); + OUTREG(R128_DP_WRITE_MASK, planemask); + OUTREG(R128_DP_BRUSH_FRGD_CLR, fg); + OUTREG(R128_DP_BRUSH_BKGD_CLR, bg); + OUTREG(R128_BRUSH_DATA0, patternx); + OUTREG(R128_BRUSH_DATA1, patterny); +} + +/* Subsequent XAA 8x8 pattern color expansion. Because they are used in + the setup function, `patternx' and `patterny' are not used here. */ +static void R128SubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, + int patternx, int patterny, + int x, int y, int w, int h) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 3); + OUTREG(R128_BRUSH_Y_X, (patterny << 8) | patternx); + OUTREG(R128_DST_Y_X, (y << 16) | x); + OUTREG(R128_DST_HEIGHT_WIDTH, (h << 16) | w); +} + +#if 0 +/* Setup for XAA color 8x8 pattern fill. + + Tests: xtest XFree86/fllrctngl (with Mono8x8PatternFill off) +*/ +static void R128SetupForColor8x8PatternFill(ScrnInfoPtr pScrn, + int patx, int paty, + int rop, unsigned int planemask, + int trans_color) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128TRACE(("Color8x8 %d %d %d\n", trans_color, patx, paty)); + + R128WaitForFifo(pScrn, 2); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_BRUSH_8x8_COLOR + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].rop + | R128_DP_SRC_SOURCE_MEMORY)); + OUTREG(R128_DP_WRITE_MASK, planemask); + + if (trans_color != -1) { + /* Set up for transparency */ + R128WaitForFifo(pScrn, 3); + OUTREG(R128_CLR_CMP_CLR_SRC, trans_color); + OUTREG(R128_CLR_CMP_MASK, R128_CLR_CMP_MSK); + OUTREG(R128_CLR_CMP_CNTL, (R128_SRC_CMP_NEQ_COLOR + | R128_CLR_CMP_SRC_SOURCE)); + } +} + +/* Subsequent XAA 8x8 pattern color expansion. */ +static void R128SubsequentColor8x8PatternFillRect( ScrnInfoPtr pScrn, + int patx, int paty, + int x, int y, int w, int h) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128TRACE(("Color8x8 %d,%d %d,%d %d %d\n", patx, paty, x, y, w, h)); + R128WaitForFifo(pScrn, 3); + OUTREG(R128_SRC_Y_X, (paty << 16) | patx); + OUTREG(R128_DST_Y_X, (y << 16) | x); + OUTREG(R128_DST_HEIGHT_WIDTH, (h << 16) | w); +} +#endif + +/* Setup for XAA indirect CPU-to-screen color expansion (indirect). + Because of how the scratch buffer is initialized, this is really a + mainstore-to-screen color expansion. Transparency is supported when `bg + == -1'. + + x11perf -ftext (pure indirect): + 1024x768@76Hz 1024x768@76Hz + 8bpp 32bpp + not used: 685000.0/sec 794000.0/sec + used: 1070000.0/sec 1080000.0/sec + + We could improve this indirect routine by about 10% if the hardware + could accept DWORD padded scanlines, or if XAA could provide bit-packed + data. We might also be able to move to a direct routine if there were + more HOST_DATA registers. + + Implementing the hybrid indirect/direct scheme improved performance in a + few areas: + + 1024x768@76 8bpp + Indirect Hybrid + x11perf -oddsrect10 50100.0/sec 71700.0/sec + x11perf -oddsrect100 4240.0/sec 6660.0/sec + x11perf -bigsrect10 50300.0/sec 71100.0/sec + x11perf -bigsrect100 4190.0/sec 6800.0/sec + x11perf -polytext 584000.0/sec 714000.0/sec + x11perf -polytext16 154000.0/sec 172000.0/sec + x11perf -seg1 1780000.0/sec 1880000.0/sec + x11perf -copyplane10 42900.0/sec 58300.0/sec + x11perf -copyplane100 4400.0/sec 6710.0/sec + x11perf -putimagexy10 5090.0/sec 6670.0/sec + x11perf -putimagexy100 424.0/sec 575.0/sec + + 1024x768@76 -depth 24 -fbbpp 32 + Indirect Hybrid + x11perf -oddsrect100 4240.0/sec 6670.0/sec + x11perf -bigsrect100 4190.0/sec 6800.0/sec + x11perf -polytext 585000.0/sec 719000.0/sec + x11perf -seg1 2960000.0/sec 2990000.0/sec + x11perf -copyplane100 4400.0/sec 6700.0/sec + x11perf -putimagexy100 138.0/sec 191.0/sec + +*/ +static void R128SetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int + planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 4); +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_DST_CLIPPING + | R128_GMC_BRUSH_NONE + | (bg == -1 + ? R128_GMC_SRC_DATATYPE_MONO_FG_LA + : R128_GMC_SRC_DATATYPE_MONO_FG_BG) + | R128_ROP[rop].rop + | R128_GMC_BYTE_LSB_TO_MSB + | R128_DP_SRC_SOURCE_HOST_DATA)); +#else /* X_BYTE_ORDER == X_BIG_ENDIAN */ + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_DST_CLIPPING + | R128_GMC_BRUSH_NONE + | (bg == -1 + ? R128_GMC_SRC_DATATYPE_MONO_FG_LA + : R128_GMC_SRC_DATATYPE_MONO_FG_BG) + | R128_ROP[rop].rop + | R128_DP_SRC_SOURCE_HOST_DATA)); +#endif + OUTREG(R128_DP_WRITE_MASK, planemask); + OUTREG(R128_DP_SRC_FRGD_CLR, fg); + OUTREG(R128_DP_SRC_BKGD_CLR, bg); +} + +/* Subsequent XAA indirect CPU-to-screen color expansion. This is only + called once for each rectangle. */ +static void R128SubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int x, int y, + int w, int h, + int skipleft) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int x1clip = x+skipleft; + int x2clip = x+w; + + info->scanline_h = h; + info->scanline_words = (w + 31) >> 5; + +#if 0 + /* Seems as though the Rage128's doesn't like blitting directly + * as we must be overwriting something too quickly, therefore we + * render to the buffer first and then blit */ + if ((info->scanline_words * h) <= 9) { + /* Turn on direct for less than 9 dword colour expansion */ + info->scratch_buffer[0] + = (unsigned char *)(ADDRREG(R128_HOST_DATA_LAST) + - (info->scanline_words - 1)); + info->scanline_direct = 1; + } else +#endif + { + /* Use indirect for anything else */ + info->scratch_buffer[0] = info->scratch_save; + info->scanline_direct = 0; + } + + if (pScrn->bitsPerPixel == 24) { + x1clip *= 3; + x2clip *= 3; + } + + R128WaitForFifo(pScrn, 4 + (info->scanline_direct ? + (info->scanline_words * h) : 0) ); + OUTREG(R128_SC_TOP_LEFT, (y << 16) | (x1clip & 0xffff)); + OUTREG(R128_SC_BOTTOM_RIGHT, ((y+h-1) << 16) | ((x2clip-1) & 0xffff)); + OUTREG(R128_DST_Y_X, (y << 16) | (x & 0xffff)); + /* Have to pad the width here and use clipping engine */ + OUTREG(R128_DST_HEIGHT_WIDTH, (h << 16) | ((w + 31) & ~31)); +} + +/* Subsequent XAA indirect CPU-to-screen color expansion. This is called + once for each scanline. */ +static void R128SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + CARD32 *p = (pointer)info->scratch_buffer[bufno]; + int i; + int left = info->scanline_words; + volatile CARD32 *d; + + if (info->scanline_direct) return; + --info->scanline_h; + while (left) { + write_mem_barrier(); + if (left <= 8) { + /* Last scanline - finish write to DATA_LAST */ + if (info->scanline_h == 0) { + R128WaitForFifo(pScrn, left); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(R128_HOST_DATA_LAST) - (left - 1); left; --left) + *d++ = *p++; + return; + } else { + R128WaitForFifo(pScrn, left); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(R128_HOST_DATA7) - (left - 1); left; --left) + *d++ = *p++; + } + } else { + R128WaitForFifo(pScrn, 8); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(R128_HOST_DATA0), i = 0; i < 8; i++) + *d++ = *p++; + left -= 8; + } + } +} + +/* Setup for XAA indirect image write. + + 1024x768@76Hz 8bpp + Without With + x11perf -putimage10 37500.0/sec 39300.0/sec + x11perf -putimage100 2150.0/sec 1170.0/sec + x11perf -putimage500 108.0/sec 49.8/sec + */ +static void R128SetupForScanlineImageWrite(ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int trans_color, + int bpp, + int depth) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + info->scanline_bpp = bpp; + + R128WaitForFifo(pScrn, 2); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_DST_CLIPPING + | R128_GMC_BRUSH_1X8_COLOR + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].rop + | R128_GMC_BYTE_LSB_TO_MSB + | R128_DP_SRC_SOURCE_HOST_DATA)); + OUTREG(R128_DP_WRITE_MASK, planemask); + + if (trans_color != -1) { + /* Set up for transparency */ + R128WaitForFifo(pScrn, 3); + OUTREG(R128_CLR_CMP_CLR_SRC, trans_color); + OUTREG(R128_CLR_CMP_MASK, R128_CLR_CMP_MSK); + OUTREG(R128_CLR_CMP_CNTL, (R128_SRC_CMP_NEQ_COLOR + | R128_CLR_CMP_SRC_SOURCE)); + } +} + +/* Subsequent XAA indirect image write. This is only called once for each + rectangle. */ +static void R128SubsequentScanlineImageWriteRect(ScrnInfoPtr pScrn, + int x, int y, + int w, int h, + int skipleft) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int x1clip = x+skipleft; + int x2clip = x+w; + + int shift = 0; /* 32bpp */ + + if (pScrn->bitsPerPixel == 8) shift = 3; + else if (pScrn->bitsPerPixel == 16) shift = 1; + + info->scanline_h = h; + info->scanline_words = (w * info->scanline_bpp + 31) >> 5; + +#if 0 + /* Seeing as the CPUToScreen doesn't like this, I've done this + * here too, as it uses pretty much the same path. */ + if ((info->scanline_words * h) <= 9) { + /* Turn on direct for less than 9 dword colour expansion */ + info->scratch_buffer[0] + = (unsigned char *)(ADDRREG(R128_HOST_DATA_LAST) + - (info->scanline_words - 1)); + info->scanline_direct = 1; + } else +#endif + { + /* Use indirect for anything else */ + info->scratch_buffer[0] = info->scratch_save; + info->scanline_direct = 0; + } + + if (pScrn->bitsPerPixel == 24) { + x1clip *= 3; + x2clip *= 3; + } + + R128WaitForFifo(pScrn, 4 + (info->scanline_direct ? + (info->scanline_words * h) : 0) ); + OUTREG(R128_SC_TOP_LEFT, (y << 16) | (x1clip & 0xffff)); + OUTREG(R128_SC_BOTTOM_RIGHT, ((y+h-1) << 16) | ((x2clip-1) & 0xffff)); + OUTREG(R128_DST_Y_X, (y << 16) | (x & 0xffff)); + /* Have to pad the width here and use clipping engine */ + OUTREG(R128_DST_HEIGHT_WIDTH, (h << 16) | ((w + shift) & ~shift)); +} + +/* Subsequent XAA indirect iamge write. This is called once for each + scanline. */ +static void R128SubsequentImageWriteScanline(ScrnInfoPtr pScrn, int bufno) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + CARD32 *p = (pointer)info->scratch_buffer[bufno]; + int i; + int left = info->scanline_words; + volatile CARD32 *d; + + if (info->scanline_direct) return; + --info->scanline_h; + while (left) { + write_mem_barrier(); + if (left <= 8) { + /* Last scanline - finish write to DATA_LAST */ + if (info->scanline_h == 0) { + R128WaitForFifo(pScrn, left); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(R128_HOST_DATA_LAST) - (left - 1); left; --left) + *d++ = *p++; + return; + } else { + R128WaitForFifo(pScrn, left); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(R128_HOST_DATA7) - (left - 1); left; --left) + *d++ = *p++; + } + } else { + R128WaitForFifo(pScrn, 8); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(R128_HOST_DATA0), i = 0; i < 8; i++) + *d++ = *p++; + left -= 8; + } + } +} + +/* Initialize the acceleration hardware. */ +void R128EngineInit(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128TRACE(("EngineInit (%d/%d)\n", info->CurrentLayout.pixel_code, info->CurrentLayout.bitsPerPixel)); + + OUTREG(R128_SCALE_3D_CNTL, 0); + R128EngineReset(pScrn); + + switch (info->CurrentLayout.pixel_code) { + case 8: info->datatype = 2; break; + case 15: info->datatype = 3; break; + case 16: info->datatype = 4; break; + case 24: info->datatype = 5; break; + case 32: info->datatype = 6; break; + default: + R128TRACE(("Unknown depth/bpp = %d/%d (code = %d)\n", + info->CurrentLayout.depth, info->CurrentLayout.bitsPerPixel, + info->CurrentLayout.pixel_code)); + } + info->pitch = (info->CurrentLayout.displayWidth / 8) * (info->CurrentLayout.pixel_bytes == 3 ? 3 : 1); + + R128TRACE(("Pitch for acceleration = %d\n", info->pitch)); + + R128WaitForFifo(pScrn, 2); + OUTREG(R128_DEFAULT_OFFSET, 0); + OUTREG(R128_DEFAULT_PITCH, info->pitch); + + R128WaitForFifo(pScrn, 4); + OUTREG(R128_AUX_SC_CNTL, 0); + OUTREG(R128_DEFAULT_SC_BOTTOM_RIGHT, (R128_DEFAULT_SC_RIGHT_MAX + | R128_DEFAULT_SC_BOTTOM_MAX)); + OUTREG(R128_SC_TOP_LEFT, 0); + OUTREG(R128_SC_BOTTOM_RIGHT, (R128_DEFAULT_SC_RIGHT_MAX + | R128_DEFAULT_SC_BOTTOM_MAX)); + + info->dp_gui_master_cntl = ((info->datatype << R128_GMC_DST_DATATYPE_SHIFT) + | R128_GMC_CLR_CMP_CNTL_DIS + | R128_GMC_AUX_CLIP_DIS); + R128WaitForFifo(pScrn, 1); + OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_BRUSH_SOLID_COLOR + | R128_GMC_SRC_DATATYPE_COLOR)); + + R128WaitForFifo(pScrn, 8); + OUTREG(R128_DST_BRES_ERR, 0); + OUTREG(R128_DST_BRES_INC, 0); + OUTREG(R128_DST_BRES_DEC, 0); + OUTREG(R128_DP_BRUSH_FRGD_CLR, 0xffffffff); + OUTREG(R128_DP_BRUSH_BKGD_CLR, 0x00000000); + OUTREG(R128_DP_SRC_FRGD_CLR, 0xffffffff); + OUTREG(R128_DP_SRC_BKGD_CLR, 0x00000000); + OUTREG(R128_DP_WRITE_MASK, 0xffffffff); + + R128WaitForFifo(pScrn, 1); + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* FIXME: this is a kludge for texture uploads in the 3D driver. Look at + * how the radeon driver handles HOST_DATA_SWAP if you want to implement + * CCE ImageWrite acceleration or anything needing this bit */ +#ifdef XF86DRI + if (info->directRenderingEnabled) + OUTREGP(R128_DP_DATATYPE, 0, ~R128_HOST_BIG_ENDIAN_EN); + else +#endif + OUTREGP(R128_DP_DATATYPE, + R128_HOST_BIG_ENDIAN_EN, ~R128_HOST_BIG_ENDIAN_EN); +#else /* X_LITTLE_ENDIAN */ + OUTREGP(R128_DP_DATATYPE, 0, ~R128_HOST_BIG_ENDIAN_EN); +#endif + +#ifdef XF86DRI + info->sc_left = 0x00000000; + info->sc_right = R128_DEFAULT_SC_RIGHT_MAX; + info->sc_top = 0x00000000; + info->sc_bottom = R128_DEFAULT_SC_BOTTOM_MAX; + + info->re_top_left = 0x00000000; + info->re_width_height = ((0x7ff << R128_RE_WIDTH_SHIFT) | + (0x7ff << R128_RE_HEIGHT_SHIFT)); + + info->aux_sc_cntl = 0x00000000; +#endif + + R128WaitForIdle(pScrn); +} + +#ifdef XF86DRI + +/* Setup for XAA SolidFill. */ +static void R128CCESetupForSolidFill(ScrnInfoPtr pScrn, + int color, int rop, + unsigned int planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 8 ); + + OUT_RING_REG( R128_DP_GUI_MASTER_CNTL, + (info->dp_gui_master_cntl + | R128_GMC_BRUSH_SOLID_COLOR + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].pattern) ); + + OUT_RING_REG( R128_DP_BRUSH_FRGD_CLR, color ); + OUT_RING_REG( R128_DP_WRITE_MASK, planemask ); + OUT_RING_REG( R128_DP_CNTL, (R128_DST_X_LEFT_TO_RIGHT | + R128_DST_Y_TOP_TO_BOTTOM)); + ADVANCE_RING(); +} + +/* Subsequent XAA SolidFillRect. + + Tests: xtest CH06/fllrctngl, xterm +*/ +static void R128CCESubsequentSolidFillRect(ScrnInfoPtr pScrn, + int x, int y, int w, int h) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 4 ); + + OUT_RING_REG( R128_DST_Y_X, (y << 16) | x ); + OUT_RING_REG( R128_DST_WIDTH_HEIGHT, (w << 16) | h ); + + ADVANCE_RING(); +} + +/* Setup for XAA screen-to-screen copy. + + Tests: xtest CH06/fllrctngl (also tests transparency). +*/ +static void R128CCESetupForScreenToScreenCopy(ScrnInfoPtr pScrn, + int xdir, int ydir, int rop, + unsigned int planemask, + int trans_color) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + info->xdir = xdir; + info->ydir = ydir; + + BEGIN_RING( 6 ); + + OUT_RING_REG( R128_DP_GUI_MASTER_CNTL, + (info->dp_gui_master_cntl + | R128_GMC_BRUSH_NONE + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].rop + | R128_DP_SRC_SOURCE_MEMORY) ); + + OUT_RING_REG( R128_DP_WRITE_MASK, planemask ); + OUT_RING_REG( R128_DP_CNTL, + ((xdir >= 0 ? R128_DST_X_LEFT_TO_RIGHT : 0) | + (ydir >= 0 ? R128_DST_Y_TOP_TO_BOTTOM : 0)) ); + + ADVANCE_RING(); + + if ((trans_color != -1) || (info->XAAForceTransBlit == TRUE)) { + BEGIN_RING( 6 ); + + OUT_RING_REG( R128_CLR_CMP_CLR_SRC, trans_color ); + OUT_RING_REG( R128_CLR_CMP_MASK, R128_CLR_CMP_MSK ); + OUT_RING_REG( R128_CLR_CMP_CNTL, (R128_SRC_CMP_NEQ_COLOR | + R128_CLR_CMP_SRC_SOURCE) ); + + ADVANCE_RING(); + } +} + +/* Subsequent XAA screen-to-screen copy. */ +static void R128CCESubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, + int xa, int ya, + int xb, int yb, + int w, int h) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + if (info->xdir < 0) xa += w - 1, xb += w - 1; + if (info->ydir < 0) ya += h - 1, yb += h - 1; + + BEGIN_RING( 6 ); + + OUT_RING_REG( R128_SRC_Y_X, (ya << 16) | xa ); + OUT_RING_REG( R128_DST_Y_X, (yb << 16) | xb ); + OUT_RING_REG( R128_DST_HEIGHT_WIDTH, (h << 16) | w ); + + ADVANCE_RING(); +} + + +/* + * XAA scanline color expansion + * + * We use HOSTDATA_BLT CCE packets, dividing the image in chunks that fit into + * the indirect buffer if necessary. + */ +static void R128CCESetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, + unsigned int + planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 2 ); + OUT_RING_REG(R128_DP_WRITE_MASK, planemask); + ADVANCE_RING(); + + info->scanline_rop = rop; + info->scanline_fg = fg; + info->scanline_bg = bg; +} + +/* Helper function to write out a HOSTDATA_BLT packet into the indirect buffer + and set the XAA scratch buffer address appropriately */ +static void R128CCEScanlineCPUToScreenColorExpandFillPacket(ScrnInfoPtr pScrn, + int bufno) +{ + R128InfoPtr info = R128PTR(pScrn); + int chunk_words = info->scanline_hpass * info->scanline_words; + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( chunk_words+9 ); + + OUT_RING( CCE_PACKET3( R128_CCE_PACKET3_CNTL_HOSTDATA_BLT, chunk_words+9-2 ) ); +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + OUT_RING( (info->dp_gui_master_cntl + | R128_GMC_DST_CLIPPING + | R128_GMC_BRUSH_NONE + | (info->scanline_bg == -1 + ? R128_GMC_SRC_DATATYPE_MONO_FG_LA + : R128_GMC_SRC_DATATYPE_MONO_FG_BG) + | R128_ROP[info->scanline_rop].rop + | R128_GMC_BYTE_LSB_TO_MSB + | R128_DP_SRC_SOURCE_HOST_DATA)); +#else /* X_BYTE_ORDER == X_BIG_ENDIAN */ + OUT_RING( (info->dp_gui_master_cntl + | R128_GMC_DST_CLIPPING + | R128_GMC_BRUSH_NONE + | (info->scanline_bg == -1 + ? R128_GMC_SRC_DATATYPE_MONO_FG_LA + : R128_GMC_SRC_DATATYPE_MONO_FG_BG) + | R128_ROP[info->scanline_rop].rop + | R128_DP_SRC_SOURCE_HOST_DATA)); +#endif + OUT_RING( (info->scanline_y << 16) | (info->scanline_x1clip & 0xffff) ); + OUT_RING( ((info->scanline_y+info->scanline_hpass-1) << 16) | ((info->scanline_x2clip-1) & 0xffff) ); + OUT_RING( info->scanline_fg ); + OUT_RING( info->scanline_bg ); + OUT_RING( (info->scanline_y << 16) | (info->scanline_x & 0xffff)); + + /* Have to pad the width here and use clipping engine */ + OUT_RING( (info->scanline_hpass << 16) | ((info->scanline_w + 31) & ~31)); + + OUT_RING( chunk_words ); + + info->scratch_buffer[bufno] = (unsigned char *) &__head[__count]; + __count += chunk_words; + + ADVANCE_RING(); + + info->scanline_y += info->scanline_hpass; + info->scanline_h -= info->scanline_hpass; + + if ( R128_VERBOSE ) + xf86DrvMsg( pScrn->scrnIndex, X_INFO, + "%s: hpass=%d, words=%d => chunk_words=%d, y=%d, h=%d\n", + __FUNCTION__, info->scanline_hpass, info->scanline_words, + chunk_words, info->scanline_y, info->scanline_h ); +} + +/* Subsequent XAA indirect CPU-to-screen color expansion. This is only + called once for each rectangle. */ +static void R128CCESubsequentScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, + int x, int y, + int w, int h, + int skipleft) +{ + R128InfoPtr info = R128PTR(pScrn); + +#define BUFSIZE ( R128_BUFFER_SIZE/4-9 ) + + info->scanline_x = x; + info->scanline_y = y; + info->scanline_w = w; + info->scanline_h = h; + + info->scanline_x1clip = x+skipleft; + info->scanline_x2clip = x+w; + + info->scanline_words = (w + 31) >> 5; + info->scanline_hpass = min(h,(BUFSIZE/info->scanline_words)); + + if ( R128_VERBOSE ) + xf86DrvMsg( pScrn->scrnIndex, X_INFO, + "%s: x=%d, y=%d, w=%d, h=%d, skipleft=%d => x1clip=%d, x2clip=%d, hpass=%d, words=%d\n", + __FUNCTION__, x, y, w, h, skipleft, info->scanline_x1clip, info->scanline_x2clip, + info->scanline_hpass, info->scanline_words ); + + R128CCEScanlineCPUToScreenColorExpandFillPacket(pScrn, 0); +} + +/* Subsequent XAA indirect CPU-to-screen color expansion. This is called + once for each scanline. */ +static void R128CCESubsequentColorExpandScanline(ScrnInfoPtr pScrn, + int bufno) +{ + R128InfoPtr info = R128PTR(pScrn); + + if ( R128_VERBOSE ) + xf86DrvMsg( pScrn->scrnIndex, X_INFO, + "%s enter: scanline_hpass=%d, scanline_h=%d\n", + __FUNCTION__, info->scanline_hpass, info->scanline_h ); + + if (--info->scanline_hpass) { + info->scratch_buffer[bufno] += 4 * info->scanline_words; + } + else if(info->scanline_h) { + info->scanline_hpass = min(info->scanline_h,(BUFSIZE/info->scanline_words)); + R128CCEScanlineCPUToScreenColorExpandFillPacket(pScrn, bufno); + } + + if ( R128_VERBOSE ) + xf86DrvMsg( pScrn->scrnIndex, X_INFO, + "%s exit: scanline_hpass=%d, scanline_h=%d\n", + __FUNCTION__, info->scanline_hpass, info->scanline_h ); +} + +/* Solid lines */ +static void R128CCESetupForSolidLine(ScrnInfoPtr pScrn, + int color, int rop, unsigned int planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 6 ); + + OUT_RING_REG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | R128_GMC_BRUSH_SOLID_COLOR + | R128_GMC_SRC_DATATYPE_COLOR + | R128_ROP[rop].pattern)); + OUT_RING_REG(R128_DP_BRUSH_FRGD_CLR, color); + OUT_RING_REG(R128_DP_WRITE_MASK, planemask); + + ADVANCE_RING(); +} + +static void R128CCESubsequentSolidBresenhamLine(ScrnInfoPtr pScrn, + int x, int y, + int major, int minor, + int err, int len, int octant) +{ + R128InfoPtr info = R128PTR(pScrn); + int flags = 0; + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + if (octant & YMAJOR) flags |= R128_DST_Y_MAJOR; + if (!(octant & XDECREASING)) flags |= R128_DST_X_DIR_LEFT_TO_RIGHT; + if (!(octant & YDECREASING)) flags |= R128_DST_Y_DIR_TOP_TO_BOTTOM; + + BEGIN_RING( 12 ); + + OUT_RING_REG(R128_DP_CNTL_XDIR_YDIR_YMAJOR, flags); + OUT_RING_REG(R128_DST_Y_X, (y << 16) | x); + OUT_RING_REG(R128_DST_BRES_ERR, err); + OUT_RING_REG(R128_DST_BRES_INC, minor); + OUT_RING_REG(R128_DST_BRES_DEC, -major); + OUT_RING_REG(R128_DST_BRES_LNTH, len); + + ADVANCE_RING(); +} + +static void R128CCESubsequentSolidHorVertLine(ScrnInfoPtr pScrn, + int x, int y, int len, int dir ) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 2 ); + + OUT_RING_REG(R128_DP_CNTL, (R128_DST_X_LEFT_TO_RIGHT + | R128_DST_Y_TOP_TO_BOTTOM)); + + ADVANCE_RING(); + + if (dir == DEGREES_0) { + R128CCESubsequentSolidFillRect(pScrn, x, y, len, 1); + } else { + R128CCESubsequentSolidFillRect(pScrn, x, y, 1, len); + } +} + +/* Dashed lines */ +static void R128CCESetupForDashedLine(ScrnInfoPtr pScrn, + int fg, int bg, + int rop, unsigned int planemask, + int length, unsigned char *pattern) +{ + R128InfoPtr info = R128PTR(pScrn); + CARD32 pat = *(CARD32 *)(pointer)pattern; + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN +# define PAT_SHIFT(pat,n) pat << n +#else +# define PAT_SHIFT(pat,n) pat >> n +#endif + + switch (length) { + case 2: pat |= PAT_SHIFT(pat,2); /* fall through */ + case 4: pat |= PAT_SHIFT(pat,4); /* fall through */ + case 8: pat |= PAT_SHIFT(pat,8); /* fall through */ + case 16: pat |= PAT_SHIFT(pat,16); + } + + BEGIN_RING( 10 ); + + OUT_RING_REG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | (bg == -1 + ? R128_GMC_BRUSH_32x1_MONO_FG_LA + : R128_GMC_BRUSH_32x1_MONO_FG_BG) + | R128_ROP[rop].pattern + | R128_GMC_BYTE_LSB_TO_MSB)); + OUT_RING_REG(R128_DP_WRITE_MASK, planemask); + OUT_RING_REG(R128_DP_BRUSH_FRGD_CLR, fg); + OUT_RING_REG(R128_DP_BRUSH_BKGD_CLR, bg); + OUT_RING_REG(R128_BRUSH_DATA0, pat); + + ADVANCE_RING(); +} + +static void R128CCESubsequentDashedBresenhamLine(ScrnInfoPtr pScrn, + int x, int y, + int major, int minor, + int err, int len, int octant, + int phase) +{ + R128InfoPtr info = R128PTR(pScrn); + int flags = 0; + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + if (octant & YMAJOR) flags |= R128_DST_Y_MAJOR; + if (!(octant & XDECREASING)) flags |= R128_DST_X_DIR_LEFT_TO_RIGHT; + if (!(octant & YDECREASING)) flags |= R128_DST_Y_DIR_TOP_TO_BOTTOM; + + BEGIN_RING( 14 ); + + OUT_RING_REG(R128_DP_CNTL_XDIR_YDIR_YMAJOR, flags); + OUT_RING_REG(R128_DST_Y_X, (y << 16) | x); + OUT_RING_REG(R128_BRUSH_Y_X, (phase << 16) | phase); + OUT_RING_REG(R128_DST_BRES_ERR, err); + OUT_RING_REG(R128_DST_BRES_INC, minor); + OUT_RING_REG(R128_DST_BRES_DEC, -major); + OUT_RING_REG(R128_DST_BRES_LNTH, len); + + ADVANCE_RING(); +} + +/* Mono 8x8 pattern color expansion */ +static void R128CCESetupForMono8x8PatternFill(ScrnInfoPtr pScrn, + int patternx, int patterny, + int fg, int bg, int rop, + unsigned int planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 12 ); + + OUT_RING_REG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | (bg == -1 + ? R128_GMC_BRUSH_8X8_MONO_FG_LA + : R128_GMC_BRUSH_8X8_MONO_FG_BG) + | R128_ROP[rop].pattern + | R128_GMC_BYTE_LSB_TO_MSB)); + OUT_RING_REG(R128_DP_WRITE_MASK, planemask); + OUT_RING_REG(R128_DP_BRUSH_FRGD_CLR, fg); + OUT_RING_REG(R128_DP_BRUSH_BKGD_CLR, bg); + OUT_RING_REG(R128_BRUSH_DATA0, patternx); + OUT_RING_REG(R128_BRUSH_DATA1, patterny); + + ADVANCE_RING(); +} + +static void R128CCESubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, + int patternx, int patterny, + int x, int y, int w, int h) +{ + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 6 ); + + OUT_RING_REG(R128_BRUSH_Y_X, (patterny << 8) | patternx); + OUT_RING_REG(R128_DST_Y_X, (y << 16) | x); + OUT_RING_REG(R128_DST_HEIGHT_WIDTH, (h << 16) | w); + + ADVANCE_RING(); +} + +/* Get an indirect buffer for the CCE 2D acceleration commands. + */ +drmBufPtr R128CCEGetBuffer( ScrnInfoPtr pScrn ) +{ + R128InfoPtr info = R128PTR(pScrn); + drmDMAReq dma; + drmBufPtr buf = NULL; + int indx = 0; + int size = 0; + int ret, i = 0; + +#if 0 + /* FIXME: pScrn->pScreen has not been initialized when this is first + called from RADEONSelectBuffer via RADEONDRICPInit. We could use + the screen index from pScrn, which is initialized, and then get + the screen from screenInfo.screens[index], but that is a hack. */ + dma.context = DRIGetContext(pScrn->pScreen); +#else + dma.context = 0x00000001; /* This is the X server's context */ +#endif + dma.send_count = 0; + dma.send_list = NULL; + dma.send_sizes = NULL; + dma.flags = 0; + dma.request_count = 1; + dma.request_size = R128_BUFFER_SIZE; + dma.request_list = &indx; + dma.request_sizes = &size; + dma.granted_count = 0; + + while ( 1 ) { + do { + ret = drmDMA( info->drmFD, &dma ); + if ( ret && ret != -EAGAIN ) { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, + "%s: CCE GetBuffer %d\n", __FUNCTION__, ret ); + } + } while ( ( ret == -EAGAIN ) && ( i++ < R128_TIMEOUT ) ); + + if ( ret == 0 ) { + buf = &info->buffers->list[indx]; + buf->used = 0; + if ( R128_VERBOSE ) { + xf86DrvMsg( pScrn->scrnIndex, X_INFO, + " GetBuffer returning %d\n", buf->idx ); + } + return buf; + } + + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, + "GetBuffer timed out, resetting engine...\n"); + R128EngineReset( pScrn ); + /* R128EngineRestore( pScrn ); FIXME ??? */ + + /* Always restart the engine when doing CCE 2D acceleration */ + R128CCE_RESET( pScrn, info ); + R128CCE_START( pScrn, info ); + } +} + +/* Flush the indirect buffer to the kernel for submission to the card. + */ +void R128CCEFlushIndirect( ScrnInfoPtr pScrn, int discard ) +{ + R128InfoPtr info = R128PTR(pScrn); + drmBufPtr buffer = info->indirectBuffer; + int start = info->indirectStart; + drmR128Indirect indirect; + + if ( !buffer ) + return; + + if ( (start == buffer->used) && !discard ) + return; + + indirect.idx = buffer->idx; + indirect.start = start; + indirect.end = buffer->used; + indirect.discard = discard; + + drmCommandWriteRead( info->drmFD, DRM_R128_INDIRECT, + &indirect, sizeof(drmR128Indirect)); + + if ( discard ) + buffer = info->indirectBuffer = R128CCEGetBuffer( pScrn ); + + /* pad to an even number of dwords */ + if (buffer->used & 7) + buffer->used = ( buffer->used+7 ) & ~7; + + info->indirectStart = buffer->used; +} + +/* Flush and release the indirect buffer. + */ +void R128CCEReleaseIndirect( ScrnInfoPtr pScrn ) +{ + R128InfoPtr info = R128PTR(pScrn); + drmBufPtr buffer = info->indirectBuffer; + int start = info->indirectStart; + drmR128Indirect indirect; + + info->indirectBuffer = NULL; + info->indirectStart = 0; + + if ( !buffer ) + return; + + indirect.idx = buffer->idx; + indirect.start = start; + indirect.end = buffer->used; + indirect.discard = 1; + + drmCommandWriteRead( info->drmFD, DRM_R128_INDIRECT, + &indirect, sizeof(drmR128Indirect)); +} + +static void R128CCEAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a) +{ + R128InfoPtr info = R128PTR(pScrn); + + a->Flags = (PIXMAP_CACHE + | OFFSCREEN_PIXMAPS + | LINEAR_FRAMEBUFFER); + + /* Sync */ + a->Sync = R128CCEWaitForIdle; + + /* Solid Filled Rectangle */ + a->PolyFillRectSolidFlags = 0; + a->SetupForSolidFill = R128CCESetupForSolidFill; + a->SubsequentSolidFillRect = R128CCESubsequentSolidFillRect; + + /* Screen-to-screen Copy */ + /* Transparency uses the wrong colors for + 24 bpp mode -- the transparent part is + correct, but the opaque color is wrong. + This can be seen with netscape's I-bar + cursor when editing in the URL location + box. */ + a->ScreenToScreenCopyFlags = ((pScrn->bitsPerPixel == 24) + ? NO_TRANSPARENCY + : 0); + a->SetupForScreenToScreenCopy = R128CCESetupForScreenToScreenCopy; + a->SubsequentScreenToScreenCopy = R128CCESubsequentScreenToScreenCopy; + + /* Indirect CPU-To-Screen Color Expand */ + a->ScanlineCPUToScreenColorExpandFillFlags = LEFT_EDGE_CLIPPING + | LEFT_EDGE_CLIPPING_NEGATIVE_X; + a->NumScanlineColorExpandBuffers = 1; + a->ScanlineColorExpandBuffers = info->scratch_buffer; + info->scratch_buffer[0] = NULL; + a->SetupForScanlineCPUToScreenColorExpandFill + = R128CCESetupForScanlineCPUToScreenColorExpandFill; + a->SubsequentScanlineCPUToScreenColorExpandFill + = R128CCESubsequentScanlineCPUToScreenColorExpandFill; + a->SubsequentColorExpandScanline = R128CCESubsequentColorExpandScanline; + + /* Bresenham Solid Lines */ + a->SetupForSolidLine = R128CCESetupForSolidLine; + a->SubsequentSolidBresenhamLine = R128CCESubsequentSolidBresenhamLine; + a->SubsequentSolidHorVertLine = R128CCESubsequentSolidHorVertLine; + + /* Bresenham Dashed Lines*/ + a->SetupForDashedLine = R128CCESetupForDashedLine; + a->SubsequentDashedBresenhamLine = R128CCESubsequentDashedBresenhamLine; + a->DashPatternMaxLength = 32; + a->DashedLineFlags = (LINE_PATTERN_LSBFIRST_LSBJUSTIFIED + | LINE_PATTERN_POWER_OF_2_ONLY); + + /* Mono 8x8 Pattern Fill (Color Expand) */ + a->SetupForMono8x8PatternFill = R128CCESetupForMono8x8PatternFill; + a->SubsequentMono8x8PatternFillRect = R128CCESubsequentMono8x8PatternFillRect; + a->Mono8x8PatternFillFlags = (HARDWARE_PATTERN_PROGRAMMED_BITS + | HARDWARE_PATTERN_PROGRAMMED_ORIGIN + | HARDWARE_PATTERN_SCREEN_ORIGIN + | BIT_ORDER_IN_BYTE_LSBFIRST); +} +#endif + +static void R128MMIOAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a) +{ + R128InfoPtr info = R128PTR(pScrn); + + a->Flags = (PIXMAP_CACHE + | OFFSCREEN_PIXMAPS + | LINEAR_FRAMEBUFFER); + + /* Sync */ + a->Sync = R128WaitForIdle; + + /* Solid Filled Rectangle */ + a->PolyFillRectSolidFlags = 0; + a->SetupForSolidFill = R128SetupForSolidFill; + a->SubsequentSolidFillRect = R128SubsequentSolidFillRect; + + /* Screen-to-screen Copy */ + /* Transparency uses the wrong colors for + 24 bpp mode -- the transparent part is + correct, but the opaque color is wrong. + This can be seen with netscape's I-bar + cursor when editing in the URL location + box. */ + a->ScreenToScreenCopyFlags = ((pScrn->bitsPerPixel == 24) + ? NO_TRANSPARENCY + : 0); + a->SetupForScreenToScreenCopy = R128SetupForScreenToScreenCopy; + a->SubsequentScreenToScreenCopy = R128SubsequentScreenToScreenCopy; + + /* Mono 8x8 Pattern Fill (Color Expand) */ + a->SetupForMono8x8PatternFill = R128SetupForMono8x8PatternFill; + a->SubsequentMono8x8PatternFillRect = R128SubsequentMono8x8PatternFillRect; + a->Mono8x8PatternFillFlags = (HARDWARE_PATTERN_PROGRAMMED_BITS + | HARDWARE_PATTERN_PROGRAMMED_ORIGIN + | HARDWARE_PATTERN_SCREEN_ORIGIN + | BIT_ORDER_IN_BYTE_LSBFIRST); + + /* Indirect CPU-To-Screen Color Expand */ + a->ScanlineCPUToScreenColorExpandFillFlags = LEFT_EDGE_CLIPPING + | LEFT_EDGE_CLIPPING_NEGATIVE_X; + a->NumScanlineColorExpandBuffers = 1; + a->ScanlineColorExpandBuffers = info->scratch_buffer; + info->scratch_save = xalloc(((pScrn->virtualX+31)/32*4) + + (pScrn->virtualX + * info->CurrentLayout.pixel_bytes)); + info->scratch_buffer[0] = info->scratch_save; + a->SetupForScanlineCPUToScreenColorExpandFill + = R128SetupForScanlineCPUToScreenColorExpandFill; + a->SubsequentScanlineCPUToScreenColorExpandFill + = R128SubsequentScanlineCPUToScreenColorExpandFill; + a->SubsequentColorExpandScanline = R128SubsequentColorExpandScanline; + + /* Bresenham Solid Lines */ + a->SetupForSolidLine = R128SetupForSolidLine; + a->SubsequentSolidBresenhamLine = R128SubsequentSolidBresenhamLine; + a->SubsequentSolidHorVertLine = R128SubsequentSolidHorVertLine; + + /* Bresenham Dashed Lines*/ + a->SetupForDashedLine = R128SetupForDashedLine; + a->SubsequentDashedBresenhamLine = R128SubsequentDashedBresenhamLine; + a->DashPatternMaxLength = 32; + a->DashedLineFlags = (LINE_PATTERN_LSBFIRST_LSBJUSTIFIED + | LINE_PATTERN_POWER_OF_2_ONLY); + + /* ImageWrite */ + a->NumScanlineImageWriteBuffers = 1; + a->ScanlineImageWriteBuffers = info->scratch_buffer; + info->scratch_buffer[0] = info->scratch_save; + a->SetupForScanlineImageWrite = R128SetupForScanlineImageWrite; + a->SubsequentScanlineImageWriteRect= R128SubsequentScanlineImageWriteRect; + a->SubsequentImageWriteScanline = R128SubsequentImageWriteScanline; + a->ScanlineImageWriteFlags = CPU_TRANSFER_PAD_DWORD + /* Performance tests show that we shouldn't use GXcopy for + * uploads as a memcpy is faster */ + | NO_GXCOPY + | LEFT_EDGE_CLIPPING + | LEFT_EDGE_CLIPPING_NEGATIVE_X + | SCANLINE_PAD_DWORD; +} + +/* Initialize XAA for supported acceleration and also initialize the + graphics hardware for acceleration. */ +Bool R128AccelInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + XAAInfoRecPtr a; + + if (!(a = info->accel = XAACreateInfoRec())) return FALSE; + +#ifdef XF86DRI + if (info->directRenderingEnabled) + R128CCEAccelInit(pScrn, a); + else +#endif + R128MMIOAccelInit(pScrn, a); + + R128EngineInit(pScrn); + return XAAInit(pScreen, a); +} diff --git a/src/r128_chipset.h b/src/r128_chipset.h new file mode 100644 index 0000000..e896f76 --- /dev/null +++ b/src/r128_chipset.h @@ -0,0 +1,54 @@ +static SymTabRec R128Chipsets[] = { + /* FIXME: The chipsets with (PCI/AGP) are not known wether they are AGP or + * PCI, so I've labeled them as such in hopes users will submit + * data if we're unable to gather it from official documentation + */ + { PCI_CHIP_RAGE128LE, "ATI Rage 128 Mobility M3 LE (PCI)" }, + { PCI_CHIP_RAGE128LF, "ATI Rage 128 Mobility M3 LF (AGP)" }, + { PCI_CHIP_RAGE128MF, "ATI Rage 128 Mobility M4 MF (AGP)" }, + { PCI_CHIP_RAGE128ML, "ATI Rage 128 Mobility M4 ML (AGP)" }, + { PCI_CHIP_RAGE128PA, "ATI Rage 128 Pro GL PA (PCI/AGP)" }, + { PCI_CHIP_RAGE128PB, "ATI Rage 128 Pro GL PB (PCI/AGP)" }, + { PCI_CHIP_RAGE128PC, "ATI Rage 128 Pro GL PC (PCI/AGP)" }, + { PCI_CHIP_RAGE128PD, "ATI Rage 128 Pro GL PD (PCI)" }, + { PCI_CHIP_RAGE128PE, "ATI Rage 128 Pro GL PE (PCI/AGP)" }, + { PCI_CHIP_RAGE128PF, "ATI Rage 128 Pro GL PF (AGP)" }, + { PCI_CHIP_RAGE128PG, "ATI Rage 128 Pro VR PG (PCI/AGP)" }, + { PCI_CHIP_RAGE128PH, "ATI Rage 128 Pro VR PH (PCI/AGP)" }, + { PCI_CHIP_RAGE128PI, "ATI Rage 128 Pro VR PI (PCI/AGP)" }, + { PCI_CHIP_RAGE128PJ, "ATI Rage 128 Pro VR PJ (PCI/AGP)" }, + { PCI_CHIP_RAGE128PK, "ATI Rage 128 Pro VR PK (PCI/AGP)" }, + { PCI_CHIP_RAGE128PL, "ATI Rage 128 Pro VR PL (PCI/AGP)" }, + { PCI_CHIP_RAGE128PM, "ATI Rage 128 Pro VR PM (PCI/AGP)" }, + { PCI_CHIP_RAGE128PN, "ATI Rage 128 Pro VR PN (PCI/AGP)" }, + { PCI_CHIP_RAGE128PO, "ATI Rage 128 Pro VR PO (PCI/AGP)" }, + { PCI_CHIP_RAGE128PP, "ATI Rage 128 Pro VR PP (PCI)" }, + { PCI_CHIP_RAGE128PQ, "ATI Rage 128 Pro VR PQ (PCI/AGP)" }, + { PCI_CHIP_RAGE128PR, "ATI Rage 128 Pro VR PR (PCI)" }, + { PCI_CHIP_RAGE128PS, "ATI Rage 128 Pro VR PS (PCI/AGP)" }, + { PCI_CHIP_RAGE128PT, "ATI Rage 128 Pro VR PT (PCI/AGP)" }, + { PCI_CHIP_RAGE128PU, "ATI Rage 128 Pro VR PU (PCI/AGP)" }, + { PCI_CHIP_RAGE128PV, "ATI Rage 128 Pro VR PV (PCI/AGP)" }, + { PCI_CHIP_RAGE128PW, "ATI Rage 128 Pro VR PW (PCI/AGP)" }, + { PCI_CHIP_RAGE128PX, "ATI Rage 128 Pro VR PX (PCI/AGP)" }, + { PCI_CHIP_RAGE128RE, "ATI Rage 128 GL RE (PCI)" }, + { PCI_CHIP_RAGE128RF, "ATI Rage 128 GL RF (AGP)" }, + { PCI_CHIP_RAGE128RG, "ATI Rage 128 RG (AGP)" }, + { PCI_CHIP_RAGE128RK, "ATI Rage 128 VR RK (PCI)" }, + { PCI_CHIP_RAGE128RL, "ATI Rage 128 VR RL (AGP)" }, + { PCI_CHIP_RAGE128SE, "ATI Rage 128 4X SE (PCI/AGP)" }, + { PCI_CHIP_RAGE128SF, "ATI Rage 128 4X SF (PCI/AGP)" }, + { PCI_CHIP_RAGE128SG, "ATI Rage 128 4X SG (PCI/AGP)" }, + { PCI_CHIP_RAGE128SH, "ATI Rage 128 4X SH (PCI/AGP)" }, + { PCI_CHIP_RAGE128SK, "ATI Rage 128 4X SK (PCI/AGP)" }, + { PCI_CHIP_RAGE128SL, "ATI Rage 128 4X SL (PCI/AGP)" }, + { PCI_CHIP_RAGE128SM, "ATI Rage 128 4X SM (AGP)" }, + { PCI_CHIP_RAGE128SN, "ATI Rage 128 4X SN (PCI/AGP)" }, + { PCI_CHIP_RAGE128TF, "ATI Rage 128 Pro ULTRA TF (AGP)" }, + { PCI_CHIP_RAGE128TL, "ATI Rage 128 Pro ULTRA TL (AGP)" }, + { PCI_CHIP_RAGE128TR, "ATI Rage 128 Pro ULTRA TR (AGP)" }, + { PCI_CHIP_RAGE128TS, "ATI Rage 128 Pro ULTRA TS (AGP?)" }, + { PCI_CHIP_RAGE128TT, "ATI Rage 128 Pro ULTRA TT (AGP?)" }, + { PCI_CHIP_RAGE128TU, "ATI Rage 128 Pro ULTRA TU (AGP?)" }, + { -1, NULL } +}; diff --git a/src/r128_common.h b/src/r128_common.h new file mode 100644 index 0000000..506f97c --- /dev/null +++ b/src/r128_common.h @@ -0,0 +1,171 @@ +/* r128_common.h -- common header definitions for R128 2D/3D/DRM suite + * Created: Sun Apr 9 18:16:28 2000 by kevin@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2002 Tungsten Graphics, 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, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 NONINFRINGEMENT. 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. + * + * Author: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + * Converted to common header format: + * Jens Owen <jens@tungstengraphics.com> + * + * $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_common.h,v 1.2 2002/12/16 16:19:10 dawes Exp $ + * + */ + +#ifndef _R128_COMMON_H_ +#define _R128_COMMON_H_ + +#include "X11/Xmd.h" + +/* + * WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (r128_drm.h) + */ + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_R128_INIT 0x00 +#define DRM_R128_CCE_START 0x01 +#define DRM_R128_CCE_STOP 0x02 +#define DRM_R128_CCE_RESET 0x03 +#define DRM_R128_CCE_IDLE 0x04 +#define DRM_R128_UNDEFINED1 0x05 +#define DRM_R128_RESET 0x06 +#define DRM_R128_SWAP 0x07 +#define DRM_R128_CLEAR 0x08 +#define DRM_R128_VERTEX 0x09 +#define DRM_R128_INDICES 0x0a +#define DRM_R128_BLIT 0x0b +#define DRM_R128_DEPTH 0x0c +#define DRM_R128_STIPPLE 0x0d +#define DRM_R128_UNDEFINED2 0x0e +#define DRM_R128_INDIRECT 0x0f +#define DRM_R128_FULLSCREEN 0x10 +#define DRM_R128_CLEAR2 0x11 +#define DRM_R128_GETPARAM 0x12 +#define DRM_R128_FLIP 0x13 + +#define DRM_R128_FRONT_BUFFER 0x1 +#define DRM_R128_BACK_BUFFER 0x2 +#define DRM_R128_DEPTH_BUFFER 0x4 + +typedef struct { + enum { + DRM_R128_INIT_CCE = 0x01, + DRM_R128_CLEANUP_CCE = 0x02 + } func; + unsigned long sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_secure; /* FIXME: Deprecated, we should remove this */ + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + unsigned int span_offset; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; +} drmR128Init; + +typedef struct { + int flush; + int idle; +} drmR128CCEStop; + +typedef struct { + int idx; + int start; + int end; + int discard; +} drmR128Indirect; + +typedef struct { + int idx; + int pitch; + int offset; + int format; + unsigned short x, y; + unsigned short width, height; +} drmR128Blit; + +typedef struct { + enum { + DRM_R128_WRITE_SPAN = 0x01, + DRM_R128_WRITE_PIXELS = 0x02, + DRM_R128_READ_SPAN = 0x03, + DRM_R128_READ_PIXELS = 0x04 + } func; + int n; + int *x; + int *y; + unsigned int *buffer; + unsigned char *mask; +} drmR128Depth; + +typedef struct { + int prim; + int idx; /* Index of vertex buffer */ + int count; /* Number of vertices in buffer */ + int discard; /* Client finished with buffer? */ +} drmR128Vertex; + +typedef struct { + unsigned int *mask; +} drmR128Stipple; + +typedef struct { + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; +} drmR128Clear; + +typedef struct { + enum { + DRM_R128_INIT_FULLSCREEN = 0x01, + DRM_R128_CLEANUP_FULLSCREEN = 0x02 + } func; +} drmR128Fullscreen; + +typedef struct drm_r128_getparam { + int param; + int *value; +} drmR128GetParam; + +#define R128_PARAM_IRQ_NR 1 + +#endif diff --git a/src/r128_cursor.c b/src/r128_cursor.c new file mode 100644 index 0000000..7527c33 --- /dev/null +++ b/src/r128_cursor.c @@ -0,0 +1,263 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_cursor.c,v 1.5tsi Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + * References: + * + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + + /* Driver data structures */ +#include "r128.h" +#include "r128_reg.h" + + /* X and server generic header files */ +#include "xf86.h" + +#if X_BYTE_ORDER == X_BIG_ENDIAN +#define P_SWAP32( a , b ) \ + ((char *)a)[0] = ((char *)b)[3]; \ + ((char *)a)[1] = ((char *)b)[2]; \ + ((char *)a)[2] = ((char *)b)[1]; \ + ((char *)a)[3] = ((char *)b)[0] + +#define P_SWAP16( a , b ) \ + ((char *)a)[0] = ((char *)b)[1]; \ + ((char *)a)[1] = ((char *)b)[0]; \ + ((char *)a)[2] = ((char *)b)[3]; \ + ((char *)a)[3] = ((char *)b)[2] +#endif + + +/* Set cursor foreground and background colors. */ +static void R128SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREG(R128_CUR_CLR0, bg); + OUTREG(R128_CUR_CLR1, fg); +} + +/* Set cursor position to (x,y) with offset into cursor bitmap at + (xorigin,yorigin). */ +static void R128SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + xf86CursorInfoPtr cursor = info->cursor; + int xorigin = 0; + int yorigin = 0; + int total_y = pScrn->frameY1 - pScrn->frameY0; + + if (x < 0) xorigin = -x; + if (y < 0) yorigin = -y; + if (y > total_y) y = total_y; + if (info->Flags & V_DBLSCAN) y *= 2; + if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; + if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; + + OUTREG(R128_CUR_HORZ_VERT_OFF, R128_CUR_LOCK | (xorigin << 16) | yorigin); + OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK + | ((xorigin ? 0 : x) << 16) + | (yorigin ? 0 : y))); + OUTREG(R128_CUR_OFFSET, info->cursor_start + yorigin * 16); +} + +/* Copy cursor image from `image' to video memory. R128SetCursorPosition + will be called after this, so we can ignore xorigin and yorigin. */ +static void R128LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + CARD32 *s = (pointer)image; + CARD32 *d = (pointer)(info->FB + info->cursor_start); + int y; + CARD32 save; + + save = INREG(R128_CRTC_GEN_CNTL); + OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN); + +#if X_BYTE_ORDER == X_BIG_ENDIAN + switch(info->CurrentLayout.pixel_bytes) { + case 4: + case 3: + for (y = 0; y < 64; y++) { + P_SWAP32(d,s); + d++; s++; + P_SWAP32(d,s); + d++; s++; + P_SWAP32(d,s); + d++; s++; + P_SWAP32(d,s); + d++; s++; + } + break; + case 2: + for (y = 0; y < 64; y++) { + P_SWAP16(d,s); + d++; s++; + P_SWAP16(d,s); + d++; s++; + P_SWAP16(d,s); + d++; s++; + P_SWAP16(d,s); + d++; s++; + } + break; + default: + for (y = 0; y < 64; y++) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + } +#else + for (y = 0; y < 64; y++) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } +#endif + + /* Set the area after the cursor to be all transparent so that we + won't display corrupted cursors on the screen */ + for (y = 0; y < 64; y++) { + *d++ = 0xffffffff; /* The AND bits */ + *d++ = 0xffffffff; + *d++ = 0x00000000; /* The XOR bits */ + *d++ = 0x00000000; + } + + + OUTREG(R128_CRTC_GEN_CNTL, save); +} + +/* Hide hardware cursor. */ +static void R128HideCursor(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN); +} + +/* Show hardware cursor. */ +static void R128ShowCursor(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN); +} + +/* Determine if hardware cursor is in use. */ +static Bool R128UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + return info->cursor_start ? TRUE : FALSE; +} + +/* Initialize hardware cursor support. */ +Bool R128CursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + xf86CursorInfoPtr cursor; + FBAreaPtr fbarea; + int width; + int height; + int size; + + + if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE; + + cursor->MaxWidth = 64; + cursor->MaxHeight = 64; + cursor->Flags = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP + | HARDWARE_CURSOR_SHOW_TRANSPARENT + | HARDWARE_CURSOR_UPDATE_UNHIDDEN +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST +#endif + | HARDWARE_CURSOR_INVERT_MASK + | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK + | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 + | HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK); + + cursor->SetCursorColors = R128SetCursorColors; + cursor->SetCursorPosition = R128SetCursorPosition; + cursor->LoadCursorImage = R128LoadCursorImage; + cursor->HideCursor = R128HideCursor; + cursor->ShowCursor = R128ShowCursor; + cursor->UseHWCursor = R128UseHWCursor; + + size = (cursor->MaxWidth/4) * cursor->MaxHeight; + width = pScrn->displayWidth; + height = (size*2 + 1023) / pScrn->displayWidth; + fbarea = xf86AllocateOffscreenArea(pScreen, + width, + height, + 16, + NULL, + NULL, + NULL); + + if (!fbarea) { + info->cursor_start = 0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Hardware cursor disabled" + " due to insufficient offscreen memory\n"); + } else { + info->cursor_start = R128_ALIGN((fbarea->box.x1 + + width * fbarea->box.y1) + * info->CurrentLayout.pixel_bytes, 16); + info->cursor_end = info->cursor_start + size; + } + + R128TRACE(("R128CursorInit (0x%08x-0x%08x)\n", + info->cursor_start, info->cursor_end)); + + return xf86InitCursor(pScreen, cursor); +} diff --git a/src/r128_dga.c b/src/r128_dga.c new file mode 100644 index 0000000..c6d9133 --- /dev/null +++ b/src/r128_dga.c @@ -0,0 +1,397 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dga.c,v 1.9 2002/10/30 12:52:12 alanh Exp $ */ +/* + * Authors: + * Ove Kåven <ovek@transgaming.com>, + * borrowing some code from the Chips and MGA drivers. + */ + + /* Driver data structures */ +#include "r128.h" +#include "r128_probe.h" + + /* X and server generic header files */ +#include "xf86.h" + + /* DGA support */ +#include "dgaproc.h" + +#ifdef XF86DRI +#include "r128_common.h" +#endif + +static Bool R128_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, + int *, int *, int *); +static Bool R128_SetMode(ScrnInfoPtr, DGAModePtr); +static int R128_GetViewport(ScrnInfoPtr); +static void R128_SetViewport(ScrnInfoPtr, int, int, int); +static void R128_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); +static void R128_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); +static void R128_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, + unsigned long); + +static DGAModePtr R128SetupDGAMode(ScrnInfoPtr pScrn, + DGAModePtr modes, + int *num, + int bitsPerPixel, + int depth, + Bool pixmap, + int secondPitch, + unsigned long red, + unsigned long green, + unsigned long blue, + short visualClass) +{ + R128InfoPtr info = R128PTR(pScrn); + DGAModePtr newmodes = NULL; + DGAModePtr currentMode; + DisplayModePtr pMode; + DisplayModePtr firstMode; + unsigned int size; + int pitch; + int Bpp = bitsPerPixel >> 3; + +SECOND_PASS: + + pMode = firstMode = pScrn->modes; + + while (1) { + pitch = pScrn->displayWidth; + size = pitch * Bpp * pMode->VDisplay; + + if ((!secondPitch || (pitch != secondPitch)) && + (size <= info->FbMapSize)) { + + if (secondPitch) + pitch = secondPitch; + + if (!(newmodes = xrealloc(modes, (*num + 1) * sizeof(DGAModeRec)))) + break; + + modes = newmodes; + currentMode = modes + *num; + + currentMode->mode = pMode; + currentMode->flags = DGA_CONCURRENT_ACCESS; + + if (pixmap) + currentMode->flags |= DGA_PIXMAP_AVAILABLE; + + if (info->accel) { + if (info->accel->SetupForSolidFill && + info->accel->SubsequentSolidFillRect) + currentMode->flags |= DGA_FILL_RECT; + if (info->accel->SetupForScreenToScreenCopy && + info->accel->SubsequentScreenToScreenCopy) + currentMode->flags |= DGA_BLIT_RECT | DGA_BLIT_RECT_TRANS; + if (currentMode->flags & + (DGA_PIXMAP_AVAILABLE | DGA_FILL_RECT | + DGA_BLIT_RECT | DGA_BLIT_RECT_TRANS)) + currentMode->flags &= ~DGA_CONCURRENT_ACCESS; + } + if (pMode->Flags & V_DBLSCAN) + currentMode->flags |= DGA_DOUBLESCAN; + if (pMode->Flags & V_INTERLACE) + currentMode->flags |= DGA_INTERLACED; + + currentMode->byteOrder = pScrn->imageByteOrder; + currentMode->depth = depth; + currentMode->bitsPerPixel = bitsPerPixel; + currentMode->red_mask = red; + currentMode->green_mask = green; + currentMode->blue_mask = blue; + currentMode->visualClass = visualClass; + currentMode->viewportWidth = pMode->HDisplay; + currentMode->viewportHeight = pMode->VDisplay; + currentMode->xViewportStep = 8; + currentMode->yViewportStep = 1; + currentMode->viewportFlags = DGA_FLIP_RETRACE; + currentMode->offset = 0; + currentMode->address = (unsigned char*)info->LinearAddr; + currentMode->bytesPerScanline = pitch * Bpp; + currentMode->imageWidth = pitch; + currentMode->imageHeight = (info->FbMapSize + / currentMode->bytesPerScanline); + 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); + (*num)++; + } + + pMode = pMode->next; + if (pMode == firstMode) + break; + } + + if (secondPitch) { + secondPitch = 0; + goto SECOND_PASS; + } + + return modes; +} + +Bool +R128DGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + DGAModePtr modes = NULL; + int num = 0; + + /* 8 */ + modes = R128SetupDGAMode (pScrn, modes, &num, 8, 8, + (pScrn->bitsPerPixel == 8), + (pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth, + 0, 0, 0, PseudoColor); + + /* 15 */ + modes = R128SetupDGAMode (pScrn, modes, &num, 16, 15, + (pScrn->bitsPerPixel == 16), + (pScrn->depth != 15) ? 0 : pScrn->displayWidth, + 0x7c00, 0x03e0, 0x001f, TrueColor); + + modes = R128SetupDGAMode (pScrn, modes, &num, 16, 15, + (pScrn->bitsPerPixel == 16), + (pScrn->depth != 15) ? 0 : pScrn->displayWidth, + 0x7c00, 0x03e0, 0x001f, DirectColor); + + /* 16 */ + modes = R128SetupDGAMode (pScrn, modes, &num, 16, 16, + (pScrn->bitsPerPixel == 16), + (pScrn->depth != 16) ? 0 : pScrn->displayWidth, + 0xf800, 0x07e0, 0x001f, TrueColor); + + modes = R128SetupDGAMode (pScrn, modes, &num, 16, 16, + (pScrn->bitsPerPixel == 16), + (pScrn->depth != 16) ? 0 : pScrn->displayWidth, + 0xf800, 0x07e0, 0x001f, DirectColor); + + /* 24 */ + modes = R128SetupDGAMode (pScrn, modes, &num, 24, 24, + (pScrn->bitsPerPixel == 24), + (pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth, + 0xff0000, 0x00ff00, 0x0000ff, TrueColor); + + modes = R128SetupDGAMode (pScrn, modes, &num, 24, 24, + (pScrn->bitsPerPixel == 24), + (pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth, + 0xff0000, 0x00ff00, 0x0000ff, DirectColor); + + /* 32 */ + modes = R128SetupDGAMode (pScrn, modes, &num, 32, 24, + (pScrn->bitsPerPixel == 32), + (pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth, + 0xff0000, 0x00ff00, 0x0000ff, TrueColor); + + modes = R128SetupDGAMode (pScrn, modes, &num, 32, 24, + (pScrn->bitsPerPixel == 32), + (pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth, + 0xff0000, 0x00ff00, 0x0000ff, DirectColor); + + info->numDGAModes = num; + info->DGAModes = modes; + + info->DGAFuncs.OpenFramebuffer = R128_OpenFramebuffer; + info->DGAFuncs.CloseFramebuffer = NULL; + info->DGAFuncs.SetMode = R128_SetMode; + info->DGAFuncs.SetViewport = R128_SetViewport; + info->DGAFuncs.GetViewport = R128_GetViewport; + + info->DGAFuncs.Sync = NULL; + info->DGAFuncs.FillRect = NULL; + info->DGAFuncs.BlitRect = NULL; + info->DGAFuncs.BlitTransRect = NULL; + + if (info->accel) { + info->DGAFuncs.Sync = info->accel->Sync; + if (info->accel->SetupForSolidFill && + info->accel->SubsequentSolidFillRect) + info->DGAFuncs.FillRect = R128_FillRect; + if (info->accel->SetupForScreenToScreenCopy && + info->accel->SubsequentScreenToScreenCopy) { + info->DGAFuncs.BlitRect = R128_BlitRect; + info->DGAFuncs.BlitTransRect = R128_BlitTransRect; + } + } + + return DGAInit(pScreen, &(info->DGAFuncs), modes, num); +} + + +static Bool +R128_SetMode( + ScrnInfoPtr pScrn, + DGAModePtr pMode +){ + static R128FBLayout SavedLayouts[MAXSCREENS]; + int indx = pScrn->pScreen->myNum; + R128InfoPtr info = R128PTR(pScrn); + + if(!pMode) { /* restore the original mode */ + /* put the ScreenParameters back */ + if(info->DGAactive) + memcpy(&info->CurrentLayout, &SavedLayouts[indx], sizeof(R128FBLayout)); + + pScrn->currentMode = info->CurrentLayout.mode; + + pScrn->SwitchMode(indx, pScrn->currentMode, 0); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + R128CCE_STOP(pScrn, info); + } +#endif + if (info->accelOn) + R128EngineInit(pScrn); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + R128CCE_START(pScrn, info); + } +#endif + pScrn->AdjustFrame(indx, 0, 0, 0); + info->DGAactive = FALSE; + } else { + if(!info->DGAactive) { /* save the old parameters */ + memcpy(&SavedLayouts[indx], &info->CurrentLayout, sizeof(R128FBLayout)); + info->DGAactive = TRUE; + } + + info->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel; + info->CurrentLayout.depth = pMode->depth; + info->CurrentLayout.displayWidth = pMode->bytesPerScanline / + (pMode->bitsPerPixel >> 3); + info->CurrentLayout.pixel_bytes = pMode->bitsPerPixel / 8; + info->CurrentLayout.pixel_code = (pMode->bitsPerPixel != 16 + ? pMode->bitsPerPixel + : pMode->depth); + /* R128ModeInit() will set the mode field */ + + pScrn->SwitchMode(indx, pMode->mode, 0); + +#ifdef XF86DRI + if (info->directRenderingEnabled) { + R128CCE_STOP(pScrn, info); + } +#endif + if (info->accelOn) + R128EngineInit(pScrn); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + R128CCE_START(pScrn, info); + } +#endif + } + + return TRUE; +} + + + +static int +R128_GetViewport( + ScrnInfoPtr pScrn +){ + R128InfoPtr info = R128PTR(pScrn); + + return info->DGAViewportStatus; +} + + +static void +R128_SetViewport( + ScrnInfoPtr pScrn, + int x, int y, + int flags +){ + R128InfoPtr info = R128PTR(pScrn); + + pScrn->AdjustFrame(pScrn->pScreen->myNum, x, y, flags); + info->DGAViewportStatus = 0; /* FIXME */ +} + + +static void +R128_FillRect ( + ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned long color +){ + R128InfoPtr info = R128PTR(pScrn); + + (*info->accel->SetupForSolidFill)(pScrn, color, GXcopy, (CARD32)(~0)); + (*info->accel->SubsequentSolidFillRect)(pScrn, x, y, w, h); + + if (pScrn->bitsPerPixel == info->CurrentLayout.bitsPerPixel) + SET_SYNC_FLAG(info->accel); +} + +static void +R128_BlitRect( + ScrnInfoPtr pScrn, + int srcx, int srcy, + int w, int h, + int dstx, int dsty +){ + R128InfoPtr info = R128PTR(pScrn); + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*info->accel->SetupForScreenToScreenCopy)( + pScrn, xdir, ydir, GXcopy, (CARD32)(~0), -1); + (*info->accel->SubsequentScreenToScreenCopy)( + pScrn, srcx, srcy, dstx, dsty, w, h); + + if (pScrn->bitsPerPixel == info->CurrentLayout.bitsPerPixel) + SET_SYNC_FLAG(info->accel); +} + + +static void +R128_BlitTransRect( + ScrnInfoPtr pScrn, + int srcx, int srcy, + int w, int h, + int dstx, int dsty, + unsigned long color +){ + R128InfoPtr info = R128PTR(pScrn); + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + info->XAAForceTransBlit = TRUE; + + (*info->accel->SetupForScreenToScreenCopy)( + pScrn, xdir, ydir, GXcopy, (CARD32)(~0), color); + + info->XAAForceTransBlit = FALSE; + + (*info->accel->SubsequentScreenToScreenCopy)( + pScrn, srcx, srcy, dstx, dsty, w, h); + + if (pScrn->bitsPerPixel == info->CurrentLayout.bitsPerPixel) + SET_SYNC_FLAG(info->accel); +} + + +static Bool +R128_OpenFramebuffer( + ScrnInfoPtr pScrn, + char **name, + unsigned char **mem, + int *size, + int *offset, + int *flags +){ + R128InfoPtr info = R128PTR(pScrn); + + *name = NULL; /* no special device */ + *mem = (unsigned char*)info->LinearAddr; + *size = info->FbMapSize; + *offset = 0; + *flags = /* DGA_NEED_ROOT */ 0; /* don't need root, just /dev/mem access */ + + return TRUE; +} diff --git a/src/r128_dri.c b/src/r128_dri.c new file mode 100644 index 0000000..e185a27 --- /dev/null +++ b/src/r128_dri.c @@ -0,0 +1,1489 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dri.c,v 1.31 2003/09/28 20:15:53 alanh Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Rickard E. Faith <faith@valinux.com> + * Daryll Strauss <daryll@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + + /* Driver data structures */ +#include "r128.h" +#include "r128_dri.h" +#include "r128_reg.h" +#include "r128_sarea.h" +#include "r128_version.h" + + /* X and server generic header files */ +#include "xf86.h" +#include "windowstr.h" +#include "xf86PciInfo.h" + +#include "shadowfb.h" + /* GLX/DRI/DRM definitions */ +#define _XF86DRI_SERVER_ +#include "GL/glxtokens.h" +#include "sarea.h" + +/* ?? HACK - for now, put this here... */ +/* ?? Alpha - this may need to be a variable to handle UP1x00 vs TITAN */ +#if defined(__alpha__) +# define DRM_PAGE_SIZE 8192 +#elif defined(__ia64__) +# define DRM_PAGE_SIZE getpagesize() +#else +# define DRM_PAGE_SIZE 4096 +#endif + +static void R128DRITransitionTo2d(ScreenPtr pScreen); +static void R128DRITransitionTo3d(ScreenPtr pScreen); +static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen); +static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen); + +static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox); + +/* Initialize the visual configs that are supported by the hardware. + These are combined with the visual configs that the indirect + rendering core supports, and the intersection is exported to the + client. */ +static Bool R128InitVisualConfigs(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = 0; + R128ConfigPrivPtr pR128Configs = 0; + R128ConfigPrivPtr *pR128ConfigPtrs = 0; + int i, accum, stencil, db; + + switch (info->CurrentLayout.pixel_code) { + case 8: /* 8bpp mode is not support */ + case 15: /* FIXME */ + case 24: /* FIXME */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] R128DRIScreenInit failed (depth %d not supported). " + "Disabling DRI.\n", info->CurrentLayout.pixel_code); + return FALSE; + +#define R128_USE_ACCUM 1 +#define R128_USE_STENCIL 1 +#define R128_USE_DB 1 + + case 16: + numConfigs = 1; + if (R128_USE_ACCUM) numConfigs *= 2; + if (R128_USE_STENCIL) numConfigs *= 2; + if (R128_USE_DB) numConfigs *= 2; + + if (!(pConfigs + = (__GLXvisualConfig*)xcalloc(sizeof(__GLXvisualConfig), + numConfigs))) { + return FALSE; + } + if (!(pR128Configs + = (R128ConfigPrivPtr)xcalloc(sizeof(R128ConfigPrivRec), + numConfigs))) { + xfree(pConfigs); + return FALSE; + } + if (!(pR128ConfigPtrs + = (R128ConfigPrivPtr*)xcalloc(sizeof(R128ConfigPrivPtr), + numConfigs))) { + xfree(pConfigs); + xfree(pR128Configs); + return FALSE; + } + + i = 0; + for (db = 0; db <= R128_USE_DB; db++) { + for (accum = 0; accum <= R128_USE_ACCUM; accum++) { + for (stencil = 0; stencil <= R128_USE_STENCIL; stencil++) { + pR128ConfigPtrs[i] = &pR128Configs[i]; + + pConfigs[i].vid = (VisualID)(-1); + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + pConfigs[i].alphaMask = 0x00000000; + if (accum) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + if (db) + pConfigs[i].doubleBuffer = TRUE; + else + pConfigs[i].doubleBuffer = FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + pConfigs[i].depthSize = 16; + if (stencil) + pConfigs[i].stencilSize = 8; /* Simulated in software */ + else + pConfigs[i].stencilSize = 0; + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (accum || stencil) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + + case 32: + numConfigs = 1; + if (R128_USE_ACCUM) numConfigs *= 2; + if (R128_USE_STENCIL) numConfigs *= 2; + if (R128_USE_DB) numConfigs *= 2; + + if (!(pConfigs + = (__GLXvisualConfig*)xcalloc(sizeof(__GLXvisualConfig), + numConfigs))) { + return FALSE; + } + if (!(pR128Configs + = (R128ConfigPrivPtr)xcalloc(sizeof(R128ConfigPrivRec), + numConfigs))) { + xfree(pConfigs); + return FALSE; + } + if (!(pR128ConfigPtrs + = (R128ConfigPrivPtr*)xcalloc(sizeof(R128ConfigPrivPtr), + numConfigs))) { + xfree(pConfigs); + xfree(pR128Configs); + return FALSE; + } + + i = 0; + for (db = 0; db <= R128_USE_DB; db++) { + for (accum = 0; accum <= R128_USE_ACCUM; accum++) { + for (stencil = 0; stencil <= R128_USE_STENCIL; stencil++) { + pR128ConfigPtrs[i] = &pR128Configs[i]; + + pConfigs[i].vid = (VisualID)(-1); + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 8; + pConfigs[i].greenSize = 8; + pConfigs[i].blueSize = 8; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x00FF0000; + pConfigs[i].greenMask = 0x0000FF00; + pConfigs[i].blueMask = 0x000000FF; + pConfigs[i].alphaMask = 0x00000000; + if (accum) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + if (db) + pConfigs[i].doubleBuffer = TRUE; + else + pConfigs[i].doubleBuffer = FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 24; + if (stencil) { + pConfigs[i].depthSize = 24; + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].depthSize = 24; + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (accum || stencil) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + } + + info->numVisualConfigs = numConfigs; + info->pVisualConfigs = pConfigs; + info->pVisualConfigsPriv = pR128Configs; + GlxSetVisualConfigs(numConfigs, pConfigs, (void**)pR128ConfigPtrs); + return TRUE; +} + +/* Create the Rage 128-specific context information */ +static Bool R128CreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + info->drmCtx = hwContext; + return TRUE; +} + +/* Destroy the Rage 128-specific context information */ +static void R128DestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore) +{ + /* Nothing yet */ +} + +/* Called when the X server is woken up to allow the last client's + context to be saved and the X server's context to be loaded. This is + not necessary for the Rage 128 since the client detects when it's + context is not currently loaded and then load's it itself. Since the + registers to start and stop the CCE are privileged, only the X server + can start/stop the engine. */ +static void R128EnterServer(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + if (info->accel) info->accel->NeedToSync = TRUE; +} + +/* Called when the X server goes to sleep to allow the X server's + context to be saved and the last client's context to be loaded. This + is not necessary for the Rage 128 since the client detects when it's + context is not currently loaded and then load's it itself. Since the + registers to start and stop the CCE are privileged, only the X server + can start/stop the engine. */ +static void R128LeaveServer(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + if (!info->directRenderingEnabled) { + /* Save all hardware scissors */ + info->sc_left = INREG(R128_SC_LEFT); + info->sc_right = INREG(R128_SC_RIGHT); + info->sc_top = INREG(R128_SC_TOP); + info->sc_bottom = INREG(R128_SC_BOTTOM); + info->aux_sc_cntl = INREG(R128_SC_BOTTOM); + } else if (info->CCEInUse) { + R128CCEReleaseIndirect(pScrn); + + info->CCEInUse = FALSE; + } +} + +/* Contexts can be swapped by the X server if necessary. This callback + is currently only used to perform any functions necessary when + entering or leaving the X server, and in the future might not be + necessary. */ +static void R128DRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType oldContextType, void *oldContext, + DRIContextType newContextType, void *newContext) +{ + if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) && + (newContextType==DRI_2D_CONTEXT)) { /* Entering from Wakeup */ + R128EnterServer(pScreen); + } + if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) && + (newContextType==DRI_2D_CONTEXT)) { /* Exiting from Block Handler */ + R128LeaveServer(pScreen); + } +} + +/* Initialize the state of the back and depth buffers. */ +static void R128DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 indx) +{ + /* FIXME: This routine needs to have acceleration turned on */ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + BoxPtr pbox, pboxSave; + int nbox, nboxSave; + int depth; + + /* FIXME: Use accel when CCE 2D code is written + * EA: What is this code kept for? Radeon doesn't have it and + * has a comment: "There's no need for the 2d driver to be clearing + * buffers for the 3d client. It knows how to do that on its own." + */ + if (info->directRenderingEnabled) + return; + + /* FIXME: This should be based on the __GLXvisualConfig info */ + switch (pScrn->bitsPerPixel) { + case 8: depth = 0x000000ff; break; + case 16: depth = 0x0000ffff; break; + case 24: depth = 0x00ffffff; break; + case 32: depth = 0xffffffff; break; + default: depth = 0x00000000; break; + } + + /* FIXME: Copy XAAPaintWindow() and use REGION_TRANSLATE() */ + /* FIXME: Only initialize the back and depth buffers for contexts + that request them */ + + pboxSave = pbox = REGION_RECTS(prgn); + nboxSave = nbox = REGION_NUM_RECTS(prgn); + + (*info->accel->SetupForSolidFill)(pScrn, 0, GXcopy, (CARD32)(-1)); + for (; nbox; nbox--, pbox++) { + (*info->accel->SubsequentSolidFillRect)(pScrn, + pbox->x1 + info->fbX, + pbox->y1 + info->fbY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + (*info->accel->SubsequentSolidFillRect)(pScrn, + pbox->x1 + info->backX, + pbox->y1 + info->backY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + } + + pbox = pboxSave; + nbox = nboxSave; + + /* FIXME: this needs to consider depth tiling. */ + (*info->accel->SetupForSolidFill)(pScrn, depth, GXcopy, (CARD32)(-1)); + for (; nbox; nbox--, pbox++) + (*info->accel->SubsequentSolidFillRect)(pScrn, + pbox->x1 + info->depthX, + pbox->y1 + info->depthY, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + + info->accel->NeedToSync = TRUE; +} + +/* Copy the back and depth buffers when the X server moves a window. */ +static void R128DRIMoveBuffers(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 indx) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + /* FIXME: This routine needs to have acceleration turned on */ + /* FIXME: Copy XAACopyWindow() and use REGION_TRANSLATE() */ + /* FIXME: Only initialize the back and depth buffers for contexts + that request them */ + + /* FIXME: Use accel when CCE 2D code is written */ + if (info->directRenderingEnabled) + return; +} + +/* Initialize the AGP state. Request memory for use in AGP space, and + initialize the Rage 128 registers to point to that memory. */ +static Bool R128DRIAgpInit(R128InfoPtr info, ScreenPtr pScreen) +{ + unsigned char *R128MMIO = info->MMIO; + unsigned long mode; + unsigned int vendor, device; + int ret; + unsigned long cntl, chunk; + int s, l; + int flags; + unsigned long agpBase; + + if (drmAgpAcquire(info->drmFD) < 0) { + xf86DrvMsg(pScreen->myNum, X_WARNING, "[agp] AGP not available\n"); + return FALSE; + } + + /* Modify the mode if the default mode is + not appropriate for this particular + combination of graphics card and AGP + chipset. */ + + mode = drmAgpGetMode(info->drmFD); /* Default mode */ + vendor = drmAgpVendorId(info->drmFD); + device = drmAgpDeviceId(info->drmFD); + + mode &= ~R128_AGP_MODE_MASK; + switch (info->agpMode) { + case 4: mode |= R128_AGP_4X_MODE; + case 2: mode |= R128_AGP_2X_MODE; + case 1: default: mode |= R128_AGP_1X_MODE; + } + + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", + mode, vendor, device, + info->PciInfo->vendor, + info->PciInfo->chipType); + + if (drmAgpEnable(info->drmFD, mode) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n"); + drmAgpRelease(info->drmFD); + return FALSE; + } + + info->agpOffset = 0; + + if ((ret = drmAgpAlloc(info->drmFD, info->agpSize*1024*1024, 0, NULL, + &info->agpMemHandle)) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret); + drmAgpRelease(info->drmFD); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] %d kB allocated with handle 0x%08lx\n", + info->agpSize*1024, info->agpMemHandle); + + if (drmAgpBind(info->drmFD, info->agpMemHandle, info->agpOffset) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not bind\n"); + drmAgpFree(info->drmFD, info->agpMemHandle); + drmAgpRelease(info->drmFD); + return FALSE; + } + + /* Initialize the CCE ring buffer data */ + info->ringStart = info->agpOffset; + info->ringMapSize = info->ringSize*1024*1024 + DRM_PAGE_SIZE; + info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; + + info->ringReadOffset = info->ringStart + info->ringMapSize; + info->ringReadMapSize = DRM_PAGE_SIZE; + + /* Reserve space for vertex/indirect buffers */ + info->bufStart = info->ringReadOffset + info->ringReadMapSize; + info->bufMapSize = info->bufSize*1024*1024; + + /* Reserve the rest for AGP textures */ + info->agpTexStart = info->bufStart + info->bufMapSize; + s = (info->agpSize*1024*1024 - info->agpTexStart); + l = R128MinBits((s-1) / R128_NR_TEX_REGIONS); + if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; + info->agpTexMapSize = (s >> l) << l; + info->log2AGPTexGran = l; + + if (info->CCESecure) flags = DRM_READ_ONLY; + else flags = 0; + + if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize, + DRM_AGP, flags, &info->ringHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add ring mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] ring handle = 0x%08lx\n", info->ringHandle); + + if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize, + (drmAddressPtr)&info->ring) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map ring\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Ring mapped at 0x%08lx\n", + (unsigned long)info->ring); + + if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize, + DRM_AGP, flags, &info->ringReadPtrHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add ring read ptr mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] ring read ptr handle = 0x%08lx\n", + info->ringReadPtrHandle); + + if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, + (drmAddressPtr)&info->ringReadPtr) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map ring read ptr\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Ring read ptr mapped at 0x%08lx\n", + (unsigned long)info->ringReadPtr); + + if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize, + DRM_AGP, 0, &info->bufHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add vertex/indirect buffers mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] vertex/indirect buffers handle = 0x%08lx\n", + info->bufHandle); + + if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize, + (drmAddressPtr)&info->buf) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map vertex/indirect buffers\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Vertex/indirect buffers mapped at 0x%08lx\n", + (unsigned long)info->buf); + + if (drmAddMap(info->drmFD, info->agpTexStart, info->agpTexMapSize, + DRM_AGP, 0, &info->agpTexHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add AGP texture map mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP texture map handle = 0x%08lx\n", + info->agpTexHandle); + + if (drmMap(info->drmFD, info->agpTexHandle, info->agpTexMapSize, + (drmAddressPtr)&info->agpTex) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map AGP texture map\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] AGP Texture map mapped at 0x%08lx\n", + (unsigned long)info->agpTex); + + /* Initialize Rage 128's AGP registers */ + cntl = INREG(R128_AGP_CNTL); + cntl &= ~R128_AGP_APER_SIZE_MASK; + switch (info->agpSize) { + case 256: cntl |= R128_AGP_APER_SIZE_256MB; break; + case 128: cntl |= R128_AGP_APER_SIZE_128MB; break; + case 64: cntl |= R128_AGP_APER_SIZE_64MB; break; + case 32: cntl |= R128_AGP_APER_SIZE_32MB; break; + case 16: cntl |= R128_AGP_APER_SIZE_16MB; break; + case 8: cntl |= R128_AGP_APER_SIZE_8MB; break; + case 4: cntl |= R128_AGP_APER_SIZE_4MB; break; + default: + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Illegal aperture size %d kB\n", + info->agpSize*1024); + return FALSE; + } + agpBase = drmAgpBase(info->drmFD); + OUTREG(R128_AGP_BASE, agpBase); + OUTREG(R128_AGP_CNTL, cntl); + + /* Disable Rage 128's PCIGART registers */ + chunk = INREG(R128_BM_CHUNK_0_VAL); + chunk &= ~(R128_BM_PTR_FORCE_TO_PCI | + R128_BM_PM4_RD_FORCE_TO_PCI | + R128_BM_GLOBAL_FORCE_TO_PCI); + OUTREG(R128_BM_CHUNK_0_VAL, chunk); + + OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */ + + return TRUE; +} + +static Bool R128DRIPciInit(R128InfoPtr info, ScreenPtr pScreen) +{ + unsigned char *R128MMIO = info->MMIO; + CARD32 chunk; + int ret; + int flags; + + info->agpOffset = 0; + + ret = drmScatterGatherAlloc(info->drmFD, info->agpSize*1024*1024, + &info->pciMemHandle); + if (ret < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Out of memory (%d)\n", ret); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] %d kB allocated with handle 0x%08lx\n", + info->agpSize*1024, info->pciMemHandle); + + /* Initialize the CCE ring buffer data */ + info->ringStart = info->agpOffset; + info->ringMapSize = info->ringSize*1024*1024 + DRM_PAGE_SIZE; + info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; + + info->ringReadOffset = info->ringStart + info->ringMapSize; + info->ringReadMapSize = DRM_PAGE_SIZE; + + /* Reserve space for vertex/indirect buffers */ + info->bufStart = info->ringReadOffset + info->ringReadMapSize; + info->bufMapSize = info->bufSize*1024*1024; + + flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL; + + if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize, + DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not add ring mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] ring handle = 0x%08lx\n", info->ringHandle); + + if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize, + (drmAddressPtr)&info->ring) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Could not map ring\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring mapped at 0x%08lx\n", + (unsigned long)info->ring); + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring contents 0x%08lx\n", + *(unsigned long *)(pointer)info->ring); + + if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize, + DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not add ring read ptr mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] ring read ptr handle = 0x%08lx\n", + info->ringReadPtrHandle); + + if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, + (drmAddressPtr)&info->ringReadPtr) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not map ring read ptr\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring read ptr mapped at 0x%08lx\n", + (unsigned long)info->ringReadPtr); + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring read ptr contents 0x%08lx\n", + *(unsigned long *)(pointer)info->ringReadPtr); + + if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize, + DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not add vertex/indirect buffers mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] vertex/indirect buffers handle = 0x%08lx\n", + info->bufHandle); + + if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize, + (drmAddressPtr)&info->buf) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not map vertex/indirect buffers\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Vertex/indirect buffers mapped at 0x%08lx\n", + (unsigned long)info->buf); + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Vertex/indirect buffers contents 0x%08lx\n", + *(unsigned long *)(pointer)info->buf); + + switch (info->Chipset) { + case PCI_CHIP_RAGE128LE: + case PCI_CHIP_RAGE128RE: + case PCI_CHIP_RAGE128RK: + case PCI_CHIP_RAGE128PD: + case PCI_CHIP_RAGE128PP: + case PCI_CHIP_RAGE128PR: + /* This is a PCI card, do nothing */ + break; + + case PCI_CHIP_RAGE128LF: + case PCI_CHIP_RAGE128MF: + case PCI_CHIP_RAGE128ML: + case PCI_CHIP_RAGE128RF: + case PCI_CHIP_RAGE128RG: + case PCI_CHIP_RAGE128RL: + case PCI_CHIP_RAGE128SM: + case PCI_CHIP_RAGE128PF: + case PCI_CHIP_RAGE128TF: + case PCI_CHIP_RAGE128TL: + case PCI_CHIP_RAGE128TR: + /* FIXME: ATI documentation does not specify if the following chips are + * AGP or PCI, it just mentions their PCI IDs. I'm assuming they're AGP + * until I get more correct information. <mharris@redhat.com> + */ + case PCI_CHIP_RAGE128PA: + case PCI_CHIP_RAGE128PB: + case PCI_CHIP_RAGE128PC: + case PCI_CHIP_RAGE128PE: + case PCI_CHIP_RAGE128PG: + case PCI_CHIP_RAGE128PH: + case PCI_CHIP_RAGE128PI: + case PCI_CHIP_RAGE128PJ: + case PCI_CHIP_RAGE128PK: + case PCI_CHIP_RAGE128PL: + case PCI_CHIP_RAGE128PM: + case PCI_CHIP_RAGE128PN: + case PCI_CHIP_RAGE128PO: + case PCI_CHIP_RAGE128PQ: + case PCI_CHIP_RAGE128PS: + case PCI_CHIP_RAGE128PT: + case PCI_CHIP_RAGE128PU: + case PCI_CHIP_RAGE128PV: + case PCI_CHIP_RAGE128PW: + case PCI_CHIP_RAGE128PX: + case PCI_CHIP_RAGE128SE: + case PCI_CHIP_RAGE128SF: + case PCI_CHIP_RAGE128SG: + case PCI_CHIP_RAGE128SH: + case PCI_CHIP_RAGE128SK: + case PCI_CHIP_RAGE128SL: + case PCI_CHIP_RAGE128SN: + case PCI_CHIP_RAGE128TS: + case PCI_CHIP_RAGE128TT: + case PCI_CHIP_RAGE128TU: + default: + /* This is really an AGP card, force PCI GART mode */ + chunk = INREG(R128_BM_CHUNK_0_VAL); + chunk |= (R128_BM_PTR_FORCE_TO_PCI | + R128_BM_PM4_RD_FORCE_TO_PCI | + R128_BM_GLOBAL_FORCE_TO_PCI); + OUTREG(R128_BM_CHUNK_0_VAL, chunk); + OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */ + break; + } + + return TRUE; +} + +/* Add a map for the MMIO registers that will be accessed by any + DRI-based clients. */ +static Bool R128DRIMapInit(R128InfoPtr info, ScreenPtr pScreen) +{ + int flags; + + if (info->CCESecure) flags = DRM_READ_ONLY; + else flags = 0; + + /* Map registers */ + info->registerSize = R128_MMIOSIZE; + if (drmAddMap(info->drmFD, info->MMIOAddr, info->registerSize, + DRM_REGISTERS, flags, &info->registerHandle) < 0) { + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] register handle = 0x%08lx\n", info->registerHandle); + + return TRUE; +} + +/* Initialize the kernel data structures. */ +static int R128DRIKernelInit(R128InfoPtr info, ScreenPtr pScreen) +{ + drmR128Init drmInfo; + + memset( &drmInfo, 0, sizeof(drmR128Init) ); + + drmInfo.func = DRM_R128_INIT_CCE; + drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec); + drmInfo.is_pci = info->IsPCI; + drmInfo.cce_mode = info->CCEMode; + drmInfo.cce_secure = info->CCESecure; + drmInfo.ring_size = info->ringSize*1024*1024; + drmInfo.usec_timeout = info->CCEusecTimeout; + + drmInfo.fb_bpp = info->CurrentLayout.pixel_code; + drmInfo.depth_bpp = info->CurrentLayout.pixel_code; + + drmInfo.front_offset = info->frontOffset; + drmInfo.front_pitch = info->frontPitch; + + drmInfo.back_offset = info->backOffset; + drmInfo.back_pitch = info->backPitch; + + drmInfo.depth_offset = info->depthOffset; + drmInfo.depth_pitch = info->depthPitch; + drmInfo.span_offset = info->spanOffset; + + drmInfo.fb_offset = info->fbHandle; + drmInfo.mmio_offset = info->registerHandle; + drmInfo.ring_offset = info->ringHandle; + drmInfo.ring_rptr_offset = info->ringReadPtrHandle; + drmInfo.buffers_offset = info->bufHandle; + drmInfo.agp_textures_offset = info->agpTexHandle; + + if (drmCommandWrite(info->drmFD, DRM_R128_INIT, + &drmInfo, sizeof(drmR128Init)) < 0) + return FALSE; + + return TRUE; +} + +/* Add a map for the vertex buffers that will be accessed by any + DRI-based clients. */ +static Bool R128DRIBufInit(R128InfoPtr info, ScreenPtr pScreen) +{ + /* Initialize vertex buffers */ + if (info->IsPCI) { + info->bufNumBufs = drmAddBufs(info->drmFD, + info->bufMapSize / R128_BUFFER_SIZE, + R128_BUFFER_SIZE, + DRM_SG_BUFFER, + info->bufStart); + } else { + info->bufNumBufs = drmAddBufs(info->drmFD, + info->bufMapSize / R128_BUFFER_SIZE, + R128_BUFFER_SIZE, + DRM_AGP_BUFFER, + info->bufStart); + } + if (info->bufNumBufs <= 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Could not create vertex/indirect buffers list\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Added %d %d byte vertex/indirect buffers\n", + info->bufNumBufs, R128_BUFFER_SIZE); + + if (!(info->buffers = drmMapBufs(info->drmFD))) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Failed to map vertex/indirect buffers list\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Mapped %d vertex/indirect buffers\n", + info->buffers->count); + + return TRUE; +} + +static void R128DRIIrqInit(R128InfoPtr info, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (!info->irq) { + info->irq = drmGetInterruptFromBusID( + info->drmFD, + ((pciConfigPtr)info->PciInfo->thisCard)->busnum, + ((pciConfigPtr)info->PciInfo->thisCard)->devnum, + ((pciConfigPtr)info->PciInfo->thisCard)->funcnum); + + if((drmCtlInstHandler(info->drmFD, info->irq)) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding irq handler, " + "there is a device already using that irq\n" + "[drm] falling back to irq-free operation\n"); + info->irq = 0; + } else { + unsigned char *R128MMIO = info->MMIO; + info->gen_int_cntl = INREG( R128_GEN_INT_CNTL ); + } + } + + if (info->irq) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] dma control initialized, using IRQ %d\n", + info->irq); +} + +/* Initialize the CCE state, and start the CCE (if used by the X server) */ +static void R128DRICCEInit(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + /* Turn on bus mastering */ + info->BusCntl &= ~R128_BUS_MASTER_DIS; + + /* CCEMode is initialized in r128_driver.c */ + switch (info->CCEMode) { + case R128_PM4_NONPM4: info->CCEFifoSize = 0; break; + case R128_PM4_192PIO: info->CCEFifoSize = 192; break; + case R128_PM4_192BM: info->CCEFifoSize = 192; break; + case R128_PM4_128PIO_64INDBM: info->CCEFifoSize = 128; break; + case R128_PM4_128BM_64INDBM: info->CCEFifoSize = 128; break; + case R128_PM4_64PIO_128INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64BM_128INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64PIO_64VCBM_64INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64BM_64VCBM_64INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64; break; + } + + if (info->directRenderingEnabled) { + /* Make sure the CCE is on for the X server */ + R128CCE_START(pScrn, info); + } else { + /* Make sure the CCE is off for the X server */ + R128CCE_STOP(pScrn, info); + } +} + +/* Initialize the screen-specific data structures for the DRI and the + Rage 128. This is the main entry point to the device-specific + initialization code. It calls device-independent DRI functions to + create the DRI data structures and initialize the DRI state. */ +Bool R128DRIScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + DRIInfoPtr pDRIInfo; + R128DRIPtr pR128DRI; + int major, minor, patch; + drmVersionPtr version; + + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for known symbols in each module. */ + if (!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) return FALSE; + if (!xf86LoaderCheckSymbol("DRIScreenInit")) return FALSE; + if (!xf86LoaderCheckSymbol("drmAvailable")) return FALSE; + if (!xf86LoaderCheckSymbol("DRIQueryVersion")) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] R128DRIScreenInit failed (libdri.a too old)\n"); + return FALSE; + } + + /* Check the DRI version */ + DRIQueryVersion(&major, &minor, &patch); + if (major != 4 || minor < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] R128DRIScreenInit failed because of a version mismatch.\n" + "[dri] libDRI version is %d.%d.%d but version 4.0.x is needed.\n" + "[dri] Disabling the DRI.\n", + major, minor, patch); + return FALSE; + } + + switch (info->CurrentLayout.pixel_code) { + case 8: + /* These modes are not supported (yet). */ + case 15: + case 24: + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] R128DRIScreenInit failed (depth %d not supported). " + "[dri] Disabling DRI.\n", info->CurrentLayout.pixel_code); + return FALSE; + + /* Only 16 and 32 color depths are supports currently. */ + case 16: + case 32: + break; + } + + /* Create the DRI data structure, and fill it in before calling the + DRIScreenInit(). */ + if (!(pDRIInfo = DRICreateInfoRec())) return FALSE; + + info->pDRIInfo = pDRIInfo; + pDRIInfo->drmDriverName = R128_DRIVER_NAME; + pDRIInfo->clientDriverName = R128_DRIVER_NAME; + pDRIInfo->busIdString = xalloc(64); + sprintf(pDRIInfo->busIdString, + "PCI:%d:%d:%d", + info->PciInfo->bus, + info->PciInfo->device, + info->PciInfo->func); + pDRIInfo->ddxDriverMajorVersion = R128_VERSION_MAJOR; + pDRIInfo->ddxDriverMinorVersion = R128_VERSION_MINOR; + pDRIInfo->ddxDriverPatchVersion = R128_VERSION_PATCH; + pDRIInfo->frameBufferPhysicalAddress = info->LinearAddr; + pDRIInfo->frameBufferSize = info->FbMapSize; + pDRIInfo->frameBufferStride = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + pDRIInfo->ddxDrawableTableEntry = R128_MAX_DRAWABLES; + pDRIInfo->maxDrawableTableEntry = (SAREA_MAX_DRAWABLES + < R128_MAX_DRAWABLES + ? SAREA_MAX_DRAWABLES + : R128_MAX_DRAWABLES); + +#ifdef NOT_DONE + /* FIXME: Need to extend DRI protocol to pass this size back to + * client for SAREA mapping that includes a device private record + */ + pDRIInfo->SAREASize = + ((sizeof(XF86DRISAREARec) + 0xfff) & 0x1000); /* round to page */ + /* + shared memory device private rec */ +#else + /* For now the mapping works by using a fixed size defined + * in the SAREA header + */ + if (sizeof(XF86DRISAREARec)+sizeof(R128SAREAPriv)>SAREA_MAX) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] Data does not fit in SAREA. Disabling DRI.\n"); + return FALSE; + } + pDRIInfo->SAREASize = SAREA_MAX; +#endif + + if (!(pR128DRI = (R128DRIPtr)xcalloc(sizeof(R128DRIRec),1))) { + DRIDestroyInfoRec(info->pDRIInfo); + info->pDRIInfo = NULL; + return FALSE; + } + pDRIInfo->devPrivate = pR128DRI; + pDRIInfo->devPrivateSize = sizeof(R128DRIRec); + pDRIInfo->contextSize = sizeof(R128DRIContextRec); + + pDRIInfo->CreateContext = R128CreateContext; + pDRIInfo->DestroyContext = R128DestroyContext; + pDRIInfo->SwapContext = R128DRISwapContext; + pDRIInfo->InitBuffers = R128DRIInitBuffers; + pDRIInfo->MoveBuffers = R128DRIMoveBuffers; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + pDRIInfo->TransitionTo2d = R128DRITransitionTo2d; + pDRIInfo->TransitionTo3d = R128DRITransitionTo3d; + pDRIInfo->TransitionSingleToMulti3D = R128DRITransitionSingleToMulti3d; + pDRIInfo->TransitionMultiToSingle3D = R128DRITransitionMultiToSingle3d; + + pDRIInfo->createDummyCtx = TRUE; + pDRIInfo->createDummyCtxPriv = FALSE; + + if (!DRIScreenInit(pScreen, pDRIInfo, &info->drmFD)) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRIScreenInit failed. Disabling DRI.\n"); + xfree(pDRIInfo->devPrivate); + pDRIInfo->devPrivate = NULL; + DRIDestroyInfoRec(pDRIInfo); + pDRIInfo = NULL; + return FALSE; + } + + /* Check the DRM lib version. + drmGetLibVersion was not supported in version 1.0, so check for + symbol first to avoid possible crash or hang. + */ + if (xf86LoaderCheckSymbol("drmGetLibVersion")) { + version = drmGetLibVersion(info->drmFD); + } + else { + /* drmlib version 1.0.0 didn't have the drmGetLibVersion + entry point. Fake it by allocating a version record + via drmGetVersion and changing it to version 1.0.0 + */ + version = drmGetVersion(info->drmFD); + version->version_major = 1; + version->version_minor = 0; + version->version_patchlevel = 0; + } + + if (version) { + if (version->version_major != 1 || + version->version_minor < 1) { + /* incompatible drm library version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] R128DRIScreenInit failed because of a version mismatch.\n" + "[dri] libdrm.a module version is %d.%d.%d but version 1.1.x is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + R128DRICloseScreen(pScreen); + return FALSE; + } + drmFreeVersion(version); + } + + /* Check the r128 DRM version */ + version = drmGetVersion(info->drmFD); + if (version) { + if (version->version_major != 2 || + version->version_minor < 2) { + /* incompatible drm version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] R128DRIScreenInit failed because of a version mismatch.\n" + "[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n" + "[dri] Disabling the DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + R128DRICloseScreen(pScreen); + return FALSE; + } + info->drmMinor = version->version_minor; + drmFreeVersion(version); + } + + /* Initialize AGP */ + if (!info->IsPCI && !R128DRIAgpInit(info, pScreen)) { + info->IsPCI = TRUE; + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[agp] AGP failed to initialize -- falling back to PCI mode.\n"); + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[agp] Make sure you have the agpgart kernel module loaded.\n"); + } + + /* Initialize PCIGART */ + if (info->IsPCI && !R128DRIPciInit(info, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* DRIScreenInit doesn't add all the + common mappings. Add additional + mappings here. */ + if (!R128DRIMapInit(info, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* DRIScreenInit adds the frame buffer + map, but we need it as well */ + { + void *scratch_ptr; + int scratch_int; + + DRIGetDeviceInfo(pScreen, &info->fbHandle, + &scratch_int, &scratch_int, + &scratch_int, &scratch_int, + &scratch_ptr); + } + + /* FIXME: When are these mappings unmapped? */ + + if (!R128InitVisualConfigs(pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Visual configs initialized\n"); + + return TRUE; +} + +/* Finish initializing the device-dependent DRI state, and call + DRIFinishScreenInit() to complete the device-independent DRI + initialization. */ +Bool R128DRIFinishScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + R128SAREAPrivPtr pSAREAPriv; + R128DRIPtr pR128DRI; + + info->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + /* info->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */ + + /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit + because *DRIKernelInit requires that the hardware lock is held by + the X server, and the first time the hardware lock is grabbed is + in DRIFinishScreenInit. */ + if (!DRIFinishScreenInit(pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize the kernel data structures */ + if (!R128DRIKernelInit(info, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize the vertex buffers list */ + if (!R128DRIBufInit(info, pScreen)) { + R128DRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize IRQ */ + R128DRIIrqInit(info, pScreen); + + /* Initialize and start the CCE if required */ + R128DRICCEInit(pScrn); + + pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen); + memset(pSAREAPriv, 0, sizeof(*pSAREAPriv)); + + pR128DRI = (R128DRIPtr)info->pDRIInfo->devPrivate; + + pR128DRI->deviceID = info->Chipset; + pR128DRI->width = pScrn->virtualX; + pR128DRI->height = pScrn->virtualY; + pR128DRI->depth = pScrn->depth; + pR128DRI->bpp = pScrn->bitsPerPixel; + + pR128DRI->IsPCI = info->IsPCI; + pR128DRI->AGPMode = info->agpMode; + + pR128DRI->frontOffset = info->frontOffset; + pR128DRI->frontPitch = info->frontPitch; + pR128DRI->backOffset = info->backOffset; + pR128DRI->backPitch = info->backPitch; + pR128DRI->depthOffset = info->depthOffset; + pR128DRI->depthPitch = info->depthPitch; + pR128DRI->spanOffset = info->spanOffset; + pR128DRI->textureOffset = info->textureOffset; + pR128DRI->textureSize = info->textureSize; + pR128DRI->log2TexGran = info->log2TexGran; + + pR128DRI->registerHandle = info->registerHandle; + pR128DRI->registerSize = info->registerSize; + + pR128DRI->agpTexHandle = info->agpTexHandle; + pR128DRI->agpTexMapSize = info->agpTexMapSize; + pR128DRI->log2AGPTexGran = info->log2AGPTexGran; + pR128DRI->agpTexOffset = info->agpTexStart; + pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec); + + /* Have shadowfb run only while there is 3d active. */ + if (info->allowPageFlip && info->drmMinor >= 5 ) { + ShadowFBInit( pScreen, R128DRIRefreshArea ); + } else if (info->allowPageFlip) { + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[dri] Kernel module version 2.5.0 or newer is required for pageflipping.\n"); + info->allowPageFlip = 0; + } + + return TRUE; +} + +/* The screen is being closed, so clean up any state and free any + resources used by the DRI. */ +void R128DRICloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + drmR128Init drmInfo; + + /* Stop the CCE if it is still in use */ + if (info->directRenderingEnabled) { + R128CCE_STOP(pScrn, info); + } + + if (info->irq) { + drmCtlUninstHandler(info->drmFD); + info->irq = 0; + } + + /* De-allocate vertex buffers */ + if (info->buffers) { + drmUnmapBufs(info->buffers); + info->buffers = NULL; + } + + /* De-allocate all kernel resources */ + memset(&drmInfo, 0, sizeof(drmR128Init)); + drmInfo.func = DRM_R128_CLEANUP_CCE; + drmCommandWrite(info->drmFD, DRM_R128_INIT, + &drmInfo, sizeof(drmR128Init)); + + /* De-allocate all AGP resources */ + if (info->agpTex) { + drmUnmap(info->agpTex, info->agpTexMapSize); + info->agpTex = NULL; + } + if (info->buf) { + drmUnmap(info->buf, info->bufMapSize); + info->buf = NULL; + } + if (info->ringReadPtr) { + drmUnmap(info->ringReadPtr, info->ringReadMapSize); + info->ringReadPtr = NULL; + } + if (info->ring) { + drmUnmap(info->ring, info->ringMapSize); + info->ring = NULL; + } + if (info->agpMemHandle != DRM_AGP_NO_HANDLE) { + drmAgpUnbind(info->drmFD, info->agpMemHandle); + drmAgpFree(info->drmFD, info->agpMemHandle); + info->agpMemHandle = DRM_AGP_NO_HANDLE; + drmAgpRelease(info->drmFD); + } + if (info->pciMemHandle) { + drmScatterGatherFree(info->drmFD, info->pciMemHandle); + info->pciMemHandle = 0; + } + + /* De-allocate all DRI resources */ + DRICloseScreen(pScreen); + + /* De-allocate all DRI data structures */ + if (info->pDRIInfo) { + if (info->pDRIInfo->devPrivate) { + xfree(info->pDRIInfo->devPrivate); + info->pDRIInfo->devPrivate = NULL; + } + DRIDestroyInfoRec(info->pDRIInfo); + info->pDRIInfo = NULL; + } + if (info->pVisualConfigs) { + xfree(info->pVisualConfigs); + info->pVisualConfigs = NULL; + } + if (info->pVisualConfigsPriv) { + xfree(info->pVisualConfigsPriv); + info->pVisualConfigsPriv = NULL; + } +} + +/* Use callbacks from dri.c to support pageflipping mode for a single + * 3d context without need for any specific full-screen extension. + */ + +/* Use the shadowfb module to maintain a list of dirty rectangles. + * These are blitted to the back buffer to keep both buffers clean + * during page-flipping when the 3d application isn't fullscreen. + * + * Unlike most use of the shadowfb code, both buffers are in video memory. + * + * An alternative to this would be to organize for all on-screen drawing + * operations to be duplicated for the two buffers. That might be + * faster, but seems like a lot more work... + */ + + +static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + R128InfoPtr info = R128PTR(pScrn); + int i; + R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + + /* Don't want to do this when no 3d is active and pages are + * right-way-round + */ + if (!pSAREAPriv->pfAllowPageFlip && pSAREAPriv->pfCurrentPage == 0) + return; + + (*info->accel->SetupForScreenToScreenCopy)(pScrn, + 1, 1, GXcopy, + (CARD32)(-1), -1); + + for (i = 0 ; i < num ; i++, pbox++) { + int xa = max(pbox->x1, 0), xb = min(pbox->x2, pScrn->virtualX-1); + int ya = max(pbox->y1, 0), yb = min(pbox->y2, pScrn->virtualY-1); + + if (xa <= xb && ya <= yb) { + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, xa, ya, + xa + info->backX, + ya + info->backY, + xb - xa + 1, + yb - ya + 1); + } + } +} + +static void R128EnablePageFlip(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + if (info->allowPageFlip) { + /* Duplicate the frontbuffer to the backbuffer */ + (*info->accel->SetupForScreenToScreenCopy)(pScrn, + 1, 1, GXcopy, + (CARD32)(-1), -1); + + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, + 0, + 0, + info->backX, + info->backY, + pScrn->virtualX, + pScrn->virtualY); + + pSAREAPriv->pfAllowPageFlip = 1; + } +} + +static void R128DisablePageFlip(ScreenPtr pScreen) +{ + /* Tell the clients not to pageflip. How? + * -- Field in sarea, plus bumping the window counters. + * -- DRM needs to cope with Front-to-Back swapbuffers. + */ + R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + pSAREAPriv->pfAllowPageFlip = 0; +} + +static void R128DRITransitionSingleToMulti3d(ScreenPtr pScreen) +{ + R128DisablePageFlip(pScreen); +} + +static void R128DRITransitionMultiToSingle3d(ScreenPtr pScreen) +{ + /* Let the remaining 3d app start page flipping again */ + R128EnablePageFlip(pScreen); +} + +static void R128DRITransitionTo3d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + R128EnablePageFlip(pScreen); + + info->have3DWindows = 1; + + if (info->cursor_start) + xf86ForceHWCursor(pScreen, TRUE); +} + +static void R128DRITransitionTo2d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + /* Shut down shadowing if we've made it back to the front page */ + if (pSAREAPriv->pfCurrentPage == 0) { + R128DisablePageFlip(pScreen); + } else { + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[dri] R128DRITransitionTo2d: " + "kernel failed to unflip buffers.\n"); + } + + info->have3DWindows = 0; + + if (info->cursor_start) + xf86ForceHWCursor(pScreen, FALSE); +} diff --git a/src/r128_dri.h b/src/r128_dri.h new file mode 100644 index 0000000..64345d3 --- /dev/null +++ b/src/r128_dri.h @@ -0,0 +1,102 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dri.h,v 1.6 2001/03/21 17:02:21 dawes Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Rickard E. Faith <faith@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef _R128_DRI_ +#define _R128_DRI_ + +#include "xf86drm.h" +#include "r128_common.h" + +/* DRI Driver defaults */ +#define R128_DEFAULT_CCE_PIO_MODE R128_PM4_64PIO_64VCBM_64INDBM +#define R128_DEFAULT_CCE_BM_MODE R128_PM4_64BM_64VCBM_64INDBM +#define R128_DEFAULT_AGP_MODE 1 +#define R128_DEFAULT_AGP_SIZE 8 /* MB (must be a power of 2 and > 4MB) */ +#define R128_DEFAULT_RING_SIZE 1 /* MB (must be page aligned) */ +#define R128_DEFAULT_BUFFER_SIZE 2 /* MB (must be page aligned) */ +#define R128_DEFAULT_AGP_TEX_SIZE 1 /* MB (must be page aligned) */ + +#define R128_DEFAULT_CCE_TIMEOUT 10000 /* usecs */ + +#define R128_AGP_MAX_MODE 4 + +#define R128_CARD_TYPE_R128 1 +#define R128_CARD_TYPE_R128_PRO 2 +#define R128_CARD_TYPE_R128_MOBILITY 3 + +#define R128CCE_USE_RING_BUFFER(m) \ +(((m) == R128_PM4_192BM) || \ + ((m) == R128_PM4_128BM_64INDBM) || \ + ((m) == R128_PM4_64BM_128INDBM) || \ + ((m) == R128_PM4_64BM_64VCBM_64INDBM)) + +typedef struct { + /* DRI screen private data */ + int deviceID; /* PCI device ID */ + int width; /* Width in pixels of display */ + int height; /* Height in scanlines of display */ + int depth; /* Depth of display (8, 15, 16, 24) */ + int bpp; /* Bit depth of display (8, 16, 24, 32) */ + + int IsPCI; /* Current card is a PCI card */ + int AGPMode; + + int frontOffset; /* Start of front buffer */ + int frontPitch; + int backOffset; /* Start of shared back buffer */ + int backPitch; + int depthOffset; /* Start of shared depth buffer */ + int depthPitch; + int spanOffset; /* Start of scratch spanline */ + int textureOffset;/* Start of texture data in frame buffer */ + int textureSize; + int log2TexGran; + + /* MMIO register data */ + drmHandle registerHandle; + drmSize registerSize; + + /* CCE AGP Texture data */ + drmHandle agpTexHandle; + drmSize agpTexMapSize; + int log2AGPTexGran; + int agpTexOffset; + unsigned int sarea_priv_offset; +} R128DRIRec, *R128DRIPtr; + +#endif diff --git a/src/r128_dripriv.h b/src/r128_dripriv.h new file mode 100644 index 0000000..043e7bd --- /dev/null +++ b/src/r128_dripriv.h @@ -0,0 +1,58 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dripriv.h,v 1.2 2000/11/09 03:24:35 martin Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef _R128_DRIPRIV_H_ +#define _R128_DRIPRIV_H_ + +#include "GL/glxint.h" + +#define R128_MAX_DRAWABLES 256 + +extern void GlxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **configprivs); + +typedef struct { + /* Nothing here yet */ + int dummy; +} R128ConfigPrivRec, *R128ConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} R128DRIContextRec, *R128DRIContextPtr; + +#endif diff --git a/src/r128_driver.c b/src/r128_driver.c new file mode 100644 index 0000000..cd8b995 --- /dev/null +++ b/src/r128_driver.c @@ -0,0 +1,3675 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_driver.c,v 1.88 2004/01/29 02:51:17 dawes Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + * Credits: + * + * Thanks to Alan Hourihane <alanh@fairlite.demon..co.uk> and SuSE for + * providing source code to their 3.3.x Rage 128 driver. Portions of + * this file are based on the initialization code for that driver. + * + * References: + * + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + * This server does not yet support these XFree86 4.0 features: + * DDC1 & DDC2 + * shadowfb + * overlay planes + * + * Modified by Marc Aurele La France <tsi@xfree86.org> for ATI driver merge. + */ + + + /* Driver data structures */ +#include "r128.h" +#include "r128_probe.h" +#include "r128_reg.h" +#include "r128_version.h" + +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "r128_dri.h" +#include "r128_sarea.h" +#endif + +#include "fb.h" + + /* colormap initialization */ +#include "micmap.h" + + /* X and server generic header files */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86PciInfo.h" +#include "xf86RAC.h" +#include "xf86Resources.h" +#include "xf86cmap.h" +#include "xf86xv.h" +#include "vbe.h" + + /* fbdevhw & vgahw */ +#include "fbdevhw.h" +#include "vgaHW.h" +#include "dixstruct.h" + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +#define USE_CRT_ONLY 0 + + /* Forward definitions for driver functions */ +static Bool R128CloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool R128SaveScreen(ScreenPtr pScreen, int mode); +static void R128Save(ScrnInfoPtr pScrn); +static void R128Restore(ScrnInfoPtr pScrn); +static Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); +static void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); +static void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); + +typedef enum { + OPTION_NOACCEL, + OPTION_SW_CURSOR, + OPTION_DAC_6BIT, + OPTION_DAC_8BIT, +#ifdef XF86DRI + OPTION_XV_DMA, + OPTION_IS_PCI, + OPTION_CCE_PIO, + OPTION_NO_SECURITY, + OPTION_USEC_TIMEOUT, + OPTION_AGP_MODE, + OPTION_AGP_SIZE, + OPTION_RING_SIZE, + OPTION_BUFFER_SIZE, + OPTION_PAGE_FLIP, +#endif +#if USE_CRT_ONLY + /* FIXME: Disable CRTOnly until it is tested */ + OPTION_CRT, +#endif + OPTION_DISPLAY, + OPTION_PANEL_WIDTH, + OPTION_PANEL_HEIGHT, + OPTION_PROG_FP_REGS, + OPTION_FBDEV, + OPTION_VIDEO_KEY, + OPTION_SHOW_CACHE +} R128Opts; + +const OptionInfoRec R128Options[] = { + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DAC_8BIT, "Dac8Bit", OPTV_BOOLEAN, {0}, TRUE }, +#ifdef XF86DRI + { OPTION_XV_DMA, "DMAForXv", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_IS_PCI, "ForcePCIMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_CCE_PIO, "CCEPIOMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NO_SECURITY, "CCENoSecurity", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_USEC_TIMEOUT, "CCEusecTimeout", OPTV_INTEGER, {0}, FALSE }, + { OPTION_AGP_MODE, "AGPMode", OPTV_INTEGER, {0}, FALSE }, + { OPTION_AGP_SIZE, "AGPSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_RING_SIZE, "RingSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_BUFFER_SIZE, "BufferSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE }, +#endif + { OPTION_DISPLAY, "Display", OPTV_STRING, {0}, FALSE }, + { OPTION_PANEL_WIDTH, "PanelWidth", OPTV_INTEGER, {0}, FALSE }, + { OPTION_PANEL_HEIGHT, "PanelHeight", OPTV_INTEGER, {0}, FALSE }, + { OPTION_PROG_FP_REGS, "ProgramFPRegs", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, + { OPTION_SHOW_CACHE, "ShowCache", OPTV_BOOLEAN, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +R128RAMRec R128RAM[] = { /* Memory Specifications + From RAGE 128 Software Development + Manual (Technical Reference Manual P/N + SDK-G04000 Rev 0.01), page 3-21. */ + { 4, 4, 3, 3, 1, 3, 1, 16, 12, "128-bit SDR SGRAM 1:1" }, + { 4, 8, 3, 3, 1, 3, 1, 17, 13, "64-bit SDR SGRAM 1:1" }, + { 4, 4, 1, 2, 1, 2, 1, 16, 12, "64-bit SDR SGRAM 2:1" }, + { 4, 4, 3, 3, 2, 3, 1, 16, 12, "64-bit DDR SGRAM" }, +}; + +static const char *vgahwSymbols[] = { + "vgaHWFreeHWRec", + "vgaHWGetHWRec", + "vgaHWGetIndex", + "vgaHWLock", + "vgaHWRestore", + "vgaHWSave", + "vgaHWUnlock", + NULL +}; + +static const char *fbdevHWSymbols[] = { + "fbdevHWInit", + "fbdevHWUseBuildinMode", + "fbdevHWGetLineLength", + "fbdevHWGetVidmem", + + "fbdevHWDPMSSet", + + /* colormap */ + "fbdevHWLoadPalette", + + /* ScrnInfo hooks */ + "fbdevHWAdjustFrame", + "fbdevHWEnterVT", + "fbdevHWLeaveVT", + "fbdevHWModeInit", + "fbdevHWRestore", + "fbdevHWSave", + "fbdevHWSwitchMode", + "fbdevHWValidMode", + + "fbdevHWMapMMIO", + "fbdevHWMapVidmem", + "fbdevHWUnmapMMIO", + "fbdevHWUnmapVidmem", + + NULL +}; + +static const char *ddcSymbols[] = { + "xf86PrintEDID", + "xf86DoEDID_DDC1", + "xf86DoEDID_DDC2", + NULL +}; + +static const char *i2cSymbols[] = { + "xf86CreateI2CBusRec", + "xf86I2CBusInit", + NULL +}; + +static const char *fbSymbols[] = { + "fbPictureInit", + "fbScreenInit", + NULL +}; + +static const char *xaaSymbols[] = { + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAInit", + NULL +}; + +static const char *ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +#ifdef XF86DRI +static const char *drmSymbols[] = { + "drmAddBufs", + "drmAddMap", + "drmAgpAcquire", + "drmAgpAlloc", + "drmAgpBase", + "drmAgpBind", + "drmAgpDeviceId", + "drmAgpEnable", + "drmAgpFree", + "drmAgpGetMode", + "drmAgpRelease", + "drmAgpUnbind", + "drmAgpVendorId", + "drmAvailable", + "drmCommandNone", + "drmCommandRead", + "drmCommandWrite", + "drmCommandWriteRead", + "drmCtlInstHandler", + "drmCtlUninstHandler", + "drmFreeBufs", + "drmFreeVersion", + "drmGetInterruptFromBusID", + "drmGetLibVersion", + "drmGetVersion", + "drmMap", + "drmMapBufs", + "drmDMA", + "drmScatterGatherAlloc", + "drmScatterGatherFree", + "drmUnmap", + "drmUnmapBufs", + NULL +}; + +static const char *driSymbols[] = { + "DRICloseScreen", + "DRICreateInfoRec", + "DRIDestroyInfoRec", + "DRIFinishScreenInit", + "DRIGetDeviceInfo", + "DRIGetSAREAPrivate", + "DRILock", + "DRIQueryVersion", + "DRIScreenInit", + "DRIUnlock", + "GlxSetVisualConfigs", + NULL +}; + +static const char *driShadowFBSymbols[] = { + "ShadowFBInit", + NULL +}; +#endif + +static const char *vbeSymbols[] = { + "VBEInit", + "vbeDoEDID", + "vbeFree", + NULL +}; + +static const char *int10Symbols[] = { + "xf86InitInt10", + "xf86FreeInt10", + "xf86int10Addr", + NULL +}; + +void R128LoaderRefSymLists(void) +{ + /* + * Tell the loader about symbols from other modules that this module might + * refer to. + */ + xf86LoaderRefSymLists(vgahwSymbols, + fbSymbols, + xaaSymbols, + ramdacSymbols, +#ifdef XF86DRI + drmSymbols, + driSymbols, + driShadowFBSymbols, +#endif + fbdevHWSymbols, + int10Symbols, + vbeSymbols, + /* ddcsymbols, */ + i2cSymbols, + /* shadowSymbols, */ + NULL); +} + +/* Allocate our private R128InfoRec. */ +static Bool R128GetRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate) return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(R128InfoRec), 1); + return TRUE; +} + +/* Free our private R128InfoRec. */ +static void R128FreeRec(ScrnInfoPtr pScrn) +{ + if (!pScrn || !pScrn->driverPrivate) return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +/* Memory map the MMIO region. Used during pre-init and by R128MapMem, + below. */ +static Bool R128MapMMIO(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (info->FBDev) { + info->MMIO = fbdevHWMapMMIO(pScrn); + } else { + info->MMIO = xf86MapPciMem(pScrn->scrnIndex, + VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, + info->PciTag, + info->MMIOAddr, + R128_MMIOSIZE); + } + + if (!info->MMIO) return FALSE; + return TRUE; +} + +/* Unmap the MMIO region. Used during pre-init and by R128UnmapMem, + below. */ +static Bool R128UnmapMMIO(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (info->FBDev) + fbdevHWUnmapMMIO(pScrn); + else { + xf86UnMapVidMem(pScrn->scrnIndex, info->MMIO, R128_MMIOSIZE); + } + info->MMIO = NULL; + return TRUE; +} + +/* Memory map the frame buffer. Used by R128MapMem, below. */ +static Bool R128MapFB(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (info->FBDev) { + info->FB = fbdevHWMapVidmem(pScrn); + } else { + info->FB = xf86MapPciMem(pScrn->scrnIndex, + VIDMEM_FRAMEBUFFER, + info->PciTag, + info->LinearAddr, + info->FbMapSize); + } + + if (!info->FB) return FALSE; + return TRUE; +} + +/* Unmap the frame buffer. Used by R128UnmapMem, below. */ +static Bool R128UnmapFB(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (info->FBDev) + fbdevHWUnmapVidmem(pScrn); + else + xf86UnMapVidMem(pScrn->scrnIndex, info->FB, info->FbMapSize); + info->FB = NULL; + return TRUE; +} + +/* Memory map the MMIO region and the frame buffer. */ +static Bool R128MapMem(ScrnInfoPtr pScrn) +{ + if (!R128MapMMIO(pScrn)) return FALSE; + if (!R128MapFB(pScrn)) { + R128UnmapMMIO(pScrn); + return FALSE; + } + return TRUE; +} + +/* Unmap the MMIO region and the frame buffer. */ +static Bool R128UnmapMem(ScrnInfoPtr pScrn) +{ + if (!R128UnmapMMIO(pScrn) || !R128UnmapFB(pScrn)) return FALSE; + return TRUE; +} + +/* Read PLL information */ +unsigned R128INPLL(ScrnInfoPtr pScrn, int addr) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREG8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); + return INREG(R128_CLOCK_CNTL_DATA); +} + +#if 0 +/* Read PAL information (only used for debugging). */ +static int R128INPAL(int idx) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREG(R128_PALETTE_INDEX, idx << 16); + return INREG(R128_PALETTE_DATA); +} +#endif + +/* Wait for vertical sync. */ +void R128WaitForVerticalSync(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + OUTREG(R128_GEN_INT_STATUS, R128_VSYNC_INT_AK); + for (i = 0; i < R128_TIMEOUT; i++) { + if (INREG(R128_GEN_INT_STATUS) & R128_VSYNC_INT) break; + } +} + +/* Blank screen. */ +static void R128Blank(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + if(info->isDFP) + OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS); + else + OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS); +} + +/* Unblank screen. */ +static void R128Unblank(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + if(info->isDFP) + OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS); + else + OUTREGP(R128_CRTC_EXT_CNTL, 0, ~(R128_CRTC_DISPLAY_DIS | + R128_CRTC_VSYNC_DIS | + R128_CRTC_HSYNC_DIS)); +} + +/* Compute log base 2 of val. */ +int R128MinBits(int val) +{ + int bits; + + if (!val) return 1; + for (bits = 0; val; val >>= 1, ++bits); + return bits; +} + +/* Compute n/d with rounding. */ +static int R128Div(int n, int d) +{ + return (n + (d / 2)) / d; +} + +/* Read the Video BIOS block and the FP registers (if applicable). */ +static Bool R128GetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) +{ + R128InfoPtr info = R128PTR(pScrn); + int i; + int FPHeader = 0; + +#define R128_BIOS8(v) (info->VBIOS[v]) +#define R128_BIOS16(v) (info->VBIOS[v] | \ + (info->VBIOS[(v) + 1] << 8)) +#define R128_BIOS32(v) (info->VBIOS[v] | \ + (info->VBIOS[(v) + 1] << 8) | \ + (info->VBIOS[(v) + 2] << 16) | \ + (info->VBIOS[(v) + 3] << 24)) + + if (!(info->VBIOS = xalloc(R128_VBIOS_SIZE))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Cannot allocate space for hold Video BIOS!\n"); + return FALSE; + } + + if (pInt10) { + info->BIOSAddr = pInt10->BIOSseg << 4; + (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr), + R128_VBIOS_SIZE); + } else { + xf86ReadPciBIOS(0, info->PciTag, 0, info->VBIOS, R128_VBIOS_SIZE); + if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Video BIOS not detected in PCI space!\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Attempting to read Video BIOS from legacy ISA space!\n"); + info->BIOSAddr = 0x000c0000; + xf86ReadDomainMemory(info->PciTag, info->BIOSAddr, R128_VBIOS_SIZE, info->VBIOS); + } + } + if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { + info->BIOSAddr = 0x00000000; + xfree(info->VBIOS); + info->VBIOS = NULL; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Video BIOS not found!\n"); + } + + if (info->VBIOS && info->HasPanelRegs) { + info->FPBIOSstart = 0; + + /* FIXME: There should be direct access to the start of the FP info + tables, but until we find out where that offset is stored, we + must search for the ATI signature string: "M3 ". */ + for (i = 4; i < R128_VBIOS_SIZE-8; i++) { + if (R128_BIOS8(i) == 'M' && + R128_BIOS8(i+1) == '3' && + R128_BIOS8(i+2) == ' ' && + R128_BIOS8(i+3) == ' ' && + R128_BIOS8(i+4) == ' ' && + R128_BIOS8(i+5) == ' ' && + R128_BIOS8(i+6) == ' ' && + R128_BIOS8(i+7) == ' ') { + FPHeader = i-2; + break; + } + } + + if (!FPHeader) return TRUE; + + /* Assume that only one panel is attached and supported */ + for (i = FPHeader+20; i < FPHeader+84; i += 2) { + if (R128_BIOS16(i) != 0) { + info->FPBIOSstart = R128_BIOS16(i); + break; + } + } + if (!info->FPBIOSstart) return TRUE; + + if (!info->PanelXRes) + info->PanelXRes = R128_BIOS16(info->FPBIOSstart+25); + if (!info->PanelYRes) + info->PanelYRes = R128_BIOS16(info->FPBIOSstart+27); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel size: %dx%d\n", + info->PanelXRes, info->PanelYRes); + + info->PanelPwrDly = R128_BIOS8(info->FPBIOSstart+56); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel ID: "); + for (i = 1; i <= 24; i++) + ErrorF("%c", R128_BIOS8(info->FPBIOSstart+i)); + ErrorF("\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel Type: "); + i = R128_BIOS16(info->FPBIOSstart+29); + if (i & 1) ErrorF("Color, "); + else ErrorF("Monochrome, "); + if (i & 2) ErrorF("Dual(split), "); + else ErrorF("Single, "); + switch ((i >> 2) & 0x3f) { + case 0: ErrorF("STN"); break; + case 1: ErrorF("TFT"); break; + case 2: ErrorF("Active STN"); break; + case 3: ErrorF("EL"); break; + case 4: ErrorF("Plasma"); break; + default: ErrorF("UNKNOWN"); break; + } + ErrorF("\n"); + if (R128_BIOS8(info->FPBIOSstart+61) & 1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel Interface: LVDS\n"); + } else { + /* FIXME: Add Non-LVDS flat pael support */ + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Non-LVDS panel interface detected! " + "This support is untested and may not " + "function properly\n"); + } + } + + if (!info->PanelXRes || !info->PanelYRes) { + info->HasPanelRegs = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Can't determine panel dimensions, and none specified. \ + Disabling programming of FP registers.\n"); + } + + return TRUE; +} + +/* Read PLL parameters from BIOS block. Default to typical values if there + is no BIOS. */ +static Bool R128GetPLLParameters(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + R128PLLPtr pll = &info->pll; + +#if defined(__powerpc__) || defined(__alpha__) + /* there is no bios under Linux PowerPC but Open Firmware + does set up the PLL registers properly and we can use + those to calculate xclk and find the reference divider */ + + unsigned x_mpll_ref_fb_div; + unsigned xclk_cntl; + unsigned Nx, M; + unsigned PostDivSet[] = {0, 1, 2, 4, 8, 3, 6, 12}; + + /* Assume REF clock is 2950 (in units of 10khz) */ + /* and that all pllclk must be between 125 Mhz and 250Mhz */ + pll->reference_freq = 2950; + pll->min_pll_freq = 12500; + pll->max_pll_freq = 25000; + + /* need to memory map the io to use INPLL since it + has not been done yet at this point in the startup */ + R128MapMMIO(pScrn); + x_mpll_ref_fb_div = INPLL(pScrn, R128_X_MPLL_REF_FB_DIV); + xclk_cntl = INPLL(pScrn, R128_XCLK_CNTL) & 0x7; + pll->reference_div = + INPLL(pScrn,R128_PPLL_REF_DIV) & R128_PPLL_REF_DIV_MASK; + /* unmap it again */ + R128UnmapMMIO(pScrn); + + Nx = (x_mpll_ref_fb_div & 0x00FF00) >> 8; + M = (x_mpll_ref_fb_div & 0x0000FF); + + pll->xclk = R128Div((2 * Nx * pll->reference_freq), + (M * PostDivSet[xclk_cntl])); + +#else /* !defined(__powerpc__) */ + + if (!info->VBIOS) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Video BIOS not detected, using default PLL parameters!\n"); + /* These probably aren't going to work for + the card you are using. Specifically, + reference freq can be 29.50MHz, + 28.63MHz, or 14.32MHz. YMMV. */ + pll->reference_freq = 2950; + pll->reference_div = 65; + pll->min_pll_freq = 12500; + pll->max_pll_freq = 25000; + pll->xclk = 10300; + } else { + CARD16 bios_header = R128_BIOS16(0x48); + CARD16 pll_info_block = R128_BIOS16(bios_header + 0x30); + R128TRACE(("Header at 0x%04x; PLL Information at 0x%04x\n", + bios_header, pll_info_block)); + + pll->reference_freq = R128_BIOS16(pll_info_block + 0x0e); + pll->reference_div = R128_BIOS16(pll_info_block + 0x10); + pll->min_pll_freq = R128_BIOS32(pll_info_block + 0x12); + pll->max_pll_freq = R128_BIOS32(pll_info_block + 0x16); + pll->xclk = R128_BIOS16(pll_info_block + 0x08); + } +#endif /* __powerpc__ */ + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "PLL parameters: rf=%d rd=%d min=%d max=%d; xclk=%d\n", + pll->reference_freq, + pll->reference_div, + pll->min_pll_freq, + pll->max_pll_freq, + pll->xclk); + + return TRUE; +} + +/* This is called by R128PreInit to set up the default visual. */ +static Bool R128PreInitVisual(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, (Support24bppFb + | Support32bppFb + | SupportConvert32to24 + ))) + return FALSE; + + 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 %s driver\n", + pScrn->depth, R128_DRIVER_NAME); + return FALSE; + } + + xf86PrintDepthBpp(pScrn); + + info->fifo_slots = 0; + info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth); + info->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; + info->CurrentLayout.depth = pScrn->depth; + info->CurrentLayout.pixel_bytes = pScrn->bitsPerPixel / 8; + info->CurrentLayout.pixel_code = (pScrn->bitsPerPixel != 16 + ? pScrn->bitsPerPixel + : pScrn->depth); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n", + pScrn->depth, + info->CurrentLayout.pixel_bytes, + info->CurrentLayout.pixel_bytes > 1 ? "s" : "", + info->pix24bpp); + + + if (!xf86SetDefaultVisual(pScrn, -1)) return FALSE; + + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Default visual (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + return FALSE; + } + return TRUE; + +} + +/* This is called by R128PreInit to handle all color weight issues. */ +static Bool R128PreInitWeight(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + /* Save flag for 6 bit DAC to use for + setting CRTC registers. Otherwise use + an 8 bit DAC, even if xf86SetWeight sets + pScrn->rgbBits to some value other than + 8. */ + info->dac6bits = FALSE; + if (pScrn->depth > 8) { + rgb defaultWeight = { 0, 0, 0 }; + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) return FALSE; + } else { + pScrn->rgbBits = 8; + if (xf86ReturnOptValBool(info->Options, OPTION_DAC_6BIT, FALSE)) { + pScrn->rgbBits = 6; + info->dac6bits = TRUE; + } + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d bits per RGB (%d bit DAC)\n", + pScrn->rgbBits, info->dac6bits ? 6 : 8); + + return TRUE; + +} + +/* This is called by R128PreInit to handle config file overrides for things + like chipset and memory regions. Also determine memory size and type. + If memory type ever needs an override, put it in this routine. */ +static Bool R128PreInitConfig(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + EntityInfoPtr pEnt = info->pEnt; + GDevPtr dev = pEnt->device; + int offset = 0; /* RAM Type */ + MessageType from; + + /* Chipset */ + from = X_PROBED; + if (dev->chipset && *dev->chipset) { + info->Chipset = xf86StringToToken(R128Chipsets, dev->chipset); + from = X_CONFIG; + } else if (dev->chipID >= 0) { + info->Chipset = dev->chipID; + from = X_CONFIG; + } else { + info->Chipset = info->PciInfo->chipType; + } + pScrn->chipset = (char *)xf86TokenToString(R128Chipsets, info->Chipset); + + if (!pScrn->chipset) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ChipID 0x%04x is not recognized\n", info->Chipset); + return FALSE; + } + + if (info->Chipset < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Chipset \"%s\" is not recognized\n", pScrn->chipset); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, from, + "Chipset: \"%s\" (ChipID = 0x%04x)\n", + pScrn->chipset, + info->Chipset); + + /* Framebuffer */ + + from = X_PROBED; + info->LinearAddr = info->PciInfo->memBase[0] & 0xfc000000; + pScrn->memPhysBase = info->LinearAddr; + if (dev->MemBase) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Linear address override, using 0x%08lx instead of 0x%08lx\n", + dev->MemBase, + info->LinearAddr); + info->LinearAddr = dev->MemBase; + from = X_CONFIG; + } else if (!info->LinearAddr) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid linear framebuffer address\n"); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, from, + "Linear framebuffer at 0x%08lx\n", info->LinearAddr); + + /* MMIO registers */ + from = X_PROBED; + info->MMIOAddr = info->PciInfo->memBase[2] & 0xffffff00; + if (dev->IOBase) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "MMIO address override, using 0x%08lx instead of 0x%08lx\n", + dev->IOBase, + info->MMIOAddr); + info->MMIOAddr = dev->IOBase; + from = X_CONFIG; + } else if (!info->MMIOAddr) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address\n"); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, from, + "MMIO registers at 0x%08lx\n", info->MMIOAddr); + + /* BIOS */ + from = X_PROBED; + info->BIOSAddr = info->PciInfo->biosBase & 0xfffe0000; + if (dev->BiosBase) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS address override, using 0x%08lx instead of 0x%08lx\n", + dev->BiosBase, + info->BIOSAddr); + info->BIOSAddr = dev->BiosBase; + from = X_CONFIG; + } + if (info->BIOSAddr) { + xf86DrvMsg(pScrn->scrnIndex, from, + "BIOS at 0x%08lx\n", info->BIOSAddr); + } + + /* Flat panel (part 1) */ + if (xf86GetOptValBool(info->Options, OPTION_PROG_FP_REGS, + &info->HasPanelRegs)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Turned flat panel register programming %s\n", + info->HasPanelRegs ? "on" : "off"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "\n\nWARNING: Forcing the driver to use/not use the flat panel registers\nmight damage your flat panel. Use at your *OWN* *RISK*.\n\n"); + } else { + info->isDFP = FALSE; + info->isPro2 = FALSE; + switch (info->Chipset) { + /* R128 Pro and Pro2 can have DFP, we will deal with it. + No support for dual-head/xinerama yet. + M3 can also have DFP, no support for now */ + case PCI_CHIP_RAGE128TF: + case PCI_CHIP_RAGE128TL: + case PCI_CHIP_RAGE128TR: + /* FIXME: RAGE128 TS/TT/TU are assumed to be PRO2 as all 6 chips came + * out at the same time, so are of the same family likely. + * This requires confirmation however to be fully correct. + * Mike A. Harris <mharris@redhat.com> + */ + case PCI_CHIP_RAGE128TS: + case PCI_CHIP_RAGE128TT: + case PCI_CHIP_RAGE128TU: info->isPro2 = TRUE; + /* FIXME: RAGE128 P[ABCEGHIJKLMNOQSTUVWX] are assumed to have DFP + * capability, as the comment at the top suggests. + * This requires confirmation however to be fully correct. + * Mike A. Harris <mharris@redhat.com> + */ + case PCI_CHIP_RAGE128PA: + case PCI_CHIP_RAGE128PB: + case PCI_CHIP_RAGE128PC: + case PCI_CHIP_RAGE128PE: + case PCI_CHIP_RAGE128PG: + case PCI_CHIP_RAGE128PH: + case PCI_CHIP_RAGE128PI: + case PCI_CHIP_RAGE128PJ: + case PCI_CHIP_RAGE128PK: + case PCI_CHIP_RAGE128PL: + case PCI_CHIP_RAGE128PM: + case PCI_CHIP_RAGE128PN: + case PCI_CHIP_RAGE128PO: + case PCI_CHIP_RAGE128PQ: + case PCI_CHIP_RAGE128PS: + case PCI_CHIP_RAGE128PT: + case PCI_CHIP_RAGE128PU: + case PCI_CHIP_RAGE128PV: + case PCI_CHIP_RAGE128PW: + case PCI_CHIP_RAGE128PX: + + case PCI_CHIP_RAGE128PD: + case PCI_CHIP_RAGE128PF: + case PCI_CHIP_RAGE128PP: + case PCI_CHIP_RAGE128PR: info->isDFP = TRUE; break; + + case PCI_CHIP_RAGE128LE: + case PCI_CHIP_RAGE128LF: + case PCI_CHIP_RAGE128MF: + case PCI_CHIP_RAGE128ML: info->HasPanelRegs = TRUE; break; + case PCI_CHIP_RAGE128RE: + case PCI_CHIP_RAGE128RF: + case PCI_CHIP_RAGE128RG: + case PCI_CHIP_RAGE128RK: + case PCI_CHIP_RAGE128RL: + case PCI_CHIP_RAGE128SM: + /* FIXME: RAGE128 S[EFGHKLN] are assumed to be like the SM above as + * all of them are listed as "Rage 128 4x" in ATI docs. + * This requires confirmation however to be fully correct. + * Mike A. Harris <mharris@redhat.com> + */ + case PCI_CHIP_RAGE128SE: + case PCI_CHIP_RAGE128SF: + case PCI_CHIP_RAGE128SG: + case PCI_CHIP_RAGE128SH: + case PCI_CHIP_RAGE128SK: + case PCI_CHIP_RAGE128SL: + case PCI_CHIP_RAGE128SN: + default: info->HasPanelRegs = FALSE; break; + } + } + + /* Read registers used to determine options */ + from = X_PROBED; + R128MapMMIO(pScrn); + R128MMIO = info->MMIO; + + if (info->FBDev) + pScrn->videoRam = fbdevHWGetVidmem(pScrn) / 1024; + else + pScrn->videoRam = INREG(R128_CONFIG_MEMSIZE) / 1024; + + info->MemCntl = INREG(R128_MEM_CNTL); + info->BusCntl = INREG(R128_BUS_CNTL); + + /* On non-flat panel systems, the default is to display to the CRT, + and on flat panel systems, the default is to display to the flat + panel unless the user explicity chooses otherwise using the "Display" + config file setting. BIOS_5_SCRATCH holds the display device on flat + panel systems only. */ + if (info->HasPanelRegs) { + char *Display = xf86GetOptValString(info->Options, OPTION_DISPLAY); + + if (info->FBDev) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Option \"Display\" ignored " + "(framebuffer device determines display type)\n"); + else if (!Display || !xf86NameCmp(Display, "FP")) + info->BIOSDisplay = R128_BIOS_DISPLAY_FP; + else if (!xf86NameCmp(Display, "BIOS")) + info->BIOSDisplay = INREG8(R128_BIOS_5_SCRATCH); + else if (!xf86NameCmp(Display, "Mirror")) + info->BIOSDisplay = R128_BIOS_DISPLAY_FP_CRT; + else if (!xf86NameCmp(Display, "CRT")) + info->BIOSDisplay = R128_BIOS_DISPLAY_CRT; + else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported type \"%s\" specified for Option \"Display\".\n" + "\tSupported types are: " + "\"BIOS\", \"Mirror\", \"CRT\" and \"FP\"\n", Display); + return FALSE; + } + } else { + info->BIOSDisplay = R128_BIOS_DISPLAY_CRT; + } + + R128MMIO = NULL; + R128UnmapMMIO(pScrn); + + /* RAM */ + switch (info->MemCntl & 0x3) { + case 0: /* SDR SGRAM 1:1 */ + switch (info->Chipset) { + case PCI_CHIP_RAGE128TF: + case PCI_CHIP_RAGE128TL: + case PCI_CHIP_RAGE128TR: + case PCI_CHIP_RAGE128LE: + case PCI_CHIP_RAGE128LF: + case PCI_CHIP_RAGE128MF: + case PCI_CHIP_RAGE128ML: + case PCI_CHIP_RAGE128RE: + case PCI_CHIP_RAGE128RF: + case PCI_CHIP_RAGE128RG: offset = 0; break; /* 128-bit SDR SGRAM 1:1 */ + case PCI_CHIP_RAGE128RK: + case PCI_CHIP_RAGE128RL: + case PCI_CHIP_RAGE128SM: + default: offset = 1; break; /* 64-bit SDR SGRAM 1:1 */ + } + break; + case 1: offset = 2; break; /* 64-bit SDR SGRAM 2:1 */ + case 2: offset = 3; break; /* 64-bit DDR SGRAM */ + default: offset = 1; break; /* 64-bit SDR SGRAM 1:1 */ + } + info->ram = &R128RAM[offset]; + + if (dev->videoRam) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Video RAM override, using %d kB instead of %d kB\n", + dev->videoRam, + pScrn->videoRam); + from = X_CONFIG; + pScrn->videoRam = dev->videoRam; + } + pScrn->videoRam &= ~1023; + info->FbMapSize = pScrn->videoRam * 1024; + xf86DrvMsg(pScrn->scrnIndex, from, + "VideoRAM: %d kByte (%s)\n", pScrn->videoRam, info->ram->name); + + /* Flat panel (part 2) */ + switch (info->BIOSDisplay) { + case R128_BIOS_DISPLAY_FP: + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using flat panel for display\n"); + break; + case R128_BIOS_DISPLAY_CRT: + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using external CRT for display\n"); + break; + case R128_BIOS_DISPLAY_FP_CRT: + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using both flat panel and external CRT " + "for display\n"); + break; + } + + if (info->HasPanelRegs) { + /* Panel width/height overrides */ + info->PanelXRes = 0; + info->PanelYRes = 0; + if (xf86GetOptValInteger(info->Options, + OPTION_PANEL_WIDTH, &(info->PanelXRes))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Flat panel width: %d\n", info->PanelXRes); + } + if (xf86GetOptValInteger(info->Options, + OPTION_PANEL_HEIGHT, &(info->PanelYRes))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Flat panel height: %d\n", info->PanelYRes); + } + } + +#ifdef XF86DRI + /* DMA for Xv */ + info->DMAForXv = xf86ReturnOptValBool(info->Options, OPTION_XV_DMA, FALSE); + if (info->DMAForXv) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Will try to use DMA for Xv image transfers\n"); + } + + /* AGP/PCI */ + if (xf86ReturnOptValBool(info->Options, OPTION_IS_PCI, FALSE)) { + info->IsPCI = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI-only mode\n"); + } else { + switch (info->Chipset) { + case PCI_CHIP_RAGE128LE: + case PCI_CHIP_RAGE128RE: + case PCI_CHIP_RAGE128RK: + case PCI_CHIP_RAGE128PD: + case PCI_CHIP_RAGE128PR: + case PCI_CHIP_RAGE128PP: info->IsPCI = TRUE; break; + case PCI_CHIP_RAGE128LF: + case PCI_CHIP_RAGE128MF: + case PCI_CHIP_RAGE128ML: + case PCI_CHIP_RAGE128PF: + case PCI_CHIP_RAGE128RF: + case PCI_CHIP_RAGE128RG: + case PCI_CHIP_RAGE128RL: + case PCI_CHIP_RAGE128SM: + case PCI_CHIP_RAGE128TF: + case PCI_CHIP_RAGE128TL: + case PCI_CHIP_RAGE128TR: + /* FIXME: Rage 128 S[EFGHKLN], T[STU], P[ABCEGHIJKLMNOQSTUVWX] are + * believed to be AGP, but need confirmation. <mharris@redhat.com> + */ + case PCI_CHIP_RAGE128PA: + case PCI_CHIP_RAGE128PB: + case PCI_CHIP_RAGE128PC: + case PCI_CHIP_RAGE128PE: + case PCI_CHIP_RAGE128PG: + case PCI_CHIP_RAGE128PH: + case PCI_CHIP_RAGE128PI: + case PCI_CHIP_RAGE128PJ: + case PCI_CHIP_RAGE128PK: + case PCI_CHIP_RAGE128PL: + case PCI_CHIP_RAGE128PM: + case PCI_CHIP_RAGE128PN: + case PCI_CHIP_RAGE128PO: + case PCI_CHIP_RAGE128PQ: + case PCI_CHIP_RAGE128PS: + case PCI_CHIP_RAGE128PT: + case PCI_CHIP_RAGE128PU: + case PCI_CHIP_RAGE128PV: + case PCI_CHIP_RAGE128PW: + case PCI_CHIP_RAGE128PX: + case PCI_CHIP_RAGE128TS: + case PCI_CHIP_RAGE128TT: + case PCI_CHIP_RAGE128TU: + case PCI_CHIP_RAGE128SE: + case PCI_CHIP_RAGE128SF: + case PCI_CHIP_RAGE128SG: + case PCI_CHIP_RAGE128SH: + case PCI_CHIP_RAGE128SK: + case PCI_CHIP_RAGE128SL: + case PCI_CHIP_RAGE128SN: + default: info->IsPCI = FALSE; break; + } + } +#endif + + return TRUE; +} + +static Bool R128PreInitDDC(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) +{ + R128InfoPtr info = R128PTR(pScrn); + vbeInfoPtr pVbe; + + if (!xf86LoadSubModule(pScrn, "ddc")) return FALSE; + xf86LoaderReqSymLists(ddcSymbols, NULL); + +#if defined(__powerpc__) || defined(__alpha__) + /* Int10 is broken on PPC and some Alphas */ + return TRUE; +#else + if (xf86LoadSubModule(pScrn, "vbe")) { + xf86LoaderReqSymLists(vbeSymbols,NULL); + pVbe = VBEInit(pInt10,info->pEnt->index); + if (!pVbe) return FALSE; + xf86SetDDCproperties(pScrn,xf86PrintEDID(vbeDoEDID(pVbe,NULL))); + vbeFree(pVbe); + return TRUE; + } else + return FALSE; +#endif +} + +/* This is called by R128PreInit to initialize gamma correction. */ +static Bool R128PreInitGamma(ScrnInfoPtr pScrn) +{ + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) return FALSE; + return TRUE; +} + +static void +R128I2CGetBits(I2CBusPtr b, int *Clock, int *data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + unsigned long val; + unsigned char *R128MMIO = info->MMIO; + + /* Get the result. */ + val = INREG(info->DDCReg); + *Clock = (val & R128_GPIO_MONID_Y_3) != 0; + *data = (val & R128_GPIO_MONID_Y_0) != 0; + +} + +static void +R128I2CPutBits(I2CBusPtr b, int Clock, int data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + unsigned long val; + unsigned char *R128MMIO = info->MMIO; + + val = INREG(info->DDCReg) + & ~(CARD32)(R128_GPIO_MONID_EN_0 | R128_GPIO_MONID_EN_3); + val |= (Clock ? 0:R128_GPIO_MONID_EN_3); + val |= (data ? 0:R128_GPIO_MONID_EN_0); + OUTREG(info->DDCReg, val); +} + + +static Bool +R128I2cInit(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + if ( xf86LoadSubModule(pScrn, "i2c") ) + xf86LoaderReqSymLists(i2cSymbols,NULL); + else{ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to load i2c module\n"); + return FALSE; + } + + info->pI2CBus = xf86CreateI2CBusRec(); + if(!info->pI2CBus) return FALSE; + + info->pI2CBus->BusName = "DDC"; + info->pI2CBus->scrnIndex = pScrn->scrnIndex; + info->DDCReg = R128_GPIO_MONID; + info->pI2CBus->I2CPutBits = R128I2CPutBits; + info->pI2CBus->I2CGetBits = R128I2CGetBits; + info->pI2CBus->AcknTimeout = 5; + + if (!xf86I2CBusInit(info->pI2CBus)) { + return FALSE; + } + return TRUE; +} + +/* return TRUE is a DFP is indeed connected to a DVI port */ +static Bool R128GetDFPInfo(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + int i; + xf86MonPtr MonInfo = NULL; + xf86MonPtr ddc; + unsigned char *R128MMIO = info->MMIO; + + if(!R128I2cInit(pScrn)){ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I2C initialization failed!\n"); + } + + OUTREG(info->DDCReg, (INREG(info->DDCReg) + | R128_GPIO_MONID_MASK_0 | R128_GPIO_MONID_MASK_3)); + + OUTREG(info->DDCReg, INREG(info->DDCReg) + & ~(CARD32)(R128_GPIO_MONID_A_0 | R128_GPIO_MONID_A_3)); + + MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, info->pI2CBus); + if(!MonInfo) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No DFP detected\n"); + return FALSE; + } + xf86SetDDCproperties(pScrn, MonInfo); + ddc = pScrn->monitor->DDC; + + for(i=0; i<4; i++) + { + if(ddc->det_mon[i].type == 0) + { + info->PanelXRes = + ddc->det_mon[i].section.d_timings.h_active; + info->PanelYRes = + ddc->det_mon[i].section.d_timings.v_active; + + info->HOverPlus = + ddc->det_mon[i].section.d_timings.h_sync_off; + info->HSyncWidth = + ddc->det_mon[i].section.d_timings.h_sync_width; + info->HBlank = + ddc->det_mon[i].section.d_timings.h_blanking; + info->VOverPlus = + ddc->det_mon[i].section.d_timings.v_sync_off; + info->VSyncWidth = + ddc->det_mon[i].section.d_timings.v_sync_width; + info->VBlank = + ddc->det_mon[i].section.d_timings.v_blanking; + } + } + return TRUE; +} + + +static void R128SetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag) +{ + int i; + xf86MonPtr ddc = pScrn->monitor->DDC; + if(flag) /*HSync*/ + { + for(i=0; i<4; i++) + { + if(ddc->det_mon[i].type == DS_RANGES) + { + pScrn->monitor->nHsync = 1; + pScrn->monitor->hsync[0].lo = + ddc->det_mon[i].section.ranges.min_h; + pScrn->monitor->hsync[0].hi = + ddc->det_mon[i].section.ranges.max_h; + return; + } + } + /*if no sync ranges detected in detailed timing table, + let's try to derive them from supported VESA modes + Are we doing too much here!!!? + **/ + i = 0; + if(ddc->timings1.t1 & 0x02) /*800x600@56*/ + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 35.2; + i++; + } + if(ddc->timings1.t1 & 0x04) /*640x480@75*/ + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 37.5; + i++; + } + if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t1 & 0x01)) + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 37.9; + i++; + } + if(ddc->timings1.t2 & 0x40) + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 46.9; + i++; + } + if((ddc->timings1.t2 & 0x80) || (ddc->timings1.t2 & 0x08)) + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 48.1; + i++; + } + if(ddc->timings1.t2 & 0x04) + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 56.5; + i++; + } + if(ddc->timings1.t2 & 0x02) + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 60.0; + i++; + } + if(ddc->timings1.t2 & 0x01) + { + pScrn->monitor->hsync[i].lo = + pScrn->monitor->hsync[i].hi = 64.0; + i++; + } + pScrn->monitor->nHsync = i; + } + else /*Vrefresh*/ + { + for(i=0; i<4; i++) + { + if(ddc->det_mon[i].type == DS_RANGES) + { + pScrn->monitor->nVrefresh = 1; + pScrn->monitor->vrefresh[0].lo = + ddc->det_mon[i].section.ranges.min_v; + pScrn->monitor->vrefresh[0].hi = + ddc->det_mon[i].section.ranges.max_v; + return; + } + } + i = 0; + if(ddc->timings1.t1 & 0x02) /*800x600@56*/ + { + pScrn->monitor->vrefresh[i].lo = + pScrn->monitor->vrefresh[i].hi = 56; + i++; + } + if((ddc->timings1.t1 & 0x01) || (ddc->timings1.t2 & 0x08)) + { + pScrn->monitor->vrefresh[i].lo = + pScrn->monitor->vrefresh[i].hi = 60; + i++; + } + if(ddc->timings1.t2 & 0x04) + { + pScrn->monitor->vrefresh[i].lo = + pScrn->monitor->vrefresh[i].hi = 70; + i++; + } + if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t2 & 0x80)) + { + pScrn->monitor->vrefresh[i].lo = + pScrn->monitor->vrefresh[i].hi = 72; + i++; + } + if((ddc->timings1.t1 & 0x04) || (ddc->timings1.t2 & 0x40) + || (ddc->timings1.t2 & 0x02) || (ddc->timings1.t2 & 0x01)) + { + pScrn->monitor->vrefresh[i].lo = + pScrn->monitor->vrefresh[i].hi = 75; + i++; + } + pScrn->monitor->nVrefresh = i; + } +} + +/*********** + xfree's xf86ValidateModes routine deosn't work well with DFPs + here is our own validation routine. All modes between + 640<=XRes<=MaxRes and 480<=YRes<=MaxYRes will be permitted. + NOTE: RageProII doesn't support rmx, can only work with the + standard modes the monitor can support (scale). +************/ + +static int R128ValidateFPModes(ScrnInfoPtr pScrn) +{ + int i, j, count=0, width, height; + R128InfoPtr info = R128PTR(pScrn); + DisplayModePtr last = NULL, new = NULL, first = NULL; + xf86MonPtr ddc; + + /* Free any allocated modes during configuration. We don't need them*/ + while (pScrn->modes) + { + xf86DeleteMode(&pScrn->modes, pScrn->modes); + } + while (pScrn->modePool) + { + xf86DeleteMode(&pScrn->modePool, pScrn->modePool); + } + + pScrn->virtualX = pScrn->display->virtualX; + pScrn->virtualY = pScrn->display->virtualY; + + /* If no mode specified in config, we use native resolution*/ + if(!pScrn->display->modes[0]) + { + pScrn->display->modes[0] = xnfalloc(16); + sprintf(pScrn->display->modes[0], "%dx%d", + info->PanelXRes, info->PanelYRes); + } + + for(i=0; pScrn->display->modes[i] != NULL; i++) + { + if (sscanf(pScrn->display->modes[i], "%dx%d", &width, &height) == 2) + { + + if(width < 640 || width > info->PanelXRes || + height < 480 || height > info->PanelYRes) + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode %s is out of range.\n" + "Valid mode should be between 640x480-%dx%d\n", + pScrn->display->modes[i], info->PanelXRes, info->PanelYRes); + continue; + } + + new = xnfcalloc(1, sizeof(DisplayModeRec)); + new->prev = last; + new->name = xnfalloc(strlen(pScrn->display->modes[i]) + 1); + strcpy(new->name, pScrn->display->modes[i]); + new->HDisplay = new->CrtcHDisplay = width; + new->VDisplay = new->CrtcVDisplay = height; + + ddc = pScrn->monitor->DDC; + for(j=0; j<DET_TIMINGS; j++) + { + /*We use native mode clock only*/ + if(ddc->det_mon[j].type == 0){ + new->Clock = ddc->det_mon[j].section.d_timings.clock / 1000; + break; + } + } + + if(new->prev) new->prev->next = new; + last = new; + if(!first) first = new; + pScrn->display->virtualX = + pScrn->virtualX = MAX(pScrn->virtualX, width); + pScrn->display->virtualY = + pScrn->virtualY = MAX(pScrn->virtualY, height); + count++; + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode name %s is invalid\n", pScrn->display->modes[i]); + continue; + } + } + + if(last) + { + last->next = first; + first->prev = last; + pScrn->modes = first; + + /*FIXME: May need to validate line pitch here*/ + { + int dummy = 0; + switch(pScrn->depth / 8) + { + case 1: + dummy = 128 - pScrn->virtualX % 128; + break; + case 2: + dummy = 32 - pScrn->virtualX % 32; + break; + case 3: + case 4: + dummy = 16 - pScrn->virtualX % 16; + } + pScrn->displayWidth = pScrn->virtualX + dummy; + } + + } + + return count; +} + + +/* This is called by R128PreInit to validate modes and compute parameters + for all of the valid modes. */ +static Bool R128PreInitModes(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + ClockRangePtr clockRanges; + int modesFound; + + if(info->isDFP) { + R128MapMem(pScrn); + info->BIOSDisplay = R128_BIOS_DISPLAY_FP; + /* validate if DFP really connected. */ + if(!R128GetDFPInfo(pScrn)) { + info->isDFP = FALSE; + info->BIOSDisplay = R128_BIOS_DISPLAY_CRT; + } else if(!info->isPro2) { + /* RageProII doesn't support rmx, we can't use native-mode + stretching for other non-native modes. It will rely on + whatever VESA modes monitor can support. */ + modesFound = R128ValidateFPModes(pScrn); + if(modesFound < 1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid mode found for this DFP/LCD\n"); + R128UnmapMem(pScrn); + return FALSE; + + } + } + R128UnmapMem(pScrn); + } + + if(!info->isDFP || info->isPro2) { + /* Get mode information */ + pScrn->progClock = TRUE; + clockRanges = xnfcalloc(sizeof(*clockRanges), 1); + clockRanges->next = NULL; + clockRanges->minClock = info->pll.min_pll_freq; + clockRanges->maxClock = info->pll.max_pll_freq * 10; + clockRanges->clockIndex = -1; + if (info->HasPanelRegs || info->isDFP) { + clockRanges->interlaceAllowed = FALSE; + clockRanges->doubleScanAllowed = FALSE; + } else { + clockRanges->interlaceAllowed = TRUE; + clockRanges->doubleScanAllowed = TRUE; + } + + if(pScrn->monitor->DDC) { + /*if we still don't know sync range yet, let's try EDID. + Note that, since we can have dual heads, the Xconfigurator + may not be able to probe both monitors correctly through + vbe probe function (R128ProbeDDC). Here we provide an + additional way to auto-detect sync ranges if they haven't + been added to XF86Config manually. + **/ + if(pScrn->monitor->nHsync <= 0) + R128SetSyncRangeFromEdid(pScrn, 1); + if(pScrn->monitor->nVrefresh <= 0) + R128SetSyncRangeFromEdid(pScrn, 0); + } + + modesFound = xf86ValidateModes(pScrn, + pScrn->monitor->Modes, + pScrn->display->modes, + clockRanges, + NULL, /* linePitches */ + 8 * 64, /* minPitch */ + 8 * 1024, /* maxPitch */ + 8 * 64, /* pitchInc */ + 128, /* minHeight */ + 2048, /* maxHeight */ + pScrn->display->virtualX, + pScrn->display->virtualY, + info->FbMapSize, + LOOKUP_BEST_REFRESH); + + if (modesFound < 1 && info->FBDev) { + fbdevHWUseBuildinMode(pScrn); + pScrn->displayWidth = fbdevHWGetLineLength(pScrn)/(pScrn->bitsPerPixel/8); + modesFound = 1; + } + + if (modesFound == -1) return FALSE; + xf86PruneDriverModes(pScrn); + if (!modesFound || !pScrn->modes) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + return FALSE; + } + xf86SetCrtcForModes(pScrn, 0); + } + /* Set DPI */ + pScrn->currentMode = pScrn->modes; + xf86PrintModes(pScrn); + + xf86SetDpi(pScrn, 0, 0); + + /* Get ScreenInit function */ + if (!xf86LoadSubModule(pScrn, "fb")) return FALSE; + xf86LoaderReqSymLists(fbSymbols, NULL); + + info->CurrentLayout.displayWidth = pScrn->displayWidth; + info->CurrentLayout.mode = pScrn->currentMode; + + return TRUE; +} + +/* This is called by R128PreInit to initialize the hardware cursor. */ +static Bool R128PreInitCursor(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { + if (!xf86LoadSubModule(pScrn, "ramdac")) return FALSE; + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + return TRUE; +} + +/* This is called by R128PreInit to initialize hardware acceleration. */ +static Bool R128PreInitAccel(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { + if (!xf86LoadSubModule(pScrn, "xaa")) return FALSE; + xf86LoaderReqSymLists(xaaSymbols, NULL); + } + return TRUE; +} + +static Bool R128PreInitInt10(ScrnInfoPtr pScrn, xf86Int10InfoPtr *ppInt10) +{ + R128InfoPtr info = R128PTR(pScrn); +#if 1 && !defined(__alpha__) + /* int10 is broken on some Alphas */ + if (xf86LoadSubModule(pScrn, "int10")) { + xf86LoaderReqSymLists(int10Symbols, NULL); + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); + *ppInt10 = xf86InitInt10(info->pEnt->index); + } +#endif + return TRUE; +} + +#ifdef XF86DRI +static Bool R128PreInitDRI(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (xf86ReturnOptValBool(info->Options, OPTION_CCE_PIO, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing CCE into PIO mode\n"); + info->CCEMode = R128_DEFAULT_CCE_PIO_MODE; + } else { + info->CCEMode = R128_DEFAULT_CCE_BM_MODE; + } + + if (xf86ReturnOptValBool(info->Options, OPTION_NO_SECURITY, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "WARNING!!! CCE Security checks disabled!!! **********\n"); + info->CCESecure = FALSE; + } else { + info->CCESecure = TRUE; + } + + info->agpMode = R128_DEFAULT_AGP_MODE; + info->agpSize = R128_DEFAULT_AGP_SIZE; + info->ringSize = R128_DEFAULT_RING_SIZE; + info->bufSize = R128_DEFAULT_BUFFER_SIZE; + info->agpTexSize = R128_DEFAULT_AGP_TEX_SIZE; + + info->CCEusecTimeout = R128_DEFAULT_CCE_TIMEOUT; + + if (!info->IsPCI) { + if (xf86GetOptValInteger(info->Options, + OPTION_AGP_MODE, &(info->agpMode))) { + if (info->agpMode < 1 || info->agpMode > R128_AGP_MAX_MODE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal AGP Mode: %d\n", info->agpMode); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using AGP %dx mode\n", info->agpMode); + } + + if (xf86GetOptValInteger(info->Options, + OPTION_AGP_SIZE, (int *)&(info->agpSize))) { + switch (info->agpSize) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + case 256: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal AGP size: %d MB\n", info->agpSize); + return FALSE; + } + } + + if (xf86GetOptValInteger(info->Options, + OPTION_RING_SIZE, &(info->ringSize))) { + if (info->ringSize < 1 || info->ringSize >= (int)info->agpSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal ring buffer size: %d MB\n", + info->ringSize); + return FALSE; + } + } + + if (xf86GetOptValInteger(info->Options, + OPTION_BUFFER_SIZE, &(info->bufSize))) { + if (info->bufSize < 1 || info->bufSize >= (int)info->agpSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal vertex/indirect buffers size: %d MB\n", + info->bufSize); + return FALSE; + } + if (info->bufSize > 2) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal vertex/indirect buffers size: %d MB\n", + info->bufSize); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Clamping vertex/indirect buffers size to 2 MB\n"); + info->bufSize = 2; + } + } + + if (info->ringSize + info->bufSize + info->agpTexSize > + (int)info->agpSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Buffers are too big for requested AGP space\n"); + return FALSE; + } + + info->agpTexSize = info->agpSize - (info->ringSize + info->bufSize); + } + + if (xf86GetOptValInteger(info->Options, OPTION_USEC_TIMEOUT, + &(info->CCEusecTimeout))) { + /* This option checked by the R128 DRM kernel module */ + } + + if (!xf86LoadSubModule(pScrn, "shadowfb")) { + info->allowPageFlip = 0; + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't load shadowfb module:\n"); + } else { + xf86LoaderReqSymLists(driShadowFBSymbols, NULL); + + info->allowPageFlip = xf86ReturnOptValBool(info->Options, + OPTION_PAGE_FLIP, + FALSE); + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Page flipping %sabled\n", + info->allowPageFlip ? "en" : "dis"); + + return TRUE; +} +#endif + +static void +R128ProbeDDC(ScrnInfoPtr pScrn, int indx) +{ + vbeInfoPtr pVbe; + if (xf86LoadSubModule(pScrn, "vbe")) { + pVbe = VBEInit(NULL,indx); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +/* R128PreInit is called once at server startup. */ +Bool R128PreInit(ScrnInfoPtr pScrn, int flags) +{ + R128InfoPtr info; + xf86Int10InfoPtr pInt10 = NULL; + + R128TRACE(("R128PreInit\n")); + + if (pScrn->numEntities != 1) return FALSE; + + if (!R128GetRec(pScrn)) return FALSE; + + info = R128PTR(pScrn); + + info->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if (info->pEnt->location.type != BUS_PCI) goto fail; + + if (flags & PROBE_DETECT) { + R128ProbeDDC(pScrn, info->pEnt->index); + return TRUE; + } + + if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE; + xf86LoaderReqSymLists(vgahwSymbols, NULL); + if (!vgaHWGetHWRec(pScrn)) { + R128FreeRec(pScrn); + return FALSE; + } + + info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index); + info->PciTag = pciTag(info->PciInfo->bus, + info->PciInfo->device, + info->PciInfo->func); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "PCI bus %d card %d func %d\n", + info->PciInfo->bus, + info->PciInfo->device, + info->PciInfo->func); + + if (xf86RegisterResources(info->pEnt->index, 0, ResNone)) goto fail; + if (xf86SetOperatingState(resVga, info->pEnt->index, ResUnusedOpr)) goto fail; + + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; + pScrn->monitor = pScrn->confScreen->monitor; + + if (!R128PreInitVisual(pScrn)) goto fail; + + /* We can't do this until we have a + pScrn->display. */ + xf86CollectOptions(pScrn, NULL); + if (!(info->Options = xalloc(sizeof(R128Options)))) goto fail; + memcpy(info->Options, R128Options, sizeof(R128Options)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options); + + if (!R128PreInitWeight(pScrn)) goto fail; + + if(xf86GetOptValInteger(info->Options, OPTION_VIDEO_KEY, &(info->videoKey))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n", + info->videoKey); + } else { + info->videoKey = 0x1E; + } + + if (xf86ReturnOptValBool(info->Options, OPTION_SHOW_CACHE, FALSE)) { + info->showCache = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShowCache enabled\n"); + } + + if (xf86ReturnOptValBool(info->Options, OPTION_FBDEV, FALSE)) { + info->FBDev = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using framebuffer device\n"); + } + + if (info->FBDev) { + /* check for linux framebuffer device */ + if (!xf86LoadSubModule(pScrn, "fbdevhw")) return FALSE; + xf86LoaderReqSymLists(fbdevHWSymbols, NULL); + if (!fbdevHWInit(pScrn, info->PciInfo, NULL)) return FALSE; + pScrn->SwitchMode = fbdevHWSwitchMode; + pScrn->AdjustFrame = fbdevHWAdjustFrame; + pScrn->ValidMode = fbdevHWValidMode; + } + + if (!info->FBDev) + if (!R128PreInitInt10(pScrn, &pInt10)) goto fail; + + if (!R128PreInitConfig(pScrn)) goto fail; + + if (!R128GetBIOSParameters(pScrn, pInt10)) goto fail; + + if (!R128GetPLLParameters(pScrn)) goto fail; + + /* Don't fail on this one */ + R128PreInitDDC(pScrn, pInt10); + + if (!R128PreInitGamma(pScrn)) goto fail; + + if (!R128PreInitModes(pScrn)) goto fail; + + if (!R128PreInitCursor(pScrn)) goto fail; + + if (!R128PreInitAccel(pScrn)) goto fail; + +#ifdef XF86DRI + if (!R128PreInitDRI(pScrn)) goto fail; +#endif + + /* Free the video bios (if applicable) */ + if (info->VBIOS) { + xfree(info->VBIOS); + info->VBIOS = NULL; + } + + /* Free int10 info */ + if (pInt10) + xf86FreeInt10(pInt10); + + xf86DrvMsg(pScrn->scrnIndex, X_NOTICE, + "For information on using the multimedia capabilities\n of this" + " adapter, please see http://gatos.sf.net.\n"); + + return TRUE; + + fail: + /* Pre-init failed. */ + + /* Free the video bios (if applicable) */ + if (info->VBIOS) { + xfree(info->VBIOS); + info->VBIOS = NULL; + } + + /* Free int10 info */ + if (pInt10) + xf86FreeInt10(pInt10); + + vgaHWFreeHWRec(pScrn); + R128FreeRec(pScrn); + return FALSE; +} + +/* Load a palette. */ +static void R128LoadPalette(ScrnInfoPtr pScrn, int numColors, + int *indices, LOCO *colors, VisualPtr pVisual) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + int idx; + unsigned char r, g, b; + + /* Select palette 0 (main CRTC) if using FP-enabled chip */ + if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0); + + if (info->CurrentLayout.depth == 15) { + /* 15bpp mode. This sends 32 values. */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx].red; + g = colors[idx].green; + b = colors[idx].blue; + OUTPAL(idx * 8, r, g, b); + } + } + else if (info->CurrentLayout.depth == 16) { + /* 16bpp mode. This sends 64 values. */ + /* There are twice as many green values as + there are values for red and blue. So, + we take each red and blue pair, and + combine it with each of the two green + values. */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx / 2].red; + g = colors[idx].green; + b = colors[idx / 2].blue; + OUTPAL(idx * 4, r, g, b); + } + } + else { + /* 8bpp mode. This sends 256 values. */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx].red; + b = colors[idx].blue; + g = colors[idx].green; + OUTPAL(idx, r, g, b); + } + } +} + +static void +R128BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + R128InfoPtr info = R128PTR(pScrn); + +#ifdef XF86DRI + if (info->directRenderingEnabled) + FLUSH_RING(); +#endif + + pScreen->BlockHandler = info->BlockHandler; + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + pScreen->BlockHandler = R128BlockHandler; + + if(info->VideoTimerCallback) { + (*info->VideoTimerCallback)(pScrn, currentTime.milliseconds); + } +} + +/* Called at the start of each server generation. */ +Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + BoxRec MemBox; + int y2; + + R128TRACE(("R128ScreenInit %x %d\n", pScrn->memPhysBase, pScrn->fbOffset)); + +#ifdef XF86DRI + /* Turn off the CCE for now. */ + info->CCEInUse = FALSE; + info->indirectBuffer = NULL; +#endif + + if (!R128MapMem(pScrn)) return FALSE; + pScrn->fbOffset = 0; +#ifdef XF86DRI + info->fbX = 0; + info->fbY = 0; + info->frontOffset = 0; + info->frontPitch = pScrn->displayWidth; +#endif + + info->PaletteSavedOnVT = FALSE; + + R128Save(pScrn); + if (info->FBDev) { + if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE; + } else { + if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE; + } + + R128SaveScreen(pScreen, SCREEN_SAVER_ON); + pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + /* Visual setup */ + miClearVisualTypes(); + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, + pScrn->defaultVisual)) return FALSE; + miSetPixmapDepths (); + +#ifdef XF86DRI + /* Setup DRI after visuals have been + established, but before fbScreenInit is + called. fbScreenInit will eventually + call the driver's InitGLXVisuals call + back. */ + { + /* FIXME: When we move to dynamic allocation of back and depth + buffers, we will want to revisit the following check for 3 + times the virtual size of the screen below. */ + int width_bytes = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + int maxy = info->FbMapSize / width_bytes; + + if (xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { + xf86DrvMsg(scrnIndex, X_WARNING, + "Acceleration disabled, not initializing the DRI\n"); + info->directRenderingEnabled = FALSE; + } else if (maxy <= pScrn->virtualY * 3) { + xf86DrvMsg(scrnIndex, X_WARNING, + "Static buffer allocation failed -- " + "need at least %d kB video memory\n", + (pScrn->displayWidth * pScrn->virtualY * + info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024); + info->directRenderingEnabled = FALSE; + } else { + info->directRenderingEnabled = R128DRIScreenInit(pScreen); + } + } +#endif + + if (!fbScreenInit (pScreen, info->FB, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, + pScrn->bitsPerPixel)) + return FALSE; + + xf86SetBlackWhitePixels(pScreen); + + if (pScrn->bitsPerPixel > 8) { + VisualPtr visual; + + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + /* must be after RGB order fixed */ + fbPictureInit (pScreen, 0, 0); + + /* Memory manager setup */ +#ifdef XF86DRI + if (info->directRenderingEnabled) { + FBAreaPtr fbarea; + int width_bytes = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + int cpp = info->CurrentLayout.pixel_bytes; + int bufferSize = pScrn->virtualY * width_bytes; + int l, total; + int scanlines; + + switch (info->CCEMode) { + case R128_DEFAULT_CCE_PIO_MODE: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CCE in PIO mode\n"); + break; + case R128_DEFAULT_CCE_BM_MODE: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CCE in BM mode\n"); + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CCE in UNKNOWN mode\n"); + break; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB AGP aperture\n", info->agpSize); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB for the ring buffer\n", info->ringSize); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB for vertex/indirect buffers\n", info->bufSize); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB for AGP textures\n", info->agpTexSize); + + /* Try for front, back, depth, and two framebuffers worth of + * pixmap cache. Should be enough for a fullscreen background + * image plus some leftovers. + */ + info->textureSize = info->FbMapSize - 5 * bufferSize; + + /* If that gives us less than half the available memory, let's + * be greedy and grab some more. Sorry, I care more about 3D + * performance than playing nicely, and you'll get around a full + * framebuffer's worth of pixmap cache anyway. + */ + if (info->textureSize < (int)info->FbMapSize / 2) { + info->textureSize = info->FbMapSize - 4 * bufferSize; + } + + if (info->textureSize > 0) { + l = R128MinBits((info->textureSize-1) / R128_NR_TEX_REGIONS); + if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; + + /* Round the texture size up to the nearest whole number of + * texture regions. Again, be greedy about this, don't + * round down. + */ + info->log2TexGran = l; + info->textureSize = (info->textureSize >> l) << l; + } else { + info->textureSize = 0; + } + + /* Set a minimum usable local texture heap size. This will fit + * two 256x256x32bpp textures. + */ + if (info->textureSize < 512 * 1024) { + info->textureOffset = 0; + info->textureSize = 0; + } + + total = info->FbMapSize - info->textureSize; + scanlines = total / width_bytes; + if (scanlines > 8191) scanlines = 8191; + + /* Recalculate the texture offset and size to accomodate any + * rounding to a whole number of scanlines. + */ + info->textureOffset = scanlines * width_bytes; + + MemBox.x1 = 0; + MemBox.y1 = 0; + MemBox.x2 = pScrn->displayWidth; + MemBox.y2 = scanlines; + + if (!xf86InitFBManager(pScreen, &MemBox)) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Memory manager initialization to (%d,%d) (%d,%d) failed\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + return FALSE; + } else { + int width, height; + + xf86DrvMsg(scrnIndex, X_INFO, + "Memory manager initialized to (%d,%d) (%d,%d)\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->displayWidth, + 2, 0, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved area from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); + } + if (xf86QueryLargestOffscreenArea(pScreen, &width, + &height, 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + } + } + + /* Allocate the shared back buffer */ + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->virtualX, + pScrn->virtualY, + 32, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved back buffer from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + + info->backX = fbarea->box.x1; + info->backY = fbarea->box.y1; + info->backOffset = (fbarea->box.y1 * width_bytes + + fbarea->box.x1 * cpp); + info->backPitch = pScrn->displayWidth; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve back buffer\n"); + info->backX = -1; + info->backY = -1; + info->backOffset = -1; + info->backPitch = -1; + } + + /* Allocate the shared depth buffer */ + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->virtualX, + pScrn->virtualY + 1, + 32, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved depth buffer from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + + info->depthX = fbarea->box.x1; + info->depthY = fbarea->box.y1; + info->depthOffset = (fbarea->box.y1 * width_bytes + + fbarea->box.x1 * cpp); + info->depthPitch = pScrn->displayWidth; + info->spanOffset = ((fbarea->box.y2 - 1) * width_bytes + + fbarea->box.x1 * cpp); + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved depth span from (%d,%d) offset 0x%x\n", + fbarea->box.x1, fbarea->box.y2 - 1, info->spanOffset); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve depth buffer\n"); + info->depthX = -1; + info->depthY = -1; + info->depthOffset = -1; + info->depthPitch = -1; + info->spanOffset = -1; + } + + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved %d kb for textures at offset 0x%x\n", + info->textureSize/1024, info->textureOffset); + } + else +#endif + { + MemBox.x1 = 0; + MemBox.y1 = 0; + MemBox.x2 = pScrn->displayWidth; + y2 = (info->FbMapSize + / (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes)); + /* The acceleration engine uses 14 bit + signed coordinates, so we can't have any + drawable caches beyond this region. */ + if (y2 > 8191) y2 = 8191; + MemBox.y2 = y2; + + if (!xf86InitFBManager(pScreen, &MemBox)) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Memory manager initialization to (%d,%d) (%d,%d) failed\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + return FALSE; + } else { + int width, height; + FBAreaPtr fbarea; + + xf86DrvMsg(scrnIndex, X_INFO, + "Memory manager initialized to (%d,%d) (%d,%d)\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + if ((fbarea = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, + 2, 0, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved area from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); + } + if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, + 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + } + } + } + + /* Acceleration setup */ + if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { + if (R128AccelInit(pScreen)) { + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration enabled\n"); + info->accelOn = TRUE; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "Acceleration initialization failed\n"); + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); + info->accelOn = FALSE; + } + } else { + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); + info->accelOn = FALSE; + } + + /* DGA setup */ + R128DGAInit(pScreen); + + /* Backing store setup */ + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + + /* Set Silken Mouse */ + xf86SetSilkenMouse(pScreen); + + /* Cursor setup */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Hardware cursor setup */ + if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { + if (R128CursorInit(pScreen)) { + int width, height; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using hardware cursor (scanline %ld)\n", + info->cursor_start / pScrn->displayWidth); + if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, + 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + } + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + xf86DrvMsg(scrnIndex, X_INFO, "Using software cursor\n"); + } + } else { + info->cursor_start = 0; + xf86DrvMsg(scrnIndex, X_INFO, "Using software cursor\n"); + } + + /* Colormap setup */ + if (!miCreateDefColormap(pScreen)) return FALSE; + if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8, + (info->FBDev ? fbdevHWLoadPalette : + R128LoadPalette), NULL, + CMAP_PALETTED_TRUECOLOR + | CMAP_RELOAD_ON_MODE_SWITCH +#if 0 /* This option messes up text mode! (eich@suse.de) */ + | CMAP_LOAD_EVEN_IF_OFFSCREEN +#endif + )) return FALSE; + + /* DPMS setup - FIXME: also for mirror mode in non-fbdev case? - Michel */ + if (info->FBDev) + xf86DPMSInit(pScreen, fbdevHWDPMSSet, 0); + else { + if (!info->HasPanelRegs || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT) + xf86DPMSInit(pScreen, R128DisplayPowerManagementSet, 0); + else if (info->HasPanelRegs || info->BIOSDisplay == R128_BIOS_DISPLAY_FP) + xf86DPMSInit(pScreen, R128DisplayPowerManagementSetLCD, 0); + } + + R128InitVideo(pScreen); + + /* Provide SaveScreen */ + pScreen->SaveScreen = R128SaveScreen; + + /* Wrap CloseScreen */ + info->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = R128CloseScreen; + + /* Note unused options */ + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + +#ifdef XF86DRI + /* DRI finalization */ + if (info->directRenderingEnabled) { + /* Now that mi, fb, drm and others have + done their thing, complete the DRI + setup. */ + info->directRenderingEnabled = R128DRIFinishScreenInit(pScreen); + } + if (info->directRenderingEnabled) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering disabled\n"); + } +#endif + + info->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = R128BlockHandler; + + return TRUE; +} + +/* Write common registers (initialized to 0). */ +static void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREG(R128_FP_GEN_CNTL, restore->fp_gen_cntl | R128_FP_BLANK_DIS); + + OUTREG(R128_OVR_CLR, restore->ovr_clr); + OUTREG(R128_OVR_WID_LEFT_RIGHT, restore->ovr_wid_left_right); + OUTREG(R128_OVR_WID_TOP_BOTTOM, restore->ovr_wid_top_bottom); + OUTREG(R128_OV0_SCALE_CNTL, restore->ov0_scale_cntl); + OUTREG(R128_MPP_TB_CONFIG, restore->mpp_tb_config ); + OUTREG(R128_MPP_GP_CONFIG, restore->mpp_gp_config ); + OUTREG(R128_SUBPIC_CNTL, restore->subpic_cntl); + OUTREG(R128_VIPH_CONTROL, restore->viph_control); + OUTREG(R128_I2C_CNTL_1, restore->i2c_cntl_1); + OUTREG(R128_GEN_INT_CNTL, restore->gen_int_cntl); + OUTREG(R128_CAP0_TRIG_CNTL, restore->cap0_trig_cntl); + OUTREG(R128_CAP1_TRIG_CNTL, restore->cap1_trig_cntl); + OUTREG(R128_BUS_CNTL, restore->bus_cntl); + OUTREG(R128_CONFIG_CNTL, restore->config_cntl); +} + +/* Write CRTC registers. */ +static void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREG(R128_CRTC_GEN_CNTL, restore->crtc_gen_cntl); + + OUTREGP(R128_CRTC_EXT_CNTL, restore->crtc_ext_cntl, + R128_CRTC_VSYNC_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_DISPLAY_DIS); + + OUTREGP(R128_DAC_CNTL, restore->dac_cntl, + R128_DAC_RANGE_CNTL | R128_DAC_BLANKING); + + OUTREG(R128_CRTC_H_TOTAL_DISP, restore->crtc_h_total_disp); + OUTREG(R128_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid); + OUTREG(R128_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); + OUTREG(R128_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid); + OUTREG(R128_CRTC_OFFSET, restore->crtc_offset); + OUTREG(R128_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); + OUTREG(R128_CRTC_PITCH, restore->crtc_pitch); +} + +/* Write flat panel registers */ +static void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + CARD32 tmp; + + + /*OUTREG(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl);*/ + OUTREG(R128_FP_HORZ_STRETCH, restore->fp_horz_stretch); + OUTREG(R128_FP_VERT_STRETCH, restore->fp_vert_stretch); + OUTREG(R128_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp); + OUTREG(R128_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp); + OUTREG(R128_FP_H_SYNC_STRT_WID, restore->fp_h_sync_strt_wid); + OUTREG(R128_FP_V_SYNC_STRT_WID, restore->fp_v_sync_strt_wid); + OUTREG(R128_TMDS_CRC, restore->tmds_crc); + OUTREG(R128_FP_PANEL_CNTL, restore->fp_panel_cntl); + OUTREG(R128_FP_GEN_CNTL, restore->fp_gen_cntl & ~(CARD32)R128_FP_BLANK_DIS); + + if(info->isDFP) return; + + tmp = INREG(R128_LVDS_GEN_CNTL); + if ((tmp & (R128_LVDS_ON | R128_LVDS_BLON)) == + (restore->lvds_gen_cntl & (R128_LVDS_ON | R128_LVDS_BLON))) { + OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + } else { + if (restore->lvds_gen_cntl & (R128_LVDS_ON | R128_LVDS_BLON)) { + OUTREG(R128_LVDS_GEN_CNTL, + restore->lvds_gen_cntl & (CARD32)~R128_LVDS_BLON); + usleep(R128PTR(pScrn)->PanelPwrDly * 1000); + OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + } else { + OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl | R128_LVDS_BLON); + usleep(R128PTR(pScrn)->PanelPwrDly * 1000); + OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + } + } +} + +static void R128PLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn) +{ + while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R); +} + +static void R128PLLWriteUpdate(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTPLLP(pScrn, R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, 0xffff); +} + +/* Write PLL registers. */ +static void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, 0xffff); + + OUTPLLP(pScrn, + R128_PPLL_CNTL, + R128_PPLL_RESET + | R128_PPLL_ATOMIC_UPDATE_EN + | R128_PPLL_VGA_ATOMIC_UPDATE_EN, + 0xffff); + + R128PLLWaitForReadUpdateComplete(pScrn); + OUTPLLP(pScrn, R128_PPLL_REF_DIV, + restore->ppll_ref_div, ~R128_PPLL_REF_DIV_MASK); + R128PLLWriteUpdate(pScrn); + + R128PLLWaitForReadUpdateComplete(pScrn); + OUTPLLP(pScrn, R128_PPLL_DIV_3, + restore->ppll_div_3, ~R128_PPLL_FB3_DIV_MASK); + R128PLLWriteUpdate(pScrn); + OUTPLLP(pScrn, R128_PPLL_DIV_3, + restore->ppll_div_3, ~R128_PPLL_POST3_DIV_MASK); + R128PLLWriteUpdate(pScrn); + + R128PLLWaitForReadUpdateComplete(pScrn); + OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl); + R128PLLWriteUpdate(pScrn); + + OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~R128_PPLL_RESET); + + R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + restore->ppll_ref_div, + restore->ppll_div_3, + restore->htotal_cntl, + INPLL(pScrn, R128_PPLL_CNTL))); + R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n", + restore->ppll_ref_div & R128_PPLL_REF_DIV_MASK, + restore->ppll_div_3 & R128_PPLL_FB3_DIV_MASK, + (restore->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16)); +} + +/* Write DDA registers. */ +static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREG(R128_DDA_CONFIG, restore->dda_config); + OUTREG(R128_DDA_ON_OFF, restore->dda_on_off); +} + +/* Write palette data. */ +static void R128RestorePalette(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + if (!restore->palette_valid) return; + + /* Select palette 0 (main CRTC) if using FP-enabled chip */ + if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0); + + OUTPAL_START(0); + for (i = 0; i < 256; i++) OUTPAL_NEXT_CARD32(restore->palette[i]); +} + +/* Write out state to define a new video mode. */ +static void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + + R128TRACE(("R128RestoreMode(%p)\n", restore)); + R128RestoreCommonRegisters(pScrn, restore); + R128RestoreCrtcRegisters(pScrn, restore); + if (!(info->HasPanelRegs) || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT){ + R128RestorePLLRegisters(pScrn, restore); + } + R128RestoreDDARegisters(pScrn, restore); + if (info->HasPanelRegs || info->isDFP) + R128RestoreFPRegisters(pScrn, restore); + + R128RestorePalette(pScrn, restore); +} + +/* Read common registers. */ +static void R128SaveCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr save) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + save->ovr_clr = INREG(R128_OVR_CLR); + save->ovr_wid_left_right = INREG(R128_OVR_WID_LEFT_RIGHT); + save->ovr_wid_top_bottom = INREG(R128_OVR_WID_TOP_BOTTOM); + save->ov0_scale_cntl = INREG(R128_OV0_SCALE_CNTL); + save->mpp_tb_config = INREG(R128_MPP_TB_CONFIG); + save->mpp_gp_config = INREG(R128_MPP_GP_CONFIG); + save->subpic_cntl = INREG(R128_SUBPIC_CNTL); + save->viph_control = INREG(R128_VIPH_CONTROL); + save->i2c_cntl_1 = INREG(R128_I2C_CNTL_1); + save->gen_int_cntl = INREG(R128_GEN_INT_CNTL); + save->cap0_trig_cntl = INREG(R128_CAP0_TRIG_CNTL); + save->cap1_trig_cntl = INREG(R128_CAP1_TRIG_CNTL); + save->bus_cntl = INREG(R128_BUS_CNTL); + save->config_cntl = INREG(R128_CONFIG_CNTL); +} + +/* Read CRTC registers. */ +static void R128SaveCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + save->crtc_gen_cntl = INREG(R128_CRTC_GEN_CNTL); + save->crtc_ext_cntl = INREG(R128_CRTC_EXT_CNTL); + save->dac_cntl = INREG(R128_DAC_CNTL); + save->crtc_h_total_disp = INREG(R128_CRTC_H_TOTAL_DISP); + save->crtc_h_sync_strt_wid = INREG(R128_CRTC_H_SYNC_STRT_WID); + save->crtc_v_total_disp = INREG(R128_CRTC_V_TOTAL_DISP); + save->crtc_v_sync_strt_wid = INREG(R128_CRTC_V_SYNC_STRT_WID); + save->crtc_offset = INREG(R128_CRTC_OFFSET); + save->crtc_offset_cntl = INREG(R128_CRTC_OFFSET_CNTL); + save->crtc_pitch = INREG(R128_CRTC_PITCH); +} + +/* Read flat panel registers */ +static void R128SaveFPRegisters(ScrnInfoPtr pScrn, R128SavePtr save) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + save->crtc2_gen_cntl = INREG(R128_CRTC2_GEN_CNTL); + save->fp_crtc_h_total_disp = INREG(R128_FP_CRTC_H_TOTAL_DISP); + save->fp_crtc_v_total_disp = INREG(R128_FP_CRTC_V_TOTAL_DISP); + save->fp_gen_cntl = INREG(R128_FP_GEN_CNTL); + save->fp_h_sync_strt_wid = INREG(R128_FP_H_SYNC_STRT_WID); + save->fp_horz_stretch = INREG(R128_FP_HORZ_STRETCH); + save->fp_panel_cntl = INREG(R128_FP_PANEL_CNTL); + save->fp_v_sync_strt_wid = INREG(R128_FP_V_SYNC_STRT_WID); + save->fp_vert_stretch = INREG(R128_FP_VERT_STRETCH); + save->lvds_gen_cntl = INREG(R128_LVDS_GEN_CNTL); + save->tmds_crc = INREG(R128_TMDS_CRC); + save->tmds_transmitter_cntl = INREG(R128_TMDS_TRANSMITTER_CNTL); +} + +/* Read PLL registers. */ +static void R128SavePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save) +{ + save->ppll_ref_div = INPLL(pScrn, R128_PPLL_REF_DIV); + save->ppll_div_3 = INPLL(pScrn, R128_PPLL_DIV_3); + save->htotal_cntl = INPLL(pScrn, R128_HTOTAL_CNTL); + + R128TRACE(("Read: 0x%08x 0x%08x 0x%08x\n", + save->ppll_ref_div, + save->ppll_div_3, + save->htotal_cntl)); + R128TRACE(("Read: rd=%d, fd=%d, pd=%d\n", + save->ppll_ref_div & R128_PPLL_REF_DIV_MASK, + save->ppll_div_3 & R128_PPLL_FB3_DIV_MASK, + (save->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16)); +} + +/* Read DDA registers. */ +static void R128SaveDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + save->dda_config = INREG(R128_DDA_CONFIG); + save->dda_on_off = INREG(R128_DDA_ON_OFF); +} + +/* Read palette data. */ +static void R128SavePalette(ScrnInfoPtr pScrn, R128SavePtr save) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int i; + + /* Select palette 0 (main CRTC) if using FP-enabled chip */ + if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0); + + INPAL_START(0); + for (i = 0; i < 256; i++) save->palette[i] = INPAL_NEXT(); + save->palette_valid = TRUE; +} + +/* Save state that defines current video mode. */ +static void R128SaveMode(ScrnInfoPtr pScrn, R128SavePtr save) +{ + R128TRACE(("R128SaveMode(%p)\n", save)); + + R128SaveCommonRegisters(pScrn, save); + R128SaveCrtcRegisters(pScrn, save); + if (R128PTR(pScrn)->HasPanelRegs || R128PTR(pScrn)->isDFP) + R128SaveFPRegisters(pScrn, save); + R128SavePLLRegisters(pScrn, save); + R128SaveDDARegisters(pScrn, save); + R128SavePalette(pScrn, save); + + R128TRACE(("R128SaveMode returns %p\n", save)); +} + +/* Save everything needed to restore the original VC state. */ +static void R128Save(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128SavePtr save = &info->SavedReg; + vgaHWPtr hwp = VGAHWPTR(pScrn); + + R128TRACE(("R128Save\n")); + if (info->FBDev) { + fbdevHWSave(pScrn); + return; + } + vgaHWUnlock(hwp); + vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); /* save mode, fonts, cmap */ + vgaHWLock(hwp); + + R128SaveMode(pScrn, save); + + save->dp_datatype = INREG(R128_DP_DATATYPE); + save->gen_reset_cntl = INREG(R128_GEN_RESET_CNTL); + save->clock_cntl_index = INREG(R128_CLOCK_CNTL_INDEX); + save->amcgpio_en_reg = INREG(R128_AMCGPIO_EN_REG); + save->amcgpio_mask = INREG(R128_AMCGPIO_MASK); +} + +/* Restore the original (text) mode. */ +static void R128Restore(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128SavePtr restore = &info->SavedReg; + vgaHWPtr hwp = VGAHWPTR(pScrn); + + R128TRACE(("R128Restore\n")); + if (info->FBDev) { + fbdevHWRestore(pScrn); + return; + } + + R128Blank(pScrn); + OUTREG(R128_AMCGPIO_MASK, restore->amcgpio_mask); + OUTREG(R128_AMCGPIO_EN_REG, restore->amcgpio_en_reg); + OUTREG(R128_CLOCK_CNTL_INDEX, restore->clock_cntl_index); + OUTREG(R128_GEN_RESET_CNTL, restore->gen_reset_cntl); + OUTREG(R128_DP_DATATYPE, restore->dp_datatype); + + R128RestoreMode(pScrn, restore); + vgaHWUnlock(hwp); + vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); + vgaHWLock(hwp); + + R128WaitForVerticalSync(pScrn); + R128Unblank(pScrn); +} + +/* Define common registers for requested video mode. */ +static void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info) +{ + save->ovr_clr = 0; + save->ovr_wid_left_right = 0; + save->ovr_wid_top_bottom = 0; + save->ov0_scale_cntl = 0; + save->mpp_tb_config = 0; + save->mpp_gp_config = 0; + save->subpic_cntl = 0; + save->viph_control = 0; + save->i2c_cntl_1 = 0; +#ifdef XF86DRI + save->gen_int_cntl = info->gen_int_cntl; +#else + save->gen_int_cntl = 0; +#endif + save->cap0_trig_cntl = 0; + save->cap1_trig_cntl = 0; + save->bus_cntl = info->BusCntl; + /* + * If bursts are enabled, turn on discards and aborts + */ + if (save->bus_cntl & (R128_BUS_WRT_BURST|R128_BUS_READ_BURST)) + save->bus_cntl |= R128_BUS_RD_DISCARD_EN | R128_BUS_RD_ABORT_EN; +} + +/* Define CRTC registers for requested video mode. */ +static Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save, + DisplayModePtr mode, R128InfoPtr info) +{ + int format; + int hsync_start; + int hsync_wid; + int hsync_fudge; + int vsync_wid; + int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; + int hsync_fudge_fp[] = { 0x12, 0x11, 0x09, 0x09, 0x05, 0x05 }; + int hsync_fudge_fp_crt[] = { 0x12, 0x10, 0x08, 0x08, 0x04, 0x04 }; + + switch (info->CurrentLayout.pixel_code) { + case 4: format = 1; break; + case 8: format = 2; break; + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported pixel depth (%d)\n", + info->CurrentLayout.bitsPerPixel); + return FALSE; + } + + switch (info->BIOSDisplay) { + case R128_BIOS_DISPLAY_FP: + hsync_fudge = hsync_fudge_fp[format-1]; + break; + case R128_BIOS_DISPLAY_FP_CRT: + hsync_fudge = hsync_fudge_fp_crt[format-1]; + break; + case R128_BIOS_DISPLAY_CRT: + default: + hsync_fudge = hsync_fudge_default[format-1]; + break; + } + + save->crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN + | R128_CRTC_EN + | (format << 8) + | ((mode->Flags & V_DBLSCAN) + ? R128_CRTC_DBL_SCAN_EN + : 0) + | ((mode->Flags & V_INTERLACE) + ? R128_CRTC_INTERLACE_EN + : 0) + | ((mode->Flags & V_CSYNC) + ? R128_CRTC_CSYNC_EN + : 0)); + + save->crtc_ext_cntl = R128_VGA_ATI_LINEAR | R128_XCRT_CNT_EN; + save->dac_cntl = (R128_DAC_MASK_ALL + | R128_DAC_VGA_ADR_EN + | (info->dac6bits ? 0 : R128_DAC_8BIT_EN)); + + + if(info->isDFP && !info->isPro2) + { + if(info->PanelXRes < mode->CrtcHDisplay) + mode->HDisplay = mode->CrtcHDisplay = info->PanelXRes; + if(info->PanelYRes < mode->CrtcVDisplay) + mode->VDisplay = mode->CrtcVDisplay = info->PanelYRes; + mode->CrtcHTotal = mode->CrtcHDisplay + info->HBlank; + mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlus; + mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidth; + mode->CrtcVTotal = mode->CrtcVDisplay + info->VBlank; + mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlus; + mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidth; + } + + save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff) + | (((mode->CrtcHDisplay / 8) - 1) << 16)); + + hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; + if (!hsync_wid) hsync_wid = 1; + if (hsync_wid > 0x3f) hsync_wid = 0x3f; + + hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge; + + save->crtc_h_sync_strt_wid = ((hsync_start & 0xfff) + | (hsync_wid << 16) + | ((mode->Flags & V_NHSYNC) + ? R128_CRTC_H_SYNC_POL + : 0)); + +#if 1 + /* This works for double scan mode. */ + save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay - 1) << 16)); +#else + /* This is what cce/nbmode.c example code + does -- is this correct? */ + save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay + * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1) + << 16)); +#endif + + vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + if (!vsync_wid) vsync_wid = 1; + if (vsync_wid > 0x1f) vsync_wid = 0x1f; + + save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) + | (vsync_wid << 16) + | ((mode->Flags & V_NVSYNC) + ? R128_CRTC_V_SYNC_POL + : 0)); + save->crtc_offset = 0; + save->crtc_offset_cntl = 0; + save->crtc_pitch = info->CurrentLayout.displayWidth / 8; + + R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n", + save->crtc_pitch, pScrn->virtualX, info->CurrentLayout.displayWidth)); + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* Change the endianness of the aperture */ + switch (info->CurrentLayout.pixel_code) { + case 15: + case 16: save->config_cntl |= APER_0_BIG_ENDIAN_16BPP_SWAP; break; + case 32: save->config_cntl |= APER_0_BIG_ENDIAN_32BPP_SWAP; break; + default: break; + } +#endif + + return TRUE; +} + +/* Define CRTC registers for requested video mode. */ +static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save, + DisplayModePtr mode, R128InfoPtr info) +{ + int xres = mode->CrtcHDisplay; + int yres = mode->CrtcVDisplay; + float Hratio, Vratio; + + if (info->BIOSDisplay == R128_BIOS_DISPLAY_CRT) { + save->crtc_ext_cntl |= R128_CRTC_CRT_ON; + save->crtc2_gen_cntl = 0; + save->fp_gen_cntl = orig->fp_gen_cntl; + save->fp_gen_cntl &= ~(R128_FP_FPON | + R128_FP_CRTC_USE_SHADOW_VEND | + R128_FP_CRTC_HORZ_DIV2_EN | + R128_FP_CRTC_HOR_CRT_DIV2_DIS | + R128_FP_USE_SHADOW_EN); + save->fp_gen_cntl |= (R128_FP_SEL_CRTC2 | + R128_FP_CRTC_DONT_SHADOW_VPAR); + save->fp_panel_cntl = orig->fp_panel_cntl & (CARD32)~R128_FP_DIGON; + save->lvds_gen_cntl = orig->lvds_gen_cntl & + (CARD32)~(R128_LVDS_ON | R128_LVDS_BLON); + return; + } + + if (xres > info->PanelXRes) xres = info->PanelXRes; + if (yres > info->PanelYRes) yres = info->PanelYRes; + + Hratio = (float)xres/(float)info->PanelXRes; + Vratio = (float)yres/(float)info->PanelYRes; + + save->fp_horz_stretch = + (((((int)(Hratio * R128_HORZ_STRETCH_RATIO_MAX + 0.5)) + & R128_HORZ_STRETCH_RATIO_MASK) << R128_HORZ_STRETCH_RATIO_SHIFT) | + (orig->fp_horz_stretch & (R128_HORZ_PANEL_SIZE | + R128_HORZ_FP_LOOP_STRETCH | + R128_HORZ_STRETCH_RESERVED))); + save->fp_horz_stretch &= ~R128_HORZ_AUTO_RATIO_FIX_EN; + save->fp_horz_stretch &= ~R128_AUTO_HORZ_RATIO; + if (xres == info->PanelXRes) + save->fp_horz_stretch &= ~(R128_HORZ_STRETCH_BLEND | R128_HORZ_STRETCH_ENABLE); + else + save->fp_horz_stretch |= (R128_HORZ_STRETCH_BLEND | R128_HORZ_STRETCH_ENABLE); + + save->fp_vert_stretch = + (((((int)(Vratio * R128_VERT_STRETCH_RATIO_MAX + 0.5)) + & R128_VERT_STRETCH_RATIO_MASK) << R128_VERT_STRETCH_RATIO_SHIFT) | + (orig->fp_vert_stretch & (R128_VERT_PANEL_SIZE | + R128_VERT_STRETCH_RESERVED))); + save->fp_vert_stretch &= ~R128_VERT_AUTO_RATIO_EN; + if (yres == info->PanelYRes) + save->fp_vert_stretch &= ~(R128_VERT_STRETCH_ENABLE | R128_VERT_STRETCH_BLEND); + else + save->fp_vert_stretch |= (R128_VERT_STRETCH_ENABLE | R128_VERT_STRETCH_BLEND); + + save->fp_gen_cntl = (orig->fp_gen_cntl & + (CARD32)~(R128_FP_SEL_CRTC2 | + R128_FP_CRTC_USE_SHADOW_VEND | + R128_FP_CRTC_HORZ_DIV2_EN | + R128_FP_CRTC_HOR_CRT_DIV2_DIS | + R128_FP_USE_SHADOW_EN)); + + save->fp_panel_cntl = orig->fp_panel_cntl; + save->lvds_gen_cntl = orig->lvds_gen_cntl; + save->tmds_crc = orig->tmds_crc; + + /* Disable CRT output by disabling CRT output and setting the CRT + DAC to use CRTC2, which we set to 0's. In the future, we will + want to use the dual CRTC capabilities of the R128 to allow both + the flat panel and external CRT to either simultaneously display + the same image or display two different images. */ + + if(!info->isDFP){ + if (info->BIOSDisplay == R128_BIOS_DISPLAY_FP_CRT) { + save->crtc_ext_cntl |= R128_CRTC_CRT_ON; + } else { + save->crtc_ext_cntl &= ~R128_CRTC_CRT_ON; + save->dac_cntl |= R128_DAC_CRT_SEL_CRTC2; + save->crtc2_gen_cntl = 0; + } + } + + /* WARNING: Be careful about turning on the flat panel */ + if(info->isDFP){ + save->fp_gen_cntl = orig->fp_gen_cntl; + + save->fp_gen_cntl &= ~(R128_FP_CRTC_USE_SHADOW_VEND | + R128_FP_CRTC_USE_SHADOW_ROWCUR | + R128_FP_CRTC_HORZ_DIV2_EN | + R128_FP_CRTC_HOR_CRT_DIV2_DIS | + R128_FP_CRT_SYNC_SEL | + R128_FP_USE_SHADOW_EN); + + save->fp_panel_cntl |= (R128_FP_DIGON | R128_FP_BLON); + save->fp_gen_cntl |= (R128_FP_FPON | R128_FP_TDMS_EN | + R128_FP_CRTC_DONT_SHADOW_VPAR | R128_FP_CRTC_DONT_SHADOW_HEND); + save->tmds_transmitter_cntl = (orig->tmds_transmitter_cntl + & ~(CARD32)R128_TMDS_PLLRST) | R128_TMDS_PLLEN; + } + else + save->lvds_gen_cntl |= (R128_LVDS_ON | R128_LVDS_BLON); + + save->fp_crtc_h_total_disp = save->crtc_h_total_disp; + save->fp_crtc_v_total_disp = save->crtc_v_total_disp; + save->fp_h_sync_strt_wid = save->crtc_h_sync_strt_wid; + save->fp_v_sync_strt_wid = save->crtc_v_sync_strt_wid; +} + +/* Define PLL registers for requested video mode. */ +static void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save, + R128PLLPtr pll, double dot_clock) +{ + unsigned long freq = dot_clock * 100; + struct { + int divider; + int bitvalue; + } *post_div, + post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + Reference Manual (Technical Reference + Manual P/N RRG-G04100-C Rev. 0.04), page + 3-17 (PLL_DIV_[3:0]). */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + + { 3, 4 }, /* VCLK_SRC/3 */ + /* bitvalue = 5 is reserved */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + + if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; + if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + save->pll_output_freq = post_div->divider * freq; + if (save->pll_output_freq >= pll->min_pll_freq + && save->pll_output_freq <= pll->max_pll_freq) break; + } + + save->dot_clock_freq = freq; + save->feedback_div = R128Div(pll->reference_div * save->pll_output_freq, + pll->reference_freq); + save->post_div = post_div->divider; + + R128TRACE(("dc=%d, of=%d, fd=%d, pd=%d\n", + save->dot_clock_freq, + save->pll_output_freq, + save->feedback_div, + save->post_div)); + + save->ppll_ref_div = pll->reference_div; + save->ppll_div_3 = (save->feedback_div | (post_div->bitvalue << 16)); + save->htotal_cntl = 0; + +} + +/* Define DDA registers for requested video mode. */ +static Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save, + R128PLLPtr pll, R128InfoPtr info, + DisplayModePtr mode) +{ + int DisplayFifoWidth = 128; + int DisplayFifoDepth = 32; + int XclkFreq; + int VclkFreq; + int XclksPerTransfer; + int XclksPerTransferPrecise; + int UseablePrecision; + int Roff; + int Ron; + + XclkFreq = pll->xclk; + + VclkFreq = R128Div(pll->reference_freq * save->feedback_div, + pll->reference_div * save->post_div); + + if(info->isDFP && !info->isPro2){ + if(info->PanelXRes != mode->CrtcHDisplay) + VclkFreq = (VclkFreq * mode->CrtcHDisplay)/info->PanelXRes; + } + + XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth, + VclkFreq * (info->CurrentLayout.pixel_bytes * 8)); + + UseablePrecision = R128MinBits(XclksPerTransfer) + 1; + + XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth) + << (11 - UseablePrecision), + VclkFreq * (info->CurrentLayout.pixel_bytes * 8)); + + Roff = XclksPerTransferPrecise * (DisplayFifoDepth - 4); + + Ron = (4 * info->ram->MB + + 3 * MAX(info->ram->Trcd - 2, 0) + + 2 * info->ram->Trp + + info->ram->Twr + + info->ram->CL + + info->ram->Tr2w + + XclksPerTransfer) << (11 - UseablePrecision); + + if (Ron + info->ram->Rloop >= Roff) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n", + Ron, info->ram->Rloop, Roff); + return FALSE; + } + + save->dda_config = (XclksPerTransferPrecise + | (UseablePrecision << 16) + | (info->ram->Rloop << 20)); + + save->dda_on_off = (Ron << 16) | Roff; + + R128TRACE(("XclkFreq = %d; VclkFreq = %d; per = %d, %d (useable = %d)\n", + XclkFreq, + VclkFreq, + XclksPerTransfer, + XclksPerTransferPrecise, + UseablePrecision)); + R128TRACE(("Roff = %d, Ron = %d, Rloop = %d\n", + Roff, Ron, info->ram->Rloop)); + + return TRUE; +} + + +#if 0 +/* Define initial palette for requested video mode. This doesn't do + anything for XFree86 4.0. */ +static void R128InitPalette(R128SavePtr save) +{ + save->palette_valid = FALSE; +} +#endif + +/* Define registers for a requested video mode. */ +static Bool R128Init(ScrnInfoPtr pScrn, DisplayModePtr mode, R128SavePtr save) +{ + R128InfoPtr info = R128PTR(pScrn); + double dot_clock = mode->Clock/1000.0; + +#if R128_DEBUG + ErrorF("%-12.12s %7.2f %4d %4d %4d %4d %4d %4d %4d %4d (%d,%d)", + mode->name, + dot_clock, + + mode->HDisplay, + mode->HSyncStart, + mode->HSyncEnd, + mode->HTotal, + + mode->VDisplay, + mode->VSyncStart, + mode->VSyncEnd, + mode->VTotal, + pScrn->depth, + pScrn->bitsPerPixel); + if (mode->Flags & V_DBLSCAN) ErrorF(" D"); + if (mode->Flags & V_CSYNC) ErrorF(" C"); + if (mode->Flags & V_INTERLACE) ErrorF(" I"); + if (mode->Flags & V_PHSYNC) ErrorF(" +H"); + if (mode->Flags & V_NHSYNC) ErrorF(" -H"); + if (mode->Flags & V_PVSYNC) ErrorF(" +V"); + if (mode->Flags & V_NVSYNC) ErrorF(" -V"); + ErrorF("\n"); + ErrorF("%-12.12s %7.2f %4d %4d %4d %4d %4d %4d %4d %4d (%d,%d)", + mode->name, + dot_clock, + + mode->CrtcHDisplay, + mode->CrtcHSyncStart, + mode->CrtcHSyncEnd, + mode->CrtcHTotal, + + mode->CrtcVDisplay, + mode->CrtcVSyncStart, + mode->CrtcVSyncEnd, + mode->CrtcVTotal, + pScrn->depth, + pScrn->bitsPerPixel); + if (mode->Flags & V_DBLSCAN) ErrorF(" D"); + if (mode->Flags & V_CSYNC) ErrorF(" C"); + if (mode->Flags & V_INTERLACE) ErrorF(" I"); + if (mode->Flags & V_PHSYNC) ErrorF(" +H"); + if (mode->Flags & V_NHSYNC) ErrorF(" -H"); + if (mode->Flags & V_PVSYNC) ErrorF(" +V"); + if (mode->Flags & V_NVSYNC) ErrorF(" -V"); + ErrorF("\n"); +#endif + + info->Flags = mode->Flags; + + R128InitCommonRegisters(save, info); + if (!R128InitCrtcRegisters(pScrn, save, mode, info)) return FALSE; + if (info->HasPanelRegs || info->isDFP) + R128InitFPRegisters(&info->SavedReg, save, mode, info); + if(dot_clock > 0){ + R128InitPLLRegisters(pScrn, save, &info->pll, dot_clock); + if (!R128InitDDARegisters(pScrn, save, &info->pll, info, mode)) + return FALSE; + } + else{ + save->ppll_ref_div = info->SavedReg.ppll_ref_div; + save->ppll_div_3 = info->SavedReg.ppll_div_3; + save->htotal_cntl = info->SavedReg.htotal_cntl; + save->dda_config = info->SavedReg.dda_config; + save->dda_on_off = info->SavedReg.dda_on_off; + } + + R128TRACE(("R128Init returns %p\n", save)); + return TRUE; +} + +/* Initialize a new mode. */ +static Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + R128InfoPtr info = R128PTR(pScrn); + + if (!R128Init(pScrn, mode, &info->ModeReg)) return FALSE; + /* FIXME? DRILock/DRIUnlock here? */ + pScrn->vtSema = TRUE; + R128Blank(pScrn); + R128RestoreMode(pScrn, &info->ModeReg); + R128Unblank(pScrn); + + info->CurrentLayout.mode = mode; + + return TRUE; +} + +static Bool R128SaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + Bool unblank; + + unblank = xf86IsUnblank(mode); + if (unblank) + SetTimeSinceLastInputEvent(); + + if ((pScrn != NULL) && pScrn->vtSema) { + if (unblank) + R128Unblank(pScrn); + else + R128Blank(pScrn); + } + return TRUE; +} + +Bool R128SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + return R128ModeInit(xf86Screens[scrnIndex], mode); +} + +/* Used to disallow modes that are not supported by the hardware. */ +ModeStatus R128ValidMode(int scrnIndex, DisplayModePtr mode, + Bool verbose, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + + if(info->isDFP) { + if(info->PanelXRes < mode->CrtcHDisplay || + info->PanelYRes < mode->CrtcVDisplay) + return MODE_NOMODE; + else + return MODE_OK; + } + + if (info->HasPanelRegs) { + if (mode->Flags & V_INTERLACE) return MODE_NO_INTERLACE; + if (mode->Flags & V_DBLSCAN) return MODE_NO_DBLESCAN; + } + + if (info->HasPanelRegs && + info->BIOSDisplay != R128_BIOS_DISPLAY_CRT && + info->VBIOS) { + int i; + for (i = info->FPBIOSstart+64; R128_BIOS16(i) != 0; i += 2) { + int j = R128_BIOS16(i); + + if (mode->CrtcHDisplay == R128_BIOS16(j) && + mode->CrtcVDisplay == R128_BIOS16(j+2)) { + if ((flags & MODECHECK_FINAL) == MODECHECK_FINAL) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Modifying mode according to VBIOS: %ix%i [pclk %.1f MHz] for FP to: ", + mode->CrtcHDisplay,mode->CrtcVDisplay, + (float)mode->Clock/1000); + + /* Assume we are using expanded mode */ + if (R128_BIOS16(j+5)) j = R128_BIOS16(j+5); + else j += 9; + + mode->Clock = (CARD32)R128_BIOS16(j) * 10; + + mode->HDisplay = mode->CrtcHDisplay = + ((R128_BIOS16(j+10) & 0x01ff)+1)*8; + mode->HSyncStart = mode->CrtcHSyncStart = + ((R128_BIOS16(j+12) & 0x01ff)+1)*8; + mode->HSyncEnd = mode->CrtcHSyncEnd = + mode->CrtcHSyncStart + (R128_BIOS8(j+14) & 0x1f); + mode->HTotal = mode->CrtcHTotal = + ((R128_BIOS16(j+8) & 0x01ff)+1)*8; + + mode->VDisplay = mode->CrtcVDisplay = + (R128_BIOS16(j+17) & 0x07ff)+1; + mode->VSyncStart = mode->CrtcVSyncStart = + (R128_BIOS16(j+19) & 0x07ff)+1; + mode->VSyncEnd = mode->CrtcVSyncEnd = + mode->CrtcVSyncStart + ((R128_BIOS16(j+19) >> 11) & 0x1f); + mode->VTotal = mode->CrtcVTotal = + (R128_BIOS16(j+15) & 0x07ff)+1; + xf86ErrorF("%ix%i [pclk %.1f MHz]\n", + mode->CrtcHDisplay,mode->CrtcVDisplay, + (float)mode->Clock/1000); + } + return MODE_OK; + } + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 5, + "Mode rejected for FP %ix%i [pclk: %.1f] " + "(not listed in VBIOS)\n", + mode->CrtcHDisplay, mode->CrtcVDisplay, + (float)mode->Clock / 1000); + return MODE_NOMODE; + } + + return MODE_OK; +} + +/* Adjust viewport into virtual desktop such that (0,0) in viewport space + is (x,y) in virtual space. */ +void R128AdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int Base; + + if(info->showCache && y && pScrn->vtSema) + y += pScrn->virtualY - 1; + + Base = y * info->CurrentLayout.displayWidth + x; + + switch (info->CurrentLayout.pixel_code) { + case 15: + case 16: Base *= 2; break; + case 24: Base *= 3; break; + case 32: Base *= 4; break; + } + + Base &= ~7; /* 3 lower bits are always 0 */ + + if (info->CurrentLayout.pixel_code == 24) + Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */ + + OUTREG(R128_CRTC_OFFSET, Base); +} + +/* Called when VT switching back to the X server. Reinitialize the video + mode. */ +Bool R128EnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + + R128TRACE(("R128EnterVT\n")); + if (info->FBDev) { + if (!fbdevHWEnterVT(scrnIndex,flags)) return FALSE; + } else + if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE; + if (info->accelOn) + R128EngineInit(pScrn); + +#ifdef XF86DRI + if (info->directRenderingEnabled) { + if (info->irq) { + /* Need to make sure interrupts are enabled */ + unsigned char *R128MMIO = info->MMIO; + OUTREG(R128_GEN_INT_CNTL, info->gen_int_cntl); + } + R128CCE_START(pScrn, info); + DRIUnlock(pScrn->pScreen); + } +#endif + + info->PaletteSavedOnVT = FALSE; + pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + return TRUE; +} + +/* Called when VT switching away from the X server. Restore the original + text mode. */ +void R128LeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + R128SavePtr save = &info->ModeReg; + + R128TRACE(("R128LeaveVT\n")); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + DRILock(pScrn->pScreen, 0); + R128CCE_STOP(pScrn, info); + } +#endif + R128SavePalette(pScrn, save); + info->PaletteSavedOnVT = TRUE; + if (info->FBDev) + fbdevHWLeaveVT(scrnIndex,flags); + else + R128Restore(pScrn); +} + + +/* Called at the end of each server generation. Restore the original text + mode, unmap video memory, and unwrap and call the saved CloseScreen + function. */ +static Bool R128CloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + + R128TRACE(("R128CloseScreen\n")); + +#ifdef XF86DRI + /* Disable direct rendering */ + if (info->directRenderingEnabled) { + R128DRICloseScreen(pScreen); + info->directRenderingEnabled = FALSE; + } +#endif + + if (pScrn->vtSema) { + R128Restore(pScrn); + R128UnmapMem(pScrn); + } + + if (info->accel) XAADestroyInfoRec(info->accel); + info->accel = NULL; + + if (info->scratch_save) xfree(info->scratch_save); + info->scratch_save = NULL; + + if (info->cursor) xf86DestroyCursorInfoRec(info->cursor); + info->cursor = NULL; + + if (info->DGAModes) xfree(info->DGAModes); + info->DGAModes = NULL; + + if (info->adaptor) { + xfree(info->adaptor->pPortPrivates[0].ptr); + xf86XVFreeVideoAdaptorRec(info->adaptor); + info->adaptor = NULL; + } + + pScrn->vtSema = FALSE; + + pScreen->BlockHandler = info->BlockHandler; + pScreen->CloseScreen = info->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + +void R128FreeScreen(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + R128TRACE(("R128FreeScreen\n")); + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(pScrn); + R128FreeRec(pScrn); +} + +/* Sets VESA Display Power Management Signaling (DPMS) Mode. */ +static void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int mask = (R128_CRTC_DISPLAY_DIS + | R128_CRTC_HSYNC_DIS + | R128_CRTC_VSYNC_DIS); + + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask); + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + OUTREGP(R128_CRTC_EXT_CNTL, + R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask); + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + OUTREGP(R128_CRTC_EXT_CNTL, + R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask); + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask); + break; + } +} + +static int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on); + +static void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int mask = R128_LVDS_DISPLAY_DIS; + + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + OUTREGP(R128_LVDS_GEN_CNTL, 0, ~mask); + r128_set_backlight_enable(pScrn, 1); + break; + case DPMSModeStandby: + /* Fall through */ + case DPMSModeSuspend: + /* Fall through */ + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + OUTREGP(R128_LVDS_GEN_CNTL, mask, ~mask); + r128_set_backlight_enable(pScrn, 0); + break; + } +} + +static int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + unsigned int lvds_gen_cntl = INREG(R128_LVDS_GEN_CNTL); + + lvds_gen_cntl |= (/*R128_LVDS_BL_MOD_EN |*/ R128_LVDS_BLON); + if (on) { + lvds_gen_cntl |= R128_LVDS_DIGON; + if (!lvds_gen_cntl & R128_LVDS_ON) { + lvds_gen_cntl &= ~R128_LVDS_BLON; + OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl); + (void)INREG(R128_LVDS_GEN_CNTL); + usleep(10000); + lvds_gen_cntl |= R128_LVDS_BLON; + OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl); + } +#if 0 + lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (0xFF /* backlight_conv[level] */ << + R128_LVDS_BL_MOD_LEVEL_SHIFT); +#endif + lvds_gen_cntl |= (R128_LVDS_ON | R128_LVDS_EN); + lvds_gen_cntl &= ~R128_LVDS_DISPLAY_DIS; + } else { +#if 0 + lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (0xFF /* backlight_conv[0] */ << + R128_LVDS_BL_MOD_LEVEL_SHIFT); +#endif + lvds_gen_cntl |= R128_LVDS_DISPLAY_DIS; + OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl); + usleep(10); + lvds_gen_cntl &= ~(R128_LVDS_ON | R128_LVDS_EN | R128_LVDS_BLON + | R128_LVDS_DIGON); + } + + OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl); + + return 0; + } diff --git a/src/r128_misc.c b/src/r128_misc.c new file mode 100644 index 0000000..30202b3 --- /dev/null +++ b/src/r128_misc.c @@ -0,0 +1,87 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_misc.c,v 1.5 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifdef XFree86LOADER + +#include "ativersion.h" + +#include "r128_probe.h" +#include "r128_version.h" + +#include "xf86.h" + +/* Module loader interface for subsidiary driver module */ + +static XF86ModuleVersionInfo R128VersionRec = +{ + R128_DRIVER_NAME, + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + R128_VERSION_MAJOR, R128_VERSION_MINOR, R128_VERSION_PATCH, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +/* + * R128Setup -- + * + * This function is called every time the module is loaded. + */ +static pointer +R128Setup +( + pointer Module, + pointer Options, + int *ErrorMajor, + int *ErrorMinor +) +{ + static Bool Inited = FALSE; + + if (!Inited) + { + /* Ensure main driver module is loaded, but not as a submodule */ + if (!xf86ServerIsOnlyDetecting() && !LoaderSymbol(ATI_NAME)) + xf86LoadOneModule(ATI_DRIVER_NAME, Options); + + R128LoaderRefSymLists(); + + Inited = TRUE; + } + + return (pointer)TRUE; +} + +/* The following record must be called r128ModuleData */ +XF86ModuleData r128ModuleData = +{ + &R128VersionRec, + R128Setup, + NULL +}; + +#endif /* XFree86LOADER */ diff --git a/src/r128_probe.c b/src/r128_probe.c new file mode 100644 index 0000000..d017b35 --- /dev/null +++ b/src/r128_probe.c @@ -0,0 +1,308 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_probe.c,v 1.17 2003/02/07 20:41:15 martin Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + * Modified by Marc Aurele La France <tsi@xfree86.org> for ATI driver merge. + */ + +#include "atimodule.h" +#include "ativersion.h" + +#include "r128_probe.h" +#include "r128_version.h" + +#include "xf86PciInfo.h" + +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86Resources.h" + +#ifdef XFree86LOADER + +/* + * The following exists to prevent the compiler from considering entry points + * defined in a separate module from being constants. + */ +static xf86PreInitProc * const volatile PreInitProc = R128PreInit; +static xf86ScreenInitProc * const volatile ScreenInitProc = R128ScreenInit; +static xf86SwitchModeProc * const volatile SwitchModeProc = R128SwitchMode; +static xf86AdjustFrameProc * const volatile AdjustFrameProc = R128AdjustFrame; +static xf86EnterVTProc * const volatile EnterVTProc = R128EnterVT; +static xf86LeaveVTProc * const volatile LeaveVTProc = R128LeaveVT; +static xf86FreeScreenProc * const volatile FreeScreenProc = R128FreeScreen; +static xf86ValidModeProc * const volatile ValidModeProc = R128ValidMode; + +#define R128PreInit PreInitProc +#define R128ScreenInit ScreenInitProc +#define R128SwitchMode SwitchModeProc +#define R128AdjustFrame AdjustFrameProc +#define R128EnterVT EnterVTProc +#define R128LeaveVT LeaveVTProc +#define R128FreeScreen FreeScreenProc +#define R128ValidMode ValidModeProc + +#endif + +SymTabRec R128Chipsets[] = { + /* FIXME: The chipsets with (PCI/AGP) are not known wether they are AGP or + * PCI, so I've labeled them as such in hopes users will submit + * data if we're unable to gather it from official documentation + */ + { PCI_CHIP_RAGE128LE, "ATI Rage 128 Mobility M3 LE (PCI)" }, + { PCI_CHIP_RAGE128LF, "ATI Rage 128 Mobility M3 LF (AGP)" }, + { PCI_CHIP_RAGE128MF, "ATI Rage 128 Mobility M4 MF (AGP)" }, + { PCI_CHIP_RAGE128ML, "ATI Rage 128 Mobility M4 ML (AGP)" }, + { PCI_CHIP_RAGE128PA, "ATI Rage 128 Pro GL PA (PCI/AGP)" }, + { PCI_CHIP_RAGE128PB, "ATI Rage 128 Pro GL PB (PCI/AGP)" }, + { PCI_CHIP_RAGE128PC, "ATI Rage 128 Pro GL PC (PCI/AGP)" }, + { PCI_CHIP_RAGE128PD, "ATI Rage 128 Pro GL PD (PCI)" }, + { PCI_CHIP_RAGE128PE, "ATI Rage 128 Pro GL PE (PCI/AGP)" }, + { PCI_CHIP_RAGE128PF, "ATI Rage 128 Pro GL PF (AGP)" }, + { PCI_CHIP_RAGE128PG, "ATI Rage 128 Pro VR PG (PCI/AGP)" }, + { PCI_CHIP_RAGE128PH, "ATI Rage 128 Pro VR PH (PCI/AGP)" }, + { PCI_CHIP_RAGE128PI, "ATI Rage 128 Pro VR PI (PCI/AGP)" }, + { PCI_CHIP_RAGE128PJ, "ATI Rage 128 Pro VR PJ (PCI/AGP)" }, + { PCI_CHIP_RAGE128PK, "ATI Rage 128 Pro VR PK (PCI/AGP)" }, + { PCI_CHIP_RAGE128PL, "ATI Rage 128 Pro VR PL (PCI/AGP)" }, + { PCI_CHIP_RAGE128PM, "ATI Rage 128 Pro VR PM (PCI/AGP)" }, + { PCI_CHIP_RAGE128PN, "ATI Rage 128 Pro VR PN (PCI/AGP)" }, + { PCI_CHIP_RAGE128PO, "ATI Rage 128 Pro VR PO (PCI/AGP)" }, + { PCI_CHIP_RAGE128PP, "ATI Rage 128 Pro VR PP (PCI)" }, + { PCI_CHIP_RAGE128PQ, "ATI Rage 128 Pro VR PQ (PCI/AGP)" }, + { PCI_CHIP_RAGE128PR, "ATI Rage 128 Pro VR PR (PCI)" }, + { PCI_CHIP_RAGE128PS, "ATI Rage 128 Pro VR PS (PCI/AGP)" }, + { PCI_CHIP_RAGE128PT, "ATI Rage 128 Pro VR PT (PCI/AGP)" }, + { PCI_CHIP_RAGE128PU, "ATI Rage 128 Pro VR PU (PCI/AGP)" }, + { PCI_CHIP_RAGE128PV, "ATI Rage 128 Pro VR PV (PCI/AGP)" }, + { PCI_CHIP_RAGE128PW, "ATI Rage 128 Pro VR PW (PCI/AGP)" }, + { PCI_CHIP_RAGE128PX, "ATI Rage 128 Pro VR PX (PCI/AGP)" }, + { PCI_CHIP_RAGE128RE, "ATI Rage 128 GL RE (PCI)" }, + { PCI_CHIP_RAGE128RF, "ATI Rage 128 GL RF (AGP)" }, + { PCI_CHIP_RAGE128RG, "ATI Rage 128 RG (AGP)" }, + { PCI_CHIP_RAGE128RK, "ATI Rage 128 VR RK (PCI)" }, + { PCI_CHIP_RAGE128RL, "ATI Rage 128 VR RL (AGP)" }, + { PCI_CHIP_RAGE128SE, "ATI Rage 128 4X SE (PCI/AGP)" }, + { PCI_CHIP_RAGE128SF, "ATI Rage 128 4X SF (PCI/AGP)" }, + { PCI_CHIP_RAGE128SG, "ATI Rage 128 4X SG (PCI/AGP)" }, + { PCI_CHIP_RAGE128SH, "ATI Rage 128 4X SH (PCI/AGP)" }, + { PCI_CHIP_RAGE128SK, "ATI Rage 128 4X SK (PCI/AGP)" }, + { PCI_CHIP_RAGE128SL, "ATI Rage 128 4X SL (PCI/AGP)" }, + { PCI_CHIP_RAGE128SM, "ATI Rage 128 4X SM (AGP)" }, + { PCI_CHIP_RAGE128SN, "ATI Rage 128 4X SN (PCI/AGP)" }, + { PCI_CHIP_RAGE128TF, "ATI Rage 128 Pro ULTRA TF (AGP)" }, + { PCI_CHIP_RAGE128TL, "ATI Rage 128 Pro ULTRA TL (AGP)" }, + { PCI_CHIP_RAGE128TR, "ATI Rage 128 Pro ULTRA TR (AGP)" }, + { PCI_CHIP_RAGE128TS, "ATI Rage 128 Pro ULTRA TS (AGP?)" }, + { PCI_CHIP_RAGE128TT, "ATI Rage 128 Pro ULTRA TT (AGP?)" }, + { PCI_CHIP_RAGE128TU, "ATI Rage 128 Pro ULTRA TU (AGP?)" }, + { -1, NULL } +}; + +PciChipsets R128PciChipsets[] = { + { PCI_CHIP_RAGE128LE, PCI_CHIP_RAGE128LE, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128LF, PCI_CHIP_RAGE128LF, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128MF, PCI_CHIP_RAGE128MF, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128ML, PCI_CHIP_RAGE128ML, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PA, PCI_CHIP_RAGE128PA, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PB, PCI_CHIP_RAGE128PB, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PC, PCI_CHIP_RAGE128PC, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PD, PCI_CHIP_RAGE128PD, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PE, PCI_CHIP_RAGE128PE, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PF, PCI_CHIP_RAGE128PF, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PG, PCI_CHIP_RAGE128PG, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PH, PCI_CHIP_RAGE128PH, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PI, PCI_CHIP_RAGE128PI, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PJ, PCI_CHIP_RAGE128PJ, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PK, PCI_CHIP_RAGE128PK, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PL, PCI_CHIP_RAGE128PL, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PM, PCI_CHIP_RAGE128PM, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PN, PCI_CHIP_RAGE128PN, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PO, PCI_CHIP_RAGE128PO, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PP, PCI_CHIP_RAGE128PP, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PQ, PCI_CHIP_RAGE128PQ, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PR, PCI_CHIP_RAGE128PR, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PS, PCI_CHIP_RAGE128PS, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PT, PCI_CHIP_RAGE128PT, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PU, PCI_CHIP_RAGE128PU, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PV, PCI_CHIP_RAGE128PV, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PW, PCI_CHIP_RAGE128PW, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128PX, PCI_CHIP_RAGE128PX, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128RE, PCI_CHIP_RAGE128RE, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128RF, PCI_CHIP_RAGE128RF, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128RG, PCI_CHIP_RAGE128RG, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128RK, PCI_CHIP_RAGE128RK, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128RL, PCI_CHIP_RAGE128RL, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SE, PCI_CHIP_RAGE128SE, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SF, PCI_CHIP_RAGE128SF, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SG, PCI_CHIP_RAGE128SG, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SH, PCI_CHIP_RAGE128SH, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SK, PCI_CHIP_RAGE128SK, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SL, PCI_CHIP_RAGE128SL, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SM, PCI_CHIP_RAGE128SM, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128SN, PCI_CHIP_RAGE128SN, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128TF, PCI_CHIP_RAGE128TF, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128TL, PCI_CHIP_RAGE128TL, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128TR, PCI_CHIP_RAGE128TR, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128TS, PCI_CHIP_RAGE128TS, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128TT, PCI_CHIP_RAGE128TT, RES_SHARED_VGA }, + { PCI_CHIP_RAGE128TU, PCI_CHIP_RAGE128TU, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED } +}; + +/* Return the options for supported chipset 'n'; NULL otherwise */ +const OptionInfoRec * +R128AvailableOptions(int chipid, int busid) +{ + int i; + + /* + * Return options defined in the r128 submodule which will have been + * loaded by this point. + */ + if ((chipid >> 16) == PCI_VENDOR_ATI) + chipid -= PCI_VENDOR_ATI << 16; + for (i = 0; R128PciChipsets[i].PCIid > 0; i++) { + if (chipid == R128PciChipsets[i].PCIid) + return R128Options; + } + return NULL; +} + +/* Return the string name for supported chipset 'n'; NULL otherwise. */ +void +R128Identify(int flags) +{ + xf86PrintChipsets(R128_NAME, + "Driver for ATI Rage 128 chipsets", + R128Chipsets); +} + +/* Return TRUE if chipset is present; FALSE otherwise. */ +Bool +R128Probe(DriverPtr drv, int flags) +{ + int numUsed; + int numDevSections, nATIGDev, nR128GDev; + int *usedChips; + GDevPtr *devSections, *ATIGDevs, *R128GDevs; + EntityInfoPtr pEnt; + Bool foundScreen = FALSE; + int i; + + if (!xf86GetPciVideoInfo()) return FALSE; + + /* Collect unclaimed device sections for both driver names */ + nATIGDev = xf86MatchDevice(ATI_NAME, &ATIGDevs); + nR128GDev = xf86MatchDevice(R128_NAME, &R128GDevs); + + if (!(numDevSections = nATIGDev + nR128GDev)) return FALSE; + + if (!ATIGDevs) { + if (!(devSections = R128GDevs)) + numDevSections = 1; + else + numDevSections = nR128GDev; + } if (!R128GDevs) { + devSections = ATIGDevs; + numDevSections = nATIGDev; + } else { + /* Combine into one list */ + devSections = xnfalloc((numDevSections + 1) * sizeof(GDevPtr)); + (void)memcpy(devSections, + ATIGDevs, nATIGDev * sizeof(GDevPtr)); + (void)memcpy(devSections + nATIGDev, + R128GDevs, nR128GDev * sizeof(GDevPtr)); + devSections[numDevSections] = NULL; + xfree(ATIGDevs); + xfree(R128GDevs); + } + + numUsed = xf86MatchPciInstances(R128_NAME, + PCI_VENDOR_ATI, + R128Chipsets, + R128PciChipsets, + devSections, + numDevSections, + drv, + &usedChips); + + if (numUsed<=0) return FALSE; + + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i = 0; i < numUsed; i++) { + pEnt = xf86GetEntityInfo(usedChips[i]); + + if (pEnt->active) { + ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0); + +#ifdef XFree86LOADER + + if (!xf86LoadSubModule(pScrn, "r128")) { + xf86Msg(X_ERROR, + R128_NAME ": Failed to load \"r128\" module.\n"); + xf86DeleteScreen(pScrn->scrnIndex, 0); + continue; + } + + xf86LoaderReqSymLists(R128Symbols, NULL); + +#endif + + pScrn->driverVersion = R128_VERSION_CURRENT; + pScrn->driverName = R128_DRIVER_NAME; + pScrn->name = R128_NAME; + pScrn->Probe = R128Probe; + pScrn->PreInit = R128PreInit; + pScrn->ScreenInit = R128ScreenInit; + pScrn->SwitchMode = R128SwitchMode; + pScrn->AdjustFrame = R128AdjustFrame; + pScrn->EnterVT = R128EnterVT; + pScrn->LeaveVT = R128LeaveVT; + pScrn->FreeScreen = R128FreeScreen; + pScrn->ValidMode = R128ValidMode; + + foundScreen = TRUE; + + xf86ConfigActivePciEntity(pScrn, usedChips[i], R128PciChipsets, + 0, 0, 0, 0, 0); + } + xfree(pEnt); + } + + xfree(usedChips); + xfree(devSections); + + return foundScreen; +} diff --git a/src/r128_probe.h b/src/r128_probe.h new file mode 100644 index 0000000..247a8f5 --- /dev/null +++ b/src/r128_probe.h @@ -0,0 +1,78 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_probe.h,v 1.6 2002/04/06 19:06:06 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * + * Modified by Marc Aurele La France <tsi@xfree86.org> for ATI driver merge. + */ + +#ifndef _R128_PROBE_H_ +#define _R128_PROBE_H_ 1 + +#include "atiproto.h" + +#include "xf86str.h" + +/* r128_probe.c */ +extern const OptionInfoRec * R128AvailableOptions + FunctionPrototype((int, int)); +extern void R128Identify + FunctionPrototype((int)); +extern Bool R128Probe + FunctionPrototype((DriverPtr, int)); + +extern SymTabRec R128Chipsets[]; +extern PciChipsets R128PciChipsets[]; + +/* r128_driver.c */ +extern void R128LoaderRefSymLists + FunctionPrototype((void)); +extern Bool R128PreInit + FunctionPrototype((ScrnInfoPtr, int)); +extern Bool R128ScreenInit + FunctionPrototype((int, ScreenPtr, int, char **)); +extern Bool R128SwitchMode + FunctionPrototype((int, DisplayModePtr, int)); +extern void R128AdjustFrame + FunctionPrototype((int, int, int, int)); +extern Bool R128EnterVT + FunctionPrototype((int, int)); +extern void R128LeaveVT + FunctionPrototype((int, int)); +extern void R128FreeScreen + FunctionPrototype((int, int)); +extern ModeStatus R128ValidMode + FunctionPrototype((int, DisplayModePtr, Bool, + int)); + +extern const OptionInfoRec R128Options[]; + +#endif /* _R128_PROBE_H_ */ diff --git a/src/r128_reg.h b/src/r128_reg.h new file mode 100644 index 0000000..a0f21cf --- /dev/null +++ b/src/r128_reg.h @@ -0,0 +1,1511 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_reg.h,v 1.16 2003/04/06 20:36:36 martin Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + * References: + * + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +#ifndef _R128_REG_H_ +#define _R128_REG_H_ + +#ifdef XFree86Module +#include "xf86_ansic.h" +#endif +#include "compiler.h" + + /* Memory mapped register access macros */ +#define INREG8(addr) MMIO_IN8(R128MMIO, addr) +#define INREG16(addr) MMIO_IN16(R128MMIO, addr) +#define INREG(addr) MMIO_IN32(R128MMIO, addr) +#define OUTREG8(addr, val) MMIO_OUT8(R128MMIO, addr, val) +#define OUTREG16(addr, val) MMIO_OUT16(R128MMIO, addr, val) +#define OUTREG(addr, val) MMIO_OUT32(R128MMIO, addr, val) + +#define ADDRREG(addr) ((volatile CARD32 *)(pointer)(R128MMIO + (addr))) + + +#define OUTREGP(addr, val, mask) \ + do { \ + CARD32 tmp = INREG(addr); \ + tmp &= (mask); \ + tmp |= (val); \ + OUTREG(addr, tmp); \ + } while (0) + +#define INPLL(pScrn, addr) R128INPLL(pScrn, addr) + +#define OUTPLL(addr, val) \ + do { \ + OUTREG8(R128_CLOCK_CNTL_INDEX, ((addr) & 0x1f) | R128_PLL_WR_EN); \ + OUTREG(R128_CLOCK_CNTL_DATA, val); \ + } while (0) + +#define OUTPLLP(pScrn, addr, val, mask) \ + do { \ + CARD32 tmp = INPLL(pScrn, addr); \ + tmp &= (mask); \ + tmp |= (val); \ + OUTPLL(addr, tmp); \ + } while (0) + +#define OUTPAL_START(idx) \ + do { \ + OUTREG8(R128_PALETTE_INDEX, (idx)); \ + } while (0) + +#define OUTPAL_NEXT(r, g, b) \ + do { \ + OUTREG(R128_PALETTE_DATA, ((r) << 16) | ((g) << 8) | (b)); \ + } while (0) + +#define OUTPAL_NEXT_CARD32(v) \ + do { \ + OUTREG(R128_PALETTE_DATA, (v & 0x00ffffff)); \ + } while (0) + +#define OUTPAL(idx, r, g, b) \ + do { \ + OUTPAL_START((idx)); \ + OUTPAL_NEXT((r), (g), (b)); \ + } while (0) + +#define INPAL_START(idx) \ + do { \ + OUTREG(R128_PALETTE_INDEX, (idx) << 16); \ + } while (0) + +#define INPAL_NEXT() INREG(R128_PALETTE_DATA) + +#define PAL_SELECT(idx) \ + do { \ + CARD32 tmp = INREG(R128_DAC_CNTL); \ + if (idx) { \ + OUTREG(R128_DAC_CNTL, tmp | R128_DAC_PALETTE_ACC_CTL); \ + } else { \ + OUTREG(R128_DAC_CNTL, tmp & \ + (CARD32)~R128_DAC_PALETTE_ACC_CTL); \ + } \ + } while (0) + +#define R128_ADAPTER_ID 0x0f2c /* PCI */ +#define R128_AGP_APER_OFFSET 0x0178 +#define R128_AGP_BASE 0x0170 +#define R128_AGP_CNTL 0x0174 +# define R128_AGP_APER_SIZE_256MB (0x00 << 0) +# define R128_AGP_APER_SIZE_128MB (0x20 << 0) +# define R128_AGP_APER_SIZE_64MB (0x30 << 0) +# define R128_AGP_APER_SIZE_32MB (0x38 << 0) +# define R128_AGP_APER_SIZE_16MB (0x3c << 0) +# define R128_AGP_APER_SIZE_8MB (0x3e << 0) +# define R128_AGP_APER_SIZE_4MB (0x3f << 0) +# define R128_AGP_APER_SIZE_MASK (0x3f << 0) +#define R128_AGP_CNTL_B 0x0b44 +#define R128_AGP_COMMAND 0x0f58 /* PCI */ +#define R128_AGP_PLL_CNTL 0x0010 /* PLL */ +#define R128_AGP_STATUS 0x0f54 /* PCI */ +# define R128_AGP_1X_MODE 0x01 +# define R128_AGP_2X_MODE 0x02 +# define R128_AGP_4X_MODE 0x04 +# define R128_AGP_MODE_MASK 0x07 +#define R128_AMCGPIO_A_REG 0x01a0 +#define R128_AMCGPIO_EN_REG 0x01a8 +#define R128_AMCGPIO_MASK 0x0194 +#define R128_AMCGPIO_Y_REG 0x01a4 +#define R128_ATTRDR 0x03c1 /* VGA */ +#define R128_ATTRDW 0x03c0 /* VGA */ +#define R128_ATTRX 0x03c0 /* VGA */ +#define R128_AUX_SC_CNTL 0x1660 +# define R128_AUX1_SC_EN (1 << 0) +# define R128_AUX1_SC_MODE_OR (0 << 1) +# define R128_AUX1_SC_MODE_NAND (1 << 1) +# define R128_AUX2_SC_EN (1 << 2) +# define R128_AUX2_SC_MODE_OR (0 << 3) +# define R128_AUX2_SC_MODE_NAND (1 << 3) +# define R128_AUX3_SC_EN (1 << 4) +# define R128_AUX3_SC_MODE_OR (0 << 5) +# define R128_AUX3_SC_MODE_NAND (1 << 5) +#define R128_AUX1_SC_BOTTOM 0x1670 +#define R128_AUX1_SC_LEFT 0x1664 +#define R128_AUX1_SC_RIGHT 0x1668 +#define R128_AUX1_SC_TOP 0x166c +#define R128_AUX2_SC_BOTTOM 0x1680 +#define R128_AUX2_SC_LEFT 0x1674 +#define R128_AUX2_SC_RIGHT 0x1678 +#define R128_AUX2_SC_TOP 0x167c +#define R128_AUX3_SC_BOTTOM 0x1690 +#define R128_AUX3_SC_LEFT 0x1684 +#define R128_AUX3_SC_RIGHT 0x1688 +#define R128_AUX3_SC_TOP 0x168c +#define R128_AUX_WINDOW_HORZ_CNTL 0x02d8 +#define R128_AUX_WINDOW_VERT_CNTL 0x02dc + +#define R128_BASE_CODE 0x0f0b +#define R128_BIOS_0_SCRATCH 0x0010 +#define R128_BIOS_1_SCRATCH 0x0014 +#define R128_BIOS_2_SCRATCH 0x0018 +#define R128_BIOS_3_SCRATCH 0x001c +#define R128_BIOS_4_SCRATCH 0x0020 +#define R128_BIOS_5_SCRATCH 0x0024 +# define R128_BIOS_DISPLAY_FP (1 << 0) +# define R128_BIOS_DISPLAY_CRT (2 << 0) +# define R128_BIOS_DISPLAY_FP_CRT (3 << 0) +#define R128_BIOS_6_SCRATCH 0x0028 +#define R128_BIOS_7_SCRATCH 0x002c +#define R128_BIOS_ROM 0x0f30 /* PCI */ +#define R128_BIST 0x0f0f /* PCI */ +#define R128_BM_CHUNK_0_VAL 0x0a18 +# define R128_BM_PTR_FORCE_TO_PCI (1 << 21) +# define R128_BM_PM4_RD_FORCE_TO_PCI (1 << 22) +# define R128_BM_GLOBAL_FORCE_TO_PCI (1 << 23) +#define R128_BRUSH_DATA0 0x1480 +#define R128_BRUSH_DATA1 0x1484 +#define R128_BRUSH_DATA10 0x14a8 +#define R128_BRUSH_DATA11 0x14ac +#define R128_BRUSH_DATA12 0x14b0 +#define R128_BRUSH_DATA13 0x14b4 +#define R128_BRUSH_DATA14 0x14b8 +#define R128_BRUSH_DATA15 0x14bc +#define R128_BRUSH_DATA16 0x14c0 +#define R128_BRUSH_DATA17 0x14c4 +#define R128_BRUSH_DATA18 0x14c8 +#define R128_BRUSH_DATA19 0x14cc +#define R128_BRUSH_DATA2 0x1488 +#define R128_BRUSH_DATA20 0x14d0 +#define R128_BRUSH_DATA21 0x14d4 +#define R128_BRUSH_DATA22 0x14d8 +#define R128_BRUSH_DATA23 0x14dc +#define R128_BRUSH_DATA24 0x14e0 +#define R128_BRUSH_DATA25 0x14e4 +#define R128_BRUSH_DATA26 0x14e8 +#define R128_BRUSH_DATA27 0x14ec +#define R128_BRUSH_DATA28 0x14f0 +#define R128_BRUSH_DATA29 0x14f4 +#define R128_BRUSH_DATA3 0x148c +#define R128_BRUSH_DATA30 0x14f8 +#define R128_BRUSH_DATA31 0x14fc +#define R128_BRUSH_DATA32 0x1500 +#define R128_BRUSH_DATA33 0x1504 +#define R128_BRUSH_DATA34 0x1508 +#define R128_BRUSH_DATA35 0x150c +#define R128_BRUSH_DATA36 0x1510 +#define R128_BRUSH_DATA37 0x1514 +#define R128_BRUSH_DATA38 0x1518 +#define R128_BRUSH_DATA39 0x151c +#define R128_BRUSH_DATA4 0x1490 +#define R128_BRUSH_DATA40 0x1520 +#define R128_BRUSH_DATA41 0x1524 +#define R128_BRUSH_DATA42 0x1528 +#define R128_BRUSH_DATA43 0x152c +#define R128_BRUSH_DATA44 0x1530 +#define R128_BRUSH_DATA45 0x1534 +#define R128_BRUSH_DATA46 0x1538 +#define R128_BRUSH_DATA47 0x153c +#define R128_BRUSH_DATA48 0x1540 +#define R128_BRUSH_DATA49 0x1544 +#define R128_BRUSH_DATA5 0x1494 +#define R128_BRUSH_DATA50 0x1548 +#define R128_BRUSH_DATA51 0x154c +#define R128_BRUSH_DATA52 0x1550 +#define R128_BRUSH_DATA53 0x1554 +#define R128_BRUSH_DATA54 0x1558 +#define R128_BRUSH_DATA55 0x155c +#define R128_BRUSH_DATA56 0x1560 +#define R128_BRUSH_DATA57 0x1564 +#define R128_BRUSH_DATA58 0x1568 +#define R128_BRUSH_DATA59 0x156c +#define R128_BRUSH_DATA6 0x1498 +#define R128_BRUSH_DATA60 0x1570 +#define R128_BRUSH_DATA61 0x1574 +#define R128_BRUSH_DATA62 0x1578 +#define R128_BRUSH_DATA63 0x157c +#define R128_BRUSH_DATA7 0x149c +#define R128_BRUSH_DATA8 0x14a0 +#define R128_BRUSH_DATA9 0x14a4 +#define R128_BRUSH_SCALE 0x1470 +#define R128_BRUSH_Y_X 0x1474 +#define R128_BUS_CNTL 0x0030 +# define R128_BUS_MASTER_DIS (1 << 6) +# define R128_BUS_RD_DISCARD_EN (1 << 24) +# define R128_BUS_RD_ABORT_EN (1 << 25) +# define R128_BUS_MSTR_DISCONNECT_EN (1 << 28) +# define R128_BUS_WRT_BURST (1 << 29) +# define R128_BUS_READ_BURST (1 << 30) +#define R128_BUS_CNTL1 0x0034 +# define R128_BUS_WAIT_ON_LOCK_EN (1 << 4) + +#define R128_CACHE_CNTL 0x1724 +#define R128_CACHE_LINE 0x0f0c /* PCI */ +#define R128_CAP0_TRIG_CNTL 0x0950 /* ? */ +#define R128_CAP1_TRIG_CNTL 0x09c0 /* ? */ +#define R128_CAPABILITIES_ID 0x0f50 /* PCI */ +#define R128_CAPABILITIES_PTR 0x0f34 /* PCI */ +#define R128_CLK_PIN_CNTL 0x0001 /* PLL */ +#define R128_CLOCK_CNTL_DATA 0x000c +#define R128_CLOCK_CNTL_INDEX 0x0008 +# define R128_PLL_WR_EN (1 << 7) +# define R128_PLL_DIV_SEL (3 << 8) +#define R128_CLR_CMP_CLR_3D 0x1a24 +#define R128_CLR_CMP_CLR_DST 0x15c8 +#define R128_CLR_CMP_CLR_SRC 0x15c4 +#define R128_CLR_CMP_CNTL 0x15c0 +# define R128_SRC_CMP_EQ_COLOR (4 << 0) +# define R128_SRC_CMP_NEQ_COLOR (5 << 0) +# define R128_CLR_CMP_SRC_SOURCE (1 << 24) +#define R128_CLR_CMP_MASK 0x15cc +# define R128_CLR_CMP_MSK 0xffffffff +#define R128_CLR_CMP_MASK_3D 0x1A28 +#define R128_COMMAND 0x0f04 /* PCI */ +#define R128_COMPOSITE_SHADOW_ID 0x1a0c +#define R128_CONFIG_APER_0_BASE 0x0100 +#define R128_CONFIG_APER_1_BASE 0x0104 +#define R128_CONFIG_APER_SIZE 0x0108 +#define R128_CONFIG_BONDS 0x00e8 +#define R128_CONFIG_CNTL 0x00e0 +# define APER_0_BIG_ENDIAN_16BPP_SWAP (1 << 0) +# define APER_0_BIG_ENDIAN_32BPP_SWAP (2 << 0) +#define R128_CONFIG_MEMSIZE 0x00f8 +#define R128_CONFIG_MEMSIZE_EMBEDDED 0x0114 +#define R128_CONFIG_REG_1_BASE 0x010c +#define R128_CONFIG_REG_APER_SIZE 0x0110 +#define R128_CONFIG_XSTRAP 0x00e4 +#define R128_CONSTANT_COLOR_C 0x1d34 +# define R128_CONSTANT_COLOR_MASK 0x00ffffff +# define R128_CONSTANT_COLOR_ONE 0x00ffffff +# define R128_CONSTANT_COLOR_ZERO 0x00000000 +#define R128_CRC_CMDFIFO_ADDR 0x0740 +#define R128_CRC_CMDFIFO_DOUT 0x0744 +#define R128_CRTC_CRNT_FRAME 0x0214 +#define R128_CRTC_DEBUG 0x021c +#define R128_CRTC_EXT_CNTL 0x0054 +# define R128_CRTC_VGA_XOVERSCAN (1 << 0) +# define R128_VGA_ATI_LINEAR (1 << 3) +# define R128_XCRT_CNT_EN (1 << 6) +# define R128_CRTC_HSYNC_DIS (1 << 8) +# define R128_CRTC_VSYNC_DIS (1 << 9) +# define R128_CRTC_DISPLAY_DIS (1 << 10) +# define R128_CRTC_CRT_ON (1 << 15) +# define R128_FP_OUT_EN (1 << 22) +# define R128_FP_ACTIVE (1 << 23) +#define R128_CRTC_EXT_CNTL_DPMS_BYTE 0x0055 +# define R128_CRTC_HSYNC_DIS_BYTE (1 << 0) +# define R128_CRTC_VSYNC_DIS_BYTE (1 << 1) +# define R128_CRTC_DISPLAY_DIS_BYTE (1 << 2) +#define R128_CRTC_GEN_CNTL 0x0050 +# define R128_CRTC_DBL_SCAN_EN (1 << 0) +# define R128_CRTC_INTERLACE_EN (1 << 1) +# define R128_CRTC_CSYNC_EN (1 << 4) +# define R128_CRTC_CUR_EN (1 << 16) +# define R128_CRTC_CUR_MODE_MASK (7 << 17) +# define R128_CRTC_ICON_EN (1 << 20) +# define R128_CRTC_EXT_DISP_EN (1 << 24) +# define R128_CRTC_EN (1 << 25) +# define R128_CRTC_DISP_REQ_EN_B (1 << 26) +#define R128_CRTC_GUI_TRIG_VLINE 0x0218 +#define R128_CRTC_H_SYNC_STRT_WID 0x0204 +# define R128_CRTC_H_SYNC_STRT_PIX (0x07 << 0) +# define R128_CRTC_H_SYNC_STRT_CHAR (0x1ff << 3) +# define R128_CRTC_H_SYNC_STRT_CHAR_SHIFT 3 +# define R128_CRTC_H_SYNC_WID (0x3f << 16) +# define R128_CRTC_H_SYNC_WID_SHIFT 16 +# define R128_CRTC_H_SYNC_POL (1 << 23) +#define R128_CRTC_H_TOTAL_DISP 0x0200 +# define R128_CRTC_H_TOTAL (0x01ff << 0) +# define R128_CRTC_H_TOTAL_SHIFT 0 +# define R128_CRTC_H_DISP (0x00ff << 16) +# define R128_CRTC_H_DISP_SHIFT 16 +#define R128_CRTC_OFFSET 0x0224 +#define R128_CRTC_OFFSET_CNTL 0x0228 +#define R128_CRTC_PITCH 0x022c +#define R128_CRTC_STATUS 0x005c +# define R128_CRTC_VBLANK_SAVE (1 << 1) +#define R128_CRTC_V_SYNC_STRT_WID 0x020c +# define R128_CRTC_V_SYNC_STRT (0x7ff << 0) +# define R128_CRTC_V_SYNC_STRT_SHIFT 0 +# define R128_CRTC_V_SYNC_WID (0x1f << 16) +# define R128_CRTC_V_SYNC_WID_SHIFT 16 +# define R128_CRTC_V_SYNC_POL (1 << 23) +#define R128_CRTC_V_TOTAL_DISP 0x0208 +# define R128_CRTC_V_TOTAL (0x07ff << 0) +# define R128_CRTC_V_TOTAL_SHIFT 0 +# define R128_CRTC_V_DISP (0x07ff << 16) +# define R128_CRTC_V_DISP_SHIFT 16 +#define R128_CRTC_VLINE_CRNT_VLINE 0x0210 +# define R128_CRTC_CRNT_VLINE_MASK (0x7ff << 16) +#define R128_CRTC2_CRNT_FRAME 0x0314 +#define R128_CRTC2_DEBUG 0x031c +#define R128_CRTC2_GEN_CNTL 0x03f8 +#define R128_CRTC2_GUI_TRIG_VLINE 0x0318 +#define R128_CRTC2_H_SYNC_STRT_WID 0x0304 +#define R128_CRTC2_H_TOTAL_DISP 0x0300 +#define R128_CRTC2_OFFSET 0x0324 +#define R128_CRTC2_OFFSET_CNTL 0x0328 +#define R128_CRTC2_PITCH 0x032c +#define R128_CRTC2_STATUS 0x03fc +#define R128_CRTC2_V_SYNC_STRT_WID 0x030c +#define R128_CRTC2_V_TOTAL_DISP 0x0308 +#define R128_CRTC2_VLINE_CRNT_VLINE 0x0310 +#define R128_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ +#define R128_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ +#define R128_CUR_CLR0 0x026c +#define R128_CUR_CLR1 0x0270 +#define R128_CUR_HORZ_VERT_OFF 0x0268 +#define R128_CUR_HORZ_VERT_POSN 0x0264 +#define R128_CUR_OFFSET 0x0260 +# define R128_CUR_LOCK (1 << 31) + +#define R128_DAC_CNTL 0x0058 +# define R128_DAC_RANGE_CNTL (3 << 0) +# define R128_DAC_BLANKING (1 << 2) +# define R128_DAC_CRT_SEL_CRTC2 (1 << 4) +# define R128_DAC_PALETTE_ACC_CTL (1 << 5) +# define R128_DAC_8BIT_EN (1 << 8) +# define R128_DAC_VGA_ADR_EN (1 << 13) +# define R128_DAC_MASK_ALL (0xff << 24) +#define R128_DAC_CRC_SIG 0x02cc +#define R128_DAC_DATA 0x03c9 /* VGA */ +#define R128_DAC_MASK 0x03c6 /* VGA */ +#define R128_DAC_R_INDEX 0x03c7 /* VGA */ +#define R128_DAC_W_INDEX 0x03c8 /* VGA */ +#define R128_DDA_CONFIG 0x02e0 +#define R128_DDA_ON_OFF 0x02e4 +#define R128_DEFAULT_OFFSET 0x16e0 +#define R128_DEFAULT_PITCH 0x16e4 +#define R128_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 +# define R128_DEFAULT_SC_RIGHT_MAX (0x1fff << 0) +# define R128_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16) +#define R128_DESTINATION_3D_CLR_CMP_VAL 0x1820 +#define R128_DESTINATION_3D_CLR_CMP_MSK 0x1824 +#define R128_DEVICE_ID 0x0f02 /* PCI */ +#define R128_DP_BRUSH_BKGD_CLR 0x1478 +#define R128_DP_BRUSH_FRGD_CLR 0x147c +#define R128_DP_CNTL 0x16c0 +# define R128_DST_X_LEFT_TO_RIGHT (1 << 0) +# define R128_DST_Y_TOP_TO_BOTTOM (1 << 1) +#define R128_DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0 +# define R128_DST_Y_MAJOR (1 << 2) +# define R128_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15) +# define R128_DST_X_DIR_LEFT_TO_RIGHT (1 << 31) +#define R128_DP_DATATYPE 0x16c4 +# define R128_HOST_BIG_ENDIAN_EN (1 << 29) +#define R128_DP_GUI_MASTER_CNTL 0x146c +# define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define R128_GMC_SRC_CLIPPING (1 << 2) +# define R128_GMC_DST_CLIPPING (1 << 3) +# define R128_GMC_BRUSH_DATATYPE_MASK (0x0f << 4) +# define R128_GMC_BRUSH_8X8_MONO_FG_BG (0 << 4) +# define R128_GMC_BRUSH_8X8_MONO_FG_LA (1 << 4) +# define R128_GMC_BRUSH_1X8_MONO_FG_BG (4 << 4) +# define R128_GMC_BRUSH_1X8_MONO_FG_LA (5 << 4) +# define R128_GMC_BRUSH_32x1_MONO_FG_BG (6 << 4) +# define R128_GMC_BRUSH_32x1_MONO_FG_LA (7 << 4) +# define R128_GMC_BRUSH_32x32_MONO_FG_BG (8 << 4) +# define R128_GMC_BRUSH_32x32_MONO_FG_LA (9 << 4) +# define R128_GMC_BRUSH_8x8_COLOR (10 << 4) +# define R128_GMC_BRUSH_1X8_COLOR (12 << 4) +# define R128_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define R128_GMC_BRUSH_NONE (15 << 4) +# define R128_GMC_DST_8BPP_CI (2 << 8) +# define R128_GMC_DST_15BPP (3 << 8) +# define R128_GMC_DST_16BPP (4 << 8) +# define R128_GMC_DST_24BPP (5 << 8) +# define R128_GMC_DST_32BPP (6 << 8) +# define R128_GMC_DST_8BPP_RGB (7 << 8) +# define R128_GMC_DST_Y8 (8 << 8) +# define R128_GMC_DST_RGB8 (9 << 8) +# define R128_GMC_DST_VYUY (11 << 8) +# define R128_GMC_DST_YVYU (12 << 8) +# define R128_GMC_DST_AYUV444 (14 << 8) +# define R128_GMC_DST_ARGB4444 (15 << 8) +# define R128_GMC_DST_DATATYPE_MASK (0x0f << 8) +# define R128_GMC_DST_DATATYPE_SHIFT 8 +# define R128_GMC_SRC_DATATYPE_MASK (3 << 12) +# define R128_GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12) +# define R128_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12) +# define R128_GMC_SRC_DATATYPE_COLOR (3 << 12) +# define R128_GMC_BYTE_PIX_ORDER (1 << 14) +# define R128_GMC_BYTE_MSB_TO_LSB (0 << 14) +# define R128_GMC_BYTE_LSB_TO_MSB (1 << 14) +# define R128_GMC_CONVERSION_TEMP (1 << 15) +# define R128_GMC_CONVERSION_TEMP_6500 (0 << 15) +# define R128_GMC_CONVERSION_TEMP_9300 (1 << 15) +# define R128_GMC_ROP3_MASK (0xff << 16) +# define R128_DP_SRC_SOURCE_MASK (7 << 24) +# define R128_DP_SRC_SOURCE_MEMORY (2 << 24) +# define R128_DP_SRC_SOURCE_HOST_DATA (3 << 24) +# define R128_GMC_3D_FCN_EN (1 << 27) +# define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define R128_GMC_AUX_CLIP_DIS (1 << 29) +# define R128_GMC_WR_MSK_DIS (1 << 30) +# define R128_GMC_LD_BRUSH_Y_X (1 << 31) +# define R128_ROP3_ZERO 0x00000000 +# define R128_ROP3_DSa 0x00880000 +# define R128_ROP3_SDna 0x00440000 +# define R128_ROP3_S 0x00cc0000 +# define R128_ROP3_DSna 0x00220000 +# define R128_ROP3_D 0x00aa0000 +# define R128_ROP3_DSx 0x00660000 +# define R128_ROP3_DSo 0x00ee0000 +# define R128_ROP3_DSon 0x00110000 +# define R128_ROP3_DSxn 0x00990000 +# define R128_ROP3_Dn 0x00550000 +# define R128_ROP3_SDno 0x00dd0000 +# define R128_ROP3_Sn 0x00330000 +# define R128_ROP3_DSno 0x00bb0000 +# define R128_ROP3_DSan 0x00770000 +# define R128_ROP3_ONE 0x00ff0000 +# define R128_ROP3_DPa 0x00a00000 +# define R128_ROP3_PDna 0x00500000 +# define R128_ROP3_P 0x00f00000 +# define R128_ROP3_DPna 0x000a0000 +# define R128_ROP3_D 0x00aa0000 +# define R128_ROP3_DPx 0x005a0000 +# define R128_ROP3_DPo 0x00fa0000 +# define R128_ROP3_DPon 0x00050000 +# define R128_ROP3_PDxn 0x00a50000 +# define R128_ROP3_PDno 0x00f50000 +# define R128_ROP3_Pn 0x000f0000 +# define R128_ROP3_DPno 0x00af0000 +# define R128_ROP3_DPan 0x005f0000 + + +#define R128_DP_GUI_MASTER_CNTL_C 0x1c84 +#define R128_DP_MIX 0x16c8 +#define R128_DP_SRC_BKGD_CLR 0x15dc +#define R128_DP_SRC_FRGD_CLR 0x15d8 +#define R128_DP_WRITE_MASK 0x16cc +#define R128_DST_BRES_DEC 0x1630 +#define R128_DST_BRES_ERR 0x1628 +#define R128_DST_BRES_INC 0x162c +#define R128_DST_BRES_LNTH 0x1634 +#define R128_DST_BRES_LNTH_SUB 0x1638 +#define R128_DST_HEIGHT 0x1410 +#define R128_DST_HEIGHT_WIDTH 0x143c +#define R128_DST_HEIGHT_WIDTH_8 0x158c +#define R128_DST_HEIGHT_WIDTH_BW 0x15b4 +#define R128_DST_HEIGHT_Y 0x15a0 +#define R128_DST_OFFSET 0x1404 +#define R128_DST_PITCH 0x1408 +#define R128_DST_PITCH_OFFSET 0x142c +#define R128_DST_PITCH_OFFSET_C 0x1c80 +# define R128_PITCH_SHIFT 21 +# define R128_DST_TILE (1 << 31) +#define R128_DST_WIDTH 0x140c +#define R128_DST_WIDTH_HEIGHT 0x1598 +#define R128_DST_WIDTH_X 0x1588 +#define R128_DST_WIDTH_X_INCY 0x159c +#define R128_DST_X 0x141c +#define R128_DST_X_SUB 0x15a4 +#define R128_DST_X_Y 0x1594 +#define R128_DST_Y 0x1420 +#define R128_DST_Y_SUB 0x15a8 +#define R128_DST_Y_X 0x1438 + +#define R128_EXT_MEM_CNTL 0x0144 + +#define R128_FCP_CNTL 0x0012 /* PLL */ +#define R128_FLUSH_1 0x1704 +#define R128_FLUSH_2 0x1708 +#define R128_FLUSH_3 0x170c +#define R128_FLUSH_4 0x1710 +#define R128_FLUSH_5 0x1714 +#define R128_FLUSH_6 0x1718 +#define R128_FLUSH_7 0x171c +#define R128_FOG_3D_TABLE_START 0x1810 +#define R128_FOG_3D_TABLE_END 0x1814 +#define R128_FOG_3D_TABLE_DENSITY 0x181c +#define R128_FOG_TABLE_INDEX 0x1a14 +#define R128_FOG_TABLE_DATA 0x1a18 +#define R128_FP_CRTC_H_TOTAL_DISP 0x0250 +#define R128_FP_CRTC_V_TOTAL_DISP 0x0254 +#define R128_FP_GEN_CNTL 0x0284 +# define R128_FP_FPON (1 << 0) +# define R128_FP_BLANK_DIS (1 << 1) +# define R128_FP_TDMS_EN (1 << 2) +# define R128_FP_DETECT_SENSE (1 << 8) +# define R128_FP_SEL_CRTC2 (1 << 13) +# define R128_FP_CRTC_DONT_SHADOW_VPAR (1 << 16) +# define R128_FP_CRTC_DONT_SHADOW_HEND (1 << 17) +# define R128_FP_CRTC_USE_SHADOW_VEND (1 << 18) +# define R128_FP_CRTC_USE_SHADOW_ROWCUR (1 << 19) +# define R128_FP_CRTC_HORZ_DIV2_EN (1 << 20) +# define R128_FP_CRTC_HOR_CRT_DIV2_DIS (1 << 21) +# define R128_FP_CRT_SYNC_SEL (1 << 23) +# define R128_FP_USE_SHADOW_EN (1 << 24) +#define R128_FP_H_SYNC_STRT_WID 0x02c4 +#define R128_FP_HORZ_STRETCH 0x028c +# define R128_HORZ_STRETCH_RATIO_MASK 0xffff +# define R128_HORZ_STRETCH_RATIO_SHIFT 0 +# define R128_HORZ_STRETCH_RATIO_MAX 4096 +# define R128_HORZ_PANEL_SIZE (0xff << 16) +# define R128_HORZ_PANEL_SHIFT 16 +# define R128_AUTO_HORZ_RATIO (0 << 24) +# define R128_HORZ_STRETCH_PIXREP (0 << 25) +# define R128_HORZ_STRETCH_BLEND (1 << 25) +# define R128_HORZ_STRETCH_ENABLE (1 << 26) +# define R128_HORZ_FP_LOOP_STRETCH (0x7 << 27) +# define R128_HORZ_STRETCH_RESERVED (1 << 30) +# define R128_HORZ_AUTO_RATIO_FIX_EN (1 << 31) + +#define R128_FP_PANEL_CNTL 0x0288 +# define R128_FP_DIGON (1 << 0) +# define R128_FP_BLON (1 << 1) +#define R128_FP_V_SYNC_STRT_WID 0x02c8 +#define R128_FP_VERT_STRETCH 0x0290 +# define R128_VERT_PANEL_SIZE (0x7ff << 0) +# define R128_VERT_PANEL_SHIFT 0 +# define R128_VERT_STRETCH_RATIO_MASK 0x3ff +# define R128_VERT_STRETCH_RATIO_SHIFT 11 +# define R128_VERT_STRETCH_RATIO_MAX 1024 +# define R128_VERT_STRETCH_ENABLE (1 << 24) +# define R128_VERT_STRETCH_LINEREP (0 << 25) +# define R128_VERT_STRETCH_BLEND (1 << 25) +# define R128_VERT_AUTO_RATIO_EN (1 << 26) +# define R128_VERT_STRETCH_RESERVED 0xf8e00000 + +#define R128_GEN_INT_CNTL 0x0040 +#define R128_GEN_INT_STATUS 0x0044 +# define R128_VSYNC_INT_AK (1 << 2) +# define R128_VSYNC_INT (1 << 2) +#define R128_GEN_RESET_CNTL 0x00f0 +# define R128_SOFT_RESET_GUI (1 << 0) +# define R128_SOFT_RESET_VCLK (1 << 8) +# define R128_SOFT_RESET_PCLK (1 << 9) +# define R128_SOFT_RESET_DISPENG_XCLK (1 << 11) +# define R128_SOFT_RESET_MEMCTLR_XCLK (1 << 12) +#define R128_GENENB 0x03c3 /* VGA */ +#define R128_GENFC_RD 0x03ca /* VGA */ +#define R128_GENFC_WT 0x03da /* VGA, 0x03ba */ +#define R128_GENMO_RD 0x03cc /* VGA */ +#define R128_GENMO_WT 0x03c2 /* VGA */ +#define R128_GENS0 0x03c2 /* VGA */ +#define R128_GENS1 0x03da /* VGA, 0x03ba */ +#define R128_GPIO_MONID 0x0068 +# define R128_GPIO_MONID_A_0 (1 << 0) +# define R128_GPIO_MONID_A_1 (1 << 1) +# define R128_GPIO_MONID_A_2 (1 << 2) +# define R128_GPIO_MONID_A_3 (1 << 3) +# define R128_GPIO_MONID_Y_0 (1 << 8) +# define R128_GPIO_MONID_Y_1 (1 << 9) +# define R128_GPIO_MONID_Y_2 (1 << 10) +# define R128_GPIO_MONID_Y_3 (1 << 11) +# define R128_GPIO_MONID_EN_0 (1 << 16) +# define R128_GPIO_MONID_EN_1 (1 << 17) +# define R128_GPIO_MONID_EN_2 (1 << 18) +# define R128_GPIO_MONID_EN_3 (1 << 19) +# define R128_GPIO_MONID_MASK_0 (1 << 24) +# define R128_GPIO_MONID_MASK_1 (1 << 25) +# define R128_GPIO_MONID_MASK_2 (1 << 26) +# define R128_GPIO_MONID_MASK_3 (1 << 27) +#define R128_GPIO_MONIDB 0x006c +#define R128_GRPH8_DATA 0x03cf /* VGA */ +#define R128_GRPH8_IDX 0x03ce /* VGA */ +#define R128_GUI_DEBUG0 0x16a0 +#define R128_GUI_DEBUG1 0x16a4 +#define R128_GUI_DEBUG2 0x16a8 +#define R128_GUI_DEBUG3 0x16ac +#define R128_GUI_DEBUG4 0x16b0 +#define R128_GUI_DEBUG5 0x16b4 +#define R128_GUI_DEBUG6 0x16b8 +#define R128_GUI_PROBE 0x16bc +#define R128_GUI_SCRATCH_REG0 0x15e0 +#define R128_GUI_SCRATCH_REG1 0x15e4 +#define R128_GUI_SCRATCH_REG2 0x15e8 +#define R128_GUI_SCRATCH_REG3 0x15ec +#define R128_GUI_SCRATCH_REG4 0x15f0 +#define R128_GUI_SCRATCH_REG5 0x15f4 +#define R128_GUI_STAT 0x1740 +# define R128_GUI_FIFOCNT_MASK 0x0fff +# define R128_GUI_ACTIVE (1 << 31) + +#define R128_HEADER 0x0f0e /* PCI */ +#define R128_HOST_DATA0 0x17c0 +#define R128_HOST_DATA1 0x17c4 +#define R128_HOST_DATA2 0x17c8 +#define R128_HOST_DATA3 0x17cc +#define R128_HOST_DATA4 0x17d0 +#define R128_HOST_DATA5 0x17d4 +#define R128_HOST_DATA6 0x17d8 +#define R128_HOST_DATA7 0x17dc +#define R128_HOST_DATA_LAST 0x17e0 +#define R128_HOST_PATH_CNTL 0x0130 +#define R128_HTOTAL_CNTL 0x0009 /* PLL */ +#define R128_HW_DEBUG 0x0128 +#define R128_HW_DEBUG2 0x011c + +#define R128_I2C_CNTL_1 0x0094 /* ? */ +#define R128_INTERRUPT_LINE 0x0f3c /* PCI */ +#define R128_INTERRUPT_PIN 0x0f3d /* PCI */ +#define R128_IO_BASE 0x0f14 /* PCI */ + +#define R128_LATENCY 0x0f0d /* PCI */ +#define R128_LEAD_BRES_DEC 0x1608 +#define R128_LEAD_BRES_ERR 0x1600 +#define R128_LEAD_BRES_INC 0x1604 +#define R128_LEAD_BRES_LNTH 0x161c +#define R128_LEAD_BRES_LNTH_SUB 0x1624 +#define R128_LVDS_GEN_CNTL 0x02d0 +# define R128_LVDS_ON (1 << 0) +# define R128_LVDS_DISPLAY_DIS (1 << 1) +# define R128_LVDS_EN (1 << 7) +# define R128_LVDS_DIGON (1 << 18) +# define R128_LVDS_BLON (1 << 19) +# define R128_LVDS_SEL_CRTC2 (1 << 23) +# define R128_HSYNC_DELAY_SHIFT 28 +# define R128_HSYNC_DELAY_MASK (0xf << 28) + +#define R128_MAX_LATENCY 0x0f3f /* PCI */ +#define R128_MCLK_CNTL 0x000f /* PLL */ +# define R128_FORCE_GCP (1 << 16) +# define R128_FORCE_PIPE3D_CP (1 << 17) +# define R128_FORCE_RCP (1 << 18) +#define R128_MDGPIO_A_REG 0x01ac +#define R128_MDGPIO_EN_REG 0x01b0 +#define R128_MDGPIO_MASK 0x0198 +#define R128_MDGPIO_Y_REG 0x01b4 +#define R128_MEM_ADDR_CONFIG 0x0148 +#define R128_MEM_BASE 0x0f10 /* PCI */ +#define R128_MEM_CNTL 0x0140 +#define R128_MEM_INIT_LAT_TIMER 0x0154 +#define R128_MEM_INTF_CNTL 0x014c +#define R128_MEM_SDRAM_MODE_REG 0x0158 +#define R128_MEM_STR_CNTL 0x0150 +#define R128_MEM_VGA_RP_SEL 0x003c +#define R128_MEM_VGA_WP_SEL 0x0038 +#define R128_MIN_GRANT 0x0f3e /* PCI */ +#define R128_MM_DATA 0x0004 +#define R128_MM_INDEX 0x0000 +#define R128_MPLL_CNTL 0x000e /* PLL */ +#define R128_MPP_TB_CONFIG 0x01c0 /* ? */ +#define R128_MPP_GP_CONFIG 0x01c8 /* ? */ + +#define R128_N_VIF_COUNT 0x0248 + +#define R128_OVR_CLR 0x0230 +#define R128_OVR_WID_LEFT_RIGHT 0x0234 +#define R128_OVR_WID_TOP_BOTTOM 0x0238 + +/* first overlay unit (there is only one) */ + +#define R128_OV0_Y_X_START 0x0400 +#define R128_OV0_Y_X_END 0x0404 +#define R128_OV0_EXCLUSIVE_HORZ 0x0408 +# define R128_EXCL_HORZ_START_MASK 0x000000ff +# define R128_EXCL_HORZ_END_MASK 0x0000ff00 +# define R128_EXCL_HORZ_BACK_PORCH_MASK 0x00ff0000 +# define R128_EXCL_HORZ_EXCLUSIVE_EN 0x80000000 +#define R128_OV0_EXCLUSIVE_VERT 0x040C +# define R128_EXCL_VERT_START_MASK 0x000003ff +# define R128_EXCL_VERT_END_MASK 0x03ff0000 +#define R128_OV0_REG_LOAD_CNTL 0x0410 +# define R128_REG_LD_CTL_LOCK 0x00000001L +# define R128_REG_LD_CTL_VBLANK_DURING_LOCK 0x00000002L +# define R128_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L +# define R128_REG_LD_CTL_LOCK_READBACK 0x00000008L +#define R128_OV0_SCALE_CNTL 0x0420 +# define R128_SCALER_PIX_EXPAND 0x00000001L +# define R128_SCALER_Y2R_TEMP 0x00000002L +# define R128_SCALER_HORZ_PICK_NEAREST 0x00000003L +# define R128_SCALER_VERT_PICK_NEAREST 0x00000004L +# define R128_SCALER_SIGNED_UV 0x00000010L +# define R128_SCALER_GAMMA_SEL_MASK 0x00000060L +# define R128_SCALER_GAMMA_SEL_BRIGHT 0x00000000L +# define R128_SCALER_GAMMA_SEL_G22 0x00000020L +# define R128_SCALER_GAMMA_SEL_G18 0x00000040L +# define R128_SCALER_GAMMA_SEL_G14 0x00000060L +# define R128_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L +# define R128_SCALER_SURFAC_FORMAT 0x00000f00L +# define R128_SCALER_SOURCE_15BPP 0x00000300L +# define R128_SCALER_SOURCE_16BPP 0x00000400L +# define R128_SCALER_SOURCE_32BPP 0x00000600L +# define R128_SCALER_SOURCE_YUV9 0x00000900L +# define R128_SCALER_SOURCE_YUV12 0x00000A00L +# define R128_SCALER_SOURCE_VYUY422 0x00000B00L +# define R128_SCALER_SOURCE_YVYU422 0x00000C00L +# define R128_SCALER_SMART_SWITCH 0x00008000L +# define R128_SCALER_BURST_PER_PLANE 0x00ff0000L +# define R128_SCALER_DOUBLE_BUFFER 0x01000000L +# define R128_SCALER_DIS_LIMIT 0x08000000L +# define R128_SCALER_PRG_LOAD_START 0x10000000L +# define R128_SCALER_INT_EMU 0x20000000L +# define R128_SCALER_ENABLE 0x40000000L +# define R128_SCALER_SOFT_RESET 0x80000000L +#define R128_OV0_V_INC 0x0424 +#define R128_OV0_P1_V_ACCUM_INIT 0x0428 +# define R128_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L +# define R128_OV0_P1_V_ACCUM_INIT_MASK 0x01ff8000L +#define R128_OV0_P23_V_ACCUM_INIT 0x042C +#define R128_OV0_P1_BLANK_LINES_AT_TOP 0x0430 +# define R128_P1_BLNK_LN_AT_TOP_M1_MASK 0x00000fffL +# define R128_P1_ACTIVE_LINES_M1 0x0fff0000L +#define R128_OV0_P23_BLANK_LINES_AT_TOP 0x0434 +# define R128_P23_BLNK_LN_AT_TOP_M1_MASK 0x000007ffL +# define R128_P23_ACTIVE_LINES_M1 0x07ff0000L +#define R128_OV0_VID_BUF0_BASE_ADRS 0x0440 +# define R128_VIF_BUF0_PITCH_SEL 0x00000001L +# define R128_VIF_BUF0_TILE_ADRS 0x00000002L +# define R128_VIF_BUF0_BASE_ADRS_MASK 0x03fffff0L +# define R128_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L +#define R128_OV0_VID_BUF1_BASE_ADRS 0x0444 +# define R128_VIF_BUF1_PITCH_SEL 0x00000001L +# define R128_VIF_BUF1_TILE_ADRS 0x00000002L +# define R128_VIF_BUF1_BASE_ADRS_MASK 0x03fffff0L +# define R128_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L +#define R128_OV0_VID_BUF2_BASE_ADRS 0x0448 +# define R128_VIF_BUF2_PITCH_SEL 0x00000001L +# define R128_VIF_BUF2_TILE_ADRS 0x00000002L +# define R128_VIF_BUF2_BASE_ADRS_MASK 0x03fffff0L +# define R128_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L +#define R128_OV0_VID_BUF3_BASE_ADRS 0x044C +#define R128_OV0_VID_BUF4_BASE_ADRS 0x0450 +#define R128_OV0_VID_BUF5_BASE_ADRS 0x0454 +#define R128_OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define R128_OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define R128_OV0_AUTO_FLIP_CNTL 0x0470 +#define R128_OV0_DEINTERLACE_PATTERN 0x0474 +#define R128_OV0_H_INC 0x0480 +#define R128_OV0_STEP_BY 0x0484 +#define R128_OV0_P1_H_ACCUM_INIT 0x0488 +#define R128_OV0_P23_H_ACCUM_INIT 0x048C +#define R128_OV0_P1_X_START_END 0x0494 +#define R128_OV0_P2_X_START_END 0x0498 +#define R128_OV0_P3_X_START_END 0x049C +#define R128_OV0_FILTER_CNTL 0x04A0 +#define R128_OV0_FOUR_TAP_COEF_0 0x04B0 +#define R128_OV0_FOUR_TAP_COEF_1 0x04B4 +#define R128_OV0_FOUR_TAP_COEF_2 0x04B8 +#define R128_OV0_FOUR_TAP_COEF_3 0x04BC +#define R128_OV0_FOUR_TAP_COEF_4 0x04C0 +#define R128_OV0_COLOUR_CNTL 0x04E0 +#define R128_OV0_VIDEO_KEY_CLR 0x04E4 +#define R128_OV0_VIDEO_KEY_MSK 0x04E8 +#define R128_OV0_GRAPHICS_KEY_CLR 0x04EC +#define R128_OV0_GRAPHICS_KEY_MSK 0x04F0 +#define R128_OV0_KEY_CNTL 0x04F4 +# define R128_VIDEO_KEY_FN_MASK 0x00000007L +# define R128_VIDEO_KEY_FN_FALSE 0x00000000L +# define R128_VIDEO_KEY_FN_TRUE 0x00000001L +# define R128_VIDEO_KEY_FN_EQ 0x00000004L +# define R128_VIDEO_KEY_FN_NE 0x00000005L +# define R128_GRAPHIC_KEY_FN_MASK 0x00000070L +# define R128_GRAPHIC_KEY_FN_FALSE 0x00000000L +# define R128_GRAPHIC_KEY_FN_TRUE 0x00000010L +# define R128_GRAPHIC_KEY_FN_EQ 0x00000040L +# define R128_GRAPHIC_KEY_FN_NE 0x00000050L +# define R128_CMP_MIX_MASK 0x00000100L +# define R128_CMP_MIX_OR 0x00000000L +# define R128_CMP_MIX_AND 0x00000100L +#define R128_OV0_TEST 0x04F8 + + +#define R128_PALETTE_DATA 0x00b4 +#define R128_PALETTE_INDEX 0x00b0 +#define R128_PC_DEBUG_MODE 0x1760 +#define R128_PC_GUI_CTLSTAT 0x1748 +#define R128_PC_GUI_MODE 0x1744 +# define R128_PC_IGNORE_UNIFY (1 << 5) +#define R128_PC_MISC_CNTL 0x0188 +#define R128_PC_NGUI_CTLSTAT 0x0184 +# define R128_PC_FLUSH_GUI (3 << 0) +# define R128_PC_RI_GUI (1 << 2) +# define R128_PC_FLUSH_ALL 0x00ff +# define R128_PC_BUSY (1 << 31) +#define R128_PC_NGUI_MODE 0x0180 +#define R128_PCI_GART_PAGE 0x017c +#define R128_PLANE_3D_MASK_C 0x1d44 +#define R128_PLL_TEST_CNTL 0x0013 /* PLL */ +#define R128_PMI_CAP_ID 0x0f5c /* PCI */ +#define R128_PMI_DATA 0x0f63 /* PCI */ +#define R128_PMI_NXT_CAP_PTR 0x0f5d /* PCI */ +#define R128_PMI_PMC_REG 0x0f5e /* PCI */ +#define R128_PMI_PMCSR_REG 0x0f60 /* PCI */ +#define R128_PMI_REGISTER 0x0f5c /* PCI */ +#define R128_PPLL_CNTL 0x0002 /* PLL */ +# define R128_PPLL_RESET (1 << 0) +# define R128_PPLL_SLEEP (1 << 1) +# define R128_PPLL_ATOMIC_UPDATE_EN (1 << 16) +# define R128_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +#define R128_PPLL_DIV_0 0x0004 /* PLL */ +#define R128_PPLL_DIV_1 0x0005 /* PLL */ +#define R128_PPLL_DIV_2 0x0006 /* PLL */ +#define R128_PPLL_DIV_3 0x0007 /* PLL */ +# define R128_PPLL_FB3_DIV_MASK 0x07ff +# define R128_PPLL_POST3_DIV_MASK 0x00070000 +#define R128_PPLL_REF_DIV 0x0003 /* PLL */ +# define R128_PPLL_REF_DIV_MASK 0x03ff +# define R128_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define R128_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +#define R128_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */ +#define R128_REG_BASE 0x0f18 /* PCI */ +#define R128_REGPROG_INF 0x0f09 /* PCI */ +#define R128_REVISION_ID 0x0f08 /* PCI */ + +#define R128_SC_BOTTOM 0x164c +#define R128_SC_BOTTOM_RIGHT 0x16f0 +#define R128_SC_BOTTOM_RIGHT_C 0x1c8c +#define R128_SC_LEFT 0x1640 +#define R128_SC_RIGHT 0x1644 +#define R128_SC_TOP 0x1648 +#define R128_SC_TOP_LEFT 0x16ec +#define R128_SC_TOP_LEFT_C 0x1c88 +#define R128_SEQ8_DATA 0x03c5 /* VGA */ +#define R128_SEQ8_IDX 0x03c4 /* VGA */ +#define R128_SNAPSHOT_F_COUNT 0x0244 +#define R128_SNAPSHOT_VH_COUNTS 0x0240 +#define R128_SNAPSHOT_VIF_COUNT 0x024c +#define R128_SRC_OFFSET 0x15ac +#define R128_SRC_PITCH 0x15b0 +#define R128_SRC_PITCH_OFFSET 0x1428 +#define R128_SRC_SC_BOTTOM 0x165c +#define R128_SRC_SC_BOTTOM_RIGHT 0x16f4 +#define R128_SRC_SC_RIGHT 0x1654 +#define R128_SRC_X 0x1414 +#define R128_SRC_X_Y 0x1590 +#define R128_SRC_Y 0x1418 +#define R128_SRC_Y_X 0x1434 +#define R128_STATUS 0x0f06 /* PCI */ +#define R128_SUBPIC_CNTL 0x0540 /* ? */ +#define R128_SUB_CLASS 0x0f0a /* PCI */ +#define R128_SURFACE_DELAY 0x0b00 +#define R128_SURFACE0_INFO 0x0b0c +#define R128_SURFACE0_LOWER_BOUND 0x0b04 +#define R128_SURFACE0_UPPER_BOUND 0x0b08 +#define R128_SURFACE1_INFO 0x0b1c +#define R128_SURFACE1_LOWER_BOUND 0x0b14 +#define R128_SURFACE1_UPPER_BOUND 0x0b18 +#define R128_SURFACE2_INFO 0x0b2c +#define R128_SURFACE2_LOWER_BOUND 0x0b24 +#define R128_SURFACE2_UPPER_BOUND 0x0b28 +#define R128_SURFACE3_INFO 0x0b3c +#define R128_SURFACE3_LOWER_BOUND 0x0b34 +#define R128_SURFACE3_UPPER_BOUND 0x0b38 +#define R128_SW_SEMAPHORE 0x013c + +#define R128_TEST_DEBUG_CNTL 0x0120 +#define R128_TEST_DEBUG_MUX 0x0124 +#define R128_TEST_DEBUG_OUT 0x012c +#define R128_TMDS_CRC 0x02a0 +#define R128_TMDS_TRANSMITTER_CNTL 0x02a4 +# define R128_TMDS_PLLEN (1 << 0) +# define R128_TMDS_PLLRST (1 << 1) +#define R128_TRAIL_BRES_DEC 0x1614 +#define R128_TRAIL_BRES_ERR 0x160c +#define R128_TRAIL_BRES_INC 0x1610 +#define R128_TRAIL_X 0x1618 +#define R128_TRAIL_X_SUB 0x1620 + +#define R128_VCLK_ECP_CNTL 0x0008 /* PLL */ +# define R128_ECP_DIV_MASK (3 << 8) +#define R128_VENDOR_ID 0x0f00 /* PCI */ +#define R128_VGA_DDA_CONFIG 0x02e8 +#define R128_VGA_DDA_ON_OFF 0x02ec +#define R128_VID_BUFFER_CONTROL 0x0900 +#define R128_VIDEOMUX_CNTL 0x0190 +#define R128_VIPH_CONTROL 0x01D0 /* ? */ + +#define R128_WAIT_UNTIL 0x1720 + +#define R128_X_MPLL_REF_FB_DIV 0x000a /* PLL */ +#define R128_XCLK_CNTL 0x000d /* PLL */ +#define R128_XDLL_CNTL 0x000c /* PLL */ +#define R128_XPLL_CNTL 0x000b /* PLL */ + + /* Registers for CCE and Microcode Engine */ +#define R128_PM4_MICROCODE_ADDR 0x07d4 +#define R128_PM4_MICROCODE_RADDR 0x07d8 +#define R128_PM4_MICROCODE_DATAH 0x07dc +#define R128_PM4_MICROCODE_DATAL 0x07e0 + +#define R128_PM4_BUFFER_OFFSET 0x0700 +#define R128_PM4_BUFFER_CNTL 0x0704 +# define R128_PM4_NONPM4 (0 << 28) +# define R128_PM4_192PIO (1 << 28) +# define R128_PM4_192BM (2 << 28) +# define R128_PM4_128PIO_64INDBM (3 << 28) +# define R128_PM4_128BM_64INDBM (4 << 28) +# define R128_PM4_64PIO_128INDBM (5 << 28) +# define R128_PM4_64BM_128INDBM (6 << 28) +# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) +# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) +# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) +#define R128_PM4_BUFFER_WM_CNTL 0x0708 +# define R128_WMA_SHIFT 0 +# define R128_WMB_SHIFT 8 +# define R128_WMC_SHIFT 16 +# define R128_WB_WM_SHIFT 24 +#define R128_PM4_BUFFER_DL_RPTR_ADDR 0x070c +#define R128_PM4_BUFFER_DL_RPTR 0x0710 +#define R128_PM4_BUFFER_DL_WPTR 0x0714 +# define R128_PM4_BUFFER_DL_DONE (1 << 31) +#define R128_PM4_BUFFER_DL_WPTR_DELAY 0x0718 +# define R128_PRE_WRITE_TIMER_SHIFT 0 +# define R128_PRE_WRITE_LIMIT_SHIFT 23 +#define R128_PM4_VC_FPU_SETUP 0x071c +# define R128_FRONT_DIR_CW (0 << 0) +# define R128_FRONT_DIR_CCW (1 << 0) +# define R128_FRONT_DIR_MASK (1 << 0) +# define R128_BACKFACE_CULL (0 << 1) +# define R128_BACKFACE_POINTS (1 << 1) +# define R128_BACKFACE_LINES (2 << 1) +# define R128_BACKFACE_SOLID (3 << 1) +# define R128_BACKFACE_MASK (3 << 1) +# define R128_FRONTFACE_CULL (0 << 3) +# define R128_FRONTFACE_POINTS (1 << 3) +# define R128_FRONTFACE_LINES (2 << 3) +# define R128_FRONTFACE_SOLID (3 << 3) +# define R128_FRONTFACE_MASK (3 << 3) +# define R128_FPU_COLOR_SOLID (0 << 5) +# define R128_FPU_COLOR_FLAT (1 << 5) +# define R128_FPU_COLOR_GOURAUD (2 << 5) +# define R128_FPU_COLOR_GOURAUD2 (3 << 5) +# define R128_FPU_COLOR_MASK (3 << 5) +# define R128_FPU_SUB_PIX_2BITS (0 << 7) +# define R128_FPU_SUB_PIX_4BITS (1 << 7) +# define R128_FPU_MODE_2D (0 << 8) +# define R128_FPU_MODE_3D (1 << 8) +# define R128_TRAP_BITS_DISABLE (1 << 9) +# define R128_EDGE_ANTIALIAS (1 << 10) +# define R128_SUPERSAMPLE (1 << 11) +# define R128_XFACTOR_2 (0 << 12) +# define R128_XFACTOR_4 (1 << 12) +# define R128_YFACTOR_2 (0 << 13) +# define R128_YFACTOR_4 (1 << 13) +# define R128_FLAT_SHADE_VERTEX_D3D (0 << 14) +# define R128_FLAT_SHADE_VERTEX_OGL (1 << 14) +# define R128_FPU_ROUND_TRUNCATE (0 << 15) +# define R128_FPU_ROUND_NEAREST (1 << 15) +# define R128_WM_SEL_8DW (0 << 16) +# define R128_WM_SEL_16DW (1 << 16) +# define R128_WM_SEL_32DW (2 << 16) +#define R128_PM4_VC_DEBUG_CONFIG 0x07a4 +#define R128_PM4_VC_STAT 0x07a8 +#define R128_PM4_VC_TIMESTAMP0 0x07b0 +#define R128_PM4_VC_TIMESTAMP1 0x07b4 +#define R128_PM4_STAT 0x07b8 +# define R128_PM4_FIFOCNT_MASK 0x0fff +# define R128_PM4_BUSY (1 << 16) +# define R128_PM4_GUI_ACTIVE (1 << 31) +#define R128_PM4_BUFFER_ADDR 0x07f0 +#define R128_PM4_MICRO_CNTL 0x07fc +# define R128_PM4_MICRO_FREERUN (1 << 30) +#define R128_PM4_FIFO_DATA_EVEN 0x1000 +#define R128_PM4_FIFO_DATA_ODD 0x1004 + +#define R128_SCALE_3D_CNTL 0x1a00 +# define R128_SCALE_DITHER_ERR_DIFF (0 << 1) +# define R128_SCALE_DITHER_TABLE (1 << 1) +# define R128_TEX_CACHE_SIZE_FULL (0 << 2) +# define R128_TEX_CACHE_SIZE_HALF (1 << 2) +# define R128_DITHER_INIT_CURR (0 << 3) +# define R128_DITHER_INIT_RESET (1 << 3) +# define R128_ROUND_24BIT (1 << 4) +# define R128_TEX_CACHE_DISABLE (1 << 5) +# define R128_SCALE_3D_NOOP (0 << 6) +# define R128_SCALE_3D_SCALE (1 << 6) +# define R128_SCALE_3D_TEXMAP_SHADE (2 << 6) +# define R128_SCALE_PIX_BLEND (0 << 8) +# define R128_SCALE_PIX_REPLICATE (1 << 8) +# define R128_TEX_CACHE_SPLIT (1 << 9) +# define R128_APPLE_YUV_MODE (1 << 10) +# define R128_TEX_CACHE_PALLETE_MODE (1 << 11) +# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12) +# define R128_ALPHA_COMB_ADD_NCLAMP (1 << 12) +# define R128_ALPHA_COMB_SUB_DST_SRC_CLAMP (2 << 12) +# define R128_ALPHA_COMB_SUB_DST_SRC_NCLAMP (3 << 12) +# define R128_FOG_TABLE (1 << 14) +# define R128_SIGNED_DST_CLAMP (1 << 15) +# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16) +# define R128_ALPHA_BLEND_SRC_ONE (1 << 16) +# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16) +# define R128_ALPHA_BLEND_SRC_DSTALPHA (6 << 16) +# define R128_ALPHA_BLEND_SRC_INVDSTALPHA (7 << 16) +# define R128_ALPHA_BLEND_SRC_DSTCOLOR (8 << 16) +# define R128_ALPHA_BLEND_SRC_INVDSTCOLOR (9 << 16) +# define R128_ALPHA_BLEND_SRC_SAT (10 << 16) +# define R128_ALPHA_BLEND_SRC_BLEND (11 << 16) +# define R128_ALPHA_BLEND_SRC_INVBLEND (12 << 16) +# define R128_ALPHA_BLEND_DST_ZERO (0 << 20) +# define R128_ALPHA_BLEND_DST_ONE (1 << 20) +# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20) +# define R128_ALPHA_BLEND_DST_DSTALPHA (6 << 20) +# define R128_ALPHA_BLEND_DST_INVDSTALPHA (7 << 20) +# define R128_ALPHA_BLEND_DST_DSTCOLOR (8 << 20) +# define R128_ALPHA_BLEND_DST_INVDSTCOLOR (9 << 20) +# define R128_ALPHA_TEST_NEVER (0 << 24) +# define R128_ALPHA_TEST_LESS (1 << 24) +# define R128_ALPHA_TEST_LESSEQUAL (2 << 24) +# define R128_ALPHA_TEST_EQUAL (3 << 24) +# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24) +# define R128_ALPHA_TEST_GREATER (5 << 24) +# define R128_ALPHA_TEST_NEQUAL (6 << 24) +# define R128_ALPHA_TEST_ALWAYS (7 << 24) +# define R128_COMPOSITE_SHADOW_CMP_EQUAL (0 << 28) +# define R128_COMPOSITE_SHADOW_CMP_NEQUAL (1 << 28) +# define R128_COMPOSITE_SHADOW (1 << 29) +# define R128_TEX_MAP_ALPHA_IN_TEXTURE (1 << 30) +# define R128_TEX_CACHE_LINE_SIZE_8QW (0 << 31) +# define R128_TEX_CACHE_LINE_SIZE_4QW (1 << 31) +#define R128_SCALE_3D_DATATYPE 0x1a20 + +#define R128_SETUP_CNTL 0x1bc4 +# define R128_DONT_START_TRIANGLE (1 << 0) +# define R128_Z_BIAS (0 << 1) +# define R128_DONT_START_ANY_ON (1 << 2) +# define R128_COLOR_SOLID_COLOR (0 << 3) +# define R128_COLOR_FLAT_VERT_1 (1 << 3) +# define R128_COLOR_FLAT_VERT_2 (2 << 3) +# define R128_COLOR_FLAT_VERT_3 (3 << 3) +# define R128_COLOR_GOURAUD (4 << 3) +# define R128_PRIM_TYPE_TRI (0 << 7) +# define R128_PRIM_TYPE_LINE (1 << 7) +# define R128_PRIM_TYPE_POINT (2 << 7) +# define R128_PRIM_TYPE_POLY_EDGE (3 << 7) +# define R128_TEXTURE_ST_MULT_W (0 << 9) +# define R128_TEXTURE_ST_DIRECT (1 << 9) +# define R128_STARTING_VERTEX_1 (1 << 14) +# define R128_STARTING_VERTEX_2 (2 << 14) +# define R128_STARTING_VERTEX_3 (3 << 14) +# define R128_ENDING_VERTEX_1 (1 << 16) +# define R128_ENDING_VERTEX_2 (2 << 16) +# define R128_ENDING_VERTEX_3 (3 << 16) +# define R128_SU_POLY_LINE_LAST (0 << 18) +# define R128_SU_POLY_LINE_NOT_LAST (1 << 18) +# define R128_SUB_PIX_2BITS (0 << 19) +# define R128_SUB_PIX_4BITS (1 << 19) +# define R128_SET_UP_CONTINUE (1 << 31) + +#define R128_WINDOW_XY_OFFSET 0x1bcc +# define R128_WINDOW_Y_SHIFT 4 +# define R128_WINDOW_X_SHIFT 20 + +#define R128_Z_OFFSET_C 0x1c90 +#define R128_Z_PITCH_C 0x1c94 +# define R128_Z_TILE (1 << 16) +#define R128_Z_STEN_CNTL_C 0x1c98 +# define R128_Z_PIX_WIDTH_16 (0 << 1) +# define R128_Z_PIX_WIDTH_24 (1 << 1) +# define R128_Z_PIX_WIDTH_32 (2 << 1) +# define R128_Z_PIX_WIDTH_MASK (3 << 1) +# define R128_Z_TEST_NEVER (0 << 4) +# define R128_Z_TEST_LESS (1 << 4) +# define R128_Z_TEST_LESSEQUAL (2 << 4) +# define R128_Z_TEST_EQUAL (3 << 4) +# define R128_Z_TEST_GREATEREQUAL (4 << 4) +# define R128_Z_TEST_GREATER (5 << 4) +# define R128_Z_TEST_NEQUAL (6 << 4) +# define R128_Z_TEST_ALWAYS (7 << 4) +# define R128_Z_TEST_MASK (7 << 4) +# define R128_STENCIL_TEST_NEVER (0 << 12) +# define R128_STENCIL_TEST_LESS (1 << 12) +# define R128_STENCIL_TEST_LESSEQUAL (2 << 12) +# define R128_STENCIL_TEST_EQUAL (3 << 12) +# define R128_STENCIL_TEST_GREATEREQUAL (4 << 12) +# define R128_STENCIL_TEST_GREATER (5 << 12) +# define R128_STENCIL_TEST_NEQUAL (6 << 12) +# define R128_STENCIL_TEST_ALWAYS (7 << 12) +# define R128_STENCIL_S_FAIL_KEEP (0 << 16) +# define R128_STENCIL_S_FAIL_ZERO (1 << 16) +# define R128_STENCIL_S_FAIL_REPLACE (2 << 16) +# define R128_STENCIL_S_FAIL_INC (3 << 16) +# define R128_STENCIL_S_FAIL_DEC (4 << 16) +# define R128_STENCIL_S_FAIL_INV (5 << 16) +# define R128_STENCIL_ZPASS_KEEP (0 << 20) +# define R128_STENCIL_ZPASS_ZERO (1 << 20) +# define R128_STENCIL_ZPASS_REPLACE (2 << 20) +# define R128_STENCIL_ZPASS_INC (3 << 20) +# define R128_STENCIL_ZPASS_DEC (4 << 20) +# define R128_STENCIL_ZPASS_INV (5 << 20) +# define R128_STENCIL_ZFAIL_KEEP (0 << 24) +# define R128_STENCIL_ZFAIL_ZERO (1 << 24) +# define R128_STENCIL_ZFAIL_REPLACE (2 << 24) +# define R128_STENCIL_ZFAIL_INC (3 << 24) +# define R128_STENCIL_ZFAIL_DEC (4 << 24) +# define R128_STENCIL_ZFAIL_INV (5 << 24) +#define R128_TEX_CNTL_C 0x1c9c +# define R128_Z_ENABLE (1 << 0) +# define R128_Z_WRITE_ENABLE (1 << 1) +# define R128_STENCIL_ENABLE (1 << 3) +# define R128_SHADE_ENABLE (0 << 4) +# define R128_TEXMAP_ENABLE (1 << 4) +# define R128_SEC_TEXMAP_ENABLE (1 << 5) +# define R128_FOG_ENABLE (1 << 7) +# define R128_DITHER_ENABLE (1 << 8) +# define R128_ALPHA_ENABLE (1 << 9) +# define R128_ALPHA_TEST_ENABLE (1 << 10) +# define R128_SPEC_LIGHT_ENABLE (1 << 11) +# define R128_TEX_CHROMA_KEY_ENABLE (1 << 12) +# define R128_ALPHA_IN_TEX_COMPLETE_A (0 << 13) +# define R128_ALPHA_IN_TEX_LSB_A (1 << 13) +# define R128_LIGHT_DIS (0 << 14) +# define R128_LIGHT_COPY (1 << 14) +# define R128_LIGHT_MODULATE (2 << 14) +# define R128_LIGHT_ADD (3 << 14) +# define R128_LIGHT_BLEND_CONSTANT (4 << 14) +# define R128_LIGHT_BLEND_TEXTURE (5 << 14) +# define R128_LIGHT_BLEND_VERTEX (6 << 14) +# define R128_LIGHT_BLEND_CONST_COLOR (7 << 14) +# define R128_ALPHA_LIGHT_DIS (0 << 18) +# define R128_ALPHA_LIGHT_COPY (1 << 18) +# define R128_ALPHA_LIGHT_MODULATE (2 << 18) +# define R128_ALPHA_LIGHT_ADD (3 << 18) +# define R128_ANTI_ALIAS (1 << 21) +# define R128_TEX_CACHE_FLUSH (1 << 23) +# define R128_LOD_BIAS_SHIFT 24 +# define R128_LOD_BIAS_MASK (0xff << 24) +#define R128_MISC_3D_STATE_CNTL_REG 0x1ca0 +# define R128_REF_ALPHA_MASK 0xff +# define R128_MISC_SCALE_3D_NOOP (0 << 8) +# define R128_MISC_SCALE_3D_SCALE (1 << 8) +# define R128_MISC_SCALE_3D_TEXMAP_SHADE (2 << 8) +# define R128_MISC_SCALE_PIX_BLEND (0 << 10) +# define R128_MISC_SCALE_PIX_REPLICATE (1 << 10) +# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12) +# define R128_ALPHA_COMB_ADD_NO_CLAMP (1 << 12) +# define R128_ALPHA_COMB_SUB_SRC_DST_CLAMP (2 << 12) +# define R128_ALPHA_COMB_SUB_SRC_DST_NO_CLAMP (3 << 12) +# define R128_FOG_VERTEX (0 << 14) +# define R128_FOG_TABLE (1 << 14) +# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16) +# define R128_ALPHA_BLEND_SRC_ONE (1 << 16) +# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16) +# define R128_ALPHA_BLEND_SRC_DESTALPHA (6 << 16) +# define R128_ALPHA_BLEND_SRC_INVDESTALPHA (7 << 16) +# define R128_ALPHA_BLEND_SRC_DESTCOLOR (8 << 16) +# define R128_ALPHA_BLEND_SRC_INVDESTCOLOR (9 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHASAT (10 << 16) +# define R128_ALPHA_BLEND_SRC_BOTHSRCALPHA (11 << 16) +# define R128_ALPHA_BLEND_SRC_BOTHINVSRCALPHA (12 << 16) +# define R128_ALPHA_BLEND_SRC_MASK (15 << 16) +# define R128_ALPHA_BLEND_DST_ZERO (0 << 20) +# define R128_ALPHA_BLEND_DST_ONE (1 << 20) +# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20) +# define R128_ALPHA_BLEND_DST_DESTALPHA (6 << 20) +# define R128_ALPHA_BLEND_DST_INVDESTALPHA (7 << 20) +# define R128_ALPHA_BLEND_DST_DESTCOLOR (8 << 20) +# define R128_ALPHA_BLEND_DST_INVDESTCOLOR (9 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHASAT (10 << 20) +# define R128_ALPHA_BLEND_DST_MASK (15 << 20) +# define R128_ALPHA_TEST_NEVER (0 << 24) +# define R128_ALPHA_TEST_LESS (1 << 24) +# define R128_ALPHA_TEST_LESSEQUAL (2 << 24) +# define R128_ALPHA_TEST_EQUAL (3 << 24) +# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24) +# define R128_ALPHA_TEST_GREATER (5 << 24) +# define R128_ALPHA_TEST_NEQUAL (6 << 24) +# define R128_ALPHA_TEST_ALWAYS (7 << 24) +# define R128_ALPHA_TEST_MASK (7 << 24) +#define R128_TEXTURE_CLR_CMP_CLR_C 0x1ca4 +#define R128_TEXTURE_CLR_CMP_MSK_C 0x1ca8 +#define R128_FOG_COLOR_C 0x1cac +# define R128_FOG_BLUE_SHIFT 0 +# define R128_FOG_GREEN_SHIFT 8 +# define R128_FOG_RED_SHIFT 16 +#define R128_PRIM_TEX_CNTL_C 0x1cb0 +# define R128_MIN_BLEND_NEAREST (0 << 1) +# define R128_MIN_BLEND_LINEAR (1 << 1) +# define R128_MIN_BLEND_MIPNEAREST (2 << 1) +# define R128_MIN_BLEND_MIPLINEAR (3 << 1) +# define R128_MIN_BLEND_LINEARMIPNEAREST (4 << 1) +# define R128_MIN_BLEND_LINEARMIPLINEAR (5 << 1) +# define R128_MIN_BLEND_MASK (7 << 1) +# define R128_MAG_BLEND_NEAREST (0 << 4) +# define R128_MAG_BLEND_LINEAR (1 << 4) +# define R128_MAG_BLEND_MASK (7 << 4) +# define R128_MIP_MAP_DISABLE (1 << 7) +# define R128_TEX_CLAMP_S_WRAP (0 << 8) +# define R128_TEX_CLAMP_S_MIRROR (1 << 8) +# define R128_TEX_CLAMP_S_CLAMP (2 << 8) +# define R128_TEX_CLAMP_S_BORDER_COLOR (3 << 8) +# define R128_TEX_CLAMP_S_MASK (3 << 8) +# define R128_TEX_WRAP_S (1 << 10) +# define R128_TEX_CLAMP_T_WRAP (0 << 11) +# define R128_TEX_CLAMP_T_MIRROR (1 << 11) +# define R128_TEX_CLAMP_T_CLAMP (2 << 11) +# define R128_TEX_CLAMP_T_BORDER_COLOR (3 << 11) +# define R128_TEX_CLAMP_T_MASK (3 << 11) +# define R128_TEX_WRAP_T (1 << 13) +# define R128_TEX_PERSPECTIVE_DISABLE (1 << 14) +# define R128_DATATYPE_VQ (0 << 16) +# define R128_DATATYPE_CI4 (1 << 16) +# define R128_DATATYPE_CI8 (2 << 16) +# define R128_DATATYPE_ARGB1555 (3 << 16) +# define R128_DATATYPE_RGB565 (4 << 16) +# define R128_DATATYPE_RGB888 (5 << 16) +# define R128_DATATYPE_ARGB8888 (6 << 16) +# define R128_DATATYPE_RGB332 (7 << 16) +# define R128_DATATYPE_Y8 (8 << 16) +# define R128_DATATYPE_RGB8 (9 << 16) +# define R128_DATATYPE_CI16 (10 << 16) +# define R128_DATATYPE_YVYU422 (11 << 16) +# define R128_DATATYPE_VYUY422 (12 << 16) +# define R128_DATATYPE_AYUV444 (14 << 16) +# define R128_DATATYPE_ARGB4444 (15 << 16) +# define R128_PALLETE_EITHER (0 << 20) +# define R128_PALLETE_1 (1 << 20) +# define R128_PALLETE_2 (2 << 20) +# define R128_PSEUDOCOLOR_DT_RGB565 (0 << 24) +# define R128_PSEUDOCOLOR_DT_ARGB1555 (1 << 24) +# define R128_PSEUDOCOLOR_DT_ARGB4444 (2 << 24) +#define R128_PRIM_TEXTURE_COMBINE_CNTL_C 0x1cb4 +# define R128_COMB_DIS (0 << 0) +# define R128_COMB_COPY (1 << 0) +# define R128_COMB_COPY_INP (2 << 0) +# define R128_COMB_MODULATE (3 << 0) +# define R128_COMB_MODULATE2X (4 << 0) +# define R128_COMB_MODULATE4X (5 << 0) +# define R128_COMB_ADD (6 << 0) +# define R128_COMB_ADD_SIGNED (7 << 0) +# define R128_COMB_BLEND_VERTEX (8 << 0) +# define R128_COMB_BLEND_TEXTURE (9 << 0) +# define R128_COMB_BLEND_CONST (10 << 0) +# define R128_COMB_BLEND_PREMULT (11 << 0) +# define R128_COMB_BLEND_PREV (12 << 0) +# define R128_COMB_BLEND_PREMULT_INV (13 << 0) +# define R128_COMB_ADD_SIGNED2X (14 << 0) +# define R128_COMB_BLEND_CONST_COLOR (15 << 0) +# define R128_COMB_MASK (15 << 0) +# define R128_COLOR_FACTOR_CONST_COLOR (0 << 4) +# define R128_COLOR_FACTOR_NCONST_COLOR (1 << 4) +# define R128_COLOR_FACTOR_TEX (4 << 4) +# define R128_COLOR_FACTOR_NTEX (5 << 4) +# define R128_COLOR_FACTOR_ALPHA (6 << 4) +# define R128_COLOR_FACTOR_NALPHA (7 << 4) +# define R128_COLOR_FACTOR_PREV_COLOR (8 << 4) +# define R128_COLOR_FACTOR_MASK (15 << 4) +# define R128_COMB_FCN_MSB (1 << 8) +# define R128_INPUT_FACTOR_CONST_COLOR (2 << 10) +# define R128_INPUT_FACTOR_CONST_ALPHA (3 << 10) +# define R128_INPUT_FACTOR_INT_COLOR (4 << 10) +# define R128_INPUT_FACTOR_INT_ALPHA (5 << 10) +# define R128_INPUT_FACTOR_MASK (15 << 10) +# define R128_COMB_ALPHA_DIS (0 << 14) +# define R128_COMB_ALPHA_COPY (1 << 14) +# define R128_COMB_ALPHA_COPY_INP (2 << 14) +# define R128_COMB_ALPHA_MODULATE (3 << 14) +# define R128_COMB_ALPHA_MODULATE2X (4 << 14) +# define R128_COMB_ALPHA_MODULATE4X (5 << 14) +# define R128_COMB_ALPHA_ADD (6 << 14) +# define R128_COMB_ALPHA_ADD_SIGNED (7 << 14) +# define R128_COMB_ALPHA_ADD_SIGNED2X (14 << 14) +# define R128_COMB_ALPHA_MASK (15 << 14) +# define R128_ALPHA_FACTOR_TEX_ALPHA (6 << 18) +# define R128_ALPHA_FACTOR_NTEX_ALPHA (7 << 18) +# define R128_ALPHA_FACTOR_MASK (15 << 18) +# define R128_INP_FACTOR_A_CONST_ALPHA (1 << 25) +# define R128_INP_FACTOR_A_INT_ALPHA (2 << 25) +# define R128_INP_FACTOR_A_MASK (7 << 25) +#define R128_TEX_SIZE_PITCH_C 0x1cb8 +# define R128_TEX_PITCH_SHIFT 0 +# define R128_TEX_SIZE_SHIFT 4 +# define R128_TEX_HEIGHT_SHIFT 8 +# define R128_TEX_MIN_SIZE_SHIFT 12 +# define R128_SEC_TEX_PITCH_SHIFT 16 +# define R128_SEC_TEX_SIZE_SHIFT 20 +# define R128_SEC_TEX_HEIGHT_SHIFT 24 +# define R128_SEC_TEX_MIN_SIZE_SHIFT 28 +# define R128_TEX_PITCH_MASK (0x0f << 0) +# define R128_TEX_SIZE_MASK (0x0f << 4) +# define R128_TEX_HEIGHT_MASK (0x0f << 8) +# define R128_TEX_MIN_SIZE_MASK (0x0f << 12) +# define R128_SEC_TEX_PITCH_MASK (0x0f << 16) +# define R128_SEC_TEX_SIZE_MASK (0x0f << 20) +# define R128_SEC_TEX_HEIGHT_MASK (0x0f << 24) +# define R128_SEC_TEX_MIN_SIZE_MASK (0x0f << 28) +# define R128_TEX_SIZE_PITCH_SHIFT 0 +# define R128_SEC_TEX_SIZE_PITCH_SHIFT 16 +# define R128_TEX_SIZE_PITCH_MASK (0xffff << 0) +# define R128_SEC_TEX_SIZE_PITCH_MASK (0xffff << 16) +#define R128_PRIM_TEX_0_OFFSET_C 0x1cbc +#define R128_PRIM_TEX_1_OFFSET_C 0x1cc0 +#define R128_PRIM_TEX_2_OFFSET_C 0x1cc4 +#define R128_PRIM_TEX_3_OFFSET_C 0x1cc8 +#define R128_PRIM_TEX_4_OFFSET_C 0x1ccc +#define R128_PRIM_TEX_5_OFFSET_C 0x1cd0 +#define R128_PRIM_TEX_6_OFFSET_C 0x1cd4 +#define R128_PRIM_TEX_7_OFFSET_C 0x1cd8 +#define R128_PRIM_TEX_8_OFFSET_C 0x1cdc +#define R128_PRIM_TEX_9_OFFSET_C 0x1ce0 +#define R128_PRIM_TEX_10_OFFSET_C 0x1ce4 +# define R128_TEX_NO_TILE (0 << 30) +# define R128_TEX_TILED_BY_HOST (1 << 30) +# define R128_TEX_TILED_BY_STORAGE (2 << 30) +# define R128_TEX_TILED_BY_STORAGE2 (3 << 30) + +#define R128_SEC_TEX_CNTL_C 0x1d00 +# define R128_SEC_SELECT_PRIM_ST (0 << 0) +# define R128_SEC_SELECT_SEC_ST (1 << 0) +#define R128_SEC_TEX_COMBINE_CNTL_C 0x1d04 +# define R128_INPUT_FACTOR_PREV_COLOR (8 << 10) +# define R128_INPUT_FACTOR_PREV_ALPHA (9 << 10) +# define R128_INP_FACTOR_A_PREV_ALPHA (4 << 25) +#define R128_SEC_TEX_0_OFFSET_C 0x1d08 +#define R128_SEC_TEX_1_OFFSET_C 0x1d0c +#define R128_SEC_TEX_2_OFFSET_C 0x1d10 +#define R128_SEC_TEX_3_OFFSET_C 0x1d14 +#define R128_SEC_TEX_4_OFFSET_C 0x1d18 +#define R128_SEC_TEX_5_OFFSET_C 0x1d1c +#define R128_SEC_TEX_6_OFFSET_C 0x1d20 +#define R128_SEC_TEX_7_OFFSET_C 0x1d24 +#define R128_SEC_TEX_8_OFFSET_C 0x1d28 +#define R128_SEC_TEX_9_OFFSET_C 0x1d2c +#define R128_SEC_TEX_10_OFFSET_C 0x1d30 +#define R128_CONSTANT_COLOR_C 0x1d34 +# define R128_CONSTANT_BLUE_SHIFT 0 +# define R128_CONSTANT_GREEN_SHIFT 8 +# define R128_CONSTANT_RED_SHIFT 16 +# define R128_CONSTANT_ALPHA_SHIFT 24 +#define R128_PRIM_TEXTURE_BORDER_COLOR_C 0x1d38 +# define R128_PRIM_TEX_BORDER_BLUE_SHIFT 0 +# define R128_PRIM_TEX_BORDER_GREEN_SHIFT 8 +# define R128_PRIM_TEX_BORDER_RED_SHIFT 16 +# define R128_PRIM_TEX_BORDER_ALPHA_SHIFT 24 +#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c +# define R128_SEC_TEX_BORDER_BLUE_SHIFT 0 +# define R128_SEC_TEX_BORDER_GREEN_SHIFT 8 +# define R128_SEC_TEX_BORDER_RED_SHIFT 16 +# define R128_SEC_TEX_BORDER_ALPHA_SHIFT 24 +#define R128_STEN_REF_MASK_C 0x1d40 +# define R128_STEN_REFERENCE_SHIFT 0 +# define R128_STEN_MASK_SHIFT 16 +# define R128_STEN_WRITE_MASK_SHIFT 24 +#define R128_PLANE_3D_MASK_C 0x1d44 +#define R128_TEX_CACHE_STAT_COUNT 0x1974 + + + /* Constants */ +#define R128_AGP_TEX_OFFSET 0x02000000 + +#define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0 + + /* CCE packet types */ +#define R128_CCE_PACKET0 0x00000000 +#define R128_CCE_PACKET0_ONE_REG_WR 0x00008000 +#define R128_CCE_PACKET1 0x40000000 +#define R128_CCE_PACKET2 0x80000000 +#define R128_CCE_PACKET3 0xC0000000 +#define R128_CCE_PACKET3_NOP 0xC0001000 +#define R128_CCE_PACKET3_PAINT 0xC0001100 +#define R128_CCE_PACKET3_BITBLT 0xC0001200 +#define R128_CCE_PACKET3_SMALLTEXT 0xC0001300 +#define R128_CCE_PACKET3_HOSTDATA_BLT 0xC0001400 +#define R128_CCE_PACKET3_POLYLINE 0xC0001500 +#define R128_CCE_PACKET3_SCALING 0xC0001600 +#define R128_CCE_PACKET3_TRANS_SCALING 0xC0001700 +#define R128_CCE_PACKET3_POLYSCANLINES 0xC0001800 +#define R128_CCE_PACKET3_NEXT_CHAR 0xC0001900 +#define R128_CCE_PACKET3_PAINT_MULTI 0xC0001A00 +#define R128_CCE_PACKET3_BITBLT_MULTI 0xC0001B00 +#define R128_CCE_PACKET3_PLY_NEXTSCAN 0xC0001D00 +#define R128_CCE_PACKET3_SET_SCISSORS 0xC0001E00 +#define R128_CCE_PACKET3_SET_MODE24BPP 0xC0001F00 +#define R128_CCE_PACKET3_CNTL_PAINT 0xC0009100 +#define R128_CCE_PACKET3_CNTL_BITBLT 0xC0009200 +#define R128_CCE_PACKET3_CNTL_SMALLTEXT 0xC0009300 +#define R128_CCE_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400 +#define R128_CCE_PACKET3_CNTL_POLYLINE 0xC0009500 +#define R128_CCE_PACKET3_CNTL_SCALING 0xC0009600 +#define R128_CCE_PACKET3_CNTL_TRANS_SCALING 0xC0009700 +#define R128_CCE_PACKET3_CNTL_POLYSCANLINES 0xC0009800 +#define R128_CCE_PACKET3_CNTL_NEXT_CHAR 0xC0009900 +#define R128_CCE_PACKET3_CNTL_PAINT_MULTI 0xC0009A00 +#define R128_CCE_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +#define R128_CCE_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00 +#define R128_CCE_PACKET3_3D_SAVE_CONTEXT 0xC0002000 +#define R128_CCE_PACKET3_3D_PLAY_CONTEXT 0xC0002100 +#define R128_CCE_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300 +#define R128_CCE_PACKET3_3D_RNDR_GEN_PRIM 0xC0002500 +#define R128_CCE_PACKET3_LOAD_PALETTE 0xC0002C00 +#define R128_CCE_PACKET3_PURGE 0xC0002D00 +#define R128_CCE_PACKET3_NEXT_VERTEX_BUNDLE 0xC0002E00 +# define R128_CCE_PACKET_MASK 0xC0000000 +# define R128_CCE_PACKET_COUNT_MASK 0x3fff0000 +# define R128_CCE_PACKET_MAX_DWORDS (1 << 12) +# define R128_CCE_PACKET0_REG_MASK 0x000007ff +# define R128_CCE_PACKET1_REG0_MASK 0x000007ff +# define R128_CCE_PACKET1_REG1_MASK 0x003ff800 + +#define R128_CCE_VC_FRMT_RHW 0x00000001 +#define R128_CCE_VC_FRMT_DIFFUSE_BGR 0x00000002 +#define R128_CCE_VC_FRMT_DIFFUSE_A 0x00000004 +#define R128_CCE_VC_FRMT_DIFFUSE_ARGB 0x00000008 +#define R128_CCE_VC_FRMT_SPEC_BGR 0x00000010 +#define R128_CCE_VC_FRMT_SPEC_F 0x00000020 +#define R128_CCE_VC_FRMT_SPEC_FRGB 0x00000040 +#define R128_CCE_VC_FRMT_S_T 0x00000080 +#define R128_CCE_VC_FRMT_S2_T2 0x00000100 +#define R128_CCE_VC_FRMT_RHW2 0x00000200 + +#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007 +#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define R128_CCE_VC_CNTL_NUM_SHIFT 16 + +/* hmm copyed blindly (no specs) from radeon.h ... */ +#define R128_RE_TOP_LEFT 0x26c0 +# define R128_RE_LEFT_SHIFT 0 +# define R128_RE_TOP_SHIFT 16 +#define R128_RE_WIDTH_HEIGHT 0x1c44 +# define R128_RE_WIDTH_SHIFT 0 +# define R128_RE_HEIGHT_SHIFT 16 + +#endif diff --git a/src/r128_sarea.h b/src/r128_sarea.h new file mode 100644 index 0000000..beb8cfe --- /dev/null +++ b/src/r128_sarea.h @@ -0,0 +1,195 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_sarea.h,v 1.8 2003/09/28 20:15:54 alanh Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, PRECISION INSIGHT, VA LINUX + * SYSTEMS AND/OR THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef _R128_SAREA_H_ +#define _R128_SAREA_H_ + +#include "Xmd.h" + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the kernel file (r128_drm.h) + */ +#ifndef __R128_SAREA_DEFINES__ +#define __R128_SAREA_DEFINES__ + +/* What needs to be changed for the current vertex buffer? + */ +#define R128_UPLOAD_CONTEXT 0x001 +#define R128_UPLOAD_SETUP 0x002 +#define R128_UPLOAD_TEX0 0x004 +#define R128_UPLOAD_TEX1 0x008 +#define R128_UPLOAD_TEX0IMAGES 0x010 +#define R128_UPLOAD_TEX1IMAGES 0x020 +#define R128_UPLOAD_CORE 0x040 +#define R128_UPLOAD_MASKS 0x080 +#define R128_UPLOAD_WINDOW 0x100 +#define R128_UPLOAD_CLIPRECTS 0x200 /* handled client-side */ +#define R128_REQUIRE_QUIESCENCE 0x400 +#define R128_UPLOAD_ALL 0x7ff + +#define R128_FRONT 0x1 +#define R128_BACK 0x2 +#define R128_DEPTH 0x4 + +/* Primitive types + */ +#define R128_POINTS 0x1 +#define R128_LINES 0x2 +#define R128_LINE_STRIP 0x3 +#define R128_TRIANGLES 0x4 +#define R128_TRIANGLE_FAN 0x5 +#define R128_TRIANGLE_STRIP 0x6 + +/* Vertex/indirect buffer size + */ +#define R128_BUFFER_SIZE 16384 + +/* Byte offsets for indirect buffer data + */ +#define R128_INDEX_PRIM_OFFSET 20 +#define R128_HOSTDATA_BLIT_OFFSET 32 + +/* Keep these small for testing + */ +#define R128_NR_SAREA_CLIPRECTS 12 + +/* There are 2 heaps (local/AGP). Each region within a heap is a + * minimum of 64k, and there are at most 64 of them per heap. + */ +#define R128_CARD_HEAP 0 +#define R128_AGP_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 64 +#define R128_LOG_TEX_GRANULARITY 16 + +#define R128_NR_CONTEXT_REGS 12 + +#define R128_MAX_TEXTURE_LEVELS 11 +#define R128_MAX_TEXTURE_UNITS 2 + +#endif /* __R128_SAREA_DEFINES__ */ + +typedef struct { + /* Context state - can be written in one large chunk */ + unsigned int dst_pitch_offset_c; + unsigned int dp_gui_master_cntl_c; + unsigned int sc_top_left_c; + unsigned int sc_bottom_right_c; + unsigned int z_offset_c; + unsigned int z_pitch_c; + unsigned int z_sten_cntl_c; + unsigned int tex_cntl_c; + unsigned int misc_3d_state_cntl_reg; + unsigned int texture_clr_cmp_clr_c; + unsigned int texture_clr_cmp_msk_c; + unsigned int fog_color_c; + + /* Texture state */ + unsigned int tex_size_pitch_c; + unsigned int constant_color_c; + + /* Setup state */ + unsigned int pm4_vc_fpu_setup; + unsigned int setup_cntl; + + /* Mask state */ + unsigned int dp_write_mask; + unsigned int sten_ref_mask_c; + unsigned int plane_3d_mask_c; + + /* Window state */ + unsigned int window_xy_offset; + + /* Core state */ + unsigned int scale_3d_cntl; +} r128_context_regs_t; + +/* Setup registers for each texture unit + */ +typedef struct { + unsigned int tex_cntl; + unsigned int tex_combine_cntl; + unsigned int tex_size_pitch; + unsigned int tex_offset[R128_MAX_TEXTURE_LEVELS]; + unsigned int tex_border_color; +} r128_texture_regs_t; + +typedef struct { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + r128_context_regs_t ContextState; + r128_texture_regs_t TexState[R128_MAX_TEXTURE_UNITS]; + unsigned int dirty; + unsigned int vertsize; + unsigned int vc_format; + + /* The current cliprects, or a subset thereof. + */ + XF86DRIClipRectRec boxes[R128_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + /* Counters for throttling of rendering clients. + */ + unsigned int last_frame; + unsigned int last_dispatch; + + /* Maintain an LRU of contiguous regions of texture space. If you + * think you own a region of texture memory, and it has an age + * different to the one you set, then you are mistaken and it has + * been stolen by another client. If global texAge hasn't changed, + * there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained texture + * information of other clients - by maintaining them in the same + * lru which is used to age their own textures, clients have an + * approximate lru for the whole of global texture space, and can + * make informed decisions as to which areas to kick out. There is + * no need to choose whether to kick out your own texture or someone + * else's - simply eject them all in LRU order. + */ + /* Last elt is sentinal */ + drmTextureRegion texList[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + /* last time texture was uploaded */ + unsigned int texAge[R128_NR_TEX_HEAPS]; + + int ctxOwner; /* last context to upload state */ + int pfAllowPageFlip; /* set by the 2d driver, read by the client */ + int pfCurrentPage; /* set by kernel, read by others */ +} R128SAREAPriv, *R128SAREAPrivPtr; + +#endif diff --git a/src/r128_version.h b/src/r128_version.h new file mode 100644 index 0000000..846b01a --- /dev/null +++ b/src/r128_version.h @@ -0,0 +1,60 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_version.h,v 1.6 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef _R128_VERSION_H_ +#define _R128_VERSION_H_ 1 + +#undef R128_NAME +#undef R128_DRIVER_NAME +#undef R128_VERSION_MAJOR +#undef R128_VERSION_MINOR +#undef R128_VERSION_PATCH +#undef R128_VERSION_CURRENT +#undef R128_VERSION_EVALUATE +#undef R128_VERSION_STRINGIFY +#undef R128_VERSION_NAME + +#define R128_NAME "R128" +#define R128_DRIVER_NAME "r128" + +#define R128_VERSION_MAJOR 4 +#define R128_VERSION_MINOR 0 +#define R128_VERSION_PATCH 1 + +#ifndef R128_VERSION_EXTRA +#define R128_VERSION_EXTRA "" +#endif + +#define R128_VERSION_CURRENT \ + ((R128_VERSION_MAJOR << 20) | \ + (R128_VERSION_MINOR << 10) | \ + (R128_VERSION_PATCH)) + +#define R128_VERSION_EVALUATE(__x) #__x +#define R128_VERSION_STRINGIFY(_x) R128_VERSION_EVALUATE(_x) +#define R128_VERSION_NAME \ + R128_VERSION_STRINGIFY(R128_VERSION_MAJOR) "." \ + R128_VERSION_STRINGIFY(R128_VERSION_MINOR) "." \ + R128_VERSION_STRINGIFY(R128_VERSION_MINOR) R128_VERSION_EXTRA + +#endif /* _R128_VERSION_H_ */ diff --git a/src/r128_video.c b/src/r128_video.c new file mode 100644 index 0000000..7ef31af --- /dev/null +++ b/src/r128_video.c @@ -0,0 +1,1020 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_video.c,v 1.30 2003/11/10 18:22:18 tsi Exp $ */ + +#include "r128.h" +#include "r128_reg.h" + +#ifdef XF86DRI +#include "r128_common.h" +#include "r128_sarea.h" +#endif + +#include "xf86.h" +#include "dixstruct.h" + +#include "Xv.h" +#include "fourcc.h" + +#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) + +static XF86VideoAdaptorPtr R128SetupImageVideo(ScreenPtr); +static int R128SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); +static int R128GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); +static void R128StopVideo(ScrnInfoPtr, pointer, Bool); +static void R128QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, + unsigned int *, unsigned int *, pointer); +static int R128PutImage(ScrnInfoPtr, short, short, short, short, short, + short, short, short, int, unsigned char*, short, + short, Bool, RegionPtr, pointer); +static int R128QueryImageAttributes(ScrnInfoPtr, int, unsigned short *, + unsigned short *, int *, int *); + + +static void R128ResetVideo(ScrnInfoPtr); + +static void R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now); + + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer; + + +typedef struct { + int brightness; + int saturation; + Bool doubleBuffer; + unsigned char currentBuffer; + FBLinearPtr linear; + RegionRec clip; + CARD32 colorKey; + CARD32 videoStatus; + Time offTime; + Time freeTime; + int ecp_div; +} R128PortPrivRec, *R128PortPrivPtr; + +static void R128ECP(ScrnInfoPtr pScrn, R128PortPrivPtr pPriv) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + int dot_clock = info->ModeReg.dot_clock_freq; + + if (dot_clock < 12500) pPriv->ecp_div = 0; + else if (dot_clock < 25000) pPriv->ecp_div = 1; + else pPriv->ecp_div = 2; + + OUTPLLP(pScrn, R128_VCLK_ECP_CNTL, pPriv->ecp_div<<8, ~R128_ECP_DIV_MASK); +} + +void R128InitVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; + XF86VideoAdaptorPtr newAdaptor = NULL; + int num_adaptors; + + newAdaptor = R128SetupImageVideo(pScreen); + + num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); + + if(newAdaptor) { + if(!num_adaptors) { + num_adaptors = 1; + adaptors = &newAdaptor; + } else { + newAdaptors = /* need to free this someplace */ + xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); + if(newAdaptors) { + memcpy(newAdaptors, adaptors, num_adaptors * + sizeof(XF86VideoAdaptorPtr)); + newAdaptors[num_adaptors] = newAdaptor; + adaptors = newAdaptors; + num_adaptors++; + } + } + } + + if(num_adaptors) + xf86XVScreenInit(pScreen, adaptors, num_adaptors); + + if(newAdaptors) + xfree(newAdaptors); +} + +#define MAXWIDTH 2048 +#define MAXHEIGHT 2048 + +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding = +{ + 0, + "XV_IMAGE", + MAXWIDTH, MAXHEIGHT, + {1, 1} +}; + +#define NUM_FORMATS 12 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = +{ + {8, TrueColor}, {8, DirectColor}, {8, PseudoColor}, + {8, GrayScale}, {8, StaticGray}, {8, StaticColor}, + {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, + {15, DirectColor}, {16, DirectColor}, {24, DirectColor} +}; + + +#define NUM_ATTRIBUTES 4 + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -64, 63, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 31, "XV_SATURATION"}, + {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"} +}; + +#define NUM_IMAGES 4 + +static XF86ImageRec Images[NUM_IMAGES] = +{ + XVIMAGE_YUY2, + XVIMAGE_UYVY, + XVIMAGE_YV12, + XVIMAGE_I420 +}; + +static void +R128ResetVideo(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; + + + OUTREG(R128_OV0_SCALE_CNTL, 0x80000000); + OUTREG(R128_OV0_EXCLUSIVE_HORZ, 0); + OUTREG(R128_OV0_AUTO_FLIP_CNTL, 0); /* maybe */ + OUTREG(R128_OV0_FILTER_CNTL, 0x0000000f); + OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) | + (pPriv->saturation << 8) | + (pPriv->saturation << 16)); + OUTREG(R128_OV0_GRAPHICS_KEY_MSK, (1 << pScrn->depth) - 1); + OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey); + OUTREG(R128_OV0_KEY_CNTL, R128_GRAPHIC_KEY_FN_NE); + OUTREG(R128_OV0_TEST, 0); +} + + +static XF86VideoAdaptorPtr +R128AllocAdaptor(ScrnInfoPtr pScrn) +{ + XF86VideoAdaptorPtr adapt; + R128InfoPtr info = R128PTR(pScrn); + R128PortPrivPtr pPriv; + + if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) + return NULL; + + if(!(pPriv = xcalloc(1, sizeof(R128PortPrivRec) + sizeof(DevUnion)))) + { + xfree(adapt); + return NULL; + } + + adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); + adapt->pPortPrivates[0].ptr = (pointer)pPriv; + + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvSaturation = MAKE_ATOM("XV_SATURATION"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER"); + + pPriv->colorKey = info->videoKey; + pPriv->doubleBuffer = TRUE; + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->saturation = 16; + pPriv->currentBuffer = 0; + R128ECP(pScrn, pPriv); + + return adapt; +} + +static XF86VideoAdaptorPtr +R128SetupImageVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + R128PortPrivPtr pPriv; + XF86VideoAdaptorPtr adapt; + + if(!(adapt = R128AllocAdaptor(pScrn))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "ATI Rage128 Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = &DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 1; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pAttributes = Attributes; + adapt->nImages = NUM_IMAGES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = R128StopVideo; + adapt->SetPortAttribute = R128SetPortAttribute; + adapt->GetPortAttribute = R128GetPortAttribute; + adapt->QueryBestSize = R128QueryBestSize; + adapt->PutImage = R128PutImage; + adapt->QueryImageAttributes = R128QueryImageAttributes; + + info->adaptor = adapt; + + pPriv = (R128PortPrivPtr)(adapt->pPortPrivates[0].ptr); + REGION_NULL(pScreen, &(pPriv->clip)); + + R128ResetVideo(pScrn); + + return adapt; +} + +static void +R128StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128PortPrivPtr pPriv = (R128PortPrivPtr)data; + + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + + if(cleanup) { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + OUTREG(R128_OV0_SCALE_CNTL, 0); + } + 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 +R128SetPortAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data +){ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128PortPrivPtr pPriv = (R128PortPrivPtr)data; + + if(attribute == xvBrightness) { + if((value < -64) || (value > 63)) + return BadValue; + pPriv->brightness = value; + + OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) | + (pPriv->saturation << 8) | + (pPriv->saturation << 16)); + } else + if(attribute == xvSaturation) { + if((value < 0) || (value > 31)) + return BadValue; + pPriv->saturation = value; + + OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) | + (pPriv->saturation << 8) | + (pPriv->saturation << 16)); + } else + if(attribute == xvDoubleBuffer) { + if((value < 0) || (value > 1)) + return BadValue; + pPriv->doubleBuffer = value; + } else + if(attribute == xvColorKey) { + pPriv->colorKey = value; + OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey); + + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + } else return BadMatch; + + return Success; +} + +static int +R128GetPortAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data +){ + R128PortPrivPtr pPriv = (R128PortPrivPtr)data; + + if(attribute == xvBrightness) { + *value = pPriv->brightness; + } else + if(attribute == xvSaturation) { + *value = pPriv->saturation; + } else + if(attribute == xvDoubleBuffer) { + *value = pPriv->doubleBuffer ? 1 : 0; + } else + if(attribute == xvColorKey) { + *value = pPriv->colorKey; + } else return BadMatch; + + return Success; +} + + +static void +R128QueryBestSize( + 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 << 4)) + drw_w = vid_w >> 4; + if(vid_h > (drw_h << 4)) + drw_h = vid_h >> 4; + + *p_w = drw_w; + *p_h = drw_h; +} + + +/* + * + * R128DMA - abuse the texture blit ioctl to transfer rectangular blocks + * + * The block is split into 'passes' pieces of 'hpass' lines which fit entirely + * into an indirect buffer + * + */ + +static Bool +R128DMA( + R128InfoPtr info, + unsigned char *src, + unsigned char *dst, + int srcPitch, + int dstPitch, + int h, + int w +){ + +#ifdef XF86DRI + +#define BUFSIZE (R128_BUFFER_SIZE - R128_HOSTDATA_BLIT_OFFSET) +#define MAXPASSES (MAXHEIGHT/(BUFSIZE/(MAXWIDTH*2))+1) + + unsigned char *buf; + int err=-1, i, idx, offset, hpass, passes, srcpassbytes, dstpassbytes; + int sizes[MAXPASSES], list[MAXPASSES]; + drmDMAReq req; + drmR128Blit blit; + + /* Verify conditions and bail out as early as possible */ + if (!info->directRenderingEnabled || !info->DMAForXv) + return FALSE; + + if ((hpass = min(h,(BUFSIZE/w))) == 0) + return FALSE; + + if ((passes = (h+hpass-1)/hpass) > MAXPASSES) + return FALSE; + + /* Request indirect buffers */ + srcpassbytes = w*hpass; + + req.context = info->drmCtx; + req.send_count = 0; + req.send_list = NULL; + req.send_sizes = NULL; + req.flags = DRM_DMA_LARGER_OK; + req.request_count = passes; + req.request_size = srcpassbytes + R128_HOSTDATA_BLIT_OFFSET; + req.request_list = &list[0]; + req.request_sizes = &sizes[0]; + req.granted_count = 0; + + if (drmDMA(info->drmFD, &req)) + return FALSE; + + if (req.granted_count < passes) { + drmFreeBufs(info->drmFD, req.granted_count, req.request_list); + return FALSE; + } + + /* Copy parts of the block into buffers and fire them */ + dstpassbytes = hpass*dstPitch; + dstPitch /= 8; + + for (i=0, offset=dst-info->FB; i<passes; i++, offset+=dstpassbytes) { + if (i == (passes-1) && (h % hpass) != 0) { + hpass = h % hpass; + srcpassbytes = w*hpass; + } + + idx = req.request_list[i]; + buf = (unsigned char *) info->buffers->list[idx].address + R128_HOSTDATA_BLIT_OFFSET; + + if (srcPitch == w) { + memcpy(buf, src, srcpassbytes); + src += srcpassbytes; + } else { + int count = hpass; + while(count--) { + memcpy(buf, src, w); + src += srcPitch; + buf += w; + } + } + + blit.idx = idx; + blit.offset = offset; + blit.pitch = dstPitch; + blit.format = (R128_DATATYPE_CI8 >> 16); + blit.x = (offset % 32); + blit.y = 0; + blit.width = w; + blit.height = hpass; + + if ((err = drmCommandWrite(info->drmFD, DRM_R128_BLIT, + &blit, sizeof(drmR128Blit))) < 0) + break; + } + + drmFreeBufs(info->drmFD, req.granted_count, req.request_list); + + return (err==0) ? TRUE : FALSE; + +#else + + /* This is to avoid cluttering the rest of the code with '#ifdef XF86DRI' */ + return FALSE; + +#endif /* XF86DRI */ + +} + + +static void +R128CopyData422( + R128InfoPtr info, + unsigned char *src, + unsigned char *dst, + int srcPitch, + int dstPitch, + int h, + int w +){ + w <<= 1; + + /* Attempt data transfer with DMA and fall back to memcpy */ + + if (!R128DMA(info, src, dst, srcPitch, dstPitch, h, w)) { + while(h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } + } +} + +static void +R128CopyData420( + R128InfoPtr info, + unsigned char *src1, + unsigned char *src2, + unsigned char *src3, + unsigned char *dst1, + unsigned char *dst2, + unsigned char *dst3, + int srcPitch, + int srcPitch2, + int dstPitch, + int h, + int w +){ + int count; + + /* Attempt data transfer with DMA and fall back to memcpy */ + + if (!R128DMA(info, src1, dst1, srcPitch, dstPitch, h, w)) { + count = h; + while(count--) { + memcpy(dst1, src1, w); + src1 += srcPitch; + dst1 += dstPitch; + } + } + + w >>= 1; + h >>= 1; + dstPitch >>= 1; + + if (!R128DMA(info, src2, dst2, srcPitch2, dstPitch, h, w)) { + count = h; + while(count--) { + memcpy(dst2, src2, w); + src2 += srcPitch2; + dst2 += dstPitch; + } + } + + if (!R128DMA(info, src3, dst3, srcPitch2, dstPitch, h, w)) { + count = h; + while(count--) { + memcpy(dst3, src3, w); + src3 += srcPitch2; + dst3 += dstPitch; + } + } +} + + +static FBLinearPtr +R128AllocateMemory( + ScrnInfoPtr pScrn, + FBLinearPtr linear, + int size +){ + ScreenPtr pScreen; + FBLinearPtr new_linear; + + if(linear) { + if(linear->size >= size) + return linear; + + if(xf86ResizeOffscreenLinear(linear, size)) + return linear; + + xf86FreeOffscreenLinear(linear); + } + + pScreen = screenInfo.screens[pScrn->scrnIndex]; + + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, + NULL, NULL, NULL); + + if(!new_linear) { + int max_size; + + xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16, + PRIORITY_EXTREME); + + if(max_size < size) + return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, + NULL, NULL, NULL); + } + + return new_linear; +} + +static void +R128DisplayVideo422( + ScrnInfoPtr pScrn, + int id, + int offset, + short width, short height, + int pitch, + int left, int right, int top, + BoxPtr dstBox, + short src_w, short src_h, + short drw_w, short drw_h +){ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; + int v_inc, h_inc, step_by, tmp; + int p1_h_accum_init, p23_h_accum_init; + int p1_v_accum_init; + + R128ECP(pScrn, pPriv); + + v_inc = (src_h << 20) / drw_h; + h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w; + step_by = 1; + + while(h_inc >= (2 << 12)) { + step_by++; + h_inc >>= 1; + } + + /* keep everything in 16.16 */ + + offset += ((left >> 16) & ~7) << 1; + + tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3); + p1_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0xf0000000); + + tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2); + p23_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0x70000000); + + tmp = (top & 0x0000ffff) + 0x00018000; + p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001; + + left = (left >> 16) & 7; + + OUTREG(R128_OV0_REG_LOAD_CNTL, 1); + while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3))); + + OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16)); + OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8)); + OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16)); + OUTREG(R128_OV0_Y_X_END, dstBox->x2 | (dstBox->y2 << 16)); + OUTREG(R128_OV0_V_INC, v_inc); + OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16)); + OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch); + OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16)); + left >>= 1; width >>= 1; + OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (left << 16)); + OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (left << 16)); + OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset & 0xfffffff0); + OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init); + OUTREG(R128_OV0_P23_V_ACCUM_INIT, 0); + OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init); + OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init); + + if(id == FOURCC_UYVY) + OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8C03); + else + OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8B03); + + OUTREG(R128_OV0_REG_LOAD_CNTL, 0); +} + +static void +R128DisplayVideo420( + ScrnInfoPtr pScrn, + short width, short height, + int pitch, + int offset1, int offset2, int offset3, + int left, int right, int top, + BoxPtr dstBox, + short src_w, short src_h, + short drw_w, short drw_h +){ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; + int v_inc, h_inc, step_by, tmp, leftUV; + int p1_h_accum_init, p23_h_accum_init; + int p1_v_accum_init, p23_v_accum_init; + + v_inc = (src_h << 20) / drw_h; + h_inc = (src_w << (12 + pPriv->ecp_div)) / drw_w; + step_by = 1; + + while(h_inc >= (2 << 12)) { + step_by++; + h_inc >>= 1; + } + + /* keep everything in 16.16 */ + + offset1 += (left >> 16) & ~15; + offset2 += (left >> 17) & ~15; + offset3 += (left >> 17) & ~15; + + tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3); + p1_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0xf0000000); + + tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2); + p23_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0x70000000); + + tmp = (top & 0x0000ffff) + 0x00018000; + p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001; + + tmp = ((top >> 1) & 0x0000ffff) + 0x00018000; + p23_v_accum_init = ((tmp << 4) & 0x01ff8000) | 0x00000001; + + leftUV = (left >> 17) & 15; + left = (left >> 16) & 15; + + OUTREG(R128_OV0_REG_LOAD_CNTL, 1); + while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3))); + + OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16)); + OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8)); + OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16)); + OUTREG(R128_OV0_Y_X_END, dstBox->x2 | (dstBox->y2 << 16)); + OUTREG(R128_OV0_V_INC, v_inc); + OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16)); + src_h = (src_h + 1) >> 1; + OUTREG(R128_OV0_P23_BLANK_LINES_AT_TOP, 0x000007ff | ((src_h - 1) << 16)); + OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch); + OUTREG(R128_OV0_VID_BUF_PITCH1_VALUE, pitch >> 1); + OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16)); + width >>= 1; + OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (leftUV << 16)); + OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (leftUV << 16)); + OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0); + OUTREG(R128_OV0_VID_BUF1_BASE_ADRS, (offset2 & 0xfffffff0) | 0x00000001); + OUTREG(R128_OV0_VID_BUF2_BASE_ADRS, (offset3 & 0xfffffff0) | 0x00000001); + OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init); + OUTREG(R128_OV0_P23_V_ACCUM_INIT, p23_v_accum_init); + OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init); + OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init); + OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8A03); + + OUTREG(R128_OV0_REG_LOAD_CNTL, 0); +} + + + +static int +R128PutImage( + 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 +){ + R128InfoPtr info = R128PTR(pScrn); + R128PortPrivPtr pPriv = (R128PortPrivPtr)data; + INT32 xa, xb, ya, yb; + int new_size, offset, s1offset, s2offset, s3offset; + int srcPitch, srcPitch2, dstPitch; + int d1line, d2line, d3line, d1offset, d2offset, d3offset; + int top, left, npixels, nlines, bpp; + BoxRec dstBox; + CARD32 tmp; +#if X_BYTE_ORDER == X_BIG_ENDIAN + unsigned char *R128MMIO = info->MMIO; + CARD32 config_cntl = INREG(R128_CONFIG_CNTL); + + /* We need to disable byte swapping, or the data gets mangled */ + OUTREG(R128_CONFIG_CNTL, config_cntl & + ~(APER_0_BIG_ENDIAN_16BPP_SWAP | APER_0_BIG_ENDIAN_32BPP_SWAP)); +#endif + + /* + * s1offset, s2offset, s3offset - byte offsets to the Y, U and V planes + * of the source. + * + * d1offset, d2offset, d3offset - byte offsets to the Y, U and V planes + * of the destination. + * + * offset - byte offset within the framebuffer to where the destination + * is stored. + * + * d1line, d2line, d3line - byte offsets within the destination to the + * first displayed scanline in each plane. + * + */ + + if(src_w > (drw_w << 4)) + drw_w = src_w >> 4; + if(src_h > (drw_h << 4)) + drw_h = src_h >> 4; + + /* Clip */ + xa = src_x; + xb = src_x + src_w; + ya = src_y; + yb = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, + clipBoxes, width, height)) + return Success; + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + bpp = pScrn->bitsPerPixel >> 3; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + srcPitch = (width + 3) & ~3; + srcPitch2 = ((width >> 1) + 3) & ~3; + dstPitch = (width + 31) & ~31; /* of luma */ + new_size = ((dstPitch * (height + (height >> 1))) + bpp - 1) / bpp; + s1offset = 0; + s2offset = srcPitch * height; + s3offset = (srcPitch2 * (height >> 1)) + s2offset; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + srcPitch = width << 1; + srcPitch2 = 0; + dstPitch = ((width << 1) + 15) & ~15; + new_size = ((dstPitch * height) + bpp - 1) / bpp; + s1offset = 0; + s2offset = 0; + s3offset = 0; + break; + } + + if(!(pPriv->linear = R128AllocateMemory(pScrn, pPriv->linear, + pPriv->doubleBuffer ? (new_size << 1) : new_size))) + { + return BadAlloc; + } + + pPriv->currentBuffer ^= 1; + + /* copy data */ + top = ya >> 16; + left = (xa >> 16) & ~1; + npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left; + + offset = pPriv->linear->offset * bpp; + if(pPriv->doubleBuffer) + offset += pPriv->currentBuffer * new_size * bpp; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + d1line = top * dstPitch; + d2line = (height * dstPitch) + ((top >> 1) * (dstPitch >> 1)); + d3line = d2line + ((height >> 1) * (dstPitch >> 1)); + + top &= ~1; + + d1offset = (top * dstPitch) + left + offset; + d2offset = d2line + (left >> 1) + offset; + d3offset = d3line + (left >> 1) + offset; + + s1offset += (top * srcPitch) + left; + tmp = ((top >> 1) * srcPitch2) + (left >> 1); + s2offset += tmp; + s3offset += tmp; + if(id == FOURCC_YV12) { + tmp = s2offset; + s2offset = s3offset; + s3offset = tmp; + } + + nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top; + R128CopyData420(info, buf + s1offset, buf + s2offset, buf + s3offset, + info->FB+d1offset, info->FB+d2offset, info->FB+d3offset, + srcPitch, srcPitch2, dstPitch, nlines, npixels); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + left <<= 1; + d1line = top * dstPitch; + d2line = 0; + d3line = 0; + d1offset = d1line + left + offset; + d2offset = 0; + d3offset = 0; + s1offset += (top * srcPitch) + left; + nlines = ((yb + 0xffff) >> 16) - top; + R128CopyData422(info, buf + s1offset, info->FB + d1offset, + srcPitch, dstPitch, nlines, npixels); + break; + } + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* restore byte swapping */ + OUTREG(R128_CONFIG_CNTL, config_cntl); +#endif + + /* update cliplist */ + if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { + REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); + /* draw these */ + xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); + } + + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + R128DisplayVideo420(pScrn, width, height, dstPitch, + offset + d1line, offset + d2line, offset + d3line, + xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + R128DisplayVideo422(pScrn, id, offset + d1line, width, height, dstPitch, + xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h); + break; + } + + pPriv->videoStatus = CLIENT_VIDEO_ON; + + info->VideoTimerCallback = R128VideoTimerCallback; + + return Success; +} + + +static int +R128QueryImageAttributes( + ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets +){ + int size, tmp; + + if(*w > MAXWIDTH) *w = MAXWIDTH; + if(*h > MAXHEIGHT) *h = MAXHEIGHT; + + *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 +R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now) +{ + R128InfoPtr info = R128PTR(pScrn); + R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; + + if(pPriv->videoStatus & TIMER_MASK) { + if(pPriv->videoStatus & OFF_TIMER) { + if(pPriv->offTime < now) { + unsigned char *R128MMIO = info->MMIO; + OUTREG(R128_OV0_SCALE_CNTL, 0); + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = now + FREE_DELAY; + } + } else { /* FREE_TIMER */ + if(pPriv->freeTime < now) { + if(pPriv->linear) { + xf86FreeOffscreenLinear(pPriv->linear); + pPriv->linear = NULL; + } + pPriv->videoStatus = 0; + info->VideoTimerCallback = NULL; + } + } + } else /* shouldn't get here */ + info->VideoTimerCallback = NULL; +} diff --git a/src/radeon.h b/src/radeon.h new file mode 100644 index 0000000..fd91e3d --- /dev/null +++ b/src/radeon.h @@ -0,0 +1,758 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h,v 1.43 2003/11/06 18:38:00 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + */ + +#ifndef _RADEON_H_ +#define _RADEON_H_ + +#include "xf86str.h" + + /* PCI support */ +#include "xf86Pci.h" + + /* XAA and Cursor Support */ +#include "xaa.h" +#include "xf86Cursor.h" + + /* DDC support */ +#include "xf86DDC.h" + + /* Xv support */ +#include "xf86xv.h" + + /* DRI support */ +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "radeon_dripriv.h" +#include "dri.h" +#include "GL/glxint.h" +#endif + + /* Render support */ +#ifdef RENDER +#include "picturestr.h" +#endif + +#define RADEON_DEBUG 0 /* Turn off debugging output */ +#define RADEON_IDLE_RETRY 16 /* Fall out of idle loops after this count */ +#define RADEON_TIMEOUT 2000000 /* Fall out of wait loops after this count */ +#define RADEON_MMIOSIZE 0x80000 + +#define RADEON_VBIOS_SIZE 0x00010000 +#define RADEON_USE_RMX 0x80000000 /* mode flag for using RMX + * Need to comfirm this is not used + * for something else. + */ + +#if RADEON_DEBUG +#define RADEONTRACE(x) \ +do { \ + ErrorF("(**) %s(%d): ", RADEON_NAME, pScrn->scrnIndex); \ + ErrorF x; \ +} while (0); +#else +#define RADEONTRACE(x) +#endif + + +/* Other macros */ +#define RADEON_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define RADEON_ALIGN(x,bytes) (((x) + ((bytes) - 1)) & ~((bytes) - 1)) +#define RADEONPTR(pScrn) ((RADEONInfoPtr)(pScrn)->driverPrivate) + +typedef struct { + /* Common registers */ + CARD32 ovr_clr; + CARD32 ovr_wid_left_right; + CARD32 ovr_wid_top_bottom; + CARD32 ov0_scale_cntl; + CARD32 mpp_tb_config; + CARD32 mpp_gp_config; + CARD32 subpic_cntl; + CARD32 viph_control; + CARD32 i2c_cntl_1; + CARD32 gen_int_cntl; + CARD32 cap0_trig_cntl; + CARD32 cap1_trig_cntl; + CARD32 bus_cntl; + CARD32 surface_cntl; + CARD32 bios_5_scratch; + /* Other registers to save for VT switches */ + CARD32 dp_datatype; + CARD32 rbbm_soft_reset; + CARD32 clock_cntl_index; + CARD32 amcgpio_en_reg; + CARD32 amcgpio_mask; + + /* CRTC registers */ + CARD32 crtc_gen_cntl; + CARD32 crtc_ext_cntl; + CARD32 dac_cntl; + CARD32 crtc_h_total_disp; + CARD32 crtc_h_sync_strt_wid; + CARD32 crtc_v_total_disp; + CARD32 crtc_v_sync_strt_wid; + CARD32 crtc_offset; + CARD32 crtc_offset_cntl; + CARD32 crtc_pitch; + CARD32 disp_merge_cntl; + CARD32 grph_buffer_cntl; + CARD32 crtc_more_cntl; + + /* CRTC2 registers */ + CARD32 crtc2_gen_cntl; + + CARD32 dac2_cntl; + CARD32 disp_output_cntl; + CARD32 disp_hw_debug; + CARD32 disp2_merge_cntl; + CARD32 grph2_buffer_cntl; + CARD32 crtc2_h_total_disp; + CARD32 crtc2_h_sync_strt_wid; + CARD32 crtc2_v_total_disp; + CARD32 crtc2_v_sync_strt_wid; + CARD32 crtc2_offset; + CARD32 crtc2_offset_cntl; + CARD32 crtc2_pitch; + /* Flat panel registers */ + CARD32 fp_crtc_h_total_disp; + CARD32 fp_crtc_v_total_disp; + CARD32 fp_gen_cntl; + CARD32 fp2_gen_cntl; + CARD32 fp_h_sync_strt_wid; + CARD32 fp2_h_sync_strt_wid; + CARD32 fp_horz_stretch; + CARD32 fp_panel_cntl; + CARD32 fp_v_sync_strt_wid; + CARD32 fp2_v_sync_strt_wid; + CARD32 fp_vert_stretch; + CARD32 lvds_gen_cntl; + CARD32 lvds_pll_cntl; + CARD32 tmds_pll_cntl; + CARD32 tmds_transmitter_cntl; + + /* Computed values for PLL */ + CARD32 dot_clock_freq; + CARD32 pll_output_freq; + int feedback_div; + int post_div; + + /* PLL registers */ + unsigned ppll_ref_div; + unsigned ppll_div_3; + CARD32 htotal_cntl; + + /* Computed values for PLL2 */ + CARD32 dot_clock_freq_2; + CARD32 pll_output_freq_2; + int feedback_div_2; + int post_div_2; + + /* PLL2 registers */ + CARD32 p2pll_ref_div; + CARD32 p2pll_div_0; + CARD32 htotal_cntl2; + + /* Pallet */ + Bool palette_valid; + CARD32 palette[256]; + CARD32 palette2[256]; +} RADEONSaveRec, *RADEONSavePtr; + +typedef struct { + CARD16 reference_freq; + CARD16 reference_div; + CARD32 min_pll_freq; + CARD32 max_pll_freq; + CARD16 xclk; +} RADEONPLLRec, *RADEONPLLPtr; + +typedef struct { + int bitsPerPixel; + int depth; + int displayWidth; + int pixel_code; + int pixel_bytes; + DisplayModePtr mode; +} RADEONFBLayout; + +typedef enum { + MT_NONE, + MT_CRT, + MT_LCD, + MT_DFP, + MT_CTV, + MT_STV +} RADEONMonitorType; + +typedef enum { + DDC_NONE_DETECTED, + DDC_MONID, + DDC_DVI, + DDC_VGA, + DDC_CRT2 +} RADEONDDCType; + +typedef enum { + CONNECTOR_NONE, + CONNECTOR_PROPRIETARY, + CONNECTOR_CRT, + CONNECTOR_DVI_I, + CONNECTOR_DVI_D +} RADEONConnectorType; + +typedef enum { + CHIP_FAMILY_UNKNOW, + CHIP_FAMILY_LEGACY, + CHIP_FAMILY_RADEON, + CHIP_FAMILY_RV100, + CHIP_FAMILY_RS100, /* U1 (IGP320M) or A3 (IGP320)*/ + CHIP_FAMILY_RV200, + CHIP_FAMILY_RS200, /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350), RS250 (IGP 7000) */ + CHIP_FAMILY_R200, + CHIP_FAMILY_RV250, + CHIP_FAMILY_RS300, /* Radeon 9000 IGP */ + CHIP_FAMILY_RV280, + CHIP_FAMILY_R300, + CHIP_FAMILY_R350, + CHIP_FAMILY_RV350, + CHIP_FAMILY_LAST +} RADEONChipFamily; + +typedef struct { + CARD32 freq; + CARD32 value; +}RADEONTMDSPll; + +typedef struct { + EntityInfoPtr pEnt; + pciVideoPtr PciInfo; + PCITAG PciTag; + int Chipset; + RADEONChipFamily ChipFamily; + + Bool FBDev; + + unsigned long LinearAddr; /* Frame buffer physical address */ + unsigned long MMIOAddr; /* MMIO region physical address */ + unsigned long BIOSAddr; /* BIOS physical address */ + + unsigned char *MMIO; /* Map of MMIO region */ + unsigned char *FB; /* Map of frame buffer */ + CARD8 *VBIOS; /* Video BIOS pointer */ + + CARD32 MemCntl; + CARD32 BusCntl; + unsigned long FbMapSize; /* Size of frame buffer, in bytes */ + int Flags; /* Saved copy of mode flags */ + + /* VE/M6 support */ + RADEONMonitorType DisplayType; /* Monitor connected on */ + RADEONDDCType DDCType; + RADEONConnectorType ConnectorType; + Bool HasCRTC2; /* All cards except original Radeon */ + Bool IsMobility; /* Mobile chips for laptops */ + Bool IsIGP; /* IGP chips */ + Bool IsSecondary; /* Second Screen */ + Bool IsSwitching; /* Flag for switching mode */ + Bool Clone; /* Force second head to clone primary*/ + RADEONMonitorType CloneType; + RADEONDDCType CloneDDCType; + DisplayModePtr CloneModes; + DisplayModePtr CurCloneMode; + int CloneFrameX0; + int CloneFrameY0; + Bool OverlayOnCRTC2; + Bool PanelOff; /* Force panel (LCD/DFP) off */ + int FPBIOSstart; /* Start of the flat panel info */ + Bool ddc_mode; /* Validate mode by matching exactly + * the modes supported in DDC data + */ + Bool R300CGWorkaround; + + /* EDID or BIOS values for FPs */ + int PanelXRes; + int PanelYRes; + int HOverPlus; + int HSyncWidth; + int HBlank; + int VOverPlus; + int VSyncWidth; + int VBlank; + int PanelPwrDly; + int DotClock; + int RefDivider; + int FeedbackDivider; + int PostDivider; + Bool UseBiosDividers; + /* EDID data using DDC interface */ + Bool ddc_bios; + Bool ddc1; + Bool ddc2; + I2CBusPtr pI2CBus; + CARD32 DDCReg; + + RADEONPLLRec pll; + RADEONTMDSPll tmds_pll[4]; + int RamWidth; + float sclk; /* in MHz */ + float mclk; /* in MHz */ + Bool IsDDR; + int DispPriority; + + RADEONSaveRec SavedReg; /* Original (text) mode */ + RADEONSaveRec ModeReg; /* Current mode */ + Bool (*CloseScreen)(int, ScreenPtr); + + void (*BlockHandler)(int, pointer, pointer, pointer); + + Bool PaletteSavedOnVT; /* Palette saved on last VT switch */ + + XAAInfoRecPtr accel; + Bool accelOn; + xf86CursorInfoPtr cursor; + unsigned long cursor_start; + unsigned long cursor_end; +#ifdef ARGB_CURSOR + Bool cursor_argb; +#endif + int cursor_fg; + int cursor_bg; + + /* + * XAAForceTransBlit is used to change the behavior of the XAA + * SetupForScreenToScreenCopy function, to make it DGA-friendly. + */ + Bool XAAForceTransBlit; + + int fifo_slots; /* Free slots in the FIFO (64 max) */ + int pix24bpp; /* Depth of pixmap for 24bpp fb */ + Bool dac6bits; /* Use 6 bit DAC? */ + + /* Computed values for Radeon */ + int pitch; + int datatype; + CARD32 dp_gui_master_cntl; + CARD32 dp_gui_master_cntl_clip; + CARD32 trans_color; + + /* Saved values for ScreenToScreenCopy */ + int xdir; + int ydir; + + /* ScanlineScreenToScreenColorExpand support */ + unsigned char *scratch_buffer[1]; + unsigned char *scratch_save; + int scanline_x; + int scanline_y; + int scanline_w; + int scanline_h; + int scanline_h_w; + int scanline_words; + int scanline_direct; + int scanline_bpp; /* Only used for ImageWrite */ + int scanline_fg; + int scanline_bg; + int scanline_hpass; + int scanline_x1clip; + int scanline_x2clip; + + /* Saved values for DashedTwoPointLine */ + int dashLen; + CARD32 dashPattern; + int dash_fg; + int dash_bg; + + DGAModePtr DGAModes; + int numDGAModes; + Bool DGAactive; + int DGAViewportStatus; + DGAFunctionRec DGAFuncs; + + RADEONFBLayout CurrentLayout; +#ifdef XF86DRI + Bool noBackBuffer; + Bool directRenderingEnabled; + DRIInfoPtr pDRIInfo; + int drmFD; + int numVisualConfigs; + __GLXvisualConfig *pVisualConfigs; + RADEONConfigPrivPtr pVisualConfigsPriv; + + drmHandle fbHandle; + + drmSize registerSize; + drmHandle registerHandle; + + Bool IsPCI; /* Current card is a PCI card */ + drmSize pciSize; + drmHandle pciMemHandle; + unsigned char *PCI; /* Map */ + + Bool depthMoves; /* Enable depth moves -- slow! */ + Bool allowPageFlip; /* Enable 3d page flipping */ + Bool have3DWindows; /* Are there any 3d clients? */ + int drmMinor; + + drmSize gartSize; + drmHandle agpMemHandle; /* Handle from drmAgpAlloc */ + unsigned long gartOffset; + unsigned char *AGP; /* Map */ + int agpMode; + int agpFastWrite; + + CARD32 pciCommand; + + Bool CPRuns; /* CP is running */ + Bool CPInUse; /* CP has been used by X server */ + Bool CPStarted; /* CP has started */ + int CPMode; /* CP mode that server/clients use */ + int CPFifoSize; /* Size of the CP command FIFO */ + int CPusecTimeout; /* CP timeout in usecs */ + + /* CP ring buffer data */ + unsigned long ringStart; /* Offset into GART space */ + drmHandle ringHandle; /* Handle from drmAddMap */ + drmSize ringMapSize; /* Size of map */ + int ringSize; /* Size of ring (in MB) */ + unsigned char *ring; /* Map */ + int ringSizeLog2QW; + + unsigned long ringReadOffset; /* Offset into GART space */ + drmHandle ringReadPtrHandle; /* Handle from drmAddMap */ + drmSize ringReadMapSize; /* Size of map */ + unsigned char *ringReadPtr; /* Map */ + + /* CP vertex/indirect buffer data */ + unsigned long bufStart; /* Offset into GART space */ + drmHandle bufHandle; /* Handle from drmAddMap */ + drmSize bufMapSize; /* Size of map */ + int bufSize; /* Size of buffers (in MB) */ + unsigned char *buf; /* Map */ + int bufNumBufs; /* Number of buffers */ + drmBufMapPtr buffers; /* Buffer map */ + + /* CP GART Texture data */ + unsigned long gartTexStart; /* Offset into GART space */ + drmHandle gartTexHandle; /* Handle from drmAddMap */ + drmSize gartTexMapSize; /* Size of map */ + int gartTexSize; /* Size of GART tex space (in MB) */ + unsigned char *gartTex; /* Map */ + int log2GARTTexGran; + + /* CP accleration */ + drmBufPtr indirectBuffer; + int indirectStart; + + /* DRI screen private data */ + int fbX; + int fbY; + int backX; + int backY; + int depthX; + int depthY; + + int frontOffset; + int frontPitch; + int backOffset; + int backPitch; + int depthOffset; + int depthPitch; + int textureOffset; + int textureSize; + int log2TexGran; + + CARD32 frontPitchOffset; + CARD32 backPitchOffset; + CARD32 depthPitchOffset; + + CARD32 dst_pitch_offset; + + /* offscreen memory management */ + int backLines; + FBAreaPtr backArea; + int depthTexLines; + FBAreaPtr depthTexArea; + + /* Saved scissor values */ + CARD32 sc_left; + CARD32 sc_right; + CARD32 sc_top; + CARD32 sc_bottom; + + CARD32 re_top_left; + CARD32 re_width_height; + + CARD32 aux_sc_cntl; + + int irq; + +#ifdef PER_CONTEXT_SAREA + int perctx_sarea_size; +#endif +#endif + + /* XVideo */ + XF86VideoAdaptorPtr adaptor; + void (*VideoTimerCallback)(ScrnInfoPtr, Time); + FBLinearPtr videoLinear; + int videoKey; + + /* general */ + Bool showCache; + OptionInfoPtr Options; +#ifdef XFree86LOADER + XF86ModReqInfo xaaReq; +#endif +} RADEONInfoRec, *RADEONInfoPtr; + +#define RADEONWaitForFifo(pScrn, entries) \ +do { \ + if (info->fifo_slots < entries) \ + RADEONWaitForFifoFunction(pScrn, entries); \ + info->fifo_slots -= entries; \ +} while (0) + +extern void RADEONWaitForFifoFunction(ScrnInfoPtr pScrn, int entries); +extern void RADEONWaitForIdleMMIO(ScrnInfoPtr pScrn); +#ifdef XF86DRI +extern void RADEONWaitForIdleCP(ScrnInfoPtr pScrn); +#endif + +extern void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, + int clone); + +extern void RADEONEngineReset(ScrnInfoPtr pScrn); +extern void RADEONEngineFlush(ScrnInfoPtr pScrn); +extern void RADEONEngineRestore(ScrnInfoPtr pScrn); + +extern unsigned RADEONINPLL(ScrnInfoPtr pScrn, int addr); +extern void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn); +extern void RADEONWaitForVerticalSync2(ScrnInfoPtr pScrn); + +extern void RADEONSelectBuffer(ScrnInfoPtr pScrn, int buffer); + +extern Bool RADEONAccelInit(ScreenPtr pScreen); +extern void RADEONEngineInit(ScrnInfoPtr pScrn); +extern Bool RADEONCursorInit(ScreenPtr pScreen); +extern Bool RADEONDGAInit(ScreenPtr pScreen); + +extern int RADEONMinBits(int val); + +extern void RADEONInitVideo(ScreenPtr pScreen); +extern void RADEONResetVideo(ScrnInfoPtr pScrn); +extern void R300CGWorkaround(ScrnInfoPtr pScrn); + +#ifdef XF86DRI +extern Bool RADEONDRIScreenInit(ScreenPtr pScreen); +extern void RADEONDRICloseScreen(ScreenPtr pScreen); +extern void RADEONDRIResume(ScreenPtr pScreen); +extern Bool RADEONDRIFinishScreenInit(ScreenPtr pScreen); + +extern drmBufPtr RADEONCPGetBuffer(ScrnInfoPtr pScrn); +extern void RADEONCPFlushIndirect(ScrnInfoPtr pScrn, int discard); +extern void RADEONCPReleaseIndirect(ScrnInfoPtr pScrn); +extern int RADEONCPStop(ScrnInfoPtr pScrn, RADEONInfoPtr info); + + +#define RADEONCP_START(pScrn, info) \ +do { \ + int _ret = drmCommandNone(info->drmFD, DRM_RADEON_CP_START); \ + if (_ret) { \ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, \ + "%s: CP start %d\n", __FUNCTION__, _ret); \ + } \ + info->CPStarted = TRUE; \ +} while (0) + +#define RADEONCP_STOP(pScrn, info) \ +do { \ + int _ret; \ + if (info->CPStarted) { \ + _ret = RADEONCPStop(pScrn, info); \ + if (_ret) { \ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, \ + "%s: CP stop %d\n", __FUNCTION__, _ret); \ + } \ + info->CPStarted = FALSE; \ + } \ + RADEONEngineRestore(pScrn); \ + info->CPRuns = FALSE; \ +} while (0) + +#define RADEONCP_RESET(pScrn, info) \ +do { \ + if (RADEONCP_USE_RING_BUFFER(info->CPMode)) { \ + int _ret = drmCommandNone(info->drmFD, DRM_RADEON_CP_RESET); \ + if (_ret) { \ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, \ + "%s: CP reset %d\n", __FUNCTION__, _ret); \ + } \ + } \ +} while (0) + +#define RADEONCP_REFRESH(pScrn, info) \ +do { \ + if (!info->CPInUse) { \ + RADEON_WAIT_UNTIL_IDLE(); \ + BEGIN_RING(6); \ + OUT_RING_REG(RADEON_RE_TOP_LEFT, info->re_top_left); \ + OUT_RING_REG(RADEON_RE_WIDTH_HEIGHT, info->re_width_height); \ + OUT_RING_REG(RADEON_AUX_SC_CNTL, info->aux_sc_cntl); \ + ADVANCE_RING(); \ + info->CPInUse = TRUE; \ + } \ +} while (0) + + +#define CP_PACKET0(reg, n) \ + (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) +#define CP_PACKET1(reg0, reg1) \ + (RADEON_CP_PACKET1 | (((reg1) >> 2) << 11) | ((reg0) >> 2)) +#define CP_PACKET2() \ + (RADEON_CP_PACKET2) +#define CP_PACKET3(pkt, n) \ + (RADEON_CP_PACKET3 | (pkt) | ((n) << 16)) + + +#define RADEON_VERBOSE 0 + +#define RING_LOCALS CARD32 *__head = NULL; int __count = 0 + +#define BEGIN_RING(n) do { \ + if (RADEON_VERBOSE) { \ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, \ + "BEGIN_RING(%d) in %s\n", n, __FUNCTION__); \ + } \ + if (!info->indirectBuffer) { \ + info->indirectBuffer = RADEONCPGetBuffer(pScrn); \ + info->indirectStart = 0; \ + } else if (info->indirectBuffer->used + (n) * (int)sizeof(CARD32) > \ + info->indirectBuffer->total) { \ + RADEONCPFlushIndirect(pScrn, 1); \ + } \ + __head = (pointer)((char *)info->indirectBuffer->address + \ + info->indirectBuffer->used); \ + __count = 0; \ +} while (0) + +#define ADVANCE_RING() do { \ + if (RADEON_VERBOSE) { \ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, \ + "ADVANCE_RING() start: %d used: %d count: %d\n", \ + info->indirectStart, \ + info->indirectBuffer->used, \ + __count * (int)sizeof(CARD32)); \ + } \ + info->indirectBuffer->used += __count * (int)sizeof(CARD32); \ +} while (0) + +#define OUT_RING(x) do { \ + if (RADEON_VERBOSE) { \ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, \ + " OUT_RING(0x%08x)\n", (unsigned int)(x)); \ + } \ + __head[__count++] = (x); \ +} while (0) + +#define OUT_RING_REG(reg, val) \ +do { \ + OUT_RING(CP_PACKET0(reg, 0)); \ + OUT_RING(val); \ +} while (0) + +#define FLUSH_RING() \ +do { \ + if (RADEON_VERBOSE) \ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, \ + "FLUSH_RING in %s\n", __FUNCTION__); \ + if (info->indirectBuffer) { \ + RADEONCPFlushIndirect(pScrn, 0); \ + } \ +} while (0) + + +#define RADEON_WAIT_UNTIL_2D_IDLE() \ +do { \ + BEGIN_RING(2); \ + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); \ + OUT_RING((RADEON_WAIT_2D_IDLECLEAN | \ + RADEON_WAIT_HOST_IDLECLEAN)); \ + ADVANCE_RING(); \ +} while (0) + +#define RADEON_WAIT_UNTIL_3D_IDLE() \ +do { \ + BEGIN_RING(2); \ + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); \ + OUT_RING((RADEON_WAIT_3D_IDLECLEAN | \ + RADEON_WAIT_HOST_IDLECLEAN)); \ + ADVANCE_RING(); \ +} while (0) + +#define RADEON_WAIT_UNTIL_IDLE() \ +do { \ + if (RADEON_VERBOSE) { \ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, \ + "WAIT_UNTIL_IDLE() in %s\n", __FUNCTION__); \ + } \ + BEGIN_RING(2); \ + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); \ + OUT_RING((RADEON_WAIT_2D_IDLECLEAN | \ + RADEON_WAIT_3D_IDLECLEAN | \ + RADEON_WAIT_HOST_IDLECLEAN)); \ + ADVANCE_RING(); \ +} while (0) + +#define RADEON_FLUSH_CACHE() \ +do { \ + BEGIN_RING(2); \ + OUT_RING(CP_PACKET0(RADEON_RB2D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB2D_DC_FLUSH); \ + ADVANCE_RING(); \ +} while (0) + +#define RADEON_PURGE_CACHE() \ +do { \ + BEGIN_RING(2); \ + OUT_RING(CP_PACKET0(RADEON_RB2D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB2D_DC_FLUSH_ALL); \ + ADVANCE_RING(); \ +} while (0) + +#endif /* XF86DRI */ + +#endif /* _RADEON_H_ */ diff --git a/src/radeon_accel.c b/src/radeon_accel.c new file mode 100644 index 0000000..52955d4 --- /dev/null +++ b/src/radeon_accel.c @@ -0,0 +1,615 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c,v 1.36 2003/11/10 18:41:22 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + * Credits: + * + * Thanks to Ani Joshi <ajoshi@shell.unixbox.com> for providing source + * code to his Radeon driver. Portions of this file are based on the + * initialization code for that driver. + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + * Notes on unimplemented XAA optimizations: + * + * SetClipping: This has been removed as XAA expects 16bit registers + * for full clipping. + * TwoPointLine: The Radeon supports this. Not Bresenham. + * DashedLine with non-power-of-two pattern length: Apparently, there is + * no way to set the length of the pattern -- it is always + * assumed to be 8 or 32 (or 1024?). + * ScreenToScreenColorExpandFill: See p. 4-17 of the Technical Reference + * Manual where it states that monochrome expansion of frame + * buffer data is not supported. + * CPUToScreenColorExpandFill, direct: The implementation here uses a hybrid + * direct/indirect method. If we had more data registers, + * then we could do better. If XAA supported a trigger write + * address, the code would be simpler. + * Color8x8PatternFill: Apparently, an 8x8 color brush cannot take an 8x8 + * pattern from frame buffer memory. + * ImageWrites: Same as CPUToScreenColorExpandFill + * + */ + + /* Driver data structures */ +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_reg.h" +#include "radeon_version.h" +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "radeon_dri.h" +#include "radeon_sarea.h" +#endif + + /* Line support */ +#include "miline.h" + + /* X and server generic header files */ +#include "xf86.h" + +static struct { + int rop; + int pattern; +} RADEON_ROP[] = { + { RADEON_ROP3_ZERO, RADEON_ROP3_ZERO }, /* GXclear */ + { RADEON_ROP3_DSa, RADEON_ROP3_DPa }, /* Gxand */ + { RADEON_ROP3_SDna, RADEON_ROP3_PDna }, /* GXandReverse */ + { RADEON_ROP3_S, RADEON_ROP3_P }, /* GXcopy */ + { RADEON_ROP3_DSna, RADEON_ROP3_DPna }, /* GXandInverted */ + { RADEON_ROP3_D, RADEON_ROP3_D }, /* GXnoop */ + { RADEON_ROP3_DSx, RADEON_ROP3_DPx }, /* GXxor */ + { RADEON_ROP3_DSo, RADEON_ROP3_DPo }, /* GXor */ + { RADEON_ROP3_DSon, RADEON_ROP3_DPon }, /* GXnor */ + { RADEON_ROP3_DSxn, RADEON_ROP3_PDxn }, /* GXequiv */ + { RADEON_ROP3_Dn, RADEON_ROP3_Dn }, /* GXinvert */ + { RADEON_ROP3_SDno, RADEON_ROP3_PDno }, /* GXorReverse */ + { RADEON_ROP3_Sn, RADEON_ROP3_Pn }, /* GXcopyInverted */ + { RADEON_ROP3_DSno, RADEON_ROP3_DPno }, /* GXorInverted */ + { RADEON_ROP3_DSan, RADEON_ROP3_DPan }, /* GXnand */ + { RADEON_ROP3_ONE, RADEON_ROP3_ONE } /* GXset */ +}; + +extern int gRADEONEntityIndex; + +/* The FIFO has 64 slots. This routines waits until at least `entries' + * of these slots are empty. + */ +void RADEONWaitForFifoFunction(ScrnInfoPtr pScrn, int entries) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + + for (;;) { + for (i = 0; i < RADEON_TIMEOUT; i++) { + info->fifo_slots = + INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK; + if (info->fifo_slots >= entries) return; + } + RADEONTRACE(("FIFO timed out: %d entries, stat=0x%08x\n", + INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK, + INREG(RADEON_RBBM_STATUS))); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "FIFO timed out, resetting engine...\n"); + RADEONEngineReset(pScrn); + RADEONEngineRestore(pScrn); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONCP_RESET(pScrn, info); + RADEONCP_START(pScrn, info); + } +#endif + } +} + +/* Flush all dirty data in the Pixel Cache to memory */ +void RADEONEngineFlush(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + + OUTREGP(RADEON_RB2D_DSTCACHE_CTLSTAT, + RADEON_RB2D_DC_FLUSH_ALL, + ~RADEON_RB2D_DC_FLUSH_ALL); + for (i = 0; i < RADEON_TIMEOUT; i++) { + if (!(INREG(RADEON_RB2D_DSTCACHE_CTLSTAT) & RADEON_RB2D_DC_BUSY)) + break; + } +} + +/* Reset graphics card to known state */ +void RADEONEngineReset(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 clock_cntl_index; + CARD32 mclk_cntl; + CARD32 rbbm_soft_reset; + CARD32 host_path_cntl; + + RADEONEngineFlush(pScrn); + + clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX); + if (info->R300CGWorkaround) R300CGWorkaround(pScrn); + + /* Some ASICs have bugs with dynamic-on feature, which are + * ASIC-version dependent, so we force all blocks on for now + */ + if (info->HasCRTC2) { + CARD32 tmp; + + tmp = INPLL(pScrn, RADEON_SCLK_CNTL); + OUTPLL(RADEON_SCLK_CNTL, ((tmp & ~RADEON_DYN_STOP_LAT_MASK) | + RADEON_CP_MAX_DYN_STOP_LAT | + RADEON_SCLK_FORCEON_MASK)); + + if (info->ChipFamily == CHIP_FAMILY_RV200) { + tmp = INPLL(pScrn, RADEON_SCLK_MORE_CNTL); + OUTPLL(RADEON_SCLK_MORE_CNTL, tmp | RADEON_SCLK_MORE_FORCEON); + } + } + + mclk_cntl = INPLL(pScrn, RADEON_MCLK_CNTL); + OUTPLL(RADEON_MCLK_CNTL, (mclk_cntl | + RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB | + RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC | + RADEON_FORCEON_AIC)); + + /* Soft resetting HDP thru RBBM_SOFT_RESET register can cause some + * unexpected behaviour on some machines. Here we use + * RADEON_HOST_PATH_CNTL to reset it. + */ + host_path_cntl = INREG(RADEON_HOST_PATH_CNTL); + rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET); + + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) { + CARD32 tmp; + + OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset | + RADEON_SOFT_RESET_CP | + RADEON_SOFT_RESET_HI | + RADEON_SOFT_RESET_E2)); + INREG(RADEON_RBBM_SOFT_RESET); + OUTREG(RADEON_RBBM_SOFT_RESET, 0); + tmp = INREG(RADEON_RB2D_DSTCACHE_MODE); + OUTREG(RADEON_RB2D_DSTCACHE_MODE, tmp | (1 << 17)); /* FIXME */ + } else { + OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset | + RADEON_SOFT_RESET_CP | + RADEON_SOFT_RESET_HI | + RADEON_SOFT_RESET_SE | + RADEON_SOFT_RESET_RE | + RADEON_SOFT_RESET_PP | + RADEON_SOFT_RESET_E2 | + RADEON_SOFT_RESET_RB)); + INREG(RADEON_RBBM_SOFT_RESET); + OUTREG(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset & (CARD32) + ~(RADEON_SOFT_RESET_CP | + RADEON_SOFT_RESET_HI | + RADEON_SOFT_RESET_SE | + RADEON_SOFT_RESET_RE | + RADEON_SOFT_RESET_PP | + RADEON_SOFT_RESET_E2 | + RADEON_SOFT_RESET_RB))); + INREG(RADEON_RBBM_SOFT_RESET); + } + + OUTREG(RADEON_HOST_PATH_CNTL, host_path_cntl | RADEON_HDP_SOFT_RESET); + INREG(RADEON_HOST_PATH_CNTL); + OUTREG(RADEON_HOST_PATH_CNTL, host_path_cntl); + + if ((info->ChipFamily != CHIP_FAMILY_R300) && + (info->ChipFamily != CHIP_FAMILY_R350) && + (info->ChipFamily != CHIP_FAMILY_RV350)) + OUTREG(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset); + + OUTREG(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index); + OUTPLL(RADEON_MCLK_CNTL, mclk_cntl); + if (info->R300CGWorkaround) R300CGWorkaround(pScrn); +} + +/* Restore the acceleration hardware to its previous state */ +void RADEONEngineRestore(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int pitch64; + + RADEONTRACE(("EngineRestore (%d/%d)\n", + info->CurrentLayout.pixel_code, + info->CurrentLayout.bitsPerPixel)); + + RADEONWaitForFifo(pScrn, 1); + + /* NOTE: The following RB2D_DSTCACHE_MODE setting will cause the + * R300 to hang. ATI does not see a reason to change it from the + * default BIOS settings (even on non-R300 cards). This setting + * might be removed in future versions of the Radeon driver. + */ + + /* Turn of all automatic flushing - we'll do it all */ + if ((info->ChipFamily != CHIP_FAMILY_R300) && + (info->ChipFamily != CHIP_FAMILY_R350) && + (info->ChipFamily != CHIP_FAMILY_RV350)) + OUTREG(RADEON_RB2D_DSTCACHE_MODE, 0); + + pitch64 = ((pScrn->displayWidth * (pScrn->bitsPerPixel / 8) + 0x3f)) >> 6; + + RADEONWaitForFifo(pScrn, 1); + OUTREG(RADEON_DEFAULT_OFFSET, ((INREG(RADEON_DISPLAY_BASE_ADDR) >> 10) + | (pitch64 << 22))); + + RADEONWaitForFifo(pScrn, 1); +#if X_BYTE_ORDER == X_BIG_ENDIAN + OUTREGP(RADEON_DP_DATATYPE, + RADEON_HOST_BIG_ENDIAN_EN, + ~RADEON_HOST_BIG_ENDIAN_EN); +#else + OUTREGP(RADEON_DP_DATATYPE, 0, ~RADEON_HOST_BIG_ENDIAN_EN); +#endif + + /* Restore SURFACE_CNTL - only the first head contains valid data -ReneR */ + if (!info->IsSecondary) { + OUTREG(RADEON_SURFACE_CNTL, info->ModeReg.surface_cntl); + } + + RADEONWaitForFifo(pScrn, 1); + OUTREG(RADEON_DEFAULT_SC_BOTTOM_RIGHT, (RADEON_DEFAULT_SC_RIGHT_MAX + | RADEON_DEFAULT_SC_BOTTOM_MAX)); + RADEONWaitForFifo(pScrn, 1); + OUTREG(RADEON_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl + | RADEON_GMC_BRUSH_SOLID_COLOR + | RADEON_GMC_SRC_DATATYPE_COLOR)); + + RADEONWaitForFifo(pScrn, 7); + OUTREG(RADEON_DST_LINE_START, 0); + OUTREG(RADEON_DST_LINE_END, 0); + OUTREG(RADEON_DP_BRUSH_FRGD_CLR, 0xffffffff); + OUTREG(RADEON_DP_BRUSH_BKGD_CLR, 0x00000000); + OUTREG(RADEON_DP_SRC_FRGD_CLR, 0xffffffff); + OUTREG(RADEON_DP_SRC_BKGD_CLR, 0x00000000); + OUTREG(RADEON_DP_WRITE_MASK, 0xffffffff); + + RADEONWaitForIdleMMIO(pScrn); +} + +/* Initialize the acceleration hardware */ +void RADEONEngineInit(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + RADEONTRACE(("EngineInit (%d/%d)\n", + info->CurrentLayout.pixel_code, + info->CurrentLayout.bitsPerPixel)); + + OUTREG(RADEON_RB3D_CNTL, 0); +#if defined(__powerpc__) +#if defined(XF86_DRI) + if(!info->directRenderingEnabled) +#endif + { + OUTREG(RADEON_MC_FB_LOCATION, 0xffff0000); + OUTREG(RADEON_MC_AGP_LOCATION, 0xfffff000); + } +#endif + + RADEONEngineReset(pScrn); + + switch (info->CurrentLayout.pixel_code) { + case 8: info->datatype = 2; break; + case 15: info->datatype = 3; break; + case 16: info->datatype = 4; break; + case 24: info->datatype = 5; break; + case 32: info->datatype = 6; break; + default: + RADEONTRACE(("Unknown depth/bpp = %d/%d (code = %d)\n", + info->CurrentLayout.depth, + info->CurrentLayout.bitsPerPixel, + info->CurrentLayout.pixel_code)); + } + info->pitch = ((info->CurrentLayout.displayWidth / 8) * + (info->CurrentLayout.pixel_bytes == 3 ? 3 : 1)); + + RADEONTRACE(("Pitch for acceleration = %d\n", info->pitch)); + + info->dp_gui_master_cntl = + ((info->datatype << RADEON_GMC_DST_DATATYPE_SHIFT) + | RADEON_GMC_CLR_CMP_CNTL_DIS); + +#ifdef XF86DRI + info->sc_left = 0x00000000; + info->sc_right = RADEON_DEFAULT_SC_RIGHT_MAX; + info->sc_top = 0x00000000; + info->sc_bottom = RADEON_DEFAULT_SC_BOTTOM_MAX; + + info->re_top_left = 0x00000000; + info->re_width_height = ((0x7ff << RADEON_RE_WIDTH_SHIFT) | + (0x7ff << RADEON_RE_HEIGHT_SHIFT)); + + info->aux_sc_cntl = 0x00000000; +#endif + + RADEONEngineRestore(pScrn); +} + +#define ACCEL_MMIO +#define ACCEL_PREAMBLE() unsigned char *RADEONMMIO = info->MMIO +#define BEGIN_ACCEL(n) RADEONWaitForFifo(pScrn, (n)) +#define OUT_ACCEL_REG(reg, val) OUTREG(reg, val) +#define FINISH_ACCEL() + +#include "radeon_accelfuncs.c" + +#undef ACCEL_MMIO +#undef ACCEL_PREAMBLE +#undef BEGIN_ACCEL +#undef OUT_ACCEL_REG +#undef FINISH_ACCEL + +#ifdef XF86DRI + +#define ACCEL_CP +#define ACCEL_PREAMBLE() \ + RING_LOCALS; \ + RADEONCP_REFRESH(pScrn, info) +#define BEGIN_ACCEL(n) BEGIN_RING(2*(n)) +#define OUT_ACCEL_REG(reg, val) OUT_RING_REG(reg, val) +#define FINISH_ACCEL() ADVANCE_RING() + +#include "radeon_accelfuncs.c" + +#undef ACCEL_CP +#undef ACCEL_PREAMBLE +#undef BEGIN_ACCEL +#undef OUT_ACCEL_REG +#undef FINISH_ACCEL + +/* Stop the CP */ +int RADEONCPStop(ScrnInfoPtr pScrn, RADEONInfoPtr info) +{ + drmRadeonCPStop stop; + int ret, i; + + stop.flush = 1; + stop.idle = 1; + + ret = drmCommandWrite(info->drmFD, DRM_RADEON_CP_STOP, &stop, + sizeof(drmRadeonCPStop)); + + if (ret == 0) { + return 0; + } else if (errno != EBUSY) { + return -errno; + } + + stop.flush = 0; + + i = 0; + do { + ret = drmCommandWrite(info->drmFD, DRM_RADEON_CP_STOP, &stop, + sizeof(drmRadeonCPStop)); + } while (ret && errno == EBUSY && i++ < RADEON_IDLE_RETRY); + + if (ret == 0) { + return 0; + } else if (errno != EBUSY) { + return -errno; + } + + stop.idle = 0; + + if (drmCommandWrite(info->drmFD, DRM_RADEON_CP_STOP, + &stop, sizeof(drmRadeonCPStop))) { + return -errno; + } else { + return 0; + } +} + +/* Get an indirect buffer for the CP 2D acceleration commands */ +drmBufPtr RADEONCPGetBuffer(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + drmDMAReq dma; + drmBufPtr buf = NULL; + int indx = 0; + int size = 0; + int i = 0; + int ret; + +#if 0 + /* FIXME: pScrn->pScreen has not been initialized when this is first + * called from RADEONSelectBuffer via RADEONDRICPInit. We could use + * the screen index from pScrn, which is initialized, and then get + * the screen from screenInfo.screens[index], but that is a hack. + */ + dma.context = DRIGetContext(pScrn->pScreen); +#else + /* This is the X server's context */ + dma.context = 0x00000001; +#endif + + dma.send_count = 0; + dma.send_list = NULL; + dma.send_sizes = NULL; + dma.flags = 0; + dma.request_count = 1; + dma.request_size = RADEON_BUFFER_SIZE; + dma.request_list = &indx; + dma.request_sizes = &size; + dma.granted_count = 0; + + while (1) { + do { + ret = drmDMA(info->drmFD, &dma); + if (ret && ret != -EBUSY) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "%s: CP GetBuffer %d\n", __FUNCTION__, ret); + } + } while ((ret == -EBUSY) && (i++ < RADEON_TIMEOUT)); + + if (ret == 0) { + buf = &info->buffers->list[indx]; + buf->used = 0; + if (RADEON_VERBOSE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + " GetBuffer returning %d %p\n", + buf->idx, buf->address); + } + return buf; + } + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "GetBuffer timed out, resetting engine...\n"); + RADEONEngineReset(pScrn); + RADEONEngineRestore(pScrn); + + /* Always restart the engine when doing CP 2D acceleration */ + RADEONCP_RESET(pScrn, info); + RADEONCP_START(pScrn, info); + } +} + +/* Flush the indirect buffer to the kernel for submission to the card */ +void RADEONCPFlushIndirect(ScrnInfoPtr pScrn, int discard) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + drmBufPtr buffer = info->indirectBuffer; + int start = info->indirectStart; + drmRadeonIndirect indirect; + + if (!buffer) return; + if (start == buffer->used && !discard) return; + + if (RADEON_VERBOSE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Flushing buffer %d\n", + buffer->idx); + } + + indirect.idx = buffer->idx; + indirect.start = start; + indirect.end = buffer->used; + indirect.discard = discard; + + drmCommandWriteRead(info->drmFD, DRM_RADEON_INDIRECT, + &indirect, sizeof(drmRadeonIndirect)); + + if (discard) { + info->indirectBuffer = RADEONCPGetBuffer(pScrn); + info->indirectStart = 0; + } else { + /* Start on a double word boundary */ + info->indirectStart = buffer->used = (buffer->used + 7) & ~7; + if (RADEON_VERBOSE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, " Starting at %d\n", + info->indirectStart); + } + } +} + +/* Flush and release the indirect buffer */ +void RADEONCPReleaseIndirect(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + drmBufPtr buffer = info->indirectBuffer; + int start = info->indirectStart; + drmRadeonIndirect indirect; + + info->indirectBuffer = NULL; + info->indirectStart = 0; + + if (!buffer) return; + + if (RADEON_VERBOSE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Releasing buffer %d\n", + buffer->idx); + } + + indirect.idx = buffer->idx; + indirect.start = start; + indirect.end = buffer->used; + indirect.discard = 1; + + drmCommandWriteRead(info->drmFD, DRM_RADEON_INDIRECT, + &indirect, sizeof(drmRadeonIndirect)); +} +#endif + +/* Initialize XAA for supported acceleration and also initialize the + * graphics hardware for acceleration + */ +Bool RADEONAccelInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + XAAInfoRecPtr a; + + if (!(a = info->accel = XAACreateInfoRec())) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "XAACreateInfoRec Error\n"); + return FALSE; + } + +#ifdef XF86DRI + if (info->directRenderingEnabled) + RADEONAccelInitCP(pScreen, a); + else +#endif + RADEONAccelInitMMIO(pScreen, a); + + RADEONEngineInit(pScrn); + + if (!XAAInit(pScreen, a)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "XAAInit Error\n"); + return FALSE; + } + + return TRUE; +} diff --git a/src/radeon_accelfuncs.c b/src/radeon_accelfuncs.c new file mode 100644 index 0000000..0e30de6 --- /dev/null +++ b/src/radeon_accelfuncs.c @@ -0,0 +1,1351 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accelfuncs.c,v 1.7tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * Michel Dänzer <michel@daenzer.net> + * + * Credits: + * + * Thanks to Ani Joshi <ajoshi@shell.unixbox.com> for providing source + * code to his Radeon driver. Portions of this file are based on the + * initialization code for that driver. + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + * Notes on unimplemented XAA optimizations: + * + * SetClipping: This has been removed as XAA expects 16bit registers + * for full clipping. + * TwoPointLine: The Radeon supports this. Not Bresenham. + * DashedLine with non-power-of-two pattern length: Apparently, there is + * no way to set the length of the pattern -- it is always + * assumed to be 8 or 32 (or 1024?). + * ScreenToScreenColorExpandFill: See p. 4-17 of the Technical Reference + * Manual where it states that monochrome expansion of frame + * buffer data is not supported. + * CPUToScreenColorExpandFill, direct: The implementation here uses a hybrid + * direct/indirect method. If we had more data registers, + * then we could do better. If XAA supported a trigger write + * address, the code would be simpler. + * Color8x8PatternFill: Apparently, an 8x8 color brush cannot take an 8x8 + * pattern from frame buffer memory. + * ImageWrites: Same as CPUToScreenColorExpandFill + * + */ + +#if defined(ACCEL_MMIO) && defined(ACCEL_CP) +#error Cannot define both MMIO and CP acceleration! +#endif + +#if !defined(UNIXCPP) || defined(ANSICPP) +#define FUNC_NAME_CAT(prefix,suffix) prefix##suffix +#else +#define FUNC_NAME_CAT(prefix,suffix) prefix/**/suffix +#endif + +#ifdef ACCEL_MMIO +#define FUNC_NAME(prefix) FUNC_NAME_CAT(prefix,MMIO) +#else +#ifdef ACCEL_CP +#define FUNC_NAME(prefix) FUNC_NAME_CAT(prefix,CP) +#else +#error No accel type defined! +#endif +#endif + +/* MMIO: + * + * Wait for the graphics engine to be completely idle: the FIFO has + * drained, the Pixel Cache is flushed, and the engine is idle. This is + * a standard "sync" function that will make the hardware "quiescent". + * + * CP: + * + * Wait until the CP is completely idle: the FIFO has drained and the CP + * is idle. + */ +void +FUNC_NAME(RADEONWaitForIdle)(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i = 0; + +#ifdef ACCEL_CP + /* Make sure the CP is idle first */ + if (info->CPStarted) { + int ret; + FLUSH_RING(); + + for (;;) { + do { + ret = drmCommandNone(info->drmFD, DRM_RADEON_CP_IDLE); + if (ret && ret != -EBUSY) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "%s: CP idle %d\n", __FUNCTION__, ret); + } + } while ((ret == -EBUSY) && (i++ < RADEON_TIMEOUT)); + + if (ret == 0) return; + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Idle timed out, resetting engine...\n"); + RADEONEngineReset(pScrn); + RADEONEngineRestore(pScrn); + + /* Always restart the engine when doing CP 2D acceleration */ + RADEONCP_RESET(pScrn, info); + RADEONCP_START(pScrn, info); + } + } +#endif + + RADEONTRACE(("WaitForIdle (entering): %d entries, stat=0x%08x\n", + INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK, + INREG(RADEON_RBBM_STATUS))); + + /* Wait for the engine to go idle */ + RADEONWaitForFifoFunction(pScrn, 64); + + for (;;) { + for (i = 0; i < RADEON_TIMEOUT; i++) { + if (!(INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE)) { + RADEONEngineFlush(pScrn); + return; + } + } + RADEONTRACE(("Idle timed out: %d entries, stat=0x%08x\n", + INREG(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK, + INREG(RADEON_RBBM_STATUS))); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Idle timed out, resetting engine...\n"); + RADEONEngineReset(pScrn); + RADEONEngineRestore(pScrn); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONCP_RESET(pScrn, info); + RADEONCP_START(pScrn, info); + } +#endif + } +} + +/* This callback is required for multiheader cards using XAA */ +static void +FUNC_NAME(RADEONRestoreAccelState)(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + +#ifdef ACCEL_MMIO + + CARD32 pitch64; + + pitch64 = ((pScrn->displayWidth * (pScrn->bitsPerPixel / 8) + 0x3f)) >> 6; + + OUTREG(RADEON_DEFAULT_OFFSET, (((INREG(RADEON_DISPLAY_BASE_ADDR) + pScrn->fbOffset) >> 10) | + (pitch64 << 22))); + + /* FIXME: May need to restore other things, like BKGD_CLK FG_CLK... */ + + RADEONWaitForIdleMMIO(pScrn); + +#else /* ACCEL_CP */ + + RADEONWaitForFifo(pScrn, 1); + OUTREG(RADEON_DEFAULT_OFFSET, info->frontPitchOffset); + + RADEONWaitForIdleMMIO(pScrn); + +#if 0 + /* Not working yet */ + RADEONMMIO_TO_CP(pScrn, info); +#endif + + /* FIXME: May need to restore other things, like BKGD_CLK FG_CLK... */ +#endif +} + +/* Setup for XAA SolidFill */ +static void +FUNC_NAME(RADEONSetupForSolidFill)(ScrnInfoPtr pScrn, + int color, + int rop, + unsigned int planemask) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | RADEON_GMC_BRUSH_SOLID_COLOR + | RADEON_GMC_SRC_DATATYPE_COLOR + | RADEON_ROP[rop].pattern); + + BEGIN_ACCEL(4); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_BRUSH_FRGD_CLR, color); + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + OUT_ACCEL_REG(RADEON_DP_CNTL, (RADEON_DST_X_LEFT_TO_RIGHT + | RADEON_DST_Y_TOP_TO_BOTTOM)); + + FINISH_ACCEL(); +} + +/* Subsequent XAA SolidFillRect + * + * Tests: xtest CH06/fllrctngl, xterm + */ +static void +FUNC_NAME(RADEONSubsequentSolidFillRect)(ScrnInfoPtr pScrn, + int x, int y, + int w, int h) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + BEGIN_ACCEL(2); + + OUT_ACCEL_REG(RADEON_DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(RADEON_DST_WIDTH_HEIGHT, (w << 16) | h); + + FINISH_ACCEL(); +} + +/* Setup for XAA solid lines */ +static void +FUNC_NAME(RADEONSetupForSolidLine)(ScrnInfoPtr pScrn, + int color, + int rop, + unsigned int planemask) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | RADEON_GMC_BRUSH_SOLID_COLOR + | RADEON_GMC_SRC_DATATYPE_COLOR + | RADEON_ROP[rop].pattern); + + if (info->ChipFamily >= CHIP_FAMILY_RV200) { + BEGIN_ACCEL(1); + OUT_ACCEL_REG(RADEON_DST_LINE_PATCOUNT, + 0x55 << RADEON_BRES_CNTL_SHIFT); + } + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_BRUSH_FRGD_CLR, color); + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + + FINISH_ACCEL(); +} + +/* Subsequent XAA solid horizontal and vertical lines */ +static void +FUNC_NAME(RADEONSubsequentSolidHorVertLine)(ScrnInfoPtr pScrn, + int x, int y, + int len, + int dir) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int w = 1; + int h = 1; + ACCEL_PREAMBLE(); + + if (dir == DEGREES_0) w = len; + else h = len; + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_DP_CNTL, (RADEON_DST_X_LEFT_TO_RIGHT + | RADEON_DST_Y_TOP_TO_BOTTOM)); + OUT_ACCEL_REG(RADEON_DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(RADEON_DST_WIDTH_HEIGHT, (w << 16) | h); + + FINISH_ACCEL(); +} + +/* Subsequent XAA solid TwoPointLine line + * + * Tests: xtest CH06/drwln, ico, Mark Vojkovich's linetest program + * + * [See http://www.xfree86.org/devel/archives/devel/1999-Jun/0102.shtml for + * Mark Vojkovich's linetest program, posted 2Jun99 to devel@xfree86.org.] + */ +static void +FUNC_NAME(RADEONSubsequentSolidTwoPointLine)(ScrnInfoPtr pScrn, + int xa, int ya, + int xb, int yb, + int flags) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + /* TODO: Check bounds -- RADEON only has 14 bits */ + + if (!(flags & OMIT_LAST)) + FUNC_NAME(RADEONSubsequentSolidHorVertLine)(pScrn, + xb, yb, 1, + DEGREES_0); + + BEGIN_ACCEL(2); + + OUT_ACCEL_REG(RADEON_DST_LINE_START, (ya << 16) | xa); + OUT_ACCEL_REG(RADEON_DST_LINE_END, (yb << 16) | xb); + + FINISH_ACCEL(); +} + +/* Setup for XAA dashed lines + * + * Tests: xtest CH05/stdshs, XFree86/drwln + * + * NOTE: Since we can only accelerate lines with power-of-2 patterns of + * length <= 32 + */ +static void +FUNC_NAME(RADEONSetupForDashedLine)(ScrnInfoPtr pScrn, + int fg, + int bg, + int rop, + unsigned int planemask, + int length, + unsigned char *pattern) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 pat = *(CARD32 *)(pointer)pattern; + ACCEL_PREAMBLE(); + + /* Save for determining whether or not to draw last pixel */ + info->dashLen = length; + info->dashPattern = pat; + +#if X_BYTE_ORDER == X_BIG_ENDIAN +# define PAT_SHIFT(pat, shift) (pat >> shift) +#else +# define PAT_SHIFT(pat, shift) (pat << shift) +#endif + + switch (length) { + case 2: pat |= PAT_SHIFT(pat, 2); /* fall through */ + case 4: pat |= PAT_SHIFT(pat, 4); /* fall through */ + case 8: pat |= PAT_SHIFT(pat, 8); /* fall through */ + case 16: pat |= PAT_SHIFT(pat, 16); + } + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | (bg == -1 + ? RADEON_GMC_BRUSH_32x1_MONO_FG_LA + : RADEON_GMC_BRUSH_32x1_MONO_FG_BG) + | RADEON_ROP[rop].pattern + | RADEON_GMC_BYTE_LSB_TO_MSB); + info->dash_fg = fg; + info->dash_bg = bg; + + BEGIN_ACCEL((bg == -1) ? 4 : 5); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + OUT_ACCEL_REG(RADEON_DP_BRUSH_FRGD_CLR, fg); + if (bg != -1) + OUT_ACCEL_REG(RADEON_DP_BRUSH_BKGD_CLR, bg); + OUT_ACCEL_REG(RADEON_BRUSH_DATA0, pat); + + FINISH_ACCEL(); +} + +/* Helper function to draw last point for dashed lines */ +static void +FUNC_NAME(RADEONDashedLastPel)(ScrnInfoPtr pScrn, + int x, int y, + int fg) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 dp_gui_master_cntl = info->dp_gui_master_cntl_clip; + ACCEL_PREAMBLE(); + + dp_gui_master_cntl &= ~RADEON_GMC_BRUSH_DATATYPE_MASK; + dp_gui_master_cntl |= RADEON_GMC_BRUSH_SOLID_COLOR; + + dp_gui_master_cntl &= ~RADEON_GMC_SRC_DATATYPE_MASK; + dp_gui_master_cntl |= RADEON_GMC_SRC_DATATYPE_COLOR; + + BEGIN_ACCEL(7); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, dp_gui_master_cntl); + OUT_ACCEL_REG(RADEON_DP_BRUSH_FRGD_CLR, fg); + OUT_ACCEL_REG(RADEON_DP_CNTL, (RADEON_DST_X_LEFT_TO_RIGHT + | RADEON_DST_Y_TOP_TO_BOTTOM)); + OUT_ACCEL_REG(RADEON_DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(RADEON_DST_WIDTH_HEIGHT, (1 << 16) | 1); + + /* Restore old values */ + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_BRUSH_FRGD_CLR, info->dash_fg); + + FINISH_ACCEL(); +} + +/* Subsequent XAA dashed line */ +static void +FUNC_NAME(RADEONSubsequentDashedTwoPointLine)(ScrnInfoPtr pScrn, + int xa, int ya, + int xb, int yb, + int flags, + int phase) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + /* TODO: Check bounds -- RADEON only has 14 bits */ + + if (!(flags & OMIT_LAST)) { + int deltax = abs(xa - xb); + int deltay = abs(ya - yb); + int shift; + + if (deltax > deltay) shift = deltax; + else shift = deltay; + + shift += phase; + shift %= info->dashLen; + + if ((info->dashPattern >> shift) & 1) + FUNC_NAME(RADEONDashedLastPel)(pScrn, xb, yb, info->dash_fg); + else if (info->dash_bg != -1) + FUNC_NAME(RADEONDashedLastPel)(pScrn, xb, yb, info->dash_bg); + } + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_DST_LINE_START, (ya << 16) | xa); + OUT_ACCEL_REG(RADEON_DST_LINE_PATCOUNT, phase); + OUT_ACCEL_REG(RADEON_DST_LINE_END, (yb << 16) | xb); + + FINISH_ACCEL(); +} + +/* Set up for transparency + * + * Mmmm, Seems as though the transparency compare is opposite to r128. + * It should only draw when source != trans_color, this is the opposite + * of that. + */ +static void +FUNC_NAME(RADEONSetTransparency)(ScrnInfoPtr pScrn, + int trans_color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if ((trans_color != -1) || (info->XAAForceTransBlit == TRUE)) { + ACCEL_PREAMBLE(); + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_CLR_CMP_CLR_SRC, trans_color); + OUT_ACCEL_REG(RADEON_CLR_CMP_MASK, RADEON_CLR_CMP_MSK); + OUT_ACCEL_REG(RADEON_CLR_CMP_CNTL, (RADEON_SRC_CMP_EQ_COLOR + | RADEON_CLR_CMP_SRC_SOURCE)); + + FINISH_ACCEL(); + } +} + +/* Setup for XAA screen-to-screen copy + * + * Tests: xtest CH06/fllrctngl (also tests transparency) + */ +static void +FUNC_NAME(RADEONSetupForScreenToScreenCopy)(ScrnInfoPtr pScrn, + int xdir, int ydir, + int rop, + unsigned int planemask, + int trans_color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + info->xdir = xdir; + info->ydir = ydir; + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | RADEON_GMC_BRUSH_NONE + | RADEON_GMC_SRC_DATATYPE_COLOR + | RADEON_ROP[rop].rop + | RADEON_DP_SRC_SOURCE_MEMORY); + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + OUT_ACCEL_REG(RADEON_DP_CNTL, + ((xdir >= 0 ? RADEON_DST_X_LEFT_TO_RIGHT : 0) | + (ydir >= 0 ? RADEON_DST_Y_TOP_TO_BOTTOM : 0))); + + FINISH_ACCEL(); + + info->trans_color = trans_color; + FUNC_NAME(RADEONSetTransparency)(pScrn, trans_color); +} + +/* Subsequent XAA screen-to-screen copy */ +static void +FUNC_NAME(RADEONSubsequentScreenToScreenCopy)(ScrnInfoPtr pScrn, + int xa, int ya, + int xb, int yb, + int w, int h) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + if (info->xdir < 0) xa += w - 1, xb += w - 1; + if (info->ydir < 0) ya += h - 1, yb += h - 1; + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_SRC_Y_X, (ya << 16) | xa); + OUT_ACCEL_REG(RADEON_DST_Y_X, (yb << 16) | xb); + OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w); + + FINISH_ACCEL(); +} + +/* Setup for XAA mono 8x8 pattern color expansion. Patterns with + * transparency use `bg == -1'. This routine is only used if the XAA + * pixmap cache is turned on. + * + * Tests: xtest XFree86/fllrctngl (no other test will test this routine with + * both transparency and non-transparency) + */ +static void +FUNC_NAME(RADEONSetupForMono8x8PatternFill)(ScrnInfoPtr pScrn, + int patternx, + int patterny, + int fg, + int bg, + int rop, + unsigned int planemask) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); +#if X_BYTE_ORDER == X_BIG_ENDIAN + unsigned char pattern[8]; +#endif + ACCEL_PREAMBLE(); + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* Take care of endianness */ + pattern[0] = (patternx & 0x000000ff); + pattern[1] = (patternx & 0x0000ff00) >> 8; + pattern[2] = (patternx & 0x00ff0000) >> 16; + pattern[3] = (patternx & 0xff000000) >> 24; + pattern[4] = (patterny & 0x000000ff); + pattern[5] = (patterny & 0x0000ff00) >> 8; + pattern[6] = (patterny & 0x00ff0000) >> 16; + pattern[7] = (patterny & 0xff000000) >> 24; +#endif + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | (bg == -1 + ? RADEON_GMC_BRUSH_8X8_MONO_FG_LA + : RADEON_GMC_BRUSH_8X8_MONO_FG_BG) + | RADEON_ROP[rop].pattern +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + | RADEON_GMC_BYTE_MSB_TO_LSB +#endif + ); + + BEGIN_ACCEL((bg == -1) ? 5 : 6); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + OUT_ACCEL_REG(RADEON_DP_BRUSH_FRGD_CLR, fg); + if (bg != -1) + OUT_ACCEL_REG(RADEON_DP_BRUSH_BKGD_CLR, bg); +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + OUT_ACCEL_REG(RADEON_BRUSH_DATA0, patternx); + OUT_ACCEL_REG(RADEON_BRUSH_DATA1, patterny); +#else + OUT_ACCEL_REG(RADEON_BRUSH_DATA0, *(CARD32 *)(pointer)&pattern[0]); + OUT_ACCEL_REG(RADEON_BRUSH_DATA1, *(CARD32 *)(pointer)&pattern[4]); +#endif + + FINISH_ACCEL(); +} + +/* Subsequent XAA 8x8 pattern color expansion. Because they are used in + * the setup function, `patternx' and `patterny' are not used here. + */ +static void +FUNC_NAME(RADEONSubsequentMono8x8PatternFillRect)(ScrnInfoPtr pScrn, + int patternx, + int patterny, + int x, int y, + int w, int h) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_BRUSH_Y_X, (patterny << 8) | patternx); + OUT_ACCEL_REG(RADEON_DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w); + + FINISH_ACCEL(); +} + +#if 0 +/* Setup for XAA color 8x8 pattern fill + * + * Tests: xtest XFree86/fllrctngl (with Mono8x8PatternFill off) + */ +static void +FUNC_NAME(RADEONSetupForColor8x8PatternFill)(ScrnInfoPtr pScrn, + int patx, int paty, + int rop, + unsigned int planemask, + int trans_color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | RADEON_GMC_BRUSH_8x8_COLOR + | RADEON_GMC_SRC_DATATYPE_COLOR + | RADEON_ROP[rop].pattern + | RADEON_DP_SRC_SOURCE_MEMORY); + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + OUT_ACCEL_REG(RADEON_SRC_Y_X, (paty << 16) | patx); + + FINISH_ACCEL(); + + info->trans_color = trans_color; + FUNC_NAME(RADEONSetTransparency)(pScrn, trans_color); +} + +/* Subsequent XAA 8x8 pattern color expansion */ +static void +FUNC_NAME(RADEONSubsequentColor8x8PatternFillRect)(ScrnInfoPtr pScrn, + int patx, int paty, + int x, int y, + int w, int h) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_BRUSH_Y_X, (paty << 16) | patx); + OUT_ACCEL_REG(RADEON_DST_Y_X, (y << 16) | x); + OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w); + + FINISH_ACCEL(); +} +#endif + +#ifdef ACCEL_CP +#define CP_BUFSIZE (info->indirectBuffer->total/4-9) + +/* Helper function to write out a HOSTDATA_BLT packet into the indirect + * buffer and set the XAA scratch buffer address appropriately. + */ +static void +RADEONCPScanlinePacket(ScrnInfoPtr pScrn, int bufno) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int chunk_words = info->scanline_hpass * info->scanline_words; + ACCEL_PREAMBLE(); + + if (RADEON_VERBOSE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "CPScanline Packet h=%d hpass=%d chunkwords=%d\n", + info->scanline_h, info->scanline_hpass, chunk_words); + } + BEGIN_RING(chunk_words+9); + + OUT_RING(CP_PACKET3(RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT,chunk_words+9-2)); + OUT_RING(info->dp_gui_master_cntl_clip); + OUT_RING((info->scanline_y << 16) | + (info->scanline_x1clip & 0xffff)); + OUT_RING(((info->scanline_y+info->scanline_hpass) << 16) | + (info->scanline_x2clip & 0xffff)); + OUT_RING(info->scanline_fg); + OUT_RING(info->scanline_bg); + OUT_RING((info->scanline_y << 16) | + (info->scanline_x & 0xffff)); + OUT_RING((info->scanline_hpass << 16) | + (info->scanline_w & 0xffff)); + OUT_RING(chunk_words); + + info->scratch_buffer[bufno] = (unsigned char *)&__head[__count]; + __count += chunk_words; + + /* The ring can only be advanced after the __head and __count have + been adjusted above */ + FINISH_ACCEL(); + + info->scanline_y += info->scanline_hpass; + info->scanline_h -= info->scanline_hpass; +} +#endif + +/* Setup for XAA indirect CPU-to-screen color expansion (indirect). + * Because of how the scratch buffer is initialized, this is really a + * mainstore-to-screen color expansion. Transparency is supported when + * `bg == -1'. + */ +static void +FUNC_NAME(RADEONSetupForScanlineCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, + int fg, + int bg, + int rop, + unsigned int + planemask) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | RADEON_GMC_DST_CLIPPING + | RADEON_GMC_BRUSH_NONE + | (bg == -1 + ? RADEON_GMC_SRC_DATATYPE_MONO_FG_LA + : RADEON_GMC_SRC_DATATYPE_MONO_FG_BG) + | RADEON_ROP[rop].rop +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + | RADEON_GMC_BYTE_LSB_TO_MSB +#else + | RADEON_GMC_BYTE_MSB_TO_LSB +#endif + | RADEON_DP_SRC_SOURCE_HOST_DATA); + +#ifdef ACCEL_MMIO + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + BEGIN_ACCEL(4); +#else + BEGIN_ACCEL(5); + + OUT_ACCEL_REG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_NONE); +#endif + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + OUT_ACCEL_REG(RADEON_DP_SRC_FRGD_CLR, fg); + OUT_ACCEL_REG(RADEON_DP_SRC_BKGD_CLR, bg); + +#else /* ACCEL_CP */ + + info->scanline_fg = fg; + info->scanline_bg = bg; + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + BEGIN_ACCEL(1); +#else + BEGIN_ACCEL(2); + + OUT_ACCEL_REG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_32BIT); +#endif + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + +#endif + + FINISH_ACCEL(); +} + +/* Subsequent XAA indirect CPU-to-screen color expansion. This is only + * called once for each rectangle. + */ +static void +FUNC_NAME(RADEONSubsequentScanlineCPUToScreenColorExpandFill)(ScrnInfoPtr + pScrn, + int x, int y, + int w, int h, + int skipleft) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); +#ifdef ACCEL_MMIO + ACCEL_PREAMBLE(); + + info->scanline_h = h; + info->scanline_words = (w + 31) >> 5; + +#ifdef __alpha__ + /* Always use indirect for Alpha */ + if (0) +#else + if ((info->scanline_words * h) <= 9) +#endif + { + /* Turn on direct for less than 9 dword colour expansion */ + info->scratch_buffer[0] = + (unsigned char *)(ADDRREG(RADEON_HOST_DATA_LAST) + - (info->scanline_words - 1)); + info->scanline_direct = 1; + } else { + /* Use indirect for anything else */ + info->scratch_buffer[0] = info->scratch_save; + info->scanline_direct = 0; + } + + BEGIN_ACCEL(4 + (info->scanline_direct ? + (info->scanline_words * h) : 0)); + + OUT_ACCEL_REG(RADEON_SC_TOP_LEFT, (y << 16) | ((x+skipleft) + & 0xffff)); + OUT_ACCEL_REG(RADEON_SC_BOTTOM_RIGHT, ((y+h) << 16) | ((x+w) & 0xffff)); + OUT_ACCEL_REG(RADEON_DST_Y_X, (y << 16) | (x & 0xffff)); + /* Have to pad the width here and use clipping engine */ + OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | ((w + 31) & ~31)); + + FINISH_ACCEL(); + +#else /* ACCEL_CP */ + + info->scanline_x = x; + info->scanline_y = y; + /* Have to pad the width here and use clipping engine */ + info->scanline_w = (w + 31) & ~31; + info->scanline_h = h; + + info->scanline_x1clip = x + skipleft; + info->scanline_x2clip = x + w; + + info->scanline_words = info->scanline_w / 32; + info->scanline_hpass = min(h,(CP_BUFSIZE/info->scanline_words)); + + RADEONCPScanlinePacket(pScrn, 0); + +#endif +} + +/* Subsequent XAA indirect CPU-to-screen color expansion and indirect + * image write. This is called once for each scanline. + */ +static void +FUNC_NAME(RADEONSubsequentScanline)(ScrnInfoPtr pScrn, + int bufno) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); +#ifdef ACCEL_MMIO + CARD32 *p = (pointer)info->scratch_buffer[bufno]; + int i; + int left = info->scanline_words; + volatile CARD32 *d; + ACCEL_PREAMBLE(); + + if (info->scanline_direct) return; + + --info->scanline_h; + + while (left) { + write_mem_barrier(); + if (left <= 8) { + /* Last scanline - finish write to DATA_LAST */ + if (info->scanline_h == 0) { + BEGIN_ACCEL(left); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(RADEON_HOST_DATA_LAST) - (left - 1); left; --left) + *d++ = *p++; + return; + } else { + BEGIN_ACCEL(left); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(RADEON_HOST_DATA7) - (left - 1); left; --left) + *d++ = *p++; + } + } else { + BEGIN_ACCEL(8); + /* Unrolling doesn't improve performance */ + for (d = ADDRREG(RADEON_HOST_DATA0), i = 0; i < 8; i++) + *d++ = *p++; + left -= 8; + } + } + + FINISH_ACCEL(); + +#else /* ACCEL_CP */ + + if (--info->scanline_hpass) { + info->scratch_buffer[bufno] += 4 * info->scanline_words; + } else if (info->scanline_h) { + info->scanline_hpass = + min(info->scanline_h,(CP_BUFSIZE/info->scanline_words)); + RADEONCPScanlinePacket(pScrn, bufno); + } + +#endif +} + +/* Setup for XAA indirect image write */ +static void +FUNC_NAME(RADEONSetupForScanlineImageWrite)(ScrnInfoPtr pScrn, + int rop, + unsigned int planemask, + int trans_color, + int bpp, + int depth) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + info->scanline_bpp = bpp; + + /* Save for later clipping */ + info->dp_gui_master_cntl_clip = (info->dp_gui_master_cntl + | RADEON_GMC_DST_CLIPPING + | RADEON_GMC_BRUSH_NONE + | RADEON_GMC_SRC_DATATYPE_COLOR + | RADEON_ROP[rop].rop + | RADEON_GMC_BYTE_MSB_TO_LSB + | RADEON_DP_SRC_SOURCE_HOST_DATA); + +#ifdef ACCEL_MMIO + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + BEGIN_ACCEL(2); +#else + BEGIN_ACCEL(3); + + if (bpp == 16) + OUT_ACCEL_REG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_16BIT); + else if (bpp == 32) + OUT_ACCEL_REG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_32BIT); + else + OUT_ACCEL_REG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_NONE); +#endif + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + +#else /* ACCEL_CP */ + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + BEGIN_ACCEL(1); +#else + BEGIN_ACCEL(2); + + if (bpp == 16) + OUT_ACCEL_REG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_HDW); + else + OUT_ACCEL_REG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_NONE); +#endif +#endif + OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask); + + FINISH_ACCEL(); + + info->trans_color = trans_color; + FUNC_NAME(RADEONSetTransparency)(pScrn, trans_color); +} + +/* Subsequent XAA indirect image write. This is only called once for + * each rectangle. + */ +static void +FUNC_NAME(RADEONSubsequentScanlineImageWriteRect)(ScrnInfoPtr pScrn, + int x, int y, + int w, int h, + int skipleft) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + +#ifdef ACCEL_MMIO + + int shift = 0; /* 32bpp */ + ACCEL_PREAMBLE(); + + if (pScrn->bitsPerPixel == 8) shift = 3; + else if (pScrn->bitsPerPixel == 16) shift = 1; + + info->scanline_h = h; + info->scanline_words = (w * info->scanline_bpp + 31) >> 5; + +#ifdef __alpha__ + /* Always use indirect for Alpha */ + if (0) +#else + if ((info->scanline_words * h) <= 9) +#endif + { + /* Turn on direct for less than 9 dword colour expansion */ + info->scratch_buffer[0] + = (unsigned char *)(ADDRREG(RADEON_HOST_DATA_LAST) + - (info->scanline_words - 1)); + info->scanline_direct = 1; + } else { + /* Use indirect for anything else */ + info->scratch_buffer[0] = info->scratch_save; + info->scanline_direct = 0; + } + + BEGIN_ACCEL(4 + (info->scanline_direct ? + (info->scanline_words * h) : 0)); + + OUT_ACCEL_REG(RADEON_SC_TOP_LEFT, (y << 16) | ((x+skipleft) + & 0xffff)); + OUT_ACCEL_REG(RADEON_SC_BOTTOM_RIGHT, ((y+h) << 16) | ((x+w) & 0xffff)); + OUT_ACCEL_REG(RADEON_DST_Y_X, (y << 16) | (x & 0xffff)); + /* Have to pad the width here and use clipping engine */ + OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | ((w + shift) & + ~shift)); + + FINISH_ACCEL(); + +#else /* ACCEL_CP */ + + int pad = 0; /* 32bpp */ + + if (pScrn->bitsPerPixel == 8) pad = 3; + else if (pScrn->bitsPerPixel == 16) pad = 1; + + info->scanline_x = x; + info->scanline_y = y; + /* Have to pad the width here and use clipping engine */ + info->scanline_w = (w + pad) & ~pad; + info->scanline_h = h; + + info->scanline_x1clip = x + skipleft; + info->scanline_x2clip = x + w; + + info->scanline_words = (w * info->scanline_bpp + 31) / 32; + info->scanline_hpass = min(h,(CP_BUFSIZE/info->scanline_words)); + + RADEONCPScanlinePacket(pScrn, 0); + +#endif +} + +/* Set up the clipping rectangle */ +static void +FUNC_NAME(RADEONSetClippingRectangle)(ScrnInfoPtr pScrn, + int xa, int ya, + int xb, int yb) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long tmp1 = 0; + unsigned long tmp2 = 0; + ACCEL_PREAMBLE(); + + if (xa < 0) { + tmp1 = (-xa) & 0x3fff; + tmp1 |= RADEON_SC_SIGN_MASK_LO; + } else { + tmp1 = xa; + } + + if (ya < 0) { + tmp1 |= (((-ya) & 0x3fff) << 16); + tmp1 |= RADEON_SC_SIGN_MASK_HI; + } else { + tmp1 |= (ya << 16); + } + + xb++; yb++; + + if (xb < 0) { + tmp2 = (-xb) & 0x3fff; + tmp2 |= RADEON_SC_SIGN_MASK_LO; + } else { + tmp2 = xb; + } + + if (yb < 0) { + tmp2 |= (((-yb) & 0x3fff) << 16); + tmp2 |= RADEON_SC_SIGN_MASK_HI; + } else { + tmp2 |= (yb << 16); + } + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl_clip + | RADEON_GMC_DST_CLIPPING)); + OUT_ACCEL_REG(RADEON_SC_TOP_LEFT, tmp1); + OUT_ACCEL_REG(RADEON_SC_BOTTOM_RIGHT, tmp2); + + FINISH_ACCEL(); + + FUNC_NAME(RADEONSetTransparency)(pScrn, info->trans_color); +} + +/* Disable the clipping rectangle */ +static void +FUNC_NAME(RADEONDisableClipping)(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + BEGIN_ACCEL(3); + + OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL, info->dp_gui_master_cntl_clip); + OUT_ACCEL_REG(RADEON_SC_TOP_LEFT, 0); + OUT_ACCEL_REG(RADEON_SC_BOTTOM_RIGHT, (RADEON_DEFAULT_SC_RIGHT_MAX | + RADEON_DEFAULT_SC_BOTTOM_MAX)); + + FINISH_ACCEL(); + + FUNC_NAME(RADEONSetTransparency)(pScrn, info->trans_color); +} + +#ifdef ACCEL_CP +/* Point the DST_PITCH_OFFSET register at the current buffer. This + * allows us to interact with the back and depth buffers. All CP 2D + * acceleration commands use the DST_PITCH_OFFSET register. + */ +void +RADEONSelectBuffer(ScrnInfoPtr pScrn, int buffer) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + switch (buffer) { + case RADEON_BACK: + info->dst_pitch_offset = info->backPitchOffset; + break; + case RADEON_DEPTH: + info->dst_pitch_offset = info->depthPitchOffset; + break; + default: + case RADEON_FRONT: + info->dst_pitch_offset = info->frontPitchOffset; + break; + } + + BEGIN_ACCEL(1); + + OUT_ACCEL_REG(RADEON_DEFAULT_OFFSET, info->dst_pitch_offset); + + FINISH_ACCEL(); +} +#endif + +static void +FUNC_NAME(RADEONAccelInit)(ScreenPtr pScreen, XAAInfoRecPtr a) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + a->Flags = (PIXMAP_CACHE + | OFFSCREEN_PIXMAPS + | LINEAR_FRAMEBUFFER); + + /* Sync */ + a->Sync = FUNC_NAME(RADEONWaitForIdle); + + /* Solid Filled Rectangle */ + a->PolyFillRectSolidFlags = 0; + a->SetupForSolidFill + = FUNC_NAME(RADEONSetupForSolidFill); + a->SubsequentSolidFillRect + = FUNC_NAME(RADEONSubsequentSolidFillRect); + + /* Screen-to-screen Copy */ + a->ScreenToScreenCopyFlags = 0; + a->SetupForScreenToScreenCopy + = FUNC_NAME(RADEONSetupForScreenToScreenCopy); + a->SubsequentScreenToScreenCopy + = FUNC_NAME(RADEONSubsequentScreenToScreenCopy); + + /* Mono 8x8 Pattern Fill (Color Expand) */ + a->SetupForMono8x8PatternFill + = FUNC_NAME(RADEONSetupForMono8x8PatternFill); + a->SubsequentMono8x8PatternFillRect + = FUNC_NAME(RADEONSubsequentMono8x8PatternFillRect); + a->Mono8x8PatternFillFlags = (HARDWARE_PATTERN_PROGRAMMED_BITS + | HARDWARE_PATTERN_PROGRAMMED_ORIGIN + | HARDWARE_PATTERN_SCREEN_ORIGIN); + +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + if (info->ChipFamily >= CHIP_FAMILY_RV200) + a->Mono8x8PatternFillFlags |= BIT_ORDER_IN_BYTE_MSBFIRST; + else + a->Mono8x8PatternFillFlags |= BIT_ORDER_IN_BYTE_LSBFIRST; +#else + a->Mono8x8PatternFillFlags |= BIT_ORDER_IN_BYTE_LSBFIRST; +#endif + + /* Indirect CPU-To-Screen Color Expand */ + + /* RADEON gets upset, when using HOST provided data without a source + rop. To show run 'xtest's drwarc. */ + a->ScanlineCPUToScreenColorExpandFillFlags + = (LEFT_EDGE_CLIPPING + | ROP_NEEDS_SOURCE + | LEFT_EDGE_CLIPPING_NEGATIVE_X); + a->NumScanlineColorExpandBuffers = 1; + a->ScanlineColorExpandBuffers = info->scratch_buffer; + info->scratch_save + = xalloc(((pScrn->virtualX+31)/32*4) + + (pScrn->virtualX * info->CurrentLayout.pixel_bytes)); + info->scratch_buffer[0] = info->scratch_save; + a->SetupForScanlineCPUToScreenColorExpandFill + = FUNC_NAME(RADEONSetupForScanlineCPUToScreenColorExpandFill); + a->SubsequentScanlineCPUToScreenColorExpandFill + = FUNC_NAME(RADEONSubsequentScanlineCPUToScreenColorExpandFill); + a->SubsequentColorExpandScanline = FUNC_NAME(RADEONSubsequentScanline); + + /* Solid Lines */ + a->SetupForSolidLine + = FUNC_NAME(RADEONSetupForSolidLine); + a->SubsequentSolidHorVertLine + = FUNC_NAME(RADEONSubsequentSolidHorVertLine); + +#ifdef XFree86LOADER + if (info->xaaReq.minorversion >= 1) { +#endif + + /* RADEON only supports 14 bits for lines and clipping and only + * draws lines that are completely on-screen correctly. This will + * cause display corruption problem in the cases when out-of-range + * commands are issued, like when dimming screen during GNOME logout + * in dual-head setup. Solid and dashed lines are therefore limited + * to the virtual screen. + */ + + a->SolidLineFlags = LINE_LIMIT_COORDS; + a->SolidLineLimits.x1 = 0; + a->SolidLineLimits.y1 = 0; + a->SolidLineLimits.x2 = pScrn->virtualX-1; + a->SolidLineLimits.y2 = pScrn->virtualY-1; + + /* Call miSetZeroLineBias() to have mi/mfb/cfb/fb routines match + hardware accel two point lines */ + miSetZeroLineBias(pScreen, (OCTANT5 | OCTANT6 | OCTANT7 | OCTANT8)); + + a->SubsequentSolidTwoPointLine + = FUNC_NAME(RADEONSubsequentSolidTwoPointLine); + + /* Disabled on RV200 and newer because it does not pass XTest */ + if (info->ChipFamily < CHIP_FAMILY_RV200) { + a->SetupForDashedLine + = FUNC_NAME(RADEONSetupForDashedLine); + a->SubsequentDashedTwoPointLine + = FUNC_NAME(RADEONSubsequentDashedTwoPointLine); + a->DashPatternMaxLength = 32; + /* ROP3 doesn't seem to work properly for dashedline with GXinvert */ + a->DashedLineFlags = (LINE_PATTERN_LSBFIRST_LSBJUSTIFIED + | LINE_PATTERN_POWER_OF_2_ONLY + | LINE_LIMIT_COORDS + | ROP_NEEDS_SOURCE); + a->DashedLineLimits.x1 = 0; + a->DashedLineLimits.y1 = 0; + a->DashedLineLimits.x2 = pScrn->virtualX-1; + a->DashedLineLimits.y2 = pScrn->virtualY-1; + } + +#ifdef XFree86LOADER + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "libxaa too old, can't accelerate TwoPoint lines\n"); + } +#endif + + /* Clipping, note that without this, all line accelerations will + * not be called + */ + a->SetClippingRectangle + = FUNC_NAME(RADEONSetClippingRectangle); + a->DisableClipping + = FUNC_NAME(RADEONDisableClipping); + a->ClippingFlags + = (HARDWARE_CLIP_SOLID_LINE + | HARDWARE_CLIP_DASHED_LINE + /* | HARDWARE_CLIP_SOLID_FILL -- seems very slow with this on */ + | HARDWARE_CLIP_MONO_8x8_FILL + | HARDWARE_CLIP_SCREEN_TO_SCREEN_COPY); + + if (xf86IsEntityShared(info->pEnt->index)) { + /* If there are more than one devices sharing this entity, we + * have to assign this call back, otherwise the XAA will be + * disabled + */ + if (xf86GetNumEntityInstances(info->pEnt->index) > 1) + a->RestoreAccelState = FUNC_NAME(RADEONRestoreAccelState); + } + + /* ImageWrite */ + a->NumScanlineImageWriteBuffers = 1; + a->ScanlineImageWriteBuffers = info->scratch_buffer; + a->SetupForScanlineImageWrite + = FUNC_NAME(RADEONSetupForScanlineImageWrite); + a->SubsequentScanlineImageWriteRect + = FUNC_NAME(RADEONSubsequentScanlineImageWriteRect); + a->SubsequentImageWriteScanline = FUNC_NAME(RADEONSubsequentScanline); + a->ScanlineImageWriteFlags = (CPU_TRANSFER_PAD_DWORD +#ifdef ACCEL_MMIO + /* Performance tests show that we shouldn't use GXcopy + * for uploads as a memcpy is faster + */ + | NO_GXCOPY +#endif + /* RADEON gets upset, when using HOST provided data + * without a source rop. To show run 'xtest's ptimg + */ + | ROP_NEEDS_SOURCE + | SCANLINE_PAD_DWORD + | LEFT_EDGE_CLIPPING + | LEFT_EDGE_CLIPPING_NEGATIVE_X); + +#if 0 + /* Color 8x8 Pattern Fill */ + a->SetupForColor8x8PatternFill + = FUNC_NAME(RADEONSetupForColor8x8PatternFill); + a->SubsequentColor8x8PatternFillRect + = FUNC_NAME(RADEONSubsequentColor8x8PatternFillRect); + a->Color8x8PatternFillFlags = (HARDWARE_PATTERN_PROGRAMMED_ORIGIN + | HARDWARE_PATTERN_SCREEN_ORIGIN + | BIT_ORDER_IN_BYTE_LSBFIRST); +#endif +} + +#undef FUNC_NAME diff --git a/src/radeon_bios.c b/src/radeon_bios.c new file mode 100644 index 0000000..37a3e26 --- /dev/null +++ b/src/radeon_bios.c @@ -0,0 +1,567 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_bios.c,v 1.0 Exp $ */ +/* + * Copyright 2004 ATI Technologies Inc., Markham, Ontario + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_reg.h" +#include "vbe.h" + +/* Read the Video BIOS block and the FP registers (if applicable). */ +Bool RADEONGetBIOSInfo(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int tmp; + + if (!(info->VBIOS = xalloc(RADEON_VBIOS_SIZE))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Cannot allocate space for hold Video BIOS!\n"); + return FALSE; + } else { + if (pInt10) { + info->BIOSAddr = pInt10->BIOSseg << 4; + (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr), + RADEON_VBIOS_SIZE); + } else { + xf86ReadPciBIOS(0, info->PciTag, 0, info->VBIOS, RADEON_VBIOS_SIZE); + if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Video BIOS not detected in PCI space!\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Attempting to read Video BIOS from " + "legacy ISA space!\n"); + info->BIOSAddr = 0x000c0000; + xf86ReadDomainMemory(info->PciTag, info->BIOSAddr, + RADEON_VBIOS_SIZE, info->VBIOS); + } + } + } + + if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unrecognized BIOS signature, BIOS data will not be used\n"); + xfree (info->VBIOS); + info->VBIOS = NULL; + return FALSE; + } + + if (info->VBIOS) info->ROMHeaderStart = RADEON_BIOS16(0x48); + + if(!info->ROMHeaderStart) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Invalid ROM pointer, BIOS data will not be used\n"); + xfree (info->VBIOS); + info->VBIOS = NULL; + return FALSE; + } + + tmp = info->ROMHeaderStart + 4; + if ((RADEON_BIOS8(tmp) == 'A' && + RADEON_BIOS8(tmp+1) == 'T' && + RADEON_BIOS8(tmp+2) == 'O' && + RADEON_BIOS8(tmp+3) == 'M') || + (RADEON_BIOS8(tmp) == 'M' && + RADEON_BIOS8(tmp+1) == 'O' && + RADEON_BIOS8(tmp+2) == 'T' && + RADEON_BIOS8(tmp+3) == 'A')) + info->IsAtomBios = TRUE; + else + info->IsAtomBios = FALSE; + + if (info->IsAtomBios) + info->MasterDataStart = RADEON_BIOS16 (info->ROMHeaderStart + 32); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s BIOS detected\n", + info->IsAtomBios ? "ATOM":"Legacy"); + + return TRUE; +} + +Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + int i = 0, j, tmp, tmp0=0, tmp1=0; + + if(!info->VBIOS) return FALSE; + + if (info->IsAtomBios) { + if((tmp = RADEON_BIOS16 (info->MasterDataStart + 22))) { + int crtc = 0, id[2]; + tmp1 = RADEON_BIOS16 (tmp + 4); + for (i=0; i<8; i++) { + if(tmp1 & (1<<i)) { + CARD16 portinfo = RADEON_BIOS16(tmp+6+i*2); + if (crtc < 2) { + if ((i==2) || (i==6)) continue; /* ignore TV here */ + + if (crtc == 1) { + /* sharing same port with id[0] */ + if (((portinfo>>8) & 0xf) == id[0]) { + if (i == 3) + pRADEONEnt->PortInfo[0].TMDSType = TMDS_INT; + else if (i == 7) + pRADEONEnt->PortInfo[0].TMDSType = TMDS_EXT; + + if (pRADEONEnt->PortInfo[0].DACType == DAC_UNKNOWN) + pRADEONEnt->PortInfo[0].DACType = (portinfo & 0xf) - 1; + continue; + } + } + + id[crtc] = (portinfo>>8) & 0xf; + pRADEONEnt->PortInfo[crtc].DACType = (portinfo & 0xf) - 1; + pRADEONEnt->PortInfo[crtc].ConnectorType = (portinfo>>4) & 0xf; + if (i == 3) + pRADEONEnt->PortInfo[crtc].TMDSType = TMDS_INT; + else if (i == 7) + pRADEONEnt->PortInfo[crtc].TMDSType = TMDS_EXT; + + if((tmp0 = RADEON_BIOS16 (info->MasterDataStart + 24)) && id[crtc]) { + switch (RADEON_BIOS16 (tmp0 + 4 + 27 * id[crtc]) * 4) + { + case RADEON_GPIO_MONID: + pRADEONEnt->PortInfo[crtc].DDCType = DDC_MONID; + break; + case RADEON_GPIO_DVI_DDC: + pRADEONEnt->PortInfo[crtc].DDCType = DDC_DVI; + break; + case RADEON_GPIO_VGA_DDC: + pRADEONEnt->PortInfo[crtc].DDCType = DDC_VGA; + break; + case RADEON_GPIO_CRT2_DDC: + pRADEONEnt->PortInfo[crtc].DDCType = DDC_CRT2; + break; + default: + pRADEONEnt->PortInfo[crtc].DDCType = DDC_NONE; + break; + } + + } else { + pRADEONEnt->PortInfo[crtc].DDCType = DDC_NONE; + } + crtc++; + } else { + /* we have already had two CRTCs assigned. the rest may share the same + * port with the existing connector, fill in them accordingly. + */ + for (j=0; j<2; j++) { + if (((portinfo>>8) & 0xf) == id[j]) { + if (i == 3) + pRADEONEnt->PortInfo[j].TMDSType = TMDS_INT; + else if (i == 7) + pRADEONEnt->PortInfo[j].TMDSType = TMDS_EXT; + + if (pRADEONEnt->PortInfo[j].DACType == DAC_UNKNOWN) + pRADEONEnt->PortInfo[j].DACType = (portinfo & 0xf) - 1; + } + } + } + } + } + + for (i=0; i<2; i++) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", + i, pRADEONEnt->PortInfo[i].DDCType, pRADEONEnt->PortInfo[i].DACType, + pRADEONEnt->PortInfo[i].TMDSType, pRADEONEnt->PortInfo[i].ConnectorType); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n"); + return FALSE; + } + } else { + /* Some laptops only have one connector (VGA) listed in the connector table, + * we need to add LVDS in as a non-DDC display. + * Note, we can't assume the listed VGA will be filled in PortInfo[0], + * when walking through connector table. connector_found has following meaning: + * 0 -- nothing found, + * 1 -- only PortInfo[0] filled, + * 2 -- only PortInfo[1] filled, + * 3 -- both are filled. + */ + int connector_found = 0; + + if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x50))) { + for (i = 1; i < 4; i++) { + + if (!RADEON_BIOS8(tmp + i*2) && i > 1) break; /* end of table */ + + tmp0 = RADEON_BIOS16(tmp + i*2); + if (((tmp0 >> 12) & 0x0f) == 0) continue; /* no connector */ + if (connector_found > 0) { + if (pRADEONEnt->PortInfo[tmp1].DDCType == ((tmp0 >> 8) & 0x0f)) + continue; /* same connector */ + } + + /* internal DDC_DVI port will get assigned to PortInfo[0], or if there is no DDC_DVI (like in some IGPs). */ + tmp1 = ((((tmp0 >> 8) & 0xf) == DDC_DVI) || (tmp1 == 1)) ? 0 : 1; /* determine port info index */ + + pRADEONEnt->PortInfo[tmp1].DDCType = (tmp0 >> 8) & 0x0f; + if (pRADEONEnt->PortInfo[tmp1].DDCType > DDC_CRT2) pRADEONEnt->PortInfo[tmp1].DDCType = DDC_NONE_DETECTED; + pRADEONEnt->PortInfo[tmp1].DACType = (tmp0 & 0x01) ? DAC_TVDAC : DAC_PRIMARY; + pRADEONEnt->PortInfo[tmp1].ConnectorType = (tmp0 >> 12) & 0x0f; + if (pRADEONEnt->PortInfo[tmp1].ConnectorType > CONNECTOR_UNSUPPORTED) pRADEONEnt->PortInfo[tmp1].ConnectorType = CONNECTOR_UNSUPPORTED; + pRADEONEnt->PortInfo[tmp1].TMDSType = ((tmp0 >> 4) & 0x01) ? TMDS_EXT : TMDS_INT; + + /* some sanity checks */ + if (((pRADEONEnt->PortInfo[tmp1].ConnectorType != CONNECTOR_DVI_D) && + (pRADEONEnt->PortInfo[tmp1].ConnectorType != CONNECTOR_DVI_I)) && + pRADEONEnt->PortInfo[tmp1].TMDSType == TMDS_INT) + pRADEONEnt->PortInfo[tmp1].TMDSType = TMDS_UNKNOWN; + + connector_found += (tmp1 + 1); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n"); + return FALSE; + } + + if (info->IsMobility) { + /* For the cases where only one VGA connector is found, + we assume LVDS is not listed in the connector table, + add it in here as the first port. + */ + if ((connector_found < 3) && (pRADEONEnt->PortInfo[tmp1].ConnectorType == CONNECTOR_CRT)) { + if (connector_found == 1) { + memcpy (&pRADEONEnt->PortInfo[1], &pRADEONEnt->PortInfo[0], + sizeof (pRADEONEnt->PortInfo[0])); + } + pRADEONEnt->PortInfo[0].DACType = DAC_TVDAC; + pRADEONEnt->PortInfo[0].TMDSType = TMDS_UNKNOWN; + pRADEONEnt->PortInfo[0].DDCType = DDC_NONE_DETECTED; + pRADEONEnt->PortInfo[0].ConnectorType = CONNECTOR_PROPRIETARY; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS port is not in connector table, added in.\n"); + if (connector_found == 0) connector_found = 1; + else connector_found = 3; + } + + if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42))) { + if ((tmp0 = RADEON_BIOS16(tmp + 0x15))) { + if ((tmp1 = RADEON_BIOS8(tmp0+2) & 0x07)) { + pRADEONEnt->PortInfo[0].DDCType = tmp1; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n"); + } + } + } + } else if (connector_found == 2) { + memcpy (&pRADEONEnt->PortInfo[0], &pRADEONEnt->PortInfo[1], + sizeof (pRADEONEnt->PortInfo[0])); + pRADEONEnt->PortInfo[1].DACType = DAC_UNKNOWN; + pRADEONEnt->PortInfo[1].TMDSType = TMDS_UNKNOWN; + pRADEONEnt->PortInfo[1].DDCType = DDC_NONE_DETECTED; + pRADEONEnt->PortInfo[1].ConnectorType = CONNECTOR_NONE; + connector_found = 1; + } + + if (connector_found == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No connector found in Connector Info Table.\n"); + } else { + xf86DrvMsg(0, X_INFO, "Connector0: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", + pRADEONEnt->PortInfo[0].DDCType, pRADEONEnt->PortInfo[0].DACType, + pRADEONEnt->PortInfo[0].TMDSType, pRADEONEnt->PortInfo[0].ConnectorType); + } + if (connector_found == 3) { + xf86DrvMsg(0, X_INFO, "Connector1: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", + pRADEONEnt->PortInfo[1].DDCType, pRADEONEnt->PortInfo[1].DACType, + pRADEONEnt->PortInfo[1].TMDSType, pRADEONEnt->PortInfo[1].ConnectorType); + } + +#if 0 +/* External TMDS Table, not used now */ + if ((tmp0 = RADEON_BIOS16(info->ROMHeaderStart + 0x58))) { + + //pRADEONEnt->PortInfo[1].DDCType = (RADEON_BIOS8(tmp0 + 7) & 0x07); + //pRADEONEnt->PortInfo[1].ConnectorType = CONNECTOR_DVI_I; + //pRADEONEnt->PortInfo[1].TMDSType = TMDS_EXT; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "External TMDS found.\n"); + + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NO External TMDS Info found\n"); + + } +#endif + + } + return TRUE; +} + +/* Read PLL parameters from BIOS block. Default to typical values if there + is no BIOS. */ +Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + RADEONPLLPtr pll = &info->pll; + CARD16 pll_info_block; + + if (!info->VBIOS) { + return FALSE; + } else { + if (info->IsAtomBios) { + pll_info_block = RADEON_BIOS16 (info->MasterDataStart + 12); + + pll->reference_freq = RADEON_BIOS16 (pll_info_block + 82); + pll->reference_div = 0; /* Need to derive from existing setting + or use a new algorithm to calculate + from min_input and max_input + */ + pll->min_pll_freq = RADEON_BIOS16 (pll_info_block + 78); + pll->max_pll_freq = RADEON_BIOS32 (pll_info_block + 32); + pll->xclk = RADEON_BIOS16 (pll_info_block + 72); + + info->sclk = RADEON_BIOS32(pll_info_block + 8) / 100.0; + info->mclk = RADEON_BIOS32(pll_info_block + 12) / 100.0; + if (info->sclk == 0) info->sclk = 200; + if (info->mclk == 0) info->mclk = 200; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ref_freq: %d, min_pll: %ld, max_pll: %ld, xclk: %d, sclk: %f, mclk: %f\n", + pll->reference_freq, pll->min_pll_freq, pll->max_pll_freq, pll->xclk, info->sclk, info->mclk); + + } else { + pll_info_block = RADEON_BIOS16 (info->ROMHeaderStart + 0x30); + + pll->reference_freq = RADEON_BIOS16 (pll_info_block + 0x0e); + pll->reference_div = RADEON_BIOS16 (pll_info_block + 0x10); + pll->min_pll_freq = RADEON_BIOS32 (pll_info_block + 0x12); + pll->max_pll_freq = RADEON_BIOS32 (pll_info_block + 0x16); + pll->xclk = RADEON_BIOS16 (pll_info_block + 0x08); + + info->sclk = RADEON_BIOS16(pll_info_block + 8) / 100.0; + info->mclk = RADEON_BIOS16(pll_info_block + 10) / 100.0; + } + } + + return TRUE; +} + +Bool RADEONGetLVDSInfoFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long tmp, i; + + if (!info->VBIOS) return FALSE; + + if (info->IsAtomBios) { + if((tmp = RADEON_BIOS16 (info->MasterDataStart + 16))) { + + info->PanelXRes = RADEON_BIOS16(tmp+6); + info->PanelYRes = RADEON_BIOS16(tmp+10); + info->DotClock = RADEON_BIOS16(tmp+4)*10; + info->HBlank = RADEON_BIOS16(tmp+8); + info->HOverPlus = RADEON_BIOS16(tmp+14); + info->HSyncWidth = RADEON_BIOS16(tmp+16); + info->VBlank = RADEON_BIOS16(tmp+12); + info->VOverPlus = RADEON_BIOS16(tmp+18); + info->VSyncWidth = RADEON_BIOS16(tmp+20); + info->PanelPwrDly = RADEON_BIOS16(tmp+40); + + info->Flags = 0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "LVDS Info:\n" + "XRes: %d, YRes: %d, DotClock: %d\n" + "HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n" + "VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n", + info->PanelXRes, info->PanelYRes, info->DotClock, + info->HBlank,info->HOverPlus, info->HSyncWidth, + info->VBlank, info->VOverPlus, info->VSyncWidth); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No LVDS Info Table found in BIOS!\n"); + return FALSE; + } + } else { + + tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x40); + + if (!tmp) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No Panel Info Table found in BIOS!\n"); + return FALSE; + } else { + char stmp[30]; + int tmp0; + + for (i = 0; i < 24; i++) + stmp[i] = RADEON_BIOS8(tmp+i+1); + stmp[24] = 0; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Panel ID string: %s\n", stmp); + + info->PanelXRes = RADEON_BIOS16(tmp+25); + info->PanelYRes = RADEON_BIOS16(tmp+27); + xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n", + info->PanelXRes, info->PanelYRes); + + info->PanelPwrDly = RADEON_BIOS16(tmp+44); + if (info->PanelPwrDly > 2000 || info->PanelPwrDly < 0) + info->PanelPwrDly = 2000; + + /* some panels only work well with certain divider combinations. + */ + info->RefDivider = RADEON_BIOS16(tmp+46); + info->PostDivider = RADEON_BIOS8(tmp+48); + info->FeedbackDivider = RADEON_BIOS16(tmp+49); + if ((info->RefDivider != 0) && + (info->FeedbackDivider > 3)) { + info->UseBiosDividers = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS provided dividers will be used.\n"); + } + + /* We don't use a while loop here just in case we have a corrupted BIOS image. + The max number of table entries is 23 at present, but may grow in future. + To ensure it works with future revisions we loop it to 32. + */ + for (i = 0; i < 32; i++) { + tmp0 = RADEON_BIOS16(tmp+64+i*2); + if (tmp0 == 0) break; + if ((RADEON_BIOS16(tmp0) == info->PanelXRes) && + (RADEON_BIOS16(tmp0+2) == info->PanelYRes)) { + info->HBlank = (RADEON_BIOS16(tmp0+17) - + RADEON_BIOS16(tmp0+19)) * 8; + info->HOverPlus = (RADEON_BIOS16(tmp0+21) - + RADEON_BIOS16(tmp0+19) - 1) * 8; + info->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8; + info->VBlank = (RADEON_BIOS16(tmp0+24) - + RADEON_BIOS16(tmp0+26)); + info->VOverPlus = ((RADEON_BIOS16(tmp0+28) & 0x7ff) - + RADEON_BIOS16(tmp0+26)); + info->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11); + info->DotClock = RADEON_BIOS16(tmp0+9) * 10; + info->Flags = 0; + } + } + } + } + return TRUE; +} + +Bool RADEONGetHardCodedEDIDFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long tmp; + char EDID[256]; + + if (!info->VBIOS) return FALSE; + + if (info->IsAtomBios) { + /* Not yet */ + return FALSE; + } else { + if (!(tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x4c))) { + return FALSE; + } + + memcpy(EDID, (char*)(info->VBIOS + tmp), 256); + + info->DotClock = (*(CARD16*)(EDID+54)) * 10; + info->PanelXRes = (*(CARD8*)(EDID+56)) + ((*(CARD8*)(EDID+58))>>4)*256; + info->HBlank = (*(CARD8*)(EDID+57)) + ((*(CARD8*)(EDID+58)) & 0xf)*256; + info->HOverPlus = (*(CARD8*)(EDID+62)) + ((*(CARD8*)(EDID+65)>>6)*256); + info->HSyncWidth = (*(CARD8*)(EDID+63)) + (((*(CARD8*)(EDID+65)>>4) & 3)*256); + info->PanelYRes = (*(CARD8*)(EDID+59)) + ((*(CARD8*)(EDID+61))>>4)*256; + info->VBlank = ((*(CARD8*)(EDID+60)) + ((*(CARD8*)(EDID+61)) & 0xf)*256); + info->VOverPlus = (((*(CARD8*)(EDID+64))>>4) + (((*(CARD8*)(EDID+65)>>2) & 3)*16)); + info->VSyncWidth = (((*(CARD8*)(EDID+64)) & 0xf) + ((*(CARD8*)(EDID+65)) & 3)*256); + info->Flags = V_NHSYNC | V_NVSYNC; /**(CARD8*)(EDID+71);*/ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Hardcoded EDID data will be used for TMDS panel\n"); + } + return TRUE; +} + +Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 tmp, maxfreq; + int i, n; + + if (!info->VBIOS) return FALSE; + + if (info->IsAtomBios) { + if((tmp = RADEON_BIOS16 (info->MasterDataStart + 18))) { + + maxfreq = RADEON_BIOS16(tmp+4); + + for (i=0; i<4; i++) { + info->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*6+6); + /* This assumes each field in TMDS_PLL has 6 bit as in R300/R420 */ + info->tmds_pll[i].value = ((RADEON_BIOS8(tmp+i*6+8) & 0x3f) | + ((RADEON_BIOS8(tmp+i*6+10) & 0x3f)<<6) | + ((RADEON_BIOS8(tmp+i*6+9) & 0xf)<<12) | + ((RADEON_BIOS8(tmp+i*6+11) & 0xf)<<16)); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "TMDS PLL from BIOS: %ld %lx\n", + info->tmds_pll[i].freq, info->tmds_pll[i].value); + + if (maxfreq == info->tmds_pll[i].freq) { + info->tmds_pll[i].freq = 0xffffffff; + break; + } + } + return TRUE; + } + } else { + + tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x34); + if (tmp) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "DFP table revision: %d\n", RADEON_BIOS8(tmp)); + if (RADEON_BIOS8(tmp) == 3) { + n = RADEON_BIOS8(tmp + 5) + 1; + if (n > 4) n = 4; + for (i=0; i<n; i++) { + info->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08); + info->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10); + } + return TRUE; + } + + /* revision 4 has some problem as it appears in RV280, + comment it off for now, use default instead */ + /* + else if (RADEON_BIOS8(tmp) == 4) { + int stride = 0; + n = RADEON_BIOS8(tmp + 5) + 1; + if (n > 4) n = 4; + for (i=0; i<n; i++) { + info->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08); + info->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10); + if (i == 0) stride += 10; + else stride += 6; + } + return TRUE; + } + */ + } + } + return FALSE; +} diff --git a/src/radeon_chipset.h b/src/radeon_chipset.h new file mode 100644 index 0000000..f29c849 --- /dev/null +++ b/src/radeon_chipset.h @@ -0,0 +1,97 @@ +static SymTabRec RADEONChipsets[] = { + { PCI_CHIP_RADEON_QD, "ATI Radeon QD (AGP)" }, + { PCI_CHIP_RADEON_QE, "ATI Radeon QE (AGP)" }, + { PCI_CHIP_RADEON_QF, "ATI Radeon QF (AGP)" }, + { PCI_CHIP_RADEON_QG, "ATI Radeon QG (AGP)" }, + { PCI_CHIP_RV100_QY, "ATI Radeon VE/7000 QY (AGP/PCI)" }, + { PCI_CHIP_RV100_QZ, "ATI Radeon VE/7000 QZ (AGP/PCI)" }, + { PCI_CHIP_RN50_5969, "ATI ES1000 (PCI)" }, + { PCI_CHIP_RADEON_LW, "ATI Radeon Mobility M7 LW (AGP)" }, + { PCI_CHIP_RADEON_LX, "ATI Mobility FireGL 7800 M7 LX (AGP)" }, + { PCI_CHIP_RADEON_LY, "ATI Radeon Mobility M6 LY (AGP)" }, + { PCI_CHIP_RADEON_LZ, "ATI Radeon Mobility M6 LZ (AGP)" }, + { PCI_CHIP_RS100_4136, "ATI Radeon IGP320 (A3) 4136" }, + { PCI_CHIP_RS100_4336, "ATI Radeon IGP320M (U1) 4336" }, + { PCI_CHIP_RS200_4137, "ATI Radeon IGP330/340/350 (A4) 4137" }, + { PCI_CHIP_RS200_4337, "ATI Radeon IGP330M/340M/350M (U2) 4337" }, + { PCI_CHIP_RS250_4237, "ATI Radeon 7000 IGP (A4+) 4237" }, + { PCI_CHIP_RS250_4437, "ATI Radeon Mobility 7000 IGP 4437" }, + { PCI_CHIP_R200_QH, "ATI FireGL 8700/8800 QH (AGP)" }, + { PCI_CHIP_R200_QL, "ATI Radeon 8500 QL (AGP)" }, + { PCI_CHIP_R200_QM, "ATI Radeon 9100 QM (AGP)" }, + { PCI_CHIP_R200_BB, "ATI Radeon 8500 AIW BB (AGP)" }, + { PCI_CHIP_R200_BC, "ATI Radeon 8500 AIW BC (AGP)" }, + { PCI_CHIP_RV200_QW, "ATI Radeon 7500 QW (AGP/PCI)" }, + { PCI_CHIP_RV200_QX, "ATI Radeon 7500 QX (AGP/PCI)" }, + { PCI_CHIP_RV250_If, "ATI Radeon 9000/PRO If (AGP/PCI)" }, + { PCI_CHIP_RV250_Ig, "ATI Radeon 9000 Ig (AGP/PCI)" }, + { PCI_CHIP_RV250_Ld, "ATI FireGL Mobility 9000 (M9) Ld (AGP)" }, + { PCI_CHIP_RV250_Lf, "ATI Radeon Mobility 9000 (M9) Lf (AGP)" }, + { PCI_CHIP_RV250_Lg, "ATI Radeon Mobility 9000 (M9) Lg (AGP)" }, + { PCI_CHIP_RS300_5834, "ATI Radeon 9100 IGP (A5) 5834" }, + { PCI_CHIP_RS300_5835, "ATI Radeon Mobility 9100 IGP (U3) 5835" }, + { PCI_CHIP_RS350_7834, "ATI Radeon 9100 PRO IGP 7834" }, + { PCI_CHIP_RS350_7835, "ATI Radeon Mobility 9200 IGP 7835" }, + { PCI_CHIP_RV280_5960, "ATI Radeon 9200PRO 5960 (AGP)" }, + { PCI_CHIP_RV280_5961, "ATI Radeon 9200 5961 (AGP)" }, + { PCI_CHIP_RV280_5962, "ATI Radeon 9200 5962 (AGP)" }, + { PCI_CHIP_RV280_5964, "ATI Radeon 9200SE 5964 (AGP)" }, + { PCI_CHIP_RV280_5C61, "ATI Radeon Mobility 9200 (M9+) 5C61 (AGP)" }, + { PCI_CHIP_RV280_5C63, "ATI Radeon Mobility 9200 (M9+) 5C63 (AGP)" }, + { PCI_CHIP_R300_AD, "ATI Radeon 9500 AD (AGP)" }, + { PCI_CHIP_R300_AE, "ATI Radeon 9500 AE (AGP)" }, + { PCI_CHIP_R300_AF, "ATI Radeon 9600TX AF (AGP)" }, + { PCI_CHIP_R300_AG, "ATI FireGL Z1 AG (AGP)" }, + { PCI_CHIP_R300_ND, "ATI Radeon 9700 Pro ND (AGP)" }, + { PCI_CHIP_R300_NE, "ATI Radeon 9700/9500Pro NE (AGP)" }, + { PCI_CHIP_R300_NF, "ATI Radeon 9700 NF (AGP)" }, + { PCI_CHIP_R300_NG, "ATI FireGL X1 NG (AGP)" }, + { PCI_CHIP_RV350_AP, "ATI Radeon 9600 AP (AGP)" }, + { PCI_CHIP_RV350_AQ, "ATI Radeon 9600SE AQ (AGP)" }, + { PCI_CHIP_RV360_AR, "ATI Radeon 9600XT AR (AGP)" }, + { PCI_CHIP_RV350_AS, "ATI Radeon 9600 AS (AGP)" }, + { PCI_CHIP_RV350_AT, "ATI FireGL T2 AT (AGP)" }, + { PCI_CHIP_RV350_AV, "ATI FireGL RV360 AV (AGP)" }, + { PCI_CHIP_RV350_NP, "ATI Radeon Mobility 9600/9700 (M10/M11) NP (AGP)" }, + { PCI_CHIP_RV350_NQ, "ATI Radeon Mobility 9600 (M10) NQ (AGP)" }, + { PCI_CHIP_RV350_NR, "ATI Radeon Mobility 9600 (M11) NR (AGP)" }, + { PCI_CHIP_RV350_NS, "ATI Radeon Mobility 9600 (M10) NS (AGP)" }, + { PCI_CHIP_RV350_NT, "ATI FireGL Mobility T2 (M10) NT (AGP)" }, + { PCI_CHIP_RV350_NV, "ATI FireGL Mobility T2e (M11) NV (AGP)" }, + { PCI_CHIP_R350_AH, "ATI Radeon 9800SE AH (AGP)" }, + { PCI_CHIP_R350_AI, "ATI Radeon 9800 AI (AGP)" }, + { PCI_CHIP_R350_AJ, "ATI Radeon 9800 AJ (AGP)" }, + { PCI_CHIP_R350_AK, "ATI FireGL X2 AK (AGP)" }, + { PCI_CHIP_R350_NH, "ATI Radeon 9800PRO NH (AGP)" }, + { PCI_CHIP_R350_NI, "ATI Radeon 9800 NI (AGP)" }, + { PCI_CHIP_R350_NK, "ATI FireGL X2 NK (AGP)" }, + { PCI_CHIP_R360_NJ, "ATI Radeon 9800XT NJ (AGP)" }, + { PCI_CHIP_RV380_3E50, "ATI Radeon X600 (RV380) 3E50 (PCIE)" }, + { PCI_CHIP_RV380_3E54, "ATI FireGL V3200 (RV380) 3E54 (PCIE)" }, + { PCI_CHIP_RV380_3150, "ATI Radeon Mobility X600 (M24) 3150 (PCIE)" }, + { PCI_CHIP_RV380_3154, "ATI FireGL M24 GL 3154 (PCIE)" }, + { PCI_CHIP_RV370_5B60, "ATI Radeon X300 (RV370) 5B60 (PCIE)" }, + { PCI_CHIP_RV370_5B62, "ATI Radeon X600 (RV370) 5B62 (PCIE)" }, + { PCI_CHIP_RV370_5B64, "ATI FireGL V3100 (RV370) 5B64 (PCIE)" }, + { PCI_CHIP_RV370_5B65, "ATI FireGL D1100 (RV370) 5B65 (PCIE)" }, + { PCI_CHIP_RV370_5460, "ATI Radeon Mobility M300 (M22) 5460 (PCIE)" }, + { PCI_CHIP_RV370_5464, "ATI FireGL M22 GL 5464 (PCIE)" }, + { PCI_CHIP_R420_JH, "ATI Radeon X800 (R420) JH (AGP)" }, + { PCI_CHIP_R420_JI, "ATI Radeon X800PRO (R420) JI (AGP)" }, + { PCI_CHIP_R420_JJ, "ATI Radeon X800SE (R420) JJ (AGP)" }, + { PCI_CHIP_R420_JK, "ATI Radeon X800 (R420) JK (AGP)" }, + { PCI_CHIP_R420_JL, "ATI Radeon X800 (R420) JL (AGP)" }, + { PCI_CHIP_R420_JM, "ATI FireGL X3 (R420) JM (AGP)" }, + { PCI_CHIP_R420_JN, "ATI Radeon Mobility 9800 (M18) JN (AGP)" }, + { PCI_CHIP_R420_JP, "ATI Radeon X800XT (R420) JP (AGP)" }, + { PCI_CHIP_R423_UH, "ATI Radeon X800 (R423) UH (PCIE)" }, + { PCI_CHIP_R423_UI, "ATI Radeon X800PRO (R423) UI (PCIE)" }, + { PCI_CHIP_R423_UJ, "ATI Radeon X800LE (R423) UJ (PCIE)" }, + { PCI_CHIP_R423_UK, "ATI Radeon X800SE (R423) UK (PCIE)" }, + { PCI_CHIP_R423_UQ, "ATI FireGL V7200 (R423) UQ (PCIE)" }, + { PCI_CHIP_R423_UR, "ATI FireGL V5100 (R423) UR (PCIE)" }, + { PCI_CHIP_R423_UT, "ATI FireGL V7100 (R423) UT (PCIE)" }, + { PCI_CHIP_R423_5D57, "ATI Radeon X800XT (R423) 5D57 (PCIE)" }, + + { -1, NULL } +}; diff --git a/src/radeon_common.h b/src/radeon_common.h new file mode 100644 index 0000000..924c7ff --- /dev/null +++ b/src/radeon_common.h @@ -0,0 +1,462 @@ +/* radeon_common.h -- common header definitions for Radeon 2D/3D/DRM suite + * + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * Copyright 2002 Tungsten Graphics, 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, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (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 NONINFRINGEMENT. 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. + * + * Author: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + * + * Converted to common header format: + * Jens Owen <jens@tungstengraphics.com> + * + * $XdotOrg: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h,v 1.1.4.2 2003/12/06 13:24:24 kaleb Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h,v 1.8tsi Exp $ + * + */ + +#ifndef _RADEON_COMMON_H_ +#define _RADEON_COMMON_H_ + +#include "xf86drm.h" + +/* WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (radeon_drm.h) + */ + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_RADEON_CP_INIT 0x00 +#define DRM_RADEON_CP_START 0x01 +#define DRM_RADEON_CP_STOP 0x02 +#define DRM_RADEON_CP_RESET 0x03 +#define DRM_RADEON_CP_IDLE 0x04 +#define DRM_RADEON_RESET 0x05 +#define DRM_RADEON_FULLSCREEN 0x06 +#define DRM_RADEON_SWAP 0x07 +#define DRM_RADEON_CLEAR 0x08 +#define DRM_RADEON_VERTEX 0x09 +#define DRM_RADEON_INDICES 0x0a +#define DRM_RADEON_STIPPLE 0x0c +#define DRM_RADEON_INDIRECT 0x0d +#define DRM_RADEON_TEXTURE 0x0e +#define DRM_RADEON_VERTEX2 0x0f +#define DRM_RADEON_CMDBUF 0x10 +#define DRM_RADEON_GETPARAM 0x11 +#define DRM_RADEON_FLIP 0x12 +#define DRM_RADEON_ALLOC 0x13 +#define DRM_RADEON_FREE 0x14 +#define DRM_RADEON_INIT_HEAP 0x15 +#define DRM_RADEON_IRQ_EMIT 0x16 +#define DRM_RADEON_IRQ_WAIT 0x17 +#define DRM_RADEON_CP_RESUME 0x18 +#define DRM_RADEON_SETPARAM 0x19 +#define DRM_RADEON_MAX_DRM_COMMAND_INDEX 0x39 + + +#define RADEON_FRONT 0x1 +#define RADEON_BACK 0x2 +#define RADEON_DEPTH 0x4 +#define RADEON_STENCIL 0x8 + +#define RADEON_CLEAR_X1 0 +#define RADEON_CLEAR_Y1 1 +#define RADEON_CLEAR_X2 2 +#define RADEON_CLEAR_Y2 3 +#define RADEON_CLEAR_DEPTH 4 + + +typedef struct { + enum { + DRM_RADEON_INIT_CP = 0x01, + DRM_RADEON_CLEANUP_CP = 0x02, + DRM_RADEON_INIT_R200_CP = 0x03 + } func; + unsigned long sarea_priv_offset; + int is_pci; + int cp_mode; + int gart_size; + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long gart_textures_offset; +} drmRadeonInit; + +typedef struct { + int flush; + int idle; +} drmRadeonCPStop; + +typedef struct { + int idx; + int start; + int end; + int discard; +} drmRadeonIndirect; + +typedef union drmRadeonClearR { + float f[5]; + unsigned int ui[5]; +} drmRadeonClearRect; + +typedef struct drmRadeonClearT { + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; /* misnamed field: should be stencil */ + drmRadeonClearRect *depth_boxes; +} drmRadeonClearType; + +typedef struct drmRadeonFullscreenT { + enum { + RADEON_INIT_FULLSCREEN = 0x01, + RADEON_CLEANUP_FULLSCREEN = 0x02 + } func; +} drmRadeonFullscreenType; + +typedef struct { + unsigned int *mask; +} drmRadeonStipple; + +typedef struct { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + const void *data; +} drmRadeonTexImage; + +typedef struct { + unsigned int offset; + int pitch; + int format; + int width; /* Texture image coordinates */ + int height; + drmRadeonTexImage *image; +} drmRadeonTexture; + + +#define RADEON_MAX_TEXTURE_UNITS 3 + +/* Layout matches drm_radeon_state_t in linux drm_radeon.h. + */ +typedef struct { + struct { + unsigned int pp_misc; /* 0x1c14 */ + unsigned int pp_fog_color; + unsigned int re_solid_color; + unsigned int rb3d_blendcntl; + unsigned int rb3d_depthoffset; + unsigned int rb3d_depthpitch; + unsigned int rb3d_zstencilcntl; + unsigned int pp_cntl; /* 0x1c38 */ + unsigned int rb3d_cntl; + unsigned int rb3d_coloroffset; + unsigned int re_width_height; + unsigned int rb3d_colorpitch; + } context; + struct { + unsigned int se_cntl; + } setup1; + struct { + unsigned int se_coord_fmt; /* 0x1c50 */ + } vertex; + struct { + unsigned int re_line_pattern; /* 0x1cd0 */ + unsigned int re_line_state; + unsigned int se_line_width; /* 0x1db8 */ + } line; + struct { + unsigned int pp_lum_matrix; /* 0x1d00 */ + unsigned int pp_rot_matrix_0; /* 0x1d58 */ + unsigned int pp_rot_matrix_1; + } bumpmap; + struct { + unsigned int rb3d_stencilrefmask; /* 0x1d7c */ + unsigned int rb3d_ropcntl; + unsigned int rb3d_planemask; + } mask; + struct { + unsigned int se_vport_xscale; /* 0x1d98 */ + unsigned int se_vport_xoffset; + unsigned int se_vport_yscale; + unsigned int se_vport_yoffset; + unsigned int se_vport_zscale; + unsigned int se_vport_zoffset; + } viewport; + struct { + unsigned int se_cntl_status; /* 0x2140 */ + } setup2; + struct { + unsigned int re_top_left; /*ignored*/ /* 0x26c0 */ + unsigned int re_misc; + } misc; + struct { + unsigned int pp_txfilter; + unsigned int pp_txformat; + unsigned int pp_txoffset; + unsigned int pp_txcblend; + unsigned int pp_txablend; + unsigned int pp_tfactor; + unsigned int pp_border_color; + } texture[RADEON_MAX_TEXTURE_UNITS]; + struct { + unsigned int se_zbias_factor; + unsigned int se_zbias_constant; + } zbias; + unsigned int dirty; +} drmRadeonState; + +/* 1.1 vertex ioctl. Used in compatibility modes. + */ +typedef struct { + int prim; + int idx; /* Index of vertex buffer */ + int count; /* Number of vertices in buffer */ + int discard; /* Client finished with buffer? */ +} drmRadeonVertex; + +typedef struct { + unsigned int start; + unsigned int finish; + unsigned int prim:8; + unsigned int stateidx:8; + unsigned int numverts:16; /* overloaded as offset/64 for elt prims */ + unsigned int vc_format; +} drmRadeonPrim; + +typedef struct { + int idx; /* Index of vertex buffer */ + int discard; /* Client finished with buffer? */ + int nr_states; + drmRadeonState *state; + int nr_prims; + drmRadeonPrim *prim; +} drmRadeonVertex2; + +#define RADEON_MAX_STATES 16 +#define RADEON_MAX_PRIMS 64 + +/* Command buffer. Replace with true dma stream? + */ +typedef struct { + int bufsz; + char *buf; + int nbox; + drmClipRect *boxes; +} drmRadeonCmdBuffer; + +/* New style per-packet identifiers for use in cmd_buffer ioctl with + * the RADEON_EMIT_PACKET command. Comments relate new packets to old + * state bits and the packet size: + */ +#define RADEON_EMIT_PP_MISC 0 /* context/7 */ +#define RADEON_EMIT_PP_CNTL 1 /* context/3 */ +#define RADEON_EMIT_RB3D_COLORPITCH 2 /* context/1 */ +#define RADEON_EMIT_RE_LINE_PATTERN 3 /* line/2 */ +#define RADEON_EMIT_SE_LINE_WIDTH 4 /* line/1 */ +#define RADEON_EMIT_PP_LUM_MATRIX 5 /* bumpmap/1 */ +#define RADEON_EMIT_PP_ROT_MATRIX_0 6 /* bumpmap/2 */ +#define RADEON_EMIT_RB3D_STENCILREFMASK 7 /* masks/3 */ +#define RADEON_EMIT_SE_VPORT_XSCALE 8 /* viewport/6 */ +#define RADEON_EMIT_SE_CNTL 9 /* setup/2 */ +#define RADEON_EMIT_SE_CNTL_STATUS 10 /* setup/1 */ +#define RADEON_EMIT_RE_MISC 11 /* misc/1 */ +#define RADEON_EMIT_PP_TXFILTER_0 12 /* tex0/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_0 13 /* tex0/1 */ +#define RADEON_EMIT_PP_TXFILTER_1 14 /* tex1/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_1 15 /* tex1/1 */ +#define RADEON_EMIT_PP_TXFILTER_2 16 /* tex2/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_2 17 /* tex2/1 */ +#define RADEON_EMIT_SE_ZBIAS_FACTOR 18 /* zbias/2 */ +#define RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT 19 /* tcl/11 */ +#define RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED 20 /* material/17 */ +#define R200_EMIT_PP_TXCBLEND_0 21 /* tex0/4 */ +#define R200_EMIT_PP_TXCBLEND_1 22 /* tex1/4 */ +#define R200_EMIT_PP_TXCBLEND_2 23 /* tex2/4 */ +#define R200_EMIT_PP_TXCBLEND_3 24 /* tex3/4 */ +#define R200_EMIT_PP_TXCBLEND_4 25 /* tex4/4 */ +#define R200_EMIT_PP_TXCBLEND_5 26 /* tex5/4 */ +#define R200_EMIT_PP_TXCBLEND_6 27 /* /4 */ +#define R200_EMIT_PP_TXCBLEND_7 28 /* /4 */ +#define R200_EMIT_TCL_LIGHT_MODEL_CTL_0 29 /* tcl/6 */ +#define R200_EMIT_TFACTOR_0 30 /* tf/6 */ +#define R200_EMIT_VTX_FMT_0 31 /* vtx/4 */ +#define R200_EMIT_VAP_CTL 32 /* vap/1 */ +#define R200_EMIT_MATRIX_SELECT_0 33 /* msl/5 */ +#define R200_EMIT_TEX_PROC_CTL_2 34 /* tcg/5 */ +#define R200_EMIT_TCL_UCP_VERT_BLEND_CTL 35 /* tcl/1 */ +#define R200_EMIT_PP_TXFILTER_0 36 /* tex0/6 */ +#define R200_EMIT_PP_TXFILTER_1 37 /* tex1/6 */ +#define R200_EMIT_PP_TXFILTER_2 38 /* tex2/6 */ +#define R200_EMIT_PP_TXFILTER_3 39 /* tex3/6 */ +#define R200_EMIT_PP_TXFILTER_4 40 /* tex4/6 */ +#define R200_EMIT_PP_TXFILTER_5 41 /* tex5/6 */ +#define R200_EMIT_PP_TXOFFSET_0 42 /* tex0/1 */ +#define R200_EMIT_PP_TXOFFSET_1 43 /* tex1/1 */ +#define R200_EMIT_PP_TXOFFSET_2 44 /* tex2/1 */ +#define R200_EMIT_PP_TXOFFSET_3 45 /* tex3/1 */ +#define R200_EMIT_PP_TXOFFSET_4 46 /* tex4/1 */ +#define R200_EMIT_PP_TXOFFSET_5 47 /* tex5/1 */ +#define R200_EMIT_VTE_CNTL 48 /* vte/1 */ +#define R200_EMIT_OUTPUT_VTX_COMP_SEL 49 /* vtx/1 */ +#define R200_EMIT_PP_TAM_DEBUG3 50 /* tam/1 */ +#define R200_EMIT_PP_CNTL_X 51 /* cst/1 */ +#define R200_EMIT_RB3D_DEPTHXY_OFFSET 52 /* cst/1 */ +#define R200_EMIT_RE_AUX_SCISSOR_CNTL 53 /* cst/1 */ +#define R200_EMIT_RE_SCISSOR_TL_0 54 /* cst/2 */ +#define R200_EMIT_RE_SCISSOR_TL_1 55 /* cst/2 */ +#define R200_EMIT_RE_SCISSOR_TL_2 56 /* cst/2 */ +#define R200_EMIT_SE_VAP_CNTL_STATUS 57 /* cst/1 */ +#define R200_EMIT_SE_VTX_STATE_CNTL 58 /* cst/1 */ +#define R200_EMIT_RE_POINTSIZE 59 /* cst/1 */ +#define R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 60 /* cst/4 */ +#define R200_EMIT_PP_CUBIC_FACES_0 61 +#define R200_EMIT_PP_CUBIC_OFFSETS_0 62 +#define R200_EMIT_PP_CUBIC_FACES_1 63 +#define R200_EMIT_PP_CUBIC_OFFSETS_1 64 +#define R200_EMIT_PP_CUBIC_FACES_2 65 +#define R200_EMIT_PP_CUBIC_OFFSETS_2 66 +#define R200_EMIT_PP_CUBIC_FACES_3 67 +#define R200_EMIT_PP_CUBIC_OFFSETS_3 68 +#define R200_EMIT_PP_CUBIC_FACES_4 69 +#define R200_EMIT_PP_CUBIC_OFFSETS_4 70 +#define R200_EMIT_PP_CUBIC_FACES_5 71 +#define R200_EMIT_PP_CUBIC_OFFSETS_5 72 +#define RADEON_EMIT_PP_TEX_SIZE_0 73 +#define RADEON_EMIT_PP_TEX_SIZE_1 74 +#define RADEON_EMIT_PP_TEX_SIZE_2 75 +#define RADEON_MAX_STATE_PACKETS 76 + + +/* Commands understood by cmd_buffer ioctl. More can be added but + * obviously these can't be removed or changed: + */ +#define RADEON_CMD_PACKET 1 /* emit one of the register packets above */ +#define RADEON_CMD_SCALARS 2 /* emit scalar data */ +#define RADEON_CMD_VECTORS 3 /* emit vector data */ +#define RADEON_CMD_DMA_DISCARD 4 /* discard current dma buf */ +#define RADEON_CMD_PACKET3 5 /* emit hw packet */ +#define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */ +#define RADEON_CMD_SCALARS2 7 /* R200 stopgap */ +#define RADEON_CMD_WAIT 8 /* synchronization */ + +typedef union { + int i; + struct { + unsigned char cmd_type, pad0, pad1, pad2; + } header; + struct { + unsigned char cmd_type, packet_id, pad0, pad1; + } packet; + struct { + unsigned char cmd_type, offset, stride, count; + } scalars; + struct { + unsigned char cmd_type, offset, stride, count; + } vectors; + struct { + unsigned char cmd_type, buf_idx, pad0, pad1; + } dma; + struct { + unsigned char cmd_type, flags, pad0, pad1; + } wait; +} drmRadeonCmdHeader; + + +#define RADEON_WAIT_2D 0x1 +#define RADEON_WAIT_3D 0x2 + + +typedef struct drm_radeon_getparam { + int param; + int *value; +} drmRadeonGetParam; + +#define RADEON_PARAM_GART_BUFFER_OFFSET 1 +#define RADEON_PARAM_LAST_FRAME 2 +#define RADEON_PARAM_LAST_DISPATCH 3 +#define RADEON_PARAM_LAST_CLEAR 4 +#define RADEON_PARAM_IRQ_NR 5 +#define RADEON_PARAM_GART_BASE 6 + + +#define RADEON_MEM_REGION_GART 1 +#define RADEON_MEM_REGION_FB 2 + +typedef struct drm_radeon_mem_alloc { + int region; + int alignment; + int size; + int *region_offset; /* offset from start of fb or GART */ +} drmRadeonMemAlloc; + +typedef struct drm_radeon_mem_free { + int region; + int region_offset; +} drmRadeonMemFree; + +typedef struct drm_radeon_mem_init_heap { + int region; + int size; + int start; +} drmRadeonMemInitHeap; + +/* 1.6: Userspace can request & wait on irq's: + */ +typedef struct drm_radeon_irq_emit { + int *irq_seq; +} drmRadeonIrqEmit; + +typedef struct drm_radeon_irq_wait { + int irq_seq; +} drmRadeonIrqWait; + + +/* 1.10: Clients tell the DRM where they think the framebuffer is located in + * the card's address space, via a new generic ioctl to set parameters + */ + +typedef struct drm_radeon_set_param { + unsigned int param; + long long value; +} drmRadeonSetParam; + +#define RADEON_SETPARAM_FB_LOCATION 1 + + +#endif diff --git a/src/radeon_cursor.c b/src/radeon_cursor.c new file mode 100644 index 0000000..fe54cd9 --- /dev/null +++ b/src/radeon_cursor.c @@ -0,0 +1,486 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_cursor.c,v 1.25 2003/08/29 21:07:57 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + + /* Driver data structures */ +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_reg.h" + + /* X and server generic header files */ +#include "xf86.h" + +/* Mono ARGB cursor colours (premultiplied). */ +static CARD32 mono_cursor_color[] = { + 0x00000000, /* White, fully transparent. */ + 0x00000000, /* Black, fully transparent. */ + 0xffffffff, /* White, fully opaque. */ + 0xff000000, /* Black, fully opaque. */ +}; + +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + +/* + * The cursor bits are always 32bpp. On MSBFirst buses, + * configure byte swapping to swap 32 bit units when writing + * the cursor image. Byte swapping must always be returned + * to its previous value before returning. + */ +#if X_BYTE_ORDER == X_BIG_ENDIAN + +#define CURSOR_SWAPPING_DECL_MMIO unsigned char *RADEONMMIO = info->MMIO; +#define CURSOR_SWAPPING_DECL CARD32 __surface_cntl; +#define CURSOR_SWAPPING_START() \ + OUTREG(RADEON_SURFACE_CNTL, \ + ((__surface_cntl = INREG(RADEON_SURFACE_CNTL)) | \ + RADEON_NONSURF_AP0_SWP_32BPP) & \ + ~RADEON_NONSURF_AP0_SWP_16BPP) +#define CURSOR_SWAPPING_END() (OUTREG(RADEON_SURFACE_CNTL, __surface_cntl)) + +#else + +#define CURSOR_SWAPPING_DECL_MMIO +#define CURSOR_SWAPPING_DECL +#define CURSOR_SWAPPING_START() +#define CURSOR_SWAPPING_END() + +#endif + +/* Set cursor foreground and background colors */ +static void RADEONSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 *pixels = (CARD32 *)(pointer)(info->FB + info->cursor_start); + int pixel, i; + CURSOR_SWAPPING_DECL_MMIO + CURSOR_SWAPPING_DECL + +#ifdef ARGB_CURSOR + /* Don't recolour cursors set with SetCursorARGB. */ + if (info->cursor_argb) + return; +#endif + + fg |= 0xff000000; + bg |= 0xff000000; + + /* Don't recolour the image if we don't have to. */ + if (fg == info->cursor_fg && bg == info->cursor_bg) + return; + + CURSOR_SWAPPING_START(); + + /* Note: We assume that the pixels are either fully opaque or fully + * transparent, so we won't premultiply them, and we can just + * check for non-zero pixel values; those are either fg or bg + */ + for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++) + if ((pixel = *pixels)) + *pixels = (pixel == info->cursor_fg) ? fg : bg; + + CURSOR_SWAPPING_END(); + info->cursor_fg = fg; + info->cursor_bg = bg; +} + + +/* Set cursor position to (x,y) with offset into cursor bitmap at + * (xorigin,yorigin) + */ +static void RADEONSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + xf86CursorInfoPtr cursor = info->cursor; + int xorigin = 0; + int yorigin = 0; + int total_y = pScrn->frameY1 - pScrn->frameY0; + int X2 = pScrn->frameX0 + x; + int Y2 = pScrn->frameY0 + y; + int stride = 256; + + if (x < 0) xorigin = -x+1; + if (y < 0) yorigin = -y+1; + if (y > total_y) y = total_y; + if (info->Flags & V_DBLSCAN) y *= 2; + if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; + if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; + + if (info->Clone) { + int X0 = 0; + int Y0 = 0; + + if ((info->CurCloneMode->VDisplay == pScrn->currentMode->VDisplay) && + (info->CurCloneMode->HDisplay == pScrn->currentMode->HDisplay)) { + Y2 = y; + X2 = x; + X0 = pScrn->frameX0; + Y0 = pScrn->frameY0; + } else { + if (y < 0) + Y2 = pScrn->frameY0; + + if (x < 0) + X2 = pScrn->frameX0; + + if (Y2 >= info->CurCloneMode->VDisplay + info->CloneFrameY0) { + Y0 = Y2 - info->CurCloneMode->VDisplay; + Y2 = info->CurCloneMode->VDisplay - 1; + } else if (Y2 < info->CloneFrameY0) { + Y0 = Y2; + Y2 = 0; + } else { + Y2 -= info->CloneFrameY0; + Y0 = info->CloneFrameY0; + } + + if (X2 >= info->CurCloneMode->HDisplay + info->CloneFrameX0) { + X0 = X2 - info->CurCloneMode->HDisplay; + X2 = info->CurCloneMode->HDisplay - 1; + } else if (X2 < info->CloneFrameX0) { + X0 = X2; + X2 = 0; + } else { + X2 -= info->CloneFrameX0; + X0 = info->CloneFrameX0; + } + + if (info->CurCloneMode->Flags & V_DBLSCAN) + Y2 *= 2; + } + + if ((X0 >= 0 || Y0 >= 0) && + ((info->CloneFrameX0 != X0) || (info->CloneFrameY0 != Y0))) { + RADEONDoAdjustFrame(pScrn, X0, Y0, TRUE); + info->CloneFrameX0 = X0; + info->CloneFrameY0 = Y0; + } + } + + if (!info->IsSecondary) { + OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK + | ((xorigin ? 0 : x) << 16) + | (yorigin ? 0 : y))); + OUTREG(RADEON_CUR_OFFSET, info->cursor_start + yorigin * stride); + } else { + OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK + | ((xorigin ? 0 : x) << 16) + | (yorigin ? 0 : y))); + OUTREG(RADEON_CUR2_OFFSET, + info->cursor_start + pScrn->fbOffset + yorigin * stride); + } + + if (info->Clone) { + xorigin = 0; + yorigin = 0; + if (X2 < 0) xorigin = -X2 + 1; + if (Y2 < 0) yorigin = -Y2 + 1; + if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; + if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; + + OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK + | ((xorigin ? 0 : X2) << 16) + | (yorigin ? 0 : Y2))); + OUTREG(RADEON_CUR2_OFFSET, + info->cursor_start + pScrn->fbOffset + yorigin * stride); + } +} + +/* Copy cursor image from `image' to video memory. RADEONSetCursorPosition + * will be called after this, so we can ignore xorigin and yorigin. + */ +static void RADEONLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD8 *s = (CARD8 *)(pointer)image; + CARD32 *d = (CARD32 *)(pointer)(info->FB + info->cursor_start); + CARD32 save1 = 0; + CARD32 save2 = 0; + CARD8 chunk; + CARD32 i, j; + CURSOR_SWAPPING_DECL + + if (!info->IsSecondary) { + save1 = INREG(RADEON_CRTC_GEN_CNTL) & ~(CARD32) (3 << 20); + save1 |= (CARD32) (2 << 20); + OUTREG(RADEON_CRTC_GEN_CNTL, save1 & (CARD32)~RADEON_CRTC_CUR_EN); + } + + if (info->IsSecondary || info->Clone) { + save2 = INREG(RADEON_CRTC2_GEN_CNTL) & ~(CARD32) (3 << 20); + save2 |= (CARD32) (2 << 20); + OUTREG(RADEON_CRTC2_GEN_CNTL, save2 & (CARD32)~RADEON_CRTC2_CUR_EN); + } + +#ifdef ARGB_CURSOR + info->cursor_argb = FALSE; +#endif + + /* + * Convert the bitmap to ARGB32. + * + * HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 always places + * source in the low bit of the pair and mask in the high bit, + * and MSBFirst machines set HARDWARE_CURSOR_BIT_ORDER_MSBFIRST + * (which actually bit swaps the image) to make the bits LSBFirst + */ + CURSOR_SWAPPING_START(); +#define ARGB_PER_CHUNK (8 * sizeof (chunk) / 2) + for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT / ARGB_PER_CHUNK; i++) { + chunk = *s++; + for (j = 0; j < ARGB_PER_CHUNK; j++, chunk >>= 2) + *d++ = mono_cursor_color[chunk & 3]; + } + CURSOR_SWAPPING_END(); + + info->cursor_bg = mono_cursor_color[2]; + info->cursor_fg = mono_cursor_color[3]; + + if (!info->IsSecondary) + OUTREG(RADEON_CRTC_GEN_CNTL, save1); + + if (info->IsSecondary || info->Clone) + OUTREG(RADEON_CRTC2_GEN_CNTL, save2); + +} + +/* Hide hardware cursor. */ +static void RADEONHideCursor(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (info->IsSecondary || info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); + + if (!info->IsSecondary) + OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN); +} + +/* Show hardware cursor. */ +static void RADEONShowCursor(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (info->IsSecondary || info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, + ~RADEON_CRTC2_CUR_EN); + + if (!info->IsSecondary) + OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, + ~RADEON_CRTC_CUR_EN); +} + +/* Determine if hardware cursor is in use. */ +static Bool RADEONUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + return info->cursor_start ? TRUE : FALSE; +} + +#ifdef ARGB_CURSOR +#include "cursorstr.h" + +static Bool RADEONUseHWCursorARGB (ScreenPtr pScreen, CursorPtr pCurs) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->cursor_start && + pCurs->bits->height <= CURSOR_HEIGHT && pCurs->bits->width <= CURSOR_WIDTH) + return TRUE; + return FALSE; +} + +static void RADEONLoadCursorARGB (ScrnInfoPtr pScrn, CursorPtr pCurs) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 *d = (CARD32 *)(pointer)(info->FB + info->cursor_start); + int x, y, w, h; + CARD32 save1 = 0; + CARD32 save2 = 0; + CARD32 *image = pCurs->bits->argb; + CARD32 *i; + CURSOR_SWAPPING_DECL + + if (!image) + return; /* XXX can't happen */ + + if (!info->IsSecondary) { + save1 = INREG(RADEON_CRTC_GEN_CNTL) & ~(CARD32) (3 << 20); + save1 |= (CARD32) (2 << 20); + OUTREG(RADEON_CRTC_GEN_CNTL, save1 & (CARD32)~RADEON_CRTC_CUR_EN); + } + + if (info->IsSecondary || info->Clone) { + save2 = INREG(RADEON_CRTC2_GEN_CNTL) & ~(CARD32) (3 << 20); + save2 |= (CARD32) (2 << 20); + OUTREG(RADEON_CRTC2_GEN_CNTL, save2 & (CARD32)~RADEON_CRTC2_CUR_EN); + } + +#ifdef ARGB_CURSOR + info->cursor_argb = TRUE; +#endif + + CURSOR_SWAPPING_START(); + + w = pCurs->bits->width; + if (w > CURSOR_WIDTH) + w = CURSOR_WIDTH; + h = pCurs->bits->height; + if (h > CURSOR_HEIGHT) + h = CURSOR_HEIGHT; + for (y = 0; y < h; y++) + { + i = image; + image += pCurs->bits->width; + for (x = 0; x < w; x++) + *d++ = *i++; + /* pad to the right with transparent */ + for (; x < CURSOR_WIDTH; x++) + *d++ = 0; + } + /* pad below with transparent */ + for (; y < CURSOR_HEIGHT; y++) + for (x = 0; x < CURSOR_WIDTH; x++) + *d++ = 0; + + CURSOR_SWAPPING_END (); + + if (!info->IsSecondary) + OUTREG(RADEON_CRTC_GEN_CNTL, save1); + + if (info->IsSecondary || info->Clone) + OUTREG(RADEON_CRTC2_GEN_CNTL, save2); + +} + +#endif + + +/* Initialize hardware cursor support. */ +Bool RADEONCursorInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CursorInfoPtr cursor; + FBAreaPtr fbarea; + int width; + int width_bytes; + int height; + int size_bytes; + + if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE; + + cursor->MaxWidth = CURSOR_WIDTH; + cursor->MaxHeight = CURSOR_HEIGHT; + cursor->Flags = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP + | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* this is a lie -- + * HARDWARE_CURSOR_BIT_ORDER_MSBFIRST + * actually inverts the bit order, so + * this switches to LSBFIRST + */ + | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST +#endif + | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1); + + cursor->SetCursorColors = RADEONSetCursorColors; + cursor->SetCursorPosition = RADEONSetCursorPosition; + cursor->LoadCursorImage = RADEONLoadCursorImage; + cursor->HideCursor = RADEONHideCursor; + cursor->ShowCursor = RADEONShowCursor; + cursor->UseHWCursor = RADEONUseHWCursor; + +#ifdef ARGB_CURSOR + cursor->UseHWCursorARGB = RADEONUseHWCursorARGB; + cursor->LoadCursorARGB = RADEONLoadCursorARGB; +#endif + size_bytes = CURSOR_WIDTH * 4 * CURSOR_HEIGHT; + width = pScrn->displayWidth; + width_bytes = width * (pScrn->bitsPerPixel / 8); + height = (size_bytes + width_bytes - 1) / width_bytes; + fbarea = xf86AllocateOffscreenArea(pScreen, + width, + height, + 256, + NULL, + NULL, + NULL); + + if (!fbarea) { + info->cursor_start = 0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Hardware cursor disabled" + " due to insufficient offscreen memory\n"); + } else { + info->cursor_start = RADEON_ALIGN((fbarea->box.x1 + + fbarea->box.y1 * width) * + info->CurrentLayout.pixel_bytes, + 256); + info->cursor_end = info->cursor_start + size_bytes; + } + + RADEONTRACE(("RADEONCursorInit (0x%08x-0x%08x)\n", + info->cursor_start, info->cursor_end)); + + return xf86InitCursor(pScreen, cursor); +} diff --git a/src/radeon_dga.c b/src/radeon_dga.c new file mode 100644 index 0000000..f5121dc --- /dev/null +++ b/src/radeon_dga.c @@ -0,0 +1,397 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_dga.c,v 1.11 2002/09/18 18:14:58 martin Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * + * Credits: + * + * Thanks to Ove Kåven <ovek@transgaming.com> for writing the Rage 128 + * DGA support. Portions of this file are based on the initialization + * code for that driver. + * + */ + + /* Driver data structures */ +#include "radeon.h" +#include "radeon_probe.h" + + /* X and server generic header files */ +#include "xf86.h" + + /* DGA support */ +#include "dgaproc.h" + + +static Bool RADEON_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **, + int *, int *, int *); +static Bool RADEON_SetMode(ScrnInfoPtr, DGAModePtr); +static int RADEON_GetViewport(ScrnInfoPtr); +static void RADEON_SetViewport(ScrnInfoPtr, int, int, int); +static void RADEON_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); +static void RADEON_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); +static void RADEON_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, + unsigned long); + + +static DGAModePtr RADEONSetupDGAMode(ScrnInfoPtr pScrn, + DGAModePtr modes, + int *num, + int bitsPerPixel, + int depth, + Bool pixmap, + int secondPitch, + unsigned long red, + unsigned long green, + unsigned long blue, + short visualClass) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + DGAModePtr newmodes = NULL; + DGAModePtr currentMode; + DisplayModePtr pMode; + DisplayModePtr firstMode; + unsigned int size; + int pitch; + int Bpp = bitsPerPixel >> 3; + +SECOND_PASS: + + pMode = firstMode = pScrn->modes; + + while (1) { + pitch = pScrn->displayWidth; + size = pitch * Bpp * pMode->VDisplay; + + if ((!secondPitch || (pitch != secondPitch)) && + (size <= info->FbMapSize)) { + + if (secondPitch) + pitch = secondPitch; + + if (!(newmodes = xrealloc(modes, (*num + 1) * sizeof(DGAModeRec)))) + break; + + modes = newmodes; + currentMode = modes + *num; + + currentMode->mode = pMode; + currentMode->flags = DGA_CONCURRENT_ACCESS; + + if (pixmap) + currentMode->flags |= DGA_PIXMAP_AVAILABLE; + + if (info->accel) { + if (info->accel->SetupForSolidFill && + info->accel->SubsequentSolidFillRect) + currentMode->flags |= DGA_FILL_RECT; + if (info->accel->SetupForScreenToScreenCopy && + info->accel->SubsequentScreenToScreenCopy) + currentMode->flags |= DGA_BLIT_RECT | DGA_BLIT_RECT_TRANS; + if (currentMode->flags & + (DGA_PIXMAP_AVAILABLE | DGA_FILL_RECT | + DGA_BLIT_RECT | DGA_BLIT_RECT_TRANS)) + currentMode->flags &= ~DGA_CONCURRENT_ACCESS; + } + if (pMode->Flags & V_DBLSCAN) + currentMode->flags |= DGA_DOUBLESCAN; + if (pMode->Flags & V_INTERLACE) + currentMode->flags |= DGA_INTERLACED; + + currentMode->byteOrder = pScrn->imageByteOrder; + currentMode->depth = depth; + currentMode->bitsPerPixel = bitsPerPixel; + currentMode->red_mask = red; + currentMode->green_mask = green; + currentMode->blue_mask = blue; + currentMode->visualClass = visualClass; + currentMode->viewportWidth = pMode->HDisplay; + currentMode->viewportHeight = pMode->VDisplay; + currentMode->xViewportStep = 8; + currentMode->yViewportStep = 1; + currentMode->viewportFlags = DGA_FLIP_RETRACE; + currentMode->offset = 0; + currentMode->address = (unsigned char*)info->LinearAddr; + currentMode->bytesPerScanline = pitch * Bpp; + currentMode->imageWidth = pitch; + currentMode->imageHeight = (info->FbMapSize + / currentMode->bytesPerScanline); + 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); + (*num)++; + } + + pMode = pMode->next; + if (pMode == firstMode) + break; + } + + if (secondPitch) { + secondPitch = 0; + goto SECOND_PASS; + } + + return modes; +} + +Bool RADEONDGAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + DGAModePtr modes = NULL; + int num = 0; + + /* 8 */ + modes = RADEONSetupDGAMode(pScrn, modes, &num, 8, 8, + (pScrn->bitsPerPixel == 8), + ((pScrn->bitsPerPixel != 8) + ? 0 : pScrn->displayWidth), + 0, 0, 0, PseudoColor); + + /* 15 */ + modes = RADEONSetupDGAMode(pScrn, modes, &num, 16, 15, + (pScrn->bitsPerPixel == 16), + ((pScrn->depth != 15) + ? 0 : pScrn->displayWidth), + 0x7c00, 0x03e0, 0x001f, TrueColor); + + modes = RADEONSetupDGAMode(pScrn, modes, &num, 16, 15, + (pScrn->bitsPerPixel == 16), + ((pScrn->depth != 15) + ? 0 : pScrn->displayWidth), + 0x7c00, 0x03e0, 0x001f, DirectColor); + + /* 16 */ + modes = RADEONSetupDGAMode(pScrn, modes, &num, 16, 16, + (pScrn->bitsPerPixel == 16), + ((pScrn->depth != 16) + ? 0 : pScrn->displayWidth), + 0xf800, 0x07e0, 0x001f, TrueColor); + + modes = RADEONSetupDGAMode(pScrn, modes, &num, 16, 16, + (pScrn->bitsPerPixel == 16), + ((pScrn->depth != 16) + ? 0 : pScrn->displayWidth), + 0xf800, 0x07e0, 0x001f, DirectColor); + + /* 32 */ + modes = RADEONSetupDGAMode(pScrn, modes, &num, 32, 24, + (pScrn->bitsPerPixel == 32), + ((pScrn->bitsPerPixel != 32) + ? 0 : pScrn->displayWidth), + 0xff0000, 0x00ff00, 0x0000ff, TrueColor); + + modes = RADEONSetupDGAMode(pScrn, modes, &num, 32, 24, + (pScrn->bitsPerPixel == 32), + ((pScrn->bitsPerPixel != 32) + ? 0 : pScrn->displayWidth), + 0xff0000, 0x00ff00, 0x0000ff, DirectColor); + + info->numDGAModes = num; + info->DGAModes = modes; + + info->DGAFuncs.OpenFramebuffer = RADEON_OpenFramebuffer; + info->DGAFuncs.CloseFramebuffer = NULL; + info->DGAFuncs.SetMode = RADEON_SetMode; + info->DGAFuncs.SetViewport = RADEON_SetViewport; + info->DGAFuncs.GetViewport = RADEON_GetViewport; + + info->DGAFuncs.Sync = NULL; + info->DGAFuncs.FillRect = NULL; + info->DGAFuncs.BlitRect = NULL; + info->DGAFuncs.BlitTransRect = NULL; + + if (info->accel) { + info->DGAFuncs.Sync = info->accel->Sync; + if (info->accel->SetupForSolidFill && + info->accel->SubsequentSolidFillRect) + info->DGAFuncs.FillRect = RADEON_FillRect; + if (info->accel->SetupForScreenToScreenCopy && + info->accel->SubsequentScreenToScreenCopy) { + info->DGAFuncs.BlitRect = RADEON_BlitRect; + info->DGAFuncs.BlitTransRect = RADEON_BlitTransRect; + } + } + + return DGAInit(pScreen, &info->DGAFuncs, modes, num); +} + +static Bool RADEON_SetMode(ScrnInfoPtr pScrn, DGAModePtr pMode) +{ + static RADEONFBLayout SavedLayouts[MAXSCREENS]; + int indx = pScrn->pScreen->myNum; + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (!pMode) { /* restore the original mode */ + /* put the ScreenParameters back */ + if (info->DGAactive) + memcpy(&info->CurrentLayout, &SavedLayouts[indx], + sizeof(RADEONFBLayout)); + + pScrn->currentMode = info->CurrentLayout.mode; + + RADEONSwitchMode(indx, pScrn->currentMode, 0); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONCP_STOP(pScrn, info); + } +#endif + if (info->accelOn) + RADEONEngineInit(pScrn); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONCP_START(pScrn, info); + } +#endif + RADEONAdjustFrame(indx, 0, 0, 0); + info->DGAactive = FALSE; + } else { + if (!info->DGAactive) { /* save the old parameters */ + memcpy(&SavedLayouts[indx], &info->CurrentLayout, + sizeof(RADEONFBLayout)); + info->DGAactive = TRUE; + } + + info->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel; + info->CurrentLayout.depth = pMode->depth; + info->CurrentLayout.displayWidth = (pMode->bytesPerScanline / + (pMode->bitsPerPixel >> 3)); + info->CurrentLayout.pixel_bytes = pMode->bitsPerPixel / 8; + info->CurrentLayout.pixel_code = (pMode->bitsPerPixel != 16 + ? pMode->bitsPerPixel + : pMode->depth); + /* RADEONModeInit() will set the mode field */ + + RADEONSwitchMode(indx, pMode->mode, 0); + +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONCP_STOP(pScrn, info); + } +#endif + if (info->accelOn) + RADEONEngineInit(pScrn); +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONCP_START(pScrn, info); + } +#endif + } + + return TRUE; +} + +static int RADEON_GetViewport(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + return info->DGAViewportStatus; +} + +static void RADEON_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + RADEONAdjustFrame(pScrn->pScreen->myNum, x, y, flags); + info->DGAViewportStatus = 0; /* FIXME */ +} + +static void RADEON_FillRect(ScrnInfoPtr pScrn, + int x, int y, int w, int h, + unsigned long color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + (*info->accel->SetupForSolidFill)(pScrn, color, GXcopy, (CARD32)(~0)); + (*info->accel->SubsequentSolidFillRect)(pScrn, x, y, w, h); + + if (pScrn->bitsPerPixel == info->CurrentLayout.bitsPerPixel) + SET_SYNC_FLAG(info->accel); +} + +static void RADEON_BlitRect(ScrnInfoPtr pScrn, + int srcx, int srcy, int w, int h, + int dstx, int dsty) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + (*info->accel->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, + GXcopy, (CARD32)(~0), -1); + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, srcx, srcy, + dstx, dsty, w, h); + + if (pScrn->bitsPerPixel == info->CurrentLayout.bitsPerPixel) + SET_SYNC_FLAG(info->accel); +} + +static void RADEON_BlitTransRect(ScrnInfoPtr pScrn, + int srcx, int srcy, int w, int h, + int dstx, int dsty, unsigned long color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; + int ydir = (srcy < dsty) ? -1 : 1; + + info->XAAForceTransBlit = TRUE; + + (*info->accel->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, + GXcopy, (CARD32)(~0), color); + + info->XAAForceTransBlit = FALSE; + + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, srcx, srcy, + dstx, dsty, w, h); + + if (pScrn->bitsPerPixel == info->CurrentLayout.bitsPerPixel) + SET_SYNC_FLAG(info->accel); +} + +static Bool RADEON_OpenFramebuffer(ScrnInfoPtr pScrn, + char **name, + unsigned char **mem, + int *size, int *offset, int *flags) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + *name = NULL; /* no special device */ + *mem = (unsigned char*)info->LinearAddr; + *size = info->FbMapSize; + *offset = 0; + *flags = 0; /* DGA_NEED_ROOT; -- don't need root, just /dev/mem access */ + + return TRUE; +} diff --git a/src/radeon_dri.c b/src/radeon_dri.c new file mode 100644 index 0000000..0c6d555 --- /dev/null +++ b/src/radeon_dri.c @@ -0,0 +1,1910 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_dri.c,v 1.39 2003/11/06 18:38:00 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + + + /* Driver data structures */ +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_dri.h" +#include "radeon_reg.h" +#include "radeon_version.h" + + /* X and server generic header files */ +#include "xf86.h" +#include "xf86PciInfo.h" +#include "windowstr.h" + + +#include "shadowfb.h" + /* GLX/DRI/DRM definitions */ +#define _XF86DRI_SERVER_ +#include "GL/glxtokens.h" +#include "sarea.h" +#include "radeon_sarea.h" + +/* HACK - for now, put this here... */ +/* Alpha - this may need to be a variable to handle UP1x00 vs TITAN */ +#if defined(__alpha__) +# define DRM_PAGE_SIZE 8192 +#elif defined(__ia64__) +# define DRM_PAGE_SIZE getpagesize() +#else +# define DRM_PAGE_SIZE 4096 +#endif + + +static Bool RADEONDRICloseFullScreen(ScreenPtr pScreen); +static Bool RADEONDRIOpenFullScreen(ScreenPtr pScreen); +static void RADEONDRITransitionTo2d(ScreenPtr pScreen); +static void RADEONDRITransitionTo3d(ScreenPtr pScreen); +static void RADEONDRITransitionMultiToSingle3d(ScreenPtr pScreen); +static void RADEONDRITransitionSingleToMulti3d(ScreenPtr pScreen); + +static void RADEONDRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox); + +/* Initialize the visual configs that are supported by the hardware. + * These are combined with the visual configs that the indirect + * rendering core supports, and the intersection is exported to the + * client. + */ +static Bool RADEONInitVisualConfigs(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + int numConfigs = 0; + __GLXvisualConfig *pConfigs = 0; + RADEONConfigPrivPtr pRADEONConfigs = 0; + RADEONConfigPrivPtr *pRADEONConfigPtrs = 0; + int i, accum, stencil, db, use_db; + + use_db = !info->noBackBuffer ? 1 : 0; + + switch (info->CurrentLayout.pixel_code) { + case 8: /* 8bpp mode is not support */ + case 15: /* FIXME */ + case 24: /* FIXME */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] RADEONInitVisualConfigs failed " + "(depth %d not supported). " + "Disabling DRI.\n", info->CurrentLayout.pixel_code); + return FALSE; + +#define RADEON_USE_ACCUM 1 +#define RADEON_USE_STENCIL 1 + + case 16: + numConfigs = 1; + if (RADEON_USE_ACCUM) numConfigs *= 2; + if (RADEON_USE_STENCIL) numConfigs *= 2; + if (use_db) numConfigs *= 2; + + if (!(pConfigs + = (__GLXvisualConfig *)xcalloc(sizeof(__GLXvisualConfig), + numConfigs))) { + return FALSE; + } + if (!(pRADEONConfigs + = (RADEONConfigPrivPtr)xcalloc(sizeof(RADEONConfigPrivRec), + numConfigs))) { + xfree(pConfigs); + return FALSE; + } + if (!(pRADEONConfigPtrs + = (RADEONConfigPrivPtr *)xcalloc(sizeof(RADEONConfigPrivPtr), + numConfigs))) { + xfree(pConfigs); + xfree(pRADEONConfigs); + return FALSE; + } + + i = 0; + for (db = 0; db <= use_db; db++) { + for (accum = 0; accum <= RADEON_USE_ACCUM; accum++) { + for (stencil = 0; stencil <= RADEON_USE_STENCIL; stencil++) { + pRADEONConfigPtrs[i] = &pRADEONConfigs[i]; + + pConfigs[i].vid = (VisualID)(-1); + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 5; + pConfigs[i].greenSize = 6; + pConfigs[i].blueSize = 5; + pConfigs[i].alphaSize = 0; + pConfigs[i].redMask = 0x0000F800; + pConfigs[i].greenMask = 0x000007E0; + pConfigs[i].blueMask = 0x0000001F; + pConfigs[i].alphaMask = 0x00000000; + if (accum) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 0; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + if (db) + pConfigs[i].doubleBuffer = TRUE; + else + pConfigs[i].doubleBuffer = FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 16; + pConfigs[i].depthSize = 16; + if (stencil) + pConfigs[i].stencilSize = 8; + else + pConfigs[i].stencilSize = 0; + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (accum) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + + case 32: + numConfigs = 1; + if (RADEON_USE_ACCUM) numConfigs *= 2; + if (RADEON_USE_STENCIL) numConfigs *= 2; + if (use_db) numConfigs *= 2; + + if (!(pConfigs + = (__GLXvisualConfig *)xcalloc(sizeof(__GLXvisualConfig), + numConfigs))) { + return FALSE; + } + if (!(pRADEONConfigs + = (RADEONConfigPrivPtr)xcalloc(sizeof(RADEONConfigPrivRec), + numConfigs))) { + xfree(pConfigs); + return FALSE; + } + if (!(pRADEONConfigPtrs + = (RADEONConfigPrivPtr *)xcalloc(sizeof(RADEONConfigPrivPtr), + numConfigs))) { + xfree(pConfigs); + xfree(pRADEONConfigs); + return FALSE; + } + + i = 0; + for (db = 0; db <= use_db; db++) { + for (accum = 0; accum <= RADEON_USE_ACCUM; accum++) { + for (stencil = 0; stencil <= RADEON_USE_STENCIL; stencil++) { + pRADEONConfigPtrs[i] = &pRADEONConfigs[i]; + + pConfigs[i].vid = (VisualID)(-1); + pConfigs[i].class = -1; + pConfigs[i].rgba = TRUE; + pConfigs[i].redSize = 8; + pConfigs[i].greenSize = 8; + pConfigs[i].blueSize = 8; + pConfigs[i].alphaSize = 8; + pConfigs[i].redMask = 0x00FF0000; + pConfigs[i].greenMask = 0x0000FF00; + pConfigs[i].blueMask = 0x000000FF; + pConfigs[i].alphaMask = 0xFF000000; + if (accum) { /* Simulated in software */ + pConfigs[i].accumRedSize = 16; + pConfigs[i].accumGreenSize = 16; + pConfigs[i].accumBlueSize = 16; + pConfigs[i].accumAlphaSize = 16; + } else { + pConfigs[i].accumRedSize = 0; + pConfigs[i].accumGreenSize = 0; + pConfigs[i].accumBlueSize = 0; + pConfigs[i].accumAlphaSize = 0; + } + if (db) + pConfigs[i].doubleBuffer = TRUE; + else + pConfigs[i].doubleBuffer = FALSE; + pConfigs[i].stereo = FALSE; + pConfigs[i].bufferSize = 32; + if (stencil) { + pConfigs[i].depthSize = 24; + pConfigs[i].stencilSize = 8; + } else { + pConfigs[i].depthSize = 24; + pConfigs[i].stencilSize = 0; + } + pConfigs[i].auxBuffers = 0; + pConfigs[i].level = 0; + if (accum) { + pConfigs[i].visualRating = GLX_SLOW_CONFIG; + } else { + pConfigs[i].visualRating = GLX_NONE; + } + pConfigs[i].transparentPixel = GLX_NONE; + pConfigs[i].transparentRed = 0; + pConfigs[i].transparentGreen = 0; + pConfigs[i].transparentBlue = 0; + pConfigs[i].transparentAlpha = 0; + pConfigs[i].transparentIndex = 0; + i++; + } + } + } + break; + } + + info->numVisualConfigs = numConfigs; + info->pVisualConfigs = pConfigs; + info->pVisualConfigsPriv = pRADEONConfigs; + GlxSetVisualConfigs(numConfigs, pConfigs, (void**)pRADEONConfigPtrs); + return TRUE; +} + +/* Create the Radeon-specific context information */ +static Bool RADEONCreateContext(ScreenPtr pScreen, VisualPtr visual, + drmContext hwContext, void *pVisualConfigPriv, + DRIContextType contextStore) +{ +#ifdef PER_CONTEXT_SAREA + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONDRIContextPtr ctx_info; + + ctx_info = (RADEONDRIContextPtr)contextStore; + if (!ctx_info) return FALSE; + + if (drmAddMap(info->drmFD, 0, + info->perctx_sarea_size, + DRM_SHM, + DRM_REMOVABLE, + &ctx_info->sarea_handle) < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] could not create private sarea for ctx id (%d)\n", + (int)hwContext); + return FALSE; + } + + if (drmAddContextPrivateMapping(info->drmFD, hwContext, + ctx_info->sarea_handle) < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] could not associate private sarea to ctx id (%d)\n", + (int)hwContext); + drmRmMap(info->drmFD, ctx_info->sarea_handle); + return FALSE; + } + + ctx_info->ctx_id = hwContext; +#endif + return TRUE; +} + +/* Destroy the Radeon-specific context information */ +static void RADEONDestroyContext(ScreenPtr pScreen, drmContext hwContext, + DRIContextType contextStore) +{ +#ifdef PER_CONTEXT_SAREA + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONDRIContextPtr ctx_info; + + ctx_info = (RADEONDRIContextPtr)contextStore; + if (!ctx_info) return; + + if (drmRmMap(info->drmFD, ctx_info->sarea_handle) < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[dri] could not remove private sarea for ctx id (%d)\n", + (int)hwContext); + } +#endif +} + +/* Called when the X server is woken up to allow the last client's + * context to be saved and the X server's context to be loaded. This is + * not necessary for the Radeon since the client detects when it's + * context is not currently loaded and then load's it itself. Since the + * registers to start and stop the CP are privileged, only the X server + * can start/stop the engine. + */ +static void RADEONEnterServer(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->accel) info->accel->NeedToSync = TRUE; +} + +/* Called when the X server goes to sleep to allow the X server's + * context to be saved and the last client's context to be loaded. This + * is not necessary for the Radeon since the client detects when it's + * context is not currently loaded and then load's it itself. Since the + * registers to start and stop the CP are privileged, only the X server + * can start/stop the engine. + */ +static void RADEONLeaveServer(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + RING_LOCALS; + + /* The CP is always running, but if we've generated any CP commands + * we must flush them to the kernel module now. + */ + if (info->CPInUse) { + RADEON_FLUSH_CACHE(); + RADEON_WAIT_UNTIL_IDLE(); + RADEONCPReleaseIndirect(pScrn); + + info->CPInUse = FALSE; + } +} + +/* Contexts can be swapped by the X server if necessary. This callback + * is currently only used to perform any functions necessary when + * entering or leaving the X server, and in the future might not be + * necessary. + */ +static void RADEONDRISwapContext(ScreenPtr pScreen, DRISyncType syncType, + DRIContextType oldContextType, + void *oldContext, + DRIContextType newContextType, + void *newContext) +{ + if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) && + (newContextType==DRI_2D_CONTEXT)) { /* Entering from Wakeup */ + RADEONEnterServer(pScreen); + } + + if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) && + (newContextType==DRI_2D_CONTEXT)) { /* Exiting from Block Handler */ + RADEONLeaveServer(pScreen); + } +} + +/* The Radeon has depth tiling on all the time, so we have to convert + * the x,y coordinates into the memory bus address (mba) in the same + * manner as the engine. In each case, the linear block address (ba) + * is calculated, and then wired with x and y to produce the final + * memory address. + */ +static CARD32 radeon_mba_z16(RADEONInfoPtr info, int x, int y) +{ + CARD32 pitch = info->frontPitch; + CARD32 address = 0; /* a[0] = 0 */ + CARD32 ba; + + ba = (y / 16) * (pitch / 32) + (x / 32); + + address |= (x & 0x7) << 1; /* a[1..3] = x[0..2] */ + address |= (y & 0x7) << 4; /* a[4..6] = y[0..2] */ + address |= (x & 0x8) << 4; /* a[7] = x[3] */ + address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ + address |= (y & 0x8) << 7; /* a[10] = y[3] */ + address |= ((x & 0x10) ^ (y & 0x10)) << 7; /* a[11] = x[4] ^ y[4] */ + address |= (ba & ~0x3u) << 10; /* a[12..] = ba[2..] */ + + return address; +} + +static CARD32 radeon_mba_z32(RADEONInfoPtr info, int x, int y) +{ + CARD32 pitch = info->frontPitch; + CARD32 address = 0; /* a[0..1] = 0 */ + CARD32 ba; + + ba = (y / 16) * (pitch / 16) + (x / 16); + + address |= (x & 0x7) << 2; /* a[2..4] = x[0..2] */ + address |= (y & 0x3) << 5; /* a[5..6] = y[0..1] */ + address |= + (((x & 0x10) >> 2) ^ (y & 0x4)) << 5; /* a[7] = x[4] ^ y[2] */ + address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ + + address |= (y & 0x8) << 7; /* a[10] = y[3] */ + address |= + (((x & 0x8) << 1) ^ (y & 0x10)) << 7; /* a[11] = x[3] ^ y[4] */ + address |= (ba & ~0x3u) << 10; /* a[12..] = ba[2..] */ + + return address; +} + +/* 16-bit depth buffer functions */ +#define WRITE_DEPTH16(_x, _y, d) \ + *(CARD16 *)(pointer)(buf + radeon_mba_z16(info, (_x), (_y))) = (d) + +#define READ_DEPTH16(d, _x, _y) \ + (d) = *(CARD16 *)(pointer)(buf + radeon_mba_z16(info, (_x), (_y))) + +/* 24 bit depth, 8 bit stencil depthbuffer functions */ +#define WRITE_DEPTH32(_x, _y, d) \ +do { \ + CARD32 tmp = \ + *(CARD32 *)(pointer)(buf + radeon_mba_z32(info, (_x), (_y))); \ + tmp &= 0xff000000; \ + tmp |= ((d) & 0x00ffffff); \ + *(CARD32 *)(pointer)(buf + radeon_mba_z32(info, (_x), (_y))) = tmp; \ +} while (0) + +#define READ_DEPTH32(d, _x, _y) \ + d = (*(CARD32 *)(pointer)(buf + radeon_mba_z32(info, (_x), (_y))) \ + & 0x00ffffff) + +/* Screen to screen copy of data in the depth buffer */ +static void RADEONScreenToScreenCopyDepth(ScrnInfoPtr pScrn, + int xa, int ya, + int xb, int yb, + int w, int h) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *buf = info->FB + info->depthOffset; + int xstart, xend, xdir; + int ystart, yend, ydir; + int x, y, d; + + if (xa < xb) xdir = -1, xstart = w-1, xend = 0; + else xdir = 1, xstart = 0, xend = w-1; + + if (ya < yb) ydir = -1, ystart = h-1, yend = 0; + else ydir = 1, ystart = 0, yend = h-1; + + switch (pScrn->bitsPerPixel) { + case 16: + for (x = xstart; x != xend; x += xdir) { + for (y = ystart; y != yend; y += ydir) { + READ_DEPTH16(d, xa+x, ya+y); + WRITE_DEPTH16(xb+x, yb+y, d); + } + } + break; + + case 32: + for (x = xstart; x != xend; x += xdir) { + for (y = ystart; y != yend; y += ydir) { + READ_DEPTH32(d, xa+x, ya+y); + WRITE_DEPTH32(xb+x, yb+y, d); + } + } + break; + + default: + break; + } +} + +/* Initialize the state of the back and depth buffers */ +static void RADEONDRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 indx) +{ + /* NOOP. There's no need for the 2d driver to be clearing buffers + * for the 3d client. It knows how to do that on its own. + */ +} + +/* Copy the back and depth buffers when the X server moves a window. + * + * This routine is a modified form of XAADoBitBlt with the calls to + * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source + * instead of destination. My origin is upside down so the ydir cases + * are reversed. + */ +static void RADEONDRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg, + RegionPtr prgnSrc, CARD32 indx) +{ + ScreenPtr pScreen = pParent->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + BoxPtr pboxTmp, pboxNext, pboxBase; + DDXPointPtr pptTmp; + int xdir, ydir; + + int screenwidth = pScrn->virtualX; + int screenheight = pScrn->virtualY; + + BoxPtr pbox = REGION_RECTS(prgnSrc); + int nbox = REGION_NUM_RECTS(prgnSrc); + + BoxPtr pboxNew1 = NULL; + BoxPtr pboxNew2 = NULL; + DDXPointPtr pptNew1 = NULL; + DDXPointPtr pptNew2 = NULL; + DDXPointPtr pptSrc = &ptOldOrg; + + int dx = pParent->drawable.x - ptOldOrg.x; + int dy = pParent->drawable.y - ptOldOrg.y; + + /* If the copy will overlap in Y, reverse the order */ + if (dy > 0) { + ydir = -1; + + if (nbox > 1) { + /* Keep ordering in each band, reverse order of bands */ + pboxNew1 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); + if (!pboxNew1) return; + + pptNew1 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); + if (!pptNew1) { + DEALLOCATE_LOCAL(pboxNew1); + return; + } + + pboxBase = pboxNext = pbox+nbox-1; + + while (pboxBase >= pbox) { + while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1)) + pboxNext--; + + pboxTmp = pboxNext+1; + pptTmp = pptSrc + (pboxTmp - pbox); + + while (pboxTmp <= pboxBase) { + *pboxNew1++ = *pboxTmp++; + *pptNew1++ = *pptTmp++; + } + + pboxBase = pboxNext; + } + + pboxNew1 -= nbox; + pbox = pboxNew1; + pptNew1 -= nbox; + pptSrc = pptNew1; + } + } else { + /* No changes required */ + ydir = 1; + } + + /* If the regions will overlap in X, reverse the order */ + if (dx > 0) { + xdir = -1; + + if (nbox > 1) { + /* reverse order of rects in each band */ + pboxNew2 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec)*nbox); + pptNew2 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec)*nbox); + + if (!pboxNew2 || !pptNew2) { + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + return; + } + + pboxBase = pboxNext = pbox; + + while (pboxBase < pbox+nbox) { + while ((pboxNext < pbox+nbox) + && (pboxNext->y1 == pboxBase->y1)) + pboxNext++; + + pboxTmp = pboxNext; + pptTmp = pptSrc + (pboxTmp - pbox); + + while (pboxTmp != pboxBase) { + *pboxNew2++ = *--pboxTmp; + *pptNew2++ = *--pptTmp; + } + + pboxBase = pboxNext; + } + + pboxNew2 -= nbox; + pbox = pboxNew2; + pptNew2 -= nbox; + pptSrc = pptNew2; + } + } else { + /* No changes are needed */ + xdir = 1; + } + + (*info->accel->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, GXcopy, + (CARD32)(-1), -1); + + for (; nbox-- ; pbox++) { + int xa = pbox->x1; + int ya = pbox->y1; + int destx = xa + dx; + int desty = ya + dy; + int w = pbox->x2 - xa + 1; + int h = pbox->y2 - ya + 1; + + if (destx < 0) xa -= destx, w += destx, destx = 0; + if (desty < 0) ya -= desty, h += desty, desty = 0; + if (destx + w > screenwidth) w = screenwidth - destx; + if (desty + h > screenheight) h = screenheight - desty; + + if (w <= 0) continue; + if (h <= 0) continue; + + RADEONSelectBuffer(pScrn, RADEON_BACK); + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, + xa, ya, + destx, desty, + w, h); + + if (info->depthMoves) { + RADEONSelectBuffer(pScrn, RADEON_DEPTH); + RADEONScreenToScreenCopyDepth(pScrn, + xa, ya, + destx, desty, + w, h); + } + } + + RADEONSelectBuffer(pScrn, RADEON_FRONT); + + DEALLOCATE_LOCAL(pptNew2); + DEALLOCATE_LOCAL(pboxNew2); + DEALLOCATE_LOCAL(pptNew1); + DEALLOCATE_LOCAL(pboxNew1); + + info->accel->NeedToSync = TRUE; +} + +static void RADEONDRIInitGARTValues(RADEONInfoPtr info) +{ + int s, l; + + info->gartOffset = 0; + + /* Initialize the CP ring buffer data */ + info->ringStart = info->gartOffset; + info->ringMapSize = info->ringSize*1024*1024 + DRM_PAGE_SIZE; + info->ringSizeLog2QW = RADEONMinBits(info->ringSize*1024*1024/8)-1; + + info->ringReadOffset = info->ringStart + info->ringMapSize; + info->ringReadMapSize = DRM_PAGE_SIZE; + + /* Reserve space for vertex/indirect buffers */ + info->bufStart = info->ringReadOffset + info->ringReadMapSize; + info->bufMapSize = info->bufSize*1024*1024; + + /* Reserve the rest for GART textures */ + info->gartTexStart = info->bufStart + info->bufMapSize; + s = (info->gartSize*1024*1024 - info->gartTexStart); + l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS); + if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY; + info->gartTexMapSize = (s >> l) << l; + info->log2GARTTexGran = l; +} + +/* Set AGP transfer mode according to requests and constraints */ +static Bool RADEONSetAgpMode(RADEONInfoPtr info, ScreenPtr pScreen) +{ + unsigned char *RADEONMMIO = info->MMIO; + unsigned long mode = drmAgpGetMode(info->drmFD); /* Default mode */ + unsigned int vendor = drmAgpVendorId(info->drmFD); + unsigned int device = drmAgpDeviceId(info->drmFD); + + mode &= ~RADEON_AGP_MODE_MASK; + switch (info->agpMode) { + case 4: mode |= RADEON_AGP_4X_MODE; + case 2: mode |= RADEON_AGP_2X_MODE; + case 1: default: mode |= RADEON_AGP_1X_MODE; + } + + if (info->agpFastWrite) mode |= RADEON_AGP_FW_MODE; + + if ((vendor == PCI_VENDOR_AMD) && + (device == PCI_CHIP_AMD761)) { + + /* Disable fast write for AMD 761 chipset, since they cause + * lockups when enabled. + */ + mode &= ~0x10; /* FIXME: Magic number */ + } + + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", + mode, vendor, device, + info->PciInfo->vendor, + info->PciInfo->chipType); + + if (drmAgpEnable(info->drmFD, mode) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] AGP not enabled\n"); + drmAgpRelease(info->drmFD); + return FALSE; + } + + /* Workaround for some hardware bugs */ + if (info->ChipFamily < CHIP_FAMILY_R200) + OUTREG(RADEON_AGP_CNTL, INREG(RADEON_AGP_CNTL) | 0x000e0000); + + /* Modify the mode if the default mode + * is not appropriate for this + * particular combination of graphics + * card and AGP chipset. + */ + + return TRUE; +} + +/* Initialize Radeon's AGP registers */ +static void RADEONSetAgpBase(RADEONInfoPtr info) +{ + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_AGP_BASE, drmAgpBase(info->drmFD)); +} + +/* Initialize the AGP state. Request memory for use in AGP space, and + * initialize the Radeon registers to point to that memory. + */ +static Bool RADEONDRIAgpInit(RADEONInfoPtr info, ScreenPtr pScreen) +{ + int ret; + + if (drmAgpAcquire(info->drmFD) < 0) { + xf86DrvMsg(pScreen->myNum, X_WARNING, "[agp] AGP not available\n"); + return FALSE; + } + + if (!RADEONSetAgpMode(info, pScreen)) + return FALSE; + + RADEONDRIInitGARTValues(info); + + if ((ret = drmAgpAlloc(info->drmFD, info->gartSize*1024*1024, 0, NULL, + &info->agpMemHandle)) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Out of memory (%d)\n", ret); + drmAgpRelease(info->drmFD); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] %d kB allocated with handle 0x%08lx\n", + info->gartSize*1024, info->agpMemHandle); + + if (drmAgpBind(info->drmFD, + info->agpMemHandle, info->gartOffset) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not bind\n"); + drmAgpFree(info->drmFD, info->agpMemHandle); + drmAgpRelease(info->drmFD); + return FALSE; + } + + if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize, + DRM_AGP, DRM_READ_ONLY, &info->ringHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add ring mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] ring handle = 0x%08lx\n", info->ringHandle); + + if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize, + (drmAddressPtr)&info->ring) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Could not map ring\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Ring mapped at 0x%08lx\n", + (unsigned long)info->ring); + + if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize, + DRM_AGP, DRM_READ_ONLY, &info->ringReadPtrHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add ring read ptr mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] ring read ptr handle = 0x%08lx\n", + info->ringReadPtrHandle); + + if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, + (drmAddressPtr)&info->ringReadPtr) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map ring read ptr\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Ring read ptr mapped at 0x%08lx\n", + (unsigned long)info->ringReadPtr); + + if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize, + DRM_AGP, 0, &info->bufHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add vertex/indirect buffers mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] vertex/indirect buffers handle = 0x%08lx\n", + info->bufHandle); + + if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize, + (drmAddressPtr)&info->buf) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map vertex/indirect buffers\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] Vertex/indirect buffers mapped at 0x%08lx\n", + (unsigned long)info->buf); + + if (drmAddMap(info->drmFD, info->gartTexStart, info->gartTexMapSize, + DRM_AGP, 0, &info->gartTexHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not add GART texture map mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] GART texture map handle = 0x%08lx\n", + info->gartTexHandle); + + if (drmMap(info->drmFD, info->gartTexHandle, info->gartTexMapSize, + (drmAddressPtr)&info->gartTex) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[agp] Could not map GART texture map\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[agp] GART Texture map mapped at 0x%08lx\n", + (unsigned long)info->gartTex); + + RADEONSetAgpBase(info); + + return TRUE; +} + +/* Initialize the PCI GART state. Request memory for use in PCI space, + * and initialize the Radeon registers to point to that memory. + */ +static Bool RADEONDRIPciInit(RADEONInfoPtr info, ScreenPtr pScreen) +{ + int ret; + int flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL; + + ret = drmScatterGatherAlloc(info->drmFD, info->gartSize*1024*1024, + &info->pciMemHandle); + if (ret < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Out of memory (%d)\n", ret); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] %d kB allocated with handle 0x%08lx\n", + info->gartSize*1024, info->pciMemHandle); + + RADEONDRIInitGARTValues(info); + + if (drmAddMap(info->drmFD, info->ringStart, info->ringMapSize, + DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not add ring mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] ring handle = 0x%08lx\n", info->ringHandle); + + if (drmMap(info->drmFD, info->ringHandle, info->ringMapSize, + (drmAddressPtr)&info->ring) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, "[pci] Could not map ring\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring mapped at 0x%08lx\n", + (unsigned long)info->ring); + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring contents 0x%08lx\n", + *(unsigned long *)(pointer)info->ring); + + if (drmAddMap(info->drmFD, info->ringReadOffset, info->ringReadMapSize, + DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not add ring read ptr mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] ring read ptr handle = 0x%08lx\n", + info->ringReadPtrHandle); + + if (drmMap(info->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, + (drmAddressPtr)&info->ringReadPtr) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not map ring read ptr\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring read ptr mapped at 0x%08lx\n", + (unsigned long)info->ringReadPtr); + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Ring read ptr contents 0x%08lx\n", + *(unsigned long *)(pointer)info->ringReadPtr); + + if (drmAddMap(info->drmFD, info->bufStart, info->bufMapSize, + DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not add vertex/indirect buffers mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] vertex/indirect buffers handle = 0x%08lx\n", + info->bufHandle); + + if (drmMap(info->drmFD, info->bufHandle, info->bufMapSize, + (drmAddressPtr)&info->buf) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not map vertex/indirect buffers\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Vertex/indirect buffers mapped at 0x%08lx\n", + (unsigned long)info->buf); + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] Vertex/indirect buffers contents 0x%08lx\n", + *(unsigned long *)(pointer)info->buf); + + if (drmAddMap(info->drmFD, info->gartTexStart, info->gartTexMapSize, + DRM_SCATTER_GATHER, 0, &info->gartTexHandle) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not add GART texture map mapping\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] GART texture map handle = 0x%08lx\n", + info->gartTexHandle); + + if (drmMap(info->drmFD, info->gartTexHandle, info->gartTexMapSize, + (drmAddressPtr)&info->gartTex) < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[pci] Could not map GART texture map\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[pci] GART Texture map mapped at 0x%08lx\n", + (unsigned long)info->gartTex); + + return TRUE; +} + +/* Add a map for the MMIO registers that will be accessed by any + * DRI-based clients. + */ +static Bool RADEONDRIMapInit(RADEONInfoPtr info, ScreenPtr pScreen) +{ + /* Map registers */ + info->registerSize = RADEON_MMIOSIZE; + if (drmAddMap(info->drmFD, info->MMIOAddr, info->registerSize, + DRM_REGISTERS, DRM_READ_ONLY, &info->registerHandle) < 0) { + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] register handle = 0x%08lx\n", info->registerHandle); + + return TRUE; +} + +/* Initialize the kernel data structures */ +static int RADEONDRIKernelInit(RADEONInfoPtr info, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + int cpp = info->CurrentLayout.pixel_bytes; + drmRadeonInit drmInfo; + + memset(&drmInfo, 0, sizeof(drmRadeonInit)); + + if ((info->ChipFamily == CHIP_FAMILY_R200) || + (info->ChipFamily == CHIP_FAMILY_RV250) || + (info->ChipFamily == CHIP_FAMILY_RV280) ) + drmInfo.func = DRM_RADEON_INIT_R200_CP; + else + drmInfo.func = DRM_RADEON_INIT_CP; + + drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec); + drmInfo.is_pci = info->IsPCI; + drmInfo.cp_mode = info->CPMode; + drmInfo.gart_size = info->gartSize*1024*1024; + drmInfo.ring_size = info->ringSize*1024*1024; + drmInfo.usec_timeout = info->CPusecTimeout; + + drmInfo.fb_bpp = info->CurrentLayout.pixel_code; + drmInfo.depth_bpp = info->CurrentLayout.pixel_code; + + drmInfo.front_offset = info->frontOffset; + drmInfo.front_pitch = info->frontPitch * cpp; + drmInfo.back_offset = info->backOffset; + drmInfo.back_pitch = info->backPitch * cpp; + drmInfo.depth_offset = info->depthOffset; + drmInfo.depth_pitch = info->depthPitch * cpp; + + drmInfo.fb_offset = info->fbHandle; + drmInfo.mmio_offset = info->registerHandle; + drmInfo.ring_offset = info->ringHandle; + drmInfo.ring_rptr_offset = info->ringReadPtrHandle; + drmInfo.buffers_offset = info->bufHandle; + drmInfo.gart_textures_offset= info->gartTexHandle; + + if (drmCommandWrite(info->drmFD, DRM_RADEON_CP_INIT, + &drmInfo, sizeof(drmRadeonInit)) < 0) + return FALSE; + + /* DRM_RADEON_CP_INIT does an engine reset, which resets some engine + * registers back to their default values, so we need to restore + * those engine register here. + */ + RADEONEngineRestore(pScrn); + + return TRUE; +} + +static void RADEONDRIGartHeapInit(RADEONInfoPtr info, ScreenPtr pScreen) +{ + drmRadeonMemInitHeap drmHeap; + + /* Start up the simple memory manager for GART space */ + if (info->drmMinor >= 6) { + drmHeap.region = RADEON_MEM_REGION_GART; + drmHeap.start = 0; + drmHeap.size = info->gartTexMapSize; + + if (drmCommandWrite(info->drmFD, DRM_RADEON_INIT_HEAP, + &drmHeap, sizeof(drmHeap))) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Failed to initialize GART heap manager\n"); + } else { + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Initialized kernel GART heap manager, %d\n", + info->gartTexMapSize); + } + } else { + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Kernel module too old (1.%d) for GART heap manager\n", + info->drmMinor); + } +} + +/* Add a map for the vertex buffers that will be accessed by any + * DRI-based clients. + */ +static Bool RADEONDRIBufInit(RADEONInfoPtr info, ScreenPtr pScreen) +{ + /* Initialize vertex buffers */ + info->bufNumBufs = drmAddBufs(info->drmFD, + info->bufMapSize / RADEON_BUFFER_SIZE, + RADEON_BUFFER_SIZE, + info->IsPCI ? DRM_SG_BUFFER : DRM_AGP_BUFFER, + info->bufStart); + + if (info->bufNumBufs <= 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Could not create vertex/indirect buffers list\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Added %d %d byte vertex/indirect buffers\n", + info->bufNumBufs, RADEON_BUFFER_SIZE); + + if (!(info->buffers = drmMapBufs(info->drmFD))) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[drm] Failed to map vertex/indirect buffers list\n"); + return FALSE; + } + xf86DrvMsg(pScreen->myNum, X_INFO, + "[drm] Mapped %d vertex/indirect buffers\n", + info->buffers->count); + + return TRUE; +} + +static void RADEONDRIIrqInit(RADEONInfoPtr info, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (!info->irq) { + info->irq = drmGetInterruptFromBusID( + info->drmFD, + ((pciConfigPtr)info->PciInfo->thisCard)->busnum, + ((pciConfigPtr)info->PciInfo->thisCard)->devnum, + ((pciConfigPtr)info->PciInfo->thisCard)->funcnum); + + if ((drmCtlInstHandler(info->drmFD, info->irq)) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] failure adding irq handler, " + "there is a device already using that irq\n" + "[drm] falling back to irq-free operation\n"); + info->irq = 0; + } else { + unsigned char *RADEONMMIO = info->MMIO; + info->ModeReg.gen_int_cntl = INREG( RADEON_GEN_INT_CNTL ); + } + } + + if (info->irq) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "[drm] dma control initialized, using IRQ %d\n", + info->irq); +} + + +/* Initialize the CP state, and start the CP (if used by the X server) */ +static void RADEONDRICPInit(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + /* Turn on bus mastering */ + info->BusCntl &= ~RADEON_BUS_MASTER_DIS; + + /* Make sure the CP is on for the X server */ + RADEONCP_START(pScrn, info); + RADEONSelectBuffer(pScrn, RADEON_FRONT); +} + + +/* Initialize the screen-specific data structures for the DRI and the + * Radeon. This is the main entry point to the device-specific + * initialization code. It calls device-independent DRI functions to + * create the DRI data structures and initialize the DRI state. + */ +Bool RADEONDRIScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + DRIInfoPtr pDRIInfo; + RADEONDRIPtr pRADEONDRI; + int major, minor, patch; + drmVersionPtr version; + + /* Check that the GLX, DRI, and DRM modules have been loaded by testing + * for known symbols in each module. + */ + if (!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) return FALSE; + if (!xf86LoaderCheckSymbol("DRIScreenInit")) return FALSE; + if (!xf86LoaderCheckSymbol("drmAvailable")) return FALSE; + if (!xf86LoaderCheckSymbol("DRIQueryVersion")) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] RADEONDRIScreenInit failed (libdri.a too old)\n"); + return FALSE; + } + + /* Check the DRI version */ + DRIQueryVersion(&major, &minor, &patch); + if (major != 4 || minor < 0) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] RADEONDRIScreenInit failed because of a version " + "mismatch.\n" + "[dri] libDRI version is %d.%d.%d but version 4.0.x is " + "needed.\n" + "[dri] Disabling DRI.\n", + major, minor, patch); + return FALSE; + } + + switch (info->CurrentLayout.pixel_code) { + case 8: + case 15: + case 24: + /* These modes are not supported (yet). */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] RADEONInitVisualConfigs failed " + "(depth %d not supported). " + "Disabling DRI.\n", info->CurrentLayout.pixel_code); + return FALSE; + + /* Only 16 and 32 color depths are supports currently. */ + case 16: + case 32: + break; + } + + /* Create the DRI data structure, and fill it in before calling the + * DRIScreenInit(). + */ + if (!(pDRIInfo = DRICreateInfoRec())) return FALSE; + + info->pDRIInfo = pDRIInfo; + pDRIInfo->drmDriverName = RADEON_DRIVER_NAME; + + if ( (info->ChipFamily == CHIP_FAMILY_R200) || + (info->ChipFamily == CHIP_FAMILY_RV250) || + (info->ChipFamily == CHIP_FAMILY_RV280) ) + pDRIInfo->clientDriverName = R200_DRIVER_NAME; + else + pDRIInfo->clientDriverName = RADEON_DRIVER_NAME; + + pDRIInfo->busIdString = xalloc(64); + sprintf(pDRIInfo->busIdString, + "PCI:%d:%d:%d", + info->PciInfo->bus, + info->PciInfo->device, + info->PciInfo->func); + pDRIInfo->ddxDriverMajorVersion = RADEON_VERSION_MAJOR; + pDRIInfo->ddxDriverMinorVersion = RADEON_VERSION_MINOR; + pDRIInfo->ddxDriverPatchVersion = RADEON_VERSION_PATCH; + pDRIInfo->frameBufferPhysicalAddress = info->LinearAddr; + pDRIInfo->frameBufferSize = info->FbMapSize; + pDRIInfo->frameBufferStride = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + pDRIInfo->ddxDrawableTableEntry = RADEON_MAX_DRAWABLES; + pDRIInfo->maxDrawableTableEntry = (SAREA_MAX_DRAWABLES + < RADEON_MAX_DRAWABLES + ? SAREA_MAX_DRAWABLES + : RADEON_MAX_DRAWABLES); + +#ifdef PER_CONTEXT_SAREA + /* This is only here for testing per-context SAREAs. When used, the + magic number below would be properly defined in a header file. */ + info->perctx_sarea_size = 64 * 1024; +#endif + +#ifdef NOT_DONE + /* FIXME: Need to extend DRI protocol to pass this size back to + * client for SAREA mapping that includes a device private record + */ + pDRIInfo->SAREASize = ((sizeof(XF86DRISAREARec) + 0xfff) + & 0x1000); /* round to page */ + /* + shared memory device private rec */ +#else + /* For now the mapping works by using a fixed size defined + * in the SAREA header + */ + if (sizeof(XF86DRISAREARec)+sizeof(RADEONSAREAPriv) > SAREA_MAX) { + ErrorF("Data does not fit in SAREA\n"); + return FALSE; + } + pDRIInfo->SAREASize = SAREA_MAX; +#endif + + if (!(pRADEONDRI = (RADEONDRIPtr)xcalloc(sizeof(RADEONDRIRec),1))) { + DRIDestroyInfoRec(info->pDRIInfo); + info->pDRIInfo = NULL; + return FALSE; + } + pDRIInfo->devPrivate = pRADEONDRI; + pDRIInfo->devPrivateSize = sizeof(RADEONDRIRec); + pDRIInfo->contextSize = sizeof(RADEONDRIContextRec); + + pDRIInfo->CreateContext = RADEONCreateContext; + pDRIInfo->DestroyContext = RADEONDestroyContext; + pDRIInfo->SwapContext = RADEONDRISwapContext; + pDRIInfo->InitBuffers = RADEONDRIInitBuffers; + pDRIInfo->MoveBuffers = RADEONDRIMoveBuffers; + pDRIInfo->bufferRequests = DRI_ALL_WINDOWS; + pDRIInfo->OpenFullScreen = RADEONDRIOpenFullScreen; + pDRIInfo->CloseFullScreen = RADEONDRICloseFullScreen; + pDRIInfo->TransitionTo2d = RADEONDRITransitionTo2d; + pDRIInfo->TransitionTo3d = RADEONDRITransitionTo3d; + pDRIInfo->TransitionSingleToMulti3D = RADEONDRITransitionSingleToMulti3d; + pDRIInfo->TransitionMultiToSingle3D = RADEONDRITransitionMultiToSingle3d; + + pDRIInfo->createDummyCtx = TRUE; + pDRIInfo->createDummyCtxPriv = FALSE; + + if (!DRIScreenInit(pScreen, pDRIInfo, &info->drmFD)) { + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] DRIScreenInit failed. Disabling DRI.\n"); + xfree(pDRIInfo->devPrivate); + pDRIInfo->devPrivate = NULL; + DRIDestroyInfoRec(pDRIInfo); + pDRIInfo = NULL; + return FALSE; + } + + /* Check the DRM lib version. + * drmGetLibVersion was not supported in version 1.0, so check for + * symbol first to avoid possible crash or hang. + */ + if (xf86LoaderCheckSymbol("drmGetLibVersion")) { + version = drmGetLibVersion(info->drmFD); + } else { + /* drmlib version 1.0.0 didn't have the drmGetLibVersion + * entry point. Fake it by allocating a version record + * via drmGetVersion and changing it to version 1.0.0. + */ + version = drmGetVersion(info->drmFD); + version->version_major = 1; + version->version_minor = 0; + version->version_patchlevel = 0; + } + + if (version) { + if (version->version_major != 1 || + version->version_minor < 1) { + /* incompatible drm library version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] RADEONDRIScreenInit failed because of a " + "version mismatch.\n" + "[dri] libdrm.a module version is %d.%d.%d but " + "version 1.1.x is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + RADEONDRICloseScreen(pScreen); + return FALSE; + } + drmFreeVersion(version); + } + + /* Check the radeon DRM version */ + version = drmGetVersion(info->drmFD); + if (version) { + int req_minor, req_patch; + + if ((info->ChipFamily == CHIP_FAMILY_R200) || + (info->ChipFamily == CHIP_FAMILY_RV250) || + (info->ChipFamily == CHIP_FAMILY_RV280)) { + req_minor = 5; + req_patch = 0; + } else { +#if X_BYTE_ORDER == X_LITTLE_ENDIAN + req_minor = 1; + req_patch = 0; +#else + req_minor = 2; + req_patch = 1; +#endif + } + + if (version->version_major != 1 || + version->version_minor < req_minor || + (version->version_minor == req_minor && + version->version_patchlevel < req_patch)) { + /* Incompatible drm version */ + xf86DrvMsg(pScreen->myNum, X_ERROR, + "[dri] RADEONDRIScreenInit failed because of a version " + "mismatch.\n" + "[dri] radeon.o kernel module version is %d.%d.%d " + "but version 1.%d.%d or newer is needed.\n" + "[dri] Disabling DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel, + req_minor, + req_patch); + drmFreeVersion(version); + RADEONDRICloseScreen(pScreen); + return FALSE; + } + + if (version->version_minor < 3) { + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[dri] Some DRI features disabled because of version " + "mismatch.\n" + "[dri] radeon.o kernel module version is %d.%d.%d but " + "1.3.1 or later is preferred.\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + } + info->drmMinor = version->version_minor; + drmFreeVersion(version); + } + + /* Initialize AGP */ + if (!info->IsPCI && !RADEONDRIAgpInit(info, pScreen)) { +#if defined(__alpha__) || defined(__powerpc__) + info->IsPCI = TRUE; + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[agp] AGP failed to initialize " + "-- falling back to PCI mode.\n"); + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[agp] If this is an AGP card, you may want to make sure " + "the agpgart\nkernel module is loaded before the radeon " + "kernel module.\n"); +#else + RADEONDRICloseScreen(pScreen); + return FALSE; +#endif + } + + /* Initialize PCI */ + if (info->IsPCI && !RADEONDRIPciInit(info, pScreen)) { + RADEONDRICloseScreen(pScreen); + return FALSE; + } + + /* DRIScreenInit doesn't add all the + * common mappings. Add additional + * mappings here. + */ + if (!RADEONDRIMapInit(info, pScreen)) { + RADEONDRICloseScreen(pScreen); + return FALSE; + } + + /* DRIScreenInit adds the frame buffer + map, but we need it as well */ + { + void *scratch_ptr; + int scratch_int; + + DRIGetDeviceInfo(pScreen, &info->fbHandle, + &scratch_int, &scratch_int, + &scratch_int, &scratch_int, + &scratch_ptr); + } + + /* FIXME: When are these mappings unmapped? */ + + if (!RADEONInitVisualConfigs(pScreen)) { + RADEONDRICloseScreen(pScreen); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[dri] Visual configs initialized\n"); + + return TRUE; +} + +/* Finish initializing the device-dependent DRI state, and call + * DRIFinishScreenInit() to complete the device-independent DRI + * initialization. + */ +Bool RADEONDRIFinishScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONSAREAPrivPtr pSAREAPriv; + RADEONDRIPtr pRADEONDRI; + + info->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT; + /* info->pDRIInfo->driverSwapMethod = DRI_SERVER_SWAP; */ + + /* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit + * because *DRIKernelInit requires that the hardware lock is held by + * the X server, and the first time the hardware lock is grabbed is + * in DRIFinishScreenInit. + */ + if (!DRIFinishScreenInit(pScreen)) { + RADEONDRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize the kernel data structures */ + if (!RADEONDRIKernelInit(info, pScreen)) { + RADEONDRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize the vertex buffers list */ + if (!RADEONDRIBufInit(info, pScreen)) { + RADEONDRICloseScreen(pScreen); + return FALSE; + } + + /* Initialize IRQ */ + RADEONDRIIrqInit(info, pScreen); + + /* Initialize kernel GART memory manager */ + RADEONDRIGartHeapInit(info, pScreen); + + /* Initialize and start the CP if required */ + RADEONDRICPInit(pScrn); + + /* Initialize the SAREA private data structure */ + pSAREAPriv = (RADEONSAREAPrivPtr)DRIGetSAREAPrivate(pScreen); + memset(pSAREAPriv, 0, sizeof(*pSAREAPriv)); + + pRADEONDRI = (RADEONDRIPtr)info->pDRIInfo->devPrivate; + + pRADEONDRI->deviceID = info->Chipset; + pRADEONDRI->width = pScrn->virtualX; + pRADEONDRI->height = pScrn->virtualY; + pRADEONDRI->depth = pScrn->depth; + pRADEONDRI->bpp = pScrn->bitsPerPixel; + + pRADEONDRI->IsPCI = info->IsPCI; + pRADEONDRI->AGPMode = info->agpMode; + + pRADEONDRI->frontOffset = info->frontOffset; + pRADEONDRI->frontPitch = info->frontPitch; + pRADEONDRI->backOffset = info->backOffset; + pRADEONDRI->backPitch = info->backPitch; + pRADEONDRI->depthOffset = info->depthOffset; + pRADEONDRI->depthPitch = info->depthPitch; + pRADEONDRI->textureOffset = info->textureOffset; + pRADEONDRI->textureSize = info->textureSize; + pRADEONDRI->log2TexGran = info->log2TexGran; + + pRADEONDRI->registerHandle = info->registerHandle; + pRADEONDRI->registerSize = info->registerSize; + + pRADEONDRI->statusHandle = info->ringReadPtrHandle; + pRADEONDRI->statusSize = info->ringReadMapSize; + + pRADEONDRI->gartTexHandle = info->gartTexHandle; + pRADEONDRI->gartTexMapSize = info->gartTexMapSize; + pRADEONDRI->log2GARTTexGran = info->log2GARTTexGran; + pRADEONDRI->gartTexOffset = info->gartTexStart; + + pRADEONDRI->sarea_priv_offset = sizeof(XF86DRISAREARec); + +#ifdef PER_CONTEXT_SAREA + /* Set per-context SAREA size */ + pRADEONDRI->perctx_sarea_size = info->perctx_sarea_size; +#endif + + /* Have shadowfb run only while there is 3d active. */ + if (info->allowPageFlip /* && info->drmMinor >= 3 */) { + ShadowFBInit( pScreen, RADEONDRIRefreshArea ); + } else { + info->allowPageFlip = 0; + } + + return TRUE; +} + +/** + * This function will attempt to get the Radeon hardware back into shape + * after a resume from disc. + * + * Charl P. Botha <http://cpbotha.net> + */ +void RADEONDRIResume(ScreenPtr pScreen) +{ + int _ret; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->drmMinor >= 9) { + xf86DrvMsg(pScreen->myNum, X_INFO, + "[RESUME] Attempting to re-init Radeon hardware.\n"); + } else { + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[RESUME] Cannot re-init Radeon hardware, DRM too old\n" + "(need 1.9.0 or newer)\n"); + return; + } + + if (!info->IsPCI) { + if (!RADEONSetAgpMode(info, pScreen)) + return; + + RADEONSetAgpBase(info); + } + + _ret = drmCommandNone(info->drmFD, DRM_RADEON_CP_RESUME); + if (_ret) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "%s: CP resume %d\n", __FUNCTION__, _ret); + /* FIXME: return? */ + } + + RADEONEngineRestore(pScrn); + + RADEONDRICPInit(pScrn); +} + +/* The screen is being closed, so clean up any state and free any + * resources used by the DRI. + */ +void RADEONDRICloseScreen(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + drmRadeonInit drmInfo; + RING_LOCALS; + + /* Stop the CP */ + if (info->directRenderingEnabled) { + /* If we've generated any CP commands, we must flush them to the + * kernel module now. + */ + if (info->CPInUse) { + RADEON_FLUSH_CACHE(); + RADEON_WAIT_UNTIL_IDLE(); + RADEONCPReleaseIndirect(pScrn); + + info->CPInUse = FALSE; + } + RADEONCP_STOP(pScrn, info); + } + + if (info->irq) { + drmCtlUninstHandler(info->drmFD); + info->irq = 0; + info->ModeReg.gen_int_cntl = 0; + } + + /* De-allocate vertex buffers */ + if (info->buffers) { + drmUnmapBufs(info->buffers); + info->buffers = NULL; + } + + /* De-allocate all kernel resources */ + memset(&drmInfo, 0, sizeof(drmRadeonInit)); + drmInfo.func = DRM_RADEON_CLEANUP_CP; + drmCommandWrite(info->drmFD, DRM_RADEON_CP_INIT, + &drmInfo, sizeof(drmRadeonInit)); + + /* De-allocate all GART resources */ + if (info->gartTex) { + drmUnmap(info->gartTex, info->gartTexMapSize); + info->gartTex = NULL; + } + if (info->buf) { + drmUnmap(info->buf, info->bufMapSize); + info->buf = NULL; + } + if (info->ringReadPtr) { + drmUnmap(info->ringReadPtr, info->ringReadMapSize); + info->ringReadPtr = NULL; + } + if (info->ring) { + drmUnmap(info->ring, info->ringMapSize); + info->ring = NULL; + } + if (info->agpMemHandle != DRM_AGP_NO_HANDLE) { + drmAgpUnbind(info->drmFD, info->agpMemHandle); + drmAgpFree(info->drmFD, info->agpMemHandle); + info->agpMemHandle = DRM_AGP_NO_HANDLE; + drmAgpRelease(info->drmFD); + } + if (info->pciMemHandle) { + drmScatterGatherFree(info->drmFD, info->pciMemHandle); + info->pciMemHandle = 0; + } + + /* De-allocate all DRI resources */ + DRICloseScreen(pScreen); + + /* De-allocate all DRI data structures */ + if (info->pDRIInfo) { + if (info->pDRIInfo->devPrivate) { + xfree(info->pDRIInfo->devPrivate); + info->pDRIInfo->devPrivate = NULL; + } + DRIDestroyInfoRec(info->pDRIInfo); + info->pDRIInfo = NULL; + } + if (info->pVisualConfigs) { + xfree(info->pVisualConfigs); + info->pVisualConfigs = NULL; + } + if (info->pVisualConfigsPriv) { + xfree(info->pVisualConfigsPriv); + info->pVisualConfigsPriv = NULL; + } +} + + + +/* Fullscreen hooks. The DRI fullscreen mode can probably be removed as + * it adds little or nothing above the mechanism below (and isn't widely + * used). + */ +static Bool RADEONDRIOpenFullScreen(ScreenPtr pScreen) +{ + return TRUE; +} + +static Bool RADEONDRICloseFullScreen(ScreenPtr pScreen) +{ + return TRUE; +} + + + +/* Use callbacks from dri.c to support pageflipping mode for a single + * 3d context without need for any specific full-screen extension. + * + * Also use these callbacks to allocate and free 3d-specific memory on + * demand. + */ + + +/* Use the shadowfb module to maintain a list of dirty rectangles. + * These are blitted to the back buffer to keep both buffers clean + * during page-flipping when the 3d application isn't fullscreen. + * + * Unlike most use of the shadowfb code, both buffers are in video memory. + * + * An alternative to this would be to organize for all on-screen drawing + * operations to be duplicated for the two buffers. That might be + * faster, but seems like a lot more work... + */ + + +static void RADEONDRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int i; + RADEONSAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + + /* Don't want to do this when no 3d is active and pages are + * right-way-round + */ + if (!pSAREAPriv->pfAllowPageFlip && pSAREAPriv->pfCurrentPage == 0) + return; + + (*info->accel->SetupForScreenToScreenCopy)(pScrn, + 1, 1, GXcopy, + (CARD32)(-1), -1); + + for (i = 0 ; i < num ; i++, pbox++) { + int xa = max(pbox->x1, 0), xb = min(pbox->x2, pScrn->virtualX-1); + int ya = max(pbox->y1, 0), yb = min(pbox->y2, pScrn->virtualY-1); + + if (xa <= xb && ya <= yb) { + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, xa, ya, + xa + info->backX, + ya + info->backY, + xb - xa + 1, + yb - ya + 1); + } + } +} + +static void RADEONEnablePageFlip(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONSAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + if (info->allowPageFlip) { + /* Duplicate the frontbuffer to the backbuffer */ + (*info->accel->SetupForScreenToScreenCopy)(pScrn, + 1, 1, GXcopy, + (CARD32)(-1), -1); + + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, + 0, + 0, + info->backX, + info->backY, + pScrn->virtualX, + pScrn->virtualY); + + pSAREAPriv->pfAllowPageFlip = 1; + } +} + +static void RADEONDisablePageFlip(ScreenPtr pScreen) +{ + /* Tell the clients not to pageflip. How? + * -- Field in sarea, plus bumping the window counters. + * -- DRM needs to cope with Front-to-Back swapbuffers. + */ + RADEONSAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + pSAREAPriv->pfAllowPageFlip = 0; +} + +static void RADEONDRITransitionSingleToMulti3d(ScreenPtr pScreen) +{ + RADEONDisablePageFlip(pScreen); +} + +static void RADEONDRITransitionMultiToSingle3d(ScreenPtr pScreen) +{ + /* Let the remaining 3d app start page flipping again */ + RADEONEnablePageFlip(pScreen); +} + +static void RADEONDRITransitionTo3d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + FBAreaPtr fbarea; + int width, height; + + /* reserve offscreen area for back and depth buffers and textures */ + + /* If we still have an area for the back buffer reserved, free it + * first so we always start with all free offscreen memory, except + * maybe for Xv + */ + if (info->backArea) { + xf86FreeOffscreenArea(info->backArea); + info->backArea = NULL; + } + + xf86PurgeUnlockedOffscreenAreas(pScreen); + + xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0); + + /* Free Xv linear offscreen memory if necessary */ + if (height < (info->depthTexLines + info->backLines)) { + xf86FreeOffscreenLinear(info->videoLinear); + info->videoLinear = NULL; + xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0); + } + + /* Reserve placeholder area so the other areas will match the + * pre-calculated offsets + */ + fbarea = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, + height + - info->depthTexLines + - info->backLines, + pScrn->displayWidth, + NULL, NULL, NULL); + if (!fbarea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve placeholder " + "offscreen area, you might experience screen corruption\n"); + + info->backArea = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, + info->backLines, + pScrn->displayWidth, + NULL, NULL, NULL); + if (!info->backArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen " + "area for back buffer, you might experience screen " + "corruption\n"); + + info->depthTexArea = xf86AllocateOffscreenArea(pScreen, + pScrn->displayWidth, + info->depthTexLines, + pScrn->displayWidth, + NULL, NULL, NULL); + if (!info->depthTexArea) + xf86DrvMsg(pScreen->myNum, X_ERROR, "Unable to reserve offscreen " + "area for depth buffer and textures, you might " + "experience screen corruption\n"); + + xf86FreeOffscreenArea(fbarea); + + RADEONEnablePageFlip(pScreen); + + info->have3DWindows = 1; + + if (info->cursor_start) + xf86ForceHWCursor (pScreen, TRUE); +} + +static void RADEONDRITransitionTo2d(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONSAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); + + /* Shut down shadowing if we've made it back to the front page */ + if (pSAREAPriv->pfCurrentPage == 0) { + RADEONDisablePageFlip(pScreen); + xf86FreeOffscreenArea(info->backArea); + info->backArea = NULL; + } else { + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[dri] RADEONDRITransitionTo2d: " + "kernel failed to unflip buffers.\n"); + } + + xf86FreeOffscreenArea(info->depthTexArea); + + info->have3DWindows = 0; + + if (info->cursor_start) + xf86ForceHWCursor (pScreen, FALSE); +} diff --git a/src/radeon_dri.h b/src/radeon_dri.h new file mode 100644 index 0000000..3f46719 --- /dev/null +++ b/src/radeon_dri.h @@ -0,0 +1,107 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_dri.h,v 1.4 2002/10/30 12:52:13 alanh Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * + */ + +#ifndef _RADEON_DRI_ +#define _RADEON_DRI_ + +#include "xf86drm.h" +#include "radeon_common.h" + +/* DRI Driver defaults */ +#define RADEON_DEFAULT_CP_PIO_MODE RADEON_CSQ_PRIPIO_INDPIO +#define RADEON_DEFAULT_CP_BM_MODE RADEON_CSQ_PRIBM_INDBM +#define RADEON_DEFAULT_AGP_MODE 1 +#define RADEON_DEFAULT_AGP_FAST_WRITE 0 +#define RADEON_DEFAULT_GART_SIZE 8 /* MB (must be 2^n and > 4MB) */ +#define RADEON_DEFAULT_RING_SIZE 1 /* MB (must be page aligned) */ +#define RADEON_DEFAULT_BUFFER_SIZE 2 /* MB (must be page aligned) */ +#define RADEON_DEFAULT_GART_TEX_SIZE 1 /* MB (must be page aligned) */ + +#define RADEON_DEFAULT_CP_TIMEOUT 10000 /* usecs */ + +#define RADEON_AGP_MAX_MODE 4 + +#define RADEON_CARD_TYPE_RADEON 1 + +/* Buffer are aligned on 4096 byte boundaries */ +#define RADEON_BUFFER_ALIGN 0x00000fff + +#define RADEONCP_USE_RING_BUFFER(m) \ + (((m) == RADEON_CSQ_PRIBM_INDDIS) || \ + ((m) == RADEON_CSQ_PRIBM_INDBM)) + +typedef struct { + /* DRI screen private data */ + int deviceID; /* PCI device ID */ + int width; /* Width in pixels of display */ + int height; /* Height in scanlines of display */ + int depth; /* Depth of display (8, 15, 16, 24) */ + int bpp; /* Bit depth of display (8, 16, 24, 32) */ + + int IsPCI; /* Current card is a PCI card */ + int AGPMode; + + int frontOffset; /* Start of front buffer */ + int frontPitch; + int backOffset; /* Start of shared back buffer */ + int backPitch; + int depthOffset; /* Start of shared depth buffer */ + int depthPitch; + int textureOffset;/* Start of texture data in frame buffer */ + int textureSize; + int log2TexGran; + + /* MMIO register data */ + drmHandle registerHandle; + drmSize registerSize; + + /* CP in-memory status information */ + drmHandle statusHandle; + drmSize statusSize; + + /* CP GART Texture data */ + drmHandle gartTexHandle; + drmSize gartTexMapSize; + int log2GARTTexGran; + int gartTexOffset; + unsigned int sarea_priv_offset; + +#ifdef PER_CONTEXT_SAREA + drmSize perctx_sarea_size; +#endif +} RADEONDRIRec, *RADEONDRIPtr; + +#endif diff --git a/src/radeon_dripriv.h b/src/radeon_dripriv.h new file mode 100644 index 0000000..8859316 --- /dev/null +++ b/src/radeon_dripriv.h @@ -0,0 +1,64 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_dripriv.h,v 1.3 2002/04/24 16:20:40 martin Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * + */ + +#ifndef _RADEON_DRIPRIV_H_ +#define _RADEON_DRIPRIV_H_ + +#include "GL/glxint.h" +#include "xf86drm.h" +#include "radeon_common.h" + +#define RADEON_MAX_DRAWABLES 256 + +extern void GlxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **configprivs); + +typedef struct { + /* Nothing here yet */ + int dummy; +} RADEONConfigPrivRec, *RADEONConfigPrivPtr; + +typedef struct { +#ifdef PER_CONTEXT_SAREA + drmContext ctx_id; + drmHandle sarea_handle; +#else + /* Nothing here yet */ + int dummy; +#endif +} RADEONDRIContextRec, *RADEONDRIContextPtr; + +#endif diff --git a/src/radeon_driver.c b/src/radeon_driver.c new file mode 100644 index 0000000..1efa07a --- /dev/null +++ b/src/radeon_driver.c @@ -0,0 +1,7325 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c,v 1.117 2004/02/19 22:38:12 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + * Credits: + * + * Thanks to Ani Joshi <ajoshi@shell.unixbox.com> for providing source + * code to his Radeon driver. Portions of this file are based on the + * initialization code for that driver. + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + * This server does not yet support these XFree86 4.0 features: + * !!!! FIXME !!!! + * DDC1 & DDC2 + * shadowfb (Note: dri uses shadowfb for another purpose in radeon_dri.c) + * overlay planes + * + * Modified by Marc Aurele La France (tsi@xfree86.org) for ATI driver merge. + */ + + /* Driver data structures */ +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_reg.h" +#include "radeon_version.h" + +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "radeon_dri.h" +#include "radeon_sarea.h" +#endif + +#include "fb.h" + + /* colormap initialization */ +#include "micmap.h" +#include "dixstruct.h" + + /* X and server generic header files */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86PciInfo.h" +#include "xf86RAC.h" +#include "xf86Resources.h" +#include "xf86cmap.h" +#include "vbe.h" + + /* fbdevhw * vgaHW definitions */ +#include "fbdevhw.h" +#include "vgaHW.h" + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a)>(b)?(b):(a)) +#endif + + /* Forward definitions for driver functions */ +static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode); +static void RADEONSave(ScrnInfoPtr pScrn); +static void RADEONRestore(ScrnInfoPtr pScrn); +static Bool RADEONModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); +static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, + int flags); +static void RADEONInitDispBandwidth(ScrnInfoPtr pScrn); + +typedef enum { + OPTION_NOACCEL, + OPTION_SW_CURSOR, + OPTION_DAC_6BIT, + OPTION_DAC_8BIT, +#ifdef XF86DRI + OPTION_IS_PCI, + OPTION_BUS_TYPE, + OPTION_CP_PIO, + OPTION_USEC_TIMEOUT, + OPTION_AGP_MODE, + OPTION_AGP_FW, + OPTION_GART_SIZE, + OPTION_RING_SIZE, + OPTION_BUFFER_SIZE, + OPTION_DEPTH_MOVE, + OPTION_PAGE_FLIP, + OPTION_NO_BACKBUFFER, +#endif + OPTION_PANEL_OFF, + OPTION_DDC_MODE, + OPTION_MONITOR_LAYOUT, + OPTION_IGNORE_EDID, + OPTION_CRTC2_OVERLAY, + OPTION_CLONE_MODE, + OPTION_CLONE_HSYNC, + OPTION_CLONE_VREFRESH, + OPTION_FBDEV, + OPTION_VIDEO_KEY, + OPTION_DISP_PRIORITY, + OPTION_PANEL_SIZE, + OPTION_MIN_DOTCLOCK +} RADEONOpts; + +const OptionInfoRec RADEONOptions[] = { + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DAC_8BIT, "Dac8Bit", OPTV_BOOLEAN, {0}, TRUE }, +#ifdef XF86DRI + { OPTION_IS_PCI, "ForcePCIMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_BUS_TYPE, "BusType", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_CP_PIO, "CPPIOMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_USEC_TIMEOUT, "CPusecTimeout", OPTV_INTEGER, {0}, FALSE }, + { OPTION_AGP_MODE, "AGPMode", OPTV_INTEGER, {0}, FALSE }, + { OPTION_AGP_FW, "AGPFastWrite", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_GART_SIZE, "AGPSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_GART_SIZE, "GARTSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_RING_SIZE, "RingSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_BUFFER_SIZE, "BufferSize", OPTV_INTEGER, {0}, FALSE }, + { OPTION_DEPTH_MOVE, "EnableDepthMoves", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_NO_BACKBUFFER, "NoBackBuffer", OPTV_BOOLEAN, {0}, FALSE }, +#endif + { OPTION_PANEL_OFF, "PanelOff", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DDC_MODE, "DDCMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_MONITOR_LAYOUT, "MonitorLayout", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_IGNORE_EDID, "IgnoreEDID", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_CRTC2_OVERLAY , "OverlayOnCRTC2", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_CLONE_MODE, "CloneMode", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_CLONE_HSYNC, "CloneHSync", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_CLONE_VREFRESH, "CloneVRefresh", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, + { OPTION_DISP_PRIORITY, "DisplayPriority", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_PANEL_SIZE, "PanelSize", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_MIN_DOTCLOCK, "ForceMinDotClock", OPTV_FREQ, {0}, FALSE }, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +static const char *vgahwSymbols[] = { + "vgaHWFreeHWRec", + "vgaHWGetHWRec", + "vgaHWGetIndex", + "vgaHWLock", + "vgaHWRestore", + "vgaHWSave", + "vgaHWUnlock", + "vgaHWGetIOBase", + NULL +}; + +static const char *fbdevHWSymbols[] = { + "fbdevHWInit", + "fbdevHWUseBuildinMode", + + "fbdevHWGetVidmem", + + "fbdevHWDPMSSet", + + /* colormap */ + "fbdevHWLoadPalette", + /* ScrnInfo hooks */ + "fbdevHWAdjustFrame", + "fbdevHWEnterVT", + "fbdevHWLeaveVT", + "fbdevHWModeInit", + "fbdevHWRestore", + "fbdevHWSave", + "fbdevHWSwitchMode", + "fbdevHWValidMode", + + "fbdevHWMapMMIO", + "fbdevHWMapVidmem", + "fbdevHWUnmapMMIO", + "fbdevHWUnmapVidmem", + + NULL +}; + +static const char *ddcSymbols[] = { + "xf86PrintEDID", + "xf86DoEDID_DDC1", + "xf86DoEDID_DDC2", + NULL +}; + +static const char *fbSymbols[] = { + "fbScreenInit", + "fbPictureInit", + NULL +}; + +static const char *xaaSymbols[] = { + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAInit", + NULL +}; + +#if 0 +static const char *xf8_32bppSymbols[] = { + "xf86Overlay8Plus32Init", + NULL +}; +#endif + +static const char *ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86ForceHWCursor", + "xf86InitCursor", + NULL +}; + +#ifdef XF86DRI +static const char *drmSymbols[] = { + "drmGetInterruptFromBusID", + "drmCtlInstHandler", + "drmCtlUninstHandler", + "drmAddBufs", + "drmAddMap", + "drmAgpAcquire", + "drmAgpAlloc", + "drmAgpBase", + "drmAgpBind", + "drmAgpDeviceId", + "drmAgpEnable", + "drmAgpFree", + "drmAgpGetMode", + "drmAgpRelease", + "drmAgpUnbind", + "drmAgpVendorId", + "drmCommandNone", + "drmCommandRead", + "drmCommandWrite", + "drmCommandWriteRead", + "drmDMA", + "drmFreeVersion", + "drmGetLibVersion", + "drmGetVersion", + "drmMap", + "drmMapBufs", + "drmRadeonCleanupCP", + "drmRadeonClear", + "drmRadeonFlushIndirectBuffer", + "drmRadeonInitCP", + "drmRadeonResetCP", + "drmRadeonStartCP", + "drmRadeonStopCP", + "drmRadeonWaitForIdleCP", + "drmScatterGatherAlloc", + "drmScatterGatherFree", + "drmUnmap", + "drmUnmapBufs", + NULL +}; + +static const char *driSymbols[] = { + "DRICloseScreen", + "DRICreateInfoRec", + "DRIDestroyInfoRec", + "DRIFinishScreenInit", + "DRIGetContext", + "DRIGetDeviceInfo", + "DRIGetSAREAPrivate", + "DRILock", + "DRIQueryVersion", + "DRIScreenInit", + "DRIUnlock", + "GlxSetVisualConfigs", + NULL +}; + +static const char *driShadowFBSymbols[] = { + "ShadowFBInit", + NULL +}; +#endif + +static const char *vbeSymbols[] = { + "VBEInit", + "vbeDoEDID", + NULL +}; + +static const char *int10Symbols[] = { + "xf86InitInt10", + "xf86FreeInt10", + "xf86int10Addr", + NULL +}; + +static const char *i2cSymbols[] = { + "xf86CreateI2CBusRec", + "xf86I2CBusInit", + NULL +}; + +void RADEONLoaderRefSymLists(void) +{ + /* + * Tell the loader about symbols from other modules that this module might + * refer to. + */ + xf86LoaderRefSymLists(vgahwSymbols, + fbSymbols, + xaaSymbols, +#if 0 + xf8_32bppSymbols, +#endif + ramdacSymbols, +#ifdef XF86DRI + drmSymbols, + driSymbols, + driShadowFBSymbols, +#endif + fbdevHWSymbols, + vbeSymbols, + int10Symbols, + i2cSymbols, + ddcSymbols, + NULL); +} + +/* Established timings from EDID standard */ +static struct +{ + int hsize; + int vsize; + int refresh; +} est_timings[] = { + {1280, 1024, 75}, + {1024, 768, 75}, + {1024, 768, 70}, + {1024, 768, 60}, + {1024, 768, 87}, + {832, 624, 75}, + {800, 600, 75}, + {800, 600, 72}, + {800, 600, 60}, + {800, 600, 56}, + {640, 480, 75}, + {640, 480, 72}, + {640, 480, 67}, + {640, 480, 60}, + {720, 400, 88}, + {720, 400, 70}, +}; + +static const RADEONTMDSPll default_tmds_pll[CHIP_FAMILY_LAST][4] = +{ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_UNKNOW*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_LEGACY*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RADEON*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV100*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS100*/ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV200*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS200*/ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R200*/ + {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV250*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS300*/ + {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x400f7/*0x40111*/}, {0, 0}}, /*CHIP_FAMILY_RV280*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R300*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R350*/ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV350*/ +}; + +extern int gRADEONEntityIndex; + +struct RADEONInt10Save { + CARD32 MEM_CNTL; + CARD32 MEMSIZE; + CARD32 MPP_TB_CONFIG; +}; + +static Bool RADEONMapMMIO(ScrnInfoPtr pScrn); +static Bool RADEONUnmapMMIO(ScrnInfoPtr pScrn); + +static RADEONEntPtr RADEONEntPriv(ScrnInfoPtr pScrn) +{ + DevUnion *pPriv; + RADEONInfoPtr info = RADEONPTR(pScrn); + pPriv = xf86GetEntityPrivate(info->pEnt->index, + gRADEONEntityIndex); + return pPriv->ptr; +} + +static void +RADEONPreInt10Save(ScrnInfoPtr pScrn, void **pPtr) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 CardTmp; + static struct RADEONInt10Save SaveStruct = { 0, 0, 0 }; + + /* Save the values and zap MEM_CNTL */ + SaveStruct.MEM_CNTL = INREG(RADEON_MEM_CNTL); + SaveStruct.MEMSIZE = INREG(RADEON_CONFIG_MEMSIZE); + SaveStruct.MPP_TB_CONFIG = INREG(RADEON_MPP_TB_CONFIG); + + /* + * Zap MEM_CNTL and set MPP_TB_CONFIG<31:24> to 4 + */ + OUTREG(RADEON_MEM_CNTL, 0); + CardTmp = SaveStruct.MPP_TB_CONFIG & 0x00ffffffu; + CardTmp |= 0x04 << 24; + OUTREG(RADEON_MPP_TB_CONFIG, CardTmp); + + *pPtr = (void *)&SaveStruct; +} + +static void +RADEONPostInt10Check(ScrnInfoPtr pScrn, void *ptr) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + struct RADEONInt10Save *pSave = ptr; + CARD32 CardTmp; + + /* If we don't have a valid (non-zero) saved MEM_CNTL, get out now */ + if (!pSave || !pSave->MEM_CNTL) + return; + + /* + * If either MEM_CNTL is currently zero or inconistent (configured for + * two channels with the two channels configured differently), restore + * the saved registers. + */ + CardTmp = INREG(RADEON_MEM_CNTL); + if (!CardTmp || + ((CardTmp & 1) && + (((CardTmp >> 8) & 0xff) != ((CardTmp >> 24) & 0xff)))) { + /* Restore the saved registers */ + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Restoring MEM_CNTL (%08lx), setting to %08lx\n", + (unsigned long)CardTmp, (unsigned long)pSave->MEM_CNTL); + OUTREG(RADEON_MEM_CNTL, pSave->MEM_CNTL); + + CardTmp = INREG(RADEON_CONFIG_MEMSIZE); + if (CardTmp != pSave->MEMSIZE) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Restoring CONFIG_MEMSIZE (%08lx), setting to %08lx\n", + (unsigned long)CardTmp, (unsigned long)pSave->MEMSIZE); + OUTREG(RADEON_CONFIG_MEMSIZE, pSave->MEMSIZE); + } + } + + CardTmp = INREG(RADEON_MPP_TB_CONFIG); + if ((CardTmp & 0xff000000u) != (pSave->MPP_TB_CONFIG & 0xff000000u)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Restoring MPP_TB_CONFIG<31:24> (%02lx), setting to %02lx\n", + (unsigned long)CardTmp >> 24, + (unsigned long)pSave->MPP_TB_CONFIG >> 24); + CardTmp &= 0x00ffffffu; + CardTmp |= (pSave->MPP_TB_CONFIG & 0xff000000u); + OUTREG(RADEON_MPP_TB_CONFIG, CardTmp); + } +} + +/* Allocate our private RADEONInfoRec */ +static Bool RADEONGetRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate) return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(RADEONInfoRec), 1); + return TRUE; +} + +/* Free our private RADEONInfoRec */ +static void RADEONFreeRec(ScrnInfoPtr pScrn) +{ + if (!pScrn || !pScrn->driverPrivate) return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +/* Memory map the MMIO region. Used during pre-init and by RADEONMapMem, + * below + */ +static Bool RADEONMapMMIO(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->FBDev) { + info->MMIO = fbdevHWMapMMIO(pScrn); + } else { + info->MMIO = xf86MapPciMem(pScrn->scrnIndex, + VIDMEM_MMIO | VIDMEM_READSIDEEFFECT, + info->PciTag, + info->MMIOAddr, + RADEON_MMIOSIZE); + } + + if (!info->MMIO) return FALSE; + return TRUE; +} + +/* Unmap the MMIO region. Used during pre-init and by RADEONUnmapMem, + * below + */ +static Bool RADEONUnmapMMIO(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->FBDev) + fbdevHWUnmapMMIO(pScrn); + else { + xf86UnMapVidMem(pScrn->scrnIndex, info->MMIO, RADEON_MMIOSIZE); + } + info->MMIO = NULL; + return TRUE; +} + +/* Memory map the frame buffer. Used by RADEONMapMem, below. */ +static Bool RADEONMapFB(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->FBDev) { + info->FB = fbdevHWMapVidmem(pScrn); + } else { + info->FB = xf86MapPciMem(pScrn->scrnIndex, + VIDMEM_FRAMEBUFFER, + info->PciTag, + info->LinearAddr, + info->FbMapSize); + } + + if (!info->FB) return FALSE; + return TRUE; +} + +/* Unmap the frame buffer. Used by RADEONUnmapMem, below. */ +static Bool RADEONUnmapFB(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->FBDev) + fbdevHWUnmapVidmem(pScrn); + else + xf86UnMapVidMem(pScrn->scrnIndex, info->FB, info->FbMapSize); + info->FB = NULL; + return TRUE; +} + +/* Memory map the MMIO region and the frame buffer */ +static Bool RADEONMapMem(ScrnInfoPtr pScrn) +{ + if (!RADEONMapMMIO(pScrn)) return FALSE; + if (!RADEONMapFB(pScrn)) { + RADEONUnmapMMIO(pScrn); + return FALSE; + } + return TRUE; +} + +/* Unmap the MMIO region and the frame buffer */ +static Bool RADEONUnmapMem(ScrnInfoPtr pScrn) +{ + if (!RADEONUnmapMMIO(pScrn) || !RADEONUnmapFB(pScrn)) return FALSE; + return TRUE; +} + +/* This function is required to workaround a hardware bug in some (all?) + * revisions of the R300. This workaround should be called after every + * CLOCK_CNTL_INDEX register access. If not, register reads afterward + * may not be correct. + */ +void R300CGWorkaround(ScrnInfoPtr pScrn) { + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 save, tmp; + + save = INREG(RADEON_CLOCK_CNTL_INDEX); + tmp = save & ~(0x3f | RADEON_PLL_WR_EN); + OUTREG(RADEON_CLOCK_CNTL_INDEX, tmp); + tmp = INREG(RADEON_CLOCK_CNTL_DATA); + OUTREG(RADEON_CLOCK_CNTL_INDEX, save); +} + +/* Read PLL information */ +unsigned RADEONINPLL(ScrnInfoPtr pScrn, int addr) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 data; + + OUTREG8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f); + data = INREG(RADEON_CLOCK_CNTL_DATA); + if (info->R300CGWorkaround) R300CGWorkaround(pScrn); + + return data; +} + +#if 0 +/* Read PAL information (only used for debugging) */ +static int RADEONINPAL(int idx) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_PALETTE_INDEX, idx << 16); + return INREG(RADEON_PALETTE_DATA); +} +#endif + +/* Wait for vertical sync on primary CRTC */ +void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + + /* Clear the CRTC_VBLANK_SAVE bit */ + OUTREG(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); + + /* Wait for it to go back up */ + for (i = 0; i < RADEON_TIMEOUT/1000; i++) { + if (INREG(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_SAVE) break; + usleep(1); + } +} + +/* Wait for vertical sync on secondary CRTC */ +void RADEONWaitForVerticalSync2(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + + /* Clear the CRTC2_VBLANK_SAVE bit */ + OUTREG(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); + + /* Wait for it to go back up */ + for (i = 0; i < RADEON_TIMEOUT/1000; i++) { + if (INREG(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_SAVE) break; + usleep(1); + } +} + +/* Blank screen */ +static void RADEONBlank(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (!info->IsSecondary) { + switch(info->DisplayType) { + case MT_LCD: + case MT_CRT: + case MT_DFP: + OUTREGP(RADEON_CRTC_EXT_CNTL, + RADEON_CRTC_DISPLAY_DIS, + ~(RADEON_CRTC_DISPLAY_DIS)); + break; + + case MT_NONE: + default: + break; + } + if (info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_DISP_DIS, + ~(RADEON_CRTC2_DISP_DIS)); + } else { + OUTREGP(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_DISP_DIS, + ~(RADEON_CRTC2_DISP_DIS)); + } +} + +/* Unblank screen */ +static void RADEONUnblank(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (!info->IsSecondary) { + switch (info->DisplayType) { + case MT_LCD: + case MT_CRT: + case MT_DFP: + OUTREGP(RADEON_CRTC_EXT_CNTL, + RADEON_CRTC_CRT_ON, + ~(RADEON_CRTC_DISPLAY_DIS)); + break; + + case MT_NONE: + default: + break; + } + if (info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, + 0, + ~(RADEON_CRTC2_DISP_DIS)); + } else { + switch (info->DisplayType) { + case MT_LCD: + case MT_DFP: + case MT_CRT: + OUTREGP(RADEON_CRTC2_GEN_CNTL, + 0, + ~(RADEON_CRTC2_DISP_DIS)); + break; + + case MT_NONE: + default: + break; + } + } +} + +/* Compute log base 2 of val */ +int RADEONMinBits(int val) +{ + int bits; + + if (!val) return 1; + for (bits = 0; val; val >>= 1, ++bits); + return bits; +} + +/* Compute n/d with rounding */ +static int RADEONDiv(int n, int d) +{ + return (n + (d / 2)) / d; +} + +static RADEONMonitorType RADEONDisplayDDCConnected(ScrnInfoPtr pScrn, RADEONDDCType DDCType, xf86MonPtr* MonInfo) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + unsigned long DDCReg; + RADEONMonitorType MonType = MT_NONE; + int i, j; + + DDCReg = info->DDCReg; + switch(DDCType) + { + case DDC_MONID: + info->DDCReg = RADEON_GPIO_MONID; + break; + case DDC_DVI: + info->DDCReg = RADEON_GPIO_DVI_DDC; + break; + case DDC_VGA: + info->DDCReg = RADEON_GPIO_VGA_DDC; + break; + case DDC_CRT2: + info->DDCReg = RADEON_GPIO_CRT2_DDC; + break; + default: + info->DDCReg = DDCReg; + return MT_NONE; + } + + /* Read and output monitor info using DDC2 over I2C bus */ + if (info->pI2CBus && info->ddc2) { + OUTREG(info->DDCReg, INREG(info->DDCReg) & + (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1)); + + /* For some old monitors (like Compaq Presario FP500), we need + * following process to initialize/stop DDC + */ + OUTREG(info->DDCReg, INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1)); + for (j = 0; j < 3; j++) { + OUTREG(info->DDCReg, + INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0)); + usleep(13000); + + OUTREG(info->DDCReg, + INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1)); + for (i = 0; i < 10; i++) { + usleep(15000); + if (INREG(info->DDCReg) & RADEON_GPIO_Y_1) + break; + } + if (i == 10) continue; + + usleep(15000); + + OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0); + usleep(15000); + + OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1); + usleep(15000); + OUTREG(info->DDCReg, + INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0)); + usleep(15000); + *MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, info->pI2CBus); + + OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1); + OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0); + usleep(15000); + OUTREG(info->DDCReg, + INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1)); + for (i = 0; i < 5; i++) { + usleep(15000); + if (INREG(info->DDCReg) & RADEON_GPIO_Y_1) + break; + } + usleep(15000); + OUTREG(info->DDCReg, + INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0)); + usleep(15000); + + OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1); + OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0); + usleep(15000); + if(*MonInfo) break; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DDC2/I2C is not properly initialized\n"); + MonType = MT_NONE; + } + + if (*MonInfo) { + if ((*MonInfo)->rawData[0x14] & 0x80) { + if (INREG(RADEON_LVDS_GEN_CNTL) & RADEON_LVDS_ON) MonType = MT_LCD; + else MonType = MT_DFP; + } else MonType = MT_CRT; + } else MonType = MT_NONE; + + info->DDCReg = DDCReg; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "DDC Type: %d, Detected Type: %d\n", DDCType, MonType); + + return MonType; +} + +static RADEONMonitorType +RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int bConnected = 0; + + /* the monitor either wasn't connected or it is a non-DDC CRT. + * try to probe it + */ + if(IsCrtDac) { + unsigned long ulOrigVCLK_ECP_CNTL; + unsigned long ulOrigDAC_CNTL; + unsigned long ulOrigDAC_EXT_CNTL; + unsigned long ulOrigCRTC_EXT_CNTL; + unsigned long ulData; + unsigned long ulMask; + + ulOrigVCLK_ECP_CNTL = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); + + ulData = ulOrigVCLK_ECP_CNTL; + ulData &= ~(RADEON_PIXCLK_ALWAYS_ONb + | RADEON_PIXCLK_DAC_ALWAYS_ONb); + ulMask = ~(RADEON_PIXCLK_ALWAYS_ONb + |RADEON_PIXCLK_DAC_ALWAYS_ONb); + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); + + ulOrigCRTC_EXT_CNTL = INREG(RADEON_CRTC_EXT_CNTL); + ulData = ulOrigCRTC_EXT_CNTL; + ulData |= RADEON_CRTC_CRT_ON; + OUTREG(RADEON_CRTC_EXT_CNTL, ulData); + + ulOrigDAC_EXT_CNTL = INREG(RADEON_DAC_EXT_CNTL); + ulData = ulOrigDAC_EXT_CNTL; + ulData &= ~RADEON_DAC_FORCE_DATA_MASK; + ulData |= (RADEON_DAC_FORCE_BLANK_OFF_EN + |RADEON_DAC_FORCE_DATA_EN + |RADEON_DAC_FORCE_DATA_SEL_MASK); + if ((info->ChipFamily == CHIP_FAMILY_RV250) || + (info->ChipFamily == CHIP_FAMILY_RV280)) + ulData |= (0x01b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + ulData |= (0x01ac << RADEON_DAC_FORCE_DATA_SHIFT); + + OUTREG(RADEON_DAC_EXT_CNTL, ulData); + + ulOrigDAC_CNTL = INREG(RADEON_DAC_CNTL); + ulData = ulOrigDAC_CNTL; + ulData |= RADEON_DAC_CMP_EN; + ulData &= ~(RADEON_DAC_RANGE_CNTL_MASK + | RADEON_DAC_PDWN); + ulData |= 0x2; + OUTREG(RADEON_DAC_CNTL, ulData); + + usleep(1000); + + ulData = INREG(RADEON_DAC_CNTL); + bConnected = (RADEON_DAC_CMP_OUTPUT & ulData)?1:0; + + ulData = ulOrigVCLK_ECP_CNTL; + ulMask = 0xFFFFFFFFL; + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); + + OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL ); + OUTREG(RADEON_DAC_EXT_CNTL, ulOrigDAC_EXT_CNTL ); + OUTREG(RADEON_CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL); + } else { /* TV DAC */ + + /* This doesn't seem to work reliably (maybe worse on some OEM cards), + for now we always return false. If one wants to connected a + non-DDC monitor on the DVI port when CRT port is also connected, + he will need to explicitly tell the driver in the config file + with Option MonitorLayout. + */ + bConnected = FALSE; + +#if 0 + if (info->ChipFamily == CHIP_FAMILY_R200) { + + unsigned long ulOrigGPIO_MONID; + unsigned long ulOrigFP2_GEN_CNTL; + unsigned long ulOrigDISP_OUTPUT_CNTL; + unsigned long ulOrigCRTC2_GEN_CNTL; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_A; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_B; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_C; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_D; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_E; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_F; + unsigned long ulOrigCRTC2_H_TOTAL_DISP; + unsigned long ulOrigCRTC2_V_TOTAL_DISP; + unsigned long ulOrigCRTC2_H_SYNC_STRT_WID; + unsigned long ulOrigCRTC2_V_SYNC_STRT_WID; + unsigned long ulData, i; + + ulOrigGPIO_MONID = INREG(RADEON_GPIO_MONID); + ulOrigFP2_GEN_CNTL = INREG(RADEON_FP2_GEN_CNTL); + ulOrigDISP_OUTPUT_CNTL = INREG(RADEON_DISP_OUTPUT_CNTL); + ulOrigCRTC2_GEN_CNTL = INREG(RADEON_CRTC2_GEN_CNTL); + ulOrigDISP_LIN_TRANS_GRPH_A = INREG(RADEON_DISP_LIN_TRANS_GRPH_A); + ulOrigDISP_LIN_TRANS_GRPH_B = INREG(RADEON_DISP_LIN_TRANS_GRPH_B); + ulOrigDISP_LIN_TRANS_GRPH_C = INREG(RADEON_DISP_LIN_TRANS_GRPH_C); + ulOrigDISP_LIN_TRANS_GRPH_D = INREG(RADEON_DISP_LIN_TRANS_GRPH_D); + ulOrigDISP_LIN_TRANS_GRPH_E = INREG(RADEON_DISP_LIN_TRANS_GRPH_E); + ulOrigDISP_LIN_TRANS_GRPH_F = INREG(RADEON_DISP_LIN_TRANS_GRPH_F); + + ulOrigCRTC2_H_TOTAL_DISP = INREG(RADEON_CRTC2_H_TOTAL_DISP); + ulOrigCRTC2_V_TOTAL_DISP = INREG(RADEON_CRTC2_V_TOTAL_DISP); + ulOrigCRTC2_H_SYNC_STRT_WID = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); + ulOrigCRTC2_V_SYNC_STRT_WID = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); + + ulData = INREG(RADEON_GPIO_MONID); + ulData &= ~RADEON_GPIO_A_0; + OUTREG(RADEON_GPIO_MONID, ulData); + + OUTREG(RADEON_FP2_GEN_CNTL, 0x0a000c0c); + + OUTREG(RADEON_DISP_OUTPUT_CNTL, 0x00000012); + + OUTREG(RADEON_CRTC2_GEN_CNTL, 0x06000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); + + for (i = 0; i < 200; i++) { + ulData = INREG(RADEON_GPIO_MONID); + bConnected = (ulData & RADEON_GPIO_Y_0)?1:0; + if (!bConnected) break; + + usleep(1000); + } + + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, ulOrigDISP_LIN_TRANS_GRPH_A); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, ulOrigDISP_LIN_TRANS_GRPH_B); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, ulOrigDISP_LIN_TRANS_GRPH_C); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, ulOrigDISP_LIN_TRANS_GRPH_D); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, ulOrigDISP_LIN_TRANS_GRPH_E); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, ulOrigDISP_LIN_TRANS_GRPH_F); + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, ulOrigCRTC2_H_TOTAL_DISP); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, ulOrigCRTC2_V_TOTAL_DISP); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, ulOrigCRTC2_H_SYNC_STRT_WID); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, ulOrigCRTC2_V_SYNC_STRT_WID); + OUTREG(RADEON_CRTC2_GEN_CNTL, ulOrigCRTC2_GEN_CNTL); + OUTREG(RADEON_DISP_OUTPUT_CNTL, ulOrigDISP_OUTPUT_CNTL); + OUTREG(RADEON_FP2_GEN_CNTL, ulOrigFP2_GEN_CNTL); + OUTREG(RADEON_GPIO_MONID, ulOrigGPIO_MONID); + } else { + unsigned long ulOrigPIXCLKSDATA; + unsigned long ulOrigTV_MASTER_CNTL; + unsigned long ulOrigTV_DAC_CNTL; + unsigned long ulOrigTV_PRE_DAC_MUX_CNTL; + unsigned long ulOrigDAC_CNTL2; + unsigned long ulData; + unsigned long ulMask; + + ulOrigPIXCLKSDATA = INPLL(pScrn, RADEON_PIXCLKS_CNTL); + + ulData = ulOrigPIXCLKSDATA; + ulData &= ~(RADEON_PIX2CLK_ALWAYS_ONb + | RADEON_PIX2CLK_DAC_ALWAYS_ONb); + ulMask = ~(RADEON_PIX2CLK_ALWAYS_ONb + | RADEON_PIX2CLK_DAC_ALWAYS_ONb); + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); + + ulOrigTV_MASTER_CNTL = INREG(RADEON_TV_MASTER_CNTL); + ulData = ulOrigTV_MASTER_CNTL; + ulData &= ~RADEON_TVCLK_ALWAYS_ONb; + OUTREG(RADEON_TV_MASTER_CNTL, ulData); + + ulOrigDAC_CNTL2 = INREG(RADEON_DAC_CNTL2); + ulData = ulOrigDAC_CNTL2; + ulData &= ~RADEON_DAC2_DAC2_CLK_SEL; + OUTREG(RADEON_DAC_CNTL2, ulData); + + ulOrigTV_DAC_CNTL = INREG(RADEON_TV_DAC_CNTL); + + ulData = 0x00880213; + OUTREG(RADEON_TV_DAC_CNTL, ulData); + + ulOrigTV_PRE_DAC_MUX_CNTL = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); + + ulData = (RADEON_Y_RED_EN + | RADEON_C_GRN_EN + | RADEON_CMP_BLU_EN + | RADEON_RED_MX_FORCE_DAC_DATA + | RADEON_GRN_MX_FORCE_DAC_DATA + | RADEON_BLU_MX_FORCE_DAC_DATA); + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) + ulData |= 0x180 << RADEON_TV_FORCE_DAC_DATA_SHIFT; + else + ulData |= 0x1f5 << RADEON_TV_FORCE_DAC_DATA_SHIFT; + OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulData); + + usleep(1000); + + ulData = INREG(RADEON_TV_DAC_CNTL); + bConnected = (ulData & RADEON_TV_DAC_CMPOUT)?1:0; + + ulData = ulOrigPIXCLKSDATA; + ulMask = 0xFFFFFFFFL; + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); + + OUTREG(RADEON_TV_MASTER_CNTL, ulOrigTV_MASTER_CNTL); + OUTREG(RADEON_DAC_CNTL2, ulOrigDAC_CNTL2); + OUTREG(RADEON_TV_DAC_CNTL, ulOrigTV_DAC_CNTL); + OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulOrigTV_PRE_DAC_MUX_CNTL); + } +#endif + } + + return(bConnected ? MT_CRT : MT_NONE); +} + +static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + const char *s; + Bool ignore_edid = FALSE, ddc_crt2_used = FALSE; + +#define RADEON_BIOS8(v) (info->VBIOS[v]) +#define RADEON_BIOS16(v) (info->VBIOS[v] | \ + (info->VBIOS[(v) + 1] << 8)) +#define RADEON_BIOS32(v) (info->VBIOS[v] | \ + (info->VBIOS[(v) + 1] << 8) | \ + (info->VBIOS[(v) + 2] << 16) | \ + (info->VBIOS[(v) + 3] << 24)) + + pRADEONEnt->MonType1 = MT_NONE; + pRADEONEnt->MonType2 = MT_NONE; + pRADEONEnt->MonInfo1 = NULL; + pRADEONEnt->MonInfo2 = NULL; + pRADEONEnt->ReversedDAC = FALSE; + pRADEONEnt->ReversedTMDS = FALSE; + + /* IgnoreEDID option is different from NoDDC options used by DDC module + * When IgnoreEDID is used, monitor detection will still use DDC + * detection, but all EDID data will not be used in mode validation. + */ + if (xf86GetOptValBool(info->Options, OPTION_IGNORE_EDID, &ignore_edid)) { + if (ignore_edid) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "IgnoreEDID is specified, EDID data will be ignored\n"); + } + + /* + * MonitorLayout option takes a string for two monitors connected in following format: + * Option "MonitorLayout" "primary-port-display, secondary-port-display" + * primary and secondary port displays can have one of following: + * NONE, CRT, LVDS, TMDS + * With this option, driver will bring up monitors as specified, + * not using auto-detection routines to probe monitors. + */ + + /* current monitor mapping scheme: + * Two displays connected: + * Primary Port: + * CRTC1 -> FP/TMDS -> DVI port -> TMDS panel --> Primary or + * CRTC1 -> FP/LVDS -> Int. LCD -> LVDS panel --> Primary or + * CRTC1 -> TV DAC -> DVI port -> CRT monitor --> Primary + * + * Secondary Port + * CRTC2 -> CRT DAC -> VGA port -> CRT monitor --> Secondary or + * CRTC2 -> FP2/Ext. -> DVI port -> TMDS panel --> Secondary + * + * Only DVI (or Int. LDC) conneced: + * CRTC1 -> FP/TMDS -> DVI port -> TMDS panel --> Primary or + * CRTC1 -> FP/LVDS -> Int. LCD -> LVDS panel --> Primary or + * CRTC1 -> TV DAC -> DVI port -> CRT monitor --> Primary + * + * Only VGA (can be DVI on some dual-DVI boards) connected: + * CRTC1 -> CRT DAC -> VGA port -> CRT monitor --> Primary or + * CRTC1 -> FP2/Ext. -> DVI port -> TMDS panel --> Primary (not supported) + * + * Note, this is different from Windows scheme where + * if a digital panel is connected to DVI port, DVI will be the 1st port + * otherwise, VGA port will be treated as 1st port + * + * Here we always treat DVI port as primary if both ports are connected. + * When only one port is connected, it will be treated as + * primary regardless which port or what type of display is involved. + */ + + if ((s = xf86GetOptValString(info->Options, OPTION_MONITOR_LAYOUT))) { + char s1[5], s2[5]; + int i = 0, second = 0; + + /* When using user specified monitor types, we will not do DDC detection + * + */ + do { + switch(*s) + { + case ',': + s1[i] = '\0'; + i = 0; + second = 1; + break; + case ' ': + case '\t': + case '\n': + case '\r': + break; + default: + if (second) + s2[i] = *s; + else + s1[i] = *s; + i++; + if (i == 4) break; + } + } while(*s++); + s2[i] = '\0'; + + if (strcmp(s1, "NONE") == 0) + pRADEONEnt->MonType1 = MT_NONE; + else if (strcmp(s1, "CRT") == 0) + pRADEONEnt->MonType1 = MT_CRT; + else if (strcmp(s1, "TMDS") == 0) + pRADEONEnt->MonType1 = MT_DFP; + else if (strcmp(s1, "LVDS") == 0) + pRADEONEnt->MonType1 = MT_LCD; + else + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Invalid Monitor type specified for 1st port \n"); + if (strcmp(s2, "NONE") == 0) + pRADEONEnt->MonType2 = MT_NONE; + else if (strcmp(s2, "CRT") == 0) + pRADEONEnt->MonType2 = MT_CRT; + else if (strcmp(s2, "TMDS") == 0) + pRADEONEnt->MonType2 = MT_DFP; + else if (strcmp(s2, "LVDS") == 0) + pRADEONEnt->MonType2 = MT_LCD; + else + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Invalid Monitor type specified for 2nd port \n"); + + if (!ignore_edid) { + if (pRADEONEnt->MonType1) /* assuming the first port using DDC_DVI */ + if(!RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1)) { + RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1); + ddc_crt2_used = TRUE; + } + if (pRADEONEnt->MonType2) { /* assuming the second port using DDC_VGA/DDC_CRT2 */ + if(!RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo2)) + if (!ddc_crt2_used) + RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo2); + } + } + + if (!pRADEONEnt->MonType1) { + if (pRADEONEnt->MonType2) { + pRADEONEnt->MonType1 = pRADEONEnt->MonType2; + pRADEONEnt->MonInfo1 = pRADEONEnt->MonInfo2; + } else { + pRADEONEnt->MonType1 = MT_CRT; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No valid monitor specified, force to CRT on 1st port\n"); + } + pRADEONEnt->MonType2 = MT_NONE; + pRADEONEnt->MonInfo2 = NULL; + } + } else { + /* Auto detection */ + int i; + CARD32 tmp; + + /* Old single head radeon cards */ + if(!info->HasCRTC2) { + if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1))); + else if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo1))); + else if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1))); + else if (pInt10) { + if (xf86LoadSubModule(pScrn, "vbe")) { + vbeInfoPtr pVbe; + pVbe = VBEInit(pInt10, info->pEnt->index); + if (pVbe) { + for (i = 0; i < 5; i++) { + pRADEONEnt->MonInfo1 = vbeDoEDID(pVbe, NULL); + } + if (pRADEONEnt->MonInfo1->rawData[0x14] & 0x80) + pRADEONEnt->MonType1 = MT_DFP; + else pRADEONEnt->MonType1 = MT_CRT; + } + } + } else + pRADEONEnt->MonType1 = MT_CRT; + + pRADEONEnt->HasSecondary = FALSE; + if (!ignore_edid) { + if (pRADEONEnt->MonInfo1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n"); + xf86PrintEDID( pRADEONEnt->MonInfo1 ); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n"); + } + } + return; + } + + /* Normally the port uses DDC_DVI connected with TVDAC, + * But this is not true for OEM cards which have TVDAC and CRT DAC reversed. + * If that's the case, we need also reverse the port arrangement. + * BIOS settings are supposed report this correctly, work fine for all cards tested. + * But there may be some exceptions, in that case, user can reverse their monitor + * definition in config file to correct the problem. + */ + if (info->VBIOS && (tmp = RADEON_BIOS16(info->FPBIOSstart + 0x50))) { + for (i = 1; i < 4; i++) { + unsigned int tmp0; + if (!RADEON_BIOS8(tmp + i*2) && i > 1) break; + tmp0 = RADEON_BIOS16(tmp + i*2); + if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0xf) == DDC_DVI)) { + pRADEONEnt->ReversedDAC = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed DACs detected\n"); + } + if ((((tmp0 >> 8) & 0x0f) == DDC_DVI ) && ((tmp0 >> 4) & 0x1)) { + pRADEONEnt->ReversedTMDS = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed TMDS detected\n"); + } + } + } + + /* Primary Head (DVI or Laptop Int. panel)*/ + /* A ddc capable display connected on DVI port */ + if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1))); + else if((pRADEONEnt->MonType1 = + RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1))) { + ddc_crt2_used = TRUE; + } else if ((info->IsMobility) && + (info->VBIOS && (INREG(RADEON_BIOS_4_SCRATCH) & 4))) { + /* non-DDC laptop panel connected on primary */ + pRADEONEnt->MonType1 = MT_LCD; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Non-DDC laptop panel detected\n"); + } else { + /* CRT on DVI, TODO: not reliable, make it always return false for now*/ + pRADEONEnt->MonType1 = RADEONCrtIsPhysicallyConnected(pScrn, pRADEONEnt->ReversedDAC); + } + + /* Secondary Head (mostly VGA, can be DVI on some OEM boards)*/ + if((pRADEONEnt->MonType2 = + RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo2))); + else if(!ddc_crt2_used) + pRADEONEnt->MonType2 = + RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo2); + if (!pRADEONEnt->MonType2) + pRADEONEnt->MonType2 = RADEONCrtIsPhysicallyConnected(pScrn, !pRADEONEnt->ReversedDAC); + + if(pRADEONEnt->ReversedTMDS) { + /* always keep internal TMDS as primary head */ + if (pRADEONEnt->MonType1 == MT_DFP || + pRADEONEnt->MonType2 == MT_DFP) { + int tmp1 = pRADEONEnt->MonType1; + xf86MonPtr MonInfo = pRADEONEnt->MonInfo1; + pRADEONEnt->MonInfo1 = pRADEONEnt->MonInfo2; + pRADEONEnt->MonInfo2 = MonInfo; + pRADEONEnt->MonType1 = pRADEONEnt->MonType2; + pRADEONEnt->MonType2 = tmp1; + if ((pRADEONEnt->MonType1 == MT_CRT) || + (pRADEONEnt->MonType2 == MT_CRT)) { + pRADEONEnt->ReversedDAC ^= 1; + } + } + } + + /* no display detected on DVI port*/ + if (pRADEONEnt->MonType1 == MT_NONE) { + if (pRADEONEnt->MonType2 != MT_NONE) { + /* Only one detected on VGA, let it to be primary */ + pRADEONEnt->MonType1 = pRADEONEnt->MonType2; + pRADEONEnt->MonInfo1 = pRADEONEnt->MonInfo2; + pRADEONEnt->MonType2 = MT_NONE; + pRADEONEnt->MonInfo2 = NULL; + } else { + /* Non detected, Default to a CRT connected */ + pRADEONEnt->MonType1 = MT_CRT; + } + } + } + + if(s) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Displays Configured by MonitorLayout: \n\tMonitor1--Type %d, Monitor2--Type %d\n\n", + pRADEONEnt->MonType1, pRADEONEnt->MonType2); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Displays Detected: Monitor1--Type %d, Monitor2--Type %d\n\n", + pRADEONEnt->MonType1, pRADEONEnt->MonType2); + } + + if(ignore_edid) { + pRADEONEnt->MonInfo1 = NULL; + pRADEONEnt->MonInfo2 = NULL; + } + + if (!ignore_edid) { + if (pRADEONEnt->MonInfo1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n"); + xf86PrintEDID( pRADEONEnt->MonInfo1 ); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n"); + } + if (pRADEONEnt->MonInfo2) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor2 EDID data ---------------------------\n"); + xf86PrintEDID( pRADEONEnt->MonInfo2 ); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor2 EDID data --------------------\n"); + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\n"); + + info->OverlayOnCRTC2 = FALSE; + if (xf86ReturnOptValBool(info->Options, OPTION_CRTC2_OVERLAY, FALSE)) { + info->OverlayOnCRTC2 = TRUE; + } + + if (pRADEONEnt->MonType2 == MT_NONE) + pRADEONEnt->HasSecondary = FALSE; +} + + +/* Read the Video BIOS block and the FP registers (if applicable). */ +static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long tmp, i; + + if (!(info->VBIOS = xalloc(RADEON_VBIOS_SIZE))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Cannot allocate space for hold Video BIOS!\n"); + return FALSE; + } + + if (pInt10) { + info->BIOSAddr = pInt10->BIOSseg << 4; + (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr), + RADEON_VBIOS_SIZE); + } else { + xf86ReadPciBIOS(0, info->PciTag, 0, info->VBIOS, RADEON_VBIOS_SIZE); + if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Video BIOS not detected in PCI space!\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Attempting to read Video BIOS from " + "legacy ISA space!\n"); + info->BIOSAddr = 0x000c0000; + xf86ReadDomainMemory(info->PciTag, info->BIOSAddr, + RADEON_VBIOS_SIZE, info->VBIOS); + } + } + + if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { + xfree(info->VBIOS); + info->FPBIOSstart = 0; + info->VBIOS = NULL; + info->BIOSAddr = 0x00000000; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Video BIOS not found!\n"); + } else + info->FPBIOSstart = RADEON_BIOS16(0x48); + info->OverlayOnCRTC2 = FALSE; + + if (!info->IsSecondary) + RADEONQueryConnectedDisplays(pScrn, pInt10); + + { + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + info->Clone = FALSE; + info->CloneType = MT_NONE; + + if(info->HasCRTC2) { + if(info->IsSecondary) { + info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType2; + if(info->DisplayType == MT_NONE) return FALSE; + } else { + info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType1; + + if(!pRADEONEnt->HasSecondary) { + info->CloneType = (RADEONMonitorType)pRADEONEnt->MonType2; + if (info->CloneType != MT_NONE) + info->Clone = TRUE; + } + } + } else { + info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType1; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n", + (info->IsSecondary ? "Secondary" : "Primary"), + info->DisplayType); + + if (info->Clone) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clone Display == Type %d\n", + info->CloneType); + + info->HBlank = 0; + info->HOverPlus = 0; + info->HSyncWidth = 0; + info->VBlank = 0; + info->VOverPlus = 0; + info->VSyncWidth = 0; + info->DotClock = 0; + info->UseBiosDividers = FALSE; + + if (info->DisplayType == MT_LCD && info->VBIOS && + !(xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) { + tmp = RADEON_BIOS16(info->FPBIOSstart + 0x40); + if (!tmp) { + info->PanelPwrDly = 200; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No Panel Info Table found in BIOS!\n"); + } else { + char stmp[30]; + int tmp0; + + for (i = 0; i < 24; i++) + stmp[i] = RADEON_BIOS8(tmp+i+1); + stmp[24] = 0; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Panel ID string: %s\n", stmp); + + info->PanelXRes = RADEON_BIOS16(tmp+25); + info->PanelYRes = RADEON_BIOS16(tmp+27); + xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n", + info->PanelXRes, info->PanelYRes); + + info->PanelPwrDly = RADEON_BIOS16(tmp+44); + if (info->PanelPwrDly > 2000 || info->PanelPwrDly < 0) + info->PanelPwrDly = 2000; + + /* some panels only work well with certain divider combinations. + */ + info->RefDivider = RADEON_BIOS16(tmp+46); + info->PostDivider = RADEON_BIOS8(tmp+48); + info->FeedbackDivider = RADEON_BIOS16(tmp+49); + if ((info->RefDivider != 0) && + (info->FeedbackDivider > 3)) { + info->UseBiosDividers = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS provided dividers will be used.\n"); + } + + /* We don't use a while loop here just in case we have a corrupted BIOS image. + The max number of table entries is 23 at present, but may grow in future. + To ensure it works with future revisions we loop it to 32. + */ + for (i = 0; i < 32; i++) { + tmp0 = RADEON_BIOS16(tmp+64+i*2); + if (tmp0 == 0) break; + if ((RADEON_BIOS16(tmp0) == info->PanelXRes) && + (RADEON_BIOS16(tmp0+2) == info->PanelYRes)) { + info->HBlank = (RADEON_BIOS16(tmp0+17) - + RADEON_BIOS16(tmp0+19)) * 8; + info->HOverPlus = (RADEON_BIOS16(tmp0+21) - + RADEON_BIOS16(tmp0+19) - 1) * 8; + info->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8; + info->VBlank = (RADEON_BIOS16(tmp0+24) - + RADEON_BIOS16(tmp0+26)); + info->VOverPlus = ((RADEON_BIOS16(tmp0+28) & 0x7ff) - + RADEON_BIOS16(tmp0+26)); + info->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11); + info->DotClock = RADEON_BIOS16(tmp0+9) * 10; + info->Flags = 0; + } + } + + if (info->DotClock == 0) { + DisplayModePtr tmp_mode = NULL; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No valid timing info from BIOS.\n"); + /* No timing information for the native mode, + use whatever specified in the Modeline. + If no Modeline specified, we'll just pick + the VESA mode at 60Hz refresh rate which + is likely to be the best for a flat panel. + */ + tmp_mode = pScrn->monitor->Modes; + while(tmp_mode) { + if ((tmp_mode->HDisplay == info->PanelXRes) && + (tmp_mode->VDisplay == info->PanelYRes)) { + + float refresh = + (float)tmp_mode->Clock * 1000.0 / tmp_mode->HTotal / tmp_mode->VTotal; + if ((abs(60.0 - refresh) < 1.0) || + (tmp_mode->type == 0)) { + info->HBlank = tmp_mode->HTotal - tmp_mode->HDisplay; + info->HOverPlus = tmp_mode->HSyncStart - tmp_mode->HDisplay; + info->HSyncWidth = tmp_mode->HSyncEnd - tmp_mode->HSyncStart; + info->VBlank = tmp_mode->VTotal - tmp_mode->VDisplay; + info->VOverPlus = tmp_mode->VSyncStart - tmp_mode->VDisplay; + info->VSyncWidth = tmp_mode->VSyncEnd - tmp_mode->VSyncStart; + info->DotClock = tmp_mode->Clock; + info->Flags = 0; + break; + } + tmp_mode = tmp_mode->next; + } + } + if ((info->DotClock == 0) && !pRADEONEnt->MonInfo1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Panel size is not correctly detected.\n" + "Please try to use PanelSize option for correct settings.\n"); + return FALSE; + } + } + } + } + } + + if (info->VBIOS) { + tmp = RADEON_BIOS16(info->FPBIOSstart + 0x30); + info->sclk = RADEON_BIOS16(tmp + 8) / 100.0; + info->mclk = RADEON_BIOS16(tmp + 10) / 100.0; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No valid info for SCLK/MCLK for display bandwidth calculation.\n"); + info->sclk = 200.00; + info->mclk = 200.00; + } + + return TRUE; +} + +static Bool RADEONProbePLLParameters(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPLLPtr pll = &info->pll; + unsigned char *RADEONMMIO = info->MMIO; + unsigned char ppll_div_sel; + unsigned Nx, M; + unsigned xclk, tmp, ref_div; + int hTotal, vTotal, num, denom, m, n; + float hz, vclk, xtal; + long start_secs, start_usecs, stop_secs, stop_usecs, total_usecs; + int i; + + for(i=0; i<1000000; i++) + if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) + break; + + xf86getsecs(&start_secs, &start_usecs); + + for(i=0; i<1000000; i++) + if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0) + break; + + for(i=0; i<1000000; i++) + if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) + break; + + xf86getsecs(&stop_secs, &stop_usecs); + + total_usecs = abs(stop_usecs - start_usecs); + hz = 1000000/total_usecs; + + hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8; + vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0x3ff) + 1); + vclk = (float)(hTotal * (float)(vTotal * hz)); + + switch((INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x30000) >> 16) { + case 0: + default: + num = 1; + denom = 1; + break; + case 1: + n = ((INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) >> 16) & 0xff); + m = (INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) & 0xff); + num = 2*n; + denom = 2*m; + break; + case 2: + n = ((INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) >> 8) & 0xff); + m = (INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) & 0xff); + num = 2*n; + denom = 2*m; + break; + } + + OUTREG(RADEON_CLOCK_CNTL_INDEX, 1); + ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_DATA + 1) & 0x3; + + n = (INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) & 0x7ff); + m = (INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff); + + num *= n; + denom *= m; + + switch ((INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) { + case 1: + denom *= 2; + break; + case 2: + denom *= 4; + break; + case 3: + denom *= 8; + break; + case 4: + denom *= 3; + break; + case 6: + denom *= 6; + break; + case 7: + denom *= 12; + break; + } + + xtal = (int)(vclk *(float)denom/(float)num); + + if ((xtal > 26900000) && (xtal < 27100000)) + xtal = 2700; + else if ((xtal > 14200000) && (xtal < 14400000)) + xtal = 1432; + else if ((xtal > 29400000) && (xtal < 29600000)) + xtal = 2950; + else + return FALSE; + + tmp = INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV); + ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff; + + Nx = (tmp & 0xff00) >> 8; + M = (tmp & 0xff); + xclk = RADEONDiv((2 * Nx * xtal), (2 * M)); + + /* we're done, hopefully these are sane values */ + pll->reference_div = ref_div; + pll->xclk = xclk; + pll->reference_freq = xtal; + + return TRUE; +} + +static void RADEONGetTMDSInfo(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 tmp; + int i, n; + + for (i=0; i<4; i++) { + info->tmds_pll[i].value = 0; + info->tmds_pll[i].freq = 0; + } + + if (info->VBIOS) { + tmp = RADEON_BIOS16(info->FPBIOSstart + 0x34); + if (tmp) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "DFP table revision: %d\n", RADEON_BIOS8(tmp)); + if (RADEON_BIOS8(tmp) == 3) { + n = RADEON_BIOS8(tmp + 5) + 1; + if (n > 4) n = 4; + for (i=0; i<n; i++) { + info->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08); + info->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10); + } + return; + } + + /* revision 4 has some problem as it appears in RV280, + comment it off for new, use default instead */ + /* + else if (RADEON_BIOS8(tmp) == 4) { + int stride = 0; + n = RADEON_BIOS8(tmp + 5) + 1; + if (n > 4) n = 4; + for (i=0; i<n; i++) { + info->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08); + info->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10); + if (i == 0) stride += 10; + else stride += 6; + } + return; + } + */ + } + } + + for (i=0; i<4; i++) { + info->tmds_pll[i].value = default_tmds_pll[info->ChipFamily][i].value; + info->tmds_pll[i].freq = default_tmds_pll[info->ChipFamily][i].freq; + } +} + +/* Read PLL parameters from BIOS block. Default to typical values if + * there is no BIOS. + */ +static Bool RADEONGetPLLParameters(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPLLPtr pll = &info->pll; + CARD16 bios_header; + CARD16 pll_info_block; + double min_dotclock; + + if (!info->VBIOS) { + + pll->min_pll_freq = 12500; + pll->max_pll_freq = 35000; + + + if (!RADEONProbePLLParameters(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Video BIOS not detected, using default PLL parameters!\n"); + + switch (info->Chipset) { + case PCI_CHIP_R200_QL: + case PCI_CHIP_R200_QN: + case PCI_CHIP_R200_QO: + case PCI_CHIP_R200_BB: + pll->reference_freq = 2700; + pll->reference_div = 12; + pll->xclk = 27500; + break; + case PCI_CHIP_RV250_Id: + case PCI_CHIP_RV250_Ie: + case PCI_CHIP_RV250_If: + case PCI_CHIP_RV250_Ig: + pll->reference_freq = 2700; + pll->reference_div = 12; + pll->xclk = 24975; + break; + case PCI_CHIP_RV200_QW: + pll->reference_freq = 2700; + pll->reference_div = 12; + pll->xclk = 23000; + break; + default: + pll->reference_freq = 2700; + pll->reference_div = 67; + pll->xclk = 16615; + break; + } + } + } else { + bios_header = RADEON_BIOS16(0x48); + pll_info_block = RADEON_BIOS16(bios_header + 0x30); + RADEONTRACE(("Header at 0x%04x; PLL Information at 0x%04x\n", + bios_header, pll_info_block)); + + pll->reference_freq = RADEON_BIOS16(pll_info_block + 0x0e); + pll->reference_div = RADEON_BIOS16(pll_info_block + 0x10); + pll->min_pll_freq = RADEON_BIOS32(pll_info_block + 0x12); + pll->max_pll_freq = RADEON_BIOS32(pll_info_block + 0x16); + pll->xclk = RADEON_BIOS16(pll_info_block + 0x08); + } + + /* (Some?) Radeon BIOSes seem too lie about their minimum dot + * clocks. Allow users to override the detected minimum dot clock + * value (e.g., and allow it to be suitable for TV sets). + */ + if (xf86GetOptValFreq(info->Options, OPTION_MIN_DOTCLOCK, + OPTUNITS_MHZ, &min_dotclock)) { + if (min_dotclock < 12 || min_dotclock*100 >= pll->max_pll_freq) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Illegal minimum dotclock specified %.2f MHz " + "(option ignored)\n", + min_dotclock); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Forced minimum dotclock to %.2f MHz " + "(instead of detected %.2f MHz)\n", + min_dotclock, ((double)pll->min_pll_freq/1000)); + pll->min_pll_freq = min_dotclock * 1000; + } + } + + return TRUE; +} + +/* This is called by RADEONPreInit to set up the default visual */ +static Bool RADEONPreInitVisual(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) + return FALSE; + + 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 %s driver\n", + pScrn->depth, RADEON_DRIVER_NAME); + return FALSE; + } + + xf86PrintDepthBpp(pScrn); + + info->fifo_slots = 0; + info->pix24bpp = xf86GetBppFromDepth(pScrn, + pScrn->depth); + info->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; + info->CurrentLayout.depth = pScrn->depth; + info->CurrentLayout.pixel_bytes = pScrn->bitsPerPixel / 8; + info->CurrentLayout.pixel_code = (pScrn->bitsPerPixel != 16 + ? pScrn->bitsPerPixel + : pScrn->depth); + + if (info->pix24bpp == 24) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Radeon does NOT support 24bpp\n"); + return FALSE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n", + pScrn->depth, + info->CurrentLayout.pixel_bytes, + info->CurrentLayout.pixel_bytes > 1 ? "s" : "", + info->pix24bpp); + + if (!xf86SetDefaultVisual(pScrn, -1)) return FALSE; + + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Default visual (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + return FALSE; + } + return TRUE; +} + +/* This is called by RADEONPreInit to handle all color weight issues */ +static Bool RADEONPreInitWeight(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + /* Save flag for 6 bit DAC to use for + setting CRTC registers. Otherwise use + an 8 bit DAC, even if xf86SetWeight sets + pScrn->rgbBits to some value other than + 8. */ + info->dac6bits = FALSE; + + if (pScrn->depth > 8) { + rgb defaultWeight = { 0, 0, 0 }; + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) return FALSE; + } else { + pScrn->rgbBits = 8; + if (xf86ReturnOptValBool(info->Options, OPTION_DAC_6BIT, FALSE)) { + pScrn->rgbBits = 6; + info->dac6bits = TRUE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d bits per RGB (%d bit DAC)\n", + pScrn->rgbBits, info->dac6bits ? 6 : 8); + + return TRUE; +} + +static void RADEONGetVRamType(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 tmp; + + if (info->IsIGP || (info->ChipFamily >= CHIP_FAMILY_R300) || + (INREG(RADEON_MEM_SDRAM_MODE_REG) & (1<<30))) + info->IsDDR = TRUE; + else + info->IsDDR = FALSE; + + tmp = INREG(RADEON_MEM_CNTL); + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) { + tmp &= R300_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: info->RamWidth = 64; break; + case 1: info->RamWidth = 128; break; + case 2: info->RamWidth = 256; break; + default: info->RamWidth = 128; break; + } + } else if ((info->ChipFamily == CHIP_FAMILY_RV100) || + (info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200)){ + if (tmp & RV100_HALF_MODE) info->RamWidth = 32; + else info->RamWidth = 64; + } else { + if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) info->RamWidth = 128; + else info->RamWidth = 64; + } + + /* This may not be correct, as some cards can have half of channel disabled + * ToDo: identify these cases + */ +} + +/* This is called by RADEONPreInit to handle config file overrides for + * things like chipset and memory regions. Also determine memory size + * and type. If memory type ever needs an override, put it in this + * routine. + */ +static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + EntityInfoPtr pEnt = info->pEnt; + GDevPtr dev = pEnt->device; + MessageType from; + unsigned char *RADEONMMIO = info->MMIO; +#ifdef XF86DRI + const char *s; + CARD32 agpCommand; +#endif + + /* Chipset */ + from = X_PROBED; + if (dev->chipset && *dev->chipset) { + info->Chipset = xf86StringToToken(RADEONChipsets, dev->chipset); + from = X_CONFIG; + } else if (dev->chipID >= 0) { + info->Chipset = dev->chipID; + from = X_CONFIG; + } else { + info->Chipset = info->PciInfo->chipType; + } + + pScrn->chipset = (char *)xf86TokenToString(RADEONChipsets, info->Chipset); + if (!pScrn->chipset) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "ChipID 0x%04x is not recognized\n", info->Chipset); + return FALSE; + } + if (info->Chipset < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Chipset \"%s\" is not recognized\n", pScrn->chipset); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, from, + "Chipset: \"%s\" (ChipID = 0x%04x)\n", + pScrn->chipset, + info->Chipset); + + info->HasCRTC2 = TRUE; + info->IsMobility = FALSE; + info->IsIGP = FALSE; + switch (info->Chipset) { + case PCI_CHIP_RADEON_LY: + case PCI_CHIP_RADEON_LZ: + info->IsMobility = TRUE; + info->ChipFamily = CHIP_FAMILY_RV100; + break; + + case PCI_CHIP_RV100_QY: + case PCI_CHIP_RV100_QZ: + info->ChipFamily = CHIP_FAMILY_RV100; + break; + + case PCI_CHIP_RS100_4336: + info->IsMobility = TRUE; + case PCI_CHIP_RS100_4136: + info->ChipFamily = CHIP_FAMILY_RS100; + info->IsIGP = TRUE; + break; + + case PCI_CHIP_RS200_4337: + info->IsMobility = TRUE; + case PCI_CHIP_RS200_4137: + info->ChipFamily = CHIP_FAMILY_RS200; + info->IsIGP = TRUE; + break; + + case PCI_CHIP_RS250_4437: + info->IsMobility = TRUE; + case PCI_CHIP_RS250_4237: + info->ChipFamily = CHIP_FAMILY_RS200; + info->IsIGP = TRUE; + break; + + case PCI_CHIP_R200_BB: + case PCI_CHIP_R200_BC: + case PCI_CHIP_R200_QH: + case PCI_CHIP_R200_QL: + case PCI_CHIP_R200_QM: + info->ChipFamily = CHIP_FAMILY_R200; + break; + + case PCI_CHIP_RADEON_LW: + case PCI_CHIP_RADEON_LX: + info->IsMobility = TRUE; + case PCI_CHIP_RV200_QW: /* RV200 desktop */ + case PCI_CHIP_RV200_QX: + info->ChipFamily = CHIP_FAMILY_RV200; + break; + + case PCI_CHIP_RV250_Ld: + case PCI_CHIP_RV250_Lf: + case PCI_CHIP_RV250_Lg: + info->IsMobility = TRUE; + case PCI_CHIP_RV250_If: + case PCI_CHIP_RV250_Ig: + info->ChipFamily = CHIP_FAMILY_RV250; + break; + + case PCI_CHIP_RS300_5835: + info->IsMobility = TRUE; + case PCI_CHIP_RS300_5834: + info->ChipFamily = CHIP_FAMILY_RS300; + info->IsIGP = TRUE; + break; + + case PCI_CHIP_RV280_5C61: + case PCI_CHIP_RV280_5C63: + info->IsMobility = TRUE; + case PCI_CHIP_RV280_5960: + case PCI_CHIP_RV280_5961: + case PCI_CHIP_RV280_5962: + case PCI_CHIP_RV280_5964: + info->ChipFamily = CHIP_FAMILY_RV280; + break; + + case PCI_CHIP_R300_AD: + case PCI_CHIP_R300_AE: + case PCI_CHIP_R300_AF: + case PCI_CHIP_R300_AG: + case PCI_CHIP_R300_ND: + case PCI_CHIP_R300_NE: + case PCI_CHIP_R300_NF: + case PCI_CHIP_R300_NG: + info->ChipFamily = CHIP_FAMILY_R300; + break; + + case PCI_CHIP_RV350_NP: + case PCI_CHIP_RV350_NQ: + case PCI_CHIP_RV350_NR: + case PCI_CHIP_RV350_NS: + case PCI_CHIP_RV350_NT: + case PCI_CHIP_RV350_NV: + info->IsMobility = TRUE; + case PCI_CHIP_RV350_AP: + case PCI_CHIP_RV350_AQ: + case PCI_CHIP_RV360_AR: + case PCI_CHIP_RV350_AS: + case PCI_CHIP_RV350_AT: + case PCI_CHIP_RV350_AV: + info->ChipFamily = CHIP_FAMILY_RV350; + break; + + case PCI_CHIP_R350_AH: + case PCI_CHIP_R350_AI: + case PCI_CHIP_R350_AJ: + case PCI_CHIP_R350_AK: + case PCI_CHIP_R350_NH: + case PCI_CHIP_R350_NI: + case PCI_CHIP_R350_NK: + case PCI_CHIP_R360_NJ: + info->ChipFamily = CHIP_FAMILY_R350; + break; + + default: + /* Original Radeon/7200 */ + info->ChipFamily = CHIP_FAMILY_RADEON; + info->HasCRTC2 = FALSE; + } + + /* Framebuffer */ + + from = X_PROBED; + info->LinearAddr = info->PciInfo->memBase[0] & 0xfe000000; + pScrn->memPhysBase = info->LinearAddr; + if (dev->MemBase) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Linear address override, using 0x%08lx instead of 0x%08lx\n", + dev->MemBase, + info->LinearAddr); + info->LinearAddr = dev->MemBase; + from = X_CONFIG; + } else if (!info->LinearAddr) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid linear framebuffer address\n"); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, from, + "Linear framebuffer at 0x%08lx\n", info->LinearAddr); + + /* BIOS */ + from = X_PROBED; + info->BIOSAddr = info->PciInfo->biosBase & 0xfffe0000; + if (dev->BiosBase) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS address override, using 0x%08lx instead of 0x%08lx\n", + dev->BiosBase, + info->BIOSAddr); + info->BIOSAddr = dev->BiosBase; + from = X_CONFIG; + } + if (info->BIOSAddr) { + xf86DrvMsg(pScrn->scrnIndex, from, + "BIOS at 0x%08lx\n", info->BIOSAddr); + } + + /* Read registers used to determine options */ + from = X_PROBED; + if (info->FBDev) + pScrn->videoRam = fbdevHWGetVidmem(pScrn) / 1024; + else if ((info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200) || + (info->ChipFamily == CHIP_FAMILY_RS300)) { + CARD32 tom = INREG(RADEON_NB_TOM); + pScrn->videoRam = (((tom >> 16) - + (tom & 0xffff) + 1) << 6); + OUTREG(RADEON_MC_FB_LOCATION, tom); + OUTREG(RADEON_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); + OUTREG(RADEON_DISPLAY2_BASE_ADDR, (tom & 0xffff) << 16); + OUTREG(RADEON_OV0_BASE_ADDR, (tom & 0xffff) << 16); + + /* This is supposed to fix the crtc2 noise problem. + */ + OUTREG(RADEON_GRPH2_BUFFER_CNTL, + INREG(RADEON_GRPH2_BUFFER_CNTL) & ~0x7f0000); + + if ((info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200)) { + /* This is to workaround the asic bug for RMX, some versions + of BIOS dosen't have this register initialized correctly. + */ + OUTREGP(RADEON_CRTC_MORE_CNTL, RADEON_CRTC_H_CUTOFF_ACTIVE_EN, + ~RADEON_CRTC_H_CUTOFF_ACTIVE_EN); + } + + } + else + pScrn->videoRam = INREG(RADEON_CONFIG_MEMSIZE) / 1024; + + /* Some production boards of m6 will return 0 if it's 8 MB */ + if (pScrn->videoRam == 0) pScrn->videoRam = 8192; + + if (info->IsSecondary) { + /* FIXME: For now, split FB into two equal sections. This should + * be able to be adjusted by user with a config option. */ + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + RADEONInfoPtr info1; + + pScrn->videoRam /= 2; + pRADEONEnt->pPrimaryScrn->videoRam = pScrn->videoRam; + + info1 = RADEONPTR(pRADEONEnt->pPrimaryScrn); + info1->FbMapSize = pScrn->videoRam * 1024; + info->LinearAddr += pScrn->videoRam * 1024; + info1->Clone = FALSE; + info1->CurCloneMode = NULL; + } + + info->R300CGWorkaround = + (info->ChipFamily == CHIP_FAMILY_R300 && + (INREG(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) + == RADEON_CFG_ATI_REV_A11); + + info->MemCntl = INREG(RADEON_SDRAM_MODE_REG); + info->BusCntl = INREG(RADEON_BUS_CNTL); + + RADEONGetVRamType(pScrn); + + if (dev->videoRam) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Video RAM override, using %d kB instead of %d kB\n", + dev->videoRam, + pScrn->videoRam); + from = X_CONFIG; + pScrn->videoRam = dev->videoRam; + } + pScrn->videoRam &= ~1023; + info->FbMapSize = pScrn->videoRam * 1024; + xf86DrvMsg(pScrn->scrnIndex, from, + "VideoRAM: %d kByte (%d bit %s SDRAM)\n", pScrn->videoRam, info->RamWidth, info->IsDDR?"DDR":"SDR"); + +#ifdef XF86DRI + /* AGP/PCI */ + /* Proper autodetection of an AGP capable device requires examining + * PCI config registers to determine if the device implements extended + * PCI capabilities, and then walking the capability list as indicated + * in the PCI 2.2 and AGP 2.0 specifications, to determine if AGP + * capability is present. The procedure is outlined as follows: + * + * 1) Test bit 4 (CAP_LIST) of the PCI status register of the device + * to determine wether or not this device implements any extended + * capabilities. If this bit is zero, then the device is a PCI 2.1 + * or earlier device and is not AGP capable, and we can conclude it + * to be a PCI device. + * + * 2) If bit 4 of the status register is set, then the device implements + * extended capabilities. There is an 8 bit wide capabilities pointer + * register located at offset 0x34 in PCI config space which points to + * the first capability in a linked list of extended capabilities that + * this device implements. The lower two bits of this register are + * reserved and MBZ so must be masked out. + * + * 3) The extended capabilities list is formed by one or more extended + * capabilities structures which are aligned on DWORD boundaries. + * The first byte of the structure is the capability ID (CAP_ID) + * indicating what extended capability this structure refers to. The + * second byte of the structure is an offset from the beginning of + * PCI config space pointing to the next capability in the linked + * list (NEXT_PTR) or NULL (0x00) at the end of the list. The lower + * two bits of this pointer are reserved and MBZ. By examining the + * CAP_ID of each capability and walking through the list, we will + * either find the AGP_CAP_ID (0x02) indicating this device is an + * AGP device, or we'll reach the end of the list, indicating it is + * a PCI device. + * + * Mike A. Harris <mharris@redhat.com> + * + * References: + * - PCI Local Bus Specification Revision 2.2, Chapter 6 + * - AGP Interface Specification Revision 2.0, Section 6.1.5 + */ + + info->IsPCI = TRUE; + + if (pciReadLong(info->PciTag, PCI_CMD_STAT_REG) & RADEON_CAP_LIST) { + CARD32 cap_ptr, cap_id; + + cap_ptr = pciReadLong(info->PciTag, + RADEON_CAPABILITIES_PTR_PCI_CONFIG) + & RADEON_CAP_PTR_MASK; + + while(cap_ptr != RADEON_CAP_ID_NULL) { + cap_id = pciReadLong(info->PciTag, cap_ptr); + if ((cap_id & 0xff)== RADEON_CAP_ID_AGP) { + info->IsPCI = FALSE; + break; + } + cap_ptr = (cap_id >> 8) & RADEON_CAP_PTR_MASK; + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s card detected\n", + (info->IsPCI) ? "PCI" : "AGP"); + + if ((s = xf86GetOptValString(info->Options, OPTION_BUS_TYPE))) { + if (strcmp(s, "AGP") == 0) { + info->IsPCI = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into AGP mode\n"); + } else if (strcmp(s, "PCI") == 0) { + info->IsPCI = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI mode\n"); + } else if (strcmp(s, "PCIE") == 0) { + info->IsPCI = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "PCI Express not supported yet, using PCI mode\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Invalid BusType option, using detected type\n"); + } + } else if (xf86ReturnOptValBool(info->Options, OPTION_IS_PCI, FALSE)) { + info->IsPCI = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI mode\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "ForcePCIMode is deprecated -- " + "use BusType option instead\n"); + } +#endif + + return TRUE; +} + +static void RADEONI2CGetBits(I2CBusPtr b, int *Clock, int *data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long val; + unsigned char *RADEONMMIO = info->MMIO; + + /* Get the result */ + val = INREG(info->DDCReg); + + *Clock = (val & RADEON_GPIO_Y_1) != 0; + *data = (val & RADEON_GPIO_Y_0) != 0; +} + +static void RADEONI2CPutBits(I2CBusPtr b, int Clock, int data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long val; + unsigned char *RADEONMMIO = info->MMIO; + + val = INREG(info->DDCReg) & (CARD32)~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1); + val |= (Clock ? 0:RADEON_GPIO_EN_1); + val |= (data ? 0:RADEON_GPIO_EN_0); + OUTREG(info->DDCReg, val); + + /* read back to improve reliability on some cards. */ + val = INREG(info->DDCReg); +} + +static Bool RADEONI2cInit(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + info->pI2CBus = xf86CreateI2CBusRec(); + if (!info->pI2CBus) return FALSE; + + info->pI2CBus->BusName = "DDC"; + info->pI2CBus->scrnIndex = pScrn->scrnIndex; + info->pI2CBus->I2CPutBits = RADEONI2CPutBits; + info->pI2CBus->I2CGetBits = RADEONI2CGetBits; + info->pI2CBus->AcknTimeout = 5; + + if (!xf86I2CBusInit(info->pI2CBus)) return FALSE; + return TRUE; +} + +static void RADEONPreInitDDC(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + /* vbeInfoPtr pVbe; */ + + info->ddc1 = FALSE; + info->ddc_bios = FALSE; + if (!xf86LoadSubModule(pScrn, "ddc")) { + info->ddc2 = FALSE; + } else { + xf86LoaderReqSymLists(ddcSymbols, NULL); + info->ddc2 = TRUE; + } + + /* DDC can use I2C bus */ + /* Load I2C if we have the code to use it */ + if (info->ddc2) { + if (xf86LoadSubModule(pScrn, "i2c")) { + xf86LoaderReqSymLists(i2cSymbols,NULL); + info->ddc2 = RADEONI2cInit(pScrn); + } + else info->ddc2 = FALSE; + } +} + + +/* BIOS may not have right panel size, we search through all supported + * DDC modes looking for the maximum panel size. + */ +static void RADEONUpdatePanelSize(ScrnInfoPtr pScrn) +{ + int j; + RADEONInfoPtr info = RADEONPTR (pScrn); + xf86MonPtr ddc = pScrn->monitor->DDC; + DisplayModePtr p; + + /* Go thru detailed timing table first */ + for (j = 0; j < 4; j++) { + if (ddc->det_mon[j].type == 0) { + struct detailed_timings *d_timings = + &ddc->det_mon[j].section.d_timings; + if (info->PanelXRes < d_timings->h_active && + info->PanelYRes < d_timings->v_active) { + + info->PanelXRes = d_timings->h_active; + info->PanelYRes = d_timings->v_active; + info->DotClock = d_timings->clock / 1000; + info->HOverPlus = d_timings->h_sync_off; + info->HSyncWidth = d_timings->h_sync_width; + info->HBlank = d_timings->h_blanking; + info->VOverPlus = d_timings->v_sync_off; + info->VSyncWidth = d_timings->v_sync_width; + info->VBlank = d_timings->v_blanking; + } + } + } + + /* Search thru standard VESA modes from EDID */ + for (j = 0; j < 8; j++) { + if ((info->PanelXRes < ddc->timings2[j].hsize) && + (info->PanelYRes < ddc->timings2[j].vsize)) { + for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) { + if ((ddc->timings2[j].hsize == p->HDisplay) && + (ddc->timings2[j].vsize == p->VDisplay)) { + float refresh = + (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; + + if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) { + /* Is this good enough? */ + info->PanelXRes = ddc->timings2[j].hsize; + info->PanelYRes = ddc->timings2[j].vsize; + info->HBlank = p->HTotal - p->HDisplay; + info->HOverPlus = p->HSyncStart - p->HDisplay; + info->HSyncWidth = p->HSyncEnd - p->HSyncStart; + info->VBlank = p->VTotal - p->VDisplay; + info->VOverPlus = p->VSyncStart - p->VDisplay; + info->VSyncWidth = p->VSyncEnd - p->VSyncStart; + info->DotClock = p->Clock; + info->Flags = + (ddc->det_mon[j].section.d_timings.interlaced + ? V_INTERLACE + : 0); + if (ddc->det_mon[j].section.d_timings.sync == 3) { + switch (ddc->det_mon[j].section.d_timings.misc) { + case 0: info->Flags |= V_NHSYNC | V_NVSYNC; break; + case 1: info->Flags |= V_PHSYNC | V_NVSYNC; break; + case 2: info->Flags |= V_NHSYNC | V_PVSYNC; break; + case 3: info->Flags |= V_PHSYNC | V_PVSYNC; break; + } + } + } + } + } + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel size found from DDC: %dx%d\n", + info->PanelXRes, info->PanelYRes); +} + +/* This function will sort all modes according to their resolution. + * Highest resolution first. + */ +static void RADEONSortModes(DisplayModePtr *new, DisplayModePtr *first, + DisplayModePtr *last) +{ + DisplayModePtr p; + + p = *last; + while (p) { + if ((((*new)->HDisplay < p->HDisplay) && + ((*new)->VDisplay < p->VDisplay)) || + (((*new)->HDisplay == p->HDisplay) && + ((*new)->VDisplay == p->VDisplay) && + ((*new)->Clock < p->Clock))) { + + if (p->next) p->next->prev = *new; + (*new)->prev = p; + (*new)->next = p->next; + p->next = *new; + if (!((*new)->next)) *last = *new; + break; + } + if (!p->prev) { + (*new)->prev = NULL; + (*new)->next = p; + p->prev = *new; + *first = *new; + break; + } + p = p->prev; + } + + if (!*first) { + *first = *new; + (*new)->prev = NULL; + (*new)->next = NULL; + *last = *new; + } +} + +static void RADEONSetPitch (ScrnInfoPtr pScrn) +{ + int dummy = pScrn->virtualX; + + /* FIXME: May need to validate line pitch here */ + switch (pScrn->depth / 8) { + case 1: dummy = (pScrn->virtualX + 127) & ~127; break; + case 2: dummy = (pScrn->virtualX + 31) & ~31; break; + case 3: + case 4: dummy = (pScrn->virtualX + 15) & ~15; break; + } + pScrn->displayWidth = dummy; +} + +/* When no mode provided in config file, this will add all modes supported in + * DDC date the pScrn->modes list + */ +static DisplayModePtr RADEONDDCModes(ScrnInfoPtr pScrn) +{ + DisplayModePtr p; + DisplayModePtr last = NULL; + DisplayModePtr new = NULL; + DisplayModePtr first = NULL; + int count = 0; + int j, tmp; + char stmp[32]; + xf86MonPtr ddc = pScrn->monitor->DDC; + + /* Go thru detailed timing table first */ + for (j = 0; j < 4; j++) { + if (ddc->det_mon[j].type == 0) { + struct detailed_timings *d_timings = + &ddc->det_mon[j].section.d_timings; + + if (d_timings->h_active == 0 || d_timings->v_active == 0) break; + + new = xnfcalloc(1, sizeof (DisplayModeRec)); + memset(new, 0, sizeof (DisplayModeRec)); + + new->HDisplay = d_timings->h_active; + new->VDisplay = d_timings->v_active; + + sprintf(stmp, "%dx%d", new->HDisplay, new->VDisplay); + new->name = xnfalloc(strlen(stmp) + 1); + strcpy(new->name, stmp); + + new->HTotal = new->HDisplay + d_timings->h_blanking; + new->HSyncStart = new->HDisplay + d_timings->h_sync_off; + new->HSyncEnd = new->HSyncStart + d_timings->h_sync_width; + new->VTotal = new->VDisplay + d_timings->v_blanking; + new->VSyncStart = new->VDisplay + d_timings->v_sync_off; + new->VSyncEnd = new->VSyncStart + d_timings->v_sync_width; + new->Clock = d_timings->clock / 1000; + new->Flags = (d_timings->interlaced ? V_INTERLACE : 0); + new->status = MODE_OK; + new->type = M_T_DEFAULT; + + if (d_timings->sync == 3) { + switch (d_timings->misc) { + case 0: new->Flags |= V_NHSYNC | V_NVSYNC; break; + case 1: new->Flags |= V_PHSYNC | V_NVSYNC; break; + case 2: new->Flags |= V_NHSYNC | V_PVSYNC; break; + case 3: new->Flags |= V_PHSYNC | V_PVSYNC; break; + } + } + count++; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid Mode from Detailed timing table: %s\n", + new->name); + + RADEONSortModes(&new, &first, &last); + } + } + + /* Search thru standard VESA modes from EDID */ + for (j = 0; j < 8; j++) { + for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) { + /* Ignore all double scan modes */ + if ((ddc->timings2[j].hsize == p->HDisplay) && + (ddc->timings2[j].vsize == p->VDisplay)) { + float refresh = + (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; + + if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) { + /* Is this good enough? */ + new = xnfcalloc(1, sizeof (DisplayModeRec)); + memcpy(new, p, sizeof(DisplayModeRec)); + new->name = xnfalloc(strlen(p->name) + 1); + strcpy(new->name, p->name); + new->status = MODE_OK; + new->type = M_T_DEFAULT; + + count++; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid Mode from standard timing table: %s\n", + new->name); + + RADEONSortModes(&new, &first, &last); + break; + } + } + } + } + + /* Search thru established modes from EDID */ + tmp = (ddc->timings1.t1 << 8) | ddc->timings1.t2; + for (j = 0; j < 16; j++) { + if (tmp & (1 << j)) { + for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) { + if ((est_timings[j].hsize == p->HDisplay) && + (est_timings[j].vsize == p->VDisplay)) { + float refresh = + (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; + + if (abs((float)est_timings[j].refresh - refresh) < 1.0) { + /* Is this good enough? */ + new = xnfcalloc(1, sizeof (DisplayModeRec)); + memcpy(new, p, sizeof(DisplayModeRec)); + new->name = xnfalloc(strlen(p->name) + 1); + strcpy(new->name, p->name); + new->status = MODE_OK; + new->type = M_T_DEFAULT; + + count++; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid Mode from established timing " + "table: %s\n", new->name); + + RADEONSortModes(&new, &first, &last); + break; + } + } + } + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Total of %d mode(s) found.\n", count); + + return first; +} + +/* XFree86's xf86ValidateModes routine doesn't work well with DDC modes, + * so here is our own validation routine. + */ +static int RADEONValidateDDCModes(ScrnInfoPtr pScrn, char **ppModeName, + RADEONMonitorType DisplayType) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + DisplayModePtr p; + DisplayModePtr last = NULL; + DisplayModePtr first = NULL; + DisplayModePtr ddcModes = NULL; + int count = 0; + int i, width, height; + + pScrn->virtualX = pScrn->display->virtualX; + pScrn->virtualY = pScrn->display->virtualY; + + if (pScrn->monitor->DDC && !info->UseBiosDividers) { + int maxVirtX = pScrn->virtualX; + int maxVirtY = pScrn->virtualY; + + if ((DisplayType != MT_CRT) && !info->IsSecondary) { + /* The panel size we collected from BIOS may not be the + * maximum size supported by the panel. If not, we update + * it now. These will be used if no matching mode can be + * found from EDID data. + */ + RADEONUpdatePanelSize(pScrn); + } + + /* Collect all of the DDC modes */ + first = last = ddcModes = RADEONDDCModes(pScrn); + + for (p = ddcModes; p; p = p->next) { + + /* If primary head is a flat panel, use RMX by default */ + if ((!info->IsSecondary && DisplayType != MT_CRT) && + !info->ddc_mode) { + /* These values are effective values after expansion. + * They are not really used to set CRTC registers. + */ + p->HTotal = info->PanelXRes + info->HBlank; + p->HSyncStart = info->PanelXRes + info->HOverPlus; + p->HSyncEnd = p->HSyncStart + info->HSyncWidth; + p->VTotal = info->PanelYRes + info->VBlank; + p->VSyncStart = info->PanelYRes + info->VOverPlus; + p->VSyncEnd = p->VSyncStart + info->VSyncWidth; + p->Clock = info->DotClock; + + p->Flags |= RADEON_USE_RMX; + } + + maxVirtX = MAX(maxVirtX, p->HDisplay); + maxVirtY = MAX(maxVirtY, p->VDisplay); + count++; + + last = p; + } + + /* Match up modes that are specified in the XF86Config file */ + if (ppModeName[0]) { + DisplayModePtr next; + + /* Reset the max virtual dimensions */ + maxVirtX = pScrn->virtualX; + maxVirtY = pScrn->virtualY; + + /* Reset list */ + first = last = NULL; + + for (i = 0; ppModeName[i]; i++) { + /* FIXME: Use HDisplay and VDisplay instead of mode string */ + if (sscanf(ppModeName[i], "%dx%d", &width, &height) == 2) { + for (p = ddcModes; p; p = next) { + next = p->next; + + if (p->HDisplay == width && p->VDisplay == height) { + /* We found a DDC mode that matches the one + requested in the XF86Config file */ + p->type |= M_T_USERDEF; + + /* Update the max virtual setttings */ + maxVirtX = MAX(maxVirtX, width); + maxVirtY = MAX(maxVirtY, height); + + /* Unhook from DDC modes */ + if (p->prev) p->prev->next = p->next; + if (p->next) p->next->prev = p->prev; + if (p == ddcModes) ddcModes = p->next; + + /* Add to used modes */ + if (last) { + last->next = p; + p->prev = last; + } else { + first = p; + p->prev = NULL; + } + p->next = NULL; + last = p; + + break; + } + } + } + } + + /* + * Add remaining DDC modes if they're smaller than the user + * specified modes + */ + for (p = ddcModes; p; p = next) { + next = p->next; + if (p->HDisplay <= maxVirtX && p->VDisplay <= maxVirtY) { + /* Unhook from DDC modes */ + if (p->prev) p->prev->next = p->next; + if (p->next) p->next->prev = p->prev; + if (p == ddcModes) ddcModes = p->next; + + /* Add to used modes */ + if (last) { + last->next = p; + p->prev = last; + } else { + first = p; + p->prev = NULL; + } + p->next = NULL; + last = p; + } + } + + /* Delete unused modes */ + while (ddcModes) + xf86DeleteMode(&ddcModes, ddcModes); + } else { + /* + * No modes were configured, so we make the DDC modes + * available for the user to cycle through. + */ + for (p = ddcModes; p; p = p->next) + p->type |= M_T_USERDEF; + } + + pScrn->virtualX = pScrn->display->virtualX = maxVirtX; + pScrn->virtualY = pScrn->display->virtualY = maxVirtY; + } + + /* Close the doubly-linked mode list, if we found any usable modes */ + if (last) { + last->next = first; + first->prev = last; + pScrn->modes = first; + RADEONSetPitch(pScrn); + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Total number of valid DDC mode(s) found: %d\n", count); + + return count; +} + +/* This is used only when no mode is specified for FP and no ddc is + * available. We force it to native mode, if possible. + */ +static DisplayModePtr RADEONFPNativeMode(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + DisplayModePtr new = NULL; + char stmp[32]; + + if (info->PanelXRes != 0 && + info->PanelYRes != 0 && + info->DotClock != 0) { + + /* Add native panel size */ + new = xnfcalloc(1, sizeof (DisplayModeRec)); + sprintf(stmp, "%dx%d", info->PanelXRes, info->PanelYRes); + new->name = xnfalloc(strlen(stmp) + 1); + strcpy(new->name, stmp); + new->HDisplay = info->PanelXRes; + new->VDisplay = info->PanelYRes; + + new->HTotal = new->HDisplay + info->HBlank; + new->HSyncStart = new->HDisplay + info->HOverPlus; + new->HSyncEnd = new->HSyncStart + info->HSyncWidth; + new->VTotal = new->VDisplay + info->VBlank; + new->VSyncStart = new->VDisplay + info->VOverPlus; + new->VSyncEnd = new->VSyncStart + info->VSyncWidth; + + new->Clock = info->DotClock; + new->Flags = 0; + new->type = M_T_USERDEF; + + new->next = NULL; + new->prev = NULL; + + pScrn->display->virtualX = + pScrn->virtualX = MAX(pScrn->virtualX, info->PanelXRes); + pScrn->display->virtualY = + pScrn->virtualY = MAX(pScrn->virtualY, info->PanelYRes); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No valid mode specified, force to native mdoe\n"); + } + + return new; +} + +/* FP mode initialization routine for using on-chip RMX to scale + */ +static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + DisplayModePtr last = NULL; + DisplayModePtr new = NULL; + DisplayModePtr first = NULL; + DisplayModePtr p, tmp; + int count = 0; + int i, width, height; + + pScrn->virtualX = pScrn->display->virtualX; + pScrn->virtualY = pScrn->display->virtualY; + + /* We have a flat panel connected to the primary display, and we + * don't have any DDC info. + */ + for (i = 0; ppModeName[i] != NULL; i++) { + + if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2) continue; + + /* Note: We allow all non-standard modes as long as they do not + * exceed the native resolution of the panel. Since these modes + * need the internal RMX unit in the video chips (and there is + * only one per card), this will only apply to the primary head. + */ + if (width < 320 || width > info->PanelXRes || + height < 200 || height > info->PanelYRes) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode %s is out of range.\n", ppModeName[i]); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Valid modes must be between 320x200-%dx%d\n", + info->PanelXRes, info->PanelYRes); + continue; + } + + new = xnfcalloc(1, sizeof(DisplayModeRec)); + new->name = xnfalloc(strlen(ppModeName[i]) + 1); + strcpy(new->name, ppModeName[i]); + new->HDisplay = width; + new->VDisplay = height; + + /* These values are effective values after expansion They are + * not really used to set CRTC registers. + */ + new->HTotal = info->PanelXRes + info->HBlank; + new->HSyncStart = info->PanelXRes + info->HOverPlus; + new->HSyncEnd = new->HSyncStart + info->HSyncWidth; + new->VTotal = info->PanelYRes + info->VBlank; + new->VSyncStart = info->PanelYRes + info->VOverPlus; + new->VSyncEnd = new->VSyncStart + info->VSyncWidth; + new->Clock = info->DotClock; + new->Flags |= RADEON_USE_RMX; + + new->type |= M_T_USERDEF; + + new->next = NULL; + new->prev = last; + + if (last) last->next = new; + last = new; + if (!first) first = new; + + pScrn->display->virtualX = + pScrn->virtualX = MAX(pScrn->virtualX, width); + pScrn->display->virtualY = + pScrn->virtualY = MAX(pScrn->virtualY, height); + count++; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid mode using on-chip RMX: %s\n", new->name); + } + + /* If all else fails, add the native mode */ + if (!count) { + first = last = RADEONFPNativeMode(pScrn); + if (first) count = 1; + } + + /* add in all default vesa modes smaller than panel size, used for randr*/ + for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) { + if ((p->HDisplay <= info->PanelXRes) && (p->VDisplay <= info->PanelYRes)) { + tmp = first; + while (tmp) { + if ((p->HDisplay == tmp->HDisplay) && (p->VDisplay == tmp->VDisplay)) break; + tmp = tmp->next; + } + if (!tmp) { + new = xnfcalloc(1, sizeof(DisplayModeRec)); + new->name = xnfalloc(strlen(p->name) + 1); + strcpy(new->name, p->name); + new->HDisplay = p->HDisplay; + new->VDisplay = p->VDisplay; + + /* These values are effective values after expansion They are + * not really used to set CRTC registers. + */ + new->HTotal = info->PanelXRes + info->HBlank; + new->HSyncStart = info->PanelXRes + info->HOverPlus; + new->HSyncEnd = new->HSyncStart + info->HSyncWidth; + new->VTotal = info->PanelYRes + info->VBlank; + new->VSyncStart = info->PanelYRes + info->VOverPlus; + new->VSyncEnd = new->VSyncStart + info->VSyncWidth; + new->Clock = info->DotClock; + new->Flags |= RADEON_USE_RMX; + + new->type |= M_T_DEFAULT; + + new->next = NULL; + new->prev = last; + + last->next = new; + last = new; + } + } + } + + /* Close the doubly-linked mode list, if we found any usable modes */ + if (last) { + last->next = first; + first->prev = last; + pScrn->modes = first; + RADEONSetPitch(pScrn); + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Total number of valid FP mode(s) found: %d\n", count); + + return count; +} + +/* This is called by RADEONPreInit to initialize gamma correction */ +static Bool RADEONPreInitGamma(ScrnInfoPtr pScrn) +{ + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) return FALSE; + return TRUE; +} + +static void RADEONSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag) +{ + MonPtr mon = pScrn->monitor; + xf86MonPtr ddc = mon->DDC; + int i; + + if (flag) { /* HSync */ + for (i = 0; i < 4; i++) { + if (ddc->det_mon[i].type == DS_RANGES) { + mon->nHsync = 1; + mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h; + mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h; + return; + } + } + /* If no sync ranges detected in detailed timing table, let's + * try to derive them from supported VESA modes. Are we doing + * too much here!!!? */ + i = 0; + if (ddc->timings1.t1 & 0x02) { /* 800x600@56 */ + mon->hsync[i].lo = mon->hsync[i].hi = 35.2; + i++; + } + if (ddc->timings1.t1 & 0x04) { /* 640x480@75 */ + mon->hsync[i].lo = mon->hsync[i].hi = 37.5; + i++; + } + if ((ddc->timings1.t1 & 0x08) || (ddc->timings1.t1 & 0x01)) { + mon->hsync[i].lo = mon->hsync[i].hi = 37.9; + i++; + } + if (ddc->timings1.t2 & 0x40) { + mon->hsync[i].lo = mon->hsync[i].hi = 46.9; + i++; + } + if ((ddc->timings1.t2 & 0x80) || (ddc->timings1.t2 & 0x08)) { + mon->hsync[i].lo = mon->hsync[i].hi = 48.1; + i++; + } + if (ddc->timings1.t2 & 0x04) { + mon->hsync[i].lo = mon->hsync[i].hi = 56.5; + i++; + } + if (ddc->timings1.t2 & 0x02) { + mon->hsync[i].lo = mon->hsync[i].hi = 60.0; + i++; + } + if (ddc->timings1.t2 & 0x01) { + mon->hsync[i].lo = mon->hsync[i].hi = 64.0; + i++; + } + mon->nHsync = i; + } else { /* Vrefresh */ + for (i = 0; i < 4; i++) { + if (ddc->det_mon[i].type == DS_RANGES) { + mon->nVrefresh = 1; + mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v; + mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v; + return; + } + } + + i = 0; + if (ddc->timings1.t1 & 0x02) { /* 800x600@56 */ + mon->vrefresh[i].lo = mon->vrefresh[i].hi = 56; + i++; + } + if ((ddc->timings1.t1 & 0x01) || (ddc->timings1.t2 & 0x08)) { + mon->vrefresh[i].lo = mon->vrefresh[i].hi = 60; + i++; + } + if (ddc->timings1.t2 & 0x04) { + mon->vrefresh[i].lo = mon->vrefresh[i].hi = 70; + i++; + } + if ((ddc->timings1.t1 & 0x08) || (ddc->timings1.t2 & 0x80)) { + mon->vrefresh[i].lo = mon->vrefresh[i].hi = 72; + i++; + } + if ((ddc->timings1.t1 & 0x04) || (ddc->timings1.t2 & 0x40) || + (ddc->timings1.t2 & 0x02) || (ddc->timings1.t2 & 0x01)) { + mon->vrefresh[i].lo = mon->vrefresh[i].hi = 75; + i++; + } + mon->nVrefresh = i; + } +} + +static int RADEONValidateCloneModes(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ClockRangePtr clockRanges; + DisplayModePtr tmp_mode = NULL; + DisplayModePtr clone_mode, save_mode; + int modesFound = 0; + int count = 0; + int tmp_hdisplay = 0; + int tmp_vdisplay = 0; + int i, save_n_hsync, save_n_vrefresh; + range save_hsync, save_vrefresh; + char *s; + char **clone_mode_names = NULL; + Bool ddc_mode = info->ddc_mode; + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + /* Save all infomations that will be changed by clone mode validateion */ + save_mode = pScrn->modes; + pScrn->modes = NULL; + + /* Clone display mode names, duplicate all mode names for primary + * head. Allocate one more, in case pScrn->display->modes[0] == + * NULL */ + while (pScrn->display->modes[count]) count++; + clone_mode_names = xnfalloc((count+2) * sizeof(char*)); + for (i = 0; i < count; i++) { + clone_mode_names[i] = xnfalloc(strlen(pScrn->display->modes[i]) + 1); + strcpy(clone_mode_names[i], pScrn->display->modes[i]); + } + clone_mode_names[count] = NULL; + clone_mode_names[count+1] = NULL; + + pScrn->progClock = TRUE; + + clockRanges = xnfcalloc(sizeof(*clockRanges), 1); + clockRanges->next = NULL; + clockRanges->minClock = info->pll.min_pll_freq; + clockRanges->maxClock = info->pll.max_pll_freq * 10; + clockRanges->clockIndex = -1; + clockRanges->interlaceAllowed = (info->CloneType == MT_CRT); + clockRanges->doubleScanAllowed = (info->CloneType == MT_CRT); + + /* Only take one clone mode from config file for now, rest of clone + * modes will copy from primary head. + */ + if ((s = xf86GetOptValString(info->Options, OPTION_CLONE_MODE))) { + if (sscanf(s, "%dx%d", &tmp_hdisplay, &tmp_vdisplay) == 2) { + if(count > 0) free(clone_mode_names[0]); + else count++; + clone_mode_names[0] = xnfalloc(strlen(s)+1); + sprintf(clone_mode_names[0], "%dx%d", tmp_hdisplay, tmp_vdisplay); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clone mode %s in config file is used\n", clone_mode_names[0]); + } + } + + for (i = 0; i < count; i++) { + if (sscanf(clone_mode_names[i], "%dx%d", + &tmp_hdisplay, &tmp_vdisplay) == 2) { + if (pScrn->display->virtualX < tmp_hdisplay) + pScrn->display->virtualX = tmp_hdisplay; + if (pScrn->display->virtualY < tmp_vdisplay) + pScrn->display->virtualY = tmp_vdisplay; + } + } + + save_hsync = pScrn->monitor->hsync[0]; + save_vrefresh = pScrn->monitor->vrefresh[0]; + save_n_hsync = pScrn->monitor->nHsync; + save_n_vrefresh = pScrn->monitor->nVrefresh; + + pScrn->monitor->DDC = NULL; + pScrn->monitor->nHsync = 0; + pScrn->monitor->nVrefresh = 0; + + if ((s = xf86GetOptValString(info->Options, OPTION_CLONE_HSYNC))) { + if (sscanf(s, "%f-%f", &pScrn->monitor->hsync[0].lo, + &pScrn->monitor->hsync[0].hi) == 2) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "HSync for CloneMode from config file: %s\n", s); + pScrn->monitor->nHsync = 1; + } else { + pScrn->monitor->nHsync = 0; + } + } + + if ((s = xf86GetOptValString(info->Options, OPTION_CLONE_VREFRESH))) { + if (sscanf(s, "%f-%f", &pScrn->monitor->vrefresh[0].lo, + &pScrn->monitor->vrefresh[0].hi) == 2) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "VRefresh for CloneMode from config file: %s\n", s); + pScrn->monitor->nVrefresh = 1; + } else { + pScrn->monitor->nVrefresh = 0; + } + } + + pScrn->monitor->DDC = pRADEONEnt->MonInfo2; + if (pScrn->monitor->DDC) { + if ((pScrn->monitor->nVrefresh == 0) || (pScrn->monitor->nHsync == 0)) { + if (pScrn->monitor->nHsync == 0) + RADEONSetSyncRangeFromEdid(pScrn, 1); + if (pScrn->monitor->nVrefresh == 0) + RADEONSetSyncRangeFromEdid(pScrn, 0); + } + } else if (info->ddc_mode) { + ddc_mode = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No DDC data available for clone mode, " + "DDCMode option is dismissed\n"); + } + + if (info->CloneType == MT_CRT && !ddc_mode) { + modesFound = + xf86ValidateModes(pScrn, pScrn->monitor->Modes, + clone_mode_names, + clockRanges, + NULL, /* linePitches */ + 8 * 64, /* minPitch */ + 8 * 1024, /* maxPitch */ + 64 * pScrn->bitsPerPixel, /* pitchInc */ + 128, /* minHeight */ + 2048, /* maxHeight */ + pScrn->display->virtualX, + pScrn->display->virtualY, + info->FbMapSize, + LOOKUP_BEST_REFRESH); + } else { + /* Try to add DDC modes */ + info->IsSecondary = TRUE; /*fake secondary head*/ + modesFound = RADEONValidateDDCModes(pScrn, clone_mode_names, + info->CloneType); + info->IsSecondary = FALSE; + + /* If that fails and we're connect to a flat panel, then try to + * add the flat panel modes + */ + if (modesFound < 1 && info->CloneType != MT_CRT) { + modesFound = + xf86ValidateModes(pScrn, pScrn->monitor->Modes, + clone_mode_names, + clockRanges, + NULL, /* linePitches */ + 8 * 64, /* minPitch */ + 8 * 1024, /* maxPitch */ + 64 * pScrn->bitsPerPixel, /* pitchInc */ + 128, /* minHeight */ + 2048, /* maxHeight */ + pScrn->display->virtualX, + pScrn->display->virtualY, + info->FbMapSize, + LOOKUP_BEST_REFRESH); + } + } + + if (modesFound > 0) { + int valid = 0; + save_mode = pScrn->modes; + xf86SetCrtcForModes(pScrn, 0); + xf86PrintModes(pScrn); + for (i = 0; i < modesFound; i++) { + + while (pScrn->modes->status != MODE_OK) { + pScrn->modes = pScrn->modes->next; + } + if (!pScrn->modes) break; + + if (pScrn->modes->Clock != 0.0) { + + clone_mode = xnfcalloc (1, sizeof (DisplayModeRec)); + if (!clone_mode) break; + memcpy(clone_mode, pScrn->modes, sizeof(DisplayModeRec)); + clone_mode->name = xnfalloc(strlen(pScrn->modes->name) + 1); + strcpy(clone_mode->name, pScrn->modes->name); + + if (!info->CurCloneMode) { + info->CloneModes = clone_mode; + info->CurCloneMode = clone_mode; + clone_mode->prev = NULL; + } else { + clone_mode->prev = tmp_mode; + clone_mode->prev->next = clone_mode; + } + valid++; + + tmp_mode = clone_mode; + clone_mode->next = NULL; + } + pScrn->modes = pScrn->modes->next; + } + + /* no longer needed, free it */ + pScrn->modes = save_mode; + while (pScrn->modes) + xf86DeleteMode(&pScrn->modes, pScrn->modes); + pScrn->modes = NULL; + + /* modepool is no longer needed, free it */ + while (pScrn->modePool) + xf86DeleteMode(&pScrn->modePool, pScrn->modePool); + pScrn->modePool = NULL; + + modesFound = valid; + } + + /* Clone_mode_names list is no longer needed, free it. */ + if (clone_mode_names) { + for (i = 0; clone_mode_names[i]; i++) { + free(clone_mode_names[i]); + clone_mode_names[i] = NULL; + } + + free(clone_mode_names); + clone_mode_names = NULL; + } + + /* We need to restore all changed info for the primary head */ + + pScrn->monitor->hsync[0] = save_hsync; + pScrn->monitor->vrefresh[0] = save_vrefresh; + pScrn->monitor->nHsync = save_n_hsync; + pScrn->monitor->nVrefresh = save_n_vrefresh; + + /* + * Also delete the clockRanges (if it was setup) since it will be + * set up during the primary head initialization. + */ + while (pScrn->clockRanges) { + ClockRangesPtr CRtmp = pScrn->clockRanges; + pScrn->clockRanges = pScrn->clockRanges->next; + xfree(CRtmp); + } + + + return modesFound; +} + +/* This is called by RADEONPreInit to validate modes and compute + * parameters for all of the valid modes. + */ +static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ClockRangePtr clockRanges; + int modesFound; + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + char *s; + + /* This option has two purposes: + * + * 1. For CRT, if this option is on, xf86ValidateModes (to + * LOOKUP_BEST_REFRESH) is not going to be used for mode + * validation. Instead, we'll validate modes by matching exactly + * the modes supported from the DDC data. This option can be + * used (a) to enable non-standard modes listed in the Detailed + * Timings block of EDID, like 2048x1536 (not included in + * xf86DefModes), (b) to avoid unstable modes for some flat + * panels working in analog mode (some modes validated by + * xf86ValidateModes don't really work with these panels). + * + * 2. For DFP on primary head, with this option on, the validation + * routine will try to use supported modes from DDC data first + * before trying on-chip RMX streching. By default, native mode + * + RMX streching is used for all non-native modes, it appears + * more reliable. Some non-native modes listed in the DDC data + * may not work properly if they are used directly. This seems to + * only happen to a few panels (haven't nailed this down yet, it + * may related to the incorrect setting in TMDS_PLL_CNTL when + * pixel clock is changed). Use this option may give you better + * refresh rate for some non-native modes. The 2nd DVI port will + * always use DDC modes directly (only have one on-chip RMX + * unit). + * + * Note: This option will be dismissed if no DDC data is available. + */ + info->ddc_mode = + xf86ReturnOptValBool(info->Options, OPTION_DDC_MODE, FALSE); + + /* don't use RMX if we have a dual-tdms panels */ + if (pRADEONEnt->MonType2 == MT_DFP) + info->ddc_mode = TRUE; + + /* Here is a hack for cloning first display on the second head. If + * we don't do this, when both heads are connected, the same CRTC + * will be used to drive them according to the capability of the + * primary head. This can cause an unstable or blank screen, or + * even worse it can damage a monitor. This feature is also + * important for laptops (using M6, M7), where the panel can't be + * disconnect when one wants to use the CRT port. Although 2 + * Screens can be set up in the config file for displaying same + * content on two monitors, it has problems with cursor, overlay, + * DRI. + */ + if (info->HasCRTC2) { + if (info->Clone) { + + /* If we have 2 screens from the config file, we don't need + * to do clone thing, let each screen handles one head. + */ + if (!pRADEONEnt->HasSecondary) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Clone modes validation ------------ \n"); + + modesFound = RADEONValidateCloneModes(pScrn); + if (modesFound < 1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid mode found for CRTC2 clone\n"); + info->Clone = FALSE; + info->CurCloneMode = NULL; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Total of %d clone modes found ------------ \n\n", + modesFound); + } + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Validating modes on %s head ---------\n", + info->IsSecondary ? "Secondary" : "Primary"); + + if (info->IsSecondary) + pScrn->monitor->DDC = pRADEONEnt->MonInfo2; + else + pScrn->monitor->DDC = pRADEONEnt->MonInfo1; + + if (!pScrn->monitor->DDC && info->ddc_mode) { + info->ddc_mode = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No DDC data available, DDCMode option is dismissed\n"); + } + + if ((info->DisplayType == MT_DFP) || + (info->DisplayType == MT_LCD)) { + if ((s = xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) { + int PanelX, PanelY; + DisplayModePtr tmp_mode = NULL; + if (sscanf(s, "%dx%d", &PanelX, &PanelY) == 2) { + info->PanelXRes = PanelX; + info->PanelYRes = PanelY; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Panel size is forced to: %s\n", s); + + /* We can't trust BIOS or DDC timings anymore, + Use whatever specified in the Modeline. + If no Modeline specified, we'll just pick the VESA mode at + 60Hz refresh rate which is likely to be the best for a flat panel. + */ + info->ddc_mode = FALSE; + pScrn->monitor->DDC = NULL; + tmp_mode = pScrn->monitor->Modes; + while(tmp_mode) { + if ((tmp_mode->HDisplay == PanelX) && + (tmp_mode->VDisplay == PanelY)) { + + float refresh = + (float)tmp_mode->Clock * 1000.0 / tmp_mode->HTotal / tmp_mode->VTotal; + if ((abs(60.0 - refresh) < 1.0) || + (tmp_mode->type == 0)) { + info->HBlank = tmp_mode->HTotal - tmp_mode->HDisplay; + info->HOverPlus = tmp_mode->HSyncStart - tmp_mode->HDisplay; + info->HSyncWidth = tmp_mode->HSyncEnd - tmp_mode->HSyncStart; + info->VBlank = tmp_mode->VTotal - tmp_mode->VDisplay; + info->VOverPlus = tmp_mode->VSyncStart - tmp_mode->VDisplay; + info->VSyncWidth = tmp_mode->VSyncEnd - tmp_mode->VSyncStart; + info->DotClock = tmp_mode->Clock; + info->Flags = 0; + break; + } + } + tmp_mode = tmp_mode->next; + } + if (info->DotClock == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid timing info for specified panel size.\n" + "Please specify the Modeline for this panel\n"); + return FALSE; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Invalid PanelSize value: %s\n", s); + } + } + } + + if (pScrn->monitor->DDC) { + /* If we still don't know sync range yet, let's try EDID. + * + * Note that, since we can have dual heads, Xconfigurator + * may not be able to probe both monitors correctly through + * vbe probe function (RADEONProbeDDC). Here we provide an + * additional way to auto-detect sync ranges if they haven't + * been added to XF86Config manually. + */ + if (pScrn->monitor->nHsync <= 0) + RADEONSetSyncRangeFromEdid(pScrn, 1); + if (pScrn->monitor->nVrefresh <= 0) + RADEONSetSyncRangeFromEdid(pScrn, 0); + } + + /* Get mode information */ + pScrn->progClock = TRUE; + clockRanges = xnfcalloc(sizeof(*clockRanges), 1); + clockRanges->next = NULL; + clockRanges->minClock = info->pll.min_pll_freq; + clockRanges->maxClock = info->pll.max_pll_freq * 10; + clockRanges->clockIndex = -1; + clockRanges->interlaceAllowed = (info->DisplayType == MT_CRT); + clockRanges->doubleScanAllowed = (info->DisplayType == MT_CRT); + + /* We'll use our own mode validation routine for DFP/LCD, since + * xf86ValidateModes does not work correctly with the DFP/LCD modes + * 'stretched' from their native mode. + */ + if (info->DisplayType == MT_CRT && !info->ddc_mode) { + + modesFound = + xf86ValidateModes(pScrn, + pScrn->monitor->Modes, + pScrn->display->modes, + clockRanges, + NULL, /* linePitches */ + 8 * 64, /* minPitch */ + 8 * 1024, /* maxPitch */ + 64 * pScrn->bitsPerPixel, /* pitchInc */ + 128, /* minHeight */ + 2048, /* maxHeight */ + pScrn->display->virtualX, + pScrn->display->virtualY, + info->FbMapSize, + LOOKUP_BEST_REFRESH); + + if (modesFound < 1 && info->FBDev) { + fbdevHWUseBuildinMode(pScrn); + pScrn->displayWidth = pScrn->virtualX; /* FIXME: might be wrong */ + modesFound = 1; + } + + if (modesFound == -1) return FALSE; + + xf86PruneDriverModes(pScrn); + if (!modesFound || !pScrn->modes) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + return FALSE; + } + + } else { + /* First, free any allocated modes during configuration, since + * we don't need them + */ + while (pScrn->modes) + xf86DeleteMode(&pScrn->modes, pScrn->modes); + while (pScrn->modePool) + xf86DeleteMode(&pScrn->modePool, pScrn->modePool); + + /* Next try to add DDC modes */ + modesFound = RADEONValidateDDCModes(pScrn, pScrn->display->modes, + info->DisplayType); + + /* If that fails and we're connect to a flat panel, then try to + * add the flat panel modes + */ + if (info->DisplayType != MT_CRT) { + + /* some panels have DDC, but don't have internal scaler. + * in this case, we need to validate additional modes + * by using on-chip RMX. + */ + int user_modes_asked = 0, user_modes_found = 0, i; + DisplayModePtr tmp_mode = pScrn->modes; + while (pScrn->display->modes[user_modes_asked]) user_modes_asked++; + if (tmp_mode) { + for (i = 0; i < modesFound; i++) { + if (tmp_mode->type & M_T_USERDEF) user_modes_found++; + tmp_mode = tmp_mode->next; + } + } + + if ((modesFound <= 1) || (user_modes_found < user_modes_asked)) { + /* when panel size is not valid, try to validate + * mode using xf86ValidateModes routine + * This can happen when DDC is disabled. + */ + if (info->PanelXRes < 320 || info->PanelYRes < 200) + modesFound = + xf86ValidateModes(pScrn, + pScrn->monitor->Modes, + pScrn->display->modes, + clockRanges, + NULL, /* linePitches */ + 8 * 64, /* minPitch */ + 8 * 1024, /* maxPitch */ + 64 * pScrn->bitsPerPixel, /* pitchInc */ + 128, /* minHeight */ + 2048, /* maxHeight */ + pScrn->display->virtualX, + pScrn->display->virtualY, + info->FbMapSize, + LOOKUP_BEST_REFRESH); + else if (!info->IsSecondary) + modesFound = RADEONValidateFPModes(pScrn, pScrn->display->modes); + } + } + + /* Setup the screen's clockRanges for the VidMode extension */ + if (!pScrn->clockRanges) { + pScrn->clockRanges = xnfcalloc(sizeof(*(pScrn->clockRanges)), 1); + memcpy(pScrn->clockRanges, clockRanges, sizeof(*clockRanges)); + pScrn->clockRanges->strategy = LOOKUP_BEST_REFRESH; + } + + /* Fail if we still don't have any valid modes */ + if (modesFound < 1) { + if (info->DisplayType == MT_CRT) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid DDC modes found for this CRT\n"); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Try turning off the \"DDCMode\" option\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid mode found for this DFP/LCD\n"); + } + return FALSE; + } + } + + xf86SetCrtcForModes(pScrn, 0); + + /* We need to adjust virtual size if the clone modes have larger + * display size. + */ + if (info->Clone && info->CloneModes) { + DisplayModePtr clone_mode = info->CloneModes; + while (1) { + if ((clone_mode->HDisplay > pScrn->virtualX) || + (clone_mode->VDisplay > pScrn->virtualY)) { + pScrn->virtualX = + pScrn->display->virtualX = clone_mode->HDisplay; + pScrn->virtualY = + pScrn->display->virtualY = clone_mode->VDisplay; + RADEONSetPitch(pScrn); + } + if (!clone_mode->next) break; + clone_mode = clone_mode->next; + } + } + + pScrn->currentMode = pScrn->modes; + xf86PrintModes(pScrn); + + /* Set DPI */ + xf86SetDpi(pScrn, 0, 0); + + /* Get ScreenInit function */ + if (!xf86LoadSubModule(pScrn, "fb")) return FALSE; + + xf86LoaderReqSymLists(fbSymbols, NULL); + + info->CurrentLayout.displayWidth = pScrn->displayWidth; + info->CurrentLayout.mode = pScrn->currentMode; + + return TRUE; +} + +/* This is called by RADEONPreInit to initialize the hardware cursor */ +static Bool RADEONPreInitCursor(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { + if (!xf86LoadSubModule(pScrn, "ramdac")) return FALSE; + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + return TRUE; +} + +/* This is called by RADEONPreInit to initialize hardware acceleration */ +static Bool RADEONPreInitAccel(ScrnInfoPtr pScrn) +{ +#ifdef XFree86LOADER + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { + int errmaj = 0, errmin = 0; + + info->xaaReq.majorversion = 1; + info->xaaReq.minorversion = 1; + + if (!LoadSubModule(pScrn->module, "xaa", NULL, NULL, NULL, + &info->xaaReq, &errmaj, &errmin)) { + info->xaaReq.minorversion = 0; + + if (!LoadSubModule(pScrn->module, "xaa", NULL, NULL, NULL, + &info->xaaReq, &errmaj, &errmin)) { + LoaderErrorMsg(NULL, "xaa", errmaj, errmin); + return FALSE; + } + } + xf86LoaderReqSymLists(xaaSymbols, NULL); + } +#endif + + return TRUE; +} + +static Bool RADEONPreInitInt10(ScrnInfoPtr pScrn, xf86Int10InfoPtr *ppInt10) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + +#if !defined(__powerpc__) + if (xf86LoadSubModule(pScrn, "int10")) { + xf86LoaderReqSymLists(int10Symbols, NULL); + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); + *ppInt10 = xf86InitInt10(info->pEnt->index); + } +#endif + return TRUE; +} + +#ifdef XF86DRI +static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (xf86ReturnOptValBool(info->Options, OPTION_CP_PIO, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing CP into PIO mode\n"); + info->CPMode = RADEON_DEFAULT_CP_PIO_MODE; + } else { + info->CPMode = RADEON_DEFAULT_CP_BM_MODE; + } + + info->agpMode = RADEON_DEFAULT_AGP_MODE; + info->gartSize = RADEON_DEFAULT_GART_SIZE; + info->ringSize = RADEON_DEFAULT_RING_SIZE; + info->bufSize = RADEON_DEFAULT_BUFFER_SIZE; + info->gartTexSize = RADEON_DEFAULT_GART_TEX_SIZE; + info->agpFastWrite = RADEON_DEFAULT_AGP_FAST_WRITE; + + info->CPusecTimeout = RADEON_DEFAULT_CP_TIMEOUT; + + if (!info->IsPCI) { + if (xf86GetOptValInteger(info->Options, + OPTION_AGP_MODE, &(info->agpMode))) { + if (info->agpMode < 1 || info->agpMode > RADEON_AGP_MAX_MODE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal AGP Mode: %d\n", info->agpMode); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using AGP %dx mode\n", info->agpMode); + } + + if ((info->agpFastWrite = xf86ReturnOptValBool(info->Options, + OPTION_AGP_FW, + FALSE))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Enabling AGP Fast Write\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "AGP Fast Write disabled by default\n"); + } + } + + if (xf86GetOptValInteger(info->Options, + OPTION_GART_SIZE, (int *)&(info->gartSize))) { + switch (info->gartSize) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + case 256: + break; + + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal GART size: %d MB\n", info->gartSize); + return FALSE; + } + } + + if (xf86GetOptValInteger(info->Options, + OPTION_RING_SIZE, &(info->ringSize))) { + if (info->ringSize < 1 || info->ringSize >= (int)info->gartSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal ring buffer size: %d MB\n", + info->ringSize); + return FALSE; + } + } + + if (xf86GetOptValInteger(info->Options, + OPTION_BUFFER_SIZE, &(info->bufSize))) { + if (info->bufSize < 1 || info->bufSize >= (int)info->gartSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal vertex/indirect buffers size: %d MB\n", + info->bufSize); + return FALSE; + } + if (info->bufSize > 2) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Illegal vertex/indirect buffers size: %d MB\n", + info->bufSize); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Clamping vertex/indirect buffers size to 2 MB\n"); + info->bufSize = 2; + } + } + + if (info->ringSize + info->bufSize + info->gartTexSize > + (int)info->gartSize) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Buffers are too big for requested GART space\n"); + return FALSE; + } + + info->gartTexSize = info->gartSize - (info->ringSize + info->bufSize); + + if (xf86GetOptValInteger(info->Options, OPTION_USEC_TIMEOUT, + &(info->CPusecTimeout))) { + /* This option checked by the RADEON DRM kernel module */ + } + + /* Depth moves are disabled by default since they are extremely slow */ + if ((info->depthMoves = xf86ReturnOptValBool(info->Options, + OPTION_DEPTH_MOVE, FALSE))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Enabling depth moves\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Depth moves disabled by default\n"); + } + + /* Two options to try and squeeze as much texture memory as possible + * for dedicated 3d rendering boxes + */ + info->noBackBuffer = xf86ReturnOptValBool(info->Options, + OPTION_NO_BACKBUFFER, + FALSE); + + if (info->noBackBuffer) { + info->allowPageFlip = 0; + } else if (!xf86LoadSubModule(pScrn, "shadowfb")) { + info->allowPageFlip = 0; + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't load shadowfb module:\n"); + } else { + xf86LoaderReqSymLists(driShadowFBSymbols, NULL); + + info->allowPageFlip = xf86ReturnOptValBool(info->Options, + OPTION_PAGE_FLIP, + FALSE); + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Page flipping %sabled\n", + info->allowPageFlip ? "en" : "dis"); + + return TRUE; +} +#endif + +static void +RADEONProbeDDC(ScrnInfoPtr pScrn, int indx) +{ + vbeInfoPtr pVbe; + + if (xf86LoadSubModule(pScrn, "vbe")) { + pVbe = VBEInit(NULL,indx); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + } +} + +/* RADEONPreInit is called once at server startup */ +Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) +{ + RADEONInfoPtr info; + xf86Int10InfoPtr pInt10 = NULL; + void *int10_save = NULL; + const char *s; + + RADEONTRACE(("RADEONPreInit\n")); + if (pScrn->numEntities != 1) return FALSE; + + if (!RADEONGetRec(pScrn)) return FALSE; + + info = RADEONPTR(pScrn); + info->IsSecondary = FALSE; + info->Clone = FALSE; + info->CurCloneMode = NULL; + info->CloneModes = NULL; + info->IsSwitching = FALSE; + info->MMIO = NULL; + + info->pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]); + if (info->pEnt->location.type != BUS_PCI) goto fail; + + info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index); + info->PciTag = pciTag(info->PciInfo->bus, + info->PciInfo->device, + info->PciInfo->func); + info->MMIOAddr = info->PciInfo->memBase[2] & 0xffffff00; + if (info->pEnt->device->IOBase) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "MMIO address override, using 0x%08lx instead of 0x%08lx\n", + info->pEnt->device->IOBase, + info->MMIOAddr); + info->MMIOAddr = info->pEnt->device->IOBase; + } else if (!info->MMIOAddr) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address\n"); + goto fail1; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "MMIO registers at 0x%08lx\n", info->MMIOAddr); + + if(!RADEONMapMMIO(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Memory map the MMIO region failed\n"); + goto fail1; + } + +#if !defined(__alpha__) + if (xf86GetPciDomain(info->PciTag) || + !xf86IsPrimaryPci(info->PciInfo)) + RADEONPreInt10Save(pScrn, &int10_save); +#else + /* [Alpha] On the primary, the console already ran the BIOS and we're + * going to run it again - so make sure to "fix up" the card + * so that (1) we can read the BIOS ROM and (2) the BIOS will + * get the memory config right. + */ + RADEONPreInt10Save(pScrn, &int10_save); +#endif + + if (xf86IsEntityShared(info->pEnt->index)) { + if (xf86IsPrimInitDone(info->pEnt->index)) { + + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + info->IsSecondary = TRUE; + if (!pRADEONEnt->HasSecondary) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Only one monitor detected, Second screen " + "will NOT be created\n"); + goto fail2; + } + pRADEONEnt->pSecondaryScrn = pScrn; + } else { + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + xf86SetPrimInitDone(info->pEnt->index); + + pRADEONEnt->pPrimaryScrn = pScrn; + pRADEONEnt->RestorePrimary = FALSE; + pRADEONEnt->IsSecondaryRestored = FALSE; + } + } + + if (flags & PROBE_DETECT) { + RADEONProbeDDC(pScrn, info->pEnt->index); + RADEONPostInt10Check(pScrn, int10_save); + if(info->MMIO) RADEONUnmapMMIO(pScrn); + return TRUE; + } + + if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE; + xf86LoaderReqSymLists(vgahwSymbols, NULL); + if (!vgaHWGetHWRec(pScrn)) { + RADEONFreeRec(pScrn); + goto fail2; + } + + vgaHWGetIOBase(VGAHWPTR(pScrn)); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "PCI bus %d card %d func %d\n", + info->PciInfo->bus, + info->PciInfo->device, + info->PciInfo->func); + + if (xf86RegisterResources(info->pEnt->index, 0, ResExclusive)) + goto fail; + + if (xf86SetOperatingState(resVga, info->pEnt->index, ResUnusedOpr)) + goto fail; + + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; + pScrn->monitor = pScrn->confScreen->monitor; + + if (!RADEONPreInitVisual(pScrn)) + goto fail; + + /* We can't do this until we have a + pScrn->display. */ + xf86CollectOptions(pScrn, NULL); + if (!(info->Options = xalloc(sizeof(RADEONOptions)))) + goto fail; + + memcpy(info->Options, RADEONOptions, sizeof(RADEONOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options); + + if (!RADEONPreInitWeight(pScrn)) + goto fail; + + if (xf86GetOptValInteger(info->Options, OPTION_VIDEO_KEY, + &(info->videoKey))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n", + info->videoKey); + } else { + info->videoKey = 0x1E; + } + + info->DispPriority = 1; + if ((s = xf86GetOptValString(info->Options, OPTION_DISP_PRIORITY))) { + if (strcmp(s, "AUTO") == 0) { + info->DispPriority = 1; + } else if (strcmp(s, "BIOS") == 0) { + info->DispPriority = 0; + } else if (strcmp(s, "HIGH") == 0) { + info->DispPriority = 2; + } else + info->DispPriority = 1; + } + + if (xf86ReturnOptValBool(info->Options, OPTION_FBDEV, FALSE)) { + /* check for Linux framebuffer device */ + + if (xf86LoadSubModule(pScrn, "fbdevhw")) { + xf86LoaderReqSymLists(fbdevHWSymbols, NULL); + + if (fbdevHWInit(pScrn, info->PciInfo, NULL)) { + pScrn->ValidMode = fbdevHWValidMode; + info->FBDev = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Using framebuffer device\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "fbdevHWInit failed, not using framebuffer device\n"); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Couldn't load fbdevhw module, not using framebuffer device\n"); + } + } + + if (!info->FBDev) + if (!RADEONPreInitInt10(pScrn, &pInt10)) + goto fail; + + RADEONPostInt10Check(pScrn, int10_save); + + if (!RADEONPreInitConfig(pScrn)) + goto fail; + + RADEONPreInitDDC(pScrn); + + if (!RADEONGetBIOSParameters(pScrn, pInt10)) + goto fail; + + if (info->DisplayType == MT_DFP) + RADEONGetTMDSInfo(pScrn); + + if (!RADEONGetPLLParameters(pScrn)) goto fail; + + if (!RADEONPreInitGamma(pScrn)) goto fail; + + if (!RADEONPreInitModes(pScrn, pInt10)) goto fail; + + if (!RADEONPreInitCursor(pScrn)) goto fail; + + if (!RADEONPreInitAccel(pScrn)) goto fail; + +#ifdef XF86DRI + if (!RADEONPreInitDRI(pScrn)) goto fail; +#endif + + /* Free the video bios (if applicable) */ + if (info->VBIOS) { + xfree(info->VBIOS); + info->VBIOS = NULL; + } + + /* Free int10 info */ + if (pInt10) + xf86FreeInt10(pInt10); + + if(info->MMIO) RADEONUnmapMMIO(pScrn); + info->MMIO = NULL; + + xf86DrvMsg(pScrn->scrnIndex, X_NOTICE, + "For information on using the multimedia capabilities\n of this" + " adapter, please see http://gatos.sf.net.\n"); + + return TRUE; + +fail: + /* Pre-init failed. */ + if (info->IsSecondary) { + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + pRADEONEnt->HasSecondary = FALSE; + } + /* Free the video bios (if applicable) */ + if (info->VBIOS) { + xfree(info->VBIOS); + info->VBIOS = NULL; + } + + /* Free int10 info */ + if (pInt10) + xf86FreeInt10(pInt10); + + vgaHWFreeHWRec(pScrn); + + fail2: + if(info->MMIO) RADEONUnmapMMIO(pScrn); + info->MMIO = NULL; + fail1: + RADEONFreeRec(pScrn); + + return FALSE; +} + +/* Load a palette */ +static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors, + int *indices, LOCO *colors, VisualPtr pVisual) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + int idx, j; + unsigned char r, g, b; + +#ifdef XF86DRI + if (info->CPStarted) DRILock(pScrn->pScreen, 0); +#endif + + if (info->accelOn) info->accel->Sync(pScrn); + + if (info->FBDev) { + fbdevHWLoadPalette(pScrn, numColors, indices, colors, pVisual); + } else { + /* If the second monitor is connected, we also need to deal with + * the secondary palette + */ + if (info->IsSecondary) j = 1; + else j = 0; + + PAL_SELECT(j); + + if (info->CurrentLayout.depth == 15) { + /* 15bpp mode. This sends 32 values. */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx].red; + g = colors[idx].green; + b = colors[idx].blue; + OUTPAL(idx * 8, r, g, b); + } + } else if (info->CurrentLayout.depth == 16) { + /* 16bpp mode. This sends 64 values. + * + * There are twice as many green values as there are values + * for red and blue. So, we take each red and blue pair, + * and combine it with each of the two green values. + */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx / 2].red; + g = colors[idx].green; + b = colors[idx / 2].blue; + RADEONWaitForFifo(pScrn, 32); /* delay */ + OUTPAL(idx * 4, r, g, b); + + /* AH - Added to write extra green data - How come this isn't + * needed on R128? We didn't load the extra green data in the + * other routine + */ + if (idx <= 31) { + r = colors[idx].red; + g = colors[(idx * 2) + 1].green; + b = colors[idx].blue; + RADEONWaitForFifo(pScrn, 32); /* delay */ + OUTPAL(idx * 8, r, g, b); + } + } + } else { + /* 8bpp mode. This sends 256 values. */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx].red; + b = colors[idx].blue; + g = colors[idx].green; + RADEONWaitForFifo(pScrn, 32); /* delay */ + OUTPAL(idx, r, g, b); + } + } + + if (info->Clone) { + PAL_SELECT(1); + if (info->CurrentLayout.depth == 15) { + /* 15bpp mode. This sends 32 values. */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx].red; + g = colors[idx].green; + b = colors[idx].blue; + OUTPAL(idx * 8, r, g, b); + } + } else if (info->CurrentLayout.depth == 16) { + /* 16bpp mode. This sends 64 values. + * + * There are twice as many green values as there are values + * for red and blue. So, we take each red and blue pair, + * and combine it with each of the two green values. + */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx / 2].red; + g = colors[idx].green; + b = colors[idx / 2].blue; + OUTPAL(idx * 4, r, g, b); + + /* AH - Added to write extra green data - How come + * this isn't needed on R128? We didn't load the + * extra green data in the other routine. + */ + if (idx <= 31) { + r = colors[idx].red; + g = colors[(idx * 2) + 1].green; + b = colors[idx].blue; + OUTPAL(idx * 8, r, g, b); + } + } + } else { + /* 8bpp mode. This sends 256 values. */ + for (i = 0; i < numColors; i++) { + idx = indices[i]; + r = colors[idx].red; + b = colors[idx].blue; + g = colors[idx].green; + OUTPAL(idx, r, g, b); + } + } + } + } + +#ifdef XF86DRI + if (info->CPStarted) DRIUnlock(pScrn->pScreen); +#endif +} + +static void RADEONBlockHandler(int i, pointer blockData, + pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + RADEONInfoPtr info = RADEONPTR(pScrn); + +#ifdef XF86DRI + if (info->directRenderingEnabled) + FLUSH_RING(); +#endif + + pScreen->BlockHandler = info->BlockHandler; + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + pScreen->BlockHandler = RADEONBlockHandler; + + if (info->VideoTimerCallback) + (*info->VideoTimerCallback)(pScrn, currentTime.milliseconds); +} + +/* Called at the start of each server generation. */ +Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + BoxRec MemBox; + int y2; + + RADEONTRACE(("RADEONScreenInit %x %d\n", + pScrn->memPhysBase, pScrn->fbOffset)); + +#ifdef XF86DRI + /* Turn off the CP for now. */ + info->CPInUse = FALSE; + info->CPStarted = FALSE; + info->directRenderingEnabled = FALSE; +#endif + info->accelOn = FALSE; + pScrn->fbOffset = 0; + if (info->IsSecondary) pScrn->fbOffset = pScrn->videoRam * 1024; + if (!RADEONMapMem(pScrn)) return FALSE; + +#ifdef XF86DRI + info->fbX = 0; + info->fbY = 0; +#endif + + info->PaletteSavedOnVT = FALSE; + + RADEONSave(pScrn); + if (info->FBDev) { + unsigned char *RADEONMMIO = info->MMIO; + + if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE; + info->ModeReg.surface_cntl = INREG(RADEON_SURFACE_CNTL); + } else { + if (!RADEONModeInit(pScrn, pScrn->currentMode)) return FALSE; + } + + RADEONSaveScreen(pScreen, SCREEN_SAVER_ON); + + pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + if (info->CurCloneMode) { + info->CloneFrameX0 = + (pScrn->virtualX - info->CurCloneMode->HDisplay) / 2; + info->CloneFrameY0 = + (pScrn->virtualY - info->CurCloneMode->VDisplay) / 2; + RADEONDoAdjustFrame(pScrn, info->CloneFrameX0, info->CloneFrameY0, TRUE); + } + + /* Visual setup */ + miClearVisualTypes(); + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, + pScrn->defaultVisual)) return FALSE; + miSetPixmapDepths (); + +#ifdef XF86DRI + /* Setup DRI after visuals have been + established, but before fbScreenInit is + called. fbScreenInit will eventually + call the driver's InitGLXVisuals call + back. */ + { + /* FIXME: When we move to dynamic allocation of back and depth + * buffers, we will want to revisit the following check for 3 + * times the virtual size of the screen below. + */ + int width_bytes = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + int maxy = info->FbMapSize / width_bytes; + + if (xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { + xf86DrvMsg(scrnIndex, X_WARNING, + "Acceleration disabled, not initializing the DRI\n"); + info->directRenderingEnabled = FALSE; + } else if (maxy <= pScrn->virtualY * 3) { + xf86DrvMsg(scrnIndex, X_WARNING, + "Static buffer allocation failed -- " + "need at least %d kB video memory\n", + (pScrn->displayWidth * pScrn->virtualY * + info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024); + info->directRenderingEnabled = FALSE; + } else if ((info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200) || + (info->ChipFamily == CHIP_FAMILY_RS300)) { + info->directRenderingEnabled = FALSE; + xf86DrvMsg(scrnIndex, X_WARNING, + "Direct rendering not yet supported on " + "IGP320/330/340/350, 7000, 9000 integrated chips\n"); + } else if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) { + info->directRenderingEnabled = FALSE; + xf86DrvMsg(scrnIndex, X_WARNING, + "Direct rendering not yet supported on " + "Radeon 9500/9700 and newer cards\n"); + } else { + if (info->IsSecondary) + info->directRenderingEnabled = FALSE; + else { + /* Xinerama has sync problem with DRI, disable it for now */ + if (xf86IsEntityShared(info->pEnt->index)) { + info->directRenderingEnabled = FALSE; + xf86DrvMsg(scrnIndex, X_WARNING, + "Direct Rendering Disabled -- " + "Dual-head configuration is not working with " + "DRI at present.\n" + "Please use only one Device/Screen " + "section in your XFConfig file.\n"); + } else { + info->directRenderingEnabled = + RADEONDRIScreenInit(pScreen); + } + } + } + } +#endif + + if (!fbScreenInit(pScreen, info->FB, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, + pScrn->bitsPerPixel)) + return FALSE; + + xf86SetBlackWhitePixels(pScreen); + + if (pScrn->bitsPerPixel > 8) { + VisualPtr visual; + + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + /* Must be after RGB order fixed */ + fbPictureInit (pScreen, 0, 0); + +#ifdef RENDER + if (PictureGetSubpixelOrder (pScreen) == SubPixelUnknown) + { + int subPixelOrder; + + switch (info->DisplayType) { + case MT_NONE: subPixelOrder = SubPixelUnknown; break; + case MT_LCD: subPixelOrder = SubPixelHorizontalRGB; break; + case MT_DFP: subPixelOrder = SubPixelHorizontalRGB; break; + default: subPixelOrder = SubPixelNone; break; + } + PictureSetSubpixelOrder (pScreen, subPixelOrder); + } +#endif + /* Memory manager setup */ +#ifdef XF86DRI + if (info->directRenderingEnabled) { + FBAreaPtr fbarea; + int width_bytes = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + int cpp = info->CurrentLayout.pixel_bytes; + int bufferSize = ((pScrn->virtualY * width_bytes + + RADEON_BUFFER_ALIGN) + & ~RADEON_BUFFER_ALIGN); + int depthSize = ((((pScrn->virtualY+15) & ~15) * width_bytes + + RADEON_BUFFER_ALIGN) + & ~RADEON_BUFFER_ALIGN); + int l; + int scanlines; + + info->frontOffset = 0; + info->frontPitch = pScrn->displayWidth; + + switch (info->CPMode) { + case RADEON_DEFAULT_CP_PIO_MODE: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CP in PIO mode\n"); + break; + case RADEON_DEFAULT_CP_BM_MODE: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CP in BM mode\n"); + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CP in UNKNOWN mode\n"); + break; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB GART aperture\n", info->gartSize); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB for the ring buffer\n", info->ringSize); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB for vertex/indirect buffers\n", info->bufSize); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using %d MB for GART textures\n", info->gartTexSize); + + /* Try for front, back, depth, and three framebuffers worth of + * pixmap cache. Should be enough for a fullscreen background + * image plus some leftovers. + */ + info->textureSize = info->FbMapSize - 5 * bufferSize - depthSize; + + /* If that gives us less than half the available memory, let's + * be greedy and grab some more. Sorry, I care more about 3D + * performance than playing nicely, and you'll get around a full + * framebuffer's worth of pixmap cache anyway. + */ + if (info->textureSize < (int)info->FbMapSize / 2) { + info->textureSize = info->FbMapSize - 4 * bufferSize - depthSize; + } + if (info->textureSize < (int)info->FbMapSize / 2) { + info->textureSize = info->FbMapSize - 3 * bufferSize - depthSize; + } + /* If there's still no space for textures, try without pixmap cache */ + if (info->textureSize < 0) { + info->textureSize = info->FbMapSize - 2 * bufferSize - depthSize + - 64/4*64; + } + + /* Check to see if there is more room available after the 8192nd + scanline for textures */ + if ((int)info->FbMapSize - 8192*width_bytes - bufferSize - depthSize + > info->textureSize) { + info->textureSize = + info->FbMapSize - 8192*width_bytes - bufferSize - depthSize; + } + + /* If backbuffer is disabled, don't allocate memory for it */ + if (info->noBackBuffer) { + info->textureSize += bufferSize; + } + + if (info->textureSize > 0) { + l = RADEONMinBits((info->textureSize-1) / RADEON_NR_TEX_REGIONS); + if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY; + + /* Round the texture size up to the nearest whole number of + * texture regions. Again, be greedy about this, don't + * round down. + */ + info->log2TexGran = l; + info->textureSize = (info->textureSize >> l) << l; + } else { + info->textureSize = 0; + } + + /* Set a minimum usable local texture heap size. This will fit + * two 256x256x32bpp textures. + */ + if (info->textureSize < 512 * 1024) { + info->textureOffset = 0; + info->textureSize = 0; + } + + /* Reserve space for textures */ + info->textureOffset = ((info->FbMapSize - info->textureSize + + RADEON_BUFFER_ALIGN) & + ~(CARD32)RADEON_BUFFER_ALIGN); + + /* Reserve space for the shared depth + * buffer. + */ + info->depthOffset = ((info->textureOffset - depthSize + + RADEON_BUFFER_ALIGN) & + ~(CARD32)RADEON_BUFFER_ALIGN); + info->depthPitch = pScrn->displayWidth; + + /* Reserve space for the shared back buffer */ + if (info->noBackBuffer) { + info->backOffset = info->depthOffset; + info->backPitch = pScrn->displayWidth; + } else { + info->backOffset = ((info->depthOffset - bufferSize + + RADEON_BUFFER_ALIGN) & + ~(CARD32)RADEON_BUFFER_ALIGN); + info->backPitch = pScrn->displayWidth; + } + + info->backY = info->backOffset / width_bytes; + info->backX = (info->backOffset - (info->backY * width_bytes)) / cpp; + + scanlines = info->FbMapSize / width_bytes; + if (scanlines > 8191) scanlines = 8191; + + MemBox.x1 = 0; + MemBox.y1 = 0; + MemBox.x2 = pScrn->displayWidth; + MemBox.y2 = scanlines; + + if (!xf86InitFBManager(pScreen, &MemBox)) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Memory manager initialization to " + "(%d,%d) (%d,%d) failed\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + return FALSE; + } else { + int width, height; + + xf86DrvMsg(scrnIndex, X_INFO, + "Memory manager initialized to (%d,%d) (%d,%d)\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->displayWidth, + 2, 0, NULL, NULL, + NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved area from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); + } + if (xf86QueryLargestOffscreenArea(pScreen, &width, + &height, 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + + /* Lines in offscreen area needed for depth buffer and + * textures + */ + info->depthTexLines = (scanlines + - info->depthOffset / width_bytes); + info->backLines = (scanlines + - info->backOffset / width_bytes + - info->depthTexLines); + info->backArea = NULL; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "Unable to determine largest offscreen area " + "available\n"); + return FALSE; + } + } + + xf86DrvMsg(scrnIndex, X_INFO, + "Will use back buffer at offset 0x%x\n", + info->backOffset); + xf86DrvMsg(scrnIndex, X_INFO, + "Will use depth buffer at offset 0x%x\n", + info->depthOffset); + xf86DrvMsg(scrnIndex, X_INFO, + "Will use %d kb for textures at offset 0x%x\n", + info->textureSize/1024, info->textureOffset); + + info->frontPitchOffset = (((info->frontPitch * cpp / 64) << 22) | + (info->frontOffset >> 10)); + + info->backPitchOffset = (((info->backPitch * cpp / 64) << 22) | + (info->backOffset >> 10)); + + info->depthPitchOffset = (((info->depthPitch * cpp / 64) << 22) | + (info->depthOffset >> 10)); + } else +#endif + { + MemBox.x1 = 0; + MemBox.y1 = 0; + MemBox.x2 = pScrn->displayWidth; + y2 = (info->FbMapSize + / (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes)); + if (y2 >= 32768) y2 = 32767; /* because MemBox.y2 is signed short */ + MemBox.y2 = y2; + + /* The acceleration engine uses 14 bit + signed coordinates, so we can't have any + drawable caches beyond this region. */ + if (MemBox.y2 > 8191) MemBox.y2 = 8191; + + if (!xf86InitFBManager(pScreen, &MemBox)) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Memory manager initialization to " + "(%d,%d) (%d,%d) failed\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + return FALSE; + } else { + int width, height; + FBAreaPtr fbarea; + + xf86DrvMsg(scrnIndex, X_INFO, + "Memory manager initialized to (%d,%d) (%d,%d)\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->displayWidth, + 2, 0, NULL, NULL, + NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved area from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); + } + if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, + 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + } + } + } + + /* Acceleration setup */ + if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { + if (RADEONAccelInit(pScreen)) { + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration enabled\n"); + info->accelOn = TRUE; + + /* FIXME: Figure out why this was added because it shouldn't be! */ + /* This is needed by the DRI and XAA code for shared entities */ + pScrn->pScreen = pScreen; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "Acceleration initialization failed\n"); + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); + info->accelOn = FALSE; + } + } else { + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); + info->accelOn = FALSE; + } + + /* DGA setup */ + RADEONDGAInit(pScreen); + + /* Backing store setup */ + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + + /* Set Silken Mouse */ + xf86SetSilkenMouse(pScreen); + + /* Cursor setup */ + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Hardware cursor setup */ + if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) { + if (RADEONCursorInit(pScreen)) { + int width, height; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Using hardware cursor (scanline %ld)\n", + info->cursor_start / pScrn->displayWidth + / info->CurrentLayout.pixel_bytes); + if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, + 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + } + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + xf86DrvMsg(scrnIndex, X_INFO, "Using software cursor\n"); + } + } else { + info->cursor_start = 0; + xf86DrvMsg(scrnIndex, X_INFO, "Using software cursor\n"); + } + + /* Colormap setup */ + if (!miCreateDefColormap(pScreen)) return FALSE; + if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8, + RADEONLoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR +#if 0 /* This option messes up text mode! (eich@suse.de) */ + | CMAP_LOAD_EVEN_IF_OFFSCREEN +#endif + | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; + + /* DPMS setup */ + xf86DPMSInit(pScreen, RADEONDisplayPowerManagementSet, 0); + + RADEONInitVideo(pScreen); + + /* Provide SaveScreen */ + pScreen->SaveScreen = RADEONSaveScreen; + + /* Wrap CloseScreen */ + info->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = RADEONCloseScreen; + + /* Note unused options */ + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + +#ifdef XF86DRI + /* DRI finalization */ + if (info->directRenderingEnabled) { + /* Now that mi, fb, drm and others have + done their thing, complete the DRI + setup. */ + info->directRenderingEnabled = RADEONDRIFinishScreenInit(pScreen); + } + if (info->directRenderingEnabled) { + if ((info->DispPriority == 1) && (!info->IsPCI)) { + /* we need to re-calculate bandwidth because of AGPMode difference. */ + RADEONInitDispBandwidth(pScrn); + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering disabled\n"); + } +#endif + + info->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = RADEONBlockHandler; + + return TRUE; +} + +/* Write common registers (initialized to 0) */ +static void RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_OVR_CLR, restore->ovr_clr); + OUTREG(RADEON_OVR_WID_LEFT_RIGHT, restore->ovr_wid_left_right); + OUTREG(RADEON_OVR_WID_TOP_BOTTOM, restore->ovr_wid_top_bottom); + OUTREG(RADEON_OV0_SCALE_CNTL, restore->ov0_scale_cntl); + OUTREG(RADEON_SUBPIC_CNTL, restore->subpic_cntl); + OUTREG(RADEON_VIPH_CONTROL, restore->viph_control); + OUTREG(RADEON_I2C_CNTL_1, restore->i2c_cntl_1); + OUTREG(RADEON_GEN_INT_CNTL, restore->gen_int_cntl); + OUTREG(RADEON_CAP0_TRIG_CNTL, restore->cap0_trig_cntl); + OUTREG(RADEON_CAP1_TRIG_CNTL, restore->cap1_trig_cntl); + OUTREG(RADEON_BUS_CNTL, restore->bus_cntl); + OUTREG(RADEON_SURFACE_CNTL, restore->surface_cntl); + + /* Workaround for the VT switching problem in dual-head mode. This + * problem only occurs on RV style chips, typically when a FP and + * CRT are connected. + */ + if (info->HasCRTC2 && + !info->IsSwitching && + info->ChipFamily != CHIP_FAMILY_R200 && + info->ChipFamily != CHIP_FAMILY_R300 && + info->ChipFamily != CHIP_FAMILY_R350 && + info->ChipFamily != CHIP_FAMILY_RV350) { + CARD32 tmp; + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + if (pRADEONEnt->HasSecondary || info->Clone) { + tmp = INREG(RADEON_DAC_CNTL2); + OUTREG(RADEON_DAC_CNTL2, tmp & ~RADEON_DAC2_DAC_CLK_SEL); + usleep(100000); + } + } +} + +/* Write miscellaneous registers which might have been destroyed by an fbdevHW + * call + */ +static void RADEONRestoreFBDevRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ +#ifdef XF86DRI + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + /* Restore register for vertical blank interrupts */ + if (info->irq) { + OUTREG(RADEON_GEN_INT_CNTL, restore->gen_int_cntl); + } + + /* Restore registers for page flipping */ + if (info->allowPageFlip) { + OUTREG(RADEON_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); + if (info->HasCRTC2) { + OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); + } + } +#endif +} + +/* Write CRTC registers */ +static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl); + + OUTREGP(RADEON_CRTC_EXT_CNTL, + restore->crtc_ext_cntl, + RADEON_CRTC_VSYNC_DIS | + RADEON_CRTC_HSYNC_DIS | + RADEON_CRTC_DISPLAY_DIS); + + OUTREGP(RADEON_DAC_CNTL, + restore->dac_cntl, + RADEON_DAC_RANGE_CNTL | + RADEON_DAC_BLANKING); + + OUTREG(RADEON_CRTC_H_TOTAL_DISP, restore->crtc_h_total_disp); + OUTREG(RADEON_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid); + OUTREG(RADEON_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); + OUTREG(RADEON_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid); + OUTREG(RADEON_CRTC_OFFSET, restore->crtc_offset); + OUTREG(RADEON_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); + OUTREG(RADEON_CRTC_PITCH, restore->crtc_pitch); + OUTREG(RADEON_DISP_MERGE_CNTL, restore->disp_merge_cntl); + OUTREG(RADEON_CRTC_MORE_CNTL, restore->crtc_more_cntl); +} + +/* Write CRTC2 registers */ +static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREGP(RADEON_CRTC2_GEN_CNTL, + restore->crtc2_gen_cntl, + RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | + RADEON_CRTC2_DISP_DIS); + + OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); + + OUTREG(RADEON_TV_DAC_CNTL, 0x00280203); + if ((info->ChipFamily == CHIP_FAMILY_R200) || + (info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) { + OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl); + } else { + OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); + } + + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, restore->crtc2_v_total_disp); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid); + OUTREG(RADEON_CRTC2_OFFSET, restore->crtc2_offset); + OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); + OUTREG(RADEON_CRTC2_PITCH, restore->crtc2_pitch); + OUTREG(RADEON_DISP2_MERGE_CNTL, restore->disp2_merge_cntl); + + if ((info->DisplayType == MT_DFP && info->IsSecondary) || + info->CloneType == MT_DFP) { + OUTREG(RADEON_FP_H2_SYNC_STRT_WID, restore->fp2_h_sync_strt_wid); + OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp2_v_sync_strt_wid); + OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); + } +#if 0 + /* Hack for restoring text mode -- fixed elsewhere */ + usleep(100000); +#endif +} + +/* Write flat panel registers */ +static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + unsigned long tmp; + + OUTREG(RADEON_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp); + OUTREG(RADEON_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp); + OUTREG(RADEON_FP_H_SYNC_STRT_WID, restore->fp_h_sync_strt_wid); + OUTREG(RADEON_FP_V_SYNC_STRT_WID, restore->fp_v_sync_strt_wid); + OUTREG(RADEON_TMDS_PLL_CNTL, restore->tmds_pll_cntl); + OUTREG(RADEON_TMDS_TRANSMITTER_CNTL,restore->tmds_transmitter_cntl); + OUTREG(RADEON_FP_HORZ_STRETCH, restore->fp_horz_stretch); + OUTREG(RADEON_FP_VERT_STRETCH, restore->fp_vert_stretch); + OUTREG(RADEON_FP_GEN_CNTL, restore->fp_gen_cntl); + + /* old AIW Radeon has some BIOS initialization problem + * with display buffer underflow, only occurs to DFP + */ + if (!info->HasCRTC2) + OUTREG(RADEON_GRPH_BUFFER_CNTL, + INREG(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); + + if (info->DisplayType != MT_DFP) { + unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); + OUTREG(RADEON_BIOS_5_SCRATCH, restore->bios_5_scratch); + + if (info->IsMobility || info->IsIGP) { + /* Asic bug, when turning off LVDS_ON, we have to make sure + RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off + */ + if (!(restore->lvds_gen_cntl & RADEON_LVDS_ON)) { + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); + } + } + + tmp = INREG(RADEON_LVDS_GEN_CNTL); + if ((tmp & (RADEON_LVDS_ON | RADEON_LVDS_BLON)) == + (restore->lvds_gen_cntl & (RADEON_LVDS_ON | RADEON_LVDS_BLON))) { + OUTREG(RADEON_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + } else { + if (restore->lvds_gen_cntl & (RADEON_LVDS_ON | RADEON_LVDS_BLON)) { + usleep(RADEONPTR(pScrn)->PanelPwrDly * 1000); + OUTREG(RADEON_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + } else { + OUTREG(RADEON_LVDS_GEN_CNTL, + restore->lvds_gen_cntl | RADEON_LVDS_BLON); + usleep(RADEONPTR(pScrn)->PanelPwrDly * 1000); + OUTREG(RADEON_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + } + } + + if (info->IsMobility || info->IsIGP) { + if (!(restore->lvds_gen_cntl & RADEON_LVDS_ON)) { + OUTPLL(RADEON_PIXCLKS_CNTL, tmpPixclksCntl); + } + } + } +} + +static void RADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn) +{ + int i = 0; + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + i++); +} + +static void RADEONPLLWriteUpdate(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + while (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + RADEON_PPLL_ATOMIC_UPDATE_W, + ~(RADEON_PPLL_ATOMIC_UPDATE_W)); +} + +static void RADEONPLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn) +{ + int i = 0; + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + i++); +} + +static void RADEONPLL2WriteUpdate(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + while (INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + + OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV, + RADEON_P2PLL_ATOMIC_UPDATE_W, + ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); +} + +/* Write PLL registers */ +static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (info->IsMobility) { + /* A temporal workaround for the occational blanking on certain laptop panels. + This appears to related to the PLL divider registers (fail to lock?). + It occurs even when all dividers are the same with their old settings. + In this case we really don't need to fiddle with PLL registers. + By doing this we can avoid the blanking problem with some panels. + */ + if ((restore->ppll_ref_div == (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && + (restore->ppll_div_3 == (INPLL(pScrn, RADEON_PPLL_DIV_3) & (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) + return; + } + + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_CPUCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + + OUTPLLP(pScrn, + RADEON_PPLL_CNTL, + RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN, + ~(RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); + + OUTREGP(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_RS300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) { + if (restore->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { + /* When restoring console mode, use saved PPLL_REF_DIV + * setting. + */ + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + restore->ppll_ref_div, + 0); + } else { + /* R300 uses ref_div_acc field as real ref divider */ + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + ~R300_PPLL_REF_DIV_ACC_MASK); + } + } else { + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + restore->ppll_ref_div, + ~RADEON_PPLL_REF_DIV_MASK); + } + + OUTPLLP(pScrn, RADEON_PPLL_DIV_3, + restore->ppll_div_3, + ~RADEON_PPLL_FB3_DIV_MASK); + + OUTPLLP(pScrn, RADEON_PPLL_DIV_3, + restore->ppll_div_3, + ~RADEON_PPLL_POST3_DIV_MASK); + + RADEONPLLWriteUpdate(pScrn); + RADEONPLLWaitForReadUpdateComplete(pScrn); + + OUTPLL(RADEON_HTOTAL_CNTL, restore->htotal_cntl); + + OUTPLLP(pScrn, RADEON_PPLL_CNTL, + 0, + ~(RADEON_PPLL_RESET + | RADEON_PPLL_SLEEP + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); + + xf86DrvMsg(0, X_INFO, "Wrote: rd=%d, fd=%d, pd=%d\n", + restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, + (restore->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); + + RADEONTRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + restore->ppll_ref_div, + restore->ppll_div_3, + restore->htotal_cntl, + INPLL(pScrn, RADEON_PPLL_CNTL))); + RADEONTRACE(("Wrote: rd=%d, fd=%d, pd=%d\n", + restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, + (restore->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16)); + + usleep(5000); /* Let the clock to lock */ + + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_PPLLCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); +} + + +/* Write PLL2 registers */ +static void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_CPUCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + OUTPLLP(pScrn, + RADEON_P2PLL_CNTL, + RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN, + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN)); + + OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV, + restore->p2pll_ref_div, + ~RADEON_P2PLL_REF_DIV_MASK); + + OUTPLLP(pScrn, RADEON_P2PLL_DIV_0, + restore->p2pll_div_0, + ~RADEON_P2PLL_FB0_DIV_MASK); + + OUTPLLP(pScrn, RADEON_P2PLL_DIV_0, + restore->p2pll_div_0, + ~RADEON_P2PLL_POST0_DIV_MASK); + + RADEONPLL2WriteUpdate(pScrn); + RADEONPLL2WaitForReadUpdateComplete(pScrn); + + OUTPLL(RADEON_HTOTAL2_CNTL, restore->htotal_cntl2); + + OUTPLLP(pScrn, RADEON_P2PLL_CNTL, + 0, + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_SLEEP + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN)); + + RADEONTRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + restore->p2pll_ref_div, + restore->p2pll_div_0, + restore->htotal_cntl2, + INPLL(pScrn, RADEON_P2PLL_CNTL))); + RADEONTRACE(("Wrote: rd=%d, fd=%d, pd=%d\n", + restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK, + (restore->p2pll_div_0 & RADEON_P2PLL_POST0_DIV_MASK) >>16)); + + usleep(5000); /* Let the clock to lock */ + + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); +} + +#if 0 +/* Write palette data */ +static void RADEONRestorePalette(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + + if (!restore->palette_valid) return; + + PAL_SELECT(1); + OUTPAL_START(0); + for (i = 0; i < 256; i++) { + RADEONWaitForFifo(pScrn, 32); /* delay */ + OUTPAL_NEXT_CARD32(restore->palette2[i]); + } + + PAL_SELECT(0); + OUTPAL_START(0); + for (i = 0; i < 256; i++) { + RADEONWaitForFifo(pScrn, 32); /* delay */ + OUTPAL_NEXT_CARD32(restore->palette[i]); + } +} +#endif + +/* Write out state to define a new video mode */ +static void RADEONRestoreMode(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + static RADEONSaveRec restore0; + + /* For Non-dual head card, we don't have private field in the Entity */ + if (!info->HasCRTC2) { + RADEONRestoreCommonRegisters(pScrn, restore); + RADEONRestoreCrtcRegisters(pScrn, restore); + RADEONRestoreFPRegisters(pScrn, restore); + RADEONRestorePLLRegisters(pScrn, restore); + return; + } + + RADEONTRACE(("RADEONRestoreMode(%p)\n", restore)); + + /* When changing mode with Dual-head card, care must be taken for + * the special order in setting registers. CRTC2 has to be set + * before changing CRTC_EXT register. In the dual-head setup, X + * server calls this routine twice with primary and secondary pScrn + * pointers respectively. The calls can come with different + * order. Regardless the order of X server issuing the calls, we + * have to ensure we set registers in the right order!!! Otherwise + * we may get a blank screen. + */ + if (info->IsSecondary) { + if (!pRADEONEnt->RestorePrimary && !info->IsSwitching) + RADEONRestoreCommonRegisters(pScrn, restore); + RADEONRestoreCrtc2Registers(pScrn, restore); + RADEONRestorePLL2Registers(pScrn, restore); + + if(info->IsSwitching) return; + + pRADEONEnt->IsSecondaryRestored = TRUE; + + if (pRADEONEnt->RestorePrimary) { + pRADEONEnt->RestorePrimary = FALSE; + + RADEONRestoreCrtcRegisters(pScrn, &restore0); + RADEONRestoreFPRegisters(pScrn, &restore0); + RADEONRestorePLLRegisters(pScrn, &restore0); + pRADEONEnt->IsSecondaryRestored = FALSE; + } + } else { + if (!pRADEONEnt->IsSecondaryRestored) + RADEONRestoreCommonRegisters(pScrn, restore); + + if (info->Clone) { + RADEONRestoreCrtc2Registers(pScrn, restore); + RADEONRestorePLL2Registers(pScrn, restore); + } + + if (!pRADEONEnt->HasSecondary || pRADEONEnt->IsSecondaryRestored || + info->IsSwitching) { + pRADEONEnt->IsSecondaryRestored = FALSE; + + RADEONRestoreCrtcRegisters(pScrn, restore); + RADEONRestoreFPRegisters(pScrn, restore); + RADEONRestorePLLRegisters(pScrn, restore); + } else { + memcpy(&restore0, restore, sizeof(restore0)); + pRADEONEnt->RestorePrimary = TRUE; + } + } + +#if 0 + RADEONRestorePalette(pScrn, &info->SavedReg); +#endif +} + +/* Read common registers */ +static void RADEONSaveCommonRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->ovr_clr = INREG(RADEON_OVR_CLR); + save->ovr_wid_left_right = INREG(RADEON_OVR_WID_LEFT_RIGHT); + save->ovr_wid_top_bottom = INREG(RADEON_OVR_WID_TOP_BOTTOM); + save->ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL); + save->subpic_cntl = INREG(RADEON_SUBPIC_CNTL); + save->viph_control = INREG(RADEON_VIPH_CONTROL); + save->i2c_cntl_1 = INREG(RADEON_I2C_CNTL_1); + save->gen_int_cntl = INREG(RADEON_GEN_INT_CNTL); + save->cap0_trig_cntl = INREG(RADEON_CAP0_TRIG_CNTL); + save->cap1_trig_cntl = INREG(RADEON_CAP1_TRIG_CNTL); + save->bus_cntl = INREG(RADEON_BUS_CNTL); + save->surface_cntl = INREG(RADEON_SURFACE_CNTL); + save->grph_buffer_cntl = INREG(RADEON_GRPH_BUFFER_CNTL); + save->grph2_buffer_cntl = INREG(RADEON_GRPH2_BUFFER_CNTL); +} + +/* Read miscellaneous registers which might be destroyed by an fbdevHW call */ +static void RADEONSaveFBDevRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ +#ifdef XF86DRI + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + /* Save register for vertical blank interrupts */ + if (info->irq) { + save->gen_int_cntl = INREG(RADEON_GEN_INT_CNTL); + } + + /* Save registers for page flipping */ + if (info->allowPageFlip) { + save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL); + if (info->HasCRTC2) { + save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); + } + } +#endif +} + +/* Read CRTC registers */ +static void RADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); + save->crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); + save->dac_cntl = INREG(RADEON_DAC_CNTL); + save->crtc_h_total_disp = INREG(RADEON_CRTC_H_TOTAL_DISP); + save->crtc_h_sync_strt_wid = INREG(RADEON_CRTC_H_SYNC_STRT_WID); + save->crtc_v_total_disp = INREG(RADEON_CRTC_V_TOTAL_DISP); + save->crtc_v_sync_strt_wid = INREG(RADEON_CRTC_V_SYNC_STRT_WID); + save->crtc_offset = INREG(RADEON_CRTC_OFFSET); + save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL); + save->crtc_pitch = INREG(RADEON_CRTC_PITCH); + save->disp_merge_cntl = INREG(RADEON_DISP_MERGE_CNTL); + save->crtc_more_cntl = INREG(RADEON_CRTC_MORE_CNTL); +} + +/* Read flat panel registers */ +static void RADEONSaveFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->fp_crtc_h_total_disp = INREG(RADEON_FP_CRTC_H_TOTAL_DISP); + save->fp_crtc_v_total_disp = INREG(RADEON_FP_CRTC_V_TOTAL_DISP); + save->fp_gen_cntl = INREG(RADEON_FP_GEN_CNTL); + save->fp_h_sync_strt_wid = INREG(RADEON_FP_H_SYNC_STRT_WID); + save->fp_horz_stretch = INREG(RADEON_FP_HORZ_STRETCH); + save->fp_v_sync_strt_wid = INREG(RADEON_FP_V_SYNC_STRT_WID); + save->fp_vert_stretch = INREG(RADEON_FP_VERT_STRETCH); + save->lvds_gen_cntl = INREG(RADEON_LVDS_GEN_CNTL); + save->lvds_pll_cntl = INREG(RADEON_LVDS_PLL_CNTL); + save->tmds_pll_cntl = INREG(RADEON_TMDS_PLL_CNTL); + save->tmds_transmitter_cntl= INREG(RADEON_TMDS_TRANSMITTER_CNTL); + save->bios_5_scratch = INREG(RADEON_BIOS_5_SCRATCH); + + if (info->ChipFamily == CHIP_FAMILY_RV280) { + /* bit 22 of TMDS_PLL_CNTL is read-back inverted */ + save->tmds_pll_cntl ^= (1 << 22); + } +} + +/* Read CRTC2 registers */ +static void RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->dac2_cntl = INREG(RADEON_DAC_CNTL2); + save->disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); + save->disp_hw_debug = INREG (RADEON_DISP_HW_DEBUG); + + save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + save->crtc2_h_total_disp = INREG(RADEON_CRTC2_H_TOTAL_DISP); + save->crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); + save->crtc2_v_total_disp = INREG(RADEON_CRTC2_V_TOTAL_DISP); + save->crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); + save->crtc2_offset = INREG(RADEON_CRTC2_OFFSET); + save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); + save->crtc2_pitch = INREG(RADEON_CRTC2_PITCH); + + save->fp2_h_sync_strt_wid = INREG (RADEON_FP_H2_SYNC_STRT_WID); + save->fp2_v_sync_strt_wid = INREG (RADEON_FP_V2_SYNC_STRT_WID); + save->fp2_gen_cntl = INREG (RADEON_FP2_GEN_CNTL); + save->disp2_merge_cntl = INREG(RADEON_DISP2_MERGE_CNTL); +} + +/* Read PLL registers */ +static void RADEONSavePLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + save->ppll_ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV); + save->ppll_div_3 = INPLL(pScrn, RADEON_PPLL_DIV_3); + save->htotal_cntl = INPLL(pScrn, RADEON_HTOTAL_CNTL); + + RADEONTRACE(("Read: 0x%08x 0x%08x 0x%08x\n", + save->ppll_ref_div, + save->ppll_div_3, + save->htotal_cntl)); + RADEONTRACE(("Read: rd=%d, fd=%d, pd=%d\n", + save->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + save->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, + (save->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16)); +} + +/* Read PLL registers */ +static void RADEONSavePLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + save->p2pll_ref_div = INPLL(pScrn, RADEON_P2PLL_REF_DIV); + save->p2pll_div_0 = INPLL(pScrn, RADEON_P2PLL_DIV_0); + save->htotal_cntl2 = INPLL(pScrn, RADEON_HTOTAL2_CNTL); + + RADEONTRACE(("Read: 0x%08x 0x%08x 0x%08x\n", + save->p2pll_ref_div, + save->p2pll_div_0, + save->htotal_cntl2)); + RADEONTRACE(("Read: rd=%d, fd=%d, pd=%d\n", + save->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + save->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK, + (save->p2pll_div_0 & RADEON_P2PLL_POST0_DIV_MASK) >> 16)); +} + +/* Read palette data */ +static void RADEONSavePalette(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + +#ifdef ENABLE_FLAT_PANEL + /* Select palette 0 (main CRTC) if using FP-enabled chip */ + /* if (info->Port1 == MT_DFP) PAL_SELECT(1); */ +#endif + PAL_SELECT(1); + INPAL_START(0); + for (i = 0; i < 256; i++) save->palette2[i] = INPAL_NEXT(); + PAL_SELECT(0); + INPAL_START(0); + for (i = 0; i < 256; i++) save->palette[i] = INPAL_NEXT(); + save->palette_valid = TRUE; +} + +/* Save state that defines current video mode */ +static void RADEONSaveMode(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + RADEONTRACE(("RADEONSaveMode(%p)\n", save)); + RADEONSaveCommonRegisters(pScrn, save); + if (info->IsSecondary) { + RADEONSaveCrtc2Registers(pScrn, save); + RADEONSavePLL2Registers(pScrn, save); + } else { + RADEONSavePLLRegisters(pScrn, save); + RADEONSaveCrtcRegisters(pScrn, save); + RADEONSaveFPRegisters(pScrn, save); + + if (info->Clone) { + RADEONSaveCrtc2Registers(pScrn, save); + RADEONSavePLL2Registers(pScrn, save); + } + /* RADEONSavePalette(pScrn, save); */ + } + + RADEONTRACE(("RADEONSaveMode returns %p\n", save)); +} + +/* Save everything needed to restore the original VC state */ +static void RADEONSave(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONSavePtr save = &info->SavedReg; + vgaHWPtr hwp = VGAHWPTR(pScrn); + + RADEONTRACE(("RADEONSave\n")); + if (info->FBDev) { + fbdevHWSave(pScrn); + return; + } + + if (!info->IsSecondary) { + vgaHWUnlock(hwp); +#if defined(__powerpc__) + /* temporary hack to prevent crashing on PowerMacs when trying to + * read VGA fonts and colormap, will find a better solution + * in the future + */ + vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */ +#else + vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS); /* Save mode + * & fonts & cmap + */ +#endif + vgaHWLock(hwp); + save->dp_datatype = INREG(RADEON_DP_DATATYPE); + save->rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET); + save->clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX); + if (info->R300CGWorkaround) R300CGWorkaround(pScrn); + } + + RADEONSaveMode(pScrn, save); +} + +/* Restore the original (text) mode */ +static void RADEONRestore(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONSavePtr restore = &info->SavedReg; + vgaHWPtr hwp = VGAHWPTR(pScrn); + + RADEONTRACE(("RADEONRestore\n")); + +#if X_BYTE_ORDER == X_BIG_ENDIAN + RADEONWaitForFifo(pScrn, 1); + OUTREG(RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_NONE); +#endif + + if (info->FBDev) { + fbdevHWRestore(pScrn); + return; + } + RADEONBlank(pScrn); + + OUTREG(RADEON_CLOCK_CNTL_INDEX, restore->clock_cntl_index); + if (info->R300CGWorkaround) R300CGWorkaround(pScrn); + OUTREG(RADEON_RBBM_SOFT_RESET, restore->rbbm_soft_reset); + OUTREG(RADEON_DP_DATATYPE, restore->dp_datatype); + OUTREG(RADEON_GRPH_BUFFER_CNTL, restore->grph_buffer_cntl); + OUTREG(RADEON_GRPH2_BUFFER_CNTL, restore->grph2_buffer_cntl); + +#if 0 + /* M6 card has trouble restoring text mode for its CRT. + * This is fixed elsewhere and will be removed in the future. + */ + if ((xf86IsEntityShared(info->pEnt->index) || info->Clone) + && info->IsM6) + OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); +#endif + + RADEONRestoreMode(pScrn, restore); + +#if 0 + /* Temp fix to "solve" VT switch problems. When switching VTs on + * some systems, the console can either hang or the fonts can be + * corrupted. This hack solves the problem 99% of the time. A + * correct fix is being worked on. + */ + usleep(100000); +#endif + + if (!info->IsSecondary) { + vgaHWUnlock(hwp); +#if defined(__powerpc__) + /* Temporary hack to prevent crashing on PowerMacs when trying to + * write VGA fonts, will find a better solution in the future + */ + vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE ); +#else + vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); +#endif + vgaHWLock(hwp); + } else { + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + ScrnInfoPtr pScrn0; + vgaHWPtr hwp0; + + pScrn0 = pRADEONEnt->pPrimaryScrn; + hwp0 = VGAHWPTR(pScrn0); + vgaHWUnlock(hwp0); + vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); + vgaHWLock(hwp0); + } + RADEONUnblank(pScrn); + +#if 0 + RADEONWaitForVerticalSync(pScrn); +#endif +} + +/* Define common registers for requested video mode */ +static void RADEONInitCommonRegisters(RADEONSavePtr save, RADEONInfoPtr info) +{ + save->ovr_clr = 0; + save->ovr_wid_left_right = 0; + save->ovr_wid_top_bottom = 0; + save->ov0_scale_cntl = 0; + save->subpic_cntl = 0; + save->viph_control = 0; + save->i2c_cntl_1 = 0; + save->rbbm_soft_reset = 0; + save->cap0_trig_cntl = 0; + save->cap1_trig_cntl = 0; + save->bus_cntl = info->BusCntl; + /* + * If bursts are enabled, turn on discards + * Radeon doesn't have write bursts + */ + if (save->bus_cntl & (RADEON_BUS_READ_BURST)) + save->bus_cntl |= RADEON_BUS_RD_DISCARD_EN; +} + +/* Calculate display buffer watermark to prevent buffer underflow */ +static void RADEONInitDispBandwidth(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONInfoPtr info2 = NULL; + + DisplayModePtr mode1, mode2; + + CARD32 temp, data, mem_trcd, mem_trp, mem_tras, mem_trbs=0; + float mem_tcas; + int k1, c; + CARD32 MemTrcdExtMemCntl[4] = {1, 2, 3, 4}; + CARD32 MemTrpExtMemCntl[4] = {1, 2, 3, 4}; + CARD32 MemTrasExtMemCntl[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + CARD32 MemTrcdMemTimingCntl[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + CARD32 MemTrpMemTimingCntl[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + CARD32 MemTrasMemTimingCntl[16] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; + + float MemTcas[8] = {0, 1, 2, 3, 0, 1.5, 2.5, 0}; + float MemTcas2[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + float MemTrbs[8] = {1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5}; + + float mem_bw, peak_disp_bw; + float min_mem_eff = 0.8; + float sclk_eff, sclk_delay; + float mc_latency_mclk, mc_latency_sclk, cur_latency_mclk, cur_latency_sclk; + float disp_latency, disp_latency_overhead, disp_drain_rate, disp_drain_rate2; + float pix_clk, pix_clk2; /* in MHz */ + int cur_size = 16; /* in octawords */ + int critical_point, critical_point2; + int stop_req, max_stop_req; + float read_return_rate, time_disp1_drop_priority; + + if (pRADEONEnt->pSecondaryScrn) { + if (info->IsSecondary) return; + info2 = RADEONPTR(pRADEONEnt->pSecondaryScrn); + } else if (info->Clone) info2 = info; + + /* + * Determine if there is enough bandwidth for current display mode + */ + mem_bw = info->mclk * (info->RamWidth / 8) * (info->IsDDR ? 2 : 1); + + mode1 = info->CurrentLayout.mode; + if (info->Clone) + mode2 = info->CurCloneMode; + else if ((pRADEONEnt->HasSecondary) && info2) + mode2 = info2->CurrentLayout.mode; + else + mode2 = NULL; + + pix_clk = mode1->Clock/1000.0; + if (mode2) + pix_clk2 = mode2->Clock/1000.0; + else + pix_clk2 = 0; + + peak_disp_bw = (pix_clk * info->CurrentLayout.pixel_bytes); + if (info2) + peak_disp_bw += (pix_clk2 * info2->CurrentLayout.pixel_bytes); + + if (peak_disp_bw >= mem_bw * min_mem_eff) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "You may not have enough display bandwidth for current mode\n" + "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); + } + + /* CRTC1 + Set GRPH_BUFFER_CNTL register using h/w defined optimal values. + GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] + */ + stop_req = mode1->HDisplay * info->CurrentLayout.pixel_bytes / 16; + + /* setup Max GRPH_STOP_REQ default value */ + if ((info->ChipFamily == CHIP_FAMILY_RV100) || + (info->ChipFamily == CHIP_FAMILY_RV200) || + (info->ChipFamily == CHIP_FAMILY_RV250) || + (info->ChipFamily == CHIP_FAMILY_RV280) || + (info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200) || + (info->ChipFamily == CHIP_FAMILY_RS300)) + max_stop_req = 0x5c; + else + max_stop_req = 0x7c; + if (stop_req > max_stop_req) + stop_req = max_stop_req; + + /* Get values from the EXT_MEM_CNTL register...converting its contents. */ + temp = INREG(RADEON_MEM_TIMING_CNTL); + if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */ + mem_trcd = MemTrcdExtMemCntl[(temp & 0x0c) >> 2]; + mem_trp = MemTrpExtMemCntl[ (temp & 0x03) >> 0]; + mem_tras = MemTrasExtMemCntl[(temp & 0x70) >> 4]; + } else { /* RV200 and later */ + mem_trcd = MemTrcdMemTimingCntl[(temp & 0x07) >> 0]; + mem_trp = MemTrpMemTimingCntl[ (temp & 0x700) >> 8]; + mem_tras = MemTrasMemTimingCntl[(temp & 0xf000) >> 12]; + } + + /* Get values from the MEM_SDRAM_MODE_REG register...converting its */ + temp = INREG(RADEON_MEM_SDRAM_MODE_REG); + data = (temp & (7<<20)) >> 20; + if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */ + mem_tcas = MemTcas [data]; + } else { + mem_tcas = MemTcas2 [data]; + } + + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) { + + /* on the R300, Tcas is included in Trbs. + */ + temp = INREG(RADEON_MEM_CNTL); + data = (R300_MEM_NUM_CHANNELS_MASK & temp); + if (data == 2) { + if (R300_MEM_USE_CD_CH_ONLY & temp) { + temp = INREG(R300_MC_IND_INDEX); + temp &= ~R300_MC_IND_ADDR_MASK; + temp |= R300_MC_READ_CNTL_CD_mcind; + OUTREG(R300_MC_IND_INDEX, temp); + temp = INREG(R300_MC_IND_DATA); + data = (R300_MEM_RBS_POSITION_C_MASK & temp); + } else { + temp = INREG(R300_MC_READ_CNTL_AB); + data = (R300_MEM_RBS_POSITION_A_MASK & temp); + } + } else { + temp = INREG(R300_MC_READ_CNTL_AB); + data = (R300_MEM_RBS_POSITION_A_MASK & temp); + } + + mem_trbs = MemTrbs[data]; + mem_tcas += mem_trbs; + } + + if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */ + /* DDR64 SCLK_EFF = SCLK for analysis */ + sclk_eff = info->sclk; + } else { +#ifdef XF86DRI + if (info->directRenderingEnabled) + sclk_eff = info->sclk - (info->agpMode * 50.0 / 3.0); + else +#endif + sclk_eff = info->sclk; + } + + /* Find the memory controller latency for the display client. + */ + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350)) { + /*not enough for R350 ???*/ + /* + if (!mode2) sclk_delay = 150; + else { + if (info->RamWidth == 256) sclk_delay = 87; + else sclk_delay = 97; + } + */ + sclk_delay = 250; + } else { + if ((info->ChipFamily == CHIP_FAMILY_RV100) || + info->IsIGP) { + if (info->IsDDR) sclk_delay = 41; + else sclk_delay = 33; + } else { + if (info->RamWidth == 128) sclk_delay = 57; + else sclk_delay = 41; + } + } + + mc_latency_sclk = sclk_delay / sclk_eff; + + if (info->IsDDR) { + if (info->RamWidth == 32) { + k1 = 40; + c = 3; + } else { + k1 = 20; + c = 1; + } + } else { + k1 = 40; + c = 3; + } + mc_latency_mclk = ((2.0*mem_trcd + mem_tcas*c + 4.0*mem_tras + 4.0*mem_trp + k1) / + info->mclk) + (4.0 / sclk_eff); + + /* + HW cursor time assuming worst case of full size colour cursor. + */ + cur_latency_mclk = (mem_trp + MAX(mem_tras, (mem_trcd + 2*(cur_size - (info->IsDDR+1))))) / info->mclk; + cur_latency_sclk = cur_size / sclk_eff; + + /* + Find the total latency for the display data. + */ + disp_latency_overhead = 8.0 / info->sclk; + mc_latency_mclk = mc_latency_mclk + disp_latency_overhead + cur_latency_mclk; + mc_latency_sclk = mc_latency_sclk + disp_latency_overhead + cur_latency_sclk; + disp_latency = MAX(mc_latency_mclk, mc_latency_sclk); + + /* + Find the drain rate of the display buffer. + */ + disp_drain_rate = pix_clk / (16.0/info->CurrentLayout.pixel_bytes); + if (info2) + disp_drain_rate2 = pix_clk2 / (16.0/info2->CurrentLayout.pixel_bytes); + else + disp_drain_rate2 = 0; + + /* + Find the critical point of the display buffer. + */ + critical_point= (CARD32)(disp_drain_rate * disp_latency + 0.5); + + /* ???? */ + /* + temp = (info->SavedReg.grph_buffer_cntl & RADEON_GRPH_CRITICAL_POINT_MASK) >> RADEON_GRPH_CRITICAL_POINT_SHIFT; + if (critical_point < temp) critical_point = temp; + */ + if (info->DispPriority == 2) { + if (mode2) { + /*??some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ + if (info->ChipFamily == CHIP_FAMILY_R300) + critical_point += 0x10; + else + critical_point = 0; + } + else + critical_point = 0; + } + + /* + The critical point should never be above max_stop_req-4. Setting + GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. + */ + if (max_stop_req - critical_point < 4) critical_point = 0; + + temp = info->SavedReg.grph_buffer_cntl; + temp &= ~(RADEON_GRPH_STOP_REQ_MASK); + temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); + temp &= ~(RADEON_GRPH_START_REQ_MASK); + if ((info->ChipFamily == CHIP_FAMILY_R350) && + (stop_req > 0x15)) { + stop_req -= 0x10; + } + temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); + + temp |= RADEON_GRPH_BUFFER_SIZE; + temp &= ~(RADEON_GRPH_CRITICAL_CNTL | + RADEON_GRPH_CRITICAL_AT_SOF | + RADEON_GRPH_STOP_CNTL); + /* + Write the result into the register. + */ + OUTREG(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | + (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + + RADEONTRACE(("GRPH_BUFFER_CNTL from %x to %x\n", + info->SavedReg.grph_buffer_cntl, INREG(RADEON_GRPH_BUFFER_CNTL))); + + if (mode2) { + stop_req = mode2->HDisplay * info2->CurrentLayout.pixel_bytes / 16; + + if (stop_req > max_stop_req) stop_req = max_stop_req; + + temp = info->SavedReg.grph2_buffer_cntl; + temp &= ~(RADEON_GRPH_STOP_REQ_MASK); + temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); + temp &= ~(RADEON_GRPH_START_REQ_MASK); + if ((info->ChipFamily == CHIP_FAMILY_R350) && + (stop_req > 0x15)) { + stop_req -= 0x10; + } + temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); + temp |= RADEON_GRPH_BUFFER_SIZE; + temp &= ~(RADEON_GRPH_CRITICAL_CNTL | + RADEON_GRPH_CRITICAL_AT_SOF | + RADEON_GRPH_STOP_CNTL); + + if ((info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200)) + critical_point2 = 0; + else { + read_return_rate = MIN(info->sclk, info->mclk*(info->RamWidth*(info->IsDDR+1)/128)); + time_disp1_drop_priority = critical_point / (read_return_rate - disp_drain_rate); + + critical_point2 = (CARD32)((disp_latency + time_disp1_drop_priority + + disp_latency) * disp_drain_rate2 + 0.5); + + if (info->DispPriority == 2) { + if (info->ChipFamily == CHIP_FAMILY_R300) + critical_point2 += 0x10; + else + critical_point2 = 0; + } + + if (max_stop_req - critical_point2 < 4) critical_point2 = 0; + + } + + OUTREG(RADEON_GRPH2_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | + (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + + RADEONTRACE(("GRPH2_BUFFER_CNTL from %x to %x\n", + info->SavedReg.grph2_buffer_cntl, INREG(RADEON_GRPH2_BUFFER_CNTL))); + } +} + +/* Define CRTC registers for requested video mode */ +static Bool RADEONInitCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, RADEONInfoPtr info) +{ + unsigned char *RADEONMMIO = info->MMIO; + + int format; + int hsync_start; + int hsync_wid; + int hsync_fudge; + int vsync_wid; + int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; + int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 }; + + switch (info->CurrentLayout.pixel_code) { + case 4: format = 1; break; + case 8: format = 2; break; + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported pixel depth (%d)\n", + info->CurrentLayout.bitsPerPixel); + return FALSE; + } + + if ((info->DisplayType == MT_DFP) || + (info->DisplayType == MT_LCD)) { + hsync_fudge = hsync_fudge_fp[format-1]; + if (mode->Flags & RADEON_USE_RMX) { +#if 0 + mode->CrtcHDisplay = info->PanelXRes; + mode->CrtcVDisplay = info->PanelYRes; +#endif + mode->CrtcHTotal = mode->CrtcHDisplay + info->HBlank; + mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlus; + mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidth; + mode->CrtcVTotal = mode->CrtcVDisplay + info->VBlank; + mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlus; + mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidth; + mode->Clock = info->DotClock; + mode->Flags = info->Flags | RADEON_USE_RMX; + } + } else { + hsync_fudge = hsync_fudge_default[format-1]; + } + + save->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN + | RADEON_CRTC_EN + | (format << 8) + | ((mode->Flags & V_DBLSCAN) + ? RADEON_CRTC_DBL_SCAN_EN + : 0) + | ((mode->Flags & V_CSYNC) + ? RADEON_CRTC_CSYNC_EN + : 0) + | ((mode->Flags & V_INTERLACE) + ? RADEON_CRTC_INTERLACE_EN + : 0)); + + if ((info->DisplayType == MT_DFP) || + (info->DisplayType == MT_LCD)) { + save->crtc_ext_cntl = RADEON_VGA_ATI_LINEAR | RADEON_XCRT_CNT_EN; + save->crtc_gen_cntl &= ~(RADEON_CRTC_DBL_SCAN_EN | + RADEON_CRTC_CSYNC_EN | + RADEON_CRTC_INTERLACE_EN); + } else { + save->crtc_ext_cntl = (RADEON_VGA_ATI_LINEAR | + RADEON_XCRT_CNT_EN | + RADEON_CRTC_CRT_ON); + } + + save->dac_cntl = (RADEON_DAC_MASK_ALL + | RADEON_DAC_VGA_ADR_EN + | (info->dac6bits ? 0 : RADEON_DAC_8BIT_EN)); + + save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff) + | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) + << 16)); + + hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; + if (!hsync_wid) hsync_wid = 1; + hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge; + + save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->Flags & V_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + +#if 1 + /* This works for double scan mode. */ + save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay - 1) << 16)); +#else + /* This is what cce/nbmode.c example code + * does -- is this correct? + */ + save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay + * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1) + << 16)); +#endif + + vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + if (!vsync_wid) vsync_wid = 1; + + save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->Flags & V_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0)); + + save->crtc_offset = 0; + save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL); + + save->crtc_pitch = (((pScrn->displayWidth * pScrn->bitsPerPixel) + + ((pScrn->bitsPerPixel * 8) -1)) / + (pScrn->bitsPerPixel * 8)); + save->crtc_pitch |= save->crtc_pitch << 16; + + /* Some versions of BIOS setup CRTC_MORE_CNTL for a DFP, if we + have a CRT here, it should be cleared to avoild a blank screen. + */ + if (info->DisplayType == MT_CRT) + save->crtc_more_cntl = (info->SavedReg.crtc_more_cntl & + ~(RADEON_CRTC_H_CUTOFF_ACTIVE_EN | + RADEON_CRTC_V_CUTOFF_ACTIVE_EN)); + else + save->crtc_more_cntl = info->SavedReg.crtc_more_cntl; + + save->surface_cntl = 0; + save->disp_merge_cntl = info->SavedReg.disp_merge_cntl; + save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* Alhought we current onlu use aperture 0, also setting aperture 1 should not harm -ReneR */ + switch (pScrn->bitsPerPixel) { + case 16: + save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP; + save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP; + break; + + case 32: + save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP; + save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP; + break; + } +#endif + + RADEONTRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n", + save->crtc_pitch, pScrn->virtualX, + info->CurrentLayout.displayWidth)); + return TRUE; +} + +/* Define CRTC2 registers for requested video mode */ +static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, RADEONInfoPtr info) +{ + unsigned char *RADEONMMIO = info->MMIO; + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + int format; + int hsync_start; + int hsync_wid; + int hsync_fudge; + int vsync_wid; + int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; + + switch (info->CurrentLayout.pixel_code) { + case 4: format = 1; break; + case 8: format = 2; break; + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported pixel depth (%d)\n", + info->CurrentLayout.bitsPerPixel); + return FALSE; + } + + hsync_fudge = hsync_fudge_default[format-1]; + + save->crtc2_gen_cntl = (RADEON_CRTC2_EN + | RADEON_CRTC2_CRT2_ON + | (format << 8) + | ((mode->Flags & V_DBLSCAN) + ? RADEON_CRTC2_DBL_SCAN_EN + : 0) + | ((mode->Flags & V_CSYNC) + ? RADEON_CRTC2_CSYNC_EN + : 0) + | ((mode->Flags & V_INTERLACE) + ? RADEON_CRTC2_INTERLACE_EN + : 0)); + + /* Turn CRT on in case the first head is a DFP */ + save->crtc_ext_cntl |= RADEON_CRTC_CRT_ON; + save->dac2_cntl = info->SavedReg.dac2_cntl; + /* always let TVDAC drive CRT2, we don't support tvout yet */ + save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + save->disp_output_cntl = info->SavedReg.disp_output_cntl; + if (info->ChipFamily == CHIP_FAMILY_R200 || + info->ChipFamily == CHIP_FAMILY_R300 || + info->ChipFamily == CHIP_FAMILY_R350 || + info->ChipFamily == CHIP_FAMILY_RV350) { + save->disp_output_cntl &= ~(RADEON_DISP_DAC_SOURCE_MASK | + RADEON_DISP_DAC2_SOURCE_MASK); + if (pRADEONEnt->MonType1 != MT_CRT) { + save->disp_output_cntl |= (RADEON_DISP_DAC_SOURCE_CRTC2 | + RADEON_DISP_DAC2_SOURCE_CRTC2); + } else { + if (pRADEONEnt->ReversedDAC) { + save->disp_output_cntl |= RADEON_DISP_DAC2_SOURCE_CRTC2; + } else { + save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + } + } + } else { + save->disp_hw_debug = info->SavedReg.disp_hw_debug; + /* Turn on 2nd CRT */ + if (pRADEONEnt->MonType1 != MT_CRT) { + /* This is for some sample boards with the VGA port + connected to the TVDAC, but BIOS doesn't reflect this. + Here we configure both DACs to use CRTC2. + Not sure if this happens in any retail board. + */ + save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; + save->dac2_cntl |= RADEON_DAC2_DAC_CLK_SEL; + } else { + if (pRADEONEnt->ReversedDAC) { + save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; + save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; + } else { + save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + save->dac2_cntl |= RADEON_DAC2_DAC_CLK_SEL; + } + } + } + + save->crtc2_h_total_disp = + ((((mode->CrtcHTotal / 8) - 1) & 0x3ff) + | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) << 16)); + + hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; + if (!hsync_wid) hsync_wid = 1; + hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge; + + save->crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->Flags & V_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + +#if 1 + /* This works for double scan mode. */ + save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay - 1) << 16)); +#else + /* This is what cce/nbmode.c example code + * does -- is this correct? + */ + save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay + * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1) + << 16)); +#endif + + vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + if (!vsync_wid) vsync_wid = 1; + + save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->Flags & V_NVSYNC) + ? RADEON_CRTC2_V_SYNC_POL + : 0)); + + save->crtc2_offset = 0; + save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); + + save->crtc2_pitch = (((pScrn->displayWidth * pScrn->bitsPerPixel) + + ((pScrn->bitsPerPixel * 8) -1)) / + (pScrn->bitsPerPixel * 8)); + save->crtc2_pitch |= save->crtc2_pitch << 16; + save->disp2_merge_cntl = info->SavedReg.disp2_merge_cntl; + save->disp2_merge_cntl &= ~(RADEON_DISP2_RGB_OFFSET_EN); + + if ((info->DisplayType == MT_DFP && info->IsSecondary) || + info->CloneType == MT_DFP) { + save->crtc2_gen_cntl = (RADEON_CRTC2_EN | (format << 8)); + save->fp2_h_sync_strt_wid = save->crtc2_h_sync_strt_wid; + save->fp2_v_sync_strt_wid = save->crtc2_v_sync_strt_wid; + save->fp2_gen_cntl = (RADEON_FP2_PANEL_FORMAT | + RADEON_FP2_ON); + if (info->ChipFamily >= CHIP_FAMILY_R200) { + save->fp2_gen_cntl |= RADEON_FP2_DV0_EN; + } + + if (info->ChipFamily == CHIP_FAMILY_R200 || + info->ChipFamily == CHIP_FAMILY_R300 || + info->ChipFamily == CHIP_FAMILY_R350 || + info->ChipFamily == CHIP_FAMILY_RV350) { + save->fp2_gen_cntl &= ~RADEON_FP2_SOURCE_SEL_MASK; + save->fp2_gen_cntl |= RADEON_FP2_SOURCE_SEL_CRTC2; + } else { + save->fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_MASK; + save->fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; + } + + if (pScrn->rgbBits == 8) + save->fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format */ + else + save->fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format */ + + /* FIXME: When there are two DFPs, the 2nd DFP is driven by the + * external TMDS transmitter. It may have a problem at + * high dot clock for certain panels. + */ + + /* If BIOS has not turned it on, we'll keep it on so that we'll + * have a valid VGA screen even after X quits or VT is switched + * to the console mode. + */ + info->SavedReg.fp2_gen_cntl = RADEON_FP2_ON; + } + + RADEONTRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n", + save->crtc2_pitch, pScrn->virtualX, + info->CurrentLayout.displayWidth)); + + return TRUE; +} + +/* Define CRTC registers for requested video mode */ +static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig, + RADEONSavePtr save, DisplayModePtr mode, + RADEONInfoPtr info) +{ + int xres = mode->HDisplay; + int yres = mode->VDisplay; + float Hratio, Vratio; + + /* If the FP registers have been initialized before for a panel, + * but the primary port is a CRT, we need to reinitialize + * FP registers in order for CRT to work properly + */ + + if ((info->DisplayType != MT_DFP) && (info->DisplayType != MT_LCD)) { + save->fp_crtc_h_total_disp = orig->fp_crtc_h_total_disp; + save->fp_crtc_v_total_disp = orig->fp_crtc_v_total_disp; + save->fp_gen_cntl = 0; + save->fp_h_sync_strt_wid = orig->fp_h_sync_strt_wid; + save->fp_horz_stretch = 0; + save->fp_v_sync_strt_wid = orig->fp_v_sync_strt_wid; + save->fp_vert_stretch = 0; + save->lvds_gen_cntl = orig->lvds_gen_cntl; + save->lvds_pll_cntl = orig->lvds_pll_cntl; + save->tmds_pll_cntl = orig->tmds_pll_cntl; + save->tmds_transmitter_cntl= orig->tmds_transmitter_cntl; + + save->lvds_gen_cntl |= ( RADEON_LVDS_DISPLAY_DIS | (1 << 23)); + save->lvds_gen_cntl &= ~(RADEON_LVDS_BLON | RADEON_LVDS_ON); + save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + + return; + } + + if (info->PanelXRes == 0 || info->PanelYRes == 0) { + Hratio = 1.0; + Vratio = 1.0; + } else { + if (xres > info->PanelXRes) xres = info->PanelXRes; + if (yres > info->PanelYRes) yres = info->PanelYRes; + + Hratio = (float)xres/(float)info->PanelXRes; + Vratio = (float)yres/(float)info->PanelYRes; + } + + if (Hratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) { + save->fp_horz_stretch = orig->fp_horz_stretch; + save->fp_horz_stretch &= ~(RADEON_HORZ_STRETCH_BLEND | + RADEON_HORZ_STRETCH_ENABLE); + save->fp_horz_stretch &= ~(RADEON_HORZ_AUTO_RATIO | + RADEON_HORZ_PANEL_SIZE); + save->fp_horz_stretch |= ((xres/8-1)<<16); + + } else { + save->fp_horz_stretch = + ((((unsigned long)(Hratio * RADEON_HORZ_STRETCH_RATIO_MAX + + 0.5)) & RADEON_HORZ_STRETCH_RATIO_MASK)) | + (orig->fp_horz_stretch & (RADEON_HORZ_PANEL_SIZE | + RADEON_HORZ_FP_LOOP_STRETCH | + RADEON_HORZ_AUTO_RATIO_INC)); + save->fp_horz_stretch |= (RADEON_HORZ_STRETCH_BLEND | + RADEON_HORZ_STRETCH_ENABLE); + + save->fp_horz_stretch &= ~(RADEON_HORZ_AUTO_RATIO | + RADEON_HORZ_PANEL_SIZE); + save->fp_horz_stretch |= ((info->PanelXRes / 8 - 1) << 16); + + } + + if (Vratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) { + save->fp_vert_stretch = orig->fp_vert_stretch; + save->fp_vert_stretch &= ~(RADEON_VERT_STRETCH_ENABLE| + RADEON_VERT_STRETCH_BLEND); + save->fp_vert_stretch &= ~(RADEON_VERT_AUTO_RATIO_EN | + RADEON_VERT_PANEL_SIZE); + save->fp_vert_stretch |= ((yres-1) << 12); + } else { + save->fp_vert_stretch = + (((((unsigned long)(Vratio * RADEON_VERT_STRETCH_RATIO_MAX + + 0.5)) & RADEON_VERT_STRETCH_RATIO_MASK)) | + (orig->fp_vert_stretch & (RADEON_VERT_PANEL_SIZE | + RADEON_VERT_STRETCH_RESERVED))); + save->fp_vert_stretch |= (RADEON_VERT_STRETCH_ENABLE | + RADEON_VERT_STRETCH_BLEND); + + save->fp_vert_stretch &= ~(RADEON_VERT_AUTO_RATIO_EN | + RADEON_VERT_PANEL_SIZE); + save->fp_vert_stretch |= ((info->PanelYRes-1) << 12); + + } + + save->fp_gen_cntl = (orig->fp_gen_cntl & (CARD32) + ~(RADEON_FP_SEL_CRTC2 | + RADEON_FP_RMX_HVSYNC_CONTROL_EN | + RADEON_FP_DFP_SYNC_SEL | + RADEON_FP_CRT_SYNC_SEL | + RADEON_FP_CRTC_LOCK_8DOT | + RADEON_FP_USE_SHADOW_EN | + RADEON_FP_CRTC_USE_SHADOW_VEND | + RADEON_FP_CRT_SYNC_ALT)); + save->fp_gen_cntl |= (RADEON_FP_CRTC_DONT_SHADOW_VPAR | + RADEON_FP_CRTC_DONT_SHADOW_HEND ); + + if (pScrn->rgbBits == 8) + save->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ + else + save->fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ + + save->lvds_gen_cntl = orig->lvds_gen_cntl; + save->lvds_pll_cntl = orig->lvds_pll_cntl; + + info->PanelOff = FALSE; + /* This option is used to force the ONLY DEVICE in XFConfig to use + * CRT port, instead of default DVI port. + */ + if (xf86ReturnOptValBool(info->Options, OPTION_PANEL_OFF, FALSE)) { + info->PanelOff = TRUE; + } + + save->tmds_pll_cntl = orig->tmds_pll_cntl; + save->tmds_transmitter_cntl= orig->tmds_transmitter_cntl; + if (info->PanelOff && info->Clone) { + info->OverlayOnCRTC2 = TRUE; + if (info->DisplayType == MT_LCD) { + /* Turning off LVDS_ON seems to make panel white blooming. + * For now we just turn off display data ??? + */ + save->lvds_gen_cntl |= (RADEON_LVDS_DISPLAY_DIS); + save->lvds_gen_cntl &= ~(RADEON_LVDS_BLON | RADEON_LVDS_ON); + + } else if (info->DisplayType == MT_DFP) + save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + } else { + if (info->DisplayType == MT_LCD) { + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + /* BIOS will use this setting to reset displays upon lid close/open. + * Here we let BIOS controls LCD, but the driver will control the external CRT. + */ + if (info->Clone || pRADEONEnt->HasSecondary) + save->bios_5_scratch = 0x01020201; + else + save->bios_5_scratch = orig->bios_5_scratch; + + save->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON); + save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + + } else if (info->DisplayType == MT_DFP) { + int i; + CARD32 tmp = orig->tmds_pll_cntl & 0xfffff; + for (i=0; i<4; i++) { + if (info->tmds_pll[i].freq == 0) break; + if (save->dot_clock_freq < info->tmds_pll[i].freq) { + tmp = info->tmds_pll[i].value ; + break; + } + } + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350) || + (info->ChipFamily == CHIP_FAMILY_RV280)) { + if (tmp & 0xfff00000) + save->tmds_pll_cntl = tmp; + else + save->tmds_pll_cntl = (orig->tmds_pll_cntl & 0xfff00000) | tmp; + } else save->tmds_pll_cntl = tmp; + + RADEONTRACE(("TMDS_PLL from %x to %x\n", + orig->tmds_pll_cntl, + save->tmds_pll_cntl)); + + save->tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLRST); + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350) || + (info->ChipFamily == CHIP_FAMILY_R200) || !info->HasCRTC2) + save->tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); + else /* weird, RV chips got this bit reversed? */ + save->tmds_transmitter_cntl |= (RADEON_TMDS_TRANSMITTER_PLLEN); + + save->fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); + } + } + + save->fp_crtc_h_total_disp = save->crtc_h_total_disp; + save->fp_crtc_v_total_disp = save->crtc_v_total_disp; + save->fp_h_sync_strt_wid = save->crtc_h_sync_strt_wid; + save->fp_v_sync_strt_wid = save->crtc_v_sync_strt_wid; +} + +/* Define PLL registers for requested video mode */ +static void RADEONInitPLLRegisters(RADEONSavePtr save, RADEONPLLPtr pll, + double dot_clock) +{ + unsigned long freq = dot_clock * 100; + + struct { + int divider; + int bitvalue; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 16, 5 }, /* VCLK_SRC/16 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + + if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; + if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + save->pll_output_freq = post_div->divider * freq; + + if (save->pll_output_freq >= pll->min_pll_freq + && save->pll_output_freq <= pll->max_pll_freq) break; + } + + if (!post_div->divider) { + save->pll_output_freq = freq; + post_div = &post_divs[0]; + } + + save->dot_clock_freq = freq; + save->feedback_div = RADEONDiv(pll->reference_div + * save->pll_output_freq, + pll->reference_freq); + save->post_div = post_div->divider; + + RADEONTRACE(("dc=%d, of=%d, fd=%d, pd=%d\n", + save->dot_clock_freq, + save->pll_output_freq, + save->feedback_div, + save->post_div)); + + save->ppll_ref_div = pll->reference_div; + save->ppll_div_3 = (save->feedback_div | (post_div->bitvalue << 16)); + save->htotal_cntl = 0; +} + +/* Define PLL2 registers for requested video mode */ +static void RADEONInitPLL2Registers(RADEONSavePtr save, RADEONPLLPtr pll, + double dot_clock) +{ + unsigned long freq = dot_clock * 100; + + struct { + int divider; + int bitvalue; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + + if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; + if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + save->pll_output_freq_2 = post_div->divider * freq; + if (save->pll_output_freq_2 >= pll->min_pll_freq + && save->pll_output_freq_2 <= pll->max_pll_freq) break; + } + + if (!post_div->divider) { + save->pll_output_freq_2 = freq; + post_div = &post_divs[0]; + } + + save->dot_clock_freq_2 = freq; + save->feedback_div_2 = RADEONDiv(pll->reference_div + * save->pll_output_freq_2, + pll->reference_freq); + save->post_div_2 = post_div->divider; + + RADEONTRACE(("dc=%d, of=%d, fd=%d, pd=%d\n", + save->dot_clock_freq_2, + save->pll_output_freq_2, + save->feedback_div_2, + save->post_div_2)); + + save->p2pll_ref_div = pll->reference_div; + save->p2pll_div_0 = (save->feedback_div_2 | + (post_div->bitvalue << 16)); + save->htotal_cntl2 = 0; +} + +#if 0 +/* Define initial palette for requested video mode. This doesn't do + * anything for XFree86 4.0. + */ +static void RADEONInitPalette(RADEONSavePtr save) +{ + save->palette_valid = FALSE; +} +#endif + +/* Define registers for a requested video mode */ +static Bool RADEONInit(ScrnInfoPtr pScrn, DisplayModePtr mode, + RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + double dot_clock = mode->Clock/1000.0; + +#if RADEON_DEBUG + ErrorF("%-12.12s %7.2f %4d %4d %4d %4d %4d %4d %4d %4d (%d,%d)", + mode->name, + dot_clock, + + mode->HDisplay, + mode->HSyncStart, + mode->HSyncEnd, + mode->HTotal, + + mode->VDisplay, + mode->VSyncStart, + mode->VSyncEnd, + mode->VTotal, + pScrn->depth, + pScrn->bitsPerPixel); + if (mode->Flags & V_DBLSCAN) ErrorF(" D"); + if (mode->Flags & V_CSYNC) ErrorF(" C"); + if (mode->Flags & V_INTERLACE) ErrorF(" I"); + if (mode->Flags & V_PHSYNC) ErrorF(" +H"); + if (mode->Flags & V_NHSYNC) ErrorF(" -H"); + if (mode->Flags & V_PVSYNC) ErrorF(" +V"); + if (mode->Flags & V_NVSYNC) ErrorF(" -V"); + ErrorF("\n"); + ErrorF("%-12.12s %7.2f %4d %4d %4d %4d %4d %4d %4d %4d (%d,%d)", + mode->name, + dot_clock, + + mode->CrtcHDisplay, + mode->CrtcHSyncStart, + mode->CrtcHSyncEnd, + mode->CrtcHTotal, + + mode->CrtcVDisplay, + mode->CrtcVSyncStart, + mode->CrtcVSyncEnd, + mode->CrtcVTotal, + pScrn->depth, + pScrn->bitsPerPixel); + if (mode->Flags & V_DBLSCAN) ErrorF(" D"); + if (mode->Flags & V_CSYNC) ErrorF(" C"); + if (mode->Flags & V_INTERLACE) ErrorF(" I"); + if (mode->Flags & V_PHSYNC) ErrorF(" +H"); + if (mode->Flags & V_NHSYNC) ErrorF(" -H"); + if (mode->Flags & V_PVSYNC) ErrorF(" +V"); + if (mode->Flags & V_NVSYNC) ErrorF(" -V"); + ErrorF("\n"); +#endif + + info->Flags = mode->Flags; + + RADEONInitCommonRegisters(save, info); + if (info->IsSecondary) { + if (!RADEONInitCrtc2Registers(pScrn, save, mode, info)) + return FALSE; + RADEONInitPLL2Registers(save, &info->pll, dot_clock); + } else { + if (!RADEONInitCrtcRegisters(pScrn, save, mode, info)) + return FALSE; + dot_clock = mode->Clock/1000.0; + if (dot_clock) { + if (info->UseBiosDividers) { + save->ppll_ref_div = info->RefDivider; + save->ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16); + save->htotal_cntl = 0; + } + else + RADEONInitPLLRegisters(save, &info->pll, dot_clock); + } else { + save->ppll_ref_div = info->SavedReg.ppll_ref_div; + save->ppll_div_3 = info->SavedReg.ppll_div_3; + save->htotal_cntl = info->SavedReg.htotal_cntl; + } + + if (info->Clone && info->CurCloneMode) { + RADEONInitCrtc2Registers(pScrn, save, info->CurCloneMode, info); + dot_clock = info->CurCloneMode->Clock / 1000.0; + RADEONInitPLL2Registers(save, &info->pll, dot_clock); + } + /* Not used for now: */ + /* if (!info->PaletteSavedOnVT) RADEONInitPalette(save); */ + } + + RADEONInitFPRegisters(pScrn, &info->SavedReg, save, mode, info); + + RADEONTRACE(("RADEONInit returns %p\n", save)); + return TRUE; +} + +/* Initialize a new mode */ +static Bool RADEONModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (!RADEONInit(pScrn, mode, &info->ModeReg)) return FALSE; + + pScrn->vtSema = TRUE; + RADEONBlank(pScrn); + RADEONRestoreMode(pScrn, &info->ModeReg); + RADEONUnblank(pScrn); + + info->CurrentLayout.mode = mode; + + if (info->DispPriority) + RADEONInitDispBandwidth(pScrn); + + return TRUE; +} + +static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + Bool unblank; + + unblank = xf86IsUnblank(mode); + if (unblank) SetTimeSinceLastInputEvent(); + + if ((pScrn != NULL) && pScrn->vtSema) { + if (unblank) RADEONUnblank(pScrn); + else RADEONBlank(pScrn); + } + return TRUE; +} + +Bool RADEONSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + Bool ret; +#ifdef XF86DRI + Bool CPStarted = info->CPStarted; + + if (CPStarted) { + DRILock(pScrn->pScreen, 0); + RADEONCP_STOP(pScrn, info); + } +#endif + + if (info->accelOn) info->accel->Sync(pScrn); + + if (info->FBDev) { + RADEONSaveFBDevRegisters(pScrn, &info->ModeReg); + + ret = fbdevHWSwitchMode(scrnIndex, mode, flags); + + RADEONRestoreFBDevRegisters(pScrn, &info->ModeReg); + } else { + info->IsSwitching = TRUE; + if (info->Clone && info->CloneModes) { + DisplayModePtr clone_mode = info->CloneModes; + + /* Try to match a mode on primary head + * FIXME: This may not be good if both heads don't have + * exactly the same list of mode. + */ + while (1) { + if ((clone_mode->HDisplay == mode->HDisplay) && + (clone_mode->VDisplay == mode->VDisplay) && + (!info->PanelOff)) { + info->CloneFrameX0 = (info->CurCloneMode->HDisplay + + info->CloneFrameX0 - + clone_mode->HDisplay - 1) / 2; + info->CloneFrameY0 = + (info->CurCloneMode->VDisplay + info->CloneFrameY0 - + clone_mode->VDisplay - 1) / 2; + info->CurCloneMode = clone_mode; + break; + } + + if (!clone_mode->next) { + info->CurCloneMode = info->CloneModes; + break; + } + + clone_mode = clone_mode->next; + } + } + ret = RADEONModeInit(xf86Screens[scrnIndex], mode); + + if (info->CurCloneMode) { + if (info->CloneFrameX0 + info->CurCloneMode->HDisplay >= + pScrn->virtualX) + info->CloneFrameX0 = + pScrn->virtualX - info->CurCloneMode->HDisplay; + else if (info->CloneFrameX0 < 0) + info->CloneFrameX0 = 0; + + if (info->CloneFrameY0 + info->CurCloneMode->VDisplay >= + pScrn->virtualY) + info->CloneFrameY0 = + pScrn->virtualY - info->CurCloneMode->VDisplay; + else if (info->CloneFrameY0 < 0) + info->CloneFrameY0 = 0; + + RADEONDoAdjustFrame(pScrn, info->CloneFrameX0, info->CloneFrameY0, + TRUE); + } + + info->IsSwitching = FALSE; + } + + if (info->accelOn) { + info->accel->Sync(pScrn); + RADEONEngineRestore(pScrn); + } + +#ifdef XF86DRI + if (CPStarted) { + RADEONCP_START(pScrn, info); + DRIUnlock(pScrn->pScreen); + } +#endif + + return ret; +} + +#ifdef X_XF86MiscPassMessage +Bool RADEONHandleMessage(int scrnIndex, const char* msgtype, + const char* msgval, char** retmsg) +{ + ErrorF("RADEONHandleMessage(%d, \"%s\", \"%s\", retmsg)\n", scrnIndex, + msgtype, msgval); + *retmsg = ""; + return 0; +} +#endif + +/* Used to disallow modes that are not supported by the hardware */ +ModeStatus RADEONValidMode(int scrnIndex, DisplayModePtr mode, + Bool verbose, int flag) +{ + /* There are problems with double scan mode at high clocks + * They're likely related PLL and display buffer settings. + * Disable these modes for now. + */ + if (mode->Flags & V_DBLSCAN) { + if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768)) + return MODE_CLOCK_RANGE; + } + return MODE_OK; +} + +/* Adjust viewport into virtual desktop such that (0,0) in viewport + * space is (x,y) in virtual space. + */ +void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int reg, Base = y * info->CurrentLayout.displayWidth + x; +#ifdef XF86DRI + RADEONSAREAPrivPtr pSAREAPriv; +#endif + + switch (info->CurrentLayout.pixel_code) { + case 15: + case 16: Base *= 2; break; + case 24: Base *= 3; break; + case 32: Base *= 4; break; + } + + Base &= ~7; /* 3 lower bits are always 0 */ + + if (clone || info->IsSecondary) { + Base += pScrn->fbOffset; + reg = RADEON_CRTC2_OFFSET; + } else { + reg = RADEON_CRTC_OFFSET; + } + +#ifdef XF86DRI + if (info->directRenderingEnabled) { + + pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + + if (clone || info->IsSecondary) { + pSAREAPriv->crtc2_base = Base; + } + + if (pSAREAPriv->pfCurrentPage == 1) { + Base += info->backOffset; + } + } +#endif + + OUTREG(reg, Base); +} + +void RADEONAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + +#ifdef XF86DRI + if (info->CPStarted) DRILock(pScrn->pScreen, 0); +#endif + + if (info->accelOn) info->accel->Sync(pScrn); + + if (info->FBDev) { + fbdevHWAdjustFrame(scrnIndex, x, y, flags); + } else { + RADEONDoAdjustFrame(pScrn, x, y, FALSE); + } + +#ifdef XF86DRI + if (info->CPStarted) DRIUnlock(pScrn->pScreen); +#endif +} + +/* Called when VT switching back to the X server. Reinitialize the + * video mode. + */ +Bool RADEONEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + RADEONTRACE(("RADEONEnterVT\n")); + + if (info->FBDev) { + unsigned char *RADEONMMIO = info->MMIO; + if (!fbdevHWEnterVT(scrnIndex,flags)) return FALSE; + info->PaletteSavedOnVT = FALSE; + info->ModeReg.surface_cntl = INREG(RADEON_SURFACE_CNTL); + + RADEONRestoreFBDevRegisters(pScrn, &info->ModeReg); + } else + if (!RADEONModeInit(pScrn, pScrn->currentMode)) return FALSE; + +#ifdef XF86DRI + if (info->directRenderingEnabled) { + /* get the Radeon back into shape after resume */ + RADEONDRIResume(pScrn->pScreen); + } +#endif + /* this will get XVideo going again, but only if XVideo was initialised + during server startup (hence the info->adaptor if). */ + if (info->adaptor) + RADEONResetVideo(pScrn); + + if (info->accelOn) + RADEONEngineRestore(pScrn); + +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONCP_START(pScrn, info); + DRIUnlock(pScrn->pScreen); + } +#endif + + pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + if (info->CurCloneMode) { + RADEONDoAdjustFrame(pScrn, info->CloneFrameX0, info->CloneFrameY0, TRUE); + } + + return TRUE; +} + +/* Called when VT switching away from the X server. Restore the + * original text mode. + */ +void RADEONLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONSavePtr save = &info->ModeReg; + + RADEONTRACE(("RADEONLeaveVT\n")); +#ifdef XF86DRI + if (RADEONPTR(pScrn)->directRenderingEnabled) { + DRILock(pScrn->pScreen, 0); + RADEONCP_STOP(pScrn, info); + } +#endif + + if (info->FBDev) { + RADEONSavePalette(pScrn, save); + info->PaletteSavedOnVT = TRUE; + + RADEONSaveFBDevRegisters(pScrn, &info->ModeReg); + + fbdevHWLeaveVT(scrnIndex,flags); + } + + RADEONRestore(pScrn); +} + +/* Called at the end of each server generation. Restore the original + * text mode, unmap video memory, and unwrap and call the saved + * CloseScreen function. + */ +static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + RADEONTRACE(("RADEONCloseScreen\n")); + +#ifdef XF86DRI + /* Disable direct rendering */ + if (info->directRenderingEnabled) { + RADEONDRICloseScreen(pScreen); + info->directRenderingEnabled = FALSE; + } +#endif + + if (pScrn->vtSema) { + RADEONRestore(pScrn); + } + RADEONUnmapMem(pScrn); + + if (info->accel) XAADestroyInfoRec(info->accel); + info->accel = NULL; + + if (info->scratch_save) xfree(info->scratch_save); + info->scratch_save = NULL; + + if (info->cursor) xf86DestroyCursorInfoRec(info->cursor); + info->cursor = NULL; + + if (info->DGAModes) xfree(info->DGAModes); + info->DGAModes = NULL; + + pScrn->vtSema = FALSE; + + xf86ClearPrimInitDone(info->pEnt->index); + + pScreen->BlockHandler = info->BlockHandler; + pScreen->CloseScreen = info->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + +void RADEONFreeScreen(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + RADEONTRACE(("RADEONFreeScreen\n")); + + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(pScrn); + RADEONFreeRec(pScrn); +} + +/* + * Powering done DAC, needed for DPMS problem with ViewSonic P817 (or its variant). + * + * Note for current DAC mapping when calling this function: + * For most of cards: + * single CRT: Driver doesn't change the existing CRTC->DAC mapping, + * CRTC1 could be driving either DAC or both DACs. + * CRT+CRT: CRTC1->TV DAC, CRTC2->Primary DAC + * DFP/LCD+CRT: CRTC2->TV DAC, CRTC2->Primary DAC. + * Some boards have two DACs reversed or don't even have a primary DAC, + * this is reflected in pRADEONEnt->ReversedDAC. And radeon 7200 doesn't + * have a second DAC. + * It's kind of messy, we'll need to redo DAC mapping part some day. + */ +static void RADEONDacPowerSet(ScrnInfoPtr pScrn, Bool IsOn, Bool IsPrimaryDAC) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (IsPrimaryDAC) { + CARD32 dac_cntl; + CARD32 dac_macro_cntl = 0; + dac_cntl = INREG(RADEON_DAC_CNTL); + if ((!info->IsMobility) || (info->ChipFamily == CHIP_FAMILY_RV350)) + dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL); + if (IsOn) { + dac_cntl &= ~RADEON_DAC_PDWN; + dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + } else { + dac_cntl |= RADEON_DAC_PDWN; + dac_macro_cntl |= (RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + } + OUTREG(RADEON_DAC_CNTL, dac_cntl); + if ((!info->IsMobility) || (info->ChipFamily == CHIP_FAMILY_RV350)) + OUTREG(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + } else { + if (info->ChipFamily != CHIP_FAMILY_R200) { + CARD32 tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + if (IsOn) { + tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } else { + tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } + OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl); + } else { + CARD32 fp2_gen_cntl = INREG(RADEON_FP2_GEN_CNTL); + if (IsOn) { + fp2_gen_cntl |= RADEON_FP2_DV0_EN; + } else { + fp2_gen_cntl &= ~RADEON_FP2_DV0_EN; + } + OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + } + } +} + +/* Sets VESA Display Power Management Signaling (DPMS) Mode */ +static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, + int flags) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + +#ifdef XF86DRI + if (info->CPStarted) DRILock(pScrn->pScreen, 0); +#endif + + if (info->accelOn) info->accel->Sync(pScrn); + + if (info->FBDev) { + fbdevHWDPMSSet(pScrn, PowerManagementMode, flags); + } else { + int mask1 = (RADEON_CRTC_DISPLAY_DIS | + RADEON_CRTC_HSYNC_DIS | + RADEON_CRTC_VSYNC_DIS); + int mask2 = (RADEON_CRTC2_DISP_DIS | + RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS); + + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + if (info->IsSecondary) + OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~mask2); + else { + if (info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~mask2); + OUTREGP(RADEON_CRTC_EXT_CNTL, 0, ~mask1); + } + break; + + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + if (info->IsSecondary) + OUTREGP(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS, + ~mask2); + else { + if (info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS, + ~mask2); + OUTREGP(RADEON_CRTC_EXT_CNTL, + RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS, + ~mask1); + } + break; + + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + if (info->IsSecondary) + OUTREGP(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS, + ~mask2); + else { + if (info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS, + ~mask2); + OUTREGP(RADEON_CRTC_EXT_CNTL, + RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS, + ~mask1); + } + break; + + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + if (info->IsSecondary) + OUTREGP(RADEON_CRTC2_GEN_CNTL, mask2, ~mask2); + else { + if (info->Clone) + OUTREGP(RADEON_CRTC2_GEN_CNTL, mask2, ~mask2); + OUTREGP(RADEON_CRTC_EXT_CNTL, mask1, ~mask1); + } + break; + } + + if (PowerManagementMode == DPMSModeOn) { + if (info->IsSecondary) { + if (info->DisplayType == MT_DFP) { + OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_BLANK_EN); + OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_ON, ~RADEON_FP2_ON); + if (info->ChipFamily >= CHIP_FAMILY_R200) { + OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_DV0_EN, ~RADEON_FP2_DV0_EN); + } + } else if (info->DisplayType == MT_CRT) { + RADEONDacPowerSet(pScrn, TRUE, !pRADEONEnt->ReversedDAC); + } + } else { + if (info->Clone) { + if (info->CloneType == MT_DFP) { + OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_BLANK_EN); + OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_ON, ~RADEON_FP2_ON); + if (info->ChipFamily >= CHIP_FAMILY_R200) { + OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_DV0_EN, ~RADEON_FP2_DV0_EN); + } + } else if (info->CloneType == MT_CRT) { + RADEONDacPowerSet(pScrn, TRUE, !pRADEONEnt->ReversedDAC); + } + } + if (info->DisplayType == MT_DFP) { + OUTREGP (RADEON_FP_GEN_CNTL, (RADEON_FP_FPON | RADEON_FP_TMDS_EN), + ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); + } else if (info->DisplayType == MT_LCD) { + + OUTREGP (RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON); + usleep (info->PanelPwrDly * 1000); + OUTREGP (RADEON_LVDS_GEN_CNTL, RADEON_LVDS_ON, ~RADEON_LVDS_ON); + } else if (info->DisplayType == MT_CRT) { + if ((pRADEONEnt->HasSecondary) || info->Clone) { + RADEONDacPowerSet(pScrn, TRUE, pRADEONEnt->ReversedDAC); + } else { + RADEONDacPowerSet(pScrn, TRUE, TRUE); + if (info->HasCRTC2) + RADEONDacPowerSet(pScrn, TRUE, FALSE); + } + } + } + } else if ((PowerManagementMode == DPMSModeOff) || + (PowerManagementMode == DPMSModeSuspend) || + (PowerManagementMode == DPMSModeStandby)) { + if (info->IsSecondary) { + if (info->DisplayType == MT_DFP) { + OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_BLANK_EN, ~RADEON_FP2_BLANK_EN); + OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_ON); + if (info->ChipFamily >= CHIP_FAMILY_R200) { + OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_DV0_EN); + } + } else if (info->DisplayType == MT_CRT) { + RADEONDacPowerSet(pScrn, FALSE, !pRADEONEnt->ReversedDAC); + } + } else { + if (info->Clone) { + if(info->CloneType == MT_DFP) { + OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_BLANK_EN, ~RADEON_FP2_BLANK_EN); + OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_ON); + if (info->ChipFamily >= CHIP_FAMILY_R200) { + OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_DV0_EN); + } + } else if (info->CloneType == MT_CRT) { + RADEONDacPowerSet(pScrn, FALSE, !pRADEONEnt->ReversedDAC); + } + } + if (info->DisplayType == MT_DFP) { + OUTREGP (RADEON_FP_GEN_CNTL, 0, ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); + } else if (info->DisplayType == MT_LCD) { + unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); + + if (info->IsMobility || info->IsIGP) { + /* Asic bug, when turning off LVDS_ON, we have to make sure + RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off + */ + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); + } + + OUTREGP (RADEON_LVDS_GEN_CNTL, 0, + ~(RADEON_LVDS_BLON | RADEON_LVDS_ON)); + + if (info->IsMobility || info->IsIGP) { + OUTPLL(RADEON_PIXCLKS_CNTL, tmpPixclksCntl); + } + } else if (info->DisplayType == MT_CRT) { + if ((pRADEONEnt->HasSecondary) || info->Clone) { + RADEONDacPowerSet(pScrn, FALSE, pRADEONEnt->ReversedDAC); + } else { + /* single CRT, turning both DACs off, we don't really know + * which DAC is actually connected. + */ + RADEONDacPowerSet(pScrn, FALSE, TRUE); + if (info->HasCRTC2) /* don't apply this to old radeon (singel CRTC) card */ + RADEONDacPowerSet(pScrn, FALSE, FALSE); + } + } + } + } + } + +#ifdef XF86DRI + if (info->CPStarted) DRIUnlock(pScrn->pScreen); +#endif +} diff --git a/src/radeon_macros.h b/src/radeon_macros.h new file mode 100644 index 0000000..b420a30 --- /dev/null +++ b/src/radeon_macros.h @@ -0,0 +1,134 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_macros.h,v 1.2 2003/07/08 15:39:48 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * !!!! FIXME !!!! + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + + +#ifndef _RADEON_MACROS_H_ +#define _RADEON_MACROS_H_ + +#ifdef XFree86Module +#include "xf86_ansic.h" +#endif +#include "compiler.h" + + /* Memory mapped register access macros */ +#define INREG8(addr) MMIO_IN8(RADEONMMIO, addr) +#define INREG16(addr) MMIO_IN16(RADEONMMIO, addr) +#define INREG(addr) MMIO_IN32(RADEONMMIO, addr) +#define OUTREG8(addr, val) MMIO_OUT8(RADEONMMIO, addr, val) +#define OUTREG16(addr, val) MMIO_OUT16(RADEONMMIO, addr, val) +#define OUTREG(addr, val) MMIO_OUT32(RADEONMMIO, addr, val) + +#define ADDRREG(addr) ((volatile CARD32 *)(pointer)(RADEONMMIO + (addr))) + + +#define OUTREGP(addr, val, mask) \ +do { \ + CARD32 tmp = INREG(addr); \ + tmp &= (mask); \ + tmp |= (val); \ + OUTREG(addr, tmp); \ +} while (0) + +#define INPLL(pScrn, addr) RADEONINPLL(pScrn, addr) + +#define OUTPLL(addr, val) \ +do { \ + OUTREG8(RADEON_CLOCK_CNTL_INDEX, (((addr) & 0x3f) | \ + RADEON_PLL_WR_EN)); \ + OUTREG(RADEON_CLOCK_CNTL_DATA, val); \ +} while (0) + +#define OUTPLLP(pScrn, addr, val, mask) \ +do { \ + CARD32 tmp_ = INPLL(pScrn, addr); \ + tmp_ &= (mask); \ + tmp_ |= (val); \ + OUTPLL(addr, tmp_); \ +} while (0) + +#define OUTPAL_START(idx) \ +do { \ + OUTREG8(RADEON_PALETTE_INDEX, (idx)); \ +} while (0) + +#define OUTPAL_NEXT(r, g, b) \ +do { \ + OUTREG(RADEON_PALETTE_DATA, ((r) << 16) | ((g) << 8) | (b)); \ +} while (0) + +#define OUTPAL_NEXT_CARD32(v) \ +do { \ + OUTREG(RADEON_PALETTE_DATA, (v & 0x00ffffff)); \ +} while (0) + +#define OUTPAL(idx, r, g, b) \ +do { \ + OUTPAL_START((idx)); \ + OUTPAL_NEXT((r), (g), (b)); \ +} while (0) + +#define INPAL_START(idx) \ +do { \ + OUTREG(RADEON_PALETTE_INDEX, (idx) << 16); \ +} while (0) + +#define INPAL_NEXT() INREG(RADEON_PALETTE_DATA) + +#define PAL_SELECT(idx) \ +do { \ + if (!idx) { \ + OUTREG(RADEON_DAC_CNTL2, INREG(RADEON_DAC_CNTL2) & \ + (CARD32)~RADEON_DAC2_PALETTE_ACC_CTL); \ + } else { \ + OUTREG(RADEON_DAC_CNTL2, INREG(RADEON_DAC_CNTL2) | \ + RADEON_DAC2_PALETTE_ACC_CTL); \ + } \ +} while (0) + + +#endif diff --git a/src/radeon_mergedfb.c b/src/radeon_mergedfb.c new file mode 100644 index 0000000..89bc19f --- /dev/null +++ b/src/radeon_mergedfb.c @@ -0,0 +1,1594 @@ +/* $XFree86$ */ +/* + * Copyright 2003 Alex Deucher. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ALEX DEUCHER, OR ANY OTHER + * CONTRIBUTORS 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. + */ + +/* + * Authors: + * Alex Deucher <agd5f@yahoo.com> + * Based, in large part, on the sis driver by Thomas Winischhofer. + */ + +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86Resources.h" +#include "xf86_OSproc.h" +#include "extnsionst.h" /* required */ +#include "panoramiXproto.h" /* required */ +#include "dixstruct.h" +#include "vbe.h" + + +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_reg.h" +#include "radeon_mergedfb.h" + +/* psuedo xinerama support */ +static unsigned char RADEONXineramaReqCode = 0; +int RADEONXineramaPixWidth = 0; +int RADEONXineramaPixHeight = 0; +int RADEONXineramaNumScreens = 0; +RADEONXineramaData *RADEONXineramadataPtr = NULL; +static int RADEONXineramaGeneration; +Bool RADEONnoPanoramiXExtension = TRUE; + +int RADEONProcXineramaQueryVersion(ClientPtr client); +int RADEONProcXineramaGetState(ClientPtr client); +int RADEONProcXineramaGetScreenCount(ClientPtr client); +int RADEONProcXineramaGetScreenSize(ClientPtr client); +int RADEONProcXineramaIsActive(ClientPtr client); +int RADEONProcXineramaQueryScreens(ClientPtr client); +int RADEONSProcXineramaDispatch(ClientPtr client); + +static void +RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y); + +/* mergedfb functions */ +/* Helper function for CRT2 monitor vrefresh/hsync options + * (Taken from mga, sis drivers) + */ +int +RADEONStrToRanges(range *r, char *s, int max) +{ + float num = 0.0; + int rangenum = 0; + Bool gotdash = FALSE; + Bool nextdash = FALSE; + char* strnum = NULL; + do { + switch(*s) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + if(strnum == NULL) { + strnum = s; + gotdash = nextdash; + nextdash = FALSE; + } + break; + case '-': + case ' ': + case 0: + if(strnum == NULL) break; + sscanf(strnum, "%f", &num); + strnum = NULL; + if(gotdash) + r[rangenum - 1].hi = num; + else { + r[rangenum].lo = num; + r[rangenum].hi = num; + rangenum++; + } + if(*s == '-') nextdash = (rangenum != 0); + else if(rangenum >= max) return rangenum; + break; + default : + return 0; + } + } while(*(s++) != 0); + + return rangenum; +} + +/* Copy and link two modes (i, j) for merged-fb mode + * (Taken from mga, sis drivers) + * Copys mode i, merges j to copy of i, links the result to dest, and returns it. + * Links i and j in Private record. + * If dest is NULL, return value is copy of i linked to itself. + * For mergedfb auto-config, we only check the dimension + * against virtualX/Y, if they were user-provided. + */ +static DisplayModePtr +RADEONCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + DisplayModePtr mode; + int dx = 0,dy = 0; + RADEONInfoPtr info = RADEONPTR(pScrn); + + if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest; + memcpy(mode, i, sizeof(DisplayModeRec)); + if(!((mode->Private = xalloc(sizeof(RADEONMergedDisplayModeRec))))) { + xfree(mode); + return dest; + } + ((RADEONMergedDisplayModePtr)mode->Private)->CRT1 = i; + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2 = j; + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2Position = srel; + mode->PrivSize = 0; + + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + if(!(pScrn->display->virtualX)) { + dx = i->HDisplay + j->HDisplay; + } else { + dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay); + } + dx -= mode->HDisplay; + if(!(pScrn->display->virtualY)) { + dy = max(i->VDisplay, j->VDisplay); + } else { + dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); + } + dy -= mode->VDisplay; + break; + case radeonAbove: + case radeonBelow: + if(!(pScrn->display->virtualY)) { + dy = i->VDisplay + j->VDisplay; + } else { + dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay); + } + dy -= mode->VDisplay; + if(!(pScrn->display->virtualX)) { + dx = max(i->HDisplay, j->HDisplay); + } else { + dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); + } + dx -= mode->HDisplay; + break; + case radeonClone: + if(!(pScrn->display->virtualX)) { + dx = max(i->HDisplay, j->HDisplay); + } else { + dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); + } + dx -= mode->HDisplay; + if(!(pScrn->display->virtualY)) { + dy = max(i->VDisplay, j->VDisplay); + } else { + dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); + } + dy -= mode->VDisplay; + break; + } + mode->HDisplay += dx; + mode->HSyncStart += dx; + mode->HSyncEnd += dx; + mode->HTotal += dx; + mode->VDisplay += dy; + mode->VSyncStart += dy; + mode->VSyncEnd += dy; + mode->VTotal += dy; + + /* Provide a sophisticated fake DotClock in order to trick the vidmode + * extension to allow selecting among a number of modes whose merged result + * looks identical but consists of different modes for CRT1 and CRT2 + */ + mode->Clock = (((i->Clock >> 3) + i->HTotal) << 16) | ((j->Clock >> 2) + j->HTotal); + mode->Clock ^= ((i->VTotal << 19) | (j->VTotal << 3)); + + if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > + (pScrn->videoRam * 1024)) || + (mode->HDisplay > 8191) || + (mode->VDisplay > 8191) ) { + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n", + mode->name, mode->HDisplay, mode->VDisplay); + xfree(mode->Private); + xfree(mode); + + return dest; + } + + if(srel != radeonClone) { + info->AtLeastOneNonClone = TRUE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d%s\n", + i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay, + mode->HDisplay, mode->VDisplay, (srel == radeonClone) ? " (Clone)" : ""); + + mode->next = mode; + mode->prev = mode; + + if(dest) { + mode->next = dest->next; /* Insert node after "dest" */ + dest->next->prev = mode; + mode->prev = dest; + dest->next = mode; + } + + return mode; +} + +/* Helper function to find a mode from a given name + * (Taken from mga, sis drivers) + */ +static DisplayModePtr +RADEONGetModeFromName(char* str, DisplayModePtr i) +{ + DisplayModePtr c = i; + if(!i) return NULL; + do { + if(strcmp(str, c->name) == 0) return c; + c = c->next; + } while(c != i); + return NULL; +} + +static DisplayModePtr +RADEONFindWidestTallestMode(DisplayModePtr i, Bool tallest) +{ + DisplayModePtr c = i, d = NULL; + int max = 0; + if(!i) return NULL; + do { + if(tallest) { + if(c->VDisplay > max) { + max = c->VDisplay; + d = c; + } + } else { + if(c->HDisplay > max) { + max = c->HDisplay; + d = c; + } + } + c = c->next; + } while(c != i); + return d; +} + +static DisplayModePtr +RADEONGenerateModeListFromLargestModes(ScrnInfoPtr pScrn, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + + RADEONInfoPtr info = RADEONPTR(pScrn); + DisplayModePtr mode1 = NULL; + DisplayModePtr mode2 = NULL; + DisplayModePtr result = NULL; + int p = 0; + int count = 0; + + info->AtLeastOneNonClone = FALSE; + + + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + mode1 = RADEONFindWidestTallestMode(i, FALSE); + mode2 = RADEONFindWidestTallestMode(j, FALSE); + break; + case radeonAbove: + case radeonBelow: + mode1 = RADEONFindWidestTallestMode(i, TRUE); + mode2 = RADEONFindWidestTallestMode(j, TRUE); + break; + case radeonClone: + mode1 = i; + mode2 = j; + while (pScrn->display->modes[count]) count++; + for (p = 0; p < count; p++) { + result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, srel); + mode1 = mode1->next; + mode2 = mode2->next; + } + } + + if(mode1 && mode2) { + if (srel == radeonClone) + return result; + else + return(RADEONCopyModeNLink(pScrn, result, mode1, mode2, srel)); + } else { + return NULL; + } +} + +/* Generate the merged-fb mode modelist + * (Taken from mga, sis drivers) + */ +static DisplayModePtr +RADEONGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + char* strmode = str; + char modename[256]; + Bool gotdash = FALSE, gotplus = FALSE; + RADEONScrn2Rel sr; + DisplayModePtr mode1 = NULL; + DisplayModePtr mode2 = NULL; + DisplayModePtr result = NULL; + int myslen; + RADEONInfoPtr info = RADEONPTR(pScrn); + + info->AtLeastOneNonClone = FALSE; + + do { + switch(*str) { + case 0: + case '-': + case '+': + case ' ': + if(strmode != str) { + + myslen = str - strmode; + if(myslen > 255) myslen = 255; + strncpy(modename, strmode, myslen); + modename[myslen] = 0; + + if(gotdash) { + if(mode1 == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Error parsing MetaModes parameter\n"); + return NULL; + } + mode2 = RADEONGetModeFromName(modename, j); + if(!mode2) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode \"%s\" is not a supported mode for CRT2\n", modename); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "\t(Skipping metamode \"%s%s%s\")\n", mode1->name, gotplus ? "+" : "-", modename); + mode1 = NULL; + gotplus = FALSE; + } + } else { + mode1 = RADEONGetModeFromName(modename, i); + if(!mode1) { + char* tmps = str; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode \"%s\" is not a supported mode for CRT1\n", modename); + while(*tmps == ' ') tmps++; + /* skip the next mode */ + if((*tmps == '-') || (*tmps == '+')) { + tmps++; + /* skip spaces */ + while(*tmps == ' ') tmps++; + /* skip modename */ + while((*tmps != ' ') && (*tmps != '-') && (*tmps != '+') && (*tmps != 0)) tmps++; + myslen = tmps - strmode; + if(myslen > 255) myslen = 255; + strncpy(modename,strmode,myslen); + modename[myslen] = 0; + str = tmps-1; + } + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "\t(Skipping metamode \"%s\")\n", modename); + mode1 = NULL; + gotplus = FALSE; + } + } + gotdash = FALSE; + } + strmode = str + 1; + gotdash |= ((*str == '-') || (*str == '+')); + gotplus |= (*str == '+'); + + if(*str != 0) break; + /* Fall through otherwise */ + + default: + if(!gotdash && mode1) { + sr = srel; + if(gotplus) sr = radeonClone; + if(!mode2) { + mode2 = RADEONGetModeFromName(mode1->name, j); + sr = radeonClone; + } + if(!mode2) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "\t(Skipping metamode \"%s\")\n", modename); + mode1 = NULL; + } else { + result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, sr); + mode1 = NULL; + mode2 = NULL; + } + gotplus = FALSE; + } + break; + + } + + } while(*(str++) != 0); + + return result; +} + +DisplayModePtr +RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + if(str != NULL) { + return(RADEONGenerateModeListFromMetaModes(pScrn, str, i, j, srel)); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No MetaModes given, linking %s modes by default\n", + (srel == radeonClone) ? "first" : "largest"); + return(RADEONGenerateModeListFromLargestModes(pScrn, i, j, srel)); + } +} + +void +RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn) +{ + DisplayModePtr mode, bmode; + int max; + static const char *str = "MergedFB: Virtual %s %d\n"; + + if(!(pScrn->display->virtualX)) { + mode = bmode = pScrn->modes; + max = 0; + do { + if(mode->HDisplay > max) max = mode->HDisplay; + mode = mode->next; + } while(mode != bmode); + pScrn->virtualX = max; + pScrn->displayWidth = max; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", max); + } + if(!(pScrn->display->virtualY)) { + mode = bmode = pScrn->modes; + max = 0; + do { + if(mode->VDisplay > max) max = mode->VDisplay; + mode = mode->next; + } while(mode != bmode); + pScrn->virtualY = max; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", max); + } +} + +/* Pseudo-Xinerama extension for MergedFB mode */ +void +RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1) +{ + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = NULL; + int crt1scrnnum = 0, crt2scrnnum = 1; + int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0; + DisplayModePtr currentMode, firstMode; + Bool infochanged = FALSE; + + if(!info->MergedFB) return; + + if(RADEONnoPanoramiXExtension) return; + + if(!RADEONXineramadataPtr) return; + + if(info->CRT2IsScrn0) { + crt1scrnnum = 1; + crt2scrnnum = 0; + } + + pScrn2 = info->CRT2pScrn; + + /* Attention: Usage of RandR may lead into virtual X and Y values + * actually smaller than our MetaModes! To avoid this, we calculate + * the maxCRT fields here (and not somewhere else, like in CopyNLink) + */ + + if((info->RADEONXineramaVX != pScrn1->virtualX) || (info->RADEONXineramaVY != pScrn1->virtualY)) { + + if(!(pScrn1->modes)) { + xf86DrvMsg(pScrn1->scrnIndex, X_ERROR, + "Internal error: RADEONUpdateXineramaScreenInfo(): pScrn->modes is NULL\n"); + return; + } + + info->maxCRT1_X1 = info->maxCRT1_X2 = 0; + info->maxCRT1_Y1 = info->maxCRT1_Y2 = 0; + info->maxCRT2_X1 = info->maxCRT2_X2 = 0; + info->maxCRT2_Y1 = info->maxCRT2_Y2 = 0; + info->maxClone_X1 = info->maxClone_X2 = 0; + info->maxClone_Y1 = info->maxClone_Y2 = 0; + + currentMode = firstMode = pScrn1->modes; + + do { + + DisplayModePtr p = currentMode->next; + DisplayModePtr i = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT1; + DisplayModePtr j = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2; + RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2Position; + + if((i->HDisplay <= pScrn1->virtualX) && (j->HDisplay <= pScrn1->virtualX) && + (i->VDisplay <= pScrn1->virtualY) && (j->VDisplay <= pScrn1->virtualY)) { + + if(srel != radeonClone) { + if(info->maxCRT1_X1 <= i->HDisplay) { + info->maxCRT1_X1 = i->HDisplay; /* Largest CRT1 mode */ + if(info->maxCRT1_X2 < j->HDisplay) { + info->maxCRT1_X2 = j->HDisplay; /* Largest X of CRT2 mode displayed with largest CRT1 mode */ + } + } + if(info->maxCRT2_X2 <= j->HDisplay) { + info->maxCRT2_X2 = j->HDisplay; /* Largest CRT2 mode */ + if(info->maxCRT2_X1 < i->HDisplay) { + info->maxCRT2_X1 = i->HDisplay; /* Largest X of CRT1 mode displayed with largest CRT2 mode */ + } + } + if(info->maxCRT1_Y1 <= i->VDisplay) { + info->maxCRT1_Y1 = i->VDisplay; + if(info->maxCRT1_Y2 < j->VDisplay) { + info->maxCRT1_Y2 = j->VDisplay; + } + } + if(info->maxCRT2_Y2 <= j->VDisplay) { + info->maxCRT2_Y2 = j->VDisplay; + if(info->maxCRT2_Y1 < i->VDisplay) { + info->maxCRT2_Y1 = i->VDisplay; + } + } + } else { + if(info->maxClone_X1 < i->HDisplay) { + info->maxClone_X1 = i->HDisplay; + } + if(info->maxClone_X2 < j->HDisplay) { + info->maxClone_X2 = j->HDisplay; + } + if(info->maxClone_Y1 < i->VDisplay) { + info->maxClone_Y1 = i->VDisplay; + } + if(info->maxClone_Y2 < j->VDisplay) { + info->maxClone_Y2 = j->VDisplay; + } + } + } + currentMode = p; + + } while((currentMode) && (currentMode != firstMode)); + + info->RADEONXineramaVX = pScrn1->virtualX; + info->RADEONXineramaVY = pScrn1->virtualY; + infochanged = TRUE; + + } + + /* leftof + + V 1: + CRT2: x = 0 + y = 0 + w = (maxCRT2 X) + h = (virtual Y) + CRT1: x = (virtual X) - (maxCRT1 X) + y = 0 + w = (maxCRT1 X) + h = (virtual Y) + + V 2: + CRT2: x = 0 + y = 0 + w = max CRT2 mode X + h = virtual Y size + CRT1: x = (max) CRT2 mode X von dem Metamode, wo CRT1 mode maximal breit ist + y = 0 + w = max CRT1 mode X + h = virtual Y size + + V 3: (current) + CRT1: x = (maxCRT2 X von dem MMode, wo maxCRT1 X) + y = 0 + w = (virtual X) - x + h = (virtual Y) + CRT2: x = 0 + y = 0 + w = (virtual X) - (maxCRT1 X von dem MMode, wo maxCRT2 X) + h = (virtual Y) + + */ + switch(info->CRT2Position) { + case radeonLeftOf: /* V 1 */ + x1 = min(info->maxCRT1_X2, pScrn1->virtualX - info->maxCRT1_X1); /* pScrn1->virtualX - pSiS->maxCRT1_X1; +*/ + if(x1 < 0) x1 = 0; + y1 = 0; /* 0; */ + w1 = pScrn1->virtualX - x1; /* pSiS->maxCRT1_X1; */ + h1 = pScrn1->virtualY; /* pScrn1->virtualY; */ + x2 = 0; /* 0; */ + y2 = 0; /* 0; */ + w2 = max(info->maxCRT2_X2, pScrn1->virtualX - info->maxCRT2_X1); /* pSiS->maxCRT2_X2; */ + if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX; + h2 = pScrn1->virtualY; /* pScrn1->virtualY; */ + break; + case radeonRightOf: + x1 = 0; /* 0; */ + y1 = 0; /* 0; */ + w1 = max(info->maxCRT1_X1, pScrn1->virtualX - info->maxCRT1_X2); /* pSiS->maxCRT1_X1; */ + if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX; + h1 = pScrn1->virtualY; /* pScrn1->virtualY; */ + x2 = min(info->maxCRT2_X1, pScrn1->virtualX - info->maxCRT2_X2); /* pScrn1->virtualX - pSiS->maxCRT2_X2; +*/ + if(x2 < 0) x2 = 0; + y2 = 0; /* 0; */ + w2 = pScrn1->virtualX - x2; /* pSiS->maxCRT2_X2; */ + h2 = pScrn1->virtualY; /* pScrn1->virtualY; */ + break; + case radeonAbove: + x1 = 0; /* 0; */ + y1 = min(info->maxCRT1_Y2, pScrn1->virtualY - info->maxCRT1_Y1); /* pScrn1->virtualY - pSiS->maxCRT1_Y1; +*/ + if(y1 < 0) y1 = 0; + w1 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h1 = pScrn1->virtualY - y1; /* pSiS->maxCRT1_Y1; */ + x2 = 0; /* 0; */ + y2 = 0; /* 0; */ + w2 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h2 = max(info->maxCRT2_Y2, pScrn1->virtualY - info->maxCRT2_Y1); /* pSiS->maxCRT2_Y2; */ + if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY; + break; + case radeonBelow: + x1 = 0; /* 0; */ + y1 = 0; /* 0; */ + w1 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h1 = max(info->maxCRT1_Y1, pScrn1->virtualY - info->maxCRT1_Y2); /* pSiS->maxCRT1_Y1; */ + if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY; + x2 = 0; /* 0; */ + y2 = min(info->maxCRT2_Y1, pScrn1->virtualY - info->maxCRT2_Y2); /* pScrn1->virtualY - pSiS->maxCRT2_Y2; +*/ + if(y2 < 0) y2 = 0; + w2 = pScrn1->virtualX; /* pScrn1->virtualX; */ + h2 = pScrn1->virtualY - y2; /* pSiS->maxCRT2_Y2; */ + break; + default: + xf86DrvMsg(pScrn1->scrnIndex, X_ERROR, + "Internal error: UpdateXineramaInfo(): unsupported CRT2Position (%d)\n", + info->CRT2Position); + } + RADEONXineramadataPtr[crt1scrnnum].x = x1; + RADEONXineramadataPtr[crt1scrnnum].y = y1; + RADEONXineramadataPtr[crt1scrnnum].width = w1; + RADEONXineramadataPtr[crt1scrnnum].height = h1; + RADEONXineramadataPtr[crt2scrnnum].x = x2; + RADEONXineramadataPtr[crt2scrnnum].y = y2; + RADEONXineramadataPtr[crt2scrnnum].width = w2; + RADEONXineramadataPtr[crt2scrnnum].height = h2; + + if(infochanged) { + xf86DrvMsg(pScrn1->scrnIndex, X_INFO, + "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n", + crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1); + xf86DrvMsg(pScrn1->scrnIndex, X_INFO, + "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n", + crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1); + } + +} + +/* Proc */ + +int +RADEONProcXineramaQueryVersion(ClientPtr client) +{ + xPanoramiXQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = RADEON_XINERAMA_MAJOR_VERSION; + rep.minorVersion = RADEON_XINERAMA_MINOR_VERSION; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep); + return (client->noClientException); +} + +int +RADEONProcXineramaGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + WindowPtr pWin; + xPanoramiXGetStateReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + pWin = LookupWindow(stuff->window, client); + if(!pWin) return BadWindow; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !RADEONnoPanoramiXExtension; + if(client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.state, n); + } + WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep); + return client->noClientException; +} + +int +RADEONProcXineramaGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + WindowPtr pWin; + xPanoramiXGetScreenCountReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + pWin = LookupWindow(stuff->window, client); + if(!pWin) return BadWindow; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.ScreenCount = RADEONXineramaNumScreens; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.ScreenCount, n); + } + WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); + return client->noClientException; +} + +int +RADEONProcXineramaGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + WindowPtr pWin; + xPanoramiXGetScreenSizeReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + pWin = LookupWindow (stuff->window, client); + if(!pWin) return BadWindow; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.width = RADEONXineramadataPtr[stuff->screen].width; + rep.height = RADEONXineramadataPtr[stuff->screen].height; + if(client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.width, n); + swaps(&rep.height, n); + } + WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); + return client->noClientException; +} + +int +RADEONProcXineramaIsActive(ClientPtr client) +{ + xXineramaIsActiveReply rep; + + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !RADEONnoPanoramiXExtension; + if(client->swapped) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.state, n); + } + WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep); + return client->noClientException; +} + +int +RADEONProcXineramaQueryScreens(ClientPtr client) +{ + xXineramaQueryScreensReply rep; + + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.number = (RADEONnoPanoramiXExtension) ? 0 : RADEONXineramaNumScreens; + rep.length = rep.number * sz_XineramaScreenInfo >> 2; + if(client->swapped) { + register int n; + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.number, n); + } + WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep); + + if(!RADEONnoPanoramiXExtension) { + xXineramaScreenInfo scratch; + int i; + + for(i = 0; i < RADEONXineramaNumScreens; i++) { + scratch.x_org = RADEONXineramadataPtr[i].x; + scratch.y_org = RADEONXineramadataPtr[i].y; + scratch.width = RADEONXineramadataPtr[i].width; + scratch.height = RADEONXineramadataPtr[i].height; + if(client->swapped) { + register int n; + swaps(&scratch.x_org, n); + swaps(&scratch.y_org, n); + swaps(&scratch.width, n); + swaps(&scratch.height, n); + } + WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch); + } + } + + return client->noClientException; +} + +static int +RADEONProcXineramaDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_PanoramiXQueryVersion: + return RADEONProcXineramaQueryVersion(client); + case X_PanoramiXGetState: + return RADEONProcXineramaGetState(client); + case X_PanoramiXGetScreenCount: + return RADEONProcXineramaGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return RADEONProcXineramaGetScreenSize(client); + case X_XineramaIsActive: + return RADEONProcXineramaIsActive(client); + case X_XineramaQueryScreens: + return RADEONProcXineramaQueryScreens(client); + } + return BadRequest; +} + +/* SProc */ + +static int +RADEONSProcXineramaQueryVersion (ClientPtr client) +{ + REQUEST(xPanoramiXQueryVersionReq); + register int n; + swaps(&stuff->length,n); + REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); + return RADEONProcXineramaQueryVersion(client); +} + +static int +RADEONSProcXineramaGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + return RADEONProcXineramaGetState(client); +} + +static int +RADEONSProcXineramaGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + return RADEONProcXineramaGetScreenCount(client); +} + +static int +RADEONSProcXineramaGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + return RADEONProcXineramaGetScreenSize(client); +} + +static int +RADEONSProcXineramaIsActive(ClientPtr client) +{ + REQUEST(xXineramaIsActiveReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + return RADEONProcXineramaIsActive(client); +} + +static int +RADEONSProcXineramaQueryScreens(ClientPtr client) +{ + REQUEST(xXineramaQueryScreensReq); + register int n; + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + return RADEONProcXineramaQueryScreens(client); +} + +int +RADEONSProcXineramaDispatch(ClientPtr client) +{ + REQUEST(xReq); + switch (stuff->data) { + case X_PanoramiXQueryVersion: + return RADEONSProcXineramaQueryVersion(client); + case X_PanoramiXGetState: + return RADEONSProcXineramaGetState(client); + case X_PanoramiXGetScreenCount: + return RADEONSProcXineramaGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return RADEONSProcXineramaGetScreenSize(client); + case X_XineramaIsActive: + return RADEONSProcXineramaIsActive(client); + case X_XineramaQueryScreens: + return RADEONSProcXineramaQueryScreens(client); + } + return BadRequest; +} + +static void +RADEONXineramaResetProc(ExtensionEntry* extEntry) +{ + if(RADEONXineramadataPtr) { + Xfree(RADEONXineramadataPtr); + RADEONXineramadataPtr = NULL; + } +} + +void +RADEONXineramaExtensionInit(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + Bool success = FALSE; + + if(!(RADEONXineramadataPtr)) { + + if(!info->MergedFB) { + RADEONnoPanoramiXExtension = TRUE; + return; + } + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Xinerama active, not initializing Radeon Pseudo-Xinerama\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } +#endif + + if(RADEONnoPanoramiXExtension) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Radeon Pseudo-Xinerama disabled\n"); + return; + } + + if(info->CRT2Position == radeonClone) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Running MergedFB in Clone mode, Radeon Pseudo-Xinerama disabled\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } + + if(!(info->AtLeastOneNonClone)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Only Clone modes defined, Radeon Pseudo-Xinerama disabled\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } + + RADEONXineramaNumScreens = 2; + + while(RADEONXineramaGeneration != serverGeneration) { + + info->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, + RADEONProcXineramaDispatch, + RADEONSProcXineramaDispatch, + RADEONXineramaResetProc, + StandardMinorOpcode); + + if(!info->XineramaExtEntry) break; + + RADEONXineramaReqCode = (unsigned char)info->XineramaExtEntry->base; + + if(!(RADEONXineramadataPtr = (RADEONXineramaData *) + xcalloc(RADEONXineramaNumScreens, sizeof(RADEONXineramaData)))) break; + + RADEONXineramaGeneration = serverGeneration; + success = TRUE; + } + + if(!success) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize Radeon Pseudo-Xinerama extension\n"); + RADEONnoPanoramiXExtension = TRUE; + return; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Initialized Radeon Pseudo-Xinerama extension\n"); + + info->RADEONXineramaVX = 0; + info->RADEONXineramaVY = 0; + + } + + RADEONUpdateXineramaScreenInfo(pScrn); + +} +/* End of PseudoXinerama */ + +static Bool +InRegion(int x, int y, region r) +{ + return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1); +} + +void +RADEONMergePointerMoved(int scrnIndex, int x, int y) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + region out, in1, in2, f2, f1; + int deltax, deltay; + + f1.x0 = info->CRT1frameX0; + f1.x1 = info->CRT1frameX1; + f1.y0 = info->CRT1frameY0; + f1.y1 = info->CRT1frameY1; + f2.x0 = pScrn2->frameX0; + f2.x1 = pScrn2->frameX1; + f2.y0 = pScrn2->frameY0; + f2.y1 = pScrn2->frameY1; + + /* Define the outer region. Crossing this causes all frames to move */ + out.x0 = pScrn1->frameX0; + out.x1 = pScrn1->frameX1; + out.y0 = pScrn1->frameY0; + out.y1 = pScrn1->frameY1; + + /* + * Define the inner sliding window. Being outsize both frames but + * inside the outer clipping window will slide corresponding frame + */ + in1 = out; + in2 = out; + switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { + case radeonLeftOf: + in1.x0 = f1.x0; + in2.x1 = f2.x1; + break; + case radeonRightOf: + in1.x1 = f1.x1; + in2.x0 = f2.x0; + break; + case radeonBelow: + in1.y1 = f1.y1; + in2.y0 = f2.y0; + break; + case radeonAbove: + in1.y0 = f1.y0; + in2.y1 = f2.y1; + break; + case radeonClone: + break; + } + + deltay = 0; + deltax = 0; + + if(InRegion(x, y, out)) { /* inside outer region */ + + /* xf86DrvMsg(0, X_INFO, "1: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ + + if(InRegion(x, y, in1) && !InRegion(x, y, f1)) { + REBOUND(f1.x0, f1.x1, x); + REBOUND(f1.y0, f1.y1, y); + deltax = 1; + /* xf86DrvMsg(0, X_INFO, "2: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ + } + if(InRegion(x, y, in2) && !InRegion(x, y, f2)) { + REBOUND(f2.x0, f2.x1, x); + REBOUND(f2.y0, f2.y1, y); + deltax = 1; + } + + } else { /* outside outer region */ + + /* xf86DrvMsg(0, X_INFO, "3: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); + xf86DrvMsg(0, X_INFO, "3-out: %d %d %d %d\n", + out.x0, out.x1, out.y0, out.y1); */ + + if(out.x0 > x) { + deltax = x - out.x0; + } + if(out.x1 < x) { + deltax = x - out.x1; + } + if(deltax) { + pScrn1->frameX0 += deltax; + pScrn1->frameX1 += deltax; + f1.x0 += deltax; + f1.x1 += deltax; + f2.x0 += deltax; + f2.x1 += deltax; + } + + if(out.y0 > y) { + deltay = y - out.y0; + } + if(out.y1 < y) { + deltay = y - out.y1; + } + if(deltay) { + pScrn1->frameY0 += deltay; + pScrn1->frameY1 += deltay; + f1.y0 += deltay; + f1.y1 += deltay; + f2.y0 += deltay; + f2.y1 += deltay; + } + + switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { + case radeonLeftOf: + if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); } + if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); } + break; + case radeonRightOf: + if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); } + if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); } + break; + case radeonBelow: + if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); } + if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); } + break; + case radeonAbove: + if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); } + if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); } + break; + case radeonClone: + break; + } + + } + + if(deltax || deltay) { + info->CRT1frameX0 = f1.x0; + info->CRT1frameY0 = f1.y0; + pScrn2->frameX0 = f2.x0; + pScrn2->frameY0 = f2.y0; + + info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; + info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; + pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; + pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; + pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; + pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; + + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); + } +} + +static void +RADEONAdjustFrameMergedHelper(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + int VTotal = info->CurrentLayout.mode->VDisplay; + int HTotal = info->CurrentLayout.mode->HDisplay; + int VMax = VTotal; + int HMax = HTotal; + + BOUND(x, 0, pScrn1->virtualX - HTotal); + BOUND(y, 0, pScrn1->virtualY - VTotal); + + switch(SDMPTR(pScrn1)->CRT2Position) { + case radeonLeftOf: + pScrn2->frameX0 = x; + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + info->CRT1frameX0 = x + CDMPTR->CRT2->HDisplay; + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + break; + case radeonRightOf: + info->CRT1frameX0 = x; + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + pScrn2->frameX0 = x + CDMPTR->CRT1->HDisplay; + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + break; + case radeonAbove: + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + pScrn2->frameY0 = y; + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + info->CRT1frameY0 = y + CDMPTR->CRT2->VDisplay; + break; + case radeonBelow: + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + info->CRT1frameY0 = y; + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + pScrn2->frameY0 = y + CDMPTR->CRT1->VDisplay; + break; + case radeonClone: + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + break; + } + + BOUND(info->CRT1frameX0, 0, pScrn1->virtualX - CDMPTR->CRT1->HDisplay); + BOUND(info->CRT1frameY0, 0, pScrn1->virtualY - CDMPTR->CRT1->VDisplay); + BOUND(pScrn2->frameX0, 0, pScrn1->virtualX - CDMPTR->CRT2->HDisplay); + BOUND(pScrn2->frameY0, 0, pScrn1->virtualY - CDMPTR->CRT2->VDisplay); + + pScrn1->frameX0 = x; + pScrn1->frameY0 = y; + + info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; + info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; + pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; + pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; + pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; + pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; +/* + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); +*/ +} + +void +RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + + RADEONAdjustFrameMergedHelper(scrnIndex, x, y, flags); + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); +} + +void +RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel) +{ + RADEONInfoPtr info = RADEONPTR(pScrn1); + MessageType from = X_DEFAULT; + xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC); + xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC); + int ddcWidthmm = 0, ddcHeightmm = 0; + const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n"; + + /* This sets the DPI for MergedFB mode. The problem is that + * this can never be exact, because the output devices may + * have different dimensions. This function tries to compromise + * through a few assumptions, and it just calculates an average DPI + * value for both monitors. + */ + + /* Given DisplaySize should regard BOTH monitors */ + pScrn1->widthmm = pScrn1->monitor->widthmm; + pScrn1->heightmm = pScrn1->monitor->heightmm; + + /* Get DDC display size; if only either CRT1 or CRT2 provided these, + * assume equal dimensions for both, otherwise add dimensions + */ + if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) && + (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) { + ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10; + ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10; + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10; + break; + case radeonAbove: + case radeonBelow: + ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10; + default: + break; + } + + } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) { + ddcWidthmm = DDC1->features.hsize * 10; + ddcHeightmm = DDC1->features.vsize * 10; + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + ddcWidthmm *= 2; + break; + case radeonAbove: + case radeonBelow: + ddcHeightmm *= 2; + default: + break; + } + } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) { + ddcWidthmm = DDC2->features.hsize * 10; + ddcHeightmm = DDC2->features.vsize * 10; + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + ddcWidthmm *= 2; + break; + case radeonAbove: + case radeonBelow: + ddcHeightmm *= 2; + default: + break; + } + } + + if(monitorResolution > 0) { + + /* Set command line given values (overrules given options) */ + pScrn1->xDpi = monitorResolution; + pScrn1->yDpi = monitorResolution; + from = X_CMDLINE; + + } else if(info->MergedFBXDPI) { + + /* Set option-wise given values (overrule DisplaySize) */ + pScrn1->xDpi = info->MergedFBXDPI; + pScrn1->yDpi = info->MergedFBYDPI; + from = X_CONFIG; + + } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) { + + /* Set values calculated from given DisplaySize */ + from = X_CONFIG; + if(pScrn1->widthmm > 0) { + pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); + } + if(pScrn1->heightmm > 0) { + pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); + } + xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm); + + } else if(ddcWidthmm && ddcHeightmm) { + + /* Set values from DDC-provided display size */ + from = X_PROBED; + xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm ); + pScrn1->widthmm = ddcWidthmm; + pScrn1->heightmm = ddcHeightmm; + if(pScrn1->widthmm > 0) { + pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); + } + if(pScrn1->heightmm > 0) { + pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); + } + + } else { + + pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI; + + } + + /* Sanity check */ + if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0) + pScrn1->yDpi = pScrn1->xDpi; + if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0) + pScrn1->xDpi = pScrn1->yDpi; + + pScrn2->xDpi = pScrn1->xDpi; + pScrn2->yDpi = pScrn1->yDpi; + + xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n", + pScrn1->xDpi, pScrn1->yDpi); +} + +/* radeon cursor helpers */ +static void +RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y) +{ + RADEONInfoPtr info = RADEONPTR(pScrn1); + unsigned char *RADEONMMIO = info->MMIO; + RADEONScrn2Rel srel = + ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + + /* + Note: we need WaitForIdle here because OUTREGP() involves an INREG() to obtain a previous + value. This fix is needed for RV350 + 3d driver (or we get a lockup otherwise). + + It is also indicated by documentation (we should not be doing INREG if CP engine is active) + */ + RADEONWaitForIdleMMIO(pScrn1); + + if (srel == radeonClone) { + /* show cursor 2 */ + OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, + ~RADEON_CRTC2_CUR_EN); + /* show cursor 1 */ + OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, + ~RADEON_CRTC_CUR_EN); + } + else { + if (((x >= pScrn1->frameX0) && (x <= pScrn1->frameX1)) && + ((y >= pScrn1->frameY0) && (y <= pScrn1->frameY1))) { + /* hide cursor 2 */ + OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); + /* show cursor 1 */ + OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, + ~RADEON_CRTC_CUR_EN); + } + if (((x >= pScrn2->frameX0) && (x <= pScrn2->frameX1)) && + ((y >= pScrn2->frameY0) && (y <= pScrn2->frameY1))) { + /* hide cursor 1 */ + OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN); + /* show cursor 2 */ + OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, + ~RADEON_CRTC2_CUR_EN); + } + } +} + +void +RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + xf86CursorInfoPtr cursor = info->cursor; + int xorigin = 0; + int yorigin = 0; + int stride = 256; + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + DisplayModePtr mode1 = CDMPTR->CRT1; + DisplayModePtr mode2 = CDMPTR->CRT2; + int x1, y1, x2, y2; + int total_y1 = pScrn->frameY1 - pScrn->frameY0; + int total_y2 = pScrn2->frameY1 - pScrn2->frameY0; + + if (x < 0) xorigin = -x+1; + if (y < 0) yorigin = -y+1; + /* if (y > total_y) y = total_y; */ + if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; + if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; + + x += pScrn->frameX0; + y += pScrn->frameY0; + + x1 = x - info->CRT1frameX0; + y1 = y - info->CRT1frameY0; + + x2 = x - pScrn2->frameX0; + y2 = y - pScrn2->frameY0; + + if (y1 > total_y1) + y1 = total_y1; + if (y2 > total_y2) + y2 = total_y2; + + if(mode1->Flags & V_INTERLACE) + y1 /= 2; + else if(mode1->Flags & V_DBLSCAN) + y1 *= 2; + + if(mode2->Flags & V_INTERLACE) + y2 /= 2; + else if(mode2->Flags & V_DBLSCAN) + y2 *= 2; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + RADEONChooseCursorCRTC(pScrn, x, y); + + /* cursor1 */ + OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK + | ((xorigin ? 0 : x1) << 16) + | (yorigin ? 0 : y1))); + OUTREG(RADEON_CUR_OFFSET, info->cursor_start + yorigin * stride); + /* cursor2 */ + OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK + | ((xorigin ? 0 : x2) << 16) + | (yorigin ? 0 : y2))); + OUTREG(RADEON_CUR2_OFFSET, + info->cursor_start + yorigin * stride); + +} + +/* radeon Xv helpers */ + +/* choose the crtc for the overlay for mergedfb based on the location + of the output window and the orientation of the crtcs */ + +void +RADEONChooseOverlayCRTC( + ScrnInfoPtr pScrn, + BoxPtr dstBox +) { + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONScrn2Rel srel = + ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; + + if (srel == radeonLeftOf) { + if (dstBox->x1 >= info->CRT2pScrn->frameX1) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } + if (srel == radeonRightOf) { + if (dstBox->x2 <= info->CRT2pScrn->frameX0) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } + if (srel == radeonAbove) { + if (dstBox->y1 >= info->CRT2pScrn->frameY1) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } + if (srel == radeonBelow) { + if (dstBox->y2 <= info->CRT2pScrn->frameY0) + info->OverlayOnCRTC2 = FALSE; + else + info->OverlayOnCRTC2 = TRUE; + } +} diff --git a/src/radeon_mergedfb.h b/src/radeon_mergedfb.h new file mode 100644 index 0000000..e51ce5c --- /dev/null +++ b/src/radeon_mergedfb.h @@ -0,0 +1,124 @@ +/* $XFree86$ */ +/* + * Copyright 2003 Alex Deucher. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ALEX DEUCHER, OR ANY OTHER + * CONTRIBUTORS 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. + */ + +/* + * Authors: + * Alex Deucher <agd5f@yahoo.com> + * + */ + +#ifndef _RADEON_MERGEDFB_H_ +#define _RADEON_MERGEDFB_H_ + +#include "xf86.h" + +#include "radeon.h" + +#if 0 + /* Psuedo Xinerama support */ +#define NEED_REPLIES /* ? */ +#define EXTENSION_PROC_ARGS void * +#include "extnsionst.h" /* required */ +#include "panoramiXproto.h" /* required */ +#define RADEON_XINERAMA_MAJOR_VERSION 1 +#define RADEON_XINERAMA_MINOR_VERSION 1 + +/* needed for pseudo-xinerama by radeon_driver.c */ +Bool RADEONnoPanoramiXExtension = TRUE; + +/* Relative merge position */ +typedef enum { + radeonLeftOf, + radeonRightOf, + radeonAbove, + radeonBelow, + radeonClone +} RADEONScrn2Rel; +#endif + +#define SDMPTR(x) ((RADEONMergedDisplayModePtr)(x->currentMode->Private)) +#define CDMPTR ((RADEONMergedDisplayModePtr)(info->CurrentLayout.mode->Private)) + +#define BOUND(test,low,hi) { \ + if(test < low) test = low; \ + if(test > hi) test = hi; } + +#define REBOUND(low,hi,test) { \ + if(test < low) { \ + hi += test-low; \ + low = test; } \ + if(test > hi) { \ + low += test-hi; \ + hi = test; } } + +typedef struct _MergedDisplayModeRec { + DisplayModePtr CRT1; + DisplayModePtr CRT2; + RADEONScrn2Rel CRT2Position; +} RADEONMergedDisplayModeRec, *RADEONMergedDisplayModePtr; + +typedef struct _region { + int x0,x1,y0,y1; +} region; + +typedef struct _RADEONXineramaData { + int x; + int y; + int width; + int height; +} RADEONXineramaData; + +/* needed by radeon_driver.c */ +extern void +RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags); +extern void +RADEONMergePointerMoved(int scrnIndex, int x, int y); +extern DisplayModePtr +RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel); +extern int +RADEONStrToRanges(range *r, char *s, int max); +extern void +RADEONXineramaExtensionInit(ScrnInfoPtr pScrn); +extern void +RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1); +extern void +RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel); +extern void +RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn); + +/* needed by radeon_cursor.c */ +extern void +RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y); + +/* needed by radeon_video.c */ +extern void +RADEONChooseOverlayCRTC(ScrnInfoPtr, BoxPtr); + +#endif /* _RADEON_MERGEDFB_H_ */ diff --git a/src/radeon_misc.c b/src/radeon_misc.c new file mode 100644 index 0000000..6d6b17d --- /dev/null +++ b/src/radeon_misc.c @@ -0,0 +1,86 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_misc.c,v 1.7 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifdef XFree86LOADER + +#include "ativersion.h" + +#include "radeon_probe.h" +#include "radeon_version.h" + +#include "xf86.h" + +/* Module loader interface for subsidiary driver module */ + +static XF86ModuleVersionInfo RADEONVersionRec = +{ + RADEON_DRIVER_NAME, + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XF86_VERSION_CURRENT, + RADEON_VERSION_MAJOR, RADEON_VERSION_MINOR, RADEON_VERSION_PATCH, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0, 0, 0, 0} +}; + +/* + * RADEONSetup -- + * + * This function is called every time the module is loaded. + */ +static pointer +RADEONSetup +( + pointer Module, + pointer Options, + int *ErrorMajor, + int *ErrorMinor +) +{ + static Bool Inited = FALSE; + + if (!Inited) { + /* Ensure main driver module is loaded, but not as a submodule */ + if (!xf86ServerIsOnlyDetecting() && !LoaderSymbol(ATI_NAME)) + xf86LoadOneModule(ATI_DRIVER_NAME, Options); + + RADEONLoaderRefSymLists(); + + Inited = TRUE; + } + + return (pointer)TRUE; +} + +/* The following record must be called radeonModuleData */ +XF86ModuleData radeonModuleData = +{ + &RADEONVersionRec, + RADEONSetup, + NULL +}; + +#endif /* XFree86LOADER */ diff --git a/src/radeon_mm_i2c.c b/src/radeon_mm_i2c.c new file mode 100644 index 0000000..f6a3688 --- /dev/null +++ b/src/radeon_mm_i2c.c @@ -0,0 +1,597 @@ +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_reg.h" +#include "Xv.h" +#include "radeon_video.h" + +#include "xf86.h" +#include "xf86PciInfo.h" + +/* i2c stuff */ +#include "xf86i2c.h" +#include "fi1236.h" +#include "msp3430.h" +#include "tda9885.h" +#include "i2c_def.h" + + +#define I2C_DONE (1<<0) +#define I2C_NACK (1<<1) +#define I2C_HALT (1<<2) +#define I2C_SOFT_RST (1<<5) +#define I2C_DRIVE_EN (1<<6) +#define I2C_DRIVE_SEL (1<<7) +#define I2C_START (1<<8) +#define I2C_STOP (1<<9) +#define I2C_RECEIVE (1<<10) +#define I2C_ABORT (1<<11) +#define I2C_GO (1<<12) +#define I2C_SEL (1<<16) +#define I2C_EN (1<<17) + +static void RADEON_TDA9885_Init(RADEONPortPrivPtr pPriv); + + +/**************************************************************************** + * I2C_WaitForAck (void) * + * * + * Function: polls the I2C status bits, waiting for an acknowledge or * + * an error condition. * + * Inputs: NONE * + * Outputs: I2C_DONE - the I2C transfer was completed * + * I2C_NACK - an NACK was received from the slave * + * I2C_HALT - a timeout condition has occured * + ****************************************************************************/ +static CARD8 RADEON_I2C_WaitForAck (ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) +{ + CARD8 retval = 0; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + long counter = 0; + + usleep(1000); + while(1) + { + RADEONWaitForIdleMMIO(pScrn); + retval = INREG8(RADEON_I2C_CNTL_0); + if (retval & I2C_HALT) + { + return (I2C_HALT); + } + if (retval & I2C_NACK) + { + return (I2C_NACK); + } + if(retval & I2C_DONE) + { + return I2C_DONE; + } + counter++; + if(counter>1000000) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Timeout condition on Radeon i2c bus\n"); + return I2C_HALT; + } + + } +} + +static void RADEON_I2C_Halt (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD8 reg; + long counter = 0; + + /* reset status flags */ + RADEONWaitForIdleMMIO(pScrn); + reg = INREG8 (RADEON_I2C_CNTL_0 + 0) & ~(I2C_DONE|I2C_NACK|I2C_HALT); + OUTREG8 (RADEON_I2C_CNTL_0 + 0, reg); + + /* issue ABORT call */ + RADEONWaitForIdleMMIO(pScrn); + reg = INREG8 (RADEON_I2C_CNTL_0 + 1) & 0xE7; + OUTREG8 (RADEON_I2C_CNTL_0 + 1, (reg |((I2C_GO|I2C_ABORT) >> 8))); + + /* wait for GO bit to go low */ + RADEONWaitForIdleMMIO(pScrn); + while (INREG8 (RADEON_I2C_CNTL_0 + 1) & (I2C_GO>>8)) + { + counter++; + if(counter>1000000)return; + } +} + + +static Bool RADEONI2CWriteRead(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + int loop, status; + CARD32 i2c_cntl_0, i2c_cntl_1; + RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)(d->pI2CBus->DriverPrivate.ptr); + ScrnInfoPtr pScrn = xf86Screens[d->pI2CBus->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + status=I2C_DONE; + + RADEONWaitForIdleMMIO(pScrn); + if(nWrite>0){ +/* RADEONWaitForFifo(pScrn, 4+nWrite); */ + + /* Clear the status bits of the I2C Controller */ + OUTREG(RADEON_I2C_CNTL_0, I2C_DONE | I2C_NACK | I2C_HALT | I2C_SOFT_RST); + + /* Write the address into the buffer first */ + OUTREG(RADEON_I2C_DATA, (CARD32) (d->SlaveAddr) & ~(1)); + + /* Write Value into the buffer */ + for (loop = 0; loop < nWrite; loop++) + { + OUTREG8(RADEON_I2C_DATA, WriteBuffer[loop]); + } + + i2c_cntl_1 = (pPriv->radeon_i2c_timing << 24) | I2C_EN | I2C_SEL | + nWrite | 0x100; + OUTREG(RADEON_I2C_CNTL_1, i2c_cntl_1); + + i2c_cntl_0 = (pPriv->radeon_N << 24) | (pPriv->radeon_M << 16) | + I2C_GO | I2C_START | ((nRead >0)?0:I2C_STOP) | I2C_DRIVE_EN; + OUTREG(RADEON_I2C_CNTL_0, i2c_cntl_0); + + while(INREG8(RADEON_I2C_CNTL_0+1) & (I2C_GO >> 8)); + + status=RADEON_I2C_WaitForAck(pScrn,pPriv); + + if(status!=I2C_DONE){ + RADEON_I2C_Halt(pScrn); + return FALSE; + } + } + + + if(nRead > 0) { + RADEONWaitForFifo(pScrn, 4+nRead); + + OUTREG(RADEON_I2C_CNTL_0, I2C_DONE | I2C_NACK | I2C_HALT | I2C_SOFT_RST); + + /* Write the address into the buffer first */ + OUTREG(RADEON_I2C_DATA, (CARD32) (d->SlaveAddr) | (1)); + + i2c_cntl_1 = (pPriv->radeon_i2c_timing << 24) | I2C_EN | I2C_SEL | + nRead | 0x100; + OUTREG(RADEON_I2C_CNTL_1, i2c_cntl_1); + + i2c_cntl_0 = (pPriv->radeon_N << 24) | (pPriv->radeon_M << 16) | + I2C_GO | I2C_START | I2C_STOP | I2C_DRIVE_EN | I2C_RECEIVE; + OUTREG(RADEON_I2C_CNTL_0, i2c_cntl_0); + + RADEONWaitForIdleMMIO(pScrn); + while(INREG8(RADEON_I2C_CNTL_0+1) & (I2C_GO >> 8)); + + status=RADEON_I2C_WaitForAck(pScrn,pPriv); + + /* Write Value into the buffer */ + for (loop = 0; loop < nRead; loop++) + { + RADEONWaitForFifo(pScrn, 1); + if((status == I2C_HALT) || (status == I2C_NACK)) + { + ReadBuffer[loop]=0xff; + } else { + RADEONWaitForIdleMMIO(pScrn); + ReadBuffer[loop]=INREG8(RADEON_I2C_DATA) & 0xff; + } + } + } + + if(status!=I2C_DONE){ + RADEON_I2C_Halt(pScrn); + return FALSE; + } + return TRUE; +} + +static Bool R200_I2CWriteRead(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + int loop, status; + CARD32 i2c_cntl_0, i2c_cntl_1; + RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)(d->pI2CBus->DriverPrivate.ptr); + ScrnInfoPtr pScrn = xf86Screens[d->pI2CBus->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + status=I2C_DONE; + + RADEONWaitForIdleMMIO(pScrn); + if(nWrite>0){ +/* RADEONWaitForFifo(pScrn, 4+nWrite); */ + + /* Clear the status bits of the I2C Controller */ + OUTREG(RADEON_I2C_CNTL_0, I2C_DONE | I2C_NACK | I2C_HALT | I2C_SOFT_RST); + + /* Write the address into the buffer first */ + OUTREG(RADEON_I2C_DATA, (CARD32) (d->SlaveAddr) & ~(1)); + + /* Write Value into the buffer */ + for (loop = 0; loop < nWrite; loop++) + { + OUTREG8(RADEON_I2C_DATA, WriteBuffer[loop]); + } + + i2c_cntl_1 = (pPriv->radeon_i2c_timing << 24) | I2C_EN | I2C_SEL | + nWrite | 0x010; + OUTREG(RADEON_I2C_CNTL_1, i2c_cntl_1); + + i2c_cntl_0 = (pPriv->radeon_N << 24) | (pPriv->radeon_M << 16) | + I2C_GO | I2C_START | ((nRead >0)?0:I2C_STOP) | I2C_DRIVE_EN; + OUTREG(RADEON_I2C_CNTL_0, i2c_cntl_0); + + write_mem_barrier(); + + while(INREG8(RADEON_I2C_CNTL_0+1) & (I2C_GO >> 8)); + + status=RADEON_I2C_WaitForAck(pScrn,pPriv); + + if(status!=I2C_DONE){ + RADEON_I2C_Halt(pScrn); + return FALSE; + } + } + + + if(nRead > 0) { + RADEONWaitForFifo(pScrn, 4+nRead); + + OUTREG(RADEON_I2C_CNTL_0, I2C_DONE | I2C_NACK | I2C_HALT | I2C_SOFT_RST); + + /* Write the address into the buffer first */ + OUTREG(RADEON_I2C_DATA, (CARD32) (d->SlaveAddr) | (1)); + + i2c_cntl_1 = (pPriv->radeon_i2c_timing << 24) | I2C_EN | I2C_SEL | + nRead | 0x010; + OUTREG(RADEON_I2C_CNTL_1, i2c_cntl_1); + + i2c_cntl_0 = (pPriv->radeon_N << 24) | (pPriv->radeon_M << 16) | + I2C_GO | I2C_START | I2C_STOP | I2C_DRIVE_EN | I2C_RECEIVE; + OUTREG(RADEON_I2C_CNTL_0, i2c_cntl_0); + + write_mem_barrier(); + while(INREG8(RADEON_I2C_CNTL_0+1) & (I2C_GO >> 8)); + + status=RADEON_I2C_WaitForAck(pScrn,pPriv); + + RADEONWaitForIdleMMIO(pScrn); + /* Write Value into the buffer */ + for (loop = 0; loop < nRead; loop++) + { + if((status == I2C_HALT) || (status == I2C_NACK)) + { + ReadBuffer[loop]=0xff; + } else { + ReadBuffer[loop]=INREG8(RADEON_I2C_DATA) & 0xff; + } + } + } + + if(status!=I2C_DONE){ + RADEON_I2C_Halt(pScrn); + return FALSE; + } + return TRUE; +} + +static Bool RADEONProbeAddress(I2CBusPtr b, I2CSlaveAddr addr) +{ + I2CByte a; + I2CDevRec d; + + d.DevName = "Probing"; + d.SlaveAddr = addr; + d.pI2CBus = b; + d.NextDev = NULL; + + return I2C_WriteRead(&d, NULL, 0, &a, 1); +} + +#define I2C_CLOCK_FREQ (60000.0) + + +const struct +{ + char *name; + int type; +} RADEON_tuners[32] = + { + /* name ,index to tuner_parms table */ + {"NO TUNNER" , -1}, + {"Philips FI1236 (or compatible)" , TUNER_TYPE_FI1236}, + {"Philips FI1236 (or compatible)" , TUNER_TYPE_FI1236}, + {"Philips FI1216 (or compatible)" , TUNER_TYPE_FI1216}, + {"Philips FI1246 (or compatible)" , TUNER_TYPE_FI1246}, + {"Philips FI1216MF (or compatible)" , TUNER_TYPE_FI1216}, + {"Philips FI1236 (or compatible)" , TUNER_TYPE_FI1236}, + {"Philips FI1256 (or compatible)" , TUNER_TYPE_FI1256}, + {"Philips FI1236 (or compatible)" , TUNER_TYPE_FI1236}, + {"Philips FI1216 (or compatible)" , TUNER_TYPE_FI1216}, + {"Philips FI1246 (or compatible)" , TUNER_TYPE_FI1246}, + {"Philips FI1216MF (or compatible)" , TUNER_TYPE_FI1216}, + {"Philips FI1236 (or compatible)" , TUNER_TYPE_FI1236}, + {"TEMIC-FN5AL" , TUNER_TYPE_TEMIC_FN5AL}, + {"FQ1216ME/P" , TUNER_TYPE_FI1216}, + {"FI1236W" , TUNER_TYPE_FI1236W}, + {"Alps TSBH5" , -1}, + {"Alps TSCxx" , -1}, + {"Alps TSCH5 FM" , -1}, + {"UNKNOWN-19" , -1}, + {"UNKNOWN-20" , -1}, + {"UNKNOWN-21" , -1}, + {"UNKNOWN-22" , -1}, + {"UNKNOWN-23" , -1}, + {"UNKNOWN-24" , -1}, + {"UNKNOWN-25" , -1}, + {"UNKNOWN-26" , -1}, + {"UNKNOWN-27" , -1}, + {"UNKNOWN-28" , -1}, + {"Microtuner MT2032" , TUNER_TYPE_MT2032}, + {"Microtuner MT2032" , TUNER_TYPE_MT2032}, + {"UNKNOWN-31" , -1} + }; + + +void RADEONResetI2C(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + RADEONWaitForFifo(pScrn, 2); + OUTREG8(RADEON_I2C_CNTL_1+2, ((I2C_SEL | I2C_EN)>>16)); + OUTREG8(RADEON_I2C_CNTL_0+0, (I2C_DONE | I2C_NACK | I2C_HALT | I2C_SOFT_RST | I2C_DRIVE_EN | I2C_DRIVE_SEL)); +} + +void RADEONInitI2C(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) +{ + double nm; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPLLPtr pll = &(info->pll); + int i; + unsigned char *RADEONMMIO = info->MMIO; + + pPriv->i2c = NULL; + pPriv->fi1236 = NULL; + pPriv->msp3430 = NULL; + pPriv->tda9885 = NULL; + #if 0 /* put back on when saa7114 support is present */ + pPriv->saa7114 = NULL; + #endif + + /* Blacklist chipsets that lockup - these are usually older mobility chips */ + + switch(info->Chipset){ + case PCI_CHIP_RADEON_LY: + case PCI_CHIP_RADEON_LZ: + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Detected Radeon Mobility M6, disabling multimedia i2c\n"); + return; + case PCI_CHIP_RADEON_LW: + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Detected Radeon Mobility M7, disabling multimedia i2c\n"); + return; + #ifndef PCI_CHIP_RADEON_If + #define PCI_CHIP_RADEON_If 0x496e + #endif + case PCI_CHIP_RADEON_If: + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Detected Radeon 9000 - skipping multimedia i2c initialization code.\n"); + return; + } + + /* no multimedia capabilities detected and no information was provided to substitute for it */ + if(!info->MM_TABLE_valid && + !(info->tunerType>=0)) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No video input capabilities detected and no information is provided - disabling multimedia i2c\n"); + return; + } + + + if(pPriv->i2c!=NULL) return; /* for some reason we are asked to init it again.. Stop ! */ + + if(!xf86LoadSubModule(pScrn,"i2c")) + { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Unable to initialize i2c bus\n"); + pPriv->i2c = NULL; + return; + } + xf86LoaderReqSymbols("xf86CreateI2CBusRec", + "xf86I2CBusInit", + "xf86DestroyI2CBus", + "xf86CreateI2CDevRec", + "xf86DestroyI2CDevRec", + "xf86I2CDevInit", + "xf86I2CWriteRead", + NULL); + pPriv->i2c=CreateI2CBusRec(); + pPriv->i2c->scrnIndex=pScrn->scrnIndex; + pPriv->i2c->BusName="Radeon multimedia bus"; + pPriv->i2c->DriverPrivate.ptr=(pointer)pPriv; + switch(info->ChipFamily){ + case CHIP_FAMILY_R300: + case CHIP_FAMILY_R200: + case CHIP_FAMILY_RV200: + pPriv->i2c->I2CWriteRead=R200_I2CWriteRead; + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Using R200 i2c bus access method\n"); + break; + default: + pPriv->i2c->I2CWriteRead=RADEONI2CWriteRead; + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Using Radeon bus access method\n"); + } + if(!I2CBusInit(pPriv->i2c)) + { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Failed to register i2c bus\n"); + } + +#if 1 + switch(info->ChipFamily){ + case CHIP_FAMILY_RV200: + nm=(pll->reference_freq * 40000.0)/(1.0*I2C_CLOCK_FREQ); + break; + case CHIP_FAMILY_R300: + case CHIP_FAMILY_R200: + if(info->MM_TABLE_valid && (RADEON_tuners[info->MM_TABLE.tuner_type & 0x1f].type==TUNER_TYPE_MT2032)){ + nm=(pll->reference_freq * 40000.0)/(4.0*I2C_CLOCK_FREQ); + break; + } + default: + nm=(pll->reference_freq * 10000.0)/(4.0*I2C_CLOCK_FREQ); + } +#else + nm=(pll->xclk * 40000.0)/(1.0*I2C_CLOCK_FREQ); +#endif + for(pPriv->radeon_N=1; pPriv->radeon_N<255; pPriv->radeon_N++) + if((pPriv->radeon_N * (pPriv->radeon_N-1)) > nm)break; + pPriv->radeon_M=pPriv->radeon_N-1; + pPriv->radeon_i2c_timing=2*pPriv->radeon_N; + + +#if 0 + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ref=%d M=0x%02x N=0x%02x timing=0x%02x\n", pll->reference_freq, pPriv->radeon_M, pPriv->radeon_N, pPriv->radeon_i2c_timing); + pPriv->radeon_M=0x32; + pPriv->radeon_N=0x33; + pPriv->radeon_i2c_timing=2*pPriv->radeon_N; +#endif + RADEONResetI2C(pScrn, pPriv); + +#if 0 /* I don't know whether standalone boards are supported with Radeons */ + /* looks like none of them have AMC connectors anyway */ + if(!info->MM_TABLE_valid)RADEON_read_eeprom(pPriv); +#endif + + if(!xf86LoadSubModule(pScrn,"fi1236")) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to initialize fi1236 driver\n"); + } + else + { + xf86LoaderReqSymbols(FI1236SymbolsList, NULL); + if(pPriv->fi1236 == NULL) + { + pPriv->fi1236 = xf86_Detect_FI1236(pPriv->i2c, FI1236_ADDR_1); + } + if(pPriv->fi1236 == NULL) + { + pPriv->fi1236 = xf86_Detect_FI1236(pPriv->i2c, FI1236_ADDR_2); + } + } + if(pPriv->fi1236 != NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected %s device at 0x%02x\n", + RADEON_tuners[info->MM_TABLE.tuner_type & 0x1f].name, + FI1236_ADDR(pPriv->fi1236)); + if(info->MM_TABLE_valid)xf86_FI1236_set_tuner_type(pPriv->fi1236, RADEON_tuners[info->MM_TABLE.tuner_type & 0x1f].type); + else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MM_TABLE not found (standalone board ?), forcing tuner type to NTSC\n"); + xf86_FI1236_set_tuner_type(pPriv->fi1236, TUNER_TYPE_FI1236); + } + } + + if(info->MM_TABLE_valid && (RADEON_tuners[info->MM_TABLE.tuner_type & 0x1f].type==TUNER_TYPE_MT2032)){ + if(!xf86LoadSubModule(pScrn,"tda9885")) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to initialize tda9885 driver\n"); + } + else + { + xf86LoaderReqSymbols(TDA9885SymbolsList, NULL); + if(pPriv->tda9885 == NULL) + { + pPriv->tda9885 = xf86_Detect_tda9885(pPriv->i2c, TDA9885_ADDR_1); + } + if(pPriv->tda9885 == NULL) + { + pPriv->tda9885 = xf86_Detect_tda9885(pPriv->i2c, TDA9885_ADDR_2); + } + if(pPriv->tda9885 != NULL) + { + RADEON_TDA9885_Init(pPriv); + } + } + } + + if(!xf86LoadSubModule(pScrn,"msp3430")) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to initialize msp3430 driver\n"); + } + else + { + xf86LoaderReqSymbols(MSP3430SymbolsList, NULL); + if(pPriv->msp3430 == NULL) + { + pPriv->msp3430 = xf86_DetectMSP3430(pPriv->i2c, MSP3430_ADDR_1); + } + if(pPriv->msp3430 == NULL) + { + pPriv->msp3430 = xf86_DetectMSP3430(pPriv->i2c, MSP3430_ADDR_2); + } +#if 0 /* this would confuse bt829 with msp3430 */ + if(pPriv->msp3430 == NULL) + { + pPriv->msp3430 = xf86_DetectMSP3430(pPriv->i2c, MSP3430_ADDR_3); + } +#endif + } + if(pPriv->msp3430 != NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected MSP3430 at 0x%02x\n", + MSP3430_ADDR(pPriv->msp3430)); + pPriv->msp3430->standard = MSP3430_NTSC; + pPriv->msp3430->connector = MSP3430_CONNECTOR_1; + xf86_ResetMSP3430(pPriv->msp3430); + xf86_InitMSP3430(pPriv->msp3430); + xf86_MSP3430SetVolume(pPriv->msp3430, pPriv->mute ? MSP3430_FAST_MUTE : MSP3430_VOLUME(pPriv->volume)); + } + +#if 0 /* put this back when saa7114 driver is ready */ + if(!xf86LoadSubModule(pScrn,"saa7114")) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to initialize saa7114 driver\n"); + } + else + { + xf86LoaderReqSymbols(SAA7114SymbolsList, NULL); + if(pPriv->saa7114 == NULL) + { + pPriv->saa7114 = xf86_DetectSAA7114(pPriv->i2c, SAA7114_ADDR_1); + } + if(pPriv->saa7114 == NULL) + { + pPriv->saa7114 = xf86_DetectSAA7114(pPriv->i2c, SAA7114_ADDR_2); + } + } + if(pPriv->saa7114 != NULL) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected SAA7114 at 0x%02x\n", + pPriv->saa7114->d.SlaveAddr); + xf86_InitSAA7114(pPriv->saa7114); + } +#endif + +} + +static void RADEON_TDA9885_Init(RADEONPortPrivPtr pPriv) +{ +TDA9885Ptr t=pPriv->tda9885; +t->sound_trap=0; +t->auto_mute_fm=1; /* ? */ +t->carrier_mode=0; /* ??? */ +t->modulation=2; /* negative FM */ +t->forced_mute_audio=0; +t->port1=1; +t->port2=1; +t->top_adjustment=0x10; +t->deemphasis=1; +t->audio_gain=0; +t->minimum_gain=0; +t->gating=0; +t->vif_agc=1; /* set to 1 ? - depends on design */ +t->gating=0; +} diff --git a/src/radeon_probe.c b/src/radeon_probe.c new file mode 100644 index 0000000..a8edceb --- /dev/null +++ b/src/radeon_probe.c @@ -0,0 +1,380 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_probe.c,v 1.30 2003/10/07 22:47:12 martin Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * + * Modified by Marc Aurele La France <tsi@xfree86.org> for ATI driver merge. + */ + +#include "atimodule.h" +#include "ativersion.h" + +#include "radeon_probe.h" +#include "radeon_version.h" + +#include "xf86PciInfo.h" + +#include "xf86.h" +#include "xf86_ansic.h" +#define _XF86MISC_SERVER_ +#include "xf86misc.h" +#include "xf86Resources.h" + +#ifdef XFree86LOADER + +/* + * The following exists to prevent the compiler from considering entry points + * defined in a separate module from being constants. + */ +static xf86PreInitProc *const volatile PreInitProc = RADEONPreInit; +static xf86ScreenInitProc *const volatile ScreenInitProc = RADEONScreenInit; +static xf86SwitchModeProc *const volatile SwitchModeProc = RADEONSwitchMode; +static xf86AdjustFrameProc *const volatile AdjustFrameProc = RADEONAdjustFrame; +static xf86EnterVTProc *const volatile EnterVTProc = RADEONEnterVT; +static xf86LeaveVTProc *const volatile LeaveVTProc = RADEONLeaveVT; +static xf86FreeScreenProc *const volatile FreeScreenProc = RADEONFreeScreen; +static xf86ValidModeProc *const volatile ValidModeProc = RADEONValidMode; +#ifdef X_XF86MiscPassMessage +static xf86HandleMessageProc *const volatile HandleMessageProc + = RADEONHandleMessage; +#endif + +#define RADEONPreInit PreInitProc +#define RADEONScreenInit ScreenInitProc +#define RADEONSwitchMode SwitchModeProc +#define RADEONAdjustFrame AdjustFrameProc +#define RADEONEnterVT EnterVTProc +#define RADEONLeaveVT LeaveVTProc +#define RADEONFreeScreen FreeScreenProc +#define RADEONValidMode ValidModeProc +#ifdef X_XF86MiscPassMessage +# define RADEONHandleMessage HandleMessageProc +#endif + +#endif + +SymTabRec RADEONChipsets[] = { + { PCI_CHIP_RADEON_QD, "ATI Radeon QD (AGP)" }, + { PCI_CHIP_RADEON_QE, "ATI Radeon QE (AGP)" }, + { PCI_CHIP_RADEON_QF, "ATI Radeon QF (AGP)" }, + { PCI_CHIP_RADEON_QG, "ATI Radeon QG (AGP)" }, + { PCI_CHIP_RV100_QY, "ATI Radeon VE/7000 QY (AGP/PCI)" }, + { PCI_CHIP_RV100_QZ, "ATI Radeon VE/7000 QZ (AGP/PCI)" }, + { PCI_CHIP_RADEON_LW, "ATI Radeon Mobility M7 LW (AGP)" }, + { PCI_CHIP_RADEON_LX, "ATI Mobility FireGL 7800 M7 LX (AGP)" }, + { PCI_CHIP_RADEON_LY, "ATI Radeon Mobility M6 LY (AGP)" }, + { PCI_CHIP_RADEON_LZ, "ATI Radeon Mobility M6 LZ (AGP)" }, + { PCI_CHIP_RS100_4136, "ATI Radeon IGP320 (A3) 4136" }, + { PCI_CHIP_RS100_4336, "ATI Radeon IGP320M (U1) 4336" }, + { PCI_CHIP_RS200_4137, "ATI Radeon IGP330/340/350 (A4) 4137" }, + { PCI_CHIP_RS200_4337, "ATI Radeon IGP330M/340M/350M (U2) 4337" }, + { PCI_CHIP_RS250_4237, "ATI Radeon 7000 IGP (A4+) 4237" }, + { PCI_CHIP_RS250_4437, "ATI Radeon Mobility 7000 IGP 4437" }, + { PCI_CHIP_R200_QH, "ATI FireGL 8700/8800 QH (AGP)" }, + { PCI_CHIP_R200_QL, "ATI Radeon 8500 QL (AGP)" }, + { PCI_CHIP_R200_QM, "ATI Radeon 9100 QM (AGP)" }, + { PCI_CHIP_R200_BB, "ATI Radeon 8500 AIW BB (AGP)" }, + { PCI_CHIP_R200_BC, "ATI Radeon 8500 AIW BC (AGP)" }, + { PCI_CHIP_RV200_QW, "ATI Radeon 7500 QW (AGP/PCI)" }, + { PCI_CHIP_RV200_QX, "ATI Radeon 7500 QX (AGP/PCI)" }, + { PCI_CHIP_RV250_If, "ATI Radeon 9000/PRO If (AGP/PCI)" }, + { PCI_CHIP_RV250_Ig, "ATI Radeon 9000 Ig (AGP/PCI)" }, + { PCI_CHIP_RV250_Ld, "ATI FireGL Mobility 9000 (M9) Ld (AGP)" }, + { PCI_CHIP_RV250_Lf, "ATI Radeon Mobility 9000 (M9) Lf (AGP)" }, + { PCI_CHIP_RV250_Lg, "ATI Radeon Mobility 9000 (M9) Lg (AGP)" }, + { PCI_CHIP_RS300_5834, "ATI Radeon 9100 IGP (A5) 5834" }, + { PCI_CHIP_RS300_5835, "ATI Radeon Mobility 9100 IGP (U3) 5835" }, + { PCI_CHIP_RV280_5960, "ATI Radeon 9200PRO 5960 (AGP)" }, + { PCI_CHIP_RV280_5961, "ATI Radeon 9200 5961 (AGP)" }, + { PCI_CHIP_RV280_5962, "ATI Radeon 9200 5962 (AGP)" }, + { PCI_CHIP_RV280_5964, "ATI Radeon 9200SE 5964 (AGP)" }, + { PCI_CHIP_RV280_5C61, "ATI Radeon Mobility 9200 (M9+) 5C61 (AGP)" }, + { PCI_CHIP_RV280_5C63, "ATI Radeon Mobility 9200 (M9+) 5C63 (AGP)" }, + { PCI_CHIP_R300_AD, "ATI Radeon 9500 AD (AGP)" }, + { PCI_CHIP_R300_AE, "ATI Radeon 9500 AE (AGP)" }, + { PCI_CHIP_R300_AF, "ATI Radeon 9600TX AF (AGP)" }, + { PCI_CHIP_R300_AG, "ATI FireGL Z1 AG (AGP)" }, + { PCI_CHIP_R300_ND, "ATI Radeon 9700 Pro ND (AGP)" }, + { PCI_CHIP_R300_NE, "ATI Radeon 9700/9500Pro NE (AGP)" }, + { PCI_CHIP_R300_NF, "ATI Radeon 9700 NF (AGP)" }, + { PCI_CHIP_R300_NG, "ATI FireGL X1 NG (AGP)" }, + { PCI_CHIP_RV350_AP, "ATI Radeon 9600 AP (AGP)" }, + { PCI_CHIP_RV350_AQ, "ATI Radeon 9600SE AQ (AGP)" }, + { PCI_CHIP_RV360_AR, "ATI Radeon 9600XT AR (AGP)" }, + { PCI_CHIP_RV350_AS, "ATI Radeon 9600 AS (AGP)" }, + { PCI_CHIP_RV350_AT, "ATI FireGL T2 AT (AGP)" }, + { PCI_CHIP_RV350_AV, "ATI FireGL RV360 AV (AGP)" }, + { PCI_CHIP_RV350_NP, "ATI Radeon Mobility 9600 (M10) NP (AGP)" }, + { PCI_CHIP_RV350_NQ, "ATI Radeon Mobility 9600 (M10) NQ (AGP)" }, + { PCI_CHIP_RV350_NR, "ATI Radeon Mobility 9600 (M11) NR (AGP)" }, + { PCI_CHIP_RV350_NS, "ATI Radeon Mobility 9600 (M10) NS (AGP)" }, + { PCI_CHIP_RV350_NT, "ATI FireGL Mobility T2 (M10) NT (AGP)" }, + { PCI_CHIP_RV350_NV, "ATI FireGL Mobility T2 (M11) NV (AGP)" }, + { PCI_CHIP_R350_AH, "ATI Radeon 9800SE AH (AGP)" }, + { PCI_CHIP_R350_AI, "ATI Radeon 9800 AI (AGP)" }, + { PCI_CHIP_R350_AJ, "ATI Radeon 9800 AJ (AGP)" }, + { PCI_CHIP_R350_AK, "ATI FireGL X2 AK (AGP)" }, + { PCI_CHIP_R350_NH, "ATI Radeon 9800PRO NH (AGP)" }, + { PCI_CHIP_R350_NI, "ATI Radeon 9800 NI (AGP)" }, + { PCI_CHIP_R350_NK, "ATI FireGL X2 NK (AGP)" }, + { PCI_CHIP_R360_NJ, "ATI Radeon 9800XT NJ (AGP)" }, + { -1, NULL } +}; + +PciChipsets RADEONPciChipsets[] = { + { PCI_CHIP_RADEON_QD, PCI_CHIP_RADEON_QD, RES_SHARED_VGA }, + { PCI_CHIP_RADEON_QE, PCI_CHIP_RADEON_QE, RES_SHARED_VGA }, + { PCI_CHIP_RADEON_QF, PCI_CHIP_RADEON_QF, RES_SHARED_VGA }, + { PCI_CHIP_RADEON_QG, PCI_CHIP_RADEON_QG, RES_SHARED_VGA }, + { PCI_CHIP_RV100_QY, PCI_CHIP_RV100_QY, RES_SHARED_VGA }, + { PCI_CHIP_RV100_QZ, PCI_CHIP_RV100_QZ, RES_SHARED_VGA }, + { PCI_CHIP_RADEON_LW, PCI_CHIP_RADEON_LW, RES_SHARED_VGA }, + { PCI_CHIP_RADEON_LX, PCI_CHIP_RADEON_LX, RES_SHARED_VGA }, + { PCI_CHIP_RADEON_LY, PCI_CHIP_RADEON_LY, RES_SHARED_VGA }, + { PCI_CHIP_RADEON_LZ, PCI_CHIP_RADEON_LZ, RES_SHARED_VGA }, + { PCI_CHIP_RS100_4136, PCI_CHIP_RS100_4136, RES_SHARED_VGA }, + { PCI_CHIP_RS100_4336, PCI_CHIP_RS100_4336, RES_SHARED_VGA }, + { PCI_CHIP_RS200_4137, PCI_CHIP_RS200_4137, RES_SHARED_VGA }, + { PCI_CHIP_RS200_4337, PCI_CHIP_RS200_4337, RES_SHARED_VGA }, + { PCI_CHIP_RS250_4237, PCI_CHIP_RS250_4237, RES_SHARED_VGA }, + { PCI_CHIP_RS250_4437, PCI_CHIP_RS250_4437, RES_SHARED_VGA }, + { PCI_CHIP_R200_QH, PCI_CHIP_R200_QH, RES_SHARED_VGA }, + { PCI_CHIP_R200_QL, PCI_CHIP_R200_QL, RES_SHARED_VGA }, + { PCI_CHIP_R200_QM, PCI_CHIP_R200_QM, RES_SHARED_VGA }, + { PCI_CHIP_R200_BB, PCI_CHIP_R200_BB, RES_SHARED_VGA }, + { PCI_CHIP_R200_BC, PCI_CHIP_R200_BC, RES_SHARED_VGA }, + { PCI_CHIP_RV200_QW, PCI_CHIP_RV200_QW, RES_SHARED_VGA }, + { PCI_CHIP_RV200_QX, PCI_CHIP_RV200_QX, RES_SHARED_VGA }, + { PCI_CHIP_RV250_If, PCI_CHIP_RV250_If, RES_SHARED_VGA }, + { PCI_CHIP_RV250_Ig, PCI_CHIP_RV250_Ig, RES_SHARED_VGA }, + { PCI_CHIP_RV250_Ld, PCI_CHIP_RV250_Ld, RES_SHARED_VGA }, + { PCI_CHIP_RV250_Lf, PCI_CHIP_RV250_Lf, RES_SHARED_VGA }, + { PCI_CHIP_RV250_Lg, PCI_CHIP_RV250_Lg, RES_SHARED_VGA }, + { PCI_CHIP_RS300_5834, PCI_CHIP_RS300_5834, RES_SHARED_VGA }, + { PCI_CHIP_RS300_5835, PCI_CHIP_RS300_5835, RES_SHARED_VGA }, + { PCI_CHIP_RV280_5960, PCI_CHIP_RV280_5960, RES_SHARED_VGA }, + { PCI_CHIP_RV280_5961, PCI_CHIP_RV280_5961, RES_SHARED_VGA }, + { PCI_CHIP_RV280_5962, PCI_CHIP_RV280_5962, RES_SHARED_VGA }, + { PCI_CHIP_RV280_5964, PCI_CHIP_RV280_5964, RES_SHARED_VGA }, + { PCI_CHIP_RV280_5C61, PCI_CHIP_RV280_5C61, RES_SHARED_VGA }, + { PCI_CHIP_RV280_5C63, PCI_CHIP_RV280_5C63, RES_SHARED_VGA }, + { PCI_CHIP_R300_AD, PCI_CHIP_R300_AD, RES_SHARED_VGA }, + { PCI_CHIP_R300_AE, PCI_CHIP_R300_AE, RES_SHARED_VGA }, + { PCI_CHIP_R300_AF, PCI_CHIP_R300_AF, RES_SHARED_VGA }, + { PCI_CHIP_R300_AG, PCI_CHIP_R300_AG, RES_SHARED_VGA }, + { PCI_CHIP_R300_ND, PCI_CHIP_R300_ND, RES_SHARED_VGA }, + { PCI_CHIP_R300_NE, PCI_CHIP_R300_NE, RES_SHARED_VGA }, + { PCI_CHIP_R300_NF, PCI_CHIP_R300_NF, RES_SHARED_VGA }, + { PCI_CHIP_R300_NG, PCI_CHIP_R300_NG, RES_SHARED_VGA }, + { PCI_CHIP_RV350_AP, PCI_CHIP_RV350_AP, RES_SHARED_VGA }, + { PCI_CHIP_RV350_AQ, PCI_CHIP_RV350_AQ, RES_SHARED_VGA }, + { PCI_CHIP_RV360_AR, PCI_CHIP_RV360_AR, RES_SHARED_VGA }, + { PCI_CHIP_RV350_AS, PCI_CHIP_RV350_AS, RES_SHARED_VGA }, + { PCI_CHIP_RV350_AT, PCI_CHIP_RV350_AT, RES_SHARED_VGA }, + { PCI_CHIP_RV350_AV, PCI_CHIP_RV350_AV, RES_SHARED_VGA }, + { PCI_CHIP_RV350_NP, PCI_CHIP_RV350_NP, RES_SHARED_VGA }, + { PCI_CHIP_RV350_NQ, PCI_CHIP_RV350_NQ, RES_SHARED_VGA }, + { PCI_CHIP_RV350_NR, PCI_CHIP_RV350_NR, RES_SHARED_VGA }, + { PCI_CHIP_RV350_NS, PCI_CHIP_RV350_NS, RES_SHARED_VGA }, + { PCI_CHIP_RV350_NT, PCI_CHIP_RV350_NT, RES_SHARED_VGA }, + { PCI_CHIP_RV350_NV, PCI_CHIP_RV350_NV, RES_SHARED_VGA }, + { PCI_CHIP_R350_AH, PCI_CHIP_R350_AH, RES_SHARED_VGA }, + { PCI_CHIP_R350_AI, PCI_CHIP_R350_AI, RES_SHARED_VGA }, + { PCI_CHIP_R350_AJ, PCI_CHIP_R350_AJ, RES_SHARED_VGA }, + { PCI_CHIP_R350_AK, PCI_CHIP_R350_AK, RES_SHARED_VGA }, + { PCI_CHIP_R350_NH, PCI_CHIP_R350_NH, RES_SHARED_VGA }, + { PCI_CHIP_R350_NI, PCI_CHIP_R350_NI, RES_SHARED_VGA }, + { PCI_CHIP_R350_NK, PCI_CHIP_R350_NK, RES_SHARED_VGA }, + { PCI_CHIP_R360_NJ, PCI_CHIP_R360_NJ, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED } +}; + +int gRADEONEntityIndex = -1; + +/* Return the options for supported chipset 'n'; NULL otherwise */ +const OptionInfoRec * +RADEONAvailableOptions(int chipid, int busid) +{ + int i; + + /* + * Return options defined in the radeon submodule which will have been + * loaded by this point. + */ + if ((chipid >> 16) == PCI_VENDOR_ATI) + chipid -= PCI_VENDOR_ATI << 16; + for (i = 0; RADEONPciChipsets[i].PCIid > 0; i++) { + if (chipid == RADEONPciChipsets[i].PCIid) + return RADEONOptions; + } + return NULL; +} + +/* Return the string name for supported chipset 'n'; NULL otherwise. */ +void +RADEONIdentify(int flags) +{ + xf86PrintChipsets(RADEON_NAME, + "Driver for ATI Radeon chipsets", + RADEONChipsets); +} + +/* Return TRUE if chipset is present; FALSE otherwise. */ +Bool +RADEONProbe(DriverPtr drv, int flags) +{ + int numUsed; + int numDevSections, nATIGDev, nRadeonGDev; + int *usedChips; + GDevPtr *devSections, *ATIGDevs, *RadeonGDevs; + Bool foundScreen = FALSE; + int i; + + if (!xf86GetPciVideoInfo()) return FALSE; + + /* Collect unclaimed device sections for both driver names */ + nATIGDev = xf86MatchDevice(ATI_NAME, &ATIGDevs); + nRadeonGDev = xf86MatchDevice(RADEON_NAME, &RadeonGDevs); + + if (!(numDevSections = nATIGDev + nRadeonGDev)) return FALSE; + + if (!ATIGDevs) { + if (!(devSections = RadeonGDevs)) numDevSections = 1; + else numDevSections = nRadeonGDev; + } if (!RadeonGDevs) { + devSections = ATIGDevs; + numDevSections = nATIGDev; + } else { + /* Combine into one list */ + devSections = xnfalloc((numDevSections + 1) * sizeof(GDevPtr)); + (void)memcpy(devSections, + ATIGDevs, nATIGDev * sizeof(GDevPtr)); + (void)memcpy(devSections + nATIGDev, + RadeonGDevs, nRadeonGDev * sizeof(GDevPtr)); + devSections[numDevSections] = NULL; + xfree(ATIGDevs); + xfree(RadeonGDevs); + } + + numUsed = xf86MatchPciInstances(RADEON_NAME, + PCI_VENDOR_ATI, + RADEONChipsets, + RADEONPciChipsets, + devSections, + numDevSections, + drv, + &usedChips); + + if (numUsed <= 0) return FALSE; + + if (flags & PROBE_DETECT) { + foundScreen = TRUE; + } else { + for (i = 0; i < numUsed; i++) { + ScrnInfoPtr pScrn = NULL; + EntityInfoPtr pEnt; + pEnt = xf86GetEntityInfo(usedChips[i]); + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], + RADEONPciChipsets, 0, 0, 0, + 0, 0))) { +#ifdef XFree86LOADER + if (!xf86LoadSubModule(pScrn, "radeon")) { + xf86Msg(X_ERROR, RADEON_NAME + ": Failed to load \"radeon\" module.\n"); + xf86DeleteScreen(pScrn->scrnIndex, 0); + continue; + } + + xf86LoaderReqSymLists(RADEONSymbols, NULL); +#endif + + pScrn->driverVersion = RADEON_VERSION_CURRENT; + pScrn->driverName = RADEON_DRIVER_NAME; + pScrn->name = RADEON_NAME; + pScrn->Probe = RADEONProbe; + pScrn->PreInit = RADEONPreInit; + pScrn->ScreenInit = RADEONScreenInit; + pScrn->SwitchMode = RADEONSwitchMode; +#ifdef X_XF86MiscPassMessage + pScrn->HandleMessage = RADEONHandleMessage; +#endif + pScrn->AdjustFrame = RADEONAdjustFrame; + pScrn->EnterVT = RADEONEnterVT; + pScrn->LeaveVT = RADEONLeaveVT; + pScrn->FreeScreen = RADEONFreeScreen; + pScrn->ValidMode = RADEONValidMode; + foundScreen = TRUE; + } + + pEnt = xf86GetEntityInfo(usedChips[i]); + + /* create a RADEONEntity for all chips, even with + old single head Radeon, need to use pRADEONEnt + for new monitor detection routines + */ + { + DevUnion *pPriv; + RADEONEntPtr pRADEONEnt; + + xf86SetEntitySharable(usedChips[i]); + + if (gRADEONEntityIndex == -1) + gRADEONEntityIndex = xf86AllocateEntityPrivateIndex(); + + pPriv = xf86GetEntityPrivate(pEnt->index, + gRADEONEntityIndex); + + if (!pPriv->ptr) { + int j; + int instance = xf86GetNumEntityInstances(pEnt->index); + + for (j = 0; j < instance; j++) + xf86SetEntityInstanceForScreen(pScrn, pEnt->index, j); + + pPriv->ptr = xnfcalloc(sizeof(RADEONEntRec), 1); + pRADEONEnt = pPriv->ptr; + pRADEONEnt->HasSecondary = FALSE; + pRADEONEnt->IsSecondaryRestored = FALSE; + } else { + pRADEONEnt = pPriv->ptr; + pRADEONEnt->HasSecondary = TRUE; + } + } + xfree(pEnt); + } + } + + xfree(usedChips); + xfree(devSections); + + return foundScreen; +} diff --git a/src/radeon_probe.h b/src/radeon_probe.h new file mode 100644 index 0000000..af32f25 --- /dev/null +++ b/src/radeon_probe.h @@ -0,0 +1,109 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_probe.h,v 1.13 2003/10/30 17:37:00 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * + * Modified by Marc Aurele La France <tsi@xfree86.org> for ATI driver merge. + */ + +#ifndef _RADEON_PROBE_H_ +#define _RADEON_PROBE_H_ 1 + +#include "atiproto.h" + +#include "xf86str.h" +#include "xf86DDC.h" + +#define _XF86MISC_SERVER_ +#include "xf86misc.h" + +typedef struct +{ + Bool HasSecondary; + + /* + * The next two are used to make sure CRTC2 is restored before CRTC_EXT, + * otherwise it could lead to blank screens. + */ + Bool IsSecondaryRestored; + Bool RestorePrimary; + + ScrnInfoPtr pSecondaryScrn; + ScrnInfoPtr pPrimaryScrn; + + int MonType1; + int MonType2; + xf86MonPtr MonInfo1; + xf86MonPtr MonInfo2; + Bool ReversedDAC; /* TVDAC used as primary dac */ + Bool ReversedTMDS; /* DDC_DVI is used for external TMDS */ +} RADEONEntRec, *RADEONEntPtr; + +/* radeon_probe.c */ +extern const OptionInfoRec *RADEONAvailableOptions + FunctionPrototype((int, int)); +extern void RADEONIdentify + FunctionPrototype((int)); +extern Bool RADEONProbe + FunctionPrototype((DriverPtr, int)); + +extern SymTabRec RADEONChipsets[]; +extern PciChipsets RADEONPciChipsets[]; + +/* radeon_driver.c */ +extern void RADEONLoaderRefSymLists + FunctionPrototype((void)); +extern Bool RADEONPreInit + FunctionPrototype((ScrnInfoPtr, int)); +extern Bool RADEONScreenInit + FunctionPrototype((int, ScreenPtr, int, char **)); +extern Bool RADEONSwitchMode + FunctionPrototype((int, DisplayModePtr, int)); +#ifdef X_XF86MiscPassMessage +extern Bool RADEONHandleMessage + FunctionPrototype((int, const char*, const char*, + char**)); +#endif +extern void RADEONAdjustFrame + FunctionPrototype((int, int, int, int)); +extern Bool RADEONEnterVT + FunctionPrototype((int, int)); +extern void RADEONLeaveVT + FunctionPrototype((int, int)); +extern void RADEONFreeScreen + FunctionPrototype((int, int)); +extern ModeStatus RADEONValidMode + FunctionPrototype((int, DisplayModePtr, Bool, + int)); + +extern const OptionInfoRec RADEONOptions[]; + +#endif /* _RADEON_PROBE_H_ */ diff --git a/src/radeon_reg.h b/src/radeon_reg.h new file mode 100644 index 0000000..8af5da5 --- /dev/null +++ b/src/radeon_reg.h @@ -0,0 +1,2126 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h,v 1.31 2003/11/10 18:41:23 tsi Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * !!!! FIXME !!!! + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +/* !!!! FIXME !!!! NOTE: THIS FILE HAS BEEN CONVERTED FROM r128_reg.h + * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT + * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED! */ + +#ifndef _RADEON_REG_H_ +#define _RADEON_REG_H_ + + /* Registers for 2D/Video/Overlay */ +#define RADEON_ADAPTER_ID 0x0f2c /* PCI */ +#define RADEON_AGP_BASE 0x0170 +#define RADEON_AGP_CNTL 0x0174 +# define RADEON_AGP_APER_SIZE_256MB (0x00 << 0) +# define RADEON_AGP_APER_SIZE_128MB (0x20 << 0) +# define RADEON_AGP_APER_SIZE_64MB (0x30 << 0) +# define RADEON_AGP_APER_SIZE_32MB (0x38 << 0) +# define RADEON_AGP_APER_SIZE_16MB (0x3c << 0) +# define RADEON_AGP_APER_SIZE_8MB (0x3e << 0) +# define RADEON_AGP_APER_SIZE_4MB (0x3f << 0) +# define RADEON_AGP_APER_SIZE_MASK (0x3f << 0) +#define RADEON_STATUS_PCI_CONFIG 0x06 +# define RADEON_CAP_LIST 0x100000 +#define RADEON_CAPABILITIES_PTR_PCI_CONFIG 0x34 /* offset in PCI config*/ +# define RADEON_CAP_PTR_MASK 0xfc /* mask off reserved bits of CAP_PTR */ +# define RADEON_CAP_ID_NULL 0x00 /* End of capability list */ +# define RADEON_CAP_ID_AGP 0x02 /* AGP capability ID */ +#define RADEON_AGP_COMMAND 0x0f60 /* PCI */ +#define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config*/ +# define RADEON_AGP_ENABLE (1<<8) +#define RADEON_AGP_PLL_CNTL 0x000b /* PLL */ +#define RADEON_AGP_STATUS 0x0f5c /* PCI */ +# define RADEON_AGP_1X_MODE 0x01 +# define RADEON_AGP_2X_MODE 0x02 +# define RADEON_AGP_4X_MODE 0x04 +# define RADEON_AGP_FW_MODE 0x10 +# define RADEON_AGP_MODE_MASK 0x17 +#define RADEON_ATTRDR 0x03c1 /* VGA */ +#define RADEON_ATTRDW 0x03c0 /* VGA */ +#define RADEON_ATTRX 0x03c0 /* VGA */ +#define RADEON_AUX_SC_CNTL 0x1660 +# define RADEON_AUX1_SC_EN (1 << 0) +# define RADEON_AUX1_SC_MODE_OR (0 << 1) +# define RADEON_AUX1_SC_MODE_NAND (1 << 1) +# define RADEON_AUX2_SC_EN (1 << 2) +# define RADEON_AUX2_SC_MODE_OR (0 << 3) +# define RADEON_AUX2_SC_MODE_NAND (1 << 3) +# define RADEON_AUX3_SC_EN (1 << 4) +# define RADEON_AUX3_SC_MODE_OR (0 << 5) +# define RADEON_AUX3_SC_MODE_NAND (1 << 5) +#define RADEON_AUX1_SC_BOTTOM 0x1670 +#define RADEON_AUX1_SC_LEFT 0x1664 +#define RADEON_AUX1_SC_RIGHT 0x1668 +#define RADEON_AUX1_SC_TOP 0x166c +#define RADEON_AUX2_SC_BOTTOM 0x1680 +#define RADEON_AUX2_SC_LEFT 0x1674 +#define RADEON_AUX2_SC_RIGHT 0x1678 +#define RADEON_AUX2_SC_TOP 0x167c +#define RADEON_AUX3_SC_BOTTOM 0x1690 +#define RADEON_AUX3_SC_LEFT 0x1684 +#define RADEON_AUX3_SC_RIGHT 0x1688 +#define RADEON_AUX3_SC_TOP 0x168c +#define RADEON_AUX_WINDOW_HORZ_CNTL 0x02d8 +#define RADEON_AUX_WINDOW_VERT_CNTL 0x02dc + +#define RADEON_BASE_CODE 0x0f0b +#define RADEON_BIOS_0_SCRATCH 0x0010 +#define RADEON_BIOS_1_SCRATCH 0x0014 +#define RADEON_BIOS_2_SCRATCH 0x0018 +#define RADEON_BIOS_3_SCRATCH 0x001c +#define RADEON_BIOS_4_SCRATCH 0x0020 +#define RADEON_BIOS_5_SCRATCH 0x0024 +#define RADEON_BIOS_6_SCRATCH 0x0028 +#define RADEON_BIOS_7_SCRATCH 0x002c +#define RADEON_BIOS_ROM 0x0f30 /* PCI */ +#define RADEON_BIST 0x0f0f /* PCI */ +#define RADEON_BRUSH_DATA0 0x1480 +#define RADEON_BRUSH_DATA1 0x1484 +#define RADEON_BRUSH_DATA10 0x14a8 +#define RADEON_BRUSH_DATA11 0x14ac +#define RADEON_BRUSH_DATA12 0x14b0 +#define RADEON_BRUSH_DATA13 0x14b4 +#define RADEON_BRUSH_DATA14 0x14b8 +#define RADEON_BRUSH_DATA15 0x14bc +#define RADEON_BRUSH_DATA16 0x14c0 +#define RADEON_BRUSH_DATA17 0x14c4 +#define RADEON_BRUSH_DATA18 0x14c8 +#define RADEON_BRUSH_DATA19 0x14cc +#define RADEON_BRUSH_DATA2 0x1488 +#define RADEON_BRUSH_DATA20 0x14d0 +#define RADEON_BRUSH_DATA21 0x14d4 +#define RADEON_BRUSH_DATA22 0x14d8 +#define RADEON_BRUSH_DATA23 0x14dc +#define RADEON_BRUSH_DATA24 0x14e0 +#define RADEON_BRUSH_DATA25 0x14e4 +#define RADEON_BRUSH_DATA26 0x14e8 +#define RADEON_BRUSH_DATA27 0x14ec +#define RADEON_BRUSH_DATA28 0x14f0 +#define RADEON_BRUSH_DATA29 0x14f4 +#define RADEON_BRUSH_DATA3 0x148c +#define RADEON_BRUSH_DATA30 0x14f8 +#define RADEON_BRUSH_DATA31 0x14fc +#define RADEON_BRUSH_DATA32 0x1500 +#define RADEON_BRUSH_DATA33 0x1504 +#define RADEON_BRUSH_DATA34 0x1508 +#define RADEON_BRUSH_DATA35 0x150c +#define RADEON_BRUSH_DATA36 0x1510 +#define RADEON_BRUSH_DATA37 0x1514 +#define RADEON_BRUSH_DATA38 0x1518 +#define RADEON_BRUSH_DATA39 0x151c +#define RADEON_BRUSH_DATA4 0x1490 +#define RADEON_BRUSH_DATA40 0x1520 +#define RADEON_BRUSH_DATA41 0x1524 +#define RADEON_BRUSH_DATA42 0x1528 +#define RADEON_BRUSH_DATA43 0x152c +#define RADEON_BRUSH_DATA44 0x1530 +#define RADEON_BRUSH_DATA45 0x1534 +#define RADEON_BRUSH_DATA46 0x1538 +#define RADEON_BRUSH_DATA47 0x153c +#define RADEON_BRUSH_DATA48 0x1540 +#define RADEON_BRUSH_DATA49 0x1544 +#define RADEON_BRUSH_DATA5 0x1494 +#define RADEON_BRUSH_DATA50 0x1548 +#define RADEON_BRUSH_DATA51 0x154c +#define RADEON_BRUSH_DATA52 0x1550 +#define RADEON_BRUSH_DATA53 0x1554 +#define RADEON_BRUSH_DATA54 0x1558 +#define RADEON_BRUSH_DATA55 0x155c +#define RADEON_BRUSH_DATA56 0x1560 +#define RADEON_BRUSH_DATA57 0x1564 +#define RADEON_BRUSH_DATA58 0x1568 +#define RADEON_BRUSH_DATA59 0x156c +#define RADEON_BRUSH_DATA6 0x1498 +#define RADEON_BRUSH_DATA60 0x1570 +#define RADEON_BRUSH_DATA61 0x1574 +#define RADEON_BRUSH_DATA62 0x1578 +#define RADEON_BRUSH_DATA63 0x157c +#define RADEON_BRUSH_DATA7 0x149c +#define RADEON_BRUSH_DATA8 0x14a0 +#define RADEON_BRUSH_DATA9 0x14a4 +#define RADEON_BRUSH_SCALE 0x1470 +#define RADEON_BRUSH_Y_X 0x1474 +#define RADEON_BUS_CNTL 0x0030 +# define RADEON_BUS_MASTER_DIS (1 << 6) +# define RADEON_BUS_RD_DISCARD_EN (1 << 24) +# define RADEON_BUS_RD_ABORT_EN (1 << 25) +# define RADEON_BUS_MSTR_DISCONNECT_EN (1 << 28) +# define RADEON_BUS_WRT_BURST (1 << 29) +# define RADEON_BUS_READ_BURST (1 << 30) +#define RADEON_BUS_CNTL1 0x0034 +# define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) + +#define RADEON_CACHE_CNTL 0x1724 +#define RADEON_CACHE_LINE 0x0f0c /* PCI */ +#define RADEON_CAP0_TRIG_CNTL 0x0950 /* ? */ +#define RADEON_CAP1_TRIG_CNTL 0x09c0 /* ? */ +#define RADEON_CAPABILITIES_ID 0x0f50 /* PCI */ +#define RADEON_CAPABILITIES_PTR 0x0f34 /* PCI */ +#define RADEON_CLK_PIN_CNTL 0x0001 /* PLL */ +#define RADEON_CLOCK_CNTL_DATA 0x000c +#define RADEON_CLOCK_CNTL_INDEX 0x0008 +# define RADEON_PLL_WR_EN (1 << 7) +# define RADEON_PLL_DIV_SEL (3 << 8) +# define RADEON_PLL2_DIV_SEL_MASK ~(3 << 8) +#define RADEON_CLR_CMP_CLR_3D 0x1a24 +#define RADEON_CLR_CMP_CLR_DST 0x15c8 +#define RADEON_CLR_CMP_CLR_SRC 0x15c4 +#define RADEON_CLR_CMP_CNTL 0x15c0 +# define RADEON_SRC_CMP_EQ_COLOR (4 << 0) +# define RADEON_SRC_CMP_NEQ_COLOR (5 << 0) +# define RADEON_CLR_CMP_SRC_SOURCE (1 << 24) +#define RADEON_CLR_CMP_MASK 0x15cc +# define RADEON_CLR_CMP_MSK 0xffffffff +#define RADEON_CLR_CMP_MASK_3D 0x1A28 +#define RADEON_COMMAND 0x0f04 /* PCI */ +#define RADEON_COMPOSITE_SHADOW_ID 0x1a0c +#define RADEON_CONFIG_APER_0_BASE 0x0100 +#define RADEON_CONFIG_APER_1_BASE 0x0104 +#define RADEON_CONFIG_APER_SIZE 0x0108 +#define RADEON_CONFIG_BONDS 0x00e8 +#define RADEON_CONFIG_CNTL 0x00e0 +# define RADEON_CFG_ATI_REV_A11 (0 << 16) +# define RADEON_CFG_ATI_REV_A12 (1 << 16) +# define RADEON_CFG_ATI_REV_A13 (2 << 16) +# define RADEON_CFG_ATI_REV_ID_MASK (0xf << 16) +#define RADEON_CONFIG_MEMSIZE 0x00f8 +#define RADEON_CONFIG_MEMSIZE_EMBEDDED 0x0114 +#define RADEON_CONFIG_REG_1_BASE 0x010c +#define RADEON_CONFIG_REG_APER_SIZE 0x0110 +#define RADEON_CONFIG_XSTRAP 0x00e4 +#define RADEON_CONSTANT_COLOR_C 0x1d34 +# define RADEON_CONSTANT_COLOR_MASK 0x00ffffff +# define RADEON_CONSTANT_COLOR_ONE 0x00ffffff +# define RADEON_CONSTANT_COLOR_ZERO 0x00000000 +#define RADEON_CRC_CMDFIFO_ADDR 0x0740 +#define RADEON_CRC_CMDFIFO_DOUT 0x0744 +#define RADEON_GRPH_BUFFER_CNTL 0x02f0 +# define RADEON_GRPH_START_REQ_MASK (0x7f) +# define RADEON_GRPH_START_REQ_SHIFT 0 +# define RADEON_GRPH_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH_STOP_REQ_SHIFT 8 +# define RADEON_GRPH_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH_BUFFER_SIZE (1<<29) +# define RADEON_GRPH_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH_STOP_CNTL (1<<31) +#define RADEON_GRPH2_BUFFER_CNTL 0x03f0 +# define RADEON_GRPH2_START_REQ_MASK (0x7f) +# define RADEON_GRPH2_START_REQ_SHIFT 0 +# define RADEON_GRPH2_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH2_STOP_REQ_SHIFT 8 +# define RADEON_GRPH2_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH2_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH2_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH2_BUFFER_SIZE (1<<29) +# define RADEON_GRPH2_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH2_STOP_CNTL (1<<31) +#define RADEON_CRTC_CRNT_FRAME 0x0214 +#define RADEON_CRTC_EXT_CNTL 0x0054 +# define RADEON_CRTC_VGA_XOVERSCAN (1 << 0) +# define RADEON_VGA_ATI_LINEAR (1 << 3) +# define RADEON_XCRT_CNT_EN (1 << 6) +# define RADEON_CRTC_HSYNC_DIS (1 << 8) +# define RADEON_CRTC_VSYNC_DIS (1 << 9) +# define RADEON_CRTC_DISPLAY_DIS (1 << 10) +# define RADEON_CRTC_SYNC_TRISTAT (1 << 11) +# define RADEON_CRTC_CRT_ON (1 << 15) +#define RADEON_CRTC_EXT_CNTL_DPMS_BYTE 0x0055 +# define RADEON_CRTC_HSYNC_DIS_BYTE (1 << 0) +# define RADEON_CRTC_VSYNC_DIS_BYTE (1 << 1) +# define RADEON_CRTC_DISPLAY_DIS_BYTE (1 << 2) +#define RADEON_CRTC_GEN_CNTL 0x0050 +# define RADEON_CRTC_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC_INTERLACE_EN (1 << 1) +# define RADEON_CRTC_CSYNC_EN (1 << 4) +# define RADEON_CRTC_CUR_EN (1 << 16) +# define RADEON_CRTC_CUR_MODE_MASK (7 << 17) +# define RADEON_CRTC_ICON_EN (1 << 20) +# define RADEON_CRTC_EXT_DISP_EN (1 << 24) +# define RADEON_CRTC_EN (1 << 25) +# define RADEON_CRTC_DISP_REQ_EN_B (1 << 26) +#define RADEON_CRTC2_GEN_CNTL 0x03f8 +# define RADEON_CRTC2_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC2_INTERLACE_EN (1 << 1) +# define RADEON_CRTC2_SYNC_TRISTAT (1 << 4) +# define RADEON_CRTC2_HSYNC_TRISTAT (1 << 5) +# define RADEON_CRTC2_VSYNC_TRISTAT (1 << 6) +# define RADEON_CRTC2_CRT2_ON (1 << 7) +# define RADEON_CRTC2_ICON_EN (1 << 15) +# define RADEON_CRTC2_CUR_EN (1 << 16) +# define RADEON_CRTC2_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC2_DISP_DIS (1 << 23) +# define RADEON_CRTC2_EN (1 << 25) +# define RADEON_CRTC2_DISP_REQ_EN_B (1 << 26) +# define RADEON_CRTC2_CSYNC_EN (1 << 27) +# define RADEON_CRTC2_HSYNC_DIS (1 << 28) +# define RADEON_CRTC2_VSYNC_DIS (1 << 29) +#define RADEON_CRTC_MORE_CNTL 0x27c +# define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4) +# define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5) +#define RADEON_CRTC_GUI_TRIG_VLINE 0x0218 +#define RADEON_CRTC_H_SYNC_STRT_WID 0x0204 +# define RADEON_CRTC_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_H_SYNC_POL (1 << 23) +#define RADEON_CRTC2_H_SYNC_STRT_WID 0x0304 +# define RADEON_CRTC2_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC2_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC2_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_H_SYNC_POL (1 << 23) +#define RADEON_CRTC_H_TOTAL_DISP 0x0200 +# define RADEON_CRTC_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC_H_TOTAL_SHIFT 0 +# define RADEON_CRTC_H_DISP (0x01ff << 16) +# define RADEON_CRTC_H_DISP_SHIFT 16 +#define RADEON_CRTC2_H_TOTAL_DISP 0x0300 +# define RADEON_CRTC2_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC2_H_TOTAL_SHIFT 0 +# define RADEON_CRTC2_H_DISP (0x01ff << 16) +# define RADEON_CRTC2_H_DISP_SHIFT 16 +#define RADEON_CRTC_OFFSET 0x0224 +#define RADEON_CRTC2_OFFSET 0x0324 +#define RADEON_CRTC_OFFSET_CNTL 0x0228 +# define RADEON_CRTC_TILE_EN (1 << 15) +#define RADEON_CRTC2_OFFSET_CNTL 0x0328 +# define RADEON_CRTC2_TILE_EN (1 << 15) +#define RADEON_CRTC_PITCH 0x022c +#define RADEON_CRTC2_PITCH 0x032c +#define RADEON_CRTC_STATUS 0x005c +# define RADEON_CRTC_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC2_STATUS 0x03fc +# define RADEON_CRTC2_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC2_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC_V_SYNC_STRT_WID 0x020c +# define RADEON_CRTC_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_V_SYNC_POL (1 << 23) +#define RADEON_CRTC2_V_SYNC_STRT_WID 0x030c +# define RADEON_CRTC2_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC2_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC2_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC2_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_V_SYNC_POL (1 << 23) +#define RADEON_CRTC_V_TOTAL_DISP 0x0208 +# define RADEON_CRTC_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC_V_TOTAL_SHIFT 0 +# define RADEON_CRTC_V_DISP (0x07ff << 16) +# define RADEON_CRTC_V_DISP_SHIFT 16 +#define RADEON_CRTC2_V_TOTAL_DISP 0x0308 +# define RADEON_CRTC2_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC2_V_TOTAL_SHIFT 0 +# define RADEON_CRTC2_V_DISP (0x07ff << 16) +# define RADEON_CRTC2_V_DISP_SHIFT 16 +#define RADEON_CRTC_VLINE_CRNT_VLINE 0x0210 +# define RADEON_CRTC_CRNT_VLINE_MASK (0x7ff << 16) +#define RADEON_CRTC2_CRNT_FRAME 0x0314 +#define RADEON_CRTC2_GUI_TRIG_VLINE 0x0318 +#define RADEON_CRTC2_STATUS 0x03fc +#define RADEON_CRTC2_VLINE_CRNT_VLINE 0x0310 +#define RADEON_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ +#define RADEON_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ +#define RADEON_CUR_CLR0 0x026c +#define RADEON_CUR_CLR1 0x0270 +#define RADEON_CUR_HORZ_VERT_OFF 0x0268 +#define RADEON_CUR_HORZ_VERT_POSN 0x0264 +#define RADEON_CUR_OFFSET 0x0260 +# define RADEON_CUR_LOCK (1 << 31) +#define RADEON_CUR2_CLR0 0x036c +#define RADEON_CUR2_CLR1 0x0370 +#define RADEON_CUR2_HORZ_VERT_OFF 0x0368 +#define RADEON_CUR2_HORZ_VERT_POSN 0x0364 +#define RADEON_CUR2_OFFSET 0x0360 +# define RADEON_CUR2_LOCK (1 << 31) + +#define RADEON_DAC_CNTL 0x0058 +# define RADEON_DAC_RANGE_CNTL (3 << 0) +# define RADEON_DAC_RANGE_CNTL_MASK 0x03 +# define RADEON_DAC_BLANKING (1 << 2) +# define RADEON_DAC_CMP_EN (1 << 3) +# define RADEON_DAC_CMP_OUTPUT (1 << 7) +# define RADEON_DAC_8BIT_EN (1 << 8) +# define RADEON_DAC_VGA_ADR_EN (1 << 13) +# define RADEON_DAC_PDWN (1 << 15) +# define RADEON_DAC_MASK_ALL (0xff << 24) +#define RADEON_DAC_CNTL2 0x007c +# define RADEON_DAC2_DAC_CLK_SEL (1 << 0) +# define RADEON_DAC2_DAC2_CLK_SEL (1 << 1) +# define RADEON_DAC2_PALETTE_ACC_CTL (1 << 5) +#define RADEON_DAC_EXT_CNTL 0x0280 +# define RADEON_DAC_FORCE_BLANK_OFF_EN (1 << 4) +# define RADEON_DAC_FORCE_DATA_EN (1 << 5) +# define RADEON_DAC_FORCE_DATA_SEL_MASK (3 << 6) +# define RADEON_DAC_FORCE_DATA_MASK 0x0003ff00 +# define RADEON_DAC_FORCE_DATA_SHIFT 8 +#define RADEON_DAC_MACRO_CNTL 0x0d04 +# define RADEON_DAC_PDWN_R (1 << 16) +# define RADEON_DAC_PDWN_G (1 << 17) +# define RADEON_DAC_PDWN_B (1 << 18) +#define RADEON_TV_DAC_CNTL 0x088c +# define RADEON_TV_DAC_STD_MASK 0x0300 +# define RADEON_TV_DAC_RDACPD (1 << 24) +# define RADEON_TV_DAC_GDACPD (1 << 25) +# define RADEON_TV_DAC_BDACPD (1 << 26) +# define RADEON_TV_DAC_BGSLEEP (1 << 26) +#define RADEON_DISP_HW_DEBUG 0x0d14 +# define RADEON_CRT2_DISP1_SEL (1 << 5) +#define RADEON_DISP_OUTPUT_CNTL 0x0d64 +# define RADEON_DISP_DAC_SOURCE_MASK 0x03 +# define RADEON_DISP_DAC2_SOURCE_MASK 0x0c +# define RADEON_DISP_DAC_SOURCE_CRTC2 0x01 +# define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04 +#define RADEON_DAC_CRC_SIG 0x02cc +#define RADEON_DAC_DATA 0x03c9 /* VGA */ +#define RADEON_DAC_MASK 0x03c6 /* VGA */ +#define RADEON_DAC_R_INDEX 0x03c7 /* VGA */ +#define RADEON_DAC_W_INDEX 0x03c8 /* VGA */ +#define RADEON_DDA_CONFIG 0x02e0 +#define RADEON_DDA_ON_OFF 0x02e4 +#define RADEON_DEFAULT_OFFSET 0x16e0 +#define RADEON_DEFAULT_PITCH 0x16e4 +#define RADEON_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 +# define RADEON_DEFAULT_SC_RIGHT_MAX (0x1fff << 0) +# define RADEON_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16) +#define RADEON_DESTINATION_3D_CLR_CMP_VAL 0x1820 +#define RADEON_DESTINATION_3D_CLR_CMP_MSK 0x1824 +#define RADEON_DEVICE_ID 0x0f02 /* PCI */ +#define RADEON_DISP_MISC_CNTL 0x0d00 +# define RADEON_SOFT_RESET_GRPH_PP (1 << 0) +#define RADEON_DISP_MERGE_CNTL 0x0d60 +# define RADEON_DISP_ALPHA_MODE_MASK 0x03 +# define RADEON_DISP_ALPHA_MODE_KEY 0 +# define RADEON_DISP_ALPHA_MODE_PER_PIXEL 1 +# define RADEON_DISP_ALPHA_MODE_GLOBAL 2 +# define RADEON_DISP_RGB_OFFSET_EN (1<<8) +# define RADEON_DISP_GRPH_ALPHA_MASK (0xff << 16) +# define RADEON_DISP_OV0_ALPHA_MASK (0xff << 24) +# define RADEON_DISP_LIN_TRANS_BYPASS (0x01 << 9) +#define RADEON_DISP2_MERGE_CNTL 0x0d68 +# define RADEON_DISP2_RGB_OFFSET_EN (1<<8) +#define RADEON_DISP_LIN_TRANS_GRPH_A 0x0d80 +#define RADEON_DISP_LIN_TRANS_GRPH_B 0x0d84 +#define RADEON_DISP_LIN_TRANS_GRPH_C 0x0d88 +#define RADEON_DISP_LIN_TRANS_GRPH_D 0x0d8c +#define RADEON_DISP_LIN_TRANS_GRPH_E 0x0d90 +#define RADEON_DISP_LIN_TRANS_GRPH_F 0x0d98 +#define RADEON_DP_BRUSH_BKGD_CLR 0x1478 +#define RADEON_DP_BRUSH_FRGD_CLR 0x147c +#define RADEON_DP_CNTL 0x16c0 +# define RADEON_DST_X_LEFT_TO_RIGHT (1 << 0) +# define RADEON_DST_Y_TOP_TO_BOTTOM (1 << 1) +#define RADEON_DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0 +# define RADEON_DST_Y_MAJOR (1 << 2) +# define RADEON_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15) +# define RADEON_DST_X_DIR_LEFT_TO_RIGHT (1 << 31) +#define RADEON_DP_DATATYPE 0x16c4 +# define RADEON_HOST_BIG_ENDIAN_EN (1 << 29) +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define RADEON_GMC_SRC_CLIPPING (1 << 2) +# define RADEON_GMC_DST_CLIPPING (1 << 3) +# define RADEON_GMC_BRUSH_DATATYPE_MASK (0x0f << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_BG (0 << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_LA (1 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_BG (4 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_LA (5 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_BG (6 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_LA (7 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_BG (8 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_LA (9 << 4) +# define RADEON_GMC_BRUSH_8x8_COLOR (10 << 4) +# define RADEON_GMC_BRUSH_1X8_COLOR (12 << 4) +# define RADEON_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define RADEON_GMC_BRUSH_NONE (15 << 4) +# define RADEON_GMC_DST_8BPP_CI (2 << 8) +# define RADEON_GMC_DST_15BPP (3 << 8) +# define RADEON_GMC_DST_16BPP (4 << 8) +# define RADEON_GMC_DST_24BPP (5 << 8) +# define RADEON_GMC_DST_32BPP (6 << 8) +# define RADEON_GMC_DST_8BPP_RGB (7 << 8) +# define RADEON_GMC_DST_Y8 (8 << 8) +# define RADEON_GMC_DST_RGB8 (9 << 8) +# define RADEON_GMC_DST_VYUY (11 << 8) +# define RADEON_GMC_DST_YVYU (12 << 8) +# define RADEON_GMC_DST_AYUV444 (14 << 8) +# define RADEON_GMC_DST_ARGB4444 (15 << 8) +# define RADEON_GMC_DST_DATATYPE_MASK (0x0f << 8) +# define RADEON_GMC_DST_DATATYPE_SHIFT 8 +# define RADEON_GMC_SRC_DATATYPE_MASK (3 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12) +# define RADEON_GMC_SRC_DATATYPE_COLOR (3 << 12) +# define RADEON_GMC_BYTE_PIX_ORDER (1 << 14) +# define RADEON_GMC_BYTE_MSB_TO_LSB (0 << 14) +# define RADEON_GMC_BYTE_LSB_TO_MSB (1 << 14) +# define RADEON_GMC_CONVERSION_TEMP (1 << 15) +# define RADEON_GMC_CONVERSION_TEMP_6500 (0 << 15) +# define RADEON_GMC_CONVERSION_TEMP_9300 (1 << 15) +# define RADEON_GMC_ROP3_MASK (0xff << 16) +# define RADEON_DP_SRC_SOURCE_MASK (7 << 24) +# define RADEON_DP_SRC_SOURCE_MEMORY (2 << 24) +# define RADEON_DP_SRC_SOURCE_HOST_DATA (3 << 24) +# define RADEON_GMC_3D_FCN_EN (1 << 27) +# define RADEON_GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define RADEON_GMC_AUX_CLIP_DIS (1 << 29) +# define RADEON_GMC_WR_MSK_DIS (1 << 30) +# define RADEON_GMC_LD_BRUSH_Y_X (1 << 31) +# define RADEON_ROP3_ZERO 0x00000000 +# define RADEON_ROP3_DSa 0x00880000 +# define RADEON_ROP3_SDna 0x00440000 +# define RADEON_ROP3_S 0x00cc0000 +# define RADEON_ROP3_DSna 0x00220000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DSx 0x00660000 +# define RADEON_ROP3_DSo 0x00ee0000 +# define RADEON_ROP3_DSon 0x00110000 +# define RADEON_ROP3_DSxn 0x00990000 +# define RADEON_ROP3_Dn 0x00550000 +# define RADEON_ROP3_SDno 0x00dd0000 +# define RADEON_ROP3_Sn 0x00330000 +# define RADEON_ROP3_DSno 0x00bb0000 +# define RADEON_ROP3_DSan 0x00770000 +# define RADEON_ROP3_ONE 0x00ff0000 +# define RADEON_ROP3_DPa 0x00a00000 +# define RADEON_ROP3_PDna 0x00500000 +# define RADEON_ROP3_P 0x00f00000 +# define RADEON_ROP3_DPna 0x000a0000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DPx 0x005a0000 +# define RADEON_ROP3_DPo 0x00fa0000 +# define RADEON_ROP3_DPon 0x00050000 +# define RADEON_ROP3_PDxn 0x00a50000 +# define RADEON_ROP3_PDno 0x00f50000 +# define RADEON_ROP3_Pn 0x000f0000 +# define RADEON_ROP3_DPno 0x00af0000 +# define RADEON_ROP3_DPan 0x005f0000 +#define RADEON_DP_GUI_MASTER_CNTL_C 0x1c84 +#define RADEON_DP_MIX 0x16c8 +#define RADEON_DP_SRC_BKGD_CLR 0x15dc +#define RADEON_DP_SRC_FRGD_CLR 0x15d8 +#define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_DST_BRES_DEC 0x1630 +#define RADEON_DST_BRES_ERR 0x1628 +#define RADEON_DST_BRES_INC 0x162c +#define RADEON_DST_BRES_LNTH 0x1634 +#define RADEON_DST_BRES_LNTH_SUB 0x1638 +#define RADEON_DST_HEIGHT 0x1410 +#define RADEON_DST_HEIGHT_WIDTH 0x143c +#define RADEON_DST_HEIGHT_WIDTH_8 0x158c +#define RADEON_DST_HEIGHT_WIDTH_BW 0x15b4 +#define RADEON_DST_HEIGHT_Y 0x15a0 +#define RADEON_DST_LINE_START 0x1600 +#define RADEON_DST_LINE_END 0x1604 +#define RADEON_DST_LINE_PATCOUNT 0x1608 +# define RADEON_BRES_CNTL_SHIFT 8 +#define RADEON_DST_OFFSET 0x1404 +#define RADEON_DST_PITCH 0x1408 +#define RADEON_DST_PITCH_OFFSET 0x142c +#define RADEON_DST_PITCH_OFFSET_C 0x1c80 +# define RADEON_PITCH_SHIFT 21 +# define RADEON_DST_TILE_LINEAR (0 << 30) +# define RADEON_DST_TILE_MACRO (1 << 30) +# define RADEON_DST_TILE_MICRO (2 << 30) +# define RADEON_DST_TILE_BOTH (3 << 30) +#define RADEON_DST_WIDTH 0x140c +#define RADEON_DST_WIDTH_HEIGHT 0x1598 +#define RADEON_DST_WIDTH_X 0x1588 +#define RADEON_DST_WIDTH_X_INCY 0x159c +#define RADEON_DST_X 0x141c +#define RADEON_DST_X_SUB 0x15a4 +#define RADEON_DST_X_Y 0x1594 +#define RADEON_DST_Y 0x1420 +#define RADEON_DST_Y_SUB 0x15a8 +#define RADEON_DST_Y_X 0x1438 + +#define RADEON_FCP_CNTL 0x0910 +# define RADEON_FCP0_SRC_PCICLK 0 +# define RADEON_FCP0_SRC_PCLK 1 +# define RADEON_FCP0_SRC_PCLKb 2 +# define RADEON_FCP0_SRC_HREF 3 +# define RADEON_FCP0_SRC_GND 4 +# define RADEON_FCP0_SRC_HREFb 5 +#define RADEON_FLUSH_1 0x1704 +#define RADEON_FLUSH_2 0x1708 +#define RADEON_FLUSH_3 0x170c +#define RADEON_FLUSH_4 0x1710 +#define RADEON_FLUSH_5 0x1714 +#define RADEON_FLUSH_6 0x1718 +#define RADEON_FLUSH_7 0x171c +#define RADEON_FOG_3D_TABLE_START 0x1810 +#define RADEON_FOG_3D_TABLE_END 0x1814 +#define RADEON_FOG_3D_TABLE_DENSITY 0x181c +#define RADEON_FOG_TABLE_INDEX 0x1a14 +#define RADEON_FOG_TABLE_DATA 0x1a18 +#define RADEON_FP_CRTC_H_TOTAL_DISP 0x0250 +#define RADEON_FP_CRTC_V_TOTAL_DISP 0x0254 +#define RADEON_FP_CRTC2_H_TOTAL_DISP 0x0350 +#define RADEON_FP_CRTC2_V_TOTAL_DISP 0x0354 +# define RADEON_FP_CRTC_H_TOTAL_MASK 0x000003ff +# define RADEON_FP_CRTC_H_DISP_MASK 0x01ff0000 +# define RADEON_FP_CRTC_V_TOTAL_MASK 0x00000fff +# define RADEON_FP_CRTC_V_DISP_MASK 0x0fff0000 +# define RADEON_FP_H_SYNC_STRT_CHAR_MASK 0x00001ff8 +# define RADEON_FP_H_SYNC_WID_MASK 0x003f0000 +# define RADEON_FP_V_SYNC_STRT_MASK 0x00000fff +# define RADEON_FP_V_SYNC_WID_MASK 0x001f0000 +# define RADEON_FP_CRTC_H_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_H_DISP_SHIFT 0x00000010 +# define RADEON_FP_CRTC_V_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_V_DISP_SHIFT 0x00000010 +# define RADEON_FP_H_SYNC_STRT_CHAR_SHIFT 0x00000003 +# define RADEON_FP_H_SYNC_WID_SHIFT 0x00000010 +# define RADEON_FP_V_SYNC_STRT_SHIFT 0x00000000 +# define RADEON_FP_V_SYNC_WID_SHIFT 0x00000010 +#define RADEON_FP_GEN_CNTL 0x0284 +# define RADEON_FP_FPON (1 << 0) +# define RADEON_FP_TMDS_EN (1 << 2) +# define RADEON_FP_PANEL_FORMAT (1 << 3) +# define RADEON_FP_EN_TMDS (1 << 7) +# define RADEON_FP_DETECT_SENSE (1 << 8) +# define RADEON_FP_SEL_CRTC2 (1 << 13) +# define RADEON_FP_CRTC_DONT_SHADOW_HPAR (1 << 15) +# define RADEON_FP_CRTC_DONT_SHADOW_VPAR (1 << 16) +# define RADEON_FP_CRTC_DONT_SHADOW_HEND (1 << 17) +# define RADEON_FP_CRTC_USE_SHADOW_VEND (1 << 18) +# define RADEON_FP_RMX_HVSYNC_CONTROL_EN (1 << 20) +# define RADEON_FP_DFP_SYNC_SEL (1 << 21) +# define RADEON_FP_CRTC_LOCK_8DOT (1 << 22) +# define RADEON_FP_CRT_SYNC_SEL (1 << 23) +# define RADEON_FP_USE_SHADOW_EN (1 << 24) +# define RADEON_FP_CRT_SYNC_ALT (1 << 26) +#define RADEON_FP2_GEN_CNTL 0x0288 +# define RADEON_FP2_BLANK_EN (1 << 1) +# define RADEON_FP2_ON (1 << 2) +# define RADEON_FP2_PANEL_FORMAT (1 << 3) +# define RADEON_FP2_SOURCE_SEL_MASK (3 << 10) +# define RADEON_FP2_SOURCE_SEL_CRTC2 (1 << 10) +# define RADEON_FP2_SRC_SEL_MASK (3 << 13) +# define RADEON_FP2_SRC_SEL_CRTC2 (1 << 13) +# define RADEON_FP2_FP_POL (1 << 16) +# define RADEON_FP2_LP_POL (1 << 17) +# define RADEON_FP2_SCK_POL (1 << 18) +# define RADEON_FP2_LCD_CNTL_MASK (7 << 19) +# define RADEON_FP2_PAD_FLOP_EN (1 << 22) +# define RADEON_FP2_CRC_EN (1 << 23) +# define RADEON_FP2_CRC_READ_EN (1 << 24) +# define RADEON_FP2_DV0_EN (1 << 25) +# define RADEON_FP2_DV0_RATE_SEL_SDR (1 << 26) +#define RADEON_FP_H_SYNC_STRT_WID 0x02c4 +#define RADEON_FP_H2_SYNC_STRT_WID 0x03c4 +#define RADEON_FP_HORZ_STRETCH 0x028c +#define RADEON_FP_HORZ2_STRETCH 0x038c +# define RADEON_HORZ_STRETCH_RATIO_MASK 0xffff +# define RADEON_HORZ_STRETCH_RATIO_MAX 4096 +# define RADEON_HORZ_PANEL_SIZE (0x1ff << 16) +# define RADEON_HORZ_PANEL_SHIFT 16 +# define RADEON_HORZ_STRETCH_PIXREP (0 << 25) +# define RADEON_HORZ_STRETCH_BLEND (1 << 26) +# define RADEON_HORZ_STRETCH_ENABLE (1 << 25) +# define RADEON_HORZ_AUTO_RATIO (1 << 27) +# define RADEON_HORZ_FP_LOOP_STRETCH (0x7 << 28) +# define RADEON_HORZ_AUTO_RATIO_INC (1 << 31) +#define RADEON_FP_V_SYNC_STRT_WID 0x02c8 +#define RADEON_FP_VERT_STRETCH 0x0290 +#define RADEON_FP_V2_SYNC_STRT_WID 0x03c8 +#define RADEON_FP_VERT2_STRETCH 0x0390 +# define RADEON_VERT_PANEL_SIZE (0xfff << 12) +# define RADEON_VERT_PANEL_SHIFT 12 +# define RADEON_VERT_STRETCH_RATIO_MASK 0xfff +# define RADEON_VERT_STRETCH_RATIO_SHIFT 0 +# define RADEON_VERT_STRETCH_RATIO_MAX 4096 +# define RADEON_VERT_STRETCH_ENABLE (1 << 25) +# define RADEON_VERT_STRETCH_LINEREP (0 << 26) +# define RADEON_VERT_STRETCH_BLEND (1 << 26) +# define RADEON_VERT_AUTO_RATIO_EN (1 << 27) +# define RADEON_VERT_STRETCH_RESERVED 0xf1000000 + +#define RADEON_GEN_INT_CNTL 0x0040 +#define RADEON_GEN_INT_STATUS 0x0044 +# define RADEON_VSYNC_INT_AK (1 << 2) +# define RADEON_VSYNC_INT (1 << 2) +# define RADEON_VSYNC2_INT_AK (1 << 6) +# define RADEON_VSYNC2_INT (1 << 6) +#define RADEON_GENENB 0x03c3 /* VGA */ +#define RADEON_GENFC_RD 0x03ca /* VGA */ +#define RADEON_GENFC_WT 0x03da /* VGA, 0x03ba */ +#define RADEON_GENMO_RD 0x03cc /* VGA */ +#define RADEON_GENMO_WT 0x03c2 /* VGA */ +#define RADEON_GENS0 0x03c2 /* VGA */ +#define RADEON_GENS1 0x03da /* VGA, 0x03ba */ +#define RADEON_GPIO_MONID 0x0068 /* DDC interface via I2C */ +#define RADEON_GPIO_MONIDB 0x006c +#define RADEON_GPIO_CRT2_DDC 0x006c +#define RADEON_GPIO_DVI_DDC 0x0064 +#define RADEON_GPIO_VGA_DDC 0x0060 +# define RADEON_GPIO_A_0 (1 << 0) +# define RADEON_GPIO_A_1 (1 << 1) +# define RADEON_GPIO_Y_0 (1 << 8) +# define RADEON_GPIO_Y_1 (1 << 9) +# define RADEON_GPIO_Y_SHIFT_0 8 +# define RADEON_GPIO_Y_SHIFT_1 9 +# define RADEON_GPIO_EN_0 (1 << 16) +# define RADEON_GPIO_EN_1 (1 << 17) +# define RADEON_GPIO_MASK_0 (1 << 24) /*??*/ +# define RADEON_GPIO_MASK_1 (1 << 25) /*??*/ +#define RADEON_GRPH8_DATA 0x03cf /* VGA */ +#define RADEON_GRPH8_IDX 0x03ce /* VGA */ +#define RADEON_GUI_SCRATCH_REG0 0x15e0 +#define RADEON_GUI_SCRATCH_REG1 0x15e4 +#define RADEON_GUI_SCRATCH_REG2 0x15e8 +#define RADEON_GUI_SCRATCH_REG3 0x15ec +#define RADEON_GUI_SCRATCH_REG4 0x15f0 +#define RADEON_GUI_SCRATCH_REG5 0x15f4 + +#define RADEON_HEADER 0x0f0e /* PCI */ +#define RADEON_HOST_DATA0 0x17c0 +#define RADEON_HOST_DATA1 0x17c4 +#define RADEON_HOST_DATA2 0x17c8 +#define RADEON_HOST_DATA3 0x17cc +#define RADEON_HOST_DATA4 0x17d0 +#define RADEON_HOST_DATA5 0x17d4 +#define RADEON_HOST_DATA6 0x17d8 +#define RADEON_HOST_DATA7 0x17dc +#define RADEON_HOST_DATA_LAST 0x17e0 +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HDP_SOFT_RESET (1 << 26) +#define RADEON_HTOTAL_CNTL 0x0009 /* PLL */ +#define RADEON_HTOTAL2_CNTL 0x002e /* PLL */ + +#define RADEON_I2C_CNTL_1 0x0094 /* ? */ +#define RADEON_DVI_I2C_CNTL_1 0x02e4 /* ? */ +#define RADEON_INTERRUPT_LINE 0x0f3c /* PCI */ +#define RADEON_INTERRUPT_PIN 0x0f3d /* PCI */ +#define RADEON_IO_BASE 0x0f14 /* PCI */ + +#define RADEON_LATENCY 0x0f0d /* PCI */ +#define RADEON_LEAD_BRES_DEC 0x1608 +#define RADEON_LEAD_BRES_LNTH 0x161c +#define RADEON_LEAD_BRES_LNTH_SUB 0x1624 +#define RADEON_LVDS_GEN_CNTL 0x02d0 +# define RADEON_LVDS_ON (1 << 0) +# define RADEON_LVDS_DISPLAY_DIS (1 << 1) +# define RADEON_LVDS_PANEL_TYPE (1 << 2) +# define RADEON_LVDS_PANEL_FORMAT (1 << 3) +# define RADEON_LVDS_EN (1 << 7) +# define RADEON_LVDS_DIGON (1 << 18) +# define RADEON_LVDS_BLON (1 << 19) +# define RADEON_LVDS_SEL_CRTC2 (1 << 23) +#define RADEON_LVDS_PLL_CNTL 0x02d4 +# define RADEON_HSYNC_DELAY_SHIFT 28 +# define RADEON_HSYNC_DELAY_MASK (0xf << 28) + +#define RADEON_MAX_LATENCY 0x0f3f /* PCI */ +#define RADEON_MC_AGP_LOCATION 0x014c +#define RADEON_MC_FB_LOCATION 0x0148 +#define RADEON_DISPLAY_BASE_ADDR 0x23c +#define RADEON_DISPLAY2_BASE_ADDR 0x33c +#define RADEON_OV0_BASE_ADDR 0x43c +#define RADEON_NB_TOM 0x15c +#define RADEON_MCLK_CNTL 0x0012 /* PLL */ +# define RADEON_FORCEON_MCLKA (1 << 16) +# define RADEON_FORCEON_MCLKB (1 << 17) +# define RADEON_FORCEON_YCLKA (1 << 18) +# define RADEON_FORCEON_YCLKB (1 << 19) +# define RADEON_FORCEON_MC (1 << 20) +# define RADEON_FORCEON_AIC (1 << 21) +#define RADEON_MDGPIO_A_REG 0x01ac +#define RADEON_MDGPIO_EN_REG 0x01b0 +#define RADEON_MDGPIO_MASK 0x0198 +#define RADEON_MDGPIO_Y_REG 0x01b4 +#define RADEON_MEM_ADDR_CONFIG 0x0148 +#define RADEON_MEM_BASE 0x0f10 /* PCI */ +#define RADEON_MEM_CNTL 0x0140 +# define RADEON_MEM_NUM_CHANNELS_MASK 0x01 +# define RADEON_MEM_USE_B_CH_ONLY (1<<1) +# define RV100_HALF_MODE (1<<3) +# define R300_MEM_NUM_CHANNELS_MASK 0x03 +# define R300_MEM_USE_CD_CH_ONLY (1<<2) +#define RADEON_MEM_TIMING_CNTL 0x0144 /* EXT_MEM_CNTL */ +#define RADEON_MEM_INIT_LAT_TIMER 0x0154 +#define RADEON_MEM_INTF_CNTL 0x014c +#define RADEON_MEM_SDRAM_MODE_REG 0x0158 +#define RADEON_MEM_STR_CNTL 0x0150 +#define RADEON_MEM_VGA_RP_SEL 0x003c +#define RADEON_MEM_VGA_WP_SEL 0x0038 +#define RADEON_MIN_GRANT 0x0f3e /* PCI */ +#define RADEON_MM_DATA 0x0004 +#define RADEON_MM_INDEX 0x0000 +#define RADEON_MPLL_CNTL 0x000e /* PLL */ +#define RADEON_MPP_TB_CONFIG 0x01c0 /* ? */ +#define RADEON_MPP_GP_CONFIG 0x01c8 /* ? */ +#define R300_MC_IND_INDEX 0x01f8 +# define R300_MC_IND_ADDR_MASK 0x3f +#define R300_MC_IND_DATA 0x01fc +#define R300_MC_READ_CNTL_AB 0x017c +# define R300_MEM_RBS_POSITION_A_MASK 0x03 +#define R300_MC_READ_CNTL_CD_mcind 0x24 +# define R300_MEM_RBS_POSITION_C_MASK 0x03 + +#define RADEON_N_VIF_COUNT 0x0248 + +#define RADEON_OV0_AUTO_FLIP_CNTL 0x0470 +#define RADEON_OV0_COLOUR_CNTL 0x04E0 +#define RADEON_OV0_DEINTERLACE_PATTERN 0x0474 +#define RADEON_OV0_EXCLUSIVE_HORZ 0x0408 +# define RADEON_EXCL_HORZ_START_MASK 0x000000ff +# define RADEON_EXCL_HORZ_END_MASK 0x0000ff00 +# define RADEON_EXCL_HORZ_BACK_PORCH_MASK 0x00ff0000 +# define RADEON_EXCL_HORZ_EXCLUSIVE_EN 0x80000000 +#define RADEON_OV0_EXCLUSIVE_VERT 0x040C +# define RADEON_EXCL_VERT_START_MASK 0x000003ff +# define RADEON_EXCL_VERT_END_MASK 0x03ff0000 +#define RADEON_OV0_FILTER_CNTL 0x04A0 +#define RADEON_OV0_FOUR_TAP_COEF_0 0x04B0 +#define RADEON_OV0_FOUR_TAP_COEF_1 0x04B4 +#define RADEON_OV0_FOUR_TAP_COEF_2 0x04B8 +#define RADEON_OV0_FOUR_TAP_COEF_3 0x04BC +#define RADEON_OV0_FOUR_TAP_COEF_4 0x04C0 +#define RADEON_OV0_GAMMA_000_00F 0x0d40 +#define RADEON_OV0_GAMMA_010_01F 0x0d44 +#define RADEON_OV0_GAMMA_020_03F 0x0d48 +#define RADEON_OV0_GAMMA_040_07F 0x0d4c +#define RADEON_OV0_GAMMA_080_0BF 0x0e00 +#define RADEON_OV0_GAMMA_0C0_0FF 0x0e04 +#define RADEON_OV0_GAMMA_100_13F 0x0e08 +#define RADEON_OV0_GAMMA_140_17F 0x0e0c +#define RADEON_OV0_GAMMA_180_1BF 0x0e10 +#define RADEON_OV0_GAMMA_1C0_1FF 0x0e14 +#define RADEON_OV0_GAMMA_200_23F 0x0e18 +#define RADEON_OV0_GAMMA_240_27F 0x0e1c +#define RADEON_OV0_GAMMA_280_2BF 0x0e20 +#define RADEON_OV0_GAMMA_2C0_2FF 0x0e24 +#define RADEON_OV0_GAMMA_300_33F 0x0e28 +#define RADEON_OV0_GAMMA_340_37F 0x0e2c +#define RADEON_OV0_GAMMA_380_3BF 0x0d50 +#define RADEON_OV0_GAMMA_3C0_3FF 0x0d54 +#define RADEON_OV0_GRAPHICS_KEY_CLR_LOW 0x04EC +#define RADEON_OV0_GRAPHICS_KEY_CLR_HIGH 0x04F0 +#define RADEON_OV0_H_INC 0x0480 +#define RADEON_OV0_KEY_CNTL 0x04F4 +# define RADEON_VIDEO_KEY_FN_MASK 0x00000003L +# define RADEON_VIDEO_KEY_FN_FALSE 0x00000000L +# define RADEON_VIDEO_KEY_FN_TRUE 0x00000001L +# define RADEON_VIDEO_KEY_FN_EQ 0x00000002L +# define RADEON_VIDEO_KEY_FN_NE 0x00000003L +# define RADEON_GRAPHIC_KEY_FN_MASK 0x00000030L +# define RADEON_GRAPHIC_KEY_FN_FALSE 0x00000000L +# define RADEON_GRAPHIC_KEY_FN_TRUE 0x00000010L +# define RADEON_GRAPHIC_KEY_FN_EQ 0x00000020L +# define RADEON_GRAPHIC_KEY_FN_NE 0x00000030L +# define RADEON_CMP_MIX_MASK 0x00000100L +# define RADEON_CMP_MIX_OR 0x00000000L +# define RADEON_CMP_MIX_AND 0x00000100L +#define RADEON_OV0_LIN_TRANS_A 0x0d20 +#define RADEON_OV0_LIN_TRANS_B 0x0d24 +#define RADEON_OV0_LIN_TRANS_C 0x0d28 +#define RADEON_OV0_LIN_TRANS_D 0x0d2c +#define RADEON_OV0_LIN_TRANS_E 0x0d30 +#define RADEON_OV0_LIN_TRANS_F 0x0d34 +#define RADEON_OV0_P1_BLANK_LINES_AT_TOP 0x0430 +# define RADEON_P1_BLNK_LN_AT_TOP_M1_MASK 0x00000fffL +# define RADEON_P1_ACTIVE_LINES_M1 0x0fff0000L +#define RADEON_OV0_P1_H_ACCUM_INIT 0x0488 +#define RADEON_OV0_P1_V_ACCUM_INIT 0x0428 +# define RADEON_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L +# define RADEON_OV0_P1_V_ACCUM_INIT_MASK 0x01ff8000L +#define RADEON_OV0_P1_X_START_END 0x0494 +#define RADEON_OV0_P2_X_START_END 0x0498 +#define RADEON_OV0_P23_BLANK_LINES_AT_TOP 0x0434 +# define RADEON_P23_BLNK_LN_AT_TOP_M1_MASK 0x000007ffL +# define RADEON_P23_ACTIVE_LINES_M1 0x07ff0000L +#define RADEON_OV0_P23_H_ACCUM_INIT 0x048C +#define RADEON_OV0_P23_V_ACCUM_INIT 0x042C +#define RADEON_OV0_P3_X_START_END 0x049C +#define RADEON_OV0_REG_LOAD_CNTL 0x0410 +# define RADEON_REG_LD_CTL_LOCK 0x00000001L +# define RADEON_REG_LD_CTL_VBLANK_DURING_LOCK 0x00000002L +# define RADEON_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L +# define RADEON_REG_LD_CTL_LOCK_READBACK 0x00000008L +#define RADEON_OV0_SCALE_CNTL 0x0420 +# define RADEON_SCALER_HORZ_PICK_NEAREST 0x00000004L +# define RADEON_SCALER_VERT_PICK_NEAREST 0x00000008L +# define RADEON_SCALER_SIGNED_UV 0x00000010L +# define RADEON_SCALER_GAMMA_SEL_MASK 0x00000060L +# define RADEON_SCALER_GAMMA_SEL_BRIGHT 0x00000000L +# define RADEON_SCALER_GAMMA_SEL_G22 0x00000020L +# define RADEON_SCALER_GAMMA_SEL_G18 0x00000040L +# define RADEON_SCALER_GAMMA_SEL_G14 0x00000060L +# define RADEON_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L +# define RADEON_SCALER_SURFAC_FORMAT 0x00000f00L +# define RADEON_SCALER_SOURCE_15BPP 0x00000300L +# define RADEON_SCALER_SOURCE_16BPP 0x00000400L +# define RADEON_SCALER_SOURCE_32BPP 0x00000600L +# define RADEON_SCALER_SOURCE_YUV9 0x00000900L +# define RADEON_SCALER_SOURCE_YUV12 0x00000A00L +# define RADEON_SCALER_SOURCE_VYUY422 0x00000B00L +# define RADEON_SCALER_SOURCE_YVYU422 0x00000C00L +# define RADEON_SCALER_ADAPTIVE_DEINT 0x00001000L +# define RADEON_SCALER_TEMPORAL_DEINT 0x00002000L +# define RADEON_SCALER_SMART_SWITCH 0x00008000L +# define RADEON_SCALER_BURST_PER_PLANE 0x007F0000L +# define RADEON_SCALER_DOUBLE_BUFFER 0x01000000L +# define RADEON_SCALER_DIS_LIMIT 0x08000000L +# define RADEON_SCALER_INT_EMU 0x20000000L +# define RADEON_SCALER_ENABLE 0x40000000L +# define RADEON_SCALER_SOFT_RESET 0x80000000L +# define RADEON_SCALER_ADAPTIVE_DEINT 0x00001000L +#define RADEON_OV0_STEP_BY 0x0484 +#define RADEON_OV0_TEST 0x04F8 +#define RADEON_OV0_V_INC 0x0424 +#define RADEON_OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define RADEON_OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define RADEON_OV0_VID_BUF0_BASE_ADRS 0x0440 +# define RADEON_VIF_BUF0_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF0_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF0_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF1_BASE_ADRS 0x0444 +# define RADEON_VIF_BUF1_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF1_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF1_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF2_BASE_ADRS 0x0448 +# define RADEON_VIF_BUF2_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF2_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF2_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF3_BASE_ADRS 0x044C +#define RADEON_OV0_VID_BUF4_BASE_ADRS 0x0450 +#define RADEON_OV0_VID_BUF5_BASE_ADRS 0x0454 +#define RADEON_OV0_VIDEO_KEY_CLR_HIGH 0x04E8 +#define RADEON_OV0_VIDEO_KEY_CLR_LOW 0x04E4 +#define RADEON_OV0_Y_X_START 0x0400 +#define RADEON_OV0_Y_X_END 0x0404 +#define RADEON_OV1_Y_X_START 0x0600 +#define RADEON_OV1_Y_X_END 0x0604 +#define RADEON_OVR_CLR 0x0230 +#define RADEON_OVR_WID_LEFT_RIGHT 0x0234 +#define RADEON_OVR_WID_TOP_BOTTOM 0x0238 + +#define RADEON_P2PLL_CNTL 0x002a /* P2PLL */ +# define RADEON_P2PLL_RESET (1 << 0) +# define RADEON_P2PLL_SLEEP (1 << 1) +# define RADEON_P2PLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_P2PLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_P2PLL_DIV_0 0x002c +# define RADEON_P2PLL_FB0_DIV_MASK 0x07ff +# define RADEON_P2PLL_POST0_DIV_MASK 0x00070000 +#define RADEON_P2PLL_REF_DIV 0x002B /* PLL */ +# define RADEON_P2PLL_REF_DIV_MASK 0x03ff +# define RADEON_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +# define R300_PPLL_REF_DIV_ACC_MASK (0x3ff << 18) +# define R300_PPLL_REF_DIV_ACC_SHIFT 18 +#define RADEON_PALETTE_DATA 0x00b4 +#define RADEON_PALETTE_30_DATA 0x00b8 +#define RADEON_PALETTE_INDEX 0x00b0 +#define RADEON_PCI_GART_PAGE 0x017c +#define RADEON_PIXCLKS_CNTL 0x002d +# define RADEON_PIX2CLK_SRC_SEL_MASK 0x03 +# define RADEON_PIX2CLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_PIX2CLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_PIX2CLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 0x03 +# define RADEON_PIX2CLK_ALWAYS_ONb (1<<6) +# define RADEON_PIX2CLK_DAC_ALWAYS_ONb (1<<7) +# define RADEON_PIXCLK_TV_SRC_SEL (1 << 8) +# define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14) +# define RADEON_PIXCLK_TMDS_ALWAYS_ONb (1 << 15) +#define RADEON_PLANE_3D_MASK_C 0x1d44 +#define RADEON_PLL_TEST_CNTL 0x0013 /* PLL */ +#define RADEON_PMI_CAP_ID 0x0f5c /* PCI */ +#define RADEON_PMI_DATA 0x0f63 /* PCI */ +#define RADEON_PMI_NXT_CAP_PTR 0x0f5d /* PCI */ +#define RADEON_PMI_PMC_REG 0x0f5e /* PCI */ +#define RADEON_PMI_PMCSR_REG 0x0f60 /* PCI */ +#define RADEON_PMI_REGISTER 0x0f5c /* PCI */ +#define RADEON_PPLL_CNTL 0x0002 /* PLL */ +# define RADEON_PPLL_RESET (1 << 0) +# define RADEON_PPLL_SLEEP (1 << 1) +# define RADEON_PPLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_PPLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_PPLL_DIV_0 0x0004 /* PLL */ +#define RADEON_PPLL_DIV_1 0x0005 /* PLL */ +#define RADEON_PPLL_DIV_2 0x0006 /* PLL */ +#define RADEON_PPLL_DIV_3 0x0007 /* PLL */ +# define RADEON_PPLL_FB3_DIV_MASK 0x07ff +# define RADEON_PPLL_POST3_DIV_MASK 0x00070000 +#define RADEON_PPLL_REF_DIV 0x0003 /* PLL */ +# define RADEON_PPLL_REF_DIV_MASK 0x03ff +# define RADEON_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +#define RADEON_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */ + +#define RADEON_RBBM_GUICNTL 0x172c +# define RADEON_HOST_DATA_SWAP_NONE (0 << 0) +# define RADEON_HOST_DATA_SWAP_16BIT (1 << 0) +# define RADEON_HOST_DATA_SWAP_32BIT (2 << 0) +# define RADEON_HOST_DATA_SWAP_HDW (3 << 0) +#define RADEON_RBBM_SOFT_RESET 0x00f0 +# define RADEON_SOFT_RESET_CP (1 << 0) +# define RADEON_SOFT_RESET_HI (1 << 1) +# define RADEON_SOFT_RESET_SE (1 << 2) +# define RADEON_SOFT_RESET_RE (1 << 3) +# define RADEON_SOFT_RESET_PP (1 << 4) +# define RADEON_SOFT_RESET_E2 (1 << 5) +# define RADEON_SOFT_RESET_RB (1 << 6) +# define RADEON_SOFT_RESET_HDP (1 << 7) +#define RADEON_RBBM_STATUS 0x0e40 +# define RADEON_RBBM_FIFOCNT_MASK 0x007f +# define RADEON_RBBM_ACTIVE (1 << 31) +#define RADEON_RB2D_DSTCACHE_CTLSTAT 0x342c +# define RADEON_RB2D_DC_FLUSH (3 << 0) +# define RADEON_RB2D_DC_FREE (3 << 2) +# define RADEON_RB2D_DC_FLUSH_ALL 0xf +# define RADEON_RB2D_DC_BUSY (1 << 31) +#define RADEON_RB2D_DSTCACHE_MODE 0x3428 +#define RADEON_REG_BASE 0x0f18 /* PCI */ +#define RADEON_REGPROG_INF 0x0f09 /* PCI */ +#define RADEON_REVISION_ID 0x0f08 /* PCI */ + +#define RADEON_SC_BOTTOM 0x164c +#define RADEON_SC_BOTTOM_RIGHT 0x16f0 +#define RADEON_SC_BOTTOM_RIGHT_C 0x1c8c +#define RADEON_SC_LEFT 0x1640 +#define RADEON_SC_RIGHT 0x1644 +#define RADEON_SC_TOP 0x1648 +#define RADEON_SC_TOP_LEFT 0x16ec +#define RADEON_SC_TOP_LEFT_C 0x1c88 +# define RADEON_SC_SIGN_MASK_LO 0x8000 +# define RADEON_SC_SIGN_MASK_HI 0x80000000 +#define RADEON_SCLK_CNTL 0x000d /* PLL */ +# define RADEON_DYN_STOP_LAT_MASK 0x00007ff8 +# define RADEON_CP_MAX_DYN_STOP_LAT 0x0008 +# define RADEON_SCLK_FORCEON_MASK 0xffff8000 +#define RADEON_SCLK_MORE_CNTL 0x0035 /* PLL */ +# define RADEON_SCLK_MORE_FORCEON 0x0700 +#define RADEON_SDRAM_MODE_REG 0x0158 +#define RADEON_SEQ8_DATA 0x03c5 /* VGA */ +#define RADEON_SEQ8_IDX 0x03c4 /* VGA */ +#define RADEON_SNAPSHOT_F_COUNT 0x0244 +#define RADEON_SNAPSHOT_VH_COUNTS 0x0240 +#define RADEON_SNAPSHOT_VIF_COUNT 0x024c +#define RADEON_SRC_OFFSET 0x15ac +#define RADEON_SRC_PITCH 0x15b0 +#define RADEON_SRC_PITCH_OFFSET 0x1428 +#define RADEON_SRC_SC_BOTTOM 0x165c +#define RADEON_SRC_SC_BOTTOM_RIGHT 0x16f4 +#define RADEON_SRC_SC_RIGHT 0x1654 +#define RADEON_SRC_X 0x1414 +#define RADEON_SRC_X_Y 0x1590 +#define RADEON_SRC_Y 0x1418 +#define RADEON_SRC_Y_X 0x1434 +#define RADEON_STATUS 0x0f06 /* PCI */ +#define RADEON_SUBPIC_CNTL 0x0540 /* ? */ +#define RADEON_SUB_CLASS 0x0f0a /* PCI */ +#define RADEON_SURFACE_CNTL 0x0b00 +# define RADEON_SURF_TRANSLATION_DIS (1 << 8) +# define RADEON_NONSURF_AP0_SWP_16BPP (1 << 20) +# define RADEON_NONSURF_AP0_SWP_32BPP (1 << 21) +# define RADEON_NONSURF_AP1_SWP_16BPP (1 << 22) +# define RADEON_NONSURF_AP1_SWP_32BPP (1 << 23) +#define RADEON_SURFACE0_INFO 0x0b0c +#define RADEON_SURFACE0_LOWER_BOUND 0x0b04 +#define RADEON_SURFACE0_UPPER_BOUND 0x0b08 +#define RADEON_SURFACE1_INFO 0x0b1c +#define RADEON_SURFACE1_LOWER_BOUND 0x0b14 +#define RADEON_SURFACE1_UPPER_BOUND 0x0b18 +#define RADEON_SURFACE2_INFO 0x0b2c +#define RADEON_SURFACE2_LOWER_BOUND 0x0b24 +#define RADEON_SURFACE2_UPPER_BOUND 0x0b28 +#define RADEON_SURFACE3_INFO 0x0b3c +#define RADEON_SURFACE3_LOWER_BOUND 0x0b34 +#define RADEON_SURFACE3_UPPER_BOUND 0x0b38 +#define RADEON_SURFACE4_INFO 0x0b4c +#define RADEON_SURFACE4_LOWER_BOUND 0x0b44 +#define RADEON_SURFACE4_UPPER_BOUND 0x0b48 +#define RADEON_SURFACE5_INFO 0x0b5c +#define RADEON_SURFACE5_LOWER_BOUND 0x0b54 +#define RADEON_SURFACE5_UPPER_BOUND 0x0b58 +#define RADEON_SURFACE6_INFO 0x0b6c +#define RADEON_SURFACE6_LOWER_BOUND 0x0b64 +#define RADEON_SURFACE6_UPPER_BOUND 0x0b68 +#define RADEON_SURFACE7_INFO 0x0b7c +#define RADEON_SURFACE7_LOWER_BOUND 0x0b74 +#define RADEON_SURFACE7_UPPER_BOUND 0x0b78 +#define RADEON_SW_SEMAPHORE 0x013c + +#define RADEON_TEST_DEBUG_CNTL 0x0120 +#define RADEON_TEST_DEBUG_MUX 0x0124 +#define RADEON_TEST_DEBUG_OUT 0x012c +#define RADEON_TMDS_PLL_CNTL 0x02a8 +#define RADEON_TMDS_TRANSMITTER_CNTL 0x02a4 +# define RADEON_TMDS_TRANSMITTER_PLLEN 1 +# define RADEON_TMDS_TRANSMITTER_PLLRST 2 +#define RADEON_TRAIL_BRES_DEC 0x1614 +#define RADEON_TRAIL_BRES_ERR 0x160c +#define RADEON_TRAIL_BRES_INC 0x1610 +#define RADEON_TRAIL_X 0x1618 +#define RADEON_TRAIL_X_SUB 0x1620 + +#define RADEON_VCLK_ECP_CNTL 0x0008 /* PLL */ +# define RADEON_VCLK_SRC_SEL_MASK 0x03 +# define RADEON_VCLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_VCLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_VCLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_VCLK_SRC_SEL_PPLLCLK 0x03 +# define RADEON_PIXCLK_ALWAYS_ONb (1<<6) +# define RADEON_PIXCLK_DAC_ALWAYS_ONb (1<<7) + +#define RADEON_VENDOR_ID 0x0f00 /* PCI */ +#define RADEON_VGA_DDA_CONFIG 0x02e8 +#define RADEON_VGA_DDA_ON_OFF 0x02ec +#define RADEON_VID_BUFFER_CONTROL 0x0900 +#define RADEON_VIDEOMUX_CNTL 0x0190 +#define RADEON_VIPH_CONTROL 0x0c40 /* ? */ + +#define RADEON_WAIT_UNTIL 0x1720 +# define RADEON_WAIT_CRTC_PFLIP (1 << 0) +# define RADEON_WAIT_2D_IDLECLEAN (1 << 16) +# define RADEON_WAIT_3D_IDLECLEAN (1 << 17) +# define RADEON_WAIT_HOST_IDLECLEAN (1 << 18) + +#define RADEON_X_MPLL_REF_FB_DIV 0x000a /* PLL */ +#define RADEON_XCLK_CNTL 0x000d /* PLL */ +#define RADEON_XDLL_CNTL 0x000c /* PLL */ +#define RADEON_XPLL_CNTL 0x000b /* PLL */ + + + + /* Registers for 3D/TCL */ +#define RADEON_PP_BORDER_COLOR_0 0x1d40 +#define RADEON_PP_BORDER_COLOR_1 0x1d44 +#define RADEON_PP_BORDER_COLOR_2 0x1d48 +#define RADEON_PP_CNTL 0x1c38 +# define RADEON_STIPPLE_ENABLE (1 << 0) +# define RADEON_SCISSOR_ENABLE (1 << 1) +# define RADEON_PATTERN_ENABLE (1 << 2) +# define RADEON_SHADOW_ENABLE (1 << 3) +# define RADEON_TEX_ENABLE_MASK (0xf << 4) +# define RADEON_TEX_0_ENABLE (1 << 4) +# define RADEON_TEX_1_ENABLE (1 << 5) +# define RADEON_TEX_2_ENABLE (1 << 6) +# define RADEON_TEX_3_ENABLE (1 << 7) +# define RADEON_TEX_BLEND_ENABLE_MASK (0xf << 12) +# define RADEON_TEX_BLEND_0_ENABLE (1 << 12) +# define RADEON_TEX_BLEND_1_ENABLE (1 << 13) +# define RADEON_TEX_BLEND_2_ENABLE (1 << 14) +# define RADEON_TEX_BLEND_3_ENABLE (1 << 15) +# define RADEON_PLANAR_YUV_ENABLE (1 << 20) +# define RADEON_SPECULAR_ENABLE (1 << 21) +# define RADEON_FOG_ENABLE (1 << 22) +# define RADEON_ALPHA_TEST_ENABLE (1 << 23) +# define RADEON_ANTI_ALIAS_NONE (0 << 24) +# define RADEON_ANTI_ALIAS_LINE (1 << 24) +# define RADEON_ANTI_ALIAS_POLY (2 << 24) +# define RADEON_ANTI_ALIAS_LINE_POLY (3 << 24) +# define RADEON_BUMP_MAP_ENABLE (1 << 26) +# define RADEON_BUMPED_MAP_T0 (0 << 27) +# define RADEON_BUMPED_MAP_T1 (1 << 27) +# define RADEON_BUMPED_MAP_T2 (2 << 27) +# define RADEON_TEX_3D_ENABLE_0 (1 << 29) +# define RADEON_TEX_3D_ENABLE_1 (1 << 30) +# define RADEON_MC_ENABLE (1 << 31) +#define RADEON_PP_FOG_COLOR 0x1c18 +# define RADEON_FOG_COLOR_MASK 0x00ffffff +# define RADEON_FOG_VERTEX (0 << 24) +# define RADEON_FOG_TABLE (1 << 24) +# define RADEON_FOG_USE_DEPTH (0 << 25) +# define RADEON_FOG_USE_DIFFUSE_ALPHA (2 << 25) +# define RADEON_FOG_USE_SPEC_ALPHA (3 << 25) +#define RADEON_PP_LUM_MATRIX 0x1d00 +#define RADEON_PP_MISC 0x1c14 +# define RADEON_REF_ALPHA_MASK 0x000000ff +# define RADEON_ALPHA_TEST_FAIL (0 << 8) +# define RADEON_ALPHA_TEST_LESS (1 << 8) +# define RADEON_ALPHA_TEST_LEQUAL (2 << 8) +# define RADEON_ALPHA_TEST_EQUAL (3 << 8) +# define RADEON_ALPHA_TEST_GEQUAL (4 << 8) +# define RADEON_ALPHA_TEST_GREATER (5 << 8) +# define RADEON_ALPHA_TEST_NEQUAL (6 << 8) +# define RADEON_ALPHA_TEST_PASS (7 << 8) +# define RADEON_ALPHA_TEST_OP_MASK (7 << 8) +# define RADEON_CHROMA_FUNC_FAIL (0 << 16) +# define RADEON_CHROMA_FUNC_PASS (1 << 16) +# define RADEON_CHROMA_FUNC_NEQUAL (2 << 16) +# define RADEON_CHROMA_FUNC_EQUAL (3 << 16) +# define RADEON_CHROMA_KEY_NEAREST (0 << 18) +# define RADEON_CHROMA_KEY_ZERO (1 << 18) +# define RADEON_SHADOW_ID_AUTO_INC (1 << 20) +# define RADEON_SHADOW_FUNC_EQUAL (0 << 21) +# define RADEON_SHADOW_FUNC_NEQUAL (1 << 21) +# define RADEON_SHADOW_PASS_1 (0 << 22) +# define RADEON_SHADOW_PASS_2 (1 << 22) +# define RADEON_RIGHT_HAND_CUBE_D3D (0 << 24) +# define RADEON_RIGHT_HAND_CUBE_OGL (1 << 24) +#define RADEON_PP_ROT_MATRIX_0 0x1d58 +#define RADEON_PP_ROT_MATRIX_1 0x1d5c +#define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXFILTER_1 0x1c6c +#define RADEON_PP_TXFILTER_2 0x1c84 +# define RADEON_MAG_FILTER_NEAREST (0 << 0) +# define RADEON_MAG_FILTER_LINEAR (1 << 0) +# define RADEON_MAG_FILTER_MASK (1 << 0) +# define RADEON_MIN_FILTER_NEAREST (0 << 1) +# define RADEON_MIN_FILTER_LINEAR (1 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_NEAREST (2 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_LINEAR (3 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_LINEAR (7 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST (8 << 1) +# define RADEON_MIN_FILTER_ANISO_LINEAR (9 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 << 1) +# define RADEON_MIN_FILTER_MASK (15 << 1) +# define RADEON_MAX_ANISO_1_TO_1 (0 << 5) +# define RADEON_MAX_ANISO_2_TO_1 (1 << 5) +# define RADEON_MAX_ANISO_4_TO_1 (2 << 5) +# define RADEON_MAX_ANISO_8_TO_1 (3 << 5) +# define RADEON_MAX_ANISO_16_TO_1 (4 << 5) +# define RADEON_MAX_ANISO_MASK (7 << 5) +# define RADEON_LOD_BIAS_MASK (0xff << 8) +# define RADEON_LOD_BIAS_SHIFT 8 +# define RADEON_MAX_MIP_LEVEL_MASK (0x0f << 16) +# define RADEON_MAX_MIP_LEVEL_SHIFT 16 +# define RADEON_YUV_TO_RGB (1 << 20) +# define RADEON_YUV_TEMPERATURE_COOL (0 << 21) +# define RADEON_YUV_TEMPERATURE_HOT (1 << 21) +# define RADEON_YUV_TEMPERATURE_MASK (1 << 21) +# define RADEON_WRAPEN_S (1 << 22) +# define RADEON_CLAMP_S_WRAP (0 << 23) +# define RADEON_CLAMP_S_MIRROR (1 << 23) +# define RADEON_CLAMP_S_CLAMP_LAST (2 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) +# define RADEON_CLAMP_S_CLAMP_BORDER (4 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define RADEON_CLAMP_S_CLAMP_GL (6 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) +# define RADEON_CLAMP_S_MASK (7 << 23) +# define RADEON_WRAPEN_T (1 << 26) +# define RADEON_CLAMP_T_WRAP (0 << 27) +# define RADEON_CLAMP_T_MIRROR (1 << 27) +# define RADEON_CLAMP_T_CLAMP_LAST (2 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) +# define RADEON_CLAMP_T_CLAMP_BORDER (4 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define RADEON_CLAMP_T_CLAMP_GL (6 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) +# define RADEON_CLAMP_T_MASK (7 << 27) +# define RADEON_BORDER_MODE_OGL (0 << 31) +# define RADEON_BORDER_MODE_D3D (1 << 31) +#define RADEON_PP_TXFORMAT_0 0x1c58 +#define RADEON_PP_TXFORMAT_1 0x1c70 +#define RADEON_PP_TXFORMAT_2 0x1c88 +# define RADEON_TXFORMAT_I8 (0 << 0) +# define RADEON_TXFORMAT_AI88 (1 << 0) +# define RADEON_TXFORMAT_RGB332 (2 << 0) +# define RADEON_TXFORMAT_ARGB1555 (3 << 0) +# define RADEON_TXFORMAT_RGB565 (4 << 0) +# define RADEON_TXFORMAT_ARGB4444 (5 << 0) +# define RADEON_TXFORMAT_ARGB8888 (6 << 0) +# define RADEON_TXFORMAT_RGBA8888 (7 << 0) +# define RADEON_TXFORMAT_Y8 (8 << 0) +# define RADEON_TXFORMAT_VYUY422 (10 << 0) +# define RADEON_TXFORMAT_YVYU422 (11 << 0) +# define RADEON_TXFORMAT_DXT1 (12 << 0) +# define RADEON_TXFORMAT_DXT23 (14 << 0) +# define RADEON_TXFORMAT_DXT45 (15 << 0) +# define RADEON_TXFORMAT_FORMAT_MASK (31 << 0) +# define RADEON_TXFORMAT_FORMAT_SHIFT 0 +# define RADEON_TXFORMAT_APPLE_YUV_MODE (1 << 5) +# define RADEON_TXFORMAT_ALPHA_IN_MAP (1 << 6) +# define RADEON_TXFORMAT_NON_POWER2 (1 << 7) +# define RADEON_TXFORMAT_WIDTH_MASK (15 << 8) +# define RADEON_TXFORMAT_WIDTH_SHIFT 8 +# define RADEON_TXFORMAT_HEIGHT_MASK (15 << 12) +# define RADEON_TXFORMAT_HEIGHT_SHIFT 12 +# define RADEON_TXFORMAT_F5_WIDTH_MASK (15 << 16) +# define RADEON_TXFORMAT_F5_WIDTH_SHIFT 16 +# define RADEON_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define RADEON_TXFORMAT_F5_HEIGHT_SHIFT 20 +# define RADEON_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_MASK (3 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ2 (2 << 24) +# define RADEON_TXFORMAT_ENDIAN_NO_SWAP (0 << 26) +# define RADEON_TXFORMAT_ENDIAN_16BPP_SWAP (1 << 26) +# define RADEON_TXFORMAT_ENDIAN_32BPP_SWAP (2 << 26) +# define RADEON_TXFORMAT_ENDIAN_HALFDW_SWAP (3 << 26) +# define RADEON_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) +# define RADEON_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) +# define RADEON_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) +# define RADEON_TXFORMAT_PERSPECTIVE_ENABLE (1 << 31) +#define RADEON_PP_CUBIC_FACES_0 0x1d24 +#define RADEON_PP_CUBIC_FACES_1 0x1d28 +#define RADEON_PP_CUBIC_FACES_2 0x1d2c +# define RADEON_FACE_WIDTH_1_SHIFT 0 +# define RADEON_FACE_HEIGHT_1_SHIFT 4 +# define RADEON_FACE_WIDTH_1_MASK (0xf << 0) +# define RADEON_FACE_HEIGHT_1_MASK (0xf << 4) +# define RADEON_FACE_WIDTH_2_SHIFT 8 +# define RADEON_FACE_HEIGHT_2_SHIFT 12 +# define RADEON_FACE_WIDTH_2_MASK (0xf << 8) +# define RADEON_FACE_HEIGHT_2_MASK (0xf << 12) +# define RADEON_FACE_WIDTH_3_SHIFT 16 +# define RADEON_FACE_HEIGHT_3_SHIFT 20 +# define RADEON_FACE_WIDTH_3_MASK (0xf << 16) +# define RADEON_FACE_HEIGHT_3_MASK (0xf << 20) +# define RADEON_FACE_WIDTH_4_SHIFT 24 +# define RADEON_FACE_HEIGHT_4_SHIFT 28 +# define RADEON_FACE_WIDTH_4_MASK (0xf << 24) +# define RADEON_FACE_HEIGHT_4_MASK (0xf << 28) + +#define RADEON_PP_TXOFFSET_0 0x1c5c +#define RADEON_PP_TXOFFSET_1 0x1c74 +#define RADEON_PP_TXOFFSET_2 0x1c8c +# define RADEON_TXO_ENDIAN_NO_SWAP (0 << 0) +# define RADEON_TXO_ENDIAN_BYTE_SWAP (1 << 0) +# define RADEON_TXO_ENDIAN_WORD_SWAP (2 << 0) +# define RADEON_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define RADEON_TXO_MACRO_LINEAR (0 << 2) +# define RADEON_TXO_MACRO_TILE (1 << 2) +# define RADEON_TXO_MICRO_LINEAR (0 << 3) +# define RADEON_TXO_MICRO_TILE_X2 (1 << 3) +# define RADEON_TXO_MICRO_TILE_OPT (2 << 3) +# define RADEON_TXO_OFFSET_MASK 0xffffffe0 +# define RADEON_TXO_OFFSET_SHIFT 5 + +#define RADEON_PP_CUBIC_OFFSET_T0_0 0x1dd0 /* bits [31:5] */ +#define RADEON_PP_CUBIC_OFFSET_T0_1 0x1dd4 +#define RADEON_PP_CUBIC_OFFSET_T0_2 0x1dd8 +#define RADEON_PP_CUBIC_OFFSET_T0_3 0x1ddc +#define RADEON_PP_CUBIC_OFFSET_T0_4 0x1de0 +#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00 +#define RADEON_PP_CUBIC_OFFSET_T1_1 0x1e04 +#define RADEON_PP_CUBIC_OFFSET_T1_2 0x1e08 +#define RADEON_PP_CUBIC_OFFSET_T1_3 0x1e0c +#define RADEON_PP_CUBIC_OFFSET_T1_4 0x1e10 +#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14 +#define RADEON_PP_CUBIC_OFFSET_T2_1 0x1e18 +#define RADEON_PP_CUBIC_OFFSET_T2_2 0x1e1c +#define RADEON_PP_CUBIC_OFFSET_T2_3 0x1e20 +#define RADEON_PP_CUBIC_OFFSET_T2_4 0x1e24 + +#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */ +#define RADEON_PP_TEX_SIZE_1 0x1d0c +#define RADEON_PP_TEX_SIZE_2 0x1d14 +# define RADEON_TEX_USIZE_MASK (0x7ff << 0) +# define RADEON_TEX_USIZE_SHIFT 0 +# define RADEON_TEX_VSIZE_MASK (0x7ff << 16) +# define RADEON_TEX_VSIZE_SHIFT 16 +# define RADEON_SIGNED_RGB_MASK (1 << 30) +# define RADEON_SIGNED_RGB_SHIFT 30 +# define RADEON_SIGNED_ALPHA_MASK (1 << 31) +# define RADEON_SIGNED_ALPHA_SHIFT 31 +#define RADEON_PP_TEX_PITCH_0 0x1d08 /* NPOT */ +#define RADEON_PP_TEX_PITCH_1 0x1d10 /* NPOT */ +#define RADEON_PP_TEX_PITCH_2 0x1d18 /* NPOT */ +/* note: bits 13-5: 32 byte aligned stride of texture map */ + +#define RADEON_PP_TXCBLEND_0 0x1c60 +#define RADEON_PP_TXCBLEND_1 0x1c78 +#define RADEON_PP_TXCBLEND_2 0x1c90 +# define RADEON_COLOR_ARG_A_SHIFT 0 +# define RADEON_COLOR_ARG_A_MASK (0x1f << 0) +# define RADEON_COLOR_ARG_A_ZERO (0 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_COLOR (2 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_ALPHA (3 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_COLOR (4 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_ALPHA (5 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_COLOR (6 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_ALPHA (7 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_COLOR (8 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_ALPHA (9 << 0) +# define RADEON_COLOR_ARG_A_T0_COLOR (10 << 0) +# define RADEON_COLOR_ARG_A_T0_ALPHA (11 << 0) +# define RADEON_COLOR_ARG_A_T1_COLOR (12 << 0) +# define RADEON_COLOR_ARG_A_T1_ALPHA (13 << 0) +# define RADEON_COLOR_ARG_A_T2_COLOR (14 << 0) +# define RADEON_COLOR_ARG_A_T2_ALPHA (15 << 0) +# define RADEON_COLOR_ARG_A_T3_COLOR (16 << 0) +# define RADEON_COLOR_ARG_A_T3_ALPHA (17 << 0) +# define RADEON_COLOR_ARG_B_SHIFT 5 +# define RADEON_COLOR_ARG_B_MASK (0x1f << 5) +# define RADEON_COLOR_ARG_B_ZERO (0 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_COLOR (2 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_ALPHA (3 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_COLOR (4 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_ALPHA (5 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_COLOR (6 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_ALPHA (7 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_COLOR (8 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_ALPHA (9 << 5) +# define RADEON_COLOR_ARG_B_T0_COLOR (10 << 5) +# define RADEON_COLOR_ARG_B_T0_ALPHA (11 << 5) +# define RADEON_COLOR_ARG_B_T1_COLOR (12 << 5) +# define RADEON_COLOR_ARG_B_T1_ALPHA (13 << 5) +# define RADEON_COLOR_ARG_B_T2_COLOR (14 << 5) +# define RADEON_COLOR_ARG_B_T2_ALPHA (15 << 5) +# define RADEON_COLOR_ARG_B_T3_COLOR (16 << 5) +# define RADEON_COLOR_ARG_B_T3_ALPHA (17 << 5) +# define RADEON_COLOR_ARG_C_SHIFT 10 +# define RADEON_COLOR_ARG_C_MASK (0x1f << 10) +# define RADEON_COLOR_ARG_C_ZERO (0 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_COLOR (2 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_ALPHA (3 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_COLOR (4 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_ALPHA (5 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_COLOR (6 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_ALPHA (7 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_COLOR (8 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_ALPHA (9 << 10) +# define RADEON_COLOR_ARG_C_T0_COLOR (10 << 10) +# define RADEON_COLOR_ARG_C_T0_ALPHA (11 << 10) +# define RADEON_COLOR_ARG_C_T1_COLOR (12 << 10) +# define RADEON_COLOR_ARG_C_T1_ALPHA (13 << 10) +# define RADEON_COLOR_ARG_C_T2_COLOR (14 << 10) +# define RADEON_COLOR_ARG_C_T2_ALPHA (15 << 10) +# define RADEON_COLOR_ARG_C_T3_COLOR (16 << 10) +# define RADEON_COLOR_ARG_C_T3_ALPHA (17 << 10) +# define RADEON_COMP_ARG_A (1 << 15) +# define RADEON_COMP_ARG_A_SHIFT 15 +# define RADEON_COMP_ARG_B (1 << 16) +# define RADEON_COMP_ARG_B_SHIFT 16 +# define RADEON_COMP_ARG_C (1 << 17) +# define RADEON_COMP_ARG_C_SHIFT 17 +# define RADEON_BLEND_CTL_MASK (7 << 18) +# define RADEON_BLEND_CTL_ADD (0 << 18) +# define RADEON_BLEND_CTL_SUBTRACT (1 << 18) +# define RADEON_BLEND_CTL_ADDSIGNED (2 << 18) +# define RADEON_BLEND_CTL_BLEND (3 << 18) +# define RADEON_BLEND_CTL_DOT3 (4 << 18) +# define RADEON_SCALE_SHIFT 21 +# define RADEON_SCALE_MASK (3 << 21) +# define RADEON_SCALE_1X (0 << 21) +# define RADEON_SCALE_2X (1 << 21) +# define RADEON_SCALE_4X (2 << 21) +# define RADEON_CLAMP_TX (1 << 23) +# define RADEON_T0_EQ_TCUR (1 << 24) +# define RADEON_T1_EQ_TCUR (1 << 25) +# define RADEON_T2_EQ_TCUR (1 << 26) +# define RADEON_T3_EQ_TCUR (1 << 27) +# define RADEON_COLOR_ARG_MASK 0x1f +# define RADEON_COMP_ARG_SHIFT 15 +#define RADEON_PP_TXABLEND_0 0x1c64 +#define RADEON_PP_TXABLEND_1 0x1c7c +#define RADEON_PP_TXABLEND_2 0x1c94 +# define RADEON_ALPHA_ARG_A_SHIFT 0 +# define RADEON_ALPHA_ARG_A_MASK (0xf << 0) +# define RADEON_ALPHA_ARG_A_ZERO (0 << 0) +# define RADEON_ALPHA_ARG_A_CURRENT_ALPHA (1 << 0) +# define RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA (2 << 0) +# define RADEON_ALPHA_ARG_A_SPECULAR_ALPHA (3 << 0) +# define RADEON_ALPHA_ARG_A_TFACTOR_ALPHA (4 << 0) +# define RADEON_ALPHA_ARG_A_T0_ALPHA (5 << 0) +# define RADEON_ALPHA_ARG_A_T1_ALPHA (6 << 0) +# define RADEON_ALPHA_ARG_A_T2_ALPHA (7 << 0) +# define RADEON_ALPHA_ARG_A_T3_ALPHA (8 << 0) +# define RADEON_ALPHA_ARG_B_SHIFT 4 +# define RADEON_ALPHA_ARG_B_MASK (0xf << 4) +# define RADEON_ALPHA_ARG_B_ZERO (0 << 4) +# define RADEON_ALPHA_ARG_B_CURRENT_ALPHA (1 << 4) +# define RADEON_ALPHA_ARG_B_DIFFUSE_ALPHA (2 << 4) +# define RADEON_ALPHA_ARG_B_SPECULAR_ALPHA (3 << 4) +# define RADEON_ALPHA_ARG_B_TFACTOR_ALPHA (4 << 4) +# define RADEON_ALPHA_ARG_B_T0_ALPHA (5 << 4) +# define RADEON_ALPHA_ARG_B_T1_ALPHA (6 << 4) +# define RADEON_ALPHA_ARG_B_T2_ALPHA (7 << 4) +# define RADEON_ALPHA_ARG_B_T3_ALPHA (8 << 4) +# define RADEON_ALPHA_ARG_C_SHIFT 8 +# define RADEON_ALPHA_ARG_C_MASK (0xf << 8) +# define RADEON_ALPHA_ARG_C_ZERO (0 << 8) +# define RADEON_ALPHA_ARG_C_CURRENT_ALPHA (1 << 8) +# define RADEON_ALPHA_ARG_C_DIFFUSE_ALPHA (2 << 8) +# define RADEON_ALPHA_ARG_C_SPECULAR_ALPHA (3 << 8) +# define RADEON_ALPHA_ARG_C_TFACTOR_ALPHA (4 << 8) +# define RADEON_ALPHA_ARG_C_T0_ALPHA (5 << 8) +# define RADEON_ALPHA_ARG_C_T1_ALPHA (6 << 8) +# define RADEON_ALPHA_ARG_C_T2_ALPHA (7 << 8) +# define RADEON_ALPHA_ARG_C_T3_ALPHA (8 << 8) +# define RADEON_DOT_ALPHA_DONT_REPLICATE (1 << 9) +# define RADEON_ALPHA_ARG_MASK 0xf + +#define RADEON_PP_TFACTOR_0 0x1c68 +#define RADEON_PP_TFACTOR_1 0x1c80 +#define RADEON_PP_TFACTOR_2 0x1c98 + +#define RADEON_RB3D_BLENDCNTL 0x1c20 +# define RADEON_COMB_FCN_MASK (3 << 12) +# define RADEON_COMB_FCN_ADD_CLAMP (0 << 12) +# define RADEON_COMB_FCN_ADD_NOCLAMP (1 << 12) +# define RADEON_COMB_FCN_SUB_CLAMP (2 << 12) +# define RADEON_COMB_FCN_SUB_NOCLAMP (3 << 12) +# define RADEON_SRC_BLEND_GL_ZERO (32 << 16) +# define RADEON_SRC_BLEND_GL_ONE (33 << 16) +# define RADEON_SRC_BLEND_GL_SRC_COLOR (34 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16) +# define RADEON_SRC_BLEND_GL_DST_COLOR (36 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA (38 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16) +# define RADEON_SRC_BLEND_GL_DST_ALPHA (40 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE (42 << 16) +# define RADEON_SRC_BLEND_MASK (63 << 16) +# define RADEON_DST_BLEND_GL_ZERO (32 << 24) +# define RADEON_DST_BLEND_GL_ONE (33 << 24) +# define RADEON_DST_BLEND_GL_SRC_COLOR (34 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24) +# define RADEON_DST_BLEND_GL_DST_COLOR (36 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24) +# define RADEON_DST_BLEND_GL_SRC_ALPHA (38 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24) +# define RADEON_DST_BLEND_GL_DST_ALPHA (40 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24) +# define RADEON_DST_BLEND_MASK (63 << 24) +#define RADEON_RB3D_CNTL 0x1c3c +# define RADEON_ALPHA_BLEND_ENABLE (1 << 0) +# define RADEON_PLANE_MASK_ENABLE (1 << 1) +# define RADEON_DITHER_ENABLE (1 << 2) +# define RADEON_ROUND_ENABLE (1 << 3) +# define RADEON_SCALE_DITHER_ENABLE (1 << 4) +# define RADEON_DITHER_INIT (1 << 5) +# define RADEON_ROP_ENABLE (1 << 6) +# define RADEON_STENCIL_ENABLE (1 << 7) +# define RADEON_Z_ENABLE (1 << 8) +# define RADEON_DEPTH_XZ_OFFEST_ENABLE (1 << 9) +# define RADEON_COLOR_FORMAT_ARGB1555 (3 << 10) +# define RADEON_COLOR_FORMAT_RGB565 (4 << 10) +# define RADEON_COLOR_FORMAT_ARGB8888 (6 << 10) +# define RADEON_COLOR_FORMAT_RGB332 (7 << 10) +# define RADEON_COLOR_FORMAT_Y8 (8 << 10) +# define RADEON_COLOR_FORMAT_RGB8 (9 << 10) +# define RADEON_COLOR_FORMAT_YUV422_VYUY (11 << 10) +# define RADEON_COLOR_FORMAT_YUV422_YVYU (12 << 10) +# define RADEON_COLOR_FORMAT_aYUV444 (14 << 10) +# define RADEON_COLOR_FORMAT_ARGB4444 (15 << 10) +# define RADEON_CLRCMP_FLIP_ENABLE (1 << 14) +#define RADEON_RB3D_COLOROFFSET 0x1c40 +# define RADEON_COLOROFFSET_MASK 0xfffffff0 +#define RADEON_RB3D_COLORPITCH 0x1c48 +# define RADEON_COLORPITCH_MASK 0x000001ff8 +# define RADEON_COLOR_TILE_ENABLE (1 << 16) +# define RADEON_COLOR_MICROTILE_ENABLE (1 << 17) +# define RADEON_COLOR_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_COLOR_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_COLOR_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_DEPTHOFFSET 0x1c24 +#define RADEON_RB3D_DEPTHPITCH 0x1c28 +# define RADEON_DEPTHPITCH_MASK 0x00001ff8 +# define RADEON_DEPTH_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_DEPTH_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_PLANEMASK 0x1d84 +#define RADEON_RB3D_ROPCNTL 0x1d80 +# define RADEON_ROP_MASK (15 << 8) +# define RADEON_ROP_CLEAR (0 << 8) +# define RADEON_ROP_NOR (1 << 8) +# define RADEON_ROP_AND_INVERTED (2 << 8) +# define RADEON_ROP_COPY_INVERTED (3 << 8) +# define RADEON_ROP_AND_REVERSE (4 << 8) +# define RADEON_ROP_INVERT (5 << 8) +# define RADEON_ROP_XOR (6 << 8) +# define RADEON_ROP_NAND (7 << 8) +# define RADEON_ROP_AND (8 << 8) +# define RADEON_ROP_EQUIV (9 << 8) +# define RADEON_ROP_NOOP (10 << 8) +# define RADEON_ROP_OR_INVERTED (11 << 8) +# define RADEON_ROP_COPY (12 << 8) +# define RADEON_ROP_OR_REVERSE (13 << 8) +# define RADEON_ROP_OR (14 << 8) +# define RADEON_ROP_SET (15 << 8) +#define RADEON_RB3D_STENCILREFMASK 0x1d7c +# define RADEON_STENCIL_REF_SHIFT 0 +# define RADEON_STENCIL_REF_MASK (0xff << 0) +# define RADEON_STENCIL_MASK_SHIFT 16 +# define RADEON_STENCIL_VALUE_MASK (0xff << 16) +# define RADEON_STENCIL_WRITEMASK_SHIFT 24 +# define RADEON_STENCIL_WRITE_MASK (0xff << 24) +#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c +# define RADEON_DEPTH_FORMAT_MASK (0xf << 0) +# define RADEON_DEPTH_FORMAT_16BIT_INT_Z (0 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_INT_Z (2 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_Z (3 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_INT_Z (4 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_Z (5 << 0) +# define RADEON_DEPTH_FORMAT_16BIT_FLOAT_W (7 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_W (9 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_W (11 << 0) +# define RADEON_Z_TEST_NEVER (0 << 4) +# define RADEON_Z_TEST_LESS (1 << 4) +# define RADEON_Z_TEST_LEQUAL (2 << 4) +# define RADEON_Z_TEST_EQUAL (3 << 4) +# define RADEON_Z_TEST_GEQUAL (4 << 4) +# define RADEON_Z_TEST_GREATER (5 << 4) +# define RADEON_Z_TEST_NEQUAL (6 << 4) +# define RADEON_Z_TEST_ALWAYS (7 << 4) +# define RADEON_Z_TEST_MASK (7 << 4) +# define RADEON_STENCIL_TEST_NEVER (0 << 12) +# define RADEON_STENCIL_TEST_LESS (1 << 12) +# define RADEON_STENCIL_TEST_LEQUAL (2 << 12) +# define RADEON_STENCIL_TEST_EQUAL (3 << 12) +# define RADEON_STENCIL_TEST_GEQUAL (4 << 12) +# define RADEON_STENCIL_TEST_GREATER (5 << 12) +# define RADEON_STENCIL_TEST_NEQUAL (6 << 12) +# define RADEON_STENCIL_TEST_ALWAYS (7 << 12) +# define RADEON_STENCIL_TEST_MASK (0x7 << 12) +# define RADEON_STENCIL_FAIL_KEEP (0 << 16) +# define RADEON_STENCIL_FAIL_ZERO (1 << 16) +# define RADEON_STENCIL_FAIL_REPLACE (2 << 16) +# define RADEON_STENCIL_FAIL_INC (3 << 16) +# define RADEON_STENCIL_FAIL_DEC (4 << 16) +# define RADEON_STENCIL_FAIL_INVERT (5 << 16) +# define RADEON_STENCIL_FAIL_MASK (0x7 << 16) +# define RADEON_STENCIL_ZPASS_KEEP (0 << 20) +# define RADEON_STENCIL_ZPASS_ZERO (1 << 20) +# define RADEON_STENCIL_ZPASS_REPLACE (2 << 20) +# define RADEON_STENCIL_ZPASS_INC (3 << 20) +# define RADEON_STENCIL_ZPASS_DEC (4 << 20) +# define RADEON_STENCIL_ZPASS_INVERT (5 << 20) +# define RADEON_STENCIL_ZPASS_MASK (0x7 << 20) +# define RADEON_STENCIL_ZFAIL_KEEP (0 << 24) +# define RADEON_STENCIL_ZFAIL_ZERO (1 << 24) +# define RADEON_STENCIL_ZFAIL_REPLACE (2 << 24) +# define RADEON_STENCIL_ZFAIL_INC (3 << 24) +# define RADEON_STENCIL_ZFAIL_DEC (4 << 24) +# define RADEON_STENCIL_ZFAIL_INVERT (5 << 24) +# define RADEON_STENCIL_ZFAIL_MASK (0x7 << 24) +# define RADEON_Z_COMPRESSION_ENABLE (1 << 28) +# define RADEON_FORCE_Z_DIRTY (1 << 29) +# define RADEON_Z_WRITE_ENABLE (1 << 30) +#define RADEON_RE_LINE_PATTERN 0x1cd0 +# define RADEON_LINE_PATTERN_MASK 0x0000ffff +# define RADEON_LINE_REPEAT_COUNT_SHIFT 16 +# define RADEON_LINE_PATTERN_START_SHIFT 24 +# define RADEON_LINE_PATTERN_LITTLE_BIT_ORDER (0 << 28) +# define RADEON_LINE_PATTERN_BIG_BIT_ORDER (1 << 28) +# define RADEON_LINE_PATTERN_AUTO_RESET (1 << 29) +#define RADEON_RE_LINE_STATE 0x1cd4 +# define RADEON_LINE_CURRENT_PTR_SHIFT 0 +# define RADEON_LINE_CURRENT_COUNT_SHIFT 8 +#define RADEON_RE_MISC 0x26c4 +# define RADEON_STIPPLE_COORD_MASK 0x1f +# define RADEON_STIPPLE_X_OFFSET_SHIFT 0 +# define RADEON_STIPPLE_X_OFFSET_MASK (0x1f << 0) +# define RADEON_STIPPLE_Y_OFFSET_SHIFT 8 +# define RADEON_STIPPLE_Y_OFFSET_MASK (0x1f << 8) +# define RADEON_STIPPLE_LITTLE_BIT_ORDER (0 << 16) +# define RADEON_STIPPLE_BIG_BIT_ORDER (1 << 16) +#define RADEON_RE_SOLID_COLOR 0x1c1c +#define RADEON_RE_TOP_LEFT 0x26c0 +# define RADEON_RE_LEFT_SHIFT 0 +# define RADEON_RE_TOP_SHIFT 16 +#define RADEON_RE_WIDTH_HEIGHT 0x1c44 +# define RADEON_RE_WIDTH_SHIFT 0 +# define RADEON_RE_HEIGHT_SHIFT 16 + +#define RADEON_SE_CNTL 0x1c4c +# define RADEON_FFACE_CULL_CW (0 << 0) +# define RADEON_FFACE_CULL_CCW (1 << 0) +# define RADEON_FFACE_CULL_DIR_MASK (1 << 0) +# define RADEON_BFACE_CULL (0 << 1) +# define RADEON_BFACE_SOLID (3 << 1) +# define RADEON_FFACE_CULL (0 << 3) +# define RADEON_FFACE_SOLID (3 << 3) +# define RADEON_FFACE_CULL_MASK (3 << 3) +# define RADEON_BADVTX_CULL_DISABLE (1 << 5) +# define RADEON_FLAT_SHADE_VTX_0 (0 << 6) +# define RADEON_FLAT_SHADE_VTX_1 (1 << 6) +# define RADEON_FLAT_SHADE_VTX_2 (2 << 6) +# define RADEON_FLAT_SHADE_VTX_LAST (3 << 6) +# define RADEON_DIFFUSE_SHADE_SOLID (0 << 8) +# define RADEON_DIFFUSE_SHADE_FLAT (1 << 8) +# define RADEON_DIFFUSE_SHADE_GOURAUD (2 << 8) +# define RADEON_DIFFUSE_SHADE_MASK (3 << 8) +# define RADEON_ALPHA_SHADE_SOLID (0 << 10) +# define RADEON_ALPHA_SHADE_FLAT (1 << 10) +# define RADEON_ALPHA_SHADE_GOURAUD (2 << 10) +# define RADEON_ALPHA_SHADE_MASK (3 << 10) +# define RADEON_SPECULAR_SHADE_SOLID (0 << 12) +# define RADEON_SPECULAR_SHADE_FLAT (1 << 12) +# define RADEON_SPECULAR_SHADE_GOURAUD (2 << 12) +# define RADEON_SPECULAR_SHADE_MASK (3 << 12) +# define RADEON_FOG_SHADE_SOLID (0 << 14) +# define RADEON_FOG_SHADE_FLAT (1 << 14) +# define RADEON_FOG_SHADE_GOURAUD (2 << 14) +# define RADEON_FOG_SHADE_MASK (3 << 14) +# define RADEON_ZBIAS_ENABLE_POINT (1 << 16) +# define RADEON_ZBIAS_ENABLE_LINE (1 << 17) +# define RADEON_ZBIAS_ENABLE_TRI (1 << 18) +# define RADEON_WIDELINE_ENABLE (1 << 20) +# define RADEON_VPORT_XY_XFORM_ENABLE (1 << 24) +# define RADEON_VPORT_Z_XFORM_ENABLE (1 << 25) +# define RADEON_VTX_PIX_CENTER_D3D (0 << 27) +# define RADEON_VTX_PIX_CENTER_OGL (1 << 27) +# define RADEON_ROUND_MODE_TRUNC (0 << 28) +# define RADEON_ROUND_MODE_ROUND (1 << 28) +# define RADEON_ROUND_MODE_ROUND_EVEN (2 << 28) +# define RADEON_ROUND_MODE_ROUND_ODD (3 << 28) +# define RADEON_ROUND_PREC_16TH_PIX (0 << 30) +# define RADEON_ROUND_PREC_8TH_PIX (1 << 30) +# define RADEON_ROUND_PREC_4TH_PIX (2 << 30) +# define RADEON_ROUND_PREC_HALF_PIX (3 << 30) +#define RADEON_SE_CNTL_STATUS 0x2140 +# define RADEON_VC_NO_SWAP (0 << 0) +# define RADEON_VC_16BIT_SWAP (1 << 0) +# define RADEON_VC_32BIT_SWAP (2 << 0) +# define RADEON_VC_HALF_DWORD_SWAP (3 << 0) +# define RADEON_TCL_BYPASS (1 << 8) +#define RADEON_SE_COORD_FMT 0x1c50 +# define RADEON_VTX_XY_PRE_MULT_1_OVER_W0 (1 << 0) +# define RADEON_VTX_Z_PRE_MULT_1_OVER_W0 (1 << 1) +# define RADEON_VTX_ST0_NONPARAMETRIC (1 << 8) +# define RADEON_VTX_ST1_NONPARAMETRIC (1 << 9) +# define RADEON_VTX_ST2_NONPARAMETRIC (1 << 10) +# define RADEON_VTX_ST3_NONPARAMETRIC (1 << 11) +# define RADEON_VTX_W0_NORMALIZE (1 << 12) +# define RADEON_VTX_W0_IS_NOT_1_OVER_W0 (1 << 16) +# define RADEON_VTX_ST0_PRE_MULT_1_OVER_W0 (1 << 17) +# define RADEON_VTX_ST1_PRE_MULT_1_OVER_W0 (1 << 19) +# define RADEON_VTX_ST2_PRE_MULT_1_OVER_W0 (1 << 21) +# define RADEON_VTX_ST3_PRE_MULT_1_OVER_W0 (1 << 23) +# define RADEON_TEX1_W_ROUTING_USE_W0 (0 << 26) +# define RADEON_TEX1_W_ROUTING_USE_Q1 (1 << 26) +#define RADEON_SE_LINE_WIDTH 0x1db8 +#define RADEON_SE_TCL_LIGHT_MODEL_CTL 0x226c +# define RADEON_LIGHTING_ENABLE (1 << 0) +# define RADEON_LIGHT_IN_MODELSPACE (1 << 1) +# define RADEON_LOCAL_VIEWER (1 << 2) +# define RADEON_NORMALIZE_NORMALS (1 << 3) +# define RADEON_RESCALE_NORMALS (1 << 4) +# define RADEON_SPECULAR_LIGHTS (1 << 5) +# define RADEON_DIFFUSE_SPECULAR_COMBINE (1 << 6) +# define RADEON_LIGHT_ALPHA (1 << 7) +# define RADEON_LOCAL_LIGHT_VEC_GL (1 << 8) +# define RADEON_LIGHT_NO_NORMAL_AMBIENT_ONLY (1 << 9) +# define RADEON_LM_SOURCE_STATE_PREMULT 0 +# define RADEON_LM_SOURCE_STATE_MULT 1 +# define RADEON_LM_SOURCE_VERTEX_DIFFUSE 2 +# define RADEON_LM_SOURCE_VERTEX_SPECULAR 3 +# define RADEON_EMISSIVE_SOURCE_SHIFT 16 +# define RADEON_AMBIENT_SOURCE_SHIFT 18 +# define RADEON_DIFFUSE_SOURCE_SHIFT 20 +# define RADEON_SPECULAR_SOURCE_SHIFT 22 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_RED 0x2220 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_GREEN 0x2224 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_BLUE 0x2228 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_ALPHA 0x222c +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_RED 0x2230 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_GREEN 0x2234 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_BLUE 0x2238 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_ALPHA 0x223c +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED 0x2210 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_GREEN 0x2214 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_BLUE 0x2218 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_ALPHA 0x221c +#define RADEON_SE_TCL_MATERIAL_SPECULAR_RED 0x2240 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_GREEN 0x2244 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_BLUE 0x2248 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_ALPHA 0x224c +#define RADEON_SE_TCL_MATRIX_SELECT_0 0x225c +# define RADEON_MODELVIEW_0_SHIFT 0 +# define RADEON_MODELVIEW_1_SHIFT 4 +# define RADEON_MODELVIEW_2_SHIFT 8 +# define RADEON_MODELVIEW_3_SHIFT 12 +# define RADEON_IT_MODELVIEW_0_SHIFT 16 +# define RADEON_IT_MODELVIEW_1_SHIFT 20 +# define RADEON_IT_MODELVIEW_2_SHIFT 24 +# define RADEON_IT_MODELVIEW_3_SHIFT 28 +#define RADEON_SE_TCL_MATRIX_SELECT_1 0x2260 +# define RADEON_MODELPROJECT_0_SHIFT 0 +# define RADEON_MODELPROJECT_1_SHIFT 4 +# define RADEON_MODELPROJECT_2_SHIFT 8 +# define RADEON_MODELPROJECT_3_SHIFT 12 +# define RADEON_TEXMAT_0_SHIFT 16 +# define RADEON_TEXMAT_1_SHIFT 20 +# define RADEON_TEXMAT_2_SHIFT 24 +# define RADEON_TEXMAT_3_SHIFT 28 + + +#define RADEON_SE_TCL_OUTPUT_VTX_FMT 0x2254 +# define RADEON_TCL_VTX_W0 (1 << 0) +# define RADEON_TCL_VTX_FP_DIFFUSE (1 << 1) +# define RADEON_TCL_VTX_FP_ALPHA (1 << 2) +# define RADEON_TCL_VTX_PK_DIFFUSE (1 << 3) +# define RADEON_TCL_VTX_FP_SPEC (1 << 4) +# define RADEON_TCL_VTX_FP_FOG (1 << 5) +# define RADEON_TCL_VTX_PK_SPEC (1 << 6) +# define RADEON_TCL_VTX_ST0 (1 << 7) +# define RADEON_TCL_VTX_ST1 (1 << 8) +# define RADEON_TCL_VTX_Q1 (1 << 9) +# define RADEON_TCL_VTX_ST2 (1 << 10) +# define RADEON_TCL_VTX_Q2 (1 << 11) +# define RADEON_TCL_VTX_ST3 (1 << 12) +# define RADEON_TCL_VTX_Q3 (1 << 13) +# define RADEON_TCL_VTX_Q0 (1 << 14) +# define RADEON_TCL_VTX_WEIGHT_COUNT_SHIFT 15 +# define RADEON_TCL_VTX_NORM0 (1 << 18) +# define RADEON_TCL_VTX_XY1 (1 << 27) +# define RADEON_TCL_VTX_Z1 (1 << 28) +# define RADEON_TCL_VTX_W1 (1 << 29) +# define RADEON_TCL_VTX_NORM1 (1 << 30) +# define RADEON_TCL_VTX_Z0 (1 << 31) + +#define RADEON_SE_TCL_OUTPUT_VTX_SEL 0x2258 +# define RADEON_TCL_COMPUTE_XYZW (1 << 0) +# define RADEON_TCL_COMPUTE_DIFFUSE (1 << 1) +# define RADEON_TCL_COMPUTE_SPECULAR (1 << 2) +# define RADEON_TCL_FORCE_NAN_IF_COLOR_NAN (1 << 3) +# define RADEON_TCL_FORCE_INORDER_PROC (1 << 4) +# define RADEON_TCL_TEX_INPUT_TEX_0 0 +# define RADEON_TCL_TEX_INPUT_TEX_1 1 +# define RADEON_TCL_TEX_INPUT_TEX_2 2 +# define RADEON_TCL_TEX_INPUT_TEX_3 3 +# define RADEON_TCL_TEX_COMPUTED_TEX_0 8 +# define RADEON_TCL_TEX_COMPUTED_TEX_1 9 +# define RADEON_TCL_TEX_COMPUTED_TEX_2 10 +# define RADEON_TCL_TEX_COMPUTED_TEX_3 11 +# define RADEON_TCL_TEX_0_OUTPUT_SHIFT 16 +# define RADEON_TCL_TEX_1_OUTPUT_SHIFT 20 +# define RADEON_TCL_TEX_2_OUTPUT_SHIFT 24 +# define RADEON_TCL_TEX_3_OUTPUT_SHIFT 28 + +#define RADEON_SE_TCL_PER_LIGHT_CTL_0 0x2270 +# define RADEON_LIGHT_0_ENABLE (1 << 0) +# define RADEON_LIGHT_0_ENABLE_AMBIENT (1 << 1) +# define RADEON_LIGHT_0_ENABLE_SPECULAR (1 << 2) +# define RADEON_LIGHT_0_IS_LOCAL (1 << 3) +# define RADEON_LIGHT_0_IS_SPOT (1 << 4) +# define RADEON_LIGHT_0_DUAL_CONE (1 << 5) +# define RADEON_LIGHT_0_ENABLE_RANGE_ATTEN (1 << 6) +# define RADEON_LIGHT_0_CONSTANT_RANGE_ATTEN (1 << 7) +# define RADEON_LIGHT_0_SHIFT 0 +# define RADEON_LIGHT_1_ENABLE (1 << 16) +# define RADEON_LIGHT_1_ENABLE_AMBIENT (1 << 17) +# define RADEON_LIGHT_1_ENABLE_SPECULAR (1 << 18) +# define RADEON_LIGHT_1_IS_LOCAL (1 << 19) +# define RADEON_LIGHT_1_IS_SPOT (1 << 20) +# define RADEON_LIGHT_1_DUAL_CONE (1 << 21) +# define RADEON_LIGHT_1_ENABLE_RANGE_ATTEN (1 << 22) +# define RADEON_LIGHT_1_CONSTANT_RANGE_ATTEN (1 << 23) +# define RADEON_LIGHT_1_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_1 0x2274 +# define RADEON_LIGHT_2_SHIFT 0 +# define RADEON_LIGHT_3_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_2 0x2278 +# define RADEON_LIGHT_4_SHIFT 0 +# define RADEON_LIGHT_5_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_3 0x227c +# define RADEON_LIGHT_6_SHIFT 0 +# define RADEON_LIGHT_7_SHIFT 16 + +#define RADEON_SE_TCL_SHININESS 0x2250 + +#define RADEON_SE_TCL_TEXTURE_PROC_CTL 0x2268 +# define RADEON_TEXGEN_TEXMAT_0_ENABLE (1 << 0) +# define RADEON_TEXGEN_TEXMAT_1_ENABLE (1 << 1) +# define RADEON_TEXGEN_TEXMAT_2_ENABLE (1 << 2) +# define RADEON_TEXGEN_TEXMAT_3_ENABLE (1 << 3) +# define RADEON_TEXMAT_0_ENABLE (1 << 4) +# define RADEON_TEXMAT_1_ENABLE (1 << 5) +# define RADEON_TEXMAT_2_ENABLE (1 << 6) +# define RADEON_TEXMAT_3_ENABLE (1 << 7) +# define RADEON_TEXGEN_INPUT_MASK 0xf +# define RADEON_TEXGEN_INPUT_TEXCOORD_0 0 +# define RADEON_TEXGEN_INPUT_TEXCOORD_1 1 +# define RADEON_TEXGEN_INPUT_TEXCOORD_2 2 +# define RADEON_TEXGEN_INPUT_TEXCOORD_3 3 +# define RADEON_TEXGEN_INPUT_OBJ 4 +# define RADEON_TEXGEN_INPUT_EYE 5 +# define RADEON_TEXGEN_INPUT_EYE_NORMAL 6 +# define RADEON_TEXGEN_INPUT_EYE_REFLECT 7 +# define RADEON_TEXGEN_INPUT_EYE_NORMALIZED 8 +# define RADEON_TEXGEN_0_INPUT_SHIFT 16 +# define RADEON_TEXGEN_1_INPUT_SHIFT 20 +# define RADEON_TEXGEN_2_INPUT_SHIFT 24 +# define RADEON_TEXGEN_3_INPUT_SHIFT 28 + +#define RADEON_SE_TCL_UCP_VERT_BLEND_CTL 0x2264 +# define RADEON_UCP_IN_CLIP_SPACE (1 << 0) +# define RADEON_UCP_IN_MODEL_SPACE (1 << 1) +# define RADEON_UCP_ENABLE_0 (1 << 2) +# define RADEON_UCP_ENABLE_1 (1 << 3) +# define RADEON_UCP_ENABLE_2 (1 << 4) +# define RADEON_UCP_ENABLE_3 (1 << 5) +# define RADEON_UCP_ENABLE_4 (1 << 6) +# define RADEON_UCP_ENABLE_5 (1 << 7) +# define RADEON_TCL_FOG_MASK (3 << 8) +# define RADEON_TCL_FOG_DISABLE (0 << 8) +# define RADEON_TCL_FOG_EXP (1 << 8) +# define RADEON_TCL_FOG_EXP2 (2 << 8) +# define RADEON_TCL_FOG_LINEAR (3 << 8) +# define RADEON_RNG_BASED_FOG (1 << 10) +# define RADEON_LIGHT_TWOSIDE (1 << 11) +# define RADEON_BLEND_OP_COUNT_MASK (7 << 12) +# define RADEON_BLEND_OP_COUNT_SHIFT 12 +# define RADEON_POSITION_BLEND_OP_ENABLE (1 << 16) +# define RADEON_NORMAL_BLEND_OP_ENABLE (1 << 17) +# define RADEON_VERTEX_BLEND_SRC_0_PRIMARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_0_SECONDARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_1_PRIMARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_1_SECONDARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_2_PRIMARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_2_SECONDARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_3_PRIMARY (1 << 21) +# define RADEON_VERTEX_BLEND_SRC_3_SECONDARY (1 << 21) +# define RADEON_VERTEX_BLEND_WGT_MINUS_ONE (1 << 22) +# define RADEON_CULL_FRONT_IS_CW (0 << 28) +# define RADEON_CULL_FRONT_IS_CCW (1 << 28) +# define RADEON_CULL_FRONT (1 << 29) +# define RADEON_CULL_BACK (1 << 30) +# define RADEON_FORCE_W_TO_ONE (1 << 31) + +#define RADEON_SE_VPORT_XSCALE 0x1d98 +#define RADEON_SE_VPORT_XOFFSET 0x1d9c +#define RADEON_SE_VPORT_YSCALE 0x1da0 +#define RADEON_SE_VPORT_YOFFSET 0x1da4 +#define RADEON_SE_VPORT_ZSCALE 0x1da8 +#define RADEON_SE_VPORT_ZOFFSET 0x1dac +#define RADEON_SE_ZBIAS_FACTOR 0x1db0 +#define RADEON_SE_ZBIAS_CONSTANT 0x1db4 + + + + /* Registers for CP and Microcode Engine */ +#define RADEON_CP_ME_RAM_ADDR 0x07d4 +#define RADEON_CP_ME_RAM_RADDR 0x07d8 +#define RADEON_CP_ME_RAM_DATAH 0x07dc +#define RADEON_CP_ME_RAM_DATAL 0x07e0 + +#define RADEON_CP_RB_BASE 0x0700 +#define RADEON_CP_RB_CNTL 0x0704 +#define RADEON_CP_RB_RPTR_ADDR 0x070c +#define RADEON_CP_RB_RPTR 0x0710 +#define RADEON_CP_RB_WPTR 0x0714 + +#define RADEON_CP_IB_BASE 0x0738 +#define RADEON_CP_IB_BUFSZ 0x073c + +#define RADEON_CP_CSQ_CNTL 0x0740 +# define RADEON_CSQ_CNT_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_PRIDIS_INDDIS (0 << 28) +# define RADEON_CSQ_PRIPIO_INDDIS (1 << 28) +# define RADEON_CSQ_PRIBM_INDDIS (2 << 28) +# define RADEON_CSQ_PRIPIO_INDBM (3 << 28) +# define RADEON_CSQ_PRIBM_INDBM (4 << 28) +# define RADEON_CSQ_PRIPIO_INDPIO (15 << 28) +#define RADEON_CP_CSQ_STAT 0x07f8 +# define RADEON_CSQ_RPTR_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_WPTR_PRIMARY_MASK (0xff << 8) +# define RADEON_CSQ_RPTR_INDIRECT_MASK (0xff << 16) +# define RADEON_CSQ_WPTR_INDIRECT_MASK (0xff << 24) +#define RADEON_CP_CSQ_ADDR 0x07f0 +#define RADEON_CP_CSQ_DATA 0x07f4 +#define RADEON_CP_CSQ_APER_PRIMARY 0x1000 +#define RADEON_CP_CSQ_APER_INDIRECT 0x1300 + +#define RADEON_CP_RB_WPTR_DELAY 0x0718 +# define RADEON_PRE_WRITE_TIMER_SHIFT 0 +# define RADEON_PRE_WRITE_LIMIT_SHIFT 23 + +#define RADEON_AIC_CNTL 0x01d0 +# define RADEON_PCIGART_TRANSLATE_EN (1 << 0) +#define RADEON_AIC_LO_ADDR 0x01dc + + + + /* Constants */ +#define RADEON_LAST_FRAME_REG RADEON_GUI_SCRATCH_REG0 +#define RADEON_LAST_CLEAR_REG RADEON_GUI_SCRATCH_REG2 + + + + /* CP packet types */ +#define RADEON_CP_PACKET0 0x00000000 +#define RADEON_CP_PACKET1 0x40000000 +#define RADEON_CP_PACKET2 0x80000000 +#define RADEON_CP_PACKET3 0xC0000000 +# define RADEON_CP_PACKET_MASK 0xC0000000 +# define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000 +# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12) +# define RADEON_CP_PACKET0_REG_MASK 0x000007ff +# define RADEON_CP_PACKET1_REG0_MASK 0x000007ff +# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 + +#define RADEON_CP_PACKET0_ONE_REG_WR 0x00008000 + +#define RADEON_CP_PACKET3_NOP 0xC0001000 +#define RADEON_CP_PACKET3_NEXT_CHAR 0xC0001900 +#define RADEON_CP_PACKET3_PLY_NEXTSCAN 0xC0001D00 +#define RADEON_CP_PACKET3_SET_SCISSORS 0xC0001E00 +#define RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300 +#define RADEON_CP_PACKET3_LOAD_MICROCODE 0xC0002400 +#define RADEON_CP_PACKET3_WAIT_FOR_IDLE 0xC0002600 +#define RADEON_CP_PACKET3_3D_DRAW_VBUF 0xC0002800 +#define RADEON_CP_PACKET3_3D_DRAW_IMMD 0xC0002900 +#define RADEON_CP_PACKET3_3D_DRAW_INDX 0xC0002A00 +#define RADEON_CP_PACKET3_LOAD_PALETTE 0xC0002C00 +#define RADEON_CP_PACKET3_3D_LOAD_VBPNTR 0xC0002F00 +#define RADEON_CP_PACKET3_CNTL_PAINT 0xC0009100 +#define RADEON_CP_PACKET3_CNTL_BITBLT 0xC0009200 +#define RADEON_CP_PACKET3_CNTL_SMALLTEXT 0xC0009300 +#define RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400 +#define RADEON_CP_PACKET3_CNTL_POLYLINE 0xC0009500 +#define RADEON_CP_PACKET3_CNTL_POLYSCANLINES 0xC0009800 +#define RADEON_CP_PACKET3_CNTL_PAINT_MULTI 0xC0009A00 +#define RADEON_CP_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +#define RADEON_CP_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00 + + +#define RADEON_CP_VC_FRMT_XY 0x00000000 +#define RADEON_CP_VC_FRMT_W0 0x00000001 +#define RADEON_CP_VC_FRMT_FPCOLOR 0x00000002 +#define RADEON_CP_VC_FRMT_FPALPHA 0x00000004 +#define RADEON_CP_VC_FRMT_PKCOLOR 0x00000008 +#define RADEON_CP_VC_FRMT_FPSPEC 0x00000010 +#define RADEON_CP_VC_FRMT_FPFOG 0x00000020 +#define RADEON_CP_VC_FRMT_PKSPEC 0x00000040 +#define RADEON_CP_VC_FRMT_ST0 0x00000080 +#define RADEON_CP_VC_FRMT_ST1 0x00000100 +#define RADEON_CP_VC_FRMT_Q1 0x00000200 +#define RADEON_CP_VC_FRMT_ST2 0x00000400 +#define RADEON_CP_VC_FRMT_Q2 0x00000800 +#define RADEON_CP_VC_FRMT_ST3 0x00001000 +#define RADEON_CP_VC_FRMT_Q3 0x00002000 +#define RADEON_CP_VC_FRMT_Q0 0x00004000 +#define RADEON_CP_VC_FRMT_BLND_WEIGHT_CNT_MASK 0x00038000 +#define RADEON_CP_VC_FRMT_N0 0x00040000 +#define RADEON_CP_VC_FRMT_XY1 0x08000000 +#define RADEON_CP_VC_FRMT_Z1 0x10000000 +#define RADEON_CP_VC_FRMT_W1 0x20000000 +#define RADEON_CP_VC_FRMT_N1 0x40000000 +#define RADEON_CP_VC_FRMT_Z 0x80000000 + +#define RADEON_CP_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP 0x00000003 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_TYPE_2 0x00000007 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST 0x00000008 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_POINT_LIST 0x00000009 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST 0x0000000a +#define RADEON_CP_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define RADEON_CP_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define RADEON_CP_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_BGRA 0x00000000 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA 0x00000040 +#define RADEON_CP_VC_CNTL_MAOS_ENABLE 0x00000080 +#define RADEON_CP_VC_CNTL_VTX_FMT_NON_RADEON_MODE 0x00000000 +#define RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE 0x00000100 +#define RADEON_CP_VC_CNTL_TCL_DISABLE 0x00000000 +#define RADEON_CP_VC_CNTL_TCL_ENABLE 0x00000200 +#define RADEON_CP_VC_CNTL_NUM_SHIFT 16 + +#define RADEON_VS_MATRIX_0_ADDR 0 +#define RADEON_VS_MATRIX_1_ADDR 4 +#define RADEON_VS_MATRIX_2_ADDR 8 +#define RADEON_VS_MATRIX_3_ADDR 12 +#define RADEON_VS_MATRIX_4_ADDR 16 +#define RADEON_VS_MATRIX_5_ADDR 20 +#define RADEON_VS_MATRIX_6_ADDR 24 +#define RADEON_VS_MATRIX_7_ADDR 28 +#define RADEON_VS_MATRIX_8_ADDR 32 +#define RADEON_VS_MATRIX_9_ADDR 36 +#define RADEON_VS_MATRIX_10_ADDR 40 +#define RADEON_VS_MATRIX_11_ADDR 44 +#define RADEON_VS_MATRIX_12_ADDR 48 +#define RADEON_VS_MATRIX_13_ADDR 52 +#define RADEON_VS_MATRIX_14_ADDR 56 +#define RADEON_VS_MATRIX_15_ADDR 60 +#define RADEON_VS_LIGHT_AMBIENT_ADDR 64 +#define RADEON_VS_LIGHT_DIFFUSE_ADDR 72 +#define RADEON_VS_LIGHT_SPECULAR_ADDR 80 +#define RADEON_VS_LIGHT_DIRPOS_ADDR 88 +#define RADEON_VS_LIGHT_HWVSPOT_ADDR 96 +#define RADEON_VS_LIGHT_ATTENUATION_ADDR 104 +#define RADEON_VS_MATRIX_EYE2CLIP_ADDR 112 +#define RADEON_VS_UCP_ADDR 116 +#define RADEON_VS_GLOBAL_AMBIENT_ADDR 122 +#define RADEON_VS_FOG_PARAM_ADDR 123 +#define RADEON_VS_EYE_VECTOR_ADDR 124 + +#define RADEON_SS_LIGHT_DCD_ADDR 0 +#define RADEON_SS_LIGHT_SPOT_EXPONENT_ADDR 8 +#define RADEON_SS_LIGHT_SPOT_CUTOFF_ADDR 16 +#define RADEON_SS_LIGHT_SPECULAR_THRESH_ADDR 24 +#define RADEON_SS_LIGHT_RANGE_CUTOFF_ADDR 32 +#define RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR 48 +#define RADEON_SS_VERT_GUARD_DISCARD_ADJ_ADDR 49 +#define RADEON_SS_HORZ_GUARD_CLIP_ADJ_ADDR 50 +#define RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR 51 +#define RADEON_SS_SHININESS 60 + +#define RADEON_TV_MASTER_CNTL 0x0800 +# define RADEON_TVCLK_ALWAYS_ONb (1 << 30) +#define RADEON_TV_DAC_CNTL 0x088c +# define RADEON_TV_DAC_CMPOUT (1 << 5) +#define RADEON_TV_PRE_DAC_MUX_CNTL 0x0888 +# define RADEON_Y_RED_EN (1 << 0) +# define RADEON_C_GRN_EN (1 << 1) +# define RADEON_CMP_BLU_EN (1 << 2) +# define RADEON_RED_MX_FORCE_DAC_DATA (6 << 4) +# define RADEON_GRN_MX_FORCE_DAC_DATA (6 << 8) +# define RADEON_BLU_MX_FORCE_DAC_DATA (6 << 12) +# define RADEON_TV_FORCE_DAC_DATA_SHIFT 16 +#endif diff --git a/src/radeon_render.c b/src/radeon_render.c new file mode 100644 index 0000000..f4cad67 --- /dev/null +++ b/src/radeon_render.c @@ -0,0 +1,1074 @@ + +#include "dixstruct.h" + +#include "xaa.h" +#include "xaalocal.h" + +#ifndef RENDER_GENERIC_HELPER +#define RENDER_GENERIC_HELPER + +static void RadeonInit3DEngineMMIO(ScrnInfoPtr pScrn); +#ifdef XF86DRI +static void RadeonInit3DEngineCP(ScrnInfoPtr pScrn); +#endif + +struct blendinfo { + Bool dst_alpha; + Bool src_alpha; + CARD32 blend_cntl; +}; + +/* The first part of blend_cntl corresponds to Fa from the render "protocol" + * document, and the second part to Fb. + */ +static const struct blendinfo RadeonBlendOp[] = { + /* Clear */ + {0, 0, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_ZERO}, + /* Src */ + {0, 0, RADEON_SRC_BLEND_GL_ONE | + RADEON_DST_BLEND_GL_ZERO}, + /* Dst */ + {0, 0, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_ONE}, + /* Over */ + {0, 1, RADEON_SRC_BLEND_GL_ONE | + RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA}, + /* OverReverse */ + {1, 0, RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | + RADEON_DST_BLEND_GL_ONE}, + /* In */ + {1, 0, RADEON_SRC_BLEND_GL_DST_ALPHA | + RADEON_DST_BLEND_GL_ZERO}, + /* InReverse */ + {0, 1, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_SRC_ALPHA}, + /* Out */ + {1, 0, RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | + RADEON_DST_BLEND_GL_ZERO}, + /* OutReverse */ + {0, 1, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA}, + /* Atop */ + {1, 1, RADEON_SRC_BLEND_GL_DST_ALPHA | + RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA}, + /* AtopReverse */ + {1, 1, RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | + RADEON_DST_BLEND_GL_SRC_ALPHA}, + /* Xor */ + {1, 1, RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | + RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA}, + /* Add */ + {0, 0, RADEON_SRC_BLEND_GL_ONE | + RADEON_DST_BLEND_GL_ONE}, + /* Saturate */ + {1, 1, RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE | + RADEON_DST_BLEND_GL_ONE}, + {0, 0, 0}, + {0, 0, 0}, + /* DisjointClear */ + {0, 0, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_ZERO}, + /* DisjointSrc */ + {0, 0, RADEON_SRC_BLEND_GL_ONE | + RADEON_DST_BLEND_GL_ZERO}, + /* DisjointDst */ + {0, 0, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_ONE}, + /* DisjointOver unsupported */ + {0, 0, 0}, + /* DisjointOverReverse */ + {1, 1, RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE | + RADEON_DST_BLEND_GL_ONE}, + /* DisjointIn unsupported */ + {0, 0, 0}, + /* DisjointInReverse unsupported */ + {0, 0, 0}, + /* DisjointOut unsupported */ + {1, 1, RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE | + RADEON_DST_BLEND_GL_ZERO}, + /* DisjointOutReverse unsupported */ + {0, 0, 0}, + /* DisjointAtop unsupported */ + {0, 0, 0}, + /* DisjointAtopReverse unsupported */ + {0, 0, 0}, + /* DisjointXor unsupported */ + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + /* ConjointClear */ + {0, 0, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_ZERO}, + /* ConjointSrc */ + {0, 0, RADEON_SRC_BLEND_GL_ONE | + RADEON_DST_BLEND_GL_ZERO}, + /* ConjointDst */ + {0, 0, RADEON_SRC_BLEND_GL_ZERO | + RADEON_DST_BLEND_GL_ONE}, +}; +#define RadeonOpMax (sizeof(RadeonBlendOp) / sizeof(RadeonBlendOp[0])) + +/* Note on texture formats: + * TXFORMAT_Y8 expands to (Y,Y,Y,1). TXFORMAT_I8 expands to (I,I,I,I) + * The RADEON and R200 TXFORMATS we use are the same on r100/r200. + */ + +static CARD32 RADEONTextureFormats[] = { + PICT_a8r8g8b8, + PICT_a8, + PICT_x8r8g8b8, + PICT_r5g6b5, + PICT_a1r5g5b5, + PICT_x1r5g5b5, + 0 +}; + +static CARD32 RADEONDstFormats[] = { + PICT_a8r8g8b8, + PICT_x8r8g8b8, + PICT_r5g6b5, + PICT_a1r5g5b5, + PICT_x1r5g5b5, + 0 +}; + +static CARD32 +RadeonGetTextureFormat(CARD32 format) +{ + switch (format) { + case PICT_a8r8g8b8: + return RADEON_TXFORMAT_ARGB8888 | RADEON_TXFORMAT_ALPHA_IN_MAP; + case PICT_a8: + return RADEON_TXFORMAT_I8 | RADEON_TXFORMAT_ALPHA_IN_MAP; + case PICT_x8r8g8b8: + return RADEON_TXFORMAT_ARGB8888; + case PICT_r5g6b5: + return RADEON_TXFORMAT_RGB565; + case PICT_a1r5g5b5: + return RADEON_TXFORMAT_ARGB1555 | RADEON_TXFORMAT_ALPHA_IN_MAP; + case PICT_x1r5g5b5: + return RADEON_TXFORMAT_ARGB1555; + default: + return 0; + } +} + +static CARD32 +RadeonGetColorFormat(CARD32 format) +{ + switch (format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + return RADEON_COLOR_FORMAT_ARGB8888; + case PICT_r5g6b5: + return RADEON_COLOR_FORMAT_RGB565; + case PICT_a1r5g5b5: + case PICT_x1r5g5b5: + return RADEON_COLOR_FORMAT_ARGB1555; + default: + return 0; + } +} + +/* Returns a RADEON_RB3D_BLENDCNTL value, or 0 if the operation is not + * supported + */ +static CARD32 +RadeonGetBlendCntl(CARD8 op, CARD32 dstFormat) +{ + CARD32 blend_cntl; + + if (op >= RadeonOpMax || RadeonBlendOp[op].blend_cntl == 0) + return 0; + + blend_cntl = RadeonBlendOp[op].blend_cntl; + + if (RadeonBlendOp[op].dst_alpha && !PICT_FORMAT_A(dstFormat)) { + CARD32 srcblend = blend_cntl & RADEON_SRC_BLEND_MASK; + + /* If there's no destination alpha channel, we need to wire the blending + * to treat the alpha channel as always 1. + */ + if (srcblend == RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA || + srcblend == RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE) + blend_cntl = (blend_cntl & ~RADEON_SRC_BLEND_MASK) | + RADEON_SRC_BLEND_GL_ZERO; + else if (srcblend == RADEON_SRC_BLEND_GL_DST_ALPHA) + blend_cntl = (blend_cntl & ~RADEON_SRC_BLEND_MASK) | + RADEON_SRC_BLEND_GL_ONE; + } + + return blend_cntl; +} + +static __inline__ CARD32 F_TO_DW(float val) +{ + union { + float f; + CARD32 l; + } tmp; + tmp.f = val; + return tmp.l; +} + +/* Compute log base 2 of val. */ +static __inline__ int +ATILog2(int val) +{ + int bits; + + for (bits = 0; val != 0; val >>= 1, ++bits) + ; + return bits - 1; +} + +static void RadeonInit3DEngine(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + +#ifdef XF86DRI + if (info->directRenderingEnabled) { + RADEONSAREAPrivPtr pSAREAPriv; + + pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + pSAREAPriv->ctxOwner = DRIGetContext(pScrn->pScreen); + RadeonInit3DEngineCP(pScrn); + } else +#endif + RadeonInit3DEngineMMIO(pScrn); + + info->RenderInited3D = TRUE; +} + +static void +RemoveLinear (FBLinearPtr linear) +{ + RADEONInfoPtr info = (RADEONInfoPtr)(linear->devPrivate.ptr); + + info->RenderTex = NULL; +} + +static void +RenderCallback (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if ((currentTime.milliseconds > info->RenderTimeout) && info->RenderTex) { + xf86FreeOffscreenLinear(info->RenderTex); + info->RenderTex = NULL; + } + + if (!info->RenderTex) + info->RenderCallback = NULL; +} + +static Bool +AllocateLinear ( + ScrnInfoPtr pScrn, + int sizeNeeded +){ + RADEONInfoPtr info = RADEONPTR(pScrn); + + info->RenderTimeout = currentTime.milliseconds + 30000; + info->RenderCallback = RenderCallback; + + if (info->RenderTex) { + if (info->RenderTex->size >= sizeNeeded) + return TRUE; + else { + if (xf86ResizeOffscreenLinear(info->RenderTex, sizeNeeded)) + return TRUE; + + xf86FreeOffscreenLinear(info->RenderTex); + info->RenderTex = NULL; + } + } + + info->RenderTex = xf86AllocateOffscreenLinear(pScrn->pScreen, sizeNeeded, 32, + NULL, RemoveLinear, info); + + return (info->RenderTex != NULL); +} + +#if X_BYTE_ORDER == X_BIG_ENDIAN +static Bool RADEONSetupRenderByteswap(ScrnInfoPtr pScrn, int tex_bytepp) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + /* Set up byte swapping for the framebuffer aperture as needed */ + switch (tex_bytepp) { + case 1: + OUTREG(RADEON_SURFACE_CNTL, info->ModeReg.surface_cntl & + ~(RADEON_NONSURF_AP0_SWP_32BPP + | RADEON_NONSURF_AP0_SWP_16BPP)); + break; + case 2: + OUTREG(RADEON_SURFACE_CNTL, (info->ModeReg.surface_cntl & + ~RADEON_NONSURF_AP0_SWP_32BPP) + | RADEON_NONSURF_AP0_SWP_16BPP); + break; + case 4: + OUTREG(RADEON_SURFACE_CNTL, (info->ModeReg.surface_cntl & + ~RADEON_NONSURF_AP0_SWP_16BPP) + | RADEON_NONSURF_AP0_SWP_32BPP); + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "%s: Don't know what to do for " + "tex_bytepp == %d!\n", __func__, tex_bytepp); + return FALSE; + } + return TRUE; +} + +static void RADEONRestoreByteswap(RADEONInfoPtr info) +{ + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_SURFACE_CNTL, info->ModeReg.surface_cntl); +} +#endif /* X_BYTE_ORDER == X_BIG_ENDIAN */ + +#endif /* RENDER_GENERIC_HELPER */ + +#if defined(ACCEL_MMIO) && defined(ACCEL_CP) +#error Cannot define both MMIO and CP acceleration! +#endif + +#if !defined(UNIXCPP) || defined(ANSICPP) +#define FUNC_NAME_CAT(prefix,suffix) prefix##suffix +#else +#define FUNC_NAME_CAT(prefix,suffix) prefix/**/suffix +#endif + +#ifdef ACCEL_MMIO +#define FUNC_NAME(prefix) FUNC_NAME_CAT(prefix,MMIO) +#else +#ifdef ACCEL_CP +#define FUNC_NAME(prefix) FUNC_NAME_CAT(prefix,CP) +#else +#error No accel type defined! +#endif +#endif + + +static void FUNC_NAME(RadeonInit3DEngine)(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ACCEL_PREAMBLE(); + + if (info->ChipFamily >= CHIP_FAMILY_R300) { + /* Unimplemented */ + } else if ((info->ChipFamily == CHIP_FAMILY_RV250) || + (info->ChipFamily == CHIP_FAMILY_RV280) || + (info->ChipFamily == CHIP_FAMILY_RS300) || + (info->ChipFamily == CHIP_FAMILY_R200)) { + + BEGIN_ACCEL(7); + if (info->ChipFamily == CHIP_FAMILY_RS300) { + OUT_ACCEL_REG(R200_SE_VAP_CNTL_STATUS, RADEON_TCL_BYPASS); + } else { + OUT_ACCEL_REG(R200_SE_VAP_CNTL_STATUS, 0); + } + OUT_ACCEL_REG(R200_PP_CNTL_X, 0); + OUT_ACCEL_REG(R200_PP_TXMULTI_CTL_0, 0); + OUT_ACCEL_REG(R200_SE_VTX_STATE_CNTL, 0); + OUT_ACCEL_REG(R200_RE_CNTL, 0x0); + /* XXX: correct? Want it to be like RADEON_VTX_ST?_NONPARAMETRIC */ + OUT_ACCEL_REG(R200_SE_VTE_CNTL, R200_VTX_ST_DENORMALIZED); + OUT_ACCEL_REG(R200_SE_VAP_CNTL, R200_VAP_FORCE_W_TO_ONE | + R200_VAP_VF_MAX_VTX_NUM); + FINISH_ACCEL(); + } else { + BEGIN_ACCEL(2); + if ((info->ChipFamily == CHIP_FAMILY_RADEON) || + (info->ChipFamily == CHIP_FAMILY_RV200)) + OUT_ACCEL_REG(RADEON_SE_CNTL_STATUS, 0); + else + OUT_ACCEL_REG(RADEON_SE_CNTL_STATUS, RADEON_TCL_BYPASS); + OUT_ACCEL_REG(RADEON_SE_COORD_FMT, + RADEON_VTX_XY_PRE_MULT_1_OVER_W0 | + RADEON_VTX_ST0_NONPARAMETRIC | + RADEON_VTX_ST1_NONPARAMETRIC | + RADEON_TEX1_W_ROUTING_USE_W0); + FINISH_ACCEL(); + } + + BEGIN_ACCEL(3); + OUT_ACCEL_REG(RADEON_RE_TOP_LEFT, 0); + OUT_ACCEL_REG(RADEON_RE_WIDTH_HEIGHT, 0x07ff07ff); + OUT_ACCEL_REG(RADEON_SE_CNTL, RADEON_DIFFUSE_SHADE_GOURAUD | + RADEON_BFACE_SOLID | + RADEON_FFACE_SOLID | + RADEON_VTX_PIX_CENTER_OGL | + RADEON_ROUND_MODE_ROUND | + RADEON_ROUND_PREC_4TH_PIX); + FINISH_ACCEL(); +} + +static Bool FUNC_NAME(R100SetupTexture)( + ScrnInfoPtr pScrn, + CARD32 format, + CARD8 *src, + int src_pitch, + unsigned int width, + unsigned int height, + int flags) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD8 *dst; + CARD32 tex_size = 0, txformat; + int dst_pitch, offset, size, i, tex_bytepp; +#ifdef ACCEL_CP + CARD32 buf_pitch; + unsigned int hpass; + CARD8 *tmp_dst; +#endif + ACCEL_PREAMBLE(); + + if ((width > 2048) || (height > 2048)) + return FALSE; + + txformat = RadeonGetTextureFormat(format); + tex_bytepp = PICT_FORMAT_BPP(format) >> 3; + +#ifndef ACCEL_CP + +#if X_BYTE_ORDER == X_BIG_ENDIAN + if (!RADEONSetupRenderByteswap(pScrn, tex_bytepp)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "%s: RADEONSetupRenderByteswap() " + "failed!\n", __func__); + return FALSE; + } +#endif + +#endif + + dst_pitch = (width * tex_bytepp + 63) & ~63; + size = dst_pitch * height; + + if (!AllocateLinear(pScrn, size)) + return FALSE; + + if (flags & XAA_RENDER_REPEAT) { + txformat |= ATILog2(width) << RADEON_TXFORMAT_WIDTH_SHIFT; + txformat |= ATILog2(height) << RADEON_TXFORMAT_HEIGHT_SHIFT; + } else { + tex_size = ((height - 1) << 16) | (width - 1); + txformat |= RADEON_TXFORMAT_NON_POWER2; + } + + offset = info->RenderTex->offset * pScrn->bitsPerPixel / 8; + dst = (CARD8*)(info->FB + offset); + + /* Upload texture to card. */ + +#ifdef ACCEL_CP + + while ( height ) + { + tmp_dst = RADEONHostDataBlit( pScrn, tex_bytepp, width, + dst_pitch, &buf_pitch, + &dst, &height, &hpass ); + RADEONHostDataBlitCopyPass( tmp_dst, src, hpass, buf_pitch, src_pitch ); + src += hpass * src_pitch; + } + + RADEON_PURGE_CACHE(); + RADEON_WAIT_UNTIL_IDLE(); + +#else + + i = height; + + if (info->accel->NeedToSync) + info->accel->Sync(pScrn); + + while(i--) { + memcpy(dst, src, width * tex_bytepp); + src += src_pitch; + dst += dst_pitch; + } + +#if X_BYTE_ORDER == X_BIG_ENDIAN + RADEONRestoreByteswap(info); +#endif + +#endif /* ACCEL_CP */ + + BEGIN_ACCEL(5); + OUT_ACCEL_REG(RADEON_PP_TXFORMAT_0, txformat); + OUT_ACCEL_REG(RADEON_PP_TEX_SIZE_0, tex_size); + OUT_ACCEL_REG(RADEON_PP_TEX_PITCH_0, dst_pitch - 32); + OUT_ACCEL_REG(RADEON_PP_TXOFFSET_0, offset + info->fbLocation + + pScrn->fbOffset); + OUT_ACCEL_REG(RADEON_PP_TXFILTER_0, RADEON_MAG_FILTER_LINEAR | + RADEON_MIN_FILTER_LINEAR | + RADEON_CLAMP_S_WRAP | + RADEON_CLAMP_T_WRAP); + FINISH_ACCEL(); + + return TRUE; +} + +static Bool +FUNC_NAME(R100SetupForCPUToScreenAlphaTexture) ( + ScrnInfoPtr pScrn, + int op, + CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + CARD32 maskFormat, + CARD32 dstFormat, + CARD8 *alphaPtr, + int alphaPitch, + int width, + int height, + int flags +) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 colorformat, srccolor, blend_cntl; + ACCEL_PREAMBLE(); + + blend_cntl = RadeonGetBlendCntl(op, dstFormat); + if (blend_cntl == 0) + return FALSE; + + if (!info->RenderInited3D) + RadeonInit3DEngine(pScrn); + + if (!FUNC_NAME(R100SetupTexture)(pScrn, maskFormat, alphaPtr, alphaPitch, + width, height, flags)) + return FALSE; + + colorformat = RadeonGetColorFormat(dstFormat); + + srccolor = ((alpha & 0xff00) << 16) | ((red & 0xff00) << 8) | (blue >> 8) | + (green & 0xff00); + + BEGIN_ACCEL(7); + OUT_ACCEL_REG(RADEON_RB3D_CNTL, colorformat | RADEON_ALPHA_BLEND_ENABLE); + OUT_ACCEL_REG(RADEON_PP_CNTL, RADEON_TEX_0_ENABLE | + RADEON_TEX_BLEND_0_ENABLE); + OUT_ACCEL_REG(RADEON_PP_TFACTOR_0, srccolor); + OUT_ACCEL_REG(RADEON_PP_TXCBLEND_0, RADEON_COLOR_ARG_A_TFACTOR_COLOR | + RADEON_COLOR_ARG_B_T0_ALPHA); + OUT_ACCEL_REG(RADEON_PP_TXABLEND_0, RADEON_ALPHA_ARG_A_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_B_T0_ALPHA); + OUT_ACCEL_REG(RADEON_SE_VTX_FMT, RADEON_SE_VTX_FMT_XY | + RADEON_SE_VTX_FMT_ST0); + OUT_ACCEL_REG(RADEON_RB3D_BLENDCNTL, blend_cntl); + FINISH_ACCEL(); + + return TRUE; +} + + +static Bool +FUNC_NAME(R100SetupForCPUToScreenTexture) ( + ScrnInfoPtr pScrn, + int op, + CARD32 srcFormat, + CARD32 dstFormat, + CARD8 *texPtr, + int texPitch, + int width, + int height, + int flags +) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 colorformat, blend_cntl; + ACCEL_PREAMBLE(); + + blend_cntl = RadeonGetBlendCntl(op, dstFormat); + if (blend_cntl == 0) + return FALSE; + + if (!info->RenderInited3D) + RadeonInit3DEngine(pScrn); + + if (!FUNC_NAME(R100SetupTexture)(pScrn, srcFormat, texPtr, texPitch, width, + height, flags)) + return FALSE; + + colorformat = RadeonGetColorFormat(dstFormat); + + BEGIN_ACCEL(6); + OUT_ACCEL_REG(RADEON_RB3D_CNTL, colorformat | RADEON_ALPHA_BLEND_ENABLE); + OUT_ACCEL_REG(RADEON_PP_CNTL, RADEON_TEX_0_ENABLE | + RADEON_TEX_BLEND_0_ENABLE); + if (srcFormat != PICT_a8) + OUT_ACCEL_REG(RADEON_PP_TXCBLEND_0, RADEON_COLOR_ARG_C_T0_COLOR); + else + OUT_ACCEL_REG(RADEON_PP_TXCBLEND_0, RADEON_COLOR_ARG_C_ZERO); + OUT_ACCEL_REG(RADEON_PP_TXABLEND_0, RADEON_ALPHA_ARG_C_T0_ALPHA); + OUT_ACCEL_REG(RADEON_SE_VTX_FMT, RADEON_SE_VTX_FMT_XY | + RADEON_SE_VTX_FMT_ST0); + OUT_ACCEL_REG(RADEON_RB3D_BLENDCNTL, blend_cntl); + FINISH_ACCEL(); + + return TRUE; +} + + +static void +FUNC_NAME(R100SubsequentCPUToScreenTexture) ( + ScrnInfoPtr pScrn, + int dstx, + int dsty, + int srcx, + int srcy, + int width, + int height +) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int byteshift; + CARD32 fboffset; + float l, t, r, b, fl, fr, ft, fb; + + ACCEL_PREAMBLE(); + + /* Note: we can't simply set up the 3D surface at the same location as the + * front buffer, because the 2048x2048 limit on coordinates may be smaller + * than the (MergedFB) screen. + * Can't use arbitrary offsets for color tiling + */ + if (info->tilingEnabled) { + /* can't play tricks with x coordinate, or could we - tiling is disabled anyway in that case */ + fboffset = info->fbLocation + pScrn->fbOffset + + (pScrn->displayWidth * (dsty & ~15) * (pScrn->bitsPerPixel >> 3)); + l = dstx; + t = (dsty % 16); + } + else { + byteshift = (pScrn->bitsPerPixel >> 4); + fboffset = (info->fbLocation + pScrn->fbOffset + + ((pScrn->displayWidth * dsty + dstx) << byteshift)) & ~15; + l = ((dstx << byteshift) % 16) >> byteshift; + t = 0.0; + } + + r = width + l; + b = height + t; + fl = srcx; + fr = srcx + width; + ft = srcy; + fb = srcy + height; + +#ifdef ACCEL_CP + BEGIN_RING(25); + + OUT_ACCEL_REG(RADEON_RB3D_COLORPITCH, pScrn->displayWidth | + ((info->tilingEnabled && (dsty <= pScrn->virtualY)) ? RADEON_COLOR_TILE_ENABLE : 0)); + OUT_ACCEL_REG(RADEON_RB3D_COLOROFFSET, fboffset); + OUT_RING(CP_PACKET3(RADEON_CP_PACKET3_3D_DRAW_IMMD, 17)); + /* RADEON_SE_VTX_FMT */ + OUT_RING(RADEON_CP_VC_FRMT_XY | + RADEON_CP_VC_FRMT_ST0); + /* SE_VF_CNTL */ + OUT_RING(RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN | + RADEON_CP_VC_CNTL_PRIM_WALK_RING | + RADEON_CP_VC_CNTL_MAOS_ENABLE | + RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE | + (4 << RADEON_CP_VC_CNTL_NUM_SHIFT)); + + OUT_RING(F_TO_DW(l)); + OUT_RING(F_TO_DW(t)); + OUT_RING(F_TO_DW(fl)); + OUT_RING(F_TO_DW(ft)); + + OUT_RING(F_TO_DW(r)); + OUT_RING(F_TO_DW(t)); + OUT_RING(F_TO_DW(fr)); + OUT_RING(F_TO_DW(ft)); + + OUT_RING(F_TO_DW(r)); + OUT_RING(F_TO_DW(b)); + OUT_RING(F_TO_DW(fr)); + OUT_RING(F_TO_DW(fb)); + + OUT_RING(F_TO_DW(l)); + OUT_RING(F_TO_DW(b)); + OUT_RING(F_TO_DW(fl)); + OUT_RING(F_TO_DW(fb)); + + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_3D_IDLECLEAN); + + ADVANCE_RING(); +#else + BEGIN_ACCEL(20); + + OUT_ACCEL_REG(RADEON_RB3D_COLORPITCH, pScrn->displayWidth | + ((info->tilingEnabled && (dsty <= pScrn->virtualY)) ? RADEON_COLOR_TILE_ENABLE : 0)); + OUT_ACCEL_REG(RADEON_RB3D_COLOROFFSET, fboffset); + + OUT_ACCEL_REG(RADEON_SE_VF_CNTL, RADEON_VF_PRIM_TYPE_TRIANGLE_FAN | + RADEON_VF_PRIM_WALK_DATA | + RADEON_VF_RADEON_MODE | + (4 << RADEON_VF_NUM_VERTICES_SHIFT)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(l)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(t)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fl)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(ft)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(r)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(t)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fr)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(ft)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(r)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(b)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fr)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fb)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(l)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(b)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fl)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fb)); + + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_3D_IDLECLEAN); + FINISH_ACCEL(); +#endif + +} + +static Bool FUNC_NAME(R200SetupTexture)( + ScrnInfoPtr pScrn, + CARD32 format, + CARD8 *src, + int src_pitch, + unsigned int width, + unsigned int height, + int flags) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD8 *dst; + CARD32 tex_size = 0, txformat; + int dst_pitch, offset, size, i, tex_bytepp; +#ifdef ACCEL_CP + CARD32 buf_pitch; + unsigned int hpass; + CARD8 *tmp_dst; +#endif + ACCEL_PREAMBLE(); + + if ((width > 2048) || (height > 2048)) + return FALSE; + + txformat = RadeonGetTextureFormat(format); + tex_bytepp = PICT_FORMAT_BPP(format) >> 3; + +#ifndef ACCEL_CP + +#if X_BYTE_ORDER == X_BIG_ENDIAN + if (!RADEONSetupRenderByteswap(pScrn, tex_bytepp)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "%s: RADEONSetupRenderByteswap() " + "failed!\n", __func__); + return FALSE; + } +#endif + +#endif + + dst_pitch = (width * tex_bytepp + 63) & ~63; + size = dst_pitch * height; + + if (!AllocateLinear(pScrn, size)) + return FALSE; + + if (flags & XAA_RENDER_REPEAT) { + txformat |= ATILog2(width) << R200_TXFORMAT_WIDTH_SHIFT; + txformat |= ATILog2(height) << R200_TXFORMAT_HEIGHT_SHIFT; + } else { + tex_size = ((height - 1) << 16) | (width - 1); + txformat |= RADEON_TXFORMAT_NON_POWER2; + } + + offset = info->RenderTex->offset * pScrn->bitsPerPixel / 8; + dst = (CARD8*)(info->FB + offset); + + /* Upload texture to card. */ + +#ifdef ACCEL_CP + + while ( height ) + { + tmp_dst = RADEONHostDataBlit( pScrn, tex_bytepp, width, + dst_pitch, &buf_pitch, + &dst, &height, &hpass ); + RADEONHostDataBlitCopyPass( tmp_dst, src, hpass, buf_pitch, src_pitch ); + src += hpass * src_pitch; + } + + RADEON_PURGE_CACHE(); + RADEON_WAIT_UNTIL_IDLE(); + +#else + + i = height; + if (info->accel->NeedToSync) + info->accel->Sync(pScrn); + + while(i--) { + memcpy(dst, src, width * tex_bytepp); + src += src_pitch; + dst += dst_pitch; + } + +#if X_BYTE_ORDER == X_BIG_ENDIAN + RADEONRestoreByteswap(info); +#endif + +#endif /* ACCEL_CP */ + + BEGIN_ACCEL(6); + OUT_ACCEL_REG(R200_PP_TXFORMAT_0, txformat); + OUT_ACCEL_REG(R200_PP_TXFORMAT_X_0, 0); + OUT_ACCEL_REG(R200_PP_TXSIZE_0, tex_size); + OUT_ACCEL_REG(R200_PP_TXPITCH_0, dst_pitch - 32); + OUT_ACCEL_REG(R200_PP_TXOFFSET_0, offset + info->fbLocation + + pScrn->fbOffset); + OUT_ACCEL_REG(R200_PP_TXFILTER_0, R200_MAG_FILTER_NEAREST | + R200_MIN_FILTER_NEAREST | + R200_CLAMP_S_WRAP | + R200_CLAMP_T_WRAP); + FINISH_ACCEL(); + + return TRUE; +} + +static Bool +FUNC_NAME(R200SetupForCPUToScreenAlphaTexture) ( + ScrnInfoPtr pScrn, + int op, + CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + CARD32 maskFormat, + CARD32 dstFormat, + CARD8 *alphaPtr, + int alphaPitch, + int width, + int height, + int flags +) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 colorformat, srccolor, blend_cntl; + ACCEL_PREAMBLE(); + + blend_cntl = RadeonGetBlendCntl(op, dstFormat); + if (blend_cntl == 0) + return FALSE; + + if (!info->RenderInited3D) + RadeonInit3DEngine(pScrn); + + if (!FUNC_NAME(R200SetupTexture)(pScrn, maskFormat, alphaPtr, alphaPitch, + width, height, flags)) + return FALSE; + + colorformat = RadeonGetColorFormat(dstFormat); + + srccolor = ((alpha & 0xff00) << 16) | ((red & 0xff00) << 8) | (blue >> 8) | + (green & 0xff00); + + BEGIN_ACCEL(10); + OUT_ACCEL_REG(RADEON_RB3D_CNTL, colorformat | RADEON_ALPHA_BLEND_ENABLE); + OUT_ACCEL_REG(RADEON_PP_CNTL, RADEON_TEX_0_ENABLE | + RADEON_TEX_BLEND_0_ENABLE); + OUT_ACCEL_REG(R200_PP_TFACTOR_0, srccolor); + OUT_ACCEL_REG(R200_PP_TXCBLEND_0, R200_TXC_ARG_A_TFACTOR_COLOR | + R200_TXC_ARG_B_R0_ALPHA); + OUT_ACCEL_REG(R200_PP_TXCBLEND2_0, R200_TXC_OUTPUT_REG_R0); + OUT_ACCEL_REG(R200_PP_TXABLEND_0, R200_TXA_ARG_A_TFACTOR_ALPHA | + R200_TXA_ARG_B_R0_ALPHA); + OUT_ACCEL_REG(R200_PP_TXABLEND2_0, R200_TXA_OUTPUT_REG_R0); + OUT_ACCEL_REG(R200_SE_VTX_FMT_0, 0); + OUT_ACCEL_REG(R200_SE_VTX_FMT_1, (2 << R200_VTX_TEX0_COMP_CNT_SHIFT)); + OUT_ACCEL_REG(RADEON_RB3D_BLENDCNTL, blend_cntl); + FINISH_ACCEL(); + + return TRUE; +} + +static Bool +FUNC_NAME(R200SetupForCPUToScreenTexture) ( + ScrnInfoPtr pScrn, + int op, + CARD32 srcFormat, + CARD32 dstFormat, + CARD8 *texPtr, + int texPitch, + int width, + int height, + int flags +) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 colorformat, blend_cntl; + ACCEL_PREAMBLE(); + + blend_cntl = RadeonGetBlendCntl(op, dstFormat); + if (blend_cntl == 0) + return FALSE; + + if (!info->RenderInited3D) + RadeonInit3DEngine(pScrn); + + if (!FUNC_NAME(R200SetupTexture)(pScrn, srcFormat, texPtr, texPitch, width, + height, flags)) + return FALSE; + + colorformat = RadeonGetColorFormat(dstFormat); + + BEGIN_ACCEL(9); + OUT_ACCEL_REG(RADEON_RB3D_CNTL, colorformat | RADEON_ALPHA_BLEND_ENABLE); + OUT_ACCEL_REG(RADEON_PP_CNTL, RADEON_TEX_0_ENABLE | + RADEON_TEX_BLEND_0_ENABLE); + if (srcFormat != PICT_a8) + OUT_ACCEL_REG(R200_PP_TXCBLEND_0, R200_TXC_ARG_C_R0_COLOR); + else + OUT_ACCEL_REG(R200_PP_TXCBLEND_0, R200_TXC_ARG_C_ZERO); + OUT_ACCEL_REG(R200_PP_TXCBLEND2_0, R200_TXC_OUTPUT_REG_R0); + OUT_ACCEL_REG(R200_PP_TXABLEND_0, R200_TXA_ARG_C_R0_ALPHA); + OUT_ACCEL_REG(R200_PP_TXABLEND2_0, R200_TXA_OUTPUT_REG_R0); + OUT_ACCEL_REG(R200_SE_VTX_FMT_0, 0); + OUT_ACCEL_REG(R200_SE_VTX_FMT_1, (2 << R200_VTX_TEX0_COMP_CNT_SHIFT)); + OUT_ACCEL_REG(RADEON_RB3D_BLENDCNTL, blend_cntl); + FINISH_ACCEL(); + + return TRUE; +} + +static void +FUNC_NAME(R200SubsequentCPUToScreenTexture) ( + ScrnInfoPtr pScrn, + int dstx, + int dsty, + int srcx, + int srcy, + int width, + int height +) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + int byteshift; + CARD32 fboffset; + float l, t, r, b, fl, fr, ft, fb; + ACCEL_PREAMBLE(); + + /* Note: we can't simply set up the 3D surface at the same location as the + * front buffer, because the 2048x2048 limit on coordinates may be smaller + * than the (MergedFB) screen. + * Can't use arbitrary offsets for color tiling + */ + if (info->tilingEnabled) { + /* can't play tricks with x coordinate, or could we - tiling is disabled anyway in that case */ + fboffset = info->fbLocation + pScrn->fbOffset + + (pScrn->displayWidth * (dsty & ~15) * (pScrn->bitsPerPixel >> 3)); + l = dstx; + t = (dsty % 16); + } + else { + byteshift = (pScrn->bitsPerPixel >> 4); + fboffset = (info->fbLocation + pScrn->fbOffset + + ((pScrn->displayWidth * dsty + dstx) << byteshift)) & ~15; + l = ((dstx << byteshift) % 16) >> byteshift; + t = 0.0; + } + + r = width + l; + b = height + t; + fl = srcx; + fr = srcx + width; + ft = srcy; + fb = srcy + height; + +#ifdef ACCEL_CP + BEGIN_RING(24); + + OUT_ACCEL_REG(RADEON_RB3D_COLORPITCH, pScrn->displayWidth | + ((info->tilingEnabled && (dsty <= pScrn->virtualY)) ? RADEON_COLOR_TILE_ENABLE : 0)); + OUT_ACCEL_REG(RADEON_RB3D_COLOROFFSET, fboffset); + + OUT_RING(CP_PACKET3(R200_CP_PACKET3_3D_DRAW_IMMD_2, 16)); + /* RADEON_SE_VF_CNTL */ + OUT_RING(RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN | + RADEON_CP_VC_CNTL_PRIM_WALK_RING | + (4 << RADEON_CP_VC_CNTL_NUM_SHIFT)); + + OUT_RING(F_TO_DW(l)); + OUT_RING(F_TO_DW(t)); + OUT_RING(F_TO_DW(fl)); + OUT_RING(F_TO_DW(ft)); + + OUT_RING(F_TO_DW(r)); + OUT_RING(F_TO_DW(t)); + OUT_RING(F_TO_DW(fr)); + OUT_RING(F_TO_DW(ft)); + + OUT_RING(F_TO_DW(r)); + OUT_RING(F_TO_DW(b)); + OUT_RING(F_TO_DW(fr)); + OUT_RING(F_TO_DW(fb)); + + OUT_RING(F_TO_DW(l)); + OUT_RING(F_TO_DW(b)); + OUT_RING(F_TO_DW(fl)); + OUT_RING(F_TO_DW(fb)); + + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_3D_IDLECLEAN); + + ADVANCE_RING(); +#else + BEGIN_ACCEL(20); + + /* Note: we can't simply setup 3D surface at the same location as the front buffer, + some apps may draw offscreen pictures out of the limitation of radeon 3D surface. + */ + OUT_ACCEL_REG(RADEON_RB3D_COLORPITCH, pScrn->displayWidth | + ((info->tilingEnabled && (dsty <= pScrn->virtualY)) ? RADEON_COLOR_TILE_ENABLE : 0)); + OUT_ACCEL_REG(RADEON_RB3D_COLOROFFSET, fboffset); + + OUT_ACCEL_REG(RADEON_SE_VF_CNTL, (RADEON_VF_PRIM_TYPE_QUAD_LIST | + RADEON_VF_PRIM_WALK_DATA | + 4 << RADEON_VF_NUM_VERTICES_SHIFT)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(l)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(t)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fl)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(ft)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(r)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(t)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fr)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(ft)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(r)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(b)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fr)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fb)); + + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(l)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(b)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fl)); + OUT_ACCEL_REG(RADEON_SE_PORT_DATA0, F_TO_DW(fb)); + + OUT_ACCEL_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_3D_IDLECLEAN); + + FINISH_ACCEL(); +#endif +} + +#undef FUNC_NAME + diff --git a/src/radeon_sarea.h b/src/radeon_sarea.h new file mode 100644 index 0000000..95db1f3 --- /dev/null +++ b/src/radeon_sarea.h @@ -0,0 +1,231 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_sarea.h,v 1.5 2002/10/30 12:52:14 alanh Exp $ */ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, + * VA Linux Systems Inc., Fremont, California. + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (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 ATI, VA LINUX SYSTEMS AND/OR + * THEIR 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef _RADEON_SAREA_H_ +#define _RADEON_SAREA_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the kernel file (radeon_drm.h) + */ +#ifndef __RADEON_SAREA_DEFINES__ +#define __RADEON_SAREA_DEFINES__ + +/* What needs to be changed for the current vertex buffer? */ +#define RADEON_UPLOAD_CONTEXT 0x00000001 +#define RADEON_UPLOAD_VERTFMT 0x00000002 +#define RADEON_UPLOAD_LINE 0x00000004 +#define RADEON_UPLOAD_BUMPMAP 0x00000008 +#define RADEON_UPLOAD_MASKS 0x00000010 +#define RADEON_UPLOAD_VIEWPORT 0x00000020 +#define RADEON_UPLOAD_SETUP 0x00000040 +#define RADEON_UPLOAD_TCL 0x00000080 +#define RADEON_UPLOAD_MISC 0x00000100 +#define RADEON_UPLOAD_TEX0 0x00000200 +#define RADEON_UPLOAD_TEX1 0x00000400 +#define RADEON_UPLOAD_TEX2 0x00000800 +#define RADEON_UPLOAD_TEX0IMAGES 0x00001000 +#define RADEON_UPLOAD_TEX1IMAGES 0x00002000 +#define RADEON_UPLOAD_TEX2IMAGES 0x00004000 +#define RADEON_UPLOAD_CLIPRECTS 0x00008000 /* handled client-side */ +#define RADEON_REQUIRE_QUIESCENCE 0x00010000 +#define RADEON_UPLOAD_ZBIAS 0x00020000 +#define RADEON_UPLOAD_ALL 0x0002ffff +#define RADEON_UPLOAD_CONTEXT_ALL 0x000201ff + +#define RADEON_FRONT 0x1 +#define RADEON_BACK 0x2 +#define RADEON_DEPTH 0x4 +#define RADEON_STENCIL 0x8 + +/* Primitive types */ +#define RADEON_POINTS 0x1 +#define RADEON_LINES 0x2 +#define RADEON_LINE_STRIP 0x3 +#define RADEON_TRIANGLES 0x4 +#define RADEON_TRIANGLE_FAN 0x5 +#define RADEON_TRIANGLE_STRIP 0x6 +#define RADEON_3VTX_POINTS 0x9 +#define RADEON_3VTX_LINES 0xa + +/* Vertex/indirect buffer size */ +#define RADEON_BUFFER_SIZE 65536 + +/* Byte offsets for indirect buffer data */ +#define RADEON_INDEX_PRIM_OFFSET 20 +#define RADEON_HOSTDATA_BLIT_OFFSET 32 + +#define RADEON_SCRATCH_REG_OFFSET 32 + +/* Keep these small for testing */ +#define RADEON_NR_SAREA_CLIPRECTS 12 + +/* There are 2 heaps (local/GART). Each region within a heap is a + * minimum of 64k, and there are at most 64 of them per heap. + */ +#define RADEON_CARD_HEAP 0 +#define RADEON_GART_HEAP 1 +#define RADEON_NR_TEX_HEAPS 2 +#define RADEON_NR_TEX_REGIONS 64 +#define RADEON_LOG_TEX_GRANULARITY 16 + +#define RADEON_MAX_TEXTURE_LEVELS 12 +#define RADEON_MAX_TEXTURE_UNITS 3 + +/* Blits have strict offset rules. All blit offset must be aligned on + * a 1K-byte boundary. + */ +#define RADEON_OFFSET_SHIFT 10 +#define RADEON_OFFSET_ALIGN (1 << RADEON_OFFSET_SHIFT) +#define RADEON_OFFSET_MASK (RADEON_OFFSET_ALIGN - 1) + +#endif /* __RADEON_SAREA_DEFINES__ */ + +typedef struct { + unsigned int red; + unsigned int green; + unsigned int blue; + unsigned int alpha; +} radeon_color_regs_t; + +typedef struct { + /* Context state */ + unsigned int pp_misc; + unsigned int pp_fog_color; + unsigned int re_solid_color; + unsigned int rb3d_blendcntl; + unsigned int rb3d_depthoffset; + unsigned int rb3d_depthpitch; + unsigned int rb3d_zstencilcntl; + + unsigned int pp_cntl; + unsigned int rb3d_cntl; + unsigned int rb3d_coloroffset; + unsigned int re_width_height; + unsigned int rb3d_colorpitch; + unsigned int se_cntl; + + /* Vertex format state */ + unsigned int se_coord_fmt; + + /* Line state */ + unsigned int re_line_pattern; + unsigned int re_line_state; + + unsigned int se_line_width; + + /* Bumpmap state */ + unsigned int pp_lum_matrix; + + unsigned int pp_rot_matrix_0; + unsigned int pp_rot_matrix_1; + + /* Mask state */ + unsigned int rb3d_stencilrefmask; + unsigned int rb3d_ropcntl; + unsigned int rb3d_planemask; + + /* Viewport state */ + unsigned int se_vport_xscale; + unsigned int se_vport_xoffset; + unsigned int se_vport_yscale; + unsigned int se_vport_yoffset; + unsigned int se_vport_zscale; + unsigned int se_vport_zoffset; + + /* Setup state */ + unsigned int se_cntl_status; + + /* Misc state */ + unsigned int re_top_left; + unsigned int re_misc; +} radeon_context_regs_t; + +/* Setup registers for each texture unit */ +typedef struct { + unsigned int pp_txfilter; + unsigned int pp_txformat; + unsigned int pp_txoffset; + unsigned int pp_txcblend; + unsigned int pp_txablend; + unsigned int pp_tfactor; + unsigned int pp_border_color; +} radeon_texture_regs_t; + +typedef struct { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + radeon_context_regs_t ContextState; + radeon_texture_regs_t TexState[RADEON_MAX_TEXTURE_UNITS]; + unsigned int dirty; + unsigned int vertsize; + unsigned int vc_format; + + /* The current cliprects, or a subset thereof */ + XF86DRIClipRectRec boxes[RADEON_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + /* Counters for throttling of rendering clients */ + unsigned int last_frame; + unsigned int last_dispatch; + unsigned int last_clear; + + /* Maintain an LRU of contiguous regions of texture space. If you + * think you own a region of texture memory, and it has an age + * different to the one you set, then you are mistaken and it has + * been stolen by another client. If global texAge hasn't changed, + * there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained texture + * information of other clients - by maintaining them in the same + * lru which is used to age their own textures, clients have an + * approximate lru for the whole of global texture space, and can + * make informed decisions as to which areas to kick out. There is + * no need to choose whether to kick out your own texture or someone + * else's - simply eject them all in LRU order. + */ + /* Last elt is sentinal */ + drmTextureRegion texList[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; + /* last time texture was uploaded */ + unsigned int texAge[RADEON_NR_TEX_HEAPS]; + + int ctxOwner; /* last context to upload state */ + int pfAllowPageFlip; /* set by the 2d driver, read by the client */ + int pfCurrentPage; /* set by kernel, read by others */ + int crtc2_base; /* for pageflipping with CloneMode */ +} RADEONSAREAPriv, *RADEONSAREAPrivPtr; + +#endif diff --git a/src/radeon_version.h b/src/radeon_version.h new file mode 100644 index 0000000..c2a1195 --- /dev/null +++ b/src/radeon_version.h @@ -0,0 +1,62 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_version.h,v 1.10 2003/09/28 20:15:57 alanh Exp $ */ +/* + * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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 Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE 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. + */ + +#ifndef _RADEON_VERSION_H_ +#define _RADEON_VERSION_H_ 1 + +#undef RADEON_NAME +#undef RADEON_DRIVER_NAME +#undef R200_DRIVER_NAME +#undef RADEON_VERSION_MAJOR +#undef RADEON_VERSION_MINOR +#undef RADEON_VERSION_PATCH +#undef RADEON_VERSION_CURRENT +#undef RADEON_VERSION_EVALUATE +#undef RADEON_VERSION_STRINGIFY +#undef RADEON_VERSION_NAME + +#define RADEON_NAME "RADEON" +#define RADEON_DRIVER_NAME "radeon" +#define R200_DRIVER_NAME "r200" + +#define RADEON_VERSION_MAJOR 4 +#define RADEON_VERSION_MINOR 0 +#define RADEON_VERSION_PATCH 1 + +#ifndef RADEON_VERSION_EXTRA +#define RADEON_VERSION_EXTRA "" +#endif + +#define RADEON_VERSION_CURRENT \ + ((RADEON_VERSION_MAJOR << 20) | \ + (RADEON_VERSION_MINOR << 10) | \ + (RADEON_VERSION_PATCH)) + +#define RADEON_VERSION_EVALUATE(__x) #__x +#define RADEON_VERSION_STRINGIFY(_x) RADEON_VERSION_EVALUATE(_x) +#define RADEON_VERSION_NAME \ + RADEON_VERSION_STRINGIFY(RADEON_VERSION_MAJOR) "." \ + RADEON_VERSION_STRINGIFY(RADEON_VERSION_MINOR) "." \ + RADEON_VERSION_STRINGIFY(RADEON_VERSION_PATCH) RADEON_VERSION_EXTRA + +#endif /* _RADEON_VERSION_H_ */ diff --git a/src/radeon_video.c b/src/radeon_video.c new file mode 100644 index 0000000..d551ccc --- /dev/null +++ b/src/radeon_video.c @@ -0,0 +1,1452 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_video.c,v 1.30 2003/11/10 18:22:18 tsi Exp $ */ + +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_reg.h" + +#include "xf86.h" +#include "dixstruct.h" + +#include "Xv.h" +#include "fourcc.h" + +#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) + +extern int gRADEONEntityIndex; + +static void RADEONInitOffscreenImages(ScreenPtr); + +static XF86VideoAdaptorPtr RADEONSetupImageVideo(ScreenPtr); +static int RADEONSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); +static int RADEONGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); +static void RADEONStopVideo(ScrnInfoPtr, pointer, Bool); +static void RADEONQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, + unsigned int *, unsigned int *, pointer); +static int RADEONPutImage(ScrnInfoPtr, short, short, short, short, short, + short, short, short, int, unsigned char*, short, + short, Bool, RegionPtr, pointer); +static int RADEONQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, + unsigned short *, int *, int *); + +static void RADEONVideoTimerCallback(ScrnInfoPtr pScrn, Time now); + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer; +static Atom xvRedIntensity, xvGreenIntensity, xvBlueIntensity; +static Atom xvContrast, xvHue, xvColor, xvAutopaintColorkey, xvSetDefaults; + +typedef struct { + CARD32 transform_index; + int brightness; + int saturation; + int hue; + int contrast; + int red_intensity; + int green_intensity; + int blue_intensity; + int ecp_div; + + Bool doubleBuffer; + unsigned char currentBuffer; + RegionRec clip; + CARD32 colorKey; + CARD32 videoStatus; + Time offTime; + Time freeTime; + Bool autopaint_colorkey; +} RADEONPortPrivRec, *RADEONPortPrivPtr; + + +#define GET_PORT_PRIVATE(pScrn) \ + (RADEONPortPrivPtr)((RADEONPTR(pScrn))->adaptor->pPortPrivates[0].ptr) + +void RADEONInitVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; + XF86VideoAdaptorPtr newAdaptor = NULL; + int num_adaptors; + + newAdaptor = RADEONSetupImageVideo(pScreen); + RADEONInitOffscreenImages(pScreen); + num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); + + if(newAdaptor) { + if(!num_adaptors) { + num_adaptors = 1; + adaptors = &newAdaptor; + } else { + newAdaptors = /* need to free this someplace */ + xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); + if(newAdaptors) { + memcpy(newAdaptors, adaptors, num_adaptors * + sizeof(XF86VideoAdaptorPtr)); + newAdaptors[num_adaptors] = newAdaptor; + adaptors = newAdaptors; + num_adaptors++; + } + } + } + + if(num_adaptors) + xf86XVScreenInit(pScreen, adaptors, num_adaptors); + + if(newAdaptors) + xfree(newAdaptors); +} + +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding = +{ + 0, + "XV_IMAGE", + 2048, 2048, + {1, 1} +}; + +#define NUM_FORMATS 12 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = +{ + {8, TrueColor}, {8, DirectColor}, {8, PseudoColor}, + {8, GrayScale}, {8, StaticGray}, {8, StaticColor}, + {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, + {15, DirectColor}, {16, DirectColor}, {24, DirectColor} +}; + + +#define NUM_ATTRIBUTES 9+3 + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = +{ + {XvSettable , 0, 1, "XV_SET_DEFAULTS"}, + {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"}, + {XvSettable | XvGettable, 0, ~0, "XV_COLORKEY"}, + {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}, + {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, + {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, + {XvSettable | XvGettable, -1000, 1000, "XV_COLOR"}, + {XvSettable | XvGettable, -1000, 1000, "XV_HUE"}, + {XvSettable | XvGettable, -1000, 1000, "XV_RED_INTENSITY"}, + {XvSettable | XvGettable, -1000, 1000, "XV_GREEN_INTENSITY"}, + {XvSettable | XvGettable, -1000, 1000, "XV_BLUE_INTENSITY"}, +}; + +#define NUM_IMAGES 4 + +static XF86ImageRec Images[NUM_IMAGES] = +{ + XVIMAGE_YUY2, + XVIMAGE_UYVY, + XVIMAGE_YV12, + XVIMAGE_I420 +}; + +/* Reference color space transform data */ +typedef struct tagREF_TRANSFORM +{ + float RefLuma; + float RefRCb; + float RefRCr; + float RefGCb; + float RefGCr; + float RefBCb; + float RefBCr; +} REF_TRANSFORM; + +/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces */ +REF_TRANSFORM trans[2] = +{ + {1.1678, 0.0, 1.6007, -0.3929, -0.8154, 2.0232, 0.0}, /* BT.601 */ + {1.1678, 0.0, 1.7980, -0.2139, -0.5345, 2.1186, 0.0} /* BT.709 */ +}; + + +/* Gamma curve definition */ +typedef struct +{ + unsigned int gammaReg; + unsigned int gammaSlope; + unsigned int gammaOffset; +} GAMMA_SETTINGS; + +/* Recommended gamma curve parameters */ +GAMMA_SETTINGS def_gamma[18] = +{ + {RADEON_OV0_GAMMA_000_00F, 0x100, 0x0000}, + {RADEON_OV0_GAMMA_010_01F, 0x100, 0x0020}, + {RADEON_OV0_GAMMA_020_03F, 0x100, 0x0040}, + {RADEON_OV0_GAMMA_040_07F, 0x100, 0x0080}, + {RADEON_OV0_GAMMA_080_0BF, 0x100, 0x0100}, + {RADEON_OV0_GAMMA_0C0_0FF, 0x100, 0x0100}, + {RADEON_OV0_GAMMA_100_13F, 0x100, 0x0200}, + {RADEON_OV0_GAMMA_140_17F, 0x100, 0x0200}, + {RADEON_OV0_GAMMA_180_1BF, 0x100, 0x0300}, + {RADEON_OV0_GAMMA_1C0_1FF, 0x100, 0x0300}, + {RADEON_OV0_GAMMA_200_23F, 0x100, 0x0400}, + {RADEON_OV0_GAMMA_240_27F, 0x100, 0x0400}, + {RADEON_OV0_GAMMA_280_2BF, 0x100, 0x0500}, + {RADEON_OV0_GAMMA_2C0_2FF, 0x100, 0x0500}, + {RADEON_OV0_GAMMA_300_33F, 0x100, 0x0600}, + {RADEON_OV0_GAMMA_340_37F, 0x100, 0x0600}, + {RADEON_OV0_GAMMA_380_3BF, 0x100, 0x0700}, + {RADEON_OV0_GAMMA_3C0_3FF, 0x100, 0x0700} +}; + +/**************************************************************************** + * SetTransform * + * Function: Calculates and sets color space transform from supplied * + * reference transform, gamma, brightness, contrast, hue and * + * saturation. * + * Inputs: bright - brightness * + * cont - contrast * + * sat - saturation * + * hue - hue * + * red_intensity - intensity of red component * + * green_intensity - intensity of green component * + * blue_intensity - intensity of blue component * + * ref - index to the table of refernce transforms * + * Outputs: NONE * + ****************************************************************************/ + +static void RADEONSetTransform (ScrnInfoPtr pScrn, + float bright, + float cont, + float sat, + float hue, + float red_intensity, + float green_intensity, + float blue_intensity, + CARD32 ref) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + float OvHueSin, OvHueCos; + float CAdjLuma, CAdjOff; + float CAdjRCb, CAdjRCr; + float CAdjGCb, CAdjGCr; + float CAdjBCb, CAdjBCr; + float RedAdj,GreenAdj,BlueAdj; + float OvLuma, OvROff, OvGOff, OvBOff; + float OvRCb, OvRCr; + float OvGCb, OvGCr; + float OvBCb, OvBCr; + float Loff = 64.0; + float Coff = 512.0f; + + CARD32 dwOvLuma, dwOvROff, dwOvGOff, dwOvBOff; + CARD32 dwOvRCb, dwOvRCr; + CARD32 dwOvGCb, dwOvGCr; + CARD32 dwOvBCb, dwOvBCr; + + if (ref >= 2) + return; + + OvHueSin = sin(hue); + OvHueCos = cos(hue); + + CAdjLuma = cont * trans[ref].RefLuma; + CAdjOff = cont * trans[ref].RefLuma * bright * 1023.0; + RedAdj = cont * trans[ref].RefLuma * red_intensity * 1023.0; + GreenAdj = cont * trans[ref].RefLuma * green_intensity * 1023.0; + BlueAdj = cont * trans[ref].RefLuma * blue_intensity * 1023.0; + + CAdjRCb = sat * -OvHueSin * trans[ref].RefRCr; + CAdjRCr = sat * OvHueCos * trans[ref].RefRCr; + CAdjGCb = sat * (OvHueCos * trans[ref].RefGCb - OvHueSin * trans[ref].RefGCr); + CAdjGCr = sat * (OvHueSin * trans[ref].RefGCb + OvHueCos * trans[ref].RefGCr); + CAdjBCb = sat * OvHueCos * trans[ref].RefBCb; + CAdjBCr = sat * OvHueSin * trans[ref].RefBCb; + +#if 0 /* default constants */ + CAdjLuma = 1.16455078125; + + CAdjRCb = 0.0; + CAdjRCr = 1.59619140625; + CAdjGCb = -0.39111328125; + CAdjGCr = -0.8125; + CAdjBCb = 2.01708984375; + CAdjBCr = 0; +#endif + OvLuma = CAdjLuma; + OvRCb = CAdjRCb; + OvRCr = CAdjRCr; + OvGCb = CAdjGCb; + OvGCr = CAdjGCr; + OvBCb = CAdjBCb; + OvBCr = CAdjBCr; + OvROff = RedAdj + CAdjOff - + OvLuma * Loff - (OvRCb + OvRCr) * Coff; + OvGOff = GreenAdj + CAdjOff - + OvLuma * Loff - (OvGCb + OvGCr) * Coff; + OvBOff = BlueAdj + CAdjOff - + OvLuma * Loff - (OvBCb + OvBCr) * Coff; +#if 0 /* default constants */ + OvROff = -888.5; + OvGOff = 545; + OvBOff = -1104; +#endif + + dwOvROff = ((INT32)(OvROff * 2.0)) & 0x1fff; + dwOvGOff = ((INT32)(OvGOff * 2.0)) & 0x1fff; + dwOvBOff = ((INT32)(OvBOff * 2.0)) & 0x1fff; + /* + * Whatever docs say about R200 having 3.8 format instead of 3.11 + * as in Radeon is a lie + * Or more precisely the location of bit fields is a lie + */ + if(1 || info->ChipFamily < CHIP_FAMILY_R200) + { + dwOvLuma =(((INT32)(OvLuma * 2048.0))&0x7fff)<<17; + dwOvRCb = (((INT32)(OvRCb * 2048.0))&0x7fff)<<1; + dwOvRCr = (((INT32)(OvRCr * 2048.0))&0x7fff)<<17; + dwOvGCb = (((INT32)(OvGCb * 2048.0))&0x7fff)<<1; + dwOvGCr = (((INT32)(OvGCr * 2048.0))&0x7fff)<<17; + dwOvBCb = (((INT32)(OvBCb * 2048.0))&0x7fff)<<1; + dwOvBCr = (((INT32)(OvBCr * 2048.0))&0x7fff)<<17; + } + else + { + dwOvLuma = (((INT32)(OvLuma * 256.0))&0x7ff)<<20; + dwOvRCb = (((INT32)(OvRCb * 256.0))&0x7ff)<<4; + dwOvRCr = (((INT32)(OvRCr * 256.0))&0x7ff)<<20; + dwOvGCb = (((INT32)(OvGCb * 256.0))&0x7ff)<<4; + dwOvGCr = (((INT32)(OvGCr * 256.0))&0x7ff)<<20; + dwOvBCb = (((INT32)(OvBCb * 256.0))&0x7ff)<<4; + dwOvBCr = (((INT32)(OvBCr * 256.0))&0x7ff)<<20; + } + OUTREG(RADEON_OV0_LIN_TRANS_A, dwOvRCb | dwOvLuma); + OUTREG(RADEON_OV0_LIN_TRANS_B, dwOvROff | dwOvRCr); + OUTREG(RADEON_OV0_LIN_TRANS_C, dwOvGCb | dwOvLuma); + OUTREG(RADEON_OV0_LIN_TRANS_D, dwOvGOff | dwOvGCr); + OUTREG(RADEON_OV0_LIN_TRANS_E, dwOvBCb | dwOvLuma); + OUTREG(RADEON_OV0_LIN_TRANS_F, dwOvBOff | dwOvBCr); +} + +static void RADEONSetColorKey(ScrnInfoPtr pScrn, CARD32 colorKey) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 min, max; + CARD8 r, g, b; + + if (info->CurrentLayout.depth > 8) + { + CARD32 rbits, gbits, bbits; + + rbits = (colorKey & pScrn->mask.red) >> pScrn->offset.red; + gbits = (colorKey & pScrn->mask.green) >> pScrn->offset.green; + bbits = (colorKey & pScrn->mask.blue) >> pScrn->offset.blue; + + r = rbits << (8 - pScrn->weight.red); + g = gbits << (8 - pScrn->weight.green); + b = bbits << (8 - pScrn->weight.blue); + } + else + { + CARD32 bits; + + bits = colorKey & ((1 << info->CurrentLayout.depth) - 1); + r = bits; + g = bits; + b = bits; + } + min = (r << 16) | (g << 8) | (b); + max = (0xff << 24) | (r << 16) | (g << 8) | (b); + + RADEONWaitForFifo(pScrn, 2); + OUTREG(RADEON_OV0_GRAPHICS_KEY_CLR_HIGH, max); + OUTREG(RADEON_OV0_GRAPHICS_KEY_CLR_LOW, min); +} + +void +RADEONResetVideo(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONPortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; + + if (info->accelOn) info->accel->Sync(pScrn); + + RADEONWaitForIdleMMIO(pScrn); + OUTREG(RADEON_OV0_SCALE_CNTL, 0x80000000); + OUTREG(RADEON_OV0_AUTO_FLIP_CNTL, 0); /* maybe */ + OUTREG(RADEON_OV0_EXCLUSIVE_HORZ, 0); + OUTREG(RADEON_OV0_FILTER_CNTL, 0x0000000f); + OUTREG(RADEON_OV0_KEY_CNTL, RADEON_GRAPHIC_KEY_FN_EQ | + RADEON_VIDEO_KEY_FN_FALSE | + RADEON_CMP_MIX_OR); + OUTREG(RADEON_OV0_TEST, 0); + OUTREG(RADEON_FCP_CNTL, RADEON_FCP0_SRC_GND); + OUTREG(RADEON_CAP0_TRIG_CNTL, 0); + RADEONSetColorKey(pScrn, pPriv->colorKey); + + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350) || + (info->ChipFamily == CHIP_FAMILY_R200) || + (info->ChipFamily == CHIP_FAMILY_RADEON)) { + int i; + + OUTREG(RADEON_OV0_LIN_TRANS_A, 0x12a20000); + OUTREG(RADEON_OV0_LIN_TRANS_B, 0x198a190e); + OUTREG(RADEON_OV0_LIN_TRANS_C, 0x12a2f9da); + OUTREG(RADEON_OV0_LIN_TRANS_D, 0xf2fe0442); + OUTREG(RADEON_OV0_LIN_TRANS_E, 0x12a22046); + OUTREG(RADEON_OV0_LIN_TRANS_F, 0x175f); + + /* + * Set default Gamma ramp: + * + * Of 18 segments for gamma curve, all segments in R200 (and + * newer) are programmable, while only lower 4 and upper 2 + * segments are programmable in the older Radeons. + */ + for (i = 0; i < 18; i++) { + OUTREG(def_gamma[i].gammaReg, + (def_gamma[i].gammaSlope<<16) | def_gamma[i].gammaOffset); + } + } else { + OUTREG(RADEON_OV0_LIN_TRANS_A, 0x12a00000); + OUTREG(RADEON_OV0_LIN_TRANS_B, 0x1990190e); + OUTREG(RADEON_OV0_LIN_TRANS_C, 0x12a0f9c0); + OUTREG(RADEON_OV0_LIN_TRANS_D, 0xf3000442); + OUTREG(RADEON_OV0_LIN_TRANS_E, 0x12a02040); + OUTREG(RADEON_OV0_LIN_TRANS_F, 0x175f); + } +} + + +static XF86VideoAdaptorPtr +RADEONAllocAdaptor(ScrnInfoPtr pScrn) +{ + XF86VideoAdaptorPtr adapt; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPortPrivPtr pPriv; + unsigned char *RADEONMMIO = info->MMIO; + + if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) + return NULL; + + if(!(pPriv = xcalloc(1, sizeof(RADEONPortPrivRec) + sizeof(DevUnion)))) + { + xfree(adapt); + return NULL; + } + + adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); + adapt->pPortPrivates[0].ptr = (pointer)pPriv; + + pPriv->colorKey = info->videoKey; + pPriv->doubleBuffer = TRUE; + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->transform_index = 0; + pPriv->saturation = 0; + pPriv->contrast = 0; + pPriv->red_intensity = 0; + pPriv->green_intensity = 0; + pPriv->blue_intensity = 0; + pPriv->hue = 0; + pPriv->currentBuffer = 0; + pPriv->autopaint_colorkey = TRUE; + + /* + * Unlike older Mach64 chips, RADEON has only two ECP settings: + * 0 for PIXCLK < 175Mhz, and 1 (divide by 2) + * for higher clocks, sure makes life nicer + */ + if(info->ModeReg.dot_clock_freq < 17500) + pPriv->ecp_div = 0; + else + pPriv->ecp_div = 1; + +#if 0 + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dotclock is %g Mhz, setting ecp_div to %d\n", info->ModeReg.dot_clock_freq/100.0, pPriv->ecp_div); +#endif + + OUTPLL(RADEON_VCLK_ECP_CNTL, (INPLL(pScrn, RADEON_VCLK_ECP_CNTL) & + 0xfffffCff) | (pPriv->ecp_div << 8)); + + if ((info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200) || + (info->ChipFamily == CHIP_FAMILY_RS300)) { + /* Force the overlay clock on for integrated chips + */ + OUTPLL(RADEON_VCLK_ECP_CNTL, (INPLL(pScrn, RADEON_VCLK_ECP_CNTL) | (1<<18))); + } + + info->adaptor = adapt; + + return adapt; +} + +static XF86VideoAdaptorPtr +RADEONSetupImageVideo(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONPortPrivPtr pPriv; + XF86VideoAdaptorPtr adapt; + + if(!(adapt = RADEONAllocAdaptor(pScrn))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "ATI Radeon Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = &DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 1; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pAttributes = Attributes; + adapt->nImages = NUM_IMAGES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = RADEONStopVideo; + adapt->SetPortAttribute = RADEONSetPortAttribute; + adapt->GetPortAttribute = RADEONGetPortAttribute; + adapt->QueryBestSize = RADEONQueryBestSize; + adapt->PutImage = RADEONPutImage; + adapt->QueryImageAttributes = RADEONQueryImageAttributes; + + pPriv = (RADEONPortPrivPtr)(adapt->pPortPrivates[0].ptr); + REGION_NULL(pScreen, &(pPriv->clip)); + + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvSaturation = MAKE_ATOM("XV_SATURATION"); + xvColor = MAKE_ATOM("XV_COLOR"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER"); + xvHue = MAKE_ATOM("XV_HUE"); + xvRedIntensity = MAKE_ATOM("XV_RED_INTENSITY"); + xvGreenIntensity = MAKE_ATOM("XV_GREEN_INTENSITY"); + xvBlueIntensity = MAKE_ATOM("XV_BLUE_INTENSITY"); + + xvAutopaintColorkey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); + xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS"); + + RADEONResetVideo(pScrn); + + return adapt; +} + +static void +RADEONStopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; + + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + + if(cleanup) { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + RADEONWaitForFifo(pScrn, 2); + OUTREG(RADEON_OV0_SCALE_CNTL, 0); + } + if(info->videoLinear) { + xf86FreeOffscreenLinear(info->videoLinear); + info->videoLinear = NULL; + } + pPriv->videoStatus = 0; + } else { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + pPriv->videoStatus |= OFF_TIMER; + pPriv->offTime = currentTime.milliseconds + OFF_DELAY; + } + } +} + +static int +RADEONSetPortAttribute(ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; + Bool setTransform = FALSE; + + info->accel->Sync(pScrn); + +#define RTFSaturation(a) (1.0 + ((a)*1.0)/1000.0) +#define RTFBrightness(a) (((a)*1.0)/2000.0) +#define RTFIntensity(a) (((a)*1.0)/2000.0) +#define RTFContrast(a) (1.0 + ((a)*1.0)/1000.0) +#define RTFHue(a) (((a)*3.1416)/1000.0) +#define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v)) + + if(attribute == xvAutopaintColorkey) + { + pPriv->autopaint_colorkey = ClipValue (value, 0, 1); + } + else if(attribute == xvSetDefaults) + { + pPriv->autopaint_colorkey = TRUE; + pPriv->brightness = 0; + pPriv->saturation = 0; + pPriv->contrast = 0; + pPriv->hue = 0; + pPriv->red_intensity = 0; + pPriv->green_intensity = 0; + pPriv->blue_intensity = 0; + pPriv->doubleBuffer = FALSE; + setTransform = TRUE; + } + else if(attribute == xvBrightness) + { + pPriv->brightness = ClipValue (value, -1000, 1000); + setTransform = TRUE; + } + else if((attribute == xvSaturation) || (attribute == xvColor)) + { + pPriv->saturation = ClipValue (value, -1000, 1000); + setTransform = TRUE; + } + else if(attribute == xvContrast) + { + pPriv->contrast = ClipValue (value, -1000, 1000); + setTransform = TRUE; + } + else if(attribute == xvHue) + { + pPriv->hue = ClipValue (value, -1000, 1000); + setTransform = TRUE; + } + else if(attribute == xvRedIntensity) + { + pPriv->red_intensity = ClipValue (value, -1000, 1000); + setTransform = TRUE; + } + else if(attribute == xvGreenIntensity) + { + pPriv->green_intensity = ClipValue (value, -1000, 1000); + setTransform = TRUE; + } + else if(attribute == xvBlueIntensity) + { + pPriv->blue_intensity = ClipValue (value, -1000, 1000); + setTransform = TRUE; + } + else if(attribute == xvDoubleBuffer) + { + pPriv->doubleBuffer = ClipValue (value, 0, 1); + pPriv->doubleBuffer = value; + } + else if(attribute == xvColorKey) + { + pPriv->colorKey = value; + RADEONSetColorKey (pScrn, pPriv->colorKey); + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + } + else + return BadMatch; + + if (setTransform) + { + RADEONSetTransform(pScrn, + RTFBrightness(pPriv->brightness), + RTFContrast(pPriv->contrast), + RTFSaturation(pPriv->saturation), + RTFHue(pPriv->hue), + RTFIntensity(pPriv->red_intensity), + RTFIntensity(pPriv->green_intensity), + RTFIntensity(pPriv->blue_intensity), + pPriv->transform_index); + } + + return Success; +} + +static int +RADEONGetPortAttribute(ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; + + if (info->accelOn) info->accel->Sync(pScrn); + + if(attribute == xvAutopaintColorkey) + *value = pPriv->autopaint_colorkey; + else if(attribute == xvBrightness) + *value = pPriv->brightness; + else if((attribute == xvSaturation) || (attribute == xvColor)) + *value = pPriv->saturation; + else if(attribute == xvContrast) + *value = pPriv->contrast; + else if(attribute == xvHue) + *value = pPriv->hue; + else if(attribute == xvRedIntensity) + *value = pPriv->red_intensity; + else if(attribute == xvGreenIntensity) + *value = pPriv->green_intensity; + else if(attribute == xvBlueIntensity) + *value = pPriv->blue_intensity; + else if(attribute == xvDoubleBuffer) + *value = pPriv->doubleBuffer ? 1 : 0; + else if(attribute == xvColorKey) + *value = pPriv->colorKey; + else + return BadMatch; + + return Success; +} + +static void +RADEONQueryBestSize( + 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 << 4)) + drw_w = vid_w >> 4; + if(vid_h > (drw_h << 4)) + drw_h = vid_h >> 4; + + *p_w = drw_w; + *p_h = drw_h; +} + +static void +RADEONCopyData( + unsigned char *src, + unsigned char *dst, + int srcPitch, + int dstPitch, + int h, + int w +){ + w <<= 1; + while(h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} + +static void +RADEONCopyMungedData( + unsigned char *src1, + unsigned char *src2, + unsigned char *src3, + unsigned char *dst1, + int srcPitch, + int srcPitch2, + int dstPitch, + int h, + int w +){ + CARD32 *dst; + CARD8 *s1, *s2, *s3; + int i, j; + + w >>= 1; + + for(j = 0; j < h; j++) { + dst = (pointer)dst1; + s1 = src1; s2 = src2; s3 = src3; + i = w; + while(i > 4) { + dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24); + dst[1] = s1[2] | (s1[3] << 16) | (s3[1] << 8) | (s2[1] << 24); + dst[2] = s1[4] | (s1[5] << 16) | (s3[2] << 8) | (s2[2] << 24); + dst[3] = s1[6] | (s1[7] << 16) | (s3[3] << 8) | (s2[3] << 24); + dst += 4; s2 += 4; s3 += 4; s1 += 8; + i -= 4; + } + while(i--) { + dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24); + dst++; s2++; s3++; + s1 += 2; + } + + dst1 += dstPitch; + src1 += srcPitch; + if(j & 1) { + src2 += srcPitch2; + src3 += srcPitch2; + } + } +} + + +static FBLinearPtr +RADEONAllocateMemory( + ScrnInfoPtr pScrn, + FBLinearPtr linear, + int size +){ + ScreenPtr pScreen; + FBLinearPtr new_linear; + + if(linear) { + if(linear->size >= size) + return linear; + + if(xf86ResizeOffscreenLinear(linear, size)) + return linear; + + xf86FreeOffscreenLinear(linear); + } + + pScreen = screenInfo.screens[pScrn->scrnIndex]; + + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, + NULL, NULL, NULL); + + if(!new_linear) { + int max_size; + + xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16, + PRIORITY_EXTREME); + + if(max_size < size) + return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, + NULL, NULL, NULL); + } + + return new_linear; +} + +static void +RADEONDisplayVideo( + ScrnInfoPtr pScrn, + int id, + int offset1, int offset2, + short width, short height, + int pitch, + int left, int right, int top, + BoxPtr dstBox, + short src_w, short src_h, + short drw_w, short drw_h +){ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int v_inc, h_inc, step_by, tmp; + int p1_h_accum_init, p23_h_accum_init; + int p1_v_accum_init; + int ecp_div; + int v_inc_shift; + int y_mult; + int x_off; + CARD32 scaler_src; + + /* Unlike older Mach64 chips, RADEON has only two ECP settings: 0 for PIXCLK < 175Mhz, and 1 (divide by 2) + for higher clocks, sure makes life nicer + + Here we need to find ecp_div again, as the user may have switched resolutions */ + if(info->ModeReg.dot_clock_freq < 17500) + ecp_div = 0; + else + ecp_div = 1; + + OUTPLL(RADEON_VCLK_ECP_CNTL, (INPLL(pScrn, RADEON_VCLK_ECP_CNTL) & 0xfffffCff) | (ecp_div << 8)); + + v_inc_shift = 20; + if (pScrn->currentMode->Flags & V_INTERLACE) + v_inc_shift++; + if (pScrn->currentMode->Flags & V_DBLSCAN) + v_inc_shift--; + if (pScrn->currentMode->Flags & RADEON_USE_RMX) { + v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h; + } else { + v_inc = (src_h << v_inc_shift) / drw_h; + } + h_inc = ((src_w << (12 + ecp_div)) / drw_w); + step_by = 1; + + while(h_inc >= (2 << 12)) { + step_by++; + h_inc >>= 1; + } + + /* keep everything in 16.16 */ + + offset1 += ((left >> 16) & ~7) << 1; + offset2 += ((left >> 16) & ~7) << 1; + + if (info->IsSecondary) { + offset1 += info->FbMapSize; + offset2 += info->FbMapSize; + } + + tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3); + p1_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0xf0000000); + + tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2); + p23_h_accum_init = ((tmp << 4) & 0x000f8000) | + ((tmp << 12) & 0x70000000); + + tmp = (top & 0x0000ffff) + 0x00018000; + p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001; + + left = (left >> 16) & 7; + + RADEONWaitForFifo(pScrn, 2); + OUTREG(RADEON_OV0_REG_LOAD_CNTL, 1); + if (info->accelOn) info->accel->Sync(pScrn); + while(!(INREG(RADEON_OV0_REG_LOAD_CNTL) & (1 << 3))); + + RADEONWaitForFifo(pScrn, 14); + OUTREG(RADEON_OV0_H_INC, h_inc | ((h_inc >> 1) << 16)); + OUTREG(RADEON_OV0_STEP_BY, step_by | (step_by << 8)); + + y_mult = 1; + if (pScrn->currentMode->Flags & V_DBLSCAN) + y_mult = 2; + x_off = 8; + + if ((info->ChipFamily == CHIP_FAMILY_R300) || + (info->ChipFamily == CHIP_FAMILY_R350) || + (info->ChipFamily == CHIP_FAMILY_RV350) || + (info->ChipFamily == CHIP_FAMILY_R200)) + x_off = 0; + + /* Put the hardware overlay on CRTC2: + * + * Since one hardware overlay can not be displayed on two heads + * at the same time, we might need to consider using software + * rendering for the second head. + */ + if ((info->Clone && info->OverlayOnCRTC2) || info->IsSecondary) { + x_off = 0; + OUTREG(RADEON_OV1_Y_X_START, ((dstBox->x1 + + x_off + - info->CloneFrameX0 + + pScrn->frameX0) | + ((dstBox->y1*y_mult - + info->CloneFrameY0 + + pScrn->frameY0) << 16))); + OUTREG(RADEON_OV1_Y_X_END, ((dstBox->x2 + + x_off + - info->CloneFrameX0 + + pScrn->frameX0) | + ((dstBox->y2*y_mult + - info->CloneFrameY0 + + pScrn->frameY0) << 16))); + scaler_src = (1 << 14); + } else { + OUTREG(RADEON_OV0_Y_X_START, ((dstBox->x1 + x_off) | + ((dstBox->y1*y_mult) << 16))); + OUTREG(RADEON_OV0_Y_X_END, ((dstBox->x2 + x_off) | + ((dstBox->y2*y_mult) << 16))); + scaler_src = 0; + } + + OUTREG(RADEON_OV0_V_INC, v_inc); + OUTREG(RADEON_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16)); + OUTREG(RADEON_OV0_VID_BUF_PITCH0_VALUE, pitch); + OUTREG(RADEON_OV0_VID_BUF_PITCH1_VALUE, pitch); + OUTREG(RADEON_OV0_P1_X_START_END, (src_w + left - 1) | (left << 16)); + left >>= 1; src_w >>= 1; + OUTREG(RADEON_OV0_P2_X_START_END, (src_w + left - 1) | (left << 16)); + OUTREG(RADEON_OV0_P3_X_START_END, (src_w + left - 1) | (left << 16)); + OUTREG(RADEON_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0); + OUTREG(RADEON_OV0_VID_BUF1_BASE_ADRS, offset2 & 0xfffffff0); + OUTREG(RADEON_OV0_VID_BUF2_BASE_ADRS, offset1 & 0xfffffff0); + + RADEONWaitForFifo(pScrn, 9); + OUTREG(RADEON_OV0_VID_BUF3_BASE_ADRS, offset2 & 0xfffffff0); + OUTREG(RADEON_OV0_VID_BUF4_BASE_ADRS, offset1 & 0xfffffff0); + OUTREG(RADEON_OV0_VID_BUF5_BASE_ADRS, offset2 & 0xfffffff0); + OUTREG(RADEON_OV0_P1_V_ACCUM_INIT, p1_v_accum_init); + OUTREG(RADEON_OV0_P1_H_ACCUM_INIT, p1_h_accum_init); + OUTREG(RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init); + +#if 0 + if(id == FOURCC_UYVY) + OUTREG(RADEON_OV0_SCALE_CNTL, 0x41008C03); + else + OUTREG(RADEON_OV0_SCALE_CNTL, 0x41008B03); +#endif + + if (id == FOURCC_UYVY) + OUTREG(RADEON_OV0_SCALE_CNTL, (RADEON_SCALER_SOURCE_YVYU422 + | RADEON_SCALER_ADAPTIVE_DEINT + | RADEON_SCALER_SMART_SWITCH + | RADEON_SCALER_DOUBLE_BUFFER + | RADEON_SCALER_ENABLE + | scaler_src)); + else + OUTREG(RADEON_OV0_SCALE_CNTL, (RADEON_SCALER_SOURCE_VYUY422 + | RADEON_SCALER_ADAPTIVE_DEINT + | RADEON_SCALER_SMART_SWITCH + | RADEON_SCALER_DOUBLE_BUFFER + | RADEON_SCALER_ENABLE + | scaler_src)); + + OUTREG(RADEON_OV0_REG_LOAD_CNTL, 0); +} + + +static int +RADEONPutImage( + 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 +){ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; + INT32 xa, xb, ya, yb; + unsigned char *dst_start; + int new_size, offset, s2offset, s3offset; + int srcPitch, srcPitch2, dstPitch; + int top, left, npixels, nlines, bpp; + BoxRec dstBox; + CARD32 tmp; +#if X_BYTE_ORDER == X_BIG_ENDIAN + unsigned char *RADEONMMIO = info->MMIO; + CARD32 surface_cntl = INREG(RADEON_SURFACE_CNTL); + + OUTREG(RADEON_SURFACE_CNTL, (surface_cntl | + RADEON_NONSURF_AP0_SWP_32BPP) & ~RADEON_NONSURF_AP0_SWP_16BPP); +#endif + + /* + * s2offset, s3offset - byte offsets into U and V plane of the + * source where copying starts. Y plane is + * done by editing "buf". + * + * offset - byte offset to the first line of the destination. + * + * dst_start - byte address to the first displayed pel. + * + */ + + /* make the compiler happy */ + s2offset = s3offset = srcPitch2 = 0; + + if(src_w > (drw_w << 4)) + drw_w = src_w >> 4; + if(src_h > (drw_h << 4)) + drw_h = src_h >> 4; + + /* Clip */ + xa = src_x; + xb = src_x + src_w; + ya = src_y; + yb = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, + clipBoxes, width, height)) + return Success; + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + bpp = pScrn->bitsPerPixel >> 3; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + dstPitch = ((width << 1) + 15) & ~15; + new_size = ((dstPitch * height) + bpp - 1) / bpp; + srcPitch = (width + 3) & ~3; + s2offset = srcPitch * height; + srcPitch2 = ((width >> 1) + 3) & ~3; + s3offset = (srcPitch2 * (height >> 1)) + s2offset; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + dstPitch = ((width << 1) + 15) & ~15; + new_size = ((dstPitch * height) + bpp - 1) / bpp; + srcPitch = (width << 1); + break; + } + + if(!(info->videoLinear = RADEONAllocateMemory(pScrn, info->videoLinear, + pPriv->doubleBuffer ? (new_size << 1) : new_size))) + { + return BadAlloc; + } + + pPriv->currentBuffer ^= 1; + + /* copy data */ + top = ya >> 16; + left = (xa >> 16) & ~1; + npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left; + + offset = (info->videoLinear->offset * bpp) + (top * dstPitch); + if(pPriv->doubleBuffer) + offset += pPriv->currentBuffer * new_size * bpp; + + dst_start = info->FB + offset; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + top &= ~1; + dst_start += left << 1; + tmp = ((top >> 1) * srcPitch2) + (left >> 1); + s2offset += tmp; + s3offset += tmp; + if(id == FOURCC_I420) { + tmp = s2offset; + s2offset = s3offset; + s3offset = tmp; + } + nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top; +#if X_BYTE_ORDER == X_BIG_ENDIAN + OUTREG(RADEON_SURFACE_CNTL, (surface_cntl | RADEON_NONSURF_AP0_SWP_32BPP) + & ~RADEON_NONSURF_AP0_SWP_16BPP); +#endif + RADEONCopyMungedData(buf + (top * srcPitch) + left, buf + s2offset, + buf + s3offset, dst_start, srcPitch, srcPitch2, + dstPitch, nlines, npixels); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + left <<= 1; + buf += (top * srcPitch) + left; + nlines = ((yb + 0xffff) >> 16) - top; + dst_start += left; +#if X_BYTE_ORDER == X_BIG_ENDIAN + OUTREG(RADEON_SURFACE_CNTL, surface_cntl & ~(RADEON_NONSURF_AP0_SWP_32BPP + | RADEON_NONSURF_AP0_SWP_16BPP)); +#endif + RADEONCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels); + break; + } + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* restore byte swapping */ + OUTREG(RADEON_SURFACE_CNTL, surface_cntl); +#endif + + /* update cliplist */ + if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) + { + REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); + /* draw these */ + if(pPriv->autopaint_colorkey) + xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); + } + + RADEONDisplayVideo(pScrn, id, offset, offset, width, height, dstPitch, + xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h); + + pPriv->videoStatus = CLIENT_VIDEO_ON; + + info->VideoTimerCallback = RADEONVideoTimerCallback; + + return Success; +} + + +static int +RADEONQueryImageAttributes( + ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets +){ + int size, tmp; + + if(*w > 2048) *w = 2048; + if(*h > 2048) *h = 2048; + + *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 +RADEONVideoTimerCallback(ScrnInfoPtr pScrn, Time now) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr; + + if(pPriv->videoStatus & TIMER_MASK) { + if(pPriv->videoStatus & OFF_TIMER) { + if(pPriv->offTime < now) { + unsigned char *RADEONMMIO = info->MMIO; + OUTREG(RADEON_OV0_SCALE_CNTL, 0); + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = now + FREE_DELAY; + } + } else { /* FREE_TIMER */ + if(pPriv->freeTime < now) { + if(info->videoLinear) { + xf86FreeOffscreenLinear(info->videoLinear); + info->videoLinear = NULL; + } + pPriv->videoStatus = 0; + info->VideoTimerCallback = NULL; + } + } + } else /* shouldn't get here */ + info->VideoTimerCallback = NULL; +} + +/****************** Offscreen stuff ***************/ +typedef struct { + FBLinearPtr linear; + Bool isOn; +} OffscreenPrivRec, * OffscreenPrivPtr; + +static int +RADEONAllocateSurface( + ScrnInfoPtr pScrn, + int id, + unsigned short w, + unsigned short h, + XF86SurfacePtr surface +){ + FBLinearPtr linear; + int pitch, size, bpp; + OffscreenPrivPtr pPriv; + if((w > 1024) || (h > 1024)) + return BadAlloc; + + w = (w + 1) & ~1; + pitch = ((w << 1) + 15) & ~15; + bpp = pScrn->bitsPerPixel >> 3; + size = ((pitch * h) + bpp - 1) / bpp; + + if(!(linear = RADEONAllocateMemory(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 * bpp; + surface->devPrivate.ptr = (pointer)pPriv; + + return Success; +} + +static int +RADEONStopSurface( + XF86SurfacePtr surface +){ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; + RADEONInfoPtr info = RADEONPTR(surface->pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if(pPriv->isOn) { + OUTREG(RADEON_OV0_SCALE_CNTL, 0); + pPriv->isOn = FALSE; + } + return Success; +} + + +static int +RADEONFreeSurface( + XF86SurfacePtr surface +){ + OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; + + if(pPriv->isOn) + RADEONStopSurface(surface); + xf86FreeOffscreenLinear(pPriv->linear); + xfree(surface->pitches); + xfree(surface->offsets); + xfree(surface->devPrivate.ptr); + + return Success; +} + +static int +RADEONGetSurfaceAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value +){ + return RADEONGetPortAttribute(pScrn, attribute, value, + (pointer)(GET_PORT_PRIVATE(pScrn))); +} + +static int +RADEONSetSurfaceAttribute( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 value +){ + return RADEONSetPortAttribute(pScrn, attribute, value, + (pointer)(GET_PORT_PRIVATE(pScrn))); +} + + +static int +RADEONDisplaySurface( + 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; + + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPortPrivPtr portPriv = info->adaptor->pPortPrivates[0].ptr; + + INT32 xa, ya, xb, yb; + BoxRec dstBox; + + if (src_w > (drw_w << 4)) + drw_w = src_w >> 4; + if (src_h > (drw_h << 4)) + drw_h = src_h >> 4; + + xa = src_x; + xb = src_x + src_w; + ya = src_y; + yb = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if (!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, + surface->width, surface->height)) + return Success; + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + RADEONResetVideo(pScrn); + + RADEONDisplayVideo(pScrn, surface->id, + surface->offsets[0], surface->offsets[0], + surface->width, surface->height, surface->pitches[0], + xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h); + + if (portPriv->autopaint_colorkey) + xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes); + + pPriv->isOn = TRUE; + /* we've prempted the XvImage stream so set its free timer */ + if (portPriv->videoStatus & CLIENT_VIDEO_ON) { + REGION_EMPTY(pScrn->pScreen, &portPriv->clip); + UpdateCurrentTime(); + portPriv->videoStatus = FREE_TIMER; + portPriv->freeTime = currentTime.milliseconds + FREE_DELAY; + info->VideoTimerCallback = RADEONVideoTimerCallback; + } + + return Success; +} + + +static void +RADEONInitOffscreenImages(ScreenPtr pScreen) +{ +/* ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); */ + XF86OffscreenImagePtr offscreenImages; + /* need to free this someplace */ + + if (!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)))) + return; + + offscreenImages[0].image = &Images[0]; + offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | + VIDEO_CLIP_TO_VIEWPORT; + offscreenImages[0].alloc_surface = RADEONAllocateSurface; + offscreenImages[0].free_surface = RADEONFreeSurface; + offscreenImages[0].display = RADEONDisplaySurface; + offscreenImages[0].stop = RADEONStopSurface; + offscreenImages[0].setAttribute = RADEONSetSurfaceAttribute; + offscreenImages[0].getAttribute = RADEONGetSurfaceAttribute; + offscreenImages[0].max_width = 1024; + offscreenImages[0].max_height = 1024; + offscreenImages[0].num_attributes = NUM_ATTRIBUTES; + offscreenImages[0].attributes = Attributes; + + xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1); +} diff --git a/src/radeon_video.h b/src/radeon_video.h new file mode 100644 index 0000000..41c08b8 --- /dev/null +++ b/src/radeon_video.h @@ -0,0 +1,93 @@ +#ifndef __RADEON_VIDEO_H__ +#define __RADEON_VIDEO_H__ + +#include "xf86i2c.h" +#include "fi1236.h" +#include "msp3430.h" +#include "tda9885.h" +#include "i2c_def.h" + +#include "generic_bus.h" +#include "theatre.h" + +/* Xvideo port struct */ +typedef struct { + CARD32 transform_index; + CARD32 gamma; /* gamma value x 1000 */ + int brightness; + int saturation; + int hue; + int contrast; + int red_intensity; + int green_intensity; + int blue_intensity; + int ecp_div; + + /* overlay composition mode */ + int alpha_mode; /* 0 = key mode, 1 = global mode */ + int ov_alpha; + int gr_alpha; + + /* i2c bus and devices */ + I2CBusPtr i2c; + CARD32 radeon_i2c_timing; + CARD32 radeon_M; + CARD32 radeon_N; + CARD32 i2c_status; + CARD32 i2c_cntl; + + FI1236Ptr fi1236; + CARD8 tuner_type; + MSP3430Ptr msp3430; + TDA9885Ptr tda9885; + + /* VIP bus and devices */ + GENERIC_BUS_Ptr VIP; + TheatrePtr theatre; + + Bool video_stream_active; + int encoding; + CARD32 frequency; + int volume; + Bool mute; + int sap_channel; + int v; + CARD32 adjustment; /* general purpose variable */ + +#define METHOD_BOB 0 +#define METHOD_SINGLE 1 +#define METHOD_WEAVE 2 +#define METHOD_ADAPTIVE 3 + + int overlay_deinterlacing_method; + int overlay_scaler_buffer_width; + + int capture_vbi_data; + + int dec_brightness; + int dec_saturation; + int dec_hue; + int dec_contrast; + + Bool doubleBuffer; + unsigned char currentBuffer; + RegionRec clip; + CARD32 colorKey; + CARD32 videoStatus; + Time offTime; + Time freeTime; + Bool autopaint_colorkey; + Bool crt2; /* 0=CRT1, 1=CRT2 */ + + Atom device_id, location_id, instance_id; +} RADEONPortPrivRec, *RADEONPortPrivPtr; + + +void RADEONInitI2C(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); +void RADEONResetI2C(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); + +void RADEONVIP_init(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); +void RADEONVIP_reset(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv); + + +#endif diff --git a/src/radeon_vip.c b/src/radeon_vip.c new file mode 100644 index 0000000..d1ac15f --- /dev/null +++ b/src/radeon_vip.c @@ -0,0 +1,200 @@ +#include "radeon.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_reg.h" +#include "Xv.h" +#include "radeon_video.h" + +#include "xf86.h" +#include "xf86PciInfo.h" + +#include "generic_bus.h" + +#define VIP_NAME "RADEON VIP BUS" +#define VIP_TYPE "ATI VIP BUS" + +/* Status defines */ +#define VIP_BUSY 0 +#define VIP_IDLE 1 +#define VIP_RESET 2 + +static Bool RADEONVIP_ioctl(GENERIC_BUS_Ptr b, long ioctl, long arg1, char *arg2) +{ + long count; + switch(ioctl){ + case GB_IOCTL_GET_NAME: + count=strlen(VIP_NAME)+1; + if(count>arg1)return FALSE; + memcpy(arg2,VIP_NAME,count); + return TRUE; + + case GB_IOCTL_GET_TYPE: + count=strlen(VIP_TYPE)+1; + if(count>arg1)return FALSE; + memcpy(arg2,VIP_TYPE,count); + return TRUE; + + default: + return FALSE; + } +} + +static CARD32 RADEONVIP_idle(GENERIC_BUS_Ptr b) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + CARD32 timeout; + + RADEONWaitForIdleMMIO(pScrn); + timeout = INREG(RADEON_VIPH_TIMEOUT_STAT); + if(timeout & RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_STAT) /* lockup ?? */ + { + RADEONWaitForFifo(pScrn, 2); + OUTREG(RADEON_VIPH_TIMEOUT_STAT, (timeout & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_AK); + RADEONWaitForIdleMMIO(pScrn); + return (INREG(RADEON_VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_RESET; + } + RADEONWaitForIdleMMIO(pScrn); + return (INREG(RADEON_VIPH_CONTROL) & 0x2000) ? VIP_BUSY : VIP_IDLE ; +} + +/* address format: + ((device & 0x3)<<14) | (fifo << 12) | (addr) +*/ + +static Bool RADEONVIP_read(GENERIC_BUS_Ptr b, CARD32 address, CARD32 count, CARD8 *buffer) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 status,tmp; + + if((count!=1) && (count!=2) && (count!=4)) + { + xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Attempt to access VIP bus with non-stadard transaction length\n"); + return FALSE; + } + + RADEONWaitForFifo(pScrn, 2); + OUTREG(RADEON_VIPH_REG_ADDR, address | 0x2000); + write_mem_barrier(); + while(VIP_BUSY == (status = RADEONVIP_idle(b))); + if(VIP_IDLE != status) return FALSE; + +/* + disable RADEON_VIPH_REGR_DIS to enable VIP cycle. + The LSB of RADEON_VIPH_TIMEOUT_STAT are set to 0 + because 1 would have acknowledged various VIP + interrupts unexpectedly +*/ + RADEONWaitForIdleMMIO(pScrn); + OUTREG(RADEON_VIPH_TIMEOUT_STAT, INREG(RADEON_VIPH_TIMEOUT_STAT) & (0xffffff00 & ~RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS) ); + write_mem_barrier(); +/* + the value returned here is garbage. The read merely initiates + a register cycle +*/ + RADEONWaitForIdleMMIO(pScrn); + INREG(RADEON_VIPH_REG_DATA); + + while(VIP_BUSY == (status = RADEONVIP_idle(b))); + if(VIP_IDLE != status) return FALSE; +/* + set RADEON_VIPH_REGR_DIS so that the read won't take too long. +*/ + RADEONWaitForIdleMMIO(pScrn); + tmp=INREG(RADEON_VIPH_TIMEOUT_STAT); + OUTREG(RADEON_VIPH_TIMEOUT_STAT, (tmp & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); + write_mem_barrier(); + RADEONWaitForIdleMMIO(pScrn); + switch(count){ + case 1: + *buffer=(CARD8)(INREG(RADEON_VIPH_REG_DATA) & 0xff); + break; + case 2: + *(CARD16 *)buffer=(CARD16) (INREG(RADEON_VIPH_REG_DATA) & 0xffff); + break; + case 4: + *(CARD32 *)buffer=(CARD32) ( INREG(RADEON_VIPH_REG_DATA) & 0xffffffff); + break; + } + while(VIP_BUSY == (status = RADEONVIP_idle(b))); + if(VIP_IDLE != status) return FALSE; + /* + so that reading RADEON_VIPH_REG_DATA would not trigger unnecessary vip cycles. +*/ + OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xffffff00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); + write_mem_barrier(); + return TRUE; +} + +static Bool RADEONVIP_write(GENERIC_BUS_Ptr b, CARD32 address, CARD32 count, CARD8 *buffer) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + CARD32 status; + + + if((count!=4)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Attempt to access VIP bus with non-stadard transaction length\n"); + return FALSE; + } + + RADEONWaitForFifo(pScrn, 2); + OUTREG(RADEON_VIPH_REG_ADDR, address & (~0x2000)); + while(VIP_BUSY == (status = RADEONVIP_idle(b))); + + if(VIP_IDLE != status) return FALSE; + + RADEONWaitForFifo(pScrn, 2); + switch(count){ + case 4: + OUTREG(RADEON_VIPH_REG_DATA, *(CARD32 *)buffer); + break; + } + write_mem_barrier(); + while(VIP_BUSY == (status = RADEONVIP_idle(b))); + if(VIP_IDLE != status) return FALSE; + return TRUE; +} + +void RADEONVIP_reset(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + + RADEONWaitForIdleMMIO(pScrn); + switch(info->ChipFamily){ + case CHIP_FAMILY_RV250: + OUTREG(RADEON_VIPH_CONTROL, 0x003F0009); /* slowest, timeout in 16 phases */ + OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); + OUTREG(RADEON_VIPH_DV_LAT, 0x444400FF); /* set timeslice */ + OUTREG(RADEON_VIPH_BM_CHUNK, 0x0); + OUTREG(RADEON_TEST_DEBUG_CNTL, INREG(RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN)); + break; + default: + OUTREG(RADEON_VIPH_CONTROL, 0x003F0004); /* slowest, timeout in 16 phases */ + OUTREG(RADEON_VIPH_TIMEOUT_STAT, (INREG(RADEON_VIPH_TIMEOUT_STAT) & 0xFFFFFF00) | RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS); + OUTREG(RADEON_VIPH_DV_LAT, 0x444400FF); /* set timeslice */ + OUTREG(RADEON_VIPH_BM_CHUNK, 0x151); + OUTREG(RADEON_TEST_DEBUG_CNTL, INREG(RADEON_TEST_DEBUG_CNTL) & (~RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN)); + } +} + +void RADEONVIP_init(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) +{ + pPriv->VIP=xcalloc(1,sizeof(GENERIC_BUS_Rec)); + pPriv->VIP->scrnIndex=pScrn->scrnIndex; + pPriv->VIP->DriverPrivate.ptr=pPriv; + pPriv->VIP->ioctl=RADEONVIP_ioctl; + pPriv->VIP->read=RADEONVIP_read; + pPriv->VIP->write=RADEONVIP_write; + + RADEONVIP_reset(pScrn, pPriv); +} diff --git a/src/theatre.c b/src/theatre.c new file mode 100644 index 0000000..3ff0cb0 --- /dev/null +++ b/src/theatre.c @@ -0,0 +1,2201 @@ +#include "xf86.h" +#include "generic_bus.h" +#include "theatre.h" +#include "theatre_reg.h" + +#undef read +#undef write +#undef ioctl + +static Bool theatre_read(TheatrePtr t,CARD32 reg, CARD32 *data) +{ + if(t->theatre_num<0)return FALSE; + return t->VIP->read(t->VIP, ((t->theatre_num & 0x3)<<14) | reg,4, (CARD8 *) data); +} + +static Bool theatre_write(TheatrePtr t,CARD32 reg, CARD32 data) +{ + if(t->theatre_num<0)return FALSE; + return t->VIP->write(t->VIP,((t->theatre_num & 0x03)<<14) | reg,4, (CARD8 *) &data); +} + +#define RT_regr(reg,data) theatre_read(t,(reg),(data)) +#define RT_regw(reg,data) theatre_write(t,(reg),(data)) +#define VIP_TYPE "ATI VIP BUS" + + +TheatrePtr DetectTheatre(GENERIC_BUS_Ptr b) +{ + TheatrePtr t; + CARD32 i; + CARD32 val; + char s[20]; + + b->ioctl(b,GB_IOCTL_GET_TYPE,20,s); + if(strcmp(VIP_TYPE, s)){ + xf86DrvMsg(b->scrnIndex, X_ERROR, "DetectTheatre must be called with bus of type \"%s\", not \"%s\"\n", + VIP_TYPE, s); + return NULL; + } + + t = xcalloc(1,sizeof(TheatreRec)); + t->VIP = b; + t->theatre_num = -1; + t->mode=MODE_UNINITIALIZED; + + b->read(b, VIP_VIP_VENDOR_DEVICE_ID, 4, (CARD8 *)&val); + for(i=0;i<4;i++) + { + if(b->read(b, ((i & 0x03)<<14) | VIP_VIP_VENDOR_DEVICE_ID, 4, (CARD8 *)&val)) + { + if(val)xf86DrvMsg(b->scrnIndex, X_INFO, "Device %d on VIP bus ids as 0x%08x\n",i,val); + if(t->theatre_num>=0)continue; /* already found one instance */ + switch(val){ + case RT100_ATI_ID: + t->theatre_num=i; + t->theatre_id=RT100_ATI_ID; + break; + case RT200_ATI_ID: + t->theatre_num=i; + t->theatre_id=RT200_ATI_ID; + break; + } + } else { + xf86DrvMsg(b->scrnIndex, X_INFO, "No response from device %d on VIP bus\n",i); + } + } + if(t->theatre_num>=0)xf86DrvMsg(b->scrnIndex, X_INFO, "Detected Rage Theatre as device %d on VIP bus with id 0x%08x\n",t->theatre_num,t->theatre_id); + + if(t->theatre_id==RT200_ATI_ID){ + xf86DrvMsg(b->scrnIndex, X_INFO, "Rage Theatre 200 is not supported yet\n"); + t->theatre_num=-1; + } + + if(t->theatre_num < 0) + { + xfree(t); + return NULL; + } + + RT_regr(VIP_VIP_REVISION_ID, &val); + xf86DrvMsg(b->scrnIndex, X_INFO, "Detected Rage Theatre revision %8.8X\n", val); + +#if 0 +DumpRageTheatreRegsByName(t); +#endif + return t; +} + +enum +{ +fld_tmpReg1=0, +fld_tmpReg2, +fld_tmpReg3, +fld_LP_CONTRAST, +fld_LP_BRIGHTNESS, +fld_CP_HUE_CNTL, +fld_LUMA_FILTER, +fld_H_SCALE_RATIO, +fld_H_SHARPNESS, +fld_V_SCALE_RATIO, +fld_V_DEINTERLACE_ON, +fld_V_BYPSS, +fld_V_DITHER_ON, +fld_EVENF_OFFSET, +fld_ODDF_OFFSET, +fld_INTERLACE_DETECTED, +fld_VS_LINE_COUNT, +fld_VS_DETECTED_LINES, +fld_VS_ITU656_VB, +fld_VBI_CC_DATA, +fld_VBI_CC_WT, +fld_VBI_CC_WT_ACK, +fld_VBI_CC_HOLD, +fld_VBI_DECODE_EN, +fld_VBI_CC_DTO_P, +fld_VBI_20BIT_DTO_P, +fld_VBI_CC_LEVEL, +fld_VBI_20BIT_LEVEL, +fld_VBI_CLK_RUNIN_GAIN, +fld_H_VBI_WIND_START, +fld_H_VBI_WIND_END, +fld_V_VBI_WIND_START, +fld_V_VBI_WIND_END, +fld_VBI_20BIT_DATA0, +fld_VBI_20BIT_DATA1, +fld_VBI_20BIT_WT, +fld_VBI_20BIT_WT_ACK, +fld_VBI_20BIT_HOLD, +fld_VBI_CAPTURE_ENABLE, +fld_VBI_EDS_DATA, +fld_VBI_EDS_WT, +fld_VBI_EDS_WT_ACK, +fld_VBI_EDS_HOLD, +fld_VBI_SCALING_RATIO, +fld_VBI_ALIGNER_ENABLE, +fld_H_ACTIVE_START, +fld_H_ACTIVE_END, +fld_V_ACTIVE_START, +fld_V_ACTIVE_END, +fld_CH_HEIGHT, +fld_CH_KILL_LEVEL, +fld_CH_AGC_ERROR_LIM, +fld_CH_AGC_FILTER_EN, +fld_CH_AGC_LOOP_SPEED, +fld_HUE_ADJ, +fld_STANDARD_SEL, +fld_STANDARD_YC, +fld_ADC_PDWN, +fld_INPUT_SELECT, +fld_ADC_PREFLO, +fld_H_SYNC_PULSE_WIDTH, +fld_HS_GENLOCKED, +fld_HS_SYNC_IN_WIN, +fld_VIN_ASYNC_RST, +fld_DVS_ASYNC_RST, +fld_VIP_VENDOR_ID, +fld_VIP_DEVICE_ID, +fld_VIP_REVISION_ID, +fld_BLACK_INT_START, +fld_BLACK_INT_LENGTH, +fld_UV_INT_START, +fld_U_INT_LENGTH, +fld_V_INT_LENGTH, +fld_CRDR_ACTIVE_GAIN, +fld_CBDB_ACTIVE_GAIN, +fld_DVS_DIRECTION, +fld_DVS_VBI_CARD8_SWAP, +fld_DVS_CLK_SELECT, +fld_CONTINUOUS_STREAM, +fld_DVSOUT_CLK_DRV, +fld_DVSOUT_DATA_DRV, +fld_COMB_CNTL0, +fld_COMB_CNTL1, +fld_COMB_CNTL2, +fld_COMB_LENGTH, +fld_SYNCTIP_REF0, +fld_SYNCTIP_REF1, +fld_CLAMP_REF, +fld_AGC_PEAKWHITE, +fld_VBI_PEAKWHITE, +fld_WPA_THRESHOLD, +fld_WPA_TRIGGER_LO, +fld_WPA_TRIGGER_HIGH, +fld_LOCKOUT_START, +fld_LOCKOUT_END, +fld_CH_DTO_INC, +fld_PLL_SGAIN, +fld_PLL_FGAIN, +fld_CR_BURST_GAIN, +fld_CB_BURST_GAIN, +fld_VERT_LOCKOUT_START, +fld_VERT_LOCKOUT_END, +fld_H_IN_WIND_START, +fld_V_IN_WIND_START, +fld_H_OUT_WIND_WIDTH, +fld_V_OUT_WIND_WIDTH, +fld_HS_LINE_TOTAL, +fld_MIN_PULSE_WIDTH, +fld_MAX_PULSE_WIDTH, +fld_WIN_CLOSE_LIMIT, +fld_WIN_OPEN_LIMIT, +fld_VSYNC_INT_TRIGGER, +fld_VSYNC_INT_HOLD, +fld_VIN_M0, +fld_VIN_N0, +fld_MNFLIP_EN, +fld_VIN_P, +fld_REG_CLK_SEL, +fld_VIN_M1, +fld_VIN_N1, +fld_VIN_DRIVER_SEL, +fld_VIN_MNFLIP_REQ, +fld_VIN_MNFLIP_DONE, +fld_TV_LOCK_TO_VIN, +fld_TV_P_FOR_WINCLK, +fld_VINRST, +fld_VIN_CLK_SEL, +fld_VS_FIELD_BLANK_START, +fld_VS_FIELD_BLANK_END, +fld_VS_FIELD_IDLOCATION, +fld_VS_FRAME_TOTAL, +fld_SYNC_TIP_START, +fld_SYNC_TIP_LENGTH, +fld_GAIN_FORCE_DATA, +fld_GAIN_FORCE_EN, +fld_I_CLAMP_SEL, +fld_I_AGC_SEL, +fld_EXT_CLAMP_CAP, +fld_EXT_AGC_CAP, +fld_DECI_DITHER_EN, +fld_ADC_PREFHI, +fld_ADC_CH_GAIN_SEL, +fld_HS_PLL_SGAIN, +fld_NREn, +fld_NRGainCntl, +fld_NRBWTresh, +fld_NRGCTresh, +fld_NRCoefDespeclMode, +fld_GPIO_5_OE, +fld_GPIO_6_OE, +fld_GPIO_5_OUT, +fld_GPIO_6_OUT, + +regRT_MAX_REGS +} a; + + +typedef struct { + CARD8 size; + CARD32 fld_id; + CARD32 dwRegAddrLSBs; + CARD32 dwFldOffsetLSBs; + CARD32 dwMaskLSBs; + CARD32 addr2; + CARD32 offs2; + CARD32 mask2; + CARD32 dwCurrValue; + CARD32 rw; + } RTREGMAP; + +#define READONLY 1 +#define WRITEONLY 2 +#define READWRITE 3 + +/* Rage Theatre's Register Mappings, including the default values: */ +RTREGMAP RT_RegMap[regRT_MAX_REGS]={ +/* +{size, fidname, AddrOfst, Ofst, Mask, Addr, Ofst, Mask, Cur, R/W +*/ +{32 , fld_tmpReg1 ,0x151 , 0, 0x0, 0, 0,0, 0,READWRITE }, +{1 , fld_tmpReg2 ,VIP_VIP_SUB_VENDOR_DEVICE_ID , 3, 0xFFFFFFFF, 0, 0,0, 0,READWRITE }, +{1 , fld_tmpReg3 ,VIP_VIP_COMMAND_STATUS , 3, 0xFFFFFFFF, 0, 0,0, 0,READWRITE }, +{8 , fld_LP_CONTRAST ,VIP_LP_CONTRAST , 0, 0xFFFFFF00, 0, 0,0, fld_LP_CONTRAST_def ,READWRITE }, +{14 , fld_LP_BRIGHTNESS ,VIP_LP_BRIGHTNESS , 0, 0xFFFFC000, 0, 0,0, fld_LP_BRIGHTNESS_def ,READWRITE }, +{8 , fld_CP_HUE_CNTL ,VIP_CP_HUE_CNTL , 0, 0xFFFFFF00, 0, 0,0, fld_CP_HUE_CNTL_def ,READWRITE }, +{1 , fld_LUMA_FILTER ,VIP_LP_BRIGHTNESS , 15, 0xFFFF7FFF, 0, 0,0, fld_LUMA_FILTER_def ,READWRITE }, +{21 , fld_H_SCALE_RATIO ,VIP_H_SCALER_CONTROL , 0, 0xFFE00000, 0, 0,0, fld_H_SCALE_RATIO_def ,READWRITE }, +{4 , fld_H_SHARPNESS ,VIP_H_SCALER_CONTROL , 25, 0xE1FFFFFF, 0, 0,0, fld_H_SHARPNESS_def ,READWRITE }, +{12 , fld_V_SCALE_RATIO ,VIP_V_SCALER_CONTROL , 0, 0xFFFFF000, 0, 0,0, fld_V_SCALE_RATIO_def ,READWRITE }, +{1 , fld_V_DEINTERLACE_ON,VIP_V_SCALER_CONTROL , 12, 0xFFFFEFFF, 0, 0,0, fld_V_DEINTERLACE_ON_def ,READWRITE }, +{1 , fld_V_BYPSS ,VIP_V_SCALER_CONTROL , 14, 0xFFFFBFFF, 0, 0,0, fld_V_BYPSS_def ,READWRITE }, +{1 , fld_V_DITHER_ON ,VIP_V_SCALER_CONTROL , 15, 0xFFFF7FFF, 0, 0,0, fld_V_DITHER_ON_def ,READWRITE }, +{11 , fld_EVENF_OFFSET ,VIP_V_DEINTERLACE_CONTROL , 0, 0xFFFFF800, 0, 0,0, fld_EVENF_OFFSET_def ,READWRITE }, +{11 , fld_ODDF_OFFSET ,VIP_V_DEINTERLACE_CONTROL , 11, 0xFFC007FF, 0, 0,0, fld_ODDF_OFFSET_def ,READWRITE }, +{1 , fld_INTERLACE_DETECTED ,VIP_VS_LINE_COUNT , 15, 0xFFFF7FFF, 0, 0,0, fld_INTERLACE_DETECTED_def,READONLY }, +{10 , fld_VS_LINE_COUNT ,VIP_VS_LINE_COUNT , 0, 0xFFFFFC00, 0, 0,0, fld_VS_LINE_COUNT_def ,READONLY }, +{10 , fld_VS_DETECTED_LINES ,VIP_VS_LINE_COUNT , 16, 0xFC00FFFF, 0, 0,0, fld_VS_DETECTED_LINES_def ,READONLY }, +{1 , fld_VS_ITU656_VB ,VIP_VS_LINE_COUNT , 13, 0xFFFFDFFF, 0, 0,0, fld_VS_ITU656_VB_def ,READONLY }, +{16 , fld_VBI_CC_DATA ,VIP_VBI_CC_CNTL , 0, 0xFFFF0000, 0, 0,0, fld_VBI_CC_DATA_def ,READWRITE }, +{1 , fld_VBI_CC_WT ,VIP_VBI_CC_CNTL , 24, 0xFEFFFFFF, 0, 0,0, fld_VBI_CC_WT_def ,READWRITE }, +{1 , fld_VBI_CC_WT_ACK ,VIP_VBI_CC_CNTL , 25, 0xFDFFFFFF, 0, 0,0, fld_VBI_CC_WT_ACK_def ,READONLY }, +{1 , fld_VBI_CC_HOLD ,VIP_VBI_CC_CNTL , 26, 0xFBFFFFFF, 0, 0,0, fld_VBI_CC_HOLD_def ,READWRITE }, +{1 , fld_VBI_DECODE_EN ,VIP_VBI_CC_CNTL , 31, 0x7FFFFFFF, 0, 0,0, fld_VBI_DECODE_EN_def ,READWRITE }, +{16 , fld_VBI_CC_DTO_P ,VIP_VBI_DTO_CNTL , 0, 0xFFFF0000, 0, 0,0, fld_VBI_CC_DTO_P_def ,READWRITE }, +{16 ,fld_VBI_20BIT_DTO_P,VIP_VBI_DTO_CNTL , 16, 0x0000FFFF, 0, 0,0, fld_VBI_20BIT_DTO_P_def ,READWRITE }, +{7 ,fld_VBI_CC_LEVEL ,VIP_VBI_LEVEL_CNTL , 0, 0xFFFFFF80, 0, 0,0, fld_VBI_CC_LEVEL_def ,READWRITE }, +{7 ,fld_VBI_20BIT_LEVEL,VIP_VBI_LEVEL_CNTL , 8, 0xFFFF80FF, 0, 0,0, fld_VBI_20BIT_LEVEL_def ,READWRITE }, +{9 ,fld_VBI_CLK_RUNIN_GAIN,VIP_VBI_LEVEL_CNTL , 16, 0xFE00FFFF, 0, 0,0, fld_VBI_CLK_RUNIN_GAIN_def,READWRITE }, +{11 ,fld_H_VBI_WIND_START,VIP_H_VBI_WINDOW , 0, 0xFFFFF800, 0, 0,0, fld_H_VBI_WIND_START_def ,READWRITE }, +{11 ,fld_H_VBI_WIND_END,VIP_H_VBI_WINDOW , 16, 0xF800FFFF, 0, 0,0, fld_H_VBI_WIND_END_def ,READWRITE }, +{10 ,fld_V_VBI_WIND_START,VIP_V_VBI_WINDOW , 0, 0xFFFFFC00, 0, 0,0, fld_V_VBI_WIND_START_def ,READWRITE }, +{10 ,fld_V_VBI_WIND_END,VIP_V_VBI_WINDOW , 16, 0xFC00FFFF, 0, 0,0, fld_V_VBI_WIND_END_def ,READWRITE }, /* CHK */ +{16 ,fld_VBI_20BIT_DATA0,VIP_VBI_20BIT_CNTL , 0, 0xFFFF0000, 0, 0,0, fld_VBI_20BIT_DATA0_def ,READWRITE }, +{4 ,fld_VBI_20BIT_DATA1,VIP_VBI_20BIT_CNTL , 16, 0xFFF0FFFF, 0, 0,0, fld_VBI_20BIT_DATA1_def ,READWRITE }, +{1 ,fld_VBI_20BIT_WT ,VIP_VBI_20BIT_CNTL , 24, 0xFEFFFFFF, 0, 0,0, fld_VBI_20BIT_WT_def ,READWRITE }, +{1 ,fld_VBI_20BIT_WT_ACK ,VIP_VBI_20BIT_CNTL , 25, 0xFDFFFFFF, 0, 0,0, fld_VBI_20BIT_WT_ACK_def ,READONLY }, +{1 ,fld_VBI_20BIT_HOLD ,VIP_VBI_20BIT_CNTL , 26, 0xFBFFFFFF, 0, 0,0, fld_VBI_20BIT_HOLD_def ,READWRITE }, +{2 ,fld_VBI_CAPTURE_ENABLE ,VIP_VBI_CONTROL , 0, 0xFFFFFFFC, 0, 0,0, fld_VBI_CAPTURE_ENABLE_def,READWRITE }, +{16 ,fld_VBI_EDS_DATA ,VIP_VBI_EDS_CNTL , 0, 0xFFFF0000, 0, 0,0, fld_VBI_EDS_DATA_def ,READWRITE }, +{1 ,fld_VBI_EDS_WT ,VIP_VBI_EDS_CNTL , 24, 0xFEFFFFFF, 0, 0,0, fld_VBI_EDS_WT_def ,READWRITE }, +{1 ,fld_VBI_EDS_WT_ACK ,VIP_VBI_EDS_CNTL , 25, 0xFDFFFFFF, 0, 0,0, fld_VBI_EDS_WT_ACK_def ,READONLY }, +{1 ,fld_VBI_EDS_HOLD ,VIP_VBI_EDS_CNTL , 26, 0xFBFFFFFF, 0, 0,0, fld_VBI_EDS_HOLD_def ,READWRITE }, +{17 ,fld_VBI_SCALING_RATIO ,VIP_VBI_SCALER_CONTROL , 0, 0xFFFE0000, 0, 0,0, fld_VBI_SCALING_RATIO_def ,READWRITE }, +{1 ,fld_VBI_ALIGNER_ENABLE ,VIP_VBI_SCALER_CONTROL , 17, 0xFFFDFFFF, 0, 0,0, fld_VBI_ALIGNER_ENABLE_def,READWRITE }, +{11 ,fld_H_ACTIVE_START ,VIP_H_ACTIVE_WINDOW , 0, 0xFFFFF800, 0, 0,0, fld_H_ACTIVE_START_def ,READWRITE }, +{11 ,fld_H_ACTIVE_END ,VIP_H_ACTIVE_WINDOW , 16, 0xF800FFFF, 0, 0,0, fld_H_ACTIVE_END_def ,READWRITE }, +{10 ,fld_V_ACTIVE_START ,VIP_V_ACTIVE_WINDOW , 0, 0xFFFFFC00, 0, 0,0, fld_V_ACTIVE_START_def ,READWRITE }, +{10 ,fld_V_ACTIVE_END ,VIP_V_ACTIVE_WINDOW , 16, 0xFC00FFFF, 0, 0,0, fld_V_ACTIVE_END_def ,READWRITE }, +{8 ,fld_CH_HEIGHT ,VIP_CP_AGC_CNTL , 0, 0xFFFFFF00, 0, 0,0, fld_CH_HEIGHT_def ,READWRITE }, +{8 ,fld_CH_KILL_LEVEL ,VIP_CP_AGC_CNTL , 8, 0xFFFF00FF, 0, 0,0, fld_CH_KILL_LEVEL_def ,READWRITE }, +{2 ,fld_CH_AGC_ERROR_LIM ,VIP_CP_AGC_CNTL , 16, 0xFFFCFFFF, 0, 0,0, fld_CH_AGC_ERROR_LIM_def ,READWRITE }, +{1 ,fld_CH_AGC_FILTER_EN ,VIP_CP_AGC_CNTL , 18, 0xFFFBFFFF, 0, 0,0, fld_CH_AGC_FILTER_EN_def ,READWRITE }, +{1 ,fld_CH_AGC_LOOP_SPEED ,VIP_CP_AGC_CNTL , 19, 0xFFF7FFFF, 0, 0,0, fld_CH_AGC_LOOP_SPEED_def ,READWRITE }, +{8 ,fld_HUE_ADJ ,VIP_CP_HUE_CNTL , 0, 0xFFFFFF00, 0, 0,0, fld_HUE_ADJ_def ,READWRITE }, +{2 ,fld_STANDARD_SEL ,VIP_STANDARD_SELECT , 0, 0xFFFFFFFC, 0, 0,0, fld_STANDARD_SEL_def ,READWRITE }, +{1 ,fld_STANDARD_YC ,VIP_STANDARD_SELECT , 2, 0xFFFFFFFB, 0, 0,0, fld_STANDARD_YC_def ,READWRITE }, +{1 ,fld_ADC_PDWN ,VIP_ADC_CNTL , 7, 0xFFFFFF7F, 0, 0,0, fld_ADC_PDWN_def ,READWRITE }, +{3 ,fld_INPUT_SELECT ,VIP_ADC_CNTL , 0, 0xFFFFFFF8, 0, 0,0, fld_INPUT_SELECT_def ,READWRITE }, +{2 ,fld_ADC_PREFLO ,VIP_ADC_CNTL , 24, 0xFCFFFFFF, 0, 0,0, fld_ADC_PREFLO_def ,READWRITE }, +{8 ,fld_H_SYNC_PULSE_WIDTH ,VIP_HS_PULSE_WIDTH , 0, 0xFFFFFF00, 0, 0,0, fld_H_SYNC_PULSE_WIDTH_def,READONLY }, +{1 ,fld_HS_GENLOCKED ,VIP_HS_PULSE_WIDTH , 8, 0xFFFFFEFF, 0, 0,0, fld_HS_GENLOCKED_def ,READONLY }, +{1 ,fld_HS_SYNC_IN_WIN ,VIP_HS_PULSE_WIDTH , 9, 0xFFFFFDFF, 0, 0,0, fld_HS_SYNC_IN_WIN_def ,READONLY }, +{1 ,fld_VIN_ASYNC_RST ,VIP_MASTER_CNTL , 5, 0xFFFFFFDF, 0, 0,0, fld_VIN_ASYNC_RST_def ,READWRITE }, +{1 ,fld_DVS_ASYNC_RST ,VIP_MASTER_CNTL , 7, 0xFFFFFF7F, 0, 0,0, fld_DVS_ASYNC_RST_def ,READWRITE }, +{16 ,fld_VIP_VENDOR_ID ,VIP_VIP_VENDOR_DEVICE_ID, 0, 0xFFFF0000, 0, 0,0, fld_VIP_VENDOR_ID_def ,READONLY }, +{16 ,fld_VIP_DEVICE_ID ,VIP_VIP_VENDOR_DEVICE_ID,16, 0x0000FFFF, 0, 0,0, fld_VIP_DEVICE_ID_def ,READONLY }, +{16 ,fld_VIP_REVISION_ID ,VIP_VIP_REVISION_ID , 0, 0xFFFF0000, 0, 0,0, fld_VIP_REVISION_ID_def ,READONLY }, +{8 ,fld_BLACK_INT_START ,VIP_SG_BLACK_GATE , 0, 0xFFFFFF00, 0, 0,0, fld_BLACK_INT_START_def ,READWRITE }, +{4 ,fld_BLACK_INT_LENGTH ,VIP_SG_BLACK_GATE , 8, 0xFFFFF0FF, 0, 0,0, fld_BLACK_INT_LENGTH_def ,READWRITE }, +{8 ,fld_UV_INT_START ,VIP_SG_UVGATE_GATE , 0, 0xFFFFFF00, 0, 0,0, fld_UV_INT_START_def ,READWRITE }, +{4 ,fld_U_INT_LENGTH ,VIP_SG_UVGATE_GATE , 8, 0xFFFFF0FF, 0, 0,0, fld_U_INT_LENGTH_def ,READWRITE }, +{4 ,fld_V_INT_LENGTH ,VIP_SG_UVGATE_GATE , 12, 0xFFFF0FFF, 0, 0,0, fld_V_INT_LENGTH_def ,READWRITE }, +{10 ,fld_CRDR_ACTIVE_GAIN ,VIP_CP_ACTIVE_GAIN , 0, 0xFFFFFC00, 0, 0,0, fld_CRDR_ACTIVE_GAIN_def ,READWRITE }, +{10 ,fld_CBDB_ACTIVE_GAIN ,VIP_CP_ACTIVE_GAIN , 16, 0xFC00FFFF, 0, 0,0, fld_CBDB_ACTIVE_GAIN_def ,READWRITE }, +{1 ,fld_DVS_DIRECTION ,VIP_DVS_PORT_CTRL , 0, 0xFFFFFFFE, 0, 0,0, fld_DVS_DIRECTION_def ,READWRITE }, +{1 ,fld_DVS_VBI_CARD8_SWAP ,VIP_DVS_PORT_CTRL , 1, 0xFFFFFFFD, 0, 0,0, fld_DVS_VBI_CARD8_SWAP_def ,READWRITE }, +{1 ,fld_DVS_CLK_SELECT ,VIP_DVS_PORT_CTRL , 2, 0xFFFFFFFB, 0, 0,0, fld_DVS_CLK_SELECT_def ,READWRITE }, +{1 ,fld_CONTINUOUS_STREAM ,VIP_DVS_PORT_CTRL , 3, 0xFFFFFFF7, 0, 0,0, fld_CONTINUOUS_STREAM_def ,READWRITE }, +{1 ,fld_DVSOUT_CLK_DRV ,VIP_DVS_PORT_CTRL , 4, 0xFFFFFFEF, 0, 0,0, fld_DVSOUT_CLK_DRV_def ,READWRITE }, +{1 ,fld_DVSOUT_DATA_DRV ,VIP_DVS_PORT_CTRL , 5, 0xFFFFFFDF, 0, 0,0, fld_DVSOUT_DATA_DRV_def ,READWRITE }, +{32 ,fld_COMB_CNTL0 ,VIP_COMB_CNTL0 , 0, 0x00000000, 0, 0,0, fld_COMB_CNTL0_def ,READWRITE }, +{32 ,fld_COMB_CNTL1 ,VIP_COMB_CNTL1 , 0, 0x00000000, 0, 0,0, fld_COMB_CNTL1_def ,READWRITE }, +{32 ,fld_COMB_CNTL2 ,VIP_COMB_CNTL2 , 0, 0x00000000, 0, 0,0, fld_COMB_CNTL2_def ,READWRITE }, +{32 ,fld_COMB_LENGTH ,VIP_COMB_LINE_LENGTH , 0, 0x00000000, 0, 0,0, fld_COMB_LENGTH_def ,READWRITE }, +{8 ,fld_SYNCTIP_REF0 ,VIP_LP_AGC_CLAMP_CNTL0 , 0, 0xFFFFFF00, 0, 0,0, fld_SYNCTIP_REF0_def ,READWRITE }, +{8 ,fld_SYNCTIP_REF1 ,VIP_LP_AGC_CLAMP_CNTL0 , 8, 0xFFFF00FF, 0, 0,0, fld_SYNCTIP_REF1_def ,READWRITE }, +{8 ,fld_CLAMP_REF ,VIP_LP_AGC_CLAMP_CNTL0 , 16, 0xFF00FFFF, 0, 0,0, fld_CLAMP_REF_def ,READWRITE }, +{8 ,fld_AGC_PEAKWHITE ,VIP_LP_AGC_CLAMP_CNTL0 , 24, 0x00FFFFFF, 0, 0,0, fld_AGC_PEAKWHITE_def ,READWRITE }, +{8 ,fld_VBI_PEAKWHITE ,VIP_LP_AGC_CLAMP_CNTL1 , 0, 0xFFFFFF00, 0, 0,0, fld_VBI_PEAKWHITE_def ,READWRITE }, +{11 ,fld_WPA_THRESHOLD ,VIP_LP_WPA_CNTL0 , 0, 0xFFFFF800, 0, 0,0, fld_WPA_THRESHOLD_def ,READWRITE }, +{10 ,fld_WPA_TRIGGER_LO ,VIP_LP_WPA_CNTL1 , 0, 0xFFFFFC00, 0, 0,0, fld_WPA_TRIGGER_LO_def ,READWRITE }, +{10 ,fld_WPA_TRIGGER_HIGH ,VIP_LP_WPA_CNTL1 , 16, 0xFC00FFFF, 0, 0,0, fld_WPA_TRIGGER_HIGH_def ,READWRITE }, +{10 ,fld_LOCKOUT_START ,VIP_LP_VERT_LOCKOUT , 0, 0xFFFFFC00, 0, 0,0, fld_LOCKOUT_START_def ,READWRITE }, +{10 ,fld_LOCKOUT_END ,VIP_LP_VERT_LOCKOUT , 16, 0xFC00FFFF, 0, 0,0, fld_LOCKOUT_END_def ,READWRITE }, +{24 ,fld_CH_DTO_INC ,VIP_CP_PLL_CNTL0 , 0, 0xFF000000, 0, 0,0, fld_CH_DTO_INC_def ,READWRITE }, +{4 ,fld_PLL_SGAIN ,VIP_CP_PLL_CNTL0 , 24, 0xF0FFFFFF, 0, 0,0, fld_PLL_SGAIN_def ,READWRITE }, +{4 ,fld_PLL_FGAIN ,VIP_CP_PLL_CNTL0 , 28, 0x0FFFFFFF, 0, 0,0, fld_PLL_FGAIN_def ,READWRITE }, +{9 ,fld_CR_BURST_GAIN ,VIP_CP_BURST_GAIN , 0, 0xFFFFFE00, 0, 0,0, fld_CR_BURST_GAIN_def ,READWRITE }, +{9 ,fld_CB_BURST_GAIN ,VIP_CP_BURST_GAIN , 16, 0xFE00FFFF, 0, 0,0, fld_CB_BURST_GAIN_def ,READWRITE }, +{10 ,fld_VERT_LOCKOUT_START ,VIP_CP_VERT_LOCKOUT , 0, 0xFFFFFC00, 0, 0,0, fld_VERT_LOCKOUT_START_def,READWRITE }, +{10 ,fld_VERT_LOCKOUT_END ,VIP_CP_VERT_LOCKOUT , 16, 0xFC00FFFF, 0, 0,0, fld_VERT_LOCKOUT_END_def ,READWRITE }, +{11 ,fld_H_IN_WIND_START ,VIP_SCALER_IN_WINDOW , 0, 0xFFFFF800, 0, 0,0, fld_H_IN_WIND_START_def ,READWRITE }, +{10 ,fld_V_IN_WIND_START ,VIP_SCALER_IN_WINDOW , 16, 0xFC00FFFF, 0, 0,0, fld_V_IN_WIND_START_def ,READWRITE }, +{10 ,fld_H_OUT_WIND_WIDTH ,VIP_SCALER_OUT_WINDOW , 0, 0xFFFFFC00, 0, 0,0, fld_H_OUT_WIND_WIDTH_def ,READWRITE }, +{9 ,fld_V_OUT_WIND_WIDTH ,VIP_SCALER_OUT_WINDOW , 16, 0xFE00FFFF, 0, 0,0, fld_V_OUT_WIND_WIDTH_def ,READWRITE }, +{11 ,fld_HS_LINE_TOTAL ,VIP_HS_PLINE , 0, 0xFFFFF800, 0, 0,0, fld_HS_LINE_TOTAL_def ,READWRITE }, +{8 ,fld_MIN_PULSE_WIDTH ,VIP_HS_MINMAXWIDTH , 0, 0xFFFFFF00, 0, 0,0, fld_MIN_PULSE_WIDTH_def ,READWRITE }, +{8 ,fld_MAX_PULSE_WIDTH ,VIP_HS_MINMAXWIDTH , 8, 0xFFFF00FF, 0, 0,0, fld_MAX_PULSE_WIDTH_def ,READWRITE }, +{11 ,fld_WIN_CLOSE_LIMIT ,VIP_HS_WINDOW_LIMIT , 0, 0xFFFFF800, 0, 0,0, fld_WIN_CLOSE_LIMIT_def ,READWRITE }, +{11 ,fld_WIN_OPEN_LIMIT ,VIP_HS_WINDOW_LIMIT , 16, 0xF800FFFF, 0, 0,0, fld_WIN_OPEN_LIMIT_def ,READWRITE }, +{11 ,fld_VSYNC_INT_TRIGGER ,VIP_VS_DETECTOR_CNTL , 0, 0xFFFFF800, 0, 0,0, fld_VSYNC_INT_TRIGGER_def ,READWRITE }, +{11 ,fld_VSYNC_INT_HOLD ,VIP_VS_DETECTOR_CNTL , 16, 0xF800FFFF, 0, 0,0, fld_VSYNC_INT_HOLD_def ,READWRITE }, +{11 ,fld_VIN_M0 ,VIP_VIN_PLL_CNTL , 0, 0xFFFFF800, 0, 0,0, fld_VIN_M0_def ,READWRITE }, +{11 ,fld_VIN_N0 ,VIP_VIN_PLL_CNTL , 11, 0xFFC007FF, 0, 0,0, fld_VIN_N0_def ,READWRITE }, +{1 ,fld_MNFLIP_EN ,VIP_VIN_PLL_CNTL , 22, 0xFFBFFFFF, 0, 0,0, fld_MNFLIP_EN_def ,READWRITE }, +{4 ,fld_VIN_P ,VIP_VIN_PLL_CNTL , 24, 0xF0FFFFFF, 0, 0,0, fld_VIN_P_def ,READWRITE }, +{2 ,fld_REG_CLK_SEL ,VIP_VIN_PLL_CNTL , 30, 0x3FFFFFFF, 0, 0,0, fld_REG_CLK_SEL_def ,READWRITE }, +{11 ,fld_VIN_M1 ,VIP_VIN_PLL_FINE_CNTL , 0, 0xFFFFF800, 0, 0,0, fld_VIN_M1_def ,READWRITE }, +{11 ,fld_VIN_N1 ,VIP_VIN_PLL_FINE_CNTL , 11, 0xFFC007FF, 0, 0,0, fld_VIN_N1_def ,READWRITE }, +{1 ,fld_VIN_DRIVER_SEL ,VIP_VIN_PLL_FINE_CNTL , 22, 0xFFBFFFFF, 0, 0,0, fld_VIN_DRIVER_SEL_def ,READWRITE }, +{1 ,fld_VIN_MNFLIP_REQ ,VIP_VIN_PLL_FINE_CNTL , 23, 0xFF7FFFFF, 0, 0,0, fld_VIN_MNFLIP_REQ_def ,READWRITE }, +{1 ,fld_VIN_MNFLIP_DONE ,VIP_VIN_PLL_FINE_CNTL , 24, 0xFEFFFFFF, 0, 0,0, fld_VIN_MNFLIP_DONE_def ,READONLY }, +{1 ,fld_TV_LOCK_TO_VIN ,VIP_VIN_PLL_FINE_CNTL , 27, 0xF7FFFFFF, 0, 0,0, fld_TV_LOCK_TO_VIN_def ,READWRITE }, +{4 ,fld_TV_P_FOR_WINCLK ,VIP_VIN_PLL_FINE_CNTL , 28, 0x0FFFFFFF, 0, 0,0, fld_TV_P_FOR_WINCLK_def ,READWRITE }, +{1 ,fld_VINRST ,VIP_PLL_CNTL1 , 1, 0xFFFFFFFD, 0, 0,0, fld_VINRST_def ,READWRITE }, +{1 ,fld_VIN_CLK_SEL ,VIP_CLOCK_SEL_CNTL , 7, 0xFFFFFF7F, 0, 0,0, fld_VIN_CLK_SEL_def ,READWRITE }, +{10 ,fld_VS_FIELD_BLANK_START,VIP_VS_BLANKING_CNTL , 0, 0xFFFFFC00, 0, 0,0, fld_VS_FIELD_BLANK_START_def ,READWRITE }, +{10 ,fld_VS_FIELD_BLANK_END,VIP_VS_BLANKING_CNTL , 16, 0xFC00FFFF, 0, 0,0, fld_VS_FIELD_BLANK_END_def ,READWRITE }, +{9 ,fld_VS_FIELD_IDLOCATION,VIP_VS_FIELD_ID_CNTL , 0, 0xFFFFFE00, 0, 0,0, fld_VS_FIELD_IDLOCATION_def ,READWRITE }, +{10 ,fld_VS_FRAME_TOTAL ,VIP_VS_FRAME_TOTAL , 0, 0xFFFFFC00, 0, 0,0, fld_VS_FRAME_TOTAL_def ,READWRITE }, +{11 ,fld_SYNC_TIP_START ,VIP_SG_SYNCTIP_GATE , 0, 0xFFFFF800, 0, 0,0, fld_SYNC_TIP_START_def ,READWRITE }, +{4 ,fld_SYNC_TIP_LENGTH ,VIP_SG_SYNCTIP_GATE , 12, 0xFFFF0FFF, 0, 0,0, fld_SYNC_TIP_LENGTH_def ,READWRITE }, +{12 ,fld_GAIN_FORCE_DATA ,VIP_CP_DEBUG_FORCE , 0, 0xFFFFF000, 0, 0,0, fld_GAIN_FORCE_DATA_def ,READWRITE }, +{1 ,fld_GAIN_FORCE_EN ,VIP_CP_DEBUG_FORCE , 12, 0xFFFFEFFF, 0, 0,0, fld_GAIN_FORCE_EN_def ,READWRITE }, +{2 ,fld_I_CLAMP_SEL ,VIP_ADC_CNTL , 3, 0xFFFFFFE7, 0, 0,0, fld_I_CLAMP_SEL_def ,READWRITE }, +{2 ,fld_I_AGC_SEL ,VIP_ADC_CNTL , 5, 0xFFFFFF9F, 0, 0,0, fld_I_AGC_SEL_def ,READWRITE }, +{1 ,fld_EXT_CLAMP_CAP ,VIP_ADC_CNTL , 8, 0xFFFFFEFF, 0, 0,0, fld_EXT_CLAMP_CAP_def ,READWRITE }, +{1 ,fld_EXT_AGC_CAP ,VIP_ADC_CNTL , 9, 0xFFFFFDFF, 0, 0,0, fld_EXT_AGC_CAP_def ,READWRITE }, +{1 ,fld_DECI_DITHER_EN ,VIP_ADC_CNTL , 12, 0xFFFFEFFF, 0, 0,0, fld_DECI_DITHER_EN_def ,READWRITE }, +{2 ,fld_ADC_PREFHI ,VIP_ADC_CNTL , 22, 0xFF3FFFFF, 0, 0,0, fld_ADC_PREFHI_def ,READWRITE }, +{2 ,fld_ADC_CH_GAIN_SEL ,VIP_ADC_CNTL , 16, 0xFFFCFFFF, 0, 0,0, fld_ADC_CH_GAIN_SEL_def ,READWRITE }, +{4 ,fld_HS_PLL_SGAIN ,VIP_HS_PLLGAIN , 0, 0xFFFFFFF0, 0, 0,0, fld_HS_PLL_SGAIN_def ,READWRITE }, +{1 ,fld_NREn ,VIP_NOISE_CNTL0 , 0, 0xFFFFFFFE, 0, 0,0, fld_NREn_def ,READWRITE }, +{3 ,fld_NRGainCntl ,VIP_NOISE_CNTL0 , 1, 0xFFFFFFF1, 0, 0,0, fld_NRGainCntl_def ,READWRITE }, +{6 ,fld_NRBWTresh ,VIP_NOISE_CNTL0 , 4, 0xFFFFFC0F, 0, 0,0, fld_NRBWTresh_def ,READWRITE }, +{5 ,fld_NRGCTresh ,VIP_NOISE_CNTL0 , 10, 0xFFFF83FF, 0, 0,0, fld_NRGCTresh_def ,READWRITE }, +{1 ,fld_NRCoefDespeclMode ,VIP_NOISE_CNTL0 , 15, 0xFFFF7FFF, 0, 0,0, fld_NRCoefDespeclMode_def ,READWRITE }, +{1 ,fld_GPIO_5_OE ,VIP_GPIO_CNTL , 5, 0xFFFFFFDF, 0, 0,0, fld_GPIO_5_OE_def ,READWRITE }, +{1 ,fld_GPIO_6_OE ,VIP_GPIO_CNTL , 6, 0xFFFFFFBF, 0, 0,0, fld_GPIO_6_OE_def ,READWRITE }, +{1 ,fld_GPIO_5_OUT ,VIP_GPIO_INOUT , 5, 0xFFFFFFDF, 0, 0,0, fld_GPIO_5_OUT_def ,READWRITE }, +{1 ,fld_GPIO_6_OUT ,VIP_GPIO_INOUT , 6, 0xFFFFFFBF, 0, 0,0, fld_GPIO_6_OUT_def ,READWRITE }, +}; + +/* Rage Theatre's register fields default values: */ +CARD32 RT_RegDef[regRT_MAX_REGS]= +{ +fld_tmpReg1_def, +fld_tmpReg2_def, +fld_tmpReg3_def, +fld_LP_CONTRAST_def, +fld_LP_BRIGHTNESS_def, +fld_CP_HUE_CNTL_def, +fld_LUMA_FILTER_def, +fld_H_SCALE_RATIO_def, +fld_H_SHARPNESS_def, +fld_V_SCALE_RATIO_def, +fld_V_DEINTERLACE_ON_def, +fld_V_BYPSS_def, +fld_V_DITHER_ON_def, +fld_EVENF_OFFSET_def, +fld_ODDF_OFFSET_def, +fld_INTERLACE_DETECTED_def, +fld_VS_LINE_COUNT_def, +fld_VS_DETECTED_LINES_def, +fld_VS_ITU656_VB_def, +fld_VBI_CC_DATA_def, +fld_VBI_CC_WT_def, +fld_VBI_CC_WT_ACK_def, +fld_VBI_CC_HOLD_def, +fld_VBI_DECODE_EN_def, +fld_VBI_CC_DTO_P_def, +fld_VBI_20BIT_DTO_P_def, +fld_VBI_CC_LEVEL_def, +fld_VBI_20BIT_LEVEL_def, +fld_VBI_CLK_RUNIN_GAIN_def, +fld_H_VBI_WIND_START_def, +fld_H_VBI_WIND_END_def, +fld_V_VBI_WIND_START_def, +fld_V_VBI_WIND_END_def, +fld_VBI_20BIT_DATA0_def, +fld_VBI_20BIT_DATA1_def, +fld_VBI_20BIT_WT_def, +fld_VBI_20BIT_WT_ACK_def, +fld_VBI_20BIT_HOLD_def, +fld_VBI_CAPTURE_ENABLE_def, +fld_VBI_EDS_DATA_def, +fld_VBI_EDS_WT_def, +fld_VBI_EDS_WT_ACK_def, +fld_VBI_EDS_HOLD_def, +fld_VBI_SCALING_RATIO_def, +fld_VBI_ALIGNER_ENABLE_def, +fld_H_ACTIVE_START_def, +fld_H_ACTIVE_END_def, +fld_V_ACTIVE_START_def, +fld_V_ACTIVE_END_def, +fld_CH_HEIGHT_def, +fld_CH_KILL_LEVEL_def, +fld_CH_AGC_ERROR_LIM_def, +fld_CH_AGC_FILTER_EN_def, +fld_CH_AGC_LOOP_SPEED_def, +fld_HUE_ADJ_def, +fld_STANDARD_SEL_def, +fld_STANDARD_YC_def, +fld_ADC_PDWN_def, +fld_INPUT_SELECT_def, +fld_ADC_PREFLO_def, +fld_H_SYNC_PULSE_WIDTH_def, +fld_HS_GENLOCKED_def, +fld_HS_SYNC_IN_WIN_def, +fld_VIN_ASYNC_RST_def, +fld_DVS_ASYNC_RST_def, +fld_VIP_VENDOR_ID_def, +fld_VIP_DEVICE_ID_def, +fld_VIP_REVISION_ID_def, +fld_BLACK_INT_START_def, +fld_BLACK_INT_LENGTH_def, +fld_UV_INT_START_def, +fld_U_INT_LENGTH_def, +fld_V_INT_LENGTH_def, +fld_CRDR_ACTIVE_GAIN_def, +fld_CBDB_ACTIVE_GAIN_def, +fld_DVS_DIRECTION_def, +fld_DVS_VBI_CARD8_SWAP_def, +fld_DVS_CLK_SELECT_def, +fld_CONTINUOUS_STREAM_def, +fld_DVSOUT_CLK_DRV_def, +fld_DVSOUT_DATA_DRV_def, +fld_COMB_CNTL0_def, +fld_COMB_CNTL1_def, +fld_COMB_CNTL2_def, +fld_COMB_LENGTH_def, +fld_SYNCTIP_REF0_def, +fld_SYNCTIP_REF1_def, +fld_CLAMP_REF_def, +fld_AGC_PEAKWHITE_def, +fld_VBI_PEAKWHITE_def, +fld_WPA_THRESHOLD_def, +fld_WPA_TRIGGER_LO_def, +fld_WPA_TRIGGER_HIGH_def, +fld_LOCKOUT_START_def, +fld_LOCKOUT_END_def, +fld_CH_DTO_INC_def, +fld_PLL_SGAIN_def, +fld_PLL_FGAIN_def, +fld_CR_BURST_GAIN_def, +fld_CB_BURST_GAIN_def, +fld_VERT_LOCKOUT_START_def, +fld_VERT_LOCKOUT_END_def, +fld_H_IN_WIND_START_def, +fld_V_IN_WIND_START_def, +fld_H_OUT_WIND_WIDTH_def, +fld_V_OUT_WIND_WIDTH_def, +fld_HS_LINE_TOTAL_def, +fld_MIN_PULSE_WIDTH_def, +fld_MAX_PULSE_WIDTH_def, +fld_WIN_CLOSE_LIMIT_def, +fld_WIN_OPEN_LIMIT_def, +fld_VSYNC_INT_TRIGGER_def, +fld_VSYNC_INT_HOLD_def, +fld_VIN_M0_def, +fld_VIN_N0_def, +fld_MNFLIP_EN_def, +fld_VIN_P_def, +fld_REG_CLK_SEL_def, +fld_VIN_M1_def, +fld_VIN_N1_def, +fld_VIN_DRIVER_SEL_def, +fld_VIN_MNFLIP_REQ_def, +fld_VIN_MNFLIP_DONE_def, +fld_TV_LOCK_TO_VIN_def, +fld_TV_P_FOR_WINCLK_def, +fld_VINRST_def, +fld_VIN_CLK_SEL_def, +fld_VS_FIELD_BLANK_START_def, +fld_VS_FIELD_BLANK_END_def, +fld_VS_FIELD_IDLOCATION_def, +fld_VS_FRAME_TOTAL_def, +fld_SYNC_TIP_START_def, +fld_SYNC_TIP_LENGTH_def, +fld_GAIN_FORCE_DATA_def, +fld_GAIN_FORCE_EN_def, +fld_I_CLAMP_SEL_def, +fld_I_AGC_SEL_def, +fld_EXT_CLAMP_CAP_def, +fld_EXT_AGC_CAP_def, +fld_DECI_DITHER_EN_def, +fld_ADC_PREFHI_def, +fld_ADC_CH_GAIN_SEL_def, +fld_HS_PLL_SGAIN_def, +fld_NREn_def, +fld_NRGainCntl_def, +fld_NRBWTresh_def, +fld_NRGCTresh_def, +fld_NRCoefDespeclMode_def, +fld_GPIO_5_OE_def, +fld_GPIO_6_OE_def, +fld_GPIO_5_OUT_def, +fld_GPIO_6_OUT_def, +}; + +/**************************************************************************** + * WriteRT_fld (CARD32 dwReg, CARD32 dwData) * + * Function: Writes a register field within Rage Theatre * + * Inputs: CARD32 dwReg = register field to be written * + * CARD32 dwData = data that will be written to the reg field * + * Outputs: NONE * + ****************************************************************************/ +static void WriteRT_fld1 (TheatrePtr t, CARD32 dwReg, CARD32 dwData) +{ + CARD32 dwResult=0; + CARD32 dwValue=0; + + if (RT_regr (RT_RegMap[dwReg].dwRegAddrLSBs, &dwResult) == TRUE) + { + dwValue = (dwResult & RT_RegMap[dwReg].dwMaskLSBs) | + (dwData << RT_RegMap[dwReg].dwFldOffsetLSBs); + + if (RT_regw (RT_RegMap[dwReg].dwRegAddrLSBs, dwValue) == TRUE) + { + /* update the memory mapped registers */ + RT_RegMap[dwReg].dwCurrValue = dwData; + } + + } + + return; + +} /* WriteRT_fld ()... */ + +/**************************************************************************** + * ReadRT_fld (CARD32 dwReg) * + * Function: Reads a register field within Rage Theatre * + * Inputs: CARD32 dwReg = register field to be read * + * Outputs: CARD32 - value read from register field * + ****************************************************************************/ +static CARD32 ReadRT_fld1 (TheatrePtr t,CARD32 dwReg) +{ + CARD32 dwResult=0; + + if (RT_regr (RT_RegMap[dwReg].dwRegAddrLSBs, &dwResult) == TRUE) + { + RT_RegMap[dwReg].dwCurrValue = ((dwResult & ~RT_RegMap[dwReg].dwMaskLSBs) >> + RT_RegMap[dwReg].dwFldOffsetLSBs); + return (RT_RegMap[dwReg].dwCurrValue); + } + else + { + return (0xFFFFFFFF); + } + +} /* ReadRT_fld ()... */ + +#define WriteRT_fld(a,b) WriteRT_fld1(t, (a), (b)) +#define ReadRT_fld(a) ReadRT_fld1(t,(a)) + +/**************************************************************************** + * RT_SetVINClock (CARD16 wStandard) * + * Function: to set the VIN clock for the selected standard * + * Inputs: CARD16 wStandard - input standard (NTSC, PAL, SECAM) * + * Outputs: NONE * + ****************************************************************************/ +static void RT_SetVINClock(TheatrePtr t, CARD16 wStandard) +{ + CARD32 dwM0=0, dwN0=0, dwP=0; + CARD8 ref_freq; + + /* Determine the reference frequency first. This can be obtained + from the MMTABLE.video_decoder_type field (bits 4:7) + The Rage Theatre currently only supports reference frequencies of + 27 or 29.49 MHz. */ + /* + R128ReadBIOS(0x48, + (CARD8 *)&bios_header, sizeof(bios_header)); + R128ReadBIOS(bios_header + 0x30, + (CARD8 *)&pll_info_block, sizeof(pll_info_block)); + + R128ReadBIOS(pll_info_block+0x07, &video_decoder_type, sizeof(video_decoder_type)); + */ + ref_freq = (t->video_decoder_type & 0xF0) >> 4; + + + switch (wStandard & 0x00FF) + { + case (DEC_NTSC): /* NTSC GROUP - 480 lines */ + switch (wStandard & 0xFF00) + { + case (extNONE): + case (extNTSC): + case (extNTSC_J): + if (ref_freq == RT_FREF_2950) + { + dwM0 = 0x39; + dwN0 = 0x14C; + dwP = 0x6; + } + else + { + dwM0 = 0x0B; + dwN0 = 0x46; + dwP = 0x6; + } + break; + + case (extNTSC_443): + if (ref_freq == RT_FREF_2950) + { + dwM0 = 0x23; + dwN0 = 0x88; + dwP = 0x7; + } + else + { + dwM0 = 0x2C; + dwN0 = 0x121; + dwP = 0x5; + } + break; + + case (extPAL_M): + if (ref_freq == RT_FREF_2950) + { + dwM0 = 0x2C; + dwN0 = 0x12B; + dwP = 0x7; + } + else + { + dwM0 = 0x0B; + dwN0 = 0x46; + dwP = 0x6; + } + break; + + default: + return; + } + break; + case (DEC_PAL): + switch (wStandard & 0xFF00) + { + case (extPAL): + case (extPAL_N): + case (extPAL_BGHI): + case (extPAL_60): + if (ref_freq == RT_FREF_2950) + { + dwM0 = 0x0E; + dwN0 = 0x65; + dwP = 0x6; + } + else + { + dwM0 = 0x2C; + dwN0 = 0x0121; + dwP = 0x5; + } + break; + + case (extPAL_NCOMB): + if (ref_freq == RT_FREF_2950) + { + dwM0 = 0x23; + dwN0 = 0x88; + dwP = 0x7; + } + else + { + dwM0 = 0x37; + dwN0 = 0x1D3; + dwP = 0x8; + } + break; + + default: + return; + } + break; + + case (DEC_SECAM): + if (ref_freq == RT_FREF_2950) + { + dwM0 = 0xE; + dwN0 = 0x65; + dwP = 0x6; + } + else + { + dwM0 = 0x2C; + dwN0 = 0x121; + dwP = 0x5; + } + break; + } + + /* VIN_PLL_CNTL */ + WriteRT_fld (fld_VIN_M0, dwM0); + WriteRT_fld (fld_VIN_N0, dwN0); + WriteRT_fld (fld_VIN_P, dwP); + + return; +} /* RT_SetVINClock ()... */ + +/**************************************************************************** + * RT_SetTint (int hue) * + * Function: sets the tint (hue) for the Rage Theatre video in * + * Inputs: int hue - the hue value to be set. * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetTint (TheatrePtr t, int hue) +{ + CARD32 nhue = 0; + + t->iHue=hue; + /* Scale hue value from -1000<->1000 to -180<->180 */ + hue = (double)(hue+1000) * 0.18 - 180; + + /* Validate Hue level */ + if (hue < -180) + { + hue = -180; + } + else if (hue > 180) + { + hue = 180; + } + + /* save the "validated" hue, but scale it back up to -1000<->1000 */ + t->iHue = (double)hue/0.18; + + switch (t->wStandard & 0x00FF) + { + case (DEC_NTSC): /* original ATI code had _empty_ section for PAL/SECAM... which did not work, + obviously */ + case (DEC_PAL): + case (DEC_SECAM): + if (hue >= 0) + { + nhue = (CARD32) (256 * hue)/360; + } + else + { + nhue = (CARD32) (256 * (hue + 360))/360; + } + break; + + default: break; + } + + WriteRT_fld(fld_CP_HUE_CNTL, nhue); + + return; + +} /* RT_SetTint ()... */ + + +/**************************************************************************** + * RT_SetSaturation (int Saturation) * + * Function: sets the saturation level for the Rage Theatre video in * + * Inputs: int Saturation - the saturation value to be set. * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetSaturation (TheatrePtr t, int Saturation) +{ + CARD16 wSaturation_V, wSaturation_U; + double dbSaturation = 0, dbCrGain = 0, dbCbGain = 0; + + /* VALIDATE SATURATION LEVEL */ + if (Saturation < -1000L) + { + Saturation = -1000; + } + else if (Saturation > 1000L) + { + Saturation = 1000; + } + + t->iSaturation = Saturation; + + if (Saturation > 0) + { + /* Scale saturation up, to use full allowable register width */ + Saturation = (double)(Saturation) * 4.9; + } + + dbSaturation = (double) (Saturation+1000.0) / 1000.0; + + CalculateCrCbGain (t, &dbCrGain, &dbCbGain, t->wStandard); + + wSaturation_U = (CARD16) ((dbCrGain * dbSaturation * 128.0) + 0.5); + wSaturation_V = (CARD16) ((dbCbGain * dbSaturation * 128.0) + 0.5); + + /* SET SATURATION LEVEL */ + WriteRT_fld (fld_CRDR_ACTIVE_GAIN, wSaturation_U); + WriteRT_fld (fld_CBDB_ACTIVE_GAIN, wSaturation_V); + + t->wSaturation_U = wSaturation_U; + t->wSaturation_V = wSaturation_V; + + return; + +} /* RT_SetSaturation ()...*/ + +/**************************************************************************** + * RT_SetBrightness (int Brightness) * + * Function: sets the brightness level for the Rage Theatre video in * + * Inputs: int Brightness - the brightness value to be set. * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetBrightness (TheatrePtr t, int Brightness) +{ + double dbSynctipRef0=0, dbContrast=1; + + double dbYgain=0; + double dbBrightness=0; + double dbSetup=0; + CARD16 wBrightness=0; + + /* VALIDATE BRIGHTNESS LEVEL */ + if (Brightness < -1000) + { + Brightness = -1000; + } + else if (Brightness > 1000) + { + Brightness = 1000; + } + + /* Save value */ + t->iBrightness = Brightness; + + t->dbBrightnessRatio = (double) (Brightness+1000.0) / 10.0; + + dbBrightness = (double) (Brightness)/10.0; + + dbSynctipRef0 = ReadRT_fld (fld_SYNCTIP_REF0); + + if(t->dbContrast == 0) + { + t->dbContrast = 1.0; /*NTSC default; */ + } + + dbContrast = (double) t->dbContrast; + + /* Use the following formula to determine the brightness level */ + switch (t->wStandard & 0x00FF) + { + case (DEC_NTSC): + if ((t->wStandard & 0xFF00) == extNTSC_J) + { + dbYgain = 219.0 / ( 100.0 * (double)(dbSynctipRef0) /40.0); + } + else + { + dbSetup = 7.5 * (double)(dbSynctipRef0) / 40.0; + dbYgain = 219.0 / (92.5 * (double)(dbSynctipRef0) / 40.0); + } + break; + case (DEC_PAL): + case (DEC_SECAM): + dbYgain = 219.0 / ( 100.0 * (double)(dbSynctipRef0) /43.0); + break; + default: + break; + } + + wBrightness = (CARD16) (16.0 * ((dbBrightness-dbSetup) + (16.0 / (dbContrast * dbYgain)))); + + WriteRT_fld (fld_LP_BRIGHTNESS, wBrightness); + + /*RT_SetSaturation (t->iSaturation); */ + + return; + +} /* RT_SetBrightness ()... */ + + +/**************************************************************************** + * RT_SetSharpness (CARD16 wSharpness) * + * Function: sets the sharpness level for the Rage Theatre video in * + * Inputs: CARD16 wSharpness - the sharpness value to be set. * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetSharpness (TheatrePtr t, CARD16 wSharpness) +{ + switch (wSharpness) + { + case DEC_SMOOTH : + WriteRT_fld (fld_H_SHARPNESS, RT_NORM_SHARPNESS); + t->wSharpness = RT_NORM_SHARPNESS; + break; + case DEC_SHARP : + WriteRT_fld (fld_H_SHARPNESS, RT_HIGH_SHARPNESS); + t->wSharpness = RT_HIGH_SHARPNESS; + break; + default: + break; + } + return; + +} /* RT_SetSharpness ()... */ + + +/**************************************************************************** + * RT_SetContrast (int Contrast) * + * Function: sets the contrast level for the Rage Theatre video in * + * Inputs: int Contrast - the contrast value to be set. * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetContrast (TheatrePtr t, int Contrast) +{ + double dbSynctipRef0=0, dbContrast=0; + double dbYgain=0; + CARD8 bTempContrast=0; + + /* VALIDATE CONTRAST LEVEL */ + if (Contrast < -1000) + { + Contrast = -1000; + } + else if (Contrast > 1000) + { + Contrast = 1000; + } + + /* Save contrast value */ + t->iContrast = Contrast; + + dbSynctipRef0 = ReadRT_fld (fld_SYNCTIP_REF0); + dbContrast = (double) (Contrast+1000.0) / 1000.0; + + switch (t->wStandard & 0x00FF) + { + case (DEC_NTSC): + if ((t->wStandard & 0xFF00) == (extNTSC_J)) + { + dbYgain = 219.0 / ( 100.0 * (double)(dbSynctipRef0) /40.0); + } + else + { + dbYgain = 219.0 / ( 92.5 * (double)(dbSynctipRef0) /40.0); + } + break; + case (DEC_PAL): + case (DEC_SECAM): + dbYgain = 219.0 / ( 100.0 * (double)(dbSynctipRef0) /43.0); + break; + default: + break; + } + + bTempContrast = (CARD8) ((dbContrast * dbYgain * 64) + 0.5); + + WriteRT_fld (fld_LP_CONTRAST, (CARD32)bTempContrast); + + /* Save value for future modification */ + t->dbContrast = dbContrast; + + return; + +} /* RT_SetContrast ()... */ + +/**************************************************************************** + * RT_SetInterlace (CARD8 bInterlace) * + * Function: to set the interlacing pattern for the Rage Theatre video in * + * Inputs: CARD8 bInterlace * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetInterlace (TheatrePtr t, CARD8 bInterlace) +{ + + switch(bInterlace) + { + case (TRUE): /*DEC_INTERLACE */ + WriteRT_fld (fld_V_DEINTERLACE_ON, 0x1); + t->wInterlaced = (CARD16) RT_DECINTERLACED; + break; + case (FALSE): /*DEC_NONINTERLACE */ + WriteRT_fld (fld_V_DEINTERLACE_ON, RT_DECNONINTERLACED); + t->wInterlaced = (CARD16) RT_DECNONINTERLACED; + break; + default: + break; + } + + return; + +} /* RT_SetInterlace ()... */ + +/**************************************************************************** + * GetStandardConstants (double *LPeriod, double *FPeriod, * + * double *Fsamp, CARD16 wStandard) * + * Function: return timing values for a given standard * + * Inputs: double *LPeriod - + * double *FPeriod - + * double *Fsamp - sampling frequency used for a given standard * + * CARD16 wStandard - input standard (NTSC, PAL, SECAM) * + * Outputs: NONE * + ****************************************************************************/ +static void GetStandardConstants (double *LPeriod, double *FPeriod, + double *Fsamp, CARD16 wStandard) +{ + *LPeriod = 0.0; + *FPeriod = 0.0; + *Fsamp = 0.0; + + switch (wStandard & 0x00FF) + { + case (DEC_NTSC): /*NTSC GROUP - 480 lines*/ + switch (wStandard & 0xFF00) + { + case (extNONE): + case (extNTSC): + case (extNTSC_J): + *LPeriod = (double) 63.5555; + *FPeriod = (double) 16.6833; + *Fsamp = (double) 28.63636; + break; + case (extPAL_M): + *LPeriod = (double) 63.492; + *FPeriod = (double) 16.667; + *Fsamp = (double) 28.63689192; + break; + default: + return; + } + break; + case (DEC_PAL): + if( (wStandard & 0xFF00) == extPAL_N ) + { + *LPeriod = (double) 64.0; + *FPeriod = (double) 20.0; + *Fsamp = (double) 28.65645; + } + else + { + *LPeriod = (double) 64.0; + *FPeriod = (double) 20.0; + *Fsamp = (double) 35.46895; + } + break; + case (DEC_SECAM): + *LPeriod = (double) 64.0; + *FPeriod = (double) 20.0; + *Fsamp = (double) 35.46895; + break; + } + return; + +} /* GetStandardConstants ()...*/ + + +/**************************************************************************** + * RT_SetStandard (CARD16 wStandard) * + * Function: to set the input standard for the Rage Theatre video in * + * Inputs: CARD16 wStandard - input standard (NTSC, PAL, SECAM) * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetStandard (TheatrePtr t, CARD16 wStandard) +{ + double dbFsamp=0, dbLPeriod=0, dbFPeriod=0; + CARD16 wFrameTotal = 0; + double dbSPPeriod = 4.70; + + xf86DrvMsg(t->VIP->scrnIndex,X_INFO,"Rage Theatre setting standard 0x%04x\n", + wStandard); + t->wStandard = wStandard; + + /* Get the constants for the given standard. */ + GetStandardConstants (&dbLPeriod, &dbFPeriod, &dbFsamp, wStandard); + + wFrameTotal = (CARD16) (((2.0 * dbFPeriod) * 1000 / dbLPeriod) + 0.5); + + /* Procedures before setting the standards: */ + WriteRT_fld (fld_VIN_CLK_SEL, RT_REF_CLK); + WriteRT_fld (fld_VINRST, RT_VINRST_RESET); + + RT_SetVINClock (t, wStandard); + + WriteRT_fld (fld_VINRST, RT_VINRST_ACTIVE); + WriteRT_fld (fld_VIN_CLK_SEL, RT_PLL_VIN_CLK); + + /* Program the new standards: */ + switch (wStandard & 0x00FF) + { + case (DEC_NTSC): /*NTSC GROUP - 480 lines */ + WriteRT_fld (fld_STANDARD_SEL, RT_NTSC); + WriteRT_fld (fld_SYNCTIP_REF0, RT_NTSCM_SYNCTIP_REF0); + WriteRT_fld (fld_SYNCTIP_REF1, RT_NTSCM_SYNCTIP_REF1); + WriteRT_fld (fld_CLAMP_REF, RT_NTSCM_CLAMP_REF); + WriteRT_fld (fld_AGC_PEAKWHITE, RT_NTSCM_PEAKWHITE); + WriteRT_fld (fld_VBI_PEAKWHITE, RT_NTSCM_VBI_PEAKWHITE); + WriteRT_fld (fld_WPA_THRESHOLD, RT_NTSCM_WPA_THRESHOLD); + WriteRT_fld (fld_WPA_TRIGGER_LO, RT_NTSCM_WPA_TRIGGER_LO); + WriteRT_fld (fld_WPA_TRIGGER_HIGH, RT_NTSCM_WPA_TRIGGER_HIGH); + WriteRT_fld (fld_LOCKOUT_START, RT_NTSCM_LP_LOCKOUT_START); + WriteRT_fld (fld_LOCKOUT_END, RT_NTSCM_LP_LOCKOUT_END); + WriteRT_fld (fld_CH_DTO_INC, RT_NTSCM_CH_DTO_INC); + WriteRT_fld (fld_PLL_SGAIN, RT_NTSCM_CH_PLL_SGAIN); + WriteRT_fld (fld_PLL_FGAIN, RT_NTSCM_CH_PLL_FGAIN); + + WriteRT_fld (fld_CH_HEIGHT, RT_NTSCM_CH_HEIGHT); + WriteRT_fld (fld_CH_KILL_LEVEL, RT_NTSCM_CH_KILL_LEVEL); + + WriteRT_fld (fld_CH_AGC_ERROR_LIM, RT_NTSCM_CH_AGC_ERROR_LIM); + WriteRT_fld (fld_CH_AGC_FILTER_EN, RT_NTSCM_CH_AGC_FILTER_EN); + WriteRT_fld (fld_CH_AGC_LOOP_SPEED,RT_NTSCM_CH_AGC_LOOP_SPEED); + + WriteRT_fld (fld_VS_FIELD_BLANK_START, RT_NTSCM_VS_FIELD_BLANK_START); + WriteRT_fld (fld_VS_FIELD_BLANK_END, RT_NTSCM_VS_FIELD_BLANK_END); + + WriteRT_fld (fld_H_ACTIVE_START, RT_NTSCM_H_ACTIVE_START); + WriteRT_fld (fld_H_ACTIVE_END, RT_NTSCM_H_ACTIVE_END); + + WriteRT_fld (fld_V_ACTIVE_START, RT_NTSCM_V_ACTIVE_START); + WriteRT_fld (fld_V_ACTIVE_END, RT_NTSCM_V_ACTIVE_END); + + WriteRT_fld (fld_H_VBI_WIND_START, RT_NTSCM_H_VBI_WIND_START); + WriteRT_fld (fld_H_VBI_WIND_END, RT_NTSCM_H_VBI_WIND_END); + + WriteRT_fld (fld_V_VBI_WIND_START, RT_NTSCM_V_VBI_WIND_START); + WriteRT_fld (fld_V_VBI_WIND_END, RT_NTSCM_V_VBI_WIND_END); + + WriteRT_fld (fld_UV_INT_START, (CARD8)((0.10 * dbLPeriod * dbFsamp / 2.0) + 0.5 - 32)); + + WriteRT_fld (fld_VSYNC_INT_TRIGGER , (CARD16) RT_NTSCM_VSYNC_INT_TRIGGER); + WriteRT_fld (fld_VSYNC_INT_HOLD, (CARD16) RT_NTSCM_VSYNC_INT_HOLD); + + switch (wStandard & 0xFF00) + { + case (extPAL_M): + case (extNONE): + case (extNTSC): + WriteRT_fld (fld_CR_BURST_GAIN, RT_NTSCM_CR_BURST_GAIN); + WriteRT_fld (fld_CB_BURST_GAIN, RT_NTSCM_CB_BURST_GAIN); + + WriteRT_fld (fld_CRDR_ACTIVE_GAIN, RT_NTSCM_CRDR_ACTIVE_GAIN); + WriteRT_fld (fld_CBDB_ACTIVE_GAIN, RT_NTSCM_CBDB_ACTIVE_GAIN); + + WriteRT_fld (fld_VERT_LOCKOUT_START, RT_NTSCM_VERT_LOCKOUT_START); + WriteRT_fld (fld_VERT_LOCKOUT_END, RT_NTSCM_VERT_LOCKOUT_END); + + break; + case (extNTSC_J): + WriteRT_fld (fld_CR_BURST_GAIN, RT_NTSCJ_CR_BURST_GAIN); + WriteRT_fld (fld_CB_BURST_GAIN, RT_NTSCJ_CB_BURST_GAIN); + + WriteRT_fld (fld_CRDR_ACTIVE_GAIN, RT_NTSCJ_CRDR_ACTIVE_GAIN); + WriteRT_fld (fld_CBDB_ACTIVE_GAIN, RT_NTSCJ_CBDB_ACTIVE_GAIN); + + WriteRT_fld (fld_CH_HEIGHT, RT_NTSCJ_CH_HEIGHT); + WriteRT_fld (fld_CH_KILL_LEVEL, RT_NTSCJ_CH_KILL_LEVEL); + + WriteRT_fld (fld_CH_AGC_ERROR_LIM, RT_NTSCJ_CH_AGC_ERROR_LIM); + WriteRT_fld (fld_CH_AGC_FILTER_EN, RT_NTSCJ_CH_AGC_FILTER_EN); + WriteRT_fld (fld_CH_AGC_LOOP_SPEED, RT_NTSCJ_CH_AGC_LOOP_SPEED); + + WriteRT_fld (fld_VERT_LOCKOUT_START, RT_NTSCJ_VERT_LOCKOUT_START); + WriteRT_fld (fld_VERT_LOCKOUT_END, RT_NTSCJ_VERT_LOCKOUT_END); + + break; + default: + break; + } + break; + case (DEC_PAL): /*PAL GROUP - 525 lines */ + WriteRT_fld (fld_STANDARD_SEL, RT_PAL); + WriteRT_fld (fld_SYNCTIP_REF0, RT_PAL_SYNCTIP_REF0); + WriteRT_fld (fld_SYNCTIP_REF1, RT_PAL_SYNCTIP_REF1); + + WriteRT_fld (fld_CLAMP_REF, RT_PAL_CLAMP_REF); + WriteRT_fld (fld_AGC_PEAKWHITE, RT_PAL_PEAKWHITE); + WriteRT_fld (fld_VBI_PEAKWHITE, RT_PAL_VBI_PEAKWHITE); + + WriteRT_fld (fld_WPA_THRESHOLD, RT_PAL_WPA_THRESHOLD); + WriteRT_fld (fld_WPA_TRIGGER_LO, RT_PAL_WPA_TRIGGER_LO); + WriteRT_fld (fld_WPA_TRIGGER_HIGH, RT_PAL_WPA_TRIGGER_HIGH); + + WriteRT_fld (fld_LOCKOUT_START,RT_PAL_LP_LOCKOUT_START); + WriteRT_fld (fld_LOCKOUT_END, RT_PAL_LP_LOCKOUT_END); + WriteRT_fld (fld_CH_DTO_INC, RT_PAL_CH_DTO_INC); + WriteRT_fld (fld_PLL_SGAIN, RT_PAL_CH_PLL_SGAIN); + WriteRT_fld (fld_PLL_FGAIN, RT_PAL_CH_PLL_FGAIN); + + WriteRT_fld (fld_CR_BURST_GAIN, RT_PAL_CR_BURST_GAIN); + WriteRT_fld (fld_CB_BURST_GAIN, RT_PAL_CB_BURST_GAIN); + + WriteRT_fld (fld_CRDR_ACTIVE_GAIN, RT_PAL_CRDR_ACTIVE_GAIN); + WriteRT_fld (fld_CBDB_ACTIVE_GAIN, RT_PAL_CBDB_ACTIVE_GAIN); + + WriteRT_fld (fld_CH_HEIGHT, RT_PAL_CH_HEIGHT); + WriteRT_fld (fld_CH_KILL_LEVEL, RT_PAL_CH_KILL_LEVEL); + + WriteRT_fld (fld_CH_AGC_ERROR_LIM, RT_PAL_CH_AGC_ERROR_LIM); + WriteRT_fld (fld_CH_AGC_FILTER_EN, RT_PAL_CH_AGC_FILTER_EN); + WriteRT_fld (fld_CH_AGC_LOOP_SPEED,RT_PAL_CH_AGC_LOOP_SPEED); + + WriteRT_fld (fld_VERT_LOCKOUT_START, RT_PAL_VERT_LOCKOUT_START); + WriteRT_fld (fld_VERT_LOCKOUT_END, RT_PAL_VERT_LOCKOUT_END); + WriteRT_fld (fld_VS_FIELD_BLANK_START, (CARD16)RT_PALSEM_VS_FIELD_BLANK_START); + + WriteRT_fld (fld_VS_FIELD_BLANK_END, RT_PAL_VS_FIELD_BLANK_END); + + WriteRT_fld (fld_H_ACTIVE_START, RT_PAL_H_ACTIVE_START); + WriteRT_fld (fld_H_ACTIVE_END, RT_PAL_H_ACTIVE_END); + + WriteRT_fld (fld_V_ACTIVE_START, RT_PAL_V_ACTIVE_START); + WriteRT_fld (fld_V_ACTIVE_END, RT_PAL_V_ACTIVE_END); + + WriteRT_fld (fld_H_VBI_WIND_START, RT_PAL_H_VBI_WIND_START); + WriteRT_fld (fld_H_VBI_WIND_END, RT_PAL_H_VBI_WIND_END); + + WriteRT_fld (fld_V_VBI_WIND_START, RT_PAL_V_VBI_WIND_START); + WriteRT_fld (fld_V_VBI_WIND_END, RT_PAL_V_VBI_WIND_END); + + /* Magic 0.10 is correct - according to Ivo. Also see SECAM code below */ +/* WriteRT_fld (fld_UV_INT_START, (CARD8)( (0.12 * dbLPeriod * dbFsamp / 2.0) + 0.5 - 32 )); */ + WriteRT_fld (fld_UV_INT_START, (CARD8)( (0.10 * dbLPeriod * dbFsamp / 2.0) + 0.5 - 32 )); + + WriteRT_fld (fld_VSYNC_INT_TRIGGER , (CARD16) RT_PALSEM_VSYNC_INT_TRIGGER); + WriteRT_fld (fld_VSYNC_INT_HOLD, (CARD16) RT_PALSEM_VSYNC_INT_HOLD); + + break; + case (DEC_SECAM): /*PAL GROUP*/ + WriteRT_fld (fld_STANDARD_SEL, RT_SECAM); + WriteRT_fld (fld_SYNCTIP_REF0, RT_SECAM_SYNCTIP_REF0); + WriteRT_fld (fld_SYNCTIP_REF1, RT_SECAM_SYNCTIP_REF1); + WriteRT_fld (fld_CLAMP_REF, RT_SECAM_CLAMP_REF); + WriteRT_fld (fld_AGC_PEAKWHITE, RT_SECAM_PEAKWHITE); + WriteRT_fld (fld_VBI_PEAKWHITE, RT_SECAM_VBI_PEAKWHITE); + + WriteRT_fld (fld_WPA_THRESHOLD, RT_SECAM_WPA_THRESHOLD); + + WriteRT_fld (fld_WPA_TRIGGER_LO, RT_SECAM_WPA_TRIGGER_LO); + WriteRT_fld (fld_WPA_TRIGGER_HIGH, RT_SECAM_WPA_TRIGGER_HIGH); + + WriteRT_fld (fld_LOCKOUT_START,RT_SECAM_LP_LOCKOUT_START); + WriteRT_fld (fld_LOCKOUT_END, RT_SECAM_LP_LOCKOUT_END); + + WriteRT_fld (fld_CH_DTO_INC, RT_SECAM_CH_DTO_INC); + WriteRT_fld (fld_PLL_SGAIN, RT_SECAM_CH_PLL_SGAIN); + WriteRT_fld (fld_PLL_FGAIN, RT_SECAM_CH_PLL_FGAIN); + + WriteRT_fld (fld_CR_BURST_GAIN, RT_SECAM_CR_BURST_GAIN); + WriteRT_fld (fld_CB_BURST_GAIN, RT_SECAM_CB_BURST_GAIN); + + WriteRT_fld (fld_CRDR_ACTIVE_GAIN, RT_SECAM_CRDR_ACTIVE_GAIN); + WriteRT_fld (fld_CBDB_ACTIVE_GAIN, RT_SECAM_CBDB_ACTIVE_GAIN); + + WriteRT_fld (fld_CH_HEIGHT, RT_SECAM_CH_HEIGHT); + WriteRT_fld (fld_CH_KILL_LEVEL, RT_SECAM_CH_KILL_LEVEL); + + WriteRT_fld (fld_CH_AGC_ERROR_LIM, RT_SECAM_CH_AGC_ERROR_LIM); + WriteRT_fld (fld_CH_AGC_FILTER_EN, RT_SECAM_CH_AGC_FILTER_EN); + WriteRT_fld (fld_CH_AGC_LOOP_SPEED,RT_SECAM_CH_AGC_LOOP_SPEED); + + WriteRT_fld (fld_VERT_LOCKOUT_START, RT_SECAM_VERT_LOCKOUT_START); /*Might not need */ + WriteRT_fld (fld_VERT_LOCKOUT_END, RT_SECAM_VERT_LOCKOUT_END); /* Might not need */ + + WriteRT_fld (fld_VS_FIELD_BLANK_START, (CARD16)RT_PALSEM_VS_FIELD_BLANK_START); + WriteRT_fld (fld_VS_FIELD_BLANK_END, RT_PAL_VS_FIELD_BLANK_END); + + WriteRT_fld (fld_H_ACTIVE_START, RT_PAL_H_ACTIVE_START); + WriteRT_fld (fld_H_ACTIVE_END, RT_PAL_H_ACTIVE_END); + + WriteRT_fld (fld_V_ACTIVE_START, RT_PAL_V_ACTIVE_START); + WriteRT_fld (fld_V_ACTIVE_END, RT_PAL_V_ACTIVE_END); + + WriteRT_fld (fld_H_VBI_WIND_START, RT_PAL_H_VBI_WIND_START); + WriteRT_fld (fld_H_VBI_WIND_END, RT_PAL_H_VBI_WIND_END); + + WriteRT_fld (fld_V_VBI_WIND_START, RT_PAL_V_VBI_WIND_START); + WriteRT_fld (fld_V_VBI_WIND_END, RT_PAL_V_VBI_WIND_END); + + WriteRT_fld (fld_VSYNC_INT_TRIGGER , (CARD16) RT_PALSEM_VSYNC_INT_TRIGGER); + WriteRT_fld (fld_VSYNC_INT_HOLD, (CARD16) RT_PALSEM_VSYNC_INT_HOLD); + +/* WriteRT_fld (fld_UV_INT_START, (CARD8)( (0.12 * dbLPeriod * dbFsamp / 2.0) + 0.5 - 32 )); */ + WriteRT_fld (fld_UV_INT_START, (CARD8)( (0.10 * dbLPeriod * dbFsamp / 2.0) + 0.5 - 32 )); + + break; + default: + break; + } + + if (t->wConnector == DEC_SVIDEO) + { + + RT_SetCombFilter (t, wStandard, RT_SVIDEO); + } + else + { + /* Set up extra (connector and std) registers. */ + RT_SetCombFilter (t, wStandard, RT_COMPOSITE); + } + + /* Set the following values according to the formulas */ + WriteRT_fld (fld_HS_LINE_TOTAL, (CARD16)((dbLPeriod * dbFsamp / 2.0) +0.5)); + /* According to Ivo PAL/SECAM needs different treatment */ + switch(wStandard & 0x00FF) + { + case DEC_PAL: + case DEC_SECAM: + WriteRT_fld (fld_MIN_PULSE_WIDTH, (CARD8)(0.5 * dbSPPeriod * dbFsamp/2.0)); + WriteRT_fld (fld_MAX_PULSE_WIDTH, (CARD8)(1.5 * dbSPPeriod * dbFsamp/2.0)); + WriteRT_fld (fld_WIN_OPEN_LIMIT, (CARD16)(((dbLPeriod * dbFsamp / 4.0) + 0.5) - 16)); + WriteRT_fld (fld_WIN_CLOSE_LIMIT, (CARD16)(2.39 * dbSPPeriod * dbFsamp / 2.0)); + /* WriteRT_fld (fld_VS_FIELD_IDLOCATION, (CARD16)RT_PAL_FIELD_IDLOCATION); */ + /* According to docs the following value will work right, though the resulting stream deviates + slightly from CCIR..., in particular the value that was before will do nuts to VCRs in + pause/rewind state. */ + WriteRT_fld (fld_VS_FIELD_IDLOCATION, (CARD16)0x01); + WriteRT_fld (fld_HS_PLL_SGAIN, 2); + break; + case DEC_NTSC: + WriteRT_fld (fld_MIN_PULSE_WIDTH, (CARD8)(0.75 * dbSPPeriod * dbFsamp/2.0)); + WriteRT_fld (fld_MAX_PULSE_WIDTH, (CARD8)(1.25 * dbSPPeriod * dbFsamp/2.0)); + WriteRT_fld (fld_WIN_OPEN_LIMIT, (CARD16)(((dbLPeriod * dbFsamp / 4.0) + 0.5) - 16)); + WriteRT_fld (fld_WIN_CLOSE_LIMIT, (CARD16)(1.15 * dbSPPeriod * dbFsamp / 2.0)); + /* WriteRT_fld (fld_VS_FIELD_IDLOCATION, (CARD16)fld_VS_FIELD_IDLOCATION_def);*/ + /* I think the default value was the same as the one here.. does not hurt to hardcode it */ + WriteRT_fld (fld_VS_FIELD_IDLOCATION, (CARD16)0x01); + + } + + WriteRT_fld (fld_VS_FRAME_TOTAL, (CARD16)(wFrameTotal) + 10); + WriteRT_fld (fld_BLACK_INT_START, (CARD8)((0.09 * dbLPeriod * dbFsamp / 2.0) - 32 )); + WriteRT_fld (fld_SYNC_TIP_START, (CARD16)((dbLPeriod * dbFsamp / 2.0 + 0.5) - 28 )); + + return; + +} /* RT_SetStandard ()... */ + + + +/**************************************************************************** + * RT_SetCombFilter (CARD16 wStandard, CARD16 wConnector) * + * Function: sets the input comb filter based on the standard and * + * connector being used (composite vs. svideo) * + * Inputs: CARD16 wStandard - input standard (NTSC, PAL, SECAM) * + * CARD16 wConnector - COMPOSITE, SVIDEO * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetCombFilter (TheatrePtr t, CARD16 wStandard, CARD16 wConnector) +{ + CARD32 dwComb_Cntl0=0; + CARD32 dwComb_Cntl1=0; + CARD32 dwComb_Cntl2=0; + CARD32 dwComb_Line_Length=0; + + switch (wConnector) + { + case RT_COMPOSITE: + switch (wStandard & 0x00FF) + { + case (DEC_NTSC): + switch (wStandard & 0xFF00) + { + case (extNONE): + case (extNTSC): + case (extNTSC_J): + dwComb_Cntl0= RT_NTSCM_COMB_CNTL0_COMPOSITE; + dwComb_Cntl1= RT_NTSCM_COMB_CNTL1_COMPOSITE; + dwComb_Cntl2= RT_NTSCM_COMB_CNTL2_COMPOSITE; + dwComb_Line_Length= RT_NTSCM_COMB_LENGTH_COMPOSITE; + break; + case (extPAL_M): + dwComb_Cntl0= RT_PALM_COMB_CNTL0_COMPOSITE; + dwComb_Cntl1= RT_PALM_COMB_CNTL1_COMPOSITE; + dwComb_Cntl2= RT_PALM_COMB_CNTL2_COMPOSITE; + dwComb_Line_Length= RT_PALM_COMB_LENGTH_COMPOSITE; + break; + default: + return; + } + break; + case (DEC_PAL): + switch (wStandard & 0xFF00) + { + case (extNONE): + case (extPAL): + dwComb_Cntl0= RT_PAL_COMB_CNTL0_COMPOSITE; + dwComb_Cntl1= RT_PAL_COMB_CNTL1_COMPOSITE; + dwComb_Cntl2= RT_PAL_COMB_CNTL2_COMPOSITE; + dwComb_Line_Length= RT_PAL_COMB_LENGTH_COMPOSITE; + break; + case (extPAL_N): + dwComb_Cntl0= RT_PALN_COMB_CNTL0_COMPOSITE; + dwComb_Cntl1= RT_PALN_COMB_CNTL1_COMPOSITE; + dwComb_Cntl2= RT_PALN_COMB_CNTL2_COMPOSITE; + dwComb_Line_Length= RT_PALN_COMB_LENGTH_COMPOSITE; + break; + default: + return; + } + break; + case (DEC_SECAM): + dwComb_Cntl0= RT_SECAM_COMB_CNTL0_COMPOSITE; + dwComb_Cntl1= RT_SECAM_COMB_CNTL1_COMPOSITE; + dwComb_Cntl2= RT_SECAM_COMB_CNTL2_COMPOSITE; + dwComb_Line_Length= RT_SECAM_COMB_LENGTH_COMPOSITE; + break; + default: + return; + } + break; + case RT_SVIDEO: + switch (wStandard & 0x00FF) + { + case (DEC_NTSC): + switch (wStandard & 0xFF00) + { + case (extNONE): + case (extNTSC): + dwComb_Cntl0= RT_NTSCM_COMB_CNTL0_SVIDEO; + dwComb_Cntl1= RT_NTSCM_COMB_CNTL1_SVIDEO; + dwComb_Cntl2= RT_NTSCM_COMB_CNTL2_SVIDEO; + dwComb_Line_Length= RT_NTSCM_COMB_LENGTH_SVIDEO; + break; + case (extPAL_M): + dwComb_Cntl0= RT_PALM_COMB_CNTL0_SVIDEO; + dwComb_Cntl1= RT_PALM_COMB_CNTL1_SVIDEO; + dwComb_Cntl2= RT_PALM_COMB_CNTL2_SVIDEO; + dwComb_Line_Length= RT_PALM_COMB_LENGTH_SVIDEO; + break; + default: + return; + } + break; + case (DEC_PAL): + switch (wStandard & 0xFF00) + { + case (extNONE): + case (extPAL): + dwComb_Cntl0= RT_PAL_COMB_CNTL0_SVIDEO; + dwComb_Cntl1= RT_PAL_COMB_CNTL1_SVIDEO; + dwComb_Cntl2= RT_PAL_COMB_CNTL2_SVIDEO; + dwComb_Line_Length= RT_PAL_COMB_LENGTH_SVIDEO; + break; + case (extPAL_N): + dwComb_Cntl0= RT_PALN_COMB_CNTL0_SVIDEO; + dwComb_Cntl1= RT_PALN_COMB_CNTL1_SVIDEO; + dwComb_Cntl2= RT_PALN_COMB_CNTL2_SVIDEO; + dwComb_Line_Length= RT_PALN_COMB_LENGTH_SVIDEO; + break; + default: + return; + } + break; + case (DEC_SECAM): + dwComb_Cntl0= RT_SECAM_COMB_CNTL0_SVIDEO; + dwComb_Cntl1= RT_SECAM_COMB_CNTL1_SVIDEO; + dwComb_Cntl2= RT_SECAM_COMB_CNTL2_SVIDEO; + dwComb_Line_Length= RT_SECAM_COMB_LENGTH_SVIDEO; + break; + default: + return; + } + break; + default: + return; + } + + WriteRT_fld (fld_COMB_CNTL0, dwComb_Cntl0); + WriteRT_fld (fld_COMB_CNTL1, dwComb_Cntl1); + WriteRT_fld (fld_COMB_CNTL2, dwComb_Cntl2); + WriteRT_fld (fld_COMB_LENGTH, dwComb_Line_Length); + + return; + +} /* RT_SetCombFilter ()... */ + + +/**************************************************************************** + * RT_SetOutputVideoSize (CARD16 wHorzSize, CARD16 wVertSize, * + * CARD8 fCC_On, CARD8 fVBICap_On) * + * Function: sets the output video size for the Rage Theatre video in * + * Inputs: CARD16 wHorzSize - width of output in pixels * + * CARD16 wVertSize - height of output in pixels (lines) * + * CARD8 fCC_On - enable CC output * + * CARD8 fVBI_Cap_On - enable VBI capture * + * Outputs: NONE * + ****************************************************************************/ +void RT_SetOutputVideoSize (TheatrePtr t, CARD16 wHorzSize, CARD16 wVertSize, CARD8 fCC_On, CARD8 fVBICap_On) +{ + CARD32 dwHwinStart=0; + CARD32 dwHScaleRatio=0; + CARD32 dwHActiveLength=0; + CARD32 dwVwinStart=0; + CARD32 dwVScaleRatio=0; + CARD32 dwVActiveLength=0; + CARD32 dwTempRatio=0; + CARD32 dwEvenFieldOffset=0; + CARD32 dwOddFieldOffset=0; + CARD32 dwXin=0; + CARD32 dwYin=0; + + if (fVBICap_On) + { + WriteRT_fld (fld_VBI_CAPTURE_ENABLE, 1); + WriteRT_fld (fld_VBI_SCALING_RATIO, fld_VBI_SCALING_RATIO_def); + switch (t->wStandard & 0x00FF) + { + case (DEC_NTSC): + WriteRT_fld (fld_H_VBI_WIND_START, RT_NTSCM_H_VBI_WIND_START); + WriteRT_fld (fld_H_VBI_WIND_END, RT_NTSCM_H_VBI_WIND_END); + WriteRT_fld (fld_V_VBI_WIND_START, RT_NTSCM_V_VBI_WIND_START); + WriteRT_fld (fld_V_VBI_WIND_END, RT_NTSCM_V_VBI_WIND_END); + break; + case (DEC_PAL): + WriteRT_fld (fld_H_VBI_WIND_START, RT_PAL_H_VBI_WIND_START); + WriteRT_fld (fld_H_VBI_WIND_END, RT_PAL_H_VBI_WIND_END); + WriteRT_fld (fld_V_VBI_WIND_START, RT_PAL_V_VBI_WIND_START); + WriteRT_fld (fld_V_VBI_WIND_END, RT_PAL_V_VBI_WIND_END); + break; + case (DEC_SECAM): + WriteRT_fld (fld_H_VBI_WIND_START, RT_PAL_H_VBI_WIND_START); + WriteRT_fld (fld_H_VBI_WIND_END, RT_PAL_H_VBI_WIND_END); + WriteRT_fld (fld_V_VBI_WIND_START, RT_PAL_V_VBI_WIND_START); + WriteRT_fld (fld_V_VBI_WIND_END, RT_PAL_V_VBI_WIND_END); + break; + default: + break; + } + } + else + { + WriteRT_fld (fld_VBI_CAPTURE_ENABLE, 0); + } + + if (t->wInterlaced != RT_DECINTERLACED) + { + wVertSize *= 2; + } + + /*1. Calculate Horizontal Scaling ratio:*/ + switch (t->wStandard & 0x00FF) + { + case (DEC_NTSC): + dwHwinStart = RT_NTSCM_H_IN_START; + dwXin = (ReadRT_fld (fld_H_ACTIVE_END) - ReadRT_fld (fld_H_ACTIVE_START)); /*tempscaler*/ + dwXin = RT_NTSC_H_ACTIVE_SIZE; + dwHScaleRatio = (CARD32) ((long) dwXin * 65536L / wHorzSize); + dwHScaleRatio = dwHScaleRatio & 0x001FFFFF; /*21 bit number;*/ + dwHActiveLength = wHorzSize; + break; + case (DEC_PAL): + dwHwinStart = RT_PAL_H_IN_START; + dwXin = RT_PAL_H_ACTIVE_SIZE; + dwHScaleRatio = (CARD32) ((long) dwXin * 65536L / wHorzSize); + dwHScaleRatio = dwHScaleRatio & 0x001FFFFF; /*21 bit number;*/ + dwHActiveLength = wHorzSize; + break; + case (DEC_SECAM): + dwHwinStart = RT_SECAM_H_IN_START; + dwXin = RT_SECAM_H_ACTIVE_SIZE; + dwHScaleRatio = (CARD32) ((long) dwXin * 65536L / wHorzSize); + dwHScaleRatio = dwHScaleRatio & 0x001FFFFF; /*21 bit number;*/ + dwHActiveLength = wHorzSize; + break; + default: + break; + } + + /*2. Calculate Vertical Scaling ratio:*/ + switch (t->wStandard & 0x00FF) + { + case (DEC_NTSC): + dwVwinStart = RT_NTSCM_V_IN_START; + /* dwYin = (ReadRT_fld (fld_V_ACTIVE_END) - ReadRT_fld (fld_V_ACTIVE_START)); */ /*tempscaler*/ + dwYin = RT_NTSCM_V_ACTIVE_SIZE; + dwTempRatio = (CARD32)((long) wVertSize / dwYin); + dwVScaleRatio = (CARD32)((long)wVertSize * 2048L / dwYin); + dwVScaleRatio = dwVScaleRatio & 0x00000FFF; + dwVActiveLength = wVertSize/2; + break; + case (DEC_PAL): + dwVwinStart = RT_PAL_V_IN_START; + dwYin = RT_PAL_V_ACTIVE_SIZE; + dwTempRatio = (CARD32)(wVertSize/dwYin); + dwVScaleRatio = (CARD32)((long)wVertSize * 2048L / dwYin); + dwVScaleRatio = dwVScaleRatio & 0x00000FFF; + dwVActiveLength = wVertSize/2; + break; + case (DEC_SECAM): + dwVwinStart = RT_SECAM_V_IN_START; + dwYin = RT_SECAM_V_ACTIVE_SIZE; + dwTempRatio = (CARD32) (wVertSize / dwYin); + dwVScaleRatio = (CARD32) ((long) wVertSize * 2048L / dwYin); + dwVScaleRatio = dwVScaleRatio & 0x00000FFF; + dwVActiveLength = wVertSize/2; + break; + default: + break; + } + + /*4. Set up offset based on if interlaced or not:*/ + if (t->wInterlaced == RT_DECINTERLACED) + { + dwEvenFieldOffset = (CARD32) ((1.0 - ((double) wVertSize / (double) dwYin)) * 512.0); + dwOddFieldOffset = dwEvenFieldOffset; + WriteRT_fld (fld_V_DEINTERLACE_ON, 0x1); + } + else + { + dwEvenFieldOffset = (CARD32)(dwTempRatio * 512.0); + dwOddFieldOffset = (CARD32)(2048 - dwEvenFieldOffset); + WriteRT_fld (fld_V_DEINTERLACE_ON, 0x0); + } + + /* Set the registers:*/ + WriteRT_fld (fld_H_IN_WIND_START, dwHwinStart); + WriteRT_fld (fld_H_SCALE_RATIO, dwHScaleRatio); + WriteRT_fld (fld_H_OUT_WIND_WIDTH, dwHActiveLength); + + WriteRT_fld (fld_V_IN_WIND_START, dwVwinStart); + WriteRT_fld (fld_V_SCALE_RATIO, dwVScaleRatio); + WriteRT_fld (fld_V_OUT_WIND_WIDTH, dwVActiveLength); + + WriteRT_fld (fld_EVENF_OFFSET, dwEvenFieldOffset); + WriteRT_fld (fld_ODDF_OFFSET, dwOddFieldOffset); + + t->dwHorzScalingRatio = dwHScaleRatio; + t->dwVertScalingRatio = dwVScaleRatio; + + return; + +} /* RT_SetOutputVideoSize ()...*/ + + + +/**************************************************************************** + * CalculateCrCbGain (double *CrGain, double *CbGain, CARD16 wStandard) * + * Function: * + * Inputs: double *CrGain - + * double *CbGain - + * CARD16 wStandard - input standard (NTSC, PAL, SECAM) * + * Outputs: NONE * + ****************************************************************************/ +void CalculateCrCbGain (TheatrePtr t, double *CrGain, double *CbGain, CARD16 wStandard) +{ + #define UVFLTGAIN 1.5 + #define FRMAX 280000.0 + #define FBMAX 230000.0 + + double dbSynctipRef0=0, dbFsamp=0, dbLPeriod=0, dbFPeriod=0; + + dbSynctipRef0 = ReadRT_fld (fld_SYNCTIP_REF0); + + GetStandardConstants (&dbLPeriod, &dbFPeriod, &dbFsamp, wStandard); + + *CrGain=0.0; + *CbGain=0.0; + + switch (wStandard & 0x00FF) + { + case (DEC_NTSC): /*NTSC GROUP - 480 lines*/ + switch (wStandard & 0xFF00) + { + case (extNONE): + case (extNTSC): + case (extPAL_M): + *CrGain = (double)(40.0 / (dbSynctipRef0)) * (100.0/92.5) * (1.0/0.877) * ((112.0/70.1)/UVFLTGAIN); + *CbGain = (double)(40.0 / (dbSynctipRef0)) * (100.0/92.5) * (1.0/0.492) * ((112.0/88.6)/UVFLTGAIN); + break; + case (extNTSC_J): + *CrGain = (double)(40.0 / (dbSynctipRef0)) * (100.0/100.0) * (1.0/0.877) * ((112.0/70.1)/UVFLTGAIN); + *CbGain = (double)(40.0 / (dbSynctipRef0)) * (100.0/100.0) * (1.0/0.492) * ((112.0/88.6)/UVFLTGAIN); + break; + default: + return; + } + break; + case (DEC_PAL): + *CrGain = (double)(43.0 / (dbSynctipRef0)) * (100.0/92.5) * (1.0/0.877) * ((112.0/70.1)/UVFLTGAIN); + *CbGain = (double)(43.0 / (dbSynctipRef0)) * (100.0/92.5) * (1.0/0.492) * ((112.0/88.6)/UVFLTGAIN); + break; + case (DEC_SECAM): + *CrGain = (double) 32.0 * 32768.0 / FRMAX / (33554432.0 / dbFsamp) * (1.597 / 1.902) / UVFLTGAIN; + *CbGain = (double) 32.0 * 32768.0 / FBMAX / (33554432.0 / dbFsamp) * (1.267 / 1.505) / UVFLTGAIN; + break; + } + + return; + +} /* CalculateCrCbGain ()...*/ + + +/**************************************************************************** + * RT_SetConnector (CARD16 wStandard, int tunerFlag) * + * Function: + * Inputs: CARD16 wStandard - input standard (NTSC, PAL, SECAM) * + * int tunerFlag + * Outputs: NONE * + ****************************************************************************/ +void RT_SetConnector (TheatrePtr t, CARD16 wConnector, int tunerFlag) +{ + CARD32 dwTempContrast=0; + int i; + long counter; + + t->wConnector = wConnector; + + /* Get the contrast value - make sure we are viewing a visible line*/ + counter=0; + #if 0 + while (!((ReadRT_fld (fld_VS_LINE_COUNT)> 1) && (ReadRT_fld (fld_VS_LINE_COUNT)<20)) && (counter < 100000)){ + #endif + while ((ReadRT_fld (fld_VS_LINE_COUNT)<20) && (counter < 10000)){ + counter++; + } + dwTempContrast = ReadRT_fld (fld_LP_CONTRAST); + if(counter>=10000)xf86DrvMsg(t->VIP->scrnIndex, X_INFO, "Rage Theatre: timeout waiting for line count (%d)\n", ReadRT_fld (fld_VS_LINE_COUNT)); + + + WriteRT_fld (fld_LP_CONTRAST, 0x0); + + switch (wConnector) + { + case (DEC_TUNER): /* Tuner*/ + WriteRT_fld (fld_INPUT_SELECT, t->wTunerConnector ); + WriteRT_fld (fld_STANDARD_YC, RT_COMPOSITE); + RT_SetCombFilter (t, t->wStandard, RT_COMPOSITE); + break; + case (DEC_COMPOSITE): /* Comp*/ + WriteRT_fld (fld_INPUT_SELECT, t->wComp0Connector); + WriteRT_fld (fld_STANDARD_YC, RT_COMPOSITE); + RT_SetCombFilter (t, t->wStandard, RT_COMPOSITE); + break; + case (DEC_SVIDEO): /* Svideo*/ + WriteRT_fld (fld_INPUT_SELECT, t->wSVideo0Connector); + WriteRT_fld (fld_STANDARD_YC, RT_SVIDEO); + RT_SetCombFilter (t, t->wStandard, RT_SVIDEO); + break; + default: + WriteRT_fld (fld_INPUT_SELECT, t->wComp0Connector); + WriteRT_fld (fld_STANDARD_YC, RT_COMPOSITE); + RT_SetCombFilter (t, t->wStandard, RT_COMPOSITE); + break; + } + + t->wConnector = wConnector; + + WriteRT_fld (fld_COMB_CNTL1, ReadRT_fld (fld_COMB_CNTL1) ^ 0x100); + WriteRT_fld (fld_COMB_CNTL1, ReadRT_fld (fld_COMB_CNTL1) ^ 0x100); + + /* wait at most 1 sec here + VIP bus has a bandwidth of 27MB and it is 8bit. + A single Rage Theatre read should take at least 6 bytes (2 for address one way and 4 for data the other way) + However there are also latencies associated with such reads, plus latencies for PCI accesses. + + I guess we should not be doing more than 100000 per second.. At some point + I should really write a program to time this. + */ + i = 100000; + + while ((i>=0) && (! ReadRT_fld (fld_HS_GENLOCKED))) + { + i--; + } + if(i<0) xf86DrvMsg(t->VIP->scrnIndex, X_INFO, "Rage Theatre: waiting for fld_HS_GENLOCKED failed\n"); + /* now we are waiting for a non-visible line.. and there is absolutely no point to wait too long */ + counter = 0; + while (!((ReadRT_fld (fld_VS_LINE_COUNT)> 1) && (ReadRT_fld (fld_VS_LINE_COUNT)<20)) && (counter < 10000)){ + counter++; + } + WriteRT_fld (fld_LP_CONTRAST, dwTempContrast); + if(counter>=10000)xf86DrvMsg(t->VIP->scrnIndex, X_INFO, "Rage Theatre: timeout waiting for line count (%d)\n", ReadRT_fld (fld_VS_LINE_COUNT)); + + + + return; + +} /* RT_SetConnector ()...*/ + + +void InitTheatre(TheatrePtr t) +{ + CARD32 data; + + + /* 0 reset Rage Theatre */ + ShutdownTheatre(t); + usleep(100000); + + t->mode=MODE_INITIALIZATION_IN_PROGRESS; + /* 1. + Set the VIN_PLL to NTSC value */ + RT_SetVINClock(t, RT_NTSC); + + /* Take VINRST and L54RST out of reset */ + RT_regr (VIP_PLL_CNTL1, &data); + RT_regw (VIP_PLL_CNTL1, data & ~((RT_VINRST_RESET << 1) | (RT_L54RST_RESET << 3))); + RT_regr (VIP_PLL_CNTL1, &data); + + /* Set VIN_CLK_SEL to PLL_VIN_CLK */ + RT_regr (VIP_CLOCK_SEL_CNTL, &data); + RT_regw (VIP_CLOCK_SEL_CNTL, data | (RT_PLL_VIN_CLK << 7)); + RT_regr (VIP_CLOCK_SEL_CNTL, &data); + + /* 2. + Set HW_DEBUG to 0xF000 before setting the standards registers */ + RT_regw (VIP_HW_DEBUG, 0x0000F000); + + /* wait for things to settle */ + usleep(100000); + + RT_SetStandard(t, t->wStandard); + + /* 3. + Set DVS port to OUTPUT */ + RT_regr (VIP_DVS_PORT_CTRL, &data); + RT_regw (VIP_DVS_PORT_CTRL, data | RT_DVSDIR_OUT); + RT_regr (VIP_DVS_PORT_CTRL, &data); + + /* 4. + Set default values for ADC_CNTL */ + RT_regw (VIP_ADC_CNTL, RT_ADC_CNTL_DEFAULT); + + /* 5. + Clear the VIN_ASYNC_RST bit */ + RT_regr (VIP_MASTER_CNTL, &data); + RT_regw (VIP_MASTER_CNTL, data & ~0x20); + RT_regr (VIP_MASTER_CNTL, &data); + + /* Clear the DVS_ASYNC_RST bit */ + RT_regr (VIP_MASTER_CNTL, &data); + RT_regw (VIP_MASTER_CNTL, data & ~(RT_DVS_ASYNC_RST)); + RT_regr (VIP_MASTER_CNTL, &data); + + /* Set the GENLOCK delay */ + RT_regw (VIP_HS_GENLOCKDELAY, 0x10); + + RT_regr (fld_DVS_DIRECTION, &data); + RT_regw (fld_DVS_DIRECTION, data & RT_DVSDIR_OUT); +/* WriteRT_fld (fld_DVS_DIRECTION, RT_DVSDIR_IN); */ + + t->mode=MODE_INITIALIZED_FOR_TV_IN; +} + + +void ShutdownTheatre(TheatrePtr t) +{ + WriteRT_fld (fld_VIN_ASYNC_RST, RT_ASYNC_DISABLE); + WriteRT_fld (fld_VINRST , RT_VINRST_RESET); + WriteRT_fld (fld_ADC_PDWN , RT_ADC_DISABLE); + WriteRT_fld (fld_DVS_DIRECTION, RT_DVSDIR_IN); + t->mode=MODE_UNINITIALIZED; +} + +void DumpRageTheatreRegs(TheatrePtr t) +{ + int i; + CARD32 data; + + for(i=0;i<0x900;i+=4) + { + RT_regr(i, &data); + xf86DrvMsg(t->VIP->scrnIndex, X_INFO, "register 0x%04x is equal to 0x%08x\n", i, data); + } + +} + +void DumpRageTheatreRegsByName(TheatrePtr t) +{ + int i; + CARD32 data; + struct { char *name; long addr; } rt_reg_list[]={ + { "ADC_CNTL ", 0x0400 }, + { "ADC_DEBUG ", 0x0404 }, + { "AUD_CLK_DIVIDERS ", 0x00e8 }, + { "AUD_DTO_INCREMENTS ", 0x00ec }, + { "AUD_PLL_CNTL ", 0x00e0 }, + { "AUD_PLL_FINE_CNTL ", 0x00e4 }, + { "CLKOUT_CNTL ", 0x004c }, + { "CLKOUT_GPIO_CNTL ", 0x0038 }, + { "CLOCK_SEL_CNTL ", 0x00d0 }, + { "COMB_CNTL0 ", 0x0440 }, + { "COMB_CNTL1 ", 0x0444 }, + { "COMB_CNTL2 ", 0x0448 }, + { "COMB_LINE_LENGTH ", 0x044c }, + { "CP_ACTIVE_GAIN ", 0x0594 }, + { "CP_AGC_CNTL ", 0x0590 }, + { "CP_BURST_GAIN ", 0x058c }, + { "CP_DEBUG_FORCE ", 0x05b8 }, + { "CP_HUE_CNTL ", 0x0588 }, + { "CP_PLL_CNTL0 ", 0x0580 }, + { "CP_PLL_CNTL1 ", 0x0584 }, + { "CP_PLL_STATUS0 ", 0x0598 }, + { "CP_PLL_STATUS1 ", 0x059c }, + { "CP_PLL_STATUS2 ", 0x05a0 }, + { "CP_PLL_STATUS3 ", 0x05a4 }, + { "CP_PLL_STATUS4 ", 0x05a8 }, + { "CP_PLL_STATUS5 ", 0x05ac }, + { "CP_PLL_STATUS6 ", 0x05b0 }, + { "CP_PLL_STATUS7 ", 0x05b4 }, + { "CP_VERT_LOCKOUT ", 0x05bc }, + { "CRC_CNTL ", 0x02c0 }, + { "CRT_DTO_INCREMENTS ", 0x0394 }, + { "CRT_PLL_CNTL ", 0x00c4 }, + { "CRT_PLL_FINE_CNTL ", 0x00bc }, + { "DECODER_DEBUG_CNTL ", 0x05d4 }, + { "DELAY_ONE_MAP_A ", 0x0114 }, + { "DELAY_ONE_MAP_B ", 0x0118 }, + { "DELAY_ZERO_MAP_A ", 0x011c }, + { "DELAY_ZERO_MAP_B ", 0x0120 }, + { "DFCOUNT ", 0x00a4 }, + { "DFRESTART ", 0x00a8 }, + { "DHRESTART ", 0x00ac }, + { "DVRESTART ", 0x00b0 }, + { "DVS_PORT_CTRL ", 0x0610 }, + { "DVS_PORT_READBACK ", 0x0614 }, + { "FIFOA_CONFIG ", 0x0800 }, + { "FIFOB_CONFIG ", 0x0804 }, + { "FIFOC_CONFIG ", 0x0808 }, + { "FRAME_LOCK_CNTL ", 0x0100 }, + { "GAIN_LIMIT_SETTINGS ", 0x01e4 }, + { "GPIO_CNTL ", 0x0034 }, + { "GPIO_INOUT ", 0x0030 }, + { "HCOUNT ", 0x0090 }, + { "HDISP ", 0x0084 }, + { "HOST_RD_WT_CNTL ", 0x0188 }, + { "HOST_READ_DATA ", 0x0180 }, + { "HOST_WRITE_DATA ", 0x0184 }, + { "HSIZE ", 0x0088 }, + { "HSTART ", 0x008c }, + { "HS_DTOINC ", 0x0484 }, + { "HS_GENLOCKDELAY ", 0x0490 }, + { "HS_MINMAXWIDTH ", 0x048c }, + { "HS_PLINE ", 0x0480 }, + { "HS_PLLGAIN ", 0x0488 }, + { "HS_PLL_ERROR ", 0x04a0 }, + { "HS_PLL_FS_PATH ", 0x04a4 }, + { "HS_PULSE_WIDTH ", 0x049c }, + { "HS_WINDOW_LIMIT ", 0x0494 }, + { "HS_WINDOW_OC_SPEED ", 0x0498 }, + { "HTOTAL ", 0x0080 }, + { "HW_DEBUG ", 0x0010 }, + { "H_ACTIVE_WINDOW ", 0x05c0 }, + { "H_SCALER_CONTROL ", 0x0600 }, + { "H_VBI_WINDOW ", 0x05c8 }, + { "I2C_CNTL ", 0x0054 }, + { "I2C_CNTL_0 ", 0x0020 }, + { "I2C_CNTL_1 ", 0x0024 }, + { "I2C_DATA ", 0x0028 }, + { "I2S_RECEIVE_CNTL ", 0x081c }, + { "I2S_TRANSMIT_CNTL ", 0x0818 }, + { "IIS_TX_CNT_REG ", 0x0824 }, + { "INT_CNTL ", 0x002c }, + { "L54_DTO_INCREMENTS ", 0x00f8 }, + { "L54_PLL_CNTL ", 0x00f0 }, + { "L54_PLL_FINE_CNTL ", 0x00f4 }, + { "LINEAR_GAIN_SETTINGS ", 0x01e8 }, + { "LP_AGC_CLAMP_CNTL0 ", 0x0500 }, + { "LP_AGC_CLAMP_CNTL1 ", 0x0504 }, + { "LP_BLACK_LEVEL ", 0x051c }, + { "LP_BRIGHTNESS ", 0x0508 }, + { "LP_CONTRAST ", 0x050c }, + { "LP_SLICE_LEVEL ", 0x0520 }, + { "LP_SLICE_LIMIT ", 0x0510 }, + { "LP_SYNCTIP_LEVEL ", 0x0524 }, + { "LP_VERT_LOCKOUT ", 0x0528 }, + { "LP_WPA_CNTL0 ", 0x0514 }, + { "LP_WPA_CNTL1 ", 0x0518 }, + { "MASTER_CNTL ", 0x0040 }, + { "MODULATOR_CNTL1 ", 0x0200 }, + { "MODULATOR_CNTL2 ", 0x0204 }, + { "MV_LEVEL_CNTL1 ", 0x0210 }, + { "MV_LEVEL_CNTL2 ", 0x0214 }, + { "MV_MODE_CNTL ", 0x0208 }, + { "MV_STATUS ", 0x0330 }, + { "MV_STRIPE_CNTL ", 0x020c }, + { "NOISE_CNTL0 ", 0x0450 }, + { "PLL_CNTL0 ", 0x00c8 }, + { "PLL_CNTL1 ", 0x00fc }, + { "PLL_TEST_CNTL ", 0x00cc }, + { "PRE_DAC_MUX_CNTL ", 0x0240 }, + { "RGB_CNTL ", 0x0048 }, + { "RIPINTF_PORT_CNTL ", 0x003c }, + { "SCALER_IN_WINDOW ", 0x0618 }, + { "SCALER_OUT_WINDOW ", 0x061c }, + { "SG_BLACK_GATE ", 0x04c0 }, + { "SG_SYNCTIP_GATE ", 0x04c4 }, + { "SG_UVGATE_GATE ", 0x04c8 }, + { "SINGLE_STEP_DATA ", 0x05d8 }, + { "SPDIF_AC3_PREAMBLE ", 0x0814 }, + { "SPDIF_CHANNEL_STAT ", 0x0810 }, + { "SPDIF_PORT_CNTL ", 0x080c }, + { "SPDIF_TX_CNT_REG ", 0x0820 }, + { "STANDARD_SELECT ", 0x0408 }, + { "SW_SCRATCH ", 0x0014 }, + { "SYNC_CNTL ", 0x0050 }, + { "SYNC_LOCK_CNTL ", 0x0104 }, + { "SYNC_SIZE ", 0x00b4 }, + { "THERMO2BIN_STATUS ", 0x040c }, + { "TIMING_CNTL ", 0x01c4 }, + { "TVO_DATA_DELAY_A ", 0x0140 }, + { "TVO_DATA_DELAY_B ", 0x0144 }, + { "TVO_SYNC_PAT_ACCUM ", 0x0108 }, + { "TVO_SYNC_PAT_EXPECT ", 0x0110 }, + { "TVO_SYNC_THRESHOLD ", 0x010c }, + { "TV_DAC_CNTL ", 0x0280 }, + { "TV_DTO_INCREMENTS ", 0x0390 }, + { "TV_PLL_CNTL ", 0x00c0 }, + { "TV_PLL_FINE_CNTL ", 0x00b8 }, + { "UPSAMP_AND_GAIN_CNTL ", 0x01e0 }, + { "UPSAMP_COEFF0_0 ", 0x0340 }, + { "UPSAMP_COEFF0_1 ", 0x0344 }, + { "UPSAMP_COEFF0_2 ", 0x0348 }, + { "UPSAMP_COEFF1_0 ", 0x034c }, + { "UPSAMP_COEFF1_1 ", 0x0350 }, + { "UPSAMP_COEFF1_2 ", 0x0354 }, + { "UPSAMP_COEFF2_0 ", 0x0358 }, + { "UPSAMP_COEFF2_1 ", 0x035c }, + { "UPSAMP_COEFF2_2 ", 0x0360 }, + { "UPSAMP_COEFF3_0 ", 0x0364 }, + { "UPSAMP_COEFF3_1 ", 0x0368 }, + { "UPSAMP_COEFF3_2 ", 0x036c }, + { "UPSAMP_COEFF4_0 ", 0x0370 }, + { "UPSAMP_COEFF4_1 ", 0x0374 }, + { "UPSAMP_COEFF4_2 ", 0x0378 }, + { "UV_ADR ", 0x0300 }, + { "VBI_20BIT_CNTL ", 0x02d0 }, + { "VBI_CC_CNTL ", 0x02c8 }, + { "VBI_CONTROL ", 0x05d0 }, + { "VBI_DTO_CNTL ", 0x02d4 }, + { "VBI_EDS_CNTL ", 0x02cc }, + { "VBI_LEVEL_CNTL ", 0x02d8 }, + { "VBI_SCALER_CONTROL ", 0x060c }, + { "VCOUNT ", 0x009c }, + { "VDISP ", 0x0098 }, + { "VFTOTAL ", 0x00a0 }, + { "VIDEO_PORT_SIG ", 0x02c4 }, + { "VIN_PLL_CNTL ", 0x00d4 }, + { "VIN_PLL_FINE_CNTL ", 0x00d8 }, + { "VIP_COMMAND_STATUS ", 0x0008 }, + { "VIP_REVISION_ID ", 0x000c }, + { "VIP_SUB_VENDOR_DEVICE_ID", 0x0004 }, + { "VIP_VENDOR_DEVICE_ID ", 0x0000 }, + { "VSCALER_CNTL1 ", 0x01c0 }, + { "VSCALER_CNTL2 ", 0x01c8 }, + { "VSYNC_DIFF_CNTL ", 0x03a0 }, + { "VSYNC_DIFF_LIMITS ", 0x03a4 }, + { "VSYNC_DIFF_RD_DATA ", 0x03a8 }, + { "VS_BLANKING_CNTL ", 0x0544 }, + { "VS_COUNTER_CNTL ", 0x054c }, + { "VS_DETECTOR_CNTL ", 0x0540 }, + { "VS_FIELD_ID_CNTL ", 0x0548 }, + { "VS_FRAME_TOTAL ", 0x0550 }, + { "VS_LINE_COUNT ", 0x0554 }, + { "VTOTAL ", 0x0094 }, + { "V_ACTIVE_WINDOW ", 0x05c4 }, + { "V_DEINTERLACE_CONTROL ", 0x0608 }, + { "V_SCALER_CONTROL ", 0x0604 }, + { "V_VBI_WINDOW ", 0x05cc }, + { "Y_FALL_CNTL ", 0x01cc }, + { "Y_RISE_CNTL ", 0x01d0 }, + { "Y_SAW_TOOTH_CNTL ", 0x01d4 }, + {NULL, NULL} + }; + + for(i=0; rt_reg_list[i].name!=NULL;i++){ + RT_regr(rt_reg_list[i].addr, &data); + xf86DrvMsg(t->VIP->scrnIndex, X_INFO, "register (0x%04x) %s is equal to 0x%08x\n", rt_reg_list[i].addr, rt_reg_list[i].name, data); + } + +} + +void ResetTheatreRegsForNoTVout(TheatrePtr t) +{ + int i; + CARD32 data; + + RT_regw(VIP_CLKOUT_CNTL, 0x0); + RT_regw(VIP_HCOUNT, 0x0); + RT_regw(VIP_VCOUNT, 0x0); + RT_regw(VIP_DFCOUNT, 0x0); + #if 0 + RT_regw(VIP_CLOCK_SEL_CNTL, 0x2b7); /* versus 0x237 <-> 0x2b7 */ + RT_regw(VIP_VIN_PLL_CNTL, 0x60a6039); + #endif + RT_regw(VIP_FRAME_LOCK_CNTL, 0x0); +} + + +void ResetTheatreRegsForTVout(TheatrePtr t) +{ + int i; + CARD32 data; + +/* RT_regw(VIP_HW_DEBUG, 0x200); */ +/* RT_regw(VIP_INT_CNTL, 0x0); + RT_regw(VIP_GPIO_INOUT, 0x10090000); + RT_regw(VIP_GPIO_INOUT, 0x340b0000); */ +/* RT_regw(VIP_MASTER_CNTL, 0x6e8); */ + RT_regw(VIP_CLKOUT_CNTL, 0x29); +#if 1 + RT_regw(VIP_HCOUNT, 0x1d1); + RT_regw(VIP_VCOUNT, 0x1e3); +#else + RT_regw(VIP_HCOUNT, 0x322); + RT_regw(VIP_VCOUNT, 0x151); +#endif + RT_regw(VIP_DFCOUNT, 0x01); +/* RT_regw(VIP_CLOCK_SEL_CNTL, 0xb7); /* versus 0x237 <-> 0x2b7 */ + RT_regw(VIP_CLOCK_SEL_CNTL, 0x2b7); /* versus 0x237 <-> 0x2b7 */ + RT_regw(VIP_VIN_PLL_CNTL, 0x60a6039); +/* RT_regw(VIP_PLL_CNTL1, 0xacacac74); */ + RT_regw(VIP_FRAME_LOCK_CNTL, 0x0f); +/* RT_regw(VIP_ADC_CNTL, 0x02a420a8); + RT_regw(VIP_COMB_CNTL_0, 0x0d438083); + RT_regw(VIP_COMB_CNTL_2, 0x06080102); + RT_regw(VIP_HS_MINMAXWIDTH, 0x462f); + ... + */ +/* + RT_regw(VIP_HS_PULSE_WIDTH, 0x359); + RT_regw(VIP_HS_PLL_ERROR, 0xab6); + RT_regw(VIP_HS_PLL_FS_PATH, 0x7fff08f8); + RT_regw(VIP_VS_LINE_COUNT, 0x49b5e005); + */ +} diff --git a/src/theatre.h b/src/theatre.h new file mode 100644 index 0000000..287cc1a --- /dev/null +++ b/src/theatre.h @@ -0,0 +1,122 @@ +#ifndef __THEATRE_H__ +#define __THEATRE_H__ + +#define MODE_UNINITIALIZED 1 +#define MODE_INITIALIZATION_IN_PROGRESS 2 +#define MODE_INITIALIZED_FOR_TV_IN 3 + +typedef struct { + GENERIC_BUS_Ptr VIP; + + int theatre_num; + CARD32 theatre_id; + int mode; + + CARD16 video_decoder_type; + CARD32 wStandard; + CARD32 wConnector; + int iHue; + int iSaturation; + CARD32 wSaturation_U; + CARD32 wSaturation_V; + int iBrightness; + int dbBrightnessRatio; + CARD32 wSharpness; + int iContrast; + int dbContrast; + CARD32 wInterlaced; + CARD32 wTunerConnector; + CARD32 wComp0Connector; + CARD32 wSVideo0Connector; + CARD32 dwHorzScalingRatio; + CARD32 dwVertScalingRatio; + + } TheatreRec, * TheatrePtr; + +TheatrePtr DetectTheatre(GENERIC_BUS_Ptr b); + +/* DO NOT FORGET to setup constants before calling InitTheatre */ +void InitTheatre(TheatrePtr t); + +void RT_SetTint (TheatrePtr t, int hue); +void RT_SetSaturation (TheatrePtr t, int Saturation); +void RT_SetBrightness (TheatrePtr t, int Brightness); +void RT_SetSharpness (TheatrePtr t, CARD16 wSharpness); +void RT_SetContrast (TheatrePtr t, int Contrast); +void RT_SetInterlace (TheatrePtr t, CARD8 bInterlace); +void RT_SetStandard (TheatrePtr t, CARD16 wStandard); +void RT_SetCombFilter (TheatrePtr t, CARD16 wStandard, CARD16 wConnector); +void RT_SetOutputVideoSize (TheatrePtr t, CARD16 wHorzSize, CARD16 wVertSize, CARD8 fCC_On, CARD8 fVBICap_On); +void CalculateCrCbGain (TheatrePtr t, double *CrGain, double *CbGain, CARD16 wStandard); +void RT_SetConnector (TheatrePtr t, CARD16 wConnector, int tunerFlag); + +void RageTheatreDebugGain(TheatrePtr t, Bool on, CARD32 gain); +void ShutdownTheatre(TheatrePtr t); +void DumpRageTheatreRegs(TheatrePtr t); +void ResetTheatreRegsForTVout(TheatrePtr t); + + +#define TheatreSymbolsList \ + "InitTheatre" \ + "DetectTheatre" \ + "RT_SetTint", \ + "RT_SetSaturation", \ + "RT_SetBrightness", \ + "RT_SetSharpness", \ + "RT_SetContrast", \ + "RT_SetInterlace", \ + "RT_SetStandard", \ + "RT_SetCombFilter", \ + "RT_SetOutputVideoSize", \ + "RT_SetConnector", \ + "ResetTheatreRegsForNoTVout", \ + "ResetTheatreRegsForTVout", \ + "DumpRageTheatreRegs", \ + "ShutdownTheatre" + +#ifdef XFree86LOADER + +#define xf86_DetectTheatre ((TheatrePtr (*)(GENERIC_BUS_Ptr))LoaderSymbol("DetectTheatre")) + +#define xf86_InitTheatre ((void (*)(TheatrePtr t))LoaderSymbol("InitTheatre")) + +#define xf86_RT_SetTint ((void (*)(TheatrePtr, int))LoaderSymbol("RT_SetTint")) +#define xf86_RT_SetSaturation ((void (*)(TheatrePtr, int))LoaderSymbol("RT_SetSaturation")) +#define xf86_RT_SetBrightness ((void (*)(TheatrePtr, int))LoaderSymbol("RT_SetBrightness")) +#define xf86_RT_SetSharpness ((void (*)(TheatrePtr, CARD16))LoaderSymbol("RT_SetSharpness")) +#define xf86_RT_SetContrast ((void (*)(TheatrePtr, int))LoaderSymbol("RT_SetContrast")) +#define xf86_RT_SetInterlace ((void (*)(TheatrePtr, CARD8))LoaderSymbol("RT_SetInterlace")) +#define xf86_RT_SetStandard ((void (*)(TheatrePtr, CARD16))LoaderSymbol("RT_SetStandard")) +#define xf86_RT_SetOutputVideoSize ((void (*)(TheatrePtr, CARD16, CARD16, CARD8, CARD8))LoaderSymbol("RT_SetOutputVideoSize")) +#define xf86_RT_SetConnector ((void (*)(TheatrePtr, CARD16, int))LoaderSymbol("RT_SetConnector")) + +#define xf86_RageTheatreDebugGain ((void (*)(TheatrePtr, Bool, CARD32))LoaderSymbol("RageTheatreDebugGain")) +#define xf86_ShutdownTheatre ((void (*)(TheatrePtr))LoaderSymbol("ShutdownTheatre")) +#define xf86_DumpRageTheatreRegs ((void (*)(TheatrePtr))LoaderSymbol("DumpRageTheatreRegs")) +#define xf86_ResetTheatreRegsForTVout ((void (*)(TheatrePtr))LoaderSymbol("ResetTheatreRegsForTVout")) +#define xf86_ResetTheatreRegsForNoTVout ((void (*)(TheatrePtr))LoaderSymbol("ResetTheatreRegsForNoTVout")) +#else + +#define xf86_DetectTheatre DetectTheatre + +#define xf86_InitTheatre InitTheatre + +#define xf86_RT_SetTint RT_SetTint +#define xf86_RT_SetSaturation RT_SetSaturation +#define xf86_RT_SetBrightness RT_SetBrightness +#define xf86_RT_SetSharpness RT_SetSharpness +#define xf86_RT_SetContrast RT_SetContrast +#define xf86_RT_SetInterlace RT_SetInterlace +#define xf86_RT_SetStandard RT_SetStandard +#define xf86_RT_SetOutputVideoSize RT_SetOutputVideoSize +#define xf86_RT_SetConnector RT_SetConnector + +#define xf86_RageTheatreDebugGain RageTheatreDebugGain +#define xf86_ShutdownTheatre ShutdownTheatre +#define xf86_DumpRageTheatreRegs DumpRageTheatreRegs +#define xf86_ResetTheatreRegsForTVout ResetTheatreRegsForTVout +#define xf86_ResetTheatreRegsForNoTVout ResetTheatreRegsForNoTVout + +#endif + +#endif diff --git a/src/theatre_module.c b/src/theatre_module.c new file mode 100644 index 0000000..dd1c9af --- /dev/null +++ b/src/theatre_module.c @@ -0,0 +1,26 @@ + +#include "xf86Module.h" + +static MODULESETUPPROTO(theatreSetup); + + +static XF86ModuleVersionInfo theatreVersRec = +{ + "theatre", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + 1, 0, 0, + ABI_CLASS_VIDEODRV, /* This needs the video driver ABI */ + ABI_VIDEODRV_VERSION, + MOD_CLASS_NONE, + {0,0,0,0} +}; + +XF86ModuleData theatreModuleData = { &theatreVersRec, theatreSetup, NULL }; + +static pointer +theatreSetup(pointer module, pointer opts, int *errmaj, int *errmin) { + return (pointer)1; +} diff --git a/src/theatre_reg.h b/src/theatre_reg.h new file mode 100644 index 0000000..8a8a162 --- /dev/null +++ b/src/theatre_reg.h @@ -0,0 +1,766 @@ +#ifndef __THEATRE_REGS_H__ +#define __THEATRE_REGS_H__ + + +/* Address Space Rage Theatre Registers (VIP Access) */ +#define VIP_VIP_VENDOR_DEVICE_ID 0x0000 +#define VIP_VIP_SUB_VENDOR_DEVICE_ID 0x0004 +#define VIP_VIP_COMMAND_STATUS 0x0008 +#define VIP_VIP_REVISION_ID 0x000c +#define VIP_HW_DEBUG 0x0010 +#define VIP_SW_SCRATCH 0x0014 +#define VIP_I2C_CNTL_0 0x0020 +#define VIP_I2C_CNTL_1 0x0024 +#define VIP_I2C_DATA 0x0028 +#define VIP_INT_CNTL 0x002c +#define VIP_GPIO_INOUT 0x0030 +#define VIP_GPIO_CNTL 0x0034 +#define VIP_CLKOUT_GPIO_CNTL 0x0038 +#define VIP_RIPINTF_PORT_CNTL 0x003c +#define VIP_ADC_CNTL 0x0400 +#define VIP_ADC_DEBUG 0x0404 +#define VIP_STANDARD_SELECT 0x0408 +#define VIP_THERMO2BIN_STATUS 0x040c +#define VIP_COMB_CNTL0 0x0440 +#define VIP_COMB_CNTL1 0x0444 +#define VIP_COMB_CNTL2 0x0448 +#define VIP_COMB_LINE_LENGTH 0x044c +#define VIP_NOISE_CNTL0 0x0450 +#define VIP_HS_PLINE 0x0480 +#define VIP_HS_DTOINC 0x0484 +#define VIP_HS_PLLGAIN 0x0488 +#define VIP_HS_MINMAXWIDTH 0x048c +#define VIP_HS_GENLOCKDELAY 0x0490 +#define VIP_HS_WINDOW_LIMIT 0x0494 +#define VIP_HS_WINDOW_OC_SPEED 0x0498 +#define VIP_HS_PULSE_WIDTH 0x049c +#define VIP_HS_PLL_ERROR 0x04a0 +#define VIP_HS_PLL_FS_PATH 0x04a4 +#define VIP_SG_BLACK_GATE 0x04c0 +#define VIP_SG_SYNCTIP_GATE 0x04c4 +#define VIP_SG_UVGATE_GATE 0x04c8 +#define VIP_LP_AGC_CLAMP_CNTL0 0x0500 +#define VIP_LP_AGC_CLAMP_CNTL1 0x0504 +#define VIP_LP_BRIGHTNESS 0x0508 +#define VIP_LP_CONTRAST 0x050c +#define VIP_LP_SLICE_LIMIT 0x0510 +#define VIP_LP_WPA_CNTL0 0x0514 +#define VIP_LP_WPA_CNTL1 0x0518 +#define VIP_LP_BLACK_LEVEL 0x051c +#define VIP_LP_SLICE_LEVEL 0x0520 +#define VIP_LP_SYNCTIP_LEVEL 0x0524 +#define VIP_LP_VERT_LOCKOUT 0x0528 +#define VIP_VS_DETECTOR_CNTL 0x0540 +#define VIP_VS_BLANKING_CNTL 0x0544 +#define VIP_VS_FIELD_ID_CNTL 0x0548 +#define VIP_VS_COUNTER_CNTL 0x054c +#define VIP_VS_FRAME_TOTAL 0x0550 +#define VIP_VS_LINE_COUNT 0x0554 +#define VIP_CP_PLL_CNTL0 0x0580 +#define VIP_CP_PLL_CNTL1 0x0584 +#define VIP_CP_HUE_CNTL 0x0588 +#define VIP_CP_BURST_GAIN 0x058c +#define VIP_CP_AGC_CNTL 0x0590 +#define VIP_CP_ACTIVE_GAIN 0x0594 +#define VIP_CP_PLL_STATUS0 0x0598 +#define VIP_CP_PLL_STATUS1 0x059c +#define VIP_CP_PLL_STATUS2 0x05a0 +#define VIP_CP_PLL_STATUS3 0x05a4 +#define VIP_CP_PLL_STATUS4 0x05a8 +#define VIP_CP_PLL_STATUS5 0x05ac +#define VIP_CP_PLL_STATUS6 0x05b0 +#define VIP_CP_PLL_STATUS7 0x05b4 +#define VIP_CP_DEBUG_FORCE 0x05b8 +#define VIP_CP_VERT_LOCKOUT 0x05bc +#define VIP_H_ACTIVE_WINDOW 0x05c0 +#define VIP_V_ACTIVE_WINDOW 0x05c4 +#define VIP_H_VBI_WINDOW 0x05c8 +#define VIP_V_VBI_WINDOW 0x05cc +#define VIP_VBI_CONTROL 0x05d0 +#define VIP_DECODER_DEBUG_CNTL 0x05d4 +#define VIP_SINGLE_STEP_DATA 0x05d8 +#define VIP_MASTER_CNTL 0x0040 +#define VIP_RGB_CNTL 0x0048 +#define VIP_CLKOUT_CNTL 0x004c +#define VIP_SYNC_CNTL 0x0050 +#define VIP_I2C_CNTL 0x0054 +#define VIP_HTOTAL 0x0080 +#define VIP_HDISP 0x0084 +#define VIP_HSIZE 0x0088 +#define VIP_HSTART 0x008c +#define VIP_HCOUNT 0x0090 +#define VIP_VTOTAL 0x0094 +#define VIP_VDISP 0x0098 +#define VIP_VCOUNT 0x009c +#define VIP_VFTOTAL 0x00a0 +#define VIP_DFCOUNT 0x00a4 +#define VIP_DFRESTART 0x00a8 +#define VIP_DHRESTART 0x00ac +#define VIP_DVRESTART 0x00b0 +#define VIP_SYNC_SIZE 0x00b4 +#define VIP_TV_PLL_FINE_CNTL 0x00b8 +#define VIP_CRT_PLL_FINE_CNTL 0x00bc +#define VIP_TV_PLL_CNTL 0x00c0 +#define VIP_CRT_PLL_CNTL 0x00c4 +#define VIP_PLL_CNTL0 0x00c8 +#define VIP_PLL_TEST_CNTL 0x00cc +#define VIP_CLOCK_SEL_CNTL 0x00d0 +#define VIP_VIN_PLL_CNTL 0x00d4 +#define VIP_VIN_PLL_FINE_CNTL 0x00d8 +#define VIP_AUD_PLL_CNTL 0x00e0 +#define VIP_AUD_PLL_FINE_CNTL 0x00e4 +#define VIP_AUD_CLK_DIVIDERS 0x00e8 +#define VIP_AUD_DTO_INCREMENTS 0x00ec +#define VIP_L54_PLL_CNTL 0x00f0 +#define VIP_L54_PLL_FINE_CNTL 0x00f4 +#define VIP_L54_DTO_INCREMENTS 0x00f8 +#define VIP_PLL_CNTL1 0x00fc +#define VIP_FRAME_LOCK_CNTL 0x0100 +#define VIP_SYNC_LOCK_CNTL 0x0104 +#define VIP_TVO_SYNC_PAT_ACCUM 0x0108 +#define VIP_TVO_SYNC_THRESHOLD 0x010c +#define VIP_TVO_SYNC_PAT_EXPECT 0x0110 +#define VIP_DELAY_ONE_MAP_A 0x0114 +#define VIP_DELAY_ONE_MAP_B 0x0118 +#define VIP_DELAY_ZERO_MAP_A 0x011c +#define VIP_DELAY_ZERO_MAP_B 0x0120 +#define VIP_TVO_DATA_DELAY_A 0x0140 +#define VIP_TVO_DATA_DELAY_B 0x0144 +#define VIP_HOST_READ_DATA 0x0180 +#define VIP_HOST_WRITE_DATA 0x0184 +#define VIP_HOST_RD_WT_CNTL 0x0188 +#define VIP_VSCALER_CNTL1 0x01c0 +#define VIP_TIMING_CNTL 0x01c4 +#define VIP_VSCALER_CNTL2 0x01c8 +#define VIP_Y_FALL_CNTL 0x01cc +#define VIP_Y_RISE_CNTL 0x01d0 +#define VIP_Y_SAW_TOOTH_CNTL 0x01d4 +#define VIP_UPSAMP_AND_GAIN_CNTL 0x01e0 +#define VIP_GAIN_LIMIT_SETTINGS 0x01e4 +#define VIP_LINEAR_GAIN_SETTINGS 0x01e8 +#define VIP_MODULATOR_CNTL1 0x0200 +#define VIP_MODULATOR_CNTL2 0x0204 +#define VIP_MV_MODE_CNTL 0x0208 +#define VIP_MV_STRIPE_CNTL 0x020c +#define VIP_MV_LEVEL_CNTL1 0x0210 +#define VIP_MV_LEVEL_CNTL2 0x0214 +#define VIP_PRE_DAC_MUX_CNTL 0x0240 +#define VIP_TV_DAC_CNTL 0x0280 +#define VIP_CRC_CNTL 0x02c0 +#define VIP_VIDEO_PORT_SIG 0x02c4 +#define VIP_VBI_CC_CNTL 0x02c8 +#define VIP_VBI_EDS_CNTL 0x02cc +#define VIP_VBI_20BIT_CNTL 0x02d0 +#define VIP_VBI_DTO_CNTL 0x02d4 +#define VIP_VBI_LEVEL_CNTL 0x02d8 +#define VIP_UV_ADR 0x0300 +#define VIP_MV_STATUS 0x0330 +#define VIP_UPSAMP_COEFF0_0 0x0340 +#define VIP_UPSAMP_COEFF0_1 0x0344 +#define VIP_UPSAMP_COEFF0_2 0x0348 +#define VIP_UPSAMP_COEFF1_0 0x034c +#define VIP_UPSAMP_COEFF1_1 0x0350 +#define VIP_UPSAMP_COEFF1_2 0x0354 +#define VIP_UPSAMP_COEFF2_0 0x0358 +#define VIP_UPSAMP_COEFF2_1 0x035c +#define VIP_UPSAMP_COEFF2_2 0x0360 +#define VIP_UPSAMP_COEFF3_0 0x0364 +#define VIP_UPSAMP_COEFF3_1 0x0368 +#define VIP_UPSAMP_COEFF3_2 0x036c +#define VIP_UPSAMP_COEFF4_0 0x0370 +#define VIP_UPSAMP_COEFF4_1 0x0374 +#define VIP_UPSAMP_COEFF4_2 0x0378 +#define VIP_TV_DTO_INCREMENTS 0x0390 +#define VIP_CRT_DTO_INCREMENTS 0x0394 +#define VIP_VSYNC_DIFF_CNTL 0x03a0 +#define VIP_VSYNC_DIFF_LIMITS 0x03a4 +#define VIP_VSYNC_DIFF_RD_DATA 0x03a8 +#define VIP_SCALER_IN_WINDOW 0x0618 +#define VIP_SCALER_OUT_WINDOW 0x061c +#define VIP_H_SCALER_CONTROL 0x0600 +#define VIP_V_SCALER_CONTROL 0x0604 +#define VIP_V_DEINTERLACE_CONTROL 0x0608 +#define VIP_VBI_SCALER_CONTROL 0x060c +#define VIP_DVS_PORT_CTRL 0x0610 +#define VIP_DVS_PORT_READBACK 0x0614 +#define VIP_FIFOA_CONFIG 0x0800 +#define VIP_FIFOB_CONFIG 0x0804 +#define VIP_FIFOC_CONFIG 0x0808 +#define VIP_SPDIF_PORT_CNTL 0x080c +#define VIP_SPDIF_CHANNEL_STAT 0x0810 +#define VIP_SPDIF_AC3_PREAMBLE 0x0814 +#define VIP_I2S_TRANSMIT_CNTL 0x0818 +#define VIP_I2S_RECEIVE_CNTL 0x081c +#define VIP_SPDIF_TX_CNT_REG 0x0820 +#define VIP_IIS_TX_CNT_REG 0x0824 + +#define RT100_ATI_ID 0x4D541002 +#define RT200_ATI_ID 0x4f4a1002 + +/* Register/Field values: */ +#define RT_COMP0 0x0 +#define RT_COMP1 0x1 +#define RT_COMP2 0x2 +#define RT_YF_COMP3 0x3 +#define RT_YR_COMP3 0x4 +#define RT_YCF_COMP4 0x5 +#define RT_YCR_COMP4 0x6 + +/* Video standard defines */ +#define RT_NTSC 0x0 +#define RT_PAL 0x1 +#define RT_SECAM 0x2 +#define extNONE 0x0000 +#define extNTSC 0x0100 +#define extRsvd 0x0200 +#define extPAL 0x0300 +#define extPAL_M 0x0400 +#define extPAL_N 0x0500 +#define extSECAM 0x0600 +#define extPAL_NCOMB 0x0700 +#define extNTSC_J 0x0800 +#define extNTSC_443 0x0900 +#define extPAL_BGHI 0x0A00 +#define extPAL_60 0x0B00 + /* these are used in MSP3430 */ +#define extPAL_DK1 0x0C00 +#define extPAL_AUTO 0x0D00 + +#define RT_FREF_2700 6 +#define RT_FREF_2950 5 + +#define RT_COMPOSITE 0x0 +#define RT_SVIDEO 0x1 + +#define RT_NORM_SHARPNESS 0x03 +#define RT_HIGH_SHARPNESS 0x0F + +#define RT_HUE_PAL_DEF 0x00 + +#define RT_DECINTERLACED 0x1 +#define RT_DECNONINTERLACED 0x0 + +#define NTSC_LINES 525 +#define PAL_SECAM_LINES 625 + +#define RT_ASYNC_ENABLE 0x0 +#define RT_ASYNC_DISABLE 0x1 +#define RT_ASYNC_RESET 0x1 + +#define RT_VINRST_ACTIVE 0x0 +#define RT_VINRST_RESET 0x1 +#define RT_L54RST_RESET 0x1 + +#define RT_REF_CLK 0x0 +#define RT_PLL_VIN_CLK 0x1 + +#define RT_VIN_ASYNC_RST 0x20 +#define RT_DVS_ASYNC_RST 0x80 + +#define RT_ADC_ENABLE 0x0 +#define RT_ADC_DISABLE 0x1 + +#define RT_DVSDIR_IN 0x0 +#define RT_DVSDIR_OUT 0x1 + +#define RT_DVSCLK_HIGH 0x0 +#define RT_DVSCLK_LOW 0x1 + +#define RT_DVSCLK_SEL_8FS 0x0 +#define RT_DVSCLK_SEL_27MHZ 0x1 + +#define RT_DVS_CONTSTREAM 0x1 +#define RT_DVS_NONCONTSTREAM 0x0 + +#define RT_DVSDAT_HIGH 0x0 +#define RT_DVSDAT_LOW 0x1 + +#define RT_ADC_CNTL_DEFAULT 0x03252338 + +/* COMB_CNTL0 FILTER SETTINGS FOR DIFFERENT STANDARDS: */ +#define RT_NTSCM_COMB_CNTL0_COMPOSITE 0x09438090 /* was 0x09438090 */ +#define RT_NTSCM_COMB_CNTL0_SVIDEO 0x48540000 + +#define RT_PAL_COMB_CNTL0_COMPOSITE 0x09438090 +#define RT_PAL_COMB_CNTL0_SVIDEO 0x40348090 + +#define RT_SECAM_COMB_CNTL0_COMPOSITE 0xD0108090 /* instead of orig 0xD0088090 - eric*/ +#define RT_SECAM_COMB_CNTL0_SVIDEO 0x50148090 + +#define RT_PALN_COMB_CNTL0_COMPOSITE 0x09438090 +#define RT_PALN_COMB_CNTL0_SVIDEO 0x40348090 + +#define RT_PALM_COMB_CNTL0_COMPOSITE 0x09438090 +#define RT_PALM_COMB_CNTL0_SVIDEO 0x40348090 +/* End of filter settings. */ + +/* COMB_CNTL1 FILTER SETTINGS FOR DIFFERENT STANDARDS: */ +#define RT_NTSCM_COMB_CNTL1_COMPOSITE 0x00000010 +#define RT_NTSCM_COMB_CNTL1_SVIDEO 0x00000081 + +#define RT_PAL_COMB_CNTL1_COMPOSITE 0x00000010 +#define RT_PAL_COMB_CNTL1_SVIDEO 0x000000A1 + +#define RT_SECAM_COMB_CNTL1_COMPOSITE 0x00000091 +#define RT_SECAM_COMB_CNTL1_SVIDEO 0x00000081 + +#define RT_PALN_COMB_CNTL1_COMPOSITE 0x00000010 +#define RT_PALN_COMB_CNTL1_SVIDEO 0x000000A1 + +#define RT_PALM_COMB_CNTL1_COMPOSITE 0x00000010 +#define RT_PALM_COMB_CNTL1_SVIDEO 0x000000A1 +/* End of filter settings. */ + +/* COMB_CNTL2 FILTER SETTINGS FOR DIFFERENT STANDARDS: */ +#define RT_NTSCM_COMB_CNTL2_COMPOSITE 0x16161010 +#define RT_NTSCM_COMB_CNTL2_SVIDEO 0xFFFFFFFF + +#define RT_PAL_COMB_CNTL2_COMPOSITE 0x06080102 /* instead of 0x16161010 - Ivo */ +#define RT_PAL_COMB_CNTL2_SVIDEO 0x06080102 + +#define RT_SECAM_COMB_CNTL2_COMPOSITE 0xffffffff /* instead of 0x06080102 - eric */ +#define RT_SECAM_COMB_CNTL2_SVIDEO 0x06080102 + +#define RT_PALN_COMB_CNTL2_COMPOSITE 0x06080102 +#define RT_PALN_COMB_CNTL2_SVIDEO 0x06080102 + +#define RT_PALM_COMB_CNTL2_COMPOSITE 0x06080102 +#define RT_PALM_COMB_CNTL2_SVIDEO 0x06080102 +/* End of filter settings. */ + +/* COMB_LINE_LENGTH FILTER SETTINGS FOR DIFFERENT STANDARDS: */ +#define RT_NTSCM_COMB_LENGTH_COMPOSITE 0x0718038A +#define RT_NTSCM_COMB_LENGTH_SVIDEO 0x0718038A + +#define RT_PAL_COMB_LENGTH_COMPOSITE 0x08DA046B +#define RT_PAL_COMB_LENGTH_SVIDEO 0x08DA046B + +#define RT_SECAM_COMB_LENGTH_COMPOSITE 0x08DA046A +#define RT_SECAM_COMB_LENGTH_SVIDEO 0x08DA046A + +#define RT_PALN_COMB_LENGTH_COMPOSITE 0x07260391 +#define RT_PALN_COMB_LENGTH_SVIDEO 0x07260391 + +#define RT_PALM_COMB_LENGTH_COMPOSITE 0x07160389 +#define RT_PALM_COMB_LENGTH_SVIDEO 0x07160389 +/* End of filter settings. */ + +/* LP_AGC_CLAMP_CNTL0 */ +#define RT_NTSCM_SYNCTIP_REF0 0x00000037 +#define RT_NTSCM_SYNCTIP_REF1 0x00000029 +#define RT_NTSCM_CLAMP_REF 0x0000003B +#define RT_NTSCM_PEAKWHITE 0x000000FF +#define RT_NTSCM_VBI_PEAKWHITE 0x000000D2 /* was 0xc2 - docs say d2 */ + +#define RT_NTSCM_WPA_THRESHOLD 0x00000406 +#define RT_NTSCM_WPA_TRIGGER_LO 0x000000B3 + +#define RT_NTSCM_WPA_TRIGGER_HIGH 0x0000021B + +#define RT_NTSCM_LP_LOCKOUT_START 0x00000206 +#define RT_NTSCM_LP_LOCKOUT_END 0x00000021 +#define RT_NTSCM_CH_DTO_INC 0x00400000 +#define RT_NTSCM_CH_PLL_SGAIN 0x00000001 +#define RT_NTSCM_CH_PLL_FGAIN 0x00000002 + +#define RT_NTSCM_CR_BURST_GAIN 0x0000007A +#define RT_NTSCM_CB_BURST_GAIN 0x000000AC + +#define RT_NTSCM_CH_HEIGHT 0x000000CD +#define RT_NTSCM_CH_KILL_LEVEL 0x000000C0 +#define RT_NTSCM_CH_AGC_ERROR_LIM 0x00000002 +#define RT_NTSCM_CH_AGC_FILTER_EN 0x00000000 +#define RT_NTSCM_CH_AGC_LOOP_SPEED 0x00000000 + +#define RT_NTSCM_CRDR_ACTIVE_GAIN 0x0000007A +#define RT_NTSCM_CBDB_ACTIVE_GAIN 0x000000AC + +#define RT_NTSCM_VERT_LOCKOUT_START 0x00000207 +#define RT_NTSCM_VERT_LOCKOUT_END 0x0000000E + +#define RT_NTSCJ_SYNCTIP_REF0 0x00000004 +#define RT_NTSCJ_SYNCTIP_REF1 0x00000012 +#define RT_NTSCJ_CLAMP_REF 0x0000003B +#define RT_NTSCJ_PEAKWHITE 0x000000CB +#define RT_NTSCJ_VBI_PEAKWHITE 0x000000C2 +#define RT_NTSCJ_WPA_THRESHOLD 0x000004B0 +#define RT_NTSCJ_WPA_TRIGGER_LO 0x000000B4 +#define RT_NTSCJ_WPA_TRIGGER_HIGH 0x0000021C +#define RT_NTSCJ_LP_LOCKOUT_START 0x00000206 +#define RT_NTSCJ_LP_LOCKOUT_END 0x00000021 + +#define RT_NTSCJ_CR_BURST_GAIN 0x00000071 +#define RT_NTSCJ_CB_BURST_GAIN 0x0000009F +#define RT_NTSCJ_CH_HEIGHT 0x000000CD +#define RT_NTSCJ_CH_KILL_LEVEL 0x000000C0 +#define RT_NTSCJ_CH_AGC_ERROR_LIM 0x00000002 +#define RT_NTSCJ_CH_AGC_FILTER_EN 0x00000000 +#define RT_NTSCJ_CH_AGC_LOOP_SPEED 0x00000000 + +#define RT_NTSCJ_CRDR_ACTIVE_GAIN 0x00000071 +#define RT_NTSCJ_CBDB_ACTIVE_GAIN 0x0000009F +#define RT_NTSCJ_VERT_LOCKOUT_START 0x00000207 +#define RT_NTSCJ_VERT_LOCKOUT_END 0x0000000E + +#define RT_PAL_SYNCTIP_REF0 0x37 /* instead of 0x00000004 - Ivo */ +#define RT_PAL_SYNCTIP_REF1 0x26 /* instead of 0x0000000F - Ivo */ +#define RT_PAL_CLAMP_REF 0x0000003B +#define RT_PAL_PEAKWHITE 0xFF /* instead of 0x000000C1 - Ivo */ +#define RT_PAL_VBI_PEAKWHITE 0xC6 /* instead of 0x000000C7 - Ivo */ +#define RT_PAL_WPA_THRESHOLD 0x59C /* instead of 0x000006A4 - Ivo */ + +#define RT_PAL_WPA_TRIGGER_LO 0x00000096 +#define RT_PAL_WPA_TRIGGER_HIGH 0x000001C2 +#define RT_PAL_LP_LOCKOUT_START 0x00000263 +#define RT_PAL_LP_LOCKOUT_END 0x0000002C + +#define RT_PAL_CH_DTO_INC 0x00400000 +#define RT_PAL_CH_PLL_SGAIN 1 /* instead of 0x00000002 - Ivo */ +#define RT_PAL_CH_PLL_FGAIN 2 /* instead of 0x00000001 - Ivo */ +#define RT_PAL_CR_BURST_GAIN 0x0000007A +#define RT_PAL_CB_BURST_GAIN 0x000000AB +#define RT_PAL_CH_HEIGHT 0x0000009C +#define RT_PAL_CH_KILL_LEVEL 4 /* instead of 0x00000090 - Ivo */ +#define RT_PAL_CH_AGC_ERROR_LIM 1 /* instead of 0x00000002 - Ivo */ +#define RT_PAL_CH_AGC_FILTER_EN 1 /* instead of 0x00000000 - Ivo */ +#define RT_PAL_CH_AGC_LOOP_SPEED 0x00000000 + +#define RT_PAL_CRDR_ACTIVE_GAIN 0x9E /* instead of 0x0000007A - Ivo */ +#define RT_PAL_CBDB_ACTIVE_GAIN 0xDF /* instead of 0x000000AB - Ivo */ +#define RT_PAL_VERT_LOCKOUT_START 0x00000269 +#define RT_PAL_VERT_LOCKOUT_END 0x00000012 + +#define RT_SECAM_SYNCTIP_REF0 0x37 /* instead of 0x00000004 - Ivo */ +#define RT_SECAM_SYNCTIP_REF1 0x26 /* instead of 0x0000000F - Ivo */ +#define RT_SECAM_CLAMP_REF 0x0000003B +#define RT_SECAM_PEAKWHITE 0xFF /* instead of 0x000000C1 - Ivo */ +#define RT_SECAM_VBI_PEAKWHITE 0xC6 /* instead of 0x000000C7 - Ivo */ +#define RT_SECAM_WPA_THRESHOLD 0x57A /* instead of 0x6A4, instead of 0x0000059C is Ivo's value , -eric*/ + +#define RT_SECAM_WPA_TRIGGER_LO 0x96 /* instead of 0x0000026B - eric */ +#define RT_SECAM_WPA_TRIGGER_HIGH 0x000001C2 +#define RT_SECAM_LP_LOCKOUT_START 0x263 /* instead of 0x0000026B - eric */ +#define RT_SECAM_LP_LOCKOUT_END 0x2b /* instead of 0x0000002C -eric */ + +#define RT_SECAM_CH_DTO_INC 0x003E7A28 +#define RT_SECAM_CH_PLL_SGAIN 0x4 /* instead of 0x00000006 - Volodya */ +#define RT_SECAM_CH_PLL_FGAIN 0x7 /* instead of 0x00000006 -Volodya */ + +#define RT_SECAM_CR_BURST_GAIN 0x1FF /* instead of 0x00000200 -Volodya */ +#define RT_SECAM_CB_BURST_GAIN 0x1FF /* instead of 0x00000200 -Volodya */ +#define RT_SECAM_CH_HEIGHT 0x00000066 +#define RT_SECAM_CH_KILL_LEVEL 0x00000060 +#define RT_SECAM_CH_AGC_ERROR_LIM 0x00000003 +#define RT_SECAM_CH_AGC_FILTER_EN 0x00000000 +#define RT_SECAM_CH_AGC_LOOP_SPEED 0x00000000 + +#define RT_SECAM_CRDR_ACTIVE_GAIN 0x11B /* instead of 0x00000200 - eric */ +#define RT_SECAM_CBDB_ACTIVE_GAIN 0x15A /* instead of 0x00000200 - eric */ +#define RT_SECAM_VERT_LOCKOUT_START 0x00000269 +#define RT_SECAM_VERT_LOCKOUT_END 0x00000012 + +#define RT_PAL_VS_FIELD_BLANK_END 0x2A /* instead of 0x0000002C - Ivo*/ +#define RT_NTSCM_VS_FIELD_BLANK_END 0x0000000a + +#define RT_NTSCM_FIELD_IDLOCATION 0x00000105 +#define RT_PAL_FIELD_IDLOCATION 0x00000137 + +#define RT_NTSCM_H_ACTIVE_START 0x00000070 +#define RT_NTSCM_H_ACTIVE_END 0x00000363 + +#define RT_PAL_H_ACTIVE_START 0x0000009A +#define RT_PAL_H_ACTIVE_END 0x00000439 + +#define RT_NTSCM_V_ACTIVE_START ((22-4)*2+1) +#define RT_NTSCM_V_ACTIVE_END ((22+240-4)*2+1) + +#define RT_PAL_V_ACTIVE_START 0x2E /* instead of 0x00000023 (Same as SECAM) - Ivo */ +#define RT_PAL_V_ACTIVE_END 0x269 /* instead of 0x00000262 - Ivo */ + +/* VBI */ +#define RT_NTSCM_H_VBI_WIND_START 0x32 /* instead of 0x00000049 - V.D. */ +#define RT_NTSCM_H_VBI_WIND_END 0x367 /* instead of 0x00000366 - V.D. */ + +#define RT_PAL_H_VBI_WIND_START 0x00000084 +#define RT_PAL_H_VBI_WIND_END 0x0000041F + +#define RT_NTSCM_V_VBI_WIND_START fld_V_VBI_WIND_START_def +#define RT_NTSCM_V_VBI_WIND_END fld_V_VBI_WIND_END_def + +#define RT_PAL_V_VBI_WIND_START 0x8 /* instead of 0x0000000B - Ivo */ +#define RT_PAL_V_VBI_WIND_END 0x2D /* instead of 0x00000022 - Ivo */ + +#define RT_VBI_CAPTURE_EN 0x00000001 /* Enable */ +#define RT_VBI_CAPTURE_DIS 0x00000000 /* Disable */ +#define RT_RAW_CAPTURE 0x00000002 /* Use raw Video Capture. */ + +#define RT_NTSCM_VSYNC_INT_TRIGGER 0x2AA +#define RT_PALSEM_VSYNC_INT_TRIGGER 0x353 + +#define RT_NTSCM_VSYNC_INT_HOLD 0x17 +#define RT_PALSEM_VSYNC_INT_HOLD 0x1C + +#define RT_NTSCM_VS_FIELD_BLANK_START 0x206 +#define RT_PALSEM_VS_FIELD_BLANK_START 0x26D /* instead of 0x26C - Ivo */ + +#define RT_FIELD_FLIP_EN 0x4 +#define RT_V_FIELD_FLIP_INVERTED 0x2000 + +#define RT_NTSCM_H_IN_START 0x70 +#define RT_PAL_H_IN_START 154 /* instead of 144 - Ivo */ +#define RT_SECAM_H_IN_START 0x91 /* instead of 0x9A, Ivo value is 154, instead of 144 - Volodya, - eric */ +#define RT_NTSC_H_ACTIVE_SIZE 744 +#define RT_PAL_H_ACTIVE_SIZE 928 /* instead of 927 - Ivo */ +#define RT_SECAM_H_ACTIVE_SIZE 932 /* instead of 928, instead of 927 - Ivo, - eric */ +#define RT_NTSCM_V_IN_START (0x23) +#define RT_PAL_V_IN_START 44 /* instead of (45-6) - Ivo */ +#define RT_SECAM_V_IN_START 0x2C /* instead of (45-6) - Volodya */ +#define RT_NTSCM_V_ACTIVE_SIZE 480 +#define RT_PAL_V_ACTIVE_SIZE 572 /* instead of 575 - Ivo */ +#define RT_SECAM_V_ACTIVE_SIZE 570 /* instead of 572, instead of 575 - Ivo, - eric */ + +#define RT_NTSCM_WIN_CLOSE_LIMIT 0x4D +#define RT_NTSCJ_WIN_CLOSE_LIMIT 0x4D +#define RT_NTSC443_WIN_CLOSE_LIMIT 0x5F +#define RT_PALM_WIN_CLOSE_LIMIT 0x4D +#define RT_PALN_WIN_CLOSE_LIMIT 0x5F +#define RT_SECAM_WIN_CLOSE_LIMIT 0xC7 /* instead of 0x5F - eric */ + +#define RT_NTSCM_VS_FIELD_BLANK_START 0x206 + +#define RT_NTSCM_HS_PLL_SGAIN 0x5 +#define RT_NTSCM_HS_PLL_FGAIN 0x7 + +#define RT_NTSCM_H_OUT_WIND_WIDTH 0x2F4 +#define RT_NTSCM_V_OUT_WIND_HEIGHT 0xF0 + +#define TV 0x1 +#define LINEIN 0x2 +#define MUTE 0x3 + +#define DEC_COMPOSITE 0 +#define DEC_SVIDEO 1 +#define DEC_TUNER 2 + +#define DEC_NTSC 0 +#define DEC_PAL 1 +#define DEC_SECAM 2 +#define DEC_NTSC_J 8 + +#define DEC_SMOOTH 0 +#define DEC_SHARP 1 + +/* RT Register Field Defaults: */ +#define fld_tmpReg1_def (CARD32) 0x00000000 +#define fld_tmpReg2_def (CARD32) 0x00000001 +#define fld_tmpReg3_def (CARD32) 0x00000002 + +#define fld_LP_CONTRAST_def (CARD32) 0x0000006e +#define fld_LP_BRIGHTNESS_def (CARD32) 0x00003ff0 +#define fld_CP_HUE_CNTL_def (CARD32) 0x00000000 +#define fld_LUMA_FILTER_def (CARD32) 0x00000001 +#define fld_H_SCALE_RATIO_def (CARD32) 0x00010000 +#define fld_H_SHARPNESS_def (CARD32) 0x00000000 + +#define fld_V_SCALE_RATIO_def (CARD32) 0x00000800 +#define fld_V_DEINTERLACE_ON_def (CARD32) 0x00000001 +#define fld_V_BYPSS_def (CARD32) 0x00000000 +#define fld_V_DITHER_ON_def (CARD32) 0x00000001 +#define fld_EVENF_OFFSET_def (CARD32) 0x00000000 +#define fld_ODDF_OFFSET_def (CARD32) 0x00000000 + +#define fld_INTERLACE_DETECTED_def (CARD32) 0x00000000 + +#define fld_VS_LINE_COUNT_def (CARD32) 0x00000000 +#define fld_VS_DETECTED_LINES_def (CARD32) 0x00000000 +#define fld_VS_ITU656_VB_def (CARD32) 0x00000000 + +#define fld_VBI_CC_DATA_def (CARD32) 0x00000000 +#define fld_VBI_CC_WT_def (CARD32) 0x00000000 +#define fld_VBI_CC_WT_ACK_def (CARD32) 0x00000000 +#define fld_VBI_CC_HOLD_def (CARD32) 0x00000000 +#define fld_VBI_DECODE_EN_def (CARD32) 0x00000000 + +#define fld_VBI_CC_DTO_P_def (CARD32) 0x00001802 +#define fld_VBI_20BIT_DTO_P_def (CARD32) 0x0000155c + +#define fld_VBI_CC_LEVEL_def (CARD32) 0x0000003f +#define fld_VBI_20BIT_LEVEL_def (CARD32) 0x00000059 +#define fld_VBI_CLK_RUNIN_GAIN_def (CARD32) 0x0000010f + +#define fld_H_VBI_WIND_START_def (CARD32) 0x00000041 +#define fld_H_VBI_WIND_END_def (CARD32) 0x00000366 + +#define fld_V_VBI_WIND_START_def (CARD32) 0x0B /* instead of 0x0D - V.D. */ +#define fld_V_VBI_WIND_END_def (CARD32) 0x24 + +#define fld_VBI_20BIT_DATA0_def (CARD32) 0x00000000 +#define fld_VBI_20BIT_DATA1_def (CARD32) 0x00000000 +#define fld_VBI_20BIT_WT_def (CARD32) 0x00000000 +#define fld_VBI_20BIT_WT_ACK_def (CARD32) 0x00000000 +#define fld_VBI_20BIT_HOLD_def (CARD32) 0x00000000 + +#define fld_VBI_CAPTURE_ENABLE_def (CARD32) 0x00000000 + +#define fld_VBI_EDS_DATA_def (CARD32) 0x00000000 +#define fld_VBI_EDS_WT_def (CARD32) 0x00000000 +#define fld_VBI_EDS_WT_ACK_def (CARD32) 0x00000000 +#define fld_VBI_EDS_HOLD_def (CARD32) 0x00000000 + +#define fld_VBI_SCALING_RATIO_def (CARD32) 0x00010000 +#define fld_VBI_ALIGNER_ENABLE_def (CARD32) 0x00000000 + +#define fld_H_ACTIVE_START_def (CARD32) 0x00000070 +#define fld_H_ACTIVE_END_def (CARD32) 0x000002f0 + +#define fld_V_ACTIVE_START_def (CARD32) ((22-4)*2+1) +#define fld_V_ACTIVE_END_def (CARD32) ((22+240-4)*2+2) + +#define fld_CH_HEIGHT_def (CARD32) 0x000000CD +#define fld_CH_KILL_LEVEL_def (CARD32) 0x000000C0 +#define fld_CH_AGC_ERROR_LIM_def (CARD32) 0x00000002 +#define fld_CH_AGC_FILTER_EN_def (CARD32) 0x00000000 +#define fld_CH_AGC_LOOP_SPEED_def (CARD32) 0x00000000 + +#define fld_HUE_ADJ_def (CARD32) 0x00000000 + +#define fld_STANDARD_SEL_def (CARD32) 0x00000000 +#define fld_STANDARD_YC_def (CARD32) 0x00000000 + +#define fld_ADC_PDWN_def (CARD32) 0x00000001 +#define fld_INPUT_SELECT_def (CARD32) 0x00000000 + +#define fld_ADC_PREFLO_def (CARD32) 0x00000003 +#define fld_H_SYNC_PULSE_WIDTH_def (CARD32) 0x00000000 +#define fld_HS_GENLOCKED_def (CARD32) 0x00000000 +#define fld_HS_SYNC_IN_WIN_def (CARD32) 0x00000000 + +#define fld_VIN_ASYNC_RST_def (CARD32) 0x00000001 +#define fld_DVS_ASYNC_RST_def (CARD32) 0x00000001 + +/* Vendor IDs: */ +#define fld_VIP_VENDOR_ID_def (CARD32) 0x00001002 +#define fld_VIP_DEVICE_ID_def (CARD32) 0x00004d54 +#define fld_VIP_REVISION_ID_def (CARD32) 0x00000001 + +/* AGC Delay Register */ +#define fld_BLACK_INT_START_def (CARD32) 0x00000031 +#define fld_BLACK_INT_LENGTH_def (CARD32) 0x0000000f + +#define fld_UV_INT_START_def (CARD32) 0x0000003b +#define fld_U_INT_LENGTH_def (CARD32) 0x0000000f +#define fld_V_INT_LENGTH_def (CARD32) 0x0000000f +#define fld_CRDR_ACTIVE_GAIN_def (CARD32) 0x0000007a +#define fld_CBDB_ACTIVE_GAIN_def (CARD32) 0x000000ac + +#define fld_DVS_DIRECTION_def (CARD32) 0x00000000 +#define fld_DVS_VBI_CARD8_SWAP_def (CARD32) 0x00000000 +#define fld_DVS_CLK_SELECT_def (CARD32) 0x00000000 +#define fld_CONTINUOUS_STREAM_def (CARD32) 0x00000000 +#define fld_DVSOUT_CLK_DRV_def (CARD32) 0x00000001 +#define fld_DVSOUT_DATA_DRV_def (CARD32) 0x00000001 + +#define fld_COMB_CNTL0_def (CARD32) 0x09438090 +#define fld_COMB_CNTL1_def (CARD32) 0x00000010 + +#define fld_COMB_CNTL2_def (CARD32) 0x16161010 +#define fld_COMB_LENGTH_def (CARD32) 0x0718038A + +#define fld_SYNCTIP_REF0_def (CARD32) 0x00000037 +#define fld_SYNCTIP_REF1_def (CARD32) 0x00000029 +#define fld_CLAMP_REF_def (CARD32) 0x0000003B +#define fld_AGC_PEAKWHITE_def (CARD32) 0x000000FF +#define fld_VBI_PEAKWHITE_def (CARD32) 0x000000D2 + +#define fld_WPA_THRESHOLD_def (CARD32) 0x000003B0 + +#define fld_WPA_TRIGGER_LO_def (CARD32) 0x000000B4 +#define fld_WPA_TRIGGER_HIGH_def (CARD32) 0x0000021C + +#define fld_LOCKOUT_START_def (CARD32) 0x00000206 +#define fld_LOCKOUT_END_def (CARD32) 0x00000021 + +#define fld_CH_DTO_INC_def (CARD32) 0x00400000 +#define fld_PLL_SGAIN_def (CARD32) 0x00000001 +#define fld_PLL_FGAIN_def (CARD32) 0x00000002 + +#define fld_CR_BURST_GAIN_def (CARD32) 0x0000007a +#define fld_CB_BURST_GAIN_def (CARD32) 0x000000ac + +#define fld_VERT_LOCKOUT_START_def (CARD32) 0x00000207 +#define fld_VERT_LOCKOUT_END_def (CARD32) 0x0000000E + +#define fld_H_IN_WIND_START_def (CARD32) 0x00000070 +#define fld_V_IN_WIND_START_def (CARD32) 0x00000027 + +#define fld_H_OUT_WIND_WIDTH_def (CARD32) 0x000002f4 + +#define fld_V_OUT_WIND_WIDTH_def (CARD32) 0x000000f0 + +#define fld_HS_LINE_TOTAL_def (CARD32) 0x0000038E + +#define fld_MIN_PULSE_WIDTH_def (CARD32) 0x0000002F +#define fld_MAX_PULSE_WIDTH_def (CARD32) 0x00000046 + +#define fld_WIN_CLOSE_LIMIT_def (CARD32) 0x0000004D +#define fld_WIN_OPEN_LIMIT_def (CARD32) 0x000001B7 + +#define fld_VSYNC_INT_TRIGGER_def (CARD32) 0x000002AA + +#define fld_VSYNC_INT_HOLD_def (CARD32) 0x0000001D + +#define fld_VIN_M0_def (CARD32) 0x00000039 +#define fld_VIN_N0_def (CARD32) 0x0000014c +#define fld_MNFLIP_EN_def (CARD32) 0x00000000 +#define fld_VIN_P_def (CARD32) 0x00000006 +#define fld_REG_CLK_SEL_def (CARD32) 0x00000000 + +#define fld_VIN_M1_def (CARD32) 0x00000000 +#define fld_VIN_N1_def (CARD32) 0x00000000 +#define fld_VIN_DRIVER_SEL_def (CARD32) 0x00000000 +#define fld_VIN_MNFLIP_REQ_def (CARD32) 0x00000000 +#define fld_VIN_MNFLIP_DONE_def (CARD32) 0x00000000 +#define fld_TV_LOCK_TO_VIN_def (CARD32) 0x00000000 +#define fld_TV_P_FOR_WINCLK_def (CARD32) 0x00000004 + +#define fld_VINRST_def (CARD32) 0x00000001 +#define fld_VIN_CLK_SEL_def (CARD32) 0x00000000 + +#define fld_VS_FIELD_BLANK_START_def (CARD32) 0x00000206 + +#define fld_VS_FIELD_BLANK_END_def (CARD32) 0x0000000A + +/*#define fld_VS_FIELD_IDLOCATION_def (CARD32) 0x00000105 */ +#define fld_VS_FIELD_IDLOCATION_def (CARD32) 0x00000001 +#define fld_VS_FRAME_TOTAL_def (CARD32) 0x00000217 + +#define fld_SYNC_TIP_START_def (CARD32) 0x00000372 +#define fld_SYNC_TIP_LENGTH_def (CARD32) 0x0000000F + +#define fld_GAIN_FORCE_DATA_def (CARD32) 0x00000000 +#define fld_GAIN_FORCE_EN_def (CARD32) 0x00000000 +#define fld_I_CLAMP_SEL_def (CARD32) 0x00000003 +#define fld_I_AGC_SEL_def (CARD32) 0x00000001 +#define fld_EXT_CLAMP_CAP_def (CARD32) 0x00000001 +#define fld_EXT_AGC_CAP_def (CARD32) 0x00000001 +#define fld_DECI_DITHER_EN_def (CARD32) 0x00000001 +#define fld_ADC_PREFHI_def (CARD32) 0x00000000 +#define fld_ADC_CH_GAIN_SEL_def (CARD32) 0x00000001 + +#define fld_HS_PLL_SGAIN_def (CARD32) 0x00000003 + +#define fld_NREn_def (CARD32) 0x00000000 +#define fld_NRGainCntl_def (CARD32) 0x00000000 +#define fld_NRBWTresh_def (CARD32) 0x00000000 +#define fld_NRGCTresh_def (CARD32) 0x00000000 +#define fld_NRCoefDespeclMode_def (CARD32) 0x00000000 + +#define fld_GPIO_5_OE_def (CARD32) 0x00000000 +#define fld_GPIO_6_OE_def (CARD32) 0x00000000 + +#define fld_GPIO_5_OUT_def (CARD32) 0x00000000 +#define fld_GPIO_6_OUT_def (CARD32) 0x00000000 + +/* End of field default values. */ + +#endif |