/************************************************************************** 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); static Bool I810Probe(DriverPtr drv, int flags); #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 */ _X_EXPORT DriverRec I810 = { I810_VERSION, I810_DRIVER_NAME, I810Identify, I810Probe, I810AvailableOptions, NULL, 0 }; /* *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"}, {-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}, {-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", NULL }; const char *I810driSymbols[] = { "DRICloseScreen", "DRICreateInfoRec", "DRIGetContext", "DRIDestroyInfoRec", "DRIFinishScreenInit", "DRIGetSAREAPrivate", "DRILock", "DRIQueryVersion", "DRIScreenInit", "DRIUnlock", "GlxSetVisualConfigs", "DRICreatePCIBusID", NULL }; #endif const char *I810shadowSymbols[] = { "shadowInit", "shadowSetup", "shadowAdd", "shadowRemove", "shadowUpdateRotatePacked", 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 i810VersRec = { "i810", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, I810_MAJOR_VERSION, I810_MINOR_VERSION, I810_PATCHLEVEL, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0, 0, 0, 0} }; _X_EXPORT XF86ModuleData i810ModuleData = { &i810VersRec, i810Setup, 0 }; 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, 0); /* * Tell the loader about symbols from other modules that this module * might refer to. */ LoaderRefSymLists(I810vgahwSymbols, I810fbSymbols, I810xaaSymbols, I810ramdacSymbols, #ifdef XF86DRI I810drmSymbols, I810driSymbols, I810shadowSymbols, I810shadowFBSymbols, #endif 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 = 0; } #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 = I830BIOSAvailableOptions(chipid, busid))) return pOptions; return I810Options; #else return I830BIOSAvailableOptions(chipid, busid); #endif } /* * 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) { 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, 0, 0, 0, 0, 0))) { 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: 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; } #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); pI810->PciTag = pciTag(pI810->PciInfo->bus, pI810->PciInfo->device, pI810->PciInfo->func); if (xf86RegisterResources(pI810->pEnt->index, 0, ResNone)) return FALSE; pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; /* Set pScrn->monitor */ pScrn->monitor = pScrn->confScreen->monitor; flags24 = Support24bppFb | PreferConvert32to24 | SupportConvert32to24; if (!xf86SetDepthBpp(pScrn, 0, 0, 0, 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_CONFIG, "DRI is disabled because it " "needs 2D acceleration.\n"); pI810->directRenderingDisabled=TRUE; } else if (pScrn->depth!=16) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "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, pI810->PciInfo->chipType); } 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 (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; } } xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", (unsigned long)pI810->LinearAddr); 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; } } 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. */ { unsigned long whtcfg_pamr_drp = pciReadLong(pI810->PciTag, WHTCFG_PAMR_DRP); /* 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 */ { PCITAG bridge; long smram_miscc; bridge = pciTag(0, 0, 0); /* This is always the host bridge */ smram_miscc = pciReadLong(bridge, SMRAM_MISCC); 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 !defined(__alpha__) mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; #else mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT | VIDMEM_SPARSE; #endif pI810->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, pI810->PciTag, pI810->MMIOAddr, I810_REG_SIZE); if (!pI810->MMIOBase) return FALSE; return TRUE; } static Bool I810MapMem(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); long i; for (i = 2; i < pI810->FbMapSize; i <<= 1) ; pI810->FbMapSize = i; if (!I810MapMMIO(pScrn)) return FALSE; pI810->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, pI810->PciTag, pI810->LinearAddr, pI810->FbMapSize); if (!pI810->FbBase) return FALSE; pI810->LpRing->virtual_start = pI810->FbBase + pI810->LpRing->mem.Start; return TRUE; } static void I810UnmapMMIO(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI810->MMIOBase, I810_REG_SIZE); pI810->MMIOBase = 0; } static Bool I810UnmapMem(ScrnInfoPtr pScrn) { I810Ptr pI810 = I810PTR(pScrn); xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pI810->FbBase, pI810->FbMapSize); pI810->FbBase = 0; 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; CARD32 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 */ { CARD32 LCD_TV_Control = INREG(LCD_TV_C); CARD32 TV_HTotal = INREG(LCD_TV_HTOTAL); CARD32 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, 0, 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, 0, CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } else { if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette16, 0, CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } } else { if (!xf86HandleColormaps(pScreen, 256, 8, I810LoadPalette24, 0, 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 = 0; } if (infoPtr) { if (infoPtr->ScanlineColorExpandBuffers) xfree(infoPtr->ScanlineColorExpandBuffers); XAADestroyInfoRec(infoPtr); pI810->AccelInfoRec = 0; } if (pI810->CursorInfoRec) { xf86DestroyCursorInfoRec(pI810->CursorInfoRec); pI810->CursorInfoRec = 0; } /* 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 */