summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorKeith Packard2011-09-22 21:01:57 +0200
committerKeith Packard2011-09-27 20:12:56 +0200
commit199e5d79f1c988a8039fa75b736a3adcdda56abc (patch)
tree1a2b4ef5d6105b4457e3e47df20e1e1a41feca97 /drivers/gpu/drm/i915/intel_display.c
parentdrm/i915: Allow SSC parameter to override VBT value (diff)
downloadkernel-qcow2-linux-199e5d79f1c988a8039fa75b736a3adcdda56abc.tar.gz
kernel-qcow2-linux-199e5d79f1c988a8039fa75b736a3adcdda56abc.tar.xz
kernel-qcow2-linux-199e5d79f1c988a8039fa75b736a3adcdda56abc.zip
drm/i915: Fix PCH SSC reference clock settings
The PCH refclk settings are global, so we need to look at all of the encoders, not just the current encoder when deciding how to configure it. Also, handle systems with more than one panel (any combination of PCH/non-PCH eDP and LVDS). Disable SSC clocks when no panels are connected. Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c96
1 files changed, 59 insertions, 37 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 603949622104..f99993577168 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5113,31 +5113,32 @@ static void ironlake_update_pch_refclk(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mode_config *mode_config = &dev->mode_config;
- struct drm_crtc *crtc;
struct intel_encoder *encoder;
- struct intel_encoder *has_edp_encoder = NULL;
u32 temp;
bool has_lvds = false;
+ bool has_cpu_edp = false;
+ bool has_pch_edp = false;
+ bool has_panel = false;
/* We need to take the global config into account */
- list_for_each_entry(crtc, &mode_config->crtc_list, head) {
- if (!crtc->enabled)
- continue;
-
- list_for_each_entry(encoder, &mode_config->encoder_list,
- base.head) {
- if (encoder->base.crtc != crtc)
- continue;
-
- switch (encoder->type) {
- case INTEL_OUTPUT_LVDS:
- has_lvds = true;
- case INTEL_OUTPUT_EDP:
- has_edp_encoder = encoder;
- break;
- }
+ list_for_each_entry(encoder, &mode_config->encoder_list,
+ base.head) {
+ switch (encoder->type) {
+ case INTEL_OUTPUT_LVDS:
+ has_panel = true;
+ has_lvds = true;
+ break;
+ case INTEL_OUTPUT_EDP:
+ has_panel = true;
+ if (intel_encoder_is_pch_edp(&encoder->base))
+ has_pch_edp = true;
+ else
+ has_cpu_edp = true;
+ break;
}
}
+ DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d\n",
+ has_panel, has_lvds, has_pch_edp, has_cpu_edp);
/* Ironlake: try to setup display ref clock before DPLL
* enabling. This is only under driver's control after
@@ -5148,36 +5149,57 @@ static void ironlake_update_pch_refclk(struct drm_device *dev)
/* Always enable nonspread source */
temp &= ~DREF_NONSPREAD_SOURCE_MASK;
temp |= DREF_NONSPREAD_SOURCE_ENABLE;
- temp &= ~DREF_SSC_SOURCE_MASK;
- temp |= DREF_SSC_SOURCE_ENABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
- POSTING_READ(PCH_DREF_CONTROL);
- udelay(200);
+ if (has_panel) {
+ temp &= ~DREF_SSC_SOURCE_MASK;
+ temp |= DREF_SSC_SOURCE_ENABLE;
- if (has_edp_encoder) {
+ /* SSC must be turned on before enabling the CPU output */
if (intel_panel_use_ssc(dev_priv)) {
+ DRM_DEBUG_KMS("Using SSC on panel\n");
temp |= DREF_SSC1_ENABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
-
- POSTING_READ(PCH_DREF_CONTROL);
- udelay(200);
}
+
+ /* Get SSC going before enabling the outputs */
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
+
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
/* Enable CPU source on CPU attached eDP */
- if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- if (intel_panel_use_ssc(dev_priv))
+ if (has_cpu_edp) {
+ if (intel_panel_use_ssc(dev_priv)) {
+ DRM_DEBUG_KMS("Using SSC on eDP\n");
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+ }
else
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
- } else {
- /* Enable SSC on PCH eDP if needed */
- if (intel_panel_use_ssc(dev_priv)) {
- DRM_ERROR("enabling SSC on PCH\n");
- temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
- }
- }
+ } else
+ temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
+ } else {
+ DRM_DEBUG_KMS("Disabling SSC entirely\n");
+
+ temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+ /* Turn off CPU output */
+ temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
+
+ /* Turn off the SSC source */
+ temp &= ~DREF_SSC_SOURCE_MASK;
+ temp |= DREF_SSC_SOURCE_DISABLE;
+
+ /* Turn off SSC1 */
+ temp &= ~ DREF_SSC1_ENABLE;
+
I915_WRITE(PCH_DREF_CONTROL, temp);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);