xref: /haiku/src/add-ons/accelerants/intel_extreme/Ports.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Michael Lotz, mmlr@mlotz.ch
8  *		Alexander von Gluck IV, kallisti5@unixzen.com
9  */
10 
11 
12 #include "Ports.h"
13 
14 #include <ddc.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <Debug.h>
18 #include <KernelExport.h>
19 
20 #include "accelerant.h"
21 #include "accelerant_protos.h"
22 #include "FlexibleDisplayInterface.h"
23 #include "intel_extreme.h"
24 #include "PanelFitter.h"
25 
26 #include <new>
27 
28 
29 #undef TRACE
30 #define TRACE_PORTS
31 #ifdef TRACE_PORTS
32 #   define TRACE(x...) _sPrintf("intel_extreme: " x)
33 #else
34 #   define TRACE(x...)
35 #endif
36 
37 #define ERROR(x...) _sPrintf("intel_extreme: " x)
38 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
39 
40 
41 static bool
42 wait_for_set(addr_t address, uint32 mask, uint32 timeout)
43 {
44 	int interval = 50;
45 	uint32 i = 0;
46 	for(i = 0; i <= timeout; i += interval) {
47 		spin(interval);
48 		if ((read32(address) & mask) != 0)
49 			return true;
50 	}
51 	return false;
52 }
53 
54 
55 static bool
56 wait_for_clear(addr_t address, uint32 mask, uint32 timeout)
57 {
58 	int interval = 50;
59 	uint32 i = 0;
60 	for(i = 0; i <= timeout; i += interval) {
61 		spin(interval);
62 		if ((read32(address) & mask) == 0)
63 			return true;
64 	}
65 	return false;
66 }
67 
68 
69 Port::Port(port_index index, const char* baseName)
70 	:
71 	fPipe(NULL),
72 	fEDIDState(B_NO_INIT),
73 	fPortIndex(index),
74 	fPortName(NULL)
75 {
76 	char portID[2];
77 	portID[0] = 'A' + index - INTEL_PORT_A;
78 	portID[1] = 0;
79 
80 	char buffer[32];
81 	buffer[0] = 0;
82 
83 	strlcat(buffer, baseName, sizeof(buffer));
84 	strlcat(buffer, " ", sizeof(buffer));
85 	strlcat(buffer, portID, sizeof(buffer));
86 	fPortName = strdup(buffer);
87 }
88 
89 
90 Port::~Port()
91 {
92 	free(fPortName);
93 }
94 
95 
96 bool
97 Port::HasEDID()
98 {
99 	if (fEDIDState == B_NO_INIT)
100 		GetEDID(NULL);
101 
102 	return fEDIDState == B_OK;
103 }
104 
105 
106 status_t
107 Port::SetPipe(Pipe* pipe)
108 {
109 	CALLED();
110 
111 	if (pipe == NULL) {
112 		ERROR("%s: Invalid pipe provided!\n", __func__);
113 		return B_ERROR;
114 	}
115 
116 	uint32 portRegister = _PortRegister();
117 	if (portRegister == 0) {
118 		ERROR("%s: Invalid PortRegister ((0x%" B_PRIx32 ") for %s\n", __func__,
119 			portRegister, PortName());
120 		return B_ERROR;
121 	}
122 
123 	// TODO: UnAssignPipe?  This likely needs reworked a little
124 	if (fPipe != NULL) {
125 		ERROR("%s: Can't reassign display pipe (yet)\n", __func__);
126 		return B_ERROR;
127 	}
128 
129 	TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe %s\n", __func__,
130 		PortName(), portRegister, (pipe->Index() == INTEL_PIPE_A) ? "A" : "B");
131 
132 	uint32 portState = read32(portRegister);
133 
134 	// FIXME is the use of PORT_TRANS_* constants correct for Sandy Bridge /
135 	// Cougar Point? Or is it only for Ivy Bridge / Panther point onwards?
136 	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
137 		portState &= ~PORT_TRANS_SEL_MASK;
138 		if (pipe->Index() == INTEL_PIPE_A)
139 			write32(portRegister, portState | PORT_TRANS_A_SEL_CPT);
140 		else
141 			write32(portRegister, portState | PORT_TRANS_B_SEL_CPT);
142 	} else {
143 		if (pipe->Index() == INTEL_PIPE_A)
144 			write32(portRegister, portState & ~DISPLAY_MONITOR_PIPE_B);
145 		else
146 			write32(portRegister, portState | DISPLAY_MONITOR_PIPE_B);
147 	}
148 	fPipe = pipe;
149 
150 	if (fPipe == NULL)
151 		return B_NO_MEMORY;
152 
153 	// Disable display pipe until modesetting enables it
154 	if (fPipe->IsEnabled())
155 		fPipe->Enable(false);
156 
157 	read32(portRegister);
158 
159 	return B_OK;
160 }
161 
162 
163 status_t
164 Port::Power(bool enabled)
165 {
166 	if (fPipe == NULL) {
167 		ERROR("%s: Setting power mode without assigned pipe!\n", __func__);
168 		return B_ERROR;
169 	}
170 
171 	fPipe->Enable(enabled);
172 
173 	return B_OK;
174 }
175 
176 
177 status_t
178 Port::GetEDID(edid1_info* edid, bool forceRead)
179 {
180 	CALLED();
181 
182 	if (fEDIDState == B_NO_INIT || forceRead) {
183 		TRACE("%s: trying to read EDID\n", PortName());
184 
185 		addr_t ddcRegister = _DDCRegister();
186 		if (ddcRegister == 0) {
187 			TRACE("%s: no DDC register found\n", PortName());
188 			fEDIDState = B_ERROR;
189 			return fEDIDState;
190 		}
191 
192 		TRACE("%s: using ddc @ 0x%" B_PRIxADDR "\n", PortName(), ddcRegister);
193 
194 		i2c_bus bus;
195 		bus.cookie = (void*)ddcRegister;
196 		bus.set_signals = &_SetI2CSignals;
197 		bus.get_signals = &_GetI2CSignals;
198 		ddc2_init_timing(&bus);
199 
200 		fEDIDState = ddc2_read_edid1(&bus, &fEDIDInfo, NULL, NULL);
201 
202 		if (fEDIDState == B_OK) {
203 			TRACE("%s: found EDID information!\n", PortName());
204 			edid_dump(&fEDIDInfo);
205 		}
206 	}
207 
208 	if (fEDIDState != B_OK) {
209 		TRACE("%s: no EDID information found.\n", PortName());
210 		return fEDIDState;
211 	}
212 
213 	if (edid != NULL)
214 		memcpy(edid, &fEDIDInfo, sizeof(edid1_info));
215 
216 	return B_OK;
217 }
218 
219 
220 status_t
221 Port::GetPLLLimits(pll_limits& limits)
222 {
223 	return B_ERROR;
224 }
225 
226 
227 pipe_index
228 Port::PipePreference()
229 {
230 	CALLED();
231 	// Ideally we could just return INTEL_PIPE_ANY for all devices by default, but
232 	// this doesn't quite work yet. We need to use the BIOS presetup pipes for now.
233 	if (gInfo->shared_info->device_type.Generation() < 4)
234 		return INTEL_PIPE_ANY;
235 
236 	// Notes:
237 	// - The BIOSes seen sofar do not use PIPE C by default.
238 	// - The BIOSes seen sofar program transcoder A to PIPE A, etc.
239 	// - Later devices add a pipe C alongside the added transcoder C.
240 
241 	// FIXME How's this setup in newer gens? Currently return INTEL_PIPE_ANY there..
242 	if ((gInfo->shared_info->device_type.Generation() <= 7) &&
243 		(!gInfo->shared_info->device_type.HasDDI())) {
244 		uint32 portState = read32(_PortRegister());
245 		if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
246 			portState &= PORT_TRANS_SEL_MASK;
247 			if (portState == PORT_TRANS_B_SEL_CPT)
248 				return INTEL_PIPE_B;
249 			else
250 				return INTEL_PIPE_A;
251 		} else {
252 			if (portState & DISPLAY_MONITOR_PIPE_B)
253 				return INTEL_PIPE_B;
254 			else
255 				return INTEL_PIPE_A;
256 		}
257 	}
258 
259 	if (gInfo->shared_info->device_type.HasDDI()) {
260 		//fixme implement detection via PIPE_DDI_FUNC_CTL_x scan..
261 	}
262 
263 	return INTEL_PIPE_ANY;
264 }
265 
266 
267 status_t
268 Port::_GetI2CSignals(void* cookie, int* _clock, int* _data)
269 {
270 	addr_t ioRegister = (addr_t)cookie;
271 	uint32 value = read32(ioRegister);
272 
273 	*_clock = (value & I2C_CLOCK_VALUE_IN) != 0;
274 	*_data = (value & I2C_DATA_VALUE_IN) != 0;
275 
276 	return B_OK;
277 }
278 
279 
280 status_t
281 Port::_SetI2CSignals(void* cookie, int clock, int data)
282 {
283 	addr_t ioRegister = (addr_t)cookie;
284 	uint32 value;
285 
286 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_83x)) {
287 		// on these chips, the reserved values are fixed
288 		value = 0;
289 	} else {
290 		// on all others, we have to preserve them manually
291 		value = read32(ioRegister) & I2C_RESERVED;
292 	}
293 
294 	if (data != 0)
295 		value |= I2C_DATA_DIRECTION_MASK;
296 	else {
297 		value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT
298 			| I2C_DATA_VALUE_MASK;
299 	}
300 
301 	if (clock != 0)
302 		value |= I2C_CLOCK_DIRECTION_MASK;
303 	else {
304 		value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT
305 			| I2C_CLOCK_VALUE_MASK;
306 	}
307 
308 	write32(ioRegister, value);
309 	read32(ioRegister);
310 		// make sure the PCI bus has flushed the write
311 
312 	return B_OK;
313 }
314 
315 
316 // #pragma mark - Analog Port
317 
318 
319 AnalogPort::AnalogPort()
320 	:
321 	Port(INTEL_PORT_A, "Analog")
322 {
323 }
324 
325 
326 bool
327 AnalogPort::IsConnected()
328 {
329 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
330 		_PortRegister());
331 	return HasEDID();
332 }
333 
334 
335 addr_t
336 AnalogPort::_DDCRegister()
337 {
338 	// always fixed
339 	return INTEL_I2C_IO_A;
340 }
341 
342 
343 addr_t
344 AnalogPort::_PortRegister()
345 {
346 	// always fixed
347 	return INTEL_ANALOG_PORT;
348 }
349 
350 
351 status_t
352 AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
353 {
354 	CALLED();
355 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->timing.h_display,
356 		target->timing.v_display);
357 
358 	if (fPipe == NULL) {
359 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
360 		return B_ERROR;
361 	}
362 
363 	// Setup PanelFitter and Train FDI if it exists
364 	PanelFitter* fitter = fPipe->PFT();
365 	if (fitter != NULL)
366 		fitter->Enable(*target);
367 	FDILink* link = fPipe->FDI();
368 	if (link != NULL)
369 		link->Train(target);
370 
371 	pll_divisors divisors;
372 	compute_pll_divisors(target, &divisors, false);
373 
374 	uint32 extraPLLFlags = 0;
375 	if (gInfo->shared_info->device_type.Generation() >= 3)
376 		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
377 
378 	// Program general pipe config
379 	fPipe->Configure(target);
380 
381 	// Program pipe PLL's
382 	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
383 
384 	write32(_PortRegister(), (read32(_PortRegister())
385 		& ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY))
386 		| ((target->timing.flags & B_POSITIVE_HSYNC) != 0
387 			? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
388 		| ((target->timing.flags & B_POSITIVE_VSYNC) != 0
389 			? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
390 
391 	// Program target display mode
392 	fPipe->ConfigureTimings(target);
393 
394 	// Set fCurrentMode to our set display mode
395 	memcpy(&fCurrentMode, target, sizeof(display_mode));
396 
397 	return B_OK;
398 }
399 
400 
401 // #pragma mark - LVDS Panel
402 
403 
404 LVDSPort::LVDSPort()
405 	:
406 	Port(INTEL_PORT_C, "LVDS")
407 {
408 	// Always unlock LVDS port as soon as we start messing with it.
409 	uint32 panelControl = INTEL_PANEL_CONTROL;
410 	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
411 		// FIXME writing there results in black screen on SandyBridge
412 		return;
413 		// panelControl = PCH_PANEL_CONTROL;
414 	}
415 	write32(panelControl, read32(panelControl) | PANEL_REGISTER_UNLOCK);
416 }
417 
418 
419 pipe_index
420 LVDSPort::PipePreference()
421 {
422 	CALLED();
423 	// Older devices have hardcoded pipe/port mappings, so just use that
424 	if (gInfo->shared_info->device_type.Generation() < 4)
425 		return INTEL_PIPE_B;
426 
427 	// Ideally we could just return INTEL_PIPE_ANY for the newer devices, but
428 	// this doesn't quite work yet.
429 
430 	// On SandyBridge and later, there is a transcoder C. On SandyBridge at least
431 	// that can't be used by the LVDS port (but A and B would be fine).
432 	// On Ibex Point, SandyBridge and IvyBridge (tested) changing pipes does not
433 	// work yet.
434 	// Notes:
435 	// - Switching Pipes only works reliably when a 'full modeswitch' is executed
436 	//   (FDI training) so we have to reuse the BIOS preset setup always for now.
437 	// - The BIOSes seen sofar do not use PIPE C by default.
438 	// - The BIOSes seen sofar program transcoder A to PIPE A, etc.
439 	// - Later devices add a pipe C alongside the added transcoder C.
440 
441 	// FIXME How's this setup in newer gens? Currently return Pipe B fixed there..
442 	if (gInfo->shared_info->device_type.Generation() <= 7) {
443 		uint32 portState = read32(_PortRegister());
444 		if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
445 			portState &= PORT_TRANS_SEL_MASK;
446 			if (portState == PORT_TRANS_B_SEL_CPT)
447 				return INTEL_PIPE_B;
448 			else
449 				return INTEL_PIPE_A;
450 		} else {
451 			if (portState & DISPLAY_MONITOR_PIPE_B)
452 				return INTEL_PIPE_B;
453 			else
454 				return INTEL_PIPE_A;
455 		}
456 	}
457 
458 	return INTEL_PIPE_B;
459 }
460 
461 
462 bool
463 LVDSPort::IsConnected()
464 {
465 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
466 		_PortRegister());
467 
468 	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
469 		uint32 registerValue = read32(_PortRegister());
470 		// there's a detection bit we can use
471 		if ((registerValue & PCH_LVDS_DETECTED) == 0) {
472 			TRACE("LVDS: Not detected\n");
473 			return false;
474 		}
475 		// TODO: Skip if eDP support
476 	} else if (gInfo->shared_info->device_type.Generation() <= 4) {
477 		// Older generations don't have LVDS detection. If not mobile skip.
478 		if (!gInfo->shared_info->device_type.IsMobile()) {
479 			TRACE("LVDS: Skipping LVDS detection due to gen and not mobile\n");
480 			return false;
481 		}
482 		// If mobile, try to grab EDID
483 		// Linux seems to look at lid status for LVDS port detection
484 		// If we don't get EDID, we can use vbios native mode or vesa?
485 		if (!HasEDID()) {
486 			if (gInfo->shared_info->has_vesa_edid_info) {
487 				TRACE("LVDS: Using VESA edid info\n");
488 				memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info,
489 					sizeof(edid1_info));
490 				fEDIDState = B_OK;
491 				// HasEDID now true
492 			} else if (gInfo->shared_info->got_vbt) {
493 				TRACE("LVDS: No EDID, but force enabled as we have a VBT\n");
494 				return true;
495 			} else {
496 				TRACE("LVDS: Couldn't find any valid EDID!\n");
497 				return false;
498 			}
499 		}
500 	}
501 
502 	// Try getting EDID, as the LVDS port doesn't overlap with anything else,
503 	// we don't run the risk of getting someone else's data.
504 	return HasEDID();
505 }
506 
507 
508 addr_t
509 LVDSPort::_DDCRegister()
510 {
511 	// always fixed
512 	return INTEL_I2C_IO_C;
513 }
514 
515 
516 addr_t
517 LVDSPort::_PortRegister()
518 {
519 	// always fixed
520 	return INTEL_DIGITAL_LVDS_PORT;
521 }
522 
523 
524 status_t
525 LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
526 {
527 	CALLED();
528 	if (target == NULL) {
529 		ERROR("%s: Invalid target mode passed!\n", __func__);
530 		return B_ERROR;
531 	}
532 
533 	TRACE("%s: %s-%d %dx%d\n", __func__, PortName(), PortIndex(),
534 		target->timing.h_display, target->timing.v_display);
535 
536 	if (fPipe == NULL) {
537 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
538 		return B_ERROR;
539 	}
540 
541 	addr_t panelControl = INTEL_PANEL_CONTROL;
542 	addr_t panelStatus = INTEL_PANEL_STATUS;
543 	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
544 		panelControl = PCH_PANEL_CONTROL;
545 		panelStatus = PCH_PANEL_STATUS;
546 	}
547 
548 	if (gInfo->shared_info->device_type.Generation() != 4) {
549 		// TODO not needed on any generation if we are using the panel fitter
550 		// Power off Panel
551 		write32(panelControl,
552 			read32(panelControl) & ~PANEL_CONTROL_POWER_TARGET_ON);
553 		read32(panelControl);
554 
555 		if (!wait_for_clear(panelStatus, PANEL_STATUS_POWER_ON, 1000)) {
556 			ERROR("%s: %s didn't power off within 1000ms!\n", __func__,
557 				PortName());
558 		}
559 	}
560 
561 	// For LVDS panels, we may need to set the timings according to the panel
562 	// native video mode, and let the panel fitter do the scaling. But the
563 	// place where the scaling happens varies accross generations of devices.
564 	display_mode hardwareTarget;
565 	bool needsScaling = false;
566 
567 	// TODO figure out how it's done (or if we need to configure something at
568 	// all) for other generations
569 	if (gInfo->shared_info->device_type.Generation() <= 6
570 		&& gInfo->shared_info->device_type.Generation() >= 3
571 		&& gInfo->shared_info->got_vbt) {
572 		// Set vbios hardware panel mode as base
573 		hardwareTarget = gInfo->shared_info->panel_mode;
574 
575 		if (hardwareTarget.timing.h_display == target->timing.h_display
576 				&& hardwareTarget.timing.v_display == target->timing.v_display) {
577 			// We are setting the native video mode, nothing special to do
578 			TRACE("Setting LVDS to native mode\n");
579 			hardwareTarget = *target;
580 		} else {
581 			// We need to enable the panel fitter
582 			TRACE("%s: hardware mode will actually be %dx%d\n", __func__,
583 				hardwareTarget.timing.h_display, hardwareTarget.timing.v_display);
584 
585 			hardwareTarget.space = target->space;
586 			// retain requested virtual size
587 			hardwareTarget.virtual_width = target->virtual_width;
588 			hardwareTarget.virtual_height = target->virtual_height;
589 			// FIXME we should also get the refresh frequency from the target
590 			// mode, and then "sanitize" the resulting mode we made up.
591 
592 			needsScaling = true;
593 		}
594 	} else {
595 		TRACE("Setting LVDS mode without VBT info or on unhandled hardware "
596 			"generation, scaling may not work\n");
597 		// We don't have VBT data, try to set the requested mode directly
598 		// and hope for the best
599 		hardwareTarget = *target;
600 	}
601 
602 	// Setup PanelFitter and Train FDI if it exists
603 	PanelFitter* fitter = fPipe->PFT();
604 	if (fitter != NULL)
605 		fitter->Enable(hardwareTarget);
606 	FDILink* link = fPipe->FDI();
607 	if (link != NULL)
608 		link->Train(&hardwareTarget);
609 
610 	pll_divisors divisors;
611 	compute_pll_divisors(&hardwareTarget, &divisors, true);
612 
613 	uint32 lvds = read32(_PortRegister())
614 		| LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
615 
616 	if (gInfo->shared_info->device_type.Generation() == 4) {
617 		// LVDS_A3_POWER_UP == 24bpp
618 		// otherwise, 18bpp
619 		if ((lvds & LVDS_A3_POWER_MASK) != LVDS_A3_POWER_UP)
620 			lvds |= LVDS_18BIT_DITHER;
621 	}
622 
623 	// LVDS on PCH needs set before display enable
624 	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
625 		lvds &= ~PORT_TRANS_SEL_MASK;
626 		if (fPipe->Index() == INTEL_PIPE_A)
627 			lvds |= PORT_TRANS_A_SEL_CPT;
628 		else
629 			lvds |= PORT_TRANS_B_SEL_CPT;
630 	}
631 
632 	// Set the B0-B3 data pairs corresponding to whether we're going to
633 	// set the DPLLs for dual-channel mode or not.
634 	if (divisors.p2 == 5 || divisors.p2 == 7) {
635 		TRACE("LVDS: dual channel\n");
636 		lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
637 	} else {
638 		TRACE("LVDS: single channel\n");
639 		lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
640 	}
641 
642 	// LVDS port control moves polarity bits because Intel hates you.
643 	// Set LVDS sync polarity
644 	lvds &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
645 
646 	// set on - polarity.
647 	if ((target->timing.flags & B_POSITIVE_HSYNC) == 0)
648 		lvds |= LVDS_HSYNC_POLARITY;
649 	if ((target->timing.flags & B_POSITIVE_VSYNC) == 0)
650 		lvds |= LVDS_VSYNC_POLARITY;
651 
652 	TRACE("%s: LVDS Write: 0x%" B_PRIx32 "\n", __func__, lvds);
653 	write32(_PortRegister(), lvds);
654 	read32(_PortRegister());
655 
656 	uint32 extraPLLFlags = 0;
657 
658 	// DPLL mode LVDS for i915+
659 	if (gInfo->shared_info->device_type.Generation() >= 3)
660 		extraPLLFlags |= DISPLAY_PLL_MODE_LVDS | DISPLAY_PLL_2X_CLOCK;
661 
662 	// Program general pipe config
663 	fPipe->Configure(target);
664 
665 	// Program pipe PLL's (using the hardware mode timings, since that's what
666 	// the PLL is used for)
667 	fPipe->ConfigureClocks(divisors, hardwareTarget.timing.pixel_clock,
668 		extraPLLFlags);
669 
670 	if (gInfo->shared_info->device_type.Generation() != 4) {
671 		// G45: no need to power the panel off
672 		// Power on Panel
673 		write32(panelControl,
674 			read32(panelControl) | PANEL_CONTROL_POWER_TARGET_ON);
675 		read32(panelControl);
676 
677 		if (!wait_for_set(panelStatus, PANEL_STATUS_POWER_ON, 1000)) {
678 			ERROR("%s: %s didn't power on within 1000ms!\n", __func__,
679 				PortName());
680 		}
681 	}
682 
683 	// Program target display mode
684 	fPipe->ConfigureTimings(target, !needsScaling);
685 
686 	if (needsScaling) {
687 		if (gInfo->shared_info->device_type.Generation() <= 4) {
688 			// Enable panel fitter in automatic mode. It will figure out
689 			// the scaling ratios automatically.
690 			uint32 panelFitterControl = read32(INTEL_PANEL_FIT_CONTROL);
691 			panelFitterControl |= PANEL_FITTER_ENABLED;
692 			panelFitterControl &= ~(PANEL_FITTER_SCALING_MODE_MASK
693 				| PANEL_FITTER_PIPE_MASK);
694 			panelFitterControl |= PANEL_FITTER_PIPE_B;
695 			// LVDS is always on pipe B.
696 			write32(INTEL_PANEL_FIT_CONTROL, panelFitterControl);
697 		}
698 		// TODO do we need to do anything on later generations?
699 	} else {
700 		if (gInfo->shared_info->device_type.Generation() == 4
701 			|| gInfo->shared_info->device_type.Generation() == 3) {
702 			// Bypass the panel fitter
703 			uint32 panelFitterControl = read32(INTEL_PANEL_FIT_CONTROL);
704 			panelFitterControl &= ~PANEL_FITTER_ENABLED;
705 			write32(INTEL_PANEL_FIT_CONTROL, panelFitterControl);
706 		} else {
707 			// We don't need to do anything more for later generations, the
708 			// scaling is handled at the transcoder level. We may want to
709 			// configure dithering, but the code below ignores the previous
710 			// value in the register and may mess things up so we should do
711 			// this in a safeer way. For now, assume the BIOS did the right
712 			// thing.
713 #if 0
714 			// Disable panel fitting, but enable 8 to 6-bit dithering
715 			write32(INTEL_PANEL_FIT_CONTROL, 0x4);
716 				// TODO: do not do this if the connected panel is 24-bit
717 				// (I don't know how to detect that)
718 #endif
719 		}
720 	}
721 
722 	// Set fCurrentMode to our set display mode
723 	memcpy(&fCurrentMode, target, sizeof(display_mode));
724 
725 	return B_OK;
726 }
727 
728 
729 // #pragma mark - DVI/SDVO/generic
730 
731 
732 DigitalPort::DigitalPort(port_index index, const char* baseName)
733 	:
734 	Port(index, baseName)
735 {
736 }
737 
738 
739 bool
740 DigitalPort::IsConnected()
741 {
742 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
743 		_PortRegister());
744 
745 	// As this port overlaps with pretty much everything, this must be called
746 	// after having ruled out all other port types.
747 	return HasEDID();
748 }
749 
750 
751 addr_t
752 DigitalPort::_DDCRegister()
753 {
754 	//TODO: IS BROXTON, B = B, C = C, D = NIL
755 	switch (PortIndex()) {
756 		case INTEL_PORT_B:
757 			return INTEL_I2C_IO_E;
758 		case INTEL_PORT_C:
759 			return INTEL_I2C_IO_D;
760 		case INTEL_PORT_D:
761 			return INTEL_I2C_IO_F;
762 		default:
763 			return 0;
764 	}
765 
766 	return 0;
767 }
768 
769 
770 addr_t
771 DigitalPort::_PortRegister()
772 {
773 	switch (PortIndex()) {
774 		case INTEL_PORT_A:
775 			return INTEL_DIGITAL_PORT_A;
776 		case INTEL_PORT_B:
777 			return INTEL_DIGITAL_PORT_B;
778 		case INTEL_PORT_C:
779 			return INTEL_DIGITAL_PORT_C;
780 		default:
781 			return 0;
782 	}
783 	return 0;
784 }
785 
786 
787 status_t
788 DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
789 {
790 	CALLED();
791 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->timing.h_display,
792 		target->timing.v_display);
793 
794 	if (fPipe == NULL) {
795 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
796 		return B_ERROR;
797 	}
798 
799 	// Setup PanelFitter and Train FDI if it exists
800 	PanelFitter* fitter = fPipe->PFT();
801 	if (fitter != NULL)
802 		fitter->Enable(*target);
803 	FDILink* link = fPipe->FDI();
804 	if (link != NULL)
805 		link->Train(target);
806 
807 	pll_divisors divisors;
808 	compute_pll_divisors(target, &divisors, false);
809 
810 	uint32 extraPLLFlags = 0;
811 	if (gInfo->shared_info->device_type.Generation() >= 3)
812 		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL | DISPLAY_PLL_2X_CLOCK;
813 
814 	// Program general pipe config
815 	fPipe->Configure(target);
816 
817 	// Program pipe PLL's
818 	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
819 
820 	// Program target display mode
821 	fPipe->ConfigureTimings(target);
822 
823 	// Set fCurrentMode to our set display mode
824 	memcpy(&fCurrentMode, target, sizeof(display_mode));
825 
826 	return B_OK;
827 }
828 
829 
830 // #pragma mark - LVDS Panel
831 // #pragma mark - HDMI
832 
833 
834 HDMIPort::HDMIPort(port_index index)
835 	:
836 	DigitalPort(index, "HDMI")
837 {
838 }
839 
840 
841 bool
842 HDMIPort::IsConnected()
843 {
844 	if (!gInfo->shared_info->device_type.SupportsHDMI())
845 		return false;
846 
847 	addr_t portRegister = _PortRegister();
848 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
849 		portRegister);
850 
851 	if (portRegister == 0)
852 		return false;
853 
854 	//Notes:
855 	//- DISPLAY_MONITOR_PORT_DETECTED does only tell you *some* sort of digital display is
856 	//  connected to the port *if* you have the AUX channel stuff under power. It does not
857 	//  tell you which -type- of digital display is connected.
858 	//- Since we rely on the BIOS anyway, let's just use the conclusions it made for us :)
859 	//  Beware though: set_display_power_mode() uses this DISPLAY_MONITOR_PORT_ENABLED bit
860 	//  for DPMS as well. So we should better buffer our findings here for i.e. possible
861 	//  accelerant clones starting up. For DPMS there's currently no problem as this bit
862 	//  is only programmed for LVDS, DVI and VGA while we detect presence only for DP and HDMI.
863 	//
864 	//if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0)
865 	if ((read32(portRegister) & DISPLAY_MONITOR_PORT_ENABLED) == 0)
866 		return false;
867 
868 	return HasEDID();
869 }
870 
871 
872 addr_t
873 HDMIPort::_PortRegister()
874 {
875 	// on PCH there's an additional port sandwiched in
876 	bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
877 	bool fourthGen = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV);
878 
879 	switch (PortIndex()) {
880 		case INTEL_PORT_B:
881 			if (fourthGen)
882 				return GEN4_HDMI_PORT_B;
883 			return hasPCH ? PCH_HDMI_PORT_B : INTEL_HDMI_PORT_B;
884 		case INTEL_PORT_C:
885 			if (fourthGen)
886 				return GEN4_HDMI_PORT_C;
887 			return hasPCH ? PCH_HDMI_PORT_C : INTEL_HDMI_PORT_C;
888 		case INTEL_PORT_D:
889 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
890 				return CHV_HDMI_PORT_D;
891 			return hasPCH ? PCH_HDMI_PORT_D : 0;
892 		default:
893 			return 0;
894 		}
895 
896 	return 0;
897 }
898 
899 
900 // #pragma mark - DisplayPort
901 
902 
903 DisplayPort::DisplayPort(port_index index, const char* baseName)
904 	:
905 	Port(index, baseName)
906 {
907 }
908 
909 
910 pipe_index
911 DisplayPort::PipePreference()
912 {
913 	CALLED();
914 	if (gInfo->shared_info->device_type.Generation() <= 4)
915 		return INTEL_PIPE_ANY;
916 
917 	// Notes:
918 	// - The BIOSes seen sofar do not use PIPE C by default.
919 	// - Looks like BIOS selected Transcoder (A,B,C) is not always same as selected Pipe (A,B,C)
920 	//   so these should probably be handled seperately. For now this is OK as we don't touch
921 	//   the pipe for DisplayPort, only the transcoder..
922 	uint32 TranscoderPort = INTEL_TRANS_DP_PORT_NONE;
923 	switch (PortIndex()) {
924 		case INTEL_PORT_A:
925 			return INTEL_PIPE_ANY;
926 		case INTEL_PORT_B:
927 			TranscoderPort = INTEL_TRANS_DP_PORT_B;
928 			break;
929 		case INTEL_PORT_C:
930 			TranscoderPort = INTEL_TRANS_DP_PORT_C;
931 			break;
932 		case INTEL_PORT_D:
933 			TranscoderPort = INTEL_TRANS_DP_PORT_D;
934 			break;
935 		default:
936 			return INTEL_PIPE_ANY;
937 	}
938 
939 	for (uint32 Transcoder = 0; Transcoder < 3; Transcoder++) {
940 		if ((read32(INTEL_TRANSCODER_A_DP_CTL + (Transcoder << 12)) & INTEL_TRANS_DP_PORT_MASK) ==
941 			INTEL_TRANS_DP_PORT(TranscoderPort)) {
942 			switch (Transcoder) {
943 				case 0:
944 					return INTEL_PIPE_A;
945 				case 1:
946 					return INTEL_PIPE_B;
947 				case 2:
948 					return INTEL_PIPE_C;
949 			}
950 		}
951 	}
952 
953 	return INTEL_PIPE_ANY;
954 }
955 
956 
957 bool
958 DisplayPort::IsConnected()
959 {
960 	addr_t portRegister = _PortRegister();
961 
962 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
963 		portRegister);
964 
965 	if (portRegister == 0)
966 		return false;
967 
968 	//Notes:
969 	//- DISPLAY_MONITOR_PORT_DETECTED does only tell you *some* sort of digital display is
970 	//  connected to the port *if* you have the AUX channel stuff under power. It does not
971 	//  tell you which -type- of digital display is connected.
972 	//- Since we rely on the BIOS anyway, let's just use the conclusions it made for us :)
973 	//  Beware though: set_display_power_mode() uses this DISPLAY_MONITOR_PORT_ENABLED bit
974 	//  for DPMS as well. So we should better buffer our findings here for i.e. possible
975 	//  accelerant clones starting up. For DPMS there's currently no problem as this bit
976 	//  is only programmed for LVDS, DVI and VGA while we detect presence only for DP and HDMI.
977 	//
978 	//if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
979 	if ((read32(portRegister) & DISPLAY_MONITOR_PORT_ENABLED) == 0) {
980 		TRACE("%s: %s link not detected\n", __func__, PortName());
981 		return false;
982 	}
983 
984 	//since EDID is not correctly implemented yet for this connection type we'll do without it for now
985 	//return HasEDID();
986 	TRACE("%s: %s link detected\n", __func__, PortName());
987 	return true;
988 }
989 
990 
991 addr_t
992 DisplayPort::_DDCRegister()
993 {
994 	// TODO: Do VLV + CHV use the VLV_DP_AUX_CTL_B + VLV_DP_AUX_CTL_C?
995 	switch (PortIndex()) {
996 		case INTEL_PORT_A:
997 			return INTEL_DP_AUX_CTL_A;
998 		case INTEL_PORT_B:
999 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
1000 				return VLV_DP_AUX_CTL_B;
1001 			return INTEL_DP_AUX_CTL_B;
1002 		case INTEL_PORT_C:
1003 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
1004 				return VLV_DP_AUX_CTL_C;
1005 			return INTEL_DP_AUX_CTL_C;
1006 		case INTEL_PORT_D:
1007 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
1008 				return CHV_DP_AUX_CTL_D;
1009 			else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
1010 				return 0;
1011 			return INTEL_DP_AUX_CTL_D;
1012 		default:
1013 			return 0;
1014 	}
1015 
1016 	return 0;
1017 }
1018 
1019 
1020 addr_t
1021 DisplayPort::_PortRegister()
1022 {
1023 	// There are 6000 lines of intel linux code probing DP registers
1024 	// to properly detect DP vs eDP to then in-turn properly figure out
1025 	// what is DP and what is HDMI. It only takes 3 lines to
1026 	// ignore DisplayPort on ValleyView / CherryView
1027 
1028 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)
1029 		|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
1030 		ERROR("TODO: DisplayPort on ValleyView / CherryView");
1031 		return 0;
1032 	}
1033 
1034 	// Intel, are humans even involved anymore?
1035 	// This is a lot more complex than this code makes it look. (see defines)
1036 	// INTEL_DISPLAY_PORT_X moves around a lot based on PCH
1037 	// except on ValleyView and CherryView.
1038 	switch (PortIndex()) {
1039 		case INTEL_PORT_A:
1040 			return INTEL_DISPLAY_PORT_A;
1041 		case INTEL_PORT_B:
1042 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
1043 				return VLV_DISPLAY_PORT_B;
1044 			return INTEL_DISPLAY_PORT_B;
1045 		case INTEL_PORT_C:
1046 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
1047 				return VLV_DISPLAY_PORT_C;
1048 			return INTEL_DISPLAY_PORT_C;
1049 		case INTEL_PORT_D:
1050 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
1051 				return CHV_DISPLAY_PORT_D;
1052 			else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
1053 				return 0;
1054 			return INTEL_DISPLAY_PORT_D;
1055 		default:
1056 			return 0;
1057 	}
1058 
1059 	return 0;
1060 }
1061 
1062 
1063 status_t
1064 DisplayPort::_SetPortLinkGen4(display_mode* target)
1065 {
1066 	// Khz / 10. ( each output octet encoded as 10 bits.
1067 	//uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; //=270000 khz
1068 	//fixme: always so?
1069 	uint32 linkBandwidth = 270000; //khz
1070 	uint32 fPipeOffset = 0;
1071 	if (fPipe->Index() == INTEL_PIPE_B)
1072 		fPipeOffset = 0x1000;
1073 
1074 	TRACE("%s: DP M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_DATA_M + fPipeOffset));
1075 	TRACE("%s: DP N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_DATA_N + fPipeOffset));
1076 	TRACE("%s: DP M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_LINK_M + fPipeOffset));
1077 	TRACE("%s: DP N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_LINK_N + fPipeOffset));
1078 
1079 	uint32 bitsPerPixel = 24;	//fixme: always so?
1080 	uint32 lanes = 4;			//fixme: always so?
1081 
1082 	//Setup Data M/N
1083 	uint64 linkspeed = lanes * linkBandwidth * 8;
1084 	uint64 ret_n = 1;
1085 	while(ret_n < linkspeed) {
1086 		ret_n *= 2;
1087 	}
1088 	if (ret_n > 0x800000) {
1089 		ret_n = 0x800000;
1090 	}
1091 	uint64 ret_m = target->timing.pixel_clock * ret_n * bitsPerPixel / linkspeed;
1092 	while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
1093 		ret_m >>= 1;
1094 		ret_n >>= 1;
1095 	}
1096 	//Set TU size bits (to default, max) before link training so that error detection works
1097 	write32(INTEL_PIPE_A_DATA_M + fPipeOffset, ret_m | FDI_PIPE_MN_TU_SIZE_MASK);
1098 	write32(INTEL_PIPE_A_DATA_N + fPipeOffset, ret_n);
1099 
1100 	//Setup Link M/N
1101 	linkspeed = linkBandwidth;
1102 	ret_n = 1;
1103 	while(ret_n < linkspeed) {
1104 		ret_n *= 2;
1105 	}
1106 	if (ret_n > 0x800000) {
1107 		ret_n = 0x800000;
1108 	}
1109 	ret_m = target->timing.pixel_clock * ret_n / linkspeed;
1110 	while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) {
1111 		ret_m >>= 1;
1112 		ret_n >>= 1;
1113 	}
1114 	write32(INTEL_PIPE_A_LINK_M + fPipeOffset, ret_m);
1115 	//Writing Link N triggers all four registers to be activated also (on next VBlank)
1116 	write32(INTEL_PIPE_A_LINK_N + fPipeOffset, ret_n);
1117 
1118 	TRACE("%s: DP M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_DATA_M + fPipeOffset));
1119 	TRACE("%s: DP N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_DATA_N + fPipeOffset));
1120 	TRACE("%s: DP M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_LINK_M + fPipeOffset));
1121 	TRACE("%s: DP N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(INTEL_PIPE_A_LINK_N + fPipeOffset));
1122 
1123 	return B_OK;
1124 }
1125 
1126 
1127 status_t
1128 DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode)
1129 {
1130 	CALLED();
1131 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->timing.h_display,
1132 		target->timing.v_display);
1133 
1134 	if (fPipe == NULL) {
1135 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
1136 		return B_ERROR;
1137 	}
1138 
1139 	status_t result = B_OK;
1140 	if (gInfo->shared_info->device_type.Generation() <= 4) {
1141 		fPipe->ConfigureTimings(target);
1142 		result = _SetPortLinkGen4(target);
1143 	} else {
1144 		//fixme: doesn't work yet. For now just scale to native mode.
1145 #if 0
1146 		// Setup PanelFitter and Train FDI if it exists
1147 		PanelFitter* fitter = fPipe->PFT();
1148 		if (fitter != NULL)
1149 			fitter->Enable(*target);
1150 		FDILink* link = fPipe->FDI();
1151 		if (link != NULL)
1152 			link->Train(target);
1153 
1154 		pll_divisors divisors;
1155 		compute_pll_divisors(target, &divisors, false);
1156 
1157 		uint32 extraPLLFlags = 0;
1158 		if (gInfo->shared_info->device_type.Generation() >= 3)
1159 			extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL | DISPLAY_PLL_2X_CLOCK;
1160 
1161 		// Program general pipe config
1162 		fPipe->Configure(target);
1163 
1164 		// Program pipe PLL's
1165 		fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
1166 
1167 		// Program target display mode
1168 		fPipe->ConfigureTimings(target);
1169 #endif
1170 
1171 		// Keep monitor at native mode and scale image to that
1172 		fPipe->ConfigureScalePos(target);
1173 	}
1174 
1175 	// Set fCurrentMode to our set display mode
1176 	memcpy(&fCurrentMode, target, sizeof(display_mode));
1177 
1178 	return result;
1179 }
1180 
1181 
1182 // #pragma mark - Embedded DisplayPort
1183 
1184 
1185 EmbeddedDisplayPort::EmbeddedDisplayPort()
1186 	:
1187 	DisplayPort(INTEL_PORT_A, "Embedded DisplayPort")
1188 {
1189 }
1190 
1191 
1192 bool
1193 EmbeddedDisplayPort::IsConnected()
1194 {
1195 	addr_t portRegister = _PortRegister();
1196 
1197 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
1198 		portRegister);
1199 
1200 	if (!gInfo->shared_info->device_type.IsMobile()) {
1201 		TRACE("%s: skipping eDP on non-mobile GPU\n", __func__);
1202 		return false;
1203 	}
1204 
1205 	if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
1206 		TRACE("%s: %s link not detected\n", __func__, PortName());
1207 		return false;
1208 	}
1209 
1210 	HasEDID();
1211 
1212 	// If eDP has EDID, awesome. We use it.
1213 	// No EDID? The modesetting code falls back to VBIOS panel_mode
1214 	return true;
1215 }
1216 
1217 
1218 // #pragma mark - Digital Display Port
1219 
1220 
1221 DigitalDisplayInterface::DigitalDisplayInterface(port_index index,
1222 		const char* baseName)
1223 	:
1224 	Port(index, baseName)
1225 {
1226 	// As of Haswell, Intel decided to change eDP ports to a "DDI" bus...
1227 	// on a dare because the hardware engineers were drunk one night.
1228 }
1229 
1230 
1231 addr_t
1232 DigitalDisplayInterface::_PortRegister()
1233 {
1234 	// TODO: Linux does a DDI_BUF_CTL(INTEL_PORT_A) which is cleaner
1235 	// (but we have to ensure the offsets + region base is correct)
1236 	switch (PortIndex()) {
1237 		case INTEL_PORT_A:
1238 			return DDI_BUF_CTL_A;
1239 		case INTEL_PORT_B:
1240 			return DDI_BUF_CTL_B;
1241 		case INTEL_PORT_C:
1242 			return DDI_BUF_CTL_C;
1243 		case INTEL_PORT_D:
1244 			return DDI_BUF_CTL_D;
1245 		case INTEL_PORT_E:
1246 			return DDI_BUF_CTL_E;
1247 		default:
1248 			return 0;
1249 	}
1250 	return 0;
1251 }
1252 
1253 
1254 addr_t
1255 DigitalDisplayInterface::_DDCRegister()
1256 {
1257 	// TODO: No idea, does DDI have DDC?
1258 	return 0;
1259 }
1260 
1261 
1262 status_t
1263 DigitalDisplayInterface::Power(bool enabled)
1264 {
1265 	TRACE("%s: %s DDI enabled: %s\n", __func__, PortName(),
1266 		enabled ? "true" : "false");
1267 
1268 	fPipe->Enable(enabled);
1269 
1270 	addr_t portRegister = _PortRegister();
1271 	uint32 state = read32(portRegister);
1272 	write32(portRegister,
1273 		enabled ? (state | DDI_BUF_CTL_ENABLE) : (state & ~DDI_BUF_CTL_ENABLE));
1274 	read32(portRegister);
1275 
1276 	return B_OK;
1277 }
1278 
1279 
1280 bool
1281 DigitalDisplayInterface::IsConnected()
1282 {
1283 	addr_t portRegister = _PortRegister();
1284 
1285 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
1286 		portRegister);
1287 
1288 	if (portRegister == 0)
1289 		return false;
1290 
1291 	if ((read32(portRegister) & DDI_INIT_DISPLAY_DETECTED) == 0) {
1292 		TRACE("%s: %s link not detected\n", __func__, PortName());
1293 		return false;
1294 	}
1295 
1296 	// Probe a little port info.
1297 	if ((read32(DDI_BUF_CTL_A) & DDI_A_4_LANES) != 0) {
1298 		switch (PortIndex()) {
1299 			case INTEL_PORT_A:
1300 				fMaxLanes = 4;
1301 				break;
1302 			case INTEL_PORT_E:
1303 				fMaxLanes = 0;
1304 				break;
1305 			default:
1306 				fMaxLanes = 4;
1307 				break;
1308 		}
1309 	} else {
1310 		switch (PortIndex()) {
1311 			case INTEL_PORT_A:
1312 				fMaxLanes = 2;
1313 				break;
1314 			case INTEL_PORT_E:
1315 				fMaxLanes = 2;
1316 				break;
1317 			default:
1318 				fMaxLanes = 4;
1319 				break;
1320 		}
1321 	}
1322 
1323 	TRACE("%s: %s Maximum Lanes: %" B_PRId8 "\n", __func__,
1324 		PortName(), fMaxLanes);
1325 
1326 	//since EDID is not correctly implemented yet for this connection type we'll do without it for now
1327 	//return HasEDID();
1328 	TRACE("%s: %s link detected\n", __func__, PortName());
1329 	return true;
1330 }
1331 
1332 
1333 status_t
1334 DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
1335 {
1336 	CALLED();
1337 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->timing.h_display,
1338 		target->timing.v_display);
1339 
1340 	if (fPipe == NULL) {
1341 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
1342 		return B_ERROR;
1343 	}
1344 
1345 	// Setup PanelFitter and Train FDI if it exists
1346 	PanelFitter* fitter = fPipe->PFT();
1347 	if (fitter != NULL)
1348 		fitter->Enable(*target);
1349 	// Skip FDI if we have a CPU connected display
1350 	if (PortIndex() != INTEL_PORT_A) {
1351 		FDILink* link = fPipe->FDI();
1352 		if (link != NULL)
1353 			link->Train(target);
1354 	}
1355 
1356 	pll_divisors divisors;
1357 	compute_pll_divisors(target, &divisors, false);
1358 
1359 	uint32 extraPLLFlags = 0;
1360 	if (gInfo->shared_info->device_type.Generation() >= 3)
1361 		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL | DISPLAY_PLL_2X_CLOCK;
1362 
1363 	// Program general pipe config
1364 	fPipe->Configure(target);
1365 
1366 	// Program pipe PLL's
1367 	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
1368 
1369 	// Program target display mode
1370 	fPipe->ConfigureTimings(target);
1371 
1372 	// Set fCurrentMode to our set display mode
1373 	memcpy(&fCurrentMode, target, sizeof(display_mode));
1374 
1375 	return B_OK;
1376 }
1377