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