diff options
Diffstat (limited to 'src/i830_driver.c')
-rw-r--r-- | src/i830_driver.c | 3586 |
1 files changed, 3586 insertions, 0 deletions
diff --git a/src/i830_driver.c b/src/i830_driver.c new file mode 100644 index 00000000..073f8eb6 --- /dev/null +++ b/src/i830_driver.c @@ -0,0 +1,3586 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_driver.c,v 1.27 2003/02/14 17:12:42 dawes Exp $ */ +/************************************************************************** + +Copyright 2001 VA Linux Systems Inc., Fremont, California. +Copyright © 2002 by David Dawes + +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, sub +license, and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS 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. + +**************************************************************************/ + +/* + * Reformatted with GNU indent (2.2.8), using the following options: + * + * -bad -bap -c41 -cd0 -ncdb -ci6 -cli0 -cp0 -ncs -d0 -di3 -i3 -ip3 -l78 + * -lp -npcs -psl -sob -ss -br -ce -sc -hnl + * + * This provides a good match with the original i810 code and preferred + * XFree86 formatting conventions. + * + * When editing this driver, please follow the existing formatting, and edit + * with <TAB> characters expanded at 8-column intervals. + */ + +/* + * Authors: Jeff Hartmann <jhartmann@valinux.com> + * Abraham van der Merwe <abraham@2d3d.co.za> + * David Dawes <dawes@tungstengraphics.com> + */ + +/* + * Mode handling is based on the VESA driver written by: + * Paulo César Pereira de Andrade <pcpa@conectiva.com.br> + */ + +/* + * Changes: + * + * 23/08/2001 Abraham van der Merwe <abraham@2d3d.co.za> + * - Fixed display timing bug (mode information for some + * modes were not initialized correctly) + * - Added workarounds for GTT corruptions (I don't adjust + * the pitches for 1280x and 1600x modes so we don't + * need extra memory) + * - The code will now default to 60Hz if LFP is connected + * - Added different refresh rate setting code to work + * around 0x4f02 BIOS bug + * - BIOS workaround for some mode sets (I use legacy BIOS + * calls for setting those) + * - Removed 0x4f04, 0x01 (save state) BIOS call which causes + * LFP to malfunction (do some house keeping and restore + * modes ourselves instead - not perfect, but at least the + * LFP is working now) + * - Several other smaller bug fixes + * + * 06/09/2001 Abraham van der Merwe <abraham@2d3d.co.za> + * - Preliminary local memory support (works without agpgart) + * - DGA fixes (the code were still using i810 mode sets, etc.) + * - agpgart fixes + * + * 18/09/2001 + * - Proper local memory support (should work correctly now + * with/without agpgart module) + * - more agpgart fixes + * - got rid of incorrect GTT adjustments + * + * 09/10/2001 + * - Changed the DPRINTF() variadic macro to an ANSI C compatible + * version + * + * 10/10/2001 + * - Fixed DPRINTF_stub(). I forgot the __...__ macros in there + * instead of the function arguments :P + * - Added a workaround for the 1600x1200 bug (Text mode corrupts + * when you exit from any 1600x1200 mode and 1280x1024@85Hz. I + * suspect this is a BIOS bug (hence the 1280x1024@85Hz case)). + * For now I'm switching to 800x600@60Hz then to 80x25 text mode + * and then restoring the registers - very ugly indeed. + * + * 15/10/2001 + * - Improved 1600x1200 mode set workaround. The previous workaround + * was causing mode set problems later on. + * + * 18/10/2001 + * - Fixed a bug in I830BIOSLeaveVT() which caused a bug when you + * switched VT's + */ +/* + * 07/2002 David Dawes + * - Add Intel(R) 855GM/852GM support. + */ +/* + * 07/2002 David Dawes + * - Cleanup code formatting. + * - Improve VESA mode selection, and fix refresh rate selection. + * - Don't duplicate functions provided in 4.2 vbe modules. + * - Don't duplicate functions provided in the vgahw module. + * - Rewrite memory allocation. + * - Rewrite initialisation and save/restore state handling. + * - Decouple the i810 support from i830 and later. + * - Remove various unnecessary hacks and workarounds. + * - Fix an 845G problem with the ring buffer not in pre-allocated + * memory. + * - Fix screen blanking. + * - Clear the screen at startup so you don't see the previous session. + * - Fix some HW cursor glitches, and turn HW cursor off at VT switch + * and exit. + * + * 08/2002 Keith Whitwell + * - Fix DRI initialisation. + */ +/* + * 08/2002 Alan Hourihane and David Dawes + * - Add XVideo support. + */ +/* + * 10/2002 David Dawes + * - Add Intel(R) 865G support. + */ + + +#ifndef PRINT_MODE_INFO +#define PRINT_MODE_INFO 0 +#endif + +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "xf86cmap.h" +#include "compiler.h" +#include "mibstore.h" +#include "vgaHW.h" +#include "mipointer.h" +#include "micmap.h" + +#include "fb.h" +#include "miscstruct.h" +#include "xf86xv.h" +#include "Xv.h" +#include "vbe.h" +#include "vbeModes.h" + +#include "i830.h" + +#ifdef XF86DRI +#include "dri.h" +#endif + +#define BIT(x) (1 << (x)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define NB_OF(x) (sizeof (x) / sizeof (*x)) + +/* *INDENT-OFF* */ +static SymTabRec I830BIOSChipsets[] = { + {PCI_CHIP_I830_M, "i830"}, + {PCI_CHIP_845_G, "845G"}, + {PCI_CHIP_I855_GM, "852GM/855GM"}, + {PCI_CHIP_I865_G, "865G"}, + {-1, NULL} +}; + +static PciChipsets I830BIOSPciChipsets[] = { + {PCI_CHIP_I830_M, PCI_CHIP_I830_M, RES_SHARED_VGA}, + {PCI_CHIP_845_G, PCI_CHIP_845_G, RES_SHARED_VGA}, + {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA}, + {PCI_CHIP_I865_G, PCI_CHIP_I865_G, RES_SHARED_VGA}, + {-1, -1, RES_UNDEFINED} +}; + +/* + * Note: "ColorKey" is provided for compatibility with the i810 driver. + * However, the correct option name is "VideoKey". "ColorKey" usually + * refers to the tranparency key for 8+24 overlays, not for video overlays. + */ + +typedef enum { + OPTION_NOACCEL, + OPTION_SW_CURSOR, + OPTION_CACHE_LINES, + OPTION_DRI, + OPTION_PAGEFLIP, + OPTION_XVIDEO, + OPTION_VIDEO_KEY, + OPTION_COLOR_KEY, + OPTION_STRETCH, + OPTION_CENTER +} I830Opts; + +static OptionInfoRec I830BIOSOptions[] = { + {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE}, + {OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, TRUE}, + {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_XVIDEO, "XVideo", OPTV_BOOLEAN, {0}, TRUE}, + {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE}, + {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE}, + {OPTION_STRETCH, "Stretch", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_CENTER, "Center", OPTV_BOOLEAN, {0}, FALSE}, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; +/* *INDENT-ON* */ + +static void I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagementMode, int flags); +static void I830BIOSAdjustFrame(int scrnIndex, int x, int y, int flags); +static Bool I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool I830BIOSSaveScreen(ScreenPtr pScreen, int unblack); +static Bool I830BIOSEnterVT(int scrnIndex, int flags); +static Bool I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, + VbeCRTCInfoBlock *block); + +static Bool OffsetFrame = FALSE; + + + +#ifdef I830DEBUG +void +I830DPRINTF_stub(const char *filename, int line, const char *function, + const char *fmt, ...) +{ + va_list ap; + + ErrorF("\n##############################################\n" + "*** In function %s, on line %d, in file %s ***\n", + function, line, filename); + va_start(ap, fmt); + VErrorF(fmt, ap); + va_end(ap); + ErrorF("##############################################\n\n"); +} +#else /* #ifdef I830DEBUG */ +void +I830DPRINTF_stub(const char *filename, int line, const char *function, + const char *fmt, ...) +{ + /* do nothing */ +} +#endif /* #ifdef I830DEBUG */ + +/* XXX Check if this is still needed. */ +const OptionInfoRec * +I830BIOSAvailableOptions(int chipid, int busid) +{ + int i; + + for (i = 0; I830BIOSPciChipsets[i].PCIid > 0; i++) { + if (chipid == I830BIOSPciChipsets[i].PCIid) + return I830BIOSOptions; + } + return NULL; +} + +static Bool +I830BIOSGetRec(ScrnInfoPtr pScrn) +{ + I830Ptr pI830; + + if (pScrn->driverPrivate) + return TRUE; + pI830 = pScrn->driverPrivate = xnfcalloc(sizeof(I830Rec), 1); + pI830->vesa = xnfcalloc(sizeof(VESARec), 1); + return TRUE; +} + +static void +I830BIOSFreeRec(ScrnInfoPtr pScrn) +{ + I830Ptr pI830; + VESAPtr pVesa; + DisplayModePtr mode; + + if (!pScrn) + return; + if (!pScrn->driverPrivate) + return; + + pI830 = I830PTR(pScrn); + mode = pScrn->modes; + + if (mode) { + do { + if (mode->Private) { + VbeModeInfoData *data = (VbeModeInfoData *) mode->Private; + + if (data->block) + xfree(data->block); + xfree(data); + mode->Private = NULL; + } + mode = mode->next; + } while (mode && mode != pScrn->modes); + } + + if (pI830->vbeInfo) + VBEFreeVBEInfo(pI830->vbeInfo); + if (pI830->pVbe) + vbeFree(pI830->pVbe); + + pVesa = pI830->vesa; + if (pVesa->monitor) + xfree(pVesa->monitor); + if (pVesa->savedPal) + xfree(pVesa->savedPal); + xfree(pVesa); + + xfree(pScrn->driverPrivate); + pScrn->driverPrivate = NULL; +} + +static void +I830BIOSProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + + /* The vbe module gets loaded in PreInit(), so no need to load it here. */ + + pVbe = VBEInit(NULL, index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); +} + +/* Various extended video BIOS functions. */ +static const int refreshes[] = { + 43, 56, 60, 70, 72, 75, 85, 100, 120 +}; +static const int nrefreshes = sizeof(refreshes) / sizeof(refreshes[0]); + +static Bool +Check5fStatus(ScrnInfoPtr pScrn, int func, int ax) +{ + if (ax == 0x005f) + return TRUE; + else if (ax == 0x015f) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Extended BIOS function 0x%04x failed.\n", func); + return FALSE; + } else if ((ax & 0xff) != 0x5f) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Extended BIOS function 0x%04x not supported.\n", func); + return FALSE; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Extended BIOS function 0x%04x returns 0x%04x.\n", + func, ax & 0xffff); + return FALSE; + } +} + +#if 0 +static int +BitToRefresh(int bits) +{ + int i; + + for (i = 0; i < nrefreshes; i++) + if (bits & (1 << i)) + return refreshes[i]; + return 0; +} + +static int +GetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh, int *availRefresh) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetRefreshRate\n"); + + /* Only 8-bit mode numbers are supported. */ + if (mode & 0x100) + return 0; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f05; + pVbe->pInt10->bx = (mode & 0xff) | 0x100; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f05, pVbe->pInt10->ax)) { + if (availRefresh) + *availRefresh = pVbe->pInt10->bx; + return BitToRefresh(pVbe->pInt10->cx); + } else + return 0; +} +#endif + +static int +SetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh) +{ + int i; + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "SetRefreshRate: mode 0x%x, refresh: %d\n", mode, refresh); + + /* Only 8-bit mode numbers are supported. */ + if (mode & 0x100) + return 0; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f05; + pVbe->pInt10->bx = mode & 0xff; + + for (i = nrefreshes - 1; i >= 0; i--) { + /* + * Look for the highest value that the requested (refresh + 2) is + * greater than or equal to. + */ + if (refreshes[i] <= (refresh + 2)) + break; + } + /* i can be 0 if the requested refresh was higher than the max. */ + if (i == 0) { + if (refresh >= refreshes[nrefreshes - 1]) + i = nrefreshes - 1; + } + DPRINTF(PFX, "Setting refresh rate to %dHz for mode 0x%02x\n", + refreshes[i], mode & 0xff); + pVbe->pInt10->cx = 1 << i; + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f05, pVbe->pInt10->ax)) + return refreshes[i]; + else + return 0; +} + +static Bool +GetModeSupport(ScrnInfoPtr pScrn, int modePipeA, int modePipeB, + int devicesPipeA, int devicesPipeB, int *maxBandwidth, + int *bandwidthPipeA, int *bandwidthPipeB) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetModeSupport: modes 0x%x, 0x%x, devices: 0x%x, 0x%x\n", + modePipeA, modePipeB, devicesPipeA, devicesPipeB); + + /* Only 8-bit mode numbers are supported. */ + if ((modePipeA & 0x100) || (modePipeB & 0x100)) + return 0; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f28; + pVbe->pInt10->bx = (modePipeA & 0xff) | ((modePipeB & 0xff) << 8); + if ((devicesPipeA & 0x80) || (devicesPipeB & 0x80)) + pVbe->pInt10->cx = 0x8000; + else + pVbe->pInt10->cx = (devicesPipeA & 0xff) | ((devicesPipeB & 0xff) << 8); + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f28, pVbe->pInt10->ax)) { + if (maxBandwidth) + *maxBandwidth = pVbe->pInt10->cx; + if (bandwidthPipeA) + *bandwidthPipeA = pVbe->pInt10->dx & 0xffff; + /* XXX For XFree86 4.2.0 and earlier, ->dx is truncated to 16 bits. */ + if (bandwidthPipeB) + *bandwidthPipeB = (pVbe->pInt10->dx >> 16) & 0xffff; + return TRUE; + } else + return FALSE; +} + +static int +GetLFPCompMode(ScrnInfoPtr pScrn) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetLFPCompMode\n"); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f61; + pVbe->pInt10->bx = 0x100; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f61, pVbe->pInt10->ax)) + return pVbe->pInt10->cx & 0xffff; + else + return -1; +} + +#if 0 +static Bool +SetLFPCompMode(ScrnInfoPtr pScrn, int compMode) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "SetLFPCompMode: compMode %d\n", compMode); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f61; + pVbe->pInt10->bx = 0; + pVbe->pInt10->cx = compMode; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + return Check5fStatus(pScrn, 0x5f61, pVbe->pInt10->ax); +} +#endif + +static int +GetDisplayDevices(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + + DPRINTF(PFX, "GetDisplayDevices\n"); + +#if 0 + { + CARD32 temp; + ErrorF("ADPA is 0x%08x\n", INREG(ADPA)); + ErrorF("DVOA is 0x%08x\n", INREG(DVOA)); + ErrorF("DVOB is 0x%08x\n", INREG(DVOB)); + ErrorF("DVOC is 0x%08x\n", INREG(DVOC)); + ErrorF("LVDS is 0x%08x\n", INREG(LVDS)); + temp = INREG(DVOA_SRCDIM); + ErrorF("DVOA_SRCDIM is 0x%08x (%d x %d)\n", temp, + (temp >> 12) & 0xfff, temp & 0xfff); + temp = INREG(DVOB_SRCDIM); + ErrorF("DVOB_SRCDIM is 0x%08x (%d x %d)\n", temp, + (temp >> 12) & 0xfff, temp & 0xfff); + temp = INREG(DVOC_SRCDIM); + ErrorF("DVOC_SRCDIM is 0x%08x (%d x %d)\n", temp, + (temp >> 12) & 0xfff, temp & 0xfff); + ErrorF("SWF0 is 0x%08x\n", INREG(SWF0)); + ErrorF("SWF4 is 0x%08x\n", INREG(SWF4)); + } +#endif + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x100; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) + return pVbe->pInt10->cx & 0xffff; + else + return -1; +} + +static Bool +SetDisplayDevices(ScrnInfoPtr pScrn, int devices) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + CARD32 temp; + + DPRINTF(PFX, "SetDisplayDevices: devices 0x%x\n", devices); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x1; + pVbe->pInt10->cx = devices; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) + return TRUE; + else { + ErrorF("Writing config directly to SWF0\n"); + temp = INREG(SWF0); + OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff)); + ErrorF("SetDisplayDevices failed. devices is 0x%x instead of 0x%x\n", + GetDisplayDevices(pScrn), devices); + return FALSE; + } +} + +#if 0 +static Bool +GetDevicePresence(ScrnInfoPtr pScrn, Bool *required, int *attached, + int *encoderPresent) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetDevicePresence\n"); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x200; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { + if (required) + *required = ((pVbe->pInt10->bx & 0x1) == 0); + if (attached) + *attached = (pVbe->pInt10->cx >> 8) & 0xff; + if (encoderPresent) + *encoderPresent = pVbe->pInt10->cx & 0xff; + return TRUE; + } else + return FALSE; +} +#endif + +static Bool +GetDisplayInfo(ScrnInfoPtr pScrn, int device, Bool *attached, Bool *present, + short *x, short *y) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetDisplayInfo: device: 0x%x\n", device); + + switch (device & 0xff) { + case 0x01: + case 0x02: + case 0x04: + case 0x08: + case 0x10: + case 0x20: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "GetDisplayInfo: invalid device: 0x%x\n", device & 0xff); + return FALSE; + } + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x300; + pVbe->pInt10->cx = device & 0xff; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { + if (attached) + *attached = ((pVbe->pInt10->bx & 0x2) != 0); + if (present) + *present = ((pVbe->pInt10->bx & 0x1) != 0); + if (pVbe->pInt10->cx != (device & 0xff)) { + if (y) { + *y = pVbe->pInt10->cx & 0xffff; + } + if (x) { + *x = (pVbe->pInt10->cx >> 16) & 0xffff; + } + } + return TRUE; + } else + return FALSE; +} + +/* + * Returns a string matching the device corresponding to the first bit set + * in "device". savedDevice is then set to device with that bit cleared. + * Subsequent calls with device == -1 will use savedDevice. + */ + +static const char *displayDevices[] = { + "CRT", + "TV", + "DFP (digital flat panel)", + "LFP (local flat panel)", + "TV2 (second TV)", + "DFP2 (second digital flat panel)", + NULL +}; + +static const char * +DeviceToString(int device) +{ + static int savedDevice = -1; + static int bit = 0; + const char *name; + + if (device == -1) { + device = savedDevice; + bit = 0; + } + + if (device == -1) + return NULL; + + while (displayDevices[bit]) { + if (device & (1 << bit)) { + name = displayDevices[bit]; + savedDevice = device & ~(1 << bit); + bit++; + return name; + } + bit++; + } + return NULL; +} + +static void +PrintDisplayDeviceInfo(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int pipe, n; + int displays; + + DPRINTF(PFX, "PrintDisplayDeviceInfo\n"); + + displays = pI830->configuredDevices; + if (displays == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No active display devices.\n"); + return; + } + + /* Check for active devices connected to each display pipe. */ + for (n = 0; n < pI830->availablePipes; n++) { + pipe = ((displays >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); + if (pipe) { + const char *name; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Currently active displays on Pipe %c:\n", PIPE_NAME(n)); + name = DeviceToString(pipe); + do { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\t%s\n", name); + name = DeviceToString(-1); + } while (name); + + if (pipe & PIPE_UNKNOWN_ACTIVE) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "\tSome unknown display devices may also be present\n"); + + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No active displays on Pipe %c.\n", PIPE_NAME(n)); + } + + if (pI830->pipeDisplaySize[n].x2 != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Lowest common panel size for pipe %c is %d x %d\n", + PIPE_NAME(n), pI830->pipeDisplaySize[n].x2, + pI830->pipeDisplaySize[n].y2); + } else if (pI830->pipeEnabled[n] && pipe & ~PIPE_CRT_ACTIVE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No display size information available for pipe %c.\n", + PIPE_NAME(n)); + } + } +} + +static void +GetPipeSizes(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int pipe, n; + DisplayType i; + + DPRINTF(PFX, "GetPipeSizes\n"); + + + for (n = 0; n < pI830->availablePipes; n++) { + pipe = (pI830->configuredDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK; + pI830->pipeDisplaySize[n].x1 = pI830->pipeDisplaySize[n].y1 = 0; + pI830->pipeDisplaySize[n].x2 = pI830->pipeDisplaySize[n].y2 = 4096; + for (i = 0; i < NumKnownDisplayTypes; i++) { + if (pipe & (1 << i) & PIPE_SIZED_DISP_MASK) { + if (pI830->displaySize[i].x2 != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Size of device %s is %d x %d\n", + displayDevices[i], + pI830->displaySize[i].x2, + pI830->displaySize[i].y2); + if (pI830->displaySize[i].x2 < pI830->pipeDisplaySize[n].x2) + pI830->pipeDisplaySize[n].x2 = pI830->displaySize[i].x2; + if (pI830->displaySize[i].y2 < pI830->pipeDisplaySize[n].y2) + pI830->pipeDisplaySize[n].y2 = pI830->displaySize[i].y2; + } + } + } + + if (pI830->pipeDisplaySize[n].x2 == 4096) + pI830->pipeDisplaySize[n].x2 = 0; + if (pI830->pipeDisplaySize[n].y2 == 4096) + pI830->pipeDisplaySize[n].y2 = 0; + } +} + +static Bool +I830DetectDisplayDevice(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int pipe, n; + DisplayType i; + + for (i = 0; i < NumKnownDisplayTypes; i++) { + if (GetDisplayInfo(pScrn, 1 << i, &pI830->displayAttached[i], + &pI830->displayPresent[i], + &pI830->displaySize[i].x2, + &pI830->displaySize[i].y2)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Display Info: %s: attached: %s, present: %s, size: " + "(%d,%d)\n", displayDevices[i], + BOOLTOSTRING(pI830->displayAttached[i]), + BOOLTOSTRING(pI830->displayPresent[i]), + pI830->displaySize[i].x2, pI830->displaySize[i].y2); + } + } + + pI830->configuredDevices = GetDisplayDevices(pScrn); + if (pI830->configuredDevices == -1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Failed to detect active display devices\n"); + return FALSE; + } + + /* Check for active devices connected to each display pipe. */ + for (n = 0; n < pI830->availablePipes; n++) { + pipe = ((pI830->configuredDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); + if (pipe) { + pI830->pipeEnabled[n] = TRUE; + } + } + + GetPipeSizes(pScrn); + PrintDisplayDeviceInfo(pScrn); + +#if 0 + /* A quick hack to change the set of enabled devices. */ + enabledDevices = PIPE_CRT_ACTIVE; + if (!SetDisplayDevices(pScrn, enabledDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to switch to configured display devices\n"); + } +#endif + + return TRUE; +} + +static int +I830DetectMemory(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + PCITAG bridge; + CARD16 gmch_ctrl; + int memsize = 0; + + bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); + + if (IS_I85X(pI830) || IS_I865G(pI830)) + { + switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + case I855_GMCH_GMS_STOLEN_1M: + memsize = MB(1) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_4M: + memsize = MB(4) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_8M: + memsize = MB(8) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_16M: + memsize = MB(16) - KB(132); + break; + case I855_GMCH_GMS_STOLEN_32M: + memsize = MB(32) - KB(132); + break; + } + } else + { + switch (gmch_ctrl & I830_GMCH_GMS_MASK) { + case I830_GMCH_GMS_STOLEN_512: + memsize = KB(512) - KB(132); + break; + case I830_GMCH_GMS_STOLEN_1024: + memsize = MB(1) - KB(132); + break; + case I830_GMCH_GMS_STOLEN_8192: + memsize = MB(8) - KB(132); + break; + case I830_GMCH_GMS_LOCAL: + memsize = 0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Local memory found, but won't be used.\n"); + break; + } + } + if (memsize > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "detected %d kB stolen memory.\n", memsize / 1024); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "no video memory detected.\n"); + } + return memsize; +} + +static Bool +I830MapMMIO(ScrnInfoPtr pScrn) +{ + int mmioFlags; + I830Ptr pI830 = I830PTR(pScrn); + +#if !defined(__alpha__) + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; +#else + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT | VIDMEM_SPARSE; +#endif + + pI830->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, + pI830->PciTag, + pI830->MMIOAddr, I810_REG_SIZE); + if (!pI830->MMIOBase) + return FALSE; + return TRUE; +} + +static Bool +I830MapMem(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned i; + + for (i = 2; i < pI830->FbMapSize; i <<= 1) ; + pI830->FbMapSize = i; + + if (!I830MapMMIO(pScrn)) + return FALSE; + + pI830->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + pI830->PciTag, + pI830->LinearAddr, pI830->FbMapSize); + if (!pI830->FbBase) + return FALSE; + + pI830->LpRing.virtual_start = pI830->FbBase + pI830->LpRing.mem.Start; + + return TRUE; +} + +static void +I830UnmapMMIO(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI830->MMIOBase, + I810_REG_SIZE); + pI830->MMIOBase = 0; +} + +static Bool +I830UnmapMem(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI830->FbBase, + pI830->FbMapSize); + pI830->FbBase = 0; + I830UnmapMMIO(pScrn); + return TRUE; +} + +#ifndef HAVE_GET_PUT_BIOSMEMSIZE +#define HAVE_GET_PUT_BIOSMEMSIZE 1 +#endif + +#if HAVE_GET_PUT_BIOSMEMSIZE +/* + * Tell the BIOS how much video memory is available. The BIOS call used + * here won't always be available. + */ +static Bool +PutBIOSMemSize(ScrnInfoPtr pScrn, int memSize) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "PutBIOSMemSize: %d kB\n", memSize / 1024); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f11; + pVbe->pInt10->bx = 0; + pVbe->pInt10->cx = memSize / GTT_PAGE_SIZE; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + return Check5fStatus(pScrn, 0x5f11, pVbe->pInt10->ax); +} + +/* + * This reports what the previous VBEGetVBEInfo() found. Be sure to call + * VBEGetVBEInfo() after changing the BIOS memory size view. If + * a separate BIOS call is added for this, it can be put here. Only + * return a valid value if the funtionality for PutBIOSMemSize() + * is available. + */ +static int +GetBIOSMemSize(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int memSize = KB(pI830->vbeInfo->TotalMemory * 64); + + DPRINTF(PFX, "GetBIOSMemSize\n"); + + if (PutBIOSMemSize(pScrn, memSize)) + return memSize; + else + return -1; +} +#endif + +/* + * These three functions allow the video BIOS's view of the available video + * memory to be changed. This is currently implemented only for the 830 + * and 845G, which can do this via a BIOS scratch register that holds the + * BIOS's view of the (pre-reserved) memory size. If another mechanism + * is available in the future, it can be plugged in here. + * + * The mapping used for the 830/845G scratch register's low 4 bits is: + * + * 320k => 0 + * 832k => 1 + * 8000k => 8 + * + * The "unusual" values are the 512k, 1M, 8M pre-reserved memory, less + * overhead, rounded down to the BIOS-reported 64k granularity. + */ + +static Bool +SaveBIOSMemSize(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "SaveBIOSMemSize\n"); + + pI830->useSWF1 = FALSE; + +#if HAVE_GET_PUT_BIOSMEMSIZE + if ((pI830->saveBIOSMemSize = GetBIOSMemSize(pScrn)) != -1) + return TRUE; +#endif + + if (IS_I830(pI830) || IS_845G(pI830)) { + pI830->useSWF1 = TRUE; + pI830->saveSWF1 = INREG(SWF1) & 0x0f; + + /* + * This is for sample purposes only. pI830->saveBIOSMemSize isn't used + * when pI830->useSWF1 is TRUE. + */ + switch (pI830->saveSWF1) { + case 0: + pI830->saveBIOSMemSize = KB(320); + break; + case 1: + pI830->saveBIOSMemSize = KB(832); + break; + case 8: + pI830->saveBIOSMemSize = KB(8000); + break; + default: + pI830->saveBIOSMemSize = 0; + break; + } + return TRUE; + } + return FALSE; +} + +static void +RestoreBIOSMemSize(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 swf1; + + DPRINTF(PFX, "RestoreBIOSMemSize\n"); + + if (!pI830->overrideBIOSMemSize) + return; + +#if HAVE_GET_PUT_BIOSMEMSIZE + if (!pI830->useSWF1) { + PutBIOSMemSize(pScrn, pI830->saveBIOSMemSize); + return; + } +#endif + + if ((IS_I830(pI830) || IS_845G(pI830)) && pI830->useSWF1) { + swf1 = INREG(SWF1); + swf1 &= ~0x0f; + swf1 |= (pI830->saveSWF1 & 0x0f); + OUTREG(SWF1, swf1); + } +} + +static void +SetBIOSMemSize(ScrnInfoPtr pScrn, int newSize) +{ + I830Ptr pI830 = I830PTR(pScrn); + CARD32 swf1; + Bool mapped; + + DPRINTF(PFX, "SetBIOSMemSize: %d kB\n", newSize / 1024); + + if (!pI830->overrideBIOSMemSize) + return; + +#if HAVE_GET_PUT_BIOSMEMSIZE + if (!pI830->useSWF1) { + PutBIOSMemSize(pScrn, newSize); + return; + } +#endif + + if ((IS_I830(pI830) || IS_845G(pI830)) && pI830->useSWF1) { + CARD32 newSWF1; + + /* Need MMIO access here. */ + mapped = (pI830->MMIOBase != NULL); + if (!mapped) + I830MapMMIO(pScrn); + + if (newSize <= KB(832)) + newSWF1 = 1; + else + newSWF1 = 8; + + swf1 = INREG(SWF1); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Before: SWF1 is 0x%08x\n", swf1); + swf1 &= ~0x0f; + swf1 |= (newSWF1 & 0x0f); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "After: SWF1 is 0x%08x\n", swf1); + OUTREG(SWF1, swf1); + if (!mapped) + I830UnmapMMIO(pScrn); + } +} + +/* + * Use the native method instead of the vgahw method. So far this is + * only used for 8-bit mode. + * + * XXX Look into using the 10-bit gamma correction mode for 15/16/24 bit, + * and see if a DirectColor visual can be offered. + */ +static void +I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, + LOCO * colors, VisualPtr pVisual) +{ + I830Ptr pI830; + int i, index; + unsigned char r, g, b; + CARD32 val, temp; + + DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors); + pI830 = I830PTR(pScrn); + + if (pI830->pipeEnabled[0]) { + /* It seems that an initial read is needed. */ + temp = INREG(PALETTE_A); + for (i = 0; i < numColors; i++) { + index = indices[i]; + r = colors[index].red; + g = colors[index].green; + b = colors[index].blue; + val = (r << 16) | (g << 8) | b; + OUTREG(PALETTE_A + index * 4, val); + } + } + if (pI830->pipeEnabled[1]) { + /* It seems that an initial read is needed. */ + temp = INREG(PALETTE_B); + for (i = 0; i < numColors; i++) { + index = indices[i]; + r = colors[index].red; + g = colors[index].green; + b = colors[index].blue; + val = (r << 16) | (g << 8) | b; + OUTREG(PALETTE_B + index * 4, val); + } + } +} + +static void +PreInitCleanup(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + RestoreBIOSMemSize(pScrn); + if (pI830->swfSaved) { + OUTREG(SWF0, pI830->saveSWF0); + OUTREG(SWF4, pI830->saveSWF4); + } + if (pI830->MMIOBase) + I830UnmapMMIO(pScrn); + I830BIOSFreeRec(pScrn); +} + +static Bool +I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) +{ + vgaHWPtr hwp; + I830Ptr pI830; + MessageType from; + rgb defaultWeight = { 0, 0, 0 }; + vbeInfoPtr pVbe; + EntityInfoPtr pEnt; + int mem, memsize; + int flags24; + int i, n; + pointer pDDCModule, pVBEModule; + Bool enable; + const char *chipname; + + if (pScrn->numEntities != 1) + return FALSE; + + /* Load int10 module */ + if (!xf86LoadSubModule(pScrn, "int10")) + return FALSE; + xf86LoaderReqSymLists(I810int10Symbols, NULL); + + /* Load vbe module */ + if (!(pVBEModule = xf86LoadSubModule(pScrn, "vbe"))) + return FALSE; + xf86LoaderReqSymLists(I810vbeSymbols, NULL); + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (flags & PROBE_DETECT) { + I830BIOSProbeDDC(pScrn, pEnt->index); + return TRUE; + } + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) + return FALSE; + xf86LoaderReqSymLists(I810vgahwSymbols, NULL); + + + /* Allocate a vgaHWRec */ + if (!vgaHWGetHWRec(pScrn)) + return FALSE; + + /* Allocate driverPrivate */ + if (!I830BIOSGetRec(pScrn)) + return FALSE; + + pI830 = I830PTR(pScrn); + pI830->pEnt = pEnt; + + if (pI830->pEnt->location.type != BUS_PCI) + return FALSE; + + pI830->PciInfo = xf86GetPciInfoForEntity(pI830->pEnt->index); + pI830->PciTag = pciTag(pI830->PciInfo->bus, pI830->PciInfo->device, + pI830->PciInfo->func); + + if (xf86RegisterResources(pI830->pEnt->index, 0, ResNone)) { + PreInitCleanup(pScrn); + return FALSE; + + } + + pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; + pScrn->monitor = pScrn->confScreen->monitor; + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + + flags24 = Support32bppFb | PreferConvert24to32 | SupportConvert24to32; + + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24)) + 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 I830 driver\n", + pScrn->depth); + return FALSE; + } + xf86PrintDepthBpp(pScrn); + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + hwp = VGAHWPTR(pScrn); + pI830->cpp = pScrn->bitsPerPixel / 8; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(pI830->Options = xalloc(sizeof(I830BIOSOptions)))) + return FALSE; + memcpy(pI830->Options, I830BIOSOptions, sizeof(I830BIOSOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI830->Options); + + /* We have to use PIO to probe, because we haven't mapped yet. */ + I830SetPIOAccess(pI830); + + /* Initialize VBE record */ + if ((pI830->pVbe = VBEInit(NULL, pI830->pEnt->index)) == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "VBE initialization failed.\n"); + return FALSE; + } + + switch (pI830->PciInfo->chipType) { + case PCI_CHIP_I830_M: + chipname = "830M"; + break; + case PCI_CHIP_845_G: + chipname = "845G"; + break; + case PCI_CHIP_I855_GM: + /* Check capid register to find the chipset variant */ + pI830->variant = (pciReadLong(pI830->PciTag, I85X_CAPID) + >> I85X_VARIANT_SHIFT) & I85X_VARIANT_MASK; + switch (pI830->variant) { + case I855_GM: + chipname = "855GM"; + break; + case I855_GME: + chipname = "855GME"; + break; + case I852_GM: + chipname = "852GM"; + break; + case I852_GME: + chipname = "852GME"; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Unknown 852GM/855GM variant: 0x%x)\n", pI830->variant); + chipname = "852GM/855GM (unknown variant)"; + break; + } + break; + case PCI_CHIP_I865_G: + chipname = "865G"; + break; + default: + chipname = "unknown chipset"; + break; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Integrated Graphics Chipset: Intel(R) %s\n", chipname); + + pVbe = pI830->pVbe; + + pI830->vbeInfo = VBEGetVBEInfo(pVbe); + + /* Set the Chipset and ChipRev, allowing config file entries to override. */ + if (pI830->pEnt->device->chipset && *pI830->pEnt->device->chipset) { + pScrn->chipset = pI830->pEnt->device->chipset; + from = X_CONFIG; + } else if (pI830->pEnt->device->chipID >= 0) { + pScrn->chipset = (char *)xf86TokenToString(I830BIOSChipsets, + pI830->pEnt->device->chipID); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + pI830->pEnt->device->chipID); + } else { + from = X_PROBED; + pScrn->chipset = (char *)xf86TokenToString(I830BIOSChipsets, + pI830->PciInfo->chipType); + } + + if (pI830->pEnt->device->chipRev >= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pI830->pEnt->device->chipRev); + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", + (pScrn->chipset != NULL) ? pScrn->chipset : "Unknown i8xx"); + + if (pI830->pEnt->device->MemBase != 0) { + pI830->LinearAddr = pI830->pEnt->device->MemBase; + from = X_CONFIG; + } else { + if (pI830->PciInfo->memBase[1] != 0) { + /* XXX Check mask. */ + pI830->LinearAddr = pI830->PciInfo->memBase[0] & 0xFF000000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid FB address in PCI config space\n"); + PreInitCleanup(pScrn); + return FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", + (unsigned long)pI830->LinearAddr); + + if (pI830->pEnt->device->IOBase != 0) { + pI830->MMIOAddr = pI830->pEnt->device->IOBase; + from = X_CONFIG; + } else { + if (pI830->PciInfo->memBase[1]) { + pI830->MMIOAddr = pI830->PciInfo->memBase[1] & 0xFFF80000; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid MMIO address in PCI config space\n"); + PreInitCleanup(pScrn); + return FALSE; + } + } + + xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n", + (unsigned long)pI830->MMIOAddr); + + /* Some of the probing needs MMIO access, so map it here. */ + I830MapMMIO(pScrn); + +#if 1 + pI830->saveSWF0 = INREG(SWF0); + pI830->saveSWF4 = INREG(SWF4); + pI830->swfSaved = TRUE; + + /* Set "extended desktop" */ + OUTREG(SWF0, pI830->saveSWF0 | (1 << 21)); + + /* Set "driver loaded", "OS unknown", "APM 1.2" */ + OUTREG(SWF4, (pI830->saveSWF4 & ~((3 << 19) | (7 << 16))) | + (1 << 23) | (2 << 16)); +#endif + + if (IS_I830(pI830) || IS_845G(pI830)) { + PCITAG bridge; + CARD16 gmch_ctrl; + + bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); + if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { + pI830->FbMapSize = 0x8000000; + } else { + pI830->FbMapSize = 0x4000000; + } + } + else { + /* 128MB aperture for later chips */ + pI830->FbMapSize = 0x8000000; + } + + /* + * Get the pre-allocated (stolen) memory size. + */ + pI830->StolenMemory.Size = I830DetectMemory(pScrn); + pI830->StolenMemory.Start = 0; + pI830->StolenMemory.End = pI830->StolenMemory.Size; + + /* Sanity check: compare with what the BIOS thinks. */ + if (pI830->vbeInfo->TotalMemory != pI830->StolenMemory.Size / 1024 / 64) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Detected stolen memory (%d kB) doesn't match what the BIOS" + " reports (%d kB)\n", + ROUND_DOWN_TO(pI830->StolenMemory.Size / 1024, 64), + pI830->vbeInfo->TotalMemory * 64); + } + + /* Find the maximum amount of agpgart memory available. */ + mem = I830CheckAvailableMemory(pScrn); + pI830->StolenOnly = FALSE; + + if (mem <= 0) { + if (pI830->StolenMemory.Size <= 0) { + /* Shouldn't happen. */ + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "/dev/agpgart is either not available, or no memory " + "is available\nfor allocation, " + "and no pre-allocated memory is available.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "/dev/agpgart is either not available, or no memory " + "is available\nfor allocation. " + "Using pre-allocated memory only.\n"); + mem = 0; + pI830->StolenOnly = TRUE; + } + + if (xf86ReturnOptValBool(pI830->Options, OPTION_NOACCEL, FALSE)) { + pI830->noAccel = TRUE; + } + if (xf86ReturnOptValBool(pI830->Options, OPTION_SW_CURSOR, FALSE)) { + pI830->SWCursor = TRUE; + } + + pI830->directRenderingDisabled = + !xf86ReturnOptValBool(pI830->Options, OPTION_DRI, TRUE); + +#ifdef XF86DRI + if (!pI830->directRenderingDisabled) { + if (pI830->noAccel || pI830->SWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it " + "needs HW cursor and 2D acceleration.\n"); + pI830->directRenderingDisabled = TRUE; + } else if (pScrn->depth != 16 && pScrn->depth != 24) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "DRI is disabled because it " + "runs only at depths 16 and 24.\n"); + pI830->directRenderingDisabled = TRUE; + } + } +#endif + + /* + * The "VideoRam" config file parameter specifies the total amount of + * memory that will be used/allocated. When agpgart support isn't + * available (StolenOnly == TRUE), this is limited to the amount of + * pre-allocated ("stolen") memory. + */ + + /* + * Default to I830_DEFAULT_VIDEOMEM_2D (8192KB) for 2D-only, + * or I830_DEFAULT_VIDEOMEM_3D (32768KB) for 3D. If the stolen memory + * amount is higher, default to it rounded up to the nearest MB. This + * guarantees that by default there will be at least some run-time + * space for things that need a physical address. + */ + if (!pI830->pEnt->device->videoRam) { + from = X_DEFAULT; +#ifdef XF86DRI + if (!pI830->directRenderingDisabled) + pScrn->videoRam = I830_DEFAULT_VIDEOMEM_3D; + else +#endif + pScrn->videoRam = I830_DEFAULT_VIDEOMEM_2D; + if (pI830->StolenMemory.Size / 1024 > pScrn->videoRam) + pScrn->videoRam = ROUND_TO(pI830->StolenMemory.Size / 1024, 1024); + } else { + from = X_CONFIG; + pScrn->videoRam = pI830->pEnt->device->videoRam; + } + + DPRINTF(PFX, + "Available memory: %dk\n" + "Requested memory: %dk\n", mem, pScrn->videoRam); + + + if (mem + (pI830->StolenMemory.Size / 1024) < pScrn->videoRam) { + pScrn->videoRam = mem + (pI830->StolenMemory.Size / 1024); + from = X_PROBED; + if (mem + (pI830->StolenMemory.Size / 1024) < + pI830->pEnt->device->videoRam) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "VideoRAM reduced to %d kByte " + "(limited to available sysmem)\n", pScrn->videoRam); + } + } + + if (pScrn->videoRam > pI830->FbMapSize / 1024) { + pScrn->videoRam = pI830->FbMapSize / 1024; + if (pI830->FbMapSize / 1024 < pI830->pEnt->device->videoRam) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "VideoRam reduced to %d kByte (limited to aperture size)\n", + pScrn->videoRam); + } + + if (mem > 0) { + /* + * If the reserved (BIOS accessible) memory is less than the desired + * amount, try to increase it. So far this is only implemented for + * the 845G and 830, but those details are handled in SetBIOSMemSize(). + * + * The BIOS-accessible amount is only important for setting video + * modes. The maximum amount we try to set is limited to what would + * be enough for 1920x1440 with a 2048 pitch. + * + * If ALLOCATE_ALL_BIOSMEM is enabled in i830_memory.c, all of the + * BIOS-aware memory will get allocated. If it isn't then it may + * not be, and in that case there is an assumption that the video + * BIOS won't attempt to access memory beyond what is needed for + * modes that are actually used. ALLOCATE_ALL_BIOSMEM is enabled by + * default. + */ + + /* Try to keep HW cursor and Overlay amounts separate from this. */ + int reserve = (HWCURSOR_SIZE + OVERLAY_SIZE) / 1024; + + if (pScrn->videoRam - reserve >= I830_MAXIMUM_VBIOS_MEM) + pI830->newBIOSMemSize = KB(I830_MAXIMUM_VBIOS_MEM); + else + pI830->newBIOSMemSize = + KB(ROUND_DOWN_TO(pScrn->videoRam - reserve, 64)); + + if (pI830->vbeInfo->TotalMemory * 64 < pI830->newBIOSMemSize / 1024) { + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Will attempt to tell the BIOS that there is " + "%d kB VideoRAM\n", pI830->newBIOSMemSize / 1024); + + if (SaveBIOSMemSize(pScrn)) { + pI830->overrideBIOSMemSize = TRUE; + SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); + + VBEFreeVBEInfo(pI830->vbeInfo); + vbeFree(pI830->pVbe); + pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); + pVbe = pI830->pVbe; + pI830->vbeInfo = VBEGetVBEInfo(pVbe); + + pI830->BIOSMemorySize = KB(pI830->vbeInfo->TotalMemory * 64); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS now sees %d kB VideoRAM\n", + pI830->BIOSMemorySize / 1024); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS view of memory size can't be changed " + "(this is not an error).\n"); + } + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Pre-allocated VideoRAM: %d kByte\n", + pI830->StolenMemory.Size / 1024); + xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", pScrn->videoRam); + pI830->TotalVideoRam = KB(pScrn->videoRam); + + /* + * If the requested videoRam amount is less than the stolen memory size, + * reduce the stolen memory size accordingly. + */ + if (pI830->StolenMemory.Size > pI830->TotalVideoRam) { + pI830->StolenMemory.Size = pI830->TotalVideoRam; + pI830->StolenMemory.End = pI830->TotalVideoRam; + } + + if (xf86GetOptValInteger(pI830->Options, OPTION_CACHE_LINES, + &(pI830->CacheLines))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Requested %d cache lines\n", + pI830->CacheLines); + } else { + pI830->CacheLines = -1; + } + + pI830->XvDisabled = + !xf86ReturnOptValBool(pI830->Options, OPTION_XVIDEO, TRUE); + +#ifdef I830_XV + if (xf86GetOptValInteger(pI830->Options, OPTION_VIDEO_KEY, + &(pI830->colorKey))) { + from = X_CONFIG; + } else if (xf86GetOptValInteger(pI830->Options, OPTION_COLOR_KEY, + &(pI830->colorKey))) { + from = X_CONFIG; + } else { + pI830->colorKey = (1 << pScrn->offset.red) | + (1 << pScrn->offset.green) | + (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << + pScrn->offset.blue); + from = X_DEFAULT; + } + xf86DrvMsg(pScrn->scrnIndex, from, "video overlay key set to 0x%x\n", + pI830->colorKey); +#endif + + pI830->allowPageFlip = FALSE; + enable = xf86ReturnOptValBool(pI830->Options, OPTION_PAGEFLIP, FALSE); +#ifdef XF86DRI + if (!pI830->directRenderingDisabled) { + pI830->allowPageFlip = enable; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "page flipping %s\n", + enable ? "enabled" : "disabled"); + } +#endif + + /* Check if the HW cursor needs physical address. */ + if (IS_MOBILE(pI830)) + pI830->CursorNeedsPhysical = TRUE; + else + pI830->CursorNeedsPhysical = FALSE; + + /* Force ring buffer to be in low memory for the 845G. */ + if (IS_845G(pI830)) + pI830->NeedRingBufferLow = TRUE; + + /* + * XXX If we knew the pre-initialised GTT format for certain, we could + * probably figure out the physical address even in the StolenOnly case. + */ + if (pI830->StolenOnly && pI830->CursorNeedsPhysical && !pI830->SWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "HW Cursor disabled because it needs agpgart memory.\n"); + pI830->SWCursor = TRUE; + } + + /* + * Reduce the maximum videoram available for video modes by the ring buffer, + * minimum scratch space and HW cursor amounts. + */ + if (!pI830->SWCursor) + pScrn->videoRam -= (HWCURSOR_SIZE / 1024); + if (!pI830->XvDisabled) + pScrn->videoRam -= (OVERLAY_SIZE / 1024); + if (!pI830->noAccel) { + pScrn->videoRam -= (PRIMARY_RINGBUFFER_SIZE / 1024); + pScrn->videoRam -= (MIN_SCRATCH_BUFFER_SIZE / 1024); + } + + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Maximum frambuffer space: %d kByte\n", pScrn->videoRam); + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() here. + */ + + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) + return FALSE; + } + + if (IS_MOBILE(pI830)) + pI830->availablePipes = 2; + else + pI830->availablePipes = 1; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%d display pipe%s available.\n", + pI830->availablePipes, pI830->availablePipes > 1 ? "s" : ""); + + if (!I830DetectDisplayDevice(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't detect display devices.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) { + PreInitCleanup(pScrn); + return FALSE; + } + + if ((pI830->vesa->monitor = vbeDoEDID(pVbe, pDDCModule)) != NULL) { + xf86PrintEDID(pI830->vesa->monitor); + } + if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) + xf86SetDDCproperties(pScrn, pI830->vesa->monitor); + xf86UnloadSubModule(pDDCModule); + + /* XXX Move this to a header. */ +#define VIDEO_BIOS_SCRATCH 0x18 + +#if 1 + /* + * XXX This should be in ScreenInit/EnterVT. PreInit should not leave the + * state changed. + */ + /* Enable hot keys by writing the proper value to GR18 */ + { + CARD8 gr18; + + gr18 = pI830->readControl(pI830, GRX, VIDEO_BIOS_SCRATCH); + gr18 &= ~0x80; /* + * Clear Hot key bit so that Video + * BIOS performs the hot key + * servicing + */ + pI830->writeControl(pI830, GRX, VIDEO_BIOS_SCRATCH, gr18); + } +#endif + + for (i = 0; i < pI830->availablePipes; i++) { + int pipe = + (pI830->configuredDevices >> PIPE_SHIFT(i)) & PIPE_ACTIVE_MASK; + if (pipe & ~PIPE_CRT_ACTIVE) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "A non-CRT device is attached to pipe %c.\n" + "\tNo refresh rate overrides will be attempted.\n", + PIPE_NAME(i)); + pI830->vesa->useDefaultRefresh = TRUE; + } + /* + * Some desktop platforms might not have 0x5f05, so useExtendedRefresh + * would need to be set to FALSE for those cases. + */ + if (!pI830->vesa->useDefaultRefresh) + pI830->useExtendedRefresh = TRUE; + } + + if (pI830->useExtendedRefresh) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Will use BIOS call 0x5f05 to set refresh rates for CRTs.\n"); + } + + /* + * Calling 0x5f64 can reset the refresh rate, so only do this when + * using 0x5f05, or when not overriding the default refresh rate. + * Also, 0x5f64 doesn't work correctly in i830 platforms. + */ + pI830->enableDisplays = !IS_I830(pI830) && pI830->useExtendedRefresh; + + if (pI830->enableDisplays) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Will use BIOS call 0x5f64 to enable displays.\n"); + } + + /* + * Limit videoram available for mode selection to what the video + * BIOS can see. + */ + if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64)) + memsize = pI830->vbeInfo->TotalMemory * 64; + else + memsize = pScrn->videoRam; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Maximum space available for video modes: %d kByte\n", memsize); + + /* + * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS + * functions. For that reason it's important to set only + * V_MODETYPE_VGA in the flags for VBEGetModePool(). + */ + pScrn->modePool = VBEGetModePool(pScrn, pVbe, pI830->vbeInfo, + V_MODETYPE_VGA); + + if (!pScrn->modePool) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No Video BIOS modes for chosen depth.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + VBESetModeNames(pScrn->modePool); + + /* + * XXX DDC information: There's code in xf86ValidateModes + * (VBEValidateModes) to set monitor defaults based on DDC information + * where available. If we need something that does better than this, + * there's code in vesa/vesa.c. + */ + + /* XXX Need to get relevant modes and virtual parameters. */ + /* Do the mode validation without regard to special scanline pitches. */ + n = VBEValidateModes(pScrn, NULL, pScrn->display->modes, NULL, + NULL, 0, MAX_DISPLAY_PITCH, 1, + 0, MAX_DISPLAY_HEIGHT, + pScrn->display->virtualX, + pScrn->display->virtualY, + memsize, LOOKUP_BEST_REFRESH); + if (n <= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + xf86PruneDriverModes(pScrn); + + pScrn->currentMode = pScrn->modes; + + if (pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + +#ifndef USE_PITCHES +#define USE_PITCHES 1 +#endif + + /* + * If DRI is potentially usable, check if there is enough memory available + * for it, and if there's also enough to allow tiling to be enabled. + */ +#if defined(XF86DRI) + if (!pI830->directRenderingDisabled) { + int savedDisplayWidth = pScrn->displayWidth; + int memNeeded = 0; + /* Good pitches to allow tiling. Don't care about pitches < 256. */ + static const int pitches[] = { + 128 * 2, + 128 * 4, + 128 * 8, + 128 * 16, + 128 * 32, + 128 * 64, + 0 + }; + +#ifdef I830_XV + /* + * Set this so that the overlay allocation is factored in when + * appropriate. + */ + pI830->XvEnabled = !pI830->XvDisabled; +#endif + + for (i = 0; pitches[i] != 0; i++) { +#if USE_PITCHES + if (pitches[i] >= pScrn->displayWidth) { + pScrn->displayWidth = pitches[i]; + break; + } +#else + if (pitches[i] == pScrn->displayWidth) + break; +#endif + } + + /* + * If the displayWidth is a tilable pitch, test if there's enough + * memory available to enable tiling. + */ + if (pScrn->displayWidth == pitches[i]) { + I830ResetAllocations(pScrn, 0); + if (I830Allocate2DMemory(pScrn, ALLOCATE_DRY_RUN | ALLOC_INITIAL) && + I830Allocate3DMemory(pScrn, ALLOCATE_DRY_RUN)) { + memNeeded = I830GetExcessMemoryAllocations(pScrn); + if (memNeeded > 0 || pI830->MemoryAperture.Size < 0) { + if (memNeeded > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "%d kBytes additional video memory is " + "required to\n\tenable tiling mode for DRI.\n", + (memNeeded + 1023) / 1024); + } + if (pI830->MemoryAperture.Size < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Allocation with DRI tiling enabled would " + "exceed the\n" + "\tmemory aperture size (%d kB) by %d kB.\n" + "\tReduce VideoRam amount to avoid this!\n", + pI830->FbMapSize / 1024, + -pI830->MemoryAperture.Size / 1024); + } + pScrn->displayWidth = savedDisplayWidth; + pI830->allowPageFlip = FALSE; + } else if (pScrn->displayWidth != savedDisplayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Increasing the scanline pitch to allow tiling mode " + "(%d -> %d).\n", + savedDisplayWidth, pScrn->displayWidth); + } + } else { + memNeeded = 0; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unexpected dry run allocation failure (1).\n"); + } + } + if (memNeeded > 0 || pI830->MemoryAperture.Size < 0) { + /* + * Tiling can't be enabled. Check if there's enough memory for DRI + * without tiling. + */ + I830ResetAllocations(pScrn, 0); + if (I830Allocate2DMemory(pScrn, ALLOCATE_DRY_RUN | ALLOC_INITIAL) && + I830Allocate3DMemory(pScrn, ALLOCATE_DRY_RUN | ALLOC_NO_TILING)) { + memNeeded = I830GetExcessMemoryAllocations(pScrn); + if (memNeeded > 0 || pI830->MemoryAperture.Size < 0) { + if (memNeeded > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "%d kBytes additional video memory is required " + "to enable DRI.\n", + (memNeeded + 1023) / 1024); + } + if (pI830->MemoryAperture.Size < 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Allocation with DRI enabled would " + "exceed the\n" + "\tmemory aperture size (%d kB) by %d kB.\n" + "\tReduce VideoRam amount to avoid this!\n", + pI830->FbMapSize / 1024, + -pI830->MemoryAperture.Size / 1024); + } + pI830->directRenderingDisabled = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DRI.\n"); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unexpected dry run allocation failure (2).\n"); + } + } + } +#endif + + VBEPrintModes(pScrn); + + if (!pI830->vesa->useDefaultRefresh) { + /* + * This sets the parameters for the VBE modes according to the best + * usable parameters from the Monitor sections modes (usually the + * default VESA modes), allowing for better than default refresh rates. + * This only works for VBE 3.0 and later. Also, we only do this + * if there are no non-CRT devices attached. + */ + VBESetModeParameters(pScrn, pVbe); + } + + /* PreInit shouldn't leave any state changes, so restore this. */ + RestoreBIOSMemSize(pScrn); + + /* Don't need MMIO access anymore. */ + if (pI830->swfSaved) { + OUTREG(SWF0, pI830->saveSWF0); + OUTREG(SWF4, pI830->saveSWF4); + } + I830UnmapMMIO(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load the required sub modules */ + if (!xf86LoadSubModule(pScrn, "fb")) { + PreInitCleanup(pScrn); + return FALSE; + } + + xf86LoaderReqSymLists(I810fbSymbols, NULL); + + if (!pI830->noAccel) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + PreInitCleanup(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810xaaSymbols, NULL); + } + + if (!pI830->SWCursor) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + PreInitCleanup(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810ramdacSymbols, NULL); + } + + /* We won't be using the VGA access after the probe. */ + I830SetMMIOAccess(pI830); + xf86SetOperatingState(resVgaIo, pI830->pEnt->index, ResUnusedOpr); + xf86SetOperatingState(resVgaMem, pI830->pEnt->index, ResDisableOpr); + + VBEFreeVBEInfo(pI830->vbeInfo); + vbeFree(pVbe); + +#if defined(XF86DRI) + if (!pI830->directRenderingDisabled) { + if (!xf86LoadSubModule(pScrn, "shadow")) { + PreInitCleanup(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(I810shadowSymbols, NULL); + } +#endif + + return TRUE; +} + +/* + * As the name says. Check that the initial state is reasonable. + * If any unrecoverable problems are found, bail out here. + */ +static Bool +CheckInheritedState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int errors = 0, fatal = 0; + unsigned long temp, head, tail; + + /* Check first for page table errors */ + temp = INREG(PGE_ERR); + if (temp != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "PGTBL_ER is 0x%08x\n", temp); + errors++; + } + temp = INREG(PGETBL_CTL); + if (!(temp & 1)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PGTBL_CTL (0x%08x) indicates GTT is disabled\n", temp); + errors++; + } + temp = INREG(LP_RING + RING_LEN); + if (temp & 1) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PRB0_CTL (0x%08x) indicates ring buffer enabled\n", temp); + errors++; + } + head = INREG(LP_RING + RING_HEAD); + tail = INREG(LP_RING + RING_TAIL); + if ((tail & I830_TAIL_MASK) != (head & I830_HEAD_MASK)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "PRB0_HEAD (0x%08x) and PRB0_TAIL (0x%08x) indicate " + "ring buffer not flushed\n", head, tail); + errors++; + } +#if 0 + if (errors) + I830PrintErrorState(pScrn); +#endif + + if (fatal) + FatalError("CheckInheritedState: can't recover from the above\n"); + + return (errors != 0); +} + +/* + * Reset registers that it doesn't make sense to save/restore to a sane state. + * This is basically the ring buffer and fence registers. Restoring these + * doesn't make sense without restoring GTT mappings. This is something that + * whoever gets control next should do. + */ +static void +ResetState(ScrnInfoPtr pScrn, Bool flush) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + unsigned long temp; + + DPRINTF(PFX, "ResetState: flush is %s\n", BOOLTOSTRING(flush)); + + /* Reset the fence registers to 0 */ + for (i = 0; i < 8; i++) + OUTREG(FENCE + i * 4, 0); + + /* Flush the ring buffer (if enabled), then disable it. */ + if (pI830->AccelInfoRec != NULL && flush) { + temp = INREG(LP_RING + RING_LEN); + if (temp & 1) { + I830RefreshRing(pScrn); + I830Sync(pScrn); + DO_RING_IDLE(); + } + } + OUTREG(LP_RING + RING_LEN, 0); + OUTREG(LP_RING + RING_HEAD, 0); + OUTREG(LP_RING + RING_TAIL, 0); + OUTREG(LP_RING + RING_START, 0); + + if (pI830->CursorInfoRec && pI830->CursorInfoRec->HideCursor) + pI830->CursorInfoRec->HideCursor(pScrn); +} + +static void +SetFenceRegs(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int i; + + DPRINTF(PFX, "SetFenceRegs\n"); + + for (i = 0; i < 8; i++) { + OUTREG(FENCE + i * 4, pI830->ModeReg.Fence[i]); + if (I810_DEBUG & DEBUG_VERBOSE_VGA) + ErrorF("Fence Register : %x\n", pI830->ModeReg.Fence[i]); + } +} + +static void +SetRingRegs(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int itemp; + + DPRINTF(PFX, "SetRingRegs\n"); + + if (pI830->noAccel) + return; + + OUTREG(LP_RING + RING_LEN, 0); + OUTREG(LP_RING + RING_TAIL, 0); + OUTREG(LP_RING + RING_HEAD, 0); + + if ((pI830->LpRing.mem.Start & I830_RING_START_MASK) != + pI830->LpRing.mem.Start) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I830SetRingRegs: Ring buffer start (%x) violates its " + "mask (%x)\n", pI830->LpRing.mem.Start, I830_RING_START_MASK); + } + /* Don't care about the old value. Reserved bits must be zero anyway. */ + itemp = pI830->LpRing.mem.Start & I830_RING_START_MASK; + OUTREG(LP_RING + RING_START, itemp); + + if (((pI830->LpRing.mem.Size - 4096) & I830_RING_NR_PAGES) != + pI830->LpRing.mem.Size - 4096) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "I830SetRingRegs: Ring buffer size - 4096 (%x) violates its " + "mask (%x)\n", pI830->LpRing.mem.Size - 4096, + I830_RING_NR_PAGES); + } + /* Don't care about the old value. Reserved bits must be zero anyway. */ + itemp = (pI830->LpRing.mem.Size - 4096) & I830_RING_NR_PAGES; + itemp |= (RING_NO_REPORT | RING_VALID); + OUTREG(LP_RING + RING_LEN, itemp); + I830RefreshRing(pScrn); +} + +/* + * This should be called everytime the X server gains control of the screen, + * before any video modes are programmed (ScreenInit, EnterVT). + */ +static void +SetHWOperatingState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "SetHWOperatingState\n"); + + if (!pI830->noAccel) + SetRingRegs(pScrn); + SetFenceRegs(pScrn); + if (!pI830->SWCursor) + I830InitHWCursor(pScrn); +} + +static Bool +SaveHWState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + vgaHWPtr hwp = VGAHWPTR(pScrn); + vgaRegPtr vgaReg = &hwp->SavedReg; + VbeModeInfoBlock *modeInfo; + VESAPtr pVesa; + + DPRINTF(PFX, "SaveHWState\n"); + + pVesa = pI830->vesa; + /* Make sure we save at least this information in case of failure. */ + VBEGetVBEMode(pVbe, &pVesa->stateMode); + modeInfo = VBEGetModeInfo(pVbe, pVesa->stateMode); + pVesa->savedScanlinePitch = 0; + if (modeInfo) { + if (VBE_MODE_GRAPHICS(modeInfo)) { + VBEGetLogicalScanline(pVbe, &pVesa->savedScanlinePitch, NULL, NULL); + } + VBEFreeModeInfo(modeInfo); + } + + vgaHWUnlock(hwp); + vgaHWSave(pScrn, vgaReg, VGA_SR_FONTS); + +#ifndef I845G_VBE_WORKAROUND +#define I845G_VBE_WORKAROUND 1 +#endif + + pVesa = pI830->vesa; + /* This save/restore method doesn't work for 845G BIOS */ + /* + * XXX If it's fixed in production versions, this could be removed. + * + * KW: This may have been because of the behaviour I've found on my + * board: The 'save' command actually modifies the interrupt + * registers, turning off the irq & breaking the kernel module + * behaviour. + */ + if (!I845G_VBE_WORKAROUND || !IS_845G(pI830)) { + CARD16 imr = INREG16(IMR); + CARD16 ier = INREG16(IER); + CARD16 hwstam = INREG16(HWSTAM); + + if (!VBESaveRestore(pVbe, MODE_SAVE, &pVesa->state, &pVesa->stateSize, + &pVesa->statePage)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "SaveHWState: VBESaveRestore(MODE_SAVE) failed.\n"); + return FALSE; + } + + OUTREG16(IMR, imr); + OUTREG16(IER, ier); + OUTREG16(HWSTAM, hwstam); + } + + pVesa->savedPal = VBESetGetPaletteData(pVbe, FALSE, 0, 256, + NULL, FALSE, FALSE); + if (!pVesa->savedPal) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "SaveHWState: VBESetGetPaletteData(GET) failed.\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +RestoreHWState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + vgaHWPtr hwp = VGAHWPTR(pScrn); + vgaRegPtr vgaReg = &hwp->SavedReg; + VESAPtr pVesa; + Bool restored = FALSE; + + DPRINTF(PFX, "RestoreHWState\n"); + + pVesa = pI830->vesa; + + /* + * Workaround for text mode restoration with some flat panels. + * Temporarily program a 640x480 mode before switching back to + * text mode. + */ + if (pVesa->useDefaultRefresh) { + int mode = 0; + + switch (pScrn->depth) { + case 8: + mode = 0x30; + break; + case 15: + mode = 0x40; + break; + case 16: + mode = 0x41; + break; + case 24: + mode = 0x50; + break; + } + mode |= (1 << 15) | (1 << 14); + I830VESASetVBEMode(pScrn, mode, NULL); + } + + if (pVesa->state && pVesa->stateSize) { + CARD16 imr = INREG16(IMR); + CARD16 ier = INREG16(IER); + CARD16 hwstam = INREG16(HWSTAM); + + /* Make a copy of the state. Don't rely on it not being touched. */ + if (!pVesa->pstate) { + pVesa->pstate = xalloc(pVesa->stateSize); + if (pVesa->pstate) + memcpy(pVesa->pstate, pVesa->state, pVesa->stateSize); + } + restored = VBESaveRestore(pVbe, MODE_RESTORE, &pVesa->state, + &pVesa->stateSize, &pVesa->statePage); + if (!restored) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "RestoreHWState: VBESaveRestore failed.\n"); + } + /* Copy back */ + if (pVesa->pstate) + memcpy(pVesa->state, pVesa->pstate, pVesa->stateSize); + + OUTREG16(IMR, imr); + OUTREG16(IER, ier); + OUTREG16(HWSTAM, hwstam); + } + /* If that failed, restore the original mode. */ + if (!restored) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Setting the original video mode instead of restoring\n\t" + "the saved state\n"); + I830VESASetVBEMode(pScrn, pVesa->stateMode, NULL); + } + if (pVesa->savedScanlinePitch) + VBESetLogicalScanline(pVbe, pVesa->savedScanlinePitch); + + if (pVesa->savedPal) + VBESetGetPaletteData(pVbe, TRUE, 0, 256, pVesa->savedPal, FALSE, TRUE); + + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS); + vgaHWLock(hwp); + return TRUE; +} + +#ifndef USE_VBE +#define USE_VBE 1 +#endif + +static Bool +I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block) +{ + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "Setting mode 0x%.8x\n", mode); +#if USE_VBE + return VBESetVBEMode(pI830->pVbe, mode, block); +#else + { + vbeInfoPtr pVbe = pI830->pVbe; + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x80 | (mode & 0x7f); + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + pVbe->pInt10->ax = 0x0f00; + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if ((pVbe->pInt10->ax & 0x7f) == (mode & 0x7f)) + return TRUE; + else + return FALSE; + } +#endif +} + +static Bool +I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + VbeModeInfoData *data; + int mode, i; + CARD32 planeA, planeB, temp; + int refresh = 60; +#ifdef XF86DRI + Bool didLock = FALSE; +#endif + + DPRINTF(PFX, "I830VESASetMode\n"); + + data = (VbeModeInfoData *) pMode->Private; + + /* Always Enable Linear Addressing */ + mode = data->mode | (1 << 15) | (1 << 14); + +#ifdef XF86DRI + if (pI830->directRenderingEnabled && !pI830->LockHeld) { + DRILock(screenInfo.screens[pScrn->scrnIndex], 0); + pI830->LockHeld = 1; + didLock = TRUE; + } +#endif + +#ifndef MODESWITCH_RESET_STATE +#define MODESWITCH_RESET_STATE 0 +#endif +#if MODESWITCH_RESET_STATE + ResetState(pScrn, TRUE); +#endif + + /* XXX Add macros for the various mode parameter bits. */ + + if (pI830->vesa->useDefaultRefresh) + mode &= ~(1 << 11); + + if (I830VESASetVBEMode(pScrn, mode, data->block) == FALSE) { + if ((data->block && (mode & (1 << 11))) && + I830VESASetVBEMode(pScrn, (mode & ~(1 << 11)), NULL) == TRUE) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Set VBE Mode rejected this modeline.\n\t" + "Trying standard mode instead!\n"); + DPRINTF(PFX, "OOPS!\n"); + xfree(data->block); + data->block = NULL; + data->mode &= ~(1 << 11); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); + return FALSE; + } + } + + /* + * The BIOS may not set a scanline pitch that would require more video + * memory than it's aware of. We check for this later, and set it + * explicitly if necessary. + */ + if (data->data->XResolution != pScrn->displayWidth) + VBESetLogicalScanline(pVbe, pScrn->displayWidth); + + if (pScrn->bitsPerPixel >= 8 && pI830->vbeInfo->Capabilities[0] & 0x01) + VBESetGetDACPaletteFormat(pVbe, 8); + + /* + * XXX This location of this isn't correct. + * + * Turn on the configured displays. This has the effect of resetting + * the default refresh rates to values that the configured displays + * can handle. This seems to be the safest way to make sure that this + * happens. When it's safe to set higher values, we do that after this. + * + * Note: When a DFP is connected to an 830, this causes the mode setting + * to be trashed. So, we don't do it on the 830. + * + * XXX Need to test an 830 with a LFP. + */ + if (pI830->enableDisplays) { + if (!SetDisplayDevices(pScrn, pI830->configuredDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to switch to configured display devices\n"); + } + } + + /* + * When it's OK to set better than default refresh rates, set them here. + */ + if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && + (mode & (1 << 11)) && data && data->data && data->block) { + refresh = SetRefreshRate(pScrn, mode, data->block->RefreshRate / 100); + if (!refresh) { + refresh = 60; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set refresh rate to %dHz.\n", + data->block->RefreshRate / 100); + } + } + + + /* XXX Fix plane A with pipe A, and plane B with pipe B. */ + planeA = INREG(DSPACNTR); + planeB = INREG(DSPBCNTR); + + pI830->planeEnabled[0] = ((planeA & DISPLAY_PLANE_ENABLE) != 0); + pI830->planeEnabled[1] = ((planeB & DISPLAY_PLANE_ENABLE) != 0); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane A is %s.\n", + pI830->planeEnabled[0] ? "enabled" : "disabled"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane B is %s.\n", + pI830->planeEnabled[1] ? "enabled" : "disabled"); + + /* + * Sometimes it seems that no display planes are enabled at this point. + * For mobile platforms pick the plane(s) connected to enabled pipes. + * For others choose plane A. + */ + if (!pI830->planeEnabled[0] && !pI830->planeEnabled[1]) { + if (IS_MOBILE(pI830)) { + if ((pI830->pipeEnabled[0] && + ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) || + (pI830->pipeEnabled[1] && + ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) { + pI830->planeEnabled[0] = TRUE; + } + if ((pI830->pipeEnabled[0] && + ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) || + (pI830->pipeEnabled[1] && + ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) { + pI830->planeEnabled[1] = TRUE; + } + } else { + pI830->planeEnabled[0] = TRUE; + } + if (pI830->planeEnabled[0]) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane A.\n"); + planeA |= DISPLAY_PLANE_ENABLE; + OUTREG(DSPACNTR, planeA); + /* flush the change. */ + temp = INREG(DSPABASE); + OUTREG(DSPABASE, temp); + } + if (pI830->planeEnabled[1]) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane B.\n"); + planeB |= DISPLAY_PLANE_ENABLE; + OUTREG(DSPBCNTR, planeB); + /* flush the change. */ + temp = INREG(DSPBADDR); + OUTREG(DSPBADDR, temp); + } + } + + /* XXX Plane C is ignored for now (overlay). */ + + /* + * Print out the PIPEACONF and PIPEBCONF registers. + */ + temp = INREG(PIPEACONF); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEACONF is 0x%08x\n", temp); + if (IS_MOBILE(pI830)) { + temp = INREG(PIPEBCONF); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08x\n", temp); + } + +#if PRINT_MODE_INFO + /* Print out some CRTC/display information. */ + temp = INREG(HTOTAL_A); + ErrorF("Horiz active: %d, Horiz total: %d\n", temp & 0x7ff, + (temp >> 16) & 0xfff); + temp = INREG(HBLANK_A); + ErrorF("Horiz blank start: %d, Horiz blank end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(HSYNC_A); + ErrorF("Horiz sync start: %d, Horiz sync end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(VTOTAL_A); + ErrorF("Vert active: %d, Vert total: %d\n", temp & 0x7ff, + (temp >> 16) & 0xfff); + temp = INREG(VBLANK_A); + ErrorF("Vert blank start: %d, Vert blank end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(VSYNC_A); + ErrorF("Vert sync start: %d, Vert sync end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(PIPEASRC); + ErrorF("Image size: %dx%d (%dx%d)\n", + (temp >> 16) & 0x7ff, temp & 0x7ff, + (((temp >> 16) & 0x7ff) + 1), ((temp & 0x7ff) + 1)); + ErrorF("Pixel multiply is %d\n", (planeA >> 20) & 0x3); + temp = INREG(DSPABASE); + ErrorF("Plane A start offset is %d\n", temp); + temp = INREG(DSPASTRIDE); + ErrorF("Plane A stride is %d bytes (%d pixels)\n", temp, temp / pI830->cpp); +#endif + + for (i = 0; i < MAX_DISPLAY_PIPES; i++) { + CARD32 stridereg = i ? DSPBSTRIDE : DSPASTRIDE; + CARD32 basereg = i ? DSPBBASE : DSPABASE; + + if (!pI830->planeEnabled[i]) + continue; + + temp = INREG(stridereg); + if (temp / pI830->cpp != pScrn->displayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(i), + temp / pI830->cpp, pScrn->displayWidth); + OUTREG(stridereg, pScrn->displayWidth * pI830->cpp); + /* Trigger update */ + temp = INREG(basereg); + OUTREG(basereg, temp); + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Mode bandwidth is %d Mpixel/s\n", + pMode->HDisplay * pMode->VDisplay * refresh / 1000000); + + { + int maxBandwidth, bandwidthA, bandwidthB; + + if (GetModeSupport(pScrn, 0x80, 0x80, 0x80, 0x80, + &maxBandwidth, &bandwidthA, &bandwidthB)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "maxBandwidth is %d Mbyte/s, " + "pipe bandwidths are %d Mbyte/s, %d Mbyte/s\n", + maxBandwidth, bandwidthA, bandwidthB); + } + } + + { + int ret; + + ret = GetLFPCompMode(pScrn); + if (ret != -1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "LFP compensation mode: 0x%x\n", ret); + } + } + +#if MODESWITCH_RESET_STATE + ResetState(pScrn, TRUE); + SetHWOperatingState(pScrn); +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled && didLock) { + DRIUnlock(screenInfo.screens[pScrn->scrnIndex]); + pI830->LockHeld = 0; + } +#endif + + pScrn->vtSema = TRUE; + return TRUE; +} + +static void +InitRegisterRec(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RegPtr i830Reg = &pI830->ModeReg; + int i; + + for (i = 0; i < 8; i++) + i830Reg->Fence[i] = 0; +} + +/* Famous last words + */ +void +I830PrintErrorState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + ErrorF("pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n", + INREG(PGETBL_CTL), INREG(PGE_ERR)); + + ErrorF("ipeir: %lx iphdr: %lx\n", INREG(IPEIR), INREG(IPEHR)); + + ErrorF("LP ring tail: %lx head: %lx len: %lx start %lx\n", + INREG(LP_RING + RING_TAIL), + INREG(LP_RING + RING_HEAD) & HEAD_ADDR, + INREG(LP_RING + RING_LEN), INREG(LP_RING + RING_START)); + + ErrorF("eir: %x esr: %x emr: %x\n", + INREG16(EIR), INREG16(ESR), INREG16(EMR)); + + ErrorF("instdone: %x instpm: %x\n", INREG16(INST_DONE), INREG8(INST_PM)); + + ErrorF("memmode: %lx instps: %lx\n", INREG(MEMMODE), INREG(INST_PS)); + + ErrorF("hwstam: %x ier: %x imr: %x iir: %x\n", + INREG16(HWSTAM), INREG16(IER), INREG16(IMR), INREG16(IIR)); +} + +#ifdef I830DEBUG +static void +dump_DSPACNTR(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int tmp; + + /* Display A Control */ + tmp = INREG(0x70180); + ErrorF("Display A Plane Control Register (0x%.8x)\n", tmp); + + if (tmp & BIT(31)) + ErrorF(" Display Plane A (Primary) Enable\n"); + else + ErrorF(" Display Plane A (Primary) Disabled\n"); + + if (tmp & BIT(30)) + ErrorF(" Display A pixel data is gamma corrected\n"); + else + ErrorF(" Display A pixel data bypasses gamma correction logic (default)\n"); + + switch ((tmp & 0x3c000000) >> 26) { /* bit 29:26 */ + case 0x00: + case 0x01: + case 0x03: + ErrorF(" Reserved\n"); + break; + case 0x02: + ErrorF(" 8-bpp Indexed\n"); + break; + case 0x04: + ErrorF(" 15-bit (5-5-5) pixel format (Targa compatible)\n"); + break; + case 0x05: + ErrorF(" 16-bit (5-6-5) pixel format (XGA compatible)\n"); + break; + case 0x06: + ErrorF(" 32-bit format (X:8:8:8)\n"); + break; + case 0x07: + ErrorF(" 32-bit format (8:8:8:8)\n"); + break; + default: + ErrorF(" Unknown - Invalid register value maybe?\n"); + } + + if (tmp & BIT(25)) + ErrorF(" Stereo Enable\n"); + else + ErrorF(" Stereo Disable\n"); + + if (tmp & BIT(24)) + ErrorF(" Display A, Pipe B Select\n"); + else + ErrorF(" Display A, Pipe A Select\n"); + + if (tmp & BIT(22)) + ErrorF(" Source key is enabled\n"); + else + ErrorF(" Source key is disabled\n"); + + switch ((tmp & 0x00300000) >> 20) { /* bit 21:20 */ + case 0x00: + ErrorF(" No line duplication\n"); + break; + case 0x01: + ErrorF(" Line/pixel Doubling\n"); + break; + case 0x02: + case 0x03: + ErrorF(" Reserved\n"); + break; + } + + if (tmp & BIT(18)) + ErrorF(" Stereo output is high during second image\n"); + else + ErrorF(" Stereo output is high during first image\n"); +} + +static void +dump_DSPBCNTR(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int tmp; + + /* Display B/Sprite Control */ + tmp = INREG(0x71180); + ErrorF("Display B/Sprite Plane Control Register (0x%.8x)\n", tmp); + + if (tmp & BIT(31)) + ErrorF(" Display B/Sprite Enable\n"); + else + ErrorF(" Display B/Sprite Disable\n"); + + if (tmp & BIT(30)) + ErrorF(" Display B pixel data is gamma corrected\n"); + else + ErrorF(" Display B pixel data bypasses gamma correction logic (default)\n"); + + switch ((tmp & 0x3c000000) >> 26) { /* bit 29:26 */ + case 0x00: + case 0x01: + case 0x03: + ErrorF(" Reserved\n"); + break; + case 0x02: + ErrorF(" 8-bpp Indexed\n"); + break; + case 0x04: + ErrorF(" 15-bit (5-5-5) pixel format (Targa compatible)\n"); + break; + case 0x05: + ErrorF(" 16-bit (5-6-5) pixel format (XGA compatible)\n"); + break; + case 0x06: + ErrorF(" 32-bit format (X:8:8:8)\n"); + break; + case 0x07: + ErrorF(" 32-bit format (8:8:8:8)\n"); + break; + default: + ErrorF(" Unknown - Invalid register value maybe?\n"); + } + + if (tmp & BIT(25)) + ErrorF(" Stereo is enabled and both start addresses are used in a two frame sequence\n"); + else + ErrorF(" Stereo disable and only a single start address is used\n"); + + if (tmp & BIT(24)) + ErrorF(" Display B/Sprite, Pipe B Select\n"); + else + ErrorF(" Display B/Sprite, Pipe A Select\n"); + + if (tmp & BIT(22)) + ErrorF(" Sprite source key is enabled\n"); + else + ErrorF(" Sprite source key is disabled (default)\n"); + + switch ((tmp & 0x00300000) >> 20) { /* bit 21:20 */ + case 0x00: + ErrorF(" No line duplication\n"); + break; + case 0x01: + ErrorF(" Line/pixel Doubling\n"); + break; + case 0x02: + case 0x03: + ErrorF(" Reserved\n"); + break; + } + + if (tmp & BIT(18)) + ErrorF(" Stereo output is high during second image\n"); + else + ErrorF(" Stereo output is high during first image\n"); + + if (tmp & BIT(15)) + ErrorF(" Alpha transfer mode enabled\n"); + else + ErrorF(" Alpha transfer mode disabled\n"); + + if (tmp & BIT(0)) + ErrorF(" Sprite is above overlay\n"); + else + ErrorF(" Sprite is above display A (default)\n"); +} + +void +I830_dump_registers(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + unsigned int i; + + ErrorF("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); + + dump_DSPACNTR(pScrn); + dump_DSPBCNTR(pScrn); + + ErrorF("0x71400 == 0x%.8x\n", INREG(0x71400)); + ErrorF("0x70008 == 0x%.8x\n", INREG(0x70008)); + for (i = 0x71410; i <= 0x71428; i += 4) + ErrorF("0x%x == 0x%.8x\n", i, INREG(i)); + + ErrorF("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); +} +#endif + +static Bool +I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + I830Ptr pI830; + VisualPtr visual; +#ifdef XF86DRI + Bool driDisabled; +#endif + + pScrn = xf86Screens[pScreen->myNum]; + pI830 = I830PTR(pScrn); + hwp = VGAHWPTR(pScrn); + + pI830->starting = TRUE; + + /* + * If we're changing the BIOS's view of the video memory size, do that + * first, then re-initialise the VBE information. + */ + pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); + SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); + if (!pI830->pVbe) + return FALSE; + pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); + + miClearVisualTypes(); + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + if (pScrn->bitsPerPixel > 8) { + if (!miSetVisualTypes(pScrn->depth, TrueColorMask, + pScrn->rgbBits, TrueColor)) + return FALSE; + } else { + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + } + if (!miSetPixmapDepths()) + return FALSE; + +#ifdef I830_XV + pI830->XvEnabled = !pI830->XvDisabled; + if (pI830->XvEnabled) { + if (pI830->noAccel || pI830->StolenOnly) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled because it " + "needs 2D accel and AGPGART.\n"); + pI830->XvEnabled = FALSE; + } + } +#else + pI830->XvEnabled = FALSE; +#endif + + I830ResetAllocations(pScrn, 0); + + I830Allocate2DMemory(pScrn, ALLOC_INITIAL); + + if (!pI830->noAccel) { + if (pI830->LpRing.mem.Size == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling acceleration because the ring buffer " + "allocation failed.\n"); + pI830->noAccel = TRUE; + } + } + + if (!pI830->SWCursor) { + if (pI830->CursorMem.Size == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling HW cursor because the cursor memory " + "allocation failed.\n"); + pI830->SWCursor = TRUE; + } + } + +#ifdef I830_XV + if (pI830->XvEnabled) { + if (pI830->noAccel) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Xv because it " + "needs 2D acceleration.\n"); + pI830->XvEnabled = FALSE; + } + if (pI830->OverlayMem.Physical == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling Xv because the overlay register buffer " + "allocation failed.\n"); + pI830->XvEnabled = FALSE; + } + } +#endif + + InitRegisterRec(pScrn); + +#ifdef XF86DRI + /* + * pI830->directRenderingDisabled is set once in PreInit. Reinitialise + * pI830->directRenderingEnabled based on it each generation. + */ + pI830->directRenderingEnabled = !pI830->directRenderingDisabled; + /* + * Setup DRI after visuals have been established, but before fbScreenInit + * is called. fbScreenInit will eventually call into the drivers + * InitGLXVisuals call back. + */ + + if (pI830->directRenderingEnabled) { + if (pI830->noAccel || pI830->SWCursor || pI830->StolenOnly) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DRI is disabled because it " + "needs HW cursor, 2D accel and AGPGART.\n"); + pI830->directRenderingEnabled = FALSE; + } + } + + driDisabled = !pI830->directRenderingEnabled; + + if (pI830->directRenderingEnabled) + pI830->directRenderingEnabled = I830DRIScreenInit(pScreen); + + if (pI830->directRenderingEnabled) + if (!(pI830->directRenderingEnabled = I830Allocate3DMemory(pScrn, 0))) + I830DRICloseScreen(pScreen); + +#else + pI830->directRenderingEnabled = FALSE; +#endif + + /* + * After the 3D allocations have been done, see if there's any free space + * that can be added to the framebuffer allocation. + */ + I830Allocate2DMemory(pScrn, 0); + + DPRINTF(PFX, "assert(if(!I830DoPoolAllocation(pScrn, pI830->StolenPool)))\n"); + if (!I830DoPoolAllocation(pScrn, &(pI830->StolenPool))) + return FALSE; + + DPRINTF(PFX, "assert( if(!I830FixupOffsets(pScrn)) )\n"); + if (!I830FixupOffsets(pScrn)) + return FALSE; + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + I830SetupMemoryTiling(pScrn); + pI830->directRenderingEnabled = I830DRIDoMappings(pScreen); + } +#endif + + DPRINTF(PFX, "assert( if(!I830MapMem(pScrn)) )\n"); + if (!I830MapMem(pScrn)) + return FALSE; + + pScrn->memPhysBase = (unsigned long)pI830->FbBase; + pScrn->fbOffset = pI830->FrontBuffer.Start; + + vgaHWSetMmioFuncs(hwp, pI830->MMIOBase, 0); + vgaHWGetIOBase(hwp); + DPRINTF(PFX, "assert( if(!vgaHWMapMem(pScrn)) )\n"); + if (!vgaHWMapMem(pScrn)) + return FALSE; + + /* Clear SavedReg */ + memset(&pI830->SavedReg, 0, sizeof(pI830->SavedReg)); + + DPRINTF(PFX, "assert( if(!I830BIOSEnterVT(scrnIndex, 0)) )\n"); + if (!I830BIOSEnterVT(scrnIndex, 0)) + return FALSE; + + DPRINTF(PFX, "assert( if(!fbScreenInit(pScreen, ...) )\n"); + if (!fbScreenInit(pScreen, pI830->FbBase + pScrn->fbOffset, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) + return FALSE; + + if (pScrn->bitsPerPixel > 8) { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + fbPictureInit(pScreen, 0, 0); + + xf86SetBlackWhitePixels(pScreen); + +#if 1 + I830DGAInit(pScreen); +#endif + + DPRINTF(PFX, + "assert( if(!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) )\n"); + if (!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to init memory manager\n"); + return FALSE; + } + + if (!pI830->noAccel) { + if (!I830AccelInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware acceleration initialization failed\n"); + } + } + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (!pI830->SWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing HW Cursor\n"); + if (!I830CursorInit(pScreen)) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + } else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing SW Cursor!\n"); + + DPRINTF(PFX, "assert( if(!miCreateDefColormap(pScreen)) )\n"); + if (!miCreateDefColormap(pScreen)) + return FALSE; + + DPRINTF(PFX, "assert( if(!xf86HandleColormaps(pScreen, ...)) )\n"); + if (!xf86HandleColormaps(pScreen, 256, 8, I830LoadPalette, 0, + CMAP_RELOAD_ON_MODE_SWITCH)) { + return FALSE; + } + +#ifdef DPMSExtension + xf86DPMSInit(pScreen, I830DisplayPowerManagementSet, 0); +#endif + +#ifdef I830_XV + /* Init video */ + if (pI830->XvEnabled) + I830InitVideo(pScreen); +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + pI830->directRenderingEnabled = I830DRIFinishScreenInit(pScreen); + } +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + pI830->directRenderingOpen = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Enabled\n"); + /* Setup 3D engine */ + I830EmitInvarientState(pScrn); + } else { + if (driDisabled) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Disabled\n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Failed\n"); + } +#else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "direct rendering: Not available\n"); +#endif + + pScreen->SaveScreen = I830BIOSSaveScreen; + pI830->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = I830BIOSCloseScreen; + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); +#if 0 +#ifdef I830DEBUG + I830_dump_registers(pScrn); +#endif +#endif + + pI830->starting = FALSE; + pI830->closing = FALSE; + pI830->suspended = FALSE; + return TRUE; +} + +static void +I830BIOSAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn; + I830Ptr pI830; + vbeInfoPtr pVbe; + static int xoffset = 0, yoffset = 0; + static int adjustGeneration = -1; + + pScrn = xf86Screens[scrnIndex]; + pI830 = I830PTR(pScrn); + pVbe = pI830->pVbe; + + DPRINTF(PFX, "I830BIOSAdjustFrame: y = %d (+ %d), x = %d (+ %d)\n", + x, xoffset, y, yoffset); + + /* Calculate the offsets once per server generation. */ + if (adjustGeneration != serverGeneration) { + adjustGeneration = serverGeneration; + xoffset = (pScrn->fbOffset / pI830->cpp) % pScrn->displayWidth; + yoffset = (pScrn->fbOffset / pI830->cpp) / pScrn->displayWidth; + } + + if (OffsetFrame) { + y = (pI830->FbMemBox.y2 - pScrn->currentMode->VDisplay); + ErrorF("AdjustFrame: OffsetFrame is set, setting y to %d\n", y); + } + x += xoffset; + y += yoffset; +#if 0 + x >>= 4; + x <<= 4; +#endif + VBESetDisplayStart(pVbe, x, y, TRUE); +} + +static void +I830BIOSFreeScreen(int scrnIndex, int flags) +{ + I830BIOSFreeRec(xf86Screens[scrnIndex]); + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); +} + +#ifndef SAVERESTORE_HWSTATE +#define SAVERESTORE_HWSTATE 0 +#endif + +#if SAVERESTORE_HWSTATE +static void +SaveHWOperatingState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RegPtr save = &pI830->SavedReg; + + DPRINTF(PFX, "SaveHWOperatingState\n"); + + return; +} + +static void +RestoreHWOperatingState(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + I830RegPtr save = &pI830->SavedReg; + + DPRINTF(PFX, "RestoreHWOperatingState\n"); + + return; +} +#endif + +static void +I830BIOSLeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; +#ifdef XF86DRI + I830Ptr pI830 = I830PTR(pScrn); +#endif + + DPRINTF(PFX, "Leave VT\n"); + +#ifdef XF86DRI + if (pI830->directRenderingOpen) { + DPRINTF(PFX, "calling dri lock\n"); + DRILock(screenInfo.screens[scrnIndex], 0); + pI830->LockHeld = 1; + } +#endif + +#if SAVERESTORE_HWSTATE + if (!pI830->closing) + SaveHWOperatingState(pScrn); +#endif + + ResetState(pScrn, TRUE); + RestoreHWState(pScrn); + RestoreBIOSMemSize(pScrn); + I830UnbindGARTMemory(pScrn); +} + +/* + * This gets called when gaining control of the VT, and from ScreenInit(). + */ +static Bool +I830BIOSEnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + static int SaveGeneration = -1; + + DPRINTF(PFX, "Enter VT\n"); + + if (!I830BindGARTMemory(pScrn)) + return FALSE; + + CheckInheritedState(pScrn); + SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); + + /* + * Only save state once per server generation since that's what most + * drivers do. Could change this to save state at each VT enter. + */ + if (SaveGeneration != serverGeneration) { + SaveGeneration = serverGeneration; + SaveHWState(pScrn); + } + ResetState(pScrn, FALSE); + SetHWOperatingState(pScrn); + +#if 1 + /* Clear the framebuffer */ + memset(pI830->FbBase + pScrn->fbOffset, 0, + pScrn->virtualY * pScrn->displayWidth * pI830->cpp); +#endif + + if (!I830VESASetMode(pScrn, pScrn->currentMode)) + return FALSE; +#ifdef I830_XV + I830VideoSwitchModeAfter(pScrn, pScrn->currentMode); +#endif + + ResetState(pScrn, TRUE); + SetHWOperatingState(pScrn); + + pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + +#if SAVERESTORE_HWSTATE + RestoreHWOperatingState(pScrn); +#endif + +#ifdef XF86DRI + if (pI830->directRenderingEnabled) { + if (!pI830->starting) { + I830EmitInvarientState(pScrn); + I830RefreshRing(pScrn); + I830Sync(pScrn); + DO_RING_IDLE(); + + DPRINTF(PFX, "calling dri unlock\n"); + DRIUnlock(screenInfo.screens[scrnIndex]); + } + pI830->LockHeld = 0; + } +#endif + + return TRUE; +} + +static Bool +I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + + int _head; + int _tail; + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + int ret = TRUE; + + DPRINTF(PFX, "I830BIOSSwitchMode: mode == %p\n", mode); + + /* Stops head pointer freezes for 845G */ + if (!pI830->noAccel && (1 || IS_845G(pI830))) { + do { + _head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK; + _tail = INREG(LP_RING + RING_TAIL) & I830_TAIL_MASK; + DELAY(1000); + } while (_head != _tail); + } + +#if 0 + OffsetFrame = !OffsetFrame; + pScrn->AdjustFrame(scrnIndex, 0, 0, 0); +#endif + +#ifndef BINDUNBIND +#define BINDUNBIND 0 +#endif +#if BINDUNBIND + I830UnbindGARTMemory(pScrn); +#endif +#ifdef I830_XV + /* Give the video overlay code a chance to see the new mode. */ + I830VideoSwitchModeBefore(pScrn, mode); +#endif + if (!I830VESASetMode(pScrn, mode)) + ret = FALSE; +#ifdef I830_XV + /* Give the video overlay code a chance to see the new mode. */ + I830VideoSwitchModeAfter(pScrn, mode); +#endif +#if BINDUNBIND + I830BindGARTMemory(pScrn); +#endif + + return ret; +} + +static Bool +I830BIOSSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + Bool on = xf86IsUnblank(mode); + CARD32 temp, ctrl, base, i; + + DPRINTF(PFX, "I830BIOSSaveScreen: %d, on is %s\n", mode, BOOLTOSTRING(on)); + + for (i = 0; i < MAX_DISPLAY_PIPES; i++) { + if (i == 0) { + ctrl = DSPACNTR; + base = DSPABASE; + } else { + ctrl = DSPBCNTR; + base = DSPBADDR; + } + if (pI830->planeEnabled[i]) { + temp = INREG(ctrl); + if (on) + temp |= DISPLAY_PLANE_ENABLE; + else + temp &= ~DISPLAY_PLANE_ENABLE; + OUTREG(ctrl, temp); + /* Flush changes */ + temp = INREG(base); + OUTREG(base, temp); + } + } + + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { + if (on) + pI830->CursorInfoRec->ShowCursor(pScrn); + else + pI830->CursorInfoRec->HideCursor(pScrn); + pI830->cursorOn = TRUE; + } + + return TRUE; +} + +/* Use the VBE version when available. */ +static void +I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + + if (xf86LoaderCheckSymbol("VBEDPMSSet")) { + VBEDPMSSet(pVbe, PowerManagementMode); + } else { + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f10; + pVbe->pInt10->bx = 0x01; + + switch (PowerManagementMode) { + case DPMSModeOn: + break; + case DPMSModeStandby: + pVbe->pInt10->bx |= 0x0100; + break; + case DPMSModeSuspend: + pVbe->pInt10->bx |= 0x0200; + break; + case DPMSModeOff: + pVbe->pInt10->bx |= 0x0400; + break; + } + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + } +} + +static Bool +I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + XAAInfoRecPtr infoPtr = pI830->AccelInfoRec; + + pI830->closing = TRUE; +#ifdef XF86DRI + if (pI830->directRenderingOpen) { + pI830->directRenderingOpen = FALSE; + I830DRICloseScreen(pScreen); + } +#endif + + if (pScrn->vtSema == TRUE) { + I830BIOSLeaveVT(scrnIndex, 0); + } + + DPRINTF(PFX, "\nUnmapping memory\n"); + I830UnmapMem(pScrn); + vgaHWUnmapMem(pScrn); + + if (pI830->ScanlineColorExpandBuffers) { + xfree(pI830->ScanlineColorExpandBuffers); + pI830->ScanlineColorExpandBuffers = 0; + } + + if (infoPtr) { + if (infoPtr->ScanlineColorExpandBuffers) + xfree(infoPtr->ScanlineColorExpandBuffers); + XAADestroyInfoRec(infoPtr); + pI830->AccelInfoRec = NULL; + } + + if (pI830->CursorInfoRec) { + xf86DestroyCursorInfoRec(pI830->CursorInfoRec); + pI830->CursorInfoRec = 0; + } + + xf86GARTCloseScreen(scrnIndex); + + pScrn->vtSema = FALSE; + pI830->closing = FALSE; + pScreen->CloseScreen = pI830->CloseScreen; + return (*pScreen->CloseScreen) (scrnIndex, pScreen); +} + +static int +I830ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + if (mode->Flags & V_INTERLACE) { + if (verbose) { + xf86DrvMsg(scrnIndex, X_PROBED, + "Removing interlaced mode \"%s\"\n", mode->name); + } + return MODE_BAD; + } + return MODE_OK; +} + +#ifndef SUSPEND_SLEEP +#define SUSPEND_SLEEP 0 +#endif +#ifndef RESUME_SLEEP +#define RESUME_SLEEP 0 +#endif + +/* + * This function is only required if we need to do anything differently from + * DoApmEvent() in common/xf86PM.c, including if we want to see events other + * than suspend/resume. + */ +static Bool +I830PMEvent(int scrnIndex, pmEvent event, Bool undo) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + I830Ptr pI830 = I830PTR(pScrn); + + DPRINTF(PFX, "Enter VT, event %d, undo: %s\n", event, BOOLTOSTRING(undo)); + + switch(event) { + case XF86_APM_SYS_SUSPEND: + case XF86_APM_CRITICAL_SUSPEND: /*do we want to delay a critical suspend?*/ + case XF86_APM_USER_SUSPEND: + case XF86_APM_SYS_STANDBY: + case XF86_APM_USER_STANDBY: + if (!undo && !pI830->suspended) { + pScrn->LeaveVT(scrnIndex, 0); + pI830->suspended = TRUE; + sleep(SUSPEND_SLEEP); + } else if (undo && pI830->suspended) { + sleep(RESUME_SLEEP); + pScrn->EnterVT(scrnIndex, 0); + pI830->suspended = FALSE; + } + break; + case XF86_APM_STANDBY_RESUME: + case XF86_APM_NORMAL_RESUME: + case XF86_APM_CRITICAL_RESUME: + if (pI830->suspended) { + sleep(RESUME_SLEEP); + pScrn->EnterVT(scrnIndex, 0); + pI830->suspended = FALSE; + /* + * Turn the screen saver off when resuming. This seems to be + * needed to stop xscreensaver kicking in (when used). + * + * XXX DoApmEvent() should probably call this just like + * xf86VTSwitch() does. Maybe do it here only in 4.2 + * compatibility mode. + */ + SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset); + } + break; + default: + ErrorF("I830PMEvent: received APM event %d\n", event); + } + return TRUE; +} + +void +I830InitpScrn(ScrnInfoPtr pScrn) +{ + pScrn->PreInit = I830BIOSPreInit; + pScrn->ScreenInit = I830BIOSScreenInit; + pScrn->SwitchMode = I830BIOSSwitchMode; + pScrn->AdjustFrame = I830BIOSAdjustFrame; + pScrn->EnterVT = I830BIOSEnterVT; + pScrn->LeaveVT = I830BIOSLeaveVT; + pScrn->FreeScreen = I830BIOSFreeScreen; + pScrn->ValidMode = I830ValidMode; + pScrn->PMEvent = I830PMEvent; +} |