Adam Jackson was watching the screensaver fade out and expressed a desire for the gamma updates to be synchronized to vblank to avoid the unsightly tears. Reported-by: Adam Jackson <ajax at redhat.com> Cc: Adam Jackson <ajax at redhat.com> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk> --- drivers/gpu/drm/i915/intel_display.c | 61 ++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dc4bf49..279474a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -44,6 +44,7 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type); static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); +static void __intel_crtc_load_lut(struct intel_crtc *crtc, void *data); static void i9xx_crtc_clock_get(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config); @@ -3457,7 +3458,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) * On ILK+ LUT must be loaded before the pipe is running but with * clocks enabled */ - intel_crtc_load_lut(crtc); + __intel_crtc_load_lut(to_intel_crtc(crtc), NULL); intel_ddi_set_pipe_settings(crtc); intel_ddi_enable_transcoder_func(crtc); @@ -6411,47 +6412,58 @@ void intel_write_eld(struct drm_encoder *encoder, dev_priv->display.write_eld(connector, crtc); } -/** Loads the palette/gamma unit for the CRTC with the prepared values */ -void intel_crtc_load_lut(struct drm_crtc *crtc) +static void __intel_crtc_load_lut(struct intel_crtc *crtc, + void *data) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - int palreg = PALETTE(pipe); - int i; + enum pipe pipe = crtc->pipe; bool reenable_ips = false; + int reg, i; - /* The clocks have to be on to load the palette. */ - if (!crtc->enabled || !intel_crtc->active) + if (!crtc->base.enabled || !crtc->active) return; - if (!HAS_PCH_SPLIT(dev_priv->dev)) + if (!HAS_PCH_SPLIT(dev)) assert_pll_enabled(dev_priv, pipe); - /* use legacy palette for Ironlake */ - if (HAS_PCH_SPLIT(dev)) - 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 && + if (crtc->config.ips_enabled && ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) == GAMMA_MODE_MODE_SPLIT)) { - hsw_disable_ips(intel_crtc); + hsw_disable_ips(crtc); reenable_ips = true; } - for (i = 0; i < 256; i++) { - I915_WRITE(palreg + 4 * i, - (intel_crtc->lut_r[i] << 16) | - (intel_crtc->lut_g[i] << 8) | - intel_crtc->lut_b[i]); - } + /* use legacy palette for Ironlake */ + reg = PALETTE(pipe); + if (HAS_PCH_SPLIT(crtc->base.dev)) + reg = LGC_PALETTE(pipe); + + for (i = 0; i < 256; i++) + I915_WRITE(reg + 4 * i, + crtc->lut_r[i] << 16 | + crtc->lut_g[i] << 8 | + crtc->lut_b[i]); if (reenable_ips) - hsw_enable_ips(intel_crtc); + hsw_enable_ips(crtc); +} + +/** Loads the palette/gamma unit for the CRTC with the prepared values */ +void intel_crtc_load_lut(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* The clocks have to be on to load the palette. */ + if (!crtc->enabled || !intel_crtc->active) + return; + + if (intel_crtc_add_vblank_task(intel_crtc, true, + __intel_crtc_load_lut, NULL)) + __intel_crtc_load_lut(intel_crtc, NULL); } static void i845_update_cursor(struct drm_crtc *crtc, u32 base) @@ -6749,6 +6761,7 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, int end = (start + size > 256) ? 256 : start + size, i; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + /* We race here with setting the lut and reading it during vblank. */ for (i = start; i < end; i++) { intel_crtc->lut_r[i] = red[i] >> 8; intel_crtc->lut_g[i] = green[i] >> 8; -- 1.8.3.2