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