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