xref: /haiku/src/add-ons/accelerants/radeon_hd/mode.cpp (revision 46b7da1f4f40f7157d74fc7fb26ff9ec7f2416f2)
1a90ebd77SClemens Zeidler /*
200bc40adSAlexander von Gluck IV  * Copyright 2006-2013, 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 
42d2a69507SAlexander von Gluck IV 
43a90ebd77SClemens Zeidler status_t
create_mode_list(void)44a90ebd77SClemens Zeidler create_mode_list(void)
45a90ebd77SClemens Zeidler {
46f35af704SAlexander von Gluck IV 	// TODO: multi-monitor?  for now we use VESA and not gDisplay edid
47878a8d3fSAlexander von Gluck IV 	uint8 crtcID = 0;
48f35af704SAlexander von Gluck IV 
49192781ddSAlexander von Gluck IV 	const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
50192781ddSAlexander von Gluck IV 		B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
51a90ebd77SClemens Zeidler 
52192781ddSAlexander von Gluck IV 	gInfo->mode_list_area = create_display_modes("radeon HD modes",
53878a8d3fSAlexander von Gluck IV 		&gDisplay[crtcID]->edidData, NULL, 0, kRadeonHDSpaces,
543de924d0SAlexander von Gluck IV 		B_COUNT_OF(kRadeonHDSpaces), is_mode_supported, &gInfo->mode_list,
553de924d0SAlexander von Gluck IV 		&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
radeon_accelerant_mode_count(void)69a90ebd77SClemens Zeidler radeon_accelerant_mode_count(void)
70a90ebd77SClemens Zeidler {
71333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
7200bc40adSAlexander von Gluck IV 	// TODO: multi-monitor?  we need crtcid here
73a90ebd77SClemens Zeidler 
74a90ebd77SClemens Zeidler 	return gInfo->shared_info->mode_count;
75a90ebd77SClemens Zeidler }
76a90ebd77SClemens Zeidler 
77a90ebd77SClemens Zeidler 
78a90ebd77SClemens Zeidler status_t
radeon_get_mode_list(display_mode * modeList)79a90ebd77SClemens Zeidler radeon_get_mode_list(display_mode* modeList)
80a90ebd77SClemens Zeidler {
81333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
8200bc40adSAlexander von Gluck IV 	// TODO: multi-monitor?  we need crtcid here
83a90ebd77SClemens Zeidler 	memcpy(modeList, gInfo->mode_list,
84a90ebd77SClemens Zeidler 		gInfo->shared_info->mode_count * sizeof(display_mode));
85a90ebd77SClemens Zeidler 	return B_OK;
86a90ebd77SClemens Zeidler }
87a90ebd77SClemens Zeidler 
88a90ebd77SClemens Zeidler 
8988bfef92SAlexander von Gluck IV status_t
radeon_get_preferred_mode(display_mode * preferredMode)904bd6c200SAlexander von Gluck IV radeon_get_preferred_mode(display_mode* preferredMode)
914bd6c200SAlexander von Gluck IV {
924bd6c200SAlexander von Gluck IV 	TRACE("%s\n", __func__);
9300bc40adSAlexander von Gluck IV 	// TODO: multi-monitor?  we need crtcid here
944bd6c200SAlexander von Gluck IV 
954bd6c200SAlexander von Gluck IV 	uint8_t crtc = 0;
964bd6c200SAlexander von Gluck IV 
974bd6c200SAlexander von Gluck IV 	if (gDisplay[crtc]->preferredMode.virtual_width > 0
984bd6c200SAlexander von Gluck IV 		&& gDisplay[crtc]->preferredMode.virtual_height > 0) {
994bd6c200SAlexander von Gluck IV 		TRACE("%s: preferred mode was found for display %" B_PRIu8 "\n",
1004bd6c200SAlexander von Gluck IV 			__func__, crtc);
1014bd6c200SAlexander von Gluck IV 		memcpy(preferredMode, &gDisplay[crtc]->preferredMode,
1024bd6c200SAlexander von Gluck IV 			sizeof(gDisplay[crtc]->preferredMode));
1034bd6c200SAlexander von Gluck IV 		return B_OK;
1044bd6c200SAlexander von Gluck IV 	}
1054bd6c200SAlexander von Gluck IV 
1064bd6c200SAlexander von Gluck IV 	return B_ERROR;
1074bd6c200SAlexander von Gluck IV }
1084bd6c200SAlexander von Gluck IV 
1094bd6c200SAlexander von Gluck IV 
1104bd6c200SAlexander von Gluck IV status_t
radeon_get_edid_info(void * info,size_t size,uint32 * edid_version)11188bfef92SAlexander von Gluck IV radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
11288bfef92SAlexander von Gluck IV {
113339a0181SAlexander von Gluck IV 	// TODO: multi-monitor?  for now we use display 0
114878a8d3fSAlexander von Gluck IV 	uint8 crtcID = 0;
115f35af704SAlexander von Gluck IV 
11688bfef92SAlexander von Gluck IV 	TRACE("%s\n", __func__);
11788bfef92SAlexander von Gluck IV 	if (!gInfo->shared_info->has_edid)
11888bfef92SAlexander von Gluck IV 		return B_ERROR;
11988bfef92SAlexander von Gluck IV 	if (size < sizeof(struct edid1_info))
12088bfef92SAlexander von Gluck IV 		return B_BUFFER_OVERFLOW;
12188bfef92SAlexander von Gluck IV 
122878a8d3fSAlexander von Gluck IV 	//memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
12307a90a63SAlexander von Gluck IV 		// VESA
124878a8d3fSAlexander von Gluck IV 	memcpy(info, &gDisplay[crtcID]->edidData, sizeof(struct edid1_info));
12500bc40adSAlexander von Gluck IV 		// Display 0
12607a90a63SAlexander von Gluck IV 
12788bfef92SAlexander von Gluck IV 	*edid_version = EDID_VERSION_1;
12888bfef92SAlexander von Gluck IV 
12988bfef92SAlexander von Gluck IV 	return B_OK;
13088bfef92SAlexander von Gluck IV }
13188bfef92SAlexander von Gluck IV 
13288bfef92SAlexander von Gluck IV 
1337934da0fSAlexander von Gluck IV uint32
radeon_dpms_capabilities(void)1347934da0fSAlexander von Gluck IV radeon_dpms_capabilities(void)
1357934da0fSAlexander von Gluck IV {
1367934da0fSAlexander von Gluck IV 	// These should be pretty universally supported on Radeon HD cards
1377934da0fSAlexander von Gluck IV 	return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF;
1387934da0fSAlexander von Gluck IV }
1397934da0fSAlexander von Gluck IV 
1407934da0fSAlexander von Gluck IV 
1417934da0fSAlexander von Gluck IV uint32
radeon_dpms_mode(void)1427934da0fSAlexander von Gluck IV radeon_dpms_mode(void)
1437934da0fSAlexander von Gluck IV {
1447934da0fSAlexander von Gluck IV 	// TODO: this really isn't a good long-term solution
1457934da0fSAlexander von Gluck IV 	// we may need to look at the encoder dpms scratch registers
1467934da0fSAlexander von Gluck IV 	return gInfo->dpms_mode;
1477934da0fSAlexander von Gluck IV }
1487934da0fSAlexander von Gluck IV 
1497934da0fSAlexander von Gluck IV 
150b54c8119SAlexander von Gluck IV void
radeon_dpms_set(uint8 id,int mode)15100bc40adSAlexander von Gluck IV radeon_dpms_set(uint8 id, int mode)
152b54c8119SAlexander von Gluck IV {
15300bc40adSAlexander von Gluck IV 	if (mode == B_DPMS_ON) {
15400bc40adSAlexander von Gluck IV 		display_crtc_dpms(id, mode);
15500bc40adSAlexander von Gluck IV 		encoder_dpms_set(id, mode);
15600bc40adSAlexander von Gluck IV 	} else {
15764ff3d18SAlexander von Gluck IV 		encoder_dpms_set(id, mode);
1582399d174SAlexander von Gluck IV 		display_crtc_dpms(id, mode);
15964ff3d18SAlexander von Gluck IV 	}
1607934da0fSAlexander von Gluck IV 	gInfo->dpms_mode = mode;
161b54c8119SAlexander von Gluck IV }
162b54c8119SAlexander von Gluck IV 
163b54c8119SAlexander von Gluck IV 
16400bc40adSAlexander von Gluck IV void
radeon_dpms_set_hook(int mode)16500bc40adSAlexander von Gluck IV radeon_dpms_set_hook(int mode)
16600bc40adSAlexander von Gluck IV {
167339a0181SAlexander von Gluck IV 	// TODO: multi-monitor?
16800bc40adSAlexander von Gluck IV 
169339a0181SAlexander von Gluck IV 	uint8 crtcID = 0;
170339a0181SAlexander von Gluck IV 
171339a0181SAlexander von Gluck IV 	if (gDisplay[crtcID]->attached)
172339a0181SAlexander von Gluck IV 		radeon_dpms_set(crtcID, mode);
17300bc40adSAlexander von Gluck IV }
17400bc40adSAlexander von Gluck IV 
17500bc40adSAlexander von Gluck IV 
176a90ebd77SClemens Zeidler status_t
radeon_set_display_mode(display_mode * mode)177a90ebd77SClemens Zeidler radeon_set_display_mode(display_mode* mode)
178a90ebd77SClemens Zeidler {
17900bc40adSAlexander von Gluck IV 	// TODO: multi-monitor? For now we set the mode on
180339a0181SAlexander von Gluck IV 	// the first display found.
181f089aa52SAlexander von Gluck IV 
182756884adSX512 	TRACE("%s\n", __func__);
183756884adSX512 	TRACE("  mode->space: %#" B_PRIx32 "\n", mode->space);
184756884adSX512 	TRACE("  mode->virtual_width: %" B_PRIu16 "\n", mode->virtual_width);
185756884adSX512 	TRACE("  mode->virtual_height: %" B_PRIu16 "\n", mode->virtual_height);
186756884adSX512 	TRACE("  mode->h_display_start: %" B_PRIu16 "\n", mode->h_display_start);
187756884adSX512 	TRACE("  mode->v_display_start: %" B_PRIu16 "\n", mode->v_display_start);
188756884adSX512 	TRACE("  mode->flags: %#" B_PRIx32 "\n", mode->flags);
189756884adSX512 
190339a0181SAlexander von Gluck IV 	uint8 crtcID = 0;
191339a0181SAlexander von Gluck IV 
192339a0181SAlexander von Gluck IV 	if (gDisplay[crtcID]->attached == false)
193339a0181SAlexander von Gluck IV 		return B_ERROR;
194f2fe29a0SAlexander von Gluck IV 
19500bc40adSAlexander von Gluck IV 	// Copy this display mode into the "current mode" for the display
196339a0181SAlexander von Gluck IV 	memcpy(&gDisplay[crtcID]->currentMode, mode, sizeof(display_mode));
19700bc40adSAlexander von Gluck IV 
198339a0181SAlexander von Gluck IV 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
19917b66d82SAlexander von Gluck IV 
20009aaa658SAlexander von Gluck IV 	// Determine DP lanes if DP
2014e7e3e33SAlexander von Gluck IV 	if (connector_is_dp(connectorIndex)) {
2024e7e3e33SAlexander von Gluck IV 		dp_info *dpInfo = &gConnector[connectorIndex]->dpInfo;
2034e7e3e33SAlexander von Gluck IV 		dpInfo->laneCount = dp_get_lane_count(connectorIndex, mode);
2044e7e3e33SAlexander von Gluck IV 		dpInfo->linkRate = dp_get_link_rate(connectorIndex, mode);
2054e7e3e33SAlexander von Gluck IV 	}
20609aaa658SAlexander von Gluck IV 
207bb228d7cSAlexander von Gluck IV 	// *** crtc and encoder prep
208b54c8119SAlexander von Gluck IV 	encoder_output_lock(true);
209339a0181SAlexander von Gluck IV 	display_crtc_lock(crtcID, ATOM_ENABLE);
210339a0181SAlexander von Gluck IV 	radeon_dpms_set(crtcID, B_DPMS_OFF);
211f35af704SAlexander von Gluck IV 
212bb228d7cSAlexander von Gluck IV 	// *** Set up encoder -> crtc routing
213339a0181SAlexander von Gluck IV 	encoder_assign_crtc(crtcID);
214bb228d7cSAlexander von Gluck IV 
215b54c8119SAlexander von Gluck IV 	// *** CRT controler mode set
21647274433SAlexander von Gluck IV 	// Set up PLL for connector
21747274433SAlexander von Gluck IV 	pll_pick(connectorIndex);
21847274433SAlexander von Gluck IV 	pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
21947274433SAlexander von Gluck IV 	TRACE("%s: pll %d selected for connector %" B_PRIu32 "\n", __func__,
22047274433SAlexander von Gluck IV 		pll->id, connectorIndex);
221339a0181SAlexander von Gluck IV 	pll_set(mode, crtcID);
22247274433SAlexander von Gluck IV 
223339a0181SAlexander von Gluck IV 	display_crtc_set_dtd(crtcID, mode);
224b54c8119SAlexander von Gluck IV 
225339a0181SAlexander von Gluck IV 	display_crtc_fb_set(crtcID, mode);
226b54c8119SAlexander von Gluck IV 	// atombios_overscan_setup
227339a0181SAlexander von Gluck IV 	display_crtc_scale(crtcID, mode);
2286ab8261bSAlexander von Gluck IV 
229b54c8119SAlexander von Gluck IV 	// *** encoder mode set
230339a0181SAlexander von Gluck IV 	encoder_mode_set(crtcID);
231b54c8119SAlexander von Gluck IV 
23200bc40adSAlexander von Gluck IV 	// *** encoder and CRT controller commit
233339a0181SAlexander von Gluck IV 	radeon_dpms_set(crtcID, B_DPMS_ON);
234339a0181SAlexander von Gluck IV 	display_crtc_lock(crtcID, ATOM_DISABLE);
235b54c8119SAlexander von Gluck IV 	encoder_output_lock(false);
2366604b1b6SAlexander von Gluck IV 
23700bc40adSAlexander von Gluck IV 	#ifdef TRACE_MODE
238245fe001SAlexander von Gluck IV 	// for debugging
23900bc40adSAlexander von Gluck IV 	debug_dp_info();
240d92959abSAlexander von Gluck IV 
24193aac98dSAlexander von Gluck IV 	TRACE("D1CRTC_STATUS        Value: 0x%X\n",
24293aac98dSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_STATUS));
24393aac98dSAlexander von Gluck IV 	TRACE("D2CRTC_STATUS        Value: 0x%X\n",
24493aac98dSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2CRTC_STATUS));
24593aac98dSAlexander von Gluck IV 	TRACE("D1CRTC_CONTROL       Value: 0x%X\n",
24693aac98dSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_CONTROL));
24793aac98dSAlexander von Gluck IV 	TRACE("D2CRTC_CONTROL       Value: 0x%X\n",
24893aac98dSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2CRTC_CONTROL));
249025d4eedSAlexander von Gluck IV 	TRACE("D1GRPH_ENABLE        Value: 0x%X\n",
250025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1GRPH_ENABLE));
251025d4eedSAlexander von Gluck IV 	TRACE("D2GRPH_ENABLE        Value: 0x%X\n",
252025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2GRPH_ENABLE));
253025d4eedSAlexander von Gluck IV 	TRACE("D1SCL_ENABLE         Value: 0x%X\n",
254025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1SCL_SCALER_ENABLE));
255025d4eedSAlexander von Gluck IV 	TRACE("D2SCL_ENABLE         Value: 0x%X\n",
256025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D2SCL_SCALER_ENABLE));
25746af8165SAlexander von Gluck IV 	TRACE("D1CRTC_BLANK_CONTROL Value: 0x%X\n",
258025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
25946af8165SAlexander von Gluck IV 	TRACE("D2CRTC_BLANK_CONTROL Value: 0x%X\n",
260025d4eedSAlexander von Gluck IV 		Read32(CRT, AVIVO_D1CRTC_BLANK_CONTROL));
26100bc40adSAlexander von Gluck IV 	#endif
2623be5e036SAlexander von Gluck IV 
263a90ebd77SClemens Zeidler 	return B_OK;
264a90ebd77SClemens Zeidler }
265a90ebd77SClemens Zeidler 
266a90ebd77SClemens Zeidler 
267a90ebd77SClemens Zeidler status_t
radeon_get_display_mode(display_mode * _currentMode)268a90ebd77SClemens Zeidler radeon_get_display_mode(display_mode* _currentMode)
269a90ebd77SClemens Zeidler {
270d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
271a90ebd77SClemens Zeidler 
272192781ddSAlexander von Gluck IV 	*_currentMode = gInfo->shared_info->current_mode;
27300bc40adSAlexander von Gluck IV 	//*_currentMode = gDisplay[X]->currentMode;
274a90ebd77SClemens Zeidler 	return B_OK;
275a90ebd77SClemens Zeidler }
276a90ebd77SClemens Zeidler 
277a90ebd77SClemens Zeidler 
278a90ebd77SClemens Zeidler status_t
radeon_get_frame_buffer_config(frame_buffer_config * config)279a90ebd77SClemens Zeidler radeon_get_frame_buffer_config(frame_buffer_config* config)
280a90ebd77SClemens Zeidler {
281d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
282a90ebd77SClemens Zeidler 
2833be5e036SAlexander von Gluck IV 	config->frame_buffer = gInfo->shared_info->frame_buffer;
2843be5e036SAlexander von Gluck IV 	config->frame_buffer_dma = (uint8*)gInfo->shared_info->frame_buffer_phys;
28551a43d0fSAlexander von Gluck IV 
286a90ebd77SClemens Zeidler 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
287a90ebd77SClemens Zeidler 
288756884adSX512 	TRACE("  config->frame_buffer: %#" B_PRIxADDR "\n",
289756884adSX512 		(phys_addr_t)config->frame_buffer);
290756884adSX512 	TRACE("  config->frame_buffer_dma: %#" B_PRIxADDR "\n",
291756884adSX512 		(phys_addr_t)config->frame_buffer_dma);
292756884adSX512 	TRACE("  config->bytes_per_row: %" B_PRIu32 "\n", config->bytes_per_row);
293756884adSX512 
294a90ebd77SClemens Zeidler 	return B_OK;
295a90ebd77SClemens Zeidler }
296a90ebd77SClemens Zeidler 
297a90ebd77SClemens Zeidler 
298a90ebd77SClemens Zeidler status_t
radeon_get_pixel_clock_limits(display_mode * mode,uint32 * _low,uint32 * _high)299a90ebd77SClemens Zeidler radeon_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high)
300a90ebd77SClemens Zeidler {
301d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
302e7e76b29SAlexander von Gluck IV 
303a90ebd77SClemens Zeidler 	if (_low != NULL) {
304a90ebd77SClemens Zeidler 		// lower limit of about 48Hz vertical refresh
3055f6744a8SAlexander von Gluck IV 		uint32 totalClocks = (uint32)mode->timing.h_total
3065f6744a8SAlexander von Gluck IV 			* (uint32)mode->timing.v_total;
307a90ebd77SClemens Zeidler 		uint32 low = (totalClocks * 48L) / 1000L;
308e7e76b29SAlexander von Gluck IV 
309d3e8b642SAlexander von Gluck IV 		if (low < PLL_MIN_DEFAULT)
310d3e8b642SAlexander von Gluck IV 			low = PLL_MIN_DEFAULT;
311d3e8b642SAlexander von Gluck IV 		else if (low > PLL_MAX_DEFAULT)
312a90ebd77SClemens Zeidler 			return B_ERROR;
313a90ebd77SClemens Zeidler 
314a90ebd77SClemens Zeidler 		*_low = low;
315a90ebd77SClemens Zeidler 	}
316a90ebd77SClemens Zeidler 
317a90ebd77SClemens Zeidler 	if (_high != NULL)
318d3e8b642SAlexander von Gluck IV 		*_high = PLL_MAX_DEFAULT;
319e7e76b29SAlexander von Gluck IV 
320e7e76b29SAlexander von Gluck IV 	//*_low = 48L;
321e7e76b29SAlexander von Gluck IV 	//*_high = 100 * 1000000L;
322a90ebd77SClemens Zeidler 	return B_OK;
323a90ebd77SClemens Zeidler }
324a90ebd77SClemens Zeidler 
325a90ebd77SClemens Zeidler 
326192781ddSAlexander von Gluck IV bool
is_mode_supported(display_mode * mode)327192781ddSAlexander von Gluck IV is_mode_supported(display_mode* mode)
328192781ddSAlexander von Gluck IV {
329f52ca69cSAlexander von Gluck IV 	bool sane = true;
330d1d65a79SAlexander von Gluck IV 
3311dac4469SAlexander von Gluck IV 	// Validate modeline is within a sane range
332192781ddSAlexander von Gluck IV 	if (is_mode_sane(mode) != B_OK)
333f52ca69cSAlexander von Gluck IV 		sane = false;
334192781ddSAlexander von Gluck IV 
33595e1d7e8SAlexander von Gluck IV 	// TODO: is_mode_supported on *which* display?
336d1d65a79SAlexander von Gluck IV 	uint32 crtid = 0;
3371dac4469SAlexander von Gluck IV 
338d1d65a79SAlexander von Gluck IV 	// if we have edid info, check frequency adginst crt reported valid ranges
339e1b9d6e6SAlexander von Gluck IV 	if (gInfo->shared_info->has_edid
340f4647825SAlexander von Gluck IV 		&& gDisplay[crtid]->foundRanges) {
3411dac4469SAlexander von Gluck IV 
342f52ca69cSAlexander von Gluck IV 		// validate horizontal frequency range
343d1d65a79SAlexander von Gluck IV 		uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total;
344f4647825SAlexander von Gluck IV 		if (hfreq > gDisplay[crtid]->hfreqMax + 1
345f4647825SAlexander von Gluck IV 			|| hfreq < gDisplay[crtid]->hfreqMin - 1) {
346f52ca69cSAlexander von Gluck IV 			//TRACE("!!! mode below falls outside of hfreq range!\n");
347f52ca69cSAlexander von Gluck IV 			sane = false;
348d1d65a79SAlexander von Gluck IV 		}
349d1d65a79SAlexander von Gluck IV 
350f52ca69cSAlexander von Gluck IV 		// validate vertical frequency range
351d1d65a79SAlexander von Gluck IV 		uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total
352d1d65a79SAlexander von Gluck IV 			* mode->timing.h_total) / 1000);
353f4647825SAlexander von Gluck IV 		if (vfreq > gDisplay[crtid]->vfreqMax + 1
354f4647825SAlexander von Gluck IV 			|| vfreq < gDisplay[crtid]->vfreqMin - 1) {
355f52ca69cSAlexander von Gluck IV 			//TRACE("!!! mode below falls outside of vfreq range!\n");
356f52ca69cSAlexander von Gluck IV 			sane = false;
357d1d65a79SAlexander von Gluck IV 		}
358e1b9d6e6SAlexander von Gluck IV 	}
359e1b9d6e6SAlexander von Gluck IV 
360142345a5SAlexander von Gluck IV 	#if 0
361142345a5SAlexander von Gluck IV 	// Lots of spam, but good for understanding what modelines are in use
362f52ca69cSAlexander von Gluck IV 	TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d is %s\n",
363f52ca69cSAlexander von Gluck IV 		mode->timing.pixel_clock, mode->timing.h_display,
364f52ca69cSAlexander von Gluck IV 		mode->timing.h_sync_start, mode->timing.h_sync_end,
365f52ca69cSAlexander von Gluck IV 		mode->timing.h_total, mode->timing.v_display,
366f52ca69cSAlexander von Gluck IV 		mode->timing.v_sync_start, mode->timing.v_sync_end,
367f52ca69cSAlexander von Gluck IV 		mode->timing.v_total,
368f52ca69cSAlexander von Gluck IV 		sane ? "OK." : "BAD, out of range!");
369142345a5SAlexander von Gluck IV 	#endif
370192781ddSAlexander von Gluck IV 
371f52ca69cSAlexander von Gluck IV 	return sane;
372192781ddSAlexander von Gluck IV }
373192781ddSAlexander von Gluck IV 
374192781ddSAlexander von Gluck IV 
375d5c3acacSAlexander von Gluck IV /*
376d5c3acacSAlexander von Gluck IV  * A quick sanity check of the provided display_mode
377d5c3acacSAlexander von Gluck IV  */
378d5c3acacSAlexander von Gluck IV status_t
is_mode_sane(display_mode * mode)379192781ddSAlexander von Gluck IV is_mode_sane(display_mode* mode)
380d5c3acacSAlexander von Gluck IV {
381333bd770SAlexander von Gluck IV 	// horizontal timing
382333bd770SAlexander von Gluck IV 	// validate h_sync_start is less then h_sync_end
383333bd770SAlexander von Gluck IV 	if (mode->timing.h_sync_start > mode->timing.h_sync_end) {
38491235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
38591235829SAlexander von Gluck IV 			"received h_sync_start greater then h_sync_end!\n",
386333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
387333bd770SAlexander von Gluck IV 		return B_ERROR;
388333bd770SAlexander von Gluck IV 	}
389333bd770SAlexander von Gluck IV 	// validate h_total is greater then h_display
390333bd770SAlexander von Gluck IV 	if (mode->timing.h_total < mode->timing.h_display) {
39191235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
39291235829SAlexander von Gluck IV 			"received h_total greater then h_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 
397333bd770SAlexander von Gluck IV 	// vertical timing
398333bd770SAlexander von Gluck IV 	// validate v_start is less then v_end
399333bd770SAlexander von Gluck IV 	if (mode->timing.v_sync_start > mode->timing.v_sync_end) {
40091235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
40191235829SAlexander von Gluck IV 			"received v_sync_start greater then v_sync_end!\n",
402333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
403d5c3acacSAlexander von Gluck IV 		return B_ERROR;
404d5c3acacSAlexander von Gluck IV 	}
405333bd770SAlexander von Gluck IV 	// validate v_total is greater then v_display
406333bd770SAlexander von Gluck IV 	if (mode->timing.v_total < mode->timing.v_display) {
40791235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
40891235829SAlexander von Gluck IV 			"received v_total greater then v_display!\n",
409333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
410d5c3acacSAlexander von Gluck IV 		return B_ERROR;
411d5c3acacSAlexander von Gluck IV 	}
412d5c3acacSAlexander von Gluck IV 
41391235829SAlexander von Gluck IV 	// calculate refresh rate for given timings to whole int (in Hz)
41491235829SAlexander von Gluck IV 	int refresh = mode->timing.pixel_clock * 1000
41591235829SAlexander von Gluck IV 		/ (mode->timing.h_total * mode->timing.v_total);
41691235829SAlexander von Gluck IV 
41791235829SAlexander von Gluck IV 	if (refresh < 30 || refresh > 250) {
41891235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
41991235829SAlexander von Gluck IV 			"refresh rate of %dHz is unlikely for any kind of monitor!\n",
42091235829SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display, refresh);
42191235829SAlexander von Gluck IV 		return B_ERROR;
42291235829SAlexander von Gluck IV 	}
42391235829SAlexander von Gluck IV 
424d5c3acacSAlexander von Gluck IV 	return B_OK;
425d5c3acacSAlexander von Gluck IV }
426d5c3acacSAlexander von Gluck IV 
427d1d65a79SAlexander von Gluck IV 
42809aaa658SAlexander von Gluck IV uint32
get_mode_bpp(display_mode * mode)42909aaa658SAlexander von Gluck IV get_mode_bpp(display_mode* mode)
43009aaa658SAlexander von Gluck IV {
43109aaa658SAlexander von Gluck IV 	// Get bitsPerPixel for given mode
43209aaa658SAlexander von Gluck IV 
43309aaa658SAlexander von Gluck IV 	switch (mode->space) {
43409aaa658SAlexander von Gluck IV 		case B_CMAP8:
43509aaa658SAlexander von Gluck IV 			return 8;
43609aaa658SAlexander von Gluck IV 		case B_RGB15_LITTLE:
43709aaa658SAlexander von Gluck IV 			return 15;
43809aaa658SAlexander von Gluck IV 		case B_RGB16_LITTLE:
43909aaa658SAlexander von Gluck IV 			return 16;
44009aaa658SAlexander von Gluck IV 		case B_RGB24_LITTLE:
44109aaa658SAlexander von Gluck IV 		case B_RGB32_LITTLE:
44209aaa658SAlexander von Gluck IV 			return 32;
44309aaa658SAlexander von Gluck IV 	}
44409aaa658SAlexander von Gluck IV 	ERROR("%s: Unknown colorspace for mode, guessing 32 bits per pixel\n",
44509aaa658SAlexander von Gluck IV 		__func__);
44609aaa658SAlexander von Gluck IV 	return 32;
44709aaa658SAlexander von Gluck IV }
448*69fdc6beSAnarchos 
449*69fdc6beSAnarchos 
450*69fdc6beSAnarchos static uint32_t
radeon_get_backlight_register()451*69fdc6beSAnarchos radeon_get_backlight_register()
452*69fdc6beSAnarchos {
453*69fdc6beSAnarchos 	// R600 and up is 0x172c else its 0x0018
454*69fdc6beSAnarchos 	if (gInfo->shared_info->chipsetID >= RADEON_R600)
455*69fdc6beSAnarchos 		return 0x172c;
456*69fdc6beSAnarchos 	return 0x0018;
457*69fdc6beSAnarchos }
458*69fdc6beSAnarchos 
459*69fdc6beSAnarchos 
460*69fdc6beSAnarchos status_t
radeon_set_brightness(float brightness)461*69fdc6beSAnarchos radeon_set_brightness(float brightness)
462*69fdc6beSAnarchos {
463*69fdc6beSAnarchos 	TRACE("%s (%f)\n", __func__, brightness);
464*69fdc6beSAnarchos 
465*69fdc6beSAnarchos 	if (brightness < 0 || brightness > 1)
466*69fdc6beSAnarchos 		return B_BAD_VALUE;
467*69fdc6beSAnarchos 
468*69fdc6beSAnarchos 	uint32_t backlightReg = radeon_get_backlight_register();
469*69fdc6beSAnarchos 	uint8_t brightnessRaw = (uint8_t)ceilf(brightness * 255);
470*69fdc6beSAnarchos 	uint32_t level = Read32(OUT, backlightReg);
471*69fdc6beSAnarchos 	TRACE("brightness level = %lx\n", level);
472*69fdc6beSAnarchos 	level &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
473*69fdc6beSAnarchos 	level |= (( brightnessRaw << ATOM_S2_CURRENT_BL_LEVEL_SHIFT )
474*69fdc6beSAnarchos 					& ATOM_S2_CURRENT_BL_LEVEL_MASK);
475*69fdc6beSAnarchos 	TRACE("new brightness level = %lx\n", level);
476*69fdc6beSAnarchos 
477*69fdc6beSAnarchos 	Write32(OUT, backlightReg, level);
478*69fdc6beSAnarchos 
479*69fdc6beSAnarchos 	//TODO crtcID = 0: see create_mode
480*69fdc6beSAnarchos 	// TODO: multi-monitor?  for now we use VESA and not gDisplay edid
481*69fdc6beSAnarchos 	uint8 crtcID = 0;
482*69fdc6beSAnarchos 	//TODO : test if it is a LCD ?
483*69fdc6beSAnarchos 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
484*69fdc6beSAnarchos 	connector_info* connector = gConnector[connectorIndex];
485*69fdc6beSAnarchos 	pll_info* pll = &connector->encoder.pll;
486*69fdc6beSAnarchos 
487*69fdc6beSAnarchos 	transmitter_dig_setup(connectorIndex, pll->pixelClock,
488*69fdc6beSAnarchos 		0, 0, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL);
489*69fdc6beSAnarchos 	transmitter_dig_setup(connectorIndex, pll->pixelClock,
490*69fdc6beSAnarchos 		0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLON);
491*69fdc6beSAnarchos 
492*69fdc6beSAnarchos 	return B_OK;
493*69fdc6beSAnarchos }
494*69fdc6beSAnarchos 
495*69fdc6beSAnarchos 
496*69fdc6beSAnarchos status_t
radeon_get_brightness(float * brightness)497*69fdc6beSAnarchos radeon_get_brightness(float* brightness)
498*69fdc6beSAnarchos {
499*69fdc6beSAnarchos 	TRACE("%s\n", __func__);
500*69fdc6beSAnarchos 
501*69fdc6beSAnarchos 	if (brightness == NULL)
502*69fdc6beSAnarchos 		return B_BAD_VALUE;
503*69fdc6beSAnarchos 
504*69fdc6beSAnarchos 	uint32_t backlightReg = Read32(OUT, radeon_get_backlight_register());
505*69fdc6beSAnarchos 	uint8_t brightnessRaw = ((backlightReg & ATOM_S2_CURRENT_BL_LEVEL_MASK) >>
506*69fdc6beSAnarchos 			ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
507*69fdc6beSAnarchos 	*brightness = (float)brightnessRaw / 255;
508*69fdc6beSAnarchos 
509*69fdc6beSAnarchos 	return B_OK;
510*69fdc6beSAnarchos }
511