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