150f0b3feSAlexander von Gluck IV/*
250f0b3feSAlexander von Gluck IV * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
350f0b3feSAlexander von Gluck IV * Distributed under the terms of the MIT License.
450f0b3feSAlexander von Gluck IV *
550f0b3feSAlexander von Gluck IV * Authors:
650f0b3feSAlexander von Gluck IV *		Axel D��rfler, axeld@pinc-software.de
750f0b3feSAlexander von Gluck IV *		Michael Lotz, mmlr@mlotz.ch
850f0b3feSAlexander von Gluck IV *		Alexander von Gluck IV, kallisti5@unixzen.com
950f0b3feSAlexander von Gluck IV */
1050f0b3feSAlexander von Gluck IV
1150f0b3feSAlexander von Gluck IV
1250f0b3feSAlexander von Gluck IV#include "Ports.h"
1350f0b3feSAlexander von Gluck IV
1450f0b3feSAlexander von Gluck IV#include <ddc.h>
1550f0b3feSAlexander von Gluck IV#include <stdlib.h>
1650f0b3feSAlexander von Gluck IV#include <string.h>
17b3f14fb7SAlexander von Gluck IV#include <Debug.h>
18b3f14fb7SAlexander von Gluck IV#include <KernelExport.h>
1950f0b3feSAlexander von Gluck IV
2050f0b3feSAlexander von Gluck IV#include "accelerant.h"
21b3f14fb7SAlexander von Gluck IV#include "accelerant_protos.h"
2200e0982fSAlexander von Gluck IV#include "FlexibleDisplayInterface.h"
2350f0b3feSAlexander von Gluck IV#include "intel_extreme.h"
2450f0b3feSAlexander von Gluck IV
256e1ff82fSAlexander von Gluck IV#include <new>
266e1ff82fSAlexander von Gluck IV
2750f0b3feSAlexander von Gluck IV
2850f0b3feSAlexander von Gluck IV#undef TRACE
2950f0b3feSAlexander von Gluck IV#define TRACE_PORTS
3050f0b3feSAlexander von Gluck IV#ifdef TRACE_PORTS
31be3f7a8fSAlexander von Gluck IV#   define TRACE(x...) _sPrintf("intel_extreme: " x)
3250f0b3feSAlexander von Gluck IV#else
3350f0b3feSAlexander von Gluck IV#   define TRACE(x...)
3450f0b3feSAlexander von Gluck IV#endif
3550f0b3feSAlexander von Gluck IV
3650f0b3feSAlexander von Gluck IV#define ERROR(x...) _sPrintf("intel_extreme: " x)
3750f0b3feSAlexander von Gluck IV#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
3850f0b3feSAlexander von Gluck IV
3950f0b3feSAlexander von Gluck IV
40bc98dc42SAlexander von Gluck IVstatic bool
41bc98dc42SAlexander von Gluck IVwait_for_set(addr_t address, uint32 mask, uint32 timeout)
42bc98dc42SAlexander von Gluck IV{
43bc98dc42SAlexander von Gluck IV	int interval = 50;
44bc98dc42SAlexander von Gluck IV	uint32 i = 0;
45bc98dc42SAlexander von Gluck IV	for(i = 0; i <= timeout; i += interval) {
46bc98dc42SAlexander von Gluck IV		spin(interval);
47bc98dc42SAlexander von Gluck IV		if ((read32(address) & mask) != 0)
48bc98dc42SAlexander von Gluck IV			return true;
49bc98dc42SAlexander von Gluck IV	}
50bc98dc42SAlexander von Gluck IV	return false;
51bc98dc42SAlexander von Gluck IV}
52bc98dc42SAlexander von Gluck IV
53bc98dc42SAlexander von Gluck IV
54bc98dc42SAlexander von Gluck IVstatic bool
55bc98dc42SAlexander von Gluck IVwait_for_clear(addr_t address, uint32 mask, uint32 timeout)
56bc98dc42SAlexander von Gluck IV{
57bc98dc42SAlexander von Gluck IV	int interval = 50;
58bc98dc42SAlexander von Gluck IV	uint32 i = 0;
59bc98dc42SAlexander von Gluck IV	for(i = 0; i <= timeout; i += interval) {
60bc98dc42SAlexander von Gluck IV		spin(interval);
61bc98dc42SAlexander von Gluck IV		if ((read32(address) & mask) == 0)
62bc98dc42SAlexander von Gluck IV			return true;
63bc98dc42SAlexander von Gluck IV	}
64bc98dc42SAlexander von Gluck IV	return false;
65bc98dc42SAlexander von Gluck IV}
66bc98dc42SAlexander von Gluck IV
67bc98dc42SAlexander von Gluck IV
6850f0b3feSAlexander von Gluck IVPort::Port(port_index index, const char* baseName)
6950f0b3feSAlexander von Gluck IV	:
70b01aed83SAlexander von Gluck IV	fPipe(NULL),
71dee0f365SAlexander von Gluck IV	fEDIDState(B_NO_INIT),
7250f0b3feSAlexander von Gluck IV	fPortIndex(index),
73dee0f365SAlexander von Gluck IV	fPortName(NULL)
7450f0b3feSAlexander von Gluck IV{
7550f0b3feSAlexander von Gluck IV	char portID[2];
7650f0b3feSAlexander von Gluck IV	portID[0] = 'A' + index - INTEL_PORT_A;
7750f0b3feSAlexander von Gluck IV	portID[1] = 0;
7850f0b3feSAlexander von Gluck IV
7950f0b3feSAlexander von Gluck IV	char buffer[32];
8050f0b3feSAlexander von Gluck IV	buffer[0] = 0;
8150f0b3feSAlexander von Gluck IV
8250f0b3feSAlexander von Gluck IV	strlcat(buffer, baseName, sizeof(buffer));
8350f0b3feSAlexander von Gluck IV	strlcat(buffer, " ", sizeof(buffer));
8450f0b3feSAlexander von Gluck IV	strlcat(buffer, portID, sizeof(buffer));
8550f0b3feSAlexander von Gluck IV	fPortName = strdup(buffer);
8650f0b3feSAlexander von Gluck IV}
8750f0b3feSAlexander von Gluck IV
8850f0b3feSAlexander von Gluck IV
8950f0b3feSAlexander von Gluck IVPort::~Port()
9050f0b3feSAlexander von Gluck IV{
9150f0b3feSAlexander von Gluck IV	free(fPortName);
9250f0b3feSAlexander von Gluck IV}
9350f0b3feSAlexander von Gluck IV
9450f0b3feSAlexander von Gluck IV
9550f0b3feSAlexander von Gluck IVbool
9650f0b3feSAlexander von Gluck IVPort::HasEDID()
9750f0b3feSAlexander von Gluck IV{
9850f0b3feSAlexander von Gluck IV	if (fEDIDState == B_NO_INIT)
9950f0b3feSAlexander von Gluck IV		GetEDID(NULL);
10050f0b3feSAlexander von Gluck IV
10150f0b3feSAlexander von Gluck IV	return fEDIDState == B_OK;
10250f0b3feSAlexander von Gluck IV}
10350f0b3feSAlexander von Gluck IV
10450f0b3feSAlexander von Gluck IV
1056e1ff82fSAlexander von Gluck IVstatus_t
106b01aed83SAlexander von Gluck IVPort::SetPipe(Pipe* pipe)
10737b903fbSAlexander von Gluck IV{
10895e38537SAlexander von Gluck IV	CALLED();
10937b903fbSAlexander von Gluck IV
110b01aed83SAlexander von Gluck IV	if (pipe == NULL) {
111b01aed83SAlexander von Gluck IV		ERROR("%s: Invalid pipe provided!\n", __func__);
112b01aed83SAlexander von Gluck IV		return B_ERROR;
113b01aed83SAlexander von Gluck IV	}
114b01aed83SAlexander von Gluck IV
11595e38537SAlexander von Gluck IV	uint32 portRegister = _PortRegister();
11637b903fbSAlexander von Gluck IV	if (portRegister == 0) {
11737b903fbSAlexander von Gluck IV		ERROR("%s: Invalid PortRegister ((0x%" B_PRIx32 ") for %s\n", __func__,
11837b903fbSAlexander von Gluck IV			portRegister, PortName());
1196e1ff82fSAlexander von Gluck IV		return B_ERROR;
12037b903fbSAlexander von Gluck IV	}
12137b903fbSAlexander von Gluck IV
12200e0982fSAlexander von Gluck IV	// TODO: UnAssignPipe?  This likely needs reworked a little
123b01aed83SAlexander von Gluck IV	if (fPipe != NULL) {
124b01aed83SAlexander von Gluck IV		ERROR("%s: Can't reassign display pipe (yet)\n", __func__);
12500e0982fSAlexander von Gluck IV		return B_ERROR;
12600e0982fSAlexander von Gluck IV	}
12700e0982fSAlexander von Gluck IV
12837b903fbSAlexander von Gluck IV	TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe %s\n", __func__,
129b01aed83SAlexander von Gluck IV		PortName(), portRegister, (pipe->Index() == INTEL_PIPE_A) ? "A" : "B");
13037b903fbSAlexander von Gluck IV
13195e38537SAlexander von Gluck IV	uint32 portState = read32(portRegister);
13237b903fbSAlexander von Gluck IV
13392e254d0SAlexander von Gluck IV	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
13492e254d0SAlexander von Gluck IV		portState &= PORT_TRANS_SEL_MASK;
13592e254d0SAlexander von Gluck IV		if (pipe->Index() == INTEL_PIPE_A)
13692e254d0SAlexander von Gluck IV			write32(portRegister, portState | PORT_TRANS_A_SEL_CPT);
13792e254d0SAlexander von Gluck IV		else
13892e254d0SAlexander von Gluck IV			write32(portRegister, portState | PORT_TRANS_B_SEL_CPT);
13992e254d0SAlexander von Gluck IV	} else {
14092e254d0SAlexander von Gluck IV		if (pipe->Index() == INTEL_PIPE_A)
14192e254d0SAlexander von Gluck IV			write32(portRegister, portState & ~DISPLAY_MONITOR_PIPE_B);
14292e254d0SAlexander von Gluck IV		else
14392e254d0SAlexander von Gluck IV			write32(portRegister, portState | DISPLAY_MONITOR_PIPE_B);
14492e254d0SAlexander von Gluck IV	}
14537b903fbSAlexander von Gluck IV
146b01aed83SAlexander von Gluck IV	fPipe = pipe;
1476e1ff82fSAlexander von Gluck IV
148b01aed83SAlexander von Gluck IV	if (fPipe == NULL)
1496e1ff82fSAlexander von Gluck IV		return B_NO_MEMORY;
1506e1ff82fSAlexander von Gluck IV
15121e840d1SAlexander von Gluck IV	// Disable display pipe until modesetting enables it
152b01aed83SAlexander von Gluck IV	if (fPipe->IsEnabled())
153b979c66cSAlexander von Gluck IV		fPipe->Enable(false);
15421e840d1SAlexander von Gluck IV
15537b903fbSAlexander von Gluck IV	read32(portRegister);
1566e1ff82fSAlexander von Gluck IV
1576e1ff82fSAlexander von Gluck IV	return B_OK;
15837b903fbSAlexander von Gluck IV}
15937b903fbSAlexander von Gluck IV
16037b903fbSAlexander von Gluck IV
161b979c66cSAlexander von Gluck IVstatus_t
162b979c66cSAlexander von Gluck IVPort::Power(bool enabled)
163b979c66cSAlexander von Gluck IV{
164b979c66cSAlexander von Gluck IV	fPipe->Enable(enabled);
165b979c66cSAlexander von Gluck IV
166b979c66cSAlexander von Gluck IV	return B_OK;
167b979c66cSAlexander von Gluck IV}
168b979c66cSAlexander von Gluck IV
169b979c66cSAlexander von Gluck IV
17050f0b3feSAlexander von Gluck IVstatus_t
17150f0b3feSAlexander von Gluck IVPort::GetEDID(edid1_info* edid, bool forceRead)
17250f0b3feSAlexander von Gluck IV{
17350f0b3feSAlexander von Gluck IV	CALLED();
17450f0b3feSAlexander von Gluck IV
17550f0b3feSAlexander von Gluck IV	if (fEDIDState == B_NO_INIT || forceRead) {
17650f0b3feSAlexander von Gluck IV		TRACE("%s: trying to read EDID\n", PortName());
17750f0b3feSAlexander von Gluck IV
17850f0b3feSAlexander von Gluck IV		addr_t ddcRegister = _DDCRegister();
17950f0b3feSAlexander von Gluck IV		if (ddcRegister == 0) {
180e747cbe1SAlexander von Gluck IV			TRACE("%s: no DDC register found\n", PortName());
18150f0b3feSAlexander von Gluck IV			fEDIDState = B_ERROR;
18250f0b3feSAlexander von Gluck IV			return fEDIDState;
18350f0b3feSAlexander von Gluck IV		}
18450f0b3feSAlexander von Gluck IV
18561fbdb06SAlexander von Gluck IV		TRACE("%s: using ddc @ 0x%" B_PRIxADDR "\n", PortName(), ddcRegister);
18650f0b3feSAlexander von Gluck IV
18750f0b3feSAlexander von Gluck IV		i2c_bus bus;
18850f0b3feSAlexander von Gluck IV		bus.cookie = (void*)ddcRegister;
18950f0b3feSAlexander von Gluck IV		bus.set_signals = &_SetI2CSignals;
19050f0b3feSAlexander von Gluck IV		bus.get_signals = &_GetI2CSignals;
19150f0b3feSAlexander von Gluck IV		ddc2_init_timing(&bus);
19250f0b3feSAlexander von Gluck IV
19350f0b3feSAlexander von Gluck IV		fEDIDState = ddc2_read_edid1(&bus, &fEDIDInfo, NULL, NULL);
19450f0b3feSAlexander von Gluck IV
19550f0b3feSAlexander von Gluck IV		if (fEDIDState == B_OK) {
19650f0b3feSAlexander von Gluck IV			TRACE("%s: found EDID information!\n", PortName());
19750f0b3feSAlexander von Gluck IV			edid_dump(&fEDIDInfo);
19850f0b3feSAlexander von Gluck IV		}
19950f0b3feSAlexander von Gluck IV	}
20050f0b3feSAlexander von Gluck IV
20150f0b3feSAlexander von Gluck IV	if (fEDIDState != B_OK) {
20250f0b3feSAlexander von Gluck IV		TRACE("%s: no EDID information found.\n", PortName());
20350f0b3feSAlexander von Gluck IV		return fEDIDState;
20450f0b3feSAlexander von Gluck IV	}
20550f0b3feSAlexander von Gluck IV
20650f0b3feSAlexander von Gluck IV	if (edid != NULL)
20750f0b3feSAlexander von Gluck IV		memcpy(edid, &fEDIDInfo, sizeof(edid1_info));
20850f0b3feSAlexander von Gluck IV
20950f0b3feSAlexander von Gluck IV	return B_OK;
21050f0b3feSAlexander von Gluck IV}
21150f0b3feSAlexander von Gluck IV
21250f0b3feSAlexander von Gluck IV
21350f0b3feSAlexander von Gluck IVstatus_t
21450f0b3feSAlexander von Gluck IVPort::GetPLLLimits(pll_limits& limits)
21550f0b3feSAlexander von Gluck IV{
21650f0b3feSAlexander von Gluck IV	return B_ERROR;
21750f0b3feSAlexander von Gluck IV}
21850f0b3feSAlexander von Gluck IV
21950f0b3feSAlexander von Gluck IV
22050f0b3feSAlexander von Gluck IVstatus_t
22150f0b3feSAlexander von Gluck IVPort::_GetI2CSignals(void* cookie, int* _clock, int* _data)
22250f0b3feSAlexander von Gluck IV{
22350f0b3feSAlexander von Gluck IV	addr_t ioRegister = (addr_t)cookie;
22450f0b3feSAlexander von Gluck IV	uint32 value = read32(ioRegister);
22550f0b3feSAlexander von Gluck IV
22650f0b3feSAlexander von Gluck IV	*_clock = (value & I2C_CLOCK_VALUE_IN) != 0;
22750f0b3feSAlexander von Gluck IV	*_data = (value & I2C_DATA_VALUE_IN) != 0;
22850f0b3feSAlexander von Gluck IV
22950f0b3feSAlexander von Gluck IV	return B_OK;
23050f0b3feSAlexander von Gluck IV}
23150f0b3feSAlexander von Gluck IV
23250f0b3feSAlexander von Gluck IV
23350f0b3feSAlexander von Gluck IVstatus_t
23450f0b3feSAlexander von Gluck IVPort::_SetI2CSignals(void* cookie, int clock, int data)
23550f0b3feSAlexander von Gluck IV{
23650f0b3feSAlexander von Gluck IV	addr_t ioRegister = (addr_t)cookie;
23750f0b3feSAlexander von Gluck IV	uint32 value;
23850f0b3feSAlexander von Gluck IV
23984b7116dSAlexander von Gluck IV	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_83x)) {
24050f0b3feSAlexander von Gluck IV		// on these chips, the reserved values are fixed
24150f0b3feSAlexander von Gluck IV		value = 0;
24250f0b3feSAlexander von Gluck IV	} else {
24350f0b3feSAlexander von Gluck IV		// on all others, we have to preserve them manually
24450f0b3feSAlexander von Gluck IV		value = read32(ioRegister) & I2C_RESERVED;
24550f0b3feSAlexander von Gluck IV	}
24650f0b3feSAlexander von Gluck IV
24750f0b3feSAlexander von Gluck IV	if (data != 0)
24850f0b3feSAlexander von Gluck IV		value |= I2C_DATA_DIRECTION_MASK;
24950f0b3feSAlexander von Gluck IV	else {
25050f0b3feSAlexander von Gluck IV		value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT
25150f0b3feSAlexander von Gluck IV			| I2C_DATA_VALUE_MASK;
25250f0b3feSAlexander von Gluck IV	}
25350f0b3feSAlexander von Gluck IV
25450f0b3feSAlexander von Gluck IV	if (clock != 0)
25550f0b3feSAlexander von Gluck IV		value |= I2C_CLOCK_DIRECTION_MASK;
25650f0b3feSAlexander von Gluck IV	else {
25750f0b3feSAlexander von Gluck IV		value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT
25850f0b3feSAlexander von Gluck IV			| I2C_CLOCK_VALUE_MASK;
25950f0b3feSAlexander von Gluck IV	}
26050f0b3feSAlexander von Gluck IV
26150f0b3feSAlexander von Gluck IV	write32(ioRegister, value);
26250f0b3feSAlexander von Gluck IV	read32(ioRegister);
26350f0b3feSAlexander von Gluck IV		// make sure the PCI bus has flushed the write
26450f0b3feSAlexander von Gluck IV
26550f0b3feSAlexander von Gluck IV	return B_OK;
26650f0b3feSAlexander von Gluck IV}
26750f0b3feSAlexander von Gluck IV
26850f0b3feSAlexander von Gluck IV
26950f0b3feSAlexander von Gluck IV// #pragma mark - Analog Port
27050f0b3feSAlexander von Gluck IV
27150f0b3feSAlexander von Gluck IV
27250f0b3feSAlexander von Gluck IVAnalogPort::AnalogPort()
27350f0b3feSAlexander von Gluck IV	:
27450f0b3feSAlexander von Gluck IV	Port(INTEL_PORT_A, "Analog")
27550f0b3feSAlexander von Gluck IV{
27650f0b3feSAlexander von Gluck IV}
27750f0b3feSAlexander von Gluck IV
27850f0b3feSAlexander von Gluck IV
27950f0b3feSAlexander von Gluck IVbool
28050f0b3feSAlexander von Gluck IVAnalogPort::IsConnected()
28150f0b3feSAlexander von Gluck IV{
282236a3e93SAlexander von Gluck IV	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
283236a3e93SAlexander von Gluck IV		_PortRegister());
28450f0b3feSAlexander von Gluck IV	return HasEDID();
28550f0b3feSAlexander von Gluck IV}
28650f0b3feSAlexander von Gluck IV
28750f0b3feSAlexander von Gluck IV
28827134c66SAlexander von Gluck IVaddr_t
28950f0b3feSAlexander von Gluck IVAnalogPort::_DDCRegister()
29050f0b3feSAlexander von Gluck IV{
29150f0b3feSAlexander von Gluck IV	// always fixed
29250f0b3feSAlexander von Gluck IV	return INTEL_I2C_IO_A;
29350f0b3feSAlexander von Gluck IV}
29450f0b3feSAlexander von Gluck IV
29550f0b3feSAlexander von Gluck IV
29637b903fbSAlexander von Gluck IVaddr_t
29737b903fbSAlexander von Gluck IVAnalogPort::_PortRegister()
29837b903fbSAlexander von Gluck IV{
29937b903fbSAlexander von Gluck IV	// always fixed
30037b903fbSAlexander von Gluck IV	return INTEL_ANALOG_PORT;
30137b903fbSAlexander von Gluck IV}
30237b903fbSAlexander von Gluck IV
30337b903fbSAlexander von Gluck IV
304b3f14fb7SAlexander von Gluck IVstatus_t
305b3f14fb7SAlexander von Gluck IVAnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
306b3f14fb7SAlexander von Gluck IV{
30761fbdb06SAlexander von Gluck IV	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
30861fbdb06SAlexander von Gluck IV		target->virtual_height);
309b3f14fb7SAlexander von Gluck IV
310b01aed83SAlexander von Gluck IV	if (fPipe == NULL) {
31161fbdb06SAlexander von Gluck IV		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
31261fbdb06SAlexander von Gluck IV		return B_ERROR;
313b3f14fb7SAlexander von Gluck IV	}
314b3f14fb7SAlexander von Gluck IV
315b1c582baSAdrien Destugues#if 0
316b1c582baSAdrien Destugues	// Disabled for now as our code doesn't work. Let's hope VESA/EFI has
317b1c582baSAdrien Destugues	// already set things up for us during boot.
31800e0982fSAlexander von Gluck IV	// Train FDI if it exists
319b01aed83SAlexander von Gluck IV	FDILink* link = fPipe->FDI();
320e6fefa6cSAlexander von Gluck IV	if (link != NULL)
321e6fefa6cSAlexander von Gluck IV		link->Train(target);
322b1c582baSAdrien Destugues#endif
32300e0982fSAlexander von Gluck IV
32461fbdb06SAlexander von Gluck IV	pll_divisors divisors;
32561fbdb06SAlexander von Gluck IV	compute_pll_divisors(target, &divisors, false);
326b3f14fb7SAlexander von Gluck IV
32761fbdb06SAlexander von Gluck IV	uint32 extraPLLFlags = 0;
328af0dad47SAlexander von Gluck IV	if (gInfo->shared_info->device_type.Generation() >= 3)
32992bcdd79SAlexander von Gluck IV		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
330b3f14fb7SAlexander von Gluck IV
331c9c61669SAlexander von Gluck IV	// Program general pipe config
332c9c61669SAlexander von Gluck IV	fPipe->Configure(target);
333c9c61669SAlexander von Gluck IV
334b979c66cSAlexander von Gluck IV	// Program pipe PLL's
335b979c66cSAlexander von Gluck IV	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
336b979c66cSAlexander von Gluck IV
337d35a52e8SAlexander von Gluck IV	write32(_PortRegister(), (read32(_PortRegister())
339d35a52e8SAlexander von Gluck IV		| ((target->timing.flags & B_POSITIVE_HSYNC) != 0
340d35a52e8SAlexander von Gluck IV			? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
341d35a52e8SAlexander von Gluck IV		| ((target->timing.flags & B_POSITIVE_VSYNC) != 0
342d35a52e8SAlexander von Gluck IV			? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
343d35a52e8SAlexander von Gluck IV
34461fbdb06SAlexander von Gluck IV	// Program target display mode
345b979c66cSAlexander von Gluck IV	fPipe->ConfigureTimings(target);
346b3f14fb7SAlexander von Gluck IV
347b3f14fb7SAlexander von Gluck IV	// Set fCurrentMode to our set display mode
34839f61d21SAlexander von Gluck IV	memcpy(&fCurrentMode, target, sizeof(display_mode));
349b3f14fb7SAlexander von Gluck IV
350b3f14fb7SAlexander von Gluck IV	return B_OK;
351b3f14fb7SAlexander von Gluck IV}
352b3f14fb7SAlexander von Gluck IV
353b3f14fb7SAlexander von Gluck IV
35450f0b3feSAlexander von Gluck IV// #pragma mark - LVDS Panel
35550f0b3feSAlexander von Gluck IV
35650f0b3feSAlexander von Gluck IV
35750f0b3feSAlexander von Gluck IVLVDSPort::LVDSPort()
35850f0b3feSAlexander von Gluck IV	:
35950f0b3feSAlexander von Gluck IV	Port(INTEL_PORT_C, "LVDS")
36050f0b3feSAlexander von Gluck IV{
361c86f3dbaSAlexander von Gluck IV	// Always unlock LVDS port as soon as we start messing with it.
3620ea662e5SAlexander von Gluck IV	uint32 panelControl = INTEL_PANEL_CONTROL;
363adc0f76eSAdrien Destugues	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
364adc0f76eSAdrien Destugues		// FIXME writing there results in black screen on SandyBridge
365adc0f76eSAdrien Destugues		return;
366adc0f76eSAdrien Destugues		// panelControl = PCH_PANEL_CONTROL;
367adc0f76eSAdrien Destugues	}
3680ea662e5SAlexander von Gluck IV	write32(panelControl, read32(panelControl) | PANEL_REGISTER_UNLOCK);
36950f0b3feSAlexander von Gluck IV}
37050f0b3feSAlexander von Gluck IV
37150f0b3feSAlexander von Gluck IV
37217ecf642SAlexander von Gluck IVpipe_index
37317ecf642SAlexander von Gluck IVLVDSPort::PipePreference()
37417ecf642SAlexander von Gluck IV{
37549cabb0dSAlexander von Gluck IV	// TODO: Technically INTEL_PIPE_B is only required on < gen 4
37649cabb0dSAlexander von Gluck IV	// otherwise we can use INTEL_PIPE_ANY, however it seems to break
37749cabb0dSAlexander von Gluck IV	// modesetting atm. (likely due to a bug on our end)
37849cabb0dSAlexander von Gluck IV	//if (gInfo->shared_info->device_type.Generation() < 4)
37949cabb0dSAlexander von Gluck IV	//	return INTEL_PIPE_B;
38017ecf642SAlexander von Gluck IV
38149cabb0dSAlexander von Gluck IV	return INTEL_PIPE_B;
38217ecf642SAlexander von Gluck IV}
38317ecf642SAlexander von Gluck IV
38417ecf642SAlexander von Gluck IV
38550f0b3feSAlexander von Gluck IVbool
38650f0b3feSAlexander von Gluck IVLVDSPort::IsConnected()
38750f0b3feSAlexander von Gluck IV{
388236a3e93SAlexander von Gluck IV	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
389236a3e93SAlexander von Gluck IV		_PortRegister());
390236a3e93SAlexander von Gluck IV
39192e254d0SAlexander von Gluck IV	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
392dee0f365SAlexander von Gluck IV		uint32 registerValue = read32(_PortRegister());
39350f0b3feSAlexander von Gluck IV		// there's a detection bit we can use
394c86f3dbaSAlexander von Gluck IV		if ((registerValue & PCH_LVDS_DETECTED) == 0) {
395c86f3dbaSAlexander von Gluck IV			TRACE("LVDS: Not detected\n");
39650f0b3feSAlexander von Gluck IV			return false;
397c86f3dbaSAlexander von Gluck IV		}
398c86f3dbaSAlexander von Gluck IV		// TODO: Skip if eDP support
399dee0f365SAlexander von Gluck IV	} else if (gInfo->shared_info->device_type.Generation() <= 4) {
400dee0f365SAlexander von Gluck IV		// Older generations don't have LVDS detection. If not mobile skip.
401dee0f365SAlexander von Gluck IV		if (!gInfo->shared_info->device_type.IsMobile()) {
402dee0f365SAlexander von Gluck IV			TRACE("LVDS: Skipping LVDS detection due to gen and not mobile\n");
403dee0f365SAlexander von Gluck IV			return false;
404dee0f365SAlexander von Gluck IV		}
405dee0f365SAlexander von Gluck IV		// If mobile, try to grab EDID
406dee0f365SAlexander von Gluck IV		// Linux seems to look at lid status for LVDS port detection
407dee0f365SAlexander von Gluck IV		// If we don't get EDID, we can use vbios native mode or vesa?
408dee0f365SAlexander von Gluck IV		if (!HasEDID()) {
409dee0f365SAlexander von Gluck IV			#if 0
410dee0f365SAlexander von Gluck IV			if (gInfo->shared_info->got_vbt) {
411dee0f365SAlexander von Gluck IV				// TODO: Fake EDID from vbios native mode?
412dee0f365SAlexander von Gluck IV				// I feel like this would be more accurate
413dee0f365SAlexander von Gluck IV			} else if...
414dee0f365SAlexander von Gluck IV			#endif
415dee0f365SAlexander von Gluck IV			if (gInfo->shared_info->has_vesa_edid_info) {
416dee0f365SAlexander von Gluck IV				TRACE("LVDS: Using VESA edid info\n");
417dee0f365SAlexander von Gluck IV				memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info,
418dee0f365SAlexander von Gluck IV					sizeof(edid1_info));
419dee0f365SAlexander von Gluck IV				fEDIDState = B_OK;
420dee0f365SAlexander von Gluck IV				// HasEDID now true
421dee0f365SAlexander von Gluck IV			} else {
422dee0f365SAlexander von Gluck IV				TRACE("LVDS: Couldn't find any valid EDID!\n");
423dee0f365SAlexander von Gluck IV				return false;
424dee0f365SAlexander von Gluck IV			}
425dee0f365SAlexander von Gluck IV		}
42650f0b3feSAlexander von Gluck IV	}
42750f0b3feSAlexander von Gluck IV
42850f0b3feSAlexander von Gluck IV	// Try getting EDID, as the LVDS port doesn't overlap with anything else,
42950f0b3feSAlexander von Gluck IV	// we don't run the risk of getting someone else's data.
43050f0b3feSAlexander von Gluck IV	return HasEDID();
43150f0b3feSAlexander von Gluck IV}
43250f0b3feSAlexander von Gluck IV
43350f0b3feSAlexander von Gluck IV
43427134c66SAlexander von Gluck IVaddr_t
43550f0b3feSAlexander von Gluck IVLVDSPort::_DDCRegister()
43650f0b3feSAlexander von Gluck IV{
43750f0b3feSAlexander von Gluck IV	// always fixed
43850f0b3feSAlexander von Gluck IV	return INTEL_I2C_IO_C;
43950f0b3feSAlexander von Gluck IV}
44050f0b3feSAlexander von Gluck IV
44150f0b3feSAlexander von Gluck IV
44237b903fbSAlexander von Gluck IVaddr_t
44337b903fbSAlexander von Gluck IVLVDSPort::_PortRegister()
44437b903fbSAlexander von Gluck IV{
44537b903fbSAlexander von Gluck IV	// always fixed
44637b903fbSAlexander von Gluck IV	return INTEL_DIGITAL_LVDS_PORT;
44737b903fbSAlexander von Gluck IV}
44837b903fbSAlexander von Gluck IV
44937b903fbSAlexander von Gluck IV
450b3f14fb7SAlexander von Gluck IVstatus_t
451b3f14fb7SAlexander von Gluck IVLVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
452b3f14fb7SAlexander von Gluck IV{
45395e38537SAlexander von Gluck IV	CALLED();
45461fbdb06SAlexander von Gluck IV	if (target == NULL) {
45561fbdb06SAlexander von Gluck IV		ERROR("%s: Invalid target mode passed!\n", __func__);
45661fbdb06SAlexander von Gluck IV		return B_ERROR;
45761fbdb06SAlexander von Gluck IV	}
45861fbdb06SAlexander von Gluck IV
45961fbdb06SAlexander von Gluck IV	TRACE("%s: %s-%d %dx%d\n", __func__, PortName(), PortIndex(),
46061fbdb06SAlexander von Gluck IV		target->virtual_width, target->virtual_height);
46161fbdb06SAlexander von Gluck IV
462b01aed83SAlexander von Gluck IV	if (fPipe == NULL) {
46361fbdb06SAlexander von Gluck IV		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
46461fbdb06SAlexander von Gluck IV		return B_ERROR;
46561fbdb06SAlexander von Gluck IV	}
46661fbdb06SAlexander von Gluck IV
467bc98dc42SAlexander von Gluck IV	addr_t panelControl = INTEL_PANEL_CONTROL;
468bc98dc42SAlexander von Gluck IV	addr_t panelStatus = INTEL_PANEL_STATUS;
46992e254d0SAlexander von Gluck IV	if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
470bc98dc42SAlexander von Gluck IV		panelControl = PCH_PANEL_CONTROL;
471bc98dc42SAlexander von Gluck IV		panelStatus = PCH_PANEL_STATUS;
472bc98dc42SAlexander von Gluck IV	}
473bc98dc42SAlexander von Gluck IV
474bc98dc42SAlexander von Gluck IV	// Power off Panel
475bc98dc42SAlexander von Gluck IV	write32(panelControl, read32(panelControl) & ~PANEL_CONTROL_POWER_TARGET_ON);
476bc98dc42SAlexander von Gluck IV	read32(panelControl);
477bc98dc42SAlexander von Gluck IV
478bc98dc42SAlexander von Gluck IV	if (!wait_for_clear(panelStatus, PANEL_STATUS_POWER_ON, 1000))
479bc98dc42SAlexander von Gluck IV		ERROR("%s: %s didn't power off within 1000ms!\n", __func__, PortName());
480bc98dc42SAlexander von Gluck IV
481b1c582baSAdrien Destugues#if 0
482b1c582baSAdrien Destugues	// Disabled for now as our code doesn't work. Let's hope VESA/EFI has
483b1c582baSAdrien Destugues	// already set things up for us during boot.
484c0d4def4SAlexander von Gluck IV	// Train FDI if it exists
485c0d4def4SAlexander von Gluck IV	FDILink* link = fPipe->FDI();
486c0d4def4SAlexander von Gluck IV	if (link != NULL)
487c0d4def4SAlexander von Gluck IV		link->Train(target);
488b1c582baSAdrien Destugues#endif
489c0d4def4SAlexander von Gluck IV
4903b0f09dbSAlexander von Gluck IV#if 0
491eb56837dSAlexander von Gluck IV	// Disable PanelFitter for now
492eb56837dSAlexander von Gluck IV	addr_t panelFitterControl = PCH_PANEL_FITTER_BASE_REGISTER
493eb56837dSAlexander von Gluck IV		+ PCH_PANEL_FITTER_CONTROL;
494b01aed83SAlexander von Gluck IV	if (fPipe->Index() == INTEL_PIPE_B)
495eb56837dSAlexander von Gluck IV		panelFitterControl += PCH_PANEL_FITTER_PIPE_OFFSET;
496eb56837dSAlexander von Gluck IV	write32(panelFitterControl, (read32(panelFitterControl) & ~PANEL_FITTER_ENABLED));
497eb56837dSAlexander von Gluck IV	read32(panelFitterControl);
4983b0f09dbSAlexander von Gluck IV#endif
499eb56837dSAlexander von Gluck IV
500b3f14fb7SAlexander von Gluck IV	// For LVDS panels, we actually always set the native mode in hardware
501b3f14fb7SAlexander von Gluck IV	// Then we use the panel fitter to scale the picture to that.
502b3f14fb7SAlexander von Gluck IV	display_mode hardwareTarget;
503b3f14fb7SAlexander von Gluck IV	bool needsScaling = false;
504b3f14fb7SAlexander von Gluck IV		// Try to get the panel preferred screen mode from EDID info
5053b0f09dbSAlexander von Gluck IV
5063b0f09dbSAlexander von Gluck IV	if (gInfo->shared_info->got_vbt) {
5073b0f09dbSAlexander von Gluck IV		// Set vbios hardware panel mode as base
5083b0f09dbSAlexander von Gluck IV		memcpy(&hardwareTarget, &gInfo->shared_info->panel_mode,
5093b0f09dbSAlexander von Gluck IV			sizeof(display_mode));
510b3f14fb7SAlexander von Gluck IV		hardwareTarget.space = target->space;
511b3f14fb7SAlexander von Gluck IV
512b3f14fb7SAlexander von Gluck IV		if ((hardwareTarget.virtual_width <= target->virtual_width
513b3f14fb7SAlexander von Gluck IV				&& hardwareTarget.virtual_height <= target->virtual_height
514b3f14fb7SAlexander von Gluck IV				&& hardwareTarget.space <= target->space)
515b3f14fb7SAlexander von Gluck IV			|| intel_propose_display_mode(&hardwareTarget, target, target)) {
516b3f14fb7SAlexander von Gluck IV			hardwareTarget = *target;
517b3f14fb7SAlexander von Gluck IV		} else
518b3f14fb7SAlexander von Gluck IV			needsScaling = true;
5193b0f09dbSAlexander von Gluck IV
5203b0f09dbSAlexander von Gluck IV		TRACE("%s: hardware mode will actually be %dx%d (%s)\n", __func__,
5213b0f09dbSAlexander von Gluck IV			hardwareTarget.virtual_width, hardwareTarget.virtual_height,
5223b0f09dbSAlexander von Gluck IV			needsScaling ? "scaled" : "unscaled");
523b3f14fb7SAlexander von Gluck IV	} else {
524b3f14fb7SAlexander von Gluck IV		// We don't have EDID data, try to set the requested mode directly
525b3f14fb7SAlexander von Gluck IV		hardwareTarget = *target;
526b3f14fb7SAlexander von Gluck IV	}
5273b0f09dbSAlexander von Gluck IV
528b3f14fb7SAlexander von Gluck IV	pll_divisors divisors;
529b3f14fb7SAlexander von Gluck IV	if (needsScaling)
530b3f14fb7SAlexander von Gluck IV		compute_pll_divisors(&hardwareTarget, &divisors, true);
531b3f14fb7SAlexander von Gluck IV	else
532b3f14fb7SAlexander von Gluck IV		compute_pll_divisors(target, &divisors, true);
533b3f14fb7SAlexander von Gluck IV
53461fbdb06SAlexander von Gluck IV	uint32 lvds = read32(_PortRegister())
53561fbdb06SAlexander von Gluck IV		| LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
536b3f14fb7SAlexander von Gluck IV
537f979e62eSAlexander von Gluck IV	if (gInfo->shared_info->device_type.Generation() == 4) {
538f979e62eSAlexander von Gluck IV		// LVDS_A3_POWER_UP == 24bpp
539f979e62eSAlexander von Gluck IV		// otherwise, 18bpp
540f979e62eSAlexander von Gluck IV		if ((lvds & LVDS_A3_POWER_MASK) != LVDS_A3_POWER_UP)
541f979e62eSAlexander von Gluck IV			lvds |= LVDS_18BIT_DITHER;
542f979e62eSAlexander von Gluck IV	}
543b3f14fb7SAlexander von Gluck IV
54492e254d0SAlexander von Gluck IV	// LVDS on PCH needs set before display enable
54592e254d0SAlexander von Gluck IV	if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
54692e254d0SAlexander von Gluck IV		lvds &= PORT_TRANS_SEL_MASK;
54792e254d0SAlexander von Gluck IV		if (fPipe->Index() == INTEL_PIPE_A)
54892e254d0SAlexander von Gluck IV			lvds |= PORT_TRANS_A_SEL_CPT;
54992e254d0SAlexander von Gluck IV		else
55092e254d0SAlexander von Gluck IV			lvds |= PORT_TRANS_B_SEL_CPT;
55192e254d0SAlexander von Gluck IV	}
55292e254d0SAlexander von Gluck IV
553b3f14fb7SAlexander von Gluck IV	// Set the B0-B3 data pairs corresponding to whether we're going to
554b3f14fb7SAlexander von Gluck IV	// set the DPLLs for dual-channel mode or not.
5559407ab29SAlexander von Gluck IV	if (divisors.p2 == 5 || divisors.p2 == 7) {
556d35a52e8SAlexander von Gluck IV		TRACE("LVDS: dual channel\n");
5570ea662e5SAlexander von Gluck IV		lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
558d35a52e8SAlexander von Gluck IV	} else {
559d35a52e8SAlexander von Gluck IV		TRACE("LVDS: single channel\n");
5600ea662e5SAlexander von Gluck IV		lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
561d35a52e8SAlexander von Gluck IV	}
562b3f14fb7SAlexander von Gluck IV
563d35a52e8SAlexander von Gluck IV	// LVDS port control moves polarity bits because Intel hates you.
564f979e62eSAlexander von Gluck IV	// Set LVDS sync polarity
565f979e62eSAlexander von Gluck IV	lvds &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
56686427512SAlexander von Gluck IV
56786427512SAlexander von Gluck IV	// set on - polarity.
56886427512SAlexander von Gluck IV	if ((target->timing.flags & B_POSITIVE_HSYNC) == 0)
569f979e62eSAlexander von Gluck IV		lvds |= LVDS_HSYNC_POLARITY;
57086427512SAlexander von Gluck IV	if ((target->timing.flags & B_POSITIVE_VSYNC) == 0)
571f979e62eSAlexander von Gluck IV		lvds |= LVDS_VSYNC_POLARITY;
572f979e62eSAlexander von Gluck IV
573d35a52e8SAlexander von Gluck IV	TRACE("%s: LVDS Write: 0x%" B_PRIx32 "\n", __func__, lvds);
57461fbdb06SAlexander von Gluck IV	write32(_PortRegister(), lvds);
57561fbdb06SAlexander von Gluck IV	read32(_PortRegister());
57661fbdb06SAlexander von Gluck IV
57761fbdb06SAlexander von Gluck IV	uint32 extraPLLFlags = 0;
57861fbdb06SAlexander von Gluck IV
57961fbdb06SAlexander von Gluck IV	// DPLL mode LVDS for i915+
5805b0b486bSAlexander von Gluck IV	if (gInfo->shared_info->device_type.Generation() >= 3)
58161fbdb06SAlexander von Gluck IV		extraPLLFlags |= DISPLAY_PLL_MODE_LVDS;
58261fbdb06SAlexander von Gluck IV
583c9c61669SAlexander von Gluck IV	// Program general pipe config
584c9c61669SAlexander von Gluck IV	fPipe->Configure(target);
585c9c61669SAlexander von Gluck IV
586de048108SAlexander von Gluck IV	// Program pipe PLL's (pixel_clock is *always* the hardware pixel clock)
5873b0f09dbSAlexander von Gluck IV	fPipe->ConfigureClocks(divisors, hardwareTarget.timing.pixel_clock,
5883b0f09dbSAlexander von Gluck IV		extraPLLFlags);
5893b0f09dbSAlexander von Gluck IV
5903b0f09dbSAlexander von Gluck IV	// Disable panel fitting, but enable 8 to 6-bit dithering
5913b0f09dbSAlexander von Gluck IV	write32(INTEL_PANEL_FIT_CONTROL, 0x4);
5923b0f09dbSAlexander von Gluck IV		// TODO: do not do this if the connected panel is 24-bit
5933b0f09dbSAlexander von Gluck IV		// (I don't know how to detect that)
594b3f14fb7SAlexander von Gluck IV
595222f5929SAlexander von Gluck IV	// Power on Panel
596222f5929SAlexander von Gluck IV	write32(panelControl, read32(panelControl) | PANEL_CONTROL_POWER_TARGET_ON);
597bc98dc42SAlexander von Gluck IV	read32(panelControl);
598222f5929SAlexander von Gluck IV
599bc98dc42SAlexander von Gluck IV	if (!wait_for_set(panelStatus, PANEL_STATUS_POWER_ON, 1000))
600bc98dc42SAlexander von Gluck IV		ERROR("%s: %s didn't power on within 1000ms!\n", __func__, PortName());
601222f5929SAlexander von Gluck IV
60261fbdb06SAlexander von Gluck IV	// Program target display mode
603b979c66cSAlexander von Gluck IV	fPipe->ConfigureTimings(target);
60461fbdb06SAlexander von Gluck IV
60561fbdb06SAlexander von Gluck IV#if 0
606b3f14fb7SAlexander von Gluck IV	// update timing parameters
607b3f14fb7SAlexander von Gluck IV	if (needsScaling) {
608b3f14fb7SAlexander von Gluck IV		// TODO: Alternatively, it should be possible to use the panel
609b3f14fb7SAlexander von Gluck IV		// fitter and scale the picture.
610b3f14fb7SAlexander von Gluck IV
611b3f14fb7SAlexander von Gluck IV		// TODO: Perform some sanity check, for example if the target is
612b3f14fb7SAlexander von Gluck IV		// wider than the hardware mode we end up with negative borders and
613b3f14fb7SAlexander von Gluck IV		// broken timings
614b3f14fb7SAlexander von Gluck IV		uint32 borderWidth = hardwareTarget.timing.h_display
615b3f14fb7SAlexander von Gluck IV			- target->timing.h_display;
616b3f14fb7SAlexander von Gluck IV
617b3f14fb7SAlexander von Gluck IV		uint32 syncWidth = hardwareTarget.timing.h_sync_end
618b3f14fb7SAlexander von Gluck IV			- hardwareTarget.timing.h_sync_start;
619b3f14fb7SAlexander von Gluck IV
620b3f14fb7SAlexander von Gluck IV		uint32 syncCenter = target->timing.h_display
621b3f14fb7SAlexander von Gluck IV			+ (hardwareTarget.timing.h_total
622b3f14fb7SAlexander von Gluck IV			- target->timing.h_display) / 2;
623b3f14fb7SAlexander von Gluck IV
624b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_HTOTAL,
625b3f14fb7SAlexander von Gluck IV			((uint32)(hardwareTarget.timing.h_total - 1) << 16)
626b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.h_display - 1));
627b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_HBLANK,
628b3f14fb7SAlexander von Gluck IV			((uint32)(hardwareTarget.timing.h_total - borderWidth / 2 - 1)
629b3f14fb7SAlexander von Gluck IV				<< 16)
630b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.h_display + borderWidth / 2 - 1));
631b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_HSYNC,
632b3f14fb7SAlexander von Gluck IV			((uint32)(syncCenter + syncWidth / 2 - 1) << 16)
633b3f14fb7SAlexander von Gluck IV			| ((uint32)syncCenter - syncWidth / 2 - 1));
634b3f14fb7SAlexander von Gluck IV
635b3f14fb7SAlexander von Gluck IV		uint32 borderHeight = hardwareTarget.timing.v_display
636b3f14fb7SAlexander von Gluck IV			- target->timing.v_display;
637b3f14fb7SAlexander von Gluck IV
638b3f14fb7SAlexander von Gluck IV		uint32 syncHeight = hardwareTarget.timing.v_sync_end
639b3f14fb7SAlexander von Gluck IV			- hardwareTarget.timing.v_sync_start;
640b3f14fb7SAlexander von Gluck IV
641b3f14fb7SAlexander von Gluck IV		syncCenter = target->timing.v_display
642b3f14fb7SAlexander von Gluck IV			+ (hardwareTarget.timing.v_total
643b3f14fb7SAlexander von Gluck IV			- target->timing.v_display) / 2;
644b3f14fb7SAlexander von Gluck IV
645b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_VTOTAL,
646b3f14fb7SAlexander von Gluck IV			((uint32)(hardwareTarget.timing.v_total - 1) << 16)
647b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.v_display - 1));
648b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_VBLANK,
649b3f14fb7SAlexander von Gluck IV			((uint32)(hardwareTarget.timing.v_total - borderHeight / 2 - 1)
650b3f14fb7SAlexander von Gluck IV				<< 16)
651b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.v_display
652b3f14fb7SAlexander von Gluck IV				+ borderHeight / 2 - 1));
653b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_VSYNC,
654b3f14fb7SAlexander von Gluck IV			((uint32)(syncCenter + syncHeight / 2 - 1) << 16)
655b3f14fb7SAlexander von Gluck IV			| ((uint32)syncCenter - syncHeight / 2 - 1));
656b3f14fb7SAlexander von Gluck IV
657b3f14fb7SAlexander von Gluck IV		// This is useful for debugging: it sets the border to red, so you
658b3f14fb7SAlexander von Gluck IV		// can see what is border and what is porch (black area around the
659b3f14fb7SAlexander von Gluck IV		// sync)
660b3f14fb7SAlexander von Gluck IV		// write32(0x61020, 0x00FF0000);
661b3f14fb7SAlexander von Gluck IV	} else {
662b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_HTOTAL,
663b3f14fb7SAlexander von Gluck IV			((uint32)(target->timing.h_total - 1) << 16)
664b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.h_display - 1));
665b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_HBLANK,
666b3f14fb7SAlexander von Gluck IV			((uint32)(target->timing.h_total - 1) << 16)
667b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.h_display - 1));
668b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_HSYNC,
669b3f14fb7SAlexander von Gluck IV			((uint32)(target->timing.h_sync_end - 1) << 16)
670b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.h_sync_start - 1));
671b3f14fb7SAlexander von Gluck IV
672b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_VTOTAL,
673b3f14fb7SAlexander von Gluck IV			((uint32)(target->timing.v_total - 1) << 16)
674b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.v_display - 1));
675b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_VBLANK,
676b3f14fb7SAlexander von Gluck IV			((uint32)(target->timing.v_total - 1) << 16)
677b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.v_display - 1));
678b3f14fb7SAlexander von Gluck IV		write32(INTEL_DISPLAY_B_VSYNC, (
679b3f14fb7SAlexander von Gluck IV			(uint32)(target->timing.v_sync_end - 1) << 16)
680b3f14fb7SAlexander von Gluck IV			| ((uint32)target->timing.v_sync_start - 1));
681b3f14fb7SAlexander von Gluck IV	}
68261fbdb06SAlexander von Gluck IV#endif
68361fbdb06SAlexander von Gluck IV
68461fbdb06SAlexander von Gluck IV	// Set fCurrentMode to our set display mode
68539f61d21SAlexander von Gluck IV	memcpy(&fCurrentMode, target, sizeof(display_mode));
686b3f14fb7SAlexander von Gluck IV
687b3f14fb7SAlexander von Gluck IV	return B_OK;
688b3f14fb7SAlexander von Gluck IV}
689b3f14fb7SAlexander von Gluck IV
690b3f14fb7SAlexander von Gluck IV
69150f0b3feSAlexander von Gluck IV// #pragma mark - DVI/SDVO/generic
69250f0b3feSAlexander von Gluck IV
69350f0b3feSAlexander von Gluck IV
69450f0b3feSAlexander von Gluck IVDigitalPort::DigitalPort(port_index index, const char* baseName)
69550f0b3feSAlexander von Gluck IV	:
69650f0b3feSAlexander von Gluck IV	Port(index, baseName)
69750f0b3feSAlexander von Gluck IV{
69850f0b3feSAlexander von Gluck IV}
69950f0b3feSAlexander von Gluck IV
70050f0b3feSAlexander von Gluck IV
70150f0b3feSAlexander von Gluck IVbool
70250f0b3feSAlexander von Gluck IVDigitalPort::IsConnected()
70350f0b3feSAlexander von Gluck IV{
704236a3e93SAlexander von Gluck IV	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
705236a3e93SAlexander von Gluck IV		_PortRegister());
706236a3e93SAlexander von Gluck IV
70750f0b3feSAlexander von Gluck IV	// As this port overlaps with pretty much everything, this must be called
70850f0b3feSAlexander von Gluck IV	// after having ruled out all other port types.
70950f0b3feSAlexander von Gluck IV	return HasEDID();
71050f0b3feSAlexander von Gluck IV}
71150f0b3feSAlexander von Gluck IV
71250f0b3feSAlexander von Gluck IV
71327134c66SAlexander von Gluck IVaddr_t
71450f0b3feSAlexander von Gluck IVDigitalPort::_DDCRegister()
71550f0b3feSAlexander von Gluck IV{
716e747cbe1SAlexander von Gluck IV	//TODO: IS BROXTON, B = B, C = C, D = NIL
71750f0b3feSAlexander von Gluck IV	switch (PortIndex()) {
71850f0b3feSAlexander von Gluck IV		case INTEL_PORT_B:
71950f0b3feSAlexander von Gluck IV			return INTEL_I2C_IO_E;
72050f0b3feSAlexander von Gluck IV		case INTEL_PORT_C:
72150f0b3feSAlexander von Gluck IV			return INTEL_I2C_IO_D;
72250f0b3feSAlexander von Gluck IV		case INTEL_PORT_D:
72350f0b3feSAlexander von Gluck IV			return INTEL_I2C_IO_F;
72450f0b3feSAlexander von Gluck IV		default:
72550f0b3feSAlexander von Gluck IV			return 0;
72650f0b3feSAlexander von Gluck IV	}
72750f0b3feSAlexander von Gluck IV
72850f0b3feSAlexander von Gluck IV	return 0;
72950f0b3feSAlexander von Gluck IV}
73050f0b3feSAlexander von Gluck IV
73150f0b3feSAlexander von Gluck IV
73237b903fbSAlexander von Gluck IVaddr_t
73337b903fbSAlexander von Gluck IVDigitalPort::_PortRegister()
73437b903fbSAlexander von Gluck IV{
73592bcdd79SAlexander von Gluck IV	switch (PortIndex()) {
73692bcdd79SAlexander von Gluck IV		case INTEL_PORT_A:
73792bcdd79SAlexander von Gluck IV			return INTEL_DIGITAL_PORT_A;
73892bcdd79SAlexander von Gluck IV		case INTEL_PORT_B:
73992bcdd79SAlexander von Gluck IV			return INTEL_DIGITAL_PORT_B;
74092bcdd79SAlexander von Gluck IV		case INTEL_PORT_C:
74192bcdd79SAlexander von Gluck IV			return INTEL_DIGITAL_PORT_C;
74292bcdd79SAlexander von Gluck IV		default:
74392bcdd79SAlexander von Gluck IV			return 0;
74492bcdd79SAlexander von Gluck IV	}
74537b903fbSAlexander von Gluck IV	return 0;
74637b903fbSAlexander von Gluck IV}
74737b903fbSAlexander von Gluck IV
74837b903fbSAlexander von Gluck IV
74992bcdd79SAlexander von Gluck IVstatus_t
75092bcdd79SAlexander von Gluck IVDigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
75192bcdd79SAlexander von Gluck IV{
75292bcdd79SAlexander von Gluck IV	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
75392bcdd79SAlexander von Gluck IV		target->virtual_height);
75492bcdd79SAlexander von Gluck IV
755b01aed83SAlexander von Gluck IV	if (fPipe == NULL) {
75692bcdd79SAlexander von Gluck IV		ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
75792bcdd79SAlexander von Gluck IV		return B_ERROR;
75892bcdd79SAlexander von Gluck IV	}
75992bcdd79SAlexander von Gluck IV
760b1c582baSAdrien Destugues#if 0
761b1c582baSAdrien Destugues	// Disabled for now as our code doesn't work. Let's hope VESA/EFI has
762b1c582baSAdrien Destugues	// already set things up for us during boot.
76300e0982fSAlexander von Gluck IV	// Train FDI if it exists
764b01aed83SAlexander von Gluck IV	FDILink* link = fPipe->FDI();
765e6fefa6cSAlexander von Gluck IV	if (link != NULL)
766e6fefa6cSAlexander von Gluck IV		link->Train(target);
767b1c582baSAdrien Destugues#endif
76800e0982fSAlexander von Gluck IV
76992bcdd79SAlexander von Gluck IV	pll_divisors divisors;
77092bcdd79SAlexander von Gluck IV	compute_pll_divisors(target, &divisors, false);
77192bcdd79SAlexander von Gluck IV
77292bcdd79SAlexander von Gluck IV	uint32 extraPLLFlags = 0;
773af0dad47SAlexander von Gluck IV	if (gInfo->shared_info->device_type.Generation() >= 3)
77492bcdd79SAlexander von Gluck IV		extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
77592bcdd79SAlexander von Gluck IV
776c9c61669SAlexander von Gluck IV	// Program general pipe config
777c9c61669SAlexander von Gluck IV	fPipe->Configure(target);
778c9c61669SAlexander von Gluck IV
77992bcdd79SAlexander von Gluck IV	// Program pipe PLL's
780b979c66cSAlexander von Gluck IV	fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
78192bcdd79SAlexander von Gluck IV
78292bcdd79SAlexander von Gluck IV	// Program target display mode
783b979c66cSAlexander von Gluck IV	fPipe->ConfigureTimings(target);
78492bcdd79SAlexander von Gluck IV
78592bcdd79SAlexander von Gluck IV	// Set fCurrentMode to our set display mode
78639f61d21SAlexander von Gluck IV	memcpy(&fCurrentMode, target, sizeof(display_mode));
78792bcdd79SAlexander von Gluck IV
78892bcdd79SAlexander von Gluck IV	return B_OK;
78992bcdd79SAlexander von Gluck IV}
79092bcdd79SAlexander von Gluck IV
79192bcdd79SAlexander von Gluck IV
79292bcdd79SAlexander von Gluck IV// #pragma mark - LVDS Panel
79350f0b3feSAlexander von Gluck IV// #pragma mark - HDMI
79450f0b3feSAlexander von Gluck IV
79550f0b3feSAlexander von Gluck IV
79650f0b3feSAlexander von Gluck IVHDMIPort::HDMIPort(port_index index)
79750f0b3feSAlexander von Gluck IV	:
79850f0b3feSAlexander von Gluck IV	DigitalPort(index, "HDMI")
79950f0b3feSAlexander von Gluck IV{
80050f0b3feSAlexander von Gluck IV}
80150f0b3feSAlexander von Gluck IV
80250f0b3feSAlexander von Gluck IV
80350f0b3feSAlexander von Gluck IVbool
80450f0b3feSAlexander von Gluck IVHDMIPort::IsConnected()
80550f0b3feSAlexander von Gluck IV{
80650f0b3feSAlexander von Gluck IV	if (!gInfo->shared_info->device_type.SupportsHDMI())
80750f0b3feSAlexander von Gluck IV		return false;
80850f0b3feSAlexander von Gluck IV
80937b903fbSAlexander von Gluck IV	addr_t portRegister = _PortRegister();
8106e1ff82fSAlexander von Gluck IV	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
811bc5cad73SAlexander von Gluck IV		portRegister);
812bc5cad73SAlexander von Gluck IV
81350f0b3feSAlexander von Gluck IV	if (portRegister == 0)
81450f0b3feSAlexander von Gluck IV		return false;
81550f0b3feSAlexander von Gluck IV
81692e254d0SAlexander von Gluck IV	bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
81792e254d0SAlexander von Gluck IV	if (!hasPCH && PortIndex() == INTEL_PORT_C) {
81850f0b3feSAlexander von Gluck IV		// there's no detection bit on this port
81937b903fbSAlexander von Gluck IV	} else if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0)
82050f0b3feSAlexander von Gluck IV		return false;
82150f0b3feSAlexander von Gluck IV
82250f0b3feSAlexander von Gluck IV	return HasEDID();
82350f0b3feSAlexander von Gluck IV}
82450f0b3feSAlexander von Gluck IV
82550f0b3feSAlexander von Gluck IV
82637b903fbSAlexander von Gluck IVaddr_t
82750f0b3feSAlexander von Gluck IVHDMIPort::_PortRegister()
82850f0b3feSAlexander von Gluck IV{
82950f0b3feSAlexander von Gluck IV	// on PCH there's an additional port sandwiched in
83092e254d0SAlexander von Gluck IV	bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
831fb255821SAlexander von Gluck IV	bool fourthGen = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV);
83250f0b3feSAlexander von Gluck IV
83350f0b3feSAlexander von Gluck IV	switch (PortIndex()) {
83450f0b3feSAlexander von Gluck IV		case INTEL_PORT_B:
835bc5cad73SAlexander von Gluck IV			if (fourthGen)
836bc5cad73SAlexander von Gluck IV				return GEN4_HDMI_PORT_B;
83750f0b3feSAlexander von Gluck IV			return hasPCH ? PCH_HDMI_PORT_B : INTEL_HDMI_PORT_B;
83850f0b3feSAlexander von Gluck IV		case INTEL_PORT_C:
839bc5cad73SAlexander von Gluck IV			if (fourthGen)
840bc5cad73SAlexander von Gluck IV				return GEN4_HDMI_PORT_C;
84150f0b3feSAlexander von Gluck IV			return hasPCH ? PCH_HDMI_PORT_C : INTEL_HDMI_PORT_C;
84250f0b3feSAlexander von Gluck IV		case INTEL_PORT_D:
843fb255821SAlexander von Gluck IV			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
84484b7116dSAlexander von Gluck IV				return CHV_HDMI_PORT_D;
84550f0b3feSAlexander von Gluck IV			return hasPCH ? PCH_HDMI_PORT_D : 0;
84650f0b3feSAlexander von Gluck IV		default:
84750f0b3feSAlexander von Gluck IV			return 0;
848bc5cad73SAlexander von Gluck IV		}
84950f0b3feSAlexander von Gluck IV
85050f0b3feSAlexander von Gluck IV	return 0;
85150f0b3feSAlexander von Gluck IV}
85250f0b3feSAlexander von Gluck IV
85350f0b3feSAlexander von Gluck IV
85450f0b3feSAlexander von Gluck IV// #pragma mark - DisplayPort
85550f0b3feSAlexander von Gluck IV
85650f0b3feSAlexander von Gluck IV
85750f0b3feSAlexander von Gluck IVDisplayPort::DisplayPort(port_index index, const char* baseName)
85850f0b3feSAlexander von Gluck IV	:
859721ba9afSAlexander von Gluck IV	Port(index, baseName)
86050f0b3feSAlexander von Gluck IV{
86150f0b3feSAlexander von Gluck IV}
86250f0b3feSAlexander von Gluck IV
86350f0b3feSAlexander von Gluck IV
86450f0b3feSAlexander von Gluck IVbool
86550f0b3feSAlexander von Gluck IVDisplayPort::IsConnected()
86650f0b3feSAlexander von Gluck IV{
86737b903fbSAlexander von Gluck IV	addr_t portRegister = _PortRegister();
868236a3e93SAlexander von Gluck IV
869236a3e93SAlexander von Gluck IV	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
870236a3e93SAlexander von Gluck IV		portRegister);
871236a3e93SAlexander von Gluck IV
87250f0b3feSAlexander von Gluck IV	if (portRegister == 0)
87350f0b3feSAlexander von Gluck IV		return false;
87450f0b3feSAlexander von Gluck IV
875236a3e93SAlexander von Gluck IV	if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
876236a3e93SAlexander von Gluck IV		TRACE("%s: %s link not detected\n", __func__, PortName());
87750f0b3feSAlexander von Gluck IV		return false;
878236a3e93SAlexander von Gluck IV	}
87950f0b3feSAlexander von Gluck IV
88050f0b3feSAlexander von Gluck IV	return HasEDID();
88150f0b3feSAlexander von Gluck IV}
88250f0b3feSAlexander von Gluck IV
88350f0b3feSAlexander von Gluck IV
884721ba9afSAlexander von Gluck IVaddr_t
885721ba9afSAlexander von Gluck IVDisplayPort::_DDCRegister()
886721ba9afSAlexander von Gluck IV{
887721ba9afSAlexander von Gluck IV	// TODO: Do VLV + CHV use the VLV_DP_AUX_CTL_B + VLV_DP_AUX_CTL_C?
888721ba9afSAlexander von Gluck IV	switch (PortIndex()) {
889721ba9afSAlexander von Gluck IV		case INTEL_PORT_A:
890721ba9afSAlexander von Gluck IV			return INTEL_DP_AUX_CTL_A;
891721ba9afSAlexander von Gluck IV		case INTEL_PORT_B:
892721ba9afSAlexander von Gluck IV			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
893721ba9afSAlexander von Gluck IV				return VLV_DP_AUX_CTL_B;
894721ba9afSAlexander von Gluck IV			return INTEL_DP_AUX_CTL_B;
895721ba9afSAlexander von Gluck IV		case INTEL_PORT_C:
896721ba9afSAlexander von Gluck IV			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
897721ba9afSAlexander von Gluck IV				return VLV_DP_AUX_CTL_C;
898721ba9afSAlexander von Gluck IV			return INTEL_DP_AUX_CTL_C;
899721ba9afSAlexander von Gluck IV		case INTEL_PORT_D:
900721ba9afSAlexander von Gluck IV			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
901721ba9afSAlexander von Gluck IV				return CHV_DP_AUX_CTL_D;
902721ba9afSAlexander von Gluck IV			else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
903721ba9afSAlexander von Gluck IV				return 0;
904721ba9afSAlexander von Gluck IV			return INTEL_DP_AUX_CTL_D;
905721ba9afSAlexander von Gluck IV		default:
906721ba9afSAlexander von Gluck IV			return 0;
907721ba9afSAlexander von Gluck IV	}
908721ba9afSAlexander von Gluck IV
909721ba9afSAlexander von Gluck IV	return 0;
910721ba9afSAlexander von Gluck IV}
911721ba9afSAlexander von Gluck IV
912721ba9afSAlexander von Gluck IV
91337b903fbSAlexander von Gluck IVaddr_t
91450f0b3feSAlexander von Gluck IVDisplayPort::_PortRegister()
91550f0b3feSAlexander von Gluck IV{
916e5494f1bSAlexander von Gluck IV	// There are 6000 lines of intel linux code probing DP registers
917e5494f1bSAlexander von Gluck IV	// to properly detect DP vs eDP to then in-turn properly figure out
918e5494f1bSAlexander von Gluck IV	// what is DP and what is HDMI. It only takes 3 lines to
919e5494f1bSAlexander von Gluck IV	// ignore DisplayPort on ValleyView / CherryView
920e5494f1bSAlexander von Gluck IV
921e5494f1bSAlexander von Gluck IV	if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)
922721ba9afSAlexander von Gluck IV		|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
923721ba9afSAlexander von Gluck IV		ERROR("TODO: DisplayPort on ValleyView / CherryView");
924e5494f1bSAlexander von Gluck IV		return 0;
925721ba9afSAlexander von Gluck IV	}
926e5494f1bSAlexander von Gluck IV
927e5494f1bSAlexander von Gluck IV	// Intel, are humans even involved anymore?
928e5494f1bSAlexander von Gluck IV	// This is a lot more complex than this code makes it look. (see defines)
929e5494f1bSAlexander von Gluck IV	// INTEL_DISPLAY_PORT_X moves around a lot based on PCH
930e5494f1bSAlexander von Gluck IV	// except on ValleyView and CherryView.
93150f0b3feSAlexander von Gluck IV	switch (PortIndex()) {
93250f0b3feSAlexander von Gluck IV		case INTEL_PORT_A:
93350f0b3feSAlexander von Gluck IV			return INTEL_DISPLAY_PORT_A;
93450f0b3feSAlexander von Gluck IV		case INTEL_PORT_B:
935e5494f1bSAlexander von Gluck IV			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
936e5494f1bSAlexander von Gluck IV				return VLV_DISPLAY_PORT_B;
93750f0b3feSAlexander von Gluck IV			return INTEL_DISPLAY_PORT_B;
93850f0b3feSAlexander von Gluck IV		case INTEL_PORT_C:
939e5494f1bSAlexander von Gluck IV			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
940e5494f1bSAlexander von Gluck IV				return VLV_DISPLAY_PORT_C;
94150f0b3feSAlexander von Gluck IV			return INTEL_DISPLAY_PORT_C;
94250f0b3feSAlexander von Gluck IV		case INTEL_PORT_D:
943e5494f1bSAlexander von Gluck IV			if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
944e5494f1bSAlexander von Gluck IV				return CHV_DISPLAY_PORT_D;
945e5494f1bSAlexander von Gluck IV			else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
946e5494f1bSAlexander von Gluck IV				return 0;
94750f0b3feSAlexander von Gluck IV			return INTEL_DISPLAY_PORT_D;
94850f0b3feSAlexander von Gluck IV		default:
94950f0b3feSAlexander von Gluck IV			return 0;
95050f0b3feSAlexander von Gluck IV	}
95150f0b3feSAlexander von Gluck IV
95250f0b3feSAlexander von Gluck IV	return 0;
95350f0b3feSAlexander von Gluck IV}
95450f0b3feSAlexander von Gluck IV
95550f0b3feSAlexander von Gluck IV
956721ba9afSAlexander von Gluck IVstatus_t
957721ba9afSAlexander von Gluck IVDisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode)
958721ba9afSAlexander von Gluck IV{
959721ba9afSAlexander von Gluck IV	TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
960721ba9afSAlexander von Gluck IV		target->virtual_height);
961721ba9afSAlexander von Gluck IV
962721ba9afSAlexander von Gluck IV	ERROR("TODO: DisplayPort\n");
963721ba9afSAlexander von Gluck IV	return B_ERROR;
964721ba9afSAlexander von Gluck IV}
965721ba9afSAlexander von Gluck IV
966721ba9afSAlexander von Gluck IV
96750f0b3feSAlexander von Gluck IV// #pragma mark - Embedded DisplayPort
96850f0b3feSAlexander von Gluck IV
96950f0b3feSAlexander von Gluck IV
97050f0b3feSAlexander von Gluck IVEmbeddedDisplayPort::EmbeddedDisplayPort()
97150f0b3feSAlexander von Gluck IV	:
97250f0b3feSAlexander von Gluck IV	DisplayPort(INTEL_PORT_A, "Embedded DisplayPort")
97350f0b3feSAlexander von Gluck IV{
97450f0b3feSAlexander von Gluck IV}
97550f0b3feSAlexander von Gluck IV
97650f0b3feSAlexander von Gluck IV
97750f0b3feSAlexander von Gluck IVbool
97850f0b3feSAlexander von Gluck IVEmbeddedDisplayPort::IsConnected()
97950f0b3feSAlexander von Gluck IV{
9803d1bd895SAlexander von Gluck IV	addr_t portRegister = _PortRegister();
9813d1bd895SAlexander von Gluck IV
9823d1bd895SAlexander von Gluck IV	TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
9833d1bd895SAlexander von Gluck IV		portRegister);
9843d1bd895SAlexander von Gluck IV
9853d1bd895SAlexander von Gluck IV	if (!gInfo->shared_info->device_type.IsMobile()) {
9863d1bd895SAlexander von Gluck IV		TRACE("%s: skipping eDP on non-mobile GPU\n", __func__);
9873d1bd895SAlexander von Gluck IV		return false;
9883d1bd895SAlexander von Gluck IV	}
9893d1bd895SAlexander von Gluck IV
9903d1bd895SAlexander von Gluck IV	if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
9913d1bd895SAlexander von Gluck IV		TRACE("%s: %s link not detected\n", __func__, PortName());
99250f0b3feSAlexander von Gluck IV		return false;
9933d1bd895SAlexander von Gluck IV	}
9943d1bd895SAlexander von Gluck IV
9953d1bd895SAlexander von Gluck IV	HasEDID();
99650f0b3feSAlexander von Gluck IV
9973d1bd895SAlexander von Gluck IV	// If eDP has EDID, awesome. We use it.
9983d1bd895SAlexander von Gluck IV	// No EDID? The modesetting code falls back to VBIOS panel_mode
9993d1bd895SAlexander von Gluck IV	return true;