From a933bb4cbca665fa18c5718219a3143a63763f30 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Sun, 17 Jul 2016 15:25:08 -0500 Subject: [PATCH] intel_extreme: IronLake reference clock activation --- .../graphics/intel_extreme/intel_extreme.h | 24 ++++++ .../accelerants/intel_extreme/accelerant.cpp | 19 +++- src/add-ons/accelerants/intel_extreme/pll.cpp | 86 +++++++++++++++++++ src/add-ons/accelerants/intel_extreme/pll.h | 2 + 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 0a5e951f7c..839bdb44f0 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -711,6 +711,30 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_B_PLL (0x6018 | REGS_SOUTH_SHARED) #define CHV_DISPLAY_C_PLL (0x6030 | REGS_SOUTH_SHARED) +// Ironlake PCH reference clk control +#define PCH_DREF_CONTROL (0x6200 | REGS_SOUTH_SHARED) +#define DREF_CONTROL_MASK 0x7fc3 +#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0 << 13) +#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2 << 13) +#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3 << 13) +#define DREF_CPU_SOURCE_OUTPUT_MASK (3 << 13) +#define DREF_SSC_SOURCE_DISABLE (0 << 11) +#define DREF_SSC_SOURCE_ENABLE (2 << 11) +#define DREF_SSC_SOURCE_MASK (3 << 11) +#define DREF_NONSPREAD_SOURCE_DISABLE (0 << 9) +#define DREF_NONSPREAD_CK505_ENABLE (1 << 9) +#define DREF_NONSPREAD_SOURCE_ENABLE (2 << 9) +#define DREF_NONSPREAD_SOURCE_MASK (3 << 9) +#define DREF_SUPERSPREAD_SOURCE_DISABLE (0 << 7) +#define DREF_SUPERSPREAD_SOURCE_ENABLE (2 << 7) +#define DREF_SUPERSPREAD_SOURCE_MASK (3 << 7) +#define DREF_SSC4_DOWNSPREAD (0 << 6) +#define DREF_SSC4_CENTERSPREAD (1 << 6) +#define DREF_SSC1_DISABLE (0 << 1) +#define DREF_SSC1_ENABLE (1 << 1) +#define DREF_SSC4_DISABLE (0 << 0) +#define DREF_SSC4_ENABLE (1 << 0) + // Multiplier Divisor #define INTEL_DISPLAY_A_PLL_MD (0x601C | REGS_SOUTH_SHARED) #define INTEL_DISPLAY_B_PLL_MD (0x6020 | REGS_SOUTH_SHARED) diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index f2adfe2e26..d9ca2374b5 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2016, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -294,6 +294,8 @@ probe_ports() read32(INTEL_DIGITAL_PORT_B), read32(INTEL_DIGITAL_PORT_C)); TRACE("lvds: %08" B_PRIx32 "\n", read32(INTEL_DIGITAL_LVDS_PORT)); + bool foundLVDS = false; + gInfo->port_count = 0; for (int i = INTEL_PORT_A; i <= INTEL_PORT_D; i++) { Port* displayPort = new(std::nothrow) DisplayPort((port_index)i); @@ -368,6 +370,7 @@ probe_ports() if (lvdsPort == NULL) return B_NO_MEMORY; if (lvdsPort->IsConnected()) { + foundLVDS = true; gInfo->ports[gInfo->port_count++] = lvdsPort; gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; gInfo->head_mode |= HEAD_MODE_B_DIGITAL; @@ -387,6 +390,20 @@ probe_ports() if (gInfo->port_count == 0) return B_ERROR; + // Activate reference clocks if needed + if (gInfo->shared_info->pch_info == INTEL_PCH_IBX + || gInfo->shared_info->pch_info == INTEL_PCH_CPT) { + // XXX: Is LVDS the same as Panel? + refclk_activate_ilk(foundLVDS); + } + /* + } else if (gInfo->shared_info->pch_info == INTEL_PCH_LPT) { + // TODO: Some kind of stepped bend thing? + // only needed for vga + refclk_activate_lpt(foundLVDS); + } + */ + return B_OK; } diff --git a/src/add-ons/accelerants/intel_extreme/pll.cpp b/src/add-ons/accelerants/intel_extreme/pll.cpp index fa6b9cb4e6..ff80495230 100644 --- a/src/add-ons/accelerants/intel_extreme/pll.cpp +++ b/src/add-ons/accelerants/intel_extreme/pll.cpp @@ -463,6 +463,92 @@ compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS) } +void +refclk_activate_ilk(bool hasPanel) +{ + CALLED(); + + // aka, our engineers hate you + + bool wantsSSC; + bool hasCK505; + if (gInfo->shared_info->pch_info == INTEL_PCH_IBX) { + //XXX: This should be == vbt display_clock_mode + hasCK505 = true; + wantsSSC = hasCK505; + } else { + hasCK505 = false; + wantsSSC = true; + } + + uint32 clkRef = read32(PCH_DREF_CONTROL); + uint32 newRef = clkRef; + + newRef &= ~DREF_NONSPREAD_SOURCE_MASK; + + if (hasCK505) + newRef |= DREF_NONSPREAD_CK505_ENABLE; + else + newRef |= DREF_NONSPREAD_SOURCE_ENABLE; + + newRef &= ~DREF_SSC_SOURCE_MASK; + newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + newRef &= ~DREF_SSC1_ENABLE; + + if (newRef == clkRef) { + TRACE("%s: No changes to reference clock.\n", __func__); + return; + } + + if (hasPanel) { + newRef &= ~DREF_SSC_SOURCE_MASK; + newRef |= DREF_SSC_SOURCE_ENABLE; + + if (wantsSSC) + newRef |= DREF_SSC1_ENABLE; + else + newRef &= ~DREF_SSC1_ENABLE; + + // Power up SSC before enabling outputs + write32(PCH_DREF_CONTROL, newRef); + read32(PCH_DREF_CONTROL); + spin(200); + + newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + + bool hasEDP = true; + if (hasEDP) { + if (wantsSSC) + newRef |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; + else + newRef |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; + } else + newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + + write32(PCH_DREF_CONTROL, newRef); + read32(PCH_DREF_CONTROL); + spin(200); + } else { + newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + + write32(PCH_DREF_CONTROL, newRef); + read32(PCH_DREF_CONTROL); + spin(200); + + if (!wantsSSC) { + newRef &= ~DREF_SSC_SOURCE_MASK; + newRef |= DREF_SSC_SOURCE_DISABLE; + newRef &= ~DREF_SSC1_ENABLE; + + write32(PCH_DREF_CONTROL, newRef); + read32(PCH_DREF_CONTROL); + spin(200); + } + } +} + + #ifdef PLL_TEST_MODE const struct test_device { diff --git a/src/add-ons/accelerants/intel_extreme/pll.h b/src/add-ons/accelerants/intel_extreme/pll.h index 2b607ce756..d30edd2c46 100644 --- a/src/add-ons/accelerants/intel_extreme/pll.h +++ b/src/add-ons/accelerants/intel_extreme/pll.h @@ -36,5 +36,7 @@ bool valid_pll_divisors(pll_divisors* divisors, pll_limits* limits); void compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS); +void refclk_activate_ilk(bool hasPanel); + #endif /* INTEL_EXTREME_PLL_H */