diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 78 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 |
3 files changed, 88 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 89fac19d3249..5a593d20036c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1023,6 +1023,8 @@ /* Framebuffer compression for Ivybridge */ #define IVB_FBC_RT_BASE 0x7020 +#define IPS_CTL 0x43408 +#define IPS_ENABLE (1 << 31) #define _HSW_PIPE_SLICE_CHICKEN_1_A 0x420B0 #define _HSW_PIPE_SLICE_CHICKEN_1_B 0x420B4 @@ -3666,6 +3668,15 @@ #define _LGC_PALETTE_B 0x4a800 #define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) +#define _GAMMA_MODE_A 0x4a480 +#define _GAMMA_MODE_B 0x4ac80 +#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) +#define GAMMA_MODE_MODE_MASK (3 << 0) +#define GAMMA_MODE_MODE_8bit (0 << 0) +#define GAMMA_MODE_MODE_10bit (1 << 0) +#define GAMMA_MODE_MODE_12bit (2 << 0) +#define GAMMA_MODE_MODE_SPLIT (3 << 0) + /* interrupts */ #define DE_MASTER_IRQ_CONTROL (1 << 31) #define DE_SPRITEB_FLIP_DONE (1 << 29) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e2c6a370f52..acfc6a164a59 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3242,6 +3242,42 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_wait_for_vblank(dev, intel_crtc->pipe); } +/* IPS only exists on ULT machines and is tied to pipe A. */ +static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) +{ + return IS_ULT(crtc->base.dev) && crtc->pipe == PIPE_A; +} + +static void hsw_enable_ips(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (!crtc->config.ips_enabled) + return; + + /* We can only enable IPS after we enable a plane and wait for a vblank. + * We guarantee that the plane is enabled by calling intel_enable_ips + * only after intel_enable_plane. And intel_enable_plane already waits + * for a vblank, so all we need to do here is to enable the IPS bit. */ + assert_plane_enabled(dev_priv, crtc->plane); + I915_WRITE(IPS_CTL, IPS_ENABLE); +} + +static void hsw_disable_ips(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!crtc->config.ips_enabled) + return; + + assert_plane_enabled(dev_priv, crtc->plane); + I915_WRITE(IPS_CTL, 0); + + /* We need to wait for a vblank before we can disable the plane. */ + intel_wait_for_vblank(dev, crtc->pipe); +} + static void haswell_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3289,6 +3325,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); + hsw_enable_ips(intel_crtc); + if (intel_crtc->config.has_pch_encoder) lpt_pch_enable(crtc); @@ -3431,6 +3469,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (dev_priv->cfb_plane == plane) intel_disable_fbc(dev); + hsw_disable_ips(intel_crtc); + intel_disable_plane(dev_priv, plane, pipe); if (intel_crtc->config.has_pch_encoder) @@ -3991,11 +4031,19 @@ retry: return setup_ok ? 0 : -EINVAL; } +static void hsw_compute_ips_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && + pipe_config->pipe_bpp == 24; +} + static int intel_crtc_compute_config(struct drm_crtc *crtc, struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); if (HAS_PCH_SPLIT(dev)) { /* FDI link clock is fixed at 2.7G */ @@ -4025,8 +4073,11 @@ static int intel_crtc_compute_config(struct drm_crtc *crtc, pipe_config->pipe_bpp = 8*3; } + if (IS_HASWELL(dev)) + hsw_compute_ips_config(intel_crtc, pipe_config); + if (pipe_config->has_pch_encoder) - return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); + return ironlake_fdi_compute_config(intel_crtc, pipe_config); return 0; } @@ -5932,6 +5983,9 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, if (intel_display_power_enabled(dev, pfit_domain)) ironlake_get_pfit_config(crtc, pipe_config); + pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && + (I915_READ(IPS_CTL) & IPS_ENABLE); + return true; } @@ -6236,8 +6290,10 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int palreg = PALETTE(intel_crtc->pipe); + enum pipe pipe = intel_crtc->pipe; + int palreg = PALETTE(pipe); int i; + bool reenable_ips = false; /* The clocks have to be on to load the palette. */ if (!crtc->enabled || !intel_crtc->active) @@ -6245,7 +6301,17 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) /* use legacy palette for Ironlake */ if (HAS_PCH_SPLIT(dev)) - palreg = LGC_PALETTE(intel_crtc->pipe); + palreg = LGC_PALETTE(pipe); + + /* Workaround : Do not read or write the pipe palette/gamma data while + * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. + */ + if (intel_crtc->config.ips_enabled && + ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) == + GAMMA_MODE_MODE_SPLIT)) { + hsw_disable_ips(intel_crtc); + reenable_ips = true; + } for (i = 0; i < 256; i++) { I915_WRITE(palreg + 4 * i, @@ -6253,6 +6319,9 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) (intel_crtc->lut_g[i] << 8) | intel_crtc->lut_b[i]); } + + if (reenable_ips) + hsw_enable_ips(intel_crtc); } static void i845_update_cursor(struct drm_crtc *crtc, u32 base) @@ -7680,6 +7749,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n", pipe_config->pch_pfit.pos, pipe_config->pch_pfit.size); + DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled); } static struct intel_crtc_config * @@ -7996,6 +8066,8 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(pch_pfit.pos); PIPE_CONF_CHECK_I(pch_pfit.size); + PIPE_CONF_CHECK_I(ips_enabled); + #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bb4c50b57085..fdf6303be0a9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -268,6 +268,8 @@ struct intel_crtc_config { /* FDI configuration, only valid if has_pch_encoder is set. */ int fdi_lanes; struct intel_link_m_n fdi_m_n; + + bool ips_enabled; }; struct intel_crtc { |