diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 70 | 
1 files changed, 48 insertions, 22 deletions
| diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 878acc432a4b..123585eeb87d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1000,7 +1000,8 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,  	return crtc->config->cpu_transcoder;  } -static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe) +static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv, +				    enum pipe pipe)  {  	i915_reg_t reg = PIPEDSL(pipe);  	u32 line1, line2; @@ -1015,7 +1016,28 @@ static bool pipe_dsl_stopped(struct drm_i915_private *dev_priv, enum pipe pipe)  	msleep(5);  	line2 = I915_READ(reg) & line_mask; -	return line1 == line2; +	return line1 != line2; +} + +static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state) +{ +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); +	enum pipe pipe = crtc->pipe; + +	/* Wait for the display line to settle/start moving */ +	if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100)) +		DRM_ERROR("pipe %c scanline %s wait timed out\n", +			  pipe_name(pipe), onoff(state)); +} + +static void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc) +{ +	wait_for_pipe_scanline_moving(crtc, false); +} + +static void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc) +{ +	wait_for_pipe_scanline_moving(crtc, true);  }  /* @@ -1038,7 +1060,6 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)  {  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);  	enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; -	enum pipe pipe = crtc->pipe;  	if (INTEL_GEN(dev_priv) >= 4) {  		i915_reg_t reg = PIPECONF(cpu_transcoder); @@ -1049,9 +1070,7 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)  					    100))  			WARN(1, "pipe_off wait timed out\n");  	} else { -		/* Wait for the display line to settle */ -		if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100)) -			WARN(1, "pipe_off wait timed out\n"); +		intel_wait_for_pipe_scanline_stopped(crtc);  	}  } @@ -1936,15 +1955,14 @@ static void intel_enable_pipe(struct intel_crtc *crtc)  	POSTING_READ(reg);  	/* -	 * Until the pipe starts DSL will read as 0, which would cause -	 * an apparent vblank timestamp jump, which messes up also the -	 * frame count when it's derived from the timestamps. So let's -	 * wait for the pipe to start properly before we call -	 * drm_crtc_vblank_on() +	 * Until the pipe starts PIPEDSL reads will return a stale value, +	 * which causes an apparent vblank timestamp jump when PIPEDSL +	 * resets to its proper value. That also messes up the frame count +	 * when it's derived from the timestamps. So let's wait for the +	 * pipe to start properly before we call drm_crtc_vblank_on()  	 */ -	if (dev->max_vblank_count == 0 && -	    wait_for(intel_get_crtc_scanline(crtc) != crtc->scanline_offset, 50)) -		DRM_ERROR("pipe %c didn't start\n", pipe_name(pipe)); +	if (dev->max_vblank_count == 0) +		intel_wait_for_pipe_scanline_moving(crtc);  }  /** @@ -9926,11 +9944,10 @@ found:  	}  	ret = intel_modeset_setup_plane_state(state, crtc, mode, fb, 0, 0); +	drm_framebuffer_put(fb);  	if (ret)  		goto fail; -	drm_framebuffer_put(fb); -  	ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, mode);  	if (ret)  		goto fail; @@ -12527,11 +12544,15 @@ static int intel_atomic_commit(struct drm_device *dev,  	INIT_WORK(&state->commit_work, intel_atomic_commit_work);  	i915_sw_fence_commit(&intel_state->commit_ready); -	if (nonblock) +	if (nonblock && intel_state->modeset) { +		queue_work(dev_priv->modeset_wq, &state->commit_work); +	} else if (nonblock) {  		queue_work(system_unbound_wq, &state->commit_work); -	else +	} else { +		if (intel_state->modeset) +			flush_workqueue(dev_priv->modeset_wq);  		intel_atomic_commit_tail(state); - +	}  	return 0;  } @@ -13177,7 +13198,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)  	primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe);  	primary->check_plane = intel_check_primary_plane; -	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { +	if (INTEL_GEN(dev_priv) >= 10) {  		intel_primary_formats = skl_primary_formats;  		num_formats = ARRAY_SIZE(skl_primary_formats);  		modifiers = skl_format_modifiers_ccs; @@ -14445,6 +14466,8 @@ int intel_modeset_init(struct drm_device *dev)  	enum pipe pipe;  	struct intel_crtc *crtc; +	dev_priv->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0); +  	drm_mode_config_init(dev);  	dev->mode_config.min_width = 0; @@ -14643,6 +14666,8 @@ void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)  void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)  { +	struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); +  	DRM_DEBUG_KMS("disabling pipe %c due to force quirk\n",  		      pipe_name(pipe)); @@ -14652,8 +14677,7 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)  	I915_WRITE(PIPECONF(pipe), 0);  	POSTING_READ(PIPECONF(pipe)); -	if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100)) -		DRM_ERROR("pipe %c off wait timed out\n", pipe_name(pipe)); +	intel_wait_for_pipe_scanline_stopped(crtc);  	I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS);  	POSTING_READ(DPLL(pipe)); @@ -15252,6 +15276,8 @@ void intel_modeset_cleanup(struct drm_device *dev)  	intel_cleanup_gt_powersave(dev_priv);  	intel_teardown_gmbus(dev_priv); + +	destroy_workqueue(dev_priv->modeset_wq);  }  void intel_connector_attach_encoder(struct intel_connector *connector, |