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
19static void
20VirgeWaitFifoGX2(uint32 slots )
21{
22	while (((ReadReg32(SUBSYS_STAT_REG) >> 9) & 0x60) < slots) {}
23}
24
25
26
27static void
28VirgeWaitFifoMain(uint32 slots )
29{
30	while (((ReadReg32(SUBSYS_STAT_REG) >> 8) & 0x1f) < slots) {}
31}
32
33
34static void
35VirgeWaitIdleEmpty()
36{
37	// Wait until GP is idle and queue is empty.
38
39	if(gInfo.sharedInfo->chipType == S3_TRIO_3D)
40		while ((IN_SUBSYS_STAT() & 0x3f802000 & 0x20002000) != 0x20002000);
41	else
42		while ((IN_SUBSYS_STAT() & 0x3f00) != 0x3000);
43}
44
45
46static bool
47Virge_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock)
48{
49	// Get parameters for a color space which is supported by the Virge chips.
50	// Argument maxPixelClock is in KHz.
51	// Return true if the color space is supported;  else return false.
52
53	// Note that the X.org code set the max clock to 440000 for a Virge VX chip
54	// and 270000 for all other chips.  440000 seems rather high for a chip that
55	// old;  thus, 270000 is used for all chips.
56
57	switch (colorSpace) {
58		case B_RGB16:
59			bitsPerPixel = 16;
60			maxPixelClock = 270000;
61			break;
62		case B_CMAP8:
63			bitsPerPixel = 8;
64			maxPixelClock = 270000;
65			break;
66		default:
67			TRACE("Unsupported color space: 0x%X\n", colorSpace);
68			return false;
69	}
70
71	return true;
72}
73
74
75
76status_t
77Virge_Init(void)
78{
79	TRACE("Virge_Init()\n");
80
81	SharedInfo& si = *gInfo.sharedInfo;
82
83	// Use PIO for following operations since MMIO may not be currently enabled.
84
85	WritePIO_8(VGA_ENABLE, ReadPIO_8(VGA_ENABLE) | 0x01);	// enable VGA
86	WritePIO_8(MISC_OUT_W, ReadPIO_8(MISC_OUT_R) | 0x01);	// enable color
87
88	// Set linear base register to the PCI register value;
89	// some DX chipsets don't seem to do it automatically.
90
91	WritePIO_8(CRTC_INDEX, 0x59);
92	WritePIO_8(CRTC_DATA, (uint8)((uint32)(si.videoMemPCI) >> 24));
93	WritePIO_8(CRTC_INDEX, 0x5A);
94	WritePIO_8(CRTC_DATA, (uint8)((uint32)(si.videoMemPCI) >> 16));
95
96	// Enable MMIO.
97
98	WritePIO_8(CRTC_INDEX, 0x53);
99	WritePIO_8(CRTC_DATA, ReadPIO_8(CRTC_DATA) | 0x8);
100
101	if (si.chipType == S3_TRIO_3D)
102		WriteCrtcReg(0x40, 0x01, 0x01);
103
104	// Detect amount of installed ram.
105
106	uint8 config1 = ReadCrtcReg(0x36);	// get amount of vram installed
107	uint8 config2 = ReadCrtcReg(0x37);	// get amount of off-screen ram
108
109	// Compute the amount of video memory and offscreen memory.
110
111	int   ramOffScreenMB = 0;	// off screen memory size in megabytes
112	int   ramSizeMB = 0;		// memory size in megabytes
113
114	if (si.chipType == S3_VIRGE_VX) {
115		switch ((config2 & 0x60) >> 5) {
116			case 1:
117				ramOffScreenMB = 4;
118				break;
119			case 2:
120				ramOffScreenMB = 2;
121				break;
122		}
123
124		switch ((config1 & 0x60) >> 5) {
125			case 0:
126				ramSizeMB = 2;
127				break;
128			case 1:
129				ramSizeMB = 4;
130				break;
131			case 2:
132				ramSizeMB = 6;
133				break;
134			case 3:
135				ramSizeMB = 8;
136				break;
137		}
138		ramSizeMB -= ramOffScreenMB;
139
140	} else if (si.chipType == S3_TRIO_3D_2X) {
141		switch ((config1 & 0xE0) >> 5) {
142			case 0:   	// 8MB -- only 4MB usable for display/cursor
143				ramSizeMB = 4;
144				ramOffScreenMB = 4;
145				break;
146			case 1:     // 32 bit interface -- yuck
147				TRACE("Undefined video memory size on S3 Trio 3D/2X\n");
148			case 2:
149				ramSizeMB = 4;
150				break;
151			case 6:
152				ramSizeMB = 2;
153				break;
154		}
155	} else if (si.chipType == S3_TRIO_3D) {
156		switch ((config1 & 0xE0) >> 5) {
157			case 0:
158			case 2:
159				ramSizeMB = 4;
160				break;
161			case 4:
162				ramSizeMB = 2;
163				break;
164		}
165	} else if (si.chipType == S3_VIRGE_GX2 || S3_VIRGE_MX_SERIES(si.chipType)) {
166		switch ((config1 & 0xC0) >> 6) {
167			case 1:
168				ramSizeMB = 4;
169				break;
170			case 3:
171				ramSizeMB = 2;
172				break;
173		}
174	} else {
175		switch ((config1 & 0xE0) >> 5) {
176			case 0:
177				ramSizeMB = 4;
178				break;
179			case 4:
180				ramSizeMB = 2;
181				break;
182			case 6:
183				ramSizeMB = 1;
184				break;
185		}
186	}
187
188	TRACE("usable memory: %d MB,  off-screen memory: %d MB\n", ramSizeMB, ramOffScreenMB);
189
190	if (ramSizeMB <= 0)
191		return B_ERROR;
192
193	si.videoMemSize = ramSizeMB * 1024 * 1024;
194	si.cursorOffset = si.videoMemSize - CURSOR_BYTES;	// put cursor at end of video memory
195	si.frameBufferOffset = 0;
196	si.maxFrameBufferSize = si.videoMemSize - CURSOR_BYTES;
197
198	// Detect current mclk.
199
200	WriteSeqReg(0x08, 0x06);		// unlock extended sequencer regs
201
202	uint8 m = ReadSeqReg(0x11) & 0x7f;
203	uint8 n = ReadSeqReg(0x10);
204	uint8 n1 = n & 0x1f;
205	uint8 n2 = (n >> 5) & 0x03;
206	si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
207
208	TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0);
209
210	if (S3_VIRGE_MX_SERIES(si.chipType)) {
211		si.displayType = ((ReadSeqReg(0x31) & 0x10) ? MT_LCD : MT_CRT);
212		si.panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8;
213		si.panelY =  ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1;
214
215		TRACE("%dx%d LCD panel detected %s\n", si.panelX, si.panelY,
216				 si.displayType == MT_LCD ? "and active" : "but not active");
217	} else {
218		si.displayType = MT_CRT;
219		si.panelX = 0;
220		si.panelY = 0;
221	}
222
223	// Set up the array of color spaces supported by the Virge/Trio3D chips.
224
225	si.colorSpaces[0] = B_CMAP8;
226	si.colorSpaces[1] = B_RGB16;
227	si.colorSpaceCount = 2;
228
229	si.bDisableHdwCursor = false;	// allow use of hardware cursor
230	si.bDisableAccelDraw = false;	// allow use of accelerated drawing functions
231
232	// Setup the mode list.
233
234	return CreateModeList(IsModeUsable, Virge_GetEdidInfo);
235}
236
237
238void
239Virge_SetFunctionPointers(void)
240{
241	// Setting the function pointers must be done prior to first ModeInit call
242	// or any accel activity.
243
244	if (S3_VIRGE_GX2_SERIES(gInfo.sharedInfo->chipType)) {
245		gInfo.WaitQueue = VirgeWaitFifoGX2;
246	} else {
247		gInfo.WaitQueue = VirgeWaitFifoMain;
248	}
249
250	gInfo.WaitIdleEmpty = VirgeWaitIdleEmpty;
251
252	gInfo.DPMSCapabilities = Virge_DPMSCapabilities;
253	gInfo.GetDPMSMode = Virge_GetDPMSMode;
254	gInfo.SetDPMSMode = Virge_SetDPMSMode;
255
256	gInfo.LoadCursorImage = Virge_LoadCursorImage;
257	gInfo.SetCursorPosition = Virge_SetCursorPosition;
258	gInfo.ShowCursor = Virge_ShowCursor;
259
260	gInfo.FillRectangle = Virge_FillRectangle;
261	gInfo.FillSpan = Virge_FillSpan;
262	gInfo.InvertRectangle = Virge_InvertRectangle;
263	gInfo.ScreenToScreenBlit = Virge_ScreenToScreenBlit;
264
265	gInfo.AdjustFrame = Virge_AdjustFrame;
266	gInfo.ChipInit = Virge_Init;
267	gInfo.GetColorSpaceParams = Virge_GetColorSpaceParams;
268	gInfo.SetDisplayMode = Virge_SetDisplayMode;
269	gInfo.SetIndexedColors = Virge_SetIndexedColors;
270}
271