1130803Smarcel/*
2130803Smarcel	Haiku ATI video driver adapted from the X.org ATI driver.
3130803Smarcel
4130803Smarcel	Copyright 1992,1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina.
5130803Smarcel	Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
6130803Smarcel
7130803Smarcel	Copyright 2009 Haiku, Inc.  All rights reserved.
8130803Smarcel	Distributed under the terms of the MIT license.
9130803Smarcel
10130803Smarcel	Authors:
11130803Smarcel	Gerald Zajac 2009
12130803Smarcel*/
13130803Smarcel
14130803Smarcel
15130803Smarcel#include "accelerant.h"
16130803Smarcel#include "mach64.h"
17130803Smarcel
18130803Smarcel
19130803Smarcel
20130803Smarcelstatic bool
21130803SmarcelMach64_InitDSPParams()
22130803Smarcel{
23130803Smarcel	// Initialize global variables used to set DSP registers on a VT-B or later.
24130803Smarcel
25130803Smarcel	SharedInfo& si = *gInfo.sharedInfo;
26130803Smarcel	M64_Params& params = si.m64Params;
27130803Smarcel
28130803Smarcel	// Retrieve XCLK settings.
29130803Smarcel
30130803Smarcel	uint8 ioValue = Mach64_GetPLLReg(PLL_XCLK_CNTL);
31130803Smarcel	params.xClkPostDivider = ioValue & 0x7;
32130803Smarcel
33130803Smarcel	switch (params.xClkPostDivider) {
34130803Smarcel	case 0:
35130803Smarcel	case 1:
36130803Smarcel	case 2:
37130803Smarcel	case 3:
38130803Smarcel		params.xClkRefDivider = 1;
39130803Smarcel		break;
40130803Smarcel
41130803Smarcel	case 4:
42130803Smarcel		params.xClkRefDivider = 3;
43130803Smarcel		params.xClkPostDivider = 0;
44130803Smarcel		break;
45130803Smarcel
46130803Smarcel	default:
47130803Smarcel		TRACE("Unsupported XCLK source:  %d.\n", params.xClkPostDivider);
48130803Smarcel		return false;
49130803Smarcel	}
50130803Smarcel
51130803Smarcel	if (ioValue & PLL_MFB_TIMES_4_2B)
52130803Smarcel		params.xClkPostDivider--;
53130803Smarcel
54130803Smarcel	// Compute maximum RAS delay and related params.
55130803Smarcel
56130803Smarcel	uint32 memCntl = INREG(MEM_CNTL);
57130803Smarcel	int trp = GetBits(memCntl, CTL_MEM_TRP);
58130803Smarcel	params.xClkPageFaultDelay = GetBits(memCntl, CTL_MEM_TRCD) +
59130803Smarcel							   GetBits(memCntl, CTL_MEM_TCRD) + trp + 2;
60130803Smarcel	params.xClkMaxRASDelay = GetBits(memCntl, CTL_MEM_TRAS) + trp + 2;
61130803Smarcel
62130803Smarcel	params.displayFIFODepth = 32;
63130803Smarcel
64130803Smarcel	if (si.chipType < MACH64_264VT4) {
65130803Smarcel		params.xClkPageFaultDelay += 2;
66130803Smarcel		params.xClkMaxRASDelay += 3;
67130803Smarcel		params.displayFIFODepth = 24;
68130803Smarcel	}
69130803Smarcel
70130803Smarcel	// Determine type of memory used with the chip.
71130803Smarcel
72130803Smarcel	int memType = INREG(CONFIG_STAT0) & 0x7;
73130803Smarcel	TRACE("Memory type: %d\n", memType);
74130803Smarcel
75130803Smarcel	switch (memType) {
76130803Smarcel	case MEM_DRAM:
77130803Smarcel		if (si.videoMemSize <= 1024 * 1024) {
78130803Smarcel			params.displayLoopLatency = 10;
79130803Smarcel		} else {
80130803Smarcel			params.displayLoopLatency = 8;
81130803Smarcel			params.xClkPageFaultDelay += 2;
82130803Smarcel		}
83130803Smarcel		break;
84130803Smarcel
85130803Smarcel	case MEM_EDO:
86130803Smarcel	case MEM_PSEUDO_EDO:
87130803Smarcel		if (si.videoMemSize <= 1024 * 1024) {
88130803Smarcel			params.displayLoopLatency = 9;
89130803Smarcel		} else {
90130803Smarcel			params.displayLoopLatency = 8;
91130803Smarcel			params.xClkPageFaultDelay++;
92130803Smarcel		}
93130803Smarcel		break;
94130803Smarcel
95130803Smarcel	case MEM_SDRAM:
96130803Smarcel		if (si.videoMemSize <= 1024 * 1024) {
97130803Smarcel			params.displayLoopLatency = 11;
98130803Smarcel		} else {
99130803Smarcel			params.displayLoopLatency = 10;
100130803Smarcel			params.xClkPageFaultDelay++;
101130803Smarcel		}
102130803Smarcel		break;
103130803Smarcel
104130803Smarcel	case MEM_SGRAM:
105130803Smarcel		params.displayLoopLatency = 8;
106130803Smarcel		params.xClkPageFaultDelay += 3;
107130803Smarcel		break;
108130803Smarcel
109130803Smarcel	default:                 /* Set maximums */
110130803Smarcel		params.displayLoopLatency = 11;
111130803Smarcel		params.xClkPageFaultDelay += 3;
112130803Smarcel		break;
113130803Smarcel	}
114130803Smarcel
115130803Smarcel	if (params.xClkMaxRASDelay <= params.xClkPageFaultDelay)
116130803Smarcel		params.xClkMaxRASDelay = params.xClkPageFaultDelay + 1;
117130803Smarcel
118130803Smarcel	uint32 dspConfig = INREG(DSP_CONFIG);
119130803Smarcel	if (dspConfig)
120130803Smarcel		params.displayLoopLatency = GetBits(dspConfig, DSP_LOOP_LATENCY);
121130803Smarcel
122130803Smarcel	return true;
123130803Smarcel}
124130803Smarcel
125130803Smarcel
126130803Smarcelstatic bool
127130803SmarcelMach64_GetColorSpaceParams(int colorSpace, uint8& bitsPerPixel, uint32& maxPixelClock)
128130803Smarcel{
129130803Smarcel	// Get parameters for a color space which is supported by the Mach64 chips.
130130803Smarcel	// Argument maxPixelClock is in KHz.
131130803Smarcel	// Return true if the color space is supported;  else return false.
132130803Smarcel
133130803Smarcel	SharedInfo& si = *gInfo.sharedInfo;
134130803Smarcel
135130803Smarcel	switch (colorSpace) {
136130803Smarcel		case B_RGB32:
137130803Smarcel			bitsPerPixel = 32;
138130803Smarcel			break;
139130803Smarcel		case B_RGB16:
140130803Smarcel			bitsPerPixel = 16;
141130803Smarcel			break;
142130803Smarcel		case B_RGB15:
143130803Smarcel			bitsPerPixel = 15;
144130803Smarcel			break;
145130803Smarcel		case B_CMAP8:
146130803Smarcel			bitsPerPixel = 8;
147130803Smarcel			break;
148130803Smarcel		default:
149130803Smarcel			TRACE("Unsupported color space: 0x%X\n", colorSpace);
150130803Smarcel			return false;
151130803Smarcel	}
152130803Smarcel
153130803Smarcel	if (si.chipType >= MACH64_264VTB) {
154130803Smarcel		if ((si.chipType >= MACH64_264VT4) && (si.chipType != MACH64_264LTPRO))
155130803Smarcel			maxPixelClock = 230000;
156130803Smarcel		else if (si.chipType >= MACH64_264VT3)
157130803Smarcel			maxPixelClock = 200000;
158130803Smarcel		else
159130803Smarcel			maxPixelClock = 170000;
160130803Smarcel	} else {
161130803Smarcel		if (bitsPerPixel == 8)
162130803Smarcel			maxPixelClock = 135000;
163130803Smarcel		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