From 6e644626945c7c1a7f4d4f83b806b898297846d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 17 Aug 2017 17:55:09 +0300 Subject: [PATCH] drm/i915: Beef up the IPS vs. CRC workaround Mime-version: 1.0 Content-type: text/plain; charset=UTF-8 Content-transfer-encoding: 8bit Git-commit: 6e644626945c7c1a7f4d4f83b806b898297846d0 Patch-mainline: v4.15-rc1 References: FATE#322643 bsc#1055900 Oneshot disabling of IPS when CRC capturing is started is insufficient. IPS may get re-enabled by any plane update, and hence tests that keep CRC capturing on across plane updates will start to see inconsistent results as soon as IPS kicks back in. Add a new knob into the crtc state to make sure IPS stays disabled as long as CRC capturing is enabled. Forcing a modeset is the easiest way to handle this since that's already how we do the panel fitter workaround. It's a little heavy handed just for IPS, but seeing as we might already do the panel fitter workaround I think it's better to follow that. We migth want to optimize both cases later if someone gets too upset by the extra delay from the modeset. V2: Check the right thing when deciding whether to force a modeset V3: Rebase, check HAS_IPS before forcing a modeset, move ips_force_disable check into pipe_config_supports_ips() Cc: Paulo Zanoni Cc: Daniel Vetter Cc: Maarten Lankhorst Cc: Marta Lofstedt Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101664 Reviewed-by: Paulo Zanoni Tested-by: Marta Lofsted #v2 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20170817145509.15549-1-ville.syrjala@linux.intel.com Acked-by: Takashi Iwai --- drivers/gpu/drm/i915/intel_display.c | 7 +++ drivers/gpu/drm/i915/intel_drv.h | 1 drivers/gpu/drm/i915/intel_pipe_crc.c | 62 +++++++++++++++------------------- 3 files changed, 36 insertions(+), 34 deletions(-) --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6283,6 +6283,9 @@ retry: static bool pipe_config_supports_ips(struct drm_i915_private *dev_priv, struct intel_crtc_state *pipe_config) { + if (pipe_config->ips_force_disable) + return false; + if (pipe_config->pipe_bpp > 24) return false; @@ -10854,7 +10857,7 @@ clear_intel_crtc_state(struct intel_crtc struct intel_dpll_hw_state dpll_hw_state; struct intel_shared_dpll *shared_dpll; struct intel_crtc_wm_state wm_state; - bool force_thru; + bool force_thru, ips_force_disable; /* FIXME: before the switch to atomic started, a new pipe_config was * kzalloc'd. Code that depends on any field being zero should be @@ -10865,6 +10868,7 @@ clear_intel_crtc_state(struct intel_crtc shared_dpll = crtc_state->shared_dpll; dpll_hw_state = crtc_state->dpll_hw_state; force_thru = crtc_state->pch_pfit.force_thru; + ips_force_disable = crtc_state->ips_force_disable; if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) wm_state = crtc_state->wm; @@ -10878,6 +10882,7 @@ clear_intel_crtc_state(struct intel_crtc crtc_state->shared_dpll = shared_dpll; crtc_state->dpll_hw_state = dpll_hw_state; crtc_state->pch_pfit.force_thru = force_thru; + crtc_state->ips_force_disable = ips_force_disable; if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) crtc_state->wm = wm_state; --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -752,6 +752,7 @@ struct intel_crtc_state { struct intel_link_m_n fdi_m_n; bool ips_enabled; + bool ips_force_disable; bool enable_fbc; --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -506,8 +506,8 @@ static int ilk_pipe_crc_ctl_reg(enum int return 0; } -static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv, - bool enable) +static void hsw_pipe_A_crc_wa(struct drm_i915_private *dev_priv, + bool enable) { struct drm_device *dev = &dev_priv->drm; struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A); @@ -533,10 +533,24 @@ retry: goto put_state; } - pipe_config->pch_pfit.force_thru = enable; - if (pipe_config->cpu_transcoder == TRANSCODER_EDP && - pipe_config->pch_pfit.enabled != enable) - pipe_config->base.connectors_changed = true; + if (HAS_IPS(dev_priv)) { + /* + * When IPS gets enabled, the pipe CRC changes. Since IPS gets + * enabled and disabled dynamically based on package C states, + * user space can't make reliable use of the CRCs, so let's just + * completely disable it. + */ + pipe_config->ips_force_disable = enable; + if (pipe_config->ips_enabled == enable) + pipe_config->base.connectors_changed = true; + } + + if (IS_HASWELL(dev_priv)) { + pipe_config->pch_pfit.force_thru = enable; + if (pipe_config->cpu_transcoder == TRANSCODER_EDP && + pipe_config->pch_pfit.enabled != enable) + pipe_config->base.connectors_changed = true; + } ret = drm_atomic_commit(state); @@ -570,8 +584,9 @@ static int ivb_pipe_crc_ctl_reg(struct d *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; break; case INTEL_PIPE_CRC_SOURCE_PF: - if (IS_HASWELL(dev_priv) && pipe == PIPE_A) - hsw_trans_edp_pipe_A_crc_wa(dev_priv, true); + if ((IS_HASWELL(dev_priv) || + IS_BROADWELL(dev_priv)) && pipe == PIPE_A) + hsw_pipe_A_crc_wa(dev_priv, true); *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB; break; @@ -606,7 +621,6 @@ static int pipe_crc_set_source(struct dr enum intel_pipe_crc_source source) { struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; - struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); enum intel_display_power_domain power_domain; u32 val = 0; /* shut up gcc */ int ret; @@ -643,14 +657,6 @@ static int pipe_crc_set_source(struct dr goto out; } - /* - * When IPS gets enabled, the pipe CRC changes. Since IPS gets - * enabled and disabled dynamically based on package C states, - * user space can't make reliable use of the CRCs, so let's just - * completely disable it. - */ - hsw_disable_ips(crtc); - spin_lock_irq(&pipe_crc->lock); kfree(pipe_crc->entries); pipe_crc->entries = entries; @@ -691,10 +697,9 @@ static int pipe_crc_set_source(struct dr g4x_undo_pipe_scramble_reset(dev_priv, pipe); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) vlv_undo_pipe_scramble_reset(dev_priv, pipe); - else if (IS_HASWELL(dev_priv) && pipe == PIPE_A) - hsw_trans_edp_pipe_A_crc_wa(dev_priv, false); - - hsw_enable_ips(crtc); + else if ((IS_HASWELL(dev_priv) || + IS_BROADWELL(dev_priv)) && pipe == PIPE_A) + hsw_pipe_A_crc_wa(dev_priv, false); } ret = 0; @@ -935,16 +940,6 @@ int intel_crtc_set_crc_source(struct drm if (ret != 0) goto out; - if (source) { - /* - * When IPS gets enabled, the pipe CRC changes. Since IPS gets - * enabled and disabled dynamically based on package C states, - * user space can't make reliable use of the CRCs, so let's just - * completely disable it. - */ - hsw_disable_ips(intel_crtc); - } - I915_WRITE(PIPE_CRC_CTL(crtc->index), val); POSTING_READ(PIPE_CRC_CTL(crtc->index)); @@ -953,8 +948,9 @@ int intel_crtc_set_crc_source(struct drm g4x_undo_pipe_scramble_reset(dev_priv, crtc->index); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) vlv_undo_pipe_scramble_reset(dev_priv, crtc->index); - else if (IS_HASWELL(dev_priv) && crtc->index == PIPE_A) - hsw_trans_edp_pipe_A_crc_wa(dev_priv, false); + else if ((IS_HASWELL(dev_priv) || + IS_BROADWELL(dev_priv)) && crtc->index == PIPE_A) + hsw_pipe_A_crc_wa(dev_priv, false); hsw_enable_ips(intel_crtc); }