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
20static bool
21Savage_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
51static void
52WaitQueue3D(uint32 v)
53{
54	uint32 slots = MAXFIFO - v;
55	while ((STATUS_WORD0 & 0x0000ffff) > slots);
56}
57
58
59static void
60WaitQueue4(uint32 v)
61{
62	uint32 slots = MAXFIFO - v;
63	while ((ALT_STATUS_WORD0 & 0x001fffff) > slots);
64}
65
66
67static void
68WaitQueue2K(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
77static void
78WaitIdleEmpty3D()
79{
80	while ((STATUS_WORD0 & 0x0008ffff) != 0x80000);
81}
82
83
84static void
85WaitIdleEmpty4()
86{
87	while ((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) ;
88}
89
90
91static void
92WaitIdleEmpty2K()
93{
94	while ((ALT_STATUS_WORD0 & 0x009fffff) != 0);
95}
96
97
98static void
99Savage_GetPanelInfo()
100{
101	SharedInfo& si = *gInfo.sharedInfo;
102
103	enum ACTIVE_DISPLAYS {		// these are the bits in CR6B
104		ActiveCRT = 0x01,
105		ActiveLCD = 0x02,
106		ActiveTV	= 0x04,
107		ActiveCRT2 = 0x20,
108		ActiveDUO = 0x80
109	};
110
111	// Check LCD panel information.
112
113	uint8 cr6b = ReadCrtcReg(0x6b);
114
115	int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8;
116	int panelY =  ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1;
117
118	// A Savage IX/MV in a Thinkpad T22 or SuperSavage in a Thinkpad T23 with
119	// a 1400x1050 display will return a width of 1408;  thus, in this case,
120	// set the width to the correct value of 1400.
121
122	if (panelX == 1408)
123		panelX = 1400;
124
125	const char* sTechnology;
126
127	if ((ReadSeqReg(0x39) & 0x03) == 0)
128		sTechnology = "TFT";
129	else if ((ReadSeqReg(0x30) & 0x01) == 0)
130		sTechnology = "DSTN";
131	else
132		sTechnology = "STN";
133
134	TRACE("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology,
135			 cr6b & ActiveLCD ? "and active" : "but not active");
136
137	if (cr6b & ActiveLCD) {
138		TRACE("Limiting max video mode to %dx%d\n", panelX, panelY);
139		si.panelX = panelX;
140		si.panelY = panelY;
141	} else {
142		si.displayType = MT_CRT;
143	}
144}
145
146
147status_t
148Savage_Init(void)
149{
150	TRACE("Savage_Init()\n");
151
152	SharedInfo& si = *gInfo.sharedInfo;
153
154	// MMIO should be automatically enabled for Savage chips;  thus, use MMIO
155	// to enable VGA and turn color on.
156
157	WriteReg8(VGA_ENABLE + 0x8000, ReadReg8(VGA_ENABLE + 0x8000) | 0x01);
158	WriteMiscOutReg(ReadMiscOutReg() | 0x01);		// turn color on
159
160	if (si.chipType >= S3_SAVAGE4)
161		WriteCrtcReg(0x40, 0x01, 0x01);
162
163	WriteCrtcReg(0x11, 0x00, 0x80);	// unlock CRTC reg's 0-7 by clearing bit 7 of cr11
164	WriteCrtcReg(0x38, 0x48);		// unlock sys regs CR20~CR3F
165	WriteCrtcReg(0x39, 0xa0);		// unlock sys regs CR40~CRFF
166	WriteSeqReg(0x08, 0x06);		// unlock sequencer regs SR09~SRFF
167
168	WriteCrtcReg(0x40, 0x00, 0x01);
169	WriteCrtcReg(0x38, 0x48);		// unlock sys regs CR20~CR3F
170
171	// Compute the amount of video memory and offscreen memory.
172
173	static const uint8 RamSavage3D[] = { 8, 4, 4, 2 };
174	static		 uint8 RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
175	static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
176	static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
177	uint32 ramSizeMB = 0;		// memory size in megabytes
178
179	uint8 cr36 = ReadCrtcReg(0x36);		// get amount of video ram
180
181	switch (si.chipType) {
182		case S3_SAVAGE_3D:
183			ramSizeMB = RamSavage3D[ (cr36 & 0xC0) >> 6 ];
184			break;
185
186		case S3_SAVAGE4:
187			// The Savage4 has one ugly special case to consider.  On
188			// systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
189			// when it really means 8MB.	Why do it the same when you
190			// can do it different...
191			if ((ReadCrtcReg(0x68) & 0xC0) == (0x01 << 6))
192				RamSavage4[1] = 8;
193
194			// FALL THROUGH
195
196		case S3_SAVAGE2000:
197			ramSizeMB = RamSavage4[ (cr36 & 0xE0) >> 5 ];
198			break;
199
200		case S3_SAVAGE_MX:
201		case S3_SUPERSAVAGE:
202			ramSizeMB = RamSavageMX[ (cr36 & 0x0E) >> 1 ];
203			break;
204
205		case S3_PROSAVAGE:
206		case S3_PROSAVAGE_DDR:
207		case S3_TWISTER:
208			ramSizeMB = RamSavageNB[ (cr36 & 0xE0) >> 5 ];
209			break;
210
211		default:
212			// How did we get here?
213			ramSizeMB = 0;
214			break;
215	}
216
217	uint32 usableMB = ramSizeMB;
218
219
220	// If a Savage MX chip has > 8 MB, clamp it at 8 MB since memory for the
221	// hardware cursor above 8 MB is unusable.
222
223	if (si.chipType == S3_SAVAGE_MX && ramSizeMB > 8)
224		usableMB = 8;
225
226	TRACE("Savage_Init() memory size: %d MB, usable memory: %d MB\n", ramSizeMB, usableMB);
227
228	if (usableMB <= 0)
229		return B_ERROR;
230
231	si.videoMemSize = usableMB * 1024 * 1024;
232
233	// Compute the Command Overflow Buffer (COB) location.
234
235	uint32 cobSize = 0x20000;	// use 128kB for the COB
236	si.cobSizeIndex = 7;
237
238	// Note that the X.org developers stated that the command overflow buffer
239	// (COB) must END at a 4MB boundary which for all practical purposes means
240	// the very end of the video memory.
241
242	si.cobOffset = (si.videoMemSize - cobSize) & ~0x1ffff;	// align cob to 128k
243	si.cursorOffset = (si.cobOffset - CURSOR_BYTES) & ~0xfff;	// align to 4k boundary
244	si.frameBufferOffset = 0;
245	si.maxFrameBufferSize = si.cursorOffset - si.frameBufferOffset;
246
247	TRACE("cobSizeIndex: %d	cobSize: %d  cobOffset: 0x%x\n", si.cobSizeIndex, cobSize, si.cobOffset);
248	TRACE("cursorOffset: 0x%x  frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset);
249
250	// Reset graphics engine to avoid memory corruption.
251
252	WriteCrtcReg(0x66, 0x02, 0x02);		// set reset flag
253	snooze(10000);
254	WriteCrtcReg(0x66, 0x00, 0x02);		// clear reset flag
255	snooze(10000);
256
257	// Check for DVI/flat panel.
258
259	bool bDvi = false;
260	if (si.chipType == S3_SAVAGE4) {
261		WriteSeqReg(0x30, 0x00, 0x02);		// clear bit 1
262		if (ReadSeqReg(0x30) & 0x02 /* 0x04 */) {
263			 bDvi = true;
264			 TRACE("Digital Flat Panel Detected\n");
265		}
266	}
267
268	if (S3_SAVAGE_MOBILE_SERIES(si.chipType) || S3_MOBILE_TWISTER_SERIES(si.chipType)) {
269		si.displayType = MT_LCD;
270		Savage_GetPanelInfo();
271	}
272	else if (bDvi)
273		si.displayType = MT_DFP;
274	else
275		si.displayType = MT_CRT;
276
277	TRACE("Display Type: %d\n", si.displayType);
278
279	// Detect current mclk.
280
281	WriteSeqReg(0x08, 0x06);		// unlock extended sequencer regs
282
283	uint8 m = ReadSeqReg(0x11) & 0x7f;
284	uint8 n = ReadSeqReg(0x10);
285	uint8 n1 = n & 0x1f;
286	uint8 n2 = (n >> 5) & 0x03;
287	si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
288
289	TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0);
290
291	// Set up the array of color spaces supported by the Savage chips.
292
293	si.colorSpaces[0] = B_CMAP8;
294	si.colorSpaces[1] = B_RGB16;
295	si.colorSpaces[2] = B_RGB32;
296	si.colorSpaceCount = 3;
297
298	si.bDisableHdwCursor = false;	// allow use of hardware cursor
299	si.bDisableAccelDraw = false;	// allow use of accelerated drawing functions
300
301	// Setup the mode list.
302
303	return CreateModeList(IsModeUsable, Savage_GetEdidInfo);
304}
305
306
307void
308Savage_SetFunctionPointers(void)
309{
310	// Setting the function pointers must be done prior to first ModeInit call
311	// or any accel activity.
312
313	switch (gInfo.sharedInfo->chipType) {
314		case S3_SAVAGE_3D:
315		case S3_SAVAGE_MX:
316			 gInfo.WaitQueue		= WaitQueue3D;
317			 gInfo.WaitIdleEmpty	= WaitIdleEmpty3D;
318			 break;
319
320		case S3_SAVAGE4:
321		case S3_PROSAVAGE:
322		case S3_SUPERSAVAGE:
323		case S3_PROSAVAGE_DDR:
324		case S3_TWISTER:
325			 gInfo.WaitQueue		= WaitQueue4;
326			 gInfo.WaitIdleEmpty	= WaitIdleEmpty4;
327			 break;
328
329		case S3_SAVAGE2000:
330			 gInfo.WaitQueue		= WaitQueue2K;
331			 gInfo.WaitIdleEmpty	= WaitIdleEmpty2K;
332			 break;
333	}
334
335	gInfo.DPMSCapabilities = Savage_DPMSCapabilities;
336	gInfo.GetDPMSMode = Savage_GetDPMSMode;
337	gInfo.SetDPMSMode = Savage_SetDPMSMode;
338
339	gInfo.LoadCursorImage = Savage_LoadCursorImage;
340	gInfo.SetCursorPosition = Savage_SetCursorPosition;
341	gInfo.ShowCursor = Savage_ShowCursor;
342
343	gInfo.FillRectangle = Savage_FillRectangle;
344	gInfo.FillSpan = Savage_FillSpan;
345	gInfo.InvertRectangle = Savage_InvertRectangle;
346	gInfo.ScreenToScreenBlit = Savage_ScreenToScreenBlit;
347
348	gInfo.AdjustFrame = Savage_AdjustFrame;
349	gInfo.ChipInit = Savage_Init;
350	gInfo.GetColorSpaceParams = Savage_GetColorSpaceParams;
351	gInfo.SetDisplayMode = Savage_SetDisplayMode;
352	gInfo.SetIndexedColors = Savage_SetIndexedColors;
353}
354
355