xref: /haiku/src/add-ons/accelerants/intel_extreme/Ports.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 
25 #include <new>
26 
27 
28 #undef TRACE
29 #define TRACE_PORTS
30 #ifdef TRACE_PORTS
31 #   define TRACE(x...) _sPrintf("intel_extreme: " x)
32 #else
33 #   define TRACE(x...)
34 #endif
35 
36 #define ERROR(x...) _sPrintf("intel_extreme: " x)
37 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
38 
39 
40 static bool
41 wait_for_set(addr_t address, uint32 mask, uint32 timeout)
42 {
43 	int interval = 50;
44 	uint32 i = 0;
45 	for(i = 0; i <= timeout; i += interval) {
46 		spin(interval);
47 		if ((read32(address) & mask) != 0)
48 			return true;
49 	}
50 	return false;
51 }
52 
53 
54 static bool
55 wait_for_clear(addr_t address, uint32 mask, uint32 timeout)
56 {
57 	int interval = 50;
58 	uint32 i = 0;
59 	for(i = 0; i <= timeout; i += interval) {
60 		spin(interval);
61 		if ((read32(address) & mask) == 0)
62 			return true;
63 	}
64 	return false;
65 }
66 
67 
68 Port::Port(port_index index, const char* baseName)
69 	:
70 	fPipe(NULL),
71 	fEDIDState(B_NO_INIT),
72 	fPortIndex(index),
73 	fPortName(NULL)
74 {
75 	char portID[2];
76 	portID[0] = 'A' + index - INTEL_PORT_A;
77 	portID[1] = 0;
78 
79 	char buffer[32];
80 	buffer[0] = 0;
81 
82 	strlcat(buffer, baseName, sizeof(buffer));
83 	strlcat(buffer, " ", sizeof(buffer));
84 	strlcat(buffer, portID, sizeof(buffer));
85 	fPortName = strdup(buffer);
86 }
87 
88 
89 Port::~Port()
90 {
91 	free(fPortName);
92 }
93 
94 
95 bool
96 Port::HasEDID()
97 {
98 	if (fEDIDState == B_NO_INIT)
99 		GetEDID(NULL);
100 
101 	return fEDIDState == B_OK;
102 }
103 
104 
105 status_t
106 Port::SetPipe(Pipe* pipe)
107 {
108 	CALLED();
109 
110 	if (pipe == NULL) {
111 		ERROR("%s: Invalid pipe provided!\n", __func__);
112 		return B_ERROR;
113 	}
114 
115 	uint32 portRegister = _PortRegister();
116 	if (portRegister == 0) {
117 		ERROR("%s: Invalid PortRegister ((0x%" B_PRIx32 ") for %s\n", __func__,
118 			portRegister, PortName());
119 		return B_ERROR;
120 	}
121 
122 	// TODO: UnAssignPipe?  This likely needs reworked a little
123 	if (fPipe != NULL) {
124 		ERROR("%s: Can't reassign display pipe (yet)\n", __func__);
125 		return B_ERROR;
126 	}
127 
128 	TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe %s\n", __func__,
129 		PortName(), portRegister, (pipe->Index() == INTEL_PIPE_A) ? "A" : "B");
130 
131 	uint32 portState = read32(portRegister);
132 
133 	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
134 		portState &= PORT_TRANS_SEL_MASK;
135 		if (pipe->Index() == INTEL_PIPE_A)
136 			write32(portRegister, portState | PORT_TRANS_A_SEL_CPT);
137 		else
138 			write32(portRegister, portState | PORT_TRANS_B_SEL_CPT);
139 	} else {
140 		if (pipe->Index() == INTEL_PIPE_A)
141 			write32(portRegister, portState & ~DISPLAY_MONITOR_PIPE_B);
142 		else
143 			write32(portRegister, portState | DISPLAY_MONITOR_PIPE_B);
144 	}
145 
146 	fPipe = pipe;
147 
148 	if (fPipe == NULL)
149 		return B_NO_MEMORY;
150 
151 	// Disable display pipe until modesetting enables it
152 	if (fPipe->IsEnabled())
153 		fPipe->Enable(false);
154 
155 	read32(portRegister);
156 
157 	return B_OK;
158 }
159 
160 
161 status_t
162 Port::Power(bool enabled)
163 {
164 	fPipe->Enable(enabled);
165 
166 	return B_OK;
167 }
168 
169 
170 status_t
171 Port::GetEDID(edid1_info* edid, bool forceRead)
172 {
173 	CALLED();
174 
175 	if (fEDIDState == B_NO_INIT || forceRead) {
176 		TRACE("%s: trying to read EDID\n", PortName());
177 
178 		addr_t ddcRegister = _DDCRegister();
179 		if (ddcRegister == 0) {
180 			TRACE("%s: no DDC register found\n", PortName());
181 			fEDIDState = B_ERROR;
182 			return fEDIDState;
183 		}
184 
185 		TRACE("%s: using ddc @ 0x%" B_PRIxADDR "\n", PortName(), ddcRegister);
186 
187 		i2c_bus bus;
188 		bus.cookie = (void*)ddcRegister;
189 		bus.set_signals = &_SetI2CSignals;
190 		bus.get_signals = &_GetI2CSignals;
191 		ddc2_init_timing(&bus);
192 
193 		fEDIDState = ddc2_read_edid1(&bus, &fEDIDInfo, NULL, NULL);
194 
195 		if (fEDIDState == B_OK) {
196 			TRACE("%s: found EDID information!\n", PortName());
197 			edid_dump(&fEDIDInfo);
198 		}
199 	}
200 
201 	if (fEDIDState != B_OK) {
202 		TRACE("%s: no EDID information found.\n", PortName());
203 		return fEDIDState;
204 	}
205 
206 	if (edid != NULL)
207 		memcpy(edid, &fEDIDInfo, sizeof(edid1_info));
208 
209 	return B_OK;
210 }
211 
212 
213 status_t
214 Port::GetPLLLimits(pll_limits& limits)
215 {
216 	return B_ERROR;
217 }
218 
219 
220 status_t
221 Port::_GetI2CSignals(void* cookie, int* _clock, int* _data)
222 {
223 	addr_t ioRegister = (addr_t)cookie;
224 	uint32 value = read32(ioRegister);
225 
226 	*_clock = (value & I2C_CLOCK_VALUE_IN) != 0;
227 	*_data = (value & I2C_DATA_VALUE_IN) != 0;
228 
229 	return B_OK;
230 }
231 
232 
233 status_t
234 Port::_SetI2CSignals(void* cookie, int clock, int data)
235 {
236 	addr_t ioRegister = (addr_t)cookie;
237 	uint32 value;
238 
239 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_83x)) {
240 		// on these chips, the reserved values are fixed
241 		value = 0;
242 	} else {
243 		// on all others, we have to preserve them manually
244 		value = read32(ioRegister) & I2C_RESERVED;
245 	}
246 
247 	if (data != 0)
248 		value |= I2C_DATA_DIRECTION_MASK;
249 	else {
250 		value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT
251 			| I2C_DATA_VALUE_MASK;
252 	}
253 
254 	if (clock != 0)
255 		value |= I2C_CLOCK_DIRECTION_MASK;
256 	else {
257 		value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT
258 			| I2C_CLOCK_VALUE_MASK;
259 	}
260 
261 	write32(ioRegister, value);
262 	read32(ioRegister);
263 		// make sure the PCI bus has flushed the write
264 
265 	return B_OK;
266 }
267 
268 
269 // #pragma mark - Analog Port
270 
271 
272 AnalogPort::AnalogPort()
273 	:
274 	Port(INTEL_PORT_A, "Analog")
275 {
276 }
277 
278 
279 bool
280 AnalogPort::IsConnected()
281 {
282 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
283 		_PortRegister());
284 	return HasEDID();
285 }
286 
287 
288 addr_t
289 AnalogPort::_DDCRegister()
290 {
291 	// always fixed
292 	return INTEL_I2C_IO_A;
293 }
294 
295 
296 addr_t
297 AnalogPort::_PortRegister()
298 {
299 	// always fixed
300 	return INTEL_ANALOG_PORT;
301 }
302 
303 
304 status_t
305 AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
306 {
307 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
308 		target->virtual_height);
309 
310 	if (fPipe == NULL) {
311 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
312 		return B_ERROR;
313 	}
314 
315 	// Train FDI if it exists
316 	FDILink* link = fPipe->FDI();
317 	if (link != NULL)
318 		link->Train(target);
319 
320 	pll_divisors divisors;
321 	compute_pll_divisors(target, &divisors, false);
322 
323 	uint32 extraPLLFlags = 0;
324 	if (gInfo->shared_info->device_type.Generation() >= 3)
325 		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
326 
327 	// Program general pipe config
328 	fPipe->Configure(target);
329 
330 	// Program pipe PLL's
331 	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
332 
333 	write32(_PortRegister(), (read32(_PortRegister())
334 		& ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY))
335 		| ((target->timing.flags & B_POSITIVE_HSYNC) != 0
336 			? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
337 		| ((target->timing.flags & B_POSITIVE_VSYNC) != 0
338 			? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
339 
340 	// Program target display mode
341 	fPipe->ConfigureTimings(target);
342 
343 	// Set fCurrentMode to our set display mode
344 	memcpy(&fCurrentMode, target, sizeof(display_mode));
345 
346 	return B_OK;
347 }
348 
349 
350 // #pragma mark - LVDS Panel
351 
352 
353 LVDSPort::LVDSPort()
354 	:
355 	Port(INTEL_PORT_C, "LVDS")
356 {
357 	// Always unlock LVDS port as soon as we start messing with it.
358 	uint32 panelControl = INTEL_PANEL_CONTROL;
359 	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
360 		// FIXME writing there results in black screen on SandyBridge
361 		return;
362 		// panelControl = PCH_PANEL_CONTROL;
363 	}
364 	write32(panelControl, read32(panelControl) | PANEL_REGISTER_UNLOCK);
365 }
366 
367 
368 pipe_index
369 LVDSPort::PipePreference()
370 {
371 	// TODO: Technically INTEL_PIPE_B is only required on < gen 4
372 	// otherwise we can use INTEL_PIPE_ANY, however it seems to break
373 	// modesetting atm. (likely due to a bug on our end)
374 	//if (gInfo->shared_info->device_type.Generation() < 4)
375 	//	return INTEL_PIPE_B;
376 
377 	return INTEL_PIPE_B;
378 }
379 
380 
381 bool
382 LVDSPort::IsConnected()
383 {
384 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
385 		_PortRegister());
386 
387 	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
388 		uint32 registerValue = read32(_PortRegister());
389 		// there's a detection bit we can use
390 		if ((registerValue & PCH_LVDS_DETECTED) == 0) {
391 			TRACE("LVDS: Not detected\n");
392 			return false;
393 		}
394 		// TODO: Skip if eDP support
395 	} else if (gInfo->shared_info->device_type.Generation() <= 4) {
396 		// Older generations don't have LVDS detection. If not mobile skip.
397 		if (!gInfo->shared_info->device_type.IsMobile()) {
398 			TRACE("LVDS: Skipping LVDS detection due to gen and not mobile\n");
399 			return false;
400 		}
401 		// If mobile, try to grab EDID
402 		// Linux seems to look at lid status for LVDS port detection
403 		// If we don't get EDID, we can use vbios native mode or vesa?
404 		if (!HasEDID()) {
405 			#if 0
406 			if (gInfo->shared_info->got_vbt) {
407 				// TODO: Fake EDID from vbios native mode?
408 				// I feel like this would be more accurate
409 			} else if...
410 			#endif
411 			if (gInfo->shared_info->has_vesa_edid_info) {
412 				TRACE("LVDS: Using VESA edid info\n");
413 				memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info,
414 					sizeof(edid1_info));
415 				fEDIDState = B_OK;
416 				// HasEDID now true
417 			} else {
418 				TRACE("LVDS: Couldn't find any valid EDID!\n");
419 				return false;
420 			}
421 		}
422 	}
423 
424 	// Try getting EDID, as the LVDS port doesn't overlap with anything else,
425 	// we don't run the risk of getting someone else's data.
426 	return HasEDID();
427 }
428 
429 
430 addr_t
431 LVDSPort::_DDCRegister()
432 {
433 	// always fixed
434 	return INTEL_I2C_IO_C;
435 }
436 
437 
438 addr_t
439 LVDSPort::_PortRegister()
440 {
441 	// always fixed
442 	return INTEL_DIGITAL_LVDS_PORT;
443 }
444 
445 
446 status_t
447 LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
448 {
449 	CALLED();
450 	if (target == NULL) {
451 		ERROR("%s: Invalid target mode passed!\n", __func__);
452 		return B_ERROR;
453 	}
454 
455 	TRACE("%s: %s-%d %dx%d\n", __func__, PortName(), PortIndex(),
456 		target->virtual_width, target->virtual_height);
457 
458 	if (fPipe == NULL) {
459 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
460 		return B_ERROR;
461 	}
462 
463 	addr_t panelControl = INTEL_PANEL_CONTROL;
464 	addr_t panelStatus = INTEL_PANEL_STATUS;
465 	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
466 		panelControl = PCH_PANEL_CONTROL;
467 		panelStatus = PCH_PANEL_STATUS;
468 	}
469 
470 	// Power off Panel
471 	write32(panelControl, read32(panelControl) & ~PANEL_CONTROL_POWER_TARGET_ON);
472 	read32(panelControl);
473 
474 	if (!wait_for_clear(panelStatus, PANEL_STATUS_POWER_ON, 1000))
475 		ERROR("%s: %s didn't power off within 1000ms!\n", __func__, PortName());
476 
477 	// Train FDI if it exists
478 	FDILink* link = fPipe->FDI();
479 	if (link != NULL)
480 		link->Train(target);
481 
482 #if 0
483 	// Disable PanelFitter for now
484 	addr_t panelFitterControl = PCH_PANEL_FITTER_BASE_REGISTER
485 		+ PCH_PANEL_FITTER_CONTROL;
486 	if (fPipe->Index() == INTEL_PIPE_B)
487 		panelFitterControl += PCH_PANEL_FITTER_PIPE_OFFSET;
488 	write32(panelFitterControl, (read32(panelFitterControl) & ~PANEL_FITTER_ENABLED));
489 	read32(panelFitterControl);
490 #endif
491 
492 	// For LVDS panels, we actually always set the native mode in hardware
493 	// Then we use the panel fitter to scale the picture to that.
494 	display_mode hardwareTarget;
495 	bool needsScaling = false;
496 		// Try to get the panel preferred screen mode from EDID info
497 
498 	if (gInfo->shared_info->got_vbt) {
499 		// Set vbios hardware panel mode as base
500 		memcpy(&hardwareTarget, &gInfo->shared_info->panel_mode,
501 			sizeof(display_mode));
502 		hardwareTarget.space = target->space;
503 
504 		if ((hardwareTarget.virtual_width <= target->virtual_width
505 				&& hardwareTarget.virtual_height <= target->virtual_height
506 				&& hardwareTarget.space <= target->space)
507 			|| intel_propose_display_mode(&hardwareTarget, target, target)) {
508 			hardwareTarget = *target;
509 		} else
510 			needsScaling = true;
511 
512 		TRACE("%s: hardware mode will actually be %dx%d (%s)\n", __func__,
513 			hardwareTarget.virtual_width, hardwareTarget.virtual_height,
514 			needsScaling ? "scaled" : "unscaled");
515 	} else {
516 		// We don't have EDID data, try to set the requested mode directly
517 		hardwareTarget = *target;
518 	}
519 
520 	pll_divisors divisors;
521 	if (needsScaling)
522 		compute_pll_divisors(&hardwareTarget, &divisors, true);
523 	else
524 		compute_pll_divisors(target, &divisors, true);
525 
526 	uint32 lvds = read32(_PortRegister())
527 		| LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
528 
529 	if (gInfo->shared_info->device_type.Generation() == 4) {
530 		// LVDS_A3_POWER_UP == 24bpp
531 		// otherwise, 18bpp
532 		if ((lvds & LVDS_A3_POWER_MASK) != LVDS_A3_POWER_UP)
533 			lvds |= LVDS_18BIT_DITHER;
534 	}
535 
536 	// LVDS on PCH needs set before display enable
537 	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
538 		lvds &= PORT_TRANS_SEL_MASK;
539 		if (fPipe->Index() == INTEL_PIPE_A)
540 			lvds |= PORT_TRANS_A_SEL_CPT;
541 		else
542 			lvds |= PORT_TRANS_B_SEL_CPT;
543 	}
544 
545 	// Set the B0-B3 data pairs corresponding to whether we're going to
546 	// set the DPLLs for dual-channel mode or not.
547 	if (divisors.p2 == 5 || divisors.p2 == 7) {
548 		TRACE("LVDS: dual channel\n");
549 		lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
550 	} else {
551 		TRACE("LVDS: single channel\n");
552 		lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
553 	}
554 
555 	// LVDS port control moves polarity bits because Intel hates you.
556 	// Set LVDS sync polarity
557 	lvds &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
558 
559 	// set on - polarity.
560 	if ((target->timing.flags & B_POSITIVE_HSYNC) == 0)
561 		lvds |= LVDS_HSYNC_POLARITY;
562 	if ((target->timing.flags & B_POSITIVE_VSYNC) == 0)
563 		lvds |= LVDS_VSYNC_POLARITY;
564 
565 	TRACE("%s: LVDS Write: 0x%" B_PRIx32 "\n", __func__, lvds);
566 	write32(_PortRegister(), lvds);
567 	read32(_PortRegister());
568 
569 	uint32 extraPLLFlags = 0;
570 
571 	// DPLL mode LVDS for i915+
572 	if (gInfo->shared_info->device_type.Generation() >= 3)
573 		extraPLLFlags |= DISPLAY_PLL_MODE_LVDS;
574 
575 	// Program general pipe config
576 	fPipe->Configure(target);
577 
578 	// Program pipe PLL's (pixel_clock is *always* the hardware pixel clock)
579 	fPipe->ConfigureClocks(divisors, hardwareTarget.timing.pixel_clock,
580 		extraPLLFlags);
581 
582 	// Disable panel fitting, but enable 8 to 6-bit dithering
583 	write32(INTEL_PANEL_FIT_CONTROL, 0x4);
584 		// TODO: do not do this if the connected panel is 24-bit
585 		// (I don't know how to detect that)
586 
587 	// Power on Panel
588 	write32(panelControl, read32(panelControl) | PANEL_CONTROL_POWER_TARGET_ON);
589 	read32(panelControl);
590 
591 	if (!wait_for_set(panelStatus, PANEL_STATUS_POWER_ON, 1000))
592 		ERROR("%s: %s didn't power on within 1000ms!\n", __func__, PortName());
593 
594 	// Program target display mode
595 	fPipe->ConfigureTimings(target);
596 
597 #if 0
598 	// update timing parameters
599 	if (needsScaling) {
600 		// TODO: Alternatively, it should be possible to use the panel
601 		// fitter and scale the picture.
602 
603 		// TODO: Perform some sanity check, for example if the target is
604 		// wider than the hardware mode we end up with negative borders and
605 		// broken timings
606 		uint32 borderWidth = hardwareTarget.timing.h_display
607 			- target->timing.h_display;
608 
609 		uint32 syncWidth = hardwareTarget.timing.h_sync_end
610 			- hardwareTarget.timing.h_sync_start;
611 
612 		uint32 syncCenter = target->timing.h_display
613 			+ (hardwareTarget.timing.h_total
614 			- target->timing.h_display) / 2;
615 
616 		write32(INTEL_DISPLAY_B_HTOTAL,
617 			((uint32)(hardwareTarget.timing.h_total - 1) << 16)
618 			| ((uint32)target->timing.h_display - 1));
619 		write32(INTEL_DISPLAY_B_HBLANK,
620 			((uint32)(hardwareTarget.timing.h_total - borderWidth / 2 - 1)
621 				<< 16)
622 			| ((uint32)target->timing.h_display + borderWidth / 2 - 1));
623 		write32(INTEL_DISPLAY_B_HSYNC,
624 			((uint32)(syncCenter + syncWidth / 2 - 1) << 16)
625 			| ((uint32)syncCenter - syncWidth / 2 - 1));
626 
627 		uint32 borderHeight = hardwareTarget.timing.v_display
628 			- target->timing.v_display;
629 
630 		uint32 syncHeight = hardwareTarget.timing.v_sync_end
631 			- hardwareTarget.timing.v_sync_start;
632 
633 		syncCenter = target->timing.v_display
634 			+ (hardwareTarget.timing.v_total
635 			- target->timing.v_display) / 2;
636 
637 		write32(INTEL_DISPLAY_B_VTOTAL,
638 			((uint32)(hardwareTarget.timing.v_total - 1) << 16)
639 			| ((uint32)target->timing.v_display - 1));
640 		write32(INTEL_DISPLAY_B_VBLANK,
641 			((uint32)(hardwareTarget.timing.v_total - borderHeight / 2 - 1)
642 				<< 16)
643 			| ((uint32)target->timing.v_display
644 				+ borderHeight / 2 - 1));
645 		write32(INTEL_DISPLAY_B_VSYNC,
646 			((uint32)(syncCenter + syncHeight / 2 - 1) << 16)
647 			| ((uint32)syncCenter - syncHeight / 2 - 1));
648 
649 		// This is useful for debugging: it sets the border to red, so you
650 		// can see what is border and what is porch (black area around the
651 		// sync)
652 		// write32(0x61020, 0x00FF0000);
653 	} else {
654 		write32(INTEL_DISPLAY_B_HTOTAL,
655 			((uint32)(target->timing.h_total - 1) << 16)
656 			| ((uint32)target->timing.h_display - 1));
657 		write32(INTEL_DISPLAY_B_HBLANK,
658 			((uint32)(target->timing.h_total - 1) << 16)
659 			| ((uint32)target->timing.h_display - 1));
660 		write32(INTEL_DISPLAY_B_HSYNC,
661 			((uint32)(target->timing.h_sync_end - 1) << 16)
662 			| ((uint32)target->timing.h_sync_start - 1));
663 
664 		write32(INTEL_DISPLAY_B_VTOTAL,
665 			((uint32)(target->timing.v_total - 1) << 16)
666 			| ((uint32)target->timing.v_display - 1));
667 		write32(INTEL_DISPLAY_B_VBLANK,
668 			((uint32)(target->timing.v_total - 1) << 16)
669 			| ((uint32)target->timing.v_display - 1));
670 		write32(INTEL_DISPLAY_B_VSYNC, (
671 			(uint32)(target->timing.v_sync_end - 1) << 16)
672 			| ((uint32)target->timing.v_sync_start - 1));
673 	}
674 #endif
675 
676 	// Set fCurrentMode to our set display mode
677 	memcpy(&fCurrentMode, target, sizeof(display_mode));
678 
679 	return B_OK;
680 }
681 
682 
683 // #pragma mark - DVI/SDVO/generic
684 
685 
686 DigitalPort::DigitalPort(port_index index, const char* baseName)
687 	:
688 	Port(index, baseName)
689 {
690 }
691 
692 
693 bool
694 DigitalPort::IsConnected()
695 {
696 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
697 		_PortRegister());
698 
699 	// As this port overlaps with pretty much everything, this must be called
700 	// after having ruled out all other port types.
701 	return HasEDID();
702 }
703 
704 
705 addr_t
706 DigitalPort::_DDCRegister()
707 {
708 	//TODO: IS BROXTON, B = B, C = C, D = NIL
709 	switch (PortIndex()) {
710 		case INTEL_PORT_B:
711 			return INTEL_I2C_IO_E;
712 		case INTEL_PORT_C:
713 			return INTEL_I2C_IO_D;
714 		case INTEL_PORT_D:
715 			return INTEL_I2C_IO_F;
716 		default:
717 			return 0;
718 	}
719 
720 	return 0;
721 }
722 
723 
724 addr_t
725 DigitalPort::_PortRegister()
726 {
727 	switch (PortIndex()) {
728 		case INTEL_PORT_A:
729 			return INTEL_DIGITAL_PORT_A;
730 		case INTEL_PORT_B:
731 			return INTEL_DIGITAL_PORT_B;
732 		case INTEL_PORT_C:
733 			return INTEL_DIGITAL_PORT_C;
734 		default:
735 			return 0;
736 	}
737 	return 0;
738 }
739 
740 
741 status_t
742 DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
743 {
744 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
745 		target->virtual_height);
746 
747 	if (fPipe == NULL) {
748 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
749 		return B_ERROR;
750 	}
751 
752 	// Train FDI if it exists
753 	FDILink* link = fPipe->FDI();
754 	if (link != NULL)
755 		link->Train(target);
756 
757 	pll_divisors divisors;
758 	compute_pll_divisors(target, &divisors, false);
759 
760 	uint32 extraPLLFlags = 0;
761 	if (gInfo->shared_info->device_type.Generation() >= 3)
762 		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
763 
764 	// Program general pipe config
765 	fPipe->Configure(target);
766 
767 	// Program pipe PLL's
768 	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
769 
770 	// Program target display mode
771 	fPipe->ConfigureTimings(target);
772 
773 	// Set fCurrentMode to our set display mode
774 	memcpy(&fCurrentMode, target, sizeof(display_mode));
775 
776 	return B_OK;
777 }
778 
779 
780 // #pragma mark - LVDS Panel
781 // #pragma mark - HDMI
782 
783 
784 HDMIPort::HDMIPort(port_index index)
785 	:
786 	DigitalPort(index, "HDMI")
787 {
788 }
789 
790 
791 bool
792 HDMIPort::IsConnected()
793 {
794 	if (!gInfo->shared_info->device_type.SupportsHDMI())
795 		return false;
796 
797 	addr_t portRegister = _PortRegister();
798 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
799 		portRegister);
800 
801 	if (portRegister == 0)
802 		return false;
803 
804 	bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
805 	if (!hasPCH && PortIndex() == INTEL_PORT_C) {
806 		// there's no detection bit on this port
807 	} else if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0)
808 		return false;
809 
810 	return HasEDID();
811 }
812 
813 
814 addr_t
815 HDMIPort::_PortRegister()
816 {
817 	// on PCH there's an additional port sandwiched in
818 	bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
819 	bool fourthGen = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV);
820 
821 	switch (PortIndex()) {
822 		case INTEL_PORT_B:
823 			if (fourthGen)
824 				return GEN4_HDMI_PORT_B;
825 			return hasPCH ? PCH_HDMI_PORT_B : INTEL_HDMI_PORT_B;
826 		case INTEL_PORT_C:
827 			if (fourthGen)
828 				return GEN4_HDMI_PORT_C;
829 			return hasPCH ? PCH_HDMI_PORT_C : INTEL_HDMI_PORT_C;
830 		case INTEL_PORT_D:
831 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
832 				return CHV_HDMI_PORT_D;
833 			return hasPCH ? PCH_HDMI_PORT_D : 0;
834 		default:
835 			return 0;
836 		}
837 
838 	return 0;
839 }
840 
841 
842 // #pragma mark - DisplayPort
843 
844 
845 DisplayPort::DisplayPort(port_index index, const char* baseName)
846 	:
847 	Port(index, baseName)
848 {
849 }
850 
851 
852 bool
853 DisplayPort::IsConnected()
854 {
855 	addr_t portRegister = _PortRegister();
856 
857 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
858 		portRegister);
859 
860 	if (portRegister == 0)
861 		return false;
862 
863 	if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
864 		TRACE("%s: %s link not detected\n", __func__, PortName());
865 		return false;
866 	}
867 
868 	return HasEDID();
869 }
870 
871 
872 addr_t
873 DisplayPort::_DDCRegister()
874 {
875 	// TODO: Do VLV + CHV use the VLV_DP_AUX_CTL_B + VLV_DP_AUX_CTL_C?
876 	switch (PortIndex()) {
877 		case INTEL_PORT_A:
878 			return INTEL_DP_AUX_CTL_A;
879 		case INTEL_PORT_B:
880 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
881 				return VLV_DP_AUX_CTL_B;
882 			return INTEL_DP_AUX_CTL_B;
883 		case INTEL_PORT_C:
884 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
885 				return VLV_DP_AUX_CTL_C;
886 			return INTEL_DP_AUX_CTL_C;
887 		case INTEL_PORT_D:
888 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
889 				return CHV_DP_AUX_CTL_D;
890 			else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
891 				return 0;
892 			return INTEL_DP_AUX_CTL_D;
893 		default:
894 			return 0;
895 	}
896 
897 	return 0;
898 }
899 
900 
901 addr_t
902 DisplayPort::_PortRegister()
903 {
904 	// There are 6000 lines of intel linux code probing DP registers
905 	// to properly detect DP vs eDP to then in-turn properly figure out
906 	// what is DP and what is HDMI. It only takes 3 lines to
907 	// ignore DisplayPort on ValleyView / CherryView
908 
909 	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)
910 		|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
911 		ERROR("TODO: DisplayPort on ValleyView / CherryView");
912 		return 0;
913 	}
914 
915 	// Intel, are humans even involved anymore?
916 	// This is a lot more complex than this code makes it look. (see defines)
917 	// INTEL_DISPLAY_PORT_X moves around a lot based on PCH
918 	// except on ValleyView and CherryView.
919 	switch (PortIndex()) {
920 		case INTEL_PORT_A:
921 			return INTEL_DISPLAY_PORT_A;
922 		case INTEL_PORT_B:
923 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
924 				return VLV_DISPLAY_PORT_B;
925 			return INTEL_DISPLAY_PORT_B;
926 		case INTEL_PORT_C:
927 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
928 				return VLV_DISPLAY_PORT_C;
929 			return INTEL_DISPLAY_PORT_C;
930 		case INTEL_PORT_D:
931 			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
932 				return CHV_DISPLAY_PORT_D;
933 			else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
934 				return 0;
935 			return INTEL_DISPLAY_PORT_D;
936 		default:
937 			return 0;
938 	}
939 
940 	return 0;
941 }
942 
943 
944 status_t
945 DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode)
946 {
947 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
948 		target->virtual_height);
949 
950 	ERROR("TODO: DisplayPort\n");
951 	return B_ERROR;
952 }
953 
954 
955 // #pragma mark - Embedded DisplayPort
956 
957 
958 EmbeddedDisplayPort::EmbeddedDisplayPort()
959 	:
960 	DisplayPort(INTEL_PORT_A, "Embedded DisplayPort")
961 {
962 }
963 
964 
965 bool
966 EmbeddedDisplayPort::IsConnected()
967 {
968 	addr_t portRegister = _PortRegister();
969 
970 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
971 		portRegister);
972 
973 	if (!gInfo->shared_info->device_type.IsMobile()) {
974 		TRACE("%s: skipping eDP on non-mobile GPU\n", __func__);
975 		return false;
976 	}
977 
978 	if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
979 		TRACE("%s: %s link not detected\n", __func__, PortName());
980 		return false;
981 	}
982 
983 	HasEDID();
984 
985 	// If eDP has EDID, awesome. We use it.
986 	// No EDID? The modesetting code falls back to VBIOS panel_mode
987 	return true;
988 }
989 
990 
991 // #pragma mark - Digital Display Port
992 
993 
994 DigitalDisplayInterface::DigitalDisplayInterface(port_index index,
995 		const char* baseName)
996 	:
997 	Port(index, baseName)
998 {
999 	// As of Haswell, Intel decided to change eDP ports to a "DDI" bus...
1000 	// on a dare because the hardware engineers were drunk one night.
1001 }
1002 
1003 
1004 addr_t
1005 DigitalDisplayInterface::_PortRegister()
1006 {
1007 	// TODO: Linux does a DDI_BUF_CTL(INTEL_PORT_A) which is cleaner
1008 	// (but we have to ensure the offsets + region base is correct)
1009 	switch (PortIndex()) {
1010 		case INTEL_PORT_A:
1011 			return DDI_BUF_CTL_A;
1012 		case INTEL_PORT_B:
1013 			return DDI_BUF_CTL_B;
1014 		case INTEL_PORT_C:
1015 			return DDI_BUF_CTL_C;
1016 		case INTEL_PORT_D:
1017 			return DDI_BUF_CTL_D;
1018 		case INTEL_PORT_E:
1019 			return DDI_BUF_CTL_E;
1020 		default:
1021 			return 0;
1022 	}
1023 	return 0;
1024 }
1025 
1026 
1027 addr_t
1028 DigitalDisplayInterface::_DDCRegister()
1029 {
1030 	// TODO: No idea, does DDI have DDC?
1031 	return 0;
1032 }
1033 
1034 
1035 status_t
1036 DigitalDisplayInterface::Power(bool enabled)
1037 {
1038 	TRACE("%s: %s DDI enabled: %s\n", __func__, PortName(),
1039 		enabled ? "true" : "false");
1040 
1041 	fPipe->Enable(enabled);
1042 
1043 	addr_t portRegister = _PortRegister();
1044 	uint32 state = read32(portRegister);
1045 	write32(portRegister,
1046 		enabled ? (state | DDI_BUF_CTL_ENABLE) : (state & ~DDI_BUF_CTL_ENABLE));
1047 	read32(portRegister);
1048 
1049 	return B_OK;
1050 }
1051 
1052 
1053 bool
1054 DigitalDisplayInterface::IsConnected()
1055 {
1056 	addr_t portRegister = _PortRegister();
1057 
1058 	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
1059 		portRegister);
1060 
1061 	if (portRegister == 0)
1062 		return false;
1063 
1064 	if ((read32(portRegister) & DDI_INIT_DISPLAY_DETECTED) == 0) {
1065 		TRACE("%s: %s link not detected\n", __func__, PortName());
1066 		return false;
1067 	}
1068 
1069 	// Probe a little port info.
1070 	if ((read32(DDI_BUF_CTL_A) & DDI_A_4_LANES) != 0) {
1071 		switch (PortIndex()) {
1072 			case INTEL_PORT_A:
1073 				fMaxLanes = 4;
1074 				break;
1075 			case INTEL_PORT_E:
1076 				fMaxLanes = 0;
1077 				break;
1078 			default:
1079 				fMaxLanes = 4;
1080 				break;
1081 		}
1082 	} else {
1083 		switch (PortIndex()) {
1084 			case INTEL_PORT_A:
1085 				fMaxLanes = 2;
1086 				break;
1087 			case INTEL_PORT_E:
1088 				fMaxLanes = 2;
1089 				break;
1090 			default:
1091 				fMaxLanes = 4;
1092 				break;
1093 		}
1094 	}
1095 
1096 	TRACE("%s: %s Maximum Lanes: %" B_PRId8 "\n", __func__,
1097 		PortName(), fMaxLanes);
1098 
1099 	HasEDID();
1100 
1101 	return true;
1102 }
1103 
1104 
1105 status_t
1106 DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
1107 {
1108 	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
1109 		target->virtual_height);
1110 
1111 	if (fPipe == NULL) {
1112 		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
1113 		return B_ERROR;
1114 	}
1115 
1116 	// Train FDI if it exists
1117 	FDILink* link = fPipe->FDI();
1118 	if (link != NULL)
1119 		link->Train(target);
1120 
1121 	pll_divisors divisors;
1122 	compute_pll_divisors(target, &divisors, false);
1123 
1124 	uint32 extraPLLFlags = 0;
1125 	if (gInfo->shared_info->device_type.Generation() >= 3)
1126 		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
1127 
1128 	// Program general pipe config
1129 	fPipe->Configure(target);
1130 
1131 	// Program pipe PLL's
1132 	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
1133 
1134 	// Program target display mode
1135 	fPipe->ConfigureTimings(target);
1136 
1137 	// Set fCurrentMode to our set display mode
1138 	memcpy(&fCurrentMode, target, sizeof(display_mode));
1139 
1140 	return B_OK;
1141 }
1142