xref: /haiku/src/add-ons/accelerants/radeon_hd/mode.cpp (revision 6ab8261b98f59b9751c7178a4df66bf1ae0fa66e)
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"
16a90ebd77SClemens Zeidler #include "utility.h"
17d5c3acacSAlexander von Gluck IV #include "mode.h"
18*6ab8261bSAlexander von Gluck IV #include "display.h"
19a90ebd77SClemens Zeidler 
20a90ebd77SClemens Zeidler #include <stdio.h>
21a90ebd77SClemens Zeidler #include <string.h>
22a90ebd77SClemens Zeidler #include <math.h>
23a90ebd77SClemens Zeidler 
24192781ddSAlexander von Gluck IV #include <create_display_modes.h>
25192781ddSAlexander von Gluck IV 
26a90ebd77SClemens Zeidler 
27a90ebd77SClemens Zeidler #define TRACE_MODE
28a90ebd77SClemens Zeidler #ifdef TRACE_MODE
29a90ebd77SClemens Zeidler extern "C" void _sPrintf(const char *format, ...);
30d5c3acacSAlexander von Gluck IV #	define TRACE(x...) _sPrintf("radeon_hd: " x)
31a90ebd77SClemens Zeidler #else
32d5c3acacSAlexander von Gluck IV #	define TRACE(x...) ;
33a90ebd77SClemens Zeidler #endif
34a90ebd77SClemens Zeidler 
35a90ebd77SClemens Zeidler 
36a90ebd77SClemens Zeidler status_t
37a90ebd77SClemens Zeidler create_mode_list(void)
38a90ebd77SClemens Zeidler {
39192781ddSAlexander von Gluck IV 	const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
40192781ddSAlexander von Gluck IV 		B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
41a90ebd77SClemens Zeidler 
42192781ddSAlexander von Gluck IV 	gInfo->mode_list_area = create_display_modes("radeon HD modes",
432613175eSAlexander von Gluck IV 		gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL,
442613175eSAlexander von Gluck IV 		NULL, 0, kRadeonHDSpaces,
45192781ddSAlexander von Gluck IV 		sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]),
46192781ddSAlexander von Gluck IV 		is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count);
47192781ddSAlexander von Gluck IV 	if (gInfo->mode_list_area < B_OK)
48192781ddSAlexander von Gluck IV 		return gInfo->mode_list_area;
49a90ebd77SClemens Zeidler 
50192781ddSAlexander von Gluck IV 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
51d5c3acacSAlexander von Gluck IV 
52a90ebd77SClemens Zeidler 	return B_OK;
53a90ebd77SClemens Zeidler }
54a90ebd77SClemens Zeidler 
55a90ebd77SClemens Zeidler 
56a90ebd77SClemens Zeidler //	#pragma mark -
57a90ebd77SClemens Zeidler 
58a90ebd77SClemens Zeidler 
59a90ebd77SClemens Zeidler uint32
60a90ebd77SClemens Zeidler radeon_accelerant_mode_count(void)
61a90ebd77SClemens Zeidler {
62333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
63a90ebd77SClemens Zeidler 
64a90ebd77SClemens Zeidler 	return gInfo->shared_info->mode_count;
65a90ebd77SClemens Zeidler }
66a90ebd77SClemens Zeidler 
67a90ebd77SClemens Zeidler 
68a90ebd77SClemens Zeidler status_t
69a90ebd77SClemens Zeidler radeon_get_mode_list(display_mode *modeList)
70a90ebd77SClemens Zeidler {
71333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
72a90ebd77SClemens Zeidler 	memcpy(modeList, gInfo->mode_list,
73a90ebd77SClemens Zeidler 		gInfo->shared_info->mode_count * sizeof(display_mode));
74a90ebd77SClemens Zeidler 	return B_OK;
75a90ebd77SClemens Zeidler }
76a90ebd77SClemens Zeidler 
77a90ebd77SClemens Zeidler 
7888bfef92SAlexander von Gluck IV status_t
7988bfef92SAlexander von Gluck IV radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
8088bfef92SAlexander von Gluck IV {
8188bfef92SAlexander von Gluck IV 	TRACE("%s\n", __func__);
8288bfef92SAlexander von Gluck IV 	if (!gInfo->shared_info->has_edid)
8388bfef92SAlexander von Gluck IV 		return B_ERROR;
8488bfef92SAlexander von Gluck IV 	if (size < sizeof(struct edid1_info))
8588bfef92SAlexander von Gluck IV 		return B_BUFFER_OVERFLOW;
8688bfef92SAlexander von Gluck IV 
8788bfef92SAlexander von Gluck IV 	memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
8888bfef92SAlexander von Gluck IV 	*edid_version = EDID_VERSION_1;
8988bfef92SAlexander von Gluck IV 
9088bfef92SAlexander von Gluck IV 	return B_OK;
9188bfef92SAlexander von Gluck IV }
9288bfef92SAlexander von Gluck IV 
9388bfef92SAlexander von Gluck IV 
94a90ebd77SClemens Zeidler static void
95a90ebd77SClemens Zeidler get_color_space_format(const display_mode &mode, uint32 &colorMode,
96a90ebd77SClemens Zeidler 	uint32 &bytesPerRow, uint32 &bitsPerPixel)
97a90ebd77SClemens Zeidler {
98a90ebd77SClemens Zeidler 	uint32 bytesPerPixel;
99a90ebd77SClemens Zeidler 
100a90ebd77SClemens Zeidler 	switch (mode.space) {
101a90ebd77SClemens Zeidler 		case B_RGB32_LITTLE:
102a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_RGB32;
103a90ebd77SClemens Zeidler 			bytesPerPixel = 4;
104a90ebd77SClemens Zeidler 			bitsPerPixel = 32;
105a90ebd77SClemens Zeidler 			break;
106a90ebd77SClemens Zeidler 		case B_RGB16_LITTLE:
107a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_RGB16;
108a90ebd77SClemens Zeidler 			bytesPerPixel = 2;
109a90ebd77SClemens Zeidler 			bitsPerPixel = 16;
110a90ebd77SClemens Zeidler 			break;
111a90ebd77SClemens Zeidler 		case B_RGB15_LITTLE:
112a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_RGB15;
113a90ebd77SClemens Zeidler 			bytesPerPixel = 2;
114a90ebd77SClemens Zeidler 			bitsPerPixel = 15;
115a90ebd77SClemens Zeidler 			break;
116a90ebd77SClemens Zeidler 		case B_CMAP8:
117a90ebd77SClemens Zeidler 		default:
118a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_CMAP8;
119a90ebd77SClemens Zeidler 			bytesPerPixel = 1;
120a90ebd77SClemens Zeidler 			bitsPerPixel = 8;
121a90ebd77SClemens Zeidler 			break;
122a90ebd77SClemens Zeidler 	}
123a90ebd77SClemens Zeidler 
124a90ebd77SClemens Zeidler 	bytesPerRow = mode.virtual_width * bytesPerPixel;
125a90ebd77SClemens Zeidler }
126a90ebd77SClemens Zeidler 
12747ad511fSAlexander von Gluck IV 
128cf546fa0SAlexander von Gluck IV // Blacks the screen out, useful for mode setting
1295f6744a8SAlexander von Gluck IV static void
130f2fe29a0SAlexander von Gluck IV CardBlankSet(uint8 crtid, bool blank)
1315f6744a8SAlexander von Gluck IV {
132f2fe29a0SAlexander von Gluck IV 	int blackColorReg
1333fe78837SAlexander von Gluck IV 		= crtid == 1 ? D2CRTC_BLACK_COLOR : D1CRTC_BLACK_COLOR;
134f2fe29a0SAlexander von Gluck IV 	int blankControlReg
1353fe78837SAlexander von Gluck IV 		= crtid == 1 ? D2CRTC_BLANK_CONTROL : D1CRTC_BLANK_CONTROL;
1365f6744a8SAlexander von Gluck IV 
137aa2a6e33SAlexander von Gluck IV 	Write32(CRT, blackColorReg, 0);
138aa2a6e33SAlexander von Gluck IV 	Write32Mask(CRT, blankControlReg, blank ? 1 << 8 : 0, 1 << 8);
1395f6744a8SAlexander von Gluck IV }
140cf546fa0SAlexander von Gluck IV 
141cf546fa0SAlexander von Gluck IV 
142cf546fa0SAlexander von Gluck IV static void
14395e1d7e8SAlexander von Gluck IV CardFBSet(uint8 crtid, display_mode *mode)
144cf546fa0SAlexander von Gluck IV {
14595e1d7e8SAlexander von Gluck IV 	register_info* regs = gDisplay[crtid]->regs;
14695e1d7e8SAlexander von Gluck IV 
147cf546fa0SAlexander von Gluck IV 	uint32 colorMode;
148cf546fa0SAlexander von Gluck IV 	uint32 bytesPerRow;
149cf546fa0SAlexander von Gluck IV 	uint32 bitsPerPixel;
150cf546fa0SAlexander von Gluck IV 
151cf546fa0SAlexander von Gluck IV 	get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel);
152cf546fa0SAlexander von Gluck IV 
153eb027537SAlexander von Gluck IV 	LVDSAllIdle();
154eb027537SAlexander von Gluck IV 		// DVI / HDMI / LCD
155eb027537SAlexander von Gluck IV 	TMDSAllIdle();
156eb027537SAlexander von Gluck IV 		// DVI / HDMI
15784bcfa3dSAlexander von Gluck IV 	DACAllIdle();
158eb027537SAlexander von Gluck IV 		// VGA
159eb027537SAlexander von Gluck IV 
160eb027537SAlexander von Gluck IV 	// framebuffersize = w * h * bpp  =  fb bits / 8 = bytes needed
161eb027537SAlexander von Gluck IV 	uint64 fbAddressInt = gInfo->shared_info->frame_buffer_int;
16284bcfa3dSAlexander von Gluck IV 
163*6ab8261bSAlexander von Gluck IV 	MCFBSetup();
16484bcfa3dSAlexander von Gluck IV 
16595e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphUpdate, (1<<16));
166b6c5f468SAlexander von Gluck IV 		// Lock for update (isn't this normally the other way around on VGA?
167e7e76b29SAlexander von Gluck IV 
168b6c5f468SAlexander von Gluck IV 	// Tell GPU which frame buffer address to draw from
169*6ab8261bSAlexander von Gluck IV 	Write32(CRT, regs->grphPrimarySurfaceAddr, fbAddressInt & 0xFFFFFFFF);
170*6ab8261bSAlexander von Gluck IV 	//Write32(CRT, regs->grphSecondarySurfaceAddr, fbAddressInt);
171b6c5f468SAlexander von Gluck IV 
172b6c5f468SAlexander von Gluck IV 	if (gInfo->shared_info->device_chipset >= (RADEON_R700 | 0x70)) {
17395e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->grphPrimarySurfaceAddrHigh,
174eb027537SAlexander von Gluck IV 			(fbAddressInt >> 32) & 0xf);
17595e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->grphSecondarySurfaceAddrHigh,
176eb027537SAlexander von Gluck IV 			(fbAddressInt >> 32) & 0xf);
177b6c5f468SAlexander von Gluck IV 	}
178b6c5f468SAlexander von Gluck IV 
17995e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphControl, 0);
180b6c5f468SAlexander von Gluck IV 		// Reset stored depth, format, etc
181cf546fa0SAlexander von Gluck IV 
18251a43d0fSAlexander von Gluck IV 	// set color mode on video card
183cf546fa0SAlexander von Gluck IV 	switch (mode->space) {
184cf546fa0SAlexander von Gluck IV 		case B_CMAP8:
18595e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
186bd34b2f7SAlexander von Gluck IV 				0, 0x00000703);
187cf546fa0SAlexander von Gluck IV 			break;
188cf546fa0SAlexander von Gluck IV 		case B_RGB15_LITTLE:
18995e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
190bd34b2f7SAlexander von Gluck IV 				0x000001, 0x00000703);
191cf546fa0SAlexander von Gluck IV 			break;
192cf546fa0SAlexander von Gluck IV 		case B_RGB16_LITTLE:
19395e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
194bd34b2f7SAlexander von Gluck IV 				0x000101, 0x00000703);
195cf546fa0SAlexander von Gluck IV 			break;
196cf546fa0SAlexander von Gluck IV 		case B_RGB24_LITTLE:
197cf546fa0SAlexander von Gluck IV 		case B_RGB32_LITTLE:
198cf546fa0SAlexander von Gluck IV 		default:
19995e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
200bd34b2f7SAlexander von Gluck IV 				0x000002, 0x00000703);
201cf546fa0SAlexander von Gluck IV 			break;
202cf546fa0SAlexander von Gluck IV 	}
203cf546fa0SAlexander von Gluck IV 
20495e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphSwapControl, 0);
205cf546fa0SAlexander von Gluck IV 		// only for chipsets > r600
206cf546fa0SAlexander von Gluck IV 		// R5xx - RS690 case is GRPH_CONTROL bit 16
207cf546fa0SAlexander von Gluck IV 
20895e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->grphEnable, 1, 0x00000001);
209b6c5f468SAlexander von Gluck IV 		// Enable graphics
2103be5e036SAlexander von Gluck IV 
21195e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphSurfaceOffsetX, 0);
21295e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphSurfaceOffsetY, 0);
21395e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphXStart, 0);
21495e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphYStart, 0);
21595e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphXEnd, mode->virtual_width);
21695e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphYEnd, mode->virtual_height);
21795e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphPitch, bytesPerRow / 4);
218cf546fa0SAlexander von Gluck IV 
21995e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->modeDesktopHeight, mode->virtual_height);
220eb5c4b07SAlexander von Gluck IV 
22195e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphUpdate, 0);
222b6c5f468SAlexander von Gluck IV 		// Unlock changed registers
223cf546fa0SAlexander von Gluck IV 
224cf546fa0SAlexander von Gluck IV 	// update shared info
225cf546fa0SAlexander von Gluck IV 	gInfo->shared_info->bytes_per_row = bytesPerRow;
226cf546fa0SAlexander von Gluck IV 	gInfo->shared_info->current_mode = *mode;
227cf546fa0SAlexander von Gluck IV 	gInfo->shared_info->bits_per_pixel = bitsPerPixel;
228cf546fa0SAlexander von Gluck IV }
229cf546fa0SAlexander von Gluck IV 
230cf546fa0SAlexander von Gluck IV 
231cf546fa0SAlexander von Gluck IV static void
23295e1d7e8SAlexander von Gluck IV CardModeSet(uint8 crtid, display_mode *mode)
233cf546fa0SAlexander von Gluck IV {
234a90ebd77SClemens Zeidler 	display_timing& displayTiming = mode->timing;
23595e1d7e8SAlexander von Gluck IV 	register_info* regs = gDisplay[crtid]->regs;
236a90ebd77SClemens Zeidler 
237192781ddSAlexander von Gluck IV 	TRACE("%s called to do %dx%d\n",
238192781ddSAlexander von Gluck IV 		__func__, displayTiming.h_display, displayTiming.v_display);
239a90ebd77SClemens Zeidler 
240192781ddSAlexander von Gluck IV 	// enable read requests
24195e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->grphControl, 0, 0x01000000);
242a90ebd77SClemens Zeidler 
243192781ddSAlexander von Gluck IV 	// *** Horizontal
24495e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtHTotal,
2455f6744a8SAlexander von Gluck IV 		displayTiming.h_total - 1);
246a90ebd77SClemens Zeidler 
247*6ab8261bSAlexander von Gluck IV 	/*
248f2fe29a0SAlexander von Gluck IV 	// Blanking
249*6ab8261bSAlexander von Gluck IV 	uint16 blankStart = displayTiming.h_total
250eb027537SAlexander von Gluck IV 		+ displayTiming.h_display - displayTiming.h_sync_start;
251*6ab8261bSAlexander von Gluck IV 	uint16 blankEnd = displayTiming.h_total - displayTiming.h_sync_start;
252192781ddSAlexander von Gluck IV 
25395e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtHBlank,
254e7e76b29SAlexander von Gluck IV 		blankStart | (blankEnd << 16));
255*6ab8261bSAlexander von Gluck IV 	*/
256a90ebd77SClemens Zeidler 
25795e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtHSync,
258a90ebd77SClemens Zeidler 		(displayTiming.h_sync_end - displayTiming.h_sync_start) << 16);
259a90ebd77SClemens Zeidler 
2603be5e036SAlexander von Gluck IV 	// set flag for neg. H sync. M76 Register Reference Guide 2-256
26195e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->crtHPolarity,
2623be5e036SAlexander von Gluck IV 		displayTiming.flags & B_POSITIVE_HSYNC ? 0 : 1, 0x1);
263192781ddSAlexander von Gluck IV 
264192781ddSAlexander von Gluck IV 	// *** Vertical
26595e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtVTotal,
2665f6744a8SAlexander von Gluck IV 		displayTiming.v_total - 1);
267a90ebd77SClemens Zeidler 
268*6ab8261bSAlexander von Gluck IV 	/*
269eb027537SAlexander von Gluck IV 	// Blanking
270*6ab8261bSAlexander von Gluck IV 	blankStart = displayTiming.v_total
271eb027537SAlexander von Gluck IV 		+ displayTiming.v_display - displayTiming.v_sync_start;
272*6ab8261bSAlexander von Gluck IV 	blankEnd = displayTiming.v_total - displayTiming.v_sync_start;
273a90ebd77SClemens Zeidler 
27495e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtVBlank,
275e7e76b29SAlexander von Gluck IV 		blankStart | (blankEnd << 16));
276*6ab8261bSAlexander von Gluck IV 	*/
277192781ddSAlexander von Gluck IV 
278192781ddSAlexander von Gluck IV 	// Set Interlace if specified within mode line
279192781ddSAlexander von Gluck IV 	if (displayTiming.flags & B_TIMING_INTERLACED) {
28095e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->crtInterlace, 0x1);
28195e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->modeDataFormat, 0x1);
282a90ebd77SClemens Zeidler 	} else {
28395e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->crtInterlace, 0x0);
28495e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->modeDataFormat, 0x0);
285a90ebd77SClemens Zeidler 	}
286a90ebd77SClemens Zeidler 
28795e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtVSync,
288a90ebd77SClemens Zeidler 		(displayTiming.v_sync_end - displayTiming.v_sync_start) << 16);
289192781ddSAlexander von Gluck IV 
2903be5e036SAlexander von Gluck IV 	// set flag for neg. V sync. M76 Register Reference Guide 2-258
29195e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->crtVPolarity,
292d1d65a79SAlexander von Gluck IV 		displayTiming.flags & B_POSITIVE_VSYNC ? 0 : 1, 0x1);
293a90ebd77SClemens Zeidler 
29447ad511fSAlexander von Gluck IV 	/*	set D1CRTC_HORZ_COUNT_BY2_EN to 0;
29547ad511fSAlexander von Gluck IV 		should only be set to 1 on 30bpp DVI modes
29647ad511fSAlexander von Gluck IV 	*/
29795e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->crtCountControl, 0x0, 0x1);
298a90ebd77SClemens Zeidler }
299a90ebd77SClemens Zeidler 
300a90ebd77SClemens Zeidler 
301d5009951SClemens Zeidler static void
30295e1d7e8SAlexander von Gluck IV CardModeScale(uint8 crtid, display_mode *mode)
303d5009951SClemens Zeidler {
30495e1d7e8SAlexander von Gluck IV 	register_info* regs = gDisplay[crtid]->regs;
30595e1d7e8SAlexander von Gluck IV 
306b6c5f468SAlexander von Gluck IV 	// No scaling
307d5009951SClemens Zeidler 
308f2fe29a0SAlexander von Gluck IV 	#if 0
309aa2a6e33SAlexander von Gluck IV 	Write32(CRT, D1MODE_EXT_OVERSCAN_LEFT_RIGHT,
310d1d65a79SAlexander von Gluck IV 		(OVERSCAN << 16) | OVERSCAN); // LEFT | RIGHT
311aa2a6e33SAlexander von Gluck IV 	Write32(CRT, D1MODE_EXT_OVERSCAN_TOP_BOTTOM,
312d1d65a79SAlexander von Gluck IV 		(OVERSCAN << 16) | OVERSCAN); // TOP | BOTTOM
313f2fe29a0SAlexander von Gluck IV 	#endif
3142cc7e38cSAlexander von Gluck IV 
31595e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->viewportStart, 0);
31695e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->viewportSize,
317b6c5f468SAlexander von Gluck IV 		mode->timing.v_display | (mode->timing.h_display << 16));
318*6ab8261bSAlexander von Gluck IV 
31995e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->sclEnable, 0);
32095e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->sclTapControl, 0);
32195e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->modeCenter, 2);
322b6c5f468SAlexander von Gluck IV 	// D1MODE_DATA_FORMAT?
323d5009951SClemens Zeidler }
324d5009951SClemens Zeidler 
325d5009951SClemens Zeidler 
326a90ebd77SClemens Zeidler status_t
327a90ebd77SClemens Zeidler radeon_set_display_mode(display_mode *mode)
328a90ebd77SClemens Zeidler {
329*6ab8261bSAlexander von Gluck IV 	// Disable VGA (boo, hiss)
330*6ab8261bSAlexander von Gluck IV 	Write32Mask(OUT, VGA_RENDER_CONTROL, 0, 0x00030000);
331*6ab8261bSAlexander von Gluck IV 	Write32Mask(OUT, VGA_MODE_CONTROL, 0, 0x00000030);
332*6ab8261bSAlexander von Gluck IV 	Write32Mask(OUT, VGA_HDP_CONTROL, 0x00010010, 0x00010010);
333*6ab8261bSAlexander von Gluck IV 	Write32(OUT, D1VGA_CONTROL, 0);
334*6ab8261bSAlexander von Gluck IV 	Write32(OUT, D2VGA_CONTROL, 0);
335a90ebd77SClemens Zeidler 
336*6ab8261bSAlexander von Gluck IV 	// TODO : We set the same VESA EDID mode on each display
337e7e76b29SAlexander von Gluck IV 
338*6ab8261bSAlexander von Gluck IV 	// Set mode on each display
339*6ab8261bSAlexander von Gluck IV 	for (uint8 id = 0; id < MAX_DISPLAY; id++) {
340*6ab8261bSAlexander von Gluck IV 		// Skip if display is inactive
341*6ab8261bSAlexander von Gluck IV 		if (gDisplay[id]->active == false) {
342*6ab8261bSAlexander von Gluck IV 			CardBlankSet(id, true);
343*6ab8261bSAlexander von Gluck IV 			display_power(id, RHD_POWER_ON);
344*6ab8261bSAlexander von Gluck IV 			continue;
34595e1d7e8SAlexander von Gluck IV 		}
346f2fe29a0SAlexander von Gluck IV 
347*6ab8261bSAlexander von Gluck IV 		// Program CRT Controller
348*6ab8261bSAlexander von Gluck IV 		CardFBSet(id, mode);
349*6ab8261bSAlexander von Gluck IV 		CardModeSet(id, mode);
350*6ab8261bSAlexander von Gluck IV 		CardModeScale(id, mode);
351*6ab8261bSAlexander von Gluck IV 
352*6ab8261bSAlexander von Gluck IV 		display_power(id, RHD_POWER_RESET);
353*6ab8261bSAlexander von Gluck IV 
354*6ab8261bSAlexander von Gluck IV 		// Program connector controllers
355*6ab8261bSAlexander von Gluck IV 		switch (gDisplay[id]->connection_type) {
356*6ab8261bSAlexander von Gluck IV 			case CONNECTION_DAC:
357*6ab8261bSAlexander von Gluck IV 				PLLSet(gDisplay[id]->connection_id,
358*6ab8261bSAlexander von Gluck IV 					mode->timing.pixel_clock);
359*6ab8261bSAlexander von Gluck IV 				DACSet(gDisplay[id]->connection_id, id);
360*6ab8261bSAlexander von Gluck IV 				break;
361*6ab8261bSAlexander von Gluck IV 			case CONNECTION_TMDS:
362*6ab8261bSAlexander von Gluck IV 				TMDSSet(gDisplay[id]->connection_id, mode);
363*6ab8261bSAlexander von Gluck IV 				break;
364*6ab8261bSAlexander von Gluck IV 			case CONNECTION_LVDS:
365*6ab8261bSAlexander von Gluck IV 				LVDSSet(gDisplay[id]->connection_id, mode);
366*6ab8261bSAlexander von Gluck IV 				break;
367*6ab8261bSAlexander von Gluck IV 		}
368*6ab8261bSAlexander von Gluck IV 
369*6ab8261bSAlexander von Gluck IV 		// Power CRT Controller
370*6ab8261bSAlexander von Gluck IV 		display_power(id, RHD_POWER_ON);
371*6ab8261bSAlexander von Gluck IV 		CardBlankSet(id, false);
372*6ab8261bSAlexander von Gluck IV 
373*6ab8261bSAlexander von Gluck IV 		// Power connector controllers
374*6ab8261bSAlexander von Gluck IV 		switch (gDisplay[id]->connection_type) {
375*6ab8261bSAlexander von Gluck IV 			case CONNECTION_DAC:
376*6ab8261bSAlexander von Gluck IV 				PLLPower(gDisplay[id]->connection_id, RHD_POWER_ON);
377*6ab8261bSAlexander von Gluck IV 				DACPower(gDisplay[id]->connection_id, RHD_POWER_ON);
378*6ab8261bSAlexander von Gluck IV 				break;
379*6ab8261bSAlexander von Gluck IV 			case CONNECTION_TMDS:
380*6ab8261bSAlexander von Gluck IV 				TMDSPower(gDisplay[id]->connection_id, RHD_POWER_ON);
381*6ab8261bSAlexander von Gluck IV 				break;
382*6ab8261bSAlexander von Gluck IV 			case CONNECTION_LVDS:
383*6ab8261bSAlexander von Gluck IV 				LVDSPower(gDisplay[id]->connection_id, RHD_POWER_ON);
384*6ab8261bSAlexander von Gluck IV 				break;
385*6ab8261bSAlexander von Gluck IV 		}
386*6ab8261bSAlexander von Gluck IV 	}
3876604b1b6SAlexander von Gluck IV 
388aa2a6e33SAlexander von Gluck IV 	int32 crtstatus = Read32(CRT, D1CRTC_STATUS);
3895f6744a8SAlexander von Gluck IV 	TRACE("CRT0 Status: 0x%X\n", crtstatus);
390f2fe29a0SAlexander von Gluck IV 	crtstatus = Read32(CRT, D2CRTC_STATUS);
391f2fe29a0SAlexander von Gluck IV 	TRACE("CRT1 Status: 0x%X\n", crtstatus);
3923be5e036SAlexander von Gluck IV 
393a90ebd77SClemens Zeidler 	return B_OK;
394a90ebd77SClemens Zeidler }
395a90ebd77SClemens Zeidler 
396a90ebd77SClemens Zeidler 
397a90ebd77SClemens Zeidler status_t
398a90ebd77SClemens Zeidler radeon_get_display_mode(display_mode *_currentMode)
399a90ebd77SClemens Zeidler {
400d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
401a90ebd77SClemens Zeidler 
402192781ddSAlexander von Gluck IV 	*_currentMode = gInfo->shared_info->current_mode;
403a90ebd77SClemens Zeidler 	return B_OK;
404a90ebd77SClemens Zeidler }
405a90ebd77SClemens Zeidler 
406a90ebd77SClemens Zeidler 
407a90ebd77SClemens Zeidler status_t
408a90ebd77SClemens Zeidler radeon_get_frame_buffer_config(frame_buffer_config *config)
409a90ebd77SClemens Zeidler {
410d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
411a90ebd77SClemens Zeidler 
4123be5e036SAlexander von Gluck IV 	config->frame_buffer = gInfo->shared_info->frame_buffer;
4133be5e036SAlexander von Gluck IV 	config->frame_buffer_dma = (uint8 *)gInfo->shared_info->frame_buffer_phys;
41451a43d0fSAlexander von Gluck IV 
415a90ebd77SClemens Zeidler 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
416a90ebd77SClemens Zeidler 
417a90ebd77SClemens Zeidler 	return B_OK;
418a90ebd77SClemens Zeidler }
419a90ebd77SClemens Zeidler 
420a90ebd77SClemens Zeidler 
421a90ebd77SClemens Zeidler status_t
422a90ebd77SClemens Zeidler radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high)
423a90ebd77SClemens Zeidler {
424d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
425e7e76b29SAlexander von Gluck IV 
426a90ebd77SClemens Zeidler 	if (_low != NULL) {
427a90ebd77SClemens Zeidler 		// lower limit of about 48Hz vertical refresh
4285f6744a8SAlexander von Gluck IV 		uint32 totalClocks = (uint32)mode->timing.h_total
4295f6744a8SAlexander von Gluck IV 			*(uint32)mode->timing.v_total;
430a90ebd77SClemens Zeidler 		uint32 low = (totalClocks * 48L) / 1000L;
431e7e76b29SAlexander von Gluck IV 
432a90ebd77SClemens Zeidler 		if (low < gInfo->shared_info->pll_info.min_frequency)
433a90ebd77SClemens Zeidler 			low = gInfo->shared_info->pll_info.min_frequency;
434a90ebd77SClemens Zeidler 		else if (low > gInfo->shared_info->pll_info.max_frequency)
435a90ebd77SClemens Zeidler 			return B_ERROR;
436a90ebd77SClemens Zeidler 
437a90ebd77SClemens Zeidler 		*_low = low;
438a90ebd77SClemens Zeidler 	}
439a90ebd77SClemens Zeidler 
440a90ebd77SClemens Zeidler 	if (_high != NULL)
441a90ebd77SClemens Zeidler 		*_high = gInfo->shared_info->pll_info.max_frequency;
442e7e76b29SAlexander von Gluck IV 
443e7e76b29SAlexander von Gluck IV 	//*_low = 48L;
444e7e76b29SAlexander von Gluck IV 	//*_high = 100 * 1000000L;
445a90ebd77SClemens Zeidler 	return B_OK;
446a90ebd77SClemens Zeidler }
447a90ebd77SClemens Zeidler 
448a90ebd77SClemens Zeidler 
449192781ddSAlexander von Gluck IV bool
450192781ddSAlexander von Gluck IV is_mode_supported(display_mode *mode)
451192781ddSAlexander von Gluck IV {
452d1d65a79SAlexander von Gluck IV 	TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d\n",
453d1d65a79SAlexander von Gluck IV 		mode->timing.pixel_clock, mode->timing.h_display,
454d1d65a79SAlexander von Gluck IV 		mode->timing.h_sync_start, mode->timing.h_sync_end,
455d1d65a79SAlexander von Gluck IV 		mode->timing.h_total, mode->timing.v_display,
456d1d65a79SAlexander von Gluck IV 		mode->timing.v_sync_start, mode->timing.v_sync_end,
457d1d65a79SAlexander von Gluck IV 		mode->timing.v_total);
458d1d65a79SAlexander von Gluck IV 
4591dac4469SAlexander von Gluck IV 	// Validate modeline is within a sane range
460192781ddSAlexander von Gluck IV 	if (is_mode_sane(mode) != B_OK)
461192781ddSAlexander von Gluck IV 		return false;
462192781ddSAlexander von Gluck IV 
46395e1d7e8SAlexander von Gluck IV 	// TODO : is_mode_supported on *which* display?
464d1d65a79SAlexander von Gluck IV 	uint32 crtid = 0;
4651dac4469SAlexander von Gluck IV 
466d1d65a79SAlexander von Gluck IV 	// if we have edid info, check frequency adginst crt reported valid ranges
467e1b9d6e6SAlexander von Gluck IV 	if (gInfo->shared_info->has_edid
468e1b9d6e6SAlexander von Gluck IV 		&& gDisplay[crtid]->found_ranges) {
4691dac4469SAlexander von Gluck IV 
470d1d65a79SAlexander von Gluck IV 		uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total;
47195e1d7e8SAlexander von Gluck IV 		if (hfreq > gDisplay[crtid]->hfreq_max + 1
47295e1d7e8SAlexander von Gluck IV 			|| hfreq < gDisplay[crtid]->hfreq_min - 1) {
473d1d65a79SAlexander von Gluck IV 			TRACE("!!! hfreq : %d , hfreq_min : %d, hfreq_max : %d\n",
47495e1d7e8SAlexander von Gluck IV 				hfreq, gDisplay[crtid]->hfreq_min, gDisplay[crtid]->hfreq_max);
475d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid "
476d1d65a79SAlexander von Gluck IV 				"horizontal range.\n", mode->timing.h_display,
477d1d65a79SAlexander von Gluck IV 				mode->timing.v_display, crtid);
478d1d65a79SAlexander von Gluck IV 			return false;
479d1d65a79SAlexander von Gluck IV 		}
480d1d65a79SAlexander von Gluck IV 
481d1d65a79SAlexander von Gluck IV 		uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total
482d1d65a79SAlexander von Gluck IV 			* mode->timing.h_total) / 1000);
483d1d65a79SAlexander von Gluck IV 
48495e1d7e8SAlexander von Gluck IV 		if (vfreq > gDisplay[crtid]->vfreq_max + 1
48595e1d7e8SAlexander von Gluck IV 			|| vfreq < gDisplay[crtid]->vfreq_min - 1) {
486d1d65a79SAlexander von Gluck IV 			TRACE("!!! vfreq : %d , vfreq_min : %d, vfreq_max : %d\n",
48795e1d7e8SAlexander von Gluck IV 				vfreq, gDisplay[crtid]->vfreq_min, gDisplay[crtid]->vfreq_max);
488d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid vertical range\n",
489d1d65a79SAlexander von Gluck IV 				mode->timing.h_display, mode->timing.v_display, crtid);
490d1d65a79SAlexander von Gluck IV 			return false;
491d1d65a79SAlexander von Gluck IV 		}
492e1b9d6e6SAlexander von Gluck IV 	}
493e1b9d6e6SAlexander von Gluck IV 
494d1d65a79SAlexander von Gluck IV 	TRACE("%dx%d is within CRT %d's valid frequency range\n",
495d1d65a79SAlexander von Gluck IV 		mode->timing.h_display, mode->timing.v_display, crtid);
496192781ddSAlexander von Gluck IV 
497192781ddSAlexander von Gluck IV 	return true;
498192781ddSAlexander von Gluck IV }
499192781ddSAlexander von Gluck IV 
500192781ddSAlexander von Gluck IV 
501d5c3acacSAlexander von Gluck IV /*
502d5c3acacSAlexander von Gluck IV  * A quick sanity check of the provided display_mode
503d5c3acacSAlexander von Gluck IV  */
504d5c3acacSAlexander von Gluck IV status_t
505192781ddSAlexander von Gluck IV is_mode_sane(display_mode *mode)
506d5c3acacSAlexander von Gluck IV {
507333bd770SAlexander von Gluck IV 	// horizontal timing
508333bd770SAlexander von Gluck IV 	// validate h_sync_start is less then h_sync_end
509333bd770SAlexander von Gluck IV 	if (mode->timing.h_sync_start > mode->timing.h_sync_end) {
51091235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
51191235829SAlexander von Gluck IV 			"received h_sync_start greater then h_sync_end!\n",
512333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
513333bd770SAlexander von Gluck IV 		return B_ERROR;
514333bd770SAlexander von Gluck IV 	}
515333bd770SAlexander von Gluck IV 	// validate h_total is greater then h_display
516333bd770SAlexander von Gluck IV 	if (mode->timing.h_total < mode->timing.h_display) {
51791235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
51891235829SAlexander von Gluck IV 			"received h_total greater then h_display!\n",
519333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
520d5c3acacSAlexander von Gluck IV 		return B_ERROR;
521d5c3acacSAlexander von Gluck IV 	}
522d5c3acacSAlexander von Gluck IV 
523333bd770SAlexander von Gluck IV 	// vertical timing
524333bd770SAlexander von Gluck IV 	// validate v_start is less then v_end
525333bd770SAlexander von Gluck IV 	if (mode->timing.v_sync_start > mode->timing.v_sync_end) {
52691235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
52791235829SAlexander von Gluck IV 			"received v_sync_start greater then v_sync_end!\n",
528333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
529d5c3acacSAlexander von Gluck IV 		return B_ERROR;
530d5c3acacSAlexander von Gluck IV 	}
531333bd770SAlexander von Gluck IV 	// validate v_total is greater then v_display
532333bd770SAlexander von Gluck IV 	if (mode->timing.v_total < mode->timing.v_display) {
53391235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
53491235829SAlexander von Gluck IV 			"received v_total greater then v_display!\n",
535333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
536d5c3acacSAlexander von Gluck IV 		return B_ERROR;
537d5c3acacSAlexander von Gluck IV 	}
538d5c3acacSAlexander von Gluck IV 
53991235829SAlexander von Gluck IV 	// calculate refresh rate for given timings to whole int (in Hz)
54091235829SAlexander von Gluck IV 	int refresh = mode->timing.pixel_clock * 1000
54191235829SAlexander von Gluck IV 		/ (mode->timing.h_total * mode->timing.v_total);
54291235829SAlexander von Gluck IV 
54391235829SAlexander von Gluck IV 	if (refresh < 30 || refresh > 250) {
54491235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
54591235829SAlexander von Gluck IV 			"refresh rate of %dHz is unlikely for any kind of monitor!\n",
54691235829SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display, refresh);
54791235829SAlexander von Gluck IV 		return B_ERROR;
54891235829SAlexander von Gluck IV 	}
54991235829SAlexander von Gluck IV 
550d5c3acacSAlexander von Gluck IV 	return B_OK;
551d5c3acacSAlexander von Gluck IV }
552d5c3acacSAlexander von Gluck IV 
553d1d65a79SAlexander von Gluck IV 
554