Commit 6e644626 authored by Ville Syrjälä's avatar Ville Syrjälä
Browse files

drm/i915: Beef up the IPS vs. CRC workaround

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 <paulo.r.zanoni@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Marta Lofstedt <marta.lofstedt@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101664


Reviewed-by: default avatarPaulo Zanoni <paulo.r.zanoni@intel.com>
Tested-by: Marta Lofsted <marta.lofstedt@intel.com> #v2
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170817145509.15549-1-ville.syrjala@linux.intel.com
parent 3814fd77
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -6263,6 +6263,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;

@@ -10830,7 +10833,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
	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
@@ -10841,6 +10844,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
	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;
@@ -10854,6 +10858,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
	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;
+1 −0
Original line number Diff line number Diff line
@@ -753,6 +753,7 @@ struct intel_crtc_state {
	struct intel_link_m_n fdi_m_n;

	bool ips_enabled;
	bool ips_force_disable;

	bool enable_fbc;

+29 −33
Original line number Diff line number Diff line
@@ -506,7 +506,7 @@ static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
	return 0;
}

static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv,
static void hsw_pipe_A_crc_wa(struct drm_i915_private *dev_priv,
			      bool enable)
{
	struct drm_device *dev = &dev_priv->drm;
@@ -533,10 +533,24 @@ retry:
		goto put_state;
	}

	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 drm_i915_private *dev_priv,
		*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 drm_i915_private *dev_priv,
			       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 drm_i915_private *dev_priv,
			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 drm_i915_private *dev_priv,
			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_crtc *crtc, const char *source_name,
	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_crtc *crtc, const char *source_name,
			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);
	}