xref: /haiku/src/add-ons/accelerants/radeon_hd/mode.cpp (revision 07a90a634dcc4f68fed1a426d566b78bdd0a736b)
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 
14a90ebd77SClemens Zeidler #include "accelerant_protos.h"
15a90ebd77SClemens Zeidler #include "accelerant.h"
16d77ff85eSAlexander von Gluck IV #include "bios.h"
17a90ebd77SClemens Zeidler #include "utility.h"
18d5c3acacSAlexander von Gluck IV #include "mode.h"
196ab8261bSAlexander von Gluck IV #include "display.h"
20d3e8b642SAlexander von Gluck IV #include "pll.h"
21a90ebd77SClemens Zeidler 
22a90ebd77SClemens Zeidler #include <stdio.h>
23a90ebd77SClemens Zeidler #include <string.h>
24a90ebd77SClemens Zeidler #include <math.h>
25a90ebd77SClemens Zeidler 
26192781ddSAlexander von Gluck IV #include <create_display_modes.h>
27192781ddSAlexander von Gluck IV 
28a90ebd77SClemens Zeidler 
29a90ebd77SClemens Zeidler #define TRACE_MODE
30a90ebd77SClemens Zeidler #ifdef TRACE_MODE
31a90ebd77SClemens Zeidler extern "C" void _sPrintf(const char *format, ...);
32d5c3acacSAlexander von Gluck IV #	define TRACE(x...) _sPrintf("radeon_hd: " x)
33a90ebd77SClemens Zeidler #else
34d5c3acacSAlexander von Gluck IV #	define TRACE(x...) ;
35a90ebd77SClemens Zeidler #endif
36a90ebd77SClemens Zeidler 
37a90ebd77SClemens Zeidler 
38a90ebd77SClemens Zeidler status_t
39a90ebd77SClemens Zeidler create_mode_list(void)
40a90ebd77SClemens Zeidler {
41f35af704SAlexander von Gluck IV 	// TODO: multi-monitor?  for now we use VESA and not gDisplay edid
42f35af704SAlexander von Gluck IV 
43192781ddSAlexander von Gluck IV 	const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
44192781ddSAlexander von Gluck IV 		B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
45a90ebd77SClemens Zeidler 
46192781ddSAlexander von Gluck IV 	gInfo->mode_list_area = create_display_modes("radeon HD modes",
472613175eSAlexander von Gluck IV 		gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL,
482613175eSAlexander von Gluck IV 		NULL, 0, kRadeonHDSpaces,
49192781ddSAlexander von Gluck IV 		sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]),
50192781ddSAlexander von Gluck IV 		is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count);
51192781ddSAlexander von Gluck IV 	if (gInfo->mode_list_area < B_OK)
52192781ddSAlexander von Gluck IV 		return gInfo->mode_list_area;
53a90ebd77SClemens Zeidler 
54192781ddSAlexander von Gluck IV 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
55d5c3acacSAlexander von Gluck IV 
56a90ebd77SClemens Zeidler 	return B_OK;
57a90ebd77SClemens Zeidler }
58a90ebd77SClemens Zeidler 
59a90ebd77SClemens Zeidler 
60a90ebd77SClemens Zeidler //	#pragma mark -
61a90ebd77SClemens Zeidler 
62a90ebd77SClemens Zeidler 
63a90ebd77SClemens Zeidler uint32
64a90ebd77SClemens Zeidler radeon_accelerant_mode_count(void)
65a90ebd77SClemens Zeidler {
66333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
67a90ebd77SClemens Zeidler 
68a90ebd77SClemens Zeidler 	return gInfo->shared_info->mode_count;
69a90ebd77SClemens Zeidler }
70a90ebd77SClemens Zeidler 
71a90ebd77SClemens Zeidler 
72a90ebd77SClemens Zeidler status_t
73a90ebd77SClemens Zeidler radeon_get_mode_list(display_mode *modeList)
74a90ebd77SClemens Zeidler {
75333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
76a90ebd77SClemens Zeidler 	memcpy(modeList, gInfo->mode_list,
77a90ebd77SClemens Zeidler 		gInfo->shared_info->mode_count * sizeof(display_mode));
78a90ebd77SClemens Zeidler 	return B_OK;
79a90ebd77SClemens Zeidler }
80a90ebd77SClemens Zeidler 
81a90ebd77SClemens Zeidler 
8288bfef92SAlexander von Gluck IV status_t
8388bfef92SAlexander von Gluck IV radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
8488bfef92SAlexander von Gluck IV {
85*07a90a63SAlexander von Gluck IV 	// TODO: multi-monitor?  for now we use VESA edid
86f35af704SAlexander von Gluck IV 
8788bfef92SAlexander von Gluck IV 	TRACE("%s\n", __func__);
8888bfef92SAlexander von Gluck IV 	if (!gInfo->shared_info->has_edid)
8988bfef92SAlexander von Gluck IV 		return B_ERROR;
9088bfef92SAlexander von Gluck IV 	if (size < sizeof(struct edid1_info))
9188bfef92SAlexander von Gluck IV 		return B_BUFFER_OVERFLOW;
9288bfef92SAlexander von Gluck IV 
9388bfef92SAlexander von Gluck IV 	memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
94*07a90a63SAlexander von Gluck IV 		// VESA
95*07a90a63SAlexander von Gluck IV 	//memcpy(info, &gDisplay[0]->edid_info, sizeof(struct edid1_info));
96*07a90a63SAlexander von Gluck IV 		// BitBanged display 0
97*07a90a63SAlexander von Gluck IV 
9888bfef92SAlexander von Gluck IV 	*edid_version = EDID_VERSION_1;
9988bfef92SAlexander von Gluck IV 
10088bfef92SAlexander von Gluck IV 	return B_OK;
10188bfef92SAlexander von Gluck IV }
10288bfef92SAlexander von Gluck IV 
10388bfef92SAlexander von Gluck IV 
1047934da0fSAlexander von Gluck IV uint32
1057934da0fSAlexander von Gluck IV radeon_dpms_capabilities(void)
1067934da0fSAlexander von Gluck IV {
1077934da0fSAlexander von Gluck IV 	// These should be pretty universally supported on Radeon HD cards
1087934da0fSAlexander von Gluck IV 	return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
1097934da0fSAlexander von Gluck IV }
1107934da0fSAlexander von Gluck IV 
1117934da0fSAlexander von Gluck IV 
1127934da0fSAlexander von Gluck IV uint32
1137934da0fSAlexander von Gluck IV radeon_dpms_mode(void)
1147934da0fSAlexander von Gluck IV {
1157934da0fSAlexander von Gluck IV 	// TODO: this really isn't a good long-term solution
1167934da0fSAlexander von Gluck IV 	// we may need to look at the encoder dpms scratch registers
1177934da0fSAlexander von Gluck IV 	return gInfo->dpms_mode;
1187934da0fSAlexander von Gluck IV }
1197934da0fSAlexander von Gluck IV 
1207934da0fSAlexander von Gluck IV 
121b54c8119SAlexander von Gluck IV void
122b54c8119SAlexander von Gluck IV radeon_dpms_set(int mode)
123b54c8119SAlexander von Gluck IV {
124f089aa52SAlexander von Gluck IV 	radeon_shared_info &info = *gInfo->shared_info;
125f089aa52SAlexander von Gluck IV 
126b54c8119SAlexander von Gluck IV 	switch(mode) {
127b54c8119SAlexander von Gluck IV 		case B_DPMS_ON:
128936aec74SAlexander von Gluck IV 			TRACE("%s: ON\n", __func__);
129b54c8119SAlexander von Gluck IV 			for (uint8 id = 0; id < MAX_DISPLAY; id++) {
130b54c8119SAlexander von Gluck IV 				if (gDisplay[id]->active == false)
131b54c8119SAlexander von Gluck IV 					continue;
132936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_ENABLE);
133b54c8119SAlexander von Gluck IV 				display_crtc_power(id, ATOM_ENABLE);
134f089aa52SAlexander von Gluck IV 				if (info.dceMajor >= 3)
135b54c8119SAlexander von Gluck IV 					display_crtc_memreq(id, ATOM_ENABLE);
136b54c8119SAlexander von Gluck IV 				display_crtc_blank(id, ATOM_DISABLE);
137936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_DISABLE);
138b54c8119SAlexander von Gluck IV 			}
139b54c8119SAlexander von Gluck IV 			break;
140b54c8119SAlexander von Gluck IV 		case B_DPMS_STAND_BY:
141b54c8119SAlexander von Gluck IV 		case B_DPMS_SUSPEND:
142b54c8119SAlexander von Gluck IV 		case B_DPMS_OFF:
143936aec74SAlexander von Gluck IV 			TRACE("%s: OFF\n", __func__);
144b54c8119SAlexander von Gluck IV 			for (uint8 id = 0; id < MAX_DISPLAY; id++) {
145b54c8119SAlexander von Gluck IV 				if (gDisplay[id]->active == false)
146b54c8119SAlexander von Gluck IV 					continue;
147936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_ENABLE);
148b54c8119SAlexander von Gluck IV 				display_crtc_blank(id, ATOM_ENABLE);
149f089aa52SAlexander von Gluck IV 				if (info.dceMajor >= 3)
150b54c8119SAlexander von Gluck IV 					display_crtc_memreq(id, ATOM_DISABLE);
151b54c8119SAlexander von Gluck IV 				display_crtc_power(id, ATOM_DISABLE);
152936aec74SAlexander von Gluck IV 				display_crtc_lock(id, ATOM_DISABLE);
153b54c8119SAlexander von Gluck IV 			}
154b54c8119SAlexander von Gluck IV 			break;
155b54c8119SAlexander von Gluck IV 	}
1567934da0fSAlexander von Gluck IV 	gInfo->dpms_mode = mode;
157b54c8119SAlexander von Gluck IV }
158b54c8119SAlexander von Gluck IV 
159b54c8119SAlexander von Gluck IV 
160a90ebd77SClemens Zeidler status_t
161a90ebd77SClemens Zeidler radeon_set_display_mode(display_mode *mode)
162a90ebd77SClemens Zeidler {
163f089aa52SAlexander von Gluck IV 	radeon_shared_info &info = *gInfo->shared_info;
164f089aa52SAlexander von Gluck IV 
1656ab8261bSAlexander von Gluck IV 	// Set mode on each display
1666ab8261bSAlexander von Gluck IV 	for (uint8 id = 0; id < MAX_DISPLAY; id++) {
167b54c8119SAlexander von Gluck IV 		if (gDisplay[id]->active == false)
1686ab8261bSAlexander von Gluck IV 			continue;
169f2fe29a0SAlexander von Gluck IV 
1706b0b621bSAlexander von Gluck IV 		uint16 connectorIndex = gDisplay[id]->connectorIndex;
17117b66d82SAlexander von Gluck IV 
172b54c8119SAlexander von Gluck IV 		// *** encoder prep
173b54c8119SAlexander von Gluck IV 		encoder_output_lock(true);
174e774cb4bSAlexander von Gluck IV 		encoder_dpms_set(id, gConnector[connectorIndex]->encoder.objectID,
175ffb494caSAlexander von Gluck IV 			B_DPMS_OFF);
17617b66d82SAlexander von Gluck IV 		encoder_assign_crtc(id);
177e53d6375SAlexander von Gluck IV 
178b54c8119SAlexander von Gluck IV 		// *** CRT controler prep
179b54c8119SAlexander von Gluck IV 		display_crtc_lock(id, ATOM_ENABLE);
180936aec74SAlexander von Gluck IV 		display_crtc_blank(id, ATOM_ENABLE);
181f089aa52SAlexander von Gluck IV 		if (info.dceMajor >= 3)
182936aec74SAlexander von Gluck IV 			display_crtc_memreq(id, ATOM_DISABLE);
183936aec74SAlexander von Gluck IV 		display_crtc_power(id, ATOM_DISABLE);
184f35af704SAlexander von Gluck IV 
185b54c8119SAlexander von Gluck IV 		// *** CRT controler mode set
18617b66d82SAlexander von Gluck IV 		// TODO: program SS
187e7d0abaeSAlexander von Gluck IV 		pll_set(ATOM_PPLL1, mode->timing.pixel_clock, id);
188e7d0abaeSAlexander von Gluck IV 			// TODO: check if ATOM_PPLL1 is used and use ATOM_PPLL2 if so
1896da3f7d4SAlexander von Gluck IV 		display_crtc_set_dtd(id, mode);
190b54c8119SAlexander von Gluck IV 
191afbd52f1SAlexander von Gluck IV 		display_crtc_fb_set(id, mode);
192b54c8119SAlexander von Gluck IV 		// atombios_overscan_setup
1936da3f7d4SAlexander von Gluck IV 		display_crtc_scale(id, mode);
1946ab8261bSAlexander von Gluck IV 
195b54c8119SAlexander von Gluck IV 		// *** encoder mode set
196b54c8119SAlexander von Gluck IV 		encoder_mode_set(id, mode->timing.pixel_clock);
197b54c8119SAlexander von Gluck IV 
198b54c8119SAlexander von Gluck IV 		// *** CRT controler commit
199936aec74SAlexander von Gluck IV 		display_crtc_power(id, ATOM_ENABLE);
200f089aa52SAlexander von Gluck IV 		if (info.dceMajor >= 3)
201245fe001SAlexander von Gluck IV 			display_crtc_memreq(id, ATOM_ENABLE);
202245fe001SAlexander von Gluck IV 		display_crtc_blank(id, ATOM_DISABLE);
2036da3f7d4SAlexander von Gluck IV 		display_crtc_lock(id, ATOM_DISABLE);
204b54c8119SAlexander von Gluck IV 
205b54c8119SAlexander von Gluck IV 		// *** encoder commit
206e774cb4bSAlexander von Gluck IV 		encoder_dpms_set(id, gConnector[connectorIndex]->encoder.objectID,
207ffb494caSAlexander von Gluck IV 			B_DPMS_ON);
208b54c8119SAlexander von Gluck IV 		encoder_output_lock(false);
2096ab8261bSAlexander von Gluck IV 	}
2106604b1b6SAlexander von Gluck IV 
211245fe001SAlexander von Gluck IV 	// for debugging
212245fe001SAlexander von Gluck IV 	TRACE("D1CRTC_STATUS     Value: 0x%X\n", Read32(CRT, D1CRTC_STATUS));
213245fe001SAlexander von Gluck IV 	TRACE("D2CRTC_STATUS     Value: 0x%X\n", Read32(CRT, D2CRTC_STATUS));
214245fe001SAlexander von Gluck IV 	TRACE("D1CRTC_CONTROL    Value: 0x%X\n", Read32(CRT, D1CRTC_CONTROL));
215245fe001SAlexander von Gluck IV 	TRACE("D2CRTC_CONTROL    Value: 0x%X\n", Read32(CRT, D2CRTC_CONTROL));
216245fe001SAlexander von Gluck IV 	TRACE("D1GRPH_ENABLE     Value: 0x%X\n", Read32(CRT, D1GRPH_ENABLE));
217245fe001SAlexander von Gluck IV 	TRACE("D2GRPH_ENABLE     Value: 0x%X\n", Read32(CRT, D2GRPH_ENABLE));
218245fe001SAlexander von Gluck IV 	TRACE("D1SCL_ENABLE      Value: 0x%X\n", Read32(CRT, D1SCL_ENABLE));
219245fe001SAlexander von Gluck IV 	TRACE("D2SCL_ENABLE      Value: 0x%X\n", Read32(CRT, D2SCL_ENABLE));
220245fe001SAlexander von Gluck IV 	TRACE("RV620_DACA_ENABLE Value: 0x%X\n", Read32(CRT, RV620_DACA_ENABLE));
221245fe001SAlexander von Gluck IV 	TRACE("RV620_DACB_ENABLE Value: 0x%X\n", Read32(CRT, RV620_DACB_ENABLE));
2223be5e036SAlexander von Gluck IV 
223a90ebd77SClemens Zeidler 	return B_OK;
224a90ebd77SClemens Zeidler }
225a90ebd77SClemens Zeidler 
226a90ebd77SClemens Zeidler 
227a90ebd77SClemens Zeidler status_t
228a90ebd77SClemens Zeidler radeon_get_display_mode(display_mode *_currentMode)
229a90ebd77SClemens Zeidler {
230d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
231a90ebd77SClemens Zeidler 
232192781ddSAlexander von Gluck IV 	*_currentMode = gInfo->shared_info->current_mode;
233a90ebd77SClemens Zeidler 	return B_OK;
234a90ebd77SClemens Zeidler }
235a90ebd77SClemens Zeidler 
236a90ebd77SClemens Zeidler 
237a90ebd77SClemens Zeidler status_t
238a90ebd77SClemens Zeidler radeon_get_frame_buffer_config(frame_buffer_config *config)
239a90ebd77SClemens Zeidler {
240d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
241a90ebd77SClemens Zeidler 
2423be5e036SAlexander von Gluck IV 	config->frame_buffer = gInfo->shared_info->frame_buffer;
2433be5e036SAlexander von Gluck IV 	config->frame_buffer_dma = (uint8 *)gInfo->shared_info->frame_buffer_phys;
24451a43d0fSAlexander von Gluck IV 
245a90ebd77SClemens Zeidler 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
246a90ebd77SClemens Zeidler 
247a90ebd77SClemens Zeidler 	return B_OK;
248a90ebd77SClemens Zeidler }
249a90ebd77SClemens Zeidler 
250a90ebd77SClemens Zeidler 
251a90ebd77SClemens Zeidler status_t
252a90ebd77SClemens Zeidler radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high)
253a90ebd77SClemens Zeidler {
254d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
255e7e76b29SAlexander von Gluck IV 
256a90ebd77SClemens Zeidler 	if (_low != NULL) {
257a90ebd77SClemens Zeidler 		// lower limit of about 48Hz vertical refresh
2585f6744a8SAlexander von Gluck IV 		uint32 totalClocks = (uint32)mode->timing.h_total
2595f6744a8SAlexander von Gluck IV 			*(uint32)mode->timing.v_total;
260a90ebd77SClemens Zeidler 		uint32 low = (totalClocks * 48L) / 1000L;
261e7e76b29SAlexander von Gluck IV 
262d3e8b642SAlexander von Gluck IV 		if (low < PLL_MIN_DEFAULT)
263d3e8b642SAlexander von Gluck IV 			low = PLL_MIN_DEFAULT;
264d3e8b642SAlexander von Gluck IV 		else if (low > PLL_MAX_DEFAULT)
265a90ebd77SClemens Zeidler 			return B_ERROR;
266a90ebd77SClemens Zeidler 
267a90ebd77SClemens Zeidler 		*_low = low;
268a90ebd77SClemens Zeidler 	}
269a90ebd77SClemens Zeidler 
270a90ebd77SClemens Zeidler 	if (_high != NULL)
271d3e8b642SAlexander von Gluck IV 		*_high = PLL_MAX_DEFAULT;
272e7e76b29SAlexander von Gluck IV 
273e7e76b29SAlexander von Gluck IV 	//*_low = 48L;
274e7e76b29SAlexander von Gluck IV 	//*_high = 100 * 1000000L;
275a90ebd77SClemens Zeidler 	return B_OK;
276a90ebd77SClemens Zeidler }
277a90ebd77SClemens Zeidler 
278a90ebd77SClemens Zeidler 
279192781ddSAlexander von Gluck IV bool
280192781ddSAlexander von Gluck IV is_mode_supported(display_mode *mode)
281192781ddSAlexander von Gluck IV {
282d1d65a79SAlexander von Gluck IV 	TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d\n",
283d1d65a79SAlexander von Gluck IV 		mode->timing.pixel_clock, mode->timing.h_display,
284d1d65a79SAlexander von Gluck IV 		mode->timing.h_sync_start, mode->timing.h_sync_end,
285d1d65a79SAlexander von Gluck IV 		mode->timing.h_total, mode->timing.v_display,
286d1d65a79SAlexander von Gluck IV 		mode->timing.v_sync_start, mode->timing.v_sync_end,
287d1d65a79SAlexander von Gluck IV 		mode->timing.v_total);
288d1d65a79SAlexander von Gluck IV 
2891dac4469SAlexander von Gluck IV 	// Validate modeline is within a sane range
290192781ddSAlexander von Gluck IV 	if (is_mode_sane(mode) != B_OK)
291192781ddSAlexander von Gluck IV 		return false;
292192781ddSAlexander von Gluck IV 
29395e1d7e8SAlexander von Gluck IV 	// TODO: is_mode_supported on *which* display?
294d1d65a79SAlexander von Gluck IV 	uint32 crtid = 0;
2951dac4469SAlexander von Gluck IV 
296d1d65a79SAlexander von Gluck IV 	// if we have edid info, check frequency adginst crt reported valid ranges
297e1b9d6e6SAlexander von Gluck IV 	if (gInfo->shared_info->has_edid
298e1b9d6e6SAlexander von Gluck IV 		&& gDisplay[crtid]->found_ranges) {
2991dac4469SAlexander von Gluck IV 
300d1d65a79SAlexander von Gluck IV 		uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total;
30195e1d7e8SAlexander von Gluck IV 		if (hfreq > gDisplay[crtid]->hfreq_max + 1
30295e1d7e8SAlexander von Gluck IV 			|| hfreq < gDisplay[crtid]->hfreq_min - 1) {
303d1d65a79SAlexander von Gluck IV 			TRACE("!!! hfreq : %d , hfreq_min : %d, hfreq_max : %d\n",
30495e1d7e8SAlexander von Gluck IV 				hfreq, gDisplay[crtid]->hfreq_min, gDisplay[crtid]->hfreq_max);
305d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid "
306d1d65a79SAlexander von Gluck IV 				"horizontal range.\n", mode->timing.h_display,
307d1d65a79SAlexander von Gluck IV 				mode->timing.v_display, crtid);
308d1d65a79SAlexander von Gluck IV 			return false;
309d1d65a79SAlexander von Gluck IV 		}
310d1d65a79SAlexander von Gluck IV 
311d1d65a79SAlexander von Gluck IV 		uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total
312d1d65a79SAlexander von Gluck IV 			* mode->timing.h_total) / 1000);
313d1d65a79SAlexander von Gluck IV 
31495e1d7e8SAlexander von Gluck IV 		if (vfreq > gDisplay[crtid]->vfreq_max + 1
31595e1d7e8SAlexander von Gluck IV 			|| vfreq < gDisplay[crtid]->vfreq_min - 1) {
316d1d65a79SAlexander von Gluck IV 			TRACE("!!! vfreq : %d , vfreq_min : %d, vfreq_max : %d\n",
31795e1d7e8SAlexander von Gluck IV 				vfreq, gDisplay[crtid]->vfreq_min, gDisplay[crtid]->vfreq_max);
318d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid vertical range\n",
319d1d65a79SAlexander von Gluck IV 				mode->timing.h_display, mode->timing.v_display, crtid);
320d1d65a79SAlexander von Gluck IV 			return false;
321d1d65a79SAlexander von Gluck IV 		}
322e1b9d6e6SAlexander von Gluck IV 	}
323e1b9d6e6SAlexander von Gluck IV 
324d1d65a79SAlexander von Gluck IV 	TRACE("%dx%d is within CRT %d's valid frequency range\n",
325d1d65a79SAlexander von Gluck IV 		mode->timing.h_display, mode->timing.v_display, crtid);
326192781ddSAlexander von Gluck IV 
327192781ddSAlexander von Gluck IV 	return true;
328192781ddSAlexander von Gluck IV }
329192781ddSAlexander von Gluck IV 
330192781ddSAlexander von Gluck IV 
331d5c3acacSAlexander von Gluck IV /*
332d5c3acacSAlexander von Gluck IV  * A quick sanity check of the provided display_mode
333d5c3acacSAlexander von Gluck IV  */
334d5c3acacSAlexander von Gluck IV status_t
335192781ddSAlexander von Gluck IV is_mode_sane(display_mode *mode)
336d5c3acacSAlexander von Gluck IV {
337333bd770SAlexander von Gluck IV 	// horizontal timing
338333bd770SAlexander von Gluck IV 	// validate h_sync_start is less then h_sync_end
339333bd770SAlexander von Gluck IV 	if (mode->timing.h_sync_start > mode->timing.h_sync_end) {
34091235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
34191235829SAlexander von Gluck IV 			"received h_sync_start greater then h_sync_end!\n",
342333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
343333bd770SAlexander von Gluck IV 		return B_ERROR;
344333bd770SAlexander von Gluck IV 	}
345333bd770SAlexander von Gluck IV 	// validate h_total is greater then h_display
346333bd770SAlexander von Gluck IV 	if (mode->timing.h_total < mode->timing.h_display) {
34791235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
34891235829SAlexander von Gluck IV 			"received h_total greater then h_display!\n",
349333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
350d5c3acacSAlexander von Gluck IV 		return B_ERROR;
351d5c3acacSAlexander von Gluck IV 	}
352d5c3acacSAlexander von Gluck IV 
353333bd770SAlexander von Gluck IV 	// vertical timing
354333bd770SAlexander von Gluck IV 	// validate v_start is less then v_end
355333bd770SAlexander von Gluck IV 	if (mode->timing.v_sync_start > mode->timing.v_sync_end) {
35691235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
35791235829SAlexander von Gluck IV 			"received v_sync_start greater then v_sync_end!\n",
358333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
359d5c3acacSAlexander von Gluck IV 		return B_ERROR;
360d5c3acacSAlexander von Gluck IV 	}
361333bd770SAlexander von Gluck IV 	// validate v_total is greater then v_display
362333bd770SAlexander von Gluck IV 	if (mode->timing.v_total < mode->timing.v_display) {
36391235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
36491235829SAlexander von Gluck IV 			"received v_total greater then v_display!\n",
365333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
366d5c3acacSAlexander von Gluck IV 		return B_ERROR;
367d5c3acacSAlexander von Gluck IV 	}
368d5c3acacSAlexander von Gluck IV 
36991235829SAlexander von Gluck IV 	// calculate refresh rate for given timings to whole int (in Hz)
37091235829SAlexander von Gluck IV 	int refresh = mode->timing.pixel_clock * 1000
37191235829SAlexander von Gluck IV 		/ (mode->timing.h_total * mode->timing.v_total);
37291235829SAlexander von Gluck IV 
37391235829SAlexander von Gluck IV 	if (refresh < 30 || refresh > 250) {
37491235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
37591235829SAlexander von Gluck IV 			"refresh rate of %dHz is unlikely for any kind of monitor!\n",
37691235829SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display, refresh);
37791235829SAlexander von Gluck IV 		return B_ERROR;
37891235829SAlexander von Gluck IV 	}
37991235829SAlexander von Gluck IV 
380d5c3acacSAlexander von Gluck IV 	return B_OK;
381d5c3acacSAlexander von Gluck IV }
382d5c3acacSAlexander von Gluck IV 
383d1d65a79SAlexander von Gluck IV 
384