tseng_mode.c revision 4b9470b1
1/* 2 * Copyright 2005-2006 Luc Verhaegen. 3 * Copyright 1993-1997 The XFree86 Project, Inc. 4 * Copyright 1990-1991 Thomas Roell. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sub license, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26#ifdef HAVE_CONFIG_H 27#include "config.h" 28#endif 29 30#include "tseng.h" 31 32/* 33 * lacking from hwp 34 */ 35 36#define VGA_BANK 0x3CB 37 38void 39vgaHWWriteBank(vgaHWPtr hwp, CARD8 value) 40{ 41 if (hwp->MMIOBase) 42 MMIO_OUT8(hwp->MMIOBase, hwp->MMIOOffset + VGA_BANK, value); 43 else 44#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 45 outb(hwp->PIOOffset + VGA_BANK, value); 46#else 47 pci_io_write8(hwp->io, VGA_BANK, value); 48#endif 49} 50 51CARD8 52vgaHWReadBank(vgaHWPtr hwp) 53{ 54 if (hwp->MMIOBase) 55 return MMIO_IN8(hwp->MMIOBase, hwp->MMIOOffset + VGA_BANK); 56 else 57#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 58 return inb(hwp->PIOOffset + VGA_BANK); 59#else 60 return pci_io_read8(hwp->io, VGA_BANK); 61#endif 62} 63 64#define VGA_SEGMENT 0x3CD 65 66void 67vgaHWWriteSegment(vgaHWPtr hwp, CARD8 value) 68{ 69 if (hwp->MMIOBase) 70 MMIO_OUT8(hwp->MMIOBase, hwp->MMIOOffset + VGA_SEGMENT, value); 71 else 72#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 73 outb(hwp->PIOOffset + VGA_SEGMENT, value); 74#else 75 pci_io_write8(hwp->io, VGA_SEGMENT, value); 76#endif 77} 78 79CARD8 80vgaHWReadSegment(vgaHWPtr hwp) 81{ 82 if (hwp->MMIOBase) 83 return MMIO_IN8(hwp->MMIOBase, hwp->MMIOOffset + VGA_SEGMENT); 84 else 85#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 86 return inb(hwp->PIOOffset + VGA_SEGMENT); 87#else 88 return pci_io_read8(hwp->io, VGA_SEGMENT); 89#endif 90} 91 92/* 93 * 0x3D8 Tseng Display Mode Control 94 */ 95#define VGA_MODE_CONTROL 0x08 96 97void 98vgaHWWriteModeControl(vgaHWPtr hwp, CARD8 value) 99{ 100 if (hwp->MMIOBase) 101 MMIO_OUT8(hwp->MMIOBase, 102 hwp->MMIOOffset + hwp->IOBase + VGA_MODE_CONTROL, value); 103 else 104#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 105 outb(hwp->PIOOffset + VGA_MODE_CONTROL, value); 106#else 107 pci_io_write8(hwp->io, VGA_MODE_CONTROL, value); 108#endif 109} 110 111/* 112 * 0x3BF: Hercules compatibility mode. 113 * Enable/Disable Second page (B800h-BFFFh) 114 */ 115 116#define VGA_HERCULES 0x3BF 117 118void 119vgaHWHerculesSecondPage(vgaHWPtr hwp, Bool Enable) 120{ 121 CARD8 tmp; 122 123 if (hwp->MMIOBase) { 124 tmp = MMIO_IN8(hwp->MMIOBase, hwp->MMIOOffset + VGA_HERCULES); 125 126 if (Enable) 127 tmp |= 0x02; 128 else 129 tmp &= ~0x02; 130 131 MMIO_OUT8(hwp->MMIOBase, hwp->MMIOOffset + VGA_HERCULES, tmp); 132 } else { 133#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 134 tmp = inb(hwp->PIOOffset + VGA_HERCULES); 135#else 136 tmp = pci_io_read8(hwp->io, VGA_HERCULES); 137#endif 138 139 if (Enable) 140 tmp |= 0x02; 141 else 142 tmp &= ~0x02; 143 144#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12 145 outb(hwp->PIOOffset + VGA_HERCULES, tmp); 146#else 147 pci_io_write8(hwp->io, VGA_HERCULES, tmp); 148#endif 149 } 150} 151 152/* 153 * ET6000 IO Range handling. 154 * 155 */ 156CARD8 157ET6000IORead(TsengPtr pTseng, CARD8 Offset) 158{ 159 return inb(pTseng->ET6000IOAddress + Offset); 160} 161 162void 163ET6000IOWrite(TsengPtr pTseng, CARD8 Offset, CARD8 Value) 164{ 165 outb(pTseng->ET6000IOAddress + Offset, Value); 166} 167 168/* 169 * 170 * RAMDAC handling. 171 * 172 */ 173 174/* 175 * 176 * SGS-Thomson STG-1703 177 * 178 */ 179/* 180 * 181 */ 182static Bool 183STG1703Detect(ScrnInfoPtr pScrn) 184{ 185 TsengPtr pTseng = TsengPTR(pScrn); 186 vgaHWPtr hwp = VGAHWPTR(pScrn); 187 CARD8 temp, cid, did, readDacMask; 188 189 /* TSENGFUNC(pScrn->scrnIndex); */ 190 191 /* store command register and DacMask */ 192 hwp->writeDacWriteAddr(hwp, 0x00); 193 readDacMask = hwp->readDacMask(hwp); 194 hwp->readDacMask(hwp); 195 hwp->readDacMask(hwp); 196 hwp->readDacMask(hwp); 197 temp = hwp->readDacMask(hwp); 198 199 /* enable extended registers */ 200 hwp->writeDacWriteAddr(hwp, 0x00); 201 hwp->readDacMask(hwp); 202 hwp->readDacMask(hwp); 203 hwp->readDacMask(hwp); 204 hwp->readDacMask(hwp); 205 hwp->writeDacMask(hwp, temp | 0x10); 206 207 /* set index 0x0000 and read IDs */ 208 hwp->writeDacWriteAddr(hwp, 0x00); 209 hwp->readDacMask(hwp); 210 hwp->readDacMask(hwp); 211 hwp->readDacMask(hwp); 212 hwp->readDacMask(hwp); 213 hwp->readDacMask(hwp); 214 hwp->writeDacMask(hwp, 0x00); 215 hwp->writeDacMask(hwp, 0x00); 216 cid = hwp->readDacMask(hwp); /* company ID */ 217 did = hwp->readDacMask(hwp); /* device ID */ 218 219 /* restore command register */ 220 hwp->writeDacWriteAddr(hwp, 0x00); 221 hwp->readDacMask(hwp); 222 hwp->readDacMask(hwp); 223 hwp->readDacMask(hwp); 224 hwp->readDacMask(hwp); 225 hwp->writeDacMask(hwp, temp); 226 227 /* restore DacMask */ 228 hwp->writeDacWriteAddr(hwp, 0x00); 229 hwp->writeDacMask(hwp, readDacMask); 230 231 hwp->writeDacWriteAddr(hwp, 0x00); 232 233 if ((cid == 0x44) && (did == 0x03)) { 234 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected STG-1703 RAMDAC.\n"); 235 pTseng->RAMDAC = STG1703; 236 return TRUE; 237 } 238 return FALSE; 239} 240 241/* 242 * 243 */ 244struct STG1703Regs { 245 CARD8 Command; 246 CARD8 Pixel; 247 CARD8 Timing; 248 CARD16 PLL; 249}; 250 251/* 252 * 253 */ 254static void 255STG1703PrintRegs(ScrnInfoPtr pScrn, struct STG1703Regs *Regs) 256{ 257 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "STG1703 Registers:\n"); 258 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "Command: 0x%02X\n", 259 Regs->Command); 260 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "Pixel mode: 0x%02X\n", 261 Regs->Pixel); 262 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "Timing: 0x%02X\n", 263 Regs->Timing); 264 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "PLL: 0x%04X\n", 265 Regs->PLL); 266} 267 268/* 269 * 270 */ 271static void 272STG1703Store(ScrnInfoPtr pScrn, struct STG1703Regs *Regs) 273{ 274 vgaHWPtr hwp = VGAHWPTR(pScrn); 275 CARD8 readDacMask; 276 277 /* save command register and dacMask*/ 278 hwp->writeDacWriteAddr(hwp, 0x00); 279 readDacMask = hwp->readDacMask(hwp); 280 hwp->readDacMask(hwp); 281 hwp->readDacMask(hwp); 282 hwp->readDacMask(hwp); 283 Regs->Command = hwp->readDacMask(hwp); 284 285 /* enable indexed register space */ 286 hwp->writeDacWriteAddr(hwp, 0x00); 287 hwp->readDacMask(hwp); 288 hwp->readDacMask(hwp); 289 hwp->readDacMask(hwp); 290 hwp->readDacMask(hwp); 291 hwp->writeDacMask(hwp, Regs->Command | 0x10); 292 293 /* set the index for the pixel mode */ 294 hwp->writeDacWriteAddr(hwp, 0x00); 295 hwp->readDacMask(hwp); 296 hwp->readDacMask(hwp); 297 hwp->readDacMask(hwp); 298 hwp->readDacMask(hwp); 299 hwp->readDacMask(hwp); 300 hwp->writeDacMask(hwp, 0x03); 301 hwp->writeDacMask(hwp, 0x00); 302 303 Regs->Pixel = hwp->readDacMask(hwp); /* pixel mode */ 304 305 hwp->readDacMask(hwp); /* skip secondary pixel mode */ 306 307 Regs->Timing = hwp->readDacMask(hwp); /* pipeline timing */ 308 309 /* start over for the pll register */ 310 hwp->writeDacWriteAddr(hwp, 0x00); 311 hwp->readDacMask(hwp); 312 hwp->readDacMask(hwp); 313 hwp->readDacMask(hwp); 314 hwp->readDacMask(hwp); 315 hwp->readDacMask(hwp); 316 317 /* set the index for VCLK2 */ 318 hwp->writeDacMask(hwp, 0x24); 319 hwp->writeDacMask(hwp, 0x00); 320 321 Regs->PLL = hwp->readDacMask(hwp); 322 Regs->PLL |= (hwp->readDacMask(hwp) << 8); 323 324 /* restore command register and dacMask */ 325 hwp->writeDacWriteAddr(hwp, 0x00); 326 hwp->readDacMask(hwp); 327 hwp->readDacMask(hwp); 328 hwp->readDacMask(hwp); 329 hwp->readDacMask(hwp); 330 hwp->writeDacMask(hwp, Regs->Command); 331 332 hwp->writeDacWriteAddr(hwp, 0x00); 333 hwp->writeDacMask(hwp, readDacMask); 334 335 hwp->writeDacWriteAddr(hwp, 0x00); 336 337 STG1703PrintRegs(pScrn, Regs); 338} 339 340/* 341 * 342 */ 343static void 344STG1703Restore(ScrnInfoPtr pScrn, struct STG1703Regs *Regs) 345{ 346 vgaHWPtr hwp = VGAHWPTR(pScrn); 347 CARD8 temp, readDacMask; 348 349 STG1703PrintRegs(pScrn, Regs); 350 351 /* save command register and dacMask*/ 352 hwp->writeDacWriteAddr(hwp, 0x00); 353 readDacMask = hwp->readDacMask(hwp); 354 hwp->readDacMask(hwp); 355 hwp->readDacMask(hwp); 356 hwp->readDacMask(hwp); 357 temp = hwp->readDacMask(hwp); 358 359 /* enable indexed register space */ 360 hwp->writeDacWriteAddr(hwp, 0x00); 361 hwp->readDacMask(hwp); 362 hwp->readDacMask(hwp); 363 hwp->readDacMask(hwp); 364 hwp->readDacMask(hwp); 365 hwp->writeDacMask(hwp, temp | 0x10); 366 367 /* set the index for the pixel mode */ 368 hwp->writeDacWriteAddr(hwp, 0x00); 369 hwp->readDacMask(hwp); 370 hwp->readDacMask(hwp); 371 hwp->readDacMask(hwp); 372 hwp->readDacMask(hwp); 373 hwp->readDacMask(hwp); 374 hwp->writeDacMask(hwp, 0x03); 375 hwp->writeDacMask(hwp, 0x00); 376 377 hwp->writeDacMask(hwp, Regs->Pixel); /* pixel mode */ 378 hwp->writeDacMask(hwp, Regs->Pixel); /* also secondary */ 379 hwp->writeDacMask(hwp, Regs->Timing); /* pipeline timing */ 380 381 /* start over for the pll register */ 382 hwp->writeDacWriteAddr(hwp, 0x00); 383 hwp->readDacMask(hwp); 384 hwp->readDacMask(hwp); 385 hwp->readDacMask(hwp); 386 hwp->readDacMask(hwp); 387 hwp->readDacMask(hwp); 388 389 /* set the index for VCLK2 */ 390 hwp->writeDacMask(hwp, 0x26); 391 hwp->writeDacMask(hwp, 0x00); 392 393 hwp->writeDacMask(hwp, Regs->PLL & 0xFF); 394 hwp->writeDacMask(hwp, Regs->PLL >> 8); 395 396 /* restore command register */ 397 hwp->writeDacWriteAddr(hwp, 0x00); 398 hwp->readDacMask(hwp); 399 hwp->readDacMask(hwp); 400 hwp->readDacMask(hwp); 401 hwp->readDacMask(hwp); 402 hwp->writeDacMask(hwp, Regs->Command); 403 404 /* Restore DacMask */ 405 hwp->writeDacWriteAddr(hwp, 0x00); 406 hwp->writeDacMask(hwp, readDacMask); 407 408 hwp->writeDacWriteAddr(hwp, 0x00); 409} 410 411/* 412 * Hope that the TVP3703 ramdac pll is the same as the STG1703. 413 */ 414static CARD16 415STG1703Clock(ScrnInfoPtr pScrn, int Clock) 416{ 417 CARD8 N1, N2, M; 418 CARD16 PLL = 0; 419 CARD32 Closest = 0xFFFFFFFF; 420 421 for (N2 = 0; N2 < 4; N2++) { 422 for (N1 = 7; N1 < 15; N1++) { 423 CARD8 divider = N1 << N2; 424 CARD32 temp; 425 426 /* check boundaries */ 427 temp = Clock * divider; 428 if ((temp < (64000 * N1)) || (temp > (135000 * N1))) 429 continue; 430 431 /* calculate 2M */ 432 temp = (2 * Clock * divider) / 14318; 433 if ((temp > 258) || (temp < 4)) /* (127 + 2) * 2 */ 434 continue; 435 436 /* round up/down */ 437 if (temp & 1) 438 M = temp / 2 + 1; 439 else 440 M = temp / 2; 441 442 /* is this the closest match? */ 443 temp = (14318 * M) / divider; 444 445 if (temp > Clock) 446 temp -= Clock; 447 else 448 temp = Clock - temp; 449 450 if (temp < Closest) { 451 PLL = (M - 2) | ((N1 - 2) << 8) | (N2 << 13); 452 Closest = temp; 453 } 454 } 455 } 456 457 return PLL; 458} 459 460/* 461 * Copy the given Regs into a freshly alloced STG1703Regs 462 * and init it for the new mode. 463 */ 464static struct STG1703Regs * 465STG1703Mode(ScrnInfoPtr pScrn, struct STG1703Regs *Saved, 466 DisplayModePtr mode) 467{ 468 struct STG1703Regs *Regs; 469 470 Regs = xnfalloc(sizeof(struct STG1703Regs)); 471 memcpy(Regs, Saved, sizeof(struct STG1703Regs)); 472 473 Regs->Command &= 0x04; /* keep 7.5 IRE setup setting */ 474 Regs->Command |= 0x08; /* enable extended pixel modes */ 475 476 switch (pScrn->bitsPerPixel) { 477 case 8: 478 Regs->Pixel = 0x05; 479 /* high bits of Command are already zeroed */ 480 break; 481 case 16: 482 Regs->Pixel = 0x03; 483 Regs->Command |= 0xC0; /* 16bpp */ 484 break; 485 case 24: 486 Regs->Pixel = 0x09; 487 Regs->Command |= 0xE0; /* 24bpp */ 488 break; 489 case 32: 490 Regs->Pixel = 0x04; /* 24bpp in 4Bytes */ 491 Regs->Command |= 0xE0; /* 24bpp */ 492 break; 493 default: 494 Regs->Pixel = 0x00; 495 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "STG1703 RAMDAC doesn't" 496 " support %dbpp.\n", pScrn->bitsPerPixel); 497 } 498 499 /* set PLL (input) range */ 500 if (mode->SynthClock <= 16000) 501 Regs->Timing = 0; 502 else if (mode->SynthClock <= 32000) 503 Regs->Timing = 1; 504 else if (mode->SynthClock <= 67500) 505 Regs->Timing = 2; 506 else 507 Regs->Timing = 3; 508 509 /* Calculate dotclock here */ 510 Regs->PLL = STG1703Clock(pScrn, mode->Clock); 511 512 STG1703PrintRegs(pScrn, Regs); 513 514 return Regs; 515} 516 517/* 518 * 519 * Chrontel CH8398A 520 * 521 */ 522 523/* 524 * 525 */ 526static Bool 527CH8398Detect(ScrnInfoPtr pScrn) 528{ 529 TsengPtr pTseng = TsengPTR(pScrn); 530 vgaHWPtr hwp = VGAHWPTR(pScrn); 531 CARD8 temp; 532 533 /* TSENGFUNC(pScrn->scrnIndex); */ 534 535 hwp->writeDacWriteAddr(hwp, 0x00); 536 hwp->readDacMask(hwp); 537 hwp->readDacMask(hwp); 538 hwp->readDacMask(hwp); 539 temp = hwp->readDacMask(hwp); 540 hwp->writeDacWriteAddr(hwp, 0x00); 541 542 if (temp == 0xC0) { 543 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected Chrontel CH8398 RAMDAC.\n"); 544 pTseng->RAMDAC = CH8398; 545 return TRUE; 546 } 547 return FALSE; 548} 549 550/* 551 * 552 */ 553struct CH8398Regs { 554 CARD8 Control; 555 CARD8 Aux; 556 CARD16 PLL; 557}; 558 559/* 560 * 561 */ 562static void 563CH8398PrintRegs(ScrnInfoPtr pScrn, struct CH8398Regs *Regs) 564{ 565 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "CH8398 Registers:\n"); 566 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "Control: 0x%02X\n", 567 Regs->Control); 568 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "Aux: 0x%02X\n", 569 Regs->Aux); 570 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "PLL: 0x%04X\n", 571 Regs->PLL); 572} 573 574/* 575 * 576 */ 577static void 578CH8398Store(ScrnInfoPtr pScrn, struct CH8398Regs *Regs) 579{ 580 vgaHWPtr hwp = VGAHWPTR(pScrn); 581 582 /* Get the control and auxiliary registers. */ 583 hwp->writeDacWriteAddr(hwp, 0x00); 584 hwp->readDacMask(hwp); 585 hwp->readDacMask(hwp); 586 hwp->readDacMask(hwp); 587 hwp->readDacMask(hwp); 588 Regs->Control = hwp->readDacMask(hwp); 589 Regs->Aux = hwp->readDacMask(hwp); 590 591 /* Enable PLL RAM access mode through AUX */ 592 hwp->writeDacWriteAddr(hwp, 0x00); 593 hwp->readDacMask(hwp); 594 hwp->readDacMask(hwp); 595 hwp->readDacMask(hwp); 596 hwp->readDacMask(hwp); 597 hwp->readDacMask(hwp); 598 hwp->writeDacMask(hwp, Regs->Aux | 0x80); 599 600 /* Read PLL */ 601 hwp->writeDacReadAddr(hwp, 0x03); 602 Regs->PLL = hwp->readDacData(hwp); /* N */ 603 Regs->PLL |= hwp->readDacData(hwp) << 8; /* M and K*/ 604 605 /* Disable PLL RAM access mode */ 606 hwp->writeDacWriteAddr(hwp, 0x00); 607 hwp->readDacMask(hwp); 608 hwp->readDacMask(hwp); 609 hwp->readDacMask(hwp); 610 hwp->readDacMask(hwp); 611 hwp->readDacMask(hwp); 612 hwp->writeDacMask(hwp, Regs->Aux & ~0x80); 613 614 /* exit sequence */ 615 hwp->writeDacWriteAddr(hwp, 0x00); 616 617 CH8398PrintRegs(pScrn, Regs); 618} 619 620/* 621 * 622 */ 623static void 624CH8398Restore(ScrnInfoPtr pScrn, struct CH8398Regs *Regs) 625{ 626 vgaHWPtr hwp = VGAHWPTR(pScrn); 627 628 CH8398PrintRegs(pScrn, Regs); 629 630 /* Write control and auxiliary registers */ 631 hwp->writeDacWriteAddr(hwp, 0x00); 632 hwp->readDacMask(hwp); 633 hwp->readDacMask(hwp); 634 hwp->readDacMask(hwp); 635 hwp->readDacMask(hwp); 636 hwp->writeDacMask(hwp, Regs->Control); 637 hwp->writeDacMask(hwp, Regs->Aux | 0x80); /* enable PLL RAM mode as well */ 638 639 /* Write PLL */ 640 hwp->writeDacWriteAddr(hwp, 0x02); 641 hwp->writeDacData(hwp, Regs->PLL & 0xFF); /* N */ 642 hwp->writeDacData(hwp, Regs->PLL >> 8); /* M and K */ 643 644 /* Disable PLL RAM access mode */ 645 hwp->writeDacWriteAddr(hwp, 0x00); 646 hwp->readDacMask(hwp); 647 hwp->readDacMask(hwp); 648 hwp->readDacMask(hwp); 649 hwp->readDacMask(hwp); 650 hwp->readDacMask(hwp); 651 hwp->writeDacMask(hwp, Regs->Aux & ~0x80); 652 653 /* exit sequence */ 654 hwp->writeDacWriteAddr(hwp, 0x00); 655} 656 657/* 658 * 659 */ 660static CARD16 661CH8398Clock(ScrnInfoPtr pScrn, int Clock) 662{ 663 CARD16 PLL = 0; 664 CARD8 N, M, K; 665 CARD32 Closest = 0xFFFFFFFF; 666 667 if (Clock > 68000) 668 K = 0; 669 else 670 K = 1; 671 672 for (M = 2; M < 12; M++) { 673 CARD16 divider = M << K; 674 CARD32 temp; 675 676 /* calculate 2N */ 677 temp = (2 * Clock * divider) / 14318; 678 if ((temp > 526) || (temp < 16)) /* (255 + 8) * 2 */ 679 continue; 680 681 /* round up/down */ 682 if (temp & 1) 683 N = temp / 2 + 1; 684 else 685 N = temp / 2; 686 687 /* is this the closest match? */ 688 temp = (14318 * N) / divider; 689 690 if (temp > Clock) 691 temp -= Clock; 692 else 693 temp = Clock - temp; 694 695 if (temp < Closest) { 696 PLL = (N - 8) | ((M - 2) << 8) | (K << 14); 697 Closest = temp; 698 } 699 } 700 701 return PLL; 702} 703 704/* 705 * 706 */ 707static struct CH8398Regs * 708CH8398Mode(ScrnInfoPtr pScrn, struct CH8398Regs *Saved, 709 DisplayModePtr mode) 710{ 711 struct CH8398Regs *Regs; 712 int Clock = mode->Clock; 713 714 Regs = xnfalloc(sizeof(struct CH8398Regs)); 715 memcpy(Regs, Saved, sizeof(struct CH8398Regs)); 716 717 Regs->Control &= 0x0F; 718 719 switch (pScrn->bitsPerPixel) { 720 case 8: 721 Regs->Control |= 0x20; 722 break; 723 case 16: 724 Regs->Control |= 0x30; 725 break; 726 case 24: 727 Regs->Control |= 0xB0; 728 break; 729 case 32: 730 Regs->Control |= 0x50; /* 24bpp in 4bytes */ 731 break; 732 default: 733 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CH8398 RAMDAC doesn't" 734 " support %dbpp.\n", pScrn->bitsPerPixel); 735 } 736 737 Regs->PLL = CH8398Clock(pScrn, Clock); 738 739 CH8398PrintRegs(pScrn, Regs); 740 741 return Regs; 742} 743 744 745/* 746 * 747 */ 748Bool 749TsengRAMDACProbe(ScrnInfoPtr pScrn) 750{ 751 TsengPtr pTseng = TsengPTR(pScrn); 752 753 PDEBUG(" Check_Tseng_Ramdac\n"); 754 755 if (pTseng->ChipType == ET6000) { 756 int mclk; 757 int dbyte; 758 759 /* There are some limits here though: 80000 <= MemClk <= 110000 */ 760 ET6000IORead(pTseng, 0x67); 761 ET6000IOWrite(pTseng, 0x67, 0x0A); 762 mclk = (ET6000IORead(pTseng, 0x69) + 2) * 14318; 763 dbyte = ET6000IORead(pTseng, 0x69); 764 mclk /= ((dbyte & 0x1f) + 2) * (1 << ((dbyte >> 5) & 0x03)); 765 pTseng->MemClk = mclk; 766 767 return TRUE; 768 } else { /* ET4000W32P has external ramdacs */ 769 770 /* First look for CH8398 - as this is a non-invasive detection */ 771 if (CH8398Detect(pScrn)) 772 return TRUE; 773 774 /* Now that we know that we won't mess up a CH8398 */ 775 if (STG1703Detect(pScrn)) 776 return TRUE; 777 778 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to probe RAMDAC\n"); 779 return FALSE; 780 /* hwp->writeDacMask(hwp, 0xFF); */ 781 } 782 783 return TRUE; 784} 785 786/* 787 * Memory bandwidth is important in > 8bpp modes, especially on ET4000 788 * 789 * This code evaluates a video mode with respect to requested dot clock 790 * (depends on the VGA chip and the RAMDAC) and the resulting bandwidth 791 * demand on memory (which in turn depends on color depth). 792 * 793 * For each mode, the minimum of max data transfer speed (dot clock 794 * limit) and memory bandwidth determines if the mode is allowed. 795 * 796 * We should also take acceleration into account: accelerated modes 797 * strain the bandwidth heavily, because they cause lots of random 798 * acesses to video memory, which is bad for bandwidth due to smaller 799 * page-mode memory requests. 800 */ 801void 802TsengSetupClockRange(ScrnInfoPtr pScrn) 803{ 804 TsengPtr pTseng = TsengPTR(pScrn); 805 int dacspeed, mem_bw; 806 807 PDEBUG(" tseng_clock_setup\n"); 808 809 if (pTseng->ChipType == ET6000) { 810 /* 811 * According to Tseng (about the ET6000): 812 * "Besides the 135 MHz maximum pixel clock frequency, the other limit has to 813 * do with where you get FIFO breakdown (usually appears as stray horizontal 814 * lines on the screen). Assuming the accelerator is running steadily doing a 815 * worst case operation, to avoid FIFO breakdown you should keep the product 816 * pixel_clock*(bytes/pixel) <= 225 MHz . This is based on an XCLK 817 * (system/memory) clock of 92 MHz (which is what we currently use) and 818 * a value in the RAS/CAS Configuration register (CFG 44) of either 015h 819 * or 014h (depending on the type of MDRAM chips). Also, the FIFO low 820 * threshold control bit (bit 4 of CFG 41) should be set for modes where 821 * pixel_clock*(bytes/pixel) > 130 MHz . These limits are for the 822 * current ET6000 chips. The ET6100 will raise the pixel clock limit 823 * to 175 MHz and the pixel_clock*(bytes/pixel) FIFO breakdown limit 824 * to about 275 MHz." 825 */ 826 827 if (pTseng->ChipRev == REV_ET6100) { 828 dacspeed = 175000; 829 mem_bw = 280000; /* 275000 is _just_ not enough for 1152x864x24 @ 70Hz */ 830 } else { /* ET6000 */ 831 dacspeed = 135000; 832 mem_bw = 225000; 833 } 834 835 switch (pScrn->bitsPerPixel) { 836 case 16: 837 mem_bw /= 2; 838 break; 839 case 24: 840 mem_bw /= 3; 841 break; 842 case 32: 843 mem_bw /= 4; 844 break; 845 case 8: 846 default: 847 break; 848 } 849 850 pTseng->max_vco_freq = dacspeed*2+1; 851 } else { /* ET4000W32p */ 852 853 switch (pTseng->RAMDAC) { 854 case STG1703: 855 if (pScrn->bitsPerPixel == 8) 856 dacspeed = 135000; 857 else 858 dacspeed = 110000; 859 break; 860 case CH8398: 861 dacspeed = 135000; 862 break; 863 default: 864 dacspeed = 0; 865 break; 866 } 867 868 if (pScrn->videoRam > 1024) 869 mem_bw = 150000; /* interleaved DRAM gives 70% more bandwidth */ 870 else 871 mem_bw = 90000; 872 873 switch (pScrn->bitsPerPixel) { 874 case 8: 875 /* Don't touch mem_bw or dac_speed */ 876 break; 877 case 16: 878 mem_bw /= 2; 879 /* 1:1 dotclock */ 880 break; 881 case 24: 882 mem_bw /= 3; 883 dacspeed = dacspeed * 3 / 2; 884 break; 885 case 32: 886 mem_bw /= 4; 887 dacspeed /= 2; 888 break; 889 default: 890 break; 891 } 892 } 893 894 pTseng->clockRange.next = NULL; 895 pTseng->clockRange.minClock = 12000; 896 if (mem_bw < dacspeed) 897 pTseng->clockRange.maxClock = mem_bw; 898 else 899 pTseng->clockRange.maxClock = dacspeed; 900 pTseng->clockRange.clockIndex = -1; /* programmable -- not used */ 901 pTseng->clockRange.interlaceAllowed = TRUE; 902 pTseng->clockRange.doubleScanAllowed = TRUE; 903 pTseng->clockRange.ClockMulFactor = 1; 904 pTseng->clockRange.ClockDivFactor = 1; 905 pTseng->clockRange.PrivFlags = 0; 906} 907 908 909/* 910 * 911 */ 912#define BASE_FREQ 14.31818 /* MHz */ 913static CARD16 914ET6000CalcClock(long freq, int min_m, int min_n1, int max_n1, int min_n2, 915 int max_n2, long freq_min, long freq_max) 916{ 917 double ffreq, ffreq_min, ffreq_max; 918 double div, diff, best_diff; 919 unsigned int m; 920 CARD8 n1, n2; 921 CARD8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2; 922 CARD8 ndiv, mdiv; 923 924 925 PDEBUG(" commonCalcClock\n"); 926 927 ffreq = freq / 1000.0 / BASE_FREQ; 928 ffreq_min = freq_min / 1000.0 / BASE_FREQ; 929 ffreq_max = freq_max / 1000.0 / BASE_FREQ; 930 931 if (ffreq < ffreq_min / (1 << max_n2)) { 932 ErrorF("invalid frequency %1.3f MHz [freq >= %1.3f MHz]\n", 933 ffreq * BASE_FREQ, ffreq_min * BASE_FREQ / (1 << max_n2)); 934 ffreq = ffreq_min / (1 << max_n2); 935 } 936 if (ffreq > ffreq_max / (1 << min_n2)) { 937 ErrorF("invalid frequency %1.3f MHz [freq <= %1.3f MHz]\n", 938 ffreq * BASE_FREQ, ffreq_max * BASE_FREQ / (1 << min_n2)); 939 ffreq = ffreq_max / (1 << min_n2); 940 } 941 /* work out suitable timings */ 942 943 best_diff = ffreq; 944 945 for (n2 = min_n2; n2 <= max_n2; n2++) { 946 for (n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) { 947 m = (int)(ffreq * n1 * (1 << n2) + 0.5); 948 if (m < min_m + 2 || m > 127 + 2) 949 continue; 950 div = (double)(m) / (double)(n1); 951 if ((div >= ffreq_min) && 952 (div <= ffreq_max)) { 953 diff = ffreq - div / (1 << n2); 954 if (diff < 0.0) 955 diff = -diff; 956 if (diff < best_diff) { 957 best_diff = diff; 958 best_m = m; 959 best_n1 = n1; 960 best_n2 = n2; 961 } 962 } 963 } 964 } 965 966#ifdef EXTENDED_DEBUG 967 ErrorF("Clock parameters for %1.6f MHz: m=%d, n1=%d, n2=%d\n", 968 ((double)(best_m) / (double)(best_n1) / (1 << best_n2)) * BASE_FREQ, 969 best_m - 2, best_n1 - 2, best_n2); 970#endif 971 972 if (max_n1 == 63) 973 ndiv = (best_n1 - 2) | (best_n2 << 6); 974 else 975 ndiv = (best_n1 - 2) | (best_n2 << 5); 976 mdiv = best_m - 2; 977 978 return (ndiv << 8) | mdiv; 979} 980 981/* 982 * adjust the current video frame (viewport) to display the mousecursor. 983 */ 984void 985TsengAdjustFrame(ADJUST_FRAME_ARGS_DECL) 986{ 987 SCRN_INFO_PTR(arg); 988 TsengPtr pTseng = TsengPTR(pScrn); 989 vgaHWPtr hwp = VGAHWPTR(pScrn); 990 int Base; 991 992 PDEBUG(" TsengAdjustFrame\n"); 993 994 if (pTseng->ShowCache && y) 995 y += 256; 996 997 if (pScrn->bitsPerPixel < 8) 998 Base = (y * pScrn->displayWidth + x + 3) >> 3; 999 else { 1000 Base = ((y * pScrn->displayWidth + x + 1) * pTseng->Bytesperpixel) >> 2; 1001 /* adjust Base address so it is a non-fractional multiple of pTseng->Bytesperpixel */ 1002 Base -= (Base % pTseng->Bytesperpixel); 1003 } 1004 1005 hwp->writeCrtc(hwp, 0x0C, (Base >> 8) & 0xFF); 1006 hwp->writeCrtc(hwp, 0x0D, Base & 0xFF); 1007 hwp->writeCrtc(hwp, 0x33, (Base >> 16) & 0x0F); 1008} 1009 1010/* 1011 * 1012 */ 1013ModeStatus 1014TsengValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags) 1015{ 1016 1017 PDEBUG(" TsengValidMode\n"); 1018 1019#ifdef FIXME 1020 is this needed? xf86ValidMode gets HMAX and VMAX variables, so it could deal with this. 1021 need to recheck hsize with mode->Htotal*mulFactor/divFactor 1022 /* Check for CRTC timing bits overflow. */ 1023 if (mode->HTotal > Tseng_HMAX) { 1024 return MODE_BAD_HVALUE; 1025 } 1026 if (mode->VTotal > Tseng_VMAX) { 1027 return MODE_BAD_VVALUE; 1028 } 1029#endif 1030 1031 return MODE_OK; 1032} 1033 1034/* 1035 * Save the current video mode 1036 */ 1037void 1038TsengSave(ScrnInfoPtr pScrn) 1039{ 1040 vgaHWPtr hwp = VGAHWPTR(pScrn); 1041 TsengPtr pTseng = TsengPTR(pScrn); 1042 vgaRegPtr vgaReg; 1043 TsengRegPtr tsengReg; 1044 unsigned char saveseg1 = 0, saveseg2 = 0; 1045 1046 PDEBUG(" TsengSave\n"); 1047 1048 vgaReg = &hwp->SavedReg; 1049 tsengReg = &pTseng->SavedReg; 1050 1051 /* 1052 * This function will handle creating the data structure and filling 1053 * in the generic VGA portion. 1054 */ 1055 vgaHWSave(pScrn, vgaReg, VGA_SR_ALL); 1056 1057 /* 1058 * we need this here , cause we MUST disable the ROM SYNC feature 1059 * this bit changed with W32p_rev_c... 1060 */ 1061 tsengReg->CR34 = hwp->readCrtc(hwp, 0x34); 1062 1063 if ((pTseng->ChipType == ET4000) && 1064 ((pTseng->ChipRev == REV_A) || (pTseng->ChipRev == REV_B))) 1065 /* data books say translation ROM is controlled by bits 4 and 5 */ 1066 hwp->writeCrtc(hwp, 0x34, tsengReg->CR34 & 0xCF); 1067 1068 saveseg1 = vgaHWReadSegment(hwp); 1069 vgaHWWriteSegment(hwp, 0x00); /* segment select 1 */ 1070 1071 saveseg2 = vgaHWReadBank(hwp); 1072 vgaHWWriteBank(hwp, 0x00); /* segment select 2 */ 1073 1074 tsengReg->ExtSegSel[0] = saveseg1; 1075 tsengReg->ExtSegSel[1] = saveseg2; 1076 1077 tsengReg->CR33 = hwp->readCrtc(hwp, 0x33); 1078 tsengReg->CR35 = hwp->readCrtc(hwp, 0x35); 1079 1080 if (pTseng->ChipType == ET4000) { 1081 tsengReg->CR36 = hwp->readCrtc(hwp, 0x36); 1082 tsengReg->CR37 = hwp->readCrtc(hwp, 0x37); 1083 tsengReg->CR32 = hwp->readCrtc(hwp, 0x32); 1084 } 1085 1086 TsengCursorStore(pScrn, tsengReg); 1087 1088 tsengReg->SR06 = hwp->readSeq(hwp, 0x06); 1089 tsengReg->SR07 = hwp->readSeq(hwp, 0x07) | 0x14; 1090 1091 tsengReg->ExtATC = hwp->readAttr(hwp, 0x36); 1092 hwp->writeAttr(hwp, 0x36, tsengReg->ExtATC); 1093 1094 if (pTseng->ChipType == ET4000) { 1095 switch (pTseng->RAMDAC) { 1096 case STG1703: 1097 if (!tsengReg->RAMDAC) 1098 tsengReg->RAMDAC = (struct STG1703Regs *) 1099 xnfalloc(sizeof(struct STG1703Regs)); 1100 STG1703Store(pScrn, tsengReg->RAMDAC); 1101 break; 1102 case CH8398: 1103 if (!tsengReg->RAMDAC) 1104 tsengReg->RAMDAC = (struct CH8398Regs *) 1105 xnfalloc(sizeof(struct CH8398Regs)); 1106 CH8398Store(pScrn, tsengReg->RAMDAC); 1107 break; 1108 default: 1109 break; 1110 } 1111 } else { 1112 /* Save ET6000 CLKDAC PLL registers */ 1113 ET6000IOWrite(pTseng, 0x67, 0x03); 1114 tsengReg->ET6K_PLL = ET6000IORead(pTseng, 0x69); 1115 tsengReg->ET6K_PLL |= ET6000IORead(pTseng, 0x69) << 8; 1116 1117 /* save MClk values */ 1118 ET6000IOWrite(pTseng, 0x67, 0x0A); 1119 tsengReg->ET6K_MClk = ET6000IORead(pTseng, 0x69); 1120 tsengReg->ET6K_MClk |= ET6000IORead(pTseng, 0x69) << 8; 1121 1122 tsengReg->ET6K_13 = ET6000IORead(pTseng, 0x13); 1123 tsengReg->ET6K_40 = ET6000IORead(pTseng, 0x40); 1124 tsengReg->ET6K_58 = ET6000IORead(pTseng, 0x58); 1125 tsengReg->ET6K_41 = ET6000IORead(pTseng, 0x41); 1126 tsengReg->ET6K_44 = ET6000IORead(pTseng, 0x44); 1127 tsengReg->ET6K_46 = ET6000IORead(pTseng, 0x46); 1128 } 1129 1130 tsengReg->CR30 = hwp->readCrtc(hwp, 0x30); 1131 tsengReg->CR31 = hwp->readCrtc(hwp, 0x31); 1132 tsengReg->CR3F = hwp->readCrtc(hwp, 0x3F); 1133} 1134 1135/* 1136 * Restore a video mode 1137 */ 1138void 1139TsengRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, TsengRegPtr tsengReg, 1140 int flags) 1141{ 1142 vgaHWPtr hwp = VGAHWPTR(pScrn); 1143 TsengPtr pTseng = TsengPTR(pScrn); 1144 1145 PDEBUG(" TsengRestore\n"); 1146 1147 vgaHWProtect(pScrn, TRUE); 1148 1149 vgaHWWriteSegment(hwp, 0x00); /* segment select bits 0..3 */ 1150 vgaHWWriteBank(hwp, 0x00); /* segment select bits 4,5 */ 1151 1152 if (pTseng->ChipType == ET4000) { 1153 switch (pTseng->RAMDAC) { 1154 case STG1703: 1155 STG1703Restore(pScrn, tsengReg->RAMDAC); 1156 break; 1157 case CH8398: 1158 CH8398Restore(pScrn, tsengReg->RAMDAC); 1159 break; 1160 default: 1161 break; 1162 } 1163 } else { 1164 /* Restore ET6000 CLKDAC PLL registers */ 1165 ET6000IOWrite(pTseng, 0x67, 0x03); 1166 ET6000IOWrite(pTseng, 0x69, tsengReg->ET6K_PLL & 0xFF); 1167 ET6000IOWrite(pTseng, 0x69, tsengReg->ET6K_PLL >> 8); 1168 1169 /* set MClk values if needed, but don't touch them if not needed 1170 * 1171 * Since setting the MClk to highly illegal value results in a 1172 * total system crash, we'd better play it safe here. 1173 * N1 must be <= 4, and N2 should always be 1 1174 */ 1175 if ((tsengReg->ET6K_MClk & 0xF800) != 0x2000) { 1176 xf86Msg(X_ERROR, "Internal Error in MClk registers: MClk: 0x%04X\n", 1177 tsengReg->ET6K_MClk); 1178 } else { 1179 ET6000IOWrite(pTseng, 0x67, 10); 1180 ET6000IOWrite(pTseng, 0x69, tsengReg->ET6K_MClk & 0xFF); 1181 ET6000IOWrite(pTseng, 0x69, tsengReg->ET6K_MClk >> 8); 1182 } 1183 1184 ET6000IOWrite(pTseng, 0x13, tsengReg->ET6K_13); 1185 ET6000IOWrite(pTseng, 0x40, tsengReg->ET6K_40); 1186 ET6000IOWrite(pTseng, 0x58, tsengReg->ET6K_58); 1187 ET6000IOWrite(pTseng, 0x41, tsengReg->ET6K_41); 1188 ET6000IOWrite(pTseng, 0x44, tsengReg->ET6K_44); 1189 ET6000IOWrite(pTseng, 0x46, tsengReg->ET6K_46); 1190 } 1191 1192 hwp->writeCrtc(hwp, 0x3F, tsengReg->CR3F); 1193 hwp->writeCrtc(hwp, 0x30, tsengReg->CR30); 1194 hwp->writeCrtc(hwp, 0x31, tsengReg->CR31); 1195 1196 vgaHWRestore(pScrn, vgaReg, flags); /* TODO: does this belong HERE, in the middle? */ 1197 1198 hwp->writeSeq(hwp, 0x06, tsengReg->SR06); 1199 hwp->writeSeq(hwp, 0x07, tsengReg->SR07); 1200 1201 hwp->writeAttr(hwp, 0x36, tsengReg->ExtATC); 1202 1203 hwp->writeCrtc(hwp, 0x33, tsengReg->CR33); 1204 hwp->writeCrtc(hwp, 0x34, tsengReg->CR34); 1205 hwp->writeCrtc(hwp, 0x35, tsengReg->CR35); 1206 1207 if (pTseng->ChipType == ET4000) { 1208 hwp->writeCrtc(hwp, 0x37, tsengReg->CR37); 1209 hwp->writeCrtc(hwp, 0x32, tsengReg->CR32); 1210 } 1211 1212 TsengCursorRestore(pScrn, tsengReg); 1213 1214 vgaHWWriteSegment(hwp, tsengReg->ExtSegSel[0]); 1215 vgaHWWriteBank(hwp, tsengReg->ExtSegSel[1]); 1216 1217 vgaHWProtect(pScrn, FALSE); 1218 1219 /* 1220 * We must change CRTC 0x36 only OUTSIDE the TsengProtect(pScrn, 1221 * TRUE)/TsengProtect(pScrn, FALSE) pair, because the sequencer reset 1222 * also resets the linear mode bits in CRTC 0x36. 1223 */ 1224 if (pTseng->ChipType == ET4000) 1225 hwp->writeCrtc(hwp, 0x36, tsengReg->CR36); 1226} 1227 1228/* 1229 * 1230 */ 1231Bool 1232TsengModeInit(ScrnInfoPtr pScrn, DisplayModePtr OrigMode) 1233{ 1234 vgaHWPtr hwp = VGAHWPTR(pScrn); 1235 TsengPtr pTseng = TsengPTR(pScrn); 1236 TsengRegPtr initial = &(pTseng->SavedReg); 1237 TsengRegRec new[1]; 1238 DisplayModeRec mode[1]; 1239 int row_offset; 1240 1241 PDEBUG(" TsengModeInit\n"); 1242 1243 new->RAMDAC = NULL; 1244 1245 /* We're altering this mode */ 1246 memcpy(mode, OrigMode, sizeof(DisplayModeRec)); 1247 mode->next = NULL; 1248 mode->prev = NULL; 1249 1250 if (pTseng->ChipType == ET4000) { 1251 int hmul = pTseng->Bytesperpixel; 1252 1253 /* Modify mode timings accordingly 1254 * 1255 * If we move the vgaHWInit code up here directly, we no longer have 1256 * to adjust mode->Crtc* but just handle things properly up here. 1257 */ 1258 /* now divide and multiply the horizontal timing parameters as required */ 1259 mode->CrtcHTotal = (mode->CrtcHTotal * hmul) / 2; 1260 mode->CrtcHDisplay = (mode->CrtcHDisplay * hmul) / 2; 1261 mode->CrtcHSyncStart = (mode->CrtcHSyncStart * hmul) / 2; 1262 mode->CrtcHSyncEnd = (mode->CrtcHSyncEnd * hmul) / 2; 1263 mode->CrtcHBlankStart = (mode->CrtcHBlankStart * hmul) / 2; 1264 mode->CrtcHBlankEnd = (mode->CrtcHBlankEnd * hmul) / 2; 1265 mode->CrtcHSkew = (mode->CrtcHSkew * hmul) / 2; 1266 1267 mode->Clock = (mode->Clock * hmul) / 2; 1268 1269 if (pScrn->bitsPerPixel == 24) { 1270 int rgb_skew; 1271 /* 1272 * in 24bpp, the position of the BLANK signal determines the 1273 * phase of the R,G and B values. XFree86 sets blanking equal to 1274 * the Sync, so setting the Sync correctly will also set the 1275 * BLANK corectly, and thus also the RGB phase 1276 */ 1277 rgb_skew = (mode->CrtcHTotal / 8 - mode->CrtcHBlankEnd / 8 - 1) % 3; 1278 mode->CrtcHBlankEnd += rgb_skew * 8 + 24; 1279 /* HBlankEnd must come BEFORE HTotal */ 1280 if (mode->CrtcHBlankEnd > mode->CrtcHTotal) 1281 mode->CrtcHBlankEnd -= 24; 1282 } 1283 } 1284 1285 /* Some mode info */ 1286 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, "Setting up %s (%dMhz, %dbpp)\n", 1287 mode->name, mode->Clock, pScrn->bitsPerPixel); 1288 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, 1289 "H: 0x%03X 0x%03X 0x%03X 0x%03X 0x%03X 0x%03X\n", 1290 mode->CrtcHDisplay, mode->CrtcHBlankStart, mode->CrtcHSyncStart, 1291 mode->CrtcHSyncEnd, mode->CrtcHBlankEnd, mode->CrtcHTotal); 1292 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 7, 1293 "V: 0x%03X 0x%03X 0x%03X 0x%03X 0x%03X 0x%03X\n", 1294 mode->CrtcVDisplay, mode->CrtcVBlankStart, mode->CrtcVSyncStart, 1295 mode->CrtcVSyncEnd, mode->CrtcVBlankEnd, mode->CrtcVTotal); 1296 1297 /* prepare standard VGA register contents */ 1298 if (!vgaHWInit(pScrn, mode)) 1299 return (FALSE); 1300 pScrn->vtSema = TRUE; 1301 1302 /* prepare extended (Tseng) register contents */ 1303 /* 1304 * Start by copying all the saved registers in the "new" data, so we 1305 * only have to modify those that need to change. 1306 */ 1307 1308 memcpy(new, initial, sizeof(TsengRegRec)); 1309 1310 if (pScrn->bitsPerPixel < 8) { 1311 /* Don't ask me why this is needed on the ET6000 and not on the others */ 1312 if (pTseng->ChipType == ET6000) 1313 hwp->ModeReg.Sequencer[1] |= 0x04; 1314 row_offset = hwp->ModeReg.CRTC[19]; 1315 } else { 1316 hwp->ModeReg.Attribute[16] = 0x01; /* use the FAST 256 Color Mode */ 1317 row_offset = pScrn->displayWidth >> 3; /* overruled by 16/24/32 bpp code */ 1318 } 1319 1320 hwp->ModeReg.CRTC[20] = 0x60; 1321 hwp->ModeReg.CRTC[23] = 0xAB; 1322 new->SR06 = 0x00; 1323 new->SR07 = 0xBC; 1324 new->CR33 = 0x00; 1325 1326 new->CR35 = (mode->Flags & V_INTERLACE ? 0x80 : 0x00) 1327 | 0x10 1328 | ((mode->CrtcVSyncStart & 0x400) >> 7) 1329 | (((mode->CrtcVDisplay - 1) & 0x400) >> 8) 1330 | (((mode->CrtcVTotal - 2) & 0x400) >> 9) 1331 | (((mode->CrtcVBlankStart - 1) & 0x400) >> 10); 1332 1333 if (pScrn->bitsPerPixel < 8) 1334 new->ExtATC = 0x00; 1335 else 1336 new->ExtATC = 0x80; 1337 1338 if (pScrn->bitsPerPixel >= 8) { 1339 if ((pTseng->ChipType == ET4000) && pTseng->FastDram) { 1340 /* 1341 * make sure Trsp is no more than 75ns 1342 * Tcsw is 25ns 1343 * Tcsp is 25ns 1344 * Trcd is no more than 50ns 1345 * Timings assume SCLK = 40MHz 1346 * 1347 * Note, this is experimental, but works for me (DHD) 1348 */ 1349 /* Tcsw, Tcsp, Trsp */ 1350 new->CR32 &= ~0x1F; 1351 if (initial->CR32 & 0x18) 1352 new->CR32 |= 0x08; 1353 /* Trcd */ 1354 new->CR32 &= ~0x20; 1355 } 1356 } 1357 /* 1358 * Here we make sure that CRTC regs 0x34 and 0x37 are untouched, except for 1359 * some bits we want to change. 1360 * Notably bit 7 of CRTC 0x34, which changes RAS setup time from 4 to 0 ns 1361 * (performance), 1362 * and bit 7 of CRTC 0x37, which changes the CRTC FIFO low treshold control. 1363 * At really high pixel clocks, this will avoid lots of garble on the screen 1364 * when something is being drawn. This only happens WAY beyond 80 MHz 1365 * (those 135 MHz ramdac's...) 1366 */ 1367 if (pTseng->ChipType == ET4000) { 1368 if (!pTseng->SlowDram) 1369 new->CR34 |= 0x80; 1370 if ((mode->Clock * pTseng->Bytesperpixel) > 80000) 1371 new->CR37 |= 0x80; 1372 /* 1373 * now on to the memory interleave setting (CR32 bit 7) 1374 */ 1375 if (pTseng->SetW32Interleave) { 1376 if (pTseng->W32Interleave) 1377 new->CR32 |= 0x80; 1378 else 1379 new->CR32 &= 0x7F; 1380 } 1381 1382 /* 1383 * CR34 bit 4 controls the PCI Burst option 1384 */ 1385 if (pTseng->SetPCIBurst) { 1386 if (pTseng->PCIBurst) 1387 new->CR34 |= 0x10; 1388 else 1389 new->CR34 &= 0xEF; 1390 } 1391 } 1392 1393 /* prepare clock-related registers when not Legend. 1394 * cannot really SET the clock here yet, since the ET4000Save() 1395 * is called LATER, so it would save the wrong state... 1396 * ET4000Restore() is used to actually SET vga regs. 1397 */ 1398 if (pTseng->ChipType == ET4000) { 1399 switch (pTseng->RAMDAC) { 1400 case STG1703: 1401 new->RAMDAC = 1402 (struct STG1703Regs *) STG1703Mode(pScrn, initial->RAMDAC, mode); 1403 break; 1404 case CH8398: 1405 new->RAMDAC = 1406 (struct CH8398Regs *) CH8398Mode(pScrn, initial->RAMDAC, mode); 1407 break; 1408 default: 1409 break; 1410 } 1411 } else { 1412 /* setting min_n2 to "1" will ensure a more stable clock ("0" is allowed though) */ 1413 new->ET6K_PLL = ET6000CalcClock(mode->SynthClock, 1, 1, 31, 1, 3, 1414 100000, pTseng->max_vco_freq); 1415 1416 /* above 130MB/sec, we enable the "LOW FIFO threshold" */ 1417 if (mode->Clock * pTseng->Bytesperpixel > 130000) { 1418 new->ET6K_41 |= 0x10; 1419 if (pTseng->ChipRev == REV_ET6100) 1420 new->ET6K_46 |= 0x04; 1421 } else { 1422 new->ET6K_41 &= ~0x10; 1423 if (pTseng->ChipRev == REV_ET6100) 1424 new->ET6K_46 &= ~0x04; 1425 } 1426 1427 /* according to Tseng Labs, N1 must be <= 4, and N2 should always be 1 for MClk */ 1428 new->ET6K_MClk = ET6000CalcClock(pTseng->MemClk, 1, 1, 4, 1, 1, 100000, 1429 pTseng->clockRange.maxClock * 2); 1430 1431 /* 1432 * Even when we don't allow setting the MClk value as described 1433 * above, we can use the FAST/MED/SLOW DRAM options to set up 1434 * the RAS/CAS delays as decided by the value of ET6K_44. 1435 * This is also a more correct use of the flags, as it describes 1436 * how fast the RAM works. [HNH]. 1437 */ 1438 if (pTseng->FastDram) 1439 new->ET6K_44 = 0x04; /* Fastest speed(?) */ 1440 else if (pTseng->MedDram) 1441 new->ET6K_44 = 0x15; /* Medium speed */ 1442 else if (pTseng->SlowDram) 1443 new->ET6K_44 = 0x35; /* Slow speed */ 1444 else 1445 ; /* keep current value */ 1446 } 1447 /* 1448 * Set the clock selection bits. Because of the odd mapping between 1449 * Tseng clock select bits and what XFree86 does, "CSx" refers to a 1450 * register bit with the same name in the Tseng data books. 1451 * 1452 * XFree86 uses the following mapping: 1453 * 1454 * Tseng register bit name XFree86 clock select bit 1455 * CS0 0 1456 * CS1 1 1457 * CS2 2 1458 * MCLK/2 3 1459 * CS3 4 1460 * CS4 not used 1461 */ 1462 /* CS0 and CS1 are set by standard VGA code (vgaHW) */ 1463 /* CS2 = CRTC 0x34 bit 1 */ 1464 new->CR34 &= 0xFD; 1465 /* for programmable clocks: disable MCLK/2 and MCLK/4 independent of hibit */ 1466 new->SR07 = (new->SR07 & 0xBE); 1467 /* clock select bit 4 = CS3 , clear CS4 */ 1468 new->CR31 &= 0x3F; 1469 1470 /* 1471 * linear mode handling 1472 */ 1473 if (pTseng->ChipType == ET6000) { 1474 new->ET6K_13 = pTseng->FbAddress >> 24; 1475 new->ET6K_40 |= 0x09; 1476 } else { /* et4000 style linear memory */ 1477 new->CR36 |= 0x10; 1478 new->CR30 = (pTseng->FbAddress >> 22) & 0xFF; 1479 hwp->ModeReg.Graphics[6] &= ~0x0C; 1480 new->CursorCtrl &= ~0x01; /* disable IMA port (to get >1MB lin mem) */ 1481 } 1482 1483 /* 1484 * 16/24/32 bpp handling. 1485 */ 1486 if (pTseng->ChipType == ET6000) { 1487 /* ATC index 0x16 -- bits-per-PCLK */ 1488 new->ExtATC &= 0xCF; 1489 new->ExtATC |= (pTseng->Bytesperpixel - 1) << 4; 1490 1491 if (pScrn->bitsPerPixel == 15) 1492 new->ET6K_58 &= ~0x02; /* 5-5-5 RGB mode */ 1493 else if (pScrn->bitsPerPixel == 16) 1494 new->ET6K_58 |= 0x02; /* 5-6-5 RGB mode */ 1495 } else { 1496 /* ATC index 0x16 -- bits-per-PCLK */ 1497 new->ExtATC &= 0xCF; 1498 new->ExtATC |= 0x20; 1499 } 1500 1501 row_offset *= pTseng->Bytesperpixel; 1502 1503 1504 /* 1505 * Horizontal overflow settings: for modes with > 2048 pixels per line 1506 */ 1507 1508 hwp->ModeReg.CRTC[19] = row_offset; 1509 new->CR3F = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) 1510 | ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) 1511 | ((((mode->CrtcHBlankStart >> 3) - 1) & 0x100) >> 6) 1512 | (((mode->CrtcHSyncStart >> 3) & 0x100) >> 4) 1513 | ((row_offset & 0x200) >> 3) 1514 | ((row_offset & 0x100) >> 1); 1515 1516 /* 1517 * Enable memory mapped IO registers when acceleration is needed. 1518 */ 1519 1520 if (pTseng->UseAccel) { 1521 if (pTseng->ChipType == ET6000) 1522 new->ET6K_40 |= 0x02; /* MMU can't be used here (causes system hang...) */ 1523 else 1524 new->CR36 |= 0x28; 1525 } 1526 vgaHWUnlock(hwp); /* TODO: is this needed (tsengEnterVT does this) */ 1527 1528 /* Program the registers */ 1529 TsengRestore(pScrn, &hwp->ModeReg, new, VGA_SR_MODE); 1530 1531 /* clean up */ 1532 if (new->RAMDAC) 1533 free(new->RAMDAC); 1534 1535 return TRUE; 1536} 1537 1538/* 1539 * TsengCrtcDPMSSet -- 1540 * 1541 * Sets VESA Display Power Management Signaling (DPMS) Mode. 1542 * This routine is for the ET4000W32P rev. c and later, which can 1543 * use CRTC indexed register 34 to turn off H/V Sync signals. 1544 * 1545 * '97 Harald Nordgård Hansen 1546 */ 1547void 1548TsengCrtcDPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) 1549{ 1550 vgaHWPtr hwp = VGAHWPTR(pScrn); 1551 CARD8 seq1, crtc34; 1552 1553#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 8 1554 xf86EnableAccess(pScrn); 1555#endif 1556 switch (PowerManagementMode) { 1557 case DPMSModeOn: 1558 default: 1559 /* Screen: On; HSync: On, VSync: On */ 1560 seq1 = 0x00; 1561 crtc34 = 0x00; 1562 break; 1563 case DPMSModeStandby: 1564 /* Screen: Off; HSync: Off, VSync: On */ 1565 seq1 = 0x20; 1566 crtc34 = 0x01; 1567 break; 1568 case DPMSModeSuspend: 1569 /* Screen: Off; HSync: On, VSync: Off */ 1570 seq1 = 0x20; 1571 crtc34 = 0x20; 1572 break; 1573 case DPMSModeOff: 1574 /* Screen: Off; HSync: Off, VSync: Off */ 1575 seq1 = 0x20; 1576 crtc34 = 0x21; 1577 break; 1578 } 1579 1580 seq1 |= hwp->readSeq(hwp, 0x01) & ~0x20; 1581 hwp->writeSeq(hwp, 0x01, seq1); 1582 1583 crtc34 |= hwp->readCrtc(hwp, 0x34) & ~0x21; 1584 hwp->writeCrtc(hwp, 0x34, crtc34); 1585} 1586 1587/* 1588 * TsengHVSyncDPMSSet -- 1589 * 1590 * Sets VESA Display Power Management Signaling (DPMS) Mode. 1591 * This routine is for Tseng et4000 chips that do not have any 1592 * registers to disable sync output. 1593 * 1594 * The "classic" (standard VGA compatible) method; disabling all syncs, 1595 * causes video memory corruption on Tseng cards, according to "Tseng 1596 * ET4000/W32 family tech note #20": 1597 * 1598 * "Setting CRTC Indexed Register 17 bit 7 = 0 will disable the video 1599 * syncs (=VESA DPMS power down), but will also disable DRAM refresh cycles" 1600 * 1601 * The method used here is derived from the same tech note, which describes 1602 * a method to disable specific sync signals on chips that do not have 1603 * direct support for it: 1604 * 1605 * To get vsync off, program VSYNC_START > VTOTAL 1606 * (approximately). In particular, the formula used is: 1607 * 1608 * VSYNC.ADJ = (VTOT - VSYNC.NORM) + VTOT + 4 1609 * 1610 * To test for this state, test if VTOT + 1 < VSYNC 1611 * 1612 * 1613 * To get hsync off, program HSYNC_START > HTOTAL 1614 * (approximately). In particular, the following formula is used: 1615 * 1616 * HSYNC.ADJ = (HTOT - HSYNC.NORM) + HTOT + 7 1617 * 1618 * To test for this state, test if HTOT + 3 < HSYNC 1619 * 1620 * The advantage of these formulas is that the ON state can be restored by 1621 * reversing the formula. The original state need not be stored anywhere... 1622 * 1623 * The trick in the above approach is obviously to put the start of the sync 1624 * _beyond_ the total H or V counter range, which causes the sync to never 1625 * toggle. 1626 */ 1627void 1628TsengHVSyncDPMSSet(ScrnInfoPtr pScrn, 1629 int PowerManagementMode, int flags) 1630{ 1631 vgaHWPtr hwp = VGAHWPTR(pScrn); 1632 CARD8 seq1, tmpb; 1633 CARD32 HSync, VSync, HTot, VTot, tmp; 1634 Bool chgHSync, chgVSync; 1635 1636 /* Code here to read the current values of HSync through VTot: 1637 * HSYNC: 1638 * bits 0..7 : CRTC index 0x04 1639 * bit 8 : CRTC index 0x3F, bit 4 1640 */ 1641 HSync = hwp->readCrtc(hwp, 0x04); 1642 HSync += (hwp->readCrtc(hwp, 0x3F) & 0x10) << 4; 1643 1644 /* VSYNC: 1645 * bits 0..7 : CRTC index 0x10 1646 * bits 8..9 : CRTC index 0x07 bits 2 (VSYNC bit 8) and 7 (VSYNC bit 9) 1647 * bit 10 : CRTC index 0x35 bit 3 1648 */ 1649 VSync = hwp->readCrtc(hwp, 0x10); 1650 tmp = hwp->readCrtc(hwp, 0x07); 1651 VSync += ((tmp & 0x04) << 6) + ((tmp & 0x80) << 2); 1652 VSync += (hwp->readCrtc(hwp, 0x35) & 0x08) << 7; 1653 1654 /* HTOT: 1655 * bits 0..7 : CRTC index 0x00. 1656 * bit 8 : CRTC index 0x3F, bit 0 1657 */ 1658 HTot = hwp->readCrtc(hwp, 0x00); 1659 HTot += (hwp->readCrtc(hwp, 0x3F) & 0x01) << 8; 1660 /* VTOT: 1661 * bits 0..7 : CRTC index 0x06 1662 * bits 8..9 : CRTC index 0x07 bits 0 (VTOT bit 8) and 5 (VTOT bit 9) 1663 * bit 10 : CRTC index 0x35 bit 1 1664 */ 1665 VTot = hwp->readCrtc(hwp, 0x06); 1666 tmp = hwp->readCrtc(hwp, 0x07); 1667 VTot += ((tmp & 0x01) << 8) + ((tmp & 0x20) << 4); 1668 VTot += (hwp->readCrtc(hwp, 0x35) & 0x02) << 9; 1669 1670 /* Don't write these unless we have to. */ 1671 chgHSync = chgVSync = FALSE; 1672 1673 switch (PowerManagementMode) { 1674 case DPMSModeOn: 1675 default: 1676 /* Screen: On; HSync: On, VSync: On */ 1677 seq1 = 0x00; 1678 if (HSync > HTot + 3) { /* Sync is off now, turn it on. */ 1679 HSync = (HTot - HSync) + HTot + 7; 1680 chgHSync = TRUE; 1681 } 1682 if (VSync > VTot + 1) { /* Sync is off now, turn it on. */ 1683 VSync = (VTot - VSync) + VTot + 4; 1684 chgVSync = TRUE; 1685 } 1686 break; 1687 case DPMSModeStandby: 1688 /* Screen: Off; HSync: Off, VSync: On */ 1689 seq1 = 0x20; 1690 if (HSync <= HTot + 3) { /* Sync is on now, turn it off. */ 1691 HSync = (HTot - HSync) + HTot + 7; 1692 chgHSync = TRUE; 1693 } 1694 if (VSync > VTot + 1) { /* Sync is off now, turn it on. */ 1695 VSync = (VTot - VSync) + VTot + 4; 1696 chgVSync = TRUE; 1697 } 1698 break; 1699 case DPMSModeSuspend: 1700 /* Screen: Off; HSync: On, VSync: Off */ 1701 seq1 = 0x20; 1702 if (HSync > HTot + 3) { /* Sync is off now, turn it on. */ 1703 HSync = (HTot - HSync) + HTot + 7; 1704 chgHSync = TRUE; 1705 } 1706 if (VSync <= VTot + 1) { /* Sync is on now, turn it off. */ 1707 VSync = (VTot - VSync) + VTot + 4; 1708 chgVSync = TRUE; 1709 } 1710 break; 1711 case DPMSModeOff: 1712 /* Screen: Off; HSync: Off, VSync: Off */ 1713 seq1 = 0x20; 1714 if (HSync <= HTot + 3) { /* Sync is on now, turn it off. */ 1715 HSync = (HTot - HSync) + HTot + 7; 1716 chgHSync = TRUE; 1717 } 1718 if (VSync <= VTot + 1) { /* Sync is on now, turn it off. */ 1719 VSync = (VTot - VSync) + VTot + 4; 1720 chgVSync = TRUE; 1721 } 1722 break; 1723 } 1724 1725 /* If the new hsync or vsync overflows, don't change anything. */ 1726 if (HSync >= 1 << 9 || VSync >= 1 << 11) { 1727 ErrorF("tseng: warning: Cannot go into DPMS from this resolution.\n"); 1728 chgVSync = chgHSync = FALSE; 1729 } 1730 /* The code to turn on and off video output is equal for all. */ 1731 if (chgHSync || chgVSync) { 1732 seq1 |= hwp->readSeq(hwp, 0x01) & ~0x20; 1733 hwp->writeSeq(hwp, 0x01, seq1); 1734 } 1735 /* Then the code to write VSync and HSync to the card. 1736 * HSYNC: 1737 * bits 0..7 : CRTC index 0x04 1738 * bit 8 : CRTC index 0x3F, bit 4 1739 */ 1740 if (chgHSync) { 1741 tmpb = HSync & 0xFF; 1742 hwp->writeCrtc(hwp, 0x04, tmpb); 1743 1744 tmpb = (HSync & 0x100) >> 4; 1745 tmpb |= hwp->readCrtc(hwp, 0x3F) & ~0x10; 1746 hwp->writeCrtc(hwp, 0x3F, tmpb); 1747 } 1748 /* VSYNC: 1749 * bits 0..7 : CRTC index 0x10 1750 * bits 8..9 : CRTC index 0x07 bits 2 (VSYNC bit 8) and 7 (VSYNC bit 9) 1751 * bit 10 : CRTC index 0x35 bit 3 1752 */ 1753 if (chgVSync) { 1754 tmpb = VSync & 0xFF; 1755 hwp->writeCrtc(hwp, 0x10, tmpb); 1756 1757 tmpb = (VSync & 0x100) >> 6; 1758 tmpb |= (VSync & 0x200) >> 2; 1759 tmpb |= hwp->readCrtc(hwp, 0x07) & ~0x84; 1760 hwp->writeCrtc(hwp, 0x07, tmpb); 1761 1762 tmpb = (VSync & 0x400) >> 7; 1763 tmpb |= hwp->readCrtc(hwp, 0x35) & ~0x08; 1764 hwp->writeCrtc(hwp, 0x35, tmpb); 1765 } 1766} 1767