aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2011-09-22 15:01:57 -0400
committerKeith Packard <keithp@keithp.com>2011-09-27 14:12:56 -0400
commit199e5d79f1c988a8039fa75b736a3adcdda56abc (patch)
tree1a2b4ef5d6105b4457e3e47df20e1e1a41feca97 /drivers/gpu/drm/i915/intel_display.c
parent72bbe58cd9568c7766cc219a779ea68a02132797 (diff)
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)
5113{ 5113{
5114 struct drm_i915_private *dev_priv = dev->dev_private; 5114 struct drm_i915_private *dev_priv = dev->dev_private;
5115 struct drm_mode_config *mode_config = &dev->mode_config; 5115 struct drm_mode_config *mode_config = &dev->mode_config;
5116 struct drm_crtc *crtc;
5117 struct intel_encoder *encoder; 5116 struct intel_encoder *encoder;
5118 struct intel_encoder *has_edp_encoder = NULL;
5119 u32 temp; 5117 u32 temp;
5120 bool has_lvds = false; 5118 bool has_lvds = false;
5119 bool has_cpu_edp = false;
5120 bool has_pch_edp = false;
5121 bool has_panel = false;
5121 5122
5122 /* We need to take the global config into account */ 5123 /* We need to take the global config into account */
5123 list_for_each_entry(crtc, &mode_config->crtc_list, head) { 5124 list_for_each_entry(encoder, &mode_config->encoder_list,
5124 if (!crtc->enabled) 5125 base.head) {
5125 continue; 5126 switch (encoder->type) {
5126 5127 case INTEL_OUTPUT_LVDS:
5127 list_for_each_entry(encoder, &mode_config->encoder_list, 5128 has_panel = true;
5128 base.head) { 5129 has_lvds = true;
5129 if (encoder->base.crtc != crtc) 5130 break;
5130 continue; 5131 case INTEL_OUTPUT_EDP:
5131 5132 has_panel = true;
5132 switch (encoder->type) { 5133 if (intel_encoder_is_pch_edp(&encoder->base))
5133 case INTEL_OUTPUT_LVDS: 5134 has_pch_edp = true;
5134 has_lvds = true; 5135 else
5135 case INTEL_OUTPUT_EDP: 5136 has_cpu_edp = true;
5136 has_edp_encoder = encoder; 5137 break;
5137 break;
5138 }
5139 } 5138 }
5140 } 5139 }
5140 DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d\n",
5141 has_panel, has_lvds, has_pch_edp, has_cpu_edp);
5141 5142
5142 /* Ironlake: try to setup display ref clock before DPLL 5143 /* Ironlake: try to setup display ref clock before DPLL
5143 * enabling. This is only under driver's control after 5144 * enabling. This is only under driver's control after
@@ -5148,36 +5149,57 @@ static void ironlake_update_pch_refclk(struct drm_device *dev)
5148 /* Always enable nonspread source */ 5149 /* Always enable nonspread source */
5149 temp &= ~DREF_NONSPREAD_SOURCE_MASK; 5150 temp &= ~DREF_NONSPREAD_SOURCE_MASK;
5150 temp |= DREF_NONSPREAD_SOURCE_ENABLE; 5151 temp |= DREF_NONSPREAD_SOURCE_ENABLE;
5151 temp &= ~DREF_SSC_SOURCE_MASK;
5152 temp |= DREF_SSC_SOURCE_ENABLE;
5153 I915_WRITE(PCH_DREF_CONTROL, temp);
5154 5152
5155 POSTING_READ(PCH_DREF_CONTROL); 5153 if (has_panel) {
5156 udelay(200); 5154 temp &= ~DREF_SSC_SOURCE_MASK;
5155 temp |= DREF_SSC_SOURCE_ENABLE;
5157 5156
5158 if (has_edp_encoder) { 5157 /* SSC must be turned on before enabling the CPU output */
5159 if (intel_panel_use_ssc(dev_priv)) { 5158 if (intel_panel_use_ssc(dev_priv)) {
5159 DRM_DEBUG_KMS("Using SSC on panel\n");
5160 temp |= DREF_SSC1_ENABLE; 5160 temp |= DREF_SSC1_ENABLE;
5161 I915_WRITE(PCH_DREF_CONTROL, temp);
5162
5163 POSTING_READ(PCH_DREF_CONTROL);
5164 udelay(200);
5165 } 5161 }
5162
5163 /* Get SSC going before enabling the outputs */
5164 I915_WRITE(PCH_DREF_CONTROL, temp);
5165 POSTING_READ(PCH_DREF_CONTROL);
5166 udelay(200);
5167
5166 temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 5168 temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
5167 5169
5168 /* Enable CPU source on CPU attached eDP */ 5170 /* Enable CPU source on CPU attached eDP */
5169 if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) { 5171 if (has_cpu_edp) {
5170 if (intel_panel_use_ssc(dev_priv)) 5172 if (intel_panel_use_ssc(dev_priv)) {
5173 DRM_DEBUG_KMS("Using SSC on eDP\n");
5171 temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; 5174 temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
5175 }
5172 else 5176 else
5173 temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; 5177 temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
5174 } else { 5178 } else
5175 /* Enable SSC on PCH eDP if needed */ 5179 temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
5176 if (intel_panel_use_ssc(dev_priv)) { 5180
5177 DRM_ERROR("enabling SSC on PCH\n"); 5181 I915_WRITE(PCH_DREF_CONTROL, temp);
5178 temp |= DREF_SUPERSPREAD_SOURCE_ENABLE; 5182 POSTING_READ(PCH_DREF_CONTROL);
5179 } 5183 udelay(200);
5180 } 5184 } else {
5185 DRM_DEBUG_KMS("Disabling SSC entirely\n");
5186
5187 temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
5188
5189 /* Turn off CPU output */
5190 temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
5191
5192 I915_WRITE(PCH_DREF_CONTROL, temp);
5193 POSTING_READ(PCH_DREF_CONTROL);
5194 udelay(200);
5195
5196 /* Turn off the SSC source */
5197 temp &= ~DREF_SSC_SOURCE_MASK;
5198 temp |= DREF_SSC_SOURCE_DISABLE;
5199
5200 /* Turn off SSC1 */
5201 temp &= ~ DREF_SSC1_ENABLE;
5202
5181 I915_WRITE(PCH_DREF_CONTROL, temp); 5203 I915_WRITE(PCH_DREF_CONTROL, temp);
5182 POSTING_READ(PCH_DREF_CONTROL); 5204 POSTING_READ(PCH_DREF_CONTROL);
5183 udelay(200); 5205 udelay(200);