xref: /haiku/src/add-ons/accelerants/intel_810/mode.cpp (revision 25a7b01d15612846f332751841da3579db313082)
1e0ee3b79SGerald Zajac /*
2e0ee3b79SGerald Zajac  * Copyright 2007-2012 Haiku, Inc.  All rights reserved.
3e0ee3b79SGerald Zajac  * Distributed under the terms of the MIT license.
4*0e8316ccSAlexander von Gluck IV  *
5e0ee3b79SGerald Zajac  * Authors:
6e0ee3b79SGerald Zajac  *		Gerald Zajac
7e0ee3b79SGerald Zajac  */
8e0ee3b79SGerald Zajac 
9*0e8316ccSAlexander von Gluck IV 
10e0ee3b79SGerald Zajac #include "accelerant.h"
11e0ee3b79SGerald Zajac 
12e0ee3b79SGerald Zajac #include <create_display_modes.h>		// common accelerant header file
13e0ee3b79SGerald Zajac #include <string.h>
14e0ee3b79SGerald Zajac #include <unistd.h>
15e0ee3b79SGerald Zajac 
16e0ee3b79SGerald Zajac 
17e0ee3b79SGerald Zajac static bool
IsThereEnoughFBMemory(const display_mode * mode,uint32 bitsPerPixel)18e0ee3b79SGerald Zajac IsThereEnoughFBMemory(const display_mode* mode, uint32 bitsPerPixel)
19e0ee3b79SGerald Zajac {
20e0ee3b79SGerald Zajac 	// Test if there is enough Frame Buffer memory for the mode and color depth
21e0ee3b79SGerald Zajac 	// specified by the caller, and return true if there is sufficient memory.
22e0ee3b79SGerald Zajac 
23e0ee3b79SGerald Zajac 	uint32 maxWidth = mode->virtual_width;
24e0ee3b79SGerald Zajac 	if (mode->timing.h_display > maxWidth)
25e0ee3b79SGerald Zajac 		maxWidth = mode->timing.h_display;
26e0ee3b79SGerald Zajac 
27e0ee3b79SGerald Zajac 	uint32 maxHeight = mode->virtual_height;
28e0ee3b79SGerald Zajac 	if (mode->timing.v_display > maxHeight)
29e0ee3b79SGerald Zajac 		maxHeight = mode->timing.v_display;
30e0ee3b79SGerald Zajac 
31e0ee3b79SGerald Zajac 	uint32 bytesPerPixel = (bitsPerPixel + 7) / 8;
32e0ee3b79SGerald Zajac 
33e0ee3b79SGerald Zajac 	return (maxWidth * maxHeight * bytesPerPixel
34e0ee3b79SGerald Zajac 		<= gInfo.sharedInfo->maxFrameBufferSize);
35e0ee3b79SGerald Zajac }
36e0ee3b79SGerald Zajac 
37e0ee3b79SGerald Zajac 
38e0ee3b79SGerald Zajac bool
IsModeUsable(const display_mode * mode)39e0ee3b79SGerald Zajac IsModeUsable(const display_mode* mode)
40e0ee3b79SGerald Zajac {
41e0ee3b79SGerald Zajac 	// Test if the display mode is usable by the current video chip.  That is,
42e0ee3b79SGerald Zajac 	// does the chip have enough memory for the mode and is the pixel clock
43e0ee3b79SGerald Zajac 	// within the chips allowable range, etc.
44e0ee3b79SGerald Zajac 	//
45e0ee3b79SGerald Zajac 	// Return true if the mode is usable.
46e0ee3b79SGerald Zajac 
47e0ee3b79SGerald Zajac 	SharedInfo& si = *gInfo.sharedInfo;
48e0ee3b79SGerald Zajac 	uint8 bitsPerPixel;
49e0ee3b79SGerald Zajac 	uint32 maxPixelClock;
50e0ee3b79SGerald Zajac 
51e0ee3b79SGerald Zajac 	if (!I810_GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
52e0ee3b79SGerald Zajac 		return false;
53e0ee3b79SGerald Zajac 
54e0ee3b79SGerald Zajac 	// Is there enough frame buffer memory to handle the mode?
55e0ee3b79SGerald Zajac 
56e0ee3b79SGerald Zajac 	if (!IsThereEnoughFBMemory(mode, bitsPerPixel))
57e0ee3b79SGerald Zajac 		return false;
58e0ee3b79SGerald Zajac 
59e0ee3b79SGerald Zajac 	if (mode->timing.pixel_clock > maxPixelClock)
60e0ee3b79SGerald Zajac 		return false;
61e0ee3b79SGerald Zajac 
62e0ee3b79SGerald Zajac 	// Is the color space supported?
63e0ee3b79SGerald Zajac 
64e0ee3b79SGerald Zajac 	bool colorSpaceSupported = false;
65e0ee3b79SGerald Zajac 	for (uint32 j = 0; j < si.colorSpaceCount; j++) {
66e0ee3b79SGerald Zajac 		if (mode->space == uint32(si.colorSpaces[j])) {
67e0ee3b79SGerald Zajac 			colorSpaceSupported = true;
68e0ee3b79SGerald Zajac 			break;
69e0ee3b79SGerald Zajac 		}
70e0ee3b79SGerald Zajac 	}
71e0ee3b79SGerald Zajac 
72e0ee3b79SGerald Zajac 	if (!colorSpaceSupported)
73e0ee3b79SGerald Zajac 		return false;
74e0ee3b79SGerald Zajac 
75e0ee3b79SGerald Zajac 	// Reject modes with a width of 640 and a height < 480 since they do not
76e0ee3b79SGerald Zajac 	// work properly with the i810 chipsets.
77e0ee3b79SGerald Zajac 
78e0ee3b79SGerald Zajac 	if (mode->timing.h_display == 640 && mode->timing.v_display < 480)
79e0ee3b79SGerald Zajac 		return false;
80e0ee3b79SGerald Zajac 
81e0ee3b79SGerald Zajac 	return true;
82e0ee3b79SGerald Zajac }
83e0ee3b79SGerald Zajac 
84e0ee3b79SGerald Zajac 
85e0ee3b79SGerald Zajac status_t
CreateModeList(bool (* checkMode)(const display_mode * mode))86e0ee3b79SGerald Zajac CreateModeList(bool (*checkMode)(const display_mode* mode))
87e0ee3b79SGerald Zajac {
88e0ee3b79SGerald Zajac 	SharedInfo& si = *gInfo.sharedInfo;
89e0ee3b79SGerald Zajac 
90e0ee3b79SGerald Zajac 	// Obtain EDID info which is needed for for building the mode list.
91e0ee3b79SGerald Zajac 
92e0ee3b79SGerald Zajac 	si.bHaveEDID = false;
93e0ee3b79SGerald Zajac 
94e0ee3b79SGerald Zajac 	if (!si.bHaveEDID) {
95e0ee3b79SGerald Zajac 		edid1_raw rawEdid;	// raw EDID info to obtain
96e0ee3b79SGerald Zajac 
97e0ee3b79SGerald Zajac 		if (ioctl(gInfo.deviceFileDesc, INTEL_GET_EDID, &rawEdid,
98e0ee3b79SGerald Zajac 				sizeof(rawEdid)) == B_OK) {
99e0ee3b79SGerald Zajac 			if (rawEdid.version.version != 1 || rawEdid.version.revision > 4) {
100e0ee3b79SGerald Zajac 				TRACE("CreateModeList(); EDID version %d.%d out of range\n",
101e0ee3b79SGerald Zajac 					rawEdid.version.version, rawEdid.version.revision);
102e0ee3b79SGerald Zajac 			} else {
103e0ee3b79SGerald Zajac 				edid_decode(&si.edidInfo, &rawEdid); // decode & save EDID info
104e0ee3b79SGerald Zajac 				si.bHaveEDID = true;
105e0ee3b79SGerald Zajac 			}
106e0ee3b79SGerald Zajac 		}
107e0ee3b79SGerald Zajac 
108e0ee3b79SGerald Zajac 		if (si.bHaveEDID) {
109e0ee3b79SGerald Zajac #ifdef ENABLE_DEBUG_TRACE
110e0ee3b79SGerald Zajac 			edid_dump(&(si.edidInfo));
111e0ee3b79SGerald Zajac #endif
112e0ee3b79SGerald Zajac 		} else {
113e0ee3b79SGerald Zajac 			TRACE("CreateModeList(); Unable to get EDID info\n");
114e0ee3b79SGerald Zajac 		}
115e0ee3b79SGerald Zajac 	}
116e0ee3b79SGerald Zajac 
117e0ee3b79SGerald Zajac 	display_mode* list;
118e0ee3b79SGerald Zajac 	uint32 count = 0;
119e0ee3b79SGerald Zajac 	area_id listArea;
120e0ee3b79SGerald Zajac 
121e0ee3b79SGerald Zajac 	listArea = create_display_modes("i810 modes",
122e0ee3b79SGerald Zajac 		si.bHaveEDID ? &si.edidInfo : NULL,
123e0ee3b79SGerald Zajac 		NULL, 0, si.colorSpaces, si.colorSpaceCount,
124e0ee3b79SGerald Zajac 		(check_display_mode_hook)checkMode, &list, &count);
125e0ee3b79SGerald Zajac 
126e0ee3b79SGerald Zajac 	if (listArea < 0)
127e0ee3b79SGerald Zajac 		return listArea;		// listArea has error code
128e0ee3b79SGerald Zajac 
129e0ee3b79SGerald Zajac 	si.modeArea = gInfo.modeListArea = listArea;
130e0ee3b79SGerald Zajac 	si.modeCount = count;
131e0ee3b79SGerald Zajac 	gInfo.modeList = list;
132e0ee3b79SGerald Zajac 	return B_OK;
133e0ee3b79SGerald Zajac }
134e0ee3b79SGerald Zajac 
135e0ee3b79SGerald Zajac 
136e0ee3b79SGerald Zajac status_t
ProposeDisplayMode(display_mode * target,const display_mode * low,const display_mode * high)137e0ee3b79SGerald Zajac ProposeDisplayMode(display_mode* target, const display_mode* low,
138e0ee3b79SGerald Zajac 	const display_mode* high)
139e0ee3b79SGerald Zajac {
140e0ee3b79SGerald Zajac 	(void)low;		// avoid compiler warning for unused arg
141e0ee3b79SGerald Zajac 	(void)high;		// avoid compiler warning for unused arg
142e0ee3b79SGerald Zajac 
143e0ee3b79SGerald Zajac 	TRACE("ProposeDisplayMode()  %dx%d, pixel clock: %d kHz, space: 0x%X\n",
144e0ee3b79SGerald Zajac 		target->timing.h_display, target->timing.v_display,
145e0ee3b79SGerald Zajac 		target->timing.pixel_clock, target->space);
146e0ee3b79SGerald Zajac 
147e0ee3b79SGerald Zajac 	// Search the mode list for the specified mode.
148e0ee3b79SGerald Zajac 
149e0ee3b79SGerald Zajac 	uint32 modeCount = gInfo.sharedInfo->modeCount;
150e0ee3b79SGerald Zajac 
151e0ee3b79SGerald Zajac 	for (uint32 j = 0; j < modeCount; j++) {
152e0ee3b79SGerald Zajac 		display_mode& mode = gInfo.modeList[j];
153e0ee3b79SGerald Zajac 
154e0ee3b79SGerald Zajac 		if (target->timing.h_display == mode.timing.h_display
155e0ee3b79SGerald Zajac 			&& target->timing.v_display == mode.timing.v_display
156e0ee3b79SGerald Zajac 			&& target->space == mode.space)
157e0ee3b79SGerald Zajac 			return B_OK;	// mode found in list
158e0ee3b79SGerald Zajac 	}
159e0ee3b79SGerald Zajac 
160e0ee3b79SGerald Zajac 	return B_BAD_VALUE;		// mode not found in list
161e0ee3b79SGerald Zajac }
162e0ee3b79SGerald Zajac 
163e0ee3b79SGerald Zajac 
164e0ee3b79SGerald Zajac status_t
SetDisplayMode(display_mode * pMode)165e0ee3b79SGerald Zajac SetDisplayMode(display_mode* pMode)
166e0ee3b79SGerald Zajac {
167e0ee3b79SGerald Zajac 	// First validate the mode, then call a function to set the registers.
168e0ee3b79SGerald Zajac 
169e0ee3b79SGerald Zajac 	TRACE("SetDisplayMode() begin\n");
170e0ee3b79SGerald Zajac 
171e0ee3b79SGerald Zajac 	SharedInfo& si = *gInfo.sharedInfo;
172e0ee3b79SGerald Zajac 	DisplayModeEx mode;
173e0ee3b79SGerald Zajac 	(display_mode&)mode = *pMode;
174e0ee3b79SGerald Zajac 
175e0ee3b79SGerald Zajac 	uint32 maxPixelClock;
176e0ee3b79SGerald Zajac 	if (!I810_GetColorSpaceParams(mode.space, mode.bitsPerPixel, maxPixelClock))
177e0ee3b79SGerald Zajac 		return B_BAD_VALUE;
178e0ee3b79SGerald Zajac 
179e0ee3b79SGerald Zajac 	if (ProposeDisplayMode(&mode, pMode, pMode) != B_OK)
180e0ee3b79SGerald Zajac 		return B_BAD_VALUE;
181e0ee3b79SGerald Zajac 
182e0ee3b79SGerald Zajac 	mode.bytesPerPixel = (mode.bitsPerPixel + 7) / 8;
183e0ee3b79SGerald Zajac 	mode.bytesPerRow = mode.timing.h_display * mode.bytesPerPixel;
184e0ee3b79SGerald Zajac 
185e0ee3b79SGerald Zajac 	// Is there enough frame buffer memory for this mode?
186e0ee3b79SGerald Zajac 
187e0ee3b79SGerald Zajac 	if ( ! IsThereEnoughFBMemory(&mode, mode.bitsPerPixel))
188e0ee3b79SGerald Zajac 		return B_NO_MEMORY;
189e0ee3b79SGerald Zajac 
190e0ee3b79SGerald Zajac 	TRACE("Set display mode: %dx%d  virtual size: %dx%d  "
191e0ee3b79SGerald Zajac 		"color depth: %d bits/pixel\n",
192e0ee3b79SGerald Zajac 		mode.timing.h_display, mode.timing.v_display,
193e0ee3b79SGerald Zajac 		mode.virtual_width, mode.virtual_height, mode.bitsPerPixel);
194e0ee3b79SGerald Zajac 
195e0ee3b79SGerald Zajac 	TRACE("   mode timing: %d  %d %d %d %d  %d %d %d %d\n",
196e0ee3b79SGerald Zajac 		mode.timing.pixel_clock,
197e0ee3b79SGerald Zajac 		mode.timing.h_display,
198e0ee3b79SGerald Zajac 		mode.timing.h_sync_start, mode.timing.h_sync_end,
199e0ee3b79SGerald Zajac 		mode.timing.h_total,
200e0ee3b79SGerald Zajac 		mode.timing.v_display,
201e0ee3b79SGerald Zajac 		mode.timing.v_sync_start, mode.timing.v_sync_end,
202e0ee3b79SGerald Zajac 		mode.timing.v_total);
203e0ee3b79SGerald Zajac 
204e0ee3b79SGerald Zajac 	TRACE("   mode hFreq: %.1f kHz  vFreq: %.1f Hz  %chSync %cvSync\n",
205e0ee3b79SGerald Zajac 		double(mode.timing.pixel_clock) / mode.timing.h_total,
206e0ee3b79SGerald Zajac 		((double(mode.timing.pixel_clock) / mode.timing.h_total) * 1000.0)
207e0ee3b79SGerald Zajac 		/ mode.timing.v_total,
208e0ee3b79SGerald Zajac 		(mode.timing.flags & B_POSITIVE_HSYNC) ? '+' : '-',
209e0ee3b79SGerald Zajac 		(mode.timing.flags & B_POSITIVE_VSYNC) ? '+' : '-');
210e0ee3b79SGerald Zajac 
211e0ee3b79SGerald Zajac 	status_t status = I810_SetDisplayMode(mode);
212e0ee3b79SGerald Zajac 	if (status != B_OK) {
213e0ee3b79SGerald Zajac 		TRACE("SetDisplayMode() failed;  status 0x%x\n", status);
214e0ee3b79SGerald Zajac 		return status;
215e0ee3b79SGerald Zajac 	}
216e0ee3b79SGerald Zajac 
217e0ee3b79SGerald Zajac 	si.displayMode = mode;
218e0ee3b79SGerald Zajac 
219e0ee3b79SGerald Zajac 	TRACE("SetDisplayMode() done\n");
220e0ee3b79SGerald Zajac 	return B_OK;
221e0ee3b79SGerald Zajac }
222e0ee3b79SGerald Zajac 
223e0ee3b79SGerald Zajac 
224e0ee3b79SGerald Zajac status_t
MoveDisplay(uint16 horizontalStart,uint16 verticalStart)225e0ee3b79SGerald Zajac MoveDisplay(uint16 horizontalStart, uint16 verticalStart)
226e0ee3b79SGerald Zajac {
227e0ee3b79SGerald Zajac 	// Set which pixel of the virtual frame buffer will show up in the
228e0ee3b79SGerald Zajac 	// top left corner of the display device.	Used for page-flipping
229e0ee3b79SGerald Zajac 	// games and virtual desktops.
230e0ee3b79SGerald Zajac 
231e0ee3b79SGerald Zajac 	DisplayModeEx& mode = gInfo.sharedInfo->displayMode;
232e0ee3b79SGerald Zajac 
233e0ee3b79SGerald Zajac 	if (mode.timing.h_display + horizontalStart > mode.virtual_width
234e0ee3b79SGerald Zajac 		|| mode.timing.v_display + verticalStart > mode.virtual_height)
235e0ee3b79SGerald Zajac 		return B_ERROR;
236e0ee3b79SGerald Zajac 
237e0ee3b79SGerald Zajac 	mode.h_display_start = horizontalStart;
238e0ee3b79SGerald Zajac 	mode.v_display_start = verticalStart;
239e0ee3b79SGerald Zajac 
240e0ee3b79SGerald Zajac 	I810_AdjustFrame(mode);
241e0ee3b79SGerald Zajac 	return B_OK;
242e0ee3b79SGerald Zajac }
243e0ee3b79SGerald Zajac 
244e0ee3b79SGerald Zajac 
245e0ee3b79SGerald Zajac uint32
AccelerantModeCount(void)246e0ee3b79SGerald Zajac AccelerantModeCount(void)
247e0ee3b79SGerald Zajac {
248e0ee3b79SGerald Zajac 	// Return the number of display modes in the mode list.
249e0ee3b79SGerald Zajac 
250e0ee3b79SGerald Zajac 	return gInfo.sharedInfo->modeCount;
251e0ee3b79SGerald Zajac }
252e0ee3b79SGerald Zajac 
253e0ee3b79SGerald Zajac 
254e0ee3b79SGerald Zajac status_t
GetModeList(display_mode * dmList)255e0ee3b79SGerald Zajac GetModeList(display_mode* dmList)
256e0ee3b79SGerald Zajac {
257e0ee3b79SGerald Zajac 	// Copy the list of supported video modes to the location pointed at
258e0ee3b79SGerald Zajac 	// by dmList.
259e0ee3b79SGerald Zajac 
260e0ee3b79SGerald Zajac 	memcpy(dmList, gInfo.modeList,
261e0ee3b79SGerald Zajac 		gInfo.sharedInfo->modeCount * sizeof(display_mode));
262e0ee3b79SGerald Zajac 	return B_OK;
263e0ee3b79SGerald Zajac }
264e0ee3b79SGerald Zajac 
265e0ee3b79SGerald Zajac 
266e0ee3b79SGerald Zajac status_t
GetDisplayMode(display_mode * current_mode)267e0ee3b79SGerald Zajac GetDisplayMode(display_mode* current_mode)
268e0ee3b79SGerald Zajac {
269*0e8316ccSAlexander von Gluck IV 	*current_mode = gInfo.sharedInfo->displayMode; // current display mode
270e0ee3b79SGerald Zajac 	return B_OK;
271e0ee3b79SGerald Zajac }
272e0ee3b79SGerald Zajac 
273e0ee3b79SGerald Zajac 
274e0ee3b79SGerald Zajac status_t
GetFrameBufferConfig(frame_buffer_config * pFBC)275e0ee3b79SGerald Zajac GetFrameBufferConfig(frame_buffer_config* pFBC)
276e0ee3b79SGerald Zajac {
277e0ee3b79SGerald Zajac 	SharedInfo& si = *gInfo.sharedInfo;
278e0ee3b79SGerald Zajac 
279e0ee3b79SGerald Zajac 	pFBC->frame_buffer = (void*)((addr_t)(si.videoMemAddr));
280e0ee3b79SGerald Zajac 	pFBC->frame_buffer_dma = (void*)((addr_t)(si.videoMemPCI));
281e0ee3b79SGerald Zajac 	pFBC->bytes_per_row = si.displayMode.virtual_width
282e0ee3b79SGerald Zajac 		* si.displayMode.bytesPerPixel;
283e0ee3b79SGerald Zajac 
284e0ee3b79SGerald Zajac 	return B_OK;
285e0ee3b79SGerald Zajac }
286e0ee3b79SGerald Zajac 
287e0ee3b79SGerald Zajac 
288e0ee3b79SGerald Zajac status_t
GetPixelClockLimits(display_mode * mode,uint32 * low,uint32 * high)289e0ee3b79SGerald Zajac GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high)
290e0ee3b79SGerald Zajac {
291e0ee3b79SGerald Zajac 	// Return the maximum and minium pixel clock limits for the specified mode.
292e0ee3b79SGerald Zajac 
293e0ee3b79SGerald Zajac 	uint8 bitsPerPixel;
294e0ee3b79SGerald Zajac 	uint32 maxPixelClock;
295e0ee3b79SGerald Zajac 
296e0ee3b79SGerald Zajac 	if (!I810_GetColorSpaceParams(mode->space, bitsPerPixel, maxPixelClock))
297e0ee3b79SGerald Zajac 		return B_ERROR;
298e0ee3b79SGerald Zajac 
299e0ee3b79SGerald Zajac 	if (low != NULL) {
300e0ee3b79SGerald Zajac 		// lower limit of about 48Hz vertical refresh
301e0ee3b79SGerald Zajac 		uint32 totalClocks = (uint32)mode->timing.h_total
302e0ee3b79SGerald Zajac 			* (uint32)mode->timing.v_total;
303e0ee3b79SGerald Zajac 		uint32 lowClock = (totalClocks * 48L) / 1000L;
304e0ee3b79SGerald Zajac 		if (lowClock > maxPixelClock)
305e0ee3b79SGerald Zajac 			return B_ERROR;
306e0ee3b79SGerald Zajac 
307e0ee3b79SGerald Zajac 		*low = lowClock;
308e0ee3b79SGerald Zajac 	}
309e0ee3b79SGerald Zajac 
310e0ee3b79SGerald Zajac 	if (high != NULL)
311e0ee3b79SGerald Zajac 		*high = maxPixelClock;
312e0ee3b79SGerald Zajac 
313e0ee3b79SGerald Zajac 	return B_OK;
314e0ee3b79SGerald Zajac }
315e0ee3b79SGerald Zajac 
316e0ee3b79SGerald Zajac 
317e0ee3b79SGerald Zajac #ifdef __HAIKU__
318e0ee3b79SGerald Zajac status_t
GetEdidInfo(void * info,size_t size,uint32 * _version)319e0ee3b79SGerald Zajac GetEdidInfo(void* info, size_t size, uint32* _version)
320e0ee3b79SGerald Zajac {
321e0ee3b79SGerald Zajac 	SharedInfo& si = *gInfo.sharedInfo;
322e0ee3b79SGerald Zajac 
323e0ee3b79SGerald Zajac 	if ( ! si.bHaveEDID)
324e0ee3b79SGerald Zajac 		return B_ERROR;
325e0ee3b79SGerald Zajac 
326e0ee3b79SGerald Zajac 	if (size < sizeof(struct edid1_info))
327e0ee3b79SGerald Zajac 		return B_BUFFER_OVERFLOW;
328e0ee3b79SGerald Zajac 
329e0ee3b79SGerald Zajac 	memcpy(info, &si.edidInfo, sizeof(struct edid1_info));
330e0ee3b79SGerald Zajac 	*_version = EDID_VERSION_1;
331e0ee3b79SGerald Zajac 	return B_OK;
332e0ee3b79SGerald Zajac }
333e0ee3b79SGerald Zajac #endif	// __HAIKU__
334