xref: /haiku/src/add-ons/accelerants/radeon_hd/mode.cpp (revision 1c09002cbee8e797a0f8bbfc5678dfadd39ee1a7)
1 /*
2  * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Support for i915 chipset and up based on the X driver,
6  * Copyright 2006-2007 Intel Corporation.
7  *
8  * Authors:
9  *		Axel Dörfler, axeld@pinc-software.de
10  */
11 
12 
13 #include "accelerant_protos.h"
14 #include "accelerant.h"
15 #include "utility.h"
16 
17 #include <stdio.h>
18 #include <string.h>
19 #include <math.h>
20 
21 #include <create_display_modes.h>
22 #include <ddc.h>
23 #include <edid.h>
24 
25 
26 #define TRACE_MODE
27 #ifdef TRACE_MODE
28 extern "C" void _sPrintf(const char *format, ...);
29 #	define TRACE(x) _sPrintf x
30 #else
31 #	define TRACE(x) ;
32 #endif
33 
34 
35 static display_mode gDisplayMode;
36 
37 
38 status_t
39 create_mode_list(void)
40 {
41 	// TODO : Read active monitor EDID
42 
43 	/* Populate modeline with temporary example */
44 	gDisplayMode.timing.pixel_clock = 71500;
45 	gDisplayMode.timing.h_display = 1366;	// In Pixels
46 	gDisplayMode.timing.h_sync_start = 1406;
47 	gDisplayMode.timing.h_sync_end = 1438;
48 	gDisplayMode.timing.h_total = 1510;
49 	gDisplayMode.timing.v_display = 768;	// In Pixels
50 	gDisplayMode.timing.v_sync_start = 771;
51 	gDisplayMode.timing.v_sync_end = 777;
52 	gDisplayMode.timing.v_total = 789;
53 	gDisplayMode.timing.flags = 0;			// Polarity, ex: B_POSITIVE_HSYNC
54 
55 	gDisplayMode.space = B_RGB32_LITTLE;	// Pixel configuration
56 	gDisplayMode.virtual_width = 1366;		// In Pixels
57 	gDisplayMode.virtual_height = 768;		// In Pixels
58 	gDisplayMode.h_display_start = 0;
59 	gDisplayMode.v_display_start = 0;
60 	gDisplayMode.flags = 0;					// Mode flags (Some drivers use this
61 
62 	gInfo->mode_list = &gDisplayMode;
63 	gInfo->shared_info->mode_count = 1;
64 	return B_OK;
65 }
66 
67 
68 //	#pragma mark -
69 
70 
71 uint32
72 radeon_accelerant_mode_count(void)
73 {
74 	TRACE(("radeon_accelerant_mode_count()\n"));
75 
76 	return gInfo->shared_info->mode_count;
77 }
78 
79 
80 status_t
81 radeon_get_mode_list(display_mode *modeList)
82 {
83 	TRACE(("radeon_get_mode_info()\n"));
84 	memcpy(modeList, gInfo->mode_list,
85 		gInfo->shared_info->mode_count * sizeof(display_mode));
86 	return B_OK;
87 }
88 
89 
90 inline void
91 write32AtMask(uint32 adress, uint32 value, uint32 mask)
92 {
93 	uint32 temp;
94 	temp = read32(adress);
95 	temp &= ~mask;
96 	temp |= value & mask;
97 	write32(adress, temp);
98 }
99 
100 
101 enum {
102 	/* CRTC1 registers */
103 	D1CRTC_H_TOTAL                 = 0x6000,
104 	D1CRTC_H_BLANK_START_END       = 0x6004,
105 	D1CRTC_H_SYNC_A                = 0x6008,
106 	D1CRTC_H_SYNC_A_CNTL           = 0x600C,
107 	D1CRTC_H_SYNC_B                = 0x6010,
108 	D1CRTC_H_SYNC_B_CNTL           = 0x6014,
109 
110 	D1CRTC_V_TOTAL                 = 0x6020,
111 	D1CRTC_V_BLANK_START_END       = 0x6024,
112 	D1CRTC_V_SYNC_A                = 0x6028,
113 	D1CRTC_V_SYNC_A_CNTL           = 0x602C,
114 	D1CRTC_V_SYNC_B                = 0x6030,
115 	D1CRTC_V_SYNC_B_CNTL           = 0x6034,
116 
117 	D1CRTC_CONTROL                 = 0x6080,
118 	D1CRTC_BLANK_CONTROL           = 0x6084,
119 	D1CRTC_INTERLACE_CONTROL	   = 0x6088,
120 	D1CRTC_BLACK_COLOR             = 0x6098,
121 	D1CRTC_STATUS                  = 0x609C,
122 	D1CRTC_COUNT_CONTROL           = 0x60B4,
123 
124 	/* D1GRPH registers */
125 	D1GRPH_ENABLE                  = 0x6100,
126 	D1GRPH_CONTROL                 = 0x6104,
127 	D1GRPH_LUT_SEL                 = 0x6108,
128 	D1GRPH_SWAP_CNTL               = 0x610C,
129 	D1GRPH_PRIMARY_SURFACE_ADDRESS = 0x6110,
130 	D1GRPH_SECONDARY_SURFACE_ADDRESS = 0x6118,
131 	D1GRPH_PITCH                   = 0x6120,
132 	D1GRPH_SURFACE_OFFSET_X        = 0x6124,
133 	D1GRPH_SURFACE_OFFSET_Y        = 0x6128,
134 	D1GRPH_X_START                 = 0x612C,
135 	D1GRPH_Y_START                 = 0x6130,
136 	D1GRPH_X_END                   = 0x6134,
137 	D1GRPH_Y_END                   = 0x6138,
138 	D1GRPH_UPDATE                  = 0x6144,
139 
140 	/* D1MODE */
141 	D1MODE_DESKTOP_HEIGHT          = 0x652C,
142 	D1MODE_VLINE_START_END         = 0x6538,
143 	D1MODE_VLINE_STATUS            = 0x653C,
144 	D1MODE_VIEWPORT_START          = 0x6580,
145 	D1MODE_VIEWPORT_SIZE           = 0x6584,
146 	D1MODE_EXT_OVERSCAN_LEFT_RIGHT = 0x6588,
147 	D1MODE_EXT_OVERSCAN_TOP_BOTTOM = 0x658C,
148 	D1MODE_DATA_FORMAT             = 0x6528,
149 
150 	/* D1SCL */
151 	D1SCL_ENABLE                   = 0x6590,
152 	D1SCL_TAP_CONTROL              = 0x6594,
153 	D1MODE_CENTER                  = 0x659C, /* guess */
154 	D1SCL_HVSCALE                  = 0x65A4, /* guess */
155 	D1SCL_HFILTER                  = 0x65B0, /* guess */
156 	D1SCL_VFILTER                  = 0x65C0, /* guess */
157 	D1SCL_UPDATE                   = 0x65CC,
158 	D1SCL_DITHER                   = 0x65D4, /* guess */
159 	D1SCL_FLIP_CONTROL             = 0x65D8 /* guess */
160 
161 };
162 
163 
164 static void
165 get_color_space_format(const display_mode &mode, uint32 &colorMode,
166 	uint32 &bytesPerRow, uint32 &bitsPerPixel)
167 {
168 	uint32 bytesPerPixel;
169 
170 	switch (mode.space) {
171 		case B_RGB32_LITTLE:
172 			colorMode = DISPLAY_CONTROL_RGB32;
173 			bytesPerPixel = 4;
174 			bitsPerPixel = 32;
175 			break;
176 		case B_RGB16_LITTLE:
177 			colorMode = DISPLAY_CONTROL_RGB16;
178 			bytesPerPixel = 2;
179 			bitsPerPixel = 16;
180 			break;
181 		case B_RGB15_LITTLE:
182 			colorMode = DISPLAY_CONTROL_RGB15;
183 			bytesPerPixel = 2;
184 			bitsPerPixel = 15;
185 			break;
186 		case B_CMAP8:
187 		default:
188 			colorMode = DISPLAY_CONTROL_CMAP8;
189 			bytesPerPixel = 1;
190 			bitsPerPixel = 8;
191 			break;
192 	}
193 
194 	bytesPerRow = mode.virtual_width * bytesPerPixel;
195 
196 	// Make sure bytesPerRow is a multiple of 64
197 	// TODO: check if the older chips have the same restriction!
198 	if ((bytesPerRow & 63) != 0)
199 		bytesPerRow = (bytesPerRow + 63) & ~63;
200 }
201 
202 
203 #define D1_REG_OFFSET 0x0000
204 #define D2_REG_OFFSET 0x0800
205 
206 
207 static void
208 DxModeSet(display_mode *mode)
209 {
210 	uint32 regOffset = D1_REG_OFFSET;
211 
212 	display_timing& displayTiming = mode->timing;
213 
214 
215 	/* enable read requests */
216 	write32AtMask(regOffset + D1CRTC_CONTROL, 0, 0x01000000);
217 
218 	/* Horizontal */
219 	write32(regOffset + D1CRTC_H_TOTAL, displayTiming.h_total - 1);
220 
221 	uint16 blankStart = displayTiming.h_display;	// displayTiming.h_sync_end;
222 	uint16 blankEnd = displayTiming.h_sync_start;	// displayTiming.h_total;
223 //	write32(regOffset + D1CRTC_H_BLANK_START_END,
224 //		blankStart | (blankEnd << 16));
225 
226 	write32(regOffset + D1CRTC_H_SYNC_A,
227 		(displayTiming.h_sync_end - displayTiming.h_sync_start) << 16);
228 //	write32(regOffset + D1CRTC_H_SYNC_A_CNTL, Mode->Flags & V_NHSYNC);
229 //!	write32(regOffset + D1CRTC_H_SYNC_A_CNTL, V_NHSYNC);
230 
231 	/* Vertical */
232 	write32(regOffset + D1CRTC_V_TOTAL, displayTiming.v_total - 1);
233 
234 	blankStart = displayTiming.v_display;	// displayTiming.v_sync_end;
235 	blankEnd = displayTiming.v_sync_start;	// displayTiming.v_total;
236 //  write32(regOffset + D1CRTC_V_BLANK_START_END,
237 //		blankStart | (blankEnd << 16));
238 
239 	/* set interlaced */
240 //	if (Mode->Flags & V_INTERLACE) {
241 	if (0) {
242 		write32(regOffset + D1CRTC_INTERLACE_CONTROL, 0x1);
243 		write32(regOffset + D1MODE_DATA_FORMAT, 0x1);
244 	} else {
245 		write32(regOffset + D1CRTC_INTERLACE_CONTROL, 0x0);
246 		write32(regOffset + D1MODE_DATA_FORMAT, 0x0);
247 	}
248 
249 	write32(regOffset + D1CRTC_V_SYNC_A,
250 		(displayTiming.v_sync_end - displayTiming.v_sync_start) << 16);
251 //	write32(regOffset + D1CRTC_V_SYNC_A_CNTL, Mode->Flags & V_NVSYNC);
252 //!	write32(regOffset + D1CRTC_V_SYNC_A_CNTL, V_NVSYNC);
253 
254 	/*	set D1CRTC_HORZ_COUNT_BY2_EN to 0;
255 		should only be set to 1 on 30bpp DVI modes
256 	*/
257 	write32AtMask(regOffset + D1CRTC_COUNT_CONTROL, 0x0, 0x1);
258 
259 }
260 
261 
262 static void
263 DxModeScale(display_mode *mode)
264 {
265 	uint32 regOffset = D1_REG_OFFSET;
266 
267 	/* D1Mode registers */
268 	write32(regOffset + D1MODE_VIEWPORT_SIZE,
269 		mode->timing.v_display | (mode->timing.h_display << 16));
270 	write32(regOffset + D1MODE_VIEWPORT_START, 0);
271 
272 /*  write32(regOffset + D1MODE_EXT_OVERSCAN_LEFT_RIGHT,
273 		(Overscan.OverscanLeft << 16) | Overscan.OverscanRight);
274 	write32(regOffset + D1MODE_EXT_OVERSCAN_TOP_BOTTOM,
275 		(Overscan.OverscanTop << 16) | Overscan.OverscanBottom);
276 */
277 	write32(regOffset + D1SCL_ENABLE, 0);
278 	write32(regOffset + D1SCL_TAP_CONTROL, 0);
279 	write32(regOffset + D1MODE_CENTER, 0);
280 }
281 
282 
283 status_t
284 radeon_set_display_mode(display_mode *mode)
285 {
286 	DxModeSet(mode);
287 
288 	DxModeScale(mode);
289 
290 	uint32 colorMode, bytesPerRow, bitsPerPixel;
291 	get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel);
292 
293 	uint32 regOffset = D1_REG_OFFSET;
294 
295 	write32AtMask(regOffset + D1GRPH_ENABLE, 1, 0x00000001);
296 
297 	/* disable R/B swap, disable tiling, disable 16bit alpha, etc. */
298 	write32(regOffset + D1GRPH_CONTROL, 0);
299 
300 	switch (mode->space) {
301 	case B_CMAP8:
302 		write32AtMask(regOffset + D1GRPH_CONTROL, 0, 0x00000703);
303 		break;
304 	case B_RGB15_LITTLE:
305 		write32AtMask(regOffset + D1GRPH_CONTROL, 0x000001, 0x00000703);
306 		break;
307 	case B_RGB16_LITTLE:
308 		write32AtMask(regOffset + D1GRPH_CONTROL, 0x000101, 0x00000703);
309 		break;
310 	case B_RGB24_LITTLE:
311 	case B_RGB32_LITTLE:
312 	default:
313 		write32AtMask(regOffset + D1GRPH_CONTROL, 0x000002, 0x00000703);
314 		break;
315 	/* TODO: 64bpp ;p */
316 	}
317 
318 	/* Make sure that we are not swapping colours around */
319 //	if (rhdPtr->ChipSet > RHD_R600)
320 	write32(regOffset + D1GRPH_SWAP_CNTL, 0);
321 	/* R5xx - RS690 case is GRPH_CONTROL bit 16 */
322 
323 #define R6XX_CONFIG_FB_BASE 0x542C /* AKA CONFIG_F0_BASE */
324 
325 	uint32 fbIntAddress = read32(R6XX_CONFIG_FB_BASE);
326 
327 	uint32 offset = gInfo->shared_info->frame_buffer_offset;
328 	write32(regOffset + D1GRPH_PRIMARY_SURFACE_ADDRESS,
329 		fbIntAddress + offset);
330 	write32(regOffset + D1GRPH_PITCH, bytesPerRow / 4);
331 	write32(regOffset + D1GRPH_SURFACE_OFFSET_X, 0);
332 	write32(regOffset + D1GRPH_SURFACE_OFFSET_Y, 0);
333 	write32(regOffset + D1GRPH_X_START, 0);
334 	write32(regOffset + D1GRPH_Y_START, 0);
335 	write32(regOffset + D1GRPH_X_END, mode->virtual_width);
336 	write32(regOffset + D1GRPH_Y_END, mode->virtual_height);
337 
338 	/* D1Mode registers */
339 	write32(regOffset + D1MODE_DESKTOP_HEIGHT, mode->virtual_height);
340 
341 	// update shared info
342 	gInfo->shared_info->bytes_per_row = bytesPerRow;
343 	gInfo->shared_info->current_mode = *mode;
344 	gInfo->shared_info->bits_per_pixel = bitsPerPixel;
345 
346 	return B_OK;
347 }
348 
349 
350 status_t
351 radeon_get_display_mode(display_mode *_currentMode)
352 {
353 	TRACE(("radeon_get_display_mode()\n"));
354 
355 	*_currentMode = gDisplayMode;
356 	return B_OK;
357 }
358 
359 
360 status_t
361 radeon_get_frame_buffer_config(frame_buffer_config *config)
362 {
363 	TRACE(("radeon_get_frame_buffer_config()\n"));
364 
365 	uint32 offset = gInfo->shared_info->frame_buffer_offset;
366 
367 	config->frame_buffer = gInfo->shared_info->graphics_memory + offset;
368 	config->frame_buffer_dma
369 		= (uint8 *)gInfo->shared_info->physical_graphics_memory + offset;
370 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
371 
372 	return B_OK;
373 }
374 
375 
376 status_t
377 radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high)
378 {
379 	TRACE(("radeon_get_pixel_clock_limits()\n"));
380 /*
381 	if (_low != NULL) {
382 		// lower limit of about 48Hz vertical refresh
383 		uint32 totalClocks = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total;
384 		uint32 low = (totalClocks * 48L) / 1000L;
385 		if (low < gInfo->shared_info->pll_info.min_frequency)
386 			low = gInfo->shared_info->pll_info.min_frequency;
387 		else if (low > gInfo->shared_info->pll_info.max_frequency)
388 			return B_ERROR;
389 
390 		*_low = low;
391 	}
392 
393 	if (_high != NULL)
394 		*_high = gInfo->shared_info->pll_info.max_frequency;
395 */
396 	*_low = 48L;
397 	*_high = 100 * 1000000L;
398 	return B_OK;
399 }
400 
401 
402