xref: /haiku/src/add-ons/accelerants/radeon_hd/mode.cpp (revision 025d4eed52f31e0047268227cde722164e52e2d8)
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 {
8507a90a63SAlexander 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));
9407a90a63SAlexander von Gluck IV 		// VESA
9507a90a63SAlexander von Gluck IV 	//memcpy(info, &gDisplay[0]->edid_info, sizeof(struct edid1_info));
9607a90a63SAlexander von Gluck IV 		// BitBanged display 0
9707a90a63SAlexander 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);
1366c80b06bSAlexander von Gluck IV 				display_crtc_blank(id, ATOM_BLANKING_OFF);
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);
1486c80b06bSAlexander von Gluck IV 				display_crtc_blank(id, ATOM_BLANKING);
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);
1806c80b06bSAlexander von Gluck IV 		display_crtc_blank(id, ATOM_BLANKING);
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);
2026c80b06bSAlexander von Gluck IV 		display_crtc_blank(id, ATOM_BLANKING_OFF);
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));
216*025d4eedSAlexander von Gluck IV 	TRACE("D1GRPH_ENABLE        Value: 0x%X\n",
217*025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1GRPH_ENABLE));
218*025d4eedSAlexander von Gluck IV 	TRACE("D2GRPH_ENABLE        Value: 0x%X\n",
219*025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2GRPH_ENABLE));
220*025d4eedSAlexander von Gluck IV 	TRACE("D1SCL_ENABLE         Value: 0x%X\n",
221*025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE));
222*025d4eedSAlexander von Gluck IV 	TRACE("D2SCL_ENABLE         Value: 0x%X\n",
223*025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE));
22446af8165SAlexander von Gluck IV 	TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n",
225*025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
22646af8165SAlexander von Gluck IV 	TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n",
227*025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
2283be5e036SAlexander von Gluck IV 
229a90ebd77SClemens Zeidler 	return B_OK;
230a90ebd77SClemens Zeidler }
231a90ebd77SClemens Zeidler 
232a90ebd77SClemens Zeidler 
233a90ebd77SClemens Zeidler status_t
234a90ebd77SClemens Zeidler radeon_get_display_mode(display_mode *_currentMode)
235a90ebd77SClemens Zeidler {
236d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
237a90ebd77SClemens Zeidler 
238192781ddSAlexander von Gluck IV 	*_currentMode = gInfo->shared_info->current_mode;
239a90ebd77SClemens Zeidler 	return B_OK;
240a90ebd77SClemens Zeidler }
241a90ebd77SClemens Zeidler 
242a90ebd77SClemens Zeidler 
243a90ebd77SClemens Zeidler status_t
244a90ebd77SClemens Zeidler radeon_get_frame_buffer_config(frame_buffer_config *config)
245a90ebd77SClemens Zeidler {
246d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
247a90ebd77SClemens Zeidler 
2483be5e036SAlexander von Gluck IV 	config->frame_buffer = gInfo->shared_info->frame_buffer;
2493be5e036SAlexander von Gluck IV 	config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys;
25051a43d0fSAlexander von Gluck IV 
251a90ebd77SClemens Zeidler 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
252a90ebd77SClemens Zeidler 
253a90ebd77SClemens Zeidler 	return B_OK;
254a90ebd77SClemens Zeidler }
255a90ebd77SClemens Zeidler 
256a90ebd77SClemens Zeidler 
257a90ebd77SClemens Zeidler status_t
258a90ebd77SClemens Zeidler radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high)
259a90ebd77SClemens Zeidler {
260d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
261e7e76b29SAlexander von Gluck IV 
262a90ebd77SClemens Zeidler 	if (_low != NULL) {
263a90ebd77SClemens Zeidler 		// lower limit of about 48Hz vertical refresh
2645f6744a8SAlexander von Gluck IV 		uint32 totalClocks = (uint32)mode->timing.h_total
2655f6744a8SAlexander von Gluck IV 			*(uint32)mode->timing.v_total;
266a90ebd77SClemens Zeidler 		uint32 low = (totalClocks * 48L) / 1000L;
267e7e76b29SAlexander von Gluck IV 
268d3e8b642SAlexander von Gluck IV 		if (low < PLL_MIN_DEFAULT)
269d3e8b642SAlexander von Gluck IV 			low = PLL_MIN_DEFAULT;
270d3e8b642SAlexander von Gluck IV 		else if (low > PLL_MAX_DEFAULT)
271a90ebd77SClemens Zeidler 			return B_ERROR;
272a90ebd77SClemens Zeidler 
273a90ebd77SClemens Zeidler 		*_low = low;
274a90ebd77SClemens Zeidler 	}
275a90ebd77SClemens Zeidler 
276a90ebd77SClemens Zeidler 	if (_high != NULL)
277d3e8b642SAlexander von Gluck IV 		*_high = PLL_MAX_DEFAULT;
278e7e76b29SAlexander von Gluck IV 
279e7e76b29SAlexander von Gluck IV 	//*_low = 48L;
280e7e76b29SAlexander von Gluck IV 	//*_high = 100 * 1000000L;
281a90ebd77SClemens Zeidler 	return B_OK;
282a90ebd77SClemens Zeidler }
283a90ebd77SClemens Zeidler 
284a90ebd77SClemens Zeidler 
285192781ddSAlexander von Gluck IV bool
286192781ddSAlexander von Gluck IV is_mode_supported(display_mode *mode)
287192781ddSAlexander von Gluck IV {
288d1d65a79SAlexander von Gluck IV 	TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d\n",
289d1d65a79SAlexander von Gluck IV 		mode->timing.pixel_clock, mode->timing.h_display,
290d1d65a79SAlexander von Gluck IV 		mode->timing.h_sync_start, mode->timing.h_sync_end,
291d1d65a79SAlexander von Gluck IV 		mode->timing.h_total, mode->timing.v_display,
292d1d65a79SAlexander von Gluck IV 		mode->timing.v_sync_start, mode->timing.v_sync_end,
293d1d65a79SAlexander von Gluck IV 		mode->timing.v_total);
294d1d65a79SAlexander von Gluck IV 
2951dac4469SAlexander von Gluck IV 	// Validate modeline is within a sane range
296192781ddSAlexander von Gluck IV 	if (is_mode_sane(mode) != B_OK)
297192781ddSAlexander von Gluck IV 		return false;
298192781ddSAlexander von Gluck IV 
29995e1d7e8SAlexander von Gluck IV 	// TODO: is_mode_supported on *which* display?
300d1d65a79SAlexander von Gluck IV 	uint32 crtid = 0;
3011dac4469SAlexander von Gluck IV 
302d1d65a79SAlexander von Gluck IV 	// if we have edid info, check frequency adginst crt reported valid ranges
303e1b9d6e6SAlexander von Gluck IV 	if (gInfo->shared_info->has_edid
304e1b9d6e6SAlexander von Gluck IV 		&& gDisplay[crtid]->found_ranges) {
3051dac4469SAlexander von Gluck IV 
306d1d65a79SAlexander von Gluck IV 		uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total;
30795e1d7e8SAlexander von Gluck IV 		if (hfreq > gDisplay[crtid]->hfreq_max + 1
30895e1d7e8SAlexander von Gluck IV 			|| hfreq < gDisplay[crtid]->hfreq_min - 1) {
309d1d65a79SAlexander von Gluck IV 			TRACE("!!! hfreq : %d , hfreq_min : %d, hfreq_max : %d\n",
31095e1d7e8SAlexander von Gluck IV 				hfreq, gDisplay[crtid]->hfreq_min, gDisplay[crtid]->hfreq_max);
311d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid "
312d1d65a79SAlexander von Gluck IV 				"horizontal range.\n", mode->timing.h_display,
313d1d65a79SAlexander von Gluck IV 				mode->timing.v_display, crtid);
314d1d65a79SAlexander von Gluck IV 			return false;
315d1d65a79SAlexander von Gluck IV 		}
316d1d65a79SAlexander von Gluck IV 
317d1d65a79SAlexander von Gluck IV 		uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total
318d1d65a79SAlexander von Gluck IV 			* mode->timing.h_total) / 1000);
319d1d65a79SAlexander von Gluck IV 
32095e1d7e8SAlexander von Gluck IV 		if (vfreq > gDisplay[crtid]->vfreq_max + 1
32195e1d7e8SAlexander von Gluck IV 			|| vfreq < gDisplay[crtid]->vfreq_min - 1) {
322d1d65a79SAlexander von Gluck IV 			TRACE("!!! vfreq : %d , vfreq_min : %d, vfreq_max : %d\n",
32395e1d7e8SAlexander von Gluck IV 				vfreq, gDisplay[crtid]->vfreq_min, gDisplay[crtid]->vfreq_max);
324d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid vertical range\n",
325d1d65a79SAlexander von Gluck IV 				mode->timing.h_display, mode->timing.v_display, crtid);
326d1d65a79SAlexander von Gluck IV 			return false;
327d1d65a79SAlexander von Gluck IV 		}
328e1b9d6e6SAlexander von Gluck IV 	}
329e1b9d6e6SAlexander von Gluck IV 
330d1d65a79SAlexander von Gluck IV 	TRACE("%dx%d is within CRT %d's valid frequency range\n",
331d1d65a79SAlexander von Gluck IV 		mode->timing.h_display, mode->timing.v_display, crtid);
332192781ddSAlexander von Gluck IV 
333192781ddSAlexander von Gluck IV 	return true;
334192781ddSAlexander von Gluck IV }
335192781ddSAlexander von Gluck IV 
336192781ddSAlexander von Gluck IV 
337d5c3acacSAlexander von Gluck IV /*
338d5c3acacSAlexander von Gluck IV  * A quick sanity check of the provided display_mode
339d5c3acacSAlexander von Gluck IV  */
340d5c3acacSAlexander von Gluck IV status_t
341192781ddSAlexander von Gluck IV is_mode_sane(display_mode *mode)
342d5c3acacSAlexander von Gluck IV {
343333bd770SAlexander von Gluck IV 	// horizontal timing
344333bd770SAlexander von Gluck IV 	// validate h_sync_start is less then h_sync_end
345333bd770SAlexander von Gluck IV 	if (mode->timing.h_sync_start > mode->timing.h_sync_end) {
34691235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
34791235829SAlexander von Gluck IV 			"received h_sync_start greater then h_sync_end!\n",
348333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
349333bd770SAlexander von Gluck IV 		return B_ERROR;
350333bd770SAlexander von Gluck IV 	}
351333bd770SAlexander von Gluck IV 	// validate h_total is greater then h_display
352333bd770SAlexander von Gluck IV 	if (mode->timing.h_total < mode->timing.h_display) {
35391235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
35491235829SAlexander von Gluck IV 			"received h_total greater then h_display!\n",
355333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
356d5c3acacSAlexander von Gluck IV 		return B_ERROR;
357d5c3acacSAlexander von Gluck IV 	}
358d5c3acacSAlexander von Gluck IV 
359333bd770SAlexander von Gluck IV 	// vertical timing
360333bd770SAlexander von Gluck IV 	// validate v_start is less then v_end
361333bd770SAlexander von Gluck IV 	if (mode->timing.v_sync_start > mode->timing.v_sync_end) {
36291235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
36391235829SAlexander von Gluck IV 			"received v_sync_start greater then v_sync_end!\n",
364333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
365d5c3acacSAlexander von Gluck IV 		return B_ERROR;
366d5c3acacSAlexander von Gluck IV 	}
367333bd770SAlexander von Gluck IV 	// validate v_total is greater then v_display
368333bd770SAlexander von Gluck IV 	if (mode->timing.v_total < mode->timing.v_display) {
36991235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
37091235829SAlexander von Gluck IV 			"received v_total greater then v_display!\n",
371333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
372d5c3acacSAlexander von Gluck IV 		return B_ERROR;
373d5c3acacSAlexander von Gluck IV 	}
374d5c3acacSAlexander von Gluck IV 
37591235829SAlexander von Gluck IV 	// calculate refresh rate for given timings to whole int (in Hz)
37691235829SAlexander von Gluck IV 	int refresh = mode->timing.pixel_clock * 1000
37791235829SAlexander von Gluck IV 		/ (mode->timing.h_total * mode->timing.v_total);
37891235829SAlexander von Gluck IV 
37991235829SAlexander von Gluck IV 	if (refresh < 30 || refresh > 250) {
38091235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
38191235829SAlexander von Gluck IV 			"refresh rate of %dHz is unlikely for any kind of monitor!\n",
38291235829SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display, refresh);
38391235829SAlexander von Gluck IV 		return B_ERROR;
38491235829SAlexander von Gluck IV 	}
38591235829SAlexander von Gluck IV 
386d5c3acacSAlexander von Gluck IV 	return B_OK;
387d5c3acacSAlexander von Gluck IV }
388d5c3acacSAlexander von Gluck IV 
389d1d65a79SAlexander von Gluck IV 
390