xref: /haiku/src/add-ons/accelerants/intel_extreme/mode.cpp (revision 03187b607b2b5eec7ee059f1ead09bdba14991fb)
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 struct display_registers {
36 	uint32	pll;
37 	uint32	divisors;
38 	uint32	control;
39 	uint32	pipe_config;
40 	uint32	horiz_total;
41 	uint32	horiz_blank;
42 	uint32	horiz_sync;
43 	uint32	vert_total;
44 	uint32	vert_blank;
45 	uint32	vert_sync;
46 	uint32	size;
47 	uint32	stride;
48 	uint32	position;
49 	uint32	pipe_source;
50 };
51 
52 struct pll_divisors {
53 	uint32	post;
54 	uint32	post1;
55 	uint32	post2;
56 	bool	post2_high;
57 	uint32	n;
58 	uint32	m;
59 	uint32	m1;
60 	uint32	m2;
61 };
62 
63 struct pll_limits {
64 	pll_divisors	min;
65 	pll_divisors	max;
66 	uint32			min_post2_frequency;
67 	uint32			min_vco;
68 	uint32			max_vco;
69 };
70 
71 
72 static status_t
73 get_i2c_signals(void* cookie, int* _clock, int* _data)
74 {
75 	uint32 ioRegister = (uint32)cookie;
76 	uint32 value = read32(ioRegister);
77 
78 	*_clock = (value & I2C_CLOCK_VALUE_IN) != 0;
79 	*_data = (value & I2C_DATA_VALUE_IN) != 0;
80 
81 	return B_OK;
82 }
83 
84 
85 static status_t
86 set_i2c_signals(void* cookie, int clock, int data)
87 {
88 	uint32 ioRegister = (uint32)cookie;
89 	uint32 value;
90 
91 	if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_83x)) {
92 		// on these chips, the reserved values are fixed
93 		value = 0;
94 	} else {
95 		// on all others, we have to preserve them manually
96 		value = read32(ioRegister) & I2C_RESERVED;
97 	}
98 
99 	if (data != 0)
100 		value |= I2C_DATA_DIRECTION_MASK;
101 	else
102 		value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT | I2C_DATA_VALUE_MASK;
103 
104 	if (clock != 0)
105 		value |= I2C_CLOCK_DIRECTION_MASK;
106 	else
107 		value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT | I2C_CLOCK_VALUE_MASK;
108 
109 	write32(ioRegister, value);
110 	read32(ioRegister);
111 		// make sure the PCI bus has flushed the write
112 
113 	return B_OK;
114 }
115 
116 
117 void
118 set_frame_buffer_base()
119 {
120 	intel_shared_info &sharedInfo = *gInfo->shared_info;
121 	display_mode &mode = sharedInfo.current_mode;
122 	uint32 baseRegister;
123 	uint32 surfaceRegister;
124 
125 	if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
126 		baseRegister = INTEL_DISPLAY_A_BASE;
127 		surfaceRegister = INTEL_DISPLAY_A_SURFACE;
128 	} else {
129 		baseRegister = INTEL_DISPLAY_B_BASE;
130 		surfaceRegister = INTEL_DISPLAY_B_SURFACE;
131 	}
132 
133 	if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)) {
134 		write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row
135 			+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
136 		read32(baseRegister);
137 		write32(surfaceRegister, sharedInfo.frame_buffer_offset);
138 		read32(surfaceRegister);
139 	} else {
140 		write32(baseRegister, sharedInfo.frame_buffer_offset
141 			+ mode.v_display_start * sharedInfo.bytes_per_row
142 			+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
143 		read32(baseRegister);
144 	}
145 }
146 
147 
148 /*!	Creates the initial mode list of the primary accelerant.
149 	It's called from intel_init_accelerant().
150 */
151 status_t
152 create_mode_list(void)
153 {
154 	i2c_bus bus;
155 	bus.cookie = (void*)INTEL_I2C_IO_A;
156 	bus.set_signals = &set_i2c_signals;
157 	bus.get_signals = &get_i2c_signals;
158 	ddc2_init_timing(&bus);
159 
160 	if (ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL) == B_OK) {
161 		edid_dump(&gInfo->edid_info);
162 		gInfo->has_edid = true;
163 	} else {
164 		TRACE(("intel_extreme: getting EDID failed!\n"));
165 	}
166 
167 	// TODO: support lower modes via scaling and windowing
168 	if (gInfo->head_mode & HEAD_MODE_LVDS_PANEL
169 		&& ((gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0)) {
170 		size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1)
171 			& ~(B_PAGE_SIZE - 1);
172 
173 		display_mode *list;
174 		area_id area = create_area("intel extreme modes", (void **)&list,
175 			B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
176 		if (area < B_OK)
177 			return area;
178 
179 		memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode));
180 
181 		gInfo->mode_list_area = area;
182 		gInfo->mode_list = list;
183 		gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
184 		gInfo->shared_info->mode_count = 1;
185 		return B_OK;
186 	}
187 
188 	// Otherwise return the 'real' list of modes
189 	display_mode *list;
190 	uint32 count = 0;
191 	gInfo->mode_list_area = create_display_modes("intel extreme modes",
192 		gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, NULL,
193 		&list, &count);
194 	if (gInfo->mode_list_area < B_OK)
195 		return gInfo->mode_list_area;
196 
197 	gInfo->mode_list = list;
198 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
199 	gInfo->shared_info->mode_count = count;
200 
201 	return B_OK;
202 }
203 
204 
205 void
206 wait_for_vblank(void)
207 {
208 	acquire_sem_etc(gInfo->shared_info->vblank_sem, 1, B_RELATIVE_TIMEOUT, 25000);
209 		// With the output turned off via DPMS, we might not get any interrupts anymore
210 		// that's why we don't wait forever for it.
211 }
212 
213 
214 static void
215 get_pll_limits(pll_limits &limits)
216 {
217 	// Note, the limits are taken from the X driver; they have not yet been
218 	// tested
219 
220 	if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) {
221 		// TODO: support LVDS output limits as well
222 		// (Update: Output limits are adjusted in the computation (post2=7/14))
223 		// Should move them here!
224 		static const pll_limits kLimits = {
225 			// p, p1, p2, high,   n,   m, m1, m2
226 			{  5,  1, 10, false,  5,  70, 12,  7},	// min
227 			{ 80,  8,  5, true,  10, 120, 22, 11},	// max
228 			200000, 1400000, 2800000
229 		};
230 		limits = kLimits;
231 	} else {
232 		// TODO: support LVDS output limits as well
233 		static const pll_limits kLimits = {
234 			// p, p1, p2, high,   n,   m, m1, m2
235 			{  4,  2,  4, false,  5,  96, 20,  8},
236 			{128, 33,  2, true,  18, 140, 28, 18},
237 			165000, 930000, 1400000
238 		};
239 		limits = kLimits;
240 	}
241 
242 	TRACE(("PLL limits, min: p %lu (p1 %lu, p2 %lu), n %lu, m %lu (m1 %lu, m2 %lu)\n",
243 		limits.min.post, limits.min.post1, limits.min.post2, limits.min.n,
244 		limits.min.m, limits.min.m1, limits.min.m2));
245 	TRACE(("PLL limits, max: p %lu (p1 %lu, p2 %lu), n %lu, m %lu (m1 %lu, m2 %lu)\n",
246 		limits.max.post, limits.max.post1, limits.max.post2, limits.max.n,
247 		limits.max.m, limits.max.m1, limits.max.m2));
248 }
249 
250 
251 static bool
252 valid_pll_divisors(const pll_divisors& divisors, const pll_limits& limits)
253 {
254 	pll_info &info = gInfo->shared_info->pll_info;
255 	uint32 vco = info.reference_frequency * divisors.m / divisors.n;
256 	uint32 frequency = vco / divisors.post;
257 
258 	if (divisors.post < limits.min.post || divisors.post > limits.max.post
259 		|| divisors.m < limits.min.m || divisors.m > limits.max.m
260 		|| vco < limits.min_vco || vco > limits.max_vco
261 		|| frequency < info.min_frequency || frequency > info.max_frequency)
262 		return false;
263 
264 	return true;
265 }
266 
267 
268 static void
269 compute_pll_divisors(const display_mode &current, pll_divisors& divisors,
270 	bool isLVDS)
271 {
272 	float requestedPixelClock = current.timing.pixel_clock / 1000.0f;
273 	float referenceClock = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
274 	pll_limits limits;
275 	get_pll_limits(limits);
276 
277 	TRACE(("required MHz: %g\n", requestedPixelClock));
278 
279 	if (isLVDS) {
280 		if ((read32(INTEL_DISPLAY_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
281 				== LVDS_CLKB_POWER_UP)
282 			divisors.post2 = LVDS_POST2_RATE_FAST;
283 		else
284 			divisors.post2 = LVDS_POST2_RATE_SLOW;
285 	} else {
286 		if (current.timing.pixel_clock < limits.min_post2_frequency) {
287 			// slow DAC timing
288 			divisors.post2 = limits.min.post2;
289 			divisors.post2_high = limits.min.post2_high;
290 		} else {
291 			// fast DAC timing
292 			divisors.post2 = limits.max.post2;
293 			divisors.post2_high = limits.max.post2_high;
294 		}
295 	}
296 
297 	float best = requestedPixelClock;
298 	pll_divisors bestDivisors;
299 
300 	for (divisors.m1 = limits.min.m1; divisors.m1 <= limits.max.m1; divisors.m1++) {
301 		for (divisors.m2 = limits.min.m2; divisors.m2 < divisors.m1
302 				&& divisors.m2 <= limits.max.m2; divisors.m2++) {
303 			for (divisors.n = limits.min.n; divisors.n <= limits.max.n;
304 					divisors.n++) {
305 				for (divisors.post1 = limits.min.post1;
306 						divisors.post1 <= limits.max.post1; divisors.post1++) {
307 					divisors.m = 5 * divisors.m1 + divisors.m2;
308 					divisors.post = divisors.post1 * divisors.post2;
309 
310 					if (!valid_pll_divisors(divisors, limits))
311 						continue;
312 
313 					float error = fabs(requestedPixelClock
314 						- ((referenceClock * divisors.m) / divisors.n) / divisors.post);
315 					if (error < best) {
316 						best = error;
317 						bestDivisors = divisors;
318 
319 						if (error == 0)
320 							break;
321 					}
322 				}
323 			}
324 		}
325 	}
326 
327 	divisors = bestDivisors;
328 
329 	TRACE(("found: %g MHz, p = %lu (p1 = %lu, p2 = %lu), n = %lu, m = %lu (m1 = %lu, m2 = %lu)\n",
330 		((referenceClock * divisors.m) / divisors.n) / divisors.post,
331 		divisors.post, divisors.post1, divisors.post2, divisors.n,
332 		divisors.m, divisors.m1, divisors.m2));
333 }
334 
335 
336 /*! Store away panel information if identified on startup
337 	(used for pipe B->lvds).
338 */
339 void
340 save_lvds_mode(void)
341 {
342 	// dump currently programmed mode.
343 	display_mode biosMode;
344 
345 	uint32 pll = read32(INTEL_DISPLAY_B_PLL);
346 	uint32 pllDivisor = read32(INTEL_DISPLAY_B_PLL_DIVISOR_0);
347 
348 	pll_divisors divisors;
349 	divisors.m1 = (pllDivisor & DISPLAY_PLL_M1_DIVISOR_MASK)
350 		>> DISPLAY_PLL_M1_DIVISOR_SHIFT;
351 	divisors.m2 = (pllDivisor & DISPLAY_PLL_M2_DIVISOR_MASK)
352 		>> DISPLAY_PLL_M2_DIVISOR_SHIFT;
353 	divisors.n = (pllDivisor & DISPLAY_PLL_N_DIVISOR_MASK)
354 		>> DISPLAY_PLL_N_DIVISOR_SHIFT;
355 
356 	pll_limits limits;
357 	get_pll_limits(limits);
358 
359 	if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) {
360 		divisors.post1 = (pll & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK)
361 			>> DISPLAY_PLL_POST1_DIVISOR_SHIFT;
362 
363 		if ((pll & DISPLAY_PLL_DIVIDE_HIGH) != 0)
364 			divisors.post2 = limits.max.post2;
365 		else
366 			divisors.post2 = limits.min.post2;
367 
368 		// Fix this? Need to support dual channel LVDS.
369 		divisors.post2 = LVDS_POST2_RATE_SLOW;
370 	} else {
371 		// 8xx
372 		divisors.post1 = (pll & DISPLAY_PLL_POST1_DIVISOR_MASK)
373 			>> DISPLAY_PLL_POST1_DIVISOR_SHIFT;
374 
375 		if ((pll & DISPLAY_PLL_DIVIDE_4X) != 0)
376 			divisors.post2 = limits.max.post2;
377 		else
378 			divisors.post2 = limits.min.post2;
379 	}
380 
381 	divisors.m = 5 * divisors.m1 + divisors.m2;
382 	divisors.post = divisors.post1 * divisors.post2;
383 
384 	float referenceClock = gInfo->shared_info->pll_info.reference_frequency
385 		/ 1000.0f;
386 	float pixelClock = ((referenceClock * divisors.m) / divisors.n)
387 		/ divisors.post;
388 
389 	// timing
390 
391 	biosMode.timing.pixel_clock = uint32(pixelClock * 1000);
392 	biosMode.timing.flags = 0;
393 
394 	uint32 value = read32(INTEL_DISPLAY_B_HTOTAL);
395 	biosMode.timing.h_total = (value >> 16) + 1;
396 	biosMode.timing.h_display = (value & 0xffff) + 1;
397 
398 	value = read32(INTEL_DISPLAY_B_HSYNC);
399 	biosMode.timing.h_sync_end = (value >> 16) + 1;
400 	biosMode.timing.h_sync_start = (value & 0xffff) + 1;
401 
402 	value = read32(INTEL_DISPLAY_B_VTOTAL);
403 	biosMode.timing.v_total = (value >> 16) + 1;
404 	biosMode.timing.v_display = (value & 0xffff) + 1;
405 
406 	value = read32(INTEL_DISPLAY_B_VSYNC);
407 	biosMode.timing.v_sync_end = (value >> 16) + 1;
408 	biosMode.timing.v_sync_start = (value & 0xffff) + 1;
409 
410 	// image size and color space
411 
412 	// using virtual size based on image size is the 'proper' way to do it, however the bios appears to be
413 	// suggesting scaling or somesuch, so ignore the proper virtual way for now.
414 
415 	biosMode.virtual_width = biosMode.timing.h_display;
416 	biosMode.virtual_height = biosMode.timing.v_display;
417 
418 	//value = read32(INTEL_DISPLAY_B_IMAGE_SIZE);
419 	//biosMode.virtual_width = (value >> 16) + 1;
420 	//biosMode.virtual_height = (value & 0xffff) + 1;
421 
422 	value = read32(INTEL_DISPLAY_B_CONTROL);
423 	switch (value & DISPLAY_CONTROL_COLOR_MASK) {
424 		case DISPLAY_CONTROL_RGB32:
425 		default:
426 			biosMode.space = B_RGB32;
427 			break;
428 		case DISPLAY_CONTROL_RGB16:
429 			biosMode.space = B_RGB16;
430 			break;
431 		case DISPLAY_CONTROL_RGB15:
432 			biosMode.space = B_RGB15;
433 			break;
434 		case DISPLAY_CONTROL_CMAP8:
435 			biosMode.space = B_CMAP8;
436 			break;
437 	}
438 
439 	biosMode.h_display_start = 0;
440 	biosMode.v_display_start = 0;
441 	biosMode.flags = 0;
442 
443 	gInfo->lvds_panel_mode = biosMode;
444 }
445 
446 
447 static void
448 get_color_space_format(const display_mode &mode, uint32 &colorMode,
449 	uint32 &bytesPerRow, uint32 &bitsPerPixel)
450 {
451 	uint32 bytesPerPixel;
452 
453 	switch (mode.space) {
454 		case B_RGB32_LITTLE:
455 			colorMode = DISPLAY_CONTROL_RGB32;
456 			bytesPerPixel = 4;
457 			bitsPerPixel = 32;
458 			break;
459 		case B_RGB16_LITTLE:
460 			colorMode = DISPLAY_CONTROL_RGB16;
461 			bytesPerPixel = 2;
462 			bitsPerPixel = 16;
463 			break;
464 		case B_RGB15_LITTLE:
465 			colorMode = DISPLAY_CONTROL_RGB15;
466 			bytesPerPixel = 2;
467 			bitsPerPixel = 15;
468 			break;
469 		case B_CMAP8:
470 		default:
471 			colorMode = DISPLAY_CONTROL_CMAP8;
472 			bytesPerPixel = 1;
473 			bitsPerPixel = 8;
474 			break;
475 	}
476 
477 	bytesPerRow = mode.virtual_width * bytesPerPixel;
478 
479 	// Make sure bytesPerRow is a multiple of 64
480 	// TODO: check if the older chips have the same restriction!
481 	if ((bytesPerRow & 63) != 0)
482 		bytesPerRow = (bytesPerRow + 63) & ~63;
483 }
484 
485 
486 //	#pragma mark -
487 
488 
489 uint32
490 intel_accelerant_mode_count(void)
491 {
492 	TRACE(("intel_accelerant_mode_count()\n"));
493 	return gInfo->shared_info->mode_count;
494 }
495 
496 
497 status_t
498 intel_get_mode_list(display_mode *modeList)
499 {
500 	TRACE(("intel_get_mode_info()\n"));
501 	memcpy(modeList, gInfo->mode_list,
502 		gInfo->shared_info->mode_count * sizeof(display_mode));
503 	return B_OK;
504 }
505 
506 
507 status_t
508 intel_propose_display_mode(display_mode *target, const display_mode *low,
509 	const display_mode *high)
510 {
511 	TRACE(("intel_propose_display_mode()\n"));
512 
513 	// just search for the specified mode in the list
514 
515 	for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) {
516 		display_mode *mode = &gInfo->mode_list[i];
517 
518 		// TODO: improve this, ie. adapt pixel clock to allowed values!!!
519 
520 		if (target->virtual_width != mode->virtual_width
521 			|| target->virtual_height != mode->virtual_height
522 			|| target->space != mode->space)
523 			continue;
524 
525 		*target = *mode;
526 		return B_OK;
527 	}
528 	return B_BAD_VALUE;
529 }
530 
531 
532 status_t
533 intel_set_display_mode(display_mode *mode)
534 {
535 	TRACE(("intel_set_display_mode()\n"));
536 
537 	if (mode == NULL)
538 		return B_BAD_VALUE;
539 
540 	display_mode target = *mode;
541 	if (intel_propose_display_mode(&target, mode, mode))
542 		return B_BAD_VALUE;
543 
544 	uint32 colorMode, bytesPerRow, bitsPerPixel;
545 	get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel);
546 
547 #if 0
548 static bool first = true;
549 if (first) {
550 	int fd = open("/boot/home/ie_.regs", O_CREAT | O_WRONLY, 0644);
551 	if (fd >= 0) {
552 		for (int32 i = 0; i < 0x80000; i += 16) {
553 			char line[512];
554 			int length = sprintf(line, "%05lx: %08lx %08lx %08lx %08lx\n",
555 				i, read32(i), read32(i + 4), read32(i + 8), read32(i + 12));
556 			write(fd, line, length);
557 		}
558 		close(fd);
559 		sync();
560 	}
561 	first = false;
562 }
563 #endif
564 
565 	intel_shared_info &sharedInfo = *gInfo->shared_info;
566 	Autolock locker(sharedInfo.accelerant_lock);
567 
568 	// TODO: This may not be neccesary
569 	set_display_power_mode(B_DPMS_OFF);
570 
571 	// free old and allocate new frame buffer in graphics memory
572 
573 	intel_free_memory(sharedInfo.frame_buffer);
574 
575 	uint32 base;
576 	if (intel_allocate_memory(bytesPerRow * target.virtual_height, 0,
577 			base) < B_OK) {
578 		// oh, how did that happen? Unfortunately, there is no really good way back
579 		if (intel_allocate_memory(sharedInfo.current_mode.virtual_height
580 				* sharedInfo.bytes_per_row, 0, base) == B_OK) {
581 			sharedInfo.frame_buffer = base;
582 			sharedInfo.frame_buffer_offset = base
583 				- (addr_t)sharedInfo.graphics_memory;
584 			set_frame_buffer_base();
585 		}
586 
587 		return B_NO_MEMORY;
588 	}
589 
590 	// clear frame buffer before using it
591 	memset((uint8 *)base, 0, bytesPerRow * target.virtual_height);
592 	sharedInfo.frame_buffer = base;
593 	sharedInfo.frame_buffer_offset = base - (addr_t)sharedInfo.graphics_memory;
594 
595 	// make sure VGA display is disabled
596 	write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED);
597 	read32(INTEL_VGA_DISPLAY_CONTROL);
598 
599 	if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_85x)) {
600 	}
601 
602 	if ((gInfo->head_mode & HEAD_MODE_B_DIGITAL) != 0) {
603 		pll_divisors divisors;
604 		compute_pll_divisors(target, divisors, true);
605 
606 		uint32 dpll = DISPLAY_PLL_NO_VGA_CONTROL;
607 		if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) {
608 			 dpll |= LVDS_PLL_MODE_LVDS;
609 			 	// DPLL mode LVDS for i915+
610 		}
611 
612 		// compute bitmask from p1 value
613 		dpll |= (1 << (divisors.post1 - 1)) << 16;
614 		switch (divisors.post2) {
615 			case 5:
616 			case 7:
617 				dpll |= DISPLAY_PLL_DIVIDE_HIGH;
618 				break;
619 		}
620 
621 		dpll |= (1 << (divisors.post1 - 1)) << DISPLAY_PLL_POST1_DIVISOR_SHIFT;
622 
623 		uint32 displayControl = ~(DISPLAY_CONTROL_COLOR_MASK
624 			| DISPLAY_CONTROL_GAMMA) | colorMode;
625 		displayControl |= 1 << 24; // select pipe B
626 
627 		// runs in dpms also?
628 		displayControl |= DISPLAY_PIPE_ENABLED;
629 		dpll |= DISPLAY_PLL_ENABLED;
630 
631 		write32(INTEL_PANEL_FIT_CONTROL, 0);
632 
633 		if ((dpll & DISPLAY_PLL_ENABLED) != 0) {
634 			write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
635 				(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
636 					& DISPLAY_PLL_N_DIVISOR_MASK)
637 				| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
638 					& DISPLAY_PLL_M1_DIVISOR_MASK)
639 				| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
640 					& DISPLAY_PLL_M2_DIVISOR_MASK));
641 			write32(INTEL_DISPLAY_B_PLL, dpll & ~DISPLAY_PLL_ENABLED);
642 			read32(INTEL_DISPLAY_B_PLL);
643 			spin(150);
644 		}
645 
646 		uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT)
647 			| LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
648 
649 		float referenceClock = gInfo->shared_info->pll_info.reference_frequency
650 			/ 1000.0f;
651 
652 		// Set the B0-B3 data pairs corresponding to whether we're going to
653 		// set the DPLLs for dual-channel mode or not.
654 		if (divisors.post2 == LVDS_POST2_RATE_FAST)
655 			lvds |= LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP;
656 		else
657 			lvds &= ~( LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP);
658 
659 		write32(INTEL_DISPLAY_LVDS_PORT, lvds);
660 		read32(INTEL_DISPLAY_LVDS_PORT);
661 
662 		write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
663 			(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
664 				& DISPLAY_PLL_N_DIVISOR_MASK)
665 			| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
666 				& DISPLAY_PLL_M1_DIVISOR_MASK)
667 			| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
668 				& DISPLAY_PLL_M2_DIVISOR_MASK));
669 
670 		write32(INTEL_DISPLAY_B_PLL, dpll);
671 		read32(INTEL_DISPLAY_B_PLL);
672 
673 		// Wait for the clocks to stabilize
674 		spin(150);
675 
676 		if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) {
677 			float adjusted = ((referenceClock * divisors.m) / divisors.n)
678 				/ divisors.post;
679 			uint32 pixelMultiply = uint32(adjusted
680 				/ (target.timing.pixel_clock / 1000.0f));
681 
682 			write32(INTEL_DISPLAY_B_PLL_MULTIPLIER_DIVISOR, (0 << 24)
683 				| ((pixelMultiply - 1) << 8));
684 		} else
685 			write32(INTEL_DISPLAY_B_PLL, dpll);
686 
687 		read32(INTEL_DISPLAY_B_PLL);
688 		spin(150);
689 
690 		// update timing parameters
691 		write32(INTEL_DISPLAY_B_HTOTAL, ((uint32)(target.timing.h_total - 1) << 16)
692 			| ((uint32)target.timing.h_display - 1));
693 		write32(INTEL_DISPLAY_B_HBLANK, ((uint32)(target.timing.h_total - 1) << 16)
694 			| ((uint32)target.timing.h_display - 1));
695 		write32(INTEL_DISPLAY_B_HSYNC, ((uint32)(target.timing.h_sync_end - 1) << 16)
696 			| ((uint32)target.timing.h_sync_start - 1));
697 
698 		write32(INTEL_DISPLAY_B_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16)
699 			| ((uint32)target.timing.v_display - 1));
700 		write32(INTEL_DISPLAY_B_VBLANK, ((uint32)(target.timing.v_total - 1) << 16)
701 			| ((uint32)target.timing.v_display - 1));
702 		write32(INTEL_DISPLAY_B_VSYNC, ((uint32)(target.timing.v_sync_end - 1) << 16)
703 			| ((uint32)target.timing.v_sync_start - 1));
704 
705 		write32(INTEL_DISPLAY_B_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16)
706 			| ((uint32)target.timing.v_display - 1));
707 
708 		write32(INTEL_DISPLAY_B_POS, 0);
709 		write32(INTEL_DISPLAY_B_PIPE_SIZE, ((uint32)(target.timing.v_display - 1) << 16)
710 			| ((uint32)target.timing.h_display - 1));
711 
712 		write32(INTEL_DISPLAY_B_PIPE_CONTROL,
713 			read32(INTEL_DISPLAY_B_PIPE_CONTROL) | DISPLAY_PIPE_ENABLED);
714 		read32(INTEL_DISPLAY_B_PIPE_CONTROL);
715 	}
716 
717 	if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
718 		pll_divisors divisors;
719 		compute_pll_divisors(target, divisors,false);
720 
721 		write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
722 			(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) & DISPLAY_PLL_N_DIVISOR_MASK)
723 			| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) & DISPLAY_PLL_M1_DIVISOR_MASK)
724 			| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) & DISPLAY_PLL_M2_DIVISOR_MASK));
725 
726 		uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL;
727 		if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) {
728 			pll |= ((1 << (divisors.post1 - 1))
729 					<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
730 				& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
731 //			pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
732 //				& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
733 			if (divisors.post2_high)
734 				pll |= DISPLAY_PLL_DIVIDE_HIGH;
735 
736 			pll |= DISPLAY_PLL_MODE_ANALOG;
737 
738 			if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x))
739 				pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
740 		} else {
741 			if (!divisors.post2_high)
742 				pll |= DISPLAY_PLL_DIVIDE_4X;
743 
744 			pll |= DISPLAY_PLL_2X_CLOCK;
745 
746 			if (divisors.post1 > 2) {
747 				pll |= (((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
748 					& DISPLAY_PLL_POST1_DIVISOR_MASK);
749 			} else
750 				pll |= DISPLAY_PLL_POST1_DIVIDE_2;
751 		}
752 
753 		write32(INTEL_DISPLAY_A_PLL, pll);
754 		read32(INTEL_DISPLAY_A_PLL);
755 		spin(150);
756 		write32(INTEL_DISPLAY_A_PLL, pll);
757 		read32(INTEL_DISPLAY_A_PLL);
758 		spin(150);
759 
760 		// update timing parameters
761 		write32(INTEL_DISPLAY_A_HTOTAL, ((uint32)(target.timing.h_total - 1) << 16)
762 			| ((uint32)target.timing.h_display - 1));
763 		write32(INTEL_DISPLAY_A_HBLANK, ((uint32)(target.timing.h_total - 1) << 16)
764 			| ((uint32)target.timing.h_display - 1));
765 		write32(INTEL_DISPLAY_A_HSYNC, ((uint32)(target.timing.h_sync_end - 1) << 16)
766 			| ((uint32)target.timing.h_sync_start - 1));
767 
768 		write32(INTEL_DISPLAY_A_VTOTAL, ((uint32)(target.timing.v_total - 1) << 16)
769 			| ((uint32)target.timing.v_display - 1));
770 		write32(INTEL_DISPLAY_A_VBLANK, ((uint32)(target.timing.v_total - 1) << 16)
771 			| ((uint32)target.timing.v_display - 1));
772 		write32(INTEL_DISPLAY_A_VSYNC, ((uint32)(target.timing.v_sync_end - 1) << 16)
773 			| ((uint32)target.timing.v_sync_start - 1));
774 
775 		write32(INTEL_DISPLAY_A_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16)
776 			| ((uint32)target.timing.v_display - 1));
777 
778 		write32(INTEL_DISPLAY_A_ANALOG_PORT, (read32(INTEL_DISPLAY_A_ANALOG_PORT)
779 			& ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY))
780 			| ((target.timing.flags & B_POSITIVE_HSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
781 			| ((target.timing.flags & B_POSITIVE_VSYNC) != 0 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
782 
783 		// TODO: verify the two comments below: the X driver doesn't seem to
784 		//		care about both of them!
785 
786 		// These two have to be set for display B, too - this obviously means
787 		// that the second head always must adopt the color space of the first
788 		// head.
789 		write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL)
790 			& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) | colorMode);
791 
792 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
793 			write32(INTEL_DISPLAY_B_IMAGE_SIZE, ((uint32)(target.timing.h_display - 1) << 16)
794 				| ((uint32)target.timing.v_display - 1));
795 
796 			write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL)
797 				& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) | colorMode);
798 		}
799 	}
800 
801 	set_display_power_mode(sharedInfo.dpms_mode);
802 
803 	// changing bytes per row seems to be ignored if the plane/pipe is turned off
804 
805 	if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
806 		write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow);
807 	if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
808 		write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow);
809 
810 	set_frame_buffer_base();
811 		// triggers writing back double-buffered registers
812 
813 	// update shared info
814 	sharedInfo.bytes_per_row = bytesPerRow;
815 	sharedInfo.current_mode = target;
816 	sharedInfo.bits_per_pixel = bitsPerPixel;
817 
818 	return B_OK;
819 }
820 
821 
822 status_t
823 intel_get_display_mode(display_mode *_currentMode)
824 {
825 	TRACE(("intel_get_display_mode()\n"));
826 
827 	display_mode &mode = *_currentMode;
828 
829 	uint32 pll = read32(INTEL_DISPLAY_A_PLL);
830 	uint32 pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0
831 		? INTEL_DISPLAY_A_PLL_DIVISOR_1 : INTEL_DISPLAY_A_PLL_DIVISOR_0);
832 
833 	pll_divisors divisors;
834 	divisors.m1 = (pllDivisor & DISPLAY_PLL_M1_DIVISOR_MASK)
835 		>> DISPLAY_PLL_M1_DIVISOR_SHIFT;
836 	divisors.m2 = (pllDivisor & DISPLAY_PLL_M2_DIVISOR_MASK)
837 		>> DISPLAY_PLL_M2_DIVISOR_SHIFT;
838 	divisors.n = (pllDivisor & DISPLAY_PLL_N_DIVISOR_MASK)
839 		>> DISPLAY_PLL_N_DIVISOR_SHIFT;
840 
841 	pll_limits limits;
842 	get_pll_limits(limits);
843 
844 	if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) {
845 		divisors.post1 = (pll & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK)
846 			>> DISPLAY_PLL_POST1_DIVISOR_SHIFT;
847 
848 		if ((pll & DISPLAY_PLL_DIVIDE_HIGH) != 0)
849 			divisors.post2 = limits.max.post2;
850 		else
851 			divisors.post2 = limits.min.post2;
852 	} else {
853 		// 8xx
854 		divisors.post1 = (pll & DISPLAY_PLL_POST1_DIVISOR_MASK)
855 			>> DISPLAY_PLL_POST1_DIVISOR_SHIFT;
856 
857 		if ((pll & DISPLAY_PLL_DIVIDE_4X) != 0)
858 			divisors.post2 = limits.max.post2;
859 		else
860 			divisors.post2 = limits.min.post2;
861 	}
862 
863 	divisors.m = 5 * divisors.m1 + divisors.m2;
864 	divisors.post = divisors.post1 * divisors.post2;
865 
866 	float referenceClock
867 		= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
868 	float pixelClock
869 		= ((referenceClock * divisors.m) / divisors.n) / divisors.post;
870 
871 	// timing
872 
873 	mode.timing.pixel_clock = uint32(pixelClock * 1000);
874 	mode.timing.flags = 0;
875 
876 	uint32 value = read32(INTEL_DISPLAY_A_HTOTAL);
877 	mode.timing.h_total = (value >> 16) + 1;
878 	mode.timing.h_display = (value & 0xffff) + 1;
879 
880 	value = read32(INTEL_DISPLAY_A_HSYNC);
881 	mode.timing.h_sync_end = (value >> 16) + 1;
882 	mode.timing.h_sync_start = (value & 0xffff) + 1;
883 
884 	value = read32(INTEL_DISPLAY_A_VTOTAL);
885 	mode.timing.v_total = (value >> 16) + 1;
886 	mode.timing.v_display = (value & 0xffff) + 1;
887 
888 	value = read32(INTEL_DISPLAY_A_VSYNC);
889 	mode.timing.v_sync_end = (value >> 16) + 1;
890 	mode.timing.v_sync_start = (value & 0xffff) + 1;
891 
892 	// image size and color space
893 
894 	value = read32(INTEL_DISPLAY_A_IMAGE_SIZE);
895 	mode.virtual_width = (value >> 16) + 1;
896 	mode.virtual_height = (value & 0xffff) + 1;
897 
898 	value = read32(INTEL_DISPLAY_A_CONTROL);
899 	switch (value & DISPLAY_CONTROL_COLOR_MASK) {
900 		case DISPLAY_CONTROL_RGB32:
901 		default:
902 			mode.space = B_RGB32;
903 			break;
904 		case DISPLAY_CONTROL_RGB16:
905 			mode.space = B_RGB16;
906 			break;
907 		case DISPLAY_CONTROL_RGB15:
908 			mode.space = B_RGB15;
909 			break;
910 		case DISPLAY_CONTROL_CMAP8:
911 			mode.space = B_CMAP8;
912 			break;
913 	}
914 
915 	mode.h_display_start = 0;
916 	mode.v_display_start = 0;
917 	mode.flags = 0;
918 	return B_OK;
919 }
920 
921 #ifdef __HAIKU__
922 
923 status_t
924 intel_get_edid_info(void* info, size_t size, uint32* _version)
925 {
926 	TRACE(("intel_get_edid_info()\n"));
927 
928 	if (!gInfo->has_edid)
929 		return B_ERROR;
930 	if (size < sizeof(struct edid1_info))
931 		return B_BUFFER_OVERFLOW;
932 
933 	memcpy(info, &gInfo->edid_info, sizeof(struct edid1_info));
934 	*_version = EDID_VERSION_1;
935 	return B_OK;
936 }
937 
938 #endif	// __HAIKU__
939 
940 status_t
941 intel_get_frame_buffer_config(frame_buffer_config *config)
942 {
943 	TRACE(("intel_get_frame_buffer_config()\n"));
944 
945 	uint32 offset = gInfo->shared_info->frame_buffer_offset;
946 
947 	config->frame_buffer = gInfo->shared_info->graphics_memory + offset;
948 	config->frame_buffer_dma
949 		= (uint8 *)gInfo->shared_info->physical_graphics_memory + offset;
950 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
951 
952 	return B_OK;
953 }
954 
955 
956 status_t
957 intel_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high)
958 {
959 	TRACE(("intel_get_pixel_clock_limits()\n"));
960 
961 	if (_low != NULL) {
962 		// lower limit of about 48Hz vertical refresh
963 		uint32 totalClocks = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total;
964 		uint32 low = (totalClocks * 48L) / 1000L;
965 		if (low < gInfo->shared_info->pll_info.min_frequency)
966 			low = gInfo->shared_info->pll_info.min_frequency;
967 		else if (low > gInfo->shared_info->pll_info.max_frequency)
968 			return B_ERROR;
969 
970 		*_low = low;
971 	}
972 
973 	if (_high != NULL)
974 		*_high = gInfo->shared_info->pll_info.max_frequency;
975 
976 	return B_OK;
977 }
978 
979 
980 status_t
981 intel_move_display(uint16 horizontalStart, uint16 verticalStart)
982 {
983 	TRACE(("intel_move_display()\n"));
984 
985 	intel_shared_info &sharedInfo = *gInfo->shared_info;
986 	Autolock locker(sharedInfo.accelerant_lock);
987 
988 	display_mode &mode = sharedInfo.current_mode;
989 
990 	if (horizontalStart + mode.timing.h_display > mode.virtual_width
991 		|| verticalStart + mode.timing.v_display > mode.virtual_height)
992 		return B_BAD_VALUE;
993 
994 	mode.h_display_start = horizontalStart;
995 	mode.v_display_start = verticalStart;
996 
997 	set_frame_buffer_base();
998 
999 	return B_OK;
1000 }
1001 
1002 
1003 status_t
1004 intel_get_timing_constraints(display_timing_constraints *constraints)
1005 {
1006 	TRACE(("intel_get_timing_contraints()\n"));
1007 	return B_ERROR;
1008 }
1009 
1010 
1011 void
1012 intel_set_indexed_colors(uint count, uint8 first, uint8 *colors, uint32 flags)
1013 {
1014 	TRACE(("intel_set_indexed_colors(colors = %p, first = %u)\n", colors, first));
1015 
1016 	if (colors == NULL)
1017 		return;
1018 
1019 	Autolock locker(gInfo->shared_info->accelerant_lock);
1020 
1021 	for (; count-- > 0; first++) {
1022 		uint32 color = colors[0] << 16 | colors[1] << 8 | colors[2];
1023 		colors += 3;
1024 
1025 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
1026 			write32(INTEL_DISPLAY_A_PALETTE + first * sizeof(uint32), color);
1027 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
1028 			write32(INTEL_DISPLAY_B_PALETTE + first * sizeof(uint32), color);
1029 	}
1030 }
1031 
1032