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