apm_driver.c revision 17a48c7c
1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/apm/apm_driver.c,v 1.65 2003/10/30 17:36:57 tsi Exp $ */ 2 3#ifdef HAVE_CONFIG_H 4#include "config.h" 5#endif 6 7#include "apm.h" 8#include "xf86cmap.h" 9#include "shadowfb.h" 10#include "xf86Resources.h" 11#include "xf86int10.h" 12#include "xf86RAC.h" 13#include "vbe.h" 14 15#include "opaque.h" 16#define DPMS_SERVER 17#include <X11/extensions/dpms.h> 18 19#define APM_VERSION 4000 20#define APM_NAME "APM" 21#define APM_DRIVER_NAME "apm" 22#define APM_MAJOR_VERSION 1 23#define APM_MINOR_VERSION 1 24#define APM_PATCHLEVEL 1 25#ifndef PCI_CHIP_AT3D 26#define PCI_CHIP_AT3D 0x643D 27#endif 28 29/* bytes to save for text/font data */ 30#define TEXT_AMOUNT 32768 31 32/* Mandatory functions */ 33static const OptionInfoRec * ApmAvailableOptions(int chipid, int busid); 34static void ApmIdentify(int flags); 35static Bool ApmProbe(DriverPtr drv, int flags); 36static Bool ApmPreInit(ScrnInfoPtr pScrn, int flags); 37static Bool ApmScreenInit(int Index, ScreenPtr pScreen, int argc, 38 char **argv); 39static Bool ApmEnterVT(int scrnIndex, int flags); 40static void ApmLeaveVT(int scrnIndex, int flags); 41static Bool ApmCloseScreen(int scrnIndex, ScreenPtr pScreen); 42static void ApmFreeScreen(int scrnIndex, int flags); 43static ModeStatus ApmValidMode(int scrnIndex, DisplayModePtr mode, 44 Bool verbose, int flags); 45static Bool ApmSaveScreen(ScreenPtr pScreen, int mode); 46static void ApmUnlock(ApmPtr pApm); 47static void ApmLock(ApmPtr pApm); 48static void ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, 49 ApmRegPtr ApmReg); 50static void ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, 51 LOCO *colors, VisualPtr pVisual); 52static void ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn, 53 int PowerManagementMode, 54 int flags); 55static void ApmProbeDDC(ScrnInfoPtr pScrn, int index); 56 57 58int ApmPixmapIndex = -1; 59static unsigned long ApmGeneration = 0; 60 61_X_EXPORT DriverRec APM = { 62 APM_VERSION, 63 APM_DRIVER_NAME, 64 ApmIdentify, 65 ApmProbe, 66 ApmAvailableOptions, 67 NULL, 68 0 69}; 70 71static SymTabRec ApmChipsets[] = { 72 { AP6422, "AP6422" }, 73 { AT24, "AT24" }, 74 { AT3D, "AT3D" }, 75 { -1, NULL } 76}; 77 78static PciChipsets ApmPciChipsets[] = { 79 { PCI_CHIP_AP6422, PCI_CHIP_AP6422, RES_SHARED_VGA }, 80 { PCI_CHIP_AT24, PCI_CHIP_AT24, RES_SHARED_VGA }, 81 { PCI_CHIP_AT3D, PCI_CHIP_AT3D, RES_SHARED_VGA }, 82 { -1, -1, RES_UNDEFINED } 83}; 84 85static IsaChipsets ApmIsaChipsets[] = { 86 { PCI_CHIP_AP6422, RES_EXCLUSIVE_VGA}, 87 {-1, RES_UNDEFINED} 88}; 89 90typedef enum { 91 OPTION_SET_MCLK, 92 OPTION_SW_CURSOR, 93 OPTION_HW_CURSOR, 94 OPTION_NOLINEAR, 95 OPTION_NOACCEL, 96 OPTION_SHADOW_FB, 97 OPTION_PCI_BURST, 98 OPTION_REMAP_DPMS_ON, 99 OPTION_REMAP_DPMS_STANDBY, 100 OPTION_REMAP_DPMS_SUSPEND, 101 OPTION_REMAP_DPMS_OFF, 102 OPTION_PCI_RETRY 103} ApmOpts; 104 105static const OptionInfoRec ApmOptions[] = 106{ 107 {OPTION_SET_MCLK, "SetMclk", OPTV_FREQ, 108 {0}, FALSE}, 109 {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, 110 {0}, FALSE}, 111 {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, 112 {0}, TRUE}, 113 {OPTION_NOLINEAR, "NoLinear", OPTV_BOOLEAN, 114 {0}, FALSE}, 115 {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, 116 {0}, FALSE}, 117 {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, 118 {0}, FALSE}, 119 {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN, 120 {0}, FALSE}, 121 {OPTION_REMAP_DPMS_ON, "Remap_DPMS_On", OPTV_ANYSTR, 122 {0}, FALSE}, 123 {OPTION_REMAP_DPMS_STANDBY, "Remap_DPMS_Standby", OPTV_ANYSTR, 124 {0}, FALSE}, 125 {OPTION_REMAP_DPMS_SUSPEND, "Remap_DPMS_Suspend", OPTV_ANYSTR, 126 {0}, FALSE}, 127 {OPTION_REMAP_DPMS_OFF, "Remap_DPMS_Off", OPTV_ANYSTR, 128 {0}, FALSE}, 129 {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN, 130 {0}, FALSE}, 131 {-1, NULL, OPTV_NONE, 132 {0}, FALSE} 133}; 134 135/* 136 * List of symbols from other modules that this module references. This 137 * list is used to tell the loader that it is OK for symbols here to be 138 * unresolved providing that it hasn't been told that they haven't been 139 * told that they are essential via a call to xf86LoaderReqSymbols() or 140 * xf86LoaderReqSymLists(). The purpose is this is to avoid warnings about 141 * unresolved symbols that are not required. 142 */ 143 144static const char *vgahwSymbols[] = { 145 "vgaHWBlankScreen", 146 "vgaHWCursor", 147 "vgaHWFreeHWRec", 148 "vgaHWGetHWRec", 149 "vgaHWGetIOBase", 150 "vgaHWInit", 151 "vgaHWLock", 152 "vgaHWMapMem", 153 "vgaHWProtect", 154 "vgaHWRestore", 155 "vgaHWSave", 156 "vgaHWSetMmioFuncs", 157 "vgaHWUnlock", 158 NULL 159}; 160 161static const char *xaaSymbols[] = { 162 "XAACreateInfoRec", 163 "XAACursorInfoRec", 164 "XAACursorInit", 165 "XAADestroyInfoRec", 166 "XAAGlyphScanlineFuncLSBFirst", 167 "XAAInit", 168 "XAAReverseBitOrder", 169 "XAAStippleScanlineFuncMSBFirst", 170 NULL 171}; 172 173static const char *ramdacSymbols[] = { 174 "xf86CreateCursorInfoRec", 175 "xf86DestroyCursorInfoRec", 176 "xf86InitCursor", 177 NULL 178}; 179 180#ifdef XFree86LOADER 181static const char *vbeSymbols[] = { 182 "VBEInit", 183 "vbeDoEDID", 184 "vbeFree", 185 NULL 186}; 187#endif 188 189static const char *ddcSymbols[] = { 190 "xf86DoEDID_DDC1", 191 "xf86DoEDID_DDC2", 192 "xf86PrintEDID", 193 NULL 194}; 195 196static const char *i2cSymbols[] = { 197 "xf86CreateI2CBusRec", 198 "xf86I2CBusInit", 199 NULL 200}; 201 202static const char *shadowSymbols[] = { 203 "ShadowFBInit", 204 NULL 205}; 206 207#ifdef XFree86LOADER 208static const char *miscfbSymbols[] = { 209 "xf1bppScreenInit", 210 "xf4bppScreenInit", 211 NULL 212}; 213#endif 214 215static const char *fbSymbols[] = { 216 "fbPictureInit", 217 "fbScreenInit", 218 NULL 219}; 220 221static const char *int10Symbols[] = { 222 "xf86Free10", 223 "xf86InitInt10", 224 NULL 225}; 226 227#ifdef XFree86LOADER 228 229static XF86ModuleVersionInfo apmVersRec = { 230 "apm", 231 MODULEVENDORSTRING, 232 MODINFOSTRING1, 233 MODINFOSTRING2, 234 XORG_VERSION_CURRENT, 235 APM_MAJOR_VERSION, APM_MINOR_VERSION, APM_PATCHLEVEL, 236 ABI_CLASS_VIDEODRV, /* This is a video driver */ 237 ABI_VIDEODRV_VERSION, 238 MOD_CLASS_VIDEODRV, 239 {0,0,0,0} 240}; 241 242static MODULESETUPPROTO(apmSetup); 243 244/* 245 * This is the module init data. 246 * Its name has to be the driver name followed by ModuleData. 247 */ 248_X_EXPORT XF86ModuleData apmModuleData = { &apmVersRec, apmSetup, NULL }; 249 250static pointer 251apmSetup(pointer module, pointer opts, int *errmaj, int *errmain) 252{ 253 static Bool setupDone = FALSE; 254 255 if (!setupDone) { 256 setupDone = TRUE; 257 xf86AddDriver(&APM, module, 0); 258 259 LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, 260 miscfbSymbols, ramdacSymbols, vbeSymbols, 261 ddcSymbols, i2cSymbols, shadowSymbols, 262 int10Symbols, NULL); 263 264 return (pointer)1; 265 } 266 else { 267 if (errmaj) *errmaj = LDR_ONCEONLY; 268 return NULL; 269 } 270} 271#endif 272 273static Bool 274ApmGetRec(ScrnInfoPtr pScrn) 275{ 276 if (pScrn->driverPrivate) 277 return TRUE; 278 pScrn->driverPrivate = xnfcalloc(sizeof(ApmRec), 1); 279 /* pScrn->driverPrivate != NULL at this point */ 280 281 return TRUE; 282} 283 284static void 285ApmFreeRec(ScrnInfoPtr pScrn) 286{ 287 if (pScrn->driverPrivate) { 288 xfree(pScrn->driverPrivate); 289 pScrn->driverPrivate = NULL; 290 } 291} 292 293 294/* unlock Alliance registers */ 295static void 296ApmUnlock(ApmPtr pApm) 297{ 298 if (pApm->Chipset >= AT3D && !pApm->noLinear) 299 ApmWriteSeq(0x10, 0x12); 300 else 301 wrinx(pApm->xport, 0x10, 0x12); 302} 303 304/* lock Alliance registers */ 305static void 306ApmLock(ApmPtr pApm) 307{ 308 if (pApm->Chipset >= AT3D && !pApm->noLinear) 309 ApmWriteSeq(0x10, pApm->savedSR10 ? 0 : 0x12); 310 else 311 wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12); 312} 313 314static void 315ApmIdentify(int flags) 316{ 317 xf86PrintChipsets(APM_NAME, "driver for the Alliance chipsets", 318 ApmChipsets); 319} 320 321static const OptionInfoRec * 322ApmAvailableOptions(int chipid, int busid) 323{ 324 return ApmOptions; 325} 326 327static int 328ApmFindIsaDevice(GDevPtr dev) 329{ 330 char save = rdinx(0x3C4, 0x10); 331 int i; 332 int apmChip = -1; 333 334 /* 335 * Start by probing the VGA chipset. 336 */ 337 outw(0x3C4, 0x1210); 338 if (rdinx(0x3C4, 0x11) == 'P' && rdinx(0x3C4, 0x12) == 'r' && 339 rdinx(0x3C4, 0x13) == 'o') { 340 char id_ap6420[] = "6420"; 341 char id_ap6422[] = "6422"; 342 char id_at24[] = "6424"; 343 char id_at3d[] = "AT3D"; 344 char idstring[] = " "; 345 346 /* 347 * Must be an Alliance !!! 348 */ 349 for (i = 0; i < 4; i++) 350 idstring[i] = rdinx(0x3C4, 0x14 + i); 351 if (!memcmp(id_ap6420, idstring, 4) || 352 !memcmp(id_ap6422, idstring, 4)) 353 apmChip = AP6422; 354 else if (!memcmp(id_at24, idstring, 4)) 355 apmChip = AT24; 356 else if (!memcmp(id_at3d, idstring, 4)) 357 apmChip = AT3D; 358 if (apmChip >= 0) { 359 int apm_xbase; 360 361 apm_xbase = (rdinx(0x3C4, 0x1F) << 8) | rdinx(0x3C4, 0x1E); 362 363 if (!(wrinx(0x3C4, 0x1D, 0xCA >> 2), inb(apm_xbase + 2))) { 364 /* 365 * TODO Not PCI 366 */ 367 } 368 369 } 370 } 371 wrinx(0x3C4, 0x10, save); 372 373 return apmChip; 374} 375 376static void 377ApmAssignFPtr(ScrnInfoPtr pScrn) 378{ 379 pScrn->driverVersion = APM_VERSION; 380 pScrn->driverName = APM_DRIVER_NAME; 381 pScrn->name = APM_NAME; 382 pScrn->Probe = ApmProbe; 383 pScrn->PreInit = ApmPreInit; 384 pScrn->ScreenInit = ApmScreenInit; 385 pScrn->SwitchMode = ApmSwitchMode; 386 pScrn->AdjustFrame = ApmAdjustFrame; 387 pScrn->EnterVT = ApmEnterVT; 388 pScrn->LeaveVT = ApmLeaveVT; 389 pScrn->FreeScreen = ApmFreeScreen; 390 pScrn->ValidMode = ApmValidMode; 391} 392 393static Bool 394ApmProbe(DriverPtr drv, int flags) 395{ 396 int numDevSections, numUsed, i; 397 GDevPtr *DevSections; 398 int *usedChips; 399 int foundScreen = FALSE; 400 401 /* 402 * Check if there is a chipset override in the config file 403 */ 404 if ((numDevSections = xf86MatchDevice(APM_DRIVER_NAME, 405 &DevSections)) <= 0) 406 return FALSE; 407 408 /* 409 * We need to probe the hardware first. We then need to see how this 410 * fits in with what is given in the config file, and allow the config 411 * file info to override any contradictions. 412 */ 413 414 if (xf86GetPciVideoInfo() == NULL) { 415 return FALSE; 416 } 417 numUsed = xf86MatchPciInstances(APM_NAME, PCI_VENDOR_ALLIANCE, 418 ApmChipsets, ApmPciChipsets, DevSections, numDevSections, 419 drv, &usedChips); 420 421 if (numUsed > 0) { 422 if (flags & PROBE_DETECT) 423 foundScreen = TRUE; 424 else for (i = 0; i < numUsed; i++) { 425 ScrnInfoPtr pScrn; 426 427 /* 428 * Allocate a ScrnInfoRec and claim the slot 429 */ 430 pScrn = NULL; 431 if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], 432 ApmPciChipsets, NULL, 433 NULL,NULL,NULL,NULL))){ 434 435 /* 436 * Fill in what we can of the ScrnInfoRec 437 */ 438 ApmAssignFPtr(pScrn); 439 foundScreen = TRUE; 440 } 441 } 442 } 443 444 /* Check for non-PCI cards */ 445 numUsed = xf86MatchIsaInstances(APM_NAME, ApmChipsets, 446 ApmIsaChipsets, drv, ApmFindIsaDevice, DevSections, 447 numDevSections, &usedChips); 448 if (numUsed > 0) { 449 if (flags & PROBE_DETECT) 450 foundScreen = TRUE; 451 else for (i = 0; i < numUsed; i++) { 452 ScrnInfoPtr pScrn = NULL; 453 if ((pScrn = xf86ConfigIsaEntity(pScrn, 0, usedChips[i], 454 ApmIsaChipsets, NULL, NULL, NULL, 455 NULL, NULL))) { 456 /* 457 * Fill in what we can of the ScrnInfoRec 458 */ 459 ApmAssignFPtr(pScrn); 460 foundScreen = TRUE; 461 } 462 } 463 } 464 xfree(DevSections); 465 return foundScreen; 466} 467 468/* 469 * GetAccelPitchValues - 470 * 471 * This function returns a list of display width (pitch) values that can 472 * be used in accelerated mode. 473 */ 474static int * 475GetAccelPitchValues(ScrnInfoPtr pScrn) 476{ 477 int *linePitches = NULL; 478 int linep[] = {640, 800, 1024, 1152, 1280, 0}; 479 480 if (sizeof linep > 0) { 481 linePitches = (int *)xnfalloc(sizeof linep); 482 memcpy(linePitches, linep, sizeof linep); 483 } 484 485 return linePitches; 486} 487 488static unsigned int 489ddc1Read(ScrnInfoPtr pScrn) 490{ 491 APMDECL(pScrn); 492 unsigned char tmp; 493 494 tmp = RDXB_IOP(0xD0); 495 WRXB_IOP(0xD0, tmp & 0x07); 496 while (STATUS_IOP() & 0x800); 497 while (!(STATUS_IOP() & 0x800)); 498 return (STATUS_IOP() & STATUS_SDA) != 0; 499} 500 501static void 502ApmProbeDDC(ScrnInfoPtr pScrn, int index) 503{ 504 vbeInfoPtr pVbe; 505 506 if (xf86LoadSubModule(pScrn, "vbe")) { 507 pVbe = VBEInit(NULL, index); 508 ConfiguredMonitor = vbeDoEDID(pVbe, NULL); 509 vbeFree(pVbe); 510 } 511} 512 513static Bool 514ApmPreInit(ScrnInfoPtr pScrn, int flags) 515{ 516 APMDECL(pScrn); 517 EntityInfoPtr pEnt; 518 vgaHWPtr hwp; 519 MessageType from; 520 char *mod = NULL, *req = NULL, *s; 521 ClockRangePtr clockRanges; 522 int i; 523 xf86MonPtr MonInfo = NULL; 524 double real; 525 526 /* 527 * Note: This function is only called once at server startup, and 528 * not at the start of each server generation. This means that 529 * only things that are persistent across server generations can 530 * be initialised here. xf86Screens[] is (pScrn is a pointer to one 531 * of these). Privates allocated using xf86AllocateScrnInfoPrivateIndex() 532 * are too, and should be used for data that must persist across 533 * server generations. 534 * 535 * Per-generation data should be allocated with 536 * AllocateScreenPrivateIndex() from the ScreenInit() function. 537 */ 538 539 /* Check the number of entities, and fail if it isn't one. */ 540 if (pScrn->numEntities != 1) 541 return FALSE; 542 543 /* Allocate the ApmRec driverPrivate */ 544 if (!ApmGetRec(pScrn)) { 545 return FALSE; 546 } 547 pApm = APMPTR(pScrn); 548 549 /* Get the entity */ 550 pEnt = pApm->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); 551 if (pEnt->location.type == BUS_PCI) { 552 pApm->PciInfo = xf86GetPciInfoForEntity(pEnt->index); 553 pApm->PciTag = pciTag(pApm->PciInfo->bus, pApm->PciInfo->device, 554 pApm->PciInfo->func); 555 } 556 else { 557 pApm->PciInfo = NULL; 558 pApm->PciTag = 0; 559 } 560 561 if (flags & PROBE_DETECT) { 562 ApmProbeDDC(pScrn, pEnt->index); 563 return TRUE; 564 } 565 566 /* The vgahw module should be allocated here when needed */ 567 if (!xf86LoadSubModule(pScrn, "vgahw")) 568 return FALSE; 569 570 xf86LoaderReqSymLists(vgahwSymbols, NULL); 571 572 /* 573 * Allocate a vgaHWRec 574 */ 575 if (!vgaHWGetHWRec(pScrn)) 576 return FALSE; 577 578 hwp = VGAHWPTR(pScrn); 579 vgaHWGetIOBase(hwp); 580 pApm->iobase = hwp->PIOOffset; 581 pApm->xport = hwp->PIOOffset + 0x3C4; 582 583 /* Set pScrn->monitor */ 584 pScrn->monitor = pScrn->confScreen->monitor; 585 586 /* XXX: Access funcs */ 587 /* 588 * The first thing we should figure out is the depth, bpp, etc. 589 */ 590 if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb)) { 591 return FALSE; 592 } else { 593 /* Check that the returned depth is one we support */ 594 switch (pScrn->depth) { 595 case 4: 596 case 8: 597 case 15: 598 case 16: 599 case 24: 600 /* OK */ 601 break; 602 default: 603 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 604 "Given depth (%d) is not supported by this driver\n", 605 pScrn->depth); 606 return FALSE; 607 } 608 } 609 xf86PrintDepthBpp(pScrn); 610 611 /* 612 * This must happen after pScrn->display has been set because 613 * xf86SetWeight references it. 614 */ 615 if (pScrn->depth > 8) { 616 /* The defaults are OK for us */ 617 rgb zeros = {0, 0, 0}; 618 619 if (!xf86SetWeight(pScrn, zeros, zeros)) { 620 return FALSE; 621 } else { 622 /* XXX check that weight returned is supported */ 623 ; 624 } 625 } 626 627 if (!xf86SetDefaultVisual(pScrn, -1)) { 628 return FALSE; 629 } else { 630 if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { 631 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" 632 " (%s) is not supported at depth %d\n", 633 xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); 634 return FALSE; 635 } 636 } 637 638 /* We use a programmable clock */ 639 pScrn->progClock = TRUE; 640 641 /* Collect all of the relevant option flags (fill in pScrn->options) */ 642 xf86CollectOptions(pScrn, NULL); 643 644 /* Process the options */ 645 if (!(pApm->Options = xalloc(sizeof(ApmOptions)))) 646 return FALSE; 647 memcpy(pApm->Options, ApmOptions, sizeof(ApmOptions)); 648 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pApm->Options); 649 650 pApm->scrnIndex = pScrn->scrnIndex; 651 /* Set the bits per RGB for 8bpp mode */ 652 if (pScrn->depth > 1 && pScrn->depth <= 8) { 653 /* Default to 8 */ 654 pScrn->rgbBits = 8; 655 } 656 if (xf86ReturnOptValBool(pApm->Options, OPTION_NOLINEAR, FALSE)) { 657 pApm->noLinear = TRUE; 658 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "No linear framebuffer\n"); 659 } 660 from = X_DEFAULT; 661 pApm->hwCursor = FALSE; 662 if (xf86GetOptValBool(pApm->Options, OPTION_HW_CURSOR, &pApm->hwCursor)) 663 from = X_CONFIG; 664 if (pApm->noLinear || 665 xf86ReturnOptValBool(pApm->Options, OPTION_SW_CURSOR, FALSE)) { 666 from = X_CONFIG; 667 pApm->hwCursor = FALSE; 668 } 669 xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", 670 pApm->hwCursor ? "HW" : "SW"); 671 from = X_DEFAULT; 672 if (pScrn->bitsPerPixel < 8) 673 pApm->NoAccel = TRUE; 674 if (xf86ReturnOptValBool(pApm->Options, OPTION_NOACCEL, FALSE)) { 675 from = X_CONFIG; 676 pApm->NoAccel = TRUE; 677 } 678 if (pApm->NoAccel) 679 xf86DrvMsg(pScrn->scrnIndex, from, "Acceleration disabled\n"); 680 if (xf86GetOptValFreq(pApm->Options, OPTION_SET_MCLK, OPTUNITS_MHZ, &real)) { 681 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MCLK used is %.1f MHz\n", real); 682 pApm->MemClk = (int)(real * 1000.0); 683 } 684 if (xf86ReturnOptValBool(pApm->Options, OPTION_SHADOW_FB, FALSE)) { 685 pApm->ShadowFB = TRUE; 686 pApm->NoAccel = TRUE; 687 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 688 "Using \"Shadow Framebuffer\" - acceleration disabled\n"); 689 } 690 if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_RETRY, FALSE)) { 691 if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_BURST, FALSE)) { 692 pApm->UsePCIRetry = TRUE; 693 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n"); 694 } 695 else 696 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires pci_burst \"on\".\n"); 697 } 698 pApm->DPMSMask[DPMSModeOn] = DPMSModeOn; 699 pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby; 700 pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend; 701 pApm->DPMSMask[DPMSModeOff] = DPMSModeOff; 702 if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_ON))) { 703 if (!strcmp(s, "on")) 704 pApm->DPMSMask[DPMSModeOn] = DPMSModeOn; 705 else if (!strcmp(s, "standby")) 706 pApm->DPMSMask[DPMSModeOn] = DPMSModeStandby; 707 else if (!strcmp(s, "suspend")) 708 pApm->DPMSMask[DPMSModeOn] = DPMSModeSuspend; 709 else if (!strcmp(s, "off")) 710 pApm->DPMSMask[DPMSModeOn] = DPMSModeOff; 711 else if (s[0] >= '0' && s[0] <= '9') { 712 pApm->DPMSMask[DPMSModeOn] = strtol(s, NULL, 0); 713 if (pApm->DPMSMask[DPMSModeOn] > (sizeof pApm->DPMSMask)-1) 714 pApm->DPMSMask[DPMSModeOn] = (sizeof pApm->DPMSMask) - 1; 715 } 716 } 717 if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_STANDBY))) { 718 if (!strcmp(s, "on")) 719 pApm->DPMSMask[DPMSModeStandby] = DPMSModeOn; 720 else if (!strcmp(s, "standby")) 721 pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby; 722 else if (!strcmp(s, "suspend")) 723 pApm->DPMSMask[DPMSModeStandby] = DPMSModeSuspend; 724 else if (!strcmp(s, "off")) 725 pApm->DPMSMask[DPMSModeStandby] = DPMSModeOff; 726 else if (s[0] >= '0' && s[0] <= '9') { 727 pApm->DPMSMask[DPMSModeStandby] = strtol(s, NULL, 0); 728 if (pApm->DPMSMask[DPMSModeStandby] > (sizeof pApm->DPMSMask)-1) 729 pApm->DPMSMask[DPMSModeStandby] = (sizeof pApm->DPMSMask) - 1; 730 } 731 } 732 if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_SUSPEND))) { 733 if (!strcmp(s, "on")) 734 pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOn; 735 else if (!strcmp(s, "standby")) 736 pApm->DPMSMask[DPMSModeSuspend] = DPMSModeStandby; 737 else if (!strcmp(s, "suspend")) 738 pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend; 739 else if (!strcmp(s, "off")) 740 pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOff; 741 else if (s[0] >= '0' && s[0] <= '9') { 742 pApm->DPMSMask[DPMSModeSuspend] = strtol(s, NULL, 0); 743 if (pApm->DPMSMask[DPMSModeSuspend] > (sizeof pApm->DPMSMask)-1) 744 pApm->DPMSMask[DPMSModeSuspend] = (sizeof pApm->DPMSMask) - 1; 745 } 746 } 747 if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_OFF))) { 748 if (!strcmp(s, "on")) 749 pApm->DPMSMask[DPMSModeOff] = DPMSModeOn; 750 else if (!strcmp(s, "standby")) 751 pApm->DPMSMask[DPMSModeOff] = DPMSModeStandby; 752 else if (!strcmp(s, "suspend")) 753 pApm->DPMSMask[DPMSModeOff] = DPMSModeSuspend; 754 else if (!strcmp(s, "off")) 755 pApm->DPMSMask[DPMSModeOff] = DPMSModeOff; 756 else if (s[0] >= '0' && s[0] <= '9') { 757 pApm->DPMSMask[DPMSModeOff] = strtol(s, NULL, 0); 758 if (pApm->DPMSMask[DPMSModeOff] > (sizeof pApm->DPMSMask)-1) 759 pApm->DPMSMask[DPMSModeOff] = (sizeof pApm->DPMSMask) - 1; 760 } 761 } 762 763 /* 764 * Set the Chipset and ChipRev, allowing config file entries to 765 * override. 766 */ 767 if (pEnt->device->chipset && *pEnt->device->chipset) { 768 pScrn->chipset = pEnt->device->chipset; 769 pApm->Chipset = xf86StringToToken(ApmChipsets, pScrn->chipset); 770 from = X_CONFIG; 771 } else if (pEnt->device->chipID >= 0) { 772 pApm->Chipset = pEnt->device->chipID; 773 pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset); 774 775 from = X_CONFIG; 776 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", 777 pApm->Chipset); 778 } else { 779 from = X_PROBED; 780 if (pApm->PciInfo) 781 pApm->Chipset = pApm->PciInfo->chipType; 782 else 783 pApm->Chipset = pEnt->chipset; 784 pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset); 785 } 786 if (pScrn->bitsPerPixel == 24 && pApm->Chipset < AT24) { 787 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 788 "Given depth (%d) is not supported by this driver\n", 789 pScrn->depth); 790 return FALSE; 791 } 792 if (pEnt->device->chipRev >= 0) { 793 pApm->ChipRev = pEnt->device->chipRev; 794 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", 795 pApm->ChipRev); 796 } else if (pApm->PciInfo) { 797 pApm->ChipRev = pApm->PciInfo->chipRev; 798 } 799 800 /* 801 * This shouldn't happen because such problems should be caught in 802 * ApmProbe(), but check it just in case. 803 */ 804 if (pScrn->chipset == NULL) { 805 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 806 "ChipID 0x%04X is not recognised\n", pApm->Chipset); 807 return FALSE; 808 } 809 if (pApm->Chipset < 0) { 810 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 811 "Chipset \"%s\" is not recognised\n", pScrn->chipset); 812 return FALSE; 813 } 814 815 xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset); 816 817 if (pEnt->device->MemBase != 0) { 818 pApm->LinAddress = pEnt->device->MemBase; 819 from = X_CONFIG; 820 } else if (pApm->PciInfo) { 821 pApm->LinAddress = pApm->PciInfo->memBase[0] & 0xFF800000; 822 from = X_PROBED; 823 } else { 824 /* 825 * VESA local bus. 826 * Pray that 2048MB works. 827 */ 828 pApm->LinAddress = 0x80000000; 829 } 830 831 xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", 832 (unsigned long)pApm->LinAddress); 833 834 if (xf86LoadSubModule(pScrn, "ddc")) { 835 xf86LoaderReqSymLists(ddcSymbols, NULL); 836 if (xf86LoadSubModule(pScrn, "i2c")) { 837 xf86LoaderReqSymLists(i2cSymbols, NULL); 838 pApm->I2C = TRUE; 839 } 840 } 841 842 if (pApm->noLinear) { 843 /* 844 * TODO not AT3D. 845 * XXX ICI XXX 846 */ 847 pApm->LinMapSize = 4 * 1024 * 1024 /* 0x10000 */; 848 pApm->FbMapSize = 4 * 1024 * 1024 /* 0x10000 */; 849 if (pApm->Chipset >= AT3D) 850 pApm->LinAddress += 8 * 1024 * 1024 /* 0xA0000 */; 851 } 852 else { 853 if (pApm->Chipset >= AT3D) 854 pApm->LinMapSize = 16 * 1024 * 1024; 855 else 856 pApm->LinMapSize = 6 * 1024 * 1024; 857 pApm->FbMapSize = 4 * 1024 * 1024; 858 } 859 860 if (xf86LoadSubModule(pScrn, "int10")) { 861 void *ptr; 862 863 xf86LoaderReqSymLists(int10Symbols, NULL); 864 xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n"); 865 ptr = xf86InitInt10(pEnt->index); 866 if (ptr) 867 xf86FreeInt10(ptr); 868 } 869 870 xf86RegisterResources(pEnt->index, NULL, ResNone); 871 xf86SetOperatingState(resVga, pEnt->index, ResDisableOpr); 872 pScrn->racMemFlags = 0; /* For noLinear, access to 0xA0000 */ 873 if (pApm->VGAMap) 874 pScrn->racIoFlags = 0; 875 else 876 pScrn->racIoFlags = RAC_COLORMAP | RAC_VIEWPORT; 877 878 if (pEnt->device->videoRam != 0) { 879 pScrn->videoRam = pEnt->device->videoRam; 880 from = X_CONFIG; 881 } else if (!pApm->noLinear && pApm->Chipset >= AT3D) { 882 unsigned char d9, db, uc; 883 /*unsigned long save;*/ 884 volatile unsigned char *LinMap; 885 886 LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, 887 pApm->PciTag, pApm->LinAddress, 888 pApm->LinMapSize); 889 /*save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG); 890 pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_MEM_ENABLE);*/ 891 d9 = LinMap[0xFFECD9]; 892 db = LinMap[0xFFECDB]; 893 LinMap[0xFFECDB] = (db & 0xF4) | 0x0A; 894 LinMap[0xFFECD9] = (d9 & 0xCF) | 0x20; 895 LinMap[0xFFF3C4] = 0x1C; 896 uc = LinMap[0xFFF3C5]; 897 LinMap[0xFFF3C5] = 0x3F; 898 LinMap[0xFFF3C4] = 0x20; 899 pScrn->videoRam = LinMap[0xFFF3C5] * 64; 900 LinMap[0xFFF3C4] = 0x10; 901 pApm->savedSR10 = LinMap[0xFFF3C5]; 902 LinMap[0xFFF3C4] = 0x1E; 903 pApm->xbase = LinMap[0xFFF3C5]; 904 LinMap[0xFFF3C4] = 0x1F; 905 pApm->xbase |= LinMap[0xFFF3C5] << 8; 906 LinMap[0xFFF3C4] = 0x1C; 907 LinMap[0xFFF3C5] = uc; 908 LinMap[0xFFECDB] = db; 909 LinMap[0xFFECD9] = d9; 910 /*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/ 911 xf86UnMapVidMem(pScrn->scrnIndex, (pointer)LinMap, pApm->LinMapSize); 912 from = X_PROBED; 913 } 914 else { 915 /*unsigned long save; 916 917 save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG); 918 pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_IO_ENABLE);*/ 919 pApm->savedSR10 = rdinx(pApm->xport, 0x10); 920 wrinx(pApm->xport, 0x10, 0x12); 921 pScrn->videoRam = rdinx(pApm->xport, 0x20) * 64; 922 pApm->xbase = rdinx(pApm->xport, 0x1F) << 8; 923 pApm->xbase |= rdinx(pApm->xport, 0x1E); 924 pApm->xbase += pApm->iobase; 925 wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12); 926 /*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/ 927 from = X_PROBED; 928 } 929 if (pApm->Chipset < AT3D && pScrn->videoRam >= 4096) 930 pScrn->videoRam -= 32; 931 932 xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", 933 pScrn->videoRam); 934 935 if (!xf86IsPc98()) { 936 hwp->MapSize = 0x10000; 937 vgaHWMapMem(pScrn); 938 if (pApm->I2C) { 939 if (!ApmI2CInit(pScrn)) { 940 xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n"); 941 } 942 else { 943 MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,pApm->I2CPtr); 944 } 945 } 946 if (0 && !MonInfo) 947 MonInfo = xf86DoEDID_DDC1(pScrn->scrnIndex,vgaHWddc1SetSpeed,ddc1Read); 948 if (MonInfo) 949 xf86PrintEDID(MonInfo); 950 pScrn->monitor->DDC = MonInfo; 951 } 952 953 /* The gamma fields must be initialised when using the new cmap code */ 954 if (pScrn->depth > 1) { 955 Gamma zeros = {0.0, 0.0, 0.0}; 956 957 if (!xf86SetGamma(pScrn, zeros)) { 958 return FALSE; 959 } 960 } 961 962 pApm->MinClock = 23125; 963 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock set to %d MHz\n", 964 pApm->MinClock / 1000); 965 966 /* 967 * If the user has specified ramdac speed in the XF86Config 968 * file, we respect that setting. 969 */ 970 from = X_DEFAULT; 971 if (pEnt->device->dacSpeeds[0]) { 972 int speed = 0; 973 974 switch (pScrn->bitsPerPixel) { 975 case 4: 976 case 8: 977 speed = pEnt->device->dacSpeeds[DAC_BPP8]; 978 break; 979 case 16: 980 speed = pEnt->device->dacSpeeds[DAC_BPP16]; 981 break; 982 case 24: 983 speed = pEnt->device->dacSpeeds[DAC_BPP24]; 984 break; 985 case 32: 986 speed = pEnt->device->dacSpeeds[DAC_BPP32]; 987 break; 988 } 989 if (speed == 0) 990 pApm->MaxClock = pEnt->device->dacSpeeds[0]; 991 else 992 pApm->MaxClock = speed; 993 from = X_CONFIG; 994 } else { 995 switch(pApm->Chipset) 996 { 997 /* These values come from the Manual for AT24 and AT3D 998 in the overview of various modes. I've taken the largest 999 number for the different modes. Alliance wouldn't 1000 tell me what the maximum frequency was, so... 1001 */ 1002 case AT24: 1003 switch(pScrn->bitsPerPixel) 1004 { 1005 case 4: 1006 case 8: 1007 pApm->MaxClock = 160000; 1008 break; 1009 case 16: 1010 pApm->MaxClock = 144000; 1011 break; 1012 case 24: 1013 pApm->MaxClock = 75000; /* Hmm. */ 1014 break; 1015 case 32: 1016 pApm->MaxClock = 94500; 1017 break; 1018 default: 1019 return FALSE; 1020 } 1021 break; 1022 case AT3D: 1023 switch(pScrn->bitsPerPixel) 1024 { 1025 case 4: 1026 case 8: 1027 pApm->MaxClock = 175500; 1028 break; 1029 case 16: 1030 pApm->MaxClock = 144000; 1031 break; 1032 case 24: 1033 pApm->MaxClock = 94000; /* Changed from 75000 by Grenié */ 1034 break; 1035 case 32: 1036 pApm->MaxClock = 94500; 1037 break; 1038 default: 1039 return FALSE; 1040 } 1041 break; 1042 case AP6422: 1043 switch(pScrn->bitsPerPixel) 1044 { 1045 case 4: 1046 case 8: 1047 pApm->MaxClock = 135000; 1048 break; 1049 case 16: 1050 pApm->MaxClock = 75000; 1051 break; 1052 case 32: 1053 pApm->MaxClock = 60000; 1054 break; 1055 default: 1056 return FALSE; 1057 } 1058 break; 1059 default: 1060 pApm->MaxClock = 135000; 1061 break; 1062 } 1063 } 1064 xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n", 1065 pApm->MaxClock / 1000); 1066 1067 /* 1068 * Setup the ClockRanges, which describe what clock ranges are available, 1069 * and what sort of modes they can be used for. 1070 */ 1071 clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1); 1072 clockRanges->next = NULL; 1073 clockRanges->minClock = pApm->MinClock; 1074 clockRanges->maxClock = pApm->MaxClock; 1075 clockRanges->clockIndex = -1; /* programmable */ 1076 clockRanges->interlaceAllowed = FALSE; /* XXX change this */ 1077 clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ 1078 1079 /* Select valid modes from those available */ 1080 if (pApm->NoAccel) { 1081 /* 1082 * XXX Assuming min pitch 256, max 2048 1083 * XXX Assuming min height 128, max 1024 (changed EE) 1084 */ 1085 i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, 1086 pScrn->display->modes, clockRanges, 1087 NULL, 256, 2048, 1088 pScrn->bitsPerPixel, 128, 1024, 1089 pScrn->display->virtualX, 1090 pScrn->display->virtualY, 1091 pApm->FbMapSize, 1092 LOOKUP_BEST_REFRESH); 1093 } else { 1094 /* 1095 * XXX Assuming min height 128, max 2048 1096 */ 1097 i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, 1098 pScrn->display->modes, clockRanges, 1099 GetAccelPitchValues(pScrn), 0, 0, 1100 pScrn->bitsPerPixel, 128, 1024, 1101 pScrn->display->virtualX, 1102 pScrn->display->virtualY, 1103 pApm->FbMapSize, 1104 LOOKUP_BEST_REFRESH); 1105 } 1106 1107 if (i == -1) { 1108 ApmFreeRec(pScrn); 1109 return FALSE; 1110 } 1111 1112 /* Prune the modes marked as invalid */ 1113 xf86PruneDriverModes(pScrn); 1114 1115 if (i == 0 || pScrn->modes == NULL) { 1116 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); 1117 ApmFreeRec(pScrn); 1118 return FALSE; 1119 } 1120 1121 xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); 1122 1123 /* Set the current mode to the first in the list */ 1124 pScrn->currentMode = pScrn->modes; 1125 1126 /* Print the list of modes being used */ 1127 xf86PrintModes(pScrn); 1128 1129 /* Set display resolution */ 1130 xf86SetDpi(pScrn, 0, 0); 1131 1132 /* Load bpp-specific modules */ 1133 switch (pScrn->bitsPerPixel) { 1134 case 1: 1135 mod = "xf1bpp"; 1136 req = "xf1bppScreenInit"; 1137 break; 1138 case 4: 1139 mod = "xf4bpp"; 1140 req = "xf4bppScreenInit"; 1141 break; 1142 case 8: 1143 case 16: 1144 case 24: 1145 case 32: 1146 mod = "fb"; 1147 break; 1148 } 1149 1150 if (mod && xf86LoadSubModule(pScrn, mod) == NULL) { 1151 ApmFreeRec(pScrn); 1152 return FALSE; 1153 } 1154 1155 if (mod) { 1156 if (req) { 1157 xf86LoaderReqSymbols(req, NULL); 1158 } else { 1159 xf86LoaderReqSymLists(fbSymbols, NULL); 1160 } 1161 } 1162 1163 /* Load XAA if needed */ 1164 if (!pApm->NoAccel) { 1165 if (!xf86LoadSubModule(pScrn, "xaa")) { 1166 ApmFreeRec(pScrn); 1167 return FALSE; 1168 } 1169 xf86LoaderReqSymLists(xaaSymbols, NULL); 1170 } 1171 1172 /* Load ramdac if needed */ 1173 if (pApm->hwCursor) { 1174 if (!xf86LoadSubModule(pScrn, "ramdac")) { 1175 ApmFreeRec(pScrn); 1176 return FALSE; 1177 } 1178 xf86LoaderReqSymLists(ramdacSymbols, NULL); 1179 } 1180 1181 /* Load shadowfb if needed */ 1182 if (pApm->ShadowFB) { 1183 if (!xf86LoadSubModule(pScrn, "shadowfb")) { 1184 ApmFreeRec(pScrn); 1185 return FALSE; 1186 } 1187 xf86LoaderReqSymLists(shadowSymbols, NULL); 1188 } 1189 1190 pApm->CurrentLayout.displayWidth = pScrn->virtualX; 1191 pApm->CurrentLayout.displayHeight = pScrn->virtualY; 1192 pApm->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; 1193 pApm->CurrentLayout.bytesPerScanline= (pApm->CurrentLayout.displayWidth * pApm->CurrentLayout.bitsPerPixel) >> 3; 1194 pApm->CurrentLayout.depth = pScrn->depth; 1195 pApm->CurrentLayout.Scanlines = 2 * (pScrn->videoRam << 10) / pApm->CurrentLayout.bytesPerScanline; 1196 if (pScrn->bitsPerPixel == 24) 1197 pApm->CurrentLayout.mask32 = 3; 1198 else 1199 pApm->CurrentLayout.mask32 = 32 / pScrn->bitsPerPixel - 1; 1200 1201 return TRUE; 1202} 1203 1204/* 1205 * Map the framebuffer and MMIO memory. 1206 */ 1207 1208static Bool 1209ApmMapMem(ScrnInfoPtr pScrn) 1210{ 1211 APMDECL(pScrn); 1212 vgaHWPtr hwp = VGAHWPTR(pScrn); 1213 1214 pApm->LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, 1215 pApm->PciTag, 1216 (unsigned long)pApm->LinAddress, 1217 pApm->LinMapSize); 1218 if (pApm->LinMap == NULL) 1219 return FALSE; 1220 1221 if (!pApm->noLinear) { 1222 if (pApm->Chipset >= AT3D) { 1223 pApm->FbBase = (void *)(((char *)pApm->LinMap) + 0x800000); 1224 pApm->VGAMap = ((char *)pApm->LinMap) + 0xFFF000; 1225 pApm->MemMap = ((char *)pApm->LinMap) + 0xFFEC00; 1226 pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000); 1227 } 1228 else { 1229 pApm->FbBase = (void *)pApm->LinMap; 1230 pApm->VGAMap = NULL; 1231 if (pScrn->videoRam == 6 * 1024 - 32) { 1232 pApm->MemMap = ((char *)pApm->LinMap) + 0x5FF800; 1233 pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x5F8000); 1234 } 1235 else { 1236 pApm->MemMap = ((char *)pApm->LinMap) + 0x3FF800; 1237 pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000); 1238 } 1239 } 1240 1241 /* 1242 * Initialize chipset 1243 */ 1244 pApm->c9 = RDXB(0xC9); 1245 if (pApm->Chipset >= AT3D) { 1246 pApm->d9 = RDXB(0xD9); 1247 pApm->db = RDXB(0xDB); 1248 1249 /* If you change these two, change them also in apm_funcs.c */ 1250 WRXB(0xDB, (pApm->db & 0xF4) | 0x0A); 1251 WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20); 1252 1253 vgaHWSetMmioFuncs(hwp, (CARD8 *)pApm->LinMap, 0xFFF000); 1254 } 1255 if (pApm->Chipset >= AP6422) 1256 WRXB(0xC9, pApm->c9 | 0x10); 1257 } 1258 else { 1259 pApm->FbBase = pApm->LinMap; 1260 1261 /* 1262 * Initialize chipset 1263 */ 1264 if (pApm->Chipset >= AT3D) { 1265 pApm->d9 = RDXB_IOP(0xD9); 1266 pApm->db = RDXB_IOP(0xDB); 1267 WRXB_IOP(0xDB, pApm->db & 0xF4); 1268 } 1269 } 1270 /* 1271 * Save color mode 1272 */ 1273 pApm->MiscOut = hwp->readMiscOut(hwp); 1274 1275 return TRUE; 1276} 1277 1278/* 1279 * Unmap the framebuffer and MMIO memory 1280 */ 1281 1282static Bool 1283ApmUnmapMem(ScrnInfoPtr pScrn) 1284{ 1285 APMDECL(pScrn); 1286 vgaHWPtr hwp = VGAHWPTR(pScrn); 1287 1288 /* 1289 * Reset color mode 1290 */ 1291 hwp->writeMiscOut(hwp, pApm->MiscOut); 1292 if (pApm->LinMap) { 1293 if (pApm->Chipset >= AT3D) { 1294 if (!pApm->noLinear) { 1295 WRXB(0xD9, pApm->d9); 1296 WRXB(0xDB, pApm->db); 1297 } 1298 else { 1299 WRXB_IOP(0xD9, pApm->d9); 1300 WRXB_IOP(0xDB, pApm->db); 1301 } 1302 } 1303 WRXB(0xC9, pApm->c9); 1304 xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, pApm->LinMapSize); 1305 pApm->LinMap = NULL; 1306 } 1307 else if (pApm->FbBase) 1308 xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, 0x10000); 1309 1310 return TRUE; 1311} 1312 1313/* 1314 * This function saves the video state. 1315 */ 1316static void 1317ApmSave(ScrnInfoPtr pScrn) 1318{ 1319 APMDECL(pScrn); 1320 ApmRegPtr ApmReg = &pApm->SavedReg; 1321 vgaHWPtr hwp = VGAHWPTR(pScrn); 1322 1323 if (pApm->VGAMap) { 1324 ApmReg->SEQ[0x1B] = ApmReadSeq(0x1B); 1325 ApmReg->SEQ[0x1C] = ApmReadSeq(0x1C); 1326 1327 /* 1328 * Save fonts 1329 */ 1330 if (!(hwp->SavedReg.Attribute[0x10] & 1)) { 1331 if (pApm->FontInfo || (pApm->FontInfo = (pointer)xalloc(TEXT_AMOUNT))) { 1332 int locked; 1333 1334 locked = ApmReadSeq(0x10); 1335 if (locked) 1336 ApmWriteSeq(0x10, 0x12); 1337 ApmWriteSeq(0x1C, 0x3F); 1338 memcpy(pApm->FontInfo, pApm->FbBase, TEXT_AMOUNT); 1339 ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]); 1340 if (locked) 1341 ApmWriteSeq(0x10, 0); 1342 } 1343 } 1344 /* 1345 * This function will handle creating the data structure and filling 1346 * in the generic VGA portion. 1347 */ 1348 vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_CMAP); 1349 1350 /* Hardware cursor registers. */ 1351 ApmReg->EX[XR140] = RDXL(0x140); 1352 ApmReg->EX[XR144] = RDXW(0x144); 1353 ApmReg->EX[XR148] = RDXL(0x148); 1354 ApmReg->EX[XR14C] = RDXW(0x14C); 1355 1356 ApmReg->CRT[0x19] = ApmReadCrtc(0x19); 1357 ApmReg->CRT[0x1A] = ApmReadCrtc(0x1A); 1358 ApmReg->CRT[0x1B] = ApmReadCrtc(0x1B); 1359 ApmReg->CRT[0x1C] = ApmReadCrtc(0x1C); 1360 ApmReg->CRT[0x1D] = ApmReadCrtc(0x1D); 1361 ApmReg->CRT[0x1E] = ApmReadCrtc(0x1E); 1362 1363 /* RAMDAC registers. */ 1364 ApmReg->EX[XRE8] = RDXL(0xE8); 1365 ApmReg->EX[XREC] = RDXL(0xEC); 1366 1367 /* Color correction */ 1368 ApmReg->EX[XRE0] = RDXL(0xE0); 1369 1370 ApmReg->EX[XR80] = RDXB(0x80); 1371 } 1372 else { 1373 /* 1374 * This function will handle creating the data structure and filling 1375 * in the generic VGA portion. 1376 */ 1377 vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); 1378 1379 ApmReg->SEQ[0x1B] = rdinx(pApm->xport, 0x1B); 1380 ApmReg->SEQ[0x1C] = rdinx(pApm->xport, 0x1C); 1381 1382 /* Hardware cursor registers. */ 1383 if (pApm->noLinear) { 1384 ApmReg->EX[XR140] = RDXL_IOP(0x140); 1385 ApmReg->EX[XR144] = RDXW_IOP(0x144); 1386 ApmReg->EX[XR148] = RDXL_IOP(0x148); 1387 ApmReg->EX[XR14C] = RDXW_IOP(0x14C); 1388 } 1389 else { 1390 ApmReg->EX[XR140] = RDXL(0x140); 1391 ApmReg->EX[XR144] = RDXW(0x144); 1392 ApmReg->EX[XR148] = RDXL(0x148); 1393 ApmReg->EX[XR14C] = RDXW(0x14C); 1394 } 1395 1396 ApmReg->CRT[0x19] = rdinx(pApm->iobase + 0x3D4, 0x19); 1397 ApmReg->CRT[0x1A] = rdinx(pApm->iobase + 0x3D4, 0x1A); 1398 ApmReg->CRT[0x1B] = rdinx(pApm->iobase + 0x3D4, 0x1B); 1399 ApmReg->CRT[0x1C] = rdinx(pApm->iobase + 0x3D4, 0x1C); 1400 ApmReg->CRT[0x1D] = rdinx(pApm->iobase + 0x3D4, 0x1D); 1401 ApmReg->CRT[0x1E] = rdinx(pApm->iobase + 0x3D4, 0x1E); 1402 1403 if (pApm->noLinear) { 1404 /* RAMDAC registers. */ 1405 ApmReg->EX[XRE8] = RDXL_IOP(0xE8); 1406 ApmReg->EX[XREC] = RDXL_IOP(0xEC); 1407 1408 /* Color correction */ 1409 ApmReg->EX[XRE0] = RDXL_IOP(0xE0); 1410 1411 ApmReg->EX[XR80] = RDXB_IOP(0x80); 1412 } 1413 else { 1414 /* RAMDAC registers. */ 1415 ApmReg->EX[XRE8] = RDXL(0xE8); 1416 ApmReg->EX[XREC] = RDXL(0xEC); 1417 1418 /* Color correction */ 1419 ApmReg->EX[XRE0] = RDXL(0xE0); 1420 1421 ApmReg->EX[XR80] = RDXB(0x80); 1422 } 1423 } 1424} 1425 1426#define WITHIN(v,c1,c2) (((v) >= (c1)) && ((v) <= (c2))) 1427 1428static unsigned 1429comp_lmn(ApmPtr pApm, long clock) 1430{ 1431 int n, m, l, f; 1432 double fvco; 1433 double fout; 1434 double fmax, fmin; 1435 double fref; 1436 double fvco_goal; 1437 double k, c; 1438 double fout_best = 0; 1439 unsigned int best = 0; 1440 1441 if (pApm->Chipset >= AT3D) 1442 fmax = 370000.0; 1443 else 1444 fmax = 250000.0; 1445 1446 fref = 14318.0; 1447 fmin = fmax / 2.0; 1448 1449 for (m = 1; m <= 5; m++) 1450 { 1451 for (l = 3; l >= 0; l--) 1452 { 1453 for (n = 8; n <= 127; n++) 1454 { 1455 fout = ((double)(n + 1) * fref)/((double)(m + 1) * (1 << l)); 1456 fvco_goal = (double)clock * (double)(1 << l); 1457 fvco = fout * (double)(1 << l); 1458 if (!WITHIN(fvco, 0.99*fvco_goal, 1.01*fvco_goal)) 1459 continue; 1460 if (!WITHIN(fvco, fmin, fmax)) 1461 continue; 1462 if (!WITHIN(fvco / (double)(n+1), 300.0, 300000.0)) 1463 continue; 1464 if (!WITHIN(fref / (double)(m+1), 300.0, 300000.0)) 1465 continue; 1466 1467 if (fout_best != 0) { 1468 double diff_new = clock - fout; 1469 double diff_old = clock - best; 1470 diff_new = diff_new < 0 ? -diff_new : diff_new; 1471 diff_old = diff_old < 0 ? -diff_old : diff_old; 1472 if (diff_new > diff_old) 1473 continue; 1474 } 1475 fout_best = fout; 1476 1477 /* The following formula was empirically derived by 1478 matching a number of fvco values with acceptable 1479 values of f. 1480 1481 (fvco can be 185MHz - 370MHz on AT3D) 1482 (fvco can be 125MHz - 250MHz on AT24/AP6422) 1483 1484 The table that was measured up follows: 1485 1486 AT3D 1487 1488 fvco f 1489 (125) (x-7) guess 1490 200 5-7 1491 219 4-7 1492 253 3-6 1493 289 2-5 1494 320 0-4 1495 (400) (0-x) guess 1496 1497 AT24 1498 1499 fvco f 1500 126 7 1501 200 5-7 1502 211 4-7 1503 1504 AP6422 1505 1506 fvco f 1507 126 7 1508 169 5-7 1509 200 4-5 1510 211 4-5 1511 1512 From this, a function "f = k * fvco + c" was derived. 1513 1514 For AT3D, this table was measured with MCLK == 50MHz. 1515 The driver has since been set to use MCLK == 57.3MHz for, 1516 but I don't think that makes a difference here. 1517 */ 1518 1519 if (pApm->Chipset >= AT24) 1520 { 1521 k = 7.0 / (175.0 - 380.0); 1522 c = -k * 380.0; 1523 f = (int)(k * fvco/1000.0 + c + 0.5); 1524 if (f > 7) f = 7; 1525 if (f < 0) f = 0; 1526 } else { /* i.e AP6422 */ 1527 c = (211.0*6.0-169.0*4.5)/(211.0-169.0); 1528 k = (4.5-c)/211.0; 1529 f = (int)(k * fvco/1000.0 + c + 0.5); 1530 if (f > 7) f = 7; 1531 if (f < 0) f = 0; 1532 } 1533 1534 best = (n << 16) | (m << 8) | (l << 2) | (f << 4); 1535 } 1536 } 1537 } 1538 1539 if (fout_best != 0) 1540 return best; 1541 1542 xf86DrvMsg(pApm->scrnIndex, X_PROBED, 1543 "Cannot find register values for clock %6.2f MHz. " 1544 "Please use a (slightly) different clock.\n", 1545 (double)clock / 1000.0); 1546 return 0; 1547} 1548 1549/* 1550 * Initialise a new mode. This is currently still using the old 1551 * "initialise struct, restore/write struct to HW" model. That could 1552 * be changed. 1553 */ 1554 1555static Bool 1556ApmModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) 1557{ 1558 APMDECL(pScrn); 1559 ApmRegPtr ApmReg = &pApm->ModeReg; 1560 vgaHWPtr hwp; 1561 1562 1563 /* set clockIndex to "2" for programmable clocks */ 1564 if (pScrn->progClock) 1565 mode->ClockIndex = 2; 1566 1567 /* prepare standard VGA register contents */ 1568 if (!vgaHWInit(pScrn, mode)) 1569 return FALSE; 1570 pScrn->vtSema = TRUE; 1571 hwp = VGAHWPTR(pScrn); 1572 1573 hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F); 1574 1575 if (xf86IsPc98()) 1576 outb(0xFAC, 0xFF); 1577 1578 memcpy(ApmReg, &pApm->SavedReg, sizeof pApm->SavedReg); 1579 1580 /* 1581 * The APM chips have a scale factor of 8 for the 1582 * scanline offset. There are four extended bit in addition 1583 * to the 8 VGA bits. 1584 */ 1585 { 1586 int offset; 1587 1588 offset = (pApm->CurrentLayout.displayWidth * 1589 pApm->CurrentLayout.bitsPerPixel / 8) >> 3; 1590 hwp->ModeReg.CRTC[0x13] = offset; 1591 /* Bit 8 resides at CR1C bits 7:4. */ 1592 ApmReg->CRT[0x1C] = (offset & 0xF00) >> 4; 1593 } 1594 1595 /* Set pixel depth. */ 1596 switch(pApm->CurrentLayout.bitsPerPixel) 1597 { 1598 case 4: 1599 ApmReg->EX[XR80] = 0x01; 1600 break; 1601 case 8: 1602 ApmReg->EX[XR80] = 0x02; 1603 break; 1604 case 16: 1605 if (pApm->CurrentLayout.depth == 15) 1606 ApmReg->EX[XR80] = 0x0C; 1607 else 1608 ApmReg->EX[XR80] = 0x0D; 1609 break; 1610 case 24: 1611 ApmReg->EX[XR80] = 0x0E; 1612 break; 1613 case 32: 1614 ApmReg->EX[XR80] = 0x0F; 1615 break; 1616 default: 1617 FatalError("Unsupported bit depth %d\n", pApm->CurrentLayout.depth); 1618 break; 1619 } 1620 1621 /* Set banking register to zero. */ 1622 ApmReg->EX[XRC0] = 0; 1623 1624 /* Handle the CRTC overflow bits. */ 1625 { 1626 unsigned char val; 1627 /* Vertical Overflow. */ 1628 val = 0; 1629 if ((mode->CrtcVTotal - 2) & 0x400) 1630 val |= 0x01; 1631 if ((mode->CrtcVDisplay - 1) & 0x400) 1632 val |= 0x02; 1633 /* VBlankStart is equal to VSyncStart + 1. */ 1634 if (mode->CrtcVSyncStart & 0x400) 1635 val |= 0x04; 1636 /* VRetraceStart is equal to VSyncStart + 1. */ 1637 if (mode->CrtcVSyncStart & 0x400) 1638 val |= 0x08; 1639 ApmReg->CRT[0x1A] = val; 1640 1641 /* Horizontal Overflow. */ 1642 val = 0; 1643 if ((mode->CrtcHTotal / 8 - 5) & 0x100) 1644 val |= 1; 1645 if ((mode->CrtcHDisplay / 8 - 1) & 0x100) 1646 val |= 2; 1647 /* HBlankStart is equal to HSyncStart - 1. */ 1648 if ((mode->CrtcHSyncStart / 8 - 1) & 0x100) 1649 val |= 4; 1650 /* HRetraceStart is equal to HSyncStart. */ 1651 if ((mode->CrtcHSyncStart / 8) & 0x100) 1652 val |= 8; 1653 ApmReg->CRT[0x1B] = val; 1654 1655 /* Assume the CRTC is not KGA (see vgaHWInit) */ 1656 hwp->ModeReg.CRTC[3] = (hwp->ModeReg.CRTC[3] & 0xE0) | 1657 (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F); 1658 hwp->ModeReg.CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2) 1659 | (hwp->ModeReg.CRTC[5] & 0x7F); 1660 hwp->ModeReg.CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF; 1661 } 1662 ApmReg->CRT[0x1E] = 1; /* disable autoreset feature */ 1663 1664 /* Program clock select. */ 1665 ApmReg->EX[XREC] = comp_lmn(pApm, mode->Clock); 1666 if (!ApmReg->EX[XREC]) 1667 return FALSE; 1668 hwp->ModeReg.MiscOutReg |= 0x0C; 1669 1670 /* Set up the RAMDAC registers. */ 1671 1672 if (pApm->CurrentLayout.bitsPerPixel > 8) 1673 /* Get rid of white border. */ 1674 hwp->ModeReg.Attribute[0x11] = 0x00; 1675 else 1676 hwp->ModeReg.Attribute[0x11] = 0xFF; 1677 if (pApm->MemClk) 1678 ApmReg->EX[XRE8] = comp_lmn(pApm, pApm->MemClk); 1679 else if (pApm->Chipset >= AT3D) 1680 ApmReg->EX[XRE8] = 0x071F01E8; /* Enable 58MHz MCLK (actually 57.3 MHz) 1681 This is what is used in the Windows 1682 drivers. The BIOS sets it to 50MHz. */ 1683 else if (!pApm->noLinear) 1684 ApmReg->EX[XRE8] = RDXL(0xE8); /* No change */ 1685 else 1686 ApmReg->EX[XRE8] = RDXL_IOP(0xE8); /* No change */ 1687 1688 ApmReg->EX[XRE0] = 0x10; 1689 1690 /* If you change it, change in apm_funcs.c as well */ 1691 if (pApm->Chipset >= AT3D) { 1692 ApmReg->SEQ[0x1B] = 0x20; 1693 ApmReg->SEQ[0x1C] = 0x2F; 1694 } 1695 else { 1696 ApmReg->SEQ[0x1B] = 0x24; 1697 if (pScrn->videoRam >= 6 * 1024) 1698 ApmReg->SEQ[0x1C] = 0x2F; 1699 else 1700 ApmReg->SEQ[0x1C] = 0x2D; 1701 } 1702 1703 /* ICICICICI */ 1704 ApmRestore(pScrn, &hwp->ModeReg, ApmReg); 1705 1706 return TRUE; 1707} 1708 1709/* 1710 * Restore the initial mode. 1711 */ 1712static void 1713ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, ApmRegPtr ApmReg) 1714{ 1715 APMDECL(pScrn); 1716 1717 vgaHWProtect(pScrn, TRUE); 1718 ApmUnlock(pApm); 1719 1720 if (pApm->VGAMap) { 1721 /* 1722 * Restore fonts 1723 */ 1724 if (!(vgaReg->Attribute[0x10] & 1) && pApm->FontInfo) { 1725 ApmWriteSeq(0x1C, 0x3F); 1726 memcpy(pApm->FbBase, pApm->FontInfo, TEXT_AMOUNT); 1727 } 1728 1729 /* Set aperture index to 0. */ 1730 WRXW(0xC0, 0); 1731 1732 /* 1733 * Write the extended registers first 1734 */ 1735 ApmWriteSeq(0x1B, ApmReg->SEQ[0x1B]); 1736 ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]); 1737 1738 /* Hardware cursor registers. */ 1739 WRXL(0x140, ApmReg->EX[XR140]); 1740 WRXW(0x144, ApmReg->EX[XR144]); 1741 WRXL(0x148, ApmReg->EX[XR148]); 1742 WRXW(0x14C, ApmReg->EX[XR14C]); 1743 1744 ApmWriteCrtc(0x19, ApmReg->CRT[0x19]); 1745 ApmWriteCrtc(0x1A, ApmReg->CRT[0x1A]); 1746 ApmWriteCrtc(0x1B, ApmReg->CRT[0x1B]); 1747 ApmWriteCrtc(0x1D, ApmReg->CRT[0x1D]); 1748 ApmWriteCrtc(0x1E, ApmReg->CRT[0x1E]); 1749 1750 /* RAMDAC registers. */ 1751 WRXL(0xE8, ApmReg->EX[XRE8]); 1752 1753 WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7)); 1754 WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */ 1755 1756 /* Color correction */ 1757 WRXL(0xE0, ApmReg->EX[XRE0]); 1758 1759 /* 1760 * This function handles restoring the generic VGA registers. 1761 */ 1762 vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP); 1763 1764 /* set these after setting the default VGA registers */ 1765 ApmWriteCrtc(0x1C, ApmReg->CRT[0x1C]); 1766 WRXB(0x80, ApmReg->EX[XR80]); 1767 } 1768 else { 1769 /* Set aperture index to 0. */ 1770 if (pApm->noLinear) 1771 WRXW_IOP(0xC0, 0); 1772 else 1773 WRXW(0xC0, 0); 1774 1775 /* 1776 * Write the extended registers first 1777 */ 1778 wrinx(pApm->xport, 0x1B, ApmReg->SEQ[0x1B]); 1779 wrinx(pApm->xport, 0x1C, ApmReg->SEQ[0x1C]); 1780 1781 /* Hardware cursor registers. */ 1782 if (pApm->noLinear) { 1783 WRXL_IOP(0x140, ApmReg->EX[XR140]); 1784 WRXW_IOP(0x144, ApmReg->EX[XR144]); 1785 WRXL_IOP(0x148, ApmReg->EX[XR148]); 1786 WRXW_IOP(0x14C, ApmReg->EX[XR14C]); 1787 } 1788 else { 1789 WRXL(0x140, ApmReg->EX[XR140]); 1790 WRXW(0x144, ApmReg->EX[XR144]); 1791 WRXL(0x148, ApmReg->EX[XR148]); 1792 WRXW(0x14C, ApmReg->EX[XR14C]); 1793 } 1794 1795 wrinx(pApm->iobase + 0x3D4, 0x19, ApmReg->CRT[0x19]); 1796 wrinx(pApm->iobase + 0x3D4, 0x1A, ApmReg->CRT[0x1A]); 1797 wrinx(pApm->iobase + 0x3D4, 0x1B, ApmReg->CRT[0x1B]); 1798 wrinx(pApm->iobase + 0x3D4, 0x1C, ApmReg->CRT[0x1C]); 1799 wrinx(pApm->iobase + 0x3D4, 0x1D, ApmReg->CRT[0x1D]); 1800 wrinx(pApm->iobase + 0x3D4, 0x1E, ApmReg->CRT[0x1E]); 1801 1802 /* RAMDAC registers. */ 1803 if (pApm->noLinear) { 1804 WRXL_IOP(0xE8, ApmReg->EX[XRE8]); 1805 WRXL_IOP(0xEC, ApmReg->EX[XREC] & ~(1 << 7)); 1806 WRXL_IOP(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */ 1807 } 1808 else { 1809 WRXL(0xE8, ApmReg->EX[XRE8]); 1810 WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7)); 1811 WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */ 1812 } 1813 1814 /* Color correction */ 1815 if (pApm->noLinear) 1816 WRXL_IOP(0xE0, ApmReg->EX[XRE0]); 1817 else 1818 WRXL(0xE0, ApmReg->EX[XRE0]); 1819 1820 if (pApm->noLinear) 1821 WRXB_IOP(0x80, ApmReg->EX[XR80]); 1822 else 1823 WRXB(0x80, ApmReg->EX[XR80]); 1824 1825 /* 1826 * This function handles restoring the generic VGA registers. 1827 */ 1828 vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL); 1829 } 1830 1831 vgaHWProtect(pScrn, FALSE); 1832} 1833 1834 1835/* Refresh a region of the shadow framebuffer to the screen */ 1836static void 1837ApmRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) 1838{ 1839 APMDECL(pScrn); 1840 int width, height, Bpp, FBPitch; 1841 unsigned char *src, *dst; 1842 1843 Bpp = pApm->CurrentLayout.bitsPerPixel >> 3; 1844 FBPitch = pApm->CurrentLayout.bytesPerScanline; 1845 1846 while(num--) { 1847 width = (pbox->x2 - pbox->x1) * Bpp; 1848 height = pbox->y2 - pbox->y1; 1849 src = pApm->ShadowPtr + (pbox->y1 * pApm->ShadowPitch) + 1850 (pbox->x1 * Bpp); 1851 dst = (unsigned char *)pApm->FbBase + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp); 1852 1853 while(height--) { 1854 memcpy(dst, src, width); 1855 dst += FBPitch; 1856 src += pApm->ShadowPitch; 1857 } 1858 1859 pbox++; 1860 } 1861} 1862 1863 1864/* Mandatory */ 1865 1866/* This gets called at the start of each server generation */ 1867 1868static Bool 1869ApmScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) 1870{ 1871 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 1872 APMDECL(pScrn); 1873 int ret; 1874 unsigned char *FbBase; 1875 1876 pApm->pScreen = pScreen; 1877 1878 /* Map the chip memory and MMIO areas */ 1879 if (pApm->noLinear) { 1880 pApm->saveCmd = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG); 1881 pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, pApm->saveCmd | (PCI_CMD_IO_ENABLE|PCI_CMD_MEM_ENABLE)); 1882 pApm->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, 1883 pApm->PciTag, 0xA0000, 0x10000); 1884 } 1885 else 1886 if (!ApmMapMem(pScrn)) 1887 return FALSE; 1888 1889 /* No memory reserved yet */ 1890 pApm->OffscreenReserved = 0; 1891 1892 /* Save the current state */ 1893 ApmSave(pScrn); 1894 1895 /* Initialise the first mode */ 1896 ApmModeInit(pScrn, pScrn->currentMode); 1897 pApm->CurrentLayout.pMode = pScrn->currentMode; 1898 1899 /* Darken the screen for aesthetic reasons and set the viewport */ 1900 ApmSaveScreen(pScreen, SCREEN_SAVER_ON); 1901 ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 1902 1903 /* 1904 * Reset fb's visual list. 1905 */ 1906 miClearVisualTypes(); 1907 1908 /* Setup the visuals we support. */ 1909 1910 /* 1911 * For bpp > 8, the default visuals are not acceptable because we only 1912 * support TrueColor and not DirectColor. To deal with this, call 1913 * miSetVisualTypes for each visual supported. 1914 */ 1915 1916 if (pApm->CurrentLayout.bitsPerPixel > 8) { 1917 if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, 1918 pScrn->defaultVisual)) 1919 return FALSE; 1920 } else { 1921 if (!miSetVisualTypes(pScrn->depth, 1922 miGetDefaultVisualMask(pScrn->depth), 1923 pScrn->rgbBits, pScrn->defaultVisual)) 1924 return FALSE; 1925 } 1926 1927 /* 1928 * Call the framebuffer layer's ScreenInit function, and fill in other 1929 * pScreen fields. 1930 */ 1931 1932 if(pApm->ShadowFB) { 1933 pApm->ShadowPitch = 1934 ((pScrn->virtualX * pScrn->bitsPerPixel >> 3) + 3) & ~3L; 1935 pApm->ShadowPtr = xalloc(pApm->ShadowPitch * pScrn->virtualY); 1936 FbBase = pApm->ShadowPtr; 1937 } else { 1938 pApm->ShadowPtr = NULL; 1939 FbBase = pApm->FbBase; 1940 } 1941 1942 /* Reserve memory */ 1943 ApmHWCursorReserveSpace(pApm); 1944 ApmAccelReserveSpace(pApm); 1945 1946 miSetPixmapDepths(); 1947 1948 switch (pScrn->bitsPerPixel) { 1949 case 1: 1950 ret = xf1bppScreenInit(pScreen, FbBase, 1951 pScrn->virtualX, pScrn->virtualY, 1952 pScrn->xDpi, pScrn->yDpi, 1953 pScrn->displayWidth); 1954 break; 1955 case 4: 1956 ret = xf4bppScreenInit(pScreen, FbBase, 1957 pScrn->virtualX, pScrn->virtualY, 1958 pScrn->xDpi, pScrn->yDpi, 1959 pScrn->displayWidth); 1960 break; 1961 case 8: 1962 case 16: 1963 case 24: 1964 case 32: 1965 ret = fbScreenInit(pScreen, FbBase, pScrn->virtualX, 1966 pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, 1967 pScrn->displayWidth, pScrn->bitsPerPixel); 1968 break; 1969 default: 1970 xf86DrvMsg(scrnIndex, X_ERROR, 1971 "Internal error: invalid bpp (%d) in ApmScrnInit\n", 1972 pScrn->bitsPerPixel); 1973 ret = FALSE; 1974 break; 1975 } 1976 if (!ret) 1977 return FALSE; 1978 1979 if (pScrn->bitsPerPixel > 8) { 1980 VisualPtr visual; 1981 1982 /* Fixup RGB ordering */ 1983 visual = pScreen->visuals + pScreen->numVisuals; 1984 while (--visual >= pScreen->visuals) { 1985 if ((visual->class | DynamicClass) == DirectColor) { 1986 visual->offsetRed = pScrn->offset.red; 1987 visual->offsetGreen = pScrn->offset.green; 1988 visual->offsetBlue = pScrn->offset.blue; 1989 visual->redMask = pScrn->mask.red; 1990 visual->greenMask = pScrn->mask.green; 1991 visual->blueMask = pScrn->mask.blue; 1992 } 1993 } 1994 } 1995 1996 /* must be after visual RGB order fixed */ 1997 if (pScrn->bitsPerPixel > 4) 1998 fbPictureInit(pScreen, 0, 0); 1999 2000 xf86SetBlackWhitePixels(pScreen); 2001 2002 if (!pApm->ShadowFB) { /* hardware cursor needs to wrap this layer */ 2003 if(!ApmDGAInit(pScreen)) { 2004 xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DGA initialization failed\n"); 2005 } 2006 } 2007 2008 /* 2009 * Initialize the acceleration interface. 2010 */ 2011 if (!pApm->NoAccel) { 2012 ApmAccelInit(pScreen); /* set up XAA interface */ 2013 } 2014 2015 miInitializeBackingStore(pScreen); 2016 xf86SetBackingStore(pScreen); 2017 xf86SetSilkenMouse(pScreen); 2018 2019 /* Initialise cursor functions */ 2020 miDCInitialize (pScreen, xf86GetPointerScreenFuncs()); 2021 2022 /* Initialize HW cursor layer (after DGA and SW cursor) */ 2023 if (pApm->hwCursor) { 2024 if (!ApmHWCursorInit(pScreen)) 2025 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2026 "Hardware cursor initialization failed\n"); 2027 } 2028 2029 2030 /* Initialise default colourmap */ 2031 if (!miCreateDefColormap(pScreen)) 2032 return FALSE; 2033 2034 /* 2035 * Initialize colormap layer. 2036 * Must follow initialization of the default colormap. 2037 */ 2038 if (!xf86HandleColormaps(pScreen, 256, 8, ApmLoadPalette, NULL, 2039 CMAP_RELOAD_ON_MODE_SWITCH)) { 2040 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Colormap initialization failed\n"); 2041 return FALSE; 2042 } 2043 2044 if (pApm->ShadowFB) 2045 ShadowFBInit(pScreen, ApmRefreshArea); 2046 2047 xf86DPMSInit(pScreen, ApmDisplayPowerManagementSet, 0); 2048 2049 if (pApm->noLinear) 2050 ApmInitVideo_IOP(pScreen); 2051 else 2052 ApmInitVideo(pScreen); 2053 2054 pScreen->SaveScreen = ApmSaveScreen; 2055 2056 pApm->CloseScreen = pScreen->CloseScreen; 2057 pScreen->CloseScreen = ApmCloseScreen; 2058 2059 pScrn->memPhysBase = pApm->LinAddress; 2060 pScrn->fbOffset = (((char *)pApm->FbBase) - ((char *)pApm->LinMap)); 2061 2062 /* Report any unused options (only for the first generation) */ 2063 if (serverGeneration == 1) { 2064 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 2065 } 2066 2067 if (ApmGeneration != serverGeneration) { 2068 if ((ApmPixmapIndex = AllocatePixmapPrivateIndex()) < 0) 2069 return FALSE; 2070 ApmGeneration = serverGeneration; 2071 } 2072 2073 if (!AllocatePixmapPrivate(pScreen, ApmPixmapIndex, sizeof(ApmPixmapRec))) 2074 return FALSE; 2075 2076 /* Done */ 2077 return TRUE; 2078} 2079 2080/* mandatory */ 2081static void 2082ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, 2083 VisualPtr pVisual) 2084{ 2085 APMDECL(pScrn); 2086 int i, index, last = -1; 2087 2088 if (pApm->VGAMap) { 2089 for (i = 0; i < numColors; i++) { 2090 index = indices[i]; 2091 if (index != last) 2092 ApmWriteDacWriteAddr(index); 2093 last = index + 1; 2094 ApmWriteDacData(colors[index].red); 2095 ApmWriteDacData(colors[index].green); 2096 ApmWriteDacData(colors[index].blue); 2097 } 2098 } 2099 else { 2100 for (i = 0; i < numColors; i++) { 2101 index = indices[i]; 2102 if (index != last) 2103 outb(pApm->iobase + 0x3C8, index); 2104 last = index + 1; 2105 outb(pApm->iobase + 0x3C9, colors[index].red); 2106 outb(pApm->iobase + 0x3C9, colors[index].green); 2107 outb(pApm->iobase + 0x3C9, colors[index].blue); 2108 } 2109 } 2110} 2111 2112/* Usually mandatory */ 2113Bool 2114ApmSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) 2115{ 2116 return ApmModeInit(xf86Screens[scrnIndex], mode); 2117} 2118 2119/* 2120 * This function is used to initialize the Start Address - the first 2121 * displayed location in the video memory. 2122 */ 2123/* Usually mandatory */ 2124void 2125ApmAdjustFrame(int scrnIndex, int x, int y, int flags) 2126{ 2127 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 2128 APMDECL(pScrn); 2129 int Base; 2130 2131 if (pApm->CurrentLayout.bitsPerPixel == 24) 2132 x = (x + 3) & ~3; 2133 Base = ((y * pApm->CurrentLayout.displayWidth + x) * (pApm->CurrentLayout.bitsPerPixel / 8)) >> 2; 2134 /* 2135 * These are the generic starting address registers. 2136 */ 2137 if (pApm->VGAMap) { 2138 ApmWriteCrtc(0x0C, Base >> 8); 2139 ApmWriteCrtc(0x0D, Base); 2140 2141 /* 2142 * Here the high-order bits are masked and shifted, and put into 2143 * the appropriate extended registers. 2144 */ 2145 ApmWriteCrtc(0x1C, (ApmReadCrtc(0x1C) & 0xF0) | ((Base & 0x0F0000) >> 16)); 2146 } 2147 else { 2148 outw(pApm->iobase + 0x3D4, (Base & 0x00FF00) | 0x0C); 2149 outw(pApm->iobase + 0x3D4, ((Base & 0x00FF) << 8) | 0x0D); 2150 2151 /* 2152 * Here the high-order bits are masked and shifted, and put into 2153 * the appropriate extended registers. 2154 */ 2155 modinx(pApm->iobase + 0x3D4, 0x1C, 0x0F, (Base & 0x0F0000) >> 16); 2156 } 2157} 2158 2159/* 2160 * This is called when VT switching back to the X server. Its job is 2161 * to reinitialise the video mode. 2162 * 2163 * We may wish to unmap video/MMIO memory too. 2164 */ 2165 2166/* Mandatory */ 2167static Bool 2168ApmEnterVT(int scrnIndex, int flags) 2169{ 2170 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 2171 APMDECL(pScrn); 2172 vgaHWPtr hwp = VGAHWPTR(pScrn); 2173 2174 if (pApm->Chipset >= AT3D) { 2175 if (!pApm->noLinear) { 2176 /* If you change it, change it also in apm_funcs.c */ 2177 WRXB(0xDB, (pApm->db & 0xF4) | 0x0A | pApm->Rush); 2178 WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20); 2179 } 2180 else { 2181 WRXB_IOP(0xDB, pApm->db & 0xF4); 2182 } 2183 } 2184 if (pApm->Chipset >= AP6422) 2185 WRXB(0xC9, pApm->c9 | 0x10); 2186 ApmUnlock(APMPTR(pScrn)); 2187 vgaHWUnlock(hwp); 2188 /* 2189 * Set color mode 2190 */ 2191 hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F); 2192 2193 if (!ApmModeInit(pScrn, pScrn->currentMode)) 2194 return FALSE; 2195 ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); 2196 2197 return TRUE; 2198} 2199 2200/* Mandatory */ 2201static void 2202ApmLeaveVT(int scrnIndex, int flags) 2203{ 2204 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 2205 APMDECL(pScrn); 2206 vgaHWPtr hwp = VGAHWPTR(pScrn); 2207 2208 ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg); 2209 /* 2210 * Reset color mode 2211 */ 2212 (*hwp->writeMiscOut)(hwp, pApm->MiscOut); 2213 vgaHWLock(hwp); 2214 ApmLock(pApm); 2215 if (pApm->Chipset >= AT3D) { 2216 if (!pApm->noLinear) { 2217 WRXB(0xD9, pApm->d9); 2218 WRXB(0xDB, pApm->db); 2219 } 2220 else { 2221 WRXB_IOP(0xD9, pApm->d9); 2222 WRXB_IOP(0xDB, pApm->db); 2223 } 2224 } 2225 WRXB(0xC9, pApm->c9); 2226 2227 if (xf86IsPc98()) 2228 outb(0xFAC, 0xFE); 2229} 2230 2231/* 2232 * This is called at the end of each server generation. It restores the 2233 * original (text) mode. It should really also unmap the video memory too. 2234 */ 2235 2236/* Mandatory */ 2237static Bool 2238ApmCloseScreen(int scrnIndex, ScreenPtr pScreen) 2239{ 2240 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 2241 vgaHWPtr hwp = VGAHWPTR(pScrn); 2242 APMDECL(pScrn); 2243 2244 if (pScrn->vtSema) { 2245 ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg); 2246 vgaHWLock(hwp); 2247 ApmUnmapMem(pScrn); 2248 } 2249 if(pApm->AccelInfoRec) 2250 XAADestroyInfoRec(pApm->AccelInfoRec); 2251 if(pApm->DGAXAAInfo) 2252 XAADestroyInfoRec(pApm->DGAXAAInfo); 2253 pApm->AccelInfoRec = NULL; 2254 if(pApm->CursorInfoRec) 2255 xf86DestroyCursorInfoRec(pApm->CursorInfoRec); 2256 pApm->CursorInfoRec = NULL; 2257 if (pApm->DGAModes) 2258 xfree(pApm->DGAModes); 2259 if (pApm->adaptor) 2260 xfree(pApm->adaptor); 2261 2262 pScrn->vtSema = FALSE; 2263 2264 if (xf86IsPc98()) 2265 outb(0xFAC, 0xFE); 2266 2267 pScreen->CloseScreen = pApm->CloseScreen; 2268 return (*pScreen->CloseScreen)(scrnIndex, pScreen); 2269} 2270 2271/* Free up any per-generation data structures */ 2272 2273/* Optional */ 2274static void 2275ApmFreeScreen(int scrnIndex, int flags) 2276{ 2277 vgaHWFreeHWRec(xf86Screens[scrnIndex]); 2278 ApmFreeRec(xf86Screens[scrnIndex]); 2279} 2280 2281/* Checks if a mode is suitable for the selected chipset. */ 2282 2283/* Optional */ 2284static ModeStatus 2285ApmValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) 2286{ 2287 if (mode->Flags & V_INTERLACE) 2288 return(MODE_BAD); 2289 2290 return(MODE_OK); 2291} 2292 2293 2294/* 2295 * ApmDisplayPowerManagementSet -- 2296 * 2297 * Sets VESA Display Power Management Signaling (DPMS) Mode. 2298 */ 2299static void 2300ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, 2301 int flags) 2302{ 2303 APMDECL(pScrn); 2304 unsigned char dpmsreg, tmp; 2305 2306 if (PowerManagementMode < sizeof pApm->DPMSMask && 2307 PowerManagementMode >= 0) 2308 PowerManagementMode = pApm->DPMSMask[PowerManagementMode]; 2309 switch (PowerManagementMode) 2310 { 2311 case DPMSModeOn: 2312 /* Screen: On; HSync: On, VSync: On */ 2313 dpmsreg = 0x00; 2314 break; 2315 case DPMSModeStandby: 2316 /* Screen: Off; HSync: Off, VSync: On */ 2317 dpmsreg = 0x01; 2318 break; 2319 case DPMSModeSuspend: 2320 /* Screen: Off; HSync: On, VSync: Off */ 2321 dpmsreg = 0x02; 2322 break; 2323 case DPMSModeOff: 2324 /* Screen: Off; HSync: Off, VSync: Off */ 2325 dpmsreg = 0x03; 2326 break; 2327 default: 2328 dpmsreg = 0; 2329 } 2330 if (pApm->noLinear) { 2331 tmp = RDXB_IOP(0xD0); 2332 WRXB_IOP(0xD0, (tmp & 0xFC) | dpmsreg); 2333 } else { 2334 tmp = RDXB(0xD0); 2335 WRXB(0xD0, (tmp & 0xFC) | dpmsreg); 2336 } 2337} 2338 2339static Bool 2340ApmSaveScreen(ScreenPtr pScreen, int mode) 2341{ 2342 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 2343 Bool unblank; 2344 2345 unblank = xf86IsUnblank(mode); 2346 2347 if (unblank) 2348 SetTimeSinceLastInputEvent(); 2349 2350 if (pScrn->vtSema) 2351 vgaHWBlankScreen(pScrn, unblank); 2352 return TRUE; 2353} 2354 2355#ifdef APM_DEBUG 2356unsigned char _L_ACR(unsigned char *x); 2357unsigned char _L_ACR(unsigned char *x) 2358{ 2359 return *x; 2360} 2361 2362unsigned short _L_ASR(unsigned short *x); 2363unsigned short _L_ASR(unsigned short *x) 2364{ 2365 return *x; 2366} 2367 2368unsigned int _L_AIR(unsigned int *x); 2369unsigned int _L_AIR(unsigned int *x) 2370{ 2371 return *x; 2372} 2373 2374void _L_ACW(char *x, char y); 2375void _L_ACW(char *x, char y) 2376{ 2377 *x = y; 2378} 2379 2380void _L_ASW(short *x, short y); 2381void _L_ASW(short *x, short y) 2382{ 2383 *x = y; 2384} 2385 2386void _L_AIW(int *x, int y); 2387void _L_AIW(int *x, int y) 2388{ 2389 *x = y; 2390} 2391#endif 2392