xref: /haiku/src/add-ons/accelerants/s3/savage_mode.cpp (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
1 /*
2 	Haiku S3 Savage driver adapted from the X.org Savage driver.
3 
4 	Copyright (C) 1994-2000 The XFree86 Project, Inc.	All Rights Reserved.
5 	Copyright (c) 2003-2006, X.Org Foundation
6 
7 	Copyright 2007-2008 Haiku, Inc.  All rights reserved.
8 	Distributed under the terms of the MIT license.
9 
10 	Authors:
11 	Gerald Zajac 2006-2008
12 */
13 
14 
15 #include "accel.h"
16 #include "savage.h"
17 
18 
19 #define BASE_FREQ	14.31818
20 
21 
22 struct SavageRegRec {
23 	uint8  CRTC[25];			// Crtc Controller reg's
24 
25 	uint8  SR12, SR13, SR1B, SR29;
26 	uint8  CR33, CR34, CR3A, CR3B, CR3C;
27 	uint8  CR42, CR43, CR45;
28 	uint8  CR50, CR51, CR53, CR58, CR5D, CR5E;
29 	uint8  CR65, CR66, CR67, CR69;
30 	uint8  CR86, CR88;
31 	uint8  CR90, CR91, CRB0;
32 };
33 
34 
35 
36 static void
37 Savage_SetGBD_Twister(const DisplayModeEx& mode)
38 {
39 	SharedInfo& si = *gInfo.sharedInfo;
40 	int bci_enable;
41 
42 	if (si.chipType == S3_SAVAGE4)
43 		bci_enable = BCI_ENABLE;
44 	else
45 		bci_enable = BCI_ENABLE_TWISTER;
46 
47 	// MM81C0 and 81C4 are used to control primary stream.
48 	WriteReg32(PRI_STREAM_FBUF_ADDR0, 0);
49 	WriteReg32(PRI_STREAM_FBUF_ADDR1, 0);
50 
51 	// Program Primary Stream Stride Register.
52 	//
53 	// Tell engine if tiling on or off, set primary stream stride, and
54 	// if tiling, set tiling bits/pixel and primary stream tile offset.
55 	// Note that tile offset (bits 16 - 29) must be scanline width in
56 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
57 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
58 	// bytes padded up to an even number of tilewidths.
59 
60 	WriteReg32(PRI_STREAM_STRIDE,
61 		(((mode.bytesPerRow * 2) << 16) & 0x3FFFE000) |
62 		(mode.bytesPerRow & 0x00001fff));
63 
64 	//  CR69, bit 7 = 1
65 	//  to use MM streams processor registers to control primary stream.
66 
67 	WriteCrtcReg(0x69, 0x80, 0x80);
68 
69 	WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
70 
71 	// If MS1NB style linear tiling mode.
72 	// bit MM850C[15] = 0 select NB linear tile mode.
73 	// bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode.
74 
75 	uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000;	// use MS-s style tile mode
76 	WriteReg32(ADVANCED_FUNC_CTRL, ulTmp);
77 
78 	// CR88, bit 4 - Block write enabled/disabled.
79 	//
80 	// Note: Block write must be disabled when writing to tiled
81 	//		 memory. Even when writing to non-tiled memory, block
82 	//		 write should only be enabled for certain types of SGRAM.
83 
84 	WriteCrtcReg(0x88, DISABLE_BLOCK_WRITE_2D, DISABLE_BLOCK_WRITE_2D);
85 }
86 
87 
88 static void
89 Savage_SetGBD_3D(const DisplayModeEx& mode)
90 {
91 	int bci_enable = BCI_ENABLE;
92 
93 	// MM81C0 and 81C4 are used to control primary stream.
94 	WriteReg32(PRI_STREAM_FBUF_ADDR0, 0);
95 	WriteReg32(PRI_STREAM_FBUF_ADDR1, 0);
96 
97 	// Program Primary Stream Stride Register.
98 	//
99 	// Tell engine if tiling on or off, set primary stream stride, and
100 	// if tiling, set tiling bits/pixel and primary stream tile offset.
101 	// Note that tile offset (bits 16 - 29) must be scanline width in
102 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
103 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
104 	// bytes padded up to an even number of tilewidths.
105 
106 	WriteReg32(PRI_STREAM_STRIDE,
107 		(((mode.bytesPerRow * 2) << 16) & 0x3FFFE000) |
108 		(mode.bytesPerRow & 0x00001fff));
109 
110 	// CR69, bit 7 = 1 to use MM streams processor registers to control primary
111 	// stream.
112 
113 	WriteCrtcReg(0x69, 0x80, 0x80);
114 
115 	WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
116 
117 	// If MS1NB style linear tiling mode.
118 	// bit MM850C[15] = 0 select NB linear tile mode.
119 	// bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode.
120 
121 	uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000;	// use MS-s style tile mode
122 	WriteReg32(ADVANCED_FUNC_CTRL, ulTmp);
123 
124 	// CR88, bit 4 - Block write enabled/disabled.
125 	//
126 	// Note: Block write must be disabled when writing to tiled
127 	//		 memory.  Even when writing to non-tiled memory, block
128 	//		 write should only be enabled for certain types of SGRAM.
129 
130 	WriteCrtcReg(0x88, DISABLE_BLOCK_WRITE_2D, DISABLE_BLOCK_WRITE_2D);
131 }
132 
133 
134 static void
135 Savage_SetGBD_MX(const DisplayModeEx& mode)
136 {
137 	SharedInfo& si = *gInfo.sharedInfo;
138 	int bci_enable = BCI_ENABLE;
139 
140 	// CR67_3:
141 	//	= 1  stream processor MMIO address and stride register
142 	//		 are used to control the primary stream.
143 	//	= 0  standard VGA address and stride registers
144 	//		 are used to control the primary streams.
145 
146 	WriteCrtcReg(0x67, 0x08, 0x08);
147 	// IGA 2.
148 	WriteSeqReg(0x26, 0x4f);		// select IGA 2 read/writes
149 	WriteCrtcReg(0x67, 0x08, 0x08);
150 	WriteSeqReg(0x26, 0x40);		// select IGA 1
151 
152 	// Set primary stream to bank 0 via reg CRCA.
153 	WriteCrtcReg(MEMORY_CTRL0_REG, 0x00, MEM_PS1 + MEM_PS2);
154 
155 	// MM81C0 and 81C4 are used to control primary stream.
156 	WriteReg32(PRI_STREAM_FBUF_ADDR0,  si.frameBufferOffset & 0x7fffff);
157 	WriteReg32(PRI_STREAM_FBUF_ADDR1,  si.frameBufferOffset & 0x7fffff);
158 	WriteReg32(PRI_STREAM2_FBUF_ADDR0, si.frameBufferOffset & 0x7fffff);
159 	WriteReg32(PRI_STREAM2_FBUF_ADDR1, si.frameBufferOffset & 0x7fffff);
160 
161 	// Program Primary Stream Stride Register.
162 	//
163 	// Tell engine if tiling on or off, set primary stream stride, and
164 	// if tiling, set tiling bits/pixel and primary stream tile offset.
165 	// Note that tile offset (bits 16 - 29) must be scanline width in
166 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
167 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
168 	// bytes padded up to an even number of tilewidths.
169 
170 	WriteReg32(PRI_STREAM_STRIDE,
171 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
172 		(mode.bytesPerRow & 0x00003fff));
173 	WriteReg32(PRI_STREAM2_STRIDE,
174 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
175 		(mode.bytesPerRow & 0x00003fff));
176 
177 	WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
178 
179 	// CR78, bit 3  - Block write enabled(1)/disabled(0).
180 	//		 bit 2  - Block write cycle time(0:2 cycles,1: 1 cycle)
181 	//	Note:	Block write must be disabled when writing to tiled
182 	//			memory.	Even when writing to non-tiled memory, block
183 	//			write should only be enabled for certain types of SGRAM.
184 
185 	WriteCrtcReg(0x78, 0xfb, 0xfb);
186 }
187 
188 
189 static void
190 Savage_SetGBD_Super(const DisplayModeEx& mode)
191 {
192 	SharedInfo& si = *gInfo.sharedInfo;
193 	int bci_enable = BCI_ENABLE_TWISTER;
194 
195 	// CR67_3:
196 	//	= 1 stream processor MMIO address and stride register
197 	//		are used to control the primary stream.
198 	//	= 0 standard VGA address and stride registers
199 	//		are used to control the primary streams.
200 
201 	WriteCrtcReg(0x67, 0x08, 0x08);
202 	// IGA 2.
203 	WriteSeqReg(0x26, 0x4f);		// select IGA 2 read/writes
204 	WriteCrtcReg(0x67, 0x08, 0x08);
205 	WriteSeqReg(0x26, 0x40);		// select IGA 1
206 
207 	// Load ps1 active registers as determined by MM81C0/81C4.
208 	// Load ps2 active registers as determined by MM81B0/81B4.
209 
210 	WriteCrtcReg(0x65, 0x03, 0x03);
211 
212 	// Program Primary Stream Stride Register.
213 	//
214 	// Tell engine if tiling on or off, set primary stream stride, and
215 	// if tiling, set tiling bits/pixel and primary stream tile offset.
216 	// Note that tile offset (bits 16 - 29) must be scanline width in
217 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
218 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
219 	// bytes padded up to an even number of tilewidths.
220 
221 	WriteReg32(PRI_STREAM_STRIDE,
222 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
223 		(mode.bytesPerRow & 0x00001fff));
224 	WriteReg32(PRI_STREAM2_STRIDE,
225 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
226 		(mode.bytesPerRow & 0x00001fff));
227 
228 	// MM81C0 and 81C4 are used to control primary stream.
229 	WriteReg32(PRI_STREAM_FBUF_ADDR0, si.frameBufferOffset);
230 	WriteReg32(PRI_STREAM_FBUF_ADDR1, 0x80000000);
231 	WriteReg32(PRI_STREAM2_FBUF_ADDR0, (si.frameBufferOffset & 0xfffffffc) | 0x80000000);
232 	WriteReg32(PRI_STREAM2_FBUF_ADDR1, si.frameBufferOffset & 0xfffffffc);
233 
234 	// Bit 28:block write disable.
235 	WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_BD64 | 0x10000000);
236 }
237 
238 
239 static void
240 Savage_SetGBD_2000(const DisplayModeEx& mode)
241 {
242 	SharedInfo& si = *gInfo.sharedInfo;
243 	int bci_enable = BCI_ENABLE_TWISTER;
244 
245 	// MM81C0 and 81B0 are used to control primary stream.
246 	WriteReg32(PRI_STREAM_FBUF_ADDR0, si.frameBufferOffset);
247 	WriteReg32(PRI_STREAM2_FBUF_ADDR0, si.frameBufferOffset);
248 
249 	// Program Primary Stream Stride Register.
250 	//
251 	// Tell engine if tiling on or off, set primary stream stride, and
252 	// if tiling, set tiling bits/pixel and primary stream tile offset.
253 	// Note that tile offset (bits 16 - 29) must be scanline width in
254 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
255 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
256 	// bytes padded up to an even number of tilewidths.
257 
258 	WriteReg32(PRI_STREAM_STRIDE,  ((mode.bytesPerRow << 4) & 0x7ff0));
259 	WriteReg32(PRI_STREAM2_STRIDE, ((mode.bytesPerRow << 4) & 0x7ff0));
260 
261 	// CR67_3:
262 	//	= 1 stream processor MMIO address and stride register
263 	//		are used to control the primary stream.
264 	//	= 0 standard VGA address and stride registers
265 	//		are used to control the primary streams
266 
267 	WriteCrtcReg(0x67, 0x08, 0x08);
268 
269 	// Bit 28:block write disable.
270 	WriteReg32(S3_GLOBAL_GBD_REG, bci_enable | S3_BD64 | 0x10000000);
271 
272 	WriteCrtcReg(0x73, 0x00, 0x20);		// CR73 bit 5 = 0 block write disable
273 }
274 
275 
276 
277 static void
278 Savage_SetGBD(const DisplayModeEx& mode)
279 {
280 	SharedInfo& si = *gInfo.sharedInfo;
281 
282 	VerticalRetraceWait();
283 
284 	switch (gInfo.sharedInfo->chipType) {
285 		case S3_SAVAGE_3D:
286 			Savage_SetGBD_3D(mode);
287 			break;
288 
289 		case S3_SAVAGE_MX:
290 			Savage_SetGBD_MX(mode);
291 			break;
292 
293 		case S3_SAVAGE4:
294 		case S3_PROSAVAGE:
295 		case S3_TWISTER:
296 		case S3_PROSAVAGE_DDR:
297 			Savage_SetGBD_Twister(mode);
298 			break;
299 
300 		case S3_SUPERSAVAGE:
301 			Savage_SetGBD_Super(mode);
302 			break;
303 
304 		case S3_SAVAGE2000:
305 			Savage_SetGBD_2000(mode);
306 			break;
307 	}
308 
309 	WriteCrtcReg(0x50, 0xc1, 0xc1);		// CR50, bit 7,6,0 = 111, Use GBD
310 
311 	// Set up the Global Bitmap Descriptor used for BCI.
312 	// Do not enable block_write because we can't determine if the memory
313 	// type is a certain type of SGRAM for which block write can be used.
314 	//	bit 24~25: tile format,  00 = linear
315 	//	bit 28: block write disble/enable, 0 = disable, 1 = enable
316 
317 	si.globalBitmapDesc = mode.timing.h_display | (mode.bpp << 16)
318 		| TILE_FORMAT_LINEAR | BCI_BD_BW_DISABLE | S3_BD64;	// disable block write
319 }
320 
321 
322 static void
323 Savage_Initialize2DEngine(const DisplayModeEx& mode)
324 {
325 	SharedInfo& si = *gInfo.sharedInfo;
326 
327 	WriteCrtcReg(0x40, 0x01);	// enable graphics engine
328 	WriteCrtcReg(0x31, 0x0c);	// turn on 16-bit register access
329 
330 	// Setup plane masks.
331 	WriteReg32(0x8128, ~0);		// enable all write planes
332 	WriteReg32(0x812C, ~0);		// enable all read planes
333 	WriteReg16(0x8134, 0x27);
334 	WriteReg16(0x8136, 0x07);
335 
336 	switch (si.chipType) {
337 		case S3_SAVAGE_3D:
338 		case S3_SAVAGE_MX:
339 
340 			WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0);	// Disable BCI
341 
342 			// Setup BCI command overflow buffer.  0x48c14
343 			// Bits 0-11  = Bits 22-11 of the Command Buffer Offset.
344 			// Bits 12-28 = Total number of entries in the command buffer(Read only).
345 			// Bits 29-31 = COB size index, 111 = 32K entries or 128K bytes
346 			WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobSizeIndex << 29));
347 
348 			// Program shadow status update.
349 			WriteReg32(0x48C10, 0x78207220);
350 
351 			WriteReg32(0x48C0C, 0);
352 			// Enable BCI and command overflow buffer.
353 			WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x0C);
354 			break;
355 
356 		case S3_SAVAGE4:
357 		case S3_PROSAVAGE:
358 		case S3_TWISTER:
359 		case S3_PROSAVAGE_DDR:
360 		case S3_SUPERSAVAGE:
361 
362 			// Some Savage4 and ProSavage chips have coherency problems with
363 			// respect to the Command Overflow Buffer (COB); thus, do not
364 			// enable the COB.
365 
366 			WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0);	// Disable BCI
367 			WriteReg32(0x48C10, 0x00700040);
368 			WriteReg32(0x48C0C, 0);
369 			WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x08);		// enable BCI without COB
370 
371 			break;
372 
373 		case S3_SAVAGE2000:
374 
375 			// Disable BCI.
376 			WriteReg32(0x48C18, 0);
377 			// Setup BCI command overflow buffer.
378 			WriteReg32(0x48C18, (si.cobOffset >> 7) | (si.cobSizeIndex));
379 			// Disable shadow status update.
380 			WriteReg32(0x48A30, 0);
381 			// Enable BCI and command overflow buffer.
382 			WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x00280000);
383 
384 			break;
385 	}
386 
387 	// Use and set global bitmap descriptor.
388 
389 	Savage_SetGBD(mode);
390 }
391 
392 
393 static void
394 Savage_GEReset(const DisplayModeEx& mode)
395 {
396 	gInfo.WaitIdleEmpty();
397 	snooze(10000);
398 
399 	for (int r = 1; r < 10; r++) {
400 		bool bSuccess = false;
401 
402 		WriteCrtcReg(0x66, 0x02, 0x02);
403 		snooze(10000);
404 		WriteCrtcReg(0x66, 0x00, 0x02);
405 		snooze(10000);
406 
407 		gInfo.WaitIdleEmpty();
408 
409 		WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow);
410 
411 		snooze(10000);
412 		switch (gInfo.sharedInfo->chipType) {
413 			case S3_SAVAGE_3D:
414 			case S3_SAVAGE_MX:
415 				bSuccess = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
416 				break;
417 
418 			case S3_SAVAGE4:
419 			case S3_PROSAVAGE:
420 			case S3_PROSAVAGE_DDR:
421 			case S3_TWISTER:
422 			case S3_SUPERSAVAGE:
423 				bSuccess = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
424 				break;
425 
426 			case S3_SAVAGE2000:
427 				bSuccess = (ALT_STATUS_WORD0 & 0x008fffff) == 0;
428 				break;
429 		}
430 
431 		if (bSuccess)
432 			break;
433 
434 		snooze(10000);
435 		TRACE("Savage_GEReset(), restarting S3 graphics engine reset %2d ...\n", r);
436 	}
437 
438 	// At this point, the FIFO is empty and the engine is idle.
439 
440 	WriteReg32(SRC_BASE, 0);
441 	WriteReg32(DEST_BASE, 0);
442 	WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display);
443 	WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display);
444 	WriteReg32(MONO_PAT_0, ~0);
445 	WriteReg32(MONO_PAT_1, ~0);
446 
447 	Savage_SetGBD(mode);
448 }
449 
450 
451 static void
452 Savage_CalcClock(long freq, int min_m,
453 				int min_n1, int max_n1,
454 				int min_n2, int max_n2,
455 				long freq_min, long freq_max,
456 				unsigned int *mdiv, unsigned int *ndiv, unsigned int *r)
457 {
458 	uint8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2;
459 
460 	double ffreq = freq / 1000.0 / BASE_FREQ;
461 	double ffreq_max = freq_max / 1000.0 / BASE_FREQ;
462 	double ffreq_min = freq_min / 1000.0 / BASE_FREQ;
463 
464 	if (ffreq < ffreq_min / (1 << max_n2)) {
465 		TRACE("Savage_CalcClock() invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ);
466 		ffreq = ffreq_min / (1 << max_n2);
467 	}
468 	if (ffreq > ffreq_max / (1 << min_n2)) {
469 		TRACE("Savage_CalcClock() invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ);
470 		ffreq = ffreq_max / (1 << min_n2);
471 	}
472 
473 	// Work out suitable timings.
474 
475 	double best_diff = ffreq;
476 
477 	for (uint8 n2 = min_n2; n2 <= max_n2; n2++) {
478 		for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) {
479 			int m = (int)(ffreq * n1 * (1 << n2) + 0.5);
480 			if (m < min_m + 2 || m > 127 + 2)
481 				continue;
482 
483 			double div = (double)(m) / (double)(n1);
484 			if ((div >= ffreq_min) && (div <= ffreq_max)) {
485 				double diff = ffreq - div / (1 << n2);
486 				if (diff < 0.0)
487 					diff = -diff;
488 				if (diff < best_diff) {
489 					best_diff = diff;
490 					best_m = m;
491 					best_n1 = n1;
492 					best_n2 = n2;
493 				}
494 			}
495 		}
496 	}
497 
498 	*ndiv = best_n1 - 2;
499 	*r = best_n2;
500 	*mdiv = best_m - 2;
501 }
502 
503 
504 static void
505 Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec)
506 {
507 	TRACE("Savage_WriteMode() begin\n");
508 
509 	SharedInfo& si = *gInfo.sharedInfo;
510 
511 	gInfo.WaitIdleEmpty();
512 
513 	WriteMiscOutReg(0x23);
514 	WriteCrtcReg(0x38, 0x48);		// unlock sys regs CR20~CR3F
515 	WriteCrtcReg(0x39, 0xa0);		// unlock sys regs CR40~CRFF
516 	WriteSeqReg(0x08, 0x06);		// unlock sequencer regs SR09~SRFF
517 
518 	if ( ! S3_SAVAGE_MOBILE_SERIES(si.chipType))
519 		Savage_Initialize2DEngine(mode);
520 
521 	if (ReadCrtcReg(0x66) & 0x01) {
522 		Savage_GEReset(mode);	// reset GE to make sure nothing is going on
523 	}
524 
525 	WriteCrtcReg(0x67, regRec.CR67 & ~0x0e); // no STREAMS yet old and new
526 
527 	// Set register SR19 to zero so that the ProSavage chips will start up
528 	// when booting under BeOS using the default boot screen.
529 
530 	if (si.chipType == S3_PROSAVAGE || si.chipType == S3_TWISTER)
531 		WriteSeqReg(0x19, 0);
532 
533 	// Clear bit 3 in SR30 so that Savage MX chip will startup.  If bit 3 is
534 	// not cleared, it will startup only if booting under BeOS using the
535 	// default boot screen or the boot screen resolution matches the resolution
536 	// of the mode currently being set.
537 
538 	if (si.chipType == S3_SAVAGE_MX)
539 		WriteSeqReg(0x30, 0x00, 0x08);
540 
541 	// Set extended regs.
542 
543 	WriteCrtcReg(0x66, regRec.CR66);
544 	WriteCrtcReg(0x3a, regRec.CR3A);
545 	WriteCrtcReg(0x58, regRec.CR58);
546 	WriteCrtcReg(0x53, regRec.CR53 & 0x7f);
547 
548 	// If Savage IX/MX or SuperSavage, set SR54 & SR56 to 0x10 so that when
549 	// resolutions are set where the width and/or height is less than the
550 	// native resolution of the attached LCD display, the chip will not expand
551 	// the display to fill the screen.  That is, if a resolution is set to
552 	// 640x480, it will use only 640x480 pixels for the display.  When the chip
553 	// expands the display, text is much less readable.
554 
555 	if (S3_SAVAGE_MOBILE_SERIES(si.chipType)) {
556 		WriteSeqReg(0x54, 0x10);
557 		WriteSeqReg(0x56, 0x10);
558 	}
559 
560 	// Set the standard CRTC vga regs.
561 
562 	WriteCrtcReg(0x11, 0x00, 0x80);		// unlock CRTC reg's 0-7 by clearing bit 7 of cr11
563 
564 	for (int j = 0; j < NUM_ELEMENTS(regRec.CRTC); j++)
565 		WriteCrtcReg(j, regRec.CRTC[j]);
566 
567 	// Setup HSYNC & VSYNC polarity.
568 
569 	uint8 temp = ((ReadMiscOutReg() & 0x3f) | 0x0c);
570 
571 	if (!(mode.timing.flags & B_POSITIVE_HSYNC))
572 		temp |= 0x40;
573 	if (!(mode.timing.flags & B_POSITIVE_VSYNC))
574 		temp |= 0x80;
575 
576 	WriteMiscOutReg(temp);
577 
578 	// Extended mode timing registers.
579 	WriteCrtcReg(0x53, regRec.CR53);
580 	WriteCrtcReg(0x5d, regRec.CR5D);
581 	WriteCrtcReg(0x5e, regRec.CR5E);
582 	WriteCrtcReg(0x3b, regRec.CR3B);
583 	WriteCrtcReg(0x3c, regRec.CR3C);
584 	WriteCrtcReg(0x43, regRec.CR43);
585 	WriteCrtcReg(0x65, regRec.CR65);
586 
587 	// Restore the desired video mode with cr67.
588 	WriteCrtcReg(0x67, regRec.CR67 & ~0x0e);	// no streams for new and old streams engines
589 
590 	// Other mode timing and extended regs.
591 	WriteCrtcReg(0x34, regRec.CR34);
592 	WriteCrtcReg(0x42, regRec.CR42);
593 	WriteCrtcReg(0x45, regRec.CR45);
594 	WriteCrtcReg(0x50, regRec.CR50);
595 	WriteCrtcReg(0x51, regRec.CR51);
596 
597 	// Memory timings.
598 	VerticalRetraceWait();
599 	WriteCrtcReg(0x69, regRec.CR69);
600 
601 	WriteCrtcReg(0x33, regRec.CR33);
602 	WriteCrtcReg(0x86, regRec.CR86);
603 	WriteCrtcReg(0x88, regRec.CR88);
604 	WriteCrtcReg(0x90, regRec.CR90);
605 	WriteCrtcReg(0x91, regRec.CR91);
606 
607 	if (si.chipType == S3_SAVAGE4)
608 		WriteCrtcReg(0xb0, regRec.CRB0);
609 
610 	WriteSeqReg(0x1b, regRec.SR1B);
611 
612 	if ( ! (S3_SAVAGE_MOBILE_SERIES(si.chipType) &&  si.displayType == MT_LCD)) {
613 		// Set extended seq regs for dclk.
614 		WriteSeqReg(0x12, regRec.SR12);
615 		WriteSeqReg(0x13, regRec.SR13);
616 		WriteSeqReg(0x29, regRec.SR29);
617 
618 		// Load new m, n pll values for dclk & mclk.
619 		temp = ReadSeqReg(0x15) & ~0x20;
620 		WriteSeqReg(0x15, temp);
621 		WriteSeqReg(0x15, temp | 0x20);
622 		WriteSeqReg(0x15, temp);
623 		snooze(100);
624 	}
625 
626 	// Now write out cr67 in full, possibly starting STREAMS.
627 	VerticalRetraceWait();
628 	WriteCrtcReg(0x67, regRec.CR67);
629 
630 	uint8 cr66 = ReadCrtcReg(0x66);
631 	WriteCrtcReg(0x66, cr66 | 0x80);
632 	uint8 cr3a = ReadCrtcReg(0x3a);
633 	WriteCrtcReg(0x3a, cr3a | 0x80);
634 
635 	Savage_GEReset(mode);
636 
637 	WriteCrtcReg(0x66, cr66);
638 	WriteCrtcReg(0x3a, cr3a);
639 
640 	Savage_Initialize2DEngine(mode);
641 
642 	WriteCrtcReg(0x40, 0x01);		// enable graphics engine
643 
644 	Savage_SetGBD(mode);
645 
646 	TRACE("Savage_WriteMode() done\n");
647 
648 	return;
649 }
650 
651 
652 static bool
653 Savage_ModeInit(const DisplayModeEx& mode)
654 {
655 	TRACE("Savage_ModeInit(%dx%d, %d kHz)\n",
656 		mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock);
657 
658 	SharedInfo& si = *gInfo.sharedInfo;
659 	SavageRegRec regRec;
660 
661 	int horizScaleFactor = 1;
662 
663 	if (mode.bpp == 16 && si.chipType == S3_SAVAGE_3D)
664 		horizScaleFactor = 2;
665 
666 	InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC,
667 			regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E);
668 	regRec.CRTC[0x17] = 0xEB;
669 
670 	int dclk = mode.timing.pixel_clock;
671 	regRec.CR67 = 0x00;
672 
673 	switch (mode.bpp) {
674 		case 8:
675 			if ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000))
676 				regRec.CR67 = 0x10;		// 8bpp, 2 pixels/clock
677 			else
678 				regRec.CR67 = 0x00;		// 8bpp, 1 pixel/clock
679 			break;
680 
681 		case 15:
682 			if (S3_SAVAGE_MOBILE_SERIES(si.chipType)
683 				|| ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000)))
684 				regRec.CR67 = 0x30;		// 15bpp, 2 pixel/clock
685 			else
686 				regRec.CR67 = 0x20;		// 15bpp, 1 pixels/clock
687 			break;
688 
689 		case 16:
690 			if (S3_SAVAGE_MOBILE_SERIES(si.chipType)
691 				|| ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000)))
692 				regRec.CR67 = 0x50;		// 16bpp, 2 pixel/clock
693 			else
694 				regRec.CR67 = 0x40;		// 16bpp, 1 pixels/clock
695 			break;
696 
697 		case 32:
698 			regRec.CR67 = 0xd0;
699 			break;
700 	}
701 
702 	regRec.CR3A = (ReadCrtcReg(0x3a) & 0x7f) | 0x15;
703 	regRec.CR53 = 0x00;
704 	regRec.CR66 = 0x89;
705 	regRec.CR58 = (ReadCrtcReg(0x58) & 0x80) | 0x13;
706 
707 	regRec.SR1B = ReadSeqReg(0x1b) | 0x10;	// enable 8-bit Color Lookup Table
708 
709 	regRec.CR43 = regRec.CR45 = regRec.CR65 = 0x00;
710 
711 	unsigned int m, n, r;
712 	Savage_CalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
713 	regRec.SR12 = (r << 6) | (n & 0x3f);
714 	regRec.SR13 = m & 0xff;
715 	regRec.SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
716 
717 	TRACE("CalcClock, m: %d  n: %d  r: %d\n", m, n, r);
718 
719 	regRec.CR42 = 0x00;
720 	regRec.CR34 = 0x10;
721 
722 	int width = mode.bytesPerRow / 8;
723 	regRec.CR91 = 0xff & width;
724 	regRec.CR51 = (0x300 & width) >> 4;
725 	regRec.CR90 = 0x80 | (width >> 8);
726 
727 	// Set frame buffer description.
728 
729 	if (mode.bpp <= 8)
730 		regRec.CR50 = 0;
731 	else if (mode.bpp <= 16)
732 		regRec.CR50 = 0x10;
733 	else
734 		regRec.CR50 = 0x30;
735 
736 	width = mode.timing.h_display;		// width of display in pixels
737 
738 	if (width == 640)
739 		regRec.CR50 |= 0x40;
740 	else if (width == 800)
741 		regRec.CR50 |= 0x80;
742 	else if (width == 1024)
743 		regRec.CR50 |= 0x00;
744 	else if (width == 1152)
745 		regRec.CR50 |= 0x01;
746 	else if (width == 1280)
747 		regRec.CR50 |= 0xc0;
748 	else if (width == 1600)
749 		regRec.CR50 |= 0x81;
750 	else
751 		regRec.CR50 |= 0xc1;	// use GBD
752 
753 	if (S3_SAVAGE_MOBILE_SERIES(si.chipType))
754 		regRec.CR33 = 0x00;
755 	else
756 		regRec.CR33 = 0x08;
757 
758 	regRec.CR69 = 0;
759 	regRec.CR86 = ReadCrtcReg(0x86) | 0x08;
760 	regRec.CR88 = ReadCrtcReg(0x88) | DISABLE_BLOCK_WRITE_2D;
761 	regRec.CRB0 = ReadCrtcReg(0xb0) | 0x80;
762 
763 	Savage_WriteMode(mode, regRec);		// write registers to set mode
764 
765 	return true;
766 }
767 
768 
769 
770 bool
771 Savage_SetDisplayMode(const DisplayModeEx& mode)
772 {
773 	// The code to actually configure the display.
774 	// All the error checking must be done in ProposeDisplayMode(),
775 	// and assume that the mode values we get here are acceptable.
776 
777 	WriteSeqReg(0x01, 0x20, 0x20);		// blank the screen
778 
779 	if ( ! Savage_ModeInit(mode)) {
780 		TRACE("Savage_ModeInit() failed\n");
781 		return false;
782 	}
783 
784 	Savage_AdjustFrame(mode);
785 
786 	WriteSeqReg(0x01, 0x00, 0x20);		// unblank the screen
787 
788 	return true;
789 }
790 
791 
792 
793 void
794 Savage_AdjustFrame(const DisplayModeEx& mode)
795 {
796 	// Adjust start address in frame buffer.
797 
798 	SharedInfo& si = *gInfo.sharedInfo;
799 
800 	int address = (mode.v_display_start * mode.virtual_width)
801 			+ ((mode.h_display_start & ~0x3F) * (mode.bpp / 8));
802 	address &= ~0x1F;
803 	address += si.frameBufferOffset;
804 
805 	switch (si.chipType) {
806 		case S3_SAVAGE_MX:
807 			WriteReg32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC);
808 			WriteReg32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC);
809 			break;
810 		case S3_SUPERSAVAGE:
811 			WriteReg32(PRI_STREAM_FBUF_ADDR0, 0x80000000);
812 			WriteReg32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8);
813 			break;
814 		case S3_SAVAGE2000:
815 			// Certain Y values seems to cause havoc, not sure why
816 			WriteReg32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8));
817 			WriteReg32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8));
818 			break;
819 		default:
820 			WriteReg32(PRI_STREAM_FBUF_ADDR0, address | 0xFFFFFFFC);
821 			WriteReg32(PRI_STREAM_FBUF_ADDR1, address | 0x80000000);
822 			break;
823 	}
824 
825 	return;
826 }
827 
828 
829 void
830 Savage_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
831 {
832 	// Set the indexed color palette for 8-bit color depth mode.
833 
834 	(void)flags;		// avoid compiler warning for unused arg
835 
836 	if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
837 		return ;
838 
839 	while (count--) {
840 		WriteIndexedColor(first++,	// color index
841 			colorData[0],			// red
842 			colorData[1],			// green
843 			colorData[2]);			// blue
844 		colorData += 3;
845 	}
846 }
847