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