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