xref: /haiku/src/add-ons/accelerants/radeon_hd/mode.cpp (revision 95e1d7e8288c9eb390705b0fa6e735ff091a0e65)
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"
18a90ebd77SClemens Zeidler 
19a90ebd77SClemens Zeidler #include <stdio.h>
20a90ebd77SClemens Zeidler #include <string.h>
21a90ebd77SClemens Zeidler #include <math.h>
22a90ebd77SClemens Zeidler 
23192781ddSAlexander von Gluck IV #include <create_display_modes.h>
24192781ddSAlexander von Gluck IV 
25a90ebd77SClemens Zeidler 
26a90ebd77SClemens Zeidler #define TRACE_MODE
27a90ebd77SClemens Zeidler #ifdef TRACE_MODE
28a90ebd77SClemens Zeidler extern "C" void _sPrintf(const char *format, ...);
29d5c3acacSAlexander von Gluck IV #	define TRACE(x...) _sPrintf("radeon_hd: " x)
30a90ebd77SClemens Zeidler #else
31d5c3acacSAlexander von Gluck IV #	define TRACE(x...) ;
32a90ebd77SClemens Zeidler #endif
33a90ebd77SClemens Zeidler 
34a90ebd77SClemens Zeidler 
35a90ebd77SClemens Zeidler status_t
36a90ebd77SClemens Zeidler create_mode_list(void)
37a90ebd77SClemens Zeidler {
38192781ddSAlexander von Gluck IV 	const color_space kRadeonHDSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
39192781ddSAlexander von Gluck IV 		B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
40a90ebd77SClemens Zeidler 
41192781ddSAlexander von Gluck IV 	gInfo->mode_list_area = create_display_modes("radeon HD modes",
422613175eSAlexander von Gluck IV 		gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL,
432613175eSAlexander von Gluck IV 		NULL, 0, kRadeonHDSpaces,
44192781ddSAlexander von Gluck IV 		sizeof(kRadeonHDSpaces) / sizeof(kRadeonHDSpaces[0]),
45192781ddSAlexander von Gluck IV 		is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count);
46192781ddSAlexander von Gluck IV 	if (gInfo->mode_list_area < B_OK)
47192781ddSAlexander von Gluck IV 		return gInfo->mode_list_area;
48a90ebd77SClemens Zeidler 
49192781ddSAlexander von Gluck IV 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
50d5c3acacSAlexander von Gluck IV 
51a90ebd77SClemens Zeidler 	return B_OK;
52a90ebd77SClemens Zeidler }
53a90ebd77SClemens Zeidler 
54a90ebd77SClemens Zeidler 
55a90ebd77SClemens Zeidler //	#pragma mark -
56a90ebd77SClemens Zeidler 
57a90ebd77SClemens Zeidler 
58a90ebd77SClemens Zeidler uint32
59a90ebd77SClemens Zeidler radeon_accelerant_mode_count(void)
60a90ebd77SClemens Zeidler {
61333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
62a90ebd77SClemens Zeidler 
63a90ebd77SClemens Zeidler 	return gInfo->shared_info->mode_count;
64a90ebd77SClemens Zeidler }
65a90ebd77SClemens Zeidler 
66a90ebd77SClemens Zeidler 
67a90ebd77SClemens Zeidler status_t
68a90ebd77SClemens Zeidler radeon_get_mode_list(display_mode *modeList)
69a90ebd77SClemens Zeidler {
70333bd770SAlexander von Gluck IV 	TRACE("%s\n", __func__);
71a90ebd77SClemens Zeidler 	memcpy(modeList, gInfo->mode_list,
72a90ebd77SClemens Zeidler 		gInfo->shared_info->mode_count * sizeof(display_mode));
73a90ebd77SClemens Zeidler 	return B_OK;
74a90ebd77SClemens Zeidler }
75a90ebd77SClemens Zeidler 
76a90ebd77SClemens Zeidler 
7788bfef92SAlexander von Gluck IV status_t
7888bfef92SAlexander von Gluck IV radeon_get_edid_info(void* info, size_t size, uint32* edid_version)
7988bfef92SAlexander von Gluck IV {
8088bfef92SAlexander von Gluck IV 	TRACE("%s\n", __func__);
8188bfef92SAlexander von Gluck IV 	if (!gInfo->shared_info->has_edid)
8288bfef92SAlexander von Gluck IV 		return B_ERROR;
8388bfef92SAlexander von Gluck IV 	if (size < sizeof(struct edid1_info))
8488bfef92SAlexander von Gluck IV 		return B_BUFFER_OVERFLOW;
8588bfef92SAlexander von Gluck IV 
8688bfef92SAlexander von Gluck IV 	memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
8788bfef92SAlexander von Gluck IV 	*edid_version = EDID_VERSION_1;
8888bfef92SAlexander von Gluck IV 
8988bfef92SAlexander von Gluck IV 	return B_OK;
9088bfef92SAlexander von Gluck IV }
9188bfef92SAlexander von Gluck IV 
9288bfef92SAlexander von Gluck IV 
93a90ebd77SClemens Zeidler static void
94a90ebd77SClemens Zeidler get_color_space_format(const display_mode &mode, uint32 &colorMode,
95a90ebd77SClemens Zeidler 	uint32 &bytesPerRow, uint32 &bitsPerPixel)
96a90ebd77SClemens Zeidler {
97a90ebd77SClemens Zeidler 	uint32 bytesPerPixel;
98a90ebd77SClemens Zeidler 
99a90ebd77SClemens Zeidler 	switch (mode.space) {
100a90ebd77SClemens Zeidler 		case B_RGB32_LITTLE:
101a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_RGB32;
102a90ebd77SClemens Zeidler 			bytesPerPixel = 4;
103a90ebd77SClemens Zeidler 			bitsPerPixel = 32;
104a90ebd77SClemens Zeidler 			break;
105a90ebd77SClemens Zeidler 		case B_RGB16_LITTLE:
106a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_RGB16;
107a90ebd77SClemens Zeidler 			bytesPerPixel = 2;
108a90ebd77SClemens Zeidler 			bitsPerPixel = 16;
109a90ebd77SClemens Zeidler 			break;
110a90ebd77SClemens Zeidler 		case B_RGB15_LITTLE:
111a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_RGB15;
112a90ebd77SClemens Zeidler 			bytesPerPixel = 2;
113a90ebd77SClemens Zeidler 			bitsPerPixel = 15;
114a90ebd77SClemens Zeidler 			break;
115a90ebd77SClemens Zeidler 		case B_CMAP8:
116a90ebd77SClemens Zeidler 		default:
117a90ebd77SClemens Zeidler 			colorMode = DISPLAY_CONTROL_CMAP8;
118a90ebd77SClemens Zeidler 			bytesPerPixel = 1;
119a90ebd77SClemens Zeidler 			bitsPerPixel = 8;
120a90ebd77SClemens Zeidler 			break;
121a90ebd77SClemens Zeidler 	}
122a90ebd77SClemens Zeidler 
123a90ebd77SClemens Zeidler 	bytesPerRow = mode.virtual_width * bytesPerPixel;
124a90ebd77SClemens Zeidler }
125a90ebd77SClemens Zeidler 
12647ad511fSAlexander von Gluck IV 
127cf546fa0SAlexander von Gluck IV // Blacks the screen out, useful for mode setting
1285f6744a8SAlexander von Gluck IV static void
129f2fe29a0SAlexander von Gluck IV CardBlankSet(uint8 crtid, bool blank)
1305f6744a8SAlexander von Gluck IV {
131f2fe29a0SAlexander von Gluck IV 	int blackColorReg
1323fe78837SAlexander von Gluck IV 		= crtid == 1 ? D2CRTC_BLACK_COLOR : D1CRTC_BLACK_COLOR;
133f2fe29a0SAlexander von Gluck IV 	int blankControlReg
1343fe78837SAlexander von Gluck IV 		= crtid == 1 ? D2CRTC_BLANK_CONTROL : D1CRTC_BLANK_CONTROL;
1355f6744a8SAlexander von Gluck IV 
136aa2a6e33SAlexander von Gluck IV 	Write32(CRT, blackColorReg, 0);
137aa2a6e33SAlexander von Gluck IV 	Write32Mask(CRT, blankControlReg, blank ? 1 << 8 : 0, 1 << 8);
1385f6744a8SAlexander von Gluck IV }
139cf546fa0SAlexander von Gluck IV 
140cf546fa0SAlexander von Gluck IV 
141cf546fa0SAlexander von Gluck IV static void
142*95e1d7e8SAlexander von Gluck IV CardFBSet(uint8 crtid, display_mode *mode)
143cf546fa0SAlexander von Gluck IV {
144*95e1d7e8SAlexander von Gluck IV 	register_info* regs = gDisplay[crtid]->regs;
145*95e1d7e8SAlexander von Gluck IV 
146cf546fa0SAlexander von Gluck IV 	uint32 colorMode;
147cf546fa0SAlexander von Gluck IV 	uint32 bytesPerRow;
148cf546fa0SAlexander von Gluck IV 	uint32 bitsPerPixel;
149cf546fa0SAlexander von Gluck IV 
150cf546fa0SAlexander von Gluck IV 	get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel);
151cf546fa0SAlexander von Gluck IV 
152*95e1d7e8SAlexander von Gluck IV 
15384bcfa3dSAlexander von Gluck IV 	#if 0
15484bcfa3dSAlexander von Gluck IV 	// TMDSAllIdle	// DVI / HDMI
15584bcfa3dSAlexander von Gluck IV 	// LVTMAAllIdle	// DVI
15684bcfa3dSAlexander von Gluck IV 	DACAllIdle();
15784bcfa3dSAlexander von Gluck IV 
15884bcfa3dSAlexander von Gluck IV 	// Set the inital frame buffer location in the memory controler
15984bcfa3dSAlexander von Gluck IV 	uint32 mcFbSize;
16084bcfa3dSAlexander von Gluck IV 	MCFBLocation(0, &mcFbSize);
16184bcfa3dSAlexander von Gluck IV 	MCFBSetup(Read32(OUT, R6XX_CONFIG_FB_BASE), mcFbSize);
16284bcfa3dSAlexander von Gluck IV 	#endif
16384bcfa3dSAlexander von Gluck IV 
164*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphUpdate, (1<<16));
165b6c5f468SAlexander von Gluck IV 		// Lock for update (isn't this normally the other way around on VGA?
166e7e76b29SAlexander von Gluck IV 
167b6c5f468SAlexander von Gluck IV 	// framebuffersize = w * h * bpp  =  fb bits / 8 = bytes needed
168b6c5f468SAlexander von Gluck IV 	uint64_t fbAddress = gInfo->shared_info->frame_buffer_phys;
169b6c5f468SAlexander von Gluck IV 
170b6c5f468SAlexander von Gluck IV 	// Tell GPU which frame buffer address to draw from
171*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphPrimarySurfaceAddr,
172b6c5f468SAlexander von Gluck IV 		fbAddress & 0xffffffff);
173*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphSecondarySurfaceAddr,
174b6c5f468SAlexander von Gluck IV 		fbAddress & 0xffffffff);
175b6c5f468SAlexander von Gluck IV 
176b6c5f468SAlexander von Gluck IV 	if (gInfo->shared_info->device_chipset >= (RADEON_R700 | 0x70)) {
177*95e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->grphPrimarySurfaceAddrHigh,
178b6c5f468SAlexander von Gluck IV 			(fbAddress >> 32) & 0xf);
179*95e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->grphSecondarySurfaceAddrHigh,
180b6c5f468SAlexander von Gluck IV 			(fbAddress >> 32) & 0xf);
181b6c5f468SAlexander von Gluck IV 	}
182b6c5f468SAlexander von Gluck IV 
183*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphControl, 0);
184b6c5f468SAlexander von Gluck IV 		// Reset stored depth, format, etc
185cf546fa0SAlexander von Gluck IV 
18651a43d0fSAlexander von Gluck IV 	// set color mode on video card
187cf546fa0SAlexander von Gluck IV 	switch (mode->space) {
188cf546fa0SAlexander von Gluck IV 		case B_CMAP8:
189*95e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
190bd34b2f7SAlexander von Gluck IV 				0, 0x00000703);
191cf546fa0SAlexander von Gluck IV 			break;
192cf546fa0SAlexander von Gluck IV 		case B_RGB15_LITTLE:
193*95e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
194bd34b2f7SAlexander von Gluck IV 				0x000001, 0x00000703);
195cf546fa0SAlexander von Gluck IV 			break;
196cf546fa0SAlexander von Gluck IV 		case B_RGB16_LITTLE:
197*95e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
198bd34b2f7SAlexander von Gluck IV 				0x000101, 0x00000703);
199cf546fa0SAlexander von Gluck IV 			break;
200cf546fa0SAlexander von Gluck IV 		case B_RGB24_LITTLE:
201cf546fa0SAlexander von Gluck IV 		case B_RGB32_LITTLE:
202cf546fa0SAlexander von Gluck IV 		default:
203*95e1d7e8SAlexander von Gluck IV 			Write32Mask(CRT, regs->grphControl,
204bd34b2f7SAlexander von Gluck IV 				0x000002, 0x00000703);
205cf546fa0SAlexander von Gluck IV 			break;
206cf546fa0SAlexander von Gluck IV 	}
207cf546fa0SAlexander von Gluck IV 
208*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphSwapControl, 0);
209cf546fa0SAlexander von Gluck IV 		// only for chipsets > r600
210cf546fa0SAlexander von Gluck IV 		// R5xx - RS690 case is GRPH_CONTROL bit 16
211cf546fa0SAlexander von Gluck IV 
212*95e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->grphEnable, 1, 0x00000001);
213b6c5f468SAlexander von Gluck IV 		// Enable graphics
2143be5e036SAlexander von Gluck IV 
215*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphSurfaceOffsetX, 0);
216*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphSurfaceOffsetY, 0);
217*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphXStart, 0);
218*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphYStart, 0);
219*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphXEnd, mode->virtual_width);
220*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphYEnd, mode->virtual_height);
221*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphPitch, bytesPerRow / 4);
222cf546fa0SAlexander von Gluck IV 
223*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->modeDesktopHeight, mode->virtual_height);
224eb5c4b07SAlexander von Gluck IV 
225*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->grphUpdate, 0);
226b6c5f468SAlexander von Gluck IV 		// Unlock changed registers
227cf546fa0SAlexander von Gluck IV 
228cf546fa0SAlexander von Gluck IV 	// update shared info
229cf546fa0SAlexander von Gluck IV 	gInfo->shared_info->bytes_per_row = bytesPerRow;
230cf546fa0SAlexander von Gluck IV 	gInfo->shared_info->current_mode = *mode;
231cf546fa0SAlexander von Gluck IV 	gInfo->shared_info->bits_per_pixel = bitsPerPixel;
232cf546fa0SAlexander von Gluck IV }
233cf546fa0SAlexander von Gluck IV 
234cf546fa0SAlexander von Gluck IV 
235cf546fa0SAlexander von Gluck IV static void
236*95e1d7e8SAlexander von Gluck IV CardModeSet(uint8 crtid, display_mode *mode)
237cf546fa0SAlexander von Gluck IV {
238a90ebd77SClemens Zeidler 	display_timing& displayTiming = mode->timing;
239*95e1d7e8SAlexander von Gluck IV 	register_info* regs = gDisplay[crtid]->regs;
240a90ebd77SClemens Zeidler 
241192781ddSAlexander von Gluck IV 	TRACE("%s called to do %dx%d\n",
242192781ddSAlexander von Gluck IV 		__func__, displayTiming.h_display, displayTiming.v_display);
243a90ebd77SClemens Zeidler 
244192781ddSAlexander von Gluck IV 	// enable read requests
245*95e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->grphControl, 0, 0x01000000);
246a90ebd77SClemens Zeidler 
247192781ddSAlexander von Gluck IV 	// *** Horizontal
248*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtHTotal,
2495f6744a8SAlexander von Gluck IV 		displayTiming.h_total - 1);
250a90ebd77SClemens Zeidler 
251f2fe29a0SAlexander von Gluck IV 	// Blanking
252f2fe29a0SAlexander von Gluck IV 	uint16 blankStart = displayTiming.h_total
253f2fe29a0SAlexander von Gluck IV 		+ displayTiming.h_display - displayTiming.h_sync_start;
254f2fe29a0SAlexander von Gluck IV 	uint16 blankEnd = displayTiming.h_total - displayTiming.h_sync_start;
255192781ddSAlexander von Gluck IV 
256*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtHBlank,
257e7e76b29SAlexander von Gluck IV 		blankStart | (blankEnd << 16));
258a90ebd77SClemens Zeidler 
259*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtHSync,
260a90ebd77SClemens Zeidler 		(displayTiming.h_sync_end - displayTiming.h_sync_start) << 16);
261a90ebd77SClemens Zeidler 
2623be5e036SAlexander von Gluck IV 	// set flag for neg. H sync. M76 Register Reference Guide 2-256
263*95e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->crtHPolarity,
2643be5e036SAlexander von Gluck IV 		displayTiming.flags & B_POSITIVE_HSYNC ? 0 : 1, 0x1);
265192781ddSAlexander von Gluck IV 
266192781ddSAlexander von Gluck IV 	// *** Vertical
267*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtVTotal,
2685f6744a8SAlexander von Gluck IV 		displayTiming.v_total - 1);
269a90ebd77SClemens Zeidler 
270f2fe29a0SAlexander von Gluck IV 	blankStart = displayTiming.v_total
271f2fe29a0SAlexander von Gluck IV 		+ displayTiming.v_display - displayTiming.v_sync_start;
272f2fe29a0SAlexander von Gluck IV 	blankEnd = displayTiming.v_total - displayTiming.v_sync_start;
273a90ebd77SClemens Zeidler 
274*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtVBlank,
275e7e76b29SAlexander von Gluck IV 		blankStart | (blankEnd << 16));
276192781ddSAlexander von Gluck IV 
277192781ddSAlexander von Gluck IV 	// Set Interlace if specified within mode line
278192781ddSAlexander von Gluck IV 	if (displayTiming.flags & B_TIMING_INTERLACED) {
279*95e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->crtInterlace, 0x1);
280*95e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->modeDataFormat, 0x1);
281a90ebd77SClemens Zeidler 	} else {
282*95e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->crtInterlace, 0x0);
283*95e1d7e8SAlexander von Gluck IV 		Write32(CRT, regs->modeDataFormat, 0x0);
284a90ebd77SClemens Zeidler 	}
285a90ebd77SClemens Zeidler 
286*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->crtVSync,
287a90ebd77SClemens Zeidler 		(displayTiming.v_sync_end - displayTiming.v_sync_start) << 16);
288192781ddSAlexander von Gluck IV 
2893be5e036SAlexander von Gluck IV 	// set flag for neg. V sync. M76 Register Reference Guide 2-258
290*95e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->crtVPolarity,
291d1d65a79SAlexander von Gluck IV 		displayTiming.flags & B_POSITIVE_VSYNC ? 0 : 1, 0x1);
292a90ebd77SClemens Zeidler 
29347ad511fSAlexander von Gluck IV 	/*	set D1CRTC_HORZ_COUNT_BY2_EN to 0;
29447ad511fSAlexander von Gluck IV 		should only be set to 1 on 30bpp DVI modes
29547ad511fSAlexander von Gluck IV 	*/
296*95e1d7e8SAlexander von Gluck IV 	Write32Mask(CRT, regs->crtCountControl, 0x0, 0x1);
297a90ebd77SClemens Zeidler }
298a90ebd77SClemens Zeidler 
299a90ebd77SClemens Zeidler 
300d5009951SClemens Zeidler static void
301*95e1d7e8SAlexander von Gluck IV CardModeScale(uint8 crtid, display_mode *mode)
302d5009951SClemens Zeidler {
303*95e1d7e8SAlexander von Gluck IV 	register_info* regs = gDisplay[crtid]->regs;
304*95e1d7e8SAlexander von Gluck IV 
305b6c5f468SAlexander von Gluck IV 	// No scaling
306*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->sclUpdate, (1<<16));// Lock
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 
315*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->viewportStart, 0);
316*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->viewportSize,
317b6c5f468SAlexander von Gluck IV 		mode->timing.v_display | (mode->timing.h_display << 16));
318*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->sclEnable, 0);
319*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->sclTapControl, 0);
320*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->modeCenter, 2);
321b6c5f468SAlexander von Gluck IV 	// D1MODE_DATA_FORMAT?
322*95e1d7e8SAlexander von Gluck IV 	Write32(CRT, regs->sclUpdate, 0);		// Unlock
323d5009951SClemens Zeidler }
324d5009951SClemens Zeidler 
325d5009951SClemens Zeidler 
326a90ebd77SClemens Zeidler status_t
327a90ebd77SClemens Zeidler radeon_set_display_mode(display_mode *mode)
328a90ebd77SClemens Zeidler {
329*95e1d7e8SAlexander von Gluck IV 	uint8 display_id = 0;
330a90ebd77SClemens Zeidler 
331*95e1d7e8SAlexander von Gluck IV 	CardFBSet(display_id, mode);
332*95e1d7e8SAlexander von Gluck IV 	CardModeSet(display_id, mode);
333*95e1d7e8SAlexander von Gluck IV 	CardModeScale(display_id, mode);
334e7e76b29SAlexander von Gluck IV 
335*95e1d7e8SAlexander von Gluck IV 	// If this is DAC, set our PLL
336*95e1d7e8SAlexander von Gluck IV 	if ((gDisplay[display_id]->connection_type & CONNECTION_DAC) != 0) {
337*95e1d7e8SAlexander von Gluck IV 		PLLSet(gDisplay[display_id]->connection_id, mode->timing.pixel_clock);
338*95e1d7e8SAlexander von Gluck IV 		DACSet(gDisplay[display_id]->connection_id, display_id);
339f2fe29a0SAlexander von Gluck IV 
340f2fe29a0SAlexander von Gluck IV 		// TODO : Shutdown unused PLL/DAC
341f2fe29a0SAlexander von Gluck IV 
342f2fe29a0SAlexander von Gluck IV 		// Power up the output
343*95e1d7e8SAlexander von Gluck IV 		PLLPower(gDisplay[display_id]->connection_id, RHD_POWER_ON);
344*95e1d7e8SAlexander von Gluck IV 		DACPower(gDisplay[display_id]->connection_id, RHD_POWER_ON);
345*95e1d7e8SAlexander von Gluck IV 	}
346f2fe29a0SAlexander von Gluck IV 
347f2fe29a0SAlexander von Gluck IV 	// Ensure screen isn't blanked
348*95e1d7e8SAlexander von Gluck IV 	CardBlankSet(display_id, false);
3496604b1b6SAlexander von Gluck IV 
350aa2a6e33SAlexander von Gluck IV 	int32 crtstatus = Read32(CRT, D1CRTC_STATUS);
3515f6744a8SAlexander von Gluck IV 	TRACE("CRT0 Status: 0x%X\n", crtstatus);
352f2fe29a0SAlexander von Gluck IV 	crtstatus = Read32(CRT, D2CRTC_STATUS);
353f2fe29a0SAlexander von Gluck IV 	TRACE("CRT1 Status: 0x%X\n", crtstatus);
3543be5e036SAlexander von Gluck IV 
355a90ebd77SClemens Zeidler 	return B_OK;
356a90ebd77SClemens Zeidler }
357a90ebd77SClemens Zeidler 
358a90ebd77SClemens Zeidler 
359a90ebd77SClemens Zeidler status_t
360a90ebd77SClemens Zeidler radeon_get_display_mode(display_mode *_currentMode)
361a90ebd77SClemens Zeidler {
362d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
363a90ebd77SClemens Zeidler 
364192781ddSAlexander von Gluck IV 	*_currentMode = gInfo->shared_info->current_mode;
365a90ebd77SClemens Zeidler 	return B_OK;
366a90ebd77SClemens Zeidler }
367a90ebd77SClemens Zeidler 
368a90ebd77SClemens Zeidler 
369a90ebd77SClemens Zeidler status_t
370a90ebd77SClemens Zeidler radeon_get_frame_buffer_config(frame_buffer_config *config)
371a90ebd77SClemens Zeidler {
372d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
373a90ebd77SClemens Zeidler 
3743be5e036SAlexander von Gluck IV 	config->frame_buffer = gInfo->shared_info->frame_buffer;
3753be5e036SAlexander von Gluck IV 	config->frame_buffer_dma = (uint8 *)gInfo->shared_info->frame_buffer_phys;
37651a43d0fSAlexander von Gluck IV 
377a90ebd77SClemens Zeidler 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
378a90ebd77SClemens Zeidler 
379a90ebd77SClemens Zeidler 	return B_OK;
380a90ebd77SClemens Zeidler }
381a90ebd77SClemens Zeidler 
382a90ebd77SClemens Zeidler 
383a90ebd77SClemens Zeidler status_t
384a90ebd77SClemens Zeidler radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high)
385a90ebd77SClemens Zeidler {
386d5c3acacSAlexander von Gluck IV 	TRACE("%s\n", __func__);
387e7e76b29SAlexander von Gluck IV 
388a90ebd77SClemens Zeidler 	if (_low != NULL) {
389a90ebd77SClemens Zeidler 		// lower limit of about 48Hz vertical refresh
3905f6744a8SAlexander von Gluck IV 		uint32 totalClocks = (uint32)mode->timing.h_total
3915f6744a8SAlexander von Gluck IV 			*(uint32)mode->timing.v_total;
392a90ebd77SClemens Zeidler 		uint32 low = (totalClocks * 48L) / 1000L;
393e7e76b29SAlexander von Gluck IV 
394a90ebd77SClemens Zeidler 		if (low < gInfo->shared_info->pll_info.min_frequency)
395a90ebd77SClemens Zeidler 			low = gInfo->shared_info->pll_info.min_frequency;
396a90ebd77SClemens Zeidler 		else if (low > gInfo->shared_info->pll_info.max_frequency)
397a90ebd77SClemens Zeidler 			return B_ERROR;
398a90ebd77SClemens Zeidler 
399a90ebd77SClemens Zeidler 		*_low = low;
400a90ebd77SClemens Zeidler 	}
401a90ebd77SClemens Zeidler 
402a90ebd77SClemens Zeidler 	if (_high != NULL)
403a90ebd77SClemens Zeidler 		*_high = gInfo->shared_info->pll_info.max_frequency;
404e7e76b29SAlexander von Gluck IV 
405e7e76b29SAlexander von Gluck IV 	//*_low = 48L;
406e7e76b29SAlexander von Gluck IV 	//*_high = 100 * 1000000L;
407a90ebd77SClemens Zeidler 	return B_OK;
408a90ebd77SClemens Zeidler }
409a90ebd77SClemens Zeidler 
410a90ebd77SClemens Zeidler 
411192781ddSAlexander von Gluck IV bool
412192781ddSAlexander von Gluck IV is_mode_supported(display_mode *mode)
413192781ddSAlexander von Gluck IV {
414d1d65a79SAlexander von Gluck IV 	TRACE("MODE: %d ; %d %d %d %d ; %d %d %d %d\n",
415d1d65a79SAlexander von Gluck IV 		mode->timing.pixel_clock, mode->timing.h_display,
416d1d65a79SAlexander von Gluck IV 		mode->timing.h_sync_start, mode->timing.h_sync_end,
417d1d65a79SAlexander von Gluck IV 		mode->timing.h_total, mode->timing.v_display,
418d1d65a79SAlexander von Gluck IV 		mode->timing.v_sync_start, mode->timing.v_sync_end,
419d1d65a79SAlexander von Gluck IV 		mode->timing.v_total);
420d1d65a79SAlexander von Gluck IV 
4211dac4469SAlexander von Gluck IV 	// Validate modeline is within a sane range
422192781ddSAlexander von Gluck IV 	if (is_mode_sane(mode) != B_OK)
423192781ddSAlexander von Gluck IV 		return false;
424192781ddSAlexander von Gluck IV 
425*95e1d7e8SAlexander von Gluck IV 	// TODO : is_mode_supported on *which* display?
426d1d65a79SAlexander von Gluck IV 	uint32 crtid = 0;
4271dac4469SAlexander von Gluck IV 
428d1d65a79SAlexander von Gluck IV 	// if we have edid info, check frequency adginst crt reported valid ranges
429d1d65a79SAlexander von Gluck IV 	if (gInfo->shared_info->has_edid) {
4301dac4469SAlexander von Gluck IV 
431d1d65a79SAlexander von Gluck IV 		uint32 hfreq = mode->timing.pixel_clock / mode->timing.h_total;
432*95e1d7e8SAlexander von Gluck IV 		if (hfreq > gDisplay[crtid]->hfreq_max + 1
433*95e1d7e8SAlexander von Gluck IV 			|| hfreq < gDisplay[crtid]->hfreq_min - 1) {
434d1d65a79SAlexander von Gluck IV 			TRACE("!!! hfreq : %d , hfreq_min : %d, hfreq_max : %d\n",
435*95e1d7e8SAlexander von Gluck IV 				hfreq, gDisplay[crtid]->hfreq_min, gDisplay[crtid]->hfreq_max);
436d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid "
437d1d65a79SAlexander von Gluck IV 				"horizontal range.\n", mode->timing.h_display,
438d1d65a79SAlexander von Gluck IV 				mode->timing.v_display, crtid);
439d1d65a79SAlexander von Gluck IV 			return false;
440d1d65a79SAlexander von Gluck IV 		}
441d1d65a79SAlexander von Gluck IV 
442d1d65a79SAlexander von Gluck IV 		uint32 vfreq = mode->timing.pixel_clock / ((mode->timing.v_total
443d1d65a79SAlexander von Gluck IV 			* mode->timing.h_total) / 1000);
444d1d65a79SAlexander von Gluck IV 
445*95e1d7e8SAlexander von Gluck IV 		if (vfreq > gDisplay[crtid]->vfreq_max + 1
446*95e1d7e8SAlexander von Gluck IV 			|| vfreq < gDisplay[crtid]->vfreq_min - 1) {
447d1d65a79SAlexander von Gluck IV 			TRACE("!!! vfreq : %d , vfreq_min : %d, vfreq_max : %d\n",
448*95e1d7e8SAlexander von Gluck IV 				vfreq, gDisplay[crtid]->vfreq_min, gDisplay[crtid]->vfreq_max);
449d1d65a79SAlexander von Gluck IV 			TRACE("!!! %dx%d falls outside of CRT %d's valid vertical range\n",
450d1d65a79SAlexander von Gluck IV 				mode->timing.h_display, mode->timing.v_display, crtid);
451d1d65a79SAlexander von Gluck IV 			return false;
452d1d65a79SAlexander von Gluck IV 		}
453d1d65a79SAlexander von Gluck IV 		TRACE("%dx%d is within CRT %d's valid frequency range\n",
454d1d65a79SAlexander von Gluck IV 			mode->timing.h_display, mode->timing.v_display, crtid);
455d1d65a79SAlexander von Gluck IV 	}
456192781ddSAlexander von Gluck IV 
457192781ddSAlexander von Gluck IV 	return true;
458192781ddSAlexander von Gluck IV }
459192781ddSAlexander von Gluck IV 
460192781ddSAlexander von Gluck IV 
461d5c3acacSAlexander von Gluck IV /*
462d5c3acacSAlexander von Gluck IV  * A quick sanity check of the provided display_mode
463d5c3acacSAlexander von Gluck IV  */
464d5c3acacSAlexander von Gluck IV status_t
465192781ddSAlexander von Gluck IV is_mode_sane(display_mode *mode)
466d5c3acacSAlexander von Gluck IV {
467333bd770SAlexander von Gluck IV 	// horizontal timing
468333bd770SAlexander von Gluck IV 	// validate h_sync_start is less then h_sync_end
469333bd770SAlexander von Gluck IV 	if (mode->timing.h_sync_start > mode->timing.h_sync_end) {
47091235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
47191235829SAlexander von Gluck IV 			"received h_sync_start greater then h_sync_end!\n",
472333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
473333bd770SAlexander von Gluck IV 		return B_ERROR;
474333bd770SAlexander von Gluck IV 	}
475333bd770SAlexander von Gluck IV 	// validate h_total is greater then h_display
476333bd770SAlexander von Gluck IV 	if (mode->timing.h_total < mode->timing.h_display) {
47791235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
47891235829SAlexander von Gluck IV 			"received h_total greater then h_display!\n",
479333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
480d5c3acacSAlexander von Gluck IV 		return B_ERROR;
481d5c3acacSAlexander von Gluck IV 	}
482d5c3acacSAlexander von Gluck IV 
483333bd770SAlexander von Gluck IV 	// vertical timing
484333bd770SAlexander von Gluck IV 	// validate v_start is less then v_end
485333bd770SAlexander von Gluck IV 	if (mode->timing.v_sync_start > mode->timing.v_sync_end) {
48691235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
48791235829SAlexander von Gluck IV 			"received v_sync_start greater then v_sync_end!\n",
488333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
489d5c3acacSAlexander von Gluck IV 		return B_ERROR;
490d5c3acacSAlexander von Gluck IV 	}
491333bd770SAlexander von Gluck IV 	// validate v_total is greater then v_display
492333bd770SAlexander von Gluck IV 	if (mode->timing.v_total < mode->timing.v_display) {
49391235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
49491235829SAlexander von Gluck IV 			"received v_total greater then v_display!\n",
495333bd770SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display);
496d5c3acacSAlexander von Gluck IV 		return B_ERROR;
497d5c3acacSAlexander von Gluck IV 	}
498d5c3acacSAlexander von Gluck IV 
49991235829SAlexander von Gluck IV 	// calculate refresh rate for given timings to whole int (in Hz)
50091235829SAlexander von Gluck IV 	int refresh = mode->timing.pixel_clock * 1000
50191235829SAlexander von Gluck IV 		/ (mode->timing.h_total * mode->timing.v_total);
50291235829SAlexander von Gluck IV 
50391235829SAlexander von Gluck IV 	if (refresh < 30 || refresh > 250) {
50491235829SAlexander von Gluck IV 		TRACE("%s: ERROR: (%dx%d) "
50591235829SAlexander von Gluck IV 			"refresh rate of %dHz is unlikely for any kind of monitor!\n",
50691235829SAlexander von Gluck IV 			__func__, mode->timing.h_display, mode->timing.v_display, refresh);
50791235829SAlexander von Gluck IV 		return B_ERROR;
50891235829SAlexander von Gluck IV 	}
50991235829SAlexander von Gluck IV 
510d5c3acacSAlexander von Gluck IV 	return B_OK;
511d5c3acacSAlexander von Gluck IV }
512d5c3acacSAlexander von Gluck IV 
513d1d65a79SAlexander von Gluck IV 
514