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