1 /* 2 Haiku S3 Virge driver adapted from the X.org Virge driver. 3 4 Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. 5 6 Copyright 2007-2008 Haiku, Inc. All rights reserved. 7 Distributed under the terms of the MIT license. 8 9 Authors: 10 Gerald Zajac 2007-2008 11 */ 12 13 14 #include "accel.h" 15 #include "virge.h" 16 17 18 #define BASE_FREQ 14.31818 // MHz 19 20 21 struct VirgeRegRec { 22 uint8 CRTC[25]; // Crtc Controller reg's 23 24 uint8 SR0A, SR0F; 25 uint8 SR12, SR13, SR15, SR18; // SR9-SR1C, ext seq. 26 uint8 SR29; 27 uint8 SR54, SR55, SR56, SR57; 28 uint8 CR31, CR33, CR34, CR3A, CR3B, CR3C; 29 uint8 CR40, CR41, CR42, CR43, CR45; 30 uint8 CR51, CR53, CR54, CR58, CR5D, CR5E; 31 uint8 CR63, CR65, CR66, CR67, CR68, CR69, CR6D; // Video attrib. 32 uint8 CR7B, CR7D; 33 uint8 CR85, CR86, CR87; 34 uint8 CR90, CR91, CR92, CR93; 35 }; 36 37 38 39 40 static void 41 Virge_EngineReset(const DisplayModeEx& mode) 42 { 43 SharedInfo& si = *gInfo.sharedInfo; 44 45 switch (mode.bpp) { 46 case 8: 47 si.commonCmd = DRAW | DST_8BPP; 48 break; 49 case 16: 50 si.commonCmd = DRAW | DST_16BPP; 51 break; 52 case 24: 53 si.commonCmd = DRAW | DST_24BPP; 54 break; 55 } 56 57 58 gInfo.WaitQueue(6); 59 WriteReg32(CMD_SET, CMD_NOP); // turn off auto-execute 60 WriteReg32(SRC_BASE, 0); 61 WriteReg32(DEST_BASE, 0); 62 WriteReg32(DEST_SRC_STR, mode.bytesPerRow | (mode.bytesPerRow << 16)); 63 64 WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display); 65 WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display); 66 } 67 68 69 70 static void 71 Virge_NopAllCmdSets() 72 { 73 // This function should be called only for the Trio 3D chip. 74 75 for (int i = 0; i < 1000; i++) { 76 if ( (IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) == 0x20002000) { 77 break; 78 } 79 } 80 81 gInfo.WaitQueue(7); 82 WriteReg32(CMD_SET, CMD_NOP); 83 } 84 85 86 87 static void 88 Virge_GEReset(const DisplayModeEx& mode) 89 { 90 SharedInfo& si = *gInfo.sharedInfo; 91 92 if (si.chipType == S3_TRIO_3D) 93 Virge_NopAllCmdSets(); 94 95 gInfo.WaitIdleEmpty(); 96 97 if (si.chipType == S3_TRIO_3D) { 98 bool ge_was_on = false; 99 snooze(10000); 100 101 for (int r = 1; r < 10; r++) { 102 uint8 resetidx = 0x66; 103 104 VerticalRetraceWait(); 105 uint8 tmp = ReadCrtcReg(resetidx); 106 107 VerticalRetraceWait(); 108 IN_SUBSYS_STAT(); 109 110 // turn off the GE 111 112 if (tmp & 0x01) { 113 WriteCrtcReg(resetidx, tmp); 114 ge_was_on = true; 115 snooze(10000); 116 } 117 118 IN_SUBSYS_STAT(); 119 WriteCrtcReg(resetidx, tmp | 0x02); 120 snooze(10000); 121 122 VerticalRetraceWait(); 123 WriteCrtcReg(resetidx, tmp & ~0x02); 124 snooze(10000); 125 126 if (ge_was_on) { 127 tmp |= 0x01; 128 WriteCrtcReg(resetidx, tmp); 129 snooze(10000); 130 } 131 132 VerticalRetraceWait(); 133 134 Virge_NopAllCmdSets(); 135 gInfo.WaitIdleEmpty(); 136 137 WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow); 138 snooze(10000); 139 140 if ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000) { 141 TRACE("Restarting S3 graphics engine reset %2d ...%lx\n", 142 r, IN_SUBSYS_STAT() ); 143 } else 144 break; 145 } 146 } else { 147 uint8 regIndex = (si.chipType == S3_VIRGE_VX ? 0x63 : 0x66); 148 uint8 tmp = ReadCrtcReg(regIndex); 149 snooze(10000); 150 151 // try multiple times to avoid lockup of VIRGE/MX 152 153 for (int r = 1; r < 10; r++) { 154 WriteCrtcReg(regIndex, tmp | 0x02); 155 snooze(10000); 156 WriteCrtcReg(regIndex, tmp & ~0x02); 157 snooze(10000); 158 gInfo.WaitIdleEmpty(); 159 160 WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow); 161 snooze(10000); 162 163 if (((IN_SUBSYS_STAT() & 0x3f00) != 0x3000)) { 164 TRACE("Restarting S3 graphics engine reset %2d ...\n", r); 165 } else 166 break; 167 } 168 } 169 170 gInfo.WaitQueue(2); 171 WriteReg32(SRC_BASE, 0); 172 WriteReg32(DEST_BASE, 0); 173 174 gInfo.WaitQueue(4); 175 WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display); 176 WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display); 177 WriteReg32(MONO_PAT_0, ~0); 178 WriteReg32(MONO_PAT_1, ~0); 179 180 if (si.chipType == S3_TRIO_3D) 181 Virge_NopAllCmdSets(); 182 } 183 184 185 186 static void 187 Virge_CalcClock(long freq, int min_m, 188 int min_n1, int max_n1, 189 int min_n2, int max_n2, 190 long freq_min, long freq_max, 191 uint8* mdiv, uint8* ndiv) 192 { 193 uint8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2; 194 195 double ffreq = freq / 1000.0 / BASE_FREQ; 196 double ffreq_min = freq_min / 1000.0 / BASE_FREQ; 197 double ffreq_max = freq_max / 1000.0 / BASE_FREQ; 198 199 if (ffreq < ffreq_min / (1 << max_n2)) { 200 TRACE("Virge_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f MHz]\n", 201 ffreq * BASE_FREQ, ffreq_min * BASE_FREQ / (1 << max_n2) ); 202 ffreq = ffreq_min / (1 << max_n2); 203 } 204 if (ffreq > ffreq_max / (1 << min_n2)) { 205 TRACE("Virge_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f MHz]\n", 206 ffreq * BASE_FREQ, ffreq_max * BASE_FREQ / (1 << min_n2) ); 207 ffreq = ffreq_max / (1 << min_n2); 208 } 209 210 // Work out suitable timings. 211 212 double best_diff = ffreq; 213 214 for (uint8 n2 = min_n2; n2 <= max_n2; n2++) { 215 for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) { 216 int m = (int)(ffreq * n1 * (1 << n2) + 0.5) ; 217 if (m < min_m + 2 || m > 127 + 2) 218 continue; 219 220 double div = (double)(m) / (double)(n1); 221 if ((div >= ffreq_min) && (div <= ffreq_max)) { 222 double diff = ffreq - div / (1 << n2); 223 if (diff < 0.0) 224 diff = -diff; 225 if (diff < best_diff) { 226 best_diff = diff; 227 best_m = m; 228 best_n1 = n1; 229 best_n2 = n2; 230 } 231 } 232 } 233 } 234 235 if (max_n1 == 63) 236 *ndiv = (best_n1 - 2) | (best_n2 << 6); 237 else 238 *ndiv = (best_n1 - 2) | (best_n2 << 5); 239 *mdiv = best_m - 2; 240 } 241 242 243 244 static void 245 Virge_WriteMode(const DisplayModeEx& mode, VirgeRegRec& regRec) 246 { 247 // This function writes out all of the standard VGA and extended S3 registers 248 // needed to setup a video mode. 249 250 TRACE("Virge_WriteMode()\n"); 251 252 SharedInfo& si = *gInfo.sharedInfo; 253 254 // First reset GE to make sure nothing is going on. 255 256 if (ReadCrtcReg(si.chipType == S3_VIRGE_VX ? 0x63 : 0x66) & 0x01) 257 Virge_GEReset(mode); 258 259 // As per databook, always disable STREAMS before changing modes. 260 261 if ((ReadCrtcReg(0x67) & 0x0c) == 0x0c) { 262 // STREAMS running, disable it 263 VerticalRetraceWait(); 264 WriteReg32(FIFO_CONTROL_REG, 0xC000); 265 266 WriteCrtcReg(0x67, 0x00, 0x0c); // disable STREAMS processor 267 } 268 269 // Restore S3 extended regs. 270 WriteCrtcReg(0x63, regRec.CR63); 271 WriteCrtcReg(0x66, regRec.CR66); 272 WriteCrtcReg(0x3a, regRec.CR3A); 273 WriteCrtcReg(0x31, regRec.CR31); 274 WriteCrtcReg(0x58, regRec.CR58); 275 276 // Extended mode timings registers. 277 WriteCrtcReg(0x53, regRec.CR53); 278 WriteCrtcReg(0x5d, regRec.CR5D); 279 WriteCrtcReg(0x5e, regRec.CR5E); 280 WriteCrtcReg(0x3b, regRec.CR3B); 281 WriteCrtcReg(0x3c, regRec.CR3C); 282 WriteCrtcReg(0x43, regRec.CR43); 283 WriteCrtcReg(0x65, regRec.CR65); 284 WriteCrtcReg(0x6d, regRec.CR6D); 285 286 // Restore the desired video mode with CR67. 287 288 WriteCrtcReg(0x67, 0x50, 0xf0); // possible hardware bug on VX? 289 snooze(10000); 290 WriteCrtcReg(0x67, regRec.CR67 & ~0x0c); // Don't enable STREAMS 291 292 // Other mode timing and extended regs. 293 294 WriteCrtcReg(0x34, regRec.CR34); 295 if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) { 296 WriteCrtcReg(0x40, regRec.CR40); 297 } 298 299 if (S3_VIRGE_MX_SERIES(si.chipType)) { 300 WriteCrtcReg(0x41, regRec.CR41); 301 } 302 303 WriteCrtcReg(0x42, regRec.CR42); 304 WriteCrtcReg(0x45, regRec.CR45); 305 WriteCrtcReg(0x51, regRec.CR51); 306 WriteCrtcReg(0x54, regRec.CR54); 307 308 // Memory timings. 309 WriteCrtcReg(0x68, regRec.CR68); 310 WriteCrtcReg(0x69, regRec.CR69); 311 312 WriteCrtcReg(0x33, regRec.CR33); 313 if (si.chipType == S3_TRIO_3D_2X || S3_VIRGE_GX2_SERIES(si.chipType) 314 /* MXTESTME */ || S3_VIRGE_MX_SERIES(si.chipType) ) { 315 WriteCrtcReg(0x85, regRec.CR85); 316 } 317 318 if (si.chipType == S3_VIRGE_DXGX) { 319 WriteCrtcReg(0x86, regRec.CR86); 320 } 321 322 if ( (si.chipType == S3_VIRGE_GX2) || S3_VIRGE_MX_SERIES(si.chipType) ) { 323 WriteCrtcReg(0x7b, regRec.CR7B); 324 WriteCrtcReg(0x7d, regRec.CR7D); 325 WriteCrtcReg(0x87, regRec.CR87); 326 WriteCrtcReg(0x92, regRec.CR92); 327 WriteCrtcReg(0x93, regRec.CR93); 328 } 329 330 if (si.chipType == S3_VIRGE_DXGX || S3_VIRGE_GX2_SERIES(si.chipType) || 331 S3_VIRGE_MX_SERIES(si.chipType) || si.chipType == S3_TRIO_3D) { 332 WriteCrtcReg(0x90, regRec.CR90); 333 WriteCrtcReg(0x91, regRec.CR91); 334 } 335 336 WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs 337 338 // Restore extended sequencer regs for DCLK. 339 340 WriteSeqReg(0x12, regRec.SR12); 341 WriteSeqReg(0x13, regRec.SR13); 342 343 if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) { 344 WriteSeqReg(0x29, regRec.SR29); 345 } 346 if (S3_VIRGE_MX_SERIES(si.chipType)) { 347 WriteSeqReg(0x54, regRec.SR54); 348 WriteSeqReg(0x55, regRec.SR55); 349 WriteSeqReg(0x56, regRec.SR56); 350 WriteSeqReg(0x57, regRec.SR57); 351 } 352 353 WriteSeqReg(0x18, regRec.SR18); 354 355 // Load new m,n PLL values for DCLK & MCLK. 356 uint8 tmp = ReadSeqReg(0x15) & ~0x21; 357 WriteSeqReg(0x15, tmp | 0x03); 358 WriteSeqReg(0x15, tmp | 0x23); 359 WriteSeqReg(0x15, tmp | 0x03); 360 WriteSeqReg(0x15, regRec.SR15); 361 362 if (si.chipType == S3_TRIO_3D) { 363 WriteSeqReg(0x0a, regRec.SR0A); 364 WriteSeqReg(0x0f, regRec.SR0F); 365 } 366 367 // Now write out CR67 in full, possibly starting STREAMS. 368 369 VerticalRetraceWait(); 370 WriteCrtcReg(0x67, 0x50); // For possible bug on VX?! 371 snooze(10000); 372 WriteCrtcReg(0x67, regRec.CR67); 373 374 uint8 cr66 = ReadCrtcReg(0x66); 375 WriteCrtcReg(0x66, cr66 | 0x80); 376 377 WriteCrtcReg(0x3a, regRec.CR3A | 0x80); 378 379 // Now, before we continue, check if this mode has the graphic engine ON. 380 // If yes, then we reset it. 381 382 if (si.chipType == S3_VIRGE_VX) { 383 if (regRec.CR63 & 0x01) 384 Virge_GEReset(mode); 385 } else { 386 if (regRec.CR66 & 0x01) 387 Virge_GEReset(mode); 388 } 389 390 VerticalRetraceWait(); 391 if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) { 392 WriteCrtcReg(0x85, 0x1f); // primary stream threshold 393 } 394 395 // Set the standard CRTC vga regs. 396 397 WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11 398 399 for (int j = 0; j < (int)B_COUNT_OF(regRec.CRTC); j++) { 400 WriteCrtcReg(j, regRec.CRTC[j]); 401 } 402 403 // Setup HSYNC & VSYNC polarity and select clock source 2 (0x0c) for 404 // programmable PLL. 405 406 uint8 miscOutReg = 0x23 | 0x0c; 407 408 if (!(mode.timing.flags & B_POSITIVE_HSYNC)) 409 miscOutReg |= 0x40; 410 if (!(mode.timing.flags & B_POSITIVE_VSYNC)) 411 miscOutReg |= 0x80; 412 413 WriteMiscOutReg(miscOutReg); 414 415 WriteCrtcReg(0x66, cr66); 416 WriteCrtcReg(0x3a, regRec.CR3A); 417 418 return ; 419 } 420 421 422 423 static bool 424 Virge_ModeInit(const DisplayModeEx& mode) 425 { 426 SharedInfo& si = *gInfo.sharedInfo; 427 VirgeRegRec regRec; 428 429 TRACE("Virge_ModeInit(%d x %d, %d KHz)\n", 430 mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock); 431 432 // Set scale factors for mode timings. 433 434 int horizScaleFactor = 1; 435 436 if (si.chipType == S3_VIRGE_VX || S3_VIRGE_GX2_SERIES(si.chipType) || 437 S3_VIRGE_MX_SERIES(si.chipType)) { 438 horizScaleFactor = 1; 439 } else if (mode.bpp == 8) { 440 horizScaleFactor = 1; 441 } else if (mode.bpp == 16) { 442 if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000) 443 horizScaleFactor = 1; 444 else 445 horizScaleFactor = 2; 446 } else { 447 horizScaleFactor = 1; 448 } 449 450 InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC, 451 regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E); 452 453 // Now we fill in the rest of the stuff we need for the Virge. 454 // Start with MMIO, linear address regs. 455 456 uint8 temp = ReadCrtcReg(0x3a); 457 if ( S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) 458 regRec.CR3A = (temp & 0x7f) | 0x10; // ENH 256, PCI burst 459 else 460 regRec.CR3A = (temp & 0x7f) | 0x15; // ENH 256, PCI burst 461 462 regRec.CR53 = ReadCrtcReg(0x53); 463 464 if (si.chipType == S3_TRIO_3D) { 465 regRec.CR31 = 0x0c; // [trio3d] page 54 466 } else { 467 regRec.CR53 = 0x08; // Enables MMIO 468 regRec.CR31 = 0x8c; // Dis. 64k window, en. ENH maps 469 } 470 471 // Enables S3D graphic engine and PCI disconnects. 472 if (si.chipType == S3_VIRGE_VX) { 473 regRec.CR66 = 0x90; 474 regRec.CR63 = 0x09; 475 } else { 476 regRec.CR66 = 0x89; 477 // Set display fifo. 478 if ( S3_VIRGE_GX2_SERIES(si.chipType) || 479 S3_VIRGE_MX_SERIES(si.chipType) ) { 480 // Changed from 0x08 based on reports that this 481 // prevents MX from running properly below 1024x768. 482 regRec.CR63 = 0x10; 483 } else { 484 regRec.CR63 = 0; 485 } 486 } 487 488 // Now set linear address registers. 489 // LAW size: we have 2 cases, 2MB, 4MB or >= 4MB for VX. 490 regRec.CR58 = ReadCrtcReg(0x58) & 0x80; 491 492 if (si.videoMemSize == 1 * 1024 * 1024) 493 regRec.CR58 |= 0x01 | 0x10; 494 else if (si.videoMemSize == 2 * 1024 * 1024) 495 regRec.CR58 |= 0x02 | 0x10; 496 else { 497 if (si.chipType == S3_TRIO_3D_2X && si.videoMemSize == 8 * 1024 * 1024) 498 regRec.CR58 |= 0x07 | 0x10; // 8MB window on Trio3D/2X 499 else 500 regRec.CR58 |= 0x03 | 0x10; // 4MB window on virge, 8MB on VX 501 } 502 503 if (si.chipType == S3_VIRGE_VX) 504 regRec.CR58 |= 0x40; 505 506 // ** On PCI bus, no need to reprogram the linear window base address. 507 508 // Now do clock PLL programming. Use the s3gendac function to get m,n. 509 // Also determine if we need doubling etc. 510 511 int dclk = mode.timing.pixel_clock; 512 513 if (si.chipType == S3_TRIO_3D) { 514 regRec.SR15 = (ReadSeqReg(0x15) & 0x80) | 0x03; // keep BIOS init defaults 515 regRec.SR0A = ReadSeqReg(0x0a); 516 } else 517 regRec.SR15 = 0x03 | 0x80; 518 519 regRec.SR18 = 0x00; 520 regRec.CR43 = 0x00; 521 regRec.CR45 = 0x00; 522 // Enable MMIO to RAMDAC registers. 523 regRec.CR65 = 0x00; // CR65_2 must be zero, doc seems to be wrong 524 regRec.CR54 = 0x00; 525 526 if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) { 527 regRec.CR40 = ReadCrtcReg(0x40) & ~0x01; 528 } 529 530 if (S3_VIRGE_MX_SERIES(si.chipType)) { 531 // Fix problems with APM suspend/resume trashing CR90/91. 532 switch (mode.bpp) { 533 case 8: 534 regRec.CR41 = 0x38; 535 break; 536 case 16: 537 regRec.CR41 = 0x48; 538 break; 539 default: 540 regRec.CR41 = 0x77; 541 } 542 } 543 544 regRec.CR67 = 0x00; // defaults 545 546 if (si.chipType == S3_VIRGE_VX) { 547 if (mode.bpp == 8) { 548 if (dclk <= 110000) 549 regRec.CR67 = 0x00; // 8bpp, 135MHz 550 else 551 regRec.CR67 = 0x10; // 8bpp, 220MHz 552 } else if (mode.bpp == 16) { 553 if (dclk <= 110000) 554 regRec.CR67 = 0x40; // 16bpp, 135MHz 555 else 556 regRec.CR67 = 0x50; // 16bpp, 220MHz 557 } 558 Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 220000, 440000, 559 ®Rec.SR13, ®Rec.SR12); 560 } // end VX if() 561 562 else if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) { 563 uint8 ndiv; 564 565 if (mode.bpp == 8) 566 regRec.CR67 = 0x00; 567 else if (mode.bpp == 16) 568 regRec.CR67 = 0x50; 569 570 // X.org code had a somewhat convuluted way of computing the clock for 571 // MX chips. I hope this simpler method works for most MX cases. 572 573 Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 170000, 340000, 574 ®Rec.SR13, &ndiv); 575 576 regRec.SR29 = ndiv >> 7; 577 regRec.SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1); 578 } // end GX2 or MX if() 579 580 else if (si.chipType == S3_TRIO_3D) { 581 regRec.SR0F = 0x00; 582 if (mode.bpp == 8) { 583 if (dclk > 115000) { // We need pixmux 584 regRec.CR67 = 0x10; 585 regRec.SR15 |= 0x10; // Set DCLK/2 bit 586 regRec.SR18 = 0x80; // Enable pixmux 587 } 588 } else if (mode.bpp == 16) { 589 if (dclk > 115000) { 590 regRec.CR67 = 0x40; 591 regRec.SR15 |= 0x10; 592 regRec.SR18 = 0x80; 593 regRec.SR0F = 0x10; 594 } else { 595 regRec.CR67 = 0x50; 596 } 597 } 598 Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 230000, 460000, 599 ®Rec.SR13, ®Rec.SR12); 600 } // end TRIO_3D if() 601 602 else { // Everything else ... (only VIRGE & VIRGE DX/GX). 603 if (mode.bpp == 8) { 604 if (dclk > 80000) { // We need pixmux 605 regRec.CR67 = 0x10; 606 regRec.SR15 |= 0x10; // Set DCLK/2 bit 607 regRec.SR18 = 0x80; // Enable pixmux 608 } 609 } else if (mode.bpp == 16) { 610 regRec.CR67 = 0x50; 611 } 612 Virge_CalcClock(dclk, 1, 1, 31, 0, 3, 135000, 270000, 613 ®Rec.SR13, ®Rec.SR12); 614 } // end great big if()... 615 616 617 regRec.CR42 = 0x00; 618 619 if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) { 620 regRec.CR34 = 0; 621 } else { 622 regRec.CR34 = 0x10; // set display fifo 623 } 624 625 int width = mode.bytesPerRow >> 3; 626 regRec.CRTC[0x13] = 0xFF & width; 627 regRec.CR51 = (0x300 & width) >> 4; // Extension bits 628 629 regRec.CR33 = 0x20; 630 if (si.chipType == S3_TRIO_3D_2X || S3_VIRGE_GX2_SERIES(si.chipType) 631 /* MXTESTME */ || S3_VIRGE_MX_SERIES(si.chipType) ) { 632 regRec.CR85 = 0x12; // avoid sreen flickering 633 // by increasing FIFO filling, larger # fills FIFO from memory earlier 634 // on GX2 this affects all depths, not just those running STREAMS. 635 // new, secondary stream settings. 636 regRec.CR87 = 0x10; 637 // gx2 - set up in XV init code 638 regRec.CR92 = 0x00; 639 regRec.CR93 = 0x00; 640 // gx2 primary mclk timeout, def=0xb 641 regRec.CR7B = 0xb; 642 // gx2 secondary mclk timeout, def=0xb 643 regRec.CR7D = 0xb; 644 } 645 646 if (si.chipType == S3_VIRGE_DXGX || si.chipType == S3_TRIO_3D) { 647 regRec.CR86 = 0x80; // disable DAC power saving to avoid bright left edge 648 } 649 650 if (si.chipType == S3_VIRGE_DXGX || S3_VIRGE_GX2_SERIES(si.chipType) || 651 S3_VIRGE_MX_SERIES(si.chipType) || si.chipType == S3_TRIO_3D) { 652 int dbytes = mode.bytesPerRow; 653 regRec.CR91 = (dbytes + 7) / 8; 654 regRec.CR90 = (((dbytes + 7) / 8) >> 8) | 0x80; 655 } 656 657 // S3_BLANK_DELAY settings based on defaults only. From 3.3.3. 658 659 int blank_delay; 660 661 if (si.chipType == S3_VIRGE_VX) { 662 // These values need to be changed once CR67_1 is set 663 // for gamma correction (see S3V server)! 664 if (mode.bpp == 8) 665 blank_delay = 0x00; 666 else if (mode.bpp == 16) 667 blank_delay = 0x00; 668 else 669 blank_delay = 0x51; 670 } else { 671 if (mode.bpp == 8) 672 blank_delay = 0x00; 673 else if (mode.bpp == 16) 674 blank_delay = 0x02; 675 else 676 blank_delay = 0x04; 677 } 678 679 if (si.chipType == S3_VIRGE_VX) { 680 regRec.CR6D = blank_delay; 681 } else { 682 regRec.CR65 = (regRec.CR65 & ~0x38) | (blank_delay & 0x07) << 3; 683 regRec.CR6D = ReadCrtcReg(0x6d); 684 } 685 686 regRec.CR68 = ReadCrtcReg(0x68); 687 regRec.CR69 = 0; 688 689 // Flat panel centering and expansion registers. 690 regRec.SR54 = 0x1f ; 691 regRec.SR55 = 0x9f ; 692 regRec.SR56 = 0x1f ; 693 regRec.SR57 = 0xff ; 694 695 Virge_WriteMode(mode, regRec); // write mode registers to hardware 696 697 // Note that the Virge VX chip does not display the hardware cursor when the 698 // mode is set to 640x480; thus, in this case the hardware cursor functions 699 // will be disabled so that a software cursor will be used. 700 701 si.bDisableHdwCursor = (si.chipType == S3_VIRGE_VX 702 && mode.timing.h_display == 640 && mode.timing.v_display == 480); 703 704 return true; 705 } 706 707 708 bool 709 Virge_SetDisplayMode(const DisplayModeEx& mode) 710 { 711 // The code to actually configure the display. 712 // All the error checking must be done in PROPOSE_DISPLAY_MODE(), 713 // and assume that the mode values we get here are acceptable. 714 715 WriteSeqReg(0x01, 0x20, 0x20); // blank the screen 716 717 if ( ! Virge_ModeInit(mode)) { 718 TRACE("Virge_ModeInit() failed\n"); 719 return false; 720 } 721 722 Virge_AdjustFrame(mode); 723 Virge_EngineReset(mode); 724 725 WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen 726 727 return true; 728 } 729 730 731 732 void 733 Virge_AdjustFrame(const DisplayModeEx& mode) 734 { 735 // Adjust start address in frame buffer. We use the new CR69 reg 736 // for this purpose instead of the older CR31/CR51 combo. 737 738 SharedInfo& si = *gInfo.sharedInfo; 739 740 int base = ((mode.v_display_start * mode.virtual_width + mode.h_display_start) 741 * (mode.bpp / 8)) >> 2; 742 743 if (mode.bpp == 16) 744 if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000) 745 base &= ~1; 746 747 base += si.frameBufferOffset; 748 749 // Now program the start address registers. 750 751 WriteCrtcReg(0x0c, (base >> 8) & 0xff); 752 WriteCrtcReg(0x0d, base & 0xff); 753 WriteCrtcReg(0x69, (base & 0x0F0000) >> 16); 754 } 755 756 757 void 758 Virge_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) 759 { 760 // Set the indexed color palette for 8-bit color depth mode. 761 762 (void)flags; // avoid compiler warning for unused arg 763 764 if (gInfo.sharedInfo->displayMode.space != B_CMAP8) 765 return ; 766 767 while (count--) { 768 WriteIndexedColor(first++, // color index 769 colorData[0] >> 2, // red 770 colorData[1] >> 2, // green 771 colorData[2] >> 2); // blue 772 colorData += 3; 773 } 774 } 775