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.
10 Gerald Zajac 2007-2008
18 #define BASE_FREQ 14.31818 // MHz
22 uint8 CRTC
[25]; // Crtc Controller reg's
25 uint8 SR12
, SR13
, SR15
, SR18
; // SR9-SR1C, ext seq.
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.
33 uint8 CR85
, CR86
, CR87
;
34 uint8 CR90
, CR91
, CR92
, CR93
;
41 Virge_EngineReset(const DisplayModeEx
& mode
)
43 SharedInfo
& si
= *gInfo
.sharedInfo
;
47 si
.commonCmd
= DRAW
| DST_8BPP
;
50 si
.commonCmd
= DRAW
| DST_16BPP
;
53 si
.commonCmd
= DRAW
| DST_24BPP
;
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
);
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) {
82 WriteReg32(CMD_SET
, CMD_NOP
);
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;
101 for (int r
= 1; r
< 10; r
++) {
102 uint8 resetidx
= 0x66;
104 VerticalRetraceWait();
105 uint8 tmp
= ReadCrtcReg(resetidx
);
107 VerticalRetraceWait();
113 WriteCrtcReg(resetidx
, tmp
);
119 WriteCrtcReg(resetidx
, tmp
| 0x02);
122 VerticalRetraceWait();
123 WriteCrtcReg(resetidx
, tmp
& ~0x02);
128 WriteCrtcReg(resetidx
, tmp
);
132 VerticalRetraceWait();
134 Virge_NopAllCmdSets();
135 gInfo
.WaitIdleEmpty();
137 WriteReg32(DEST_SRC_STR
, mode
.bytesPerRow
<< 16 | mode
.bytesPerRow
);
140 if ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000) {
141 TRACE("Restarting S3 graphics engine reset %2d ...%lx\n",
142 r
, IN_SUBSYS_STAT() );
147 uint8 regIndex
= (si
.chipType
== S3_VIRGE_VX
? 0x63 : 0x66);
148 uint8 tmp
= ReadCrtcReg(regIndex
);
151 // try multiple times to avoid lockup of VIRGE/MX
153 for (int r
= 1; r
< 10; r
++) {
154 WriteCrtcReg(regIndex
, tmp
| 0x02);
156 WriteCrtcReg(regIndex
, tmp
& ~0x02);
158 gInfo
.WaitIdleEmpty();
160 WriteReg32(DEST_SRC_STR
, mode
.bytesPerRow
<< 16 | mode
.bytesPerRow
);
163 if (((IN_SUBSYS_STAT() & 0x3f00) != 0x3000)) {
164 TRACE("Restarting S3 graphics engine reset %2d ...\n", r
);
171 WriteReg32(SRC_BASE
, 0);
172 WriteReg32(DEST_BASE
, 0);
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();
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)
220 double div
= (double)(m
) / (double)(n1
);
221 if ((div
>= ffreq_min
) && (div
<= ffreq_max
)) {
222 double diff
= ffreq
- div
/ (1 << n2
);
225 if (diff
< best_diff
) {
236 *ndiv
= (best_n1
- 2) | (best_n2
<< 6);
238 *ndiv
= (best_n1
- 2) | (best_n2
<< 5);
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)
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?
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
);
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?!
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)
386 if (regRec
.CR66
& 0x01)
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
406 uint8 miscOutReg
= 0x23 | 0x0c;
408 if (!(mode
.timing
.flags
& B_POSITIVE_HSYNC
))
410 if (!(mode
.timing
.flags
& B_POSITIVE_VSYNC
))
413 WriteMiscOutReg(miscOutReg
);
415 WriteCrtcReg(0x66, cr66
);
416 WriteCrtcReg(0x3a, regRec
.CR3A
);
424 Virge_ModeInit(const DisplayModeEx
& mode
)
426 SharedInfo
& si
= *gInfo
.sharedInfo
;
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;
445 horizScaleFactor
= 2;
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
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
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
) {
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.
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;
497 if (si
.chipType
== S3_TRIO_3D_2X
&& si
.videoMemSize
== 8 * 1024 * 1024)
498 regRec
.CR58
|= 0x07 | 0x10; // 8MB window on Trio3D/2X
500 regRec
.CR58
|= 0x03 | 0x10; // 4MB window on virge, 8MB on VX
503 if (si
.chipType
== S3_VIRGE_VX
)
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);
517 regRec
.SR15
= 0x03 | 0x80;
522 // Enable MMIO to RAMDAC registers.
523 regRec
.CR65
= 0x00; // CR65_2 must be zero, doc seems to be wrong
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.
544 regRec
.CR67
= 0x00; // defaults
546 if (si
.chipType
== S3_VIRGE_VX
) {
549 regRec
.CR67
= 0x00; // 8bpp, 135MHz
551 regRec
.CR67
= 0x10; // 8bpp, 220MHz
552 } else if (mode
.bpp
== 16) {
554 regRec
.CR67
= 0x40; // 16bpp, 135MHz
556 regRec
.CR67
= 0x50; // 16bpp, 220MHz
558 Virge_CalcClock(dclk
, 1, 1, 31, 0, 4, 220000, 440000,
559 ®Rec
.SR13
, ®Rec
.SR12
);
562 else if (S3_VIRGE_GX2_SERIES(si
.chipType
) || S3_VIRGE_MX_SERIES(si
.chipType
)) {
567 else if (mode
.bpp
== 16)
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 ®Rec
.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
) {
583 if (dclk
> 115000) { // We need pixmux
585 regRec
.SR15
|= 0x10; // Set DCLK/2 bit
586 regRec
.SR18
= 0x80; // Enable pixmux
588 } else if (mode
.bpp
== 16) {
598 Virge_CalcClock(dclk
, 1, 1, 31, 0, 4, 230000, 460000,
599 ®Rec
.SR13
, ®Rec
.SR12
);
600 } // end TRIO_3D if()
602 else { // Everything else ... (only VIRGE & VIRGE DX/GX).
604 if (dclk
> 80000) { // We need pixmux
606 regRec
.SR15
|= 0x10; // Set DCLK/2 bit
607 regRec
.SR18
= 0x80; // Enable pixmux
609 } else if (mode
.bpp
== 16) {
612 Virge_CalcClock(dclk
, 1, 1, 31, 0, 3, 135000, 270000,
613 ®Rec
.SR13
, ®Rec
.SR12
);
614 } // end great big if()...
619 if (S3_VIRGE_GX2_SERIES(si
.chipType
) || S3_VIRGE_MX_SERIES(si
.chipType
) ) {
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
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.
637 // gx2 - set up in XV init code
640 // gx2 primary mclk timeout, def=0xb
642 // gx2 secondary mclk timeout, def=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.
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)!
666 else if (mode
.bpp
== 16)
673 else if (mode
.bpp
== 16)
679 if (si
.chipType
== S3_VIRGE_VX
) {
680 regRec
.CR6D
= blank_delay
;
682 regRec
.CR65
= (regRec
.CR65
& ~0x38) | (blank_delay
& 0x07) << 3;
683 regRec
.CR6D
= ReadCrtcReg(0x6d);
686 regRec
.CR68
= ReadCrtcReg(0x68);
689 // Flat panel centering and expansion registers.
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);
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");
722 Virge_AdjustFrame(mode
);
723 Virge_EngineReset(mode
);
725 WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen
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;
744 if (si
.chipType
== S3_TRIO_3D
&& mode
.timing
.pixel_clock
> 115000)
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);
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
)
768 WriteIndexedColor(first
++, // color index
769 colorData
[0] >> 2, // red
770 colorData
[1] >> 2, // green
771 colorData
[2] >> 2); // blue