diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 7145aebf4e..ed7a26a8f9 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -134,6 +134,24 @@ struct DeviceType { return (type & INTEL_TYPE_MODEL_MASK) == model; } + bool IsMobile() const + { + return (type & INTEL_TYPE_MODEL_MASK) == INTEL_TYPE_MOBILE; + } + + bool SupportsHDMI() const + { + switch (type & INTEL_TYPE_GROUP_MASK) { + case INTEL_TYPE_G4x: + case INTEL_TYPE_ILK: + case INTEL_TYPE_SNB: + case INTEL_TYPE_IVBG: + case INTEL_TYPE_VLV: + return true; + } + return false; + } + bool HasPlatformControlHub() const { return InGroup(INTEL_TYPE_ILK) || InGroup(INTEL_TYPE_SNB) @@ -439,19 +457,37 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_A_IMAGE_SIZE (0x001c | REGS_NORTH_PIPE_AND_PORT) #define INTEL_DISPLAY_B_IMAGE_SIZE (0x101c | REGS_NORTH_PIPE_AND_PORT) -#define INTEL_DISPLAY_A_ANALOG_PORT (0x1100 | REGS_SOUTH_TRANSCODER_PORT) -#define INTEL_DISPLAY_A_DIGITAL_PORT (0x1120 | REGS_SOUTH_TRANSCODER_PORT) -#define INTEL_DISPLAY_B_DIGITAL_PORT (0x1140 | REGS_SOUTH_TRANSCODER_PORT) -#define INTEL_DISPLAY_C_DIGITAL (0x1160 | REGS_SOUTH_TRANSCODER_PORT) -#define INTEL_DISPLAY_LVDS_PORT (0x1180 | REGS_SOUTH_TRANSCODER_PORT) +#define INTEL_ANALOG_PORT (0x1100 | REGS_SOUTH_TRANSCODER_PORT) +#define INTEL_DIGITAL_PORT_A (0x1120 | REGS_SOUTH_TRANSCODER_PORT) +#define INTEL_DIGITAL_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT) +#define INTEL_DIGITAL_PORT_C (0x1160 | REGS_SOUTH_TRANSCODER_PORT) +#define INTEL_DIGITAL_LVDS_PORT (0x1180 | REGS_SOUTH_TRANSCODER_PORT) + +#define INTEL_HDMI_PORT_B (0x1140 | REGS_NORTH_PIPE_AND_PORT) +#define INTEL_HDMI_PORT_C (0x1160 | REGS_NORTH_PIPE_AND_PORT) + +#define PCH_HDMI_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT) +#define PCH_HDMI_PORT_C (0x1150 | REGS_SOUTH_TRANSCODER_PORT) +#define PCH_HDMI_PORT_D (0x1160 | REGS_SOUTH_TRANSCODER_PORT) + +#define INTEL_DISPLAY_PORT_A (0x4000 | REGS_NORTH_PIPE_AND_PORT) +#define INTEL_DISPLAY_PORT_B (0x4100 | REGS_NORTH_PIPE_AND_PORT) +#define INTEL_DISPLAY_PORT_C (0x4200 | REGS_NORTH_PIPE_AND_PORT) +#define INTEL_DISPLAY_PORT_D (0x4300 | REGS_NORTH_PIPE_AND_PORT) + +// valid for both DVI/HDMI and DisplayPort +#define PORT_DETECTED (1 << 2) // planes -#define INTEL_DISPLAY_A_PIPE_CONTROL (0x0008 | REGS_NORTH_PLANE_CONTROL) +#define INTEL_PIPE_ENABLED (1UL << 31) +#define INTEL_PIPE_CONTROL 0x08 +#define INTEL_PIPE_STATUS 0x24 +#define INTEL_PIPE_OFFSET 0x1000 +#define INTEL_DISPLAY_A_PIPE_CONTROL (0x0008 | REGS_NORTH_PLANE_CONTROL) #define INTEL_DISPLAY_B_PIPE_CONTROL (0x1008 | REGS_NORTH_PLANE_CONTROL) -#define DISPLAY_PIPE_ENABLED (1UL << 31) - #define INTEL_DISPLAY_A_PIPE_STATUS (0x0024 | REGS_NORTH_PLANE_CONTROL) #define INTEL_DISPLAY_B_PIPE_STATUS (0x1024 | REGS_NORTH_PLANE_CONTROL) + #define DISPLAY_PIPE_VBLANK_ENABLED (1UL << 17) #define DISPLAY_PIPE_VBLANK_STATUS (1UL << 1) @@ -594,6 +630,43 @@ struct intel_free_graphics_memory { #define INTEL_OVERLAY_GAMMA_1 0x30020 #define INTEL_OVERLAY_GAMMA_0 0x30024 +// FDI - Flexible Display Interface, the interface between the (CPU-internal) +// GPU and the PCH display outputs. Proprietary interface, based on DisplayPort +// though, so similar link training and all... +// There's an FDI transmitter (TX) on the CPU and an FDI receiver (RX) on the +// PCH for each display pipe. +// FDI receiver A is hooked up to transcoder A, FDI receiver B is hooked up to +// transcoder B, so we have the same mapping as with the display pipes. +#define PCH_FDI_RX_BASE_REGISTER 0xf0000 +#define PCH_FDI_RX_PIPE_OFFSET 0x01000 + +#define PCH_FDI_RX_CONTROL 0x0c +#define FDI_RX_CLOCK_MASK (1 << 4) +#define FDI_RX_CLOCK_RAW (0 << 4) +#define FDI_RX_CLOCK_PCD (1 << 4) + +#define PCH_FDI_RX_TRANS_UNIT_SIZE_1 0x30 +#define PCH_FDI_RX_TRANS_UNIT_SIZE_2 0x38 +#define FDI_RX_TRANS_UNIT_SIZE(x) ((x - 1) << 25) +#define FDI_RX_TRANS_UNIT_MASK 0x7e000000 + // Transfer unit size 1 is the primary and fixed transfer unit size, + // TU size 2 is the lower power state transfer unit size when using dynamic + // refresh rates (we don't do that though). + +// CPU Panel Fitters - These are for IronLake and up and are the CPU internal +// panel fitters. +#define PCH_PANEL_FITTER_BASE_REGISTER 0x68000 +#define PCH_PANEL_FITTER_PIPE_OFFSET 0x00800 + +#define PCH_PANEL_FITTER_WINDOW_POS 0x70 +#define PCH_PANEL_FITTER_WINDOW_SIZE 0x74 +#define PCH_PANEL_FITTER_CONTROL 0x80 +#define PCH_PANEL_FITTER_V_SCALE 0x84 +#define PCH_PANEL_FITTER_H_SCALE 0x90 + +#define PANEL_FITTER_ENABLED (1 << 31) +#define PANEL_FITTER_FILTER_MASK (3 << 23) + struct overlay_scale { uint32 _reserved0 : 3; uint32 horizontal_scale_fraction : 12; diff --git a/src/add-ons/accelerants/intel_extreme/DisplayPipe.cpp b/src/add-ons/accelerants/intel_extreme/DisplayPipe.cpp new file mode 100644 index 0000000000..8b237b8a24 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/DisplayPipe.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ + + +#include "DisplayPipe.h" + +#include "accelerant.h" +#include "intel_extreme.h" + +#include +#include + + +#define TRACE_PIPE +#ifdef TRACE_PIPE +extern "C" void _sPrintf(const char* format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +// #pragma mark - DisplayPipe + + +DisplayPipe::DisplayPipe(int32 pipeIndex) + : + fFDILink(NULL), + fPanelFitter(NULL), + fBaseRegister(INTEL_PIPE_BASE_REGISTER + pipeIndex * INTEL_PIPE_PIPE_OFFSET) +{ +} + + +bool +DisplayPipe::IsEnabled() +{ + return (read32(fBaseRegister + INTEL_PIPE_CONTROL) & PIPE_ENABLED) != 0; +} + + +void +DisplayPipe::Enable(const display_mode& mode) +{ + _Enable(true); +} + + +void +DisplayPipe::Disable() +{ + _Enable(false); +} + + +void +DisplayPipe::ConfigureTimings(const pll_divisors& divisors) +{ + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { + write32(INTEL_DISPLAY_A_PLL_DIVISOR_0, + (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT) + & DISPLAY_PLL_IGD_N_DIVISOR_MASK) + | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) + & DISPLAY_PLL_IGD_M2_DIVISOR_MASK)); + } else { + write32(INTEL_DISPLAY_A_PLL_DIVISOR_0, + (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) + & DISPLAY_PLL_N_DIVISOR_MASK) + | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) + & DISPLAY_PLL_M1_DIVISOR_MASK) + | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) + & DISPLAY_PLL_M2_DIVISOR_MASK)); + } + + uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL; + if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) { + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { + pll |= ((1 << (divisors.post1 - 1)) + << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT) + & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK; + } else { + pll |= ((1 << (divisors.post1 - 1)) + << DISPLAY_PLL_POST1_DIVISOR_SHIFT) + & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; +// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) +// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; + } + if (divisors.post2_high) + pll |= DISPLAY_PLL_DIVIDE_HIGH; + + pll |= DISPLAY_PLL_MODE_ANALOG; + + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) + pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT; + } else { + if (!divisors.post2_high) + pll |= DISPLAY_PLL_DIVIDE_4X; + + pll |= DISPLAY_PLL_2X_CLOCK; + + if (divisors.post1 > 2) { + pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) + & DISPLAY_PLL_POST1_DIVISOR_MASK; + } else + pll |= DISPLAY_PLL_POST1_DIVIDE_2; + } + + write32(INTEL_DISPLAY_A_PLL, pll); + read32(INTEL_DISPLAY_A_PLL); + spin(150); + write32(INTEL_DISPLAY_A_PLL, pll); + read32(INTEL_DISPLAY_A_PLL); + spin(150); + + // update timing parameters + write32(INTEL_DISPLAY_A_HTOTAL, + ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_A_HBLANK, + ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_A_HSYNC, + ((uint32)(target.timing.h_sync_end - 1) << 16) + | ((uint32)target.timing.h_sync_start - 1)); + + write32(INTEL_DISPLAY_A_VTOTAL, + ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_A_VBLANK, + ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_A_VSYNC, + ((uint32)(target.timing.v_sync_end - 1) << 16) + | ((uint32)target.timing.v_sync_start - 1)); + + write32(INTEL_DISPLAY_A_IMAGE_SIZE, + ((uint32)(target.virtual_width - 1) << 16) + | ((uint32)target.virtual_height - 1)); + + write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT) + & ~(DISPLAY_MONITOR_POLARITY_MASK + | DISPLAY_MONITOR_VGA_POLARITY)) + | ((target.timing.flags & B_POSITIVE_HSYNC) != 0 + ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0) + | ((target.timing.flags & B_POSITIVE_VSYNC) != 0 + ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0)); + + // TODO: verify the two comments below: the X driver doesn't seem to + // care about both of them! + + // These two have to be set for display B, too - this obviously means + // that the second head always must adopt the color space of the first + // head. + write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL) + & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) + | colorMode); + + if ((gInfo->head_mode & HEAD_MODE_B_DIGITAL) != 0) { + write32(INTEL_DISPLAY_B_IMAGE_SIZE, + ((uint32)(target.virtual_width - 1) << 16) + | ((uint32)target.virtual_height - 1)); + + write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL) + & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) + | colorMode); + } + +} + + +void +DisplayPipe::_Enable(bool enable) +{ + uint32 targetRegister = fBaseRegister + INTEL_PIPE_CONTROL; + write32(targetRegister, read32(targetRegister) & ~PIPE_ENABLED + | (enable ? PIPE_ENABLED | 0)); + read32(targetRegister); +} diff --git a/src/add-ons/accelerants/intel_extreme/DisplayPipe.h b/src/add-ons/accelerants/intel_extreme/DisplayPipe.h new file mode 100644 index 0000000000..7273288c49 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/DisplayPipe.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ +#ifndef INTEL_PIPE_H +#define INTEL_PIPE_H + + +class FDILink; +class PanelFitter; + +struct pll_divisors; + +class DisplayPipe { +public: + DisplayPipe(int32 pipeIndex); +virtual ~DisplayPipe(); + + bool IsEnabled(); + void Enable(const display_mode& mode); + void Disable(); + + void ConfigureTimings( + const pll_divisors& divisors); + + // access to the various parts of the pipe + ::FDILink* FDILink() + { return fFDILink; } + ::PanelFitter* PanelFitter() + { return fPanelFitter; } + +private: + void _Enable(bool enable); + + FDILink* fFDILink; + PanelFitter* fPanelFitter; + + uint32 fRegisterBase; +}; + +#endif // INTEL_PIPE_H diff --git a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp new file mode 100644 index 0000000000..d8e56a802e --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp @@ -0,0 +1,138 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ + + +#include "FlexibleDisplayInterface.h" + +#include "accelerant.h" +#include "intel_extreme.h" + +#include +#include + + +#define TRACE_FDI +#ifdef TRACE_FDI +extern "C" void _sPrintf(const char* format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +// #pragma mark - FDITransmitter + + +FDITransmitter::FDITransmitter(int32 pipeIndex) + : + fBaseRegister(PCH_FDI_TX_BASE_REGISTER + pipeIndex * PCH_FDI_TX_PIPE_OFFSET) +{ +} + + +bool +FDITransmitter::IsPLLEnabled() +{ + return (read32(fBaseRegister + PCH_FDI_TX_CONTROL) & PCH_FDI_TX_PLL_ENABLED) + != 0; +} + + +void +FDITransmitter::EnablePLL() +{ + uint32 targetRegister = fBaseRegister + PCH_FDI_TX_CONTROL; + uint32 value = read32(targetRegister); + if ((value & PCH_FDI_TX_PLL_ENABLED) != 0) { + // already enabled, possibly IronLake where it always is + return; + } + + write32(targetRegister, value | PCH_FDI_TX_PLL_ENABLED); + read32(targetRegister); + spin(100); // warmup 10us + dmi delay 20us, be generous +} + + +void +FDITransmitter::DisablePLL() +{ + if (gInfo->shared_info->device_type.IsGroup(INTEL_TYPE_ILK)) { + // on IronLake the FDI PLL is alaways enabled, so no point in trying... + return; + } + + uint32 targetRegister = fBaseRegister + PCH_FDI_TX_CONTROL; + write32(targetRegister, read32(targetRegister) & ~PCH_FDI_TX_PLL_ENABLED); + read32(targetRegister); + spin(100); +} + + +// #pragma mark - FDIReceiver + + +FDIReceiver::FDIReceiver(int32 pipeIndex) + : + fBaseRegister(PCH_FDI_RX_BASE_REGISTER + pipeIndex * PCH_FDI_RX_PIPE_OFFSET) +{ +} + + +bool +FDIReceiver::IsPLLEnabled() +{ + return (read32(fBaseRegister + PCH_FDI_RX_CONTROL) & PCH_FDI_RX_PLL_ENABLED) + != 0; +} + + +void +FDIReceiver::EnablePLL() +{ + uint32 targetRegister = fBaseRegister + PCH_FDI_RX_CONTROL; + uint32 value = read32(targetRegister); + if ((value & PCH_FDI_RX_PLL_ENABLED) != 0) + return; + + write32(targetRegister, value | PCH_FDI_RX_PLL_ENABLED); + read32(targetRegister); + spin(200); // warmup 10us + dmi delay 20us, be generous +} + + +void +FDIReceiver::DisablePLL() +{ + uint32 targetRegister = fBaseRegister + PCH_FDI_RX_CONTROL; + write32(targetRegister, read32(targetRegister) & ~PCH_FDI_RX_PLL_ENABLED); + read32(targetRegister); + spin(100); +} + + +void +FDIReceiver::SwtichClock(bool toPCDClock) +{ + uint32 targetRegister = fBaseRegister + PCH_FDI_RX_CONTROL; + write32(targetRegister, (read32(targetRegister) & ~PCH_FDI_RX_CLOCK_MASK) + | (toPCDClock ? PCH_FDI_RX_CLOCK_PCD : PCH_FDI_RX_CLOCK_RAW)); + read32(targetRegister); + spin(200); +} + + +// #pragma mark - FDILink + + +FDILink::FDILink(int32 pipeIndex) + : + fTransmitter(pipeIndex), + fReceiver(pipeIndex) +{ +} diff --git a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h new file mode 100644 index 0000000000..baa6767ec9 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h @@ -0,0 +1,53 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ +#ifndef INTEL_FDI_H +#define INTEL_FDI_H + + +class FDITransmitter { +public: + FDITransmitter(int32 pipeIndex); +virtual ~FDITransmitter(); + + bool IsPLLEnabled(); + void EnablePLL(); + void DisablePLL(); + +private: + uint32 fRegisterBase; +}; + + +class FDIReceiver { +public: + FDIReceiver(int32 pipeIndex); + + bool IsPLLEnabled(); + void EnablePLL(); + void DisablePLL(); + + void SwitchClock(bool toPCDClock); + +protected: + uint32 fRegisterBase; +}; + + +class FDILink { +public: + FDILink(int32 pipeIndex); + + FDITransmitter& Transmitter(); + FDIReceiver& Receiver(); + +private: + FDITransmitter fTransmitter; + FDIReceiver fReceiver; +}; + +#endif // INTEL_FDI_H diff --git a/src/add-ons/accelerants/intel_extreme/Jamfile b/src/add-ons/accelerants/intel_extreme/Jamfile index 3ffe818a56..701d2881fc 100644 --- a/src/add-ons/accelerants/intel_extreme/Jamfile +++ b/src/add-ons/accelerants/intel_extreme/Jamfile @@ -16,5 +16,10 @@ Addon intel_extreme.accelerant : mode.cpp overlay.cpp # overlay_3d_i965.cpp - : be libaccelerantscommon.a + # classes +# DisplayPipe.cpp +# FlexibleDisplayInterface.cpp +# PanelFitter.cpp + Ports.cpp + : be $(TARGET_LIBSTDC++) libaccelerantscommon.a ; diff --git a/src/add-ons/accelerants/intel_extreme/PanelFitter.cpp b/src/add-ons/accelerants/intel_extreme/PanelFitter.cpp new file mode 100644 index 0000000000..b52c835664 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/PanelFitter.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ + + +#include "PanelFitter.h" + +#include "accelerant.h" +#include "intel_extreme.h" + +#include +#include + + +#define TRACE_FITTER +#ifdef TRACE_FITTER +extern "C" void _sPrintf(const char* format, ...); +# define TRACE(x) _sPrintf x +#else +# define TRACE(x) ; +#endif + + +// #pragma mark - PanelFitter + + +PanelFitter::PanelFitter(int32 pipeIndex) + : + fBaseRegister(PCH_PANEL_FITTER_BASE_REGISTER + + pipeIndex * PCH_PANEL_FITTER_PIPE_OFFSET) +{ +} + + +bool +PanelFitter::IsEnabled() +{ + return (read32(fBaseRegister + PCH_PANEL_FITTER_CONTROL) + & PANEL_FITTER_ENABLED) != 0; +} + + +void +PanelFitter::Enable(const display_mode& mode) +{ + // TODO: program the right window size and position based on the mode + _Enable(true); +} + + +void +PanelFitter::Disable() +{ + _Enable(false); +} + + +void +PanelFitter::_Enable(bool enable) +{ + uint32 targetRegister = fBaseRegister + PCH_PANEL_FITTER_CONTROL; + write32(targetRegister, read32(targetRegister) & ~PANEL_FITTER_ENABLED + | (enable ? PANEL_FITTER_ENABLED | 0)); + read32(targetRegister); +} diff --git a/src/add-ons/accelerants/intel_extreme/PanelFitter.h b/src/add-ons/accelerants/intel_extreme/PanelFitter.h new file mode 100644 index 0000000000..7648ad7074 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/PanelFitter.h @@ -0,0 +1,27 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ +#ifndef INTEL_FITTER_H +#define INTEL_FITTER_H + + +class PanelFitter { +public: + PanelFitter(int32 pipeIndex); +virtual ~PanelFitter(); + + bool IsEnabled(); + void Enable(const display_mode& mode); + void Disable(); + +private: + void _Enable(bool enable); + + uint32 fRegisterBase; +}; + +#endif // INTEL_FITTER_H diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp new file mode 100644 index 0000000000..1e84aed113 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -0,0 +1,378 @@ +/* + * Copyright 2006-2015, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * Michael Lotz, mmlr@mlotz.ch + * Alexander von Gluck IV, kallisti5@unixzen.com + */ + + +#include "Ports.h" + +#include +#include + +#include +#include + +#include "accelerant.h" +#include "intel_extreme.h" + + +#undef TRACE +#define TRACE_PORTS +#ifdef TRACE_PORTS +# define TRACE(x...) _sPrintf("intel_extreme:" x) +#else +# define TRACE(x...) +#endif + +#define ERROR(x...) _sPrintf("intel_extreme: " x) +#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) + + +Port::Port(port_index index, const char* baseName) + : + fPortIndex(index), + fPortName(NULL), + fEDIDState(B_NO_INIT) +{ + char portID[2]; + portID[0] = 'A' + index - INTEL_PORT_A; + portID[1] = 0; + + char buffer[32]; + buffer[0] = 0; + + strlcat(buffer, baseName, sizeof(buffer)); + strlcat(buffer, " ", sizeof(buffer)); + strlcat(buffer, portID, sizeof(buffer)); + fPortName = strdup(buffer); +} + + +Port::~Port() +{ + free(fPortName); +} + + +bool +Port::HasEDID() +{ + if (fEDIDState == B_NO_INIT) + GetEDID(NULL); + + return fEDIDState == B_OK; +} + + +status_t +Port::GetEDID(edid1_info* edid, bool forceRead) +{ + CALLED(); + + if (fEDIDState == B_NO_INIT || forceRead) { + TRACE("%s: trying to read EDID\n", PortName()); + + addr_t ddcRegister = _DDCRegister(); + if (ddcRegister == 0) { + fEDIDState = B_ERROR; + return fEDIDState; + } + + TRACE("%s: using register %" B_PRIx32 "\n", PortName(), ddcRegister); + + i2c_bus bus; + bus.cookie = (void*)ddcRegister; + bus.set_signals = &_SetI2CSignals; + bus.get_signals = &_GetI2CSignals; + ddc2_init_timing(&bus); + + fEDIDState = ddc2_read_edid1(&bus, &fEDIDInfo, NULL, NULL); + + if (fEDIDState == B_OK) { + TRACE("%s: found EDID information!\n", PortName()); + edid_dump(&fEDIDInfo); + } + } + + if (fEDIDState != B_OK) { + TRACE("%s: no EDID information found.\n", PortName()); + return fEDIDState; + } + + if (edid != NULL) + memcpy(edid, &fEDIDInfo, sizeof(edid1_info)); + + return B_OK; +} + + +status_t +Port::GetPLLLimits(pll_limits& limits) +{ + return B_ERROR; +} + + +status_t +Port::_GetI2CSignals(void* cookie, int* _clock, int* _data) +{ + addr_t ioRegister = (addr_t)cookie; + uint32 value = read32(ioRegister); + + *_clock = (value & I2C_CLOCK_VALUE_IN) != 0; + *_data = (value & I2C_DATA_VALUE_IN) != 0; + + return B_OK; +} + + +status_t +Port::_SetI2CSignals(void* cookie, int clock, int data) +{ + addr_t ioRegister = (addr_t)cookie; + uint32 value; + + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_83x)) { + // on these chips, the reserved values are fixed + value = 0; + } else { + // on all others, we have to preserve them manually + value = read32(ioRegister) & I2C_RESERVED; + } + + if (data != 0) + value |= I2C_DATA_DIRECTION_MASK; + else { + value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT + | I2C_DATA_VALUE_MASK; + } + + if (clock != 0) + value |= I2C_CLOCK_DIRECTION_MASK; + else { + value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT + | I2C_CLOCK_VALUE_MASK; + } + + write32(ioRegister, value); + read32(ioRegister); + // make sure the PCI bus has flushed the write + + return B_OK; +} + + +// #pragma mark - Analog Port + + +AnalogPort::AnalogPort() + : + Port(INTEL_PORT_A, "Analog") +{ +} + + +bool +AnalogPort::IsConnected() +{ + return HasEDID(); +} + + +uint32 +AnalogPort::_DDCRegister() +{ + // always fixed + return INTEL_I2C_IO_A; +} + + +// #pragma mark - LVDS Panel + + +LVDSPort::LVDSPort() + : + Port(INTEL_PORT_C, "LVDS") +{ +} + + +bool +LVDSPort::IsConnected() +{ + uint32 registerValue = read32(INTEL_DIGITAL_LVDS_PORT); + if (gInfo->shared_info->device_type.HasPlatformControlHub()) { + // there's a detection bit we can use + if ((registerValue & PCH_LVDS_DETECTED) == 0) + return false; + } + + // Try getting EDID, as the LVDS port doesn't overlap with anything else, + // we don't run the risk of getting someone else's data. + return HasEDID(); +} + + +uint32 +LVDSPort::_DDCRegister() +{ + // always fixed + return INTEL_I2C_IO_C; +} + + +// #pragma mark - DVI/SDVO/generic + + +DigitalPort::DigitalPort(port_index index, const char* baseName) + : + Port(index, baseName) +{ +} + + +bool +DigitalPort::IsConnected() +{ + // As this port overlaps with pretty much everything, this must be called + // after having ruled out all other port types. + return HasEDID(); +} + + +uint32 +DigitalPort::_DDCRegister() +{ + switch (PortIndex()) { + case INTEL_PORT_B: + return INTEL_I2C_IO_E; + case INTEL_PORT_C: + return INTEL_I2C_IO_D; + case INTEL_PORT_D: + return INTEL_I2C_IO_F; + default: + return 0; + } + + return 0; +} + + +// #pragma mark - HDMI + + +HDMIPort::HDMIPort(port_index index) + : + DigitalPort(index, "HDMI") +{ +} + + +bool +HDMIPort::IsConnected() +{ + if (!gInfo->shared_info->device_type.SupportsHDMI()) + return false; + + uint32 portRegister = _PortRegister(); + if (portRegister == 0) + return false; + + if (!gInfo->shared_info->device_type.HasPlatformControlHub() + && PortIndex() == INTEL_PORT_C) { + // there's no detection bit on this port + } else if ((read32(portRegister) & PORT_DETECTED) == 0) + return false; + + return HasEDID(); +} + + +uint32 +HDMIPort::_PortRegister() +{ + // on PCH there's an additional port sandwiched in + bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub(); + + switch (PortIndex()) { + case INTEL_PORT_B: + return hasPCH ? PCH_HDMI_PORT_B : INTEL_HDMI_PORT_B; + case INTEL_PORT_C: + return hasPCH ? PCH_HDMI_PORT_C : INTEL_HDMI_PORT_C; + case INTEL_PORT_D: + return hasPCH ? PCH_HDMI_PORT_D : 0; + default: + return 0; + } + + return 0; +} + + +// #pragma mark - DisplayPort + + +DisplayPort::DisplayPort(port_index index, const char* baseName) + : + DigitalPort(index, baseName) +{ +} + + +bool +DisplayPort::IsConnected() +{ + uint32 portRegister = _PortRegister(); + if (portRegister == 0) + return false; + + if ((read32(portRegister) & PORT_DETECTED) == 0) + return false; + + return HasEDID(); +} + + +uint32 +DisplayPort::_PortRegister() +{ + switch (PortIndex()) { + case INTEL_PORT_A: + return INTEL_DISPLAY_PORT_A; + case INTEL_PORT_B: + return INTEL_DISPLAY_PORT_B; + case INTEL_PORT_C: + return INTEL_DISPLAY_PORT_C; + case INTEL_PORT_D: + return INTEL_DISPLAY_PORT_D; + default: + return 0; + } + + return 0; +} + + +// #pragma mark - Embedded DisplayPort + + +EmbeddedDisplayPort::EmbeddedDisplayPort() + : + DisplayPort(INTEL_PORT_A, "Embedded DisplayPort") +{ +} + + +bool +EmbeddedDisplayPort::IsConnected() +{ + if (!gInfo->shared_info->device_type.IsMobile()) + return false; + + return DisplayPort::IsConnected(); +} diff --git a/src/add-ons/accelerants/intel_extreme/Ports.h b/src/add-ons/accelerants/intel_extreme/Ports.h new file mode 100644 index 0000000000..41cb757415 --- /dev/null +++ b/src/add-ons/accelerants/intel_extreme/Ports.h @@ -0,0 +1,160 @@ +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ +#ifndef INTEL_PORTS_H +#define INTEL_PORTS_H + +#include + + +#define MAX_PORTS 20 // a generous upper bound + +struct pll_limits; + +enum port_type { + INTEL_PORT_TYPE_ANY, // wildcard for lookup functions + INTEL_PORT_TYPE_ANALOG, + INTEL_PORT_TYPE_DVI, + INTEL_PORT_TYPE_LVDS, + INTEL_PORT_TYPE_DP, + INTEL_PORT_TYPE_eDP, + INTEL_PORT_TYPE_HDMI +}; + +enum port_index { + INTEL_PORT_ANY, // wildcard for lookup functions + INTEL_PORT_A, + INTEL_PORT_B, + INTEL_PORT_C, + INTEL_PORT_D +}; + + +class Port { +public: + Port(port_index index, + const char* baseName); +virtual ~Port(); + +virtual uint32 Type() const = 0; + const char* PortName() const + { return fPortName; } + + port_index PortIndex() const + { return fPortIndex; } + +virtual bool IsConnected() = 0; + + bool HasEDID(); +virtual status_t GetEDID(edid1_info* edid, + bool forceRead = false); + +virtual status_t GetPLLLimits(pll_limits& limits); + +protected: + void _SetName(const char* name); + +static status_t _GetI2CSignals(void* cookie, int* _clock, + int* _data); +static status_t _SetI2CSignals(void* cookie, int clock, + int data); + +private: +virtual uint32 _DDCRegister() = 0; + + port_index fPortIndex; + char* fPortName; + + status_t fEDIDState; + edid1_info fEDIDInfo; +}; + + +class AnalogPort : public Port { +public: + AnalogPort(); + +virtual uint32 Type() const + { return INTEL_PORT_TYPE_ANALOG; } + +virtual bool IsConnected(); + +protected: +virtual uint32 _DDCRegister(); +}; + + +class LVDSPort : public Port { +public: + LVDSPort(); + +virtual uint32 Type() const + { return INTEL_PORT_TYPE_LVDS; } + +virtual bool IsConnected(); + +protected: +virtual uint32 _DDCRegister(); +}; + + +class DigitalPort : public Port { +public: + DigitalPort( + port_index index = INTEL_PORT_B, + const char* baseName = "DVI"); + +virtual uint32 Type() const + { return INTEL_PORT_TYPE_DVI; } + +virtual bool IsConnected(); + +protected: +virtual uint32 _DDCRegister(); +}; + + +class HDMIPort : public DigitalPort { +public: + HDMIPort(port_index index); + +virtual uint32 Type() const + { return INTEL_PORT_TYPE_HDMI; } + +virtual bool IsConnected(); + +protected: + uint32 _PortRegister(); +}; + + +class DisplayPort : public DigitalPort { +public: + DisplayPort(port_index index, + const char* baseName = "DisplayPort"); + +virtual uint32 Type() const + { return INTEL_PORT_TYPE_DP; } + +virtual bool IsConnected(); + +protected: + uint32 _PortRegister(); +}; + + +class EmbeddedDisplayPort : public DisplayPort { +public: + EmbeddedDisplayPort(); + +virtual uint32 Type() const + { return INTEL_PORT_TYPE_eDP; } + +virtual bool IsConnected(); +}; + +#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 903fbd28e0..f71392bdad 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -19,18 +19,20 @@ #include #include +#include + #include #undef TRACE #define TRACE_ACCELERANT #ifdef TRACE_ACCELERANT -# define TRACE(x...) _sPrintf("intel_extreme accelerant:" x) +# define TRACE(x...) _sPrintf("intel_extreme:" x) #else # define TRACE(x...) #endif -#define ERROR(x...) _sPrintf("intel_extreme accelerant: " x) +#define ERROR(x...) _sPrintf("intel_extreme: " x) #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) @@ -179,6 +181,23 @@ uninit_common(void) } +static bool +has_connected_port(port_index portIndex, uint32 type) +{ + for (uint32 i = 0; i < gInfo->port_count; i++) { + Port* port = gInfo->ports[i]; + if (type != INTEL_PORT_TYPE_ANY && port->Type() != type) + continue; + if (portIndex != INTEL_PORT_ANY && port->PortIndex() != portIndex) + continue; + + return true; + } + + return false; +} + + // #pragma mark - public accelerant functions @@ -199,36 +218,91 @@ intel_init_accelerant(int device) setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); - // determine head depending on what's already enabled from the BIOS - // TODO: it would be nicer to retrieve this data via DDC - else the - // display is gone for good if the BIOS decides to only show the - // picture on the connected analog monitor! - gInfo->head_mode = 0; - if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) - gInfo->head_mode |= HEAD_MODE_B_DIGITAL; - if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) - gInfo->head_mode |= HEAD_MODE_A_ANALOG; + TRACE("pipe control for: 0x%" B_PRIx32 " 0x%" B_PRIx32 "\n", + read32(INTEL_PIPE_CONTROL), read32(INTEL_PIPE_CONTROL)); - uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT); + // Try to determine what ports to use. We use the following heuristic: + // * Check for DisplayPort, these can be more or less detected reliably. + // * Check for HDMI, it'll fail on devices not having HDMI for us to fall + // back to DVI. + // * Assume DVI B if no HDMI and no DisplayPort is present, confirmed by + // reading EDID in the IsConnected() call. + // * Check for analog if possible (there's a detection bit on PCH), + // otherwise the assumed presence is confirmed by reading EDID in + // IsConnected(). - // If we have an enabled display pipe we save the passed information and - // assume it is the valid panel size.. - // Later we query for proper EDID info if it exists, or figure something - // else out. (Default modes, etc.) - bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub(); - if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0) - || (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) { - save_lvds_mode(); - gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; + gInfo->port_count = 0; + for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) { + Port* displayPort = new(std::nothrow) DisplayPort((port_index)i); + if (displayPort == NULL) + return B_NO_MEMORY; + + if (displayPort->IsConnected()) + gInfo->ports[gInfo->port_count++] = displayPort; + else + delete displayPort; } - TRACE("head detected: %#x\n", gInfo->head_mode); - TRACE("adpa: %08" B_PRIx32 ", dova: %08" B_PRIx32 ", dovb: %08" B_PRIx32 - ", lvds: %08" B_PRIx32 "\n", - read32(INTEL_DISPLAY_A_ANALOG_PORT), - read32(INTEL_DISPLAY_A_DIGITAL_PORT), - read32(INTEL_DISPLAY_B_DIGITAL_PORT), - read32(INTEL_DISPLAY_LVDS_PORT)); + 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 + continue; + } + + Port* hdmiPort = new(std::nothrow) HDMIPort((port_index)i); + if (hdmiPort == NULL) + return B_NO_MEMORY; + + if (hdmiPort->IsConnected()) + gInfo->ports[gInfo->port_count++] = hdmiPort; + else + delete hdmiPort; + } + + if (!has_connected_port(INTEL_PORT_ANY, INTEL_PORT_TYPE_ANY)) { + // there's neither DisplayPort nor HDMI so far, assume DVI B + Port* dviPort = new(std::nothrow) DigitalPort(INTEL_PORT_B); + if (dviPort == NULL) + return B_NO_MEMORY; + + if (dviPort->IsConnected()) { + gInfo->ports[gInfo->port_count++] = dviPort; + gInfo->head_mode |= HEAD_MODE_B_DIGITAL; + } else + delete dviPort; + } + + // always try the LVDS port, it'll simply fail if not applicable + Port* lvdsPort = new(std::nothrow) LVDSPort(); + if (lvdsPort == NULL) + return B_NO_MEMORY; + if (lvdsPort->IsConnected()) { + gInfo->ports[gInfo->port_count++] = lvdsPort; + gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; + gInfo->head_mode |= HEAD_MODE_A_ANALOG; + } 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) + return B_NO_MEMORY; + if (analogPort->IsConnected()) { + gInfo->ports[gInfo->port_count++] = analogPort; + gInfo->head_mode |= HEAD_MODE_A_ANALOG; + } else + delete analogPort; + + TRACE("connected ports detected: %" B_PRIu32 "\n", gInfo->port_count); status = create_mode_list(); if (status != B_OK) { diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.h b/src/add-ons/accelerants/intel_extreme/accelerant.h index df5e274859..e8f958e27c 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.h +++ b/src/add-ons/accelerants/intel_extreme/accelerant.h @@ -14,6 +14,8 @@ #include #include +#include "Ports.h" + struct overlay { overlay_buffer buffer; @@ -48,6 +50,9 @@ struct accelerant_info { uint32 last_vertical_overlay_scale; uint32 overlay_position_buffer_offset; + uint32 port_count; + Port* ports[MAX_PORTS]; + edid1_info edid_info; bool has_edid; @@ -64,10 +69,12 @@ struct accelerant_info { display_mode lvds_panel_mode; }; -#define HEAD_MODE_A_ANALOG 0x01 -#define HEAD_MODE_B_DIGITAL 0x02 -#define HEAD_MODE_CLONE 0x03 -#define HEAD_MODE_LVDS_PANEL 0x08 +#define HEAD_MODE_A_ANALOG 0x0001 +#define HEAD_MODE_B_DIGITAL 0x0002 +#define HEAD_MODE_CLONE 0x0003 +#define HEAD_MODE_LVDS_PANEL 0x0008 +#define HEAD_MODE_TESTING 0x1000 +#define HEAD_MODE_STIPPI 0x2000 extern accelerant_info* gInfo; diff --git a/src/add-ons/accelerants/intel_extreme/dpms.cpp b/src/add-ons/accelerants/intel_extreme/dpms.cpp index 6d8dc4496f..a6d1c6957c 100644 --- a/src/add-ons/accelerants/intel_extreme/dpms.cpp +++ b/src/add-ons/accelerants/intel_extreme/dpms.cpp @@ -71,22 +71,22 @@ enable_display_pipe(bool enable) if (enable) { if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { write32(INTEL_DISPLAY_A_PIPE_CONTROL, - pipeAControl | DISPLAY_PIPE_ENABLED); + pipeAControl | INTEL_PIPE_ENABLED); } if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { write32(INTEL_DISPLAY_B_PIPE_CONTROL, - pipeBControl | DISPLAY_PIPE_ENABLED); + pipeBControl | INTEL_PIPE_ENABLED); } } else { if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { write32(INTEL_DISPLAY_A_PIPE_CONTROL, - pipeAControl & ~DISPLAY_PIPE_ENABLED); + pipeAControl & ~INTEL_PIPE_ENABLED); } if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { write32(INTEL_DISPLAY_B_PIPE_CONTROL, - pipeBControl & ~DISPLAY_PIPE_ENABLED); + pipeBControl & ~INTEL_PIPE_ENABLED); } } @@ -188,16 +188,15 @@ set_display_power_mode(uint32 mode) } if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { - write32(INTEL_DISPLAY_A_ANALOG_PORT, - (read32(INTEL_DISPLAY_A_ANALOG_PORT) + write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT) & ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED)) | monitorMode | (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0)); } + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { - write32(INTEL_DISPLAY_B_DIGITAL_PORT, - (read32(INTEL_DISPLAY_B_DIGITAL_PORT) - & ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED)) + write32(INTEL_DIGITAL_PORT_B, (read32(INTEL_DIGITAL_PORT_B) + & ~(/*DISPLAY_MONITOR_MODE_MASK |*/ DISPLAY_MONITOR_PORT_ENABLED)) | (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0)); // TODO: monitorMode? } diff --git a/src/add-ons/accelerants/intel_extreme/mode.cpp b/src/add-ons/accelerants/intel_extreme/mode.cpp old mode 100755 new mode 100644 index 961356b769..06999fff70 --- a/src/add-ons/accelerants/intel_extreme/mode.cpp +++ b/src/add-ons/accelerants/intel_extreme/mode.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2014, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Support for i915 chipset and up based on the X driver, @@ -10,20 +10,26 @@ */ -#include "accelerant_protos.h" -#include "accelerant.h" -#include "utility.h" - -#include +#include #include #include -#include + +#include #include #include #include #include +#include "accelerant_protos.h" +#include "accelerant.h" +#if 0 +#include "DisplayPipe.h" +#include "FlexibleDisplayInterface.h" +#endif +#include "Ports.h" +#include "utility.h" + #undef TRACE #define TRACE_MODE @@ -37,23 +43,6 @@ #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) -struct display_registers { - uint32 pll; - uint32 divisors; - uint32 control; - uint32 pipe_config; - uint32 horiz_total; - uint32 horiz_blank; - uint32 horiz_sync; - uint32 vert_total; - uint32 vert_blank; - uint32 vert_sync; - uint32 size; - uint32 stride; - uint32 position; - uint32 pipe_source; -}; - struct pll_divisors { uint32 post; uint32 post1; @@ -73,64 +62,6 @@ struct pll_limits { uint32 max_vco; }; -struct gpio_map { - const char* name; - uint32 pin; - uint32 validOn; -}; - - -static void mode_fill_missing_bits(display_mode *, uint32); - - -static status_t -get_i2c_signals(void* cookie, int* _clock, int* _data) -{ - uint32 ioRegister = (uint32)(addr_t)cookie; - uint32 value = read32(ioRegister); - - *_clock = (value & I2C_CLOCK_VALUE_IN) != 0; - *_data = (value & I2C_DATA_VALUE_IN) != 0; - - return B_OK; -} - - -static status_t -set_i2c_signals(void* cookie, int clock, int data) -{ - uint32 ioRegister = (uint32)(addr_t)cookie; - uint32 value; - - if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_83x)) { - // on these chips, the reserved values are fixed - value = 0; - } else { - // on all others, we have to preserve them manually - value = read32(ioRegister) & I2C_RESERVED; - } - - if (data != 0) - value |= I2C_DATA_DIRECTION_MASK; - else { - value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT - | I2C_DATA_VALUE_MASK; - } - - if (clock != 0) - value |= I2C_CLOCK_DIRECTION_MASK; - else { - value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT - | I2C_CLOCK_VALUE_MASK; - } - - write32(ioRegister, value); - read32(ioRegister); - // make sure the PCI bus has flushed the write - - return B_OK; -} - static void get_pll_limits(pll_limits &limits) @@ -191,14 +122,16 @@ get_pll_limits(pll_limits &limits) limits = kLimits; } - TRACE("PLL limits, min: p %" B_PRIu32 " (p1 %" B_PRIu32 ", p2 %" B_PRIu32 - "), n %" B_PRIu32 ", m %" B_PRIu32 " (m1 %" B_PRIu32 ", m2 %" B_PRIu32 - ")\n", limits.min.post, limits.min.post1, limits.min.post2, - limits.min.n, limits.min.m, limits.min.m1, limits.min.m2); - TRACE("PLL limits, max: p %" B_PRIu32 " (p1 %" B_PRIu32 ", p2 %" B_PRIu32 - "), n %" B_PRIu32 ", m %" B_PRIu32 " (m1 %" B_PRIu32 ", m2 %" B_PRIu32 - ")\n", limits.max.post, limits.max.post1, limits.max.post2, - limits.max.n, limits.max.m, limits.max.m1, limits.max.m2); + TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " + "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " + "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.post, + limits.min.post1, limits.min.post2, limits.min.n, limits.min.m, + limits.min.m1, limits.min.m2); + TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " + "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " + "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.post, + limits.max.post1, limits.max.post2, limits.max.n, limits.max.m, + limits.max.m1, limits.max.m2); } @@ -232,7 +165,7 @@ compute_pll_divisors(const display_mode ¤t, pll_divisors& divisors, TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); if (isLVDS) { - if ((read32(INTEL_DISPLAY_LVDS_PORT) & LVDS_CLKB_POWER_MASK) + if ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) divisors.post2 = LVDS_POST2_RATE_FAST; else @@ -284,40 +217,15 @@ compute_pll_divisors(const display_mode ¤t, pll_divisors& divisors, divisors = bestDivisors; - TRACE("%s: found: %g MHz, p = %" B_PRIu32 " (p1 = %" B_PRIu32 ", p2 = %" - B_PRIu32 "), n = %" B_PRIu32 ", m = %" B_PRIu32 " (m1 = %" B_PRIu32 - ", m2 = %" B_PRIu32 ")\n", __func__, + TRACE("%s: found: %g MHz, p = %" B_PRId32 " (p1 = %" B_PRId32 ", " + "p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " " + "(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__, ((referenceClock * divisors.m) / divisors.n) / divisors.post, divisors.post, divisors.post1, divisors.post2, divisors.n, divisors.m, divisors.m1, divisors.m2); } -static void -mode_fill_missing_bits(display_mode *mode, uint32 cntrl) -{ - uint32 value = read32(cntrl); - - switch (value & DISPLAY_CONTROL_COLOR_MASK) { - case DISPLAY_CONTROL_RGB32: - default: - mode->space = B_RGB32; - break; - case DISPLAY_CONTROL_RGB16: - mode->space = B_RGB16; - break; - case DISPLAY_CONTROL_RGB15: - mode->space = B_RGB15; - break; - case DISPLAY_CONTROL_CMAP8: - mode->space = B_CMAP8; - break; - } - - mode->flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS; -} - - static void retrieve_current_mode(display_mode& mode, uint32 pllRegister) { @@ -352,7 +260,6 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister) controlRegister = INTEL_DISPLAY_B_CONTROL; } else { // TODO: not supported - TRACE("%s: pllRegister not yet supported\n", __func__); return; } @@ -448,13 +355,27 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister) if (mode.virtual_height < mode.timing.v_display) mode.virtual_height = mode.timing.v_display; - mode_fill_missing_bits(&mode, controlRegister); + value = read32(controlRegister); + switch (value & DISPLAY_CONTROL_COLOR_MASK) { + case DISPLAY_CONTROL_RGB32: + default: + mode.space = B_RGB32; + break; + case DISPLAY_CONTROL_RGB16: + mode.space = B_RGB16; + break; + case DISPLAY_CONTROL_RGB15: + mode.space = B_RGB15; + break; + case DISPLAY_CONTROL_CMAP8: + mode.space = B_CMAP8; + break; + } mode.h_display_start = 0; mode.v_display_start = 0; - if (gInfo->overlay_registers != NULL) { - mode.flags |= B_SUPPORTS_OVERLAYS; - } + mode.flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS + | B_DPMS | B_SUPPORTS_OVERLAYS; } @@ -502,12 +423,15 @@ sanitize_display_mode(display_mode& mode) { // Some cards only support even pixel counts, while others require an odd // one. - bool olderCard = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_Gxx); - olderCard |= gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x); - olderCard |= gInfo->shared_info->device_type.InGroup(INTEL_TYPE_94x); - olderCard |= gInfo->shared_info->device_type.InGroup(INTEL_TYPE_91x); - olderCard |= gInfo->shared_info->device_type.InFamily(INTEL_TYPE_8xx); - olderCard |= gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx); + uint16 pixelCount = 1; + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_Gxx) + || gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x) + || gInfo->shared_info->device_type.InGroup(INTEL_TYPE_94x) + || gInfo->shared_info->device_type.InGroup(INTEL_TYPE_91x) + || gInfo->shared_info->device_type.InFamily(INTEL_TYPE_8xx) + || gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx)) { + pixelCount = 2; + } // TODO: verify constraints - these are more or less taken from the // radeon driver! @@ -518,32 +442,15 @@ sanitize_display_mode(display_mode& mode) gInfo->shared_info->pll_info.min_frequency, gInfo->shared_info->pll_info.max_frequency, // horizontal - {1, 0, 8160, 32, 8192, 0, 8192}, + {pixelCount, 0, 8160, 32, 8192, 0, 8192}, {1, 1, 4092, 2, 63, 1, 4096} }; - if (olderCard) - constraints.horizontal_timing.resolution = 2; - return sanitize_display_mode(mode, constraints, gInfo->has_edid ? &gInfo->edid_info : NULL); } -static bool -check_and_sanitize_display_mode(display_mode* mode) -{ - uint16 width = mode->timing.h_display; - uint16 height = mode->timing.v_display; - - // Only accept the mode if it is within the supported resolution - // TODO: sanitize_display_mode() should report resolution changes - // differently! - return !sanitize_display_mode(*mode) || (width == mode->timing.h_display - && height == mode->timing.v_display); -} - - // #pragma mark - @@ -555,12 +462,12 @@ set_frame_buffer_base() uint32 baseRegister; uint32 surfaceRegister; - if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { - baseRegister = INTEL_DISPLAY_B_BASE; - surfaceRegister = INTEL_DISPLAY_B_SURFACE; - } else { + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { baseRegister = INTEL_DISPLAY_A_BASE; surfaceRegister = INTEL_DISPLAY_A_SURFACE; + } else { + baseRegister = INTEL_DISPLAY_B_BASE; + surfaceRegister = INTEL_DISPLAY_B_SURFACE; } if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x) @@ -568,7 +475,7 @@ set_frame_buffer_base() || sharedInfo.device_type.InGroup(INTEL_TYPE_ILK) || sharedInfo.device_type.InGroup(INTEL_TYPE_SNB) || sharedInfo.device_type.InGroup(INTEL_TYPE_IVB) - || sharedInfo.device_type.InGroup(INTEL_TYPE_VLV)) { + || gInfo->shared_info->device_type.InGroup(INTEL_TYPE_VLV)) { write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row + mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8); read32(baseRegister); @@ -589,53 +496,21 @@ set_frame_buffer_base() status_t create_mode_list(void) { - // TODO: We may want to choose different GPIO pin maps - // for different generations of cards... not sure - const gpio_map gpioPinMap[] = { - {"ssc", INTEL_I2C_IO_B, 0}, - {"vga", INTEL_I2C_IO_A, HEAD_MODE_A_ANALOG}, - {"lvds", INTEL_I2C_IO_C, HEAD_MODE_LVDS_PANEL}, - {"dpc", INTEL_I2C_IO_D, 0}, - {"dpb", INTEL_I2C_IO_E, 0}, - {"dpd", INTEL_I2C_IO_F, 0}, - }; - - // TODO: We may want to do extra validation on gpio validOn - // vs the HEAD_MODE_ in head_mode - for (uint32 i = 0; i < sizeof(gpioPinMap) / sizeof(gpioPinMap[0]); i++) { - i2c_bus bus; - bus.cookie = (void*)(uintptr_t)gpioPinMap[i].pin; - bus.set_signals = &set_i2c_signals; - bus.get_signals = &get_i2c_signals; - ddc2_init_timing(&bus); - - status_t result = ddc2_read_edid1(&bus, &gInfo->edid_info, - NULL, NULL); - - if (result != B_OK) + for (uint32 i = 0; i < gInfo->port_count; i++) { + if (gInfo->ports[i] == NULL) continue; - TRACE("found edid data on gpio '%s'\n", gpioPinMap[i].name); - - edid_dump(&gInfo->edid_info); - gInfo->has_edid = true; - if (gInfo->shared_info->single_head_locked) - gInfo->head_mode = HEAD_MODE_A_ANALOG; - - // TODO: We may want to probe multiple GPIO pins here - // someday and store valid ones for multi-head support. - // For now, we break on the first valid one. - break; + status_t status = gInfo->ports[i]->GetEDID(&gInfo->edid_info); + if (status == B_OK) + gInfo->has_edid = true; } if (!gInfo->has_edid) { // We could not read any EDID info. Fallback to creating a list with // only the mode set up by the BIOS. // TODO: support lower modes via scaling and windowing - if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 - && (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) - || ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 - && gInfo->shared_info->got_vbt)) { + if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 + && (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) { size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); @@ -643,27 +518,10 @@ create_mode_list(void) area_id area = create_area("intel extreme modes", (void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); - if (area < B_OK) + if (area < 0) return area; - // Prefer information dumped directly from VBT, as the BIOS - // one may have display scaling, but only do this if the VBT - // resolution is higher than the BIOS one. - if (gInfo->shared_info->got_vbt - && gInfo->shared_info->current_mode.virtual_width - >= gInfo->lvds_panel_mode.virtual_width - && gInfo->shared_info->current_mode.virtual_height - >= gInfo->lvds_panel_mode.virtual_height) { - memcpy(list, &gInfo->shared_info->current_mode, - sizeof(display_mode)); - mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL); - } else { - memcpy(list, &gInfo->lvds_panel_mode, - sizeof(display_mode)); - - if (gInfo->shared_info->got_vbt) - TRACE("intel_extreme: ignoring VBT mode."); - } + memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode)); gInfo->mode_list_area = area; gInfo->mode_list = list; @@ -677,8 +535,8 @@ create_mode_list(void) display_mode* list; uint32 count = 0; gInfo->mode_list_area = create_display_modes("intel extreme modes", - gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, - &check_and_sanitize_display_mode, &list, &count); + gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, NULL, + &list, &count); if (gInfo->mode_list_area < B_OK) return gInfo->mode_list_area; @@ -747,7 +605,7 @@ intel_propose_display_mode(display_mode* target, const display_mode* low, // first search for the specified mode in the list, if no mode is found // try to fix the target mode in sanitize_display_mode - // TODO: Only sanitize_display_mode should be used. However, at the moment + // TODO: Only sanitize_display_mode should be used. However, at the moments // the mode constraints are not optimal and do not work for all // configurations. for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { @@ -774,12 +632,12 @@ intel_propose_display_mode(display_mode* target, const display_mode* low, status_t intel_set_display_mode(display_mode* mode) { - if (mode == NULL) - return B_BAD_VALUE; - TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__, mode->virtual_width, mode->virtual_height); + if (mode == NULL) + return B_BAD_VALUE; + display_mode target = *mode; // TODO: it may be acceptable to continue when using panel fitting or @@ -793,9 +651,9 @@ intel_set_display_mode(display_mode* mode) uint32 colorMode, bytesPerRow, bitsPerPixel; get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel); - // TODO stop here, when the requested mode is the same as the current one. - // This would avoid screen flickering when setting a mode that's already in - // place. + // TODO: do not go further if the mode is identical to the current one. + // This would avoid the screen being off when switching workspaces when they + // have the same resolution. #if 0 static bool first = true; @@ -847,6 +705,86 @@ if (first) { sharedInfo.frame_buffer = base; sharedInfo.frame_buffer_offset = base - (addr_t)sharedInfo.graphics_memory; +#if 0 + if ((gInfo->head_mode & HEAD_MODE_TESTING) != 0) { + // 1. Enable panel power as needed to retrieve panel configuration + // (use AUX VDD enable bit) + // skip, did detection already, might need that before that though + + // 2. Enable PCH clock reference source and PCH SSC modulator, + // wait for warmup (Can be done anytime before enabling port) + // skip, most certainly already set up by bios to use other ports, + // will need for coldstart though + + // 3. If enabling CPU embedded DisplayPort A: (Can be done anytime + // before enabling CPU pipe or port) + // a. Enable PCH 120MHz clock source output to CPU, wait for DMI + // latency + // b. Configure and enable CPU DisplayPort PLL in the DisplayPort A + // register, wait for warmup + // skip, not doing eDP right now, should go into + // EmbeddedDisplayPort class though + + // 4. If enabling port on PCH: (Must be done before enabling CPU pipe + // or FDI) + // a. Enable PCH FDI Receiver PLL, wait for warmup plus DMI latency + // b. Switch from Rawclk to PCDclk in FDI Receiver (FDI A OR FDI B) + // c. [DevSNB] Enable CPU FDI Transmitter PLL, wait for warmup + // d. [DevILK] CPU FDI PLL is always on and does not need to be + // enabled + FDILink* link = pipe->FDILink(); + if (link != NULL) { + link->Receiver().EnablePLL(); + link->Receiver().SwitchClock(true); + link->Transmitter().EnablePLL(); + } + + // 5. Enable CPU panel fitter if needed for hires, required for VGA + // (Can be done anytime before enabling CPU pipe) + PanelFitter* fitter = pipe->PanelFitter(); + if (fitter != NULL) + fitter->Enable(mode); + + // 6. Configure CPU pipe timings, M/N/TU, and other pipe settings + // (Can be done anytime before enabling CPU pipe) + pll_divisors divisors; + compute_pll_divisors(target, divisors, false); + pipe->ConfigureTimings(divisors); + + // 7. Enable CPU pipe + pipe->Enable(); + +8. Configure and enable CPU planes (VGA or hires) +9. If enabling port on PCH: + // a. Program PCH FDI Receiver TU size same as Transmitter TU size for TU error checking + // b. Train FDI + // i. Set pre-emphasis and voltage (iterate if training steps fail) + ii. Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled. + iii. Wait for FDI training pattern 1 time + iv. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for bit lock in bit 8 (retry at least once if no lock) + v. Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver + vi. Wait for FDI training pattern 2 time + vii. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for symbol lock in bit 9 (retry at least once if no + lock) + viii. Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver + ix. Wait for FDI idle pattern time for link to become active + c. Configure and enable PCH DPLL, wait for PCH DPLL warmup (Can be done anytime before enabling + PCH transcoder) + d. [DevCPT] Configure DPLL SEL to set the DPLL to transcoder mapping and enable DPLL to the + transcoder. + e. [DevCPT] Configure DPLL_CTL DPLL_HDMI_multipler. + f. Configure PCH transcoder timings, M/N/TU, and other transcoder settings (should match CPU settings). + g. [DevCPT] Configure and enable Transcoder DisplayPort Control if DisplayPort will be used + h. Enable PCH transcoder +10. Enable ports (DisplayPort must enable in training pattern 1) +11. Enable panel power through panel power sequencing +12. Wait for panel power sequencing to reach enabled steady state +13. Disable panel power override +14. If DisplayPort, complete link training +15. Enable panel backlight + } +#endif + // make sure VGA display is disabled write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED); read32(INTEL_VGA_DISPLAY_CONTROL); @@ -941,7 +879,7 @@ if (first) { spin(150); } - uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT) | LVDS_PORT_EN + uint32 lvds = read32(INTEL_DIGITAL_LVDS_PORT) | LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; lvds |= LVDS_18BIT_DITHER; @@ -958,8 +896,8 @@ if (first) { else lvds &= ~(LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP); - write32(INTEL_DISPLAY_LVDS_PORT, lvds); - read32(INTEL_DISPLAY_LVDS_PORT); + write32(INTEL_DIGITAL_LVDS_PORT, lvds); + read32(INTEL_DIGITAL_LVDS_PORT); if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { write32(INTEL_DISPLAY_B_PLL_DIVISOR_0, @@ -1094,10 +1032,98 @@ if (first) { | colorMode); write32(INTEL_DISPLAY_B_PIPE_CONTROL, - read32(INTEL_DISPLAY_B_PIPE_CONTROL) | DISPLAY_PIPE_ENABLED); + read32(INTEL_DISPLAY_B_PIPE_CONTROL) | INTEL_PIPE_ENABLED); read32(INTEL_DISPLAY_B_PIPE_CONTROL); } + if ((gInfo->head_mode & HEAD_MODE_STIPPI) != 0) { + pll_divisors divisors; + compute_pll_divisors(target, divisors, false); + + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { + write32(INTEL_DISPLAY_B_PLL_DIVISOR_0, + (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT) + & DISPLAY_PLL_IGD_N_DIVISOR_MASK) + | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) + & DISPLAY_PLL_IGD_M2_DIVISOR_MASK)); + } else { + write32(INTEL_DISPLAY_B_PLL_DIVISOR_0, + (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) + & DISPLAY_PLL_N_DIVISOR_MASK) + | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) + & DISPLAY_PLL_M1_DIVISOR_MASK) + | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) + & DISPLAY_PLL_M2_DIVISOR_MASK)); + } + + uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL; + if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) { + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { + pll |= ((1 << (divisors.post1 - 1)) + << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT) + & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK; + } else { + pll |= ((1 << (divisors.post1 - 1)) + << DISPLAY_PLL_POST1_DIVISOR_SHIFT) + & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; +// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) +// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; + } + if (divisors.post2_high) + pll |= DISPLAY_PLL_DIVIDE_HIGH; + + if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) + pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT; + } else { + if (!divisors.post2_high) + pll |= DISPLAY_PLL_DIVIDE_4X; + + pll |= DISPLAY_PLL_2X_CLOCK; + + if (divisors.post1 > 2) { + pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) + & DISPLAY_PLL_POST1_DIVISOR_MASK; + } else + pll |= DISPLAY_PLL_POST1_DIVIDE_2; + } + + write32(INTEL_DISPLAY_B_PLL, pll); + read32(INTEL_DISPLAY_B_PLL); + spin(150); + write32(INTEL_DISPLAY_B_PLL, pll); + read32(INTEL_DISPLAY_B_PLL); + spin(150); + + // update timing parameters + write32(INTEL_DISPLAY_B_HTOTAL, + ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_B_HBLANK, + ((uint32)(target.timing.h_total - 1) << 16) + | ((uint32)target.timing.h_display - 1)); + write32(INTEL_DISPLAY_B_HSYNC, + ((uint32)(target.timing.h_sync_end - 1) << 16) + | ((uint32)target.timing.h_sync_start - 1)); + + write32(INTEL_DISPLAY_B_VTOTAL, + ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_B_VBLANK, + ((uint32)(target.timing.v_total - 1) << 16) + | ((uint32)target.timing.v_display - 1)); + write32(INTEL_DISPLAY_B_VSYNC, + ((uint32)(target.timing.v_sync_end - 1) << 16) + | ((uint32)target.timing.v_sync_start - 1)); + + write32(INTEL_DISPLAY_B_IMAGE_SIZE, + ((uint32)(target.virtual_width - 1) << 16) + | ((uint32)target.virtual_height - 1)); + + write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL) + & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) + | colorMode); + } + if ((gInfo->head_mode & HEAD_MODE_A_ANALOG) != 0) { pll_divisors divisors; compute_pll_divisors(target, divisors, false); @@ -1151,9 +1177,7 @@ if (first) { pll |= DISPLAY_PLL_POST1_DIVIDE_2; } - // Programmer's Ref says we must allow the DPLL to "warm up" before starting the plane - // so mask its bit, wait, enable its bit - write32(INTEL_DISPLAY_A_PLL, pll & ~DISPLAY_PLL_NO_VGA_CONTROL); + write32(INTEL_DISPLAY_A_PLL, pll); read32(INTEL_DISPLAY_A_PLL); spin(150); write32(INTEL_DISPLAY_A_PLL, pll); @@ -1185,8 +1209,7 @@ if (first) { ((uint32)(target.virtual_width - 1) << 16) | ((uint32)target.virtual_height - 1)); - write32(INTEL_DISPLAY_A_ANALOG_PORT, - (read32(INTEL_DISPLAY_A_ANALOG_PORT) + write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT) & ~(DISPLAY_MONITOR_POLARITY_MASK | DISPLAY_MONITOR_VGA_POLARITY)) | ((target.timing.flags & B_POSITIVE_HSYNC) != 0 @@ -1215,18 +1238,20 @@ if (first) { } } - set_display_power_mode(sharedInfo.dpms_mode); + if ((gInfo->head_mode & HEAD_MODE_TESTING) == 0) { + set_display_power_mode(sharedInfo.dpms_mode); - // Changing bytes per row seems to be ignored if the plane/pipe is turned - // off + // Changing bytes per row seems to be ignored if the plane/pipe is turned + // off - if (gInfo->head_mode & HEAD_MODE_A_ANALOG) - write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow); - if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) - write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow); + if (gInfo->head_mode & HEAD_MODE_A_ANALOG) + write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow); + if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) + write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow); - set_frame_buffer_base(); - // triggers writing back double-buffered registers + set_frame_buffer_base(); + // triggers writing back double-buffered registers + } // update shared info sharedInfo.bytes_per_row = bytesPerRow; diff --git a/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp b/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp index 93b8271fad..a2611151c4 100644 --- a/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp +++ b/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp @@ -47,6 +47,7 @@ (*((volatile uint32*)(address))) +// PCI "Host bridge" is most cases :-) const struct supported_device { uint32 bridge_id; uint32 display_id; @@ -112,6 +113,7 @@ const struct supported_device { {0x0c00, 0x0412, INTEL_TYPE_IVBG, "Haswell Desktop"}, {0x0c04, 0x0416, INTEL_TYPE_IVBGM, "Haswell Mobile"}, {0x0d04, 0x0d26, INTEL_TYPE_IVBGM, "Haswell Mobile"}, + {0x0a04, 0x0a16, INTEL_TYPE_IVBGM, "Haswell Mobile"}, // XXX: 0x0f00 only confirmed on 0x0f30, 0x0f31 {0x0f00, 0x0155, INTEL_TYPE_VLVG, "ValleyView Desktop"}, @@ -374,6 +376,19 @@ determine_memory_sizes(intel_info &info, size_t >tSize, size_t &stolenSize) static void set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress) { + if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_96x + || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_Gxx + || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x + || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_IGD + || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK + || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_VLV) { + // possible high bits are stored in the lower end + physicalAddress |= (physicalAddress >> 28) & 0x00f0; + } else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) { + physicalAddress |= (physicalAddress >> 28) & 0x0ff0; + physicalAddress |= 0x02; // cache control, l3 cacheable + } + // TODO: this is not 64-bit safe! write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT), (uint32)physicalAddress | GTT_ENTRY_VALID); diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp index 22dd3f0a2e..251f3ee2dc 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp @@ -100,6 +100,7 @@ const struct supported_device { {0x0412, INTEL_TYPE_IVBG, "Haswell Desktop"}, {0x0416, INTEL_TYPE_IVBGM, "Haswell Mobile"}, {0x0d26, INTEL_TYPE_IVBGM, "Haswell Mobile"}, + {0x0a16, INTEL_TYPE_IVBGM, "Haswell Mobile"}, {0x0155, INTEL_TYPE_VLVG, "ValleyView Desktop"}, {0x0f30, INTEL_TYPE_VLVGM, "ValleyView Mobile"},