xref: /haiku/src/add-ons/accelerants/s3/virge_mode.cpp (revision 6ab4ff112a084ee6f022e17b4d2668038c0b2014)
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
Virge_EngineReset(const DisplayModeEx & mode)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
Virge_NopAllCmdSets()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
Virge_GEReset(const DisplayModeEx & mode)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
Virge_CalcClock(long freq,int min_m,int min_n1,int max_n1,int min_n2,int max_n2,long freq_min,long freq_max,uint8 * mdiv,uint8 * ndiv)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
Virge_WriteMode(const DisplayModeEx & mode,VirgeRegRec & regRec)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
Virge_ModeInit(const DisplayModeEx & mode)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 						&regRec.SR13, &regRec.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 						&regRec.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 						&regRec.SR13, &regRec.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 						&regRec.SR13, &regRec.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
Virge_SetDisplayMode(const DisplayModeEx & mode)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
Virge_AdjustFrame(const DisplayModeEx & mode)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
Virge_SetIndexedColors(uint count,uint8 first,uint8 * colorData,uint32 flags)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