xref: /haiku/src/add-ons/accelerants/s3/savage_init.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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 
20 static bool
21 Savage_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock)
22 {
23 	// Get parameters for a color space which is supported by the Savage chips.
24 	// Argument maxPixelClock is in KHz.
25 	// Return true if the color space is supported;  else return false.
26 
27 	switch (colorSpace) {
28 		case B_RGB32:
29 			bitsPerPixel = 32;
30 			maxPixelClock = 220000;
31 			break;
32 		case B_RGB16:
33 			bitsPerPixel = 16;
34 			maxPixelClock = 250000;
35 			break;
36 		case B_CMAP8:
37 			bitsPerPixel = 8;
38 			maxPixelClock = 250000;
39 			break;
40 		default:
41 			TRACE("Unsupported color space: 0x%X\n", colorSpace);
42 			return false;
43 	}
44 
45 	return true;
46 }
47 
48 
49 // Wait until "v" queue entries are free.
50 
51 static void
52 WaitQueue3D(uint32 v)
53 {
54 	uint32 slots = MAXFIFO - v;
55 	while ((STATUS_WORD0 & 0x0000ffff) > slots);
56 }
57 
58 
59 static void
60 WaitQueue4(uint32 v)
61 {
62 	uint32 slots = MAXFIFO - v;
63 	while ((ALT_STATUS_WORD0 & 0x001fffff) > slots);
64 }
65 
66 
67 static void
68 WaitQueue2K(uint32 v)
69 {
70 	uint32 slots = MAXFIFO - v;
71 	while ((ALT_STATUS_WORD0 & 0x000fffff) > slots);
72 }
73 
74 
75 // Wait until GP is idle and queue is empty.
76 
77 static void
78 WaitIdleEmpty3D()
79 {
80 	while ((STATUS_WORD0 & 0x0008ffff) != 0x80000);
81 }
82 
83 
84 static void
85 WaitIdleEmpty4()
86 {
87 	while ((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) ;
88 }
89 
90 
91 static void
92 WaitIdleEmpty2K()
93 {
94 	while ((ALT_STATUS_WORD0 & 0x009fffff) != 0);
95 }
96 
97 
98 static bool
99 IsLCDWidthValid(int width)
100 {
101 	// Search the array of valid LCD widths to find a width that matches the
102 	// width by the caller, and return true if a match is found.
103 
104 	const int lcdWidths[] = { 640, 800, 1024, 1152, 1280, 1400, 1440, 1600, 1680 };
105 
106 	for (int i = 0; i < NUM_ELEMENTS(lcdWidths); i++) {
107 		if (lcdWidths[i] == width)
108 			return true;
109 	}
110 
111 	return false;		// match not found
112 }
113 
114 
115 static void
116 Savage_GetPanelInfo()
117 {
118 	SharedInfo& si = *gInfo.sharedInfo;
119 
120 	enum ACTIVE_DISPLAYS {		// these are the bits in CR6B
121 		ActiveCRT = 0x01,
122 		ActiveLCD = 0x02,
123 		ActiveTV	= 0x04,
124 		ActiveCRT2 = 0x20,
125 		ActiveDUO = 0x80
126 	};
127 
128 	// Check LCD panel information.
129 
130 	uint8 cr6b = ReadCrtcReg(0x6b);
131 
132 	int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8;
133 	int panelY =  ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1;
134 
135 	if ( ! IsLCDWidthValid(panelX)) {
136 
137 		// Some chips such as the Savage IX/MV in a Thinkpad T-22 will return
138 		// a width that is 8 pixels too wide probably because reg SR61 is set
139 		// to a value +1 higher than it should be.  Subtract 8 from the width,
140 		// and check if that is a valid width.
141 
142 		panelX -= 8;
143 		if ( ! IsLCDWidthValid(panelX)) {
144 			TRACE("%dx%d LCD panel width invalid.\n", panelX + 8, panelY);
145 			si.displayType = MT_CRT;
146 			return;
147 		}
148 	}
149 
150 	char* sTechnology;
151 
152 	if ((ReadSeqReg(0x39) & 0x03) == 0)
153 		sTechnology = "TFT";
154 	else if ((ReadSeqReg(0x30) & 0x01) == 0)
155 		sTechnology = "DSTN";
156 	else
157 		sTechnology = "STN";
158 
159 	TRACE("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology,
160 			 cr6b & ActiveLCD ? "and active" : "but not active");
161 
162 	if (cr6b & ActiveLCD) {
163 		TRACE("Limiting max video mode to %dx%d\n", panelX, panelY);
164 		si.panelX = panelX;
165 		si.panelY = panelY;
166 	} else {
167 		si.displayType = MT_CRT;
168 	}
169 }
170 
171 
172 status_t
173 Savage_Init(void)
174 {
175 	TRACE("Savage_Init()\n");
176 
177 	SharedInfo& si = *gInfo.sharedInfo;
178 
179 	// MMIO should be automatically enabled for Savage chips;  thus, use MMIO
180 	// to enable VGA and turn color on.
181 
182 	WriteReg8(VGA_ENABLE + 0x8000, ReadReg8(VGA_ENABLE + 0x8000) | 0x01);
183 	WriteMiscOutReg(ReadMiscOutReg() | 0x01);		// turn color on
184 
185 	if (si.chipType >= S3_SAVAGE4)
186 		WriteCrtcReg(0x40, 0x01, 0x01);
187 
188 	WriteCrtcReg(0x11, 0x00, 0x80);	// unlock CRTC reg's 0-7 by clearing bit 7 of cr11
189 	WriteCrtcReg(0x38, 0x48);		// unlock sys regs CR20~CR3F
190 	WriteCrtcReg(0x39, 0xa0);		// unlock sys regs CR40~CRFF
191 	WriteSeqReg(0x08, 0x06);		// unlock sequencer regs SR09~SRFF
192 
193 	WriteCrtcReg(0x40, 0x00, 0x01);
194 	WriteCrtcReg(0x38, 0x48);		// unlock sys regs CR20~CR3F
195 
196 	// Compute the amount of video memory and offscreen memory.
197 
198 	static const uint8 RamSavage3D[] = { 8, 4, 4, 2 };
199 	static		 uint8 RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
200 	static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
201 	static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
202 	int ramSizeMB = 0;		// memory size in megabytes
203 
204 	uint8 cr36 = ReadCrtcReg(0x36);		// get amount of video ram
205 
206 	switch (si.chipType) {
207 		case S3_SAVAGE_3D:
208 			ramSizeMB = RamSavage3D[ (cr36 & 0xC0) >> 6 ];
209 			break;
210 
211 		case S3_SAVAGE4:
212 			// The Savage4 has one ugly special case to consider.  On
213 			// systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
214 			// when it really means 8MB.	Why do it the same when you
215 			// can do it different...
216 			if ((ReadCrtcReg(0x68) & 0xC0) == (0x01 << 6))
217 				RamSavage4[1] = 8;
218 
219 			// FALL THROUGH
220 
221 		case S3_SAVAGE2000:
222 			ramSizeMB = RamSavage4[ (cr36 & 0xE0) >> 5 ];
223 			break;
224 
225 		case S3_SAVAGE_MX:
226 		case S3_SUPERSAVAGE:
227 			ramSizeMB = RamSavageMX[ (cr36 & 0x0E) >> 1 ];
228 			break;
229 
230 		case S3_PROSAVAGE:
231 		case S3_PROSAVAGE_DDR:
232 		case S3_TWISTER:
233 			ramSizeMB = RamSavageNB[ (cr36 & 0xE0) >> 5 ];
234 			break;
235 
236 		default:
237 			// How did we get here?
238 			ramSizeMB = 0;
239 			break;
240 	}
241 
242 	TRACE("Savage_Init() memory size: %d MB\n", ramSizeMB);
243 
244 	if (ramSizeMB <= 0)
245 		return B_ERROR;
246 
247 	si.videoMemSize = ramSizeMB * 1024 * 1024;
248 
249 
250 	// Certain Savage4 and ProSavage chips can have coherency problems
251 	// with respect to the Command Overflow Buffer (COB);	thus, to avoid
252 	// problems with these chips, set bDisableCOB to true.
253 
254 	si.bDisableCOB = false;
255 
256 	// Compute the Command Overflow Buffer (COB) location.
257 
258 	if ((S3_SAVAGE4_SERIES(si.chipType) || S3_SUPERSAVAGE == si.chipType)
259 		&& si.bDisableCOB) {
260 
261 		// The Savage4 and ProSavage have COB coherency bugs which render
262 		// the buffer useless.
263 
264 		si.cobIndex = 0;
265 		si.cobSize = 0;
266 		si.bciThresholdHi = 32;
267 		si.bciThresholdLo = 0;
268 	} else {
269 		// We use 128kB for the COB on all other chips.
270 		si.cobSize = 0x20000;
271 		if (S3_SAVAGE_3D_SERIES(si.chipType) || si.chipType == S3_SAVAGE2000)
272 			si.cobIndex = 7;	// rev.A savage4 apparently also uses 7
273 		else
274 			si.cobIndex = 2;
275 
276 		// Max command size: 2560 entries.
277 		si.bciThresholdHi = si.cobSize / 4 + 32 - 2560;
278 		si.bciThresholdLo = si.bciThresholdHi - 2560;
279 	}
280 
281 	// Note that the X.org developers stated that the command overflow buffer
282 	// (COB) must END at a 4MB boundary which for all practical purposes means
283 	// the very end of the video memory.  The cursor must be at the beginning
284 	// of the video memory.  It had been tried immediately preceding the COB,
285 	// but the Savage MX chip screws up the cursor in that case.
286 
287 	si.cobOffset = (si.videoMemSize - si.cobSize) & ~0x1ffff;	// align cob to 128k
288 	si.cursorOffset = 0;
289 	si.frameBufferOffset = si.cursorOffset + CURSOR_BYTES;
290 	si.maxFrameBufferSize = si.cobOffset - si.frameBufferOffset;
291 
292 	TRACE("cobIndex: %d	cobSize: %d  cobOffset: 0x%x\n", si.cobIndex, si.cobSize, si.cobOffset);
293 	TRACE("cursorOffset: 0x%x  frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset);
294 
295 	// Reset graphics engine to avoid memory corruption.
296 
297 	WriteCrtcReg(0x66, 0x02, 0x02);		// set reset flag
298 	snooze(10000);
299 	WriteCrtcReg(0x66, 0x00, 0x02);		// clear reset flag
300 	snooze(10000);
301 
302 	// Check for DVI/flat panel.
303 
304 	bool bDvi = false;
305 	if (si.chipType == S3_SAVAGE4) {
306 		WriteSeqReg(0x30, 0x00, 0x02);		// clear bit 1
307 		if (ReadSeqReg(0x30) & 0x02 /* 0x04 */) {
308 			 bDvi = true;
309 			 TRACE("Digital Flat Panel Detected\n");
310 		}
311 	}
312 
313 	if (S3_SAVAGE_MOBILE_SERIES(si.chipType) || S3_MOBILE_TWISTER_SERIES(si.chipType)) {
314 		si.displayType = MT_LCD;
315 		Savage_GetPanelInfo();
316 	}
317 	else if (bDvi)
318 		si.displayType = MT_DFP;
319 	else
320 		si.displayType = MT_CRT;
321 
322 	TRACE("Display Type: %d\n", si.displayType);
323 
324 	// Detect current mclk.
325 
326 	WriteSeqReg(0x08, 0x06);		// unlock extended sequencer regs
327 
328 	uint8 m = ReadSeqReg(0x11) & 0x7f;
329 	uint8 n = ReadSeqReg(0x10);
330 	uint8 n1 = n & 0x1f;
331 	uint8 n2 = (n >> 5) & 0x03;
332 	si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
333 
334 	TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0);
335 
336 	// Set up the array of color spaces supported by the Savage chips.
337 
338 	si.colorSpaces[0] = B_CMAP8;
339 	si.colorSpaces[1] = B_RGB16;
340 	si.colorSpaces[2] = B_RGB32;
341 	si.colorSpaceCount = 3;
342 
343 	// Get info about the display capabilities (EDID).
344 
345 	Savage_GetEdidInfo();
346 
347 	// Setup the mode list.
348 
349 	return CreateModeList(IsModeUsable);
350 }
351 
352 
353 void
354 Savage_SetFunctionPointers(void)
355 {
356 	// Setting the function pointers must be done prior to first ModeInit call
357 	// or any accel activity.
358 
359 	switch (gInfo.sharedInfo->chipType) {
360 		case S3_SAVAGE_3D:
361 		case S3_SAVAGE_MX:
362 			 gInfo.WaitQueue		= WaitQueue3D;
363 			 gInfo.WaitIdleEmpty	= WaitIdleEmpty3D;
364 			 break;
365 
366 		case S3_SAVAGE4:
367 		case S3_PROSAVAGE:
368 		case S3_SUPERSAVAGE:
369 		case S3_PROSAVAGE_DDR:
370 		case S3_TWISTER:
371 			 gInfo.WaitQueue		= WaitQueue4;
372 			 gInfo.WaitIdleEmpty	= WaitIdleEmpty4;
373 			 break;
374 
375 		case S3_SAVAGE2000:
376 			 gInfo.WaitQueue		= WaitQueue2K;
377 			 gInfo.WaitIdleEmpty	= WaitIdleEmpty2K;
378 			 break;
379 	}
380 
381 	gInfo.DPMSCapabilities = Savage_DPMSCapabilities;
382 	gInfo.DPMSMode = Savage_DPMSMode;
383 	gInfo.SetDPMSMode = Savage_SetDPMSMode;
384 
385 	gInfo.LoadCursorImage = Savage_LoadCursorImage;
386 	gInfo.SetCursorPosition = Savage_SetCursorPosition;
387 	gInfo.ShowCursor = Savage_ShowCursor;
388 
389 	gInfo.FillRectangle = Savage_FillRectangle;
390 	gInfo.FillSpan = Savage_FillSpan;
391 	gInfo.InvertRectangle = Savage_InvertRectangle;
392 	gInfo.ScreenToScreenBlit = Savage_ScreenToScreenBlit;
393 
394 	gInfo.AdjustFrame = Savage_AdjustFrame;
395 	gInfo.ChipInit = Savage_Init;
396 	gInfo.GetColorSpaceParams = Savage_GetColorSpaceParams;
397 	gInfo.SetDisplayMode = Savage_SetDisplayMode;
398 	gInfo.SetIndexedColors = Savage_SetIndexedColors;
399 }
400 
401