xref: /haiku/src/add-ons/accelerants/radeon_hd/mode.cpp (revision d2a69507d07969763a817447be9259b102e716ce)
1a90ebd77SClemens Zeidler /*
2d5c3acacSAlexander von Gluck IV  * Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
3a90ebd77SClemens Zeidler  * Distributed under the terms of the MIT License.
4a90ebd77SClemens Zeidler  *
5a90ebd77SClemens Zeidler  * Support for i915 chipset and up based on the X driver,
6a90ebd77SClemens Zeidler  * Copyright 2006-2007 Intel Corporation.
7a90ebd77SClemens Zeidler  *
8a90ebd77SClemens Zeidler  * Authors:
9a90ebd77SClemens Zeidler  *		Axel Dörfler, axeld@pinc-software.de
10d5c3acacSAlexander von Gluck IV  *		Alexander von Gluck, kallisti5@unixzen.com
11a90ebd77SClemens Zeidler  */
12a90ebd77SClemens Zeidler 
13a90ebd77SClemens Zeidler 
14d5c3acacSAlexander von Gluck IV #include "mode.h"
15a90ebd77SClemens Zeidler 
1661cf7133SAlexander von Gluck IV #include <create_display_modes.h>
17a90ebd77SClemens Zeidler #include <stdio.h>
18a90ebd77SClemens Zeidler #include <string.h>
19a90ebd77SClemens Zeidler #include <math.h>
20a90ebd77SClemens Zeidler 
2161cf7133SAlexander von Gluck IV #include "accelerant.h"
2261cf7133SAlexander von Gluck IV #include "accelerant_protos.h"
2361cf7133SAlexander von Gluck IV #include "bios.h"
24c8677fb1SAlexander von Gluck IV #include "connector.h"
2561cf7133SAlexander von Gluck IV #include "display.h"
26c8677fb1SAlexander von Gluck IV #include "displayport.h"
2761cf7133SAlexander von Gluck IV #include "encoder.h"
2861cf7133SAlexander von Gluck IV #include "pll.h"
2961cf7133SAlexander von Gluck IV #include "utility.h"
30192781ddSAlexander von Gluck IV 
31a90ebd77SClemens Zeidler 
32a90ebd77SClemens Zeidler #define TRACE_MODE
33a90ebd77SClemens Zeidler #ifdef TRACE_MODE
34a90ebd77SClemens Zeidler extern "C" void _sPrintf(const char* format, ...);
35d5c3acacSAlexander von Gluck IV #	define TRACE(x...) _sPrintf("radeon_hd: " x)
36a90ebd77SClemens Zeidler #else
37d5c3acacSAlexander von Gluck IV #	define TRACE(x...) ;
38a90ebd77SClemens Zeidler #endif
39a90ebd77SClemens Zeidler 
4009aaa658SAlexander von Gluck IV #define ERROR(x...) _sPrintf("radeon_hd: " x)
41a90ebd77SClemens Zeidler 
42*d2a69507SAlexander von Gluck IV 
43a90ebd77SClemens Zeidler status_t
44a90ebd77SClemens Zeidler create_mode_list(void)
45a90ebd77SClemens Zeidler {
46f35af704SAlexander von Gluck IV 	// TODO: multi-monitor?  for now we use VESA and not gDisplay edid
47f35af704SAlexander von Gluck IV 
48192781ddSAlexander von Gluck IV 	const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
49192781ddSAlexander von Gluck IV 		B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
50a90ebd77SClemens Zeidler 
51192781ddSAlexander von Gluck IV 	gInfo->mode_list_area = create_display_modes("radeon HD modes",
522613175eSAlexander von Gluck IV 		gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL,
532613175eSAlexander von Gluck IV 		NULL, 0, kRadeonHDSpaces,
54192781ddSAlexander von Gluck IV 		sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]),
55192781ddSAlexander von Gluck IV 		is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count);
56192781ddSAlexander von Gluck IV 	if (gInfo->mode_list_area < B_OK)
57192781ddSAlexander von Gluck IV 		return gInfo->mode_list_area;
58a90ebd77SClemens Zeidler 
59192781ddSAlexander von Gluck IV 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
60d5c3acacSAlexander von Gluck IV 
61a90ebd77SClemens Zeidler 	return B_OK;
62a90ebd77SClemens Zeidler }
63a90ebd77SClemens Zeidler 
64a90ebd77SClemens Zeidler 
65a90ebd77SClemens Zeidler //	#pragma mark -
66a90ebd77SClemens Zeidler 
67a90ebd77SClemens Zeidler 
68a90ebd77SClemens Zeidler uint32
69a90ebd77SClemens Zeidler radeon_accelerant_mode_count(void)
70a90ebd77SClemens Zeidler {
71333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
72a90ebd77SClemens Zeidler 
73a90ebd77SClemens Zeidler 	return gInfo->shared_info->mode_count;
74a90ebd77SClemens Zeidler }
75a90ebd77SClemens Zeidler 
76a90ebd77SClemens Zeidler 
77a90ebd77SClemens Zeidler status_t
78a90ebd77SClemens Zeidler radeon_get_mode_list(display_mode* modeList)
79a90ebd77SClemens Zeidler {
80333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
81a90ebd77SClemens Zeidler 	memcpy(modeList, gInfo->mode_list,
82a90ebd77SClemens Zeidler 		gInfo->shared_info->mode_count * sizeof(display_mode));
83a90ebd77SClemens Zeidler 	return B_OK;
84a90ebd77SClemens Zeidler }
85a90ebd77SClemens Zeidler 
86a90ebd77SClemens Zeidler 
8788bfef92SAlexander von Gluck IV status_t
8888bfef92SAlexander von Gluck IV radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
8988bfef92SAlexander von Gluck IV {
9007a90a63SAlexander von Gluck IV 	// TODO: multi-monitor?  for now we use VESA edid
91f35af704SAlexander von Gluck IV 
9288bfef92SAlexander von Gluck IV 	TRACE("%s\n", __func__);
9388bfef92SAlexander von Gluck IV 	if (!gInfo->shared_info->has_edid)
9488bfef92SAlexander von Gluck IV 		return B_ERROR;
9588bfef92SAlexander von Gluck IV 	if (size < sizeof(struct edid1_info))
9688bfef92SAlexander von Gluck IV 		return B_BUFFER_OVERFLOW;
9788bfef92SAlexander von Gluck IV 
9888bfef92SAlexander von Gluck IV 	memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
9907a90a63SAlexander von Gluck IV 		// VESA
10007a90a63SAlexander von Gluck IV 	//memcpy(info, &gDisplay[0]->edid_info, sizeof(struct edid1_info));
10107a90a63SAlexander von Gluck IV 		// BitBanged display 0
10207a90a63SAlexander von Gluck IV 
10388bfef92SAlexander von Gluck IV 	*edid_version = EDID_VERSION_1;
10488bfef92SAlexander von Gluck IV 
10588bfef92SAlexander von Gluck IV 	return B_OK;
10688bfef92SAlexander von Gluck IV }
10788bfef92SAlexander von Gluck IV 
10888bfef92SAlexander von Gluck IV 
1097934da0fSAlexander von Gluck IV uint32
1107934da0fSAlexander von Gluck IV radeon_dpms_capabilities(void)
1117934da0fSAlexander von Gluck IV {
1127934da0fSAlexander von Gluck IV 	// These should be pretty universally supported on Radeon HD cards
1137934da0fSAlexander von Gluck IV 	return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
1147934da0fSAlexander von Gluck IV }
1157934da0fSAlexander von Gluck IV 
1167934da0fSAlexander von Gluck IV 
1177934da0fSAlexander von Gluck IV uint32
1187934da0fSAlexander von Gluck IV radeon_dpms_mode(void)
1197934da0fSAlexander von Gluck IV {
1207934da0fSAlexander von Gluck IV 	// TODO: this really isn't a good long-term solution
1217934da0fSAlexander von Gluck IV 	// we may need to look at the encoder dpms scratch registers
1227934da0fSAlexander von Gluck IV 	return gInfo->dpms_mode;
1237934da0fSAlexander von Gluck IV }
1247934da0fSAlexander von Gluck IV 
1257934da0fSAlexander von Gluck IV 
126b54c8119SAlexander von Gluck IV void
127b54c8119SAlexander von Gluck IV radeon_dpms_set(int mode)
128b54c8119SAlexander von Gluck IV {
129f089aa52SAlexander von Gluck IV 	radeon_shared_info &info = *gInfo->shared_info;
130f089aa52SAlexander von Gluck IV 
131b54c8119SAlexander von Gluck IV 	switch (mode) {
132b54c8119SAlexander von Gluck IV 		case B_DPMS_ON:
133936aec74SAlexander von Gluck IV 			TRACE("%s: ON\n", __func__);
134b54c8119SAlexander von Gluck IV 			for (uint8 id = 0; id < MAX_DISPLAY; id++) {
135b54c8119SAlexander von Gluck IV 				if (gDisplay[id]->active == false)
136b54c8119SAlexander von Gluck IV 					continue;
1377dde214bSAlexander von Gluck IV 				encoder_output_lock(true);
1384e9e0295SAlexander von Gluck IV 				encoder_dpms_set(id, mode);
1397dde214bSAlexander von Gluck IV 				encoder_output_lock(false);
140936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_ENABLE);
141b54c8119SAlexander von Gluck IV 				display_crtc_power(id, ATOM_ENABLE);
142f089aa52SAlexander von Gluck IV 				if (info.dceMajor >= 3)
143b54c8119SAlexander von Gluck IV 					display_crtc_memreq(id, ATOM_ENABLE);
1446c80b06bSAlexander von Gluck IV 				display_crtc_blank(id, ATOM_BLANKING_OFF);
145936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_DISABLE);
146b54c8119SAlexander von Gluck IV 			}
147b54c8119SAlexander von Gluck IV 			break;
148b54c8119SAlexander von Gluck IV 		case B_DPMS_STAND_BY:
149b54c8119SAlexander von Gluck IV 		case B_DPMS_SUSPEND:
150b54c8119SAlexander von Gluck IV 		case B_DPMS_OFF:
151936aec74SAlexander von Gluck IV 			TRACE("%s: OFF\n", __func__);
152b54c8119SAlexander von Gluck IV 			for (uint8 id = 0; id < MAX_DISPLAY; id++) {
153b54c8119SAlexander von Gluck IV 				if (gDisplay[id]->active == false)
154b54c8119SAlexander von Gluck IV 					continue;
155936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_ENABLE);
1566c80b06bSAlexander von Gluck IV 				display_crtc_blank(id, ATOM_BLANKING);
157f089aa52SAlexander von Gluck IV 				if (info.dceMajor >= 3)
158b54c8119SAlexander von Gluck IV 					display_crtc_memreq(id, ATOM_DISABLE);
159b54c8119SAlexander von Gluck IV 				display_crtc_power(id, ATOM_DISABLE);
160936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_DISABLE);
1617dde214bSAlexander von Gluck IV 				encoder_output_lock(true);
1624e9e0295SAlexander von Gluck IV 				encoder_dpms_set(id, mode);
1637dde214bSAlexander von Gluck IV 				encoder_output_lock(false);
164b54c8119SAlexander von Gluck IV 			}
165b54c8119SAlexander von Gluck IV 			break;
166b54c8119SAlexander von Gluck IV 	}
1677934da0fSAlexander von Gluck IV 	gInfo->dpms_mode = mode;
168b54c8119SAlexander von Gluck IV }
169b54c8119SAlexander von Gluck IV 
170b54c8119SAlexander von Gluck IV 
171a90ebd77SClemens Zeidler status_t
172a90ebd77SClemens Zeidler radeon_set_display_mode(display_mode* mode)
173a90ebd77SClemens Zeidler {
174f089aa52SAlexander von Gluck IV 	radeon_shared_info &info = *gInfo->shared_info;
175f089aa52SAlexander von Gluck IV 
1766ab8261bSAlexander von Gluck IV 	// Set mode on each display
1776ab8261bSAlexander von Gluck IV 	for (uint8 id = 0; id < MAX_DISPLAY; id++) {
178b54c8119SAlexander von Gluck IV 		if (gDisplay[id]->active == false)
1796ab8261bSAlexander von Gluck IV 			continue;
180f2fe29a0SAlexander von Gluck IV 
1816b0b621bSAlexander von Gluck IV 		uint16 connectorIndex = gDisplay[id]->connectorIndex;
18217b66d82SAlexander von Gluck IV 
18309aaa658SAlexander von Gluck IV 		// Determine DP lanes if DP
18409aaa658SAlexander von Gluck IV 		if (connector_is_dp(connectorIndex))
18509aaa658SAlexander von Gluck IV 			gDPInfo[connectorIndex]->laneCount
18609aaa658SAlexander von Gluck IV 				= dp_get_lane_count(connectorIndex, mode);
18709aaa658SAlexander von Gluck IV 
188b54c8119SAlexander von Gluck IV 		// *** encoder prep
189b54c8119SAlexander von Gluck IV 		encoder_output_lock(true);
19045e71a9eSAlexander von Gluck IV 		encoder_dpms_set(id, B_DPMS_OFF);
19117b66d82SAlexander von Gluck IV 		encoder_assign_crtc(id);
192e53d6375SAlexander von Gluck IV 
193b54c8119SAlexander von Gluck IV 		// *** CRT controler prep
194b54c8119SAlexander von Gluck IV 		display_crtc_lock(id, ATOM_ENABLE);
1956c80b06bSAlexander von Gluck IV 		display_crtc_blank(id, ATOM_BLANKING);
196f089aa52SAlexander von Gluck IV 		if (info.dceMajor >= 3)
197936aec74SAlexander von Gluck IV 			display_crtc_memreq(id, ATOM_DISABLE);
198936aec74SAlexander von Gluck IV 		display_crtc_power(id, ATOM_DISABLE);
199f35af704SAlexander von Gluck IV 
200b54c8119SAlexander von Gluck IV 		// *** CRT controler mode set
20117b66d82SAlexander von Gluck IV 		// TODO: program SS
202e7d0abaeSAlexander von Gluck IV 		pll_set(ATOM_PPLL1, mode->timing.pixel_clock, id);
203e7d0abaeSAlexander von Gluck IV 			// TODO: check if ATOM_PPLL1 is used and use ATOM_PPLL2 if so
2046da3f7d4SAlexander von Gluck IV 		display_crtc_set_dtd(id, mode);
205b54c8119SAlexander von Gluck IV 
206afbd52f1SAlexander von Gluck IV 		display_crtc_fb_set(id, mode);
207b54c8119SAlexander von Gluck IV 		// atombios_overscan_setup
2086da3f7d4SAlexander von Gluck IV 		display_crtc_scale(id, mode);
2096ab8261bSAlexander von Gluck IV 
210b54c8119SAlexander von Gluck IV 		// *** encoder mode set
211b54c8119SAlexander von Gluck IV 		encoder_mode_set(id, mode->timing.pixel_clock);
212b54c8119SAlexander von Gluck IV 
213b54c8119SAlexander von Gluck IV 		// *** CRT controler commit
214936aec74SAlexander von Gluck IV 		display_crtc_power(id, ATOM_ENABLE);
215f089aa52SAlexander von Gluck IV 		if (info.dceMajor >= 3)
216245fe001SAlexander von Gluck IV 			display_crtc_memreq(id, ATOM_ENABLE);
2176c80b06bSAlexander von Gluck IV 		display_crtc_blank(id, ATOM_BLANKING_OFF);
2186da3f7d4SAlexander von Gluck IV 		display_crtc_lock(id, ATOM_DISABLE);
219b54c8119SAlexander von Gluck IV 
220b54c8119SAlexander von Gluck IV 		// *** encoder commit
221c8677fb1SAlexander von Gluck IV 
222c8677fb1SAlexander von Gluck IV 		// handle DisplayPort link training
223c8677fb1SAlexander von Gluck IV 		if (connector_is_dp(connectorIndex)) {
224c8677fb1SAlexander von Gluck IV 			if (info.dceMajor >= 4)
225c8677fb1SAlexander von Gluck IV 				encoder_dig_setup(connectorIndex,
226c8677fb1SAlexander von Gluck IV 					ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
227c8677fb1SAlexander von Gluck IV 
228c8677fb1SAlexander von Gluck IV 			dp_link_train(id, mode);
229c8677fb1SAlexander von Gluck IV 
230c8677fb1SAlexander von Gluck IV 			if (info.dceMajor >= 4)
231c8677fb1SAlexander von Gluck IV 				encoder_dig_setup(connectorIndex,
232c8677fb1SAlexander von Gluck IV 					ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
233c8677fb1SAlexander von Gluck IV 		}
234c8677fb1SAlexander von Gluck IV 
23545e71a9eSAlexander von Gluck IV 		encoder_dpms_set(id, B_DPMS_ON);
236b54c8119SAlexander von Gluck IV 		encoder_output_lock(false);
2376ab8261bSAlexander von Gluck IV 	}
2386604b1b6SAlexander von Gluck IV 
239245fe001SAlexander von Gluck IV 	// for debugging
240245fe001SAlexander von Gluck IV 	TRACE("D1CRTC_STATUS        Value: 0x%X\n", Read32(CRT, D1CRTC_STATUS));
241245fe001SAlexander von Gluck IV 	TRACE("D2CRTC_STATUS        Value: 0x%X\n", Read32(CRT, D2CRTC_STATUS));
242245fe001SAlexander von Gluck IV 	TRACE("D1CRTC_CONTROL       Value: 0x%X\n", Read32(CRT, D1CRTC_CONTROL));
243245fe001SAlexander von Gluck IV 	TRACE("D2CRTC_CONTROL       Value: 0x%X\n", Read32(CRT, D2CRTC_CONTROL));
244025d4eedSAlexander von Gluck IV 	TRACE("D1GRPH_ENABLE        Value: 0x%X\n",
245025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1GRPH_ENABLE));
246025d4eedSAlexander von Gluck IV 	TRACE("D2GRPH_ENABLE        Value: 0x%X\n",
247025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2GRPH_ENABLE));
248025d4eedSAlexander von Gluck IV 	TRACE("D1SCL_ENABLE         Value: 0x%X\n",
249025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE));
250025d4eedSAlexander von Gluck IV 	TRACE("D2SCL_ENABLE         Value: 0x%X\n",
251025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE));
25246af8165SAlexander von Gluck IV 	TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n",
253025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
25446af8165SAlexander von Gluck IV 	TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n",
255025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
2563be5e036SAlexander von Gluck IV 
257a90ebd77SClemens Zeidler 	return B_OK;
258a90ebd77SClemens Zeidler }
259a90ebd77SClemens Zeidler 
260a90ebd77SClemens Zeidler 
261a90ebd77SClemens Zeidler status_t
262a90ebd77SClemens Zeidler radeon_get_display_mode(display_mode* _currentMode)
263a90ebd77SClemens Zeidler {
264d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
265a90ebd77SClemens Zeidler 
266192781ddSAlexander von Gluck IV 	*_currentMode = gInfo->shared_info->current_mode;
267a90ebd77SClemens Zeidler 	return B_OK;
268a90ebd77SClemens Zeidler }
269a90ebd77SClemens Zeidler 
270a90ebd77SClemens Zeidler 
271a90ebd77SClemens Zeidler status_t
272a90ebd77SClemens Zeidler radeon_get_frame_buffer_config(frame_buffer_config* config)
273a90ebd77SClemens Zeidler {
274d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
275a90ebd77SClemens Zeidler 
2763be5e036SAlexander von Gluck IV 	config->frame_buffer = gInfo->shared_info->frame_buffer;
2773be5e036SAlexander von Gluck IV 	config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys;
27851a43d0fSAlexander von Gluck IV 
279a90ebd77SClemens Zeidler 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
280a90ebd77SClemens Zeidler 
281a90ebd77SClemens Zeidler 	return B_OK;
282a90ebd77SClemens Zeidler }
283a90ebd77SClemens Zeidler 
284a90ebd77SClemens Zeidler 
285a90ebd77SClemens Zeidler status_t
286a90ebd77SClemens Zeidler radeon_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high)
287a90ebd77SClemens Zeidler {
288d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
289e7e76b29SAlexander von Gluck IV 
290a90ebd77SClemens Zeidler 	if (_low != NULL) {
291a90ebd77SClemens Zeidler 		// lower limit of about 48Hz vertical refresh
2925f6744a8SAlexander von Gluck IV 		uint32 totalClocks = (uint32)mode->timing.h_total
2935f6744a8SAlexander von Gluck IV 			* (uint32)mode->timing.v_total;
294a90ebd77SClemens Zeidler 		uint32 low = (totalClocks * 48L) / 1000L;
295e7e76b29SAlexander von Gluck IV 
296d3e8b642SAlexander von Gluck IV 		if (low < PLL_MIN_DEFAULT)
297d3e8b642SAlexander von Gluck IV 			low = PLL_MIN_DEFAULT;
298d3e8b642SAlexander von Gluck IV 		else if (low > PLL_MAX_DEFAULT)
299a90ebd77SClemens Zeidler 			return B_ERROR;
300a90ebd77SClemens Zeidler 
301a90ebd77SClemens Zeidler 		*_low = low;
302a90ebd77SClemens Zeidler 	}
303a90ebd77SClemens Zeidler 
304a90ebd77SClemens Zeidler 	if (_high != NULL)
305d3e8b642SAlexander von Gluck IV 		*_high = PLL_MAX_DEFAULT;
306e7e76b29SAlexander von Gluck IV 
307e7e76b29SAlexander von Gluck IV 	//*_low = 48L;
308e7e76b29SAlexander von Gluck IV 	//*_high = 100 * 1000000L;
309a90ebd77SClemens Zeidler 	return B_OK;
310a90ebd77SClemens Zeidler }
311a90ebd77SClemens Zeidler 
312a90ebd77SClemens Zeidler 
313192781ddSAlexander von Gluck IV bool
314192781ddSAlexander von Gluck IV is_mode_supported(display_mode* mode)
315192781ddSAlexander von Gluck IV {
316f52ca69cSAlexander von Gluck IV 	bool sane = true;
317d1d65a79SAlexander von Gluck IV 
3181dac4469SAlexander von Gluck IV 	// Validate modeline is within a sane range
319192781ddSAlexander von Gluck IV 	if (is_mode_sane(mode) != B_OK)
320f52ca69cSAlexander von Gluck IV 		sane = false;
321192781ddSAlexander von Gluck IV 
32295e1d7e8SAlexander von Gluck IV 	// TODO: is_mode_supported on *which* display?
323d1d65a79SAlexander von Gluck IV 	uint32 crtid = 0;
3241dac4469SAlexander von Gluck IV 
325d1d65a79SAlexander von Gluck IV 	// if we have edid info, check frequency adginst crt reported valid ranges
326e1b9d6e6SAlexander von Gluck IV 	if (gInfo->shared_info->has_edid
327e1b9d6e6SAlexander von Gluck IV 		&& gDisplay[crtid]->found_ranges) {
3281dac4469SAlexander von Gluck IV 
329f52ca69cSAlexander von Gluck IV 		// validate horizontal frequency range
330d1d65a79SAlexander von Gluck IV 		uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total;
33195e1d7e8SAlexander von Gluck IV 		if (hfreq > gDisplay[crtid]->hfreq_max + 1
33295e1d7e8SAlexander von Gluck IV 			|| hfreq < gDisplay[crtid]->hfreq_min - 1) {
333f52ca69cSAlexander von Gluck IV 			//TRACE("!!! mode below falls outside of hfreq range!\n");
334f52ca69cSAlexander von Gluck IV 			sane = false;
335d1d65a79SAlexander von Gluck IV 		}
336d1d65a79SAlexander von Gluck IV 
337f52ca69cSAlexander von Gluck IV 		// validate vertical frequency range
338d1d65a79SAlexander von Gluck IV 		uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total
339d1d65a79SAlexander von Gluck IV 			* mode->timing.h_total) / 1000);
34095e1d7e8SAlexander von Gluck IV 		if (vfreq > gDisplay[crtid]->vfreq_max + 1
34195e1d7e8SAlexander von Gluck IV 			|| vfreq < gDisplay[crtid]->vfreq_min - 1) {
342f52ca69cSAlexander von Gluck IV 			//TRACE("!!! mode below falls outside of vfreq range!\n");
343f52ca69cSAlexander von Gluck IV 			sane = false;
344d1d65a79SAlexander von Gluck IV 		}
345e1b9d6e6SAlexander von Gluck IV 	}
346e1b9d6e6SAlexander von Gluck IV 
347f52ca69cSAlexander von Gluck IV 	TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n",
348f52ca69cSAlexander von Gluck IV 		mode->timing.pixel_clock, mode->timing.h_display,
349f52ca69cSAlexander von Gluck IV 		mode->timing.h_sync_start, mode->timing.h_sync_end,
350f52ca69cSAlexander von Gluck IV 		mode->timing.h_total, mode->timing.v_display,
351f52ca69cSAlexander von Gluck IV 		mode->timing.v_sync_start, mode->timing.v_sync_end,
352f52ca69cSAlexander von Gluck IV 		mode->timing.v_total,
353f52ca69cSAlexander von Gluck IV 		sane ? "OK." : "BAD, out of range!");
354192781ddSAlexander von Gluck IV 
355f52ca69cSAlexander von Gluck IV 	return sane;
356192781ddSAlexander von Gluck IV }
357192781ddSAlexander von Gluck IV 
358192781ddSAlexander von Gluck IV 
359d5c3acacSAlexander von Gluck IV /*
360d5c3acacSAlexander von Gluck IV  * A quick sanity check of the provided display_mode
361d5c3acacSAlexander von Gluck IV  */
362d5c3acacSAlexander von Gluck IV status_t
363192781ddSAlexander von Gluck IV is_mode_sane(display_mode* mode)
364d5c3acacSAlexander von Gluck IV {
365333bd770SAlexander von Gluck IV 	// horizontal timing
366333bd770SAlexander von Gluck IV 	// validate h_sync_start is less then h_sync_end
367333bd770SAlexander von Gluck IV 	if (mode->timing.h_sync_start > mode->timing.h_sync_end) {
36891235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
36991235829SAlexander von Gluck IV 			"received h_sync_start greater then h_sync_end!\n",
370333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
371333bd770SAlexander von Gluck IV 		return B_ERROR;
372333bd770SAlexander von Gluck IV 	}
373333bd770SAlexander von Gluck IV 	// validate h_total is greater then h_display
374333bd770SAlexander von Gluck IV 	if (mode->timing.h_total < mode->timing.h_display) {
37591235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
37691235829SAlexander von Gluck IV 			"received h_total greater then h_display!\n",
377333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
378d5c3acacSAlexander von Gluck IV 		return B_ERROR;
379d5c3acacSAlexander von Gluck IV 	}
380d5c3acacSAlexander von Gluck IV 
381333bd770SAlexander von Gluck IV 	// vertical timing
382333bd770SAlexander von Gluck IV 	// validate v_start is less then v_end
383333bd770SAlexander von Gluck IV 	if (mode->timing.v_sync_start > mode->timing.v_sync_end) {
38491235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
38591235829SAlexander von Gluck IV 			"received v_sync_start greater then v_sync_end!\n",
386333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
387d5c3acacSAlexander von Gluck IV 		return B_ERROR;
388d5c3acacSAlexander von Gluck IV 	}
389333bd770SAlexander von Gluck IV 	// validate v_total is greater then v_display
390333bd770SAlexander von Gluck IV 	if (mode->timing.v_total < mode->timing.v_display) {
39191235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
39291235829SAlexander von Gluck IV 			"received v_total greater then v_display!\n",
393333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
394d5c3acacSAlexander von Gluck IV 		return B_ERROR;
395d5c3acacSAlexander von Gluck IV 	}
396d5c3acacSAlexander von Gluck IV 
39791235829SAlexander von Gluck IV 	// calculate refresh rate for given timings to whole int (in Hz)
39891235829SAlexander von Gluck IV 	int refresh = mode->timing.pixel_clock * 1000
39991235829SAlexander von Gluck IV 		/ (mode->timing.h_total * mode->timing.v_total);
40091235829SAlexander von Gluck IV 
40191235829SAlexander von Gluck IV 	if (refresh < 30 || refresh > 250) {
40291235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
40391235829SAlexander von Gluck IV 			"refresh rate of %dHz is unlikely for any kind of monitor!\n",
40491235829SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display, refresh);
40591235829SAlexander von Gluck IV 		return B_ERROR;
40691235829SAlexander von Gluck IV 	}
40791235829SAlexander von Gluck IV 
408d5c3acacSAlexander von Gluck IV 	return B_OK;
409d5c3acacSAlexander von Gluck IV }
410d5c3acacSAlexander von Gluck IV 
411d1d65a79SAlexander von Gluck IV 
41209aaa658SAlexander von Gluck IV uint32
41309aaa658SAlexander von Gluck IV get_mode_bpp(display_mode* mode)
41409aaa658SAlexander von Gluck IV {
41509aaa658SAlexander von Gluck IV 	// Get bitsPerPixel for given mode
41609aaa658SAlexander von Gluck IV 
41709aaa658SAlexander von Gluck IV 	switch (mode->space) {
41809aaa658SAlexander von Gluck IV 		case B_CMAP8:
41909aaa658SAlexander von Gluck IV 			return 8;
42009aaa658SAlexander von Gluck IV 		case B_RGB15_LITTLE:
42109aaa658SAlexander von Gluck IV 			return 15;
42209aaa658SAlexander von Gluck IV 		case B_RGB16_LITTLE:
42309aaa658SAlexander von Gluck IV 			return 16;
42409aaa658SAlexander von Gluck IV 		case B_RGB24_LITTLE:
42509aaa658SAlexander von Gluck IV 		case B_RGB32_LITTLE:
42609aaa658SAlexander von Gluck IV 			return 32;
42709aaa658SAlexander von Gluck IV 	}
42809aaa658SAlexander von Gluck IV 	ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n",
42909aaa658SAlexander von Gluck IV 		__func__);
43009aaa658SAlexander von Gluck IV 	return 32;
43109aaa658SAlexander von Gluck IV }
432