1/*
2	Haiku ATI video driver adapted from the X.org ATI driver.
3
4	Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
5	Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
6
7	Copyright 2009 Haiku, Inc.  All rights reserved.
8	Distributed under the terms of the MIT license.
9
10	Authors:
11	Gerald Zajac 2009
12*/
13
14
15#include "accelerant.h"
16#include "mach64.h"
17
18
19
20static bool
21Mach64_InitDSPParams()
22{
23	// Initialize global variables used to set DSP registers on a VT-B or later.
24
25	SharedInfo& si = *gInfo.sharedInfo;
26	M64_Params& params = si.m64Params;
27
28	// Retrieve XCLK settings.
29
30	uint8 ioValue = Mach64_GetPLLReg(PLL_XCLK_CNTL);
31	params.xClkPostDivider = ioValue & 0x7;
32
33	switch (params.xClkPostDivider) {
34	case 0:
35	case 1:
36	case 2:
37	case 3:
38		params.xClkRefDivider = 1;
39		break;
40
41	case 4:
42		params.xClkRefDivider = 3;
43		params.xClkPostDivider = 0;
44		break;
45
46	default:
47		TRACE("Unsupported XCLK source:  %d.\n", params.xClkPostDivider);
48		return false;
49	}
50
51	if (ioValue & PLL_MFB_TIMES_4_2B)
52		params.xClkPostDivider--;
53
54	// Compute maximum RAS delay and related params.
55
56	uint32 memCntl = INREG(MEM_CNTL);
57	int trp = GetBits(memCntl, CTL_MEM_TRP);
58	params.xClkPageFaultDelay = GetBits(memCntl, CTL_MEM_TRCD) +
59							   GetBits(memCntl, CTL_MEM_TCRD) + trp + 2;
60	params.xClkMaxRASDelay = GetBits(memCntl, CTL_MEM_TRAS) + trp + 2;
61
62	params.displayFIFODepth = 32;
63
64	if (si.chipType < MACH64_264VT4) {
65		params.xClkPageFaultDelay += 2;
66		params.xClkMaxRASDelay += 3;
67		params.displayFIFODepth = 24;
68	}
69
70	// Determine type of memory used with the chip.
71
72	int memType = INREG(CONFIG_STAT0) & 0x7;
73	TRACE("Memory type: %d\n", memType);
74
75	switch (memType) {
76	case MEM_DRAM:
77		if (si.videoMemSize <= 1024 * 1024) {
78			params.displayLoopLatency = 10;
79		} else {
80			params.displayLoopLatency = 8;
81			params.xClkPageFaultDelay += 2;
82		}
83		break;
84
85	case MEM_EDO:
86	case MEM_PSEUDO_EDO:
87		if (si.videoMemSize <= 1024 * 1024) {
88			params.displayLoopLatency = 9;
89		} else {
90			params.displayLoopLatency = 8;
91			params.xClkPageFaultDelay++;
92		}
93		break;
94
95	case MEM_SDRAM:
96		if (si.videoMemSize <= 1024 * 1024) {
97			params.displayLoopLatency = 11;
98		} else {
99			params.displayLoopLatency = 10;
100			params.xClkPageFaultDelay++;
101		}
102		break;
103
104	case MEM_SGRAM:
105		params.displayLoopLatency = 8;
106		params.xClkPageFaultDelay += 3;
107		break;
108
109	default:                 /* Set maximums */
110		params.displayLoopLatency = 11;
111		params.xClkPageFaultDelay += 3;
112		break;
113	}
114
115	if (params.xClkMaxRASDelay <= params.xClkPageFaultDelay)
116		params.xClkMaxRASDelay = params.xClkPageFaultDelay + 1;
117
118	uint32 dspConfig = INREG(DSP_CONFIG);
119	if (dspConfig)
120		params.displayLoopLatency = GetBits(dspConfig, DSP_LOOP_LATENCY);
121
122	return true;
123}
124
125
126static bool
127Mach64_GetColorSpaceParams(int colorSpace, uint8& bitsPerPixel, uint32& maxPixelClock)
128{
129	// Get parameters for a color space which is supported by the Mach64 chips.
130	// Argument maxPixelClock is in KHz.
131	// Return true if the color space is supported;  else return false.
132
133	SharedInfo& si = *gInfo.sharedInfo;
134
135	switch (colorSpace) {
136		case B_RGB32:
137			bitsPerPixel = 32;
138			break;
139		case B_RGB16:
140			bitsPerPixel = 16;
141			break;
142		case B_RGB15:
143			bitsPerPixel = 15;
144			break;
145		case B_CMAP8:
146			bitsPerPixel = 8;
147			break;
148		default:
149			TRACE("Unsupported color space: 0x%X\n", colorSpace);
150			return false;
151	}
152
153	if (si.chipType >= MACH64_264VTB) {
154		if ((si.chipType >= MACH64_264VT4) && (si.chipType != MACH64_264LTPRO))
155			maxPixelClock = 230000;
156		else if (si.chipType >= MACH64_264VT3)
157			maxPixelClock = 200000;
158		else
159			maxPixelClock = 170000;
160	} else {
161		if (bitsPerPixel == 8)
162			maxPixelClock = 135000;
163		else
164			maxPixelClock = 80000;
165	}
166
167	return true;
168}
169
170
171
172status_t
173Mach64_Init(void)
174{
175	TRACE("Mach64_Init()\n");
176
177	SharedInfo& si = *gInfo.sharedInfo;
178
179	static const int videoRamSizes[] =
180		{ 512, 1024, 2*1024, 4*1024, 6*1024, 8*1024, 12*1024, 16*1024 };
181
182	uint32 memCntl = INREG(MEM_CNTL);
183	if (si.chipType < MACH64_264VTB) {
184		si.videoMemSize = videoRamSizes[memCntl & 0x7] * 1024;
185	} else {
186		uint32 ioValue = (memCntl & 0xf);
187		if (ioValue < 8)
188			si.videoMemSize = (ioValue + 1) * 512 * 1024;
189		else if (ioValue < 12)
190			si.videoMemSize = (ioValue - 3) * 1024 * 1024;
191		else
192			si.videoMemSize = (ioValue - 7) * 2048 * 1024;
193	}
194
195	si.cursorOffset = (si.videoMemSize - CURSOR_BYTES) & ~0xfff;	// align to 4k boundary
196	si.frameBufferOffset = 0;
197	si.maxFrameBufferSize = si.cursorOffset - si.frameBufferOffset;
198
199	TRACE("Video Memory size: %d MB  frameBufferOffset: 0x%x  cursorOffset: 0x%x\n",
200		si.videoMemSize / 1024 / 1024, si.frameBufferOffset, si.cursorOffset);
201
202	// 264VT-B's and later have DSP registers.
203
204	if ((si.chipType >= MACH64_264VTB) && !Mach64_InitDSPParams())
205		return B_ERROR;
206
207	// Determine if the LCD display of a laptop computer is active.
208
209	si.displayType = MT_VGA;
210
211	if (si.chipType == MACH64_MOBILITY && si.panelX > 0 && si.panelY > 0) {
212		if (Mach64_GetLCDReg(LCD_GEN_CNTL) & LCD_ON)
213			si.displayType = MT_LAPTOP;
214	}
215
216	// Set up the array of color spaces supported by the Mach64 chips.
217
218	si.colorSpaces[0] = B_CMAP8;
219	si.colorSpaces[1] = B_RGB15;
220	si.colorSpaces[2] = B_RGB16;
221	si.colorSpaces[3] = B_RGB32;
222	si.colorSpaceCount = 4;
223
224	// Setup the mode list.
225
226	return CreateModeList(IsModeUsable);
227}
228
229
230static void
231Mach64_WaitForFifo(uint32 entries)
232{
233	// The FIFO has 16 slots.  This routines waits until at least `entries'
234	// of these slots are empty.
235
236	while ((INREG(FIFO_STAT) & 0xffff) > (0x8000ul >> entries)) ;
237}
238
239
240static void
241Mach64_WaitForIdle()
242{
243	// Wait for the graphics engine to be completely idle.  That is, the FIFO
244	// has drained, the Pixel Cache is flushed, and the engine is idle.  This
245	// is a standard "sync" function that will make the hardware "quiescent".
246
247	Mach64_WaitForFifo(16);
248
249	while (INREG(GUI_STAT) & ENGINE_BUSY) ;
250}
251
252
253void
254Mach64_SetFunctionPointers(void)
255{
256	// Setting the function pointers must be done prior to first ModeInit call
257	// or any accel activity.
258
259	gInfo.WaitForFifo = Mach64_WaitForFifo;
260	gInfo.WaitForIdle = Mach64_WaitForIdle;
261
262	gInfo.DPMSCapabilities = Mach64_DPMSCapabilities;
263	gInfo.GetDPMSMode = Mach64_GetDPMSMode;
264	gInfo.SetDPMSMode = Mach64_SetDPMSMode;
265
266	gInfo.LoadCursorImage = Mach64_LoadCursorImage;
267	gInfo.SetCursorPosition = Mach64_SetCursorPosition;
268	gInfo.ShowCursor = Mach64_ShowCursor;
269
270	gInfo.FillRectangle = Mach64_FillRectangle;
271	gInfo.FillSpan = Mach64_FillSpan;
272	gInfo.InvertRectangle = Mach64_InvertRectangle;
273	gInfo.ScreenToScreenBlit = Mach64_ScreenToScreenBlit;
274
275	gInfo.AdjustFrame = Mach64_AdjustFrame;
276	gInfo.ChipInit = Mach64_Init;
277	gInfo.GetColorSpaceParams = Mach64_GetColorSpaceParams;
278	gInfo.SetDisplayMode = Mach64_SetDisplayMode;
279	gInfo.SetIndexedColors = Mach64_SetIndexedColors;
280}
281
282