diff options
| -rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 98 |
1 files changed, 54 insertions, 44 deletions
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f79327fc6653..25bcedf386fd 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
| @@ -68,7 +68,7 @@ static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector) | |||
| 68 | /** | 68 | /** |
| 69 | * Sets the power state for the panel. | 69 | * Sets the power state for the panel. |
| 70 | */ | 70 | */ |
| 71 | static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) | 71 | static void intel_lvds_enable(struct intel_lvds *intel_lvds) |
| 72 | { | 72 | { |
| 73 | struct drm_device *dev = intel_lvds->base.base.dev; | 73 | struct drm_device *dev = intel_lvds->base.base.dev; |
| 74 | struct drm_i915_private *dev_priv = dev->dev_private; | 74 | struct drm_i915_private *dev_priv = dev->dev_private; |
| @@ -82,26 +82,61 @@ static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) | |||
| 82 | lvds_reg = LVDS; | 82 | lvds_reg = LVDS; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | if (on) { | 85 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); |
| 86 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); | ||
| 87 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); | ||
| 88 | intel_panel_set_backlight(dev, dev_priv->backlight_level); | ||
| 89 | } else { | ||
| 90 | dev_priv->backlight_level = intel_panel_get_backlight(dev); | ||
| 91 | |||
| 92 | intel_panel_set_backlight(dev, 0); | ||
| 93 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); | ||
| 94 | 86 | ||
| 95 | if (intel_lvds->pfit_control) { | 87 | if (intel_lvds->pfit_dirty) { |
| 96 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) | 88 | /* |
| 97 | DRM_ERROR("timed out waiting for panel to power off\n"); | 89 | * Enable automatic panel scaling so that non-native modes |
| 98 | I915_WRITE(PFIT_CONTROL, 0); | 90 | * fill the screen. The panel fitter should only be |
| 99 | intel_lvds->pfit_control = 0; | 91 | * adjusted whilst the pipe is disabled, according to |
| 92 | * register description and PRM. | ||
| 93 | */ | ||
| 94 | DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", | ||
| 95 | intel_lvds->pfit_control, | ||
| 96 | intel_lvds->pfit_pgm_ratios); | ||
| 97 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) { | ||
| 98 | DRM_ERROR("timed out waiting for panel to power off\n"); | ||
| 99 | } else { | ||
| 100 | I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); | ||
| 101 | I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); | ||
| 100 | intel_lvds->pfit_dirty = false; | 102 | intel_lvds->pfit_dirty = false; |
| 101 | } | 103 | } |
| 104 | } | ||
| 105 | |||
| 106 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); | ||
| 107 | POSTING_READ(lvds_reg); | ||
| 108 | |||
| 109 | intel_panel_set_backlight(dev, dev_priv->backlight_level); | ||
| 110 | } | ||
| 102 | 111 | ||
| 103 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); | 112 | static void intel_lvds_disable(struct intel_lvds *intel_lvds) |
| 113 | { | ||
| 114 | struct drm_device *dev = intel_lvds->base.base.dev; | ||
| 115 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 116 | u32 ctl_reg, lvds_reg; | ||
| 117 | |||
| 118 | if (HAS_PCH_SPLIT(dev)) { | ||
| 119 | ctl_reg = PCH_PP_CONTROL; | ||
| 120 | lvds_reg = PCH_LVDS; | ||
| 121 | } else { | ||
| 122 | ctl_reg = PP_CONTROL; | ||
| 123 | lvds_reg = LVDS; | ||
| 124 | } | ||
| 125 | |||
| 126 | dev_priv->backlight_level = intel_panel_get_backlight(dev); | ||
| 127 | intel_panel_set_backlight(dev, 0); | ||
| 128 | |||
| 129 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); | ||
| 130 | |||
| 131 | if (intel_lvds->pfit_control) { | ||
| 132 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) | ||
| 133 | DRM_ERROR("timed out waiting for panel to power off\n"); | ||
| 134 | |||
| 135 | I915_WRITE(PFIT_CONTROL, 0); | ||
| 136 | intel_lvds->pfit_dirty = true; | ||
| 104 | } | 137 | } |
| 138 | |||
| 139 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); | ||
| 105 | POSTING_READ(lvds_reg); | 140 | POSTING_READ(lvds_reg); |
| 106 | } | 141 | } |
| 107 | 142 | ||
| @@ -110,9 +145,9 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) | |||
| 110 | struct intel_lvds *intel_lvds = to_intel_lvds(encoder); | 145 | struct intel_lvds *intel_lvds = to_intel_lvds(encoder); |
| 111 | 146 | ||
| 112 | if (mode == DRM_MODE_DPMS_ON) | 147 | if (mode == DRM_MODE_DPMS_ON) |
| 113 | intel_lvds_set_power(intel_lvds, true); | 148 | intel_lvds_enable(intel_lvds); |
| 114 | else | 149 | else |
| 115 | intel_lvds_set_power(intel_lvds, false); | 150 | intel_lvds_disable(intel_lvds); |
| 116 | 151 | ||
| 117 | /* XXX: We never power down the LVDS pairs. */ | 152 | /* XXX: We never power down the LVDS pairs. */ |
| 118 | } | 153 | } |
| @@ -411,43 +446,18 @@ static void intel_lvds_commit(struct drm_encoder *encoder) | |||
| 411 | /* Always do a full power on as we do not know what state | 446 | /* Always do a full power on as we do not know what state |
| 412 | * we were left in. | 447 | * we were left in. |
| 413 | */ | 448 | */ |
| 414 | intel_lvds_set_power(intel_lvds, true); | 449 | intel_lvds_enable(intel_lvds); |
| 415 | } | 450 | } |
| 416 | 451 | ||
| 417 | static void intel_lvds_mode_set(struct drm_encoder *encoder, | 452 | static void intel_lvds_mode_set(struct drm_encoder *encoder, |
| 418 | struct drm_display_mode *mode, | 453 | struct drm_display_mode *mode, |
| 419 | struct drm_display_mode *adjusted_mode) | 454 | struct drm_display_mode *adjusted_mode) |
| 420 | { | 455 | { |
| 421 | struct drm_device *dev = encoder->dev; | ||
| 422 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 423 | struct intel_lvds *intel_lvds = to_intel_lvds(encoder); | ||
| 424 | |||
| 425 | /* | 456 | /* |
| 426 | * The LVDS pin pair will already have been turned on in the | 457 | * The LVDS pin pair will already have been turned on in the |
| 427 | * intel_crtc_mode_set since it has a large impact on the DPLL | 458 | * intel_crtc_mode_set since it has a large impact on the DPLL |
| 428 | * settings. | 459 | * settings. |
| 429 | */ | 460 | */ |
| 430 | |||
| 431 | if (HAS_PCH_SPLIT(dev)) | ||
| 432 | return; | ||
| 433 | |||
| 434 | if (!intel_lvds->pfit_dirty) | ||
| 435 | return; | ||
| 436 | |||
| 437 | /* | ||
| 438 | * Enable automatic panel scaling so that non-native modes fill the | ||
| 439 | * screen. Should be enabled before the pipe is enabled, according to | ||
| 440 | * register description and PRM. | ||
| 441 | */ | ||
| 442 | DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", | ||
| 443 | intel_lvds->pfit_control, | ||
| 444 | intel_lvds->pfit_pgm_ratios); | ||
| 445 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) | ||
| 446 | DRM_ERROR("timed out waiting for panel to power off\n"); | ||
| 447 | |||
| 448 | I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); | ||
| 449 | I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); | ||
| 450 | intel_lvds->pfit_dirty = false; | ||
| 451 | } | 461 | } |
| 452 | 462 | ||
| 453 | /** | 463 | /** |
