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