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