intel_extreme: IronLake reference clock activation

This commit is contained in:
Alexander von Gluck IV 2016-07-17 15:25:08 -05:00
parent 00a3a794e0
commit a933bb4cbc
4 changed files with 130 additions and 1 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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 {

View File

@ -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 */