From ca95e9dad99c0af8c1d385a90b0f5d9e80a24a85 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Tue, 15 Mar 2016 18:12:28 -0500 Subject: [PATCH] intel_extreme: Add initial work for DDI ports --- .../graphics/intel_extreme/intel_extreme.h | 18 ++++ .../accelerants/intel_extreme/Ports.cpp | 97 +++++++++++++++++++ src/add-ons/accelerants/intel_extreme/Ports.h | 21 ++++ .../accelerants/intel_extreme/accelerant.cpp | 39 ++++++-- 4 files changed, 165 insertions(+), 10 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index b7203807ad..fe4b9b20ef 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -162,6 +162,12 @@ struct DeviceType { return InFamily(INTEL_FAMILY_SER5); } + bool HasDDI() const + { + // Intel Digital Display Interface + return InGroup(INTEL_GROUP_HAS) || (Generation() >= 8); + } + int Generation() const { if (InFamily(INTEL_FAMILY_7xx)) @@ -542,6 +548,18 @@ struct intel_free_graphics_memory { #define GEN4_HDMI_PORT_C (0x1160 | REGS_SOUTH_TRANSCODER_PORT) #define CHV_HDMI_PORT_D (0x116C | REGS_SOUTH_TRANSCODER_PORT) +// DDI Buffer Control (This replaces DP on Haswell+) +#define DDI_BUF_CTL_A (0x4000 | REGS_NORTH_PIPE_AND_PORT) +#define DDI_BUF_CTL_B (0x4100 | REGS_NORTH_PIPE_AND_PORT) +#define DDI_BUF_CTL_ENABLE (1 << 31) +#define DDI_BUF_TRANS_SELECT(n) ((n) << 24) +#define DDI_BUF_EMP_MASK (0xf << 24) +#define DDI_BUF_PORT_REVERSAL (1 << 16) +#define DDI_BUF_IS_IDLE (1 << 7) +#define DDI_A_4_LANES (1 << 4) +#define DDI_PORT_WIDTH(width) (((width) - 1) << 1) +#define DDI_INIT_DISPLAY_DETECTED (1 << 0) + // DP_A always @ 6xxxx, DP_B-DP_D move with PCH #define INTEL_DISPLAY_PORT_A (0x4000 | REGS_NORTH_PIPE_AND_PORT) #define INTEL_DISPLAY_PORT_B (0x4100 | REGS_SOUTH_TRANSCODER_PORT) diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index c52a7c4888..961a799f56 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -984,3 +984,100 @@ EmbeddedDisplayPort::IsConnected() // No EDID? The modesetting code falls back to VBIOS panel_mode return true; } + + +// #pragma mark - Digital Display Port + + +DigitalDisplayInterface::DigitalDisplayInterface(port_index index, + const char* baseName) + : + Port(index, baseName) +{ + // As of Haswell, Intel decided to change eDP ports to a "DDI" bus... + // on a dare because the hardware engineers were drunk one night. +} + + +addr_t +DigitalDisplayInterface::_PortRegister() +{ + switch (PortIndex()) { + case INTEL_PORT_A: + return DDI_BUF_CTL_A; + case INTEL_PORT_B: + return DDI_BUF_CTL_B; + default: + return 0; + } + return 0; +} + + +addr_t +DigitalDisplayInterface::_DDCRegister() +{ + // TODO: No idea, does DDI have DDC? + return 0; +} + + +bool +DigitalDisplayInterface::IsConnected() +{ + addr_t portRegister = _PortRegister(); + + TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(), + portRegister); + + if (portRegister == 0) + return false; + + if ((read32(portRegister) & DDI_INIT_DISPLAY_DETECTED) == 0) { + TRACE("%s: %s link not detected\n", __func__, PortName()); + return false; + } + + HasEDID(); + + return true; +} + + +status_t +DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) +{ + TRACE("%s: %s %dx%d\n", __func__, PortName(), target->virtual_width, + target->virtual_height); + + if (fPipe == NULL) { + ERROR("%s: Setting display mode without assigned pipe!\n", __func__); + return B_ERROR; + } + + // Train FDI if it exists + FDILink* link = fPipe->FDI(); + if (link != NULL) + link->Train(target); + + pll_divisors divisors; + compute_pll_divisors(target, &divisors, false); + + uint32 extraPLLFlags = 0; + if (gInfo->shared_info->device_type.Generation() >= 3) + extraPLLFlags |= DISPLAY_PLL_MODE_NORMAL; + + // Program general pipe config + fPipe->Configure(target); + + // Program pipe PLL's + fPipe->ConfigureClocks(divisors, target->timing.pixel_clock, extraPLLFlags); + + // Program target display mode + fPipe->ConfigureTimings(target); + + // Set fCurrentMode to our set display mode + memcpy(&fCurrentMode, target, sizeof(display_mode)); + + return B_OK; +} diff --git a/src/add-ons/accelerants/intel_extreme/Ports.h b/src/add-ons/accelerants/intel_extreme/Ports.h index e837a07930..db43b98cb4 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.h +++ b/src/add-ons/accelerants/intel_extreme/Ports.h @@ -199,4 +199,25 @@ virtual uint32 Type() const virtual bool IsConnected(); }; + +class DigitalDisplayInterface : public Port { +public: + DigitalDisplayInterface( + port_index index = INTEL_PORT_A, + const char* baseName = "Digital Display Interface"); + +virtual uint32 Type() const + { return INTEL_PORT_TYPE_DVI; } + +virtual bool IsConnected(); + +virtual status_t SetDisplayMode(display_mode* mode, + uint32 colorMode); + +protected: +virtual addr_t _DDCRegister(); +virtual addr_t _PortRegister(); +}; + + #endif // INTEL_PORTS_H diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index 0ee5c8572b..d2dcf44d82 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -306,9 +306,37 @@ probe_ports() delete displayPort; } + // Digital Display Interface + if (gInfo->shared_info->device_type.HasDDI()) { + for (int i = INTEL_PORT_A; i <= INTEL_PORT_B; i++) { + Port* ddiPort + = new(std::nothrow) DigitalDisplayInterface((port_index)i); + + if (ddiPort == NULL) + return B_NO_MEMORY; + + if (ddiPort->IsConnected()) + gInfo->ports[gInfo->port_count++] = ddiPort; + else + delete ddiPort; + } + } + + // Ensure DP_A isn't already taken (or DDI) + if (!has_connected_port((port_index)INTEL_PORT_A, INTEL_PORT_TYPE_ANY)) { + // also always try eDP, it'll also just fail if not applicable + Port* eDPPort = new(std::nothrow) EmbeddedDisplayPort(); + if (eDPPort == NULL) + return B_NO_MEMORY; + if (eDPPort->IsConnected()) + gInfo->ports[gInfo->port_count++] = eDPPort; + else + delete eDPPort; + } + for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) { if (has_connected_port((port_index)i, INTEL_PORT_TYPE_ANY)) { - // we overlap with a DisplayPort, this is not HDMI + // Ensure port not already claimed by something like DDI continue; } @@ -346,15 +374,6 @@ probe_ports() } else delete lvdsPort; - // also always try eDP, it'll also just fail if not applicable - Port* eDPPort = new(std::nothrow) EmbeddedDisplayPort(); - if (eDPPort == NULL) - return B_NO_MEMORY; - if (eDPPort->IsConnected()) - gInfo->ports[gInfo->port_count++] = eDPPort; - else - delete eDPPort; - // then finally always try the analog port Port* analogPort = new(std::nothrow) AnalogPort(); if (analogPort == NULL)