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
21struct 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
40static void
41Virge_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
70static void
71Virge_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
87static void
88Virge_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
186static void
187Virge_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
244static void
245Virge_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
423static bool
424Virge_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
708bool
709Virge_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
732void
733Virge_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
757void
758Virge_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