vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / intel_extreme / Ports.cpp
blob17d5159b6e8e10f440b4f227e839ce8d031f3ec3
1 /*
2 * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
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 */
12 #include "Ports.h"
14 #include <ddc.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <Debug.h>
18 #include <KernelExport.h>
20 #include "accelerant.h"
21 #include "accelerant_protos.h"
22 #include "FlexibleDisplayInterface.h"
23 #include "intel_extreme.h"
25 #include <new>
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
36 #define ERROR(x...) _sPrintf("intel_extreme: " x)
37 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
40 static bool
41 wait_for_set(addr_t address, uint32 mask, uint32 timeout)
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;
50 return false;
54 static bool
55 wait_for_clear(addr_t address, uint32 mask, uint32 timeout)
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;
64 return false;
68 Port::Port(port_index index, const char* baseName)
70 fPipe(NULL),
71 fEDIDState(B_NO_INIT),
72 fPortIndex(index),
73 fPortName(NULL)
75 char portID[2];
76 portID[0] = 'A' + index - INTEL_PORT_A;
77 portID[1] = 0;
79 char buffer[32];
80 buffer[0] = 0;
82 strlcat(buffer, baseName, sizeof(buffer));
83 strlcat(buffer, " ", sizeof(buffer));
84 strlcat(buffer, portID, sizeof(buffer));
85 fPortName = strdup(buffer);
89 Port::~Port()
91 free(fPortName);
95 bool
96 Port::HasEDID()
98 if (fEDIDState == B_NO_INIT)
99 GetEDID(NULL);
101 return fEDIDState == B_OK;
105 status_t
106 Port::SetPipe(Pipe* pipe)
108 CALLED();
110 if (pipe == NULL) {
111 ERROR("%s: Invalid pipe provided!\n", __func__);
112 return B_ERROR;
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;
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;
128 TRACE("%s: Assigning %s (0x%" B_PRIx32 ") to pipe %s\n", __func__,
129 PortName(), portRegister, (pipe->Index() == INTEL_PIPE_A) ? "A" : "B");
131 uint32 portState = read32(portRegister);
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);
146 fPipe = pipe;
148 if (fPipe == NULL)
149 return B_NO_MEMORY;
151 // Disable display pipe until modesetting enables it
152 if (fPipe->IsEnabled())
153 fPipe->Enable(false);
155 read32(portRegister);
157 return B_OK;
161 status_t
162 Port::Power(bool enabled)
164 fPipe->Enable(enabled);
166 return B_OK;
170 status_t
171 Port::GetEDID(edid1_info* edid, bool forceRead)
173 CALLED();
175 if (fEDIDState == B_NO_INIT || forceRead) {
176 TRACE("%s: trying to read EDID\n", PortName());
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;
185 TRACE("%s: using ddc @ 0x%" B_PRIxADDR "\n", PortName(), ddcRegister);
187 i2c_bus bus;
188 bus.cookie = (void*)ddcRegister;
189 bus.set_signals = &_SetI2CSignals;
190 bus.get_signals = &_GetI2CSignals;
191 ddc2_init_timing(&bus);
193 fEDIDState = ddc2_read_edid1(&bus, &fEDIDInfo, NULL, NULL);
195 if (fEDIDState == B_OK) {
196 TRACE("%s: found EDID information!\n", PortName());
197 edid_dump(&fEDIDInfo);
201 if (fEDIDState != B_OK) {
202 TRACE("%s: no EDID information found.\n", PortName());
203 return fEDIDState;
206 if (edid != NULL)
207 memcpy(edid, &fEDIDInfo, sizeof(edid1_info));
209 return B_OK;
213 status_t
214 Port::GetPLLLimits(pll_limits& limits)
216 return B_ERROR;
220 status_t
221 Port::_GetI2CSignals(void* cookie, int* _clock, int* _data)
223 addr_t ioRegister = (addr_t)cookie;
224 uint32 value = read32(ioRegister);
226 *_clock = (value & I2C_CLOCK_VALUE_IN) != 0;
227 *_data = (value & I2C_DATA_VALUE_IN) != 0;
229 return B_OK;
233 status_t
234 Port::_SetI2CSignals(void* cookie, int clock, int data)
236 addr_t ioRegister = (addr_t)cookie;
237 uint32 value;
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;
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;
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;
261 write32(ioRegister, value);
262 read32(ioRegister);
263 // make sure the PCI bus has flushed the write
265 return B_OK;
269 // #pragma mark - Analog Port
272 AnalogPort::AnalogPort()
274 Port(INTEL_PORT_A, "Analog")
279 bool
280 AnalogPort::IsConnected()
282 TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
283 _PortRegister());
284 return HasEDID();
288 addr_t
289 AnalogPort::_DDCRegister()
291 // always fixed
292 return INTEL_I2C_IO_A;
296 addr_t
297 AnalogPort::_PortRegister()
299 // always fixed
300 return INTEL_ANALOG_PORT;
304 status_t
305 AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode)
307 TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
308 target->virtual_height);
310 if (fPipe == NULL) {
311 ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
312 return B_ERROR;
315 // Train FDI if it exists
316 FDILink* link = fPipe->FDI();
317 if (link != NULL)
318 link->Train(target);
320 pll_divisors divisors;
321 compute_pll_divisors(target, &divisors, false);
323 uint32 extraPLLFlags = 0;
324 if (gInfo->shared_info->device_type.Generation() >= 3)
325 extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
327 // Program general pipe config
328 fPipe->Configure(target);
330 // Program pipe PLL's
331 fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
333 write32(_PortRegister(), (read32(_PortRegister())
334 & ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY))
335 | ((target->timing.flags & B_POSITIVE_HSYNC) != 0
336 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0)
337 | ((target->timing.flags & B_POSITIVE_VSYNC) != 0
338 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0));
340 // Program target display mode
341 fPipe->ConfigureTimings(target);
343 // Set fCurrentMode to our set display mode
344 memcpy(&fCurrentMode, target, sizeof(display_mode));
346 return B_OK;
350 // #pragma mark - LVDS Panel
353 LVDSPort::LVDSPort()
355 Port(INTEL_PORT_C, "LVDS")
357 // Always unlock LVDS port as soon as we start messing with it.
358 uint32 panelControl = INTEL_PANEL_CONTROL;
359 if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
360 // FIXME writing there results in black screen on SandyBridge
361 return;
362 // panelControl = PCH_PANEL_CONTROL;
364 write32(panelControl, read32(panelControl) | PANEL_REGISTER_UNLOCK);
368 pipe_index
369 LVDSPort::PipePreference()
371 // TODO: Technically INTEL_PIPE_B is only required on < gen 4
372 // otherwise we can use INTEL_PIPE_ANY, however it seems to break
373 // modesetting atm. (likely due to a bug on our end)
374 //if (gInfo->shared_info->device_type.Generation() < 4)
375 // return INTEL_PIPE_B;
377 return INTEL_PIPE_B;
381 bool
382 LVDSPort::IsConnected()
384 TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
385 _PortRegister());
387 if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
388 uint32 registerValue = read32(_PortRegister());
389 // there's a detection bit we can use
390 if ((registerValue & PCH_LVDS_DETECTED) == 0) {
391 TRACE("LVDS: Not detected\n");
392 return false;
394 // TODO: Skip if eDP support
395 } else if (gInfo->shared_info->device_type.Generation() <= 4) {
396 // Older generations don't have LVDS detection. If not mobile skip.
397 if (!gInfo->shared_info->device_type.IsMobile()) {
398 TRACE("LVDS: Skipping LVDS detection due to gen and not mobile\n");
399 return false;
401 // If mobile, try to grab EDID
402 // Linux seems to look at lid status for LVDS port detection
403 // If we don't get EDID, we can use vbios native mode or vesa?
404 if (!HasEDID()) {
405 #if 0
406 if (gInfo->shared_info->got_vbt) {
407 // TODO: Fake EDID from vbios native mode?
408 // I feel like this would be more accurate
409 } else if...
410 #endif
411 if (gInfo->shared_info->has_vesa_edid_info) {
412 TRACE("LVDS: Using VESA edid info\n");
413 memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info,
414 sizeof(edid1_info));
415 fEDIDState = B_OK;
416 // HasEDID now true
417 } else {
418 TRACE("LVDS: Couldn't find any valid EDID!\n");
419 return false;
424 // Try getting EDID, as the LVDS port doesn't overlap with anything else,
425 // we don't run the risk of getting someone else's data.
426 return HasEDID();
430 addr_t
431 LVDSPort::_DDCRegister()
433 // always fixed
434 return INTEL_I2C_IO_C;
438 addr_t
439 LVDSPort::_PortRegister()
441 // always fixed
442 return INTEL_DIGITAL_LVDS_PORT;
446 status_t
447 LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode)
449 CALLED();
450 if (target == NULL) {
451 ERROR("%s: Invalid target mode passed!\n", __func__);
452 return B_ERROR;
455 TRACE("%s: %s-%d %dx%d\n", __func__, PortName(), PortIndex(),
456 target->virtual_width, target->virtual_height);
458 if (fPipe == NULL) {
459 ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
460 return B_ERROR;
463 addr_t panelControl = INTEL_PANEL_CONTROL;
464 addr_t panelStatus = INTEL_PANEL_STATUS;
465 if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
466 panelControl = PCH_PANEL_CONTROL;
467 panelStatus = PCH_PANEL_STATUS;
470 // Power off Panel
471 write32(panelControl, read32(panelControl) & ~PANEL_CONTROL_POWER_TARGET_ON);
472 read32(panelControl);
474 if (!wait_for_clear(panelStatus, PANEL_STATUS_POWER_ON, 1000))
475 ERROR("%s: %s didn't power off within 1000ms!\n", __func__, PortName());
477 // Train FDI if it exists
478 FDILink* link = fPipe->FDI();
479 if (link != NULL)
480 link->Train(target);
482 #if 0
483 // Disable PanelFitter for now
484 addr_t panelFitterControl = PCH_PANEL_FITTER_BASE_REGISTER
485 + PCH_PANEL_FITTER_CONTROL;
486 if (fPipe->Index() == INTEL_PIPE_B)
487 panelFitterControl += PCH_PANEL_FITTER_PIPE_OFFSET;
488 write32(panelFitterControl, (read32(panelFitterControl) & ~PANEL_FITTER_ENABLED));
489 read32(panelFitterControl);
490 #endif
492 // For LVDS panels, we actually always set the native mode in hardware
493 // Then we use the panel fitter to scale the picture to that.
494 display_mode hardwareTarget;
495 bool needsScaling = false;
496 // Try to get the panel preferred screen mode from EDID info
498 if (gInfo->shared_info->got_vbt) {
499 // Set vbios hardware panel mode as base
500 memcpy(&hardwareTarget, &gInfo->shared_info->panel_mode,
501 sizeof(display_mode));
502 hardwareTarget.space = target->space;
504 if ((hardwareTarget.virtual_width <= target->virtual_width
505 && hardwareTarget.virtual_height <= target->virtual_height
506 && hardwareTarget.space <= target->space)
507 || intel_propose_display_mode(&hardwareTarget, target, target)) {
508 hardwareTarget = *target;
509 } else
510 needsScaling = true;
512 TRACE("%s: hardware mode will actually be %dx%d (%s)\n", __func__,
513 hardwareTarget.virtual_width, hardwareTarget.virtual_height,
514 needsScaling ? "scaled" : "unscaled");
515 } else {
516 // We don't have EDID data, try to set the requested mode directly
517 hardwareTarget = *target;
520 pll_divisors divisors;
521 if (needsScaling)
522 compute_pll_divisors(&hardwareTarget, &divisors, true);
523 else
524 compute_pll_divisors(target, &divisors, true);
526 uint32 lvds = read32(_PortRegister())
527 | LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
529 if (gInfo->shared_info->device_type.Generation() == 4) {
530 // LVDS_A3_POWER_UP == 24bpp
531 // otherwise, 18bpp
532 if ((lvds & LVDS_A3_POWER_MASK) != LVDS_A3_POWER_UP)
533 lvds |= LVDS_18BIT_DITHER;
536 // LVDS on PCH needs set before display enable
537 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) {
538 lvds &= PORT_TRANS_SEL_MASK;
539 if (fPipe->Index() == INTEL_PIPE_A)
540 lvds |= PORT_TRANS_A_SEL_CPT;
541 else
542 lvds |= PORT_TRANS_B_SEL_CPT;
545 // Set the B0-B3 data pairs corresponding to whether we're going to
546 // set the DPLLs for dual-channel mode or not.
547 if (divisors.p2 == 5 || divisors.p2 == 7) {
548 TRACE("LVDS: dual channel\n");
549 lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
550 } else {
551 TRACE("LVDS: single channel\n");
552 lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
555 // LVDS port control moves polarity bits because Intel hates you.
556 // Set LVDS sync polarity
557 lvds &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
559 // set on - polarity.
560 if ((target->timing.flags & B_POSITIVE_HSYNC) == 0)
561 lvds |= LVDS_HSYNC_POLARITY;
562 if ((target->timing.flags & B_POSITIVE_VSYNC) == 0)
563 lvds |= LVDS_VSYNC_POLARITY;
565 TRACE("%s: LVDS Write: 0x%" B_PRIx32 "\n", __func__, lvds);
566 write32(_PortRegister(), lvds);
567 read32(_PortRegister());
569 uint32 extraPLLFlags = 0;
571 // DPLL mode LVDS for i915+
572 if (gInfo->shared_info->device_type.Generation() >= 3)
573 extraPLLFlags |= DISPLAY_PLL_MODE_LVDS;
575 // Program general pipe config
576 fPipe->Configure(target);
578 // Program pipe PLL's (pixel_clock is *always* the hardware pixel clock)
579 fPipe->ConfigureClocks(divisors, hardwareTarget.timing.pixel_clock,
580 extraPLLFlags);
582 // Disable panel fitting, but enable 8 to 6-bit dithering
583 write32(INTEL_PANEL_FIT_CONTROL, 0x4);
584 // TODO: do not do this if the connected panel is 24-bit
585 // (I don't know how to detect that)
587 // Power on Panel
588 write32(panelControl, read32(panelControl) | PANEL_CONTROL_POWER_TARGET_ON);
589 read32(panelControl);
591 if (!wait_for_set(panelStatus, PANEL_STATUS_POWER_ON, 1000))
592 ERROR("%s: %s didn't power on within 1000ms!\n", __func__, PortName());
594 // Program target display mode
595 fPipe->ConfigureTimings(target);
597 #if 0
598 // update timing parameters
599 if (needsScaling) {
600 // TODO: Alternatively, it should be possible to use the panel
601 // fitter and scale the picture.
603 // TODO: Perform some sanity check, for example if the target is
604 // wider than the hardware mode we end up with negative borders and
605 // broken timings
606 uint32 borderWidth = hardwareTarget.timing.h_display
607 - target->timing.h_display;
609 uint32 syncWidth = hardwareTarget.timing.h_sync_end
610 - hardwareTarget.timing.h_sync_start;
612 uint32 syncCenter = target->timing.h_display
613 + (hardwareTarget.timing.h_total
614 - target->timing.h_display) / 2;
616 write32(INTEL_DISPLAY_B_HTOTAL,
617 ((uint32)(hardwareTarget.timing.h_total - 1) << 16)
618 | ((uint32)target->timing.h_display - 1));
619 write32(INTEL_DISPLAY_B_HBLANK,
620 ((uint32)(hardwareTarget.timing.h_total - borderWidth / 2 - 1)
621 << 16)
622 | ((uint32)target->timing.h_display + borderWidth / 2 - 1));
623 write32(INTEL_DISPLAY_B_HSYNC,
624 ((uint32)(syncCenter + syncWidth / 2 - 1) << 16)
625 | ((uint32)syncCenter - syncWidth / 2 - 1));
627 uint32 borderHeight = hardwareTarget.timing.v_display
628 - target->timing.v_display;
630 uint32 syncHeight = hardwareTarget.timing.v_sync_end
631 - hardwareTarget.timing.v_sync_start;
633 syncCenter = target->timing.v_display
634 + (hardwareTarget.timing.v_total
635 - target->timing.v_display) / 2;
637 write32(INTEL_DISPLAY_B_VTOTAL,
638 ((uint32)(hardwareTarget.timing.v_total - 1) << 16)
639 | ((uint32)target->timing.v_display - 1));
640 write32(INTEL_DISPLAY_B_VBLANK,
641 ((uint32)(hardwareTarget.timing.v_total - borderHeight / 2 - 1)
642 << 16)
643 | ((uint32)target->timing.v_display
644 + borderHeight / 2 - 1));
645 write32(INTEL_DISPLAY_B_VSYNC,
646 ((uint32)(syncCenter + syncHeight / 2 - 1) << 16)
647 | ((uint32)syncCenter - syncHeight / 2 - 1));
649 // This is useful for debugging: it sets the border to red, so you
650 // can see what is border and what is porch (black area around the
651 // sync)
652 // write32(0x61020, 0x00FF0000);
653 } else {
654 write32(INTEL_DISPLAY_B_HTOTAL,
655 ((uint32)(target->timing.h_total - 1) << 16)
656 | ((uint32)target->timing.h_display - 1));
657 write32(INTEL_DISPLAY_B_HBLANK,
658 ((uint32)(target->timing.h_total - 1) << 16)
659 | ((uint32)target->timing.h_display - 1));
660 write32(INTEL_DISPLAY_B_HSYNC,
661 ((uint32)(target->timing.h_sync_end - 1) << 16)
662 | ((uint32)target->timing.h_sync_start - 1));
664 write32(INTEL_DISPLAY_B_VTOTAL,
665 ((uint32)(target->timing.v_total - 1) << 16)
666 | ((uint32)target->timing.v_display - 1));
667 write32(INTEL_DISPLAY_B_VBLANK,
668 ((uint32)(target->timing.v_total - 1) << 16)
669 | ((uint32)target->timing.v_display - 1));
670 write32(INTEL_DISPLAY_B_VSYNC, (
671 (uint32)(target->timing.v_sync_end - 1) << 16)
672 | ((uint32)target->timing.v_sync_start - 1));
674 #endif
676 // Set fCurrentMode to our set display mode
677 memcpy(&fCurrentMode, target, sizeof(display_mode));
679 return B_OK;
683 // #pragma mark - DVI/SDVO/generic
686 DigitalPort::DigitalPort(port_index index, const char* baseName)
688 Port(index, baseName)
693 bool
694 DigitalPort::IsConnected()
696 TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
697 _PortRegister());
699 // As this port overlaps with pretty much everything, this must be called
700 // after having ruled out all other port types.
701 return HasEDID();
705 addr_t
706 DigitalPort::_DDCRegister()
708 //TODO: IS BROXTON, B = B, C = C, D = NIL
709 switch (PortIndex()) {
710 case INTEL_PORT_B:
711 return INTEL_I2C_IO_E;
712 case INTEL_PORT_C:
713 return INTEL_I2C_IO_D;
714 case INTEL_PORT_D:
715 return INTEL_I2C_IO_F;
716 default:
717 return 0;
720 return 0;
724 addr_t
725 DigitalPort::_PortRegister()
727 switch (PortIndex()) {
728 case INTEL_PORT_A:
729 return INTEL_DIGITAL_PORT_A;
730 case INTEL_PORT_B:
731 return INTEL_DIGITAL_PORT_B;
732 case INTEL_PORT_C:
733 return INTEL_DIGITAL_PORT_C;
734 default:
735 return 0;
737 return 0;
741 status_t
742 DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode)
744 TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
745 target->virtual_height);
747 if (fPipe == NULL) {
748 ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
749 return B_ERROR;
752 // Train FDI if it exists
753 FDILink* link = fPipe->FDI();
754 if (link != NULL)
755 link->Train(target);
757 pll_divisors divisors;
758 compute_pll_divisors(target, &divisors, false);
760 uint32 extraPLLFlags = 0;
761 if (gInfo->shared_info->device_type.Generation() >= 3)
762 extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
764 // Program general pipe config
765 fPipe->Configure(target);
767 // Program pipe PLL's
768 fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
770 // Program target display mode
771 fPipe->ConfigureTimings(target);
773 // Set fCurrentMode to our set display mode
774 memcpy(&fCurrentMode, target, sizeof(display_mode));
776 return B_OK;
780 // #pragma mark - LVDS Panel
781 // #pragma mark - HDMI
784 HDMIPort::HDMIPort(port_index index)
786 DigitalPort(index, "HDMI")
791 bool
792 HDMIPort::IsConnected()
794 if (!gInfo->shared_info->device_type.SupportsHDMI())
795 return false;
797 addr_t portRegister = _PortRegister();
798 TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
799 portRegister);
801 if (portRegister == 0)
802 return false;
804 bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
805 if (!hasPCH && PortIndex() == INTEL_PORT_C) {
806 // there's no detection bit on this port
807 } else if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0)
808 return false;
810 return HasEDID();
814 addr_t
815 HDMIPort::_PortRegister()
817 // on PCH there's an additional port sandwiched in
818 bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
819 bool fourthGen = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV);
821 switch (PortIndex()) {
822 case INTEL_PORT_B:
823 if (fourthGen)
824 return GEN4_HDMI_PORT_B;
825 return hasPCH ? PCH_HDMI_PORT_B : INTEL_HDMI_PORT_B;
826 case INTEL_PORT_C:
827 if (fourthGen)
828 return GEN4_HDMI_PORT_C;
829 return hasPCH ? PCH_HDMI_PORT_C : INTEL_HDMI_PORT_C;
830 case INTEL_PORT_D:
831 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
832 return CHV_HDMI_PORT_D;
833 return hasPCH ? PCH_HDMI_PORT_D : 0;
834 default:
835 return 0;
838 return 0;
842 // #pragma mark - DisplayPort
845 DisplayPort::DisplayPort(port_index index, const char* baseName)
847 Port(index, baseName)
852 bool
853 DisplayPort::IsConnected()
855 addr_t portRegister = _PortRegister();
857 TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
858 portRegister);
860 if (portRegister == 0)
861 return false;
863 if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
864 TRACE("%s: %s link not detected\n", __func__, PortName());
865 return false;
868 return HasEDID();
872 addr_t
873 DisplayPort::_DDCRegister()
875 // TODO: Do VLV + CHV use the VLV_DP_AUX_CTL_B + VLV_DP_AUX_CTL_C?
876 switch (PortIndex()) {
877 case INTEL_PORT_A:
878 return INTEL_DP_AUX_CTL_A;
879 case INTEL_PORT_B:
880 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
881 return VLV_DP_AUX_CTL_B;
882 return INTEL_DP_AUX_CTL_B;
883 case INTEL_PORT_C:
884 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
885 return VLV_DP_AUX_CTL_C;
886 return INTEL_DP_AUX_CTL_C;
887 case INTEL_PORT_D:
888 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
889 return CHV_DP_AUX_CTL_D;
890 else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
891 return 0;
892 return INTEL_DP_AUX_CTL_D;
893 default:
894 return 0;
897 return 0;
901 addr_t
902 DisplayPort::_PortRegister()
904 // There are 6000 lines of intel linux code probing DP registers
905 // to properly detect DP vs eDP to then in-turn properly figure out
906 // what is DP and what is HDMI. It only takes 3 lines to
907 // ignore DisplayPort on ValleyView / CherryView
909 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)
910 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
911 ERROR("TODO: DisplayPort on ValleyView / CherryView");
912 return 0;
915 // Intel, are humans even involved anymore?
916 // This is a lot more complex than this code makes it look. (see defines)
917 // INTEL_DISPLAY_PORT_X moves around a lot based on PCH
918 // except on ValleyView and CherryView.
919 switch (PortIndex()) {
920 case INTEL_PORT_A:
921 return INTEL_DISPLAY_PORT_A;
922 case INTEL_PORT_B:
923 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
924 return VLV_DISPLAY_PORT_B;
925 return INTEL_DISPLAY_PORT_B;
926 case INTEL_PORT_C:
927 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
928 return VLV_DISPLAY_PORT_C;
929 return INTEL_DISPLAY_PORT_C;
930 case INTEL_PORT_D:
931 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV))
932 return CHV_DISPLAY_PORT_D;
933 else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV))
934 return 0;
935 return INTEL_DISPLAY_PORT_D;
936 default:
937 return 0;
940 return 0;
944 status_t
945 DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode)
947 TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
948 target->virtual_height);
950 ERROR("TODO: DisplayPort\n");
951 return B_ERROR;
955 // #pragma mark - Embedded DisplayPort
958 EmbeddedDisplayPort::EmbeddedDisplayPort()
960 DisplayPort(INTEL_PORT_A, "Embedded DisplayPort")
965 bool
966 EmbeddedDisplayPort::IsConnected()
968 addr_t portRegister = _PortRegister();
970 TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
971 portRegister);
973 if (!gInfo->shared_info->device_type.IsMobile()) {
974 TRACE("%s: skipping eDP on non-mobile GPU\n", __func__);
975 return false;
978 if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) {
979 TRACE("%s: %s link not detected\n", __func__, PortName());
980 return false;
983 HasEDID();
985 // If eDP has EDID, awesome. We use it.
986 // No EDID? The modesetting code falls back to VBIOS panel_mode
987 return true;
991 // #pragma mark - Digital Display Port
994 DigitalDisplayInterface::DigitalDisplayInterface(port_index index,
995 const char* baseName)
997 Port(index, baseName)
999 // As of Haswell, Intel decided to change eDP ports to a "DDI" bus...
1000 // on a dare because the hardware engineers were drunk one night.
1004 addr_t
1005 DigitalDisplayInterface::_PortRegister()
1007 // TODO: Linux does a DDI_BUF_CTL(INTEL_PORT_A) which is cleaner
1008 // (but we have to ensure the offsets + region base is correct)
1009 switch (PortIndex()) {
1010 case INTEL_PORT_A:
1011 return DDI_BUF_CTL_A;
1012 case INTEL_PORT_B:
1013 return DDI_BUF_CTL_B;
1014 case INTEL_PORT_C:
1015 return DDI_BUF_CTL_C;
1016 case INTEL_PORT_D:
1017 return DDI_BUF_CTL_D;
1018 case INTEL_PORT_E:
1019 return DDI_BUF_CTL_E;
1020 default:
1021 return 0;
1023 return 0;
1027 addr_t
1028 DigitalDisplayInterface::_DDCRegister()
1030 // TODO: No idea, does DDI have DDC?
1031 return 0;
1035 status_t
1036 DigitalDisplayInterface::Power(bool enabled)
1038 TRACE("%s: %s DDI enabled: %s\n", __func__, PortName(),
1039 enabled ? "true" : "false");
1041 fPipe->Enable(enabled);
1043 addr_t portRegister = _PortRegister();
1044 uint32 state = read32(portRegister);
1045 write32(portRegister,
1046 enabled ? (state | DDI_BUF_CTL_ENABLE) : (state & ~DDI_BUF_CTL_ENABLE));
1047 read32(portRegister);
1049 return B_OK;
1053 bool
1054 DigitalDisplayInterface::IsConnected()
1056 addr_t portRegister = _PortRegister();
1058 TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(),
1059 portRegister);
1061 if (portRegister == 0)
1062 return false;
1064 if ((read32(portRegister) & DDI_INIT_DISPLAY_DETECTED) == 0) {
1065 TRACE("%s: %s link not detected\n", __func__, PortName());
1066 return false;
1069 // Probe a little port info.
1070 if ((read32(DDI_BUF_CTL_A) & DDI_A_4_LANES) != 0) {
1071 switch (PortIndex()) {
1072 case INTEL_PORT_A:
1073 fMaxLanes = 4;
1074 break;
1075 case INTEL_PORT_E:
1076 fMaxLanes = 0;
1077 break;
1078 default:
1079 fMaxLanes = 4;
1080 break;
1082 } else {
1083 switch (PortIndex()) {
1084 case INTEL_PORT_A:
1085 fMaxLanes = 2;
1086 break;
1087 case INTEL_PORT_E:
1088 fMaxLanes = 2;
1089 break;
1090 default:
1091 fMaxLanes = 4;
1092 break;
1096 TRACE("%s: %s Maximum Lanes: %" B_PRId8 "\n", __func__,
1097 PortName(), fMaxLanes);
1099 HasEDID();
1101 return true;
1105 status_t
1106 DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
1108 TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width,
1109 target->virtual_height);
1111 if (fPipe == NULL) {
1112 ERROR("%s: Setting display mode without assigned pipe!\n", __func__);
1113 return B_ERROR;
1116 // Train FDI if it exists
1117 FDILink* link = fPipe->FDI();
1118 if (link != NULL)
1119 link->Train(target);
1121 pll_divisors divisors;
1122 compute_pll_divisors(target, &divisors, false);
1124 uint32 extraPLLFlags = 0;
1125 if (gInfo->shared_info->device_type.Generation() >= 3)
1126 extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL;
1128 // Program general pipe config
1129 fPipe->Configure(target);
1131 // Program pipe PLL's
1132 fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags);
1134 // Program target display mode
1135 fPipe->ConfigureTimings(target);
1137 // Set fCurrentMode to our set display mode
1138 memcpy(&fCurrentMode, target, sizeof(display_mode));
1140 return B_OK;