Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d0498a2 authored by Jesse Barnes's avatar Jesse Barnes Committed by Eric Anholt
Browse files

drm/i915: wait for actual vblank, not just 20ms

Waiting for a hard coded 20ms isn't always enough to make sure a vblank
period has actually occurred, so add code to make sure we really have
passed through a vblank period (or that the pipe is off when disabling).

This prevents problems with mode setting and link training, and seems to
fix a bug like https://bugs.freedesktop.org/show_bug.cgi?id=29278, but
on an HP 8440p instead.  Hopefully also fixes
https://bugs.freedesktop.org/show_bug.cgi?id=29141

.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent d240f20f
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -2081,6 +2081,7 @@
#define PIPE_DITHER_TYPE_ST01		(1 << 2)
#define PIPE_DITHER_TYPE_ST01		(1 << 2)
/* Pipe A */
/* Pipe A */
#define PIPEADSL		0x70000
#define PIPEADSL		0x70000
#define   DSL_LINEMASK	       	0x00000fff
#define PIPEACONF		0x70008
#define PIPEACONF		0x70008
#define   PIPEACONF_ENABLE	(1<<31)
#define   PIPEACONF_ENABLE	(1<<31)
#define   PIPEACONF_DISABLE	0
#define   PIPEACONF_DISABLE	0
+1 −1
Original line number Original line Diff line number Diff line
@@ -328,7 +328,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
		/* Wait for next Vblank to substitue
		/* Wait for next Vblank to substitue
		 * border color for Color info */
		 * border color for Color info */
		intel_wait_for_vblank(dev);
		intel_wait_for_vblank(dev, pipe);
		st00 = I915_READ8(VGA_MSR_WRITE);
		st00 = I915_READ8(VGA_MSR_WRITE);
		status = ((st00 & (1 << 4)) != 0) ?
		status = ((st00 & (1 << 4)) != 0) ?
			connector_status_connected :
			connector_status_connected :
+56 −22
Original line number Original line Diff line number Diff line
@@ -977,14 +977,54 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
    return true;
    return true;
}
}


void
/**
intel_wait_for_vblank(struct drm_device *dev)
 * intel_wait_for_vblank - wait for vblank on a given pipe
 * @dev: drm device
 * @pipe: pipe to wait for
 *
 * Wait for vblank to occur on a given pipe.  Needed for various bits of
 * mode setting code.
 */
void intel_wait_for_vblank(struct drm_device *dev, int pipe)
{
{
	/* Wait for 20ms, i.e. one cycle at 50hz. */
	struct drm_i915_private *dev_priv = dev->dev_private;
	if (in_dbg_master())
	int pipestat_reg = (pipe == 0 ? PIPEASTAT : PIPEBSTAT);
		mdelay(20); /* The kernel debugger cannot call msleep() */

	else
	/* Wait for vblank interrupt bit to set */
		msleep(20);
	if (wait_for((I915_READ(pipestat_reg) &
		      PIPE_VBLANK_INTERRUPT_STATUS) == 0,
		     50, 0))
		DRM_DEBUG_KMS("vblank wait timed out\n");
}

/**
 * intel_wait_for_vblank_off - wait for vblank after disabling a pipe
 * @dev: drm device
 * @pipe: pipe to wait for
 *
 * After disabling a pipe, we can't wait for vblank in the usual way,
 * spinning on the vblank interrupt status bit, since we won't actually
 * see an interrupt when the pipe is disabled.
 *
 * So this function waits for the display line value to settle (it
 * usually ends up stopping at the start of the next frame).
 */
void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
	unsigned long timeout = jiffies + msecs_to_jiffies(100);
	u32 last_line;

	/* Wait for the display line to settle */
	do {
		last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
		mdelay(5);
	} while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
		 time_after(timeout, jiffies));

	if (time_after(jiffies, timeout))
		DRM_DEBUG_KMS("vblank wait timed out\n");
}
}


/* Parameters have changed, update FBC info */
/* Parameters have changed, update FBC info */
@@ -1057,8 +1097,6 @@ void i8xx_disable_fbc(struct drm_device *dev)
		return;
		return;
	}
	}


	intel_wait_for_vblank(dev);

	DRM_DEBUG_KMS("disabled FBC\n");
	DRM_DEBUG_KMS("disabled FBC\n");
}
}


@@ -1115,7 +1153,6 @@ void g4x_disable_fbc(struct drm_device *dev)
	dpfc_ctl = I915_READ(DPFC_CONTROL);
	dpfc_ctl = I915_READ(DPFC_CONTROL);
	dpfc_ctl &= ~DPFC_CTL_EN;
	dpfc_ctl &= ~DPFC_CTL_EN;
	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
	intel_wait_for_vblank(dev);


	DRM_DEBUG_KMS("disabled FBC\n");
	DRM_DEBUG_KMS("disabled FBC\n");
}
}
@@ -1176,7 +1213,6 @@ void ironlake_disable_fbc(struct drm_device *dev)
	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
	dpfc_ctl &= ~DPFC_CTL_EN;
	dpfc_ctl &= ~DPFC_CTL_EN;
	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
	intel_wait_for_vblank(dev);


	DRM_DEBUG_KMS("disabled FBC\n");
	DRM_DEBUG_KMS("disabled FBC\n");
}
}
@@ -1475,7 +1511,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
	if ((IS_I965G(dev) || plane == 0))
	if ((IS_I965G(dev) || plane == 0))
		intel_update_fbc(crtc, &crtc->mode);
		intel_update_fbc(crtc, &crtc->mode);


	intel_wait_for_vblank(dev);
	intel_wait_for_vblank(dev, intel_crtc->pipe);
	intel_increase_pllclock(crtc, true);
	intel_increase_pllclock(crtc, true);


	return 0;
	return 0;
@@ -1593,7 +1629,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
	if ((IS_I965G(dev) || plane == 0))
	if ((IS_I965G(dev) || plane == 0))
		intel_update_fbc(crtc, &crtc->mode);
		intel_update_fbc(crtc, &crtc->mode);


	intel_wait_for_vblank(dev);
	intel_wait_for_vblank(dev, pipe);


	if (old_fb) {
	if (old_fb) {
		intel_fb = to_intel_framebuffer(old_fb);
		intel_fb = to_intel_framebuffer(old_fb);
@@ -2343,10 +2379,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
			I915_READ(dspbase_reg);
			I915_READ(dspbase_reg);
		}
		}


		if (!IS_I9XX(dev)) {
		/* Wait for vblank for the disable to take effect */
		/* Wait for vblank for the disable to take effect */
			intel_wait_for_vblank(dev);
		intel_wait_for_vblank_off(dev, pipe);
		}


		/* Don't disable pipe A or pipe A PLLs if needed */
		/* Don't disable pipe A or pipe A PLLs if needed */
		if (pipeconf_reg == PIPEACONF &&
		if (pipeconf_reg == PIPEACONF &&
@@ -2361,7 +2395,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
		}
		}


		/* Wait for vblank for the disable to take effect. */
		/* Wait for vblank for the disable to take effect. */
		intel_wait_for_vblank(dev);
		intel_wait_for_vblank_off(dev, pipe);


		temp = I915_READ(dpll_reg);
		temp = I915_READ(dpll_reg);
		if ((temp & DPLL_VCO_ENABLE) != 0) {
		if ((temp & DPLL_VCO_ENABLE) != 0) {
@@ -4096,7 +4130,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
	I915_WRITE(pipeconf_reg, pipeconf);
	I915_WRITE(pipeconf_reg, pipeconf);
	I915_READ(pipeconf_reg);
	I915_READ(pipeconf_reg);


	intel_wait_for_vblank(dev);
	intel_wait_for_vblank(dev, pipe);


	if (IS_IRONLAKE(dev)) {
	if (IS_IRONLAKE(dev)) {
		/* enable address swizzle for tiling buffer */
		/* enable address swizzle for tiling buffer */
@@ -4508,7 +4542,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
		encoder_funcs->commit(encoder);
		encoder_funcs->commit(encoder);
	}
	}
	/* let the connector get through one full cycle before testing */
	/* let the connector get through one full cycle before testing */
	intel_wait_for_vblank(dev);
	intel_wait_for_vblank(dev, intel_crtc->pipe);


	return crtc;
	return crtc;
}
}
@@ -4713,7 +4747,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
		dpll &= ~DISPLAY_RATE_SELECT_FPA1;
		dpll &= ~DISPLAY_RATE_SELECT_FPA1;
		I915_WRITE(dpll_reg, dpll);
		I915_WRITE(dpll_reg, dpll);
		dpll = I915_READ(dpll_reg);
		dpll = I915_READ(dpll_reg);
		intel_wait_for_vblank(dev);
		intel_wait_for_vblank(dev, pipe);
		dpll = I915_READ(dpll_reg);
		dpll = I915_READ(dpll_reg);
		if (dpll & DISPLAY_RATE_SELECT_FPA1)
		if (dpll & DISPLAY_RATE_SELECT_FPA1)
			DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
			DRM_DEBUG_DRIVER("failed to upclock LVDS!\n");
@@ -4757,7 +4791,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
		dpll |= DISPLAY_RATE_SELECT_FPA1;
		dpll |= DISPLAY_RATE_SELECT_FPA1;
		I915_WRITE(dpll_reg, dpll);
		I915_WRITE(dpll_reg, dpll);
		dpll = I915_READ(dpll_reg);
		dpll = I915_READ(dpll_reg);
		intel_wait_for_vblank(dev);
		intel_wait_for_vblank(dev, pipe);
		dpll = I915_READ(dpll_reg);
		dpll = I915_READ(dpll_reg);
		if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
		if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
			DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
			DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
+2 −1
Original line number Original line Diff line number Diff line
@@ -1145,12 +1145,13 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
{
{
	struct drm_device *dev = intel_dp->base.enc.dev;
	struct drm_device *dev = intel_dp->base.enc.dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
	int ret;
	int ret;


	I915_WRITE(intel_dp->output_reg, dp_reg_value);
	I915_WRITE(intel_dp->output_reg, dp_reg_value);
	POSTING_READ(intel_dp->output_reg);
	POSTING_READ(intel_dp->output_reg);
	if (first)
	if (first)
		intel_wait_for_vblank(dev);
		intel_wait_for_vblank(dev, intel_crtc->pipe);


	intel_dp_aux_native_write_1(intel_dp,
	intel_dp_aux_native_write_1(intel_dp,
				    DP_TRAINING_PATTERN_SET,
				    DP_TRAINING_PATTERN_SET,
+2 −1
Original line number Original line Diff line number Diff line
@@ -219,7 +219,8 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
						    struct drm_crtc *crtc);
						    struct drm_crtc *crtc);
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
				struct drm_file *file_priv);
				struct drm_file *file_priv);
extern void intel_wait_for_vblank(struct drm_device *dev);
extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe);
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
						   struct drm_connector *connector,
						   struct drm_connector *connector,
Loading