diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 8cf6a59fed..3412b7669b 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -230,6 +230,8 @@ struct intel_shared_info { addr_t frame_buffer; uint32 frame_buffer_offset; + uint32 fdi_link_frequency; // In Mhz + bool got_vbt; bool single_head_locked; @@ -721,11 +723,15 @@ struct intel_free_graphics_memory { #define FDI_RX_ENABLE (1 << 31) #define FDI_RX_PLL_ENABLED (1 << 13) +#define FDI_FS_ERRC_ENABLE (1 << 27) +#define FDI_FE_ERRC_ENABLE (1 << 26) + #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 +#define FDI_RX_ENHANCE_FRAME_ENABLE (1 << 6) #define FDI_RX_CLOCK_MASK (1 << 4) #define FDI_RX_CLOCK_RAW (0 << 4) #define FDI_RX_CLOCK_PCD (1 << 4) @@ -734,8 +740,55 @@ struct intel_free_graphics_memory { #define PCH_FDI_TX_PIPE_OFFSET 0x01000 #define PCH_FDI_TX_CONTROL 0x100 #define FDI_TX_ENABLE (1 << 31) +#define FDI_TX_ENHANCE_FRAME_ENABLE (1 << 18) #define FDI_TX_PLL_ENABLED (1 << 14) +#define FDI_PLL_BIOS_0 0x46000 +#define FDI_PLL_FB_CLOCK_MASK 0xff +#define FDI_PLL_BIOS_1 0x46004 +#define FDI_PLL_BIOS_2 0x46008 + +#define FDI_LINK_TRAIN_PATTERN_1 (0 << 28) +#define FDI_LINK_TRAIN_PATTERN_2 (1 << 28) +#define FDI_LINK_TRAIN_PATTERN_IDLE (2 << 28) +#define FDI_LINK_TRAIN_NONE (3 << 28) +#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0 << 25) +#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1 << 25) +#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2 << 25) +#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3 << 25) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0 << 22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1 << 22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2 << 22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3 << 22) + +#define FDI_AUTO_TRAINING (1 << 10) +#define FDI_AUTO_TRAIN_DONE (1 << 1) + +// SNB A-stepping +#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38 << 22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02 << 22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01 << 22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x00 << 22) + +// SNB B-stepping +#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x00 << 22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a << 22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39 << 22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38 << 22) +#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f << 22) + +#define FDI_LINK_TRAIN_PATTERN_1_CPT (0 << 8) +#define FDI_LINK_TRAIN_PATTERN_2_CPT (1 << 8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2 << 8) +#define FDI_LINK_TRAIN_NORMAL_CPT (3 << 8) +#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3 << 8) + +// IvyBridge changes it up because... they hate developers? +#define FDI_LINK_TRAIN_PATTERN_1_IVB (0 << 8) +#define FDI_LINK_TRAIN_PATTERN_2_IVB (1 << 8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2 << 8) +#define FDI_LINK_TRAIN_NONE_IVB (3 << 8) + // CPU Panel Fitters - These are for IronLake and up and are the CPU internal // panel fitters. #define PCH_PANEL_FITTER_BASE_REGISTER 0x68000 diff --git a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp index a72ec8605d..a5e3adb35d 100644 --- a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp +++ b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Copyright 2011-2015, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Lotz, mmlr@mlotz.ch + * Alexander von Gluck IV, kallisti5@unixzen.com */ @@ -216,6 +217,135 @@ FDILink::FDILink(pipe_index pipeIndex) } +status_t +FDILink::Train(display_mode* target) +{ + CALLED(); + + uint32 bitsPerPixel; + switch (target->space) { + case B_RGB32_LITTLE: + bitsPerPixel = 32; + break; + case B_RGB16_LITTLE: + bitsPerPixel = 16; + break; + case B_RGB15_LITTLE: + bitsPerPixel = 15; + break; + case B_CMAP8: + default: + bitsPerPixel = 8; + break; + } + + // Khz / 10. ( each output octet encoded as 10 bits. + uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; + uint32 bps = target->timing.pixel_clock * bitsPerPixel * 21 / 20; + + uint32 lanes = bps / (linkBandwidth * 8); + + TRACE("%s: FDI Link Lanes: %" B_PRIu32 "\n", __func__, lanes); + + // Over IVB supports AutoTraining of FDI + if (gInfo->shared_info->device_type.Generation() >= 7) + return _AutoTrain(lanes); + + //return _ManualTrain(lanes); + return B_ERROR; +} + + +status_t +FDILink::_ManualTrain(uint32 lanes) +{ + CALLED(); + + // This all needs review + + // Enable FDI clocks + Receiver().EnablePLL(); + Receiver().SwitchClock(true); + Transmitter().EnablePLL(); + + ERROR("TODO: Generation 5 FDI Link Training\n"); + + // Enable pipes + Transmitter().Enable(); + Receiver().Enable(); + return B_OK; +} + + +status_t +FDILink::_AutoTrain(uint32 lanes) +{ + CALLED(); + uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; + uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; + + uint32 buffer = read32(txControl); + buffer &= ~(7 << 19); + buffer |= (lanes - 1) << 19; + if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) + buffer &= ~FDI_LINK_TRAIN_NONE_IVB; + else + buffer &= ~FDI_LINK_TRAIN_NONE; + write32(txControl, buffer); + + static const int snb_b_fdi_train_param[] = { + FDI_LINK_TRAIN_400MV_0DB_SNB_B, + FDI_LINK_TRAIN_400MV_6DB_SNB_B, + FDI_LINK_TRAIN_600MV_3_5DB_SNB_B, + FDI_LINK_TRAIN_800MV_0DB_SNB_B, + }; + + bool trained = false; + + for (uint32 i = 0; i < (sizeof(snb_b_fdi_train_param) + / sizeof(snb_b_fdi_train_param[0])); i++) { + for (int j = 0; j < 2; j++) { + buffer = read32(txControl); + buffer |= FDI_AUTO_TRAINING; + buffer &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; + buffer |= snb_b_fdi_train_param[i]; + write32(txControl, buffer | FDI_TX_ENABLE); + + write32(rxControl, read32(rxControl) | FDI_RX_ENABLE); + + spin(5); + + buffer = read32(txControl); + if ((buffer & FDI_AUTO_TRAIN_DONE) != 0) { + TRACE("%s: FDI auto train complete!\n", __func__); + trained = true; + break; + } + + write32(txControl, read32(txControl) & ~FDI_TX_ENABLE); + write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE); + read32(rxControl); + + spin(31); + } + } + + if (!trained) { + ERROR("%s: FDI auto train failed!\n", __func__); + return B_ERROR; + } + + // Enable ecc + if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { + write32(rxControl, read32(rxControl) + | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE); + read32(rxControl); + } + + return B_OK; +} + + FDILink::~FDILink() { } diff --git a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h index 2ad757cd8d..33502ba076 100644 --- a/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h +++ b/src/add-ons/accelerants/intel_extreme/FlexibleDisplayInterface.h @@ -1,9 +1,10 @@ /* - * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Copyright 2011-2015, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Lotz, mmlr@mlotz.ch + * Alexander von Gluck IV, kallisti5@unixzen.com */ #ifndef INTEL_FDI_H #define INTEL_FDI_H @@ -24,6 +25,9 @@ public: void EnablePLL(); void DisablePLL(); + uint32 Base() + { return fRegisterBase; }; + private: uint32 fRegisterBase; }; @@ -43,6 +47,9 @@ public: void SwitchClock(bool toPCDClock); + uint32 Base() + { return fRegisterBase; }; + protected: uint32 fRegisterBase; }; @@ -58,7 +65,12 @@ public: FDIReceiver& Receiver() { return fReceiver; }; + status_t Train(display_mode* target); + private: + status_t _ManualTrain(uint32 lanes); + status_t _AutoTrain(uint32 lanes); + FDITransmitter fTransmitter; FDIReceiver fReceiver; }; diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 69c3bbf5a1..db7d9fc477 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -262,11 +262,8 @@ AnalogPort::SetDisplayMode(display_mode* target, uint32 colorMode) // Train FDI if it exists FDILink* link = fDisplayPipe->FDI(); - if (link != NULL) { - link->Receiver().EnablePLL(); - link->Receiver().SwitchClock(true); - link->Transmitter().EnablePLL(); - } + if (link != NULL) + link->Train(target); pll_divisors divisors; compute_pll_divisors(target, &divisors, false); @@ -677,11 +674,8 @@ DigitalPort::SetDisplayMode(display_mode* target, uint32 colorMode) // Train FDI if it exists FDILink* link = fDisplayPipe->FDI(); - if (link != NULL) { - link->Receiver().EnablePLL(); - link->Receiver().SwitchClock(true); - link->Transmitter().EnablePLL(); - } + if (link != NULL) + link->Train(target); pll_divisors divisors; compute_pll_divisors(target, &divisors, false); diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index 3e630b656b..2b36e648e4 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -472,6 +472,18 @@ intel_extreme_init(intel_info &info) init_interrupt_handler(info); + if (info.device_type.HasPlatformControlHub()) { + if (info.device_type.Generation() == 5) { + info.shared_info->fdi_link_frequency = (read32(info, FDI_PLL_BIOS_0) + & FDI_PLL_FB_CLOCK_MASK) + 2; + info.shared_info->fdi_link_frequency *= 100; + } else { + info.shared_info->fdi_link_frequency = 2700; + } + } else { + info.shared_info->fdi_link_frequency = 0; + } + TRACE("%s: completed successfully!\n", __func__); return B_OK; }