aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-09-12 20:16:10 -0400
committerChris Wilson <chris@chris-wilson.co.uk>2010-09-13 05:25:26 -0400
commite9e331a8abeece1565d383510ed985945132ffe3 (patch)
treef35a5f938e1eda21f99d1fbdb3d85b7923417791 /drivers/gpu
parent6edc3242e35f03990e362e7c115e722717f0f7a7 (diff)
drm/i915/lvds: Ensure panel is unlocked for Ironlake or the panel fitter
Commit 77d07fd9d73ef28689737c0952dbd5d6a5017743 introduced a regression where by not waiting for the panel to be turned off, left the panel and PLL registers locked across the modeset. Thus the panel remaining blank. As pointed out by Daniel Vetter, when testing LVDS it helps to open the laptop and look at the actual panel you are purporting to test. A second issue with the patch was that in order to modify the panel fitter before gen5, the pipe and the panel must have be completely powered down. So we wait. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c31
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c103
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c33
4 files changed, 105 insertions, 63 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 594f8f2410ab..0004534e7c7d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2636,33 +2636,6 @@ static int i830_get_display_clock_speed(struct drm_device *dev)
2636 return 133000; 2636 return 133000;
2637} 2637}
2638 2638
2639/**
2640 * Return the pipe currently connected to the panel fitter,
2641 * or -1 if the panel fitter is not present or not in use
2642 */
2643int intel_panel_fitter_pipe (struct drm_device *dev)
2644{
2645 struct drm_i915_private *dev_priv = dev->dev_private;
2646 u32 pfit_control;
2647
2648 /* i830 doesn't have a panel fitter */
2649 if (IS_I830(dev))
2650 return -1;
2651
2652 pfit_control = I915_READ(PFIT_CONTROL);
2653
2654 /* See if the panel fitter is in use */
2655 if ((pfit_control & PFIT_ENABLE) == 0)
2656 return -1;
2657
2658 /* 965 can place panel fitter on either pipe */
2659 if (IS_I965G(dev))
2660 return (pfit_control >> 29) & 0x3;
2661
2662 /* older chips can only use pipe 1 */
2663 return 1;
2664}
2665
2666struct fdi_m_n { 2639struct fdi_m_n {
2667 u32 tu; 2640 u32 tu;
2668 u32 gmch_m; 2641 u32 gmch_m;
@@ -3921,10 +3894,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
3921 pipeconf |= PIPECONF_ENABLE; 3894 pipeconf |= PIPECONF_ENABLE;
3922 dpll |= DPLL_VCO_ENABLE; 3895 dpll |= DPLL_VCO_ENABLE;
3923 3896
3924 /* Disable the panel fitter if it was on our pipe */
3925 if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
3926 I915_WRITE(PFIT_CONTROL, 0);
3927
3928 DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); 3897 DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
3929 drm_mode_debug_printmodeline(mode); 3898 drm_mode_debug_printmodeline(mode);
3930 3899
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e5f2a61af9f6..7e2646f1fec9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -239,7 +239,6 @@ extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
239extern u32 intel_panel_get_backlight(struct drm_device *dev); 239extern u32 intel_panel_get_backlight(struct drm_device *dev);
240extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); 240extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
241 241
242extern int intel_panel_fitter_pipe (struct drm_device *dev);
243extern void intel_crtc_load_lut(struct drm_crtc *crtc); 242extern void intel_crtc_load_lut(struct drm_crtc *crtc);
244extern void intel_encoder_prepare (struct drm_encoder *encoder); 243extern void intel_encoder_prepare (struct drm_encoder *encoder);
245extern void intel_encoder_commit (struct drm_encoder *encoder); 244extern void intel_encoder_commit (struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 9089604011f9..bfc1bb443b05 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -46,6 +46,7 @@ struct intel_lvds {
46 int fitting_mode; 46 int fitting_mode;
47 u32 pfit_control; 47 u32 pfit_control;
48 u32 pfit_pgm_ratios; 48 u32 pfit_pgm_ratios;
49 bool pfit_dirty;
49}; 50};
50 51
51static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) 52static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
@@ -53,31 +54,20 @@ static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
53 return container_of(encoder, struct intel_lvds, base.base); 54 return container_of(encoder, struct intel_lvds, base.base);
54} 55}
55 56
56static void intel_lvds_lock_panel(struct drm_device *dev, bool lock)
57{
58 struct drm_i915_private *dev_priv = dev->dev_private;
59
60 if (lock)
61 I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
62 else
63 I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
64}
65
66/** 57/**
67 * Sets the power state for the panel. 58 * Sets the power state for the panel.
68 */ 59 */
69static void intel_lvds_set_power(struct drm_device *dev, bool on) 60static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
70{ 61{
62 struct drm_device *dev = intel_lvds->base.base.dev;
71 struct drm_i915_private *dev_priv = dev->dev_private; 63 struct drm_i915_private *dev_priv = dev->dev_private;
72 u32 ctl_reg, status_reg, lvds_reg; 64 u32 ctl_reg, lvds_reg;
73 65
74 if (HAS_PCH_SPLIT(dev)) { 66 if (HAS_PCH_SPLIT(dev)) {
75 ctl_reg = PCH_PP_CONTROL; 67 ctl_reg = PCH_PP_CONTROL;
76 status_reg = PCH_PP_STATUS;
77 lvds_reg = PCH_LVDS; 68 lvds_reg = PCH_LVDS;
78 } else { 69 } else {
79 ctl_reg = PP_CONTROL; 70 ctl_reg = PP_CONTROL;
80 status_reg = PP_STATUS;
81 lvds_reg = LVDS; 71 lvds_reg = LVDS;
82 } 72 }
83 73
@@ -86,8 +76,18 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
86 I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); 76 I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
87 intel_panel_set_backlight(dev, dev_priv->backlight_level); 77 intel_panel_set_backlight(dev, dev_priv->backlight_level);
88 } else { 78 } else {
79 dev_priv->backlight_level = intel_panel_get_backlight(dev);
80
89 intel_panel_set_backlight(dev, 0); 81 intel_panel_set_backlight(dev, 0);
90 I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); 82 I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
83
84 if (intel_lvds->pfit_control) {
85 if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
86 DRM_ERROR("timed out waiting for panel to power off\n");
87 I915_WRITE(PFIT_CONTROL, 0);
88 intel_lvds->pfit_control = 0;
89 }
90
91 I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); 91 I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
92 } 92 }
93 POSTING_READ(lvds_reg); 93 POSTING_READ(lvds_reg);
@@ -95,12 +95,12 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
95 95
96static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) 96static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
97{ 97{
98 struct drm_device *dev = encoder->dev; 98 struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
99 99
100 if (mode == DRM_MODE_DPMS_ON) 100 if (mode == DRM_MODE_DPMS_ON)
101 intel_lvds_set_power(dev, true); 101 intel_lvds_set_power(intel_lvds, true);
102 else 102 else
103 intel_lvds_set_power(dev, false); 103 intel_lvds_set_power(intel_lvds, false);
104 104
105 /* XXX: We never power down the LVDS pairs. */ 105 /* XXX: We never power down the LVDS pairs. */
106} 106}
@@ -331,8 +331,12 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
331 } 331 }
332 332
333out: 333out:
334 intel_lvds->pfit_control = pfit_control; 334 if (pfit_control != intel_lvds->pfit_control ||
335 intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; 335 pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
336 intel_lvds->pfit_control = pfit_control;
337 intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
338 intel_lvds->pfit_dirty = true;
339 }
336 dev_priv->lvds_border_bits = border; 340 dev_priv->lvds_border_bits = border;
337 341
338 /* 342 /*
@@ -352,24 +356,56 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
352 356
353 dev_priv->backlight_level = intel_panel_get_backlight(dev); 357 dev_priv->backlight_level = intel_panel_get_backlight(dev);
354 358
355 if (intel_lvds->pfit_control == I915_READ(PFIT_CONTROL)) 359 /* We try to do the minimum that is necessary in order to unlock
356 intel_lvds_lock_panel(dev, false); 360 * the registers for mode setting.
357 else 361 *
358 intel_lvds_set_power(dev, false); 362 * On Ironlake, this is quite simple as we just set the unlock key
363 * and ignore all subtleties. (This may cause some issues...)
364 *
365 * Prior to Ironlake, we must disable the pipe if we want to adjust
366 * the panel fitter. However at all other times we can just reset
367 * the registers regardless.
368 */
369
370 if (HAS_PCH_SPLIT(dev)) {
371 I915_WRITE(PCH_PP_CONTROL,
372 I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
373 } else if (intel_lvds->pfit_dirty) {
374 I915_WRITE(PP_CONTROL,
375 I915_READ(PP_CONTROL) & ~POWER_TARGET_ON);
376 I915_WRITE(LVDS, I915_READ(LVDS) & ~LVDS_PORT_EN);
377 } else {
378 I915_WRITE(PP_CONTROL,
379 I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
380 }
359} 381}
360 382
361static void intel_lvds_commit( struct drm_encoder *encoder) 383static void intel_lvds_commit(struct drm_encoder *encoder)
362{ 384{
363 struct drm_device *dev = encoder->dev; 385 struct drm_device *dev = encoder->dev;
364 struct drm_i915_private *dev_priv = dev->dev_private; 386 struct drm_i915_private *dev_priv = dev->dev_private;
387 struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
365 388
366 if (dev_priv->backlight_level == 0) 389 if (dev_priv->backlight_level == 0)
367 dev_priv->backlight_level = intel_panel_get_max_backlight(dev); 390 dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
368 391
369 if ((I915_READ(PP_CONTROL) & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS) 392 /* Undo any unlocking done in prepare to prevent accidental
370 intel_lvds_lock_panel(dev, true); 393 * adjustment of the registers.
371 else 394 */
372 intel_lvds_set_power(dev, true); 395 if (HAS_PCH_SPLIT(dev)) {
396 u32 val = I915_READ(PCH_PP_CONTROL);
397 if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
398 I915_WRITE(PCH_PP_CONTROL, val & 0x3);
399 } else {
400 u32 val = I915_READ(PP_CONTROL);
401 if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
402 I915_WRITE(PP_CONTROL, val & 0x3);
403 }
404
405 /* Always do a full power on as we do not know what state
406 * we were left in.
407 */
408 intel_lvds_set_power(intel_lvds, true);
373} 409}
374 410
375static void intel_lvds_mode_set(struct drm_encoder *encoder, 411static void intel_lvds_mode_set(struct drm_encoder *encoder,
@@ -389,13 +425,20 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
389 if (HAS_PCH_SPLIT(dev)) 425 if (HAS_PCH_SPLIT(dev))
390 return; 426 return;
391 427
428 if (!intel_lvds->pfit_dirty)
429 return;
430
392 /* 431 /*
393 * Enable automatic panel scaling so that non-native modes fill the 432 * Enable automatic panel scaling so that non-native modes fill the
394 * screen. Should be enabled before the pipe is enabled, according to 433 * screen. Should be enabled before the pipe is enabled, according to
395 * register description and PRM. 434 * register description and PRM.
396 */ 435 */
436 if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
437 DRM_ERROR("timed out waiting for panel to power off\n");
438
397 I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); 439 I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
398 I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); 440 I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
441 intel_lvds->pfit_dirty = false;
399} 442}
400 443
401/** 444/**
@@ -824,6 +867,10 @@ void intel_lvds_init(struct drm_device *dev)
824 return; 867 return;
825 } 868 }
826 869
870 if (!HAS_PCH_SPLIT(dev)) {
871 intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
872 }
873
827 intel_encoder = &intel_lvds->base; 874 intel_encoder = &intel_lvds->base;
828 encoder = &intel_encoder->base; 875 encoder = &intel_encoder->base;
829 connector = &intel_connector->base; 876 connector = &intel_connector->base;
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 9dcddfc8394c..3dff16118ee5 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -1050,6 +1050,33 @@ static int check_overlay_src(struct drm_device *dev,
1050 return 0; 1050 return 0;
1051} 1051}
1052 1052
1053/**
1054 * Return the pipe currently connected to the panel fitter,
1055 * or -1 if the panel fitter is not present or not in use
1056 */
1057static int intel_panel_fitter_pipe(struct drm_device *dev)
1058{
1059 struct drm_i915_private *dev_priv = dev->dev_private;
1060 u32 pfit_control;
1061
1062 /* i830 doesn't have a panel fitter */
1063 if (IS_I830(dev))
1064 return -1;
1065
1066 pfit_control = I915_READ(PFIT_CONTROL);
1067
1068 /* See if the panel fitter is in use */
1069 if ((pfit_control & PFIT_ENABLE) == 0)
1070 return -1;
1071
1072 /* 965 can place panel fitter on either pipe */
1073 if (IS_I965G(dev))
1074 return (pfit_control >> 29) & 0x3;
1075
1076 /* older chips can only use pipe 1 */
1077 return 1;
1078}
1079
1053int intel_overlay_put_image(struct drm_device *dev, void *data, 1080int intel_overlay_put_image(struct drm_device *dev, void *data,
1054 struct drm_file *file_priv) 1081 struct drm_file *file_priv)
1055{ 1082{
@@ -1124,9 +1151,9 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
1124 overlay->crtc = crtc; 1151 overlay->crtc = crtc;
1125 crtc->overlay = overlay; 1152 crtc->overlay = overlay;
1126 1153
1127 if (intel_panel_fitter_pipe(dev) == crtc->pipe 1154 /* line too wide, i.e. one-line-mode */
1128 /* and line to wide, i.e. one-line-mode */ 1155 if (mode->hdisplay > 1024 &&
1129 && mode->hdisplay > 1024) { 1156 intel_panel_fitter_pipe(dev) == crtc->pipe) {
1130 overlay->pfit_active = 1; 1157 overlay->pfit_active = 1;
1131 update_pfit_vscale_ratio(overlay); 1158 update_pfit_vscale_ratio(overlay);
1132 } else 1159 } else