xref: /haiku/src/add-ons/accelerants/s3/savage_mode.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
1 /*
2 	Haiku S3 Savage driver adapted from the X.org Savage driver.
3 
4 	Copyright 1995-1997 The XFree86 Project, Inc.
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 2006-2008
11 */
12 
13 
14 #include "accel.h"
15 #include "savage.h"
16 
17 
18 #define BASE_FREQ	14.31818
19 
20 
21 struct SavageRegRec {
22 	uint8  CRTC[25];			// Crtc Controller reg's
23 
24 	uint8  SR12, SR13, SR15, SR18, SR1B, SR29;
25 	uint8  CR31, CR33, CR34, CR3A, CR3B, CR3C;
26 	uint8  CR40, CR42, CR43, CR45;
27 	uint8  CR50, CR51, CR53, CR58, CR5D, CR5E;
28 	uint8  CR65, CR66, CR67, CR69;
29 	uint8  CR86, CR88;
30 	uint8  CR90, CR91, CRB0;
31 };
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 	TRACE("Savage_SetGBD_Twister()\n");
43 
44 	if (si.chipType == S3_SAVAGE4)
45 		bci_enable = BCI_ENABLE;
46 	else
47 		bci_enable = BCI_ENABLE_TWISTER;
48 
49 	// MM81C0 and 81C4 are used to control primary stream.
50 	WriteReg32(PRI_STREAM_FBUF_ADDR0, 0);
51 	WriteReg32(PRI_STREAM_FBUF_ADDR1, 0);
52 
53 	// Program Primary Stream Stride Register.
54 	//
55 	// Tell engine if tiling on or off, set primary stream stride, and
56 	// if tiling, set tiling bits/pixel and primary stream tile offset.
57 	// Note that tile offset (bits 16 - 29) must be scanline width in
58 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
59 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
60 	// bytes padded up to an even number of tilewidths.
61 
62 	WriteReg32(PRI_STREAM_STRIDE,
63 		(((mode.bytesPerRow * 2) << 16) & 0x3FFFE000) |
64 		(mode.bytesPerRow & 0x00001fff));
65 
66 	//  CR69, bit 7 = 1
67 	//  to use MM streams processor registers to control primary stream.
68 
69 	WriteCrtcReg(0x69, 0x80, 0x80);
70 
71 	WriteReg32(0x8128, 0xFFFFFFFFL);
72 	WriteReg32(0x812C, 0xFFFFFFFFL);
73 
74 	WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
75 
76 	WriteCrtcReg(0x50, 0xc1, 0xc1);		// CR50, bit 7,6,0 = 111, Use GBD
77 
78 	// If MS1NB style linear tiling mode.
79 	// bit MM850C[15] = 0 select NB linear tile mode.
80 	// bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode.
81 
82 	uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000;	// use MS-s style tile mode
83 	WriteReg32(ADVANCED_FUNC_CTRL, ulTmp);
84 
85 	// Set up Tiled Surface Registers
86 	//  Bit 25:20 - Surface width in tiles.
87 	//  Bit 29 - Y Range Flag.
88 	//  Bit 31:30	= 00, 4 bpp.
89 	// 				= 01, 8 bpp.
90 	// 				= 10, 16 bpp.
91 	// 				= 11, 32 bpp.
92 
93 	// Global Bitmap Descriptor Register MM816C - twister/prosavage
94 	//	bit 24~25: tile format
95 	//		00: linear
96 	//		01: destination tiling format
97 	//		10: texture tiling format
98 	//		11: reserved
99 	//	bit 28: block write disble/enable
100 	//		0: disable
101 	//		1: enable
102 
103 	// Global Bitmap Descriptor Register MM816C - savage4
104 	//	bit 24~25: tile format
105 	//		00: linear
106 	//		01: reserved
107 	//		10: 16 bpp tiles
108 	//		11: 32 bpp tiles
109 	//	bit 28: block write disable/enable
110 	//		0: enable
111 	//		1: disable
112 
113 	//  Do not enable block_write even for non-tiling modes, because
114 	//  the driver cannot determine if the memory type is the certain
115 	//  type of SGRAM for which block_write can be used.
116 
117 	si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR;	// linear
118 	si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10;		// disable block write
119 	// HW uses width.
120 	si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display);	// number of pixels per line
121 	si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp);
122 	si.GlobalBD.bd1.Offset = si.frameBufferOffset;
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 	// CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
133 	//		 bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
134 	//					at A000:0.
135 
136 	WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01);
137 
138 	// Program the GBD and SBD's.
139 
140 	WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart);
141 	WriteReg32(S3_GLB_BD_HIGH, si.GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
142 	WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart);
143 	WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart);
144 }
145 
146 
147 static void
148 Savage_SetGBD_3D(const DisplayModeEx& mode)
149 {
150 	TRACE("Savage_SetGBD_3D()\n");
151 
152 	SharedInfo& si = *gInfo.sharedInfo;
153 	int bci_enable = BCI_ENABLE;
154 
155 	// MM81C0 and 81C4 are used to control primary stream.
156 	WriteReg32(PRI_STREAM_FBUF_ADDR0, 0);
157 	WriteReg32(PRI_STREAM_FBUF_ADDR1, 0);
158 
159 	// Program Primary Stream Stride Register.
160 	//
161 	// Tell engine if tiling on or off, set primary stream stride, and
162 	// if tiling, set tiling bits/pixel and primary stream tile offset.
163 	// Note that tile offset (bits 16 - 29) must be scanline width in
164 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
165 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
166 	// bytes padded up to an even number of tilewidths.
167 
168 	WriteReg32(PRI_STREAM_STRIDE,
169 		(((mode.bytesPerRow * 2) << 16) & 0x3FFFE000) |
170 		(mode.bytesPerRow & 0x00001fff));
171 
172 	// CR69, bit 7 = 1 to use MM streams processor registers to control primary
173 	// stream.
174 
175 	WriteCrtcReg(0x69, 0x80, 0x80);
176 
177 	WriteReg32(0x8128, 0xFFFFFFFFL);
178 	WriteReg32(0x812C, 0xFFFFFFFFL);
179 
180 	WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
181 
182 	WriteCrtcReg(0x50, 0xc1, 0xc1);		// CR50, bit 7,6,0 = 111, Use GBD
183 
184 	// If MS1NB style linear tiling mode.
185 	// bit MM850C[15] = 0 select NB linear tile mode.
186 	// bit MM850C[15] = 1 select MS-1 128-bit non-linear tile mode.
187 
188 	uint32 ulTmp = ReadReg32(ADVANCED_FUNC_CTRL) | 0x8000;	// use MS-s style tile mode
189 	WriteReg32(ADVANCED_FUNC_CTRL, ulTmp);
190 
191 	// Tiled Surface 0 Registers MM48C40:
192 	//	bit 0~23: tile surface 0 frame buffer offset
193 	//	bit 24~29:tile surface 0 width
194 	//	bit 30~31:tile surface 0 bits/pixel
195 	//		00: reserved
196 	//		01, 8 bits
197 	//		10, 16 Bits.
198 	//		11, 32 Bits.
199 
200 	// Global Bitmap Descriptor Register MM816C
201 	//	bit 24~25: tile format
202 	//		00: linear
203 	//		01: reserved
204 	//		10: 16 bpp tiles
205 	//		11: 32 bpp tiles
206 	//	bit 28: block write disable/enable
207 	//		 0: enable
208 	//		 1: disable
209 
210 	// Do not enable block_write even for non-tiling modes, because
211 	// the driver cannot determine if the memory type is the certain
212 	// type of SGRAM for which block_write can be used.
213 
214 	si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR;	// linear
215 	si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10;		// disable block write
216 	// HW uses width.
217 	si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display);	// number of pixels per line
218 	si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp);
219 	si.GlobalBD.bd1.Offset = si.frameBufferOffset;
220 
221 	// CR88, bit 4 - Block write enabled/disabled.
222 	//
223 	// Note: Block write must be disabled when writing to tiled
224 	//		 memory.  Even when writing to non-tiled memory, block
225 	//		 write should only be enabled for certain types of SGRAM.
226 
227 	WriteCrtcReg(0x88, DISABLE_BLOCK_WRITE_2D, DISABLE_BLOCK_WRITE_2D);
228 
229 	// CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
230 	//		 bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
231 	//					at A000:0.
232 
233 	WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01);
234 
235 	// Program the GBD and SBD's.
236 	WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart);
237 	WriteReg32(S3_GLB_BD_HIGH, si.GlobalBD.bd2.HiPart | bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
238 	WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart);
239 	WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart);
240 }
241 
242 
243 static void
244 Savage_SetGBD_MX(const DisplayModeEx& mode)
245 {
246 	TRACE("Savage_SetGBD_MX()\n");
247 
248 	SharedInfo& si = *gInfo.sharedInfo;
249 	int bci_enable = BCI_ENABLE;
250 
251 	// CR67_3:
252 	//	= 1  stream processor MMIO address and stride register
253 	//		 are used to control the primary stream.
254 	//	= 0  standard VGA address and stride registers
255 	//		 are used to control the primary streams.
256 
257 	WriteCrtcReg(0x67, 0x08, 0x08);
258 	// IGA 2.
259 	WriteSeqReg(0x26, 0x4f);		// select IGA 2 read/writes
260 	WriteCrtcReg(0x67, 0x08, 0x08);
261 	WriteSeqReg(0x26, 0x40);		// select IGA 1
262 
263 	// Set primary stream to bank 0 via reg CRCA.
264 	WriteCrtcReg(MEMORY_CTRL0_REG, 0x00, MEM_PS1 + MEM_PS2);
265 
266 	// MM81C0 and 81C4 are used to control primary stream.
267 	WriteReg32(PRI_STREAM_FBUF_ADDR0,  si.frameBufferOffset & 0x7fffff);
268 	WriteReg32(PRI_STREAM_FBUF_ADDR1,  si.frameBufferOffset & 0x7fffff);
269 	WriteReg32(PRI_STREAM2_FBUF_ADDR0, si.frameBufferOffset & 0x7fffff);
270 	WriteReg32(PRI_STREAM2_FBUF_ADDR1, si.frameBufferOffset & 0x7fffff);
271 
272 	// Program Primary Stream Stride Register.
273 	//
274 	// Tell engine if tiling on or off, set primary stream stride, and
275 	// if tiling, set tiling bits/pixel and primary stream tile offset.
276 	// Note that tile offset (bits 16 - 29) must be scanline width in
277 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
278 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
279 	// bytes padded up to an even number of tilewidths.
280 
281 	WriteReg32(PRI_STREAM_STRIDE,
282 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
283 		(mode.bytesPerRow & 0x00003fff));
284 	WriteReg32(PRI_STREAM2_STRIDE,
285 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
286 		(mode.bytesPerRow & 0x00003fff));
287 
288 	WriteReg32(0x8128, 0xFFFFFFFFL);
289 	WriteReg32(0x812C, 0xFFFFFFFFL);
290 
291 	WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_LITTLE_ENDIAN | S3_BD64);
292 
293 	WriteCrtcReg(0x50, 0xc1, 0xc1);		// CR50, bit 7,6,0 = 111, Use GBD
294 
295 	// CR78, bit 3  - Block write enabled(1)/disabled(0).
296 	//		 bit 2  - Block write cycle time(0:2 cycles,1: 1 cycle)
297 	//	Note:	Block write must be disabled when writing to tiled
298 	//			memory.	Even when writing to non-tiled memory, block
299 	//			write should only be enabled for certain types of SGRAM.
300 
301 	WriteCrtcReg(0x78, 0xfb, 0xfb);
302 
303 	// Tiled Surface 0 Registers MM48C40:
304 	//	bit 0~23: tile surface 0 frame buffer offset
305 	//	bit 24~29:tile surface 0 width
306 	//	bit 30~31:tile surface 0 bits/pixel
307 	//		00: reserved
308 	//		01, 8 bits
309 	//		10, 16 Bits.
310 	//		11, 32 Bits.
311 
312 	// Global Bitmap Descriptor Register MM816C
313 	//	bit 24~25: tile format
314 	//		00: linear
315 	//		01: reserved
316 	//		10: 16 bit
317 	//		11: 32 bit
318 	//	bit 28: block write disble/enable
319 	//		0: enable
320 	//		1: disable
321 
322 	// Do not enable block_write even for non-tiling modes, because
323 	// the driver cannot determine if the memory type is the certain
324 	// type of SGRAM for which block_write can be used.
325 
326 	si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR;	// linear
327 	si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10;		// disable block write
328 	// HW uses width.
329 	si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display);	// number of pixels per line
330 	si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp);
331 	si.GlobalBD.bd1.Offset = si.frameBufferOffset;
332 
333 	// CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
334 	//		 bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
335 	//					at A000:0.
336 
337 	WriteCrtcReg(MEMORY_CONFIG_REG, 0x04, 0x05);	// CR31
338 
339 	// Program the GBD and SBD's.
340 	WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart );
341 	// 8: bci enable.
342 	WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart
343 							  | bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
344 	WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart);
345 	WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart);
346 	WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart);
347 	WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart);
348 }
349 
350 
351 static void
352 Savage_SetGBD_Super(const DisplayModeEx& mode)
353 {
354 	TRACE("Savage_SetGBD_Super()\n");
355 
356 	SharedInfo& si = *gInfo.sharedInfo;
357 	int bci_enable = BCI_ENABLE_TWISTER;
358 
359 	// CR67_3:
360 	//	= 1 stream processor MMIO address and stride register
361 	//		are used to control the primary stream.
362 	//	= 0 standard VGA address and stride registers
363 	//		are used to control the primary streams.
364 
365 	WriteCrtcReg(0x67, 0x08, 0x08);
366 	// IGA 2.
367 	WriteSeqReg(0x26, 0x4f);		// select IGA 2 read/writes
368 	WriteCrtcReg(0x67, 0x08, 0x08);
369 	WriteSeqReg(0x26, 0x40);		// select IGA 1
370 
371 	// Load ps1 active registers as determined by MM81C0/81C4.
372 	// Load ps2 active registers as determined by MM81B0/81B4.
373 
374 	WriteCrtcReg(0x65, 0x03, 0x03);
375 
376 	// Program Primary Stream Stride Register.
377 	//
378 	// Tell engine if tiling on or off, set primary stream stride, and
379 	// if tiling, set tiling bits/pixel and primary stream tile offset.
380 	// Note that tile offset (bits 16 - 29) must be scanline width in
381 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
382 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
383 	// bytes padded up to an even number of tilewidths.
384 
385 	WriteReg32(PRI_STREAM_STRIDE,
386 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
387 		(mode.bytesPerRow & 0x00001fff));
388 	WriteReg32(PRI_STREAM2_STRIDE,
389 		(((mode.bytesPerRow * 2) << 16) & 0x3FFF0000) |
390 		(mode.bytesPerRow & 0x00001fff));
391 
392 	// MM81C0 and 81C4 are used to control primary stream.
393 	WriteReg32(PRI_STREAM_FBUF_ADDR0, si.frameBufferOffset);
394 	WriteReg32(PRI_STREAM_FBUF_ADDR1, 0x80000000);
395 	WriteReg32(PRI_STREAM2_FBUF_ADDR0, (si.frameBufferOffset & 0xfffffffc) | 0x80000000);
396 	WriteReg32(PRI_STREAM2_FBUF_ADDR1, si.frameBufferOffset & 0xfffffffc);
397 
398 	WriteReg32(0x8128, 0xFFFFFFFFL);
399 	WriteReg32(0x812C, 0xFFFFFFFFL);
400 
401 	// Bit 28:block write disable.
402 	WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000);
403 
404 	WriteCrtcReg(0x50, 0xc1, 0xc1);		// CR50, bit 7,6,0 = 111, Use GBD
405 
406 	// Do not enable block_write even for non-tiling modes, because
407 	// the driver cannot determine if the memory type is the certain
408 	// type of SGRAM for which block_write can be used.
409 
410 	si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR;	// linear
411 	si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10;		// disable block write
412 	// HW uses width.
413 	si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display);	// number of pixels per line
414 	si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp);
415 	si.GlobalBD.bd1.Offset = si.frameBufferOffset;
416 
417 	// CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
418 	//		 bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
419 	//					at A000:0.
420 
421 	WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01);
422 
423 	// Program the GBD and SBDs.
424 	WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart );
425 	WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart
426 							  | bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
427 	WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart);
428 	WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart);
429 	WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart);
430 	WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart);
431 }
432 
433 
434 static void
435 Savage_SetGBD_2000(const DisplayModeEx& mode)
436 {
437 	TRACE("Savage_SetGBD_2000()\n");
438 
439 	SharedInfo& si = *gInfo.sharedInfo;
440 	int bci_enable = BCI_ENABLE_TWISTER;
441 
442 	// MM81C0 and 81B0 are used to control primary stream.
443 	WriteReg32(PRI_STREAM_FBUF_ADDR0, si.frameBufferOffset);
444 	WriteReg32(PRI_STREAM2_FBUF_ADDR0, si.frameBufferOffset);
445 
446 	// Program Primary Stream Stride Register.
447 	//
448 	// Tell engine if tiling on or off, set primary stream stride, and
449 	// if tiling, set tiling bits/pixel and primary stream tile offset.
450 	// Note that tile offset (bits 16 - 29) must be scanline width in
451 	// bytes/128bytespertile * 256 Qwords/tile.  This is equivalent to
452 	// lDelta * 2.  Remember that if tiling, lDelta is screenwidth in
453 	// bytes padded up to an even number of tilewidths.
454 
455 	WriteReg32(PRI_STREAM_STRIDE,  ((mode.bytesPerRow << 4) & 0x7ff0));
456 	WriteReg32(PRI_STREAM2_STRIDE, ((mode.bytesPerRow << 4) & 0x7ff0));
457 
458 	// CR67_3:
459 	//	= 1 stream processor MMIO address and stride register
460 	//		are used to control the primary stream.
461 	//	= 0 standard VGA address and stride registers
462 	//		are used to control the primary streams
463 
464 	WriteCrtcReg(0x67, 0x08, 0x08);
465 
466 	WriteReg32(0x8128, 0xFFFFFFFFL);
467 	WriteReg32(0x812C, 0xFFFFFFFFL);
468 
469 	// Bit 28:block write disable.
470 	WriteReg32(S3_GLB_BD_HIGH, bci_enable | S3_BD64 | 0x10000000);
471 
472 	WriteCrtcReg(0x50, 0xc1, 0xc1);		// CR50, bit 7,6,0 = 111, Use GBD
473 	WriteCrtcReg(0x73, 0x00, 0x20);		// CR73 bit 5 = 0 block write disable
474 
475 	// Do not enable block_write even for non-tiling modes, because
476 	// the driver cannot determine if the memory type is the certain
477 	// type of SGRAM for which block_write can be used.
478 
479 	si.GlobalBD.bd1.HighPart.ResBWTile = TILE_FORMAT_LINEAR;	// linear
480 	si.GlobalBD.bd1.HighPart.ResBWTile |= 0x10;		// disable block write
481 	// HW uses width.
482 	si.GlobalBD.bd1.HighPart.Stride = (uint16)(mode.timing.h_display);	// number of pixels per line
483 	si.GlobalBD.bd1.HighPart.Bpp = (uint8)(mode.bpp);
484 	si.GlobalBD.bd1.Offset = si.frameBufferOffset;
485 
486 	// CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
487 	//		 bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
488 	//					at A000:0.
489 
490 	WriteCrtcReg(MEMORY_CONFIG_REG, 0x00, 0x01);
491 
492 	// Program the GBD and SBDs.
493 	WriteReg32(S3_GLB_BD_LOW, si.GlobalBD.bd2.LoPart );
494 	WriteReg32(S3_GLB_BD_HIGH, (si.GlobalBD.bd2.HiPart
495 							  | bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
496 	WriteReg32(S3_PRI_BD_LOW, si.GlobalBD.bd2.LoPart);
497 	WriteReg32(S3_PRI_BD_HIGH, si.GlobalBD.bd2.HiPart);
498 	WriteReg32(S3_SEC_BD_LOW, si.GlobalBD.bd2.LoPart);
499 	WriteReg32(S3_SEC_BD_HIGH, si.GlobalBD.bd2.HiPart);
500 }
501 
502 
503 static void
504 Savage_SetGBD(const DisplayModeEx& mode)
505 {
506 	TRACE("Savage_SetGBD()\n");
507 
508 	VerticalRetraceWait();
509 
510 	switch (gInfo.sharedInfo->chipType) {
511 		case S3_SAVAGE_3D:
512 			Savage_SetGBD_3D(mode);
513 			break;
514 
515 		case S3_SAVAGE_MX:
516 			Savage_SetGBD_MX(mode);
517 			break;
518 
519 		case S3_SAVAGE4:
520 		case S3_PROSAVAGE:
521 		case S3_TWISTER:
522 		case S3_PROSAVAGE_DDR:
523 			Savage_SetGBD_Twister(mode);
524 			break;
525 
526 		case S3_SUPERSAVAGE:
527 			Savage_SetGBD_Super(mode);
528 			break;
529 
530 		case S3_SAVAGE2000:
531 			Savage_SetGBD_2000(mode);
532 			break;
533 	}
534 }
535 
536 
537 static void
538 Savage_Initialize2DEngine(const DisplayModeEx& mode)
539 {
540 	TRACE("Savage_Initialize2DEngine()\n");
541 
542 	SharedInfo& si = *gInfo.sharedInfo;
543 	uint32 thresholds;
544 
545 	WriteCrtcReg(0x40, 0x01);
546 	WriteCrtcReg(0x31, 0x0c);
547 
548 	// Setup plane masks.
549 	WriteReg32(0x8128, ~0);		// enable all write planes
550 	WriteReg32(0x812C, ~0);		// enable all read planes
551 	WriteReg16(0x8134, 0x27);
552 	WriteReg16(0x8136, 0x07);
553 
554 	switch (si.chipType) {
555 		case S3_SAVAGE_3D:
556 		case S3_SAVAGE_MX:
557 
558 			// Disable BCI.
559 			WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0);
560 			// Setup BCI command overflow buffer.
561 			WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobIndex << 29));	// tim
562 			// Program shadow status update.
563 			thresholds = ((si.bciThresholdLo & 0xffff) << 16) |
564 						 (si.bciThresholdHi & 0xffff);
565 			WriteReg32(0x48C10, thresholds);
566 
567 			WriteReg32(0x48C0C, 0);
568 			// Enable BCI and command overflow buffer.
569 			WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x0C);
570 			break;
571 
572 		case S3_SAVAGE4:
573 		case S3_PROSAVAGE:
574 		case S3_TWISTER:
575 		case S3_PROSAVAGE_DDR:
576 		case S3_SUPERSAVAGE:
577 
578 			// Disable BCI.
579 			WriteReg32(0x48C18, ReadReg32(0x48C18) & 0x3FF0);
580 
581 			if ( ! si.bDisableCOB) {
582 				// Setup BCI command overflow buffer.
583 				WriteReg32(0x48C14, (si.cobOffset >> 11) | (si.cobIndex << 29));
584 			}
585 			// Program shadow status update;   AGD: what should this be?
586 			thresholds = ((si.bciThresholdLo & 0x1fffe0) << 11)
587 						| ((si.bciThresholdHi & 0x1fffe0) >> 5);
588 			WriteReg32(0x48C10, thresholds);
589 
590 			WriteReg32(0x48C0C, 0);
591 			if (si.bDisableCOB)
592 				WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x08);		// enable BCI without COB
593 			else
594 				WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x0C);		// enable BCI with COB
595 
596 			break;
597 
598 		case S3_SAVAGE2000:
599 
600 			// Disable BCI.
601 			WriteReg32(0x48C18, 0);
602 			// Setup BCI command overflow buffer.
603 			WriteReg32(0x48C18, (si.cobOffset >> 7) | (si.cobIndex));
604 			// Disable shadow status update.
605 			WriteReg32(0x48A30, 0);
606 			// Enable BCI and command overflow buffer.
607 			WriteReg32(0x48C18, ReadReg32(0x48C18) | 0x00280000 );
608 
609 			break;
610 	}
611 
612 	// Use and set global bitmap descriptor.
613 
614 	// For reasons I do not fully understand yet, on the Savage4, the
615 	// write to the GBD register, MM816C, does not "take" at this time.
616 	// Only the low-order byte is acknowledged, resulting in an incorrect
617 	// stride.  Writing the register later, after the mode switch, works
618 	// correctly.	This needs to get resolved.
619 
620 	Savage_SetGBD(mode);
621 }
622 
623 
624 static void
625 Savage_GEReset(const DisplayModeEx& mode)
626 {
627 	TRACE("Savage_GEReset() begin\n");
628 
629 	gInfo.WaitIdleEmpty();
630 	snooze(10000);
631 
632 	for (int r = 1; r < 10; r++) {
633 		bool bSuccess = false;
634 
635 		WriteCrtcReg(0x66, 0x02, 0x02);
636 		snooze(10000);
637 		WriteCrtcReg(0x66, 0x00, 0x02);
638 		snooze(10000);
639 
640 		gInfo.WaitIdleEmpty();
641 
642 		WriteReg32(DEST_SRC_STR, mode.bytesPerRow << 16 | mode.bytesPerRow);
643 
644 		snooze(10000);
645 		switch (gInfo.sharedInfo->chipType) {
646 			case S3_SAVAGE_3D:
647 			case S3_SAVAGE_MX:
648 				bSuccess = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
649 				break;
650 
651 			case S3_SAVAGE4:
652 			case S3_PROSAVAGE:
653 			case S3_PROSAVAGE_DDR:
654 			case S3_TWISTER:
655 			case S3_SUPERSAVAGE:
656 				bSuccess = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
657 				break;
658 
659 			case S3_SAVAGE2000:
660 				bSuccess = (ALT_STATUS_WORD0 & 0x008fffff) == 0;
661 				break;
662 		}
663 
664 		if (bSuccess)
665 			break;
666 
667 		snooze(10000);
668 		TRACE("Restarting S3 graphics engine reset %2d ...\n", r);
669 	}
670 
671 	// At this point, the FIFO is empty and the engine is idle.
672 
673 	WriteReg32(SRC_BASE, 0);
674 	WriteReg32(DEST_BASE, 0);
675 	WriteReg32(CLIP_L_R, ((0) << 16) | mode.timing.h_display);
676 	WriteReg32(CLIP_T_B, ((0) << 16) | mode.timing.v_display);
677 	WriteReg32(MONO_PAT_0, ~0);
678 	WriteReg32(MONO_PAT_1, ~0);
679 
680 	Savage_SetGBD(mode);
681 
682 	TRACE("Savage_GEReset() end\n");
683 }
684 
685 
686 static void
687 Savage_CalcClock(long freq, int min_m,
688 				int min_n1, int max_n1,
689 				int min_n2, int max_n2,
690 				long freq_min, long freq_max,
691 				unsigned int *mdiv, unsigned int *ndiv, unsigned int *r)
692 {
693 	uint8 best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2;
694 
695 	double ffreq = freq / 1000.0 / BASE_FREQ;
696 	double ffreq_max = freq_max / 1000.0 / BASE_FREQ;
697 	double ffreq_min = freq_min / 1000.0 / BASE_FREQ;
698 
699 	if (ffreq < ffreq_min / (1 << max_n2)) {
700 		TRACE("Savage_CalcClock() invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ);
701 		ffreq = ffreq_min / (1 << max_n2);
702 	}
703 	if (ffreq > ffreq_max / (1 << min_n2)) {
704 		TRACE("Savage_CalcClock() invalid frequency %1.3f Mhz\n", ffreq * BASE_FREQ);
705 		ffreq = ffreq_max / (1 << min_n2);
706 	}
707 
708 	// Work out suitable timings.
709 
710 	double best_diff = ffreq;
711 
712 	for (uint8 n2 = min_n2; n2 <= max_n2; n2++) {
713 		for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) {
714 			int m = (int)(ffreq * n1 * (1 << n2) + 0.5);
715 			if (m < min_m + 2 || m > 127 + 2)
716 				continue;
717 
718 			double div = (double)(m) / (double)(n1);
719 			if ((div >= ffreq_min) && (div <= ffreq_max)) {
720 				double diff = ffreq - div / (1 << n2);
721 				if (diff < 0.0)
722 					diff = -diff;
723 				if (diff < best_diff) {
724 					best_diff = diff;
725 					best_m = m;
726 					best_n1 = n1;
727 					best_n2 = n2;
728 				}
729 			}
730 		}
731 	}
732 
733 	*ndiv = best_n1 - 2;
734 	*r = best_n2;
735 	*mdiv = best_m - 2;
736 }
737 
738 
739 static void
740 Savage_WriteMode(const DisplayModeEx& mode, const SavageRegRec& regRec)
741 {
742 	TRACE("Savage_WriteMode() enter\n");
743 
744 	SharedInfo& si = *gInfo.sharedInfo;
745 
746 	gInfo.WaitIdleEmpty();
747 
748 	WriteMiscOutReg(0x23);
749 	WriteCrtcReg(0x38, 0x48);		// unlock sys regs CR20~CR3F
750 	WriteCrtcReg(0x39, 0xa0);		// unlock sys regs CR40~CRFF
751 	WriteSeqReg(0x08, 0x06);		// unlock sequencer regs SR09~SRFF
752 
753 	if ( ! S3_SAVAGE_MOBILE_SERIES(si.chipType))
754 		Savage_Initialize2DEngine(mode);
755 
756 	if (ReadCrtcReg(0x66) & 0x01) {
757 		Savage_GEReset(mode);	// reset GE to make sure nothing is going on
758 	}
759 
760 	WriteCrtcReg(0x67, regRec.CR67 & ~0x0e); // no STREAMS yet old and new
761 
762 	// Set register SR19 to zero so that the ProSavage chips will start up
763 	// when booting under BeOS using the default boot screen.
764 
765 	if (si.chipType == S3_PROSAVAGE || si.chipType == S3_TWISTER)
766 		WriteSeqReg(0x19, 0);
767 
768 	// Clear bit 3 in SR30 so that Savage MX chip will startup.  If bit 3 is
769 	// not cleared, it will startup only if booting under BeOS using the
770 	// default boot screen or the boot screen resolution matches the resolution
771 	// of the mode currently being set.
772 
773 	if (si.chipType == S3_SAVAGE_MX)
774 		WriteSeqReg(0x30, 0x00, 0x08);
775 
776 	// Set extended regs.
777 
778 	WriteCrtcReg(0x66, regRec.CR66);
779 	WriteCrtcReg(0x3a, regRec.CR3A);
780 	WriteCrtcReg(0x31, regRec.CR31);
781 	WriteCrtcReg(0x58, regRec.CR58);
782 	WriteCrtcReg(0x53, regRec.CR53 & 0x7f);
783 
784 	// Set DCLK registers.
785 
786 	WriteSeqReg(0x29, regRec.SR29);
787 	WriteSeqReg(0x15, regRec.SR15);
788 
789 	// Set the standard CRTC vga regs.
790 
791 	WriteCrtcReg(0x11, 0x00, 0x80);		// unlock CRTC reg's 0-7 by clearing bit 7 of cr11
792 
793 	for (int j = 0; j < NUM_ELEMENTS(regRec.CRTC); j++)
794 		WriteCrtcReg(j, regRec.CRTC[j]);
795 
796 	// Setup HSYNC & VSYNC polarity.
797 
798 	uint8 temp = ((ReadMiscOutReg() & 0x3f) | 0x0c);
799 
800 	if (!(mode.timing.flags & B_POSITIVE_HSYNC))
801 		temp |= 0x40;
802 	if (!(mode.timing.flags & B_POSITIVE_VSYNC))
803 		temp |= 0x80;
804 
805 	WriteMiscOutReg(temp);
806 
807 	// Extended mode timing registers.
808 	WriteCrtcReg(0x53, regRec.CR53);
809 	WriteCrtcReg(0x5d, regRec.CR5D);
810 	WriteCrtcReg(0x5e, regRec.CR5E);
811 	WriteCrtcReg(0x3b, regRec.CR3B);
812 	WriteCrtcReg(0x3c, regRec.CR3C);
813 	WriteCrtcReg(0x43, regRec.CR43);
814 	WriteCrtcReg(0x65, regRec.CR65);
815 
816 	// Restore the desired video mode with cr67.
817 	WriteCrtcReg(0x67, regRec.CR67 & ~0x0e);	// no streams for new and old streams engines
818 
819 	// Other mode timing and extended regs.
820 	WriteCrtcReg(0x34, regRec.CR34);
821 	WriteCrtcReg(0x40, regRec.CR40);
822 	WriteCrtcReg(0x42, regRec.CR42);
823 	WriteCrtcReg(0x45, regRec.CR45);
824 	WriteCrtcReg(0x50, regRec.CR50);
825 	WriteCrtcReg(0x51, regRec.CR51);
826 
827 	// Memory timings.
828 	VerticalRetraceWait();
829 	WriteCrtcReg(0x69, regRec.CR69);
830 
831 	WriteCrtcReg(0x33, regRec.CR33);
832 	WriteCrtcReg(0x86, regRec.CR86);
833 	WriteCrtcReg(0x88, regRec.CR88);
834 	WriteCrtcReg(0x90, regRec.CR90);
835 	WriteCrtcReg(0x91, regRec.CR91);
836 
837 	if (si.chipType == S3_SAVAGE4)
838 		WriteCrtcReg(0xb0, regRec.CRB0);
839 
840 	// Set extended seq regs for dclk.
841 	WriteSeqReg(0x12, regRec.SR12);
842 	WriteSeqReg(0x13, regRec.SR13);
843 	WriteSeqReg(0x29, regRec.SR29);
844 
845 	WriteSeqReg(0x18, regRec.SR18);
846 	WriteSeqReg(0x1b, regRec.SR1B);
847 
848 	// Load new m, n pll values for dclk & mclk.
849 	temp = ReadSeqReg(0x15) & ~0x21;
850 
851 	WriteSeqReg(0x15, temp | 0x03);
852 	WriteSeqReg(0x15, temp | 0x23);
853 	WriteSeqReg(0x15, temp | 0x03);
854 	WriteSeqReg(0x15, regRec.SR15);
855 	snooze( 100 );
856 
857 	// Now write out cr67 in full, possibly starting STREAMS.
858 	VerticalRetraceWait();
859 	WriteCrtcReg(0x67, regRec.CR67);
860 
861 	uint8 cr66 = ReadCrtcReg(0x66);
862 	WriteCrtcReg(0x66, cr66 | 0x80);
863 	uint8 cr3a = ReadCrtcReg(0x3a);
864 	WriteCrtcReg(0x3a, cr3a | 0x80);
865 
866 	Savage_GEReset(mode);
867 
868 	WriteCrtcReg(0x66, cr66);
869 	WriteCrtcReg(0x3a, cr3a);
870 
871 	Savage_Initialize2DEngine(mode);
872 
873 	WriteCrtcReg(0x40, 0x01);		// enable graphics engine
874 
875 	Savage_SetGBD(mode);
876 
877 	TRACE("Savage_WriteMode() end\n");
878 
879 	return;
880 }
881 
882 
883 static bool
884 Savage_ModeInit(const DisplayModeEx& mode)
885 {
886 	TRACE("Savage_ModeInit(%dx%d, %dHz)\n",
887 		mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock);
888 
889 	SharedInfo& si = *gInfo.sharedInfo;
890 	SavageRegRec regRec;
891 
892 	int horizScaleFactor = 1;
893 
894 	if (mode.bpp == 16 && si.chipType == S3_SAVAGE_3D)
895 		horizScaleFactor = 2;
896 
897 	InitCrtcTimingValues(mode, horizScaleFactor, regRec.CRTC,
898 			regRec.CR3B, regRec.CR3C, regRec.CR5D, regRec.CR5E);
899 	regRec.CRTC[23] = 0xEB;
900 
901 	int dclk = mode.timing.pixel_clock;
902 	regRec.CR67 = 0x00;
903 
904 	switch (mode.bpp) {
905 		case 8:
906 			if ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000))
907 				regRec.CR67 = 0x10;		// 8bpp, 2 pixels/clock
908 			else
909 				regRec.CR67 = 0x00;		// 8bpp, 1 pixel/clock
910 			break;
911 
912 		case 15:
913 			if (S3_SAVAGE_MOBILE_SERIES(si.chipType)
914 				|| ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000)))
915 				regRec.CR67 = 0x30;		// 15bpp, 2 pixel/clock
916 			else
917 				regRec.CR67 = 0x20;		// 15bpp, 1 pixels/clock
918 			break;
919 
920 		case 16:
921 			if (S3_SAVAGE_MOBILE_SERIES(si.chipType)
922 				|| ((si.chipType == S3_SAVAGE2000) && (dclk >= 230000)))
923 				regRec.CR67 = 0x50;		// 16bpp, 2 pixel/clock
924 			else
925 				regRec.CR67 = 0x40;		// 16bpp, 1 pixels/clock
926 			break;
927 
928 		case 32:
929 			regRec.CR67 = 0xd0;
930 			break;
931 	}
932 
933 
934 	// Use traditional register-crunching to set mode.
935 
936 	regRec.CR3A = (ReadCrtcReg(0x3a) & 0x7f) | 0x15;
937 	regRec.CR53 = 0x00;
938 	regRec.CR31 = 0x8c;
939 	regRec.CR66 = 0x89;
940 	regRec.CR58 = (ReadCrtcReg(0x58) & 0x80) | 0x13;
941 
942 	if (si.chipType == S3_SAVAGE2000)
943 		regRec.SR15 = 0x02;
944 	else
945 		regRec.SR15 = 0x83;
946 
947 	regRec.SR18 = 0x00;
948 	regRec.SR1B = ReadSeqReg(0x1b) | 0x10;	// enable 8-bit Color Lookup Table
949 
950 	regRec.CR43 = regRec.CR45 = regRec.CR65 = 0x00;
951 	regRec.CR40 = ReadCrtcReg(0x40) & ~0x01;
952 
953 	unsigned int m, n, r;
954 	Savage_CalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
955 	regRec.SR12 = (r << 6) | (n & 0x3f);
956 	regRec.SR13 = m & 0xff;
957 	regRec.SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
958 
959 	TRACE("CalcClock, m: %d  n: %d  r: %d\n", m, n, r);
960 
961 	regRec.CR42 = 0x00;
962 	regRec.CR34 = 0x10;
963 
964 	int width = mode.bytesPerRow / 8;
965 	regRec.CR91 = 0xff & width;
966 	regRec.CR51 = (0x300 & width) >> 4;
967 	regRec.CR90 = 0x80 | (width >> 8);
968 
969 	// Set frame buffer description.
970 
971 	if (mode.bpp <= 8)
972 		regRec.CR50 = 0;
973 	else if (mode.bpp <= 16)
974 		regRec.CR50 = 0x10;
975 	else
976 		regRec.CR50 = 0x30;
977 
978 	width = mode.timing.h_display;		// width of display in pixels
979 
980 	if (width == 640)
981 		regRec.CR50 |= 0x40;
982 	else if (width == 800)
983 		regRec.CR50 |= 0x80;
984 	else if (width == 1024)
985 		regRec.CR50 |= 0x00;
986 	else if (width == 1152)
987 		regRec.CR50 |= 0x01;
988 	else if (width == 1280)
989 		regRec.CR50 |= 0xc0;
990 	else if (width == 1600)
991 		regRec.CR50 |= 0x81;
992 	else
993 		regRec.CR50 |= 0xc1;	// use GBD
994 
995 	if (S3_SAVAGE_MOBILE_SERIES(si.chipType))
996 		regRec.CR33 = 0x00;
997 	else
998 		regRec.CR33 = 0x08;
999 
1000 	regRec.CR67 |= 1;
1001 	regRec.CR69 = 0;
1002 	regRec.CR86 = ReadCrtcReg(0x86) | 0x08;
1003 	regRec.CR88 = ReadCrtcReg(0x88) | DISABLE_BLOCK_WRITE_2D;
1004 	regRec.CRB0 = ReadCrtcReg(0xb0) | 0x80;
1005 
1006 	Savage_WriteMode(mode, regRec);		// write registers to set mode
1007 
1008 	return true;
1009 }
1010 
1011 
1012 
1013 bool
1014 Savage_SetDisplayMode(const DisplayModeEx& mode)
1015 {
1016 	// The code to actually configure the display.
1017 	// All the error checking must be done in ProposeDisplayMode(),
1018 	// and assume that the mode values we get here are acceptable.
1019 
1020 	WriteSeqReg(0x01, 0x20, 0x20);		// blank the screen
1021 
1022 	if ( ! Savage_ModeInit(mode)) {
1023 		TRACE("Savage_ModeInit() failed\n");
1024 		return false;
1025 	}
1026 
1027 	Savage_AdjustFrame(mode);
1028 
1029 	WriteSeqReg(0x01, 0x00, 0x20);		// unblank the screen
1030 	return true;
1031 }
1032 
1033 
1034 
1035 void
1036 Savage_AdjustFrame(const DisplayModeEx& mode)
1037 {
1038 	// Adjust start address in frame buffer.
1039 
1040 	SharedInfo& si = *gInfo.sharedInfo;
1041 
1042 	int address = (mode.v_display_start * mode.virtual_width)
1043 			+ ((mode.h_display_start & ~0x3F) * (mode.bpp / 8));
1044 	address &= ~0x1F;
1045 	address += si.frameBufferOffset;
1046 
1047 	switch (si.chipType) {
1048 		case S3_SAVAGE_MX:
1049 			WriteReg32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC);
1050 			WriteReg32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC);
1051 			break;
1052 		case S3_SUPERSAVAGE:
1053 			WriteReg32(PRI_STREAM_FBUF_ADDR0, 0x80000000);
1054 			WriteReg32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8);
1055 			break;
1056 		case S3_SAVAGE2000:
1057 			// Certain Y values seems to cause havoc, not sure why
1058 			WriteReg32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8));
1059 			WriteReg32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8));
1060 			break;
1061 		default:
1062 			WriteReg32(PRI_STREAM_FBUF_ADDR0, address | 0xFFFFFFFC);
1063 			WriteReg32(PRI_STREAM_FBUF_ADDR1, address | 0x80000000);
1064 			break;
1065 	}
1066 
1067 	return;
1068 }
1069 
1070 
1071 void
1072 Savage_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
1073 {
1074 	// Set the indexed color palette for 8-bit color depth mode.
1075 
1076 	(void)flags;		// avoid compiler warning for unused arg
1077 
1078 	if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
1079 		return ;
1080 
1081 	while (count--) {
1082 		WriteIndexedColor(first++,	// color index
1083 			colorData[0],			// red
1084 			colorData[1],			// green
1085 			colorData[2]);			// blue
1086 		colorData += 3;
1087 	}
1088 }
1089