/************************************************************************** Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************/ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i810_driver.c,v 1.101 2004/01/02 20:15:47 dawes Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* * 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 characters expanded at 8-column intervals. */ /* * Authors: * Keith Whitwell * * Add ARGB HW cursor support: * Alan Hourihane * */ /* * This server does not support these XFree86 4.0 features yet * shadowFb (if requested or acceleration is off) * Overlay planes * DGA */ #include #include #include /* * These are X and server generic header files. */ #include "xf86.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 #include "vbe.h" #include "i810.h" #include "i830.h" #ifdef XF86DRI #include "dri.h" #endif /* Required Functions: */ static void I810Identify(int flags); #if XSERVER_LIBPCIACCESS static Bool intel_pci_probe (DriverPtr drv, int entity_num, struct pci_device *dev, intptr_t match_data); #else static Bool I810Probe(DriverPtr drv, int flags); #endif #ifndef I830_ONLY static Bool I810PreInit(ScrnInfoPtr pScrn, int flags); static Bool I810ScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); static Bool I810EnterVT(int scrnIndex, int flags); static void I810LeaveVT(int scrnIndex, int flags); static Bool I810CloseScreen(int scrnIndex, ScreenPtr pScreen); static Bool I810SaveScreen(ScreenPtr pScreen, Bool unblank); static void I810FreeScreen(int scrnIndex, int flags); static void I810DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagermentMode, int flags); static ModeStatus I810ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags); #endif /* I830_ONLY */ #if XSERVER_LIBPCIACCESS #define INTEL_DEVICE_MATCH(d,i) \ { 0x8086, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) } static const struct pci_id_match intel_device_match[] = { #ifndef I830_ONLY INTEL_DEVICE_MATCH (PCI_CHIP_I810, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I810_DC100, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I810_E, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I815, 0 ), #endif INTEL_DEVICE_MATCH (PCI_CHIP_I830_M, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_845_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I855_GM, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I865_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I915_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_E7221_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I915_GM, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I945_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I945_GM, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I945_GME, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I965_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_G35_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I965_Q, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I946_GZ, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I965_GM, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_I965_GME, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_G33_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_Q35_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_Q33_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_IGD_GM, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_IGD_E_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_G45_G, 0 ), INTEL_DEVICE_MATCH (PCI_CHIP_Q45_G, 0 ), { 0, 0, 0 }, }; #endif /* XSERVER_LIBPCIACCESS */ _X_EXPORT DriverRec I810 = { I810_VERSION, I810_DRIVER_NAME, I810Identify, #if XSERVER_LIBPCIACCESS NULL, #else I810Probe, #endif I810AvailableOptions, NULL, 0, NULL, #if XSERVER_LIBPCIACCESS intel_device_match, intel_pci_probe #endif }; /* *INDENT-OFF* */ /* Chipsets */ static SymTabRec I810Chipsets[] = { #ifndef I830_ONLY {PCI_CHIP_I810, "i810"}, {PCI_CHIP_I810_DC100, "i810-dc100"}, {PCI_CHIP_I810_E, "i810e"}, {PCI_CHIP_I815, "i815"}, #endif {PCI_CHIP_I830_M, "i830M"}, {PCI_CHIP_845_G, "845G"}, {PCI_CHIP_I855_GM, "852GM/855GM"}, {PCI_CHIP_I865_G, "865G"}, {PCI_CHIP_I915_G, "915G"}, {PCI_CHIP_E7221_G, "E7221 (i915)"}, {PCI_CHIP_I915_GM, "915GM"}, {PCI_CHIP_I945_G, "945G"}, {PCI_CHIP_I945_GM, "945GM"}, {PCI_CHIP_I945_GME, "945GME"}, {PCI_CHIP_I965_G, "965G"}, {PCI_CHIP_G35_G, "G35"}, {PCI_CHIP_I965_Q, "965Q"}, {PCI_CHIP_I946_GZ, "946GZ"}, {PCI_CHIP_I965_GM, "965GM"}, {PCI_CHIP_I965_GME, "965GME/GLE"}, {PCI_CHIP_G33_G, "G33"}, {PCI_CHIP_Q35_G, "Q35"}, {PCI_CHIP_Q33_G, "Q33"}, {PCI_CHIP_IGD_GM, "Intel Integrated Graphics Device"}, {PCI_CHIP_IGD_E_G, "Intel Integrated Graphics Device"}, {PCI_CHIP_G45_G, "G45/G43"}, {PCI_CHIP_Q45_G, "Q45/Q43"}, {-1, NULL} }; static PciChipsets I810PciChipsets[] = { #ifndef I830_ONLY {PCI_CHIP_I810, PCI_CHIP_I810, RES_SHARED_VGA}, {PCI_CHIP_I810_DC100, PCI_CHIP_I810_DC100, RES_SHARED_VGA}, {PCI_CHIP_I810_E, PCI_CHIP_I810_E, RES_SHARED_VGA}, {PCI_CHIP_I815, PCI_CHIP_I815, RES_SHARED_VGA}, #endif {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}, {PCI_CHIP_I915_G, PCI_CHIP_I915_G, RES_SHARED_VGA}, {PCI_CHIP_E7221_G, PCI_CHIP_E7221_G, RES_SHARED_VGA}, {PCI_CHIP_I915_GM, PCI_CHIP_I915_GM, RES_SHARED_VGA}, {PCI_CHIP_I945_G, PCI_CHIP_I945_G, RES_SHARED_VGA}, {PCI_CHIP_I945_GM, PCI_CHIP_I945_GM, RES_SHARED_VGA}, {PCI_CHIP_I945_GME, PCI_CHIP_I945_GME, RES_SHARED_VGA}, {PCI_CHIP_I965_G, PCI_CHIP_I965_G, RES_SHARED_VGA}, {PCI_CHIP_G35_G, PCI_CHIP_G35_G, RES_SHARED_VGA}, {PCI_CHIP_I965_Q, PCI_CHIP_I965_Q, RES_SHARED_VGA}, {PCI_CHIP_I946_GZ, PCI_CHIP_I946_GZ, RES_SHARED_VGA}, {PCI_CHIP_I965_GM, PCI_CHIP_I965_GM, RES_SHARED_VGA}, {PCI_CHIP_I965_GME, PCI_CHIP_I965_GME, RES_SHARED_VGA}, {PCI_CHIP_G33_G, PCI_CHIP_G33_G, RES_SHARED_VGA}, {PCI_CHIP_Q35_G, PCI_CHIP_Q35_G, RES_SHARED_VGA}, {PCI_CHIP_Q33_G, PCI_CHIP_Q33_G, RES_SHARED_VGA}, {PCI_CHIP_IGD_GM, PCI_CHIP_IGD_GM, RES_SHARED_VGA}, {PCI_CHIP_IGD_E_G, PCI_CHIP_IGD_E_G, RES_SHARED_VGA}, {PCI_CHIP_G45_G, PCI_CHIP_G45_G, RES_SHARED_VGA}, {PCI_CHIP_Q45_G, PCI_CHIP_Q45_G, RES_SHARED_VGA}, {-1, -1, RES_UNDEFINED } }; #ifndef I830_ONLY typedef enum { OPTION_NOACCEL, OPTION_SW_CURSOR, OPTION_COLOR_KEY, OPTION_CACHE_LINES, OPTION_DAC_6BIT, OPTION_DRI, OPTION_NO_DDC, OPTION_SHOW_CACHE, OPTION_XVMC_SURFACES, OPTION_PAGEFLIP } I810Opts; static const OptionInfoRec I810Options[] = { {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE}, {OPTION_CACHE_LINES, "CacheLines", OPTV_INTEGER, {0}, FALSE}, {OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_NO_DDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_SHOW_CACHE, "ShowCache", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_XVMC_SURFACES, "XvMCSurfaces", OPTV_INTEGER, {0}, FALSE}, {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; /* *INDENT-ON* */ #endif const char *I810vgahwSymbols[] = { "vgaHWFreeHWRec", "vgaHWGetHWRec", "vgaHWGetIOBase", "vgaHWGetIndex", "vgaHWInit", "vgaHWLock", "vgaHWMapMem", "vgaHWProtect", "vgaHWRestore", "vgaHWSave", "vgaHWSaveScreen", "vgaHWSetMmioFuncs", "vgaHWUnlock", "vgaHWUnmapMem", NULL }; const char *I810fbSymbols[] = { "fbPictureInit", "fbScreenInit", NULL }; const char *I810vbeSymbols[] = { "VBEFreeModeInfo", "VBEFreeVBEInfo", "VBEGetModeInfo", "VBEGetModePool", "VBEGetVBEInfo", "VBEGetVBEMode", "VBEInit", "VBEPrintModes", "VBESaveRestore", "VBESetDisplayStart", "VBESetGetDACPaletteFormat", "VBESetGetLogicalScanlineLength", "VBESetGetPaletteData", "VBESetModeNames", "VBESetModeParameters", "VBESetVBEMode", "VBEValidateModes", "vbeDoEDID", "vbeFree", NULL }; #ifdef XFree86LOADER static const char *vbeOptionalSymbols[] = { "VBEDPMSSet", "VBEGetPixelClock", NULL }; #endif const char *I810ddcSymbols[] = { "xf86PrintEDID", "xf86SetDDCproperties", NULL }; const char *I810int10Symbols[] = { "xf86ExecX86int10", "xf86InitInt10", "xf86Int10AllocPages", "xf86int10Addr", NULL }; const char *I810xaaSymbols[] = { "XAACreateInfoRec", "XAADestroyInfoRec", "XAAInit", "XAAGetCopyROP", "XAAGetPatternROP", NULL }; const char *I810ramdacSymbols[] = { "xf86CreateCursorInfoRec", "xf86DestroyCursorInfoRec", "xf86InitCursor", NULL }; const char *I810shadowFBSymbols[] = { "ShadowFBInit", NULL }; #ifdef XF86DRI const char *I810drmSymbols[] = { "drmAddBufs", "drmAddMap", "drmAgpAcquire", "drmAgpAlloc", "drmAgpBind", "drmAgpEnable", "drmAgpFree", "drmAgpRelease", "drmAgpUnbind", "drmAuthMagic", "drmCommandNone", "drmCommandWrite", "drmCreateContext", "drmCtlInstHandler", "drmCtlUninstHandler", "drmDestroyContext", "drmFreeVersion", "drmGetInterruptFromBusID", "drmGetLibVersion", "drmGetVersion", "drmRmMap", #ifdef XSERVER_LIBDRM_MM "drmMMInit", "drmMMTakedown", "drmMMLock", "drmMMUnlock", #endif NULL }; const char *I810driSymbols[] = { "DRICloseScreen", "DRICreateInfoRec", "DRIGetContext", "DRIDestroyInfoRec", "DRIFinishScreenInit", "DRIGetSAREAPrivate", "DRILock", "DRIQueryVersion", "DRIScreenInit", "DRIUnlock", "GlxSetVisualConfigs", "DRICreatePCIBusID", NULL }; #endif /* I830_ONLY */ const char *I810i2cSymbols[] = { "xf86CreateI2CBusRec", "xf86I2CBusInit", NULL }; #ifndef I810_DEBUG int I810_DEBUG = (0 /* | DEBUG_ALWAYS_SYNC */ /* | DEBUG_VERBOSE_ACCEL */ /* | DEBUG_VERBOSE_SYNC */ /* | DEBUG_VERBOSE_VGA */ /* | DEBUG_VERBOSE_RING */ /* | DEBUG_VERBOSE_OUTREG */ /* | DEBUG_VERBOSE_MEMORY */ /* | DEBUG_VERBOSE_CURSOR */ ); #endif #ifndef I830_ONLY #ifdef XF86DRI static int i810_pitches[] = { 512, 1024, 2048, 4096, 0 }; #endif #endif int I830EntityIndex = -1; #ifdef XFree86LOADER static MODULESETUPPROTO(i810Setup); static XF86ModuleVersionInfo intelVersRec = { "intel", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, INTEL_VERSION_MAJOR, INTEL_VERSION_MINOR, INTEL_VERSION_PATCH, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0, 0, 0, 0} }; _X_EXPORT XF86ModuleData intelModuleData = { &intelVersRec, i810Setup, NULL }; static XF86ModuleVersionInfo i810VersRec = { "i810", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, INTEL_VERSION_MAJOR, INTEL_VERSION_MINOR, INTEL_VERSION_PATCH, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0, 0, 0, 0} }; _X_EXPORT XF86ModuleData i810ModuleData = { &i810VersRec, i810Setup, NULL }; static pointer i810Setup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = 0; /* This module should be loaded only once, but check to be sure. */ if (!setupDone) { setupDone = 1; xf86AddDriver(&I810, module, #if XSERVER_LIBPCIACCESS HaveDriverFuncs #else 0 #endif ); /* * Tell the loader about symbols from other modules that this module * might refer to. */ LoaderRefSymLists(I810vgahwSymbols, I810fbSymbols, I810xaaSymbols, I810ramdacSymbols, #ifdef XF86DRI I810drmSymbols, I810driSymbols, #endif I810shadowFBSymbols, I810vbeSymbols, vbeOptionalSymbols, I810ddcSymbols, I810int10Symbols, NULL); /* * The return value must be non-NULL on success even though there * is no TearDownProc. */ return (pointer) 1; } else { if (errmaj) *errmaj = LDR_ONCEONLY; return NULL; } } #endif #ifndef I830_ONLY /* * I810GetRec and I810FreeRec -- * * Private data for the driver is stored in the screen structure. * These two functions create and destroy that private data. * */ static Bool I810GetRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(I810Rec), 1); return TRUE; } static void I810FreeRec(ScrnInfoPtr pScrn) { if (!pScrn) return; if (!pScrn->driverPrivate) return; xfree(pScrn->driverPrivate); pScrn->driverPrivate = NULL; } #endif /* * I810Identify -- * * Returns the string name for the driver based on the chipset. In this * case it will always be an I810, so we can return a static string. * */ static void I810Identify(int flags) { xf86PrintChipsets(I810_NAME, "Driver for Intel Integrated Graphics Chipsets", I810Chipsets); } const OptionInfoRec * I810AvailableOptions(int chipid, int busid) { #ifndef I830_ONLY const OptionInfoRec *pOptions; if ((pOptions = I830AvailableOptions(chipid, busid))) return pOptions; return I810Options; #else return I830AvailableOptions(chipid, busid); #endif } #if XSERVER_LIBPCIACCESS struct pci_device * intel_host_bridge (void) { static const struct pci_slot_match bridge_match = { 0, 0, 0, PCI_MATCH_ANY, 0 }; struct pci_device_iterator *slot_iterator; struct pci_device *bridge; slot_iterator = pci_slot_match_iterator_create (&bridge_match); bridge = pci_device_next (slot_iterator); pci_iterator_destroy (slot_iterator); return bridge; } /* * intel_pci_probe -- * * Look through the PCI bus to find cards that are intel boards. * Setup the dispatch table for the rest of the driver functions. * */ static Bool intel_pci_probe (DriverPtr driver, int entity_num, struct pci_device *device, intptr_t match_data) { ScrnInfoPtr scrn = NULL; EntityInfoPtr entity; I830EntPtr i830_ent = NULL; DevUnion *private; scrn = xf86ConfigPciEntity (scrn, 0, entity_num, I810PciChipsets, NULL, NULL, NULL, NULL, NULL); if (scrn != NULL) { scrn->driverVersion = I810_VERSION; scrn->driverName = I810_DRIVER_NAME; scrn->name = I810_NAME; scrn->Probe = NULL; entity = xf86GetEntityInfo (entity_num); switch (DEVICE_ID(device)) { #ifndef I830_ONLY case PCI_CHIP_I810: case PCI_CHIP_I810_DC100: case PCI_CHIP_I810_E: case PCI_CHIP_I815: scrn->PreInit = I810PreInit; scrn->ScreenInit = I810ScreenInit; scrn->SwitchMode = I810SwitchMode; scrn->AdjustFrame = I810AdjustFrame; scrn->EnterVT = I810EnterVT; scrn->LeaveVT = I810LeaveVT; scrn->FreeScreen = I810FreeScreen; scrn->ValidMode = I810ValidMode; break; #endif case PCI_CHIP_845_G: case PCI_CHIP_I865_G: /* * These two chips have only one pipe, and * cannot do dual-head */ I830InitpScrn(scrn); break; default: /* * Everything else is an i830-ish dual-pipe chip */ xf86SetEntitySharable(entity_num); /* Allocate an entity private if necessary */ if (I830EntityIndex < 0) I830EntityIndex = xf86AllocateEntityPrivateIndex(); private = xf86GetEntityPrivate(scrn->entityList[0], I830EntityIndex); i830_ent = private->ptr; if (!i830_ent) { private->ptr = xnfcalloc(sizeof(I830EntRec), 1); i830_ent = private->ptr; i830_ent->lastInstance = -1; } /* * Set the entity instance for this instance of the driver. * For dual head per card, instance 0 is the "master" * instance, driving the primary head, and instance 1 is * the "slave". */ i830_ent->lastInstance++; xf86SetEntityInstanceForScreen(scrn, scrn->entityList[0], i830_ent->lastInstance); I830InitpScrn(scrn); break; } } return scrn != NULL; } #else /* XSERVER_LIBPCIACCESS */ /* * I810Probe -- * * Look through the PCI bus to find cards that are I810 boards. * Setup the dispatch table for the rest of the driver functions. * */ static Bool I810Probe(DriverPtr drv, int flags) { int i, numUsed, numDevSections, *usedChips; I830EntPtr pI830Ent = NULL; DevUnion *pPriv; GDevPtr *devSections; Bool foundScreen = FALSE; pciVideoPtr *VideoInfo; pciVideoPtr *ppPci; PciChipsets *id; /* * Find the config file Device sections that match this * driver, and return if there are none. */ if ((numDevSections = xf86MatchDevice(I810_DRIVER_NAME, &devSections)) <= 0 && (numDevSections = xf86MatchDevice(I810_LEGACY_DRIVER_NAME, &devSections)) <= 0) { return FALSE; } /* * This probing is just checking the PCI data the server already * collected. */ if (!(VideoInfo = xf86GetPciVideoInfo())) return FALSE; /* * Mobile platforms may have both function 0 and 1 active, but they * are handled as a single entity. To make sure that the function 1 * entity isn't assigned to a screen, check for and claim it here * first. * * XXX If function 1's resources are ever needed, they'll need to be * added to the screen and marked active. */ for (ppPci = VideoInfo; ppPci != NULL && *ppPci != NULL; ppPci++) { if ((*ppPci)->vendor == PCI_VENDOR_INTEL && (*ppPci)->func == 1) { for (id = I810PciChipsets; id->PCIid != -1; id++) { if (id->PCIid == (*ppPci)->chipType) { /* Claim slot */ if (xf86CheckPciSlot((*ppPci)->bus, (*ppPci)->device, (*ppPci)->func)) { xf86ClaimPciSlot((*ppPci)->bus, (*ppPci)->device, (*ppPci)->func, drv, id->PCIid, NULL, FALSE); } break; } } } } /* Look for Intel i8xx devices. */ numUsed = xf86MatchPciInstances(I810_NAME, PCI_VENDOR_INTEL, I810Chipsets, I810PciChipsets, devSections, numDevSections, drv, &usedChips); if (flags & PROBE_DETECT) { if (numUsed > 0) foundScreen = TRUE; } else { for (i = 0; i < numUsed; i++) { ScrnInfoPtr pScrn = NULL; /* Allocate new ScrnInfoRec and claim the slot */ if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], I810PciChipsets, NULL, NULL, NULL, NULL, NULL))) { EntityInfoPtr pEnt; pEnt = xf86GetEntityInfo(usedChips[i]); pScrn->driverVersion = I810_VERSION; pScrn->driverName = I810_DRIVER_NAME; pScrn->name = I810_NAME; pScrn->Probe = I810Probe; foundScreen = TRUE; switch (pEnt->chipset) { case PCI_CHIP_845_G: case PCI_CHIP_I865_G: I830InitpScrn(pScrn); break; case PCI_CHIP_I830_M: case PCI_CHIP_I855_GM: case PCI_CHIP_I915_G: case PCI_CHIP_E7221_G: case PCI_CHIP_I915_GM: case PCI_CHIP_I945_G: case PCI_CHIP_I945_GM: case PCI_CHIP_I945_GME: case PCI_CHIP_I965_G: case PCI_CHIP_G35_G: case PCI_CHIP_I965_Q: case PCI_CHIP_I946_GZ: case PCI_CHIP_I965_GM: case PCI_CHIP_I965_GME: case PCI_CHIP_G33_G: case PCI_CHIP_Q35_G: case PCI_CHIP_Q33_G: case PCI_CHIP_IGD_GM: case PCI_CHIP_IGD_E_G: case PCI_CHIP_G45_G: case PCI_CHIP_Q45_G: xf86SetEntitySharable(usedChips[i]); /* Allocate an entity private if necessary */ if (I830EntityIndex < 0) I830EntityIndex = xf86AllocateEntityPrivateIndex(); pPriv = xf86GetEntityPrivate(pScrn->entityList[0], I830EntityIndex); if (!pPriv->ptr) { pPriv->ptr = xnfcalloc(sizeof(I830EntRec), 1); pI830Ent = pPriv->ptr; pI830Ent->lastInstance = -1; } else { pI830Ent = pPriv->ptr; } /* * Set the entity instance for this instance of the driver. * For dual head per card, instance 0 is the "master" * instance, driving the primary head, and instance 1 is * the "slave". */ pI830Ent->lastInstance++; xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0], pI830Ent->lastInstance); I830InitpScrn(pScrn); break; #ifndef I830_ONLY default: pScrn->PreInit = I810PreInit; pScrn->ScreenInit = I810ScreenInit; pScrn->SwitchMode = I810SwitchMode; pScrn->AdjustFrame = I810AdjustFrame; pScrn->EnterVT = I810EnterVT; pScrn->LeaveVT = I810LeaveVT; pScrn->FreeScreen = I810FreeScreen; pScrn->ValidMode = I810ValidMode; break; #endif } } } } xfree(usedChips); xfree(devSections); return foundScreen; } #endif /* else XSERVER_LIBPCIACCESS */ #ifndef I830_ONLY static void I810ProbeDDC(ScrnInfoPtr pScrn, int index) { vbeInfoPtr pVbe; if (xf86LoadSubModule(pScrn, "vbe")) { pVbe = VBEInit(NULL, index); ConfiguredMonitor = vbeDoEDID(pVbe, NULL); vbeFree(pVbe); } } static xf86MonPtr I810DoDDC(ScrnInfoPtr pScrn, int index) { vbeInfoPtr pVbe; xf86MonPtr MonInfo = NULL; I810Ptr pI810 = I810PTR(pScrn); /* Honour Option "noDDC" */ if (xf86ReturnOptValBool(pI810->Options, OPTION_NO_DDC, FALSE)) { return MonInfo; } if (xf86LoadSubModule(pScrn, "vbe") && (pVbe = VBEInit(NULL, index))) { xf86LoaderReqSymLists(I810vbeSymbols, NULL); MonInfo = vbeDoEDID(pVbe, NULL); xf86PrintEDID(MonInfo); xf86SetDDCproperties(pScrn, MonInfo); vbeFree(pVbe); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "this driver cannot do DDC without VBE\n"); } return MonInfo; } /* * I810PreInit -- * * Do initial setup of the board before we know what resolution we will * be running at. * */ static Bool I810PreInit(ScrnInfoPtr pScrn, int flags) { vgaHWPtr hwp; I810Ptr pI810; ClockRangePtr clockRanges; int i; MessageType from; int flags24; rgb defaultWeight = { 0, 0, 0 }; int mem; Bool enable; if (pScrn->numEntities != 1) return FALSE; /* Allocate driverPrivate */ if (!I810GetRec(pScrn)) return FALSE; pI810 = I810PTR(pScrn); pI810->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if (pI810->pEnt->location.type != BUS_PCI) return FALSE; if (flags & PROBE_DETECT) { I810ProbeDDC(pScrn, pI810->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; hwp = VGAHWPTR(pScrn); pI810->ioBase = hwp->PIOOffset; pI810->PciInfo = xf86GetPciInfoForEntity(pI810->pEnt->index); #if !XSERVER_LIBPCIACCESS pI810->PciTag = pciTag(pI810->PciInfo->bus, pI810->PciInfo->device, pI810->PciInfo->func); #endif if (xf86RegisterResources(pI810->pEnt->index, NULL, ResNone)) return FALSE; pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; /* Set pScrn->monitor */ pScrn->monitor = pScrn->confScreen->monitor; flags24 = Support24bppFb | PreferConvert32to24 | SupportConvert32to24; if (!xf86SetDepthBpp(pScrn, 16, 0, 16, flags24)) { return FALSE; } else { switch (pScrn->depth) { case 8: case 15: case 16: case 24: break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given depth (%d) is not supported by i810 driver\n", pScrn->depth); return FALSE; } } xf86PrintDepthBpp(pScrn); switch (pScrn->bitsPerPixel) { case 8: case 16: case 24: break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given bpp (%d) is not supported by i810 driver\n", pScrn->bitsPerPixel); return FALSE; } if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) return FALSE; if (!xf86SetDefaultVisual(pScrn, -1)) return FALSE; /* We use a programmable clock */ pScrn->progClock = TRUE; pI810->cpp = pScrn->bitsPerPixel / 8; /* Process the options */ xf86CollectOptions(pScrn, NULL); if (!(pI810->Options = xalloc(sizeof(I810Options)))) return FALSE; memcpy(pI810->Options, I810Options, sizeof(I810Options)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI810->Options); pScrn->rgbBits = 8; if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE)) pScrn->rgbBits = 6; if (xf86ReturnOptValBool(pI810->Options, OPTION_SHOW_CACHE, FALSE)) pI810->showCache = TRUE; else pI810->showCache = FALSE; /* 6-BIT dac isn't reasonable for modes with > 8bpp */ if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE) && pScrn->bitsPerPixel > 8) { OptionInfoPtr ptr; ptr = xf86TokenToOptinfo(pI810->Options, OPTION_DAC_6BIT); ptr->found = FALSE; } if (xf86ReturnOptValBool(pI810->Options, OPTION_NOACCEL, FALSE)) pI810->noAccel = TRUE; if (!pI810->noAccel) { if (!xf86LoadSubModule(pScrn, "xaa")) { I810FreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(I810xaaSymbols, NULL); } #ifdef XF86DRI pI810->directRenderingDisabled = !xf86ReturnOptValBool(pI810->Options, OPTION_DRI, TRUE); if (!pI810->directRenderingDisabled) { if (pI810->noAccel) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI is disabled because it " "needs 2D acceleration.\n"); pI810->directRenderingDisabled=TRUE; } else if (pScrn->depth!=16) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI is disabled because it " "runs only at 16-bit depth.\n"); pI810->directRenderingDisabled=TRUE; } } #endif /* Get DDC info from monitor */ /* after xf86ProcessOptions, * because it is controlled by options [no]vbe and [no]ddc */ pScrn->monitor->DDC = I810DoDDC(pScrn, pI810->pEnt->index); /* We have to use PIO to probe, because we haven't mapped yet */ I810SetPIOAccess(pI810); /* * Set the Chipset and ChipRev, allowing config file entries to * override. */ if (pI810->pEnt->device->chipset && *pI810->pEnt->device->chipset) { pScrn->chipset = pI810->pEnt->device->chipset; from = X_CONFIG; } else if (pI810->pEnt->device->chipID >= 0) { pScrn->chipset = (char *)xf86TokenToString(I810Chipsets, pI810->pEnt->device->chipID); from = X_CONFIG; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", pI810->pEnt->device->chipID); } else { from = X_PROBED; pScrn->chipset = (char *)xf86TokenToString(I810Chipsets, DEVICE_ID(pI810->PciInfo)); } if (pI810->pEnt->device->chipRev >= 0) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", pI810->pEnt->device->chipRev); } xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", (pScrn->chipset != NULL) ? pScrn->chipset : "Unknown i810"); #if XSERVER_LIBPCIACCESS pI810->LinearAddr = pI810->PciInfo->regions[0].base_addr; #else if (pI810->pEnt->device->MemBase != 0) { pI810->LinearAddr = pI810->pEnt->device->MemBase; from = X_CONFIG; } else { if (pI810->PciInfo->memBase[1] != 0) { pI810->LinearAddr = pI810->PciInfo->memBase[0] & 0xFF000000; from = X_PROBED; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid FB address in PCI config space\n"); I810FreeRec(pScrn); return FALSE; } } #endif xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", (unsigned long)pI810->LinearAddr); #if XSERVER_LIBPCIACCESS pI810->MMIOAddr = pI810->PciInfo->regions[1].base_addr; #else if (pI810->pEnt->device->IOBase != 0) { pI810->MMIOAddr = pI810->pEnt->device->IOBase; from = X_CONFIG; } else { if (pI810->PciInfo->memBase[1]) { pI810->MMIOAddr = pI810->PciInfo->memBase[1] & 0xFFF80000; from = X_PROBED; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address in PCI config space\n"); I810FreeRec(pScrn); return FALSE; } } #endif xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n", (unsigned long)pI810->MMIOAddr); /* AGP GART support is required. Don't proceed any further if it isn't * present. */ if (!xf86AgpGARTSupported()) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "AGP GART support is not available. Make sure your kernel has\n" "\tagpgart support or that the agpgart kernel module is loaded.\n"); return FALSE; } /* Find out memory bus frequency. */ { uint32_t whtcfg_pamr_drp; #if XSERVER_LIBPCIACCESS pci_device_cfg_read_u32(pI810->PciInfo, & whtcfg_pamr_drp, WHTCFG_PAMR_DRP); #else whtcfg_pamr_drp = pciReadLong(pI810->PciTag, WHTCFG_PAMR_DRP); #endif /* Need this for choosing watermarks. */ if ((whtcfg_pamr_drp & LM_FREQ_MASK) == LM_FREQ_133) pI810->LmFreqSel = 133; else pI810->LmFreqSel = 100; } /* Default to 4MB framebuffer, which is sufficient for all * supported 2d resolutions. If the user has specified a different * size in the XF86Config, use that amount instead. * * Changed to 8 Meg so we can have acceleration by default (Mark). */ mem = I810CheckAvailableMemory(pScrn); if (pI810->directRenderingDisabled || mem < 131072) /* < 128 MB */ pScrn->videoRam = 8192; else if (mem < 196608) pScrn->videoRam = 16384; /* < 192 MB */ else pScrn->videoRam = 24576; from = X_DEFAULT; if (pI810->pEnt->device->videoRam) { pScrn->videoRam = pI810->pEnt->device->videoRam; from = X_CONFIG; } if (mem > 0 && mem < pScrn->videoRam) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%dk of memory was requested," " but the\n\t maximum AGP memory available is %dk.\n", pScrn->videoRam, mem); from = X_PROBED; if (mem > (6 * 1024)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reducing video memory to 4MB\n"); pScrn->videoRam = 4096; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Less than 6MB of AGP memory" " is available. Cannot proceed.\n"); I810FreeRec(pScrn); return FALSE; } } xf86DrvMsg(pScrn->scrnIndex, from, "Will alloc AGP framebuffer: %d kByte\n", pScrn->videoRam); /* Calculate Fixed Offsets depending on graphics aperture size */ { #if XSERVER_LIBPCIACCESS struct pci_device *bridge = intel_host_bridge (); uint32_t smram_miscc; pci_device_cfg_read_u32 (bridge, & smram_miscc, SMRAM_MISCC); #else PCITAG bridge; long smram_miscc; bridge = pciTag(0, 0, 0); /* This is always the host bridge */ smram_miscc = pciReadLong(bridge, SMRAM_MISCC); #endif if ((smram_miscc & GFX_MEM_WIN_SIZE) == GFX_MEM_WIN_32M) { pI810->FbMapSize = 0x1000000; pI810->DepthOffset = 0x1000000; pI810->BackOffset = 0x1800000; } else { pI810->FbMapSize = 0x3000000; pI810->DepthOffset = 0x3000000; pI810->BackOffset = 0x3800000; } } /* * 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; } } pI810->MaxClock = 0; if (pI810->pEnt->device->dacSpeeds[0]) { switch (pScrn->bitsPerPixel) { case 8: pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP8]; break; case 16: pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP16]; break; case 24: pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP24]; break; case 32: /* not supported */ pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP32]; break; } if (!pI810->MaxClock) pI810->MaxClock = pI810->pEnt->device->dacSpeeds[0]; from = X_CONFIG; } else { switch (pScrn->bitsPerPixel) { case 8: pI810->MaxClock = 203000; break; case 16: pI810->MaxClock = 163000; break; case 24: pI810->MaxClock = 136000; break; case 32: /* not supported */ pI810->MaxClock = 86000; } } clockRanges = xnfcalloc(sizeof(ClockRange), 1); clockRanges->next = NULL; /* 9.4MHz appears to be the smallest that works. */ clockRanges->minClock = 9500; clockRanges->maxClock = pI810->MaxClock; clockRanges->clockIndex = -1; clockRanges->interlaceAllowed = TRUE; clockRanges->doubleScanAllowed = FALSE; i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, #ifndef XF86DRI 0, 320, 1600, 64 * pScrn->bitsPerPixel, #else i810_pitches, 0, 0, 64 * pScrn->bitsPerPixel, #endif 200, 1200, pScrn->display->virtualX, pScrn->display->virtualY, pScrn->videoRam * 1024, LOOKUP_BEST_REFRESH); if (i == -1) { I810FreeRec(pScrn); return FALSE; } xf86PruneDriverModes(pScrn); if (!i || !pScrn->modes) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); I810FreeRec(pScrn); return FALSE; } xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); pScrn->currentMode = pScrn->modes; xf86PrintModes(pScrn); xf86SetDpi(pScrn, 0, 0); if (!xf86LoadSubModule(pScrn, "fb")) { I810FreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(I810fbSymbols, NULL); if (!xf86ReturnOptValBool(pI810->Options, OPTION_SW_CURSOR, FALSE)) { if (!xf86LoadSubModule(pScrn, "ramdac")) { I810FreeRec(pScrn); return FALSE; } xf86LoaderReqSymLists(I810ramdacSymbols, NULL); } if (xf86GetOptValInteger (pI810->Options, OPTION_COLOR_KEY, &(pI810->colorKey))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video overlay key set to 0x%x\n", pI810->colorKey); } else { pI810->colorKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) | (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue); } pI810->allowPageFlip=FALSE; enable = xf86ReturnOptValBool(pI810->Options, OPTION_PAGEFLIP, FALSE); #ifdef XF86DRI if (!pI810->directRenderingDisabled) { pI810->allowPageFlip = enable; if (pI810->allowPageFlip == TRUE) { if (!xf86LoadSubModule(pScrn, "shadowfb")) { pI810->allowPageFlip = 0; xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Couldn't load shadowfb module:\n"); } else { xf86LoaderReqSymLists(I810shadowFBSymbols, NULL); } } xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "page flipping %s\n", enable ? "enabled" : "disabled"); } #endif if (xf86GetOptValInteger(pI810->Options, OPTION_XVMC_SURFACES, &(pI810->numSurfaces))) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "%d XvMC Surfaces Requested.\n", pI810->numSurfaces); if (pI810->numSurfaces > 7) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Using 7 XvMC Surfaces (Maximum Allowed).\n"); pI810->numSurfaces = 7; } if (pI810->numSurfaces < 6) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Using 6 XvMC Surfaces (Minimum Allowed).\n"); pI810->numSurfaces = 6; } } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "XvMC is Disabled: use XvMCSurfaces config option to enable.\n"); pI810->numSurfaces = 0; } #ifdef XF86DRI /* Load the dri module if requested. */ if (xf86ReturnOptValBool(pI810->Options, OPTION_DRI, FALSE)) { if (xf86LoadSubModule(pScrn, "dri")) { xf86LoaderReqSymLists(I810driSymbols, I810drmSymbols, NULL); } } #endif /* We won't be using the VGA access after the probe */ I810SetMMIOAccess(pI810); xf86SetOperatingState(resVgaIo, pI810->pEnt->index, ResUnusedOpr); xf86SetOperatingState(resVgaMem, pI810->pEnt->index, ResDisableOpr); return TRUE; } static Bool I810MapMMIO(ScrnInfoPtr pScrn) { int mmioFlags; I810Ptr pI810 = I810PTR(pScrn); #if XSERVER_LIBPCIACCESS struct pci_device *const device = pI810->PciInfo; int err; #endif #if !defined(__alpha__) mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; #else mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT | VIDMEM_SPARSE; #endif #if XSERVER_LIBPCIACCESS err = pci_device_map_range (device, pI810->MMIOAddr, I810_REG_SIZE, PCI_DEV_MAP_FLAG_WRITABLE, (void **) &pI810->MMIOBase); if (err) { xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Unable to map mmio BAR. %s (%d)\n", strerror (err), err); return FALSE; } #else pI810->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, pI810->PciTag, pI810->MMIOAddr, I810_REG_SIZE); if (!pI810->MMIOBase) return FALSE; #endif return TRUE; } static Bool I810MapMem(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); #if XSERVER_LIBPCIACCESS struct pci_device *const device = pI810->PciInfo; int err; #else long i; #endif if (!I810MapMMIO(pScrn)) return FALSE; #if XSERVER_LIBPCIACCESS err = pci_device_map_range (device, pI810->LinearAddr, pI810->FbMapSize, PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE, (void **) &pI810->FbBase); if (err) { xf86DrvMsg (pScrn->scrnIndex, X_ERROR, "Unable to map frame buffer BAR. %s (%d)\n", strerror (err), err); return FALSE; } #else for (i = 2; i < pI810->FbMapSize; i <<= 1) ; pI810->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, pI810->PciTag, pI810->LinearAddr, i); if (!pI810->FbBase) return FALSE; #endif pI810->LpRing->virtual_start = pI810->FbBase + pI810->LpRing->mem.Start; return TRUE; } static void I810UnmapMMIO(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); #if XSERVER_LIBPCIACCESS pci_device_unmap_range (pI810->PciInfo, pI810->MMIOBase, I810_REG_SIZE); #else xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI810->MMIOBase, I810_REG_SIZE); #endif pI810->MMIOBase = NULL; } static Bool I810UnmapMem(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); #if XSERVER_LIBPCIACCESS pci_device_unmap_range (pI810->PciInfo, pI810->FbBase, pI810->FbMapSize); #else xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI810->FbBase, pI810->FbMapSize); #endif pI810->FbBase = NULL; I810UnmapMMIO(pScrn); return TRUE; } /* Famous last words */ void I810PrintErrorState(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); ErrorF("pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n", (unsigned long) INREG(PGETBL_CTL), (unsigned long) INREG(PGE_ERR)); ErrorF("ipeir: %lx iphdr: %lx\n", (unsigned long) INREG(IPEIR), (unsigned long) INREG(IPEHR)); ErrorF("LP ring tail: %lx head: %lx len: %lx start %lx\n", (unsigned long) INREG(LP_RING + RING_TAIL), (unsigned long) INREG(LP_RING + RING_HEAD) & HEAD_ADDR, (unsigned long) INREG(LP_RING + RING_LEN), (unsigned long) 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", (unsigned long) INREG(MEMMODE), (unsigned long) INREG(INST_PS)); ErrorF("hwstam: %x ier: %x imr: %x iir: %x\n", INREG16(HWSTAM), INREG16(IER), INREG16(IMR), INREG16(IIR)); } /* * I810Save -- * * This function saves the video state. It reads all of the SVGA registers * into the vgaI810Rec data structure. There is in general no need to * mask out bits here - just read the registers. */ static void DoSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I810RegPtr i810Reg, Bool saveFonts) { I810Ptr pI810; vgaHWPtr hwp; int i; pI810 = I810PTR(pScrn); hwp = VGAHWPTR(pScrn); /* * This function will handle creating the data structure and filling * in the generic VGA portion. */ if (saveFonts) vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_FONTS | VGA_SR_CMAP); else vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); /* * The port I/O code necessary to read in the extended registers * into the fields of the vgaI810Rec structure goes here. */ i810Reg->IOControl = hwp->readCrtc(hwp, IO_CTNL); i810Reg->AddressMapping = pI810->readControl(pI810, GRX, ADDRESS_MAPPING); i810Reg->BitBLTControl = INREG8(BITBLT_CNTL); i810Reg->VideoClk2_M = INREG16(VCLK2_VCO_M); i810Reg->VideoClk2_N = INREG16(VCLK2_VCO_N); i810Reg->VideoClk2_DivisorSel = INREG8(VCLK2_VCO_DIV_SEL); i810Reg->ExtVertTotal = hwp->readCrtc(hwp, EXT_VERT_TOTAL); i810Reg->ExtVertDispEnd = hwp->readCrtc(hwp, EXT_VERT_DISPLAY); i810Reg->ExtVertSyncStart = hwp->readCrtc(hwp, EXT_VERT_SYNC_START); i810Reg->ExtVertBlankStart = hwp->readCrtc(hwp, EXT_VERT_BLANK_START); i810Reg->ExtHorizTotal = hwp->readCrtc(hwp, EXT_HORIZ_TOTAL); i810Reg->ExtHorizBlank = hwp->readCrtc(hwp, EXT_HORIZ_BLANK); i810Reg->ExtOffset = hwp->readCrtc(hwp, EXT_OFFSET); i810Reg->InterlaceControl = hwp->readCrtc(hwp, INTERLACE_CNTL); i810Reg->PixelPipeCfg0 = INREG8(PIXPIPE_CONFIG_0); i810Reg->PixelPipeCfg1 = INREG8(PIXPIPE_CONFIG_1); i810Reg->PixelPipeCfg2 = INREG8(PIXPIPE_CONFIG_2); i810Reg->DisplayControl = INREG8(DISPLAY_CNTL); i810Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC); for (i = 0; i < 8; i++) i810Reg->Fence[i] = INREG(FENCE + i * 4); i810Reg->LprbTail = INREG(LP_RING + RING_TAIL); i810Reg->LprbHead = INREG(LP_RING + RING_HEAD); i810Reg->LprbStart = INREG(LP_RING + RING_START); i810Reg->LprbLen = INREG(LP_RING + RING_LEN); if ((i810Reg->LprbTail & TAIL_ADDR) != (i810Reg->LprbHead & HEAD_ADDR) && i810Reg->LprbLen & RING_VALID) { I810PrintErrorState(pScrn); FatalError("Active ring not flushed\n"); } } static void I810Save(ScrnInfoPtr pScrn) { vgaHWPtr hwp; I810Ptr pI810; uint32_t temp; hwp = VGAHWPTR(pScrn); pI810 = I810PTR(pScrn); DoSave(pScrn, &hwp->SavedReg, &pI810->SavedReg, TRUE); temp = INREG(MEMMODE); temp |= 4; OUTREG(MEMMODE, temp); } static void i810PrintMode(vgaRegPtr vgaReg, I810RegPtr mode) { int i; ErrorF(" MiscOut: %x\n", vgaReg->MiscOutReg); ErrorF("SEQ: "); for (i = 0; i < vgaReg->numSequencer; i++) { if ((i & 7) == 0) ErrorF("\n"); ErrorF(" %d: %x", i, vgaReg->Sequencer[i]); } ErrorF("\n"); ErrorF("CRTC: "); for (i = 0; i < vgaReg->numCRTC; i++) { if ((i & 3) == 0) ErrorF("\n"); ErrorF(" %d: %x", i, vgaReg->CRTC[i]); } ErrorF("\n"); ErrorF("GFX: "); for (i = 0; i < vgaReg->numGraphics; i++) { if ((i & 7) == 0) ErrorF("\n"); ErrorF(" %d: %x", i, vgaReg->Graphics[i]); } ErrorF("\n"); ErrorF("ATTR: "); for (i = 0; i < vgaReg->numAttribute; i++) { if ((i & 7) == 0) ErrorF("\n"); ErrorF(" %d: %x", i, vgaReg->Attribute[i]); } ErrorF("\n"); ErrorF(" DisplayControl: %x\n", mode->DisplayControl); ErrorF(" PixelPipeCfg0: %x\n", mode->PixelPipeCfg0); ErrorF(" PixelPipeCfg1: %x\n", mode->PixelPipeCfg1); ErrorF(" PixelPipeCfg2: %x\n", mode->PixelPipeCfg2); ErrorF(" VideoClk2_M: %x\n", mode->VideoClk2_M); ErrorF(" VideoClk2_N: %x\n", mode->VideoClk2_N); ErrorF(" VideoClk2_DivisorSel: %x\n", mode->VideoClk2_DivisorSel); ErrorF(" AddressMapping: %x\n", mode->AddressMapping); ErrorF(" IOControl: %x\n", mode->IOControl); ErrorF(" BitBLTControl: %x\n", mode->BitBLTControl); ErrorF(" ExtVertTotal: %x\n", mode->ExtVertTotal); ErrorF(" ExtVertDispEnd: %x\n", mode->ExtVertDispEnd); ErrorF(" ExtVertSyncStart: %x\n", mode->ExtVertSyncStart); ErrorF(" ExtVertBlankStart: %x\n", mode->ExtVertBlankStart); ErrorF(" ExtHorizTotal: %x\n", mode->ExtHorizTotal); ErrorF(" ExtHorizBlank: %x\n", mode->ExtHorizBlank); ErrorF(" ExtOffset: %x\n", mode->ExtOffset); ErrorF(" InterlaceControl: %x\n", mode->InterlaceControl); ErrorF(" LMI_FIFO_Watermark: %x\n", mode->LMI_FIFO_Watermark); ErrorF(" LprbTail: %x\n", mode->LprbTail); ErrorF(" LprbHead: %x\n", mode->LprbHead); ErrorF(" LprbStart: %x\n", mode->LprbStart); ErrorF(" LprbLen: %x\n", mode->LprbLen); } static void DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I810RegPtr i810Reg, Bool restoreFonts) { I810Ptr pI810; vgaHWPtr hwp; unsigned char temp; unsigned int itemp; int i; pI810 = I810PTR(pScrn); hwp = VGAHWPTR(pScrn); if (I810_DEBUG & DEBUG_VERBOSE_VGA) { ErrorF("Setting mode in I810Restore:\n"); i810PrintMode(vgaReg, i810Reg); } vgaHWProtect(pScrn, TRUE); usleep(50000); /* Turn off DRAM Refresh */ temp = INREG8(DRAM_ROW_CNTL_HI); temp &= ~DRAM_REFRESH_RATE; temp |= DRAM_REFRESH_DISABLE; OUTREG8(DRAM_ROW_CNTL_HI, temp); usleep(1000); /* Wait 1 ms */ /* Write the M, N and P values */ OUTREG16(VCLK2_VCO_M, i810Reg->VideoClk2_M); OUTREG16(VCLK2_VCO_N, i810Reg->VideoClk2_N); OUTREG8(VCLK2_VCO_DIV_SEL, i810Reg->VideoClk2_DivisorSel); /* * Turn on 8 bit dac mode, if requested. This is needed to make * sure that vgaHWRestore writes the values into the DAC properly. * The problem occurs if 8 bit dac mode is requested and the HW is * in 6 bit dac mode. If this happens, all the values are * automatically shifted left twice by the HW and incorrect colors * will be displayed on the screen. The only time this can happen * is at server startup time and when switching back from a VT. */ temp = INREG8(PIXPIPE_CONFIG_0); temp &= 0x7F; /* Save all but the 8 bit dac mode bit */ temp |= (i810Reg->PixelPipeCfg0 & DAC_8_BIT); OUTREG8(PIXPIPE_CONFIG_0, temp); /* * Code to restore any SVGA registers that have been saved/modified * goes here. Note that it is allowable, and often correct, to * only modify certain bits in a register by a read/modify/write cycle. * * A special case - when using an external clock-setting program, * this function must not change bits associated with the clock * selection. This condition can be checked by the condition: * * if (i810Reg->std.NoClock >= 0) * restore clock-select bits. */ if (restoreFonts) vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS | VGA_SR_MODE | VGA_SR_CMAP); else vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); hwp->writeCrtc(hwp, EXT_VERT_TOTAL, i810Reg->ExtVertTotal); hwp->writeCrtc(hwp, EXT_VERT_DISPLAY, i810Reg->ExtVertDispEnd); hwp->writeCrtc(hwp, EXT_VERT_SYNC_START, i810Reg->ExtVertSyncStart); hwp->writeCrtc(hwp, EXT_VERT_BLANK_START, i810Reg->ExtVertBlankStart); hwp->writeCrtc(hwp, EXT_HORIZ_TOTAL, i810Reg->ExtHorizTotal); hwp->writeCrtc(hwp, EXT_HORIZ_BLANK, i810Reg->ExtHorizBlank); hwp->writeCrtc(hwp, EXT_OFFSET, i810Reg->ExtOffset); temp = hwp->readCrtc(hwp, INTERLACE_CNTL); temp &= ~INTERLACE_ENABLE; temp |= i810Reg->InterlaceControl; hwp->writeCrtc(hwp, INTERLACE_CNTL, temp); temp = pI810->readControl(pI810, GRX, ADDRESS_MAPPING); temp &= 0xE0; /* Save reserved bits 7:5 */ temp |= i810Reg->AddressMapping; pI810->writeControl(pI810, GRX, ADDRESS_MAPPING, temp); /* Setting the OVRACT Register for video overlay */ { uint32_t LCD_TV_Control = INREG(LCD_TV_C); uint32_t TV_HTotal = INREG(LCD_TV_HTOTAL); uint32_t ActiveStart, ActiveEnd; if((LCD_TV_Control & LCD_TV_ENABLE) && !(LCD_TV_Control & LCD_TV_VGAMOD) && TV_HTotal) { ActiveStart = ((TV_HTotal >> 16) & 0xfff) - 31; ActiveEnd = (TV_HTotal & 0x3ff) - 31; } else { ActiveStart = i810Reg->OverlayActiveStart; ActiveEnd = i810Reg->OverlayActiveEnd; } OUTREG(LCD_TV_OVRACT, (ActiveEnd << 16) | ActiveStart); } /* Turn on DRAM Refresh */ temp = INREG8(DRAM_ROW_CNTL_HI); temp &= ~DRAM_REFRESH_RATE; temp |= DRAM_REFRESH_60HZ; OUTREG8(DRAM_ROW_CNTL_HI, temp); temp = INREG8(BITBLT_CNTL); temp &= ~COLEXP_MODE; temp |= i810Reg->BitBLTControl; OUTREG8(BITBLT_CNTL, temp); temp = INREG8(DISPLAY_CNTL); temp &= ~(VGA_WRAP_MODE | GUI_MODE); temp |= i810Reg->DisplayControl; OUTREG8(DISPLAY_CNTL, temp); temp = INREG8(PIXPIPE_CONFIG_0); temp &= 0x64; /* Save reserved bits 6:5,2 */ temp |= i810Reg->PixelPipeCfg0; OUTREG8(PIXPIPE_CONFIG_0, temp); temp = INREG8(PIXPIPE_CONFIG_2); temp &= 0xF3; /* Save reserved bits 7:4,1:0 */ temp |= i810Reg->PixelPipeCfg2; OUTREG8(PIXPIPE_CONFIG_2, temp); temp = INREG8(PIXPIPE_CONFIG_1); temp &= ~DISPLAY_COLOR_MODE; temp &= 0xEF; /* Restore the CRT control bit */ temp |= i810Reg->PixelPipeCfg1; OUTREG8(PIXPIPE_CONFIG_1, temp); OUTREG16(EIR, 0); itemp = INREG(FWATER_BLC); itemp &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK | MM_BURST_LENGTH | MM_FIFO_WATERMARK); itemp |= i810Reg->LMI_FIFO_Watermark; OUTREG(FWATER_BLC, itemp); for (i = 0; i < 8; i++) { OUTREG(FENCE + i * 4, i810Reg->Fence[i]); if (I810_DEBUG & DEBUG_VERBOSE_VGA) ErrorF("Fence Register : %x\n", i810Reg->Fence[i]); } /* First disable the ring buffer (Need to wait for empty first?, if so * should probably do it before entering this section) */ itemp = INREG(LP_RING + RING_LEN); itemp &= ~RING_VALID_MASK; OUTREG(LP_RING + RING_LEN, itemp); /* Set up the low priority ring buffer. */ OUTREG(LP_RING + RING_TAIL, 0); OUTREG(LP_RING + RING_HEAD, 0); pI810->LpRing->head = 0; pI810->LpRing->tail = 0; itemp = INREG(LP_RING + RING_START); itemp &= ~(START_ADDR); itemp |= i810Reg->LprbStart; OUTREG(LP_RING + RING_START, itemp); itemp = INREG(LP_RING + RING_LEN); itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK); itemp |= i810Reg->LprbLen; OUTREG(LP_RING + RING_LEN, itemp); if (!(vgaReg->Attribute[0x10] & 0x1)) { usleep(50000); if (restoreFonts) vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS | VGA_SR_MODE | VGA_SR_CMAP); else vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); } vgaHWProtect(pScrn, FALSE); temp = hwp->readCrtc(hwp, IO_CTNL); temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL); temp |= i810Reg->IOControl; hwp->writeCrtc(hwp, IO_CTNL, temp); } static void I810SetRingRegs(ScrnInfoPtr pScrn) { unsigned int itemp; I810Ptr pI810 = I810PTR(pScrn); OUTREG(LP_RING + RING_TAIL, 0); OUTREG(LP_RING + RING_HEAD, 0); itemp = INREG(LP_RING + RING_START); itemp &= ~(START_ADDR); itemp |= pI810->LpRing->mem.Start; OUTREG(LP_RING + RING_START, itemp); itemp = INREG(LP_RING + RING_LEN); itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK); itemp |= ((pI810->LpRing->mem.Size - 4096) | RING_NO_REPORT | RING_VALID); OUTREG(LP_RING + RING_LEN, itemp); } static void I810Restore(ScrnInfoPtr pScrn) { vgaHWPtr hwp; I810Ptr pI810; hwp = VGAHWPTR(pScrn); pI810 = I810PTR(pScrn); DoRestore(pScrn, &hwp->SavedReg, &pI810->SavedReg, TRUE); } /* * I810CalcVCLK -- * * Determine the closest clock frequency to the one requested. */ #define MAX_VCO_FREQ 600.0 #define TARGET_MAX_N 30 #define REF_FREQ 24.0 #define CALC_VCLK(m,n,p) \ (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ static void I810CalcVCLK(ScrnInfoPtr pScrn, double freq) { I810Ptr pI810 = I810PTR(pScrn); I810RegPtr i810Reg = &pI810->ModeReg; int m, n, p; double f_out, f_best; double f_err; double f_vco; int m_best = 0, n_best = 0, p_best = 0; double f_target = freq; double err_max = 0.005; double err_target = 0.001; double err_best = 999999.0; p_best = p = log(MAX_VCO_FREQ / f_target) / log((double)2); /* Make sure p is within range. */ if (p_best > 5) { p_best = p = 5; } f_vco = f_target * (1 << p); n = 2; do { n++; m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5; if (m < 3) m = 3; f_out = CALC_VCLK(m, n, p); f_err = 1.0 - (f_target / f_out); if (fabs(f_err) < err_max) { m_best = m; n_best = n; f_best = f_out; err_best = f_err; } } while ((fabs(f_err) >= err_target) && ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max))); if (fabs(f_err) < err_target) { m_best = m; n_best = n; } i810Reg->VideoClk2_M = (m_best - 2) & 0x3FF; i810Reg->VideoClk2_N = (n_best - 2) & 0x3FF; i810Reg->VideoClk2_DivisorSel = (p_best << 4); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting dot clock to %.1f MHz " "[ 0x%x 0x%x 0x%x ] " "[ %d %d %d ]\n", CALC_VCLK(m_best, n_best, p_best), i810Reg->VideoClk2_M, i810Reg->VideoClk2_N, i810Reg->VideoClk2_DivisorSel, m_best, n_best, p_best); } static Bool I810SetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) { I810Ptr pI810 = I810PTR(pScrn); I810RegPtr i810Reg = &pI810->ModeReg; vgaRegPtr pVga = &VGAHWPTR(pScrn)->ModeReg; double dclk = mode->Clock / 1000.0; switch (pScrn->bitsPerPixel) { case 8: pVga->CRTC[0x13] = pScrn->displayWidth >> 3; i810Reg->ExtOffset = pScrn->displayWidth >> 11; i810Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE; i810Reg->BitBLTControl = COLEXP_8BPP; break; case 16: if (pScrn->weight.green == 5) { i810Reg->PixelPipeCfg1 = DISPLAY_15BPP_MODE; } else { i810Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE; } pVga->CRTC[0x13] = pScrn->displayWidth >> 2; i810Reg->ExtOffset = pScrn->displayWidth >> 10; i810Reg->BitBLTControl = COLEXP_16BPP; /* Enable Palette Programming for Direct Color visuals. -jens */ i810Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE; break; case 24: pVga->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3; i810Reg->ExtOffset = (pScrn->displayWidth * 3) >> 11; i810Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE; i810Reg->BitBLTControl = COLEXP_24BPP; /* Enable Palette Programming for Direct Color visuals. -jens */ i810Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE; break; default: break; } /* Turn on 8 bit dac if requested */ if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE)) i810Reg->PixelPipeCfg0 = DAC_6_BIT; else i810Reg->PixelPipeCfg0 = DAC_8_BIT; /* Do not delay CRT Blank: needed for video overlay */ i810Reg->PixelPipeCfg1 |= 0x10; /* Turn on Extended VGA Interpretation */ i810Reg->IOControl = EXTENDED_CRTC_CNTL; /* Turn on linear and page mapping */ i810Reg->AddressMapping = (LINEAR_MODE_ENABLE | GTT_MEM_MAP_ENABLE); /* Turn on GUI mode */ i810Reg->DisplayControl = HIRES_MODE; /* Calculate the extended CRTC regs */ i810Reg->ExtVertTotal = (mode->CrtcVTotal - 2) >> 8; i810Reg->ExtVertDispEnd = (mode->CrtcVDisplay - 1) >> 8; i810Reg->ExtVertSyncStart = mode->CrtcVSyncStart >> 8; i810Reg->ExtVertBlankStart = mode->CrtcVBlankStart >> 8; i810Reg->ExtHorizTotal = ((mode->CrtcHTotal >> 3) - 5) >> 8; i810Reg->ExtHorizBlank = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 6; /* * the KGA fix in vgaHW.c results in the first * scanline and the first character clock (8 pixels) * of each scanline thereafter on display with an i810 * to be blank. Restoring CRTC 3, 5, & 22 to their * "theoretical" values corrects the problem. KAO. */ pVga->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80; pVga->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) | (((mode->CrtcHSyncEnd >> 3)) & 0x1F); pVga->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; i810Reg->ExtHorizBlank = vgaHWHBlankKGA(mode, pVga, 7, 0); vgaHWVBlankKGA(mode, pVga, 8, 0); /* * The following workarounds are needed to get video overlay working * at 1024x768 and 1280x1024 display resolutions. */ if ((mode->CrtcVDisplay == 768) && (i810Reg->ExtVertBlankStart == 3)) { i810Reg->ExtVertBlankStart = 2; } if ((mode->CrtcVDisplay == 1024) && (i810Reg->ExtVertBlankStart == 4)) { i810Reg->ExtVertBlankStart = 3; } /* OVRACT Register */ i810Reg->OverlayActiveStart = mode->CrtcHTotal - 32; i810Reg->OverlayActiveEnd = mode->CrtcHDisplay - 32; /* Turn on interlaced mode if necessary */ if (mode->Flags & V_INTERLACE) { i810Reg->InterlaceControl = INTERLACE_ENABLE; i810Reg->ExtVertDispEnd *= 2; } else i810Reg->InterlaceControl = INTERLACE_DISABLE; /* * Set the overscan color to 0. * NOTE: This only affects >8bpp mode. */ pVga->Attribute[0x11] = 0; /* * Calculate the VCLK that most closely matches the requested dot * clock. */ I810CalcVCLK(pScrn, dclk); /* Since we program the clocks ourselves, always use VCLK2. */ pVga->MiscOutReg |= 0x0C; /* Calculate the FIFO Watermark and Burst Length. */ i810Reg->LMI_FIFO_Watermark = I810CalcWatermark(pScrn, dclk, FALSE); /* Setup the ring buffer */ i810Reg->LprbTail = 0; i810Reg->LprbHead = 0; i810Reg->LprbStart = pI810->LpRing->mem.Start; if (i810Reg->LprbStart) i810Reg->LprbLen = ((pI810->LpRing->mem.Size - 4096) | RING_NO_REPORT | RING_VALID); else i810Reg->LprbLen = RING_INVALID; return TRUE; } static Bool I810ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) { vgaHWPtr hwp; I810Ptr pI810; hwp = VGAHWPTR(pScrn); pI810 = I810PTR(pScrn); vgaHWUnlock(hwp); if (!vgaHWInit(pScrn, mode)) return FALSE; pScrn->vtSema = TRUE; if (!I810SetMode(pScrn, mode)) return FALSE; #ifdef XF86DRI if (pI810->directRenderingEnabled) { DRILock(screenInfo.screens[pScrn->scrnIndex], 0); pI810->LockHeld = 1; } #endif DoRestore(pScrn, &hwp->ModeReg, &pI810->ModeReg, FALSE); #ifdef XF86DRI if (pI810->directRenderingEnabled) { DRIUnlock(screenInfo.screens[pScrn->scrnIndex]); pI810->LockHeld = 0; } #endif return TRUE; } static void I810LoadPalette15(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO * colors, VisualPtr pVisual) { I810Ptr pI810; vgaHWPtr hwp; int i, j, index; unsigned char r, g, b; pI810 = I810PTR(pScrn); hwp = VGAHWPTR(pScrn); for (i = 0; i < numColors; i++) { index = indices[i]; r = colors[index].red; g = colors[index].green; b = colors[index].blue; for (j = 0; j < 8; j++) { hwp->writeDacWriteAddr(hwp, (index << 3) + j); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); } } } static void I810LoadPalette16(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO * colors, VisualPtr pVisual) { I810Ptr pI810; vgaHWPtr hwp; int i, index; unsigned char r, g, b; pI810 = I810PTR(pScrn); hwp = VGAHWPTR(pScrn); /* Load all four entries in each of the 64 color ranges. -jens */ for (i = 0; i < numColors; i++) { index = indices[i / 2]; r = colors[index].red; b = colors[index].blue; index = indices[i]; g = colors[index].green; hwp->writeDacWriteAddr(hwp, index << 2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); hwp->writeDacWriteAddr(hwp, (index << 2) + 1); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); hwp->writeDacWriteAddr(hwp, (index << 2) + 2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); hwp->writeDacWriteAddr(hwp, (index << 2) + 3); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); i++; index = indices[i]; g = colors[index].green; hwp->writeDacWriteAddr(hwp, index << 2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); hwp->writeDacWriteAddr(hwp, (index << 2) + 1); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); hwp->writeDacWriteAddr(hwp, (index << 2) + 2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); hwp->writeDacWriteAddr(hwp, (index << 2) + 3); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); } } static void I810LoadPalette24(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO * colors, VisualPtr pVisual) { I810Ptr pI810; vgaHWPtr hwp; int i, index; unsigned char r, g, b; pI810 = I810PTR(pScrn); hwp = VGAHWPTR(pScrn); for (i = 0; i < numColors; i++) { index = indices[i]; r = colors[index].red; g = colors[index].green; b = colors[index].blue; hwp->writeDacWriteAddr(hwp, index); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); } } Bool I810AllocateFront(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); int cache_lines = -1; if (pI810->DoneFrontAlloc) return TRUE; memset(&(pI810->FbMemBox), 0, sizeof(BoxRec)); /* Alloc FrontBuffer/Ring/Accel memory */ pI810->FbMemBox.x1 = 0; pI810->FbMemBox.x2 = pScrn->displayWidth; pI810->FbMemBox.y1 = 0; pI810->FbMemBox.y2 = pScrn->virtualY; xf86GetOptValInteger(pI810->Options, OPTION_CACHE_LINES, &cache_lines); if (cache_lines < 0) { /* make sure there is enough for two DVD sized YUV buffers */ cache_lines = (pScrn->depth == 24) ? 256 : 384; if (pScrn->displayWidth <= 1024) cache_lines *= 2; } /* Make sure there's enough space for cache_lines. * * Had a bug here where maxCacheLines was computed to be less than 0. * Not sure why 256 was initially subtracted from videoRam in the * maxCacheLines calculation, but that was causing a problem * for configurations that have exactly enough Ram for the framebuffer. * Common code should catch the case where there isn't enough space for * framebuffer, we'll just check for no space for cache_lines. -jens * */ { int maxCacheLines; maxCacheLines = (pScrn->videoRam * 1024 / (pScrn->bitsPerPixel / 8) / pScrn->displayWidth) - pScrn->virtualY; if (maxCacheLines < 0) maxCacheLines = 0; if (cache_lines > maxCacheLines) cache_lines = maxCacheLines; } pI810->FbMemBox.y2 += cache_lines; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Adding %i scanlines for pixmap caching\n", cache_lines); /* Reserve room for the framebuffer and pixcache. Put at the top * of memory so we can have nice alignment for the tiled regions at * the start of memory. */ if (!I810AllocLow(&(pI810->FrontBuffer), &(pI810->SysMem), ((pI810->FbMemBox.x2 * pI810->FbMemBox.y2 * pI810->cpp) + 4095) & ~4095)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Framebuffer allocation failed\n"); return FALSE; } else DPRINTF(PFX, "Frame buffer at 0x%.8x (%luk, %lu bytes)\n", pI810->FrontBuffer.Start, pI810->FrontBuffer.Size / 1024, pI810->FrontBuffer.Size); memset(pI810->LpRing, 0, sizeof(I810RingBuffer)); if (I810AllocLow(&(pI810->LpRing->mem), &(pI810->SysMem), 16 * 4096)) { DPRINTF(PFX, "Ring buffer at 0x%.8x (%luk, %lu bytes)\n", pI810->LpRing->mem.Start, pI810->LpRing->mem.Size / 1024, pI810->LpRing->mem.Size); pI810->LpRing->tail_mask = pI810->LpRing->mem.Size - 1; pI810->LpRing->virtual_start = pI810->FbBase + pI810->LpRing->mem.Start; pI810->LpRing->head = 0; pI810->LpRing->tail = 0; pI810->LpRing->space = 0; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Ring buffer allocation failed\n"); return (FALSE); } if (I810AllocLow(&pI810->Scratch, &(pI810->SysMem), 64 * 1024) || I810AllocLow(&pI810->Scratch, &(pI810->SysMem), 16 * 1024)) { DPRINTF(PFX, "Scratch memory at 0x%.8x (%luk, %lu bytes)\n", pI810->Scratch.Start, pI810->Scratch.Size / 1024, pI810->Scratch.Size); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Allocated Scratch Memory\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Scratch memory allocation failed\n"); return (FALSE); } pI810->DoneFrontAlloc = TRUE; return TRUE; } static Bool I810ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { ScrnInfoPtr pScrn; vgaHWPtr hwp; I810Ptr pI810; VisualPtr visual; MessageType driFrom = X_DEFAULT; pScrn = xf86Screens[pScreen->myNum]; pI810 = I810PTR(pScrn); hwp = VGAHWPTR(pScrn); pI810->LpRing = xcalloc(sizeof(I810RingBuffer),1); if (!pI810->LpRing) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not allocate lpring data structure.\n"); return FALSE; } miClearVisualTypes(); /* Re-implemented Direct Color support, -jens */ if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; if (!miSetPixmapDepths()) return FALSE; { I810RegPtr i810Reg = &pI810->ModeReg; int i; for (i = 0; i < 8; i++) i810Reg->Fence[i] = 0; } /* Have to init the DRM earlier than in other drivers to get agp * memory. Wonder if this is going to be a problem... */ #ifdef XF86DRI /* * Setup DRI after visuals have been established, but before fbScreenInit * is called. fbScreenInit will eventually call into the drivers * InitGLXVisuals call back. */ /* * pI810->directRenderingDisabled is set once in PreInit. Reinitialise * pI810->directRenderingEnabled based on it each generation. */ pI810->directRenderingEnabled = !pI810->directRenderingDisabled; if (pI810->directRenderingEnabled==TRUE) pI810->directRenderingEnabled = I810DRIScreenInit(pScreen); else driFrom = X_CONFIG; #else pI810->directRenderingEnabled = FALSE; if (!I810AllocateGARTMemory(pScrn)) return FALSE; if (!I810AllocateFront(pScrn)) return FALSE; #endif if (!I810MapMem(pScrn)) return FALSE; pScrn->memPhysBase = (unsigned long)pI810->LinearAddr; pScrn->fbOffset = 0; vgaHWSetMmioFuncs(hwp, pI810->MMIOBase, 0); vgaHWGetIOBase(hwp); if (!vgaHWMapMem(pScrn)) return FALSE; I810Save(pScrn); if (!I810ModeInit(pScrn, pScrn->currentMode)) return FALSE; I810SaveScreen(pScreen, FALSE); I810AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); if (!fbScreenInit(pScreen, pI810->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, NULL, 0); xf86SetBlackWhitePixels(pScreen); #ifdef XF86DRI if (pI810->LpRing->mem.Start == 0 && pI810->directRenderingEnabled) { pI810->directRenderingEnabled = FALSE; driFrom = X_PROBED; I810DRICloseScreen(pScreen); } if (!pI810->directRenderingEnabled) { pI810->DoneFrontAlloc = FALSE; if (!I810AllocateGARTMemory(pScrn)) return FALSE; if (!I810AllocateFront(pScrn)) return FALSE; } #endif I810DGAInit(pScreen); if (!xf86InitFBManager(pScreen, &(pI810->FbMemBox))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to init memory manager\n"); return FALSE; } if (!xf86ReturnOptValBool(pI810->Options, OPTION_NOACCEL, FALSE)) { if (pI810->LpRing->mem.Size != 0) { I810SetRingRegs(pScrn); if (!I810AccelInit(pScreen)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware acceleration initialization failed\n"); } else /* PK added 16.02.2004 */ I810EmitFlush(pScrn); } } miInitializeBackingStore(pScreen); xf86SetBackingStore(pScreen); xf86SetSilkenMouse(pScreen); miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); if (!xf86ReturnOptValBool(pI810->Options, OPTION_SW_CURSOR, FALSE)) { if (!I810CursorInit(pScreen)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor initialization failed\n"); } } if (!miCreateDefColormap(pScreen)) return FALSE; /* Use driver specific palette load routines for Direct Color support. -jens */ if (pScrn->bitsPerPixel == 16) { if (pScrn->depth == 15) { if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette15, NULL, CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } else { if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette16, NULL, CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } } else { if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette24, NULL, CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } xf86DPMSInit(pScreen, I810DisplayPowerManagementSet, 0); I810InitVideo(pScreen); #ifdef XF86DRI if (pI810->directRenderingEnabled) { /* Now that mi, fb, drm and others have done their thing, * complete the DRI setup. */ pI810->directRenderingEnabled = I810DRIFinishScreenInit(pScreen); } #ifdef XvMCExtension if ((pI810->directRenderingEnabled) && (pI810->numSurfaces)) { /* Initialize the hardware motion compensation code */ I810InitMC(pScreen); } #endif #endif if (pI810->directRenderingEnabled) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n"); } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n"); } pScreen->SaveScreen = I810SaveScreen; pI810->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = I810CloseScreen; if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); return TRUE; } Bool I810SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; #if 0 I810Ptr pI810 = I810PTR(pScrn); #endif if (I810_DEBUG & DEBUG_VERBOSE_CURSOR) ErrorF("I810SwitchMode %p %x\n", (void *)mode, flags); #if 0 /* * This has been added to prevent lockups on mode switch by modeling * it after I810Leave()/I810Enter() but the call to I810DRILeave() * was missing so it caused the opposite. * The version below works but it is doubtful it does any good. * If lockups on mode switch are still seen revisit this code. (EE) */ # ifdef XF86DRI if (pI810->directRenderingEnabled) { if (I810_DEBUG & DEBUG_VERBOSE_DRI) ErrorF("calling dri lock\n"); DRILock(screenInfo.screens[scrnIndex], 0); pI810->LockHeld = 1; } # endif if (pI810->AccelInfoRec != NULL) { I810RefreshRing(pScrn); I810Sync(pScrn); pI810->AccelInfoRec->NeedToSync = FALSE; } I810Restore(pScrn); # ifdef XF86DRI if (pI810->directRenderingEnabled) { if (!I810DRILeave(pScrn)) return FALSE; if (!I810DRIEnter(pScrn)) return FALSE; if (I810_DEBUG & DEBUG_VERBOSE_DRI) ErrorF("calling dri unlock\n"); DRIUnlock(screenInfo.screens[scrnIndex]); pI810->LockHeld = 0; } # endif #endif return I810ModeInit(pScrn, mode); } void I810AdjustFrame(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; I810Ptr pI810 = I810PTR(pScrn); vgaHWPtr hwp = VGAHWPTR(pScrn); int Base; #if 1 if (pI810->showCache) { int lastline = pI810->FbMapSize / ((pScrn->displayWidth * pScrn->bitsPerPixel) / 8); lastline -= pScrn->currentMode->VDisplay; if (y > 0) y += pScrn->currentMode->VDisplay; if (y > lastline) y = lastline; } #endif Base = (y * pScrn->displayWidth + x) >> 2; if (I810_DEBUG & DEBUG_VERBOSE_CURSOR) ErrorF("I810AdjustFrame %d,%d %x\n", x, y, flags); switch (pScrn->bitsPerPixel) { case 8: break; case 16: Base *= 2; break; case 24: /* KW: Need to do 16-pixel alignment for i810, otherwise you * get bad watermark problems. Need to fixup the mouse * pointer positioning to take this into account. */ pI810->CursorOffset = (Base & 0x3) * 4; Base &= ~0x3; Base *= 3; break; case 32: Base *= 4; break; } hwp->writeCrtc(hwp, START_ADDR_LO, Base & 0xFF); hwp->writeCrtc(hwp, START_ADDR_HI, (Base & 0xFF00) >> 8); hwp->writeCrtc(hwp, EXT_START_ADDR_HI, (Base & 0x3FC00000) >> 22); hwp->writeCrtc(hwp, EXT_START_ADDR, ((Base & 0x00eF0000) >> 16 | EXT_START_ADDR_ENABLE)); } /* These functions are usually called with the lock **not held**. */ static Bool I810EnterVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; #ifdef XF86DRI I810Ptr pI810 = I810PTR(pScrn); #endif if (I810_DEBUG & DEBUG_VERBOSE_DRI) ErrorF("\n\nENTER VT\n"); if (!I810BindGARTMemory(pScrn)) { return FALSE; } #ifdef XF86DRI if (!I810DRIEnter(pScrn)) { return FALSE; } if (pI810->directRenderingEnabled) { if (I810_DEBUG & DEBUG_VERBOSE_DRI) ErrorF("calling dri unlock\n"); DRIUnlock(screenInfo.screens[scrnIndex]); pI810->LockHeld = 0; } #endif if (!I810ModeInit(pScrn, pScrn->currentMode)) return FALSE; I810AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); return TRUE; } static void I810LeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; vgaHWPtr hwp = VGAHWPTR(pScrn); I810Ptr pI810 = I810PTR(pScrn); if (I810_DEBUG & DEBUG_VERBOSE_DRI) ErrorF("\n\n\nLeave VT\n"); #ifdef XF86DRI if (pI810->directRenderingEnabled) { if (I810_DEBUG & DEBUG_VERBOSE_DRI) ErrorF("calling dri lock\n"); DRILock(screenInfo.screens[scrnIndex], 0); pI810->LockHeld = 1; } #endif if (pI810->AccelInfoRec != NULL) { I810RefreshRing(pScrn); I810Sync(pScrn); pI810->AccelInfoRec->NeedToSync = FALSE; } I810Restore(pScrn); if (!I810UnbindGARTMemory(pScrn)) return; #ifdef XF86DRI if (!I810DRILeave(pScrn)) return; #endif vgaHWLock(hwp); } static Bool I810CloseScreen(int scrnIndex, ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; vgaHWPtr hwp = VGAHWPTR(pScrn); I810Ptr pI810 = I810PTR(pScrn); XAAInfoRecPtr infoPtr = pI810->AccelInfoRec; if (pScrn->vtSema == TRUE) { if (pI810->AccelInfoRec != NULL) { I810RefreshRing(pScrn); I810Sync(pScrn); pI810->AccelInfoRec->NeedToSync = FALSE; } I810Restore(pScrn); vgaHWLock(hwp); } #ifdef XF86DRI if (pI810->directRenderingEnabled) { I810DRICloseScreen(pScreen); pI810->directRenderingEnabled = FALSE; } #endif if (pScrn->vtSema == TRUE) { I810UnbindGARTMemory(pScrn); I810Restore(pScrn); vgaHWLock(hwp); } I810UnmapMem(pScrn); vgaHWUnmapMem(pScrn); if (pI810->ScanlineColorExpandBuffers) { xfree(pI810->ScanlineColorExpandBuffers); pI810->ScanlineColorExpandBuffers = NULL; } if (infoPtr) { if (infoPtr->ScanlineColorExpandBuffers) xfree(infoPtr->ScanlineColorExpandBuffers); XAADestroyInfoRec(infoPtr); pI810->AccelInfoRec = NULL; } if (pI810->CursorInfoRec) { xf86DestroyCursorInfoRec(pI810->CursorInfoRec); pI810->CursorInfoRec = NULL; } /* Free all allocated video ram. */ pI810->SysMem = pI810->SavedSysMem; pI810->DcacheMem = pI810->SavedDcacheMem; pI810->DoneFrontAlloc = FALSE; /* Need to actually close the gart fd, or the unbound memory will just sit * around. Will prevent the Xserver from recycling. */ xf86GARTCloseScreen(scrnIndex); xfree(pI810->LpRing); pI810->LpRing = NULL; pScrn->vtSema = FALSE; pScreen->CloseScreen = pI810->CloseScreen; return (*pScreen->CloseScreen) (scrnIndex, pScreen); } static void I810FreeScreen(int scrnIndex, int flags) { I810FreeRec(xf86Screens[scrnIndex]); if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) vgaHWFreeHWRec(xf86Screens[scrnIndex]); } static ModeStatus I810ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) { if (mode->Flags & V_INTERLACE) { if (verbose) { xf86DrvMsg(scrnIndex, X_PROBED, "Removing interlaced mode \"%s\"\n", mode->name); } return MODE_BAD; } return MODE_OK; } static Bool I810SaveScreen(ScreenPtr pScreen, Bool unblack) { return vgaHWSaveScreen(pScreen, unblack); } static void I810DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { I810Ptr pI810; unsigned char SEQ01 = 0; int DPMSSyncSelect = 0; pI810 = I810PTR(pScrn); switch (PowerManagementMode) { case DPMSModeOn: /* Screen: On; HSync: On, VSync: On */ SEQ01 = 0x00; DPMSSyncSelect = HSYNC_ON | VSYNC_ON; break; case DPMSModeStandby: /* Screen: Off; HSync: Off, VSync: On */ SEQ01 = 0x20; DPMSSyncSelect = HSYNC_OFF | VSYNC_ON; break; case DPMSModeSuspend: /* Screen: Off; HSync: On, VSync: Off */ SEQ01 = 0x20; DPMSSyncSelect = HSYNC_ON | VSYNC_OFF; break; case DPMSModeOff: /* Screen: Off; HSync: Off, VSync: Off */ SEQ01 = 0x20; DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF; break; } /* Turn the screen on/off */ SEQ01 |= pI810->readControl(pI810, SRX, 0x01) & ~0x20; pI810->writeControl(pI810, SRX, 0x01, SEQ01); /* Set the DPMS mode */ OUTREG8(DPMS_SYNC_SELECT, DPMSSyncSelect); } #endif /* I830_ONLY */