tseng_driver.c revision d03ff4ac
1d983712dSmrg/* 2d983712dSmrg * 3d983712dSmrg * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 4d983712dSmrg * 5d983712dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 6d983712dSmrg * documentation for any purpose is hereby granted without fee, provided that 7d983712dSmrg * the above copyright notice appear in all copies and that both that 8d983712dSmrg * copyright notice and this permission notice appear in supporting 9d983712dSmrg * documentation, and that the name of Thomas Roell not be used in 10d983712dSmrg * advertising or publicity pertaining to distribution of the software without 11d983712dSmrg * specific, written prior permission. Thomas Roell makes no representations 12d983712dSmrg * about the suitability of this software for any purpose. It is provided 13d983712dSmrg * "as is" without express or implied warranty. 14d983712dSmrg * 15d983712dSmrg * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16d983712dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17d983712dSmrg * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18d983712dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19d983712dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20d983712dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21d983712dSmrg * PERFORMANCE OF THIS SOFTWARE. 22d983712dSmrg * 23d983712dSmrg * Author: Thomas Roell, roell@informatik.tu-muenchen.de 24d983712dSmrg * ET6000 and ET4000W32 16/24/32 bpp and acceleration support by Koen Gadeyne 25d983712dSmrg * 26d983712dSmrg * Large parts rewritten for XFree86 4.0 by Koen Gadeyne. 27d983712dSmrg */ 28d983712dSmrg 29d983712dSmrg#ifdef HAVE_CONFIG_H 30d983712dSmrg#include "config.h" 31d983712dSmrg#endif 32d983712dSmrg 33d983712dSmrg/*** Generic includes ***/ 34d983712dSmrg 35d983712dSmrg#include "tseng.h" /* this includes most of the generic ones as well */ 36d983712dSmrg 37d983712dSmrg/* All drivers initialising the SW cursor need this */ 38d983712dSmrg#include "mipointer.h" 39d983712dSmrg 40d983712dSmrg/* All drivers implementing backing store need this */ 41d983712dSmrg#include "mibstore.h" 42d983712dSmrg 43d983712dSmrg#include "fb.h" 44d983712dSmrg 45d03ff4acSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 46d983712dSmrg#include "xf86RAC.h" 47d983712dSmrg#include "xf86Resources.h" 48d03ff4acSmrg#endif 49d983712dSmrg#include "xf86int10.h" 50d983712dSmrg 51d983712dSmrg#include "xf86xv.h" 52d983712dSmrg#include <X11/extensions/Xv.h> 53d983712dSmrg 54d983712dSmrg/* 55d983712dSmrg * Forward definitions for the functions that make up the driver. 56d983712dSmrg */ 57d983712dSmrg 58d983712dSmrg/* Mandatory functions */ 59d983712dSmrgstatic const OptionInfoRec * TsengAvailableOptions(int chipid, int busid); 60d983712dSmrgstatic void TsengIdentify(int flags); 61d983712dSmrgstatic Bool TsengProbe(DriverPtr drv, int flags); 62d983712dSmrgstatic Bool TsengPreInit(ScrnInfoPtr pScrn, int flags); 63d983712dSmrgstatic Bool TsengScreenInit(int Index, ScreenPtr pScreen, int argc, 64d983712dSmrg char **argv); 65d983712dSmrgstatic Bool TsengEnterVT(int scrnIndex, int flags); 66d983712dSmrgstatic void TsengLeaveVT(int scrnIndex, int flags); 67d983712dSmrgstatic Bool TsengCloseScreen(int scrnIndex, ScreenPtr pScreen); 68d983712dSmrgstatic Bool TsengSaveScreen(ScreenPtr pScreen, int mode); 69d983712dSmrg 70d983712dSmrg/* Required if the driver supports mode switching */ 71d983712dSmrgstatic Bool TsengSwitchMode(int scrnIndex, DisplayModePtr mode, int flags); 72d983712dSmrg 73d983712dSmrg/* Optional functions */ 74d983712dSmrgstatic void TsengFreeScreen(int scrnIndex, int flags); 75d983712dSmrg 76d983712dSmrg/* If driver-specific config file entries are needed, this must be defined */ 77d983712dSmrg/*static Bool TsengParseConfig(ParseInfoPtr raw); */ 78d983712dSmrg 79d983712dSmrg/* Internally used functions (some are defined in tseng.h) */ 80d983712dSmrgstatic Bool TsengMapMem(ScrnInfoPtr pScrn); 81d983712dSmrgstatic Bool TsengUnmapMem(ScrnInfoPtr pScrn); 82d983712dSmrgstatic void TsengUnlock(ScrnInfoPtr pScrn); 83d983712dSmrgstatic void TsengLock(ScrnInfoPtr pScrn); 84d983712dSmrg 85d983712dSmrg/* 86d983712dSmrg * This is intentionally screen-independent. It indicates the binding 87d983712dSmrg * choice made in the first PreInit. 88d983712dSmrg */ 89d983712dSmrgstatic int pix24bpp = 0; 90d983712dSmrg 91d983712dSmrg#define TSENG_NAME "TSENG" 92d983712dSmrg#define TSENG_DRIVER_NAME "tseng" 93d983712dSmrg#define TSENG_MAJOR_VERSION 1 94d983712dSmrg#define TSENG_MINOR_VERSION 1 95d983712dSmrg#define TSENG_PATCHLEVEL 0 96d983712dSmrg#define TSENG_VERSION (TSENG_MAJOR_VERSION << 24) | (TSENG_MINOR_VERSION << 16) | TSENG_PATCHLEVEL 97d983712dSmrg 98d983712dSmrg/* CRTC timing limits */ 99d983712dSmrg#define Tseng_HMAX (4096-8) 100d983712dSmrg#define Tseng_VMAX (2048-1) 101d983712dSmrg 102d983712dSmrg/* 103d983712dSmrg * This contains the functions needed by the server after loading the 104d983712dSmrg * driver module. It must be supplied, and gets added the driver list by 105d983712dSmrg * the Module Setup funtion in the dynamic case. In the static case a 106d983712dSmrg * reference to this is compiled in, and this requires that the name of 107d983712dSmrg * this DriverRec be an upper-case version of the driver name. 108d983712dSmrg */ 109d983712dSmrg 110d983712dSmrg_X_EXPORT DriverRec TSENG = 111d983712dSmrg{ 112d983712dSmrg TSENG_VERSION, 113d983712dSmrg TSENG_DRIVER_NAME, 114d983712dSmrg TsengIdentify, 115d983712dSmrg TsengProbe, 116d983712dSmrg TsengAvailableOptions, 117d983712dSmrg NULL, 118d983712dSmrg 0 119d983712dSmrg}; 120d983712dSmrg 121d983712dSmrg/* sub-revisions are now dealt with in the ChipRev variable */ 122d983712dSmrgstatic SymTabRec TsengChipsets[] = 123d983712dSmrg{ 124d983712dSmrg {ET4000, "ET4000W32p"}, 125d983712dSmrg {ET6000, "ET6000"}, 126d983712dSmrg {-1, NULL} 127d983712dSmrg}; 128d983712dSmrg 129d983712dSmrg/* Convert PCI ID to chipset name */ 130d983712dSmrgstatic PciChipsets TsengPciChipsets[] = 131d983712dSmrg{ 132d983712dSmrg {ET4000, PCI_CHIP_ET4000_W32P_A, RES_SHARED_VGA}, 133d983712dSmrg {ET4000, PCI_CHIP_ET4000_W32P_B, RES_SHARED_VGA}, 134d983712dSmrg {ET4000, PCI_CHIP_ET4000_W32P_C, RES_SHARED_VGA}, 135d983712dSmrg {ET4000, PCI_CHIP_ET4000_W32P_D, RES_SHARED_VGA}, 136d983712dSmrg {ET6000, PCI_CHIP_ET6000, RES_SHARED_VGA}, 137d983712dSmrg {-1, -1, RES_UNDEFINED} 138d983712dSmrg}; 139d983712dSmrg 140d983712dSmrgtypedef enum { 141d983712dSmrg OPTION_HIBIT_HIGH, 142d983712dSmrg OPTION_HIBIT_LOW, 143d983712dSmrg OPTION_SW_CURSOR, 144d983712dSmrg OPTION_HW_CURSOR, 145d983712dSmrg OPTION_PCI_BURST, 146d983712dSmrg OPTION_SLOW_DRAM, 147d983712dSmrg OPTION_MED_DRAM, 148d983712dSmrg OPTION_FAST_DRAM, 149d983712dSmrg OPTION_W32_INTERLEAVE, 150d983712dSmrg OPTION_NOACCEL, 151d983712dSmrg OPTION_SHOWCACHE, 152d983712dSmrg OPTION_PCI_RETRY 153d983712dSmrg} TsengOpts; 154d983712dSmrg 155d983712dSmrgstatic const OptionInfoRec TsengOptions[] = 156d983712dSmrg{ 157d983712dSmrg {OPTION_HIBIT_HIGH, "hibit_high", OPTV_BOOLEAN, 158d983712dSmrg {0}, FALSE}, 159d983712dSmrg {OPTION_HIBIT_LOW, "hibit_low", OPTV_BOOLEAN, 160d983712dSmrg {0}, FALSE}, 161d983712dSmrg {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, 162d983712dSmrg {0}, FALSE}, 163d983712dSmrg {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, 164d983712dSmrg {0}, FALSE}, 165d983712dSmrg {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, 166d983712dSmrg {0}, FALSE}, 167d983712dSmrg {OPTION_SLOW_DRAM, "slow_dram", OPTV_BOOLEAN, 168d983712dSmrg {0}, FALSE}, 169d983712dSmrg {OPTION_MED_DRAM, "med_dram", OPTV_BOOLEAN, 170d983712dSmrg {0}, FALSE}, 171d983712dSmrg {OPTION_FAST_DRAM, "fast_dram", OPTV_BOOLEAN, 172d983712dSmrg {0}, FALSE}, 173d983712dSmrg {OPTION_W32_INTERLEAVE, "w32_interleave", OPTV_BOOLEAN, 174d983712dSmrg {0}, FALSE}, 175d983712dSmrg {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, 176d983712dSmrg {0}, FALSE}, 177d983712dSmrg {OPTION_SHOWCACHE, "ShowCache", OPTV_BOOLEAN, 178d983712dSmrg {0}, FALSE}, 179d983712dSmrg {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN, 180d983712dSmrg {0}, FALSE}, 181d983712dSmrg {-1, NULL, OPTV_NONE, 182d983712dSmrg {0}, FALSE} 183d983712dSmrg}; 184d983712dSmrg 185d983712dSmrg#ifdef XFree86LOADER 186d983712dSmrg 187d983712dSmrgstatic MODULESETUPPROTO(tsengSetup); 188d983712dSmrg 189d983712dSmrgstatic XF86ModuleVersionInfo tsengVersRec = 190d983712dSmrg{ 191d983712dSmrg "tseng", 192d983712dSmrg MODULEVENDORSTRING, 193d983712dSmrg MODINFOSTRING1, 194d983712dSmrg MODINFOSTRING2, 195d983712dSmrg XORG_VERSION_CURRENT, 196d983712dSmrg TSENG_MAJOR_VERSION, TSENG_MINOR_VERSION, TSENG_PATCHLEVEL, 197d983712dSmrg ABI_CLASS_VIDEODRV, /* This is a video driver */ 198d983712dSmrg ABI_VIDEODRV_VERSION, 199d983712dSmrg MOD_CLASS_VIDEODRV, 200d983712dSmrg {0, 0, 0, 0} 201d983712dSmrg}; 202d983712dSmrg 203d983712dSmrg/* 204d983712dSmrg * This is the module init data for XFree86 modules. 205d983712dSmrg * 206d983712dSmrg * Its name has to be the driver name followed by ModuleData. 207d983712dSmrg */ 208d983712dSmrg_X_EXPORT XF86ModuleData tsengModuleData = { &tsengVersRec, tsengSetup, NULL }; 209d983712dSmrg 210d983712dSmrgstatic pointer 211d983712dSmrgtsengSetup(pointer module, pointer opts, int *errmaj, int *errmin) 212d983712dSmrg{ 213d983712dSmrg static Bool setupDone = FALSE; 214d983712dSmrg 215d983712dSmrg if (!setupDone) { 216d983712dSmrg setupDone = TRUE; 217d983712dSmrg xf86AddDriver(&TSENG, module, 0); 218d983712dSmrg 219d983712dSmrg /* 220d983712dSmrg * The return value must be non-NULL on success even though there 221d983712dSmrg * is no TearDownProc. 222d983712dSmrg */ 223d983712dSmrg return (pointer) 1; 224d983712dSmrg } else { 225d983712dSmrg if (errmaj) 226d983712dSmrg *errmaj = LDR_ONCEONLY; 227d983712dSmrg return NULL; 228d983712dSmrg } 229d983712dSmrg} 230d983712dSmrg 231d983712dSmrg#endif /* XFree86LOADER */ 232d983712dSmrg 233d983712dSmrgstatic Bool 234d983712dSmrgTsengGetRec(ScrnInfoPtr pScrn) 235d983712dSmrg{ 236d983712dSmrg TsengPtr pTseng; 237d983712dSmrg 238d983712dSmrg PDEBUG(" TsengGetRec\n"); 239d983712dSmrg 240d983712dSmrg /* 241d983712dSmrg * Allocate an TsengRec, and hook it into pScrn->driverPrivate. 242d983712dSmrg * pScrn->driverPrivate is initialised to NULL, so we can check if 243d983712dSmrg * the allocation has already been done. 244d983712dSmrg */ 245d983712dSmrg if (pScrn->driverPrivate != NULL) 246d983712dSmrg return TRUE; 247d983712dSmrg 248d983712dSmrg pScrn->driverPrivate = xnfcalloc(sizeof(TsengRec), 1); 249d983712dSmrg 250d983712dSmrg 251d983712dSmrg /* Initialise it here when needed (or possible) */ 252d983712dSmrg pTseng = TsengPTR(pScrn); 253d983712dSmrg 254d983712dSmrg pTseng->SavedReg.RAMDAC = NULL; 255d983712dSmrg 256d983712dSmrg return TRUE; 257d983712dSmrg} 258d983712dSmrg 259d983712dSmrgstatic void 260d983712dSmrgTsengFreeRec(ScrnInfoPtr pScrn) 261d983712dSmrg{ 262d983712dSmrg TsengPtr pTseng; 263d983712dSmrg 264d983712dSmrg PDEBUG(" TsengFreeRec\n"); 265d983712dSmrg 266d983712dSmrg if (pScrn->driverPrivate == NULL) 267d983712dSmrg return; 268d983712dSmrg 269d983712dSmrg pTseng = TsengPTR(pScrn); 270d983712dSmrg 271d983712dSmrg if (pTseng->SavedReg.RAMDAC) 272d983712dSmrg xfree(pTseng->SavedReg.RAMDAC); 273d983712dSmrg 274d983712dSmrg xfree(pScrn->driverPrivate); 275d983712dSmrg pScrn->driverPrivate = NULL; 276d983712dSmrg} 277d983712dSmrg 278d983712dSmrgstatic const OptionInfoRec * 279d983712dSmrgTsengAvailableOptions(int chipid, int busid) 280d983712dSmrg{ 281d983712dSmrg return TsengOptions; 282d983712dSmrg} 283d983712dSmrg 284d983712dSmrgstatic void 285d983712dSmrgTsengIdentify(int flags) 286d983712dSmrg{ 287d983712dSmrg xf86Msg(X_INFO, TSENG_NAME ": driver for TsengLabs ET4000W32p, ET6000 and" 288d983712dSmrg " ET6100 chips.\n"); 289d983712dSmrg} 290d983712dSmrg 291d983712dSmrg/* unlock ET4000 using KEY register */ 292d983712dSmrgstatic void 293d983712dSmrgTsengUnlock(ScrnInfoPtr pScrn) 294d983712dSmrg{ 295d983712dSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 296d983712dSmrg CARD8 tmp; 297d983712dSmrg 298d983712dSmrg PDEBUG(" TsengUnlock\n"); 299d983712dSmrg 300d983712dSmrg vgaHWHerculesSecondPage(hwp, TRUE); 301d983712dSmrg vgaHWWriteModeControl(hwp, 0xA0); 302d983712dSmrg 303d983712dSmrg tmp = hwp->readCrtc(hwp, 0x11); 304d983712dSmrg hwp->writeCrtc(hwp, 0x11, tmp & 0x7F); 305d983712dSmrg} 306d983712dSmrg 307d983712dSmrg/* lock ET4000 using KEY register. FIXME: should restore old lock status instead */ 308d983712dSmrgstatic void 309d983712dSmrgTsengLock(ScrnInfoPtr pScrn) 310d983712dSmrg{ 311d983712dSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 312d983712dSmrg CARD8 tmp; 313d983712dSmrg 314d983712dSmrg PDEBUG(" TsengLock\n"); 315d983712dSmrg 316d983712dSmrg tmp = hwp->readCrtc(hwp, 0x11); 317d983712dSmrg hwp->writeCrtc(hwp, 0x11, tmp | 0x80); 318d983712dSmrg 319d983712dSmrg vgaHWWriteModeControl(hwp, 0x00); 320d983712dSmrg vgaHWWriteModeControl(hwp, 0x29); 321d983712dSmrg vgaHWHerculesSecondPage(hwp, FALSE); 322d983712dSmrg} 323d983712dSmrg 324d983712dSmrgstatic Bool 325d983712dSmrgTsengProbe(DriverPtr drv, int flags) 326d983712dSmrg{ 327d983712dSmrg int i; 328d983712dSmrg GDevPtr *devSections; 329d983712dSmrg int numDevSections; 330d983712dSmrg int numUsed; 331d983712dSmrg int *usedChips = NULL; 332d983712dSmrg Bool foundScreen = FALSE; 333d983712dSmrg 334d983712dSmrg 335d983712dSmrg PDEBUG(" TsengProbe\n"); 336d983712dSmrg /* 337d983712dSmrg * The aim here is to find all cards that this driver can handle, 338d983712dSmrg * and for the ones not already claimed by another driver, claim the 339d983712dSmrg * slot, and allocate a ScrnInfoRec. 340d983712dSmrg * 341d983712dSmrg * This should be a minimal probe, and it should under no circumstances 342d983712dSmrg * change the state of the hardware. Because a device is found, don't 343d983712dSmrg * assume that it will be used. Don't do any initialisations other than 344d983712dSmrg * the required ScrnInfoRec initialisations. Don't allocate any new 345d983712dSmrg * data structures. 346d983712dSmrg */ 347d983712dSmrg 348d983712dSmrg /* 349d983712dSmrg * Find the config file Device sections that match this 350d983712dSmrg * driver, and return if there are none. 351d983712dSmrg */ 352d983712dSmrg if ((numDevSections = xf86MatchDevice(TSENG_DRIVER_NAME, 353d983712dSmrg &devSections)) <= 0) { 354d983712dSmrg return FALSE; 355d983712dSmrg } 356d983712dSmrg 357962c3257Smrg#ifndef XSERVER_LIBPCIACCESS 358d983712dSmrg /* PCI only driver now. */ 359d983712dSmrg if (!xf86GetPciVideoInfo()) 360d983712dSmrg return FALSE; 361962c3257Smrg#endif 362d983712dSmrg 363d983712dSmrg /* XXX maybe this can go some time soon */ 364d983712dSmrg /* 365d983712dSmrg * for the Tseng server, there can only be one matching 366d983712dSmrg * device section. So issue a warning if more than one show up. 367d983712dSmrg * Multiple Tseng cards in the same machine are not possible. 368d983712dSmrg */ 369d983712dSmrg numUsed = xf86MatchPciInstances(TSENG_NAME, PCI_VENDOR_TSENG, 370d983712dSmrg TsengChipsets, TsengPciChipsets, 371d983712dSmrg devSections,numDevSections, drv, 372d983712dSmrg &usedChips); 373d983712dSmrg if (numUsed > 0) { 374d983712dSmrg if (flags & PROBE_DETECT) 375d983712dSmrg foundScreen = TRUE; 376d983712dSmrg else for (i = 0; i < numUsed; i++) { 377d983712dSmrg /* Allocate a ScrnInfoRec */ 378d983712dSmrg ScrnInfoPtr pScrn = NULL; 379d983712dSmrg if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i], 380d983712dSmrg TsengPciChipsets,NULL, 381d983712dSmrg NULL,NULL,NULL,NULL))) { 382d983712dSmrg pScrn->driverVersion = TSENG_VERSION; 383d983712dSmrg pScrn->driverName = TSENG_DRIVER_NAME; 384d983712dSmrg pScrn->name = TSENG_NAME; 385d983712dSmrg pScrn->Probe = TsengProbe; 386d983712dSmrg pScrn->PreInit = TsengPreInit; 387d983712dSmrg pScrn->ScreenInit = TsengScreenInit; 388d983712dSmrg pScrn->SwitchMode = TsengSwitchMode; 389d983712dSmrg pScrn->AdjustFrame = TsengAdjustFrame; 390d983712dSmrg pScrn->EnterVT = TsengEnterVT; 391d983712dSmrg pScrn->LeaveVT = TsengLeaveVT; 392d983712dSmrg pScrn->FreeScreen = TsengFreeScreen; 393d983712dSmrg pScrn->ValidMode = TsengValidMode; 394d983712dSmrg 395d983712dSmrg foundScreen = TRUE; 396d983712dSmrg } 397d983712dSmrg } 398d983712dSmrg xfree(usedChips); 399d983712dSmrg } 400d983712dSmrg 401d983712dSmrg xfree(devSections); 402d983712dSmrg return foundScreen; 403d983712dSmrg} 404d983712dSmrg 405d983712dSmrg/* The PCI part of TsengPreInit() */ 406d983712dSmrgstatic Bool 407d983712dSmrgTsengPreInitPCI(ScrnInfoPtr pScrn) 408d983712dSmrg{ 409d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 410d983712dSmrg 411d983712dSmrg PDEBUG(" TsengPreInitPCI\n"); 412d983712dSmrg 413d983712dSmrg /* This is PCI, we should be able to trust it */ 414d983712dSmrg 415d983712dSmrg /* Set up ChipType, ChipRev and pScrn->chipset. 416d983712dSmrg * This last one is usually not done manually, but 417d983712dSmrg * it's for informative use only anyway. */ 418962c3257Smrg switch (PCI_DEV_DEVICE_ID(pTseng->PciInfo)) { 419d983712dSmrg case PCI_CHIP_ET4000_W32P_A: 420d983712dSmrg pTseng->ChipType = ET4000; 421d983712dSmrg pTseng->ChipRev = REV_A; 422d983712dSmrg pScrn->chipset = "ET4000/W32P (rev A)"; 423d983712dSmrg break; 424d983712dSmrg case PCI_CHIP_ET4000_W32P_B: 425d983712dSmrg pTseng->ChipType = ET4000; 426d983712dSmrg pTseng->ChipRev = REV_B; 427d983712dSmrg pScrn->chipset = "ET4000/W32P (rev B)"; 428d983712dSmrg break; 429d983712dSmrg case PCI_CHIP_ET4000_W32P_C: 430d983712dSmrg pTseng->ChipType = ET4000; 431d983712dSmrg pTseng->ChipRev = REV_C; 432d983712dSmrg pScrn->chipset = "ET4000/W32P (rev C)"; 433d983712dSmrg break; 434d983712dSmrg case PCI_CHIP_ET4000_W32P_D: 435d983712dSmrg pTseng->ChipType = ET4000; 436d983712dSmrg pTseng->ChipRev = REV_D; 437d983712dSmrg pScrn->chipset = "ET4000/W32P (rev D)"; 438d983712dSmrg break; 439d983712dSmrg case PCI_CHIP_ET6000: 440d983712dSmrg pTseng->ChipType = ET6000; 441d983712dSmrg 442962c3257Smrg if (PCI_DEV_REVISION(pTseng->PciInfo) < 0x70) { 443d983712dSmrg pScrn->chipset = "ET6000"; 444d983712dSmrg pTseng->ChipRev = REV_ET6000; 445d983712dSmrg } else { 446d983712dSmrg pScrn->chipset = "ET6100"; 447d983712dSmrg pTseng->ChipRev = REV_ET6100; 448d983712dSmrg } 449d983712dSmrg break; 450d983712dSmrg default: 451d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown Tseng PCI ID: %X\n", 452962c3257Smrg PCI_DEV_DEVICE_ID(pTseng->PciInfo)); 453d983712dSmrg return FALSE; 454d983712dSmrg } 455d983712dSmrg 456d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chipset: \"%s\"\n", pScrn->chipset); 457d983712dSmrg 458962c3257Smrg#ifndef XSERVER_LIBPCIACCESS 459d983712dSmrg pTseng->PciTag = pciTag(pTseng->PciInfo->bus, pTseng->PciInfo->device, 460d983712dSmrg pTseng->PciInfo->func); 461962c3257Smrg#endif 462d983712dSmrg 463d983712dSmrg /* only the ET6000 implements a PCI IO address */ 464d983712dSmrg if (pTseng->ChipType == ET6000) { 465962c3257Smrg if (!PCI_REGION_BASE(pTseng->PciInfo, 1, REGION_IO)) { 466d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 467d983712dSmrg "No valid PCI I/O address in PCI config space\n"); 468d983712dSmrg return FALSE; 469d983712dSmrg } 470d983712dSmrg 471962c3257Smrg pTseng->ET6000IOAddress = PCI_REGION_BASE(pTseng->PciInfo, 1, REGION_IO); 472d983712dSmrg 473d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "ET6000 PCI I/O registers at 0x%lX\n", 474d983712dSmrg (unsigned long)pTseng->ET6000IOAddress); 475d983712dSmrg } 476d983712dSmrg 477d983712dSmrg return TRUE; 478d983712dSmrg} 479d983712dSmrg 480d983712dSmrg/* 481d983712dSmrg * The 8*32kb ET6000 MDRAM granularity causes the more general probe to 482d983712dSmrg * detect too much memory in some configurations, because that code has a 483d983712dSmrg * 8-bank (=256k) granularity. E.g. it fails to recognize 2.25 MB of memory 484d983712dSmrg * (detects 2.5 instead). This function goes to check if the RAM is actually 485d983712dSmrg * there. MDRAM comes in multiples of 4 banks (16, 24, 32, 36, 40, 64, 72, 486d983712dSmrg * 80, ... 32kb-banks), so checking each 64k block should be enough granularity. 487d983712dSmrg * 488d983712dSmrg * No more than the amount of refreshed RAM is checked. Non-refreshed RAM 489d983712dSmrg * won't work anyway. 490d983712dSmrg * 491d983712dSmrg * The same code could be used on other Tseng chips, or even on ANY 492d983712dSmrg * VGA board, but probably only in case of trouble. 493d983712dSmrg * 494d983712dSmrg * FIXME: this should be done using linear memory 495d983712dSmrg */ 496d983712dSmrg#define VIDMEM ((volatile CARD32*)check_vgabase) 497d983712dSmrg#define SEGSIZE (64) /* kb */ 498d983712dSmrg 499d983712dSmrg#define ET6K_SETSEG(seg) \ 500d983712dSmrg vgaHWWriteBank(hwp, ((seg) & 0x30) | ((seg) >> 4));\ 501d983712dSmrg vgaHWWriteSegment(hwp, ((seg) & 0x0f) | ((seg) << 4)); 502d983712dSmrg 503d983712dSmrgstatic int 504d983712dSmrget6000_check_videoram(ScrnInfoPtr pScrn, int ram) 505d983712dSmrg{ 506d983712dSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 507d983712dSmrg unsigned char oldSegSel1, oldSegSel2, oldGR5, oldGR6, oldSEQ2, oldSEQ4; 508d983712dSmrg int segment, i; 509d983712dSmrg int real_ram = 0; 510d983712dSmrg pointer check_vgabase; 511d983712dSmrg Bool fooled = FALSE; 512d983712dSmrg int save_vidmem; 513d983712dSmrg 514d983712dSmrg PDEBUG(" et6000_check_videoram\n"); 515d983712dSmrg if (ram > 4096) { 516d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 517d983712dSmrg "Detected more than 4096 kb of video RAM. Clipped to 4096kb\n"); 518d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 519d983712dSmrg " (Tseng VGA chips can only use 4096kb).\n"); 520d983712dSmrg ram = 4096; 521d983712dSmrg } 522d983712dSmrg if (!vgaHWMapMem(pScrn)) { 523d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 524d983712dSmrg "Could not map VGA memory to check for video memory.\n"); 525d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 526d983712dSmrg " Detected amount may be wrong.\n"); 527d983712dSmrg return ram; 528d983712dSmrg } 529d983712dSmrg check_vgabase = (VGAHWPTR(pScrn)->Base); 530d983712dSmrg 531d983712dSmrg /* 532d983712dSmrg * We need to set the VGA controller in VGA graphics mode, or else we won't 533d983712dSmrg * be able to access the full 4MB memory range. First, we save the 534d983712dSmrg * registers we modify, of course. 535d983712dSmrg */ 536d983712dSmrg 537d983712dSmrg oldSegSel1 = vgaHWReadSegment(hwp); 538d983712dSmrg oldSegSel2 = vgaHWReadBank(hwp); 539d983712dSmrg 540d983712dSmrg oldGR5 = hwp->readGr(hwp, 0x05); 541d983712dSmrg oldGR6 = hwp->readGr(hwp, 0x06); 542d983712dSmrg 543d983712dSmrg oldSEQ2 = hwp->readSeq(hwp, 0x02); 544d983712dSmrg oldSEQ4 = hwp->readSeq(hwp, 0x04); 545d983712dSmrg 546d983712dSmrg /* set graphics mode */ 547d983712dSmrg hwp->writeGr(hwp, 0x06, 0x05); 548d983712dSmrg hwp->writeGr(hwp, 0x05, 0x40); 549d983712dSmrg hwp->writeSeq(hwp, 0x02, 0x0F); 550d983712dSmrg hwp->writeSeq(hwp, 0x04, 0x0E); 551d983712dSmrg 552d983712dSmrg /* 553d983712dSmrg * count down from presumed amount of memory in SEGSIZE steps, and 554d983712dSmrg * look at each segment for real RAM. 555d983712dSmrg * 556d983712dSmrg * To select a segment, we cannot use ET4000W32SetReadWrite(), since 557d983712dSmrg * that requires the ScreenPtr, which we don't have here. 558d983712dSmrg */ 559d983712dSmrg 560d983712dSmrg for (segment = (ram / SEGSIZE) - 1; segment >= 0; segment--) { 561d983712dSmrg /* select the segment */ 562d983712dSmrg ET6K_SETSEG(segment); 563d983712dSmrg 564d983712dSmrg /* save contents of memory probing location */ 565d983712dSmrg save_vidmem = *(VIDMEM); 566d983712dSmrg 567d983712dSmrg /* test with pattern */ 568d983712dSmrg *VIDMEM = 0xAAAA5555; 569d983712dSmrg if (*VIDMEM != 0xAAAA5555) { 570d983712dSmrg *VIDMEM = save_vidmem; 571d983712dSmrg continue; 572d983712dSmrg } 573d983712dSmrg /* test with inverted pattern */ 574d983712dSmrg *VIDMEM = 0x5555AAAA; 575d983712dSmrg if (*VIDMEM != 0x5555AAAA) { 576d983712dSmrg *VIDMEM = save_vidmem; 577d983712dSmrg continue; 578d983712dSmrg } 579d983712dSmrg /* 580d983712dSmrg * If we get here, the memory seems to be writable/readable 581d983712dSmrg * Now check if we aren't fooled by address wrapping (mirroring) 582d983712dSmrg */ 583d983712dSmrg fooled = FALSE; 584d983712dSmrg for (i = segment - 1; i >= 0; i--) { 585d983712dSmrg /* select the segment */ 586d983712dSmrg ET6K_SETSEG(i); 587d983712dSmrg 588d983712dSmrg /* again? */ 589d983712dSmrg vgaHWWriteBank(hwp, (i & 0x30) | (i >> 4)); 590d983712dSmrg vgaHWWriteSegment(hwp, (i & 0x0f) | (i << 4)); 591d983712dSmrg 592d983712dSmrg if (*VIDMEM == 0x5555AAAA) { 593d983712dSmrg /* 594d983712dSmrg * Seems like address wrap, but there could of course be 595d983712dSmrg * 0x5555AAAA in here by accident, so we check with another 596d983712dSmrg * pattern again. 597d983712dSmrg */ 598d983712dSmrg ET6K_SETSEG(segment); 599d983712dSmrg /* test with other pattern again */ 600d983712dSmrg *VIDMEM = 0xAAAA5555; 601d983712dSmrg ET6K_SETSEG(i); 602d983712dSmrg if (*VIDMEM == 0xAAAA5555) { 603d983712dSmrg /* now we're sure: this is not real memory */ 604d983712dSmrg fooled = TRUE; 605d983712dSmrg break; 606d983712dSmrg } 607d983712dSmrg } 608d983712dSmrg } 609d983712dSmrg if (!fooled) { 610d983712dSmrg real_ram = (segment + 1) * SEGSIZE; 611d983712dSmrg break; 612d983712dSmrg } 613d983712dSmrg /* restore old contents again */ 614d983712dSmrg ET6K_SETSEG(segment); 615d983712dSmrg *VIDMEM = save_vidmem; 616d983712dSmrg } 617d983712dSmrg 618d983712dSmrg /* restore original register contents */ 619d983712dSmrg vgaHWWriteSegment(hwp, oldSegSel1); 620d983712dSmrg vgaHWWriteBank(hwp, oldSegSel2); 621d983712dSmrg 622d983712dSmrg hwp->writeGr(hwp, 0x05, oldGR5); 623d983712dSmrg hwp->writeGr(hwp, 0x06, oldGR6); 624d983712dSmrg hwp->writeSeq(hwp, 0x02, oldSEQ2); 625d983712dSmrg hwp->writeSeq(hwp, 0x04, oldSEQ4); 626d983712dSmrg 627d983712dSmrg vgaHWUnmapMem(pScrn); 628d983712dSmrg return real_ram; 629d983712dSmrg} 630d983712dSmrg 631d983712dSmrg/* 632d983712dSmrg * Handle amount of allowed memory: some combinations can't use all 633d983712dSmrg * available memory. Should we still allow the user to override this? 634d983712dSmrg * 635d983712dSmrg * This must be called AFTER the decision has been made to use linear mode 636d983712dSmrg * and/or acceleration, or the memory limit code won't be able to work. 637d983712dSmrg */ 638d983712dSmrg 639d983712dSmrgstatic int 640d983712dSmrgTsengDoMemLimit(ScrnInfoPtr pScrn, int ram, int limit, char *reason) 641d983712dSmrg{ 642d983712dSmrg if (ram > limit) { 643d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Only %d kb of memory can be used %s.\n", 644d983712dSmrg limit, reason); 645d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Reducing video memory to %d kb.\n", limit); 646d983712dSmrg ram = limit; 647d983712dSmrg } 648d983712dSmrg return ram; 649d983712dSmrg} 650d983712dSmrg 651d983712dSmrgstatic int 652d983712dSmrgTsengLimitMem(ScrnInfoPtr pScrn, int ram) 653d983712dSmrg{ 654d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 655d983712dSmrg 656d983712dSmrg if (pTseng->UseAccel) { 657d983712dSmrg if (pTseng->ChipType == ET4000) { 658d983712dSmrg /* <= W32p_ab : 659d983712dSmrg * 2 MB direct access + 2*512kb via apertures MBP0 and MBP1 660d983712dSmrg * == W32p_cd : 661d983712dSmrg * 2*1MB via apertures MBP0 and MBP1 662d983712dSmrg */ 663d983712dSmrg if ((pTseng->ChipRev == REV_C) || (pTseng->ChipRev == REV_D)) 664d983712dSmrg ram = TsengDoMemLimit(pScrn, ram, 2048, 665d983712dSmrg "in linear + accelerated mode " 666d983712dSmrg "on W32p rev c and d"); 667d983712dSmrg 668d983712dSmrg ram = TsengDoMemLimit(pScrn, ram, 2048 + 1024, 669d983712dSmrg "in linear + accelerated mode " 670d983712dSmrg "on W32/W32i/W32p"); 671d983712dSmrg 672d983712dSmrg /* 673d983712dSmrg * upper 516kb of 4MB linear map used for 674d983712dSmrg * "externally mapped registers" 675d983712dSmrg */ 676d983712dSmrg ram = TsengDoMemLimit(pScrn, ram, 4096 - 516, 677d983712dSmrg "in linear + accelerated mode " 678d983712dSmrg "on W32/W32i/W32p"); 679d983712dSmrg } else { 680d983712dSmrg /* 681d983712dSmrg * upper 8kb used for externally mapped and 682d983712dSmrg * memory mapped registers 683d983712dSmrg */ 684d983712dSmrg ram = TsengDoMemLimit(pScrn, ram, 4096 - 8, 685d983712dSmrg "in linear + accelerated mode " 686d983712dSmrg "on ET6000/6100"); 687d983712dSmrg } 688d983712dSmrg } 689d983712dSmrg ram = TsengDoMemLimit(pScrn, ram, 4096, "on any Tseng card"); 690d983712dSmrg return ram; 691d983712dSmrg} 692d983712dSmrg 693d983712dSmrg/* 694d983712dSmrg * TsengDetectMem -- 695d983712dSmrg * try to find amount of video memory installed. 696d983712dSmrg * 697d983712dSmrg */ 698d983712dSmrgstatic int 699d983712dSmrgTsengDetectMem(ScrnInfoPtr pScrn) 700d983712dSmrg{ 701d983712dSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 702d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 703d983712dSmrg unsigned char config; 704d983712dSmrg int ramtype = 0; 705d983712dSmrg int ram = 0; 706d983712dSmrg 707d983712dSmrg PDEBUG(" TsengDetectMem\n"); 708d983712dSmrg if (pTseng->ChipType == ET6000) { 709d983712dSmrg ramtype = hwp->readST00(hwp) & 0x03; 710d983712dSmrg switch (ramtype) { 711d983712dSmrg case 0x03: /* MDRAM */ 712d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 713d983712dSmrg "Video memory type: Multibank DRAM (MDRAM).\n"); 714d983712dSmrg ram = ((ET6000IORead(pTseng, 0x47) & 0x07) + 1) * 8 * 32; /* number of 8 32kb banks */ 715d983712dSmrg if (ET6000IORead(pTseng, 0x45) & 0x04) { 716d983712dSmrg ram <<= 1; 717d983712dSmrg } 718d983712dSmrg /* 719d983712dSmrg * 8*32kb MDRAM refresh control granularity in the ET6000 fails to 720d983712dSmrg * recognize 2.25 MB of memory (detects 2.5 instead) 721d983712dSmrg */ 722d983712dSmrg ram = et6000_check_videoram(pScrn, ram); 723d983712dSmrg break; 724d983712dSmrg case 0x00: /* DRAM -- VERY unlikely on ET6000 cards, IMPOSSIBLE on ET6100 */ 725d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 726d983712dSmrg "Video memory type: Standard DRAM.\n"); 727d983712dSmrg ram = 1024 << (ET6000IORead(pTseng, 0x45) & 0x03); 728d983712dSmrg break; 729d983712dSmrg default: /* unknown RAM type */ 730d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 731d983712dSmrg "Unknown ET6000 video memory type %d -- assuming 1 MB (unless specified)\n", 732d983712dSmrg ramtype); 733d983712dSmrg ram = 1024; 734d983712dSmrg } 735d983712dSmrg } else { 736d983712dSmrg config = hwp->readCrtc(hwp, 0x37); 737d983712dSmrg 738d983712dSmrg ram = 128 << (config & 0x03); 739d983712dSmrg 740d983712dSmrg if (config & 0x80) 741d983712dSmrg ram <<= 1; 742d983712dSmrg 743d983712dSmrg /* Check for interleaving on W32i/p. */ 744d983712dSmrg config = hwp->readCrtc(hwp, 0x32); 745d983712dSmrg if (config & 0x80) { 746d983712dSmrg ram <<= 1; 747d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 748d983712dSmrg "Video memory type: Interleaved DRAM.\n"); 749d983712dSmrg } else { 750d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 751d983712dSmrg "Video memory type: Standard DRAM.\n"); 752d983712dSmrg } 753d983712dSmrg } 754d983712dSmrg return ram; 755d983712dSmrg} 756d983712dSmrg 757d983712dSmrgstatic Bool 758d983712dSmrgTsengProcessHibit(ScrnInfoPtr pScrn) 759d983712dSmrg{ 760d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 761d983712dSmrg MessageType from = X_CONFIG; 762d983712dSmrg int hibit_mode_width; 763d983712dSmrg 764d983712dSmrg PDEBUG(" TsengProcessHibit\n"); 765d983712dSmrg if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) { 766d983712dSmrg if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_LOW)) { 767d983712dSmrg xf86Msg(X_ERROR, "\nOptions \"hibit_high\" and \"hibit_low\" are incompatible;\n"); 768d983712dSmrg xf86Msg(X_ERROR, " specify only one (not both) in X configuration file\n"); 769d983712dSmrg return FALSE; 770d983712dSmrg } 771d983712dSmrg pTseng->save_divide = 0x40; 772d983712dSmrg } else if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) { 773d983712dSmrg pTseng->save_divide = 0; 774d983712dSmrg } else { 775d983712dSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 776d983712dSmrg 777d983712dSmrg from = X_PROBED; 778d983712dSmrg 779d983712dSmrg /* first check to see if hibit is probed from low-res mode */ 780d983712dSmrg hibit_mode_width = hwp->readCrtc(hwp, 0x01) + 1; 781d983712dSmrg 782d983712dSmrg if (hibit_mode_width > 82) { 783d983712dSmrg xf86Msg(X_WARNING, "Non-standard VGA text or graphics mode while probing for hibit:\n"); 784d983712dSmrg xf86Msg(X_WARNING, " probed 'hibit' value may be wrong.\n"); 785d983712dSmrg xf86Msg(X_WARNING, " Preferably run probe from 80x25 textmode,\n"); 786d983712dSmrg xf86Msg(X_WARNING, " or specify correct value in X configuration file.\n"); 787d983712dSmrg } 788d983712dSmrg 789d983712dSmrg /* Check for initial state of divide flag */ 790d983712dSmrg pTseng->save_divide = hwp->readSeq(hwp, 0x07) & 0x40; 791d983712dSmrg } 792d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, from, "Initial ET4000 hibit state: %s\n", 793d983712dSmrg pTseng->save_divide & 0x40 ? "high" : "low"); 794d983712dSmrg return TRUE; 795d983712dSmrg} 796d983712dSmrg 797d983712dSmrgstatic Bool 798d983712dSmrgTsengProcessOptions(ScrnInfoPtr pScrn) 799d983712dSmrg{ 800d983712dSmrg MessageType from; 801d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 802d983712dSmrg 803d983712dSmrg PDEBUG(" TsengProcessOptions\n"); 804d983712dSmrg 805d983712dSmrg /* Collect all of the relevant option flags (fill in pScrn->options) */ 806d983712dSmrg xf86CollectOptions(pScrn, NULL); 807d983712dSmrg 808d983712dSmrg /* Process the options */ 809d983712dSmrg if (!(pTseng->Options = xalloc(sizeof(TsengOptions)))) 810d983712dSmrg return FALSE; 811d983712dSmrg memcpy(pTseng->Options, TsengOptions, sizeof(TsengOptions)); 812d983712dSmrg xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pTseng->Options); 813d983712dSmrg 814d983712dSmrg from = X_DEFAULT; 815d983712dSmrg pTseng->HWCursor = FALSE; /* default */ 816d983712dSmrg if (xf86GetOptValBool(pTseng->Options, OPTION_HW_CURSOR, &pTseng->HWCursor)) 817d983712dSmrg from = X_CONFIG; 818d983712dSmrg if (xf86ReturnOptValBool(pTseng->Options, OPTION_SW_CURSOR, FALSE)) { 819d983712dSmrg from = X_CONFIG; 820d983712dSmrg pTseng->HWCursor = FALSE; 821d983712dSmrg } 822d983712dSmrg if ((pTseng->ChipType == ET4000) && pTseng->HWCursor) { 823d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, from, 824d983712dSmrg "Hardware Cursor not supported on this chipset\n"); 825d983712dSmrg pTseng->HWCursor = FALSE; 826d983712dSmrg } 827d983712dSmrg 828d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", 829d983712dSmrg pTseng->HWCursor ? "HW" : "SW"); 830d983712dSmrg 831d983712dSmrg if (pScrn->bitsPerPixel >= 8) { 832d983712dSmrg pTseng->UseAccel = TRUE; 833d983712dSmrg if (xf86ReturnOptValBool(pTseng->Options, OPTION_NOACCEL, FALSE)) { 834d983712dSmrg pTseng->UseAccel = FALSE; 835d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n"); 836d983712dSmrg } 837d983712dSmrg } else 838d983712dSmrg pTseng->UseAccel = FALSE; /* 1bpp and 4bpp are always non-accelerated */ 839d983712dSmrg 840d983712dSmrg pTseng->SlowDram = FALSE; 841d983712dSmrg if (xf86IsOptionSet(pTseng->Options, OPTION_SLOW_DRAM)) { 842d983712dSmrg pTseng->SlowDram = TRUE; 843d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using slow DRAM access\n"); 844d983712dSmrg } 845d983712dSmrg pTseng->MedDram = FALSE; 846d983712dSmrg if (xf86IsOptionSet(pTseng->Options, OPTION_MED_DRAM)) { 847d983712dSmrg pTseng->MedDram = TRUE; 848d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using Medium-speed DRAM access\n"); 849d983712dSmrg } 850d983712dSmrg pTseng->FastDram = FALSE; 851d983712dSmrg if (xf86IsOptionSet(pTseng->Options, OPTION_FAST_DRAM)) { 852d983712dSmrg pTseng->FastDram = TRUE; 853d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using fast DRAM access\n"); 854d983712dSmrg } 855d983712dSmrg if ((pTseng->SetW32Interleave = 856d983712dSmrg xf86GetOptValBool(pTseng->Options, OPTION_W32_INTERLEAVE, &pTseng->W32Interleave)) ) 857d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing W32p memory interleave %s.\n", 858d983712dSmrg pTseng->W32Interleave ? "ON" : "OFF"); 859d983712dSmrg if ((pTseng->SetPCIBurst = 860d983712dSmrg xf86GetOptValBool(pTseng->Options, OPTION_PCI_BURST, &pTseng->PCIBurst)) ) 861d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing PCI burst mode %s.\n", 862d983712dSmrg pTseng->PCIBurst ? "ON" : "OFF"); 863d983712dSmrg 864d983712dSmrg pTseng->ShowCache = FALSE; 865d983712dSmrg if (xf86ReturnOptValBool(pTseng->Options, OPTION_SHOWCACHE, FALSE)) { 866d983712dSmrg pTseng->ShowCache = TRUE; 867d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "(for debugging only:) Visible off-screen memory\n"); 868d983712dSmrg } 869d983712dSmrg 870d983712dSmrg pTseng->UsePCIRetry = FALSE; 871d983712dSmrg if (xf86ReturnOptValBool(pTseng->Options, OPTION_PCI_RETRY, FALSE)) { 872d983712dSmrg pTseng->UsePCIRetry = TRUE; 873d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n"); 874d983712dSmrg } 875d983712dSmrg return TRUE; 876d983712dSmrg} 877d983712dSmrg 878d983712dSmrgstatic Bool 879d983712dSmrgTsengGetFbAddress(ScrnInfoPtr pScrn) 880d983712dSmrg{ 881d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 882d983712dSmrg 883d983712dSmrg PDEBUG(" TsengGetFbAddress\n"); 884d983712dSmrg 885d983712dSmrg /* base0 is the framebuffer and base1 is the PCI IO space. */ 886962c3257Smrg if (PCI_REGION_BASE(pTseng->PciInfo, 0, REGION_MEM)) { 887d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 888d983712dSmrg "No valid Framebuffer address in PCI config space;\n"); 889d983712dSmrg return FALSE; 890d983712dSmrg } else 891962c3257Smrg pTseng->FbAddress = PCI_REGION_BASE(pTseng->PciInfo, 0, REGION_MEM); 892d983712dSmrg 893d983712dSmrg 894d03ff4acSmrg#ifndef XSERVER_LIBPCIACCESS 895d983712dSmrg if (xf86RegisterResources(pTseng->pEnt->index,NULL,ResNone)) { 896d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot register FB memory.\n"); 897d983712dSmrg return FALSE; 898d983712dSmrg } 899d03ff4acSmrg#endif 900d983712dSmrg 901d983712dSmrg /* The W32 linear map address space is always 4Mb (mainly because the 902d983712dSmrg * memory-mapped registers are located near the top of the 4MB area). 903d983712dSmrg * The ET6000 maps out 16 Meg, but still uses only 4Mb of that. 904d983712dSmrg * However, since all mmap()-ed space is also reflected in the "ps" 905d983712dSmrg * listing for the Xserver, many users will be worried by a server that 906d983712dSmrg * always eats 16MB of memory, even if it's not "real" memory, just 907d983712dSmrg * address space. Not mapping all of the 16M may be a potential problem 908d983712dSmrg * though: if another board is mapped on top of the remaining part of 909d983712dSmrg * the 16M... Boom! 910d983712dSmrg */ 911d983712dSmrg if (pTseng->ChipType == ET6000) 912d983712dSmrg pTseng->FbMapSize = 16384 * 1024; 913d983712dSmrg else 914d983712dSmrg pTseng->FbMapSize = 4096 * 1024; 915d983712dSmrg 916d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Framebuffer at 0x%lX\n", 917d983712dSmrg (unsigned long)pTseng->FbAddress); 918d983712dSmrg 919d983712dSmrg return TRUE; 920d983712dSmrg} 921d983712dSmrg 922d983712dSmrgstatic Bool 923d983712dSmrgTsengPreInit(ScrnInfoPtr pScrn, int flags) 924d983712dSmrg{ 925d983712dSmrg TsengPtr pTseng; 926d983712dSmrg MessageType from; 927d983712dSmrg int i; 928d983712dSmrg 929d983712dSmrg if (flags & PROBE_DETECT) return FALSE; 930d983712dSmrg 931d983712dSmrg PDEBUG(" TsengPreInit\n"); 932d983712dSmrg 933d983712dSmrg /* 934d983712dSmrg * Note: This function is only called once at server startup, and 935d983712dSmrg * not at the start of each server generation. This means that 936d983712dSmrg * only things that are persistent across server generations can 937d983712dSmrg * be initialised here. xf86Screens[] is (pScrn is a pointer to one 938d983712dSmrg * of these). Privates allocated using xf86AllocateScrnInfoPrivateIndex() 939d983712dSmrg * are too, and should be used for data that must persist across 940d983712dSmrg * server generations. 941d983712dSmrg * 942d983712dSmrg * Per-generation data should be allocated with 943d983712dSmrg * AllocateScreenPrivateIndex() from the ScreenInit() function. 944d983712dSmrg */ 945d983712dSmrg 946d983712dSmrg /* The vgahw module should be loaded here when needed */ 947d983712dSmrg 948d983712dSmrg /* This driver doesn't expect more than one entity per screen */ 949d983712dSmrg if (pScrn->numEntities > 1) 950d983712dSmrg return FALSE; 951d983712dSmrg 952d983712dSmrg /* Allocate the TsengRec driverPrivate */ 953d983712dSmrg if (!TsengGetRec(pScrn)) { 954d983712dSmrg return FALSE; 955d983712dSmrg } 956d983712dSmrg pTseng = TsengPTR(pScrn); 957d983712dSmrg 958d983712dSmrg /* This is the general case */ 959d983712dSmrg pTseng->pEnt = xf86GetEntityInfo(*pScrn->entityList); 960d983712dSmrg 961d983712dSmrg#if 1 962d983712dSmrg if (xf86LoadSubModule(pScrn, "int10")) { 963d983712dSmrg xf86Int10InfoPtr pInt; 964d983712dSmrg#if 1 965d983712dSmrg xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); 966d983712dSmrg pInt = xf86InitInt10(pTseng->pEnt->index); 967d983712dSmrg xf86FreeInt10(pInt); 968d983712dSmrg#endif 969d983712dSmrg } 970d983712dSmrg#endif 971d983712dSmrg 972d983712dSmrg if (!xf86LoadSubModule(pScrn, "vgahw")) 973d983712dSmrg return FALSE; 974d983712dSmrg /* 975d983712dSmrg * Allocate a vgaHWRec 976d983712dSmrg */ 977d983712dSmrg if (!vgaHWGetHWRec(pScrn)) 978d983712dSmrg return FALSE; 979d983712dSmrg 980d983712dSmrg vgaHWGetIOBase(VGAHWPTR(pScrn)); 981d983712dSmrg /* 982d983712dSmrg * Since, the capabilities are determined by the chipset, the very first 983d983712dSmrg * thing to do is to figure out the chipset and its capabilities. 984d983712dSmrg */ 985d983712dSmrg 986d983712dSmrg TsengUnlock(pScrn); 987d983712dSmrg 988d983712dSmrg pTseng->PciInfo = xf86GetPciInfoForEntity(pTseng->pEnt->index); 989d983712dSmrg if (!TsengPreInitPCI(pScrn)) { 990d983712dSmrg TsengFreeRec(pScrn); 991d983712dSmrg return FALSE; 992d983712dSmrg } 993d983712dSmrg 994d983712dSmrg if (!TsengRAMDACProbe(pScrn)) { 995d983712dSmrg TsengFreeRec(pScrn); 996d983712dSmrg return FALSE; 997d983712dSmrg } 998d983712dSmrg 999d983712dSmrg pScrn->progClock = TRUE; 1000d983712dSmrg 1001d983712dSmrg /* 1002d983712dSmrg * Now we can check what depth we support. 1003d983712dSmrg */ 1004d983712dSmrg 1005d983712dSmrg /* Set pScrn->monitor */ 1006d983712dSmrg pScrn->monitor = pScrn->confScreen->monitor; 1007d983712dSmrg 1008d983712dSmrg /* 1009d983712dSmrg * The first thing we should figure out is the depth, bpp, etc. 1010d983712dSmrg * Our default depth is 8, so pass it to the helper function. 1011d983712dSmrg * Our preference for depth 24 is 24bpp, so tell it that too. 1012d983712dSmrg */ 1013d983712dSmrg if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | Support32bppFb | 1014d983712dSmrg SupportConvert32to24 | PreferConvert32to24)) { 1015d983712dSmrg return FALSE; 1016d983712dSmrg } else { 1017d983712dSmrg switch (pScrn->depth) { 1018d983712dSmrg case 8: 1019d983712dSmrg case 16: 1020d983712dSmrg case 24: 1021d983712dSmrg case 32: 1022d983712dSmrg /* OK */ 1023d983712dSmrg break; 1024d983712dSmrg default: 1025d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1026d983712dSmrg "Given depth (%d) is not supported by this driver\n", 1027d983712dSmrg pScrn->depth); 1028d983712dSmrg return FALSE; 1029d983712dSmrg } 1030d983712dSmrg } 1031d983712dSmrg xf86PrintDepthBpp(pScrn); 1032d983712dSmrg 1033d983712dSmrg /* Get the depth24 pixmap format */ 1034d983712dSmrg if (pScrn->depth == 24 && pix24bpp == 0) 1035d983712dSmrg pix24bpp = xf86GetBppFromDepth(pScrn, 24); 1036d983712dSmrg 1037d983712dSmrg if (pScrn->bitsPerPixel > 8) 1038d983712dSmrg pTseng->Bytesperpixel = pScrn->bitsPerPixel / 8; 1039d983712dSmrg else 1040d983712dSmrg pTseng->Bytesperpixel = 1; /* this is fake for < 8bpp, but simplifies other code */ 1041d983712dSmrg 1042d983712dSmrg /* hardware limits */ 1043d983712dSmrg pScrn->maxHValue = Tseng_HMAX; 1044d983712dSmrg pScrn->maxVValue = Tseng_VMAX; 1045d983712dSmrg 1046d983712dSmrg /* 1047d983712dSmrg * This must happen after pScrn->display has been set because 1048d983712dSmrg * xf86SetWeight references it. 1049d983712dSmrg */ 1050d983712dSmrg 1051d983712dSmrg /* Set weight/mask/offset for depth > 8 */ 1052d983712dSmrg if (pScrn->depth > 8) { 1053d983712dSmrg /* The defaults are OK for us */ 1054d983712dSmrg rgb zeros = {0, 0, 0}; 1055d983712dSmrg 1056d983712dSmrg if (!xf86SetWeight(pScrn, zeros, zeros)) { 1057d983712dSmrg return FALSE; 1058d983712dSmrg } else { 1059d983712dSmrg /* XXX check that weight returned is supported */ 1060d983712dSmrg ; 1061d983712dSmrg } 1062d983712dSmrg } 1063d983712dSmrg 1064d983712dSmrg /* Set the default visual. */ 1065d983712dSmrg if (!xf86SetDefaultVisual(pScrn, -1)) 1066d983712dSmrg return FALSE; 1067d983712dSmrg 1068d983712dSmrg /* The gamma fields must be initialised when using the new cmap code */ 1069d983712dSmrg if (pScrn->depth > 1) { 1070d983712dSmrg Gamma zeros = {0.0, 0.0, 0.0}; 1071d983712dSmrg 1072d983712dSmrg if (!xf86SetGamma(pScrn, zeros)) { 1073d983712dSmrg return FALSE; 1074d983712dSmrg } 1075d983712dSmrg } 1076d983712dSmrg 1077d983712dSmrg /* Set the bits per RGB for 8bpp mode */ 1078d983712dSmrg if (pScrn->depth == 8) { 1079d983712dSmrg /* Default to 6, because most Tseng chips/RAMDACs don't support it */ 1080d983712dSmrg pScrn->rgbBits = 6; 1081d983712dSmrg } 1082d983712dSmrg if (!TsengProcessOptions(pScrn)) /* must be done _after_ we know what chip this is */ 1083d983712dSmrg return FALSE; 1084d983712dSmrg 1085d983712dSmrg if (!TsengGetFbAddress(pScrn)) 1086d983712dSmrg return FALSE; 1087d983712dSmrg 1088d983712dSmrg pScrn->memPhysBase = pTseng->FbAddress; 1089d983712dSmrg pScrn->fbOffset = 0; 1090d983712dSmrg 1091d983712dSmrg if (pTseng->UseAccel) 1092d983712dSmrg VGAHWPTR(pScrn)->MapSize = 0x20000; /* accelerator apertures and MMIO */ 1093d983712dSmrg else 1094d983712dSmrg VGAHWPTR(pScrn)->MapSize = 0x10000; 1095d983712dSmrg 1096d03ff4acSmrg#ifndef XSERVER_LIBPCIACCESS 1097d983712dSmrg /* 1098d983712dSmrg * XXX At least part of this range does appear to be disabled, 1099d983712dSmrg * but to play safe, it is marked as "unused" for now. 1100d983712dSmrg * Changed this to "disable". Otherwise it might interfere with DGA. 1101d983712dSmrg */ 1102d983712dSmrg xf86SetOperatingState(resVgaMem, pTseng->pEnt->index, ResDisableOpr); 1103d03ff4acSmrg#endif 1104d983712dSmrg /* hibit processing (TsengProcessOptions() must have been called first) */ 1105d983712dSmrg pTseng->save_divide = 0x40; /* default */ 1106d983712dSmrg if (pTseng->ChipType == ET4000) { 1107d983712dSmrg if (!TsengProcessHibit(pScrn)) 1108d983712dSmrg return FALSE; 1109d983712dSmrg } 1110d983712dSmrg /* 1111d983712dSmrg * If the user has specified the amount of memory in the XF86Config 1112d983712dSmrg * file, we respect that setting. 1113d983712dSmrg */ 1114d983712dSmrg if (pTseng->pEnt->device->videoRam != 0) { 1115d983712dSmrg pScrn->videoRam = pTseng->pEnt->device->videoRam; 1116d983712dSmrg from = X_CONFIG; 1117d983712dSmrg } else { 1118d983712dSmrg from = X_PROBED; 1119d983712dSmrg pScrn->videoRam = TsengDetectMem(pScrn); 1120d983712dSmrg } 1121d983712dSmrg pScrn->videoRam = TsengLimitMem(pScrn, pScrn->videoRam); 1122d983712dSmrg 1123d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte.\n", 1124d983712dSmrg pScrn->videoRam); 1125d983712dSmrg 1126d983712dSmrg TsengSetupClockRange(pScrn); 1127d983712dSmrg 1128d983712dSmrg /* 1129d983712dSmrg * xf86ValidateModes will check that the mode HTotal and VTotal values 1130d983712dSmrg * don't exceed the chipset's limit if pScrn->maxHValue and 1131d983712dSmrg * pScrn->maxVValue are set. Since our TsengValidMode() already takes 1132d983712dSmrg * care of this, we don't worry about setting them here. 1133d983712dSmrg */ 1134d983712dSmrg 1135d983712dSmrg /* Select valid modes from those available */ 1136d983712dSmrg i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, 1137d983712dSmrg pScrn->display->modes, &pTseng->clockRange, 1138d983712dSmrg NULL, 32, pScrn->maxHValue, 8*pTseng->Bytesperpixel, /* H limits */ 1139d983712dSmrg 0, pScrn->maxVValue, /* V limits */ 1140d983712dSmrg pScrn->display->virtualX, 1141d983712dSmrg pScrn->display->virtualY, 1142d983712dSmrg pTseng->FbMapSize, 1143d983712dSmrg LOOKUP_BEST_REFRESH); /* LOOKUP_CLOSEST_CLOCK | LOOKUP_CLKDIV2 when no programmable clock ? */ 1144d983712dSmrg 1145d983712dSmrg if (i == -1) { 1146d983712dSmrg TsengFreeRec(pScrn); 1147d983712dSmrg return FALSE; 1148d983712dSmrg } 1149d983712dSmrg /* Prune the modes marked as invalid */ 1150d983712dSmrg xf86PruneDriverModes(pScrn); 1151d983712dSmrg 1152d983712dSmrg if (i == 0 || pScrn->modes == NULL) { 1153d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); 1154d983712dSmrg TsengFreeRec(pScrn); 1155d983712dSmrg return FALSE; 1156d983712dSmrg } 1157d983712dSmrg /* 1158d983712dSmrg * Set the CRTC parameters for all of the modes based on the type 1159d983712dSmrg * of mode, and the chipset's interlace requirements. 1160d983712dSmrg * 1161d983712dSmrg * Calling this is required if the mode->Crtc* values are used by the 1162d983712dSmrg * driver and if the driver doesn't provide code to set them. They 1163d983712dSmrg * are not pre-initialised at all. 1164d983712dSmrg */ 1165d983712dSmrg xf86SetCrtcForModes(pScrn, 0); 1166d983712dSmrg 1167d983712dSmrg /* Set the current mode to the first in the list */ 1168d983712dSmrg pScrn->currentMode = pScrn->modes; 1169d983712dSmrg 1170d983712dSmrg /* Print the list of modes being used */ 1171d983712dSmrg xf86PrintModes(pScrn); 1172d983712dSmrg 1173d983712dSmrg /* Set display resolution */ 1174d983712dSmrg xf86SetDpi(pScrn, 0, 0); 1175d983712dSmrg 1176d983712dSmrg /* Load bpp-specific modules */ 1177d983712dSmrg switch (pScrn->bitsPerPixel) { 1178d983712dSmrg case 1: 1179d983712dSmrg if (xf86LoadSubModule(pScrn, "xf1bpp") == NULL) { 1180d983712dSmrg TsengFreeRec(pScrn); 1181d983712dSmrg return FALSE; 1182d983712dSmrg } 1183d983712dSmrg break; 1184d983712dSmrg case 4: 1185d983712dSmrg if (xf86LoadSubModule(pScrn, "xf4bpp") == NULL) { 1186d983712dSmrg TsengFreeRec(pScrn); 1187d983712dSmrg return FALSE; 1188d983712dSmrg } 1189d983712dSmrg break; 1190d983712dSmrg default: 1191d983712dSmrg if (xf86LoadSubModule(pScrn, "fb") == NULL) { 1192d983712dSmrg TsengFreeRec(pScrn); 1193d983712dSmrg return FALSE; 1194d983712dSmrg } 1195d983712dSmrg break; 1196d983712dSmrg } 1197d983712dSmrg 1198d983712dSmrg /* Load XAA if needed */ 1199d983712dSmrg if (pTseng->UseAccel) { 1200d983712dSmrg if (!xf86LoadSubModule(pScrn, "xaa")) { 1201d983712dSmrg TsengFreeRec(pScrn); 1202d983712dSmrg return FALSE; 1203d983712dSmrg } 1204d983712dSmrg } 1205d983712dSmrg /* Load ramdac if needed */ 1206d983712dSmrg if (pTseng->HWCursor) { 1207d983712dSmrg if (!xf86LoadSubModule(pScrn, "ramdac")) { 1208d983712dSmrg TsengFreeRec(pScrn); 1209d983712dSmrg return FALSE; 1210d983712dSmrg } 1211d983712dSmrg } 1212d983712dSmrg/* TsengLock(pScrn); */ 1213d983712dSmrg 1214d983712dSmrg return TRUE; 1215d983712dSmrg} 1216d983712dSmrg 1217d983712dSmrgstatic void 1218d983712dSmrgTsengSetupAccelMemory(int scrnIndex, ScreenPtr pScreen) 1219d983712dSmrg{ 1220d983712dSmrg ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1221d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 1222d983712dSmrg int offscreen_videoram, videoram_end, req_videoram; 1223d983712dSmrg int i; 1224d983712dSmrg int v; 1225d983712dSmrg 1226d983712dSmrg /* XXX Hack to suppress messages in subsequent generations. */ 1227d983712dSmrg if (serverGeneration == 1) 1228d983712dSmrg v = 1; 1229d983712dSmrg else 1230d983712dSmrg v = 100; 1231d983712dSmrg /* 1232d983712dSmrg * The accelerator requires free off-screen video memory to operate. The 1233d983712dSmrg * more there is, the more it can accelerate. 1234d983712dSmrg */ 1235d983712dSmrg 1236d983712dSmrg videoram_end = pScrn->videoRam * 1024; 1237d983712dSmrg offscreen_videoram = videoram_end - 1238d983712dSmrg pScrn->displayWidth * pScrn->virtualY * pTseng->Bytesperpixel; 1239d983712dSmrg xf86DrvMsgVerb(scrnIndex, X_INFO, v, "Available off-screen memory: %d bytes.\n", 1240d983712dSmrg offscreen_videoram); 1241d983712dSmrg 1242d983712dSmrg /* 1243d983712dSmrg * The HW cursor requires 1kb of off-screen memory, aligned to 1kb 1244d983712dSmrg * (256 DWORDS). Setting up its memory first ensures the alignment. 1245d983712dSmrg */ 1246d983712dSmrg if (pTseng->HWCursor) { 1247d983712dSmrg req_videoram = 1024; 1248d983712dSmrg if (offscreen_videoram < req_videoram) { 1249d983712dSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v, 1250d983712dSmrg "Hardware Cursor disabled. It requires %d bytes of free video memory\n", 1251d983712dSmrg req_videoram); 1252d983712dSmrg pTseng->HWCursor = FALSE; 1253d983712dSmrg pTseng->HWCursorBufferOffset = 0; 1254d983712dSmrg } else { 1255d983712dSmrg offscreen_videoram -= req_videoram; 1256d983712dSmrg videoram_end -= req_videoram; 1257d983712dSmrg pTseng->HWCursorBufferOffset = videoram_end; 1258d983712dSmrg } 1259d983712dSmrg } else { 1260d983712dSmrg pTseng->HWCursorBufferOffset = 0; 1261d983712dSmrg } 1262d983712dSmrg 1263d983712dSmrg /* 1264d983712dSmrg * Acceleration memory setup. Do this only if acceleration is enabled. 1265d983712dSmrg */ 1266d983712dSmrg if (!pTseng->UseAccel) return; 1267d983712dSmrg 1268d983712dSmrg /* 1269d983712dSmrg * Basic acceleration needs storage for FG, BG and PAT colors in 1270d983712dSmrg * off-screen memory. Each color requires 2(ping-pong)*8 bytes. 1271d983712dSmrg */ 1272d983712dSmrg req_videoram = 2 * 8 * 3; 1273d983712dSmrg if (offscreen_videoram < req_videoram) { 1274d983712dSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v, 1275d983712dSmrg "Acceleration disabled. It requires AT LEAST %d bytes of free video memory\n", 1276d983712dSmrg req_videoram); 1277d983712dSmrg pTseng->UseAccel = FALSE; 1278d983712dSmrg pTseng->AccelColorBufferOffset = 0; 1279d983712dSmrg goto end_memsetup; /* no basic acceleration means none at all */ 1280d983712dSmrg } else { 1281d983712dSmrg offscreen_videoram -= req_videoram; 1282d983712dSmrg videoram_end -= req_videoram; 1283d983712dSmrg pTseng->AccelColorBufferOffset = videoram_end; 1284d983712dSmrg } 1285d983712dSmrg 1286d983712dSmrg /* 1287d983712dSmrg * Color expansion (using triple buffering) requires 3 non-expanded 1288d983712dSmrg * scanlines, DWORD padded. 1289d983712dSmrg */ 1290d983712dSmrg req_videoram = 3 * ((pScrn->virtualX + 31) / 32) * 4; 1291d983712dSmrg if (offscreen_videoram < req_videoram) { 1292d983712dSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v, 1293d983712dSmrg "Accelerated color expansion disabled (%d more bytes of free video memory required)\n", 1294d983712dSmrg req_videoram - offscreen_videoram); 1295d983712dSmrg pTseng->AccelColorExpandBufferOffsets[0] = 0; 1296d983712dSmrg } else { 1297d983712dSmrg offscreen_videoram -= req_videoram; 1298d983712dSmrg for (i = 0; i < 3; i++) { 1299d983712dSmrg videoram_end -= req_videoram / 3; 1300d983712dSmrg pTseng->AccelColorExpandBufferOffsets[i] = videoram_end; 1301d983712dSmrg } 1302d983712dSmrg } 1303d983712dSmrg 1304d983712dSmrg /* 1305d983712dSmrg * XAA ImageWrite support needs two entire line buffers. The 1306d983712dSmrg * current code assumes buffer 1 lies in the same 8kb aperture as 1307d983712dSmrg * buffer 0. 1308d983712dSmrg * 1309d983712dSmrg * [ FIXME: aren't we forgetting the DWORD padding here ? ] 1310d983712dSmrg * [ FIXME: why here double-buffering and in colexp triple-buffering? ] 1311d983712dSmrg */ 1312d983712dSmrg req_videoram = 2 * (pScrn->virtualX * pTseng->Bytesperpixel); 1313d983712dSmrg 1314d983712dSmrg if (offscreen_videoram < req_videoram) { 1315d983712dSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v, 1316d983712dSmrg "Accelerated ImageWrites disabled (%d more bytes of free video memory required)\n", 1317d983712dSmrg req_videoram - offscreen_videoram); 1318d983712dSmrg pTseng->AccelImageWriteBufferOffsets[0] = 0; 1319d983712dSmrg } else { 1320d983712dSmrg offscreen_videoram -= req_videoram; 1321d983712dSmrg for (i = 0; i < 2; i++) { 1322d983712dSmrg videoram_end -= req_videoram / 2; 1323d983712dSmrg pTseng->AccelImageWriteBufferOffsets[i] = videoram_end; 1324d983712dSmrg } 1325d983712dSmrg } 1326d983712dSmrg 1327d983712dSmrg xf86DrvMsgVerb(scrnIndex, X_INFO, v, 1328d983712dSmrg "Remaining off-screen memory available for pixmap cache: %d bytes.\n", 1329d983712dSmrg offscreen_videoram); 1330d983712dSmrg 1331d983712dSmrgend_memsetup: 1332d983712dSmrg pScrn->videoRam = videoram_end / 1024; 1333d983712dSmrg} 1334d983712dSmrg 1335d983712dSmrgstatic Bool 1336d983712dSmrgTsengScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) 1337d983712dSmrg{ 1338d983712dSmrg ScrnInfoPtr pScrn; 1339d983712dSmrg TsengPtr pTseng; 1340d983712dSmrg int ret; 1341d983712dSmrg VisualPtr visual; 1342d983712dSmrg 1343d983712dSmrg PDEBUG(" TsengScreenInit\n"); 1344d983712dSmrg 1345d983712dSmrg /* 1346d983712dSmrg * First get the ScrnInfoRec 1347d983712dSmrg */ 1348d983712dSmrg pScrn = xf86Screens[pScreen->myNum]; 1349d983712dSmrg 1350d983712dSmrg pTseng = TsengPTR(pScrn); 1351d983712dSmrg /* Map the Tseng memory areas */ 1352d983712dSmrg if (!TsengMapMem(pScrn)) 1353d983712dSmrg return FALSE; 1354d983712dSmrg 1355d983712dSmrg /* Save the current state */ 1356d983712dSmrg TsengSave(pScrn); 1357d983712dSmrg 1358d983712dSmrg /* Initialise the first mode */ 1359d983712dSmrg TsengModeInit(pScrn, pScrn->currentMode); 1360d983712dSmrg 1361d983712dSmrg /* Darken the screen for aesthetic reasons and set the viewport */ 1362d983712dSmrg TsengSaveScreen(pScreen, SCREEN_SAVER_ON); 1363d983712dSmrg 1364d983712dSmrg TsengAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 1365d983712dSmrg /* XXX Fill the screen with black */ 1366d983712dSmrg 1367d983712dSmrg /* 1368d983712dSmrg * Reset visual list. 1369d983712dSmrg */ 1370d983712dSmrg miClearVisualTypes(); 1371d983712dSmrg 1372d983712dSmrg /* Setup the visuals we support. */ 1373d983712dSmrg 1374d983712dSmrg /* 1375d983712dSmrg * For bpp > 8, the default visuals are not acceptable because we only 1376d983712dSmrg * support TrueColor and not DirectColor. To deal with this, call 1377d983712dSmrg * miSetVisualTypes for each visual supported. 1378d983712dSmrg */ 1379d983712dSmrg if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), 1380d983712dSmrg pScrn->rgbBits, pScrn->defaultVisual)) 1381d983712dSmrg return FALSE; 1382d983712dSmrg 1383d983712dSmrg miSetPixmapDepths (); 1384d983712dSmrg 1385d983712dSmrg /* 1386d983712dSmrg * Call the framebuffer layer's ScreenInit function, and fill in other 1387d983712dSmrg * pScreen fields. 1388d983712dSmrg */ 1389d983712dSmrg 1390d983712dSmrg switch (pScrn->bitsPerPixel) { 1391962c3257Smrg#if HAVE_XF1BPP 1392d983712dSmrg case 1: 1393d983712dSmrg ret = xf1bppScreenInit(pScreen, pTseng->FbBase, 1394d983712dSmrg pScrn->virtualX, pScrn->virtualY, 1395d983712dSmrg pScrn->xDpi, pScrn->yDpi, 1396d983712dSmrg pScrn->displayWidth); 1397d983712dSmrg break; 1398962c3257Smrg#endif 1399962c3257Smrg#if HAVE_XF4BPP 1400d983712dSmrg case 4: 1401d983712dSmrg ret = xf4bppScreenInit(pScreen, pTseng->FbBase, 1402d983712dSmrg pScrn->virtualX, pScrn->virtualY, 1403d983712dSmrg pScrn->xDpi, pScrn->yDpi, 1404d983712dSmrg pScrn->displayWidth); 1405d983712dSmrg break; 1406962c3257Smrg#endif 1407d983712dSmrg default: 1408d983712dSmrg ret = fbScreenInit(pScreen, pTseng->FbBase, 1409d983712dSmrg pScrn->virtualX, pScrn->virtualY, 1410d983712dSmrg pScrn->xDpi, pScrn->yDpi, 1411d983712dSmrg pScrn->displayWidth, pScrn->bitsPerPixel); 1412d983712dSmrg break; 1413d983712dSmrg } 1414d983712dSmrg 1415d983712dSmrg if (!ret) 1416d983712dSmrg return FALSE; 1417d983712dSmrg 1418d983712dSmrg xf86SetBlackWhitePixels(pScreen); 1419d983712dSmrg 1420d983712dSmrg if (pScrn->bitsPerPixel > 8) { 1421d983712dSmrg /* Fixup RGB ordering */ 1422d983712dSmrg visual = pScreen->visuals + pScreen->numVisuals; 1423d983712dSmrg while (--visual >= pScreen->visuals) { 1424d983712dSmrg if ((visual->class | DynamicClass) == DirectColor) { 1425d983712dSmrg visual->offsetRed = pScrn->offset.red; 1426d983712dSmrg visual->offsetGreen = pScrn->offset.green; 1427d983712dSmrg visual->offsetBlue = pScrn->offset.blue; 1428d983712dSmrg visual->redMask = pScrn->mask.red; 1429d983712dSmrg visual->greenMask = pScrn->mask.green; 1430d983712dSmrg visual->blueMask = pScrn->mask.blue; 1431d983712dSmrg } 1432d983712dSmrg } 1433d983712dSmrg } 1434d983712dSmrg 1435962c3257Smrg#if HAVE_XF1BPP 1436d983712dSmrg /* must be after RGB ordering fixed */ 1437d983712dSmrg if (pScrn->bitsPerPixel > 4) 1438962c3257Smrg#endif 1439d983712dSmrg fbPictureInit(pScreen, 0, 0); 1440d983712dSmrg 1441d983712dSmrg if (pScrn->depth >= 8) 1442d983712dSmrg TsengDGAInit(pScreen); 1443d983712dSmrg 1444d983712dSmrg /* 1445d983712dSmrg * Initialize the acceleration interface. 1446d983712dSmrg */ 1447d983712dSmrg TsengSetupAccelMemory(scrnIndex, pScreen); 1448d983712dSmrg if (pTseng->UseAccel) { 1449d983712dSmrg tseng_init_acl(pScrn); /* set up accelerator */ 1450d983712dSmrg if (!TsengXAAInit(pScreen)) { /* set up XAA interface */ 1451d983712dSmrg return FALSE; 1452d983712dSmrg } 1453d983712dSmrg } 1454d983712dSmrg 1455d983712dSmrg miInitializeBackingStore(pScreen); 1456d983712dSmrg xf86SetSilkenMouse(pScreen); 1457d983712dSmrg /* Initialise cursor functions */ 1458d983712dSmrg miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); 1459d983712dSmrg 1460d983712dSmrg /* Hardware Cursor layer */ 1461d983712dSmrg if (pTseng->HWCursor) { 1462d983712dSmrg if (!TsengHWCursorInit(pScreen)) 1463d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1464d983712dSmrg "Hardware cursor initialization failed\n"); 1465d983712dSmrg } 1466d983712dSmrg 1467d983712dSmrg /* Initialise default colourmap */ 1468d983712dSmrg if (!miCreateDefColormap(pScreen)) 1469d983712dSmrg return FALSE; 1470d983712dSmrg 1471d983712dSmrg if (pScrn->depth == 4 || pScrn->depth == 8) { /* fb and xf4bpp */ 1472d983712dSmrg vgaHWHandleColormaps(pScreen); 1473d983712dSmrg } 1474d03ff4acSmrg#ifndef XSERVER_LIBPCIACCESS 1475d983712dSmrg pScrn->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT; 1476d983712dSmrg pScrn->racMemFlags = pScrn->racIoFlags; 1477d03ff4acSmrg#endif 1478d983712dSmrg /* Wrap the current CloseScreen and SaveScreen functions */ 1479d983712dSmrg pScreen->SaveScreen = TsengSaveScreen; 1480d983712dSmrg 1481d983712dSmrg /* Support for DPMS, the ET4000W32Pc and newer uses a different and 1482d983712dSmrg * simpler method than the older cards. 1483d983712dSmrg */ 1484d983712dSmrg if ((pTseng->ChipType == ET4000) && 1485d983712dSmrg ((pTseng->ChipRev == REV_A) || (pTseng->ChipRev == REV_B))) 1486d983712dSmrg xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengHVSyncDPMSSet, 0); 1487d983712dSmrg else 1488d983712dSmrg xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengCrtcDPMSSet, 0); 1489d983712dSmrg 1490d983712dSmrg pTseng->CloseScreen = pScreen->CloseScreen; 1491d983712dSmrg pScreen->CloseScreen = TsengCloseScreen; 1492d983712dSmrg 1493d983712dSmrg /* Report any unused options (only for the first generation) */ 1494d983712dSmrg if (serverGeneration == 1) { 1495d983712dSmrg xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 1496d983712dSmrg } 1497d983712dSmrg /* Done */ 1498d983712dSmrg return TRUE; 1499d983712dSmrg} 1500d983712dSmrg 1501d983712dSmrgstatic Bool 1502d983712dSmrgTsengEnterVT(int scrnIndex, int flags) 1503d983712dSmrg{ 1504d983712dSmrg ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 1505d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 1506d983712dSmrg 1507d983712dSmrg PDEBUG(" TsengEnterVT\n"); 1508d983712dSmrg 1509d983712dSmrg vgaHWUnlock(VGAHWPTR(pScrn)); 1510d983712dSmrg TsengUnlock(pScrn); 1511d983712dSmrg 1512d983712dSmrg if (!TsengModeInit(pScrn, pScrn->currentMode)) 1513d983712dSmrg return FALSE; 1514d983712dSmrg if (pTseng->UseAccel) { 1515d983712dSmrg tseng_init_acl(pScrn); /* set up accelerator */ 1516d983712dSmrg } 1517d983712dSmrg return TRUE; 1518d983712dSmrg} 1519d983712dSmrg 1520d983712dSmrgstatic void 1521d983712dSmrgTsengLeaveVT(int scrnIndex, int flags) 1522d983712dSmrg{ 1523d983712dSmrg ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 1524d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 1525d983712dSmrg 1526d983712dSmrg PDEBUG(" TsengLeaveVT\n"); 1527d983712dSmrg TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg), 1528d983712dSmrg &pTseng->SavedReg,VGA_SR_ALL); 1529d983712dSmrg 1530d983712dSmrg TsengLock(pScrn); 1531d983712dSmrg vgaHWLock(VGAHWPTR(pScrn)); 1532d983712dSmrg} 1533d983712dSmrg 1534d983712dSmrgstatic Bool 1535d983712dSmrgTsengCloseScreen(int scrnIndex, ScreenPtr pScreen) 1536d983712dSmrg{ 1537d983712dSmrg ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 1538d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 1539d983712dSmrg 1540d983712dSmrg PDEBUG(" TsengCloseScreen\n"); 1541d983712dSmrg 1542d983712dSmrg if (pScrn->vtSema) { 1543d983712dSmrg TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg), 1544d983712dSmrg &(pTseng->SavedReg),VGA_SR_ALL); 1545d983712dSmrg TsengUnmapMem(pScrn); 1546d983712dSmrg } 1547d983712dSmrg if (pTseng->AccelInfoRec) 1548d983712dSmrg XAADestroyInfoRec(pTseng->AccelInfoRec); 1549d983712dSmrg if (pTseng->CursorInfoRec) 1550d983712dSmrg xf86DestroyCursorInfoRec(pTseng->CursorInfoRec); 1551d983712dSmrg 1552d983712dSmrg pScrn->vtSema = FALSE; 1553d983712dSmrg 1554d983712dSmrg pScreen->CloseScreen = pTseng->CloseScreen; 1555d983712dSmrg return (*pScreen->CloseScreen) (scrnIndex, pScreen); 1556d983712dSmrg} 1557d983712dSmrg 1558d983712dSmrg/* 1559d983712dSmrg * SaveScreen -- 1560d983712dSmrg * 1561d983712dSmrg * perform a sequencer reset. 1562d983712dSmrg * 1563d983712dSmrg * The ET4000 "Video System Configuration 1" register (CRTC index 0x36), 1564d983712dSmrg * which is used to set linear memory mode and MMU-related stuff, is 1565d983712dSmrg * partially reset to "0" when TS register index 0 bit 1 is set (synchronous 1566d983712dSmrg * reset): bits 3..5 are reset during a sync. reset. 1567d983712dSmrg * 1568d983712dSmrg * We therefor do _not_ call vgaHWSaveScreen here, since it does a sequencer 1569d983712dSmrg * reset. Instead, we do the same as in vgaHWSaveScreen except for the seq. reset. 1570d983712dSmrg * 1571d983712dSmrg * If this is not done, the higher level code will not be able to access the 1572d983712dSmrg * framebuffer (because it is temporarily in banked mode instead of linear 1573d983712dSmrg * mode) as long as SaveScreen is active (=in between a 1574d983712dSmrg * SaveScreen(FALSE)/SaveScreen(TRUE) pair) 1575d983712dSmrg */ 1576d983712dSmrg 1577d983712dSmrgstatic Bool 1578d983712dSmrgTsengSaveScreen(ScreenPtr pScreen, int mode) 1579d983712dSmrg{ 1580d983712dSmrg ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1581d983712dSmrg vgaHWPtr hwp = VGAHWPTR(pScrn); 1582d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 1583d983712dSmrg Bool unblank; 1584d983712dSmrg 1585d983712dSmrg PDEBUG(" TsengSaveScreen\n"); 1586d983712dSmrg 1587d983712dSmrg unblank = xf86IsUnblank(mode); 1588d983712dSmrg 1589d983712dSmrg if (pTseng->ChipType == ET6000) { 1590d983712dSmrg return vgaHWSaveScreen(pScreen, unblank); 1591d983712dSmrg } else { 1592d983712dSmrg if (unblank) 1593d983712dSmrg SetTimeSinceLastInputEvent(); 1594d983712dSmrg 1595d983712dSmrg if (pScrn->vtSema) { 1596d983712dSmrg /* vgaHWBlankScreen without seq reset */ 1597d983712dSmrg CARD8 scrn; 1598d983712dSmrg 1599d983712dSmrg scrn = hwp->readSeq(hwp, 0x01); 1600d983712dSmrg 1601d983712dSmrg if (unblank) 1602d983712dSmrg scrn &= 0xDF; /* enable screen */ 1603d983712dSmrg else 1604d983712dSmrg scrn |= 0x20; /* blank screen */ 1605d983712dSmrg 1606d983712dSmrg hwp->writeSeq(hwp, 0x01, scrn); /* change mode */ 1607d983712dSmrg } 1608d983712dSmrg return (TRUE); 1609d983712dSmrg } 1610d983712dSmrg} 1611d983712dSmrg 1612d983712dSmrgstatic Bool 1613d983712dSmrgTsengMapMem(ScrnInfoPtr pScrn) 1614d983712dSmrg{ 1615d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 1616d983712dSmrg 1617d983712dSmrg PDEBUG(" TsengMapMem\n"); 1618d983712dSmrg 1619d983712dSmrg /* Map the VGA memory */ 1620d983712dSmrg 1621d983712dSmrg if (!vgaHWMapMem(pScrn)) { 1622d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1623d983712dSmrg "Could not mmap standard VGA memory aperture.\n"); 1624d983712dSmrg return FALSE; 1625d983712dSmrg } 1626d983712dSmrg 1627962c3257Smrg#ifndef XSERVER_LIBPCIACCESS 1628d983712dSmrg pTseng->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, 1629d983712dSmrg pTseng->PciTag, 1630d983712dSmrg (unsigned long)pTseng->FbAddress, 1631d983712dSmrg pTseng->FbMapSize); 1632962c3257Smrg#else 1633962c3257Smrg { 1634962c3257Smrg void** result = (void**)&pTseng->FbBase; 1635962c3257Smrg int err = pci_device_map_range(pTseng->PciInfo, 1636962c3257Smrg pTseng->FbAddress, 1637962c3257Smrg pTseng->FbMapSize, 1638962c3257Smrg PCI_DEV_MAP_FLAG_WRITABLE | 1639962c3257Smrg PCI_DEV_MAP_FLAG_WRITE_COMBINE, 1640962c3257Smrg result); 1641962c3257Smrg 1642962c3257Smrg if (err) 1643962c3257Smrg return FALSE; 1644962c3257Smrg } 1645962c3257Smrg#endif 1646d983712dSmrg if (pTseng->FbBase == NULL) { 1647d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1648d983712dSmrg "Could not mmap linear video memory.\n"); 1649d983712dSmrg return FALSE; 1650d983712dSmrg } 1651d983712dSmrg 1652d983712dSmrg /* need some sanity here */ 1653d983712dSmrg if (pTseng->UseAccel) { 1654962c3257Smrg#ifndef XSERVER_LIBPCIACCESS 1655d983712dSmrg pTseng->MMioBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, 1656d983712dSmrg pTseng->PciTag, 1657d983712dSmrg (unsigned long)pTseng->FbAddress, 1658d983712dSmrg pTseng->FbMapSize); 1659962c3257Smrg#else 1660962c3257Smrg pTseng->MMioBase = pTseng->FbBase; 1661962c3257Smrg#endif 1662d983712dSmrg if (!pTseng->MMioBase) { 1663d983712dSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1664d983712dSmrg "Could not mmap mmio memory.\n"); 1665d983712dSmrg return FALSE; 1666d983712dSmrg } 1667d983712dSmrg pTseng->MMioBase += 0x3FFF00L; 1668d983712dSmrg } 1669d983712dSmrg 1670d983712dSmrg if (pTseng->FbBase == NULL) 1671d983712dSmrg return FALSE; 1672d983712dSmrg 1673d983712dSmrg return TRUE; 1674d983712dSmrg} 1675d983712dSmrg 1676d983712dSmrgstatic Bool 1677d983712dSmrgTsengUnmapMem(ScrnInfoPtr pScrn) 1678d983712dSmrg{ 1679d983712dSmrg TsengPtr pTseng = TsengPTR(pScrn); 1680d983712dSmrg 1681d983712dSmrg PDEBUG(" TsengUnmapMem\n"); 1682d983712dSmrg 1683962c3257Smrg#ifndef XSERVER_LIBPCIACCESS 1684d983712dSmrg xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pTseng->FbBase, pTseng->FbMapSize); 1685962c3257Smrg#else 1686962c3257Smrg pci_device_unmap_range(pTseng->PciInfo, pTseng->FbBase, pTseng->FbMapSize); 1687962c3257Smrg#endif 1688d983712dSmrg 1689d983712dSmrg vgaHWUnmapMem(pScrn); 1690d983712dSmrg 1691d983712dSmrg pTseng->FbBase = NULL; 1692d983712dSmrg 1693d983712dSmrg return TRUE; 1694d983712dSmrg} 1695d983712dSmrg 1696d983712dSmrgstatic void 1697d983712dSmrgTsengFreeScreen(int scrnIndex, int flags) 1698d983712dSmrg{ 1699d983712dSmrg PDEBUG(" TsengFreeScreen\n"); 1700d983712dSmrg if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) 1701d983712dSmrg vgaHWFreeHWRec(xf86Screens[scrnIndex]); 1702d983712dSmrg TsengFreeRec(xf86Screens[scrnIndex]); 1703d983712dSmrg} 1704d983712dSmrg 1705d983712dSmrgstatic Bool 1706d983712dSmrgTsengSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) 1707d983712dSmrg{ 1708d983712dSmrg PDEBUG(" TsengSwitchMode\n"); 1709d983712dSmrg return TsengModeInit(xf86Screens[scrnIndex], mode); 1710d983712dSmrg} 1711