tcp: Add APICall trace entry and move TRACEs into locked parts.
[haiku.git] / src / add-ons / accelerants / s3 / virge_mode.cpp
blob6fc13136416195ea6194cc51bca03a3bd51e4319
1 /*
2 Haiku S3 Virge driver adapted from the X.org Virge driver.
4 Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
6 Copyright 2007-2008 Haiku, Inc. All rights reserved.
7 Distributed under the terms of the MIT license.
9 Authors:
10 Gerald Zajac 2007-2008
14 #include "accel.h"
15 #include "virge.h"
18 #define BASE_FREQ 14.31818 // MHz
21 struct VirgeRegRec {
22 uint8 CRTC[25]; // Crtc Controller reg's
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;
40 static void
41 Virge_EngineReset(const DisplayModeEx& mode)
43 SharedInfo& si = *gInfo.sharedInfo;
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;
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));
64 WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display);
65 WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display);
70 static void
71 Virge_NopAllCmdSets()
73 // This function should be called only for the Trio 3D chip.
75 for (int i = 0; i < 1000; i++) {
76 if ( (IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) == 0x20002000) {
77 break;
81 gInfo.WaitQueue(7);
82 WriteReg32(CMD_SET, CMD_NOP);
87 static void
88 Virge_GEReset(const DisplayModeEx& mode)
90 SharedInfo& si = *gInfo.sharedInfo;
92 if (si.chipType == S3_TRIO_3D)
93 Virge_NopAllCmdSets();
95 gInfo.WaitIdleEmpty();
97 if (si.chipType == S3_TRIO_3D) {
98 bool ge_was_on = false;
99 snooze(10000);
101 for (int r = 1; r < 10; r++) {
102 uint8 resetidx = 0x66;
104 VerticalRetraceWait();
105 uint8 tmp = ReadCrtcReg(resetidx);
107 VerticalRetraceWait();
108 IN_SUBSYS_STAT();
110 // turn off the GE
112 if (tmp & 0x01) {
113 WriteCrtcReg(resetidx, tmp);
114 ge_was_on = true;
115 snooze(10000);
118 IN_SUBSYS_STAT();
119 WriteCrtcReg(resetidx, tmp | 0x02);
120 snooze(10000);
122 VerticalRetraceWait();
123 WriteCrtcReg(resetidx, tmp & ~0x02);
124 snooze(10000);
126 if (ge_was_on) {
127 tmp |= 0x01;
128 WriteCrtcReg(resetidx, tmp);
129 snooze(10000);
132 VerticalRetraceWait();
134 Virge_NopAllCmdSets();
135 gInfo.WaitIdleEmpty();
137 WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow);
138 snooze(10000);
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;
146 } else {
147 uint8 regIndex = (si.chipType == S3_VIRGE_VX ? 0x63 : 0x66);
148 uint8 tmp = ReadCrtcReg(regIndex);
149 snooze(10000);
151 // try multiple times to avoid lockup of VIRGE/MX
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();
160 WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow);
161 snooze(10000);
163 if (((IN_SUBSYS_STAT() & 0x3f00) != 0x3000)) {
164 TRACE("Restarting S3 graphics engine reset %2d ...\n", r);
165 } else
166 break;
170 gInfo.WaitQueue(2);
171 WriteReg32(SRC_BASE, 0);
172 WriteReg32(DEST_BASE, 0);
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);
180 if (si.chipType == S3_TRIO_3D)
181 Virge_NopAllCmdSets();
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)
193 uint8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2;
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;
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);
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);
210 // Work out suitable timings.
212 double best_diff = ffreq;
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;
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;
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;
244 static void
245 Virge_WriteMode(const DisplayModeEx& mode, VirgeRegRec& regRec)
247 // This function writes out all of the standard VGA and extended S3 registers
248 // needed to setup a video mode.
250 TRACE("Virge_WriteMode()\n");
252 SharedInfo& si = *gInfo.sharedInfo;
254 // First reset GE to make sure nothing is going on.
256 if (ReadCrtcReg(si.chipType == S3_VIRGE_VX ? 0x63 : 0x66) & 0x01)
257 Virge_GEReset(mode);
259 // As per databook, always disable STREAMS before changing modes.
261 if ((ReadCrtcReg(0x67) & 0x0c) == 0x0c) {
262 // STREAMS running, disable it
263 VerticalRetraceWait();
264 WriteReg32(FIFO_CONTROL_REG, 0xC000);
266 WriteCrtcReg(0x67, 0x00, 0x0c); // disable STREAMS processor
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);
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);
286 // Restore the desired video mode with CR67.
288 WriteCrtcReg(0x67, 0x50, 0xf0); // possible hardware bug on VX?
289 snooze(10000);
290 WriteCrtcReg(0x67, regRec.CR67 & ~0x0c); // Don't enable STREAMS
292 // Other mode timing and extended regs.
294 WriteCrtcReg(0x34, regRec.CR34);
295 if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) {
296 WriteCrtcReg(0x40, regRec.CR40);
299 if (S3_VIRGE_MX_SERIES(si.chipType)) {
300 WriteCrtcReg(0x41, regRec.CR41);
303 WriteCrtcReg(0x42, regRec.CR42);
304 WriteCrtcReg(0x45, regRec.CR45);
305 WriteCrtcReg(0x51, regRec.CR51);
306 WriteCrtcReg(0x54, regRec.CR54);
308 // Memory timings.
309 WriteCrtcReg(0x68, regRec.CR68);
310 WriteCrtcReg(0x69, regRec.CR69);
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);
318 if (si.chipType == S3_VIRGE_DXGX) {
319 WriteCrtcReg(0x86, regRec.CR86);
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);
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);
336 WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
338 // Restore extended sequencer regs for DCLK.
340 WriteSeqReg(0x12, regRec.SR12);
341 WriteSeqReg(0x13, regRec.SR13);
343 if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) {
344 WriteSeqReg(0x29, regRec.SR29);
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);
353 WriteSeqReg(0x18, regRec.SR18);
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);
362 if (si.chipType == S3_TRIO_3D) {
363 WriteSeqReg(0x0a, regRec.SR0A);
364 WriteSeqReg(0x0f, regRec.SR0F);
367 // Now write out CR67 in full, possibly starting STREAMS.
369 VerticalRetraceWait();
370 WriteCrtcReg(0x67, 0x50); // For possible bug on VX?!
371 snooze(10000);
372 WriteCrtcReg(0x67, regRec.CR67);
374 uint8 cr66 = ReadCrtcReg(0x66);
375 WriteCrtcReg(0x66, cr66 | 0x80);
377 WriteCrtcReg(0x3a, regRec.CR3A | 0x80);
379 // Now, before we continue, check if this mode has the graphic engine ON.
380 // If yes, then we reset it.
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);
390 VerticalRetraceWait();
391 if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType) ) {
392 WriteCrtcReg(0x85, 0x1f); // primary stream threshold
395 // Set the standard CRTC vga regs.
397 WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11
399 for (int j = 0; j < (int)B_COUNT_OF(regRec.CRTC); j++) {
400 WriteCrtcReg(j, regRec.CRTC[j]);
403 // Setup HSYNC & VSYNC polarity and select clock source 2 (0x0c) for
404 // programmable PLL.
406 uint8 miscOutReg = 0x23 | 0x0c;
408 if (!(mode.timing.flags & B_POSITIVE_HSYNC))
409 miscOutReg |= 0x40;
410 if (!(mode.timing.flags & B_POSITIVE_VSYNC))
411 miscOutReg |= 0x80;
413 WriteMiscOutReg(miscOutReg);
415 WriteCrtcReg(0x66, cr66);
416 WriteCrtcReg(0x3a, regRec.CR3A);
418 return ;
423 static bool
424 Virge_ModeInit(const DisplayModeEx& mode)
426 SharedInfo& si = *gInfo.sharedInfo;
427 VirgeRegRec regRec;
429 TRACE("Virge_ModeInit(%d x %d, %d KHz)\n",
430 mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock);
432 // Set scale factors for mode timings.
434 int horizScaleFactor = 1;
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;
450 InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC,
451 regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E);
453 // Now we fill in the rest of the stuff we need for the Virge.
454 // Start with MMIO, linear address regs.
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
462 regRec.CR53 = ReadCrtcReg(0x53);
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
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;
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;
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
503 if (si.chipType == S3_VIRGE_VX)
504 regRec.CR58 |= 0x40;
506 // ** On PCI bus, no need to reprogram the linear window base address.
508 // Now do clock PLL programming. Use the s3gendac function to get m,n.
509 // Also determine if we need doubling etc.
511 int dclk = mode.timing.pixel_clock;
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;
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;
526 if (si.chipType != S3_TRIO_3D && si.chipType != S3_VIRGE_MX) {
527 regRec.CR40 = ReadCrtcReg(0x40) & ~0x01;
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;
544 regRec.CR67 = 0x00; // defaults
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
558 Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 220000, 440000,
559 &regRec.SR13, &regRec.SR12);
560 } // end VX if()
562 else if (S3_VIRGE_GX2_SERIES(si.chipType) || S3_VIRGE_MX_SERIES(si.chipType)) {
563 uint8 ndiv;
565 if (mode.bpp == 8)
566 regRec.CR67 = 0x00;
567 else if (mode.bpp == 16)
568 regRec.CR67 = 0x50;
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.
573 Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 170000, 340000,
574 &regRec.SR13, &ndiv);
576 regRec.SR29 = ndiv >> 7;
577 regRec.SR12 = (ndiv & 0x1f) | ((ndiv & 0x60) << 1);
578 } // end GX2 or MX if()
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
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;
598 Virge_CalcClock(dclk, 1, 1, 31, 0, 4, 230000, 460000,
599 &regRec.SR13, &regRec.SR12);
600 } // end TRIO_3D if()
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
609 } else if (mode.bpp == 16) {
610 regRec.CR67 = 0x50;
612 Virge_CalcClock(dclk, 1, 1, 31, 0, 3, 135000, 270000,
613 &regRec.SR13, &regRec.SR12);
614 } // end great big if()...
617 regRec.CR42 = 0x00;
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
625 int width = mode.bytesPerRow >> 3;
626 regRec.CRTC[0x13] = 0xFF & width;
627 regRec.CR51 = (0x300 & width) >> 4; // Extension bits
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;
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
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;
657 // S3_BLANK_DELAY settings based on defaults only. From 3.3.3.
659 int blank_delay;
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;
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);
686 regRec.CR68 = ReadCrtcReg(0x68);
687 regRec.CR69 = 0;
689 // Flat panel centering and expansion registers.
690 regRec.SR54 = 0x1f ;
691 regRec.SR55 = 0x9f ;
692 regRec.SR56 = 0x1f ;
693 regRec.SR57 = 0xff ;
695 Virge_WriteMode(mode, regRec); // write mode registers to hardware
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.
701 si.bDisableHdwCursor = (si.chipType == S3_VIRGE_VX
702 && mode.timing.h_display == 640 && mode.timing.v_display == 480);
704 return true;
708 bool
709 Virge_SetDisplayMode(const DisplayModeEx& mode)
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.
715 WriteSeqReg(0x01, 0x20, 0x20); // blank the screen
717 if ( ! Virge_ModeInit(mode)) {
718 TRACE("Virge_ModeInit() failed\n");
719 return false;
722 Virge_AdjustFrame(mode);
723 Virge_EngineReset(mode);
725 WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen
727 return true;
732 void
733 Virge_AdjustFrame(const DisplayModeEx& mode)
735 // Adjust start address in frame buffer. We use the new CR69 reg
736 // for this purpose instead of the older CR31/CR51 combo.
738 SharedInfo& si = *gInfo.sharedInfo;
740 int base = ((mode.v_display_start * mode.virtual_width + mode.h_display_start)
741 * (mode.bpp / 8)) >> 2;
743 if (mode.bpp == 16)
744 if (si.chipType == S3_TRIO_3D && mode.timing.pixel_clock > 115000)
745 base &= ~1;
747 base += si.frameBufferOffset;
749 // Now program the start address registers.
751 WriteCrtcReg(0x0c, (base >> 8) & 0xff);
752 WriteCrtcReg(0x0d, base & 0xff);
753 WriteCrtcReg(0x69, (base & 0x0F0000) >> 16);
757 void
758 Virge_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
760 // Set the indexed color palette for 8-bit color depth mode.
762 (void)flags; // avoid compiler warning for unused arg
764 if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
765 return ;
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;