/************************************************************************** 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. **************************************************************************/ /* * Authors: * Daryll Strauss * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include /* * This server does not support these XFree86 4.0 features yet * DDC1 & DDC2 (requires I2C) * shadowFb (if requested or acceleration is off) * Overlay planes * DGA */ /* * These are X and server generic header files. */ #include "xf86.h" #include "xf86_OSproc.h" #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 #include "xf86Resources.h" #include "xf86RAC.h" #endif #include "xf86cmap.h" /* If the driver uses port I/O directly, it needs: */ #include "compiler.h" /* All drivers using the vgahw module need this */ /* This driver needs to be modified to not use vgaHW for multihead operation */ #include "vgaHW.h" /* Drivers using the mi SW cursor need: */ #include "mipointer.h" /* Drivers using the mi colourmap code need: */ #include "micmap.h" #include "fb.h" /* The driver's own header file: */ #include "regionstr.h" #include "xf86xv.h" #include #include "vbe.h" #include "i740_dga.h" #include "i740.h" /* Required Functions: */ static const OptionInfoRec * I740AvailableOptions(int chipid, int busid); /* Print a driver identifying message. */ static void I740Identify(int flags); /* Identify if there is any hardware present that I know how to drive. */ static Bool I740Probe(DriverPtr drv, int flags); /* Process the config file and see if we have a valid configuration */ static Bool I740PreInit(ScrnInfoPtr pScrn, int flags); /* Initialize a screen */ static Bool I740ScreenInit(SCREEN_INIT_ARGS_DECL); /* Enter from a virtual terminal */ static Bool I740EnterVT(VT_FUNC_ARGS_DECL); /* Leave to a virtual terminal */ static void I740LeaveVT(VT_FUNC_ARGS_DECL); /* Close down each screen we initialized */ static Bool I740CloseScreen(CLOSE_SCREEN_ARGS_DECL); /* Change screensaver state */ static Bool I740SaveScreen(ScreenPtr pScreen, int mode); /* Cleanup server private data */ static void I740FreeScreen(FREE_SCREEN_ARGS_DECL); /* Check if a mode is valid on the hardware */ static ModeStatus I740ValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags); /* Switch to various Display Power Management System levels */ static void I740DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagermentMode, int flags); static void I740ProbeDDC(ScrnInfoPtr pScrn, int index); static Bool I740MapMem(ScrnInfoPtr pScrn); static Bool I740UnmapMem(ScrnInfoPtr pScrn); #define I740_VERSION 4000 #define I740_NAME "I740" #define I740_DRIVER_NAME "i740" #define I740_MAJOR_VERSION PACKAGE_VERSION_MAJOR #define I740_MINOR_VERSION PACKAGE_VERSION_MINOR #define I740_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL _X_EXPORT DriverRec I740 = { I740_VERSION, I740_DRIVER_NAME, I740Identify, I740Probe, I740AvailableOptions, NULL, 0 }; /* Chipsets */ static SymTabRec I740Chipsets[] = { { PCI_CHIP_I740_AGP, "i740 (agp)"}, { PCI_CHIP_I740_PCI, "i740 (pci)"}, { -1, NULL } }; static PciChipsets I740PciChipsets[] = { { PCI_CHIP_I740_AGP, PCI_CHIP_I740_AGP, RES_SHARED_VGA }, { PCI_CHIP_I740_PCI, PCI_CHIP_I740_PCI, RES_SHARED_VGA }, { -1, -1, RES_UNDEFINED } }; typedef enum { OPTION_NOACCEL, OPTION_SW_CURSOR, OPTION_SDRAM, OPTION_SGRAM, OPTION_SLOW_RAM, OPTION_DAC_6BIT, OPTION_USE_PIO, OPTION_VGACOMPAT } I740Opts; static const OptionInfoRec I740Options[] = { { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_SDRAM, "SDRAM", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_SGRAM, "SGRAM", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_SLOW_RAM, "SlowRam", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_DAC_6BIT, "Dac6Bit", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_USE_PIO, "UsePIO", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_VGACOMPAT, "VGACompat", OPTV_BOOLEAN, {0}, FALSE}, { -1, NULL, OPTV_NONE, {0}, FALSE} }; #ifdef XFree86LOADER static MODULESETUPPROTO(i740Setup); static XF86ModuleVersionInfo i740VersRec = { "i740", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, I740_MAJOR_VERSION, I740_MINOR_VERSION, I740_PATCHLEVEL, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0,0,0,0} }; _X_EXPORT XF86ModuleData i740ModuleData = {&i740VersRec, i740Setup, 0}; static pointer i740Setup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; /* This module should be loaded only once, but check to be sure. */ if (!setupDone) { setupDone = TRUE; xf86AddDriver(&I740, module, 0); /* * Modules that this driver always requires may be loaded here * by calling LoadSubModule(). */ /* * The return value must be non-NULL on success even though there * is no TearDownProc. */ return (pointer)1; } else { if (errmaj) *errmaj = LDR_ONCEONLY; return NULL; } } #endif /* * I740GetRec and I740FreeRec -- * * Private data for the driver is stored in the screen structure. * These two functions create and destroy that private data. * */ static Bool I740GetRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(I740Rec), 1); return TRUE; } static void I740FreeRec(ScrnInfoPtr pScrn) { if (!pScrn) return; free(pScrn->driverPrivate); pScrn->driverPrivate=0; } static const OptionInfoRec * I740AvailableOptions(int chipid, int busid) { return I740Options; } /* * I740Identify -- * * Returns the string name for the driver based on the chipset. In this * case it will always be an I740, so we can return a static string. * */ static void I740Identify(int flags) { xf86PrintChipsets(I740_NAME, "Driver for Intel i740 chipset", I740Chipsets); } /* * I740Probe -- * * Look through the PCI bus to find cards that are I740 boards. * Setup the dispatch table for the rest of the driver functions. * */ static Bool I740Probe(DriverPtr drv, int flags) { int i, numUsed, numDevSections, *usedChips; GDevPtr *devSections; Bool foundScreen = FALSE; /* Find the config file Device sections that match this driver, and return if there are none. */ if ((numDevSections = xf86MatchDevice(I740_DRIVER_NAME, &devSections))<=0) { return FALSE; } #ifndef XSERVER_LIBPCIACCESS /* Since these Probing is just checking the PCI data the server already collected. */ if (!xf86GetPciVideoInfo()) return FALSE; #endif /* Look for Intel based chips */ numUsed = xf86MatchPciInstances(I740_NAME, PCI_VENDOR_INTEL, I740Chipsets, I740PciChipsets, devSections, numDevSections, drv, &usedChips); if (numUsed > 0) { if (flags & PROBE_DETECT) foundScreen = TRUE; else for (i=0; idriverVersion = I740_VERSION; pScrn->driverName = I740_DRIVER_NAME; pScrn->name = I740_NAME; pScrn->Probe = I740Probe; pScrn->PreInit = I740PreInit; pScrn->ScreenInit = I740ScreenInit; pScrn->SwitchMode = I740SwitchMode; pScrn->AdjustFrame = I740AdjustFrame; pScrn->EnterVT = I740EnterVT; pScrn->LeaveVT = I740LeaveVT; pScrn->FreeScreen = I740FreeScreen; pScrn->ValidMode = I740ValidMode; foundScreen = TRUE; } } } /* Look for Real3D based chips */ numUsed = xf86MatchPciInstances(I740_NAME, PCI_VENDOR_REAL3D, I740Chipsets, I740PciChipsets, devSections, numDevSections, drv, &usedChips); if (numUsed > 0) { if (flags & PROBE_DETECT) foundScreen = TRUE; else for (i=0; idriverVersion = I740_VERSION; pScrn->driverName = I740_DRIVER_NAME; pScrn->name = I740_NAME; pScrn->Probe = I740Probe; pScrn->PreInit = I740PreInit; pScrn->ScreenInit = I740ScreenInit; pScrn->SwitchMode = I740SwitchMode; pScrn->AdjustFrame = I740AdjustFrame; pScrn->EnterVT = I740EnterVT; pScrn->LeaveVT = I740LeaveVT; pScrn->FreeScreen = I740FreeScreen; pScrn->ValidMode = I740ValidMode; foundScreen = TRUE; } } } free(devSections); free(usedChips); return foundScreen; } /* Ugh. Can we not do this? */ static void I740ProbeDDC(ScrnInfoPtr pScrn, int index) { vbeInfoPtr pVbe; if (xf86LoadSubModule(pScrn, "vbe")) { pVbe = VBEInit(NULL,index); ConfiguredMonitor = vbeDoEDID(pVbe, NULL); vbeFree(pVbe); } } /* * I740PreInit -- * * Do initial setup of the board before we know what resolution we will * be running at. * */ static Bool I740PreInit(ScrnInfoPtr pScrn, int flags) { I740Ptr pI740; ClockRangePtr clockRanges; int i; MessageType from; int temp; int flags24; rgb defaultWeight = {0, 0, 0}; if (pScrn->numEntities != 1) return FALSE; /* Allocate driverPrivate */ if (!I740GetRec(pScrn)) { return FALSE; } pI740 = I740PTR(pScrn); pI740->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if (pI740->pEnt->location.type != BUS_PCI) return FALSE; /*I740ProbeDDC(pScrn, pI740->pEnt->index);*/ if (flags & PROBE_DETECT) { I740ProbeDDC(pScrn, pI740->pEnt->index); return TRUE; } /* The vgahw module should be loaded here when needed */ if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE; /* Allocate a vgaHWRec */ if (!vgaHWGetHWRec(pScrn)) return FALSE; vgaHWSetStdFuncs(VGAHWPTR(pScrn)); pI740->PciInfo = xf86GetPciInfoForEntity(pI740->pEnt->index); #ifndef XSERVER_LIBPCIACCESS pI740->PciTag = pciTag(pI740->PciInfo->bus, pI740->PciInfo->device, pI740->PciInfo->func); if (xf86RegisterResources(pI740->pEnt->index, 0, ResNone)) return FALSE; if (pI740->usePIO) pScrn->racIoFlags = RAC_FB | RAC_COLORMAP; else pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; #endif /* Set pScrn->monitor */ pScrn->monitor = pScrn->confScreen->monitor; flags24=Support24bppFb | Support32bppFb | 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 i740 driver\n", pScrn->depth); return FALSE; } } /*xf86PrintDepthBpp(pScrn);*/ if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) return FALSE; if (!xf86SetDefaultVisual(pScrn, -1)) { return FALSE; } else { /* We don't currently support DirectColor at > 8bpp */ if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" " (%s) is not supported at depth %d\n", xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); return FALSE; } } /* We use a programamble clock */ pScrn->progClock = TRUE; pI740->cpp = pScrn->bitsPerPixel/8; /* Process the options */ xf86CollectOptions(pScrn, NULL); if (!(pI740->Options = malloc(sizeof(I740Options)))) return FALSE; memcpy(pI740->Options, I740Options, sizeof(I740Options)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pI740->Options); /* 6-BIT dac isn't reasonable for modes with > 8bpp */ if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE) && pScrn->bitsPerPixel>8) { OptionInfoPtr ptr; ptr=xf86TokenToOptinfo(pI740->Options, OPTION_DAC_6BIT); ptr->found=FALSE; } if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE)) pScrn->rgbBits=8; else pScrn->rgbBits=6; /* We have to use PIO to probe, because we haven't mappend yet */ I740SetPIOAccess(pI740); /* * Set the Chipset and ChipRev, allowing config file entries to * override. */ if (pI740->pEnt->device->chipset && *pI740->pEnt->device->chipset) { pScrn->chipset = pI740->pEnt->device->chipset; from = X_CONFIG; } else if (pI740->pEnt->device->chipID >= 0) { pScrn->chipset = (char *)xf86TokenToString(I740Chipsets, pI740->pEnt->device->chipID); from = X_CONFIG; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", pI740->pEnt->device->chipID); } else { from = X_PROBED; pScrn->chipset = (char *)xf86TokenToString(I740Chipsets, PCI_DEV_DEVICE_ID(pI740->PciInfo)); } if (pI740->pEnt->device->chipRev >= 0) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", pI740->pEnt->device->chipRev); } xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", (pScrn->chipset!=NULL)?pScrn->chipset:"Unknown i740"); if (pI740->pEnt->device->MemBase != 0) { pI740->LinearAddr = pI740->pEnt->device->MemBase; from = X_CONFIG; } else { if (PCI_REGION_BASE(pI740->PciInfo, 0, REGION_MEM) != 0) { pI740->LinearAddr = PCI_REGION_BASE(pI740->PciInfo, 0, REGION_MEM)&0xFF000000; from = X_PROBED; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid FB address in PCI config space\n"); I740FreeRec(pScrn); return FALSE; } } xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", pI740->LinearAddr); if (pI740->pEnt->device->IOBase != 0) { pI740->MMIOAddr = pI740->pEnt->device->IOBase; from = X_CONFIG; } else { if (PCI_REGION_BASE(pI740->PciInfo, 1, REGION_MEM)) { pI740->MMIOAddr = PCI_REGION_BASE(pI740->PciInfo, 1, REGION_MEM)&0xFFF80000; from = X_PROBED; } else { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address in PCI config space\n"); I740FreeRec(pScrn); return FALSE; } } xf86DrvMsg(pScrn->scrnIndex, from, "IO registers at addr 0x%lX\n", pI740->MMIOAddr); /* Calculate memory */ if (pI740->pEnt->device->videoRam) { pScrn->videoRam = pI740->pEnt->device->videoRam; from = X_CONFIG; } else { if ((pI740->readControl(pI740, XRX, DRAM_ROW_TYPE)&DRAM_ROW_1)==DRAM_ROW_1_SDRAM) pScrn->videoRam=pI740->readControl(pI740, XRX, DRAM_ROW_BNDRY_1); else pScrn->videoRam=pI740->readControl(pI740, XRX, DRAM_ROW_BNDRY_0); pScrn->videoRam = (pScrn->videoRam&0x0F)*1024; from = X_PROBED; } temp=pI740->readControl(pI740, XRX, DRAM_ROW_CNTL_LO); pI740->HasSGRAM = !((temp&DRAM_RAS_TIMING)||(temp&DRAM_RAS_PRECHARGE)); if (xf86IsOptionSet(pI740->Options, OPTION_SDRAM)) { if (xf86IsOptionSet(pI740->Options, OPTION_SGRAM)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "It is nonsensical to set both SDRAM and SGRAM options\n"); return FALSE; } if (xf86ReturnOptValBool(pI740->Options, OPTION_SDRAM, FALSE)) { pI740->HasSGRAM = FALSE; } else { pI740->HasSGRAM = TRUE; } } else { if (xf86IsOptionSet(pI740->Options, OPTION_SDRAM)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "It is nonsensical to set both SDRAM and SGRAM options\n"); return FALSE; } if (xf86ReturnOptValBool(pI740->Options, OPTION_SGRAM, FALSE)) { pI740->HasSGRAM = TRUE; } else { pI740->HasSGRAM = FALSE; } } xf86DrvMsg(pScrn->scrnIndex, from, "Steve was here! VideoRAM: %d kByte %s\n", pScrn->videoRam, (pI740->HasSGRAM)?"SGRAM":"SDRAM"); pI740->FbMapSize = pScrn->videoRam*1024; /* * If the driver can do gamma correction, it should call xf86SetGamma() * here. */ { Gamma zeros = {0.0, 0.0, 0.0}; if (!xf86SetGamma(pScrn, zeros)) { return FALSE; } } pI740->MaxClock = 0; if (pI740->pEnt->device->dacSpeeds[0]) { switch (pScrn->bitsPerPixel) { case 8: pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP8]; break; case 16: pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP16]; break; case 24: pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP24]; break; case 32: pI740->MaxClock = pI740->pEnt->device->dacSpeeds[DAC_BPP32]; break; } if (!pI740->MaxClock) pI740->MaxClock = pI740->pEnt->device->dacSpeeds[0]; from = X_CONFIG; } else { switch (pScrn->bitsPerPixel) { case 8: pI740->MaxClock = 203000; break; case 16: pI740->MaxClock = 163000; break; case 24: if (pI740->HasSGRAM) pI740->MaxClock = 136000; else pI740->MaxClock = 128000; break; case 32: pI740->MaxClock = 86000; } } clockRanges = xnfcalloc(sizeof(ClockRange), 1); clockRanges->next=NULL; clockRanges->minClock= 12000; /* !!! What's the min clock? !!! */ clockRanges->maxClock=pI740->MaxClock; clockRanges->clockIndex = -1; clockRanges->interlaceAllowed = FALSE; /*PL*/ clockRanges->doubleScanAllowed = TRUE; /*PL*/ { /*PL*/ if (xf86LoadSubModule(pScrn, "ddc")) { if (xf86LoadSubModule(pScrn, "i2c") ) { if (I740MapMem(pScrn)) { if (I740_I2CInit(pScrn)) { xf86MonPtr MonInfo; if ((MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn),pI740->rc_i2c))) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DDC Monitor info: %p\n", MonInfo); xf86PrintEDID( MonInfo ); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "end of DDC Monitor " "info\n\n"); xf86SetDDCproperties(pScrn,MonInfo); } } else xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n"); I740UnmapMem(pScrn); } } } } i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, 0, 320, 1600, 8, 200, 1200, pScrn->display->virtualX, pScrn->display->virtualY, pI740->FbMapSize, LOOKUP_BEST_REFRESH); if (i==-1) { I740FreeRec(pScrn); return FALSE; } xf86PruneDriverModes(pScrn); if (!i || !pScrn->modes) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); I740FreeRec(pScrn); return FALSE; } xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); pScrn->currentMode = pScrn->modes; xf86PrintModes(pScrn); xf86SetDpi(pScrn, 0, 0); if (!xf86LoadSubModule(pScrn, "fb")) { I740FreeRec(pScrn); return FALSE; } pI740->NoAccel = xf86ReturnOptValBool(pI740->Options, OPTION_NOACCEL, FALSE); if (!pI740->NoAccel) { if (!xf86LoadSubModule(pScrn, "xaa")) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No acceleration available\n"); pI740->NoAccel = 1; } } if (!xf86ReturnOptValBool(pI740->Options, OPTION_SW_CURSOR, FALSE)) { if (!xf86LoadSubModule(pScrn, "ramdac")) { I740FreeRec(pScrn); return FALSE; } } /* We wont be using the VGA access after the probe */ if (!xf86ReturnOptValBool(pI740->Options, OPTION_USE_PIO, FALSE)) { #ifndef XSERVER_LIBPCIACCESS resRange vgaio[] = { {ResShrIoBlock,0x3B0,0x3BB}, {ResShrIoBlock,0x3C0,0x3DF}, _END }; resRange vgamem[] = {{ResShrMemBlock,0xA0000,0xAFFFF}, {ResShrMemBlock,0xB8000,0xBFFFF}, {ResShrMemBlock,0xB0000,0xB7FFF}, _END }; #endif pI740->usePIO=FALSE; I740SetMMIOAccess(pI740); #ifndef XSERVER_LIBPCIACCESS xf86SetOperatingState(vgaio, pI740->pEnt->index, ResUnusedOpr); xf86SetOperatingState(vgamem, pI740->pEnt->index, ResDisableOpr); #endif } else { pI740->usePIO=TRUE; } if(xf86IsOptionSet(pI740->Options, OPTION_VGACOMPAT)) pI740->usevgacompat=TRUE; else pI740->usevgacompat=FALSE; { /* Overlay */ pI740->colorKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) | (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue); pI740->colorKey &= ((1 << pScrn->depth) - 1); xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video overlay key set to 0x%x\n", pI740->colorKey); } return TRUE; } static Bool I740MapMem(ScrnInfoPtr pScrn) { #ifndef XSERVER_LIBPCIACCESS int mmioFlags; #endif I740Ptr pI740; pI740 = I740PTR(pScrn); #ifndef XSERVER_LIBPCIACCESS mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; pI740->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, pI740->PciTag, pI740->MMIOAddr, 0x80000); #else { void** result = (void**)&pI740->MMIOBase; int err = pci_device_map_range(pI740->PciInfo, pI740->MMIOAddr, 0x80000, PCI_DEV_MAP_FLAG_WRITABLE, result); if (err) return FALSE; } #endif if (!pI740->MMIOBase) return FALSE; #ifndef XSERVER_LIBPCIACCESS pI740->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, pI740->PciTag, pI740->LinearAddr, pI740->FbMapSize); #else { void** result = (void**)&pI740->FbBase; int err = pci_device_map_range(pI740->PciInfo, pI740->LinearAddr, pI740->FbMapSize, PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE, result); if (err) return FALSE; } #endif if (!pI740->FbBase) return FALSE; return TRUE; } static Bool I740UnmapMem(ScrnInfoPtr pScrn) { I740Ptr pI740; pI740 = I740PTR(pScrn); #ifndef XSERVER_LIBPCIACCESS xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pI740->MMIOBase, 0x80000); #else pci_device_unmap_range(pI740->PciInfo, pI740->MMIOBase, 0x80000); #endif pI740->MMIOBase=0; #ifndef XSERVER_LIBPCIACCESS xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pI740->FbBase, pI740->FbMapSize); #else pci_device_unmap_range(pI740->PciInfo, pI740->FbBase, pI740->FbMapSize); #endif pI740->FbBase = 0; return TRUE; } /* * I740Save -- * * This function saves the video state. It reads all of the SVGA registers * into the vgaI740Rec data structure. There is in general no need to * mask out bits here - just read the registers. */ static void DoSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I740RegPtr i740Reg, Bool saveFonts) { I740Ptr pI740; vgaHWPtr hwp; pI740 = I740PTR(pScrn); hwp = VGAHWPTR(pScrn); /* * This function will handle creating the data structure and filling * in the generic VGA portion. */ if (saveFonts) vgaHWSave(pScrn, vgaReg, VGA_SR_MODE|VGA_SR_FONTS); else vgaHWSave(pScrn, vgaReg, VGA_SR_MODE); /* * The port I/O code necessary to read in the extended registers * into the fields of the vgaI740Rec structure goes here. */ i740Reg->IOControl = pI740->readControl(pI740, XRX, IO_CTNL); i740Reg->AddressMapping = pI740->readControl(pI740, XRX, ADDRESS_MAPPING); i740Reg->BitBLTControl = pI740->readControl(pI740, XRX, BITBLT_CNTL); i740Reg->VideoClk2_M = pI740->readControl(pI740, XRX, VCLK2_VCO_M); i740Reg->VideoClk2_N = pI740->readControl(pI740, XRX, VCLK2_VCO_N); i740Reg->VideoClk2_MN_MSBs = pI740->readControl(pI740, XRX, VCLK2_VCO_MN_MSBS); i740Reg->VideoClk2_DivisorSel = pI740->readControl(pI740, XRX, VCLK2_VCO_DIV_SEL); i740Reg->PLLControl = pI740->readControl(pI740, XRX, PLL_CNTL); i740Reg->ExtVertTotal=hwp->readCrtc(hwp, EXT_VERT_TOTAL); i740Reg->ExtVertDispEnd=hwp->readCrtc(hwp, EXT_VERT_DISPLAY); i740Reg->ExtVertSyncStart=hwp->readCrtc(hwp, EXT_VERT_SYNC_START); i740Reg->ExtVertBlankStart=hwp->readCrtc(hwp, EXT_VERT_BLANK_START); i740Reg->ExtHorizTotal=hwp->readCrtc(hwp, EXT_HORIZ_TOTAL); i740Reg->ExtHorizBlank=hwp->readCrtc(hwp, EXT_HORIZ_BLANK); i740Reg->ExtOffset=hwp->readCrtc(hwp, EXT_OFFSET); i740Reg->InterlaceControl=hwp->readCrtc(hwp, INTERLACE_CNTL); i740Reg->PixelPipeCfg0 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); i740Reg->PixelPipeCfg1 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_1); i740Reg->PixelPipeCfg2 = pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_2); i740Reg->DisplayControl = pI740->readControl(pI740, XRX, DISPLAY_CNTL); i740Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC); } static void I740Save(ScrnInfoPtr pScrn) { vgaHWPtr hwp; I740Ptr pI740; hwp = VGAHWPTR(pScrn); pI740 = I740PTR(pScrn); DoSave(pScrn, &hwp->SavedReg, &pI740->SavedReg, TRUE); } static void DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, I740RegPtr i740Reg, Bool restoreFonts) { I740Ptr pI740; vgaHWPtr hwp; unsigned char temp; unsigned int itemp; pI740 = I740PTR(pScrn); hwp = VGAHWPTR(pScrn); vgaHWProtect(pScrn, TRUE); #if 0 temp=hwp->readCrtc(hwp, VERT_SYNC_END); hwp->writeCrtc(hwp, VERT_SYNC_END, temp&0x7F); #endif temp = pI740->readControl(pI740, MRX, ACQ_CNTL_2); if ((temp & FRAME_CAP_MODE) == SINGLE_CAP_MODE) { temp=pI740->readControl(pI740, MRX, COL_KEY_CNTL_1); temp |= BLANK_DISP_OVERLAY; /* Disable the overlay */ pI740->writeControl(pI740, MRX, COL_KEY_CNTL_1, temp); } else { temp &= ~FRAME_CAP_MODE; pI740->writeControl(pI740, MRX, ACQ_CNTL_2, temp); } usleep(50000); /* Turn off DRAM Refresh */ pI740->writeControl(pI740, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE); usleep(1000); /* Wait 1 ms */ /* Write the M, N and P values */ pI740->writeControl(pI740, XRX, VCLK2_VCO_M, i740Reg->VideoClk2_M); pI740->writeControl(pI740, XRX, VCLK2_VCO_N, i740Reg->VideoClk2_N); pI740->writeControl(pI740, XRX, VCLK2_VCO_MN_MSBS, i740Reg->VideoClk2_MN_MSBs); pI740->writeControl(pI740, XRX, VCLK2_VCO_DIV_SEL, i740Reg->VideoClk2_DivisorSel); /* * Turn on 8 bit dac mode, if requested. This is needed to make * sure that vgaHWRestore writes the values into the DAC properly. * The problem occurs if 8 bit dac mode is requested and the HW is * in 6 bit dac mode. If this happens, all the values are * automatically shifted left twice by the HW and incorrect colors * will be displayed on the screen. The only time this can happen * is at server startup time and when switching back from a VT. */ temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); temp &= 0x7F; /* Save all but the 8 bit dac mode bit */ temp |= (i740Reg->PixelPipeCfg0 & DAC_8_BIT); pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, temp); /* * Code to restore any SVGA registers that have been saved/modified * goes here. Note that it is allowable, and often correct, to * only modify certain bits in a register by a read/modify/write cycle. * * A special case - when using an external clock-setting program, * this function must not change bits associated with the clock * selection. This condition can be checked by the condition: * * if (restore->std.NoClock >= 0) * restore clock-select bits. */ if (restoreFonts) vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS|VGA_SR_MODE); else vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE); hwp->writeCrtc(hwp, EXT_VERT_TOTAL, i740Reg->ExtVertTotal); hwp->writeCrtc(hwp, EXT_VERT_DISPLAY, i740Reg->ExtVertDispEnd); hwp->writeCrtc(hwp, EXT_VERT_SYNC_START, i740Reg->ExtVertSyncStart); hwp->writeCrtc(hwp, EXT_VERT_BLANK_START, i740Reg->ExtVertBlankStart); hwp->writeCrtc(hwp, EXT_HORIZ_TOTAL, i740Reg->ExtHorizTotal); hwp->writeCrtc(hwp, EXT_HORIZ_BLANK, i740Reg->ExtHorizBlank); hwp->writeCrtc(hwp, EXT_OFFSET, i740Reg->ExtOffset); temp=hwp->readCrtc(hwp, INTERLACE_CNTL); temp &= ~INTERLACE_ENABLE; temp |= i740Reg->InterlaceControl; hwp->writeCrtc(hwp, INTERLACE_CNTL, temp); temp=pI740->readControl(pI740, XRX, ADDRESS_MAPPING); temp &= 0xE0; /* Save reserved bits 7:5 */ temp |= i740Reg->AddressMapping; pI740->writeControl(pI740, XRX, ADDRESS_MAPPING, temp); temp=pI740->readControl(pI740, XRX, BITBLT_CNTL); temp &= ~COLEXP_MODE; temp |= i740Reg->BitBLTControl; pI740->writeControl(pI740, XRX, BITBLT_CNTL, temp); temp=pI740->readControl(pI740, XRX, DISPLAY_CNTL); temp &= ~(VGA_WRAP_MODE | GUI_MODE); temp |= i740Reg->DisplayControl; pI740->writeControl(pI740, XRX, DISPLAY_CNTL, temp); temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_0); temp &= 0x64; /* Save reserved bits 6:5,2 */ temp |= i740Reg->PixelPipeCfg0; pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_0, temp); temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_2); temp &= 0xF3; /* Save reserved bits 7:4,1:0 */ temp |= i740Reg->PixelPipeCfg2; pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_2, temp); temp=pI740->readControl(pI740, XRX, PLL_CNTL); temp = i740Reg->PLLControl; /* To fix the 2.3X BIOS problem */ pI740->writeControl(pI740, XRX, PLL_CNTL, temp); temp=pI740->readControl(pI740, XRX, PIXPIPE_CONFIG_1); temp &= ~DISPLAY_COLOR_MODE; temp |= i740Reg->PixelPipeCfg1; pI740->writeControl(pI740, XRX, PIXPIPE_CONFIG_1, temp); itemp = INREG(FWATER_BLC); itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK); itemp |= i740Reg->LMI_FIFO_Watermark; OUTREG(FWATER_BLC, itemp); /* Turn on DRAM Refresh */ pI740->writeControl(pI740, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ); temp=pI740->readControl(pI740, MRX, COL_KEY_CNTL_1); temp &= ~BLANK_DISP_OVERLAY; /* Re-enable the overlay */ pI740->writeControl(pI740, MRX, COL_KEY_CNTL_1, temp); if (!(vgaReg->Attribute[0x10] & 0x1)) { usleep(50000); if (restoreFonts) vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS|VGA_SR_MODE); else vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE); } vgaHWProtect(pScrn, FALSE); temp=pI740->readControl(pI740, XRX, IO_CTNL); temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL); temp |= i740Reg->IOControl; pI740->writeControl(pI740, XRX, IO_CTNL, temp); #if 0 temp=hwp->readCrtc(hwp, VERT_SYNC_END); hwp->writeCrtc(hwp, VERT_SYNC_END, temp|0x80); #endif } static void I740Restore(ScrnInfoPtr pScrn) { vgaHWPtr hwp; I740Ptr pI740; hwp = VGAHWPTR(pScrn); pI740 = I740PTR(pScrn); DoRestore(pScrn, &hwp->SavedReg, &pI740->SavedReg, TRUE); } /* * I740CalcFIFO -- * * Calculate burst length and FIFO watermark. */ static unsigned int I740CalcFIFO(ScrnInfoPtr pScrn, double freq) { unsigned int wm = 0x18120000; I740Ptr pI740; pI740 = I740PTR(pScrn); /* * Would like to calculate these values automatically, but a generic * algorithm does not seem possible. Note: These FIFO water mark * values were tested on several cards and seem to eliminate the * all of the snow and vertical banding, but fine adjustments will * probably be required for other cards. */ switch (pScrn->bitsPerPixel) { case 8: if (pI740->HasSGRAM) { if (freq > 200) wm = 0x18120000; else if (freq > 175) wm = 0x16110000; else if (freq > 135) wm = 0x120E0000; else wm = 0x100D0000; } else { if (freq > 200) wm = 0x18120000; else if (freq > 175) wm = 0x16110000; else if (freq > 135) wm = 0x120E0000; else wm = 0x100D0000; } break; case 16: if (pI740->HasSGRAM) { if (freq > 140) wm = 0x2C1D0000; else if (freq > 120) wm = 0x2C180000; else if (freq > 100) wm = 0x24160000; else if (freq > 90) wm = 0x18120000; else if (freq > 50) wm = 0x16110000; else if (freq > 32) wm = 0x13100000; else wm = 0x120E0000; } else { if (freq > 160) wm = 0x28200000; else if (freq > 140) wm = 0x2A1E0000; else if (freq > 130) wm = 0x2B1A0000; else if (freq > 120) wm = 0x2C180000; else if (freq > 100) wm = 0x24180000; else if (freq > 90) wm = 0x18120000; else if (freq > 50) wm = 0x16110000; else if (freq > 32) wm = 0x13100000; else wm = 0x120E0000; } break; case 24: if (pI740->HasSGRAM) { if (freq > 130) wm = 0x31200000; else if (freq > 120) wm = 0x2E200000; else if (freq > 100) wm = 0x2C1D0000; else if (freq > 80) wm = 0x25180000; else if (freq > 64) wm = 0x24160000; else if (freq > 49) wm = 0x18120000; else if (freq > 32) wm = 0x16110000; else wm = 0x13100000; } else { if (freq > 120) wm = 0x311F0000; else if (freq > 100) wm = 0x2C1D0000; else if (freq > 80) wm = 0x25180000; else if (freq > 64) wm = 0x24160000; else if (freq > 49) wm = 0x18120000; else if (freq > 32) wm = 0x16110000; else wm = 0x13100000; } break; case 32: if (pI740->HasSGRAM) { if (freq > 80) wm = 0x2A200000; else if (freq > 60) wm = 0x281A0000; else if (freq > 49) wm = 0x25180000; else if (freq > 32) wm = 0x18120000; else wm = 0x16110000; } else { if (freq > 80) wm = 0x29200000; else if (freq > 60) wm = 0x281A0000; else if (freq > 49) wm = 0x25180000; else if (freq > 32) wm = 0x18120000; else wm = 0x16110000; } break; } return wm; } /* * I740CalcVCLK -- * * Determine the closest clock frequency to the one requested. */ #define MAX_VCO_FREQ 450.0 #define TARGET_MAX_N 30 #define REF_FREQ 66.66666666667 #define CALC_VCLK(m,n,p,d) \ (double)m / ((double)n * (1 << p)) * (4 << (d << 1)) * REF_FREQ static void I740CalcVCLK(ScrnInfoPtr pScrn, double freq) { I740Ptr pI740; I740RegPtr i740Reg; int m, n, p, d; double f_out; double f_err; double f_vco; int m_best = 0, n_best = 0, p_best = 0, d_best = 0; double f_target = freq; double err_max = 0.005; double err_target = 0.001; double err_best = 999999.0; pI740 = I740PTR(pScrn); i740Reg = &pI740->ModeReg; p_best = p = log(MAX_VCO_FREQ/f_target)/log((double)2); d_best = d = 0; f_vco = f_target * (1 << p); n = 2; do { n++; m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5; if (m < 3) m = 3; f_out = CALC_VCLK(m,n,p,d); f_err = 1.0 - (f_target/f_out); if (fabs(f_err) < err_max) { m_best = m; n_best = n; err_best = f_err; } } while ((fabs(f_err) >= err_target) && ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max))); if (fabs(f_err) < err_target) { m_best = m; n_best = n; } i740Reg->VideoClk2_M = (m_best-2) & 0xFF; i740Reg->VideoClk2_N = (n_best-2) & 0xFF; i740Reg->VideoClk2_MN_MSBs = ((((n_best-2) >> 4) & VCO_N_MSBS) | (((m_best-2) >> 8) & VCO_M_MSBS)); i740Reg->VideoClk2_DivisorSel = ((p_best << 4) | (d_best ? 4 : 0) | REF_DIV_1); } static Bool I740SetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) { I740Ptr pI740; I740RegPtr i740Reg; vgaRegPtr pVga; double dclk = mode->Clock/1000.0; pI740 = I740PTR(pScrn); i740Reg = &pI740->ModeReg; pVga = &VGAHWPTR(pScrn)->ModeReg; switch (pScrn->bitsPerPixel) { case 8: pVga->CRTC[0x13] = pScrn->displayWidth >> 3; i740Reg->ExtOffset = pScrn->displayWidth >> 11; i740Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE; i740Reg->BitBLTControl = COLEXP_8BPP; break; case 16: if (pScrn->weight.green == 5) { i740Reg->PixelPipeCfg1 = DISPLAY_15BPP_MODE; } else { i740Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE; } pVga->CRTC[0x13] = pScrn->displayWidth >> 2; i740Reg->ExtOffset = pScrn->displayWidth >> 10; i740Reg->BitBLTControl = COLEXP_16BPP; break; case 24: pVga->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3; i740Reg->ExtOffset = (pScrn->displayWidth * 3) >> 11; i740Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE; i740Reg->BitBLTControl = COLEXP_24BPP; break; case 32: pVga->CRTC[0x13] = pScrn->displayWidth >> 1; i740Reg->ExtOffset = pScrn->displayWidth >> 9; i740Reg->PixelPipeCfg1 = DISPLAY_32BPP_MODE; i740Reg->BitBLTControl = COLEXP_RESERVED; /* Not implemented on i740 */ break; default: break; } /* Turn on 8 bit dac if requested */ if (xf86ReturnOptValBool(pI740->Options, OPTION_DAC_6BIT, FALSE)) i740Reg->PixelPipeCfg0 = DAC_6_BIT; else i740Reg->PixelPipeCfg0 = DAC_8_BIT; i740Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE /*| OVERLAY_GAMMA_ENABLE*/; /* Turn on Extended VGA Interpretation */ i740Reg->IOControl = EXTENDED_CRTC_CNTL; /* Turn on linear and page mapping */ i740Reg->AddressMapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE; /* Turn on GUI mode */ i740Reg->DisplayControl = HIRES_MODE; /* Set the MCLK freq */ if (xf86ReturnOptValBool(pI740->Options, OPTION_SLOW_RAM, FALSE)) i740Reg->PLLControl = PLL_MEMCLK__66667KHZ; /* 66 MHz */ else i740Reg->PLLControl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */ /* Calculate the extended CRTC regs */ i740Reg->ExtVertTotal = (mode->CrtcVTotal - 2) >> 8; i740Reg->ExtVertDispEnd = (mode->CrtcVDisplay - 1) >> 8; i740Reg->ExtVertSyncStart = mode->CrtcVSyncStart >> 8; i740Reg->ExtVertBlankStart = mode->CrtcVBlankStart >> 8; i740Reg->ExtHorizTotal = ((mode->CrtcHTotal >> 3) - 5) >> 8; /* * the KGA fix in vgaHW.c results in the first * scanline and the first character clock (8 pixels) * of each scanline thereafter on display with an i740 * to be blank. Restoring CRTC 3, 5, & 22 to their * "theoretical" values corrects the problem. KAO. */ i740Reg->ExtHorizBlank = vgaHWHBlankKGA(mode, pVga, 7, 0) << 6; vgaHWVBlankKGA(mode, pVga, 8, 0); /* Turn on interlaced mode if necessary */ if (mode->Flags & V_INTERLACE) i740Reg->InterlaceControl = INTERLACE_ENABLE; else i740Reg->InterlaceControl = INTERLACE_DISABLE; /* * Set the overscan color to 0. * NOTE: This only affects >8bpp mode. */ pVga->Attribute[0x11] = 0; /* * Calculate the VCLK that most closely matches the requested dot * clock. */ I740CalcVCLK(pScrn, dclk); /* Since we program the clocks ourselves, always use VCLK2. */ pVga->MiscOutReg |= 0x0C; /* Calculate the FIFO Watermark and Burst Length. */ i740Reg->LMI_FIFO_Watermark = I740CalcFIFO(pScrn, dclk); /*-Overlay-*/ pI740->ov_offset_x=((mode->CrtcHTotal-mode->CrtcHDisplay) & ~7)-9; pI740->ov_offset_y=mode->CrtcVTotal-mode->CrtcVSyncEnd-2; /*-*/ return TRUE; } static Bool I740ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode_src) { vgaHWPtr hwp; I740Ptr pI740; struct _DisplayModeRec mode_dst; DisplayModePtr mode=&mode_dst; *mode=*mode_src; hwp = VGAHWPTR(pScrn); pI740 = I740PTR(pScrn); vgaHWUnlock(hwp); if(pI740->usevgacompat) { /* Try to get the same visual aspect as a S3 board */ mode->CrtcHSyncStart+=16; mode->CrtcHSyncEnd +=16; } if (!vgaHWInit(pScrn, mode)) return FALSE; pScrn->vtSema = TRUE; if (!I740SetMode(pScrn, mode)) return FALSE; DoRestore(pScrn, &hwp->ModeReg, &pI740->ModeReg, FALSE); return TRUE; } static void I740LoadPalette15(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { vgaHWPtr hwp; int i, index; unsigned char r, g, b; hwp = VGAHWPTR(pScrn); for (i=0; iwriteDacWriteAddr(hwp, index<<2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); i++; hwp->writeDacWriteAddr(hwp, index<<2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); } } static void I740LoadPalette16(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { vgaHWPtr hwp; int i, index; unsigned char r, g, b; hwp = VGAHWPTR(pScrn); for (i=0; iwriteDacWriteAddr(hwp, index<<2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); i++; index=indices[i]; g=colors[index].green; hwp->writeDacWriteAddr(hwp, index<<2); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); } } static void I740LoadPalette24(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { vgaHWPtr hwp; int i, index; unsigned char r, g, b; hwp = VGAHWPTR(pScrn); for (i=0; iwriteDacWriteAddr(hwp, index); hwp->writeDacData(hwp, r); hwp->writeDacData(hwp, g); hwp->writeDacData(hwp, b); } } static Bool I740ScreenInit(SCREEN_INIT_ARGS_DECL) { ScrnInfoPtr pScrn; vgaHWPtr hwp; I740Ptr pI740; VisualPtr visual; pScrn = xf86ScreenToScrn(pScreen); pI740 = I740PTR(pScrn); hwp = VGAHWPTR(pScrn); if (!I740MapMem(pScrn)) return FALSE; pScrn->memPhysBase = pI740->LinearAddr; pScrn->fbOffset = 0; if (!pI740->usePIO) vgaHWSetMmioFuncs(hwp, pI740->MMIOBase, 0); vgaHWGetIOBase(hwp); if (!vgaHWMapMem(pScrn)) return FALSE; I740Save(pScrn); if (!I740ModeInit(pScrn, pScrn->currentMode)) return FALSE; I740SaveScreen(pScreen, SCREEN_SAVER_ON); I740AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0)); miClearVisualTypes(); if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; if (!miSetPixmapDepths ()) return FALSE; switch (pScrn->bitsPerPixel) { case 8: case 16: case 24: case 32: if (!fbScreenInit(pScreen, pI740->FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,pScrn->bitsPerPixel)) return FALSE; break; default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) in I740ScrnInit\n", pScrn->bitsPerPixel); return FALSE; } fbPictureInit(pScreen,0,0); xf86SetBlackWhitePixels(pScreen); memset(&(pI740->FbMemBox), 0, sizeof(BoxRec)); pI740->FbMemBox.x1=0; pI740->FbMemBox.x2=pScrn->displayWidth; pI740->FbMemBox.y1=0; pI740->FbMemBox.y2=pI740->FbMapSize/(pScrn->displayWidth*pI740->cpp); I740DGAInit(pScreen); if (!xf86InitFBManager(pScreen, &pI740->FbMemBox)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to init memory manager\n"); return FALSE; } if (!pI740->NoAccel) { if (!I740AccelInit(pScreen)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware acceleration initialization failed\n"); } } if (pScrn->bitsPerPixel>8) { visual = pScreen->visuals + pScreen->numVisuals; while (--visual >= pScreen->visuals) { if ((visual->class | DynamicClass) == DirectColor) { visual->offsetRed = pScrn->offset.red; visual->offsetGreen = pScrn->offset.green; visual->offsetBlue = pScrn->offset.blue; visual->redMask = pScrn->mask.red; visual->greenMask = pScrn->mask.green; visual->blueMask = pScrn->mask.blue; } } } xf86SetBackingStore(pScreen); xf86SetSilkenMouse(pScreen); miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); if (!xf86ReturnOptValBool(pI740->Options, OPTION_SW_CURSOR, FALSE)) { if (!I740CursorInit(pScreen)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor initialization failed\n"); } } if (!miCreateDefColormap(pScreen)) return FALSE; if (pScrn->bitsPerPixel==16) { if (pScrn->weight.green == 5) { if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette15, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } else { if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette16, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } } else { if (!xf86HandleColormaps(pScreen, 256, 8, I740LoadPalette24, 0, CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; } xf86DPMSInit(pScreen, I740DisplayPowerManagementSet, 0); pScreen->SaveScreen = I740SaveScreen; pI740->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = I740CloseScreen; if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); /* Overlay */ I740InitVideo(pScreen); pI740->OverlayStart = pI740->CursorStart + 1024; return TRUE; } Bool I740SwitchMode(SWITCH_MODE_ARGS_DECL) { SCRN_INFO_PTR(arg); return I740ModeInit(pScrn, mode); } void I740AdjustFrame(ADJUST_FRAME_ARGS_DECL) { SCRN_INFO_PTR(arg); int Base; vgaHWPtr hwp; hwp = VGAHWPTR(pScrn); Base = (y * pScrn->displayWidth + x) >> 2; switch (pScrn->bitsPerPixel) { case 8: break; case 16: Base *= 2; break; case 24: /* * The last bit does not seem to have any effect on the start * address register in 24bpp mode, so... */ Base &= 0xFFFFFFFE; /* ...ignore the last bit. */ Base *= 3; break; case 32: Base *= 4; break; } hwp->writeCrtc(hwp, START_ADDR_LO, Base&0xFF); hwp->writeCrtc(hwp, START_ADDR_HI, (Base&0xFF00)>>8); hwp->writeCrtc(hwp, EXT_START_ADDR_HI, (Base&0x3FC00000)>>22); hwp->writeCrtc(hwp, EXT_START_ADDR, ((Base&0x00eF0000)>>16|EXT_START_ADDR_ENABLE)); } static Bool I740EnterVT(VT_FUNC_ARGS_DECL) { SCRN_INFO_PTR(arg); if (!I740ModeInit(pScrn, pScrn->currentMode)) return FALSE; I740AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0)); return TRUE; } static void I740LeaveVT(VT_FUNC_ARGS_DECL) { SCRN_INFO_PTR(arg); vgaHWPtr hwp; hwp=VGAHWPTR(pScrn); I740Restore(pScrn); vgaHWLock(hwp); } static Bool I740CloseScreen(CLOSE_SCREEN_ARGS_DECL) { ScrnInfoPtr pScrn; vgaHWPtr hwp; I740Ptr pI740; pScrn = xf86ScreenToScrn(pScreen); hwp = VGAHWPTR(pScrn); pI740 = I740PTR(pScrn); if (pScrn->vtSema) { I740Restore(pScrn); vgaHWLock(hwp); } I740UnmapMem(pScrn); vgaHWUnmapMem(pScrn); #ifdef HAVE_XAA_H if (pI740->AccelInfoRec) XAADestroyInfoRec(pI740->AccelInfoRec); pI740->AccelInfoRec=0; #endif if (pI740->CursorInfoRec) xf86DestroyCursorInfoRec(pI740->CursorInfoRec); pI740->CursorInfoRec=0; pScrn->vtSema=FALSE; pScreen->CloseScreen = pI740->CloseScreen; return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS); } static void I740FreeScreen(FREE_SCREEN_ARGS_DECL) { SCRN_INFO_PTR(arg); I740FreeRec(pScrn); if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) vgaHWFreeHWRec(pScrn); } static ModeStatus I740ValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags) { SCRN_INFO_PTR(arg); if (mode->Flags & V_INTERLACE) { if (verbose) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Removing interlaced mode \"%s\"\n", mode->name); } return MODE_BAD; } return MODE_OK; } static Bool I740SaveScreen(ScreenPtr pScreen, int mode) { #if 0 Bool unblack = xf86IsUnblank(mode); if (unblack) outw(SRX, 0x0300); else outw(SRX, 0x0100); #endif return vgaHWSaveScreen(pScreen, mode); } static void I740DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { I740Ptr pI740; unsigned char SEQ01=0; int DPMSSyncSelect=0; pI740 = I740PTR(pScrn); switch (PowerManagementMode) { case DPMSModeOn: /* Screen: On; HSync: On, VSync: On */ SEQ01 = 0x00; DPMSSyncSelect = HSYNC_ON | VSYNC_ON; break; case DPMSModeStandby: /* Screen: Off; HSync: Off, VSync: On */ SEQ01 = 0x20; DPMSSyncSelect = HSYNC_OFF | VSYNC_ON; break; case DPMSModeSuspend: /* Screen: Off; HSync: On, VSync: Off */ SEQ01 = 0x20; DPMSSyncSelect = HSYNC_ON | VSYNC_OFF; break; case DPMSModeOff: /* Screen: Off; HSync: Off, VSync: Off */ SEQ01 = 0x20; DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF; break; } /* Turn the screen on/off */ SEQ01 |= pI740->readControl(pI740, SRX, 0x01) & ~0x20; pI740->writeControl(pI740, SRX, 0x01, SEQ01); /* Set the DPMS mode */ pI740->writeControl(pI740, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect); }