提交 9d0498a2 编写于 作者: J Jesse Barnes 提交者: Eric Anholt

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: NJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: NEric Anholt <eric@anholt.net>
上级 d240f20f
...@@ -2081,6 +2081,7 @@ ...@@ -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
......
...@@ -328,7 +328,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder ...@@ -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 :
......
...@@ -977,14 +977,54 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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_off(dev, pipe);
intel_wait_for_vblank(dev);
}
/* 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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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");
......
...@@ -1145,12 +1145,13 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, ...@@ -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,
......
...@@ -219,7 +219,8 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, ...@@ -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,
......
...@@ -1218,6 +1218,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) ...@@ -1218,6 +1218,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
u32 temp; u32 temp;
if (mode != DRM_MODE_DPMS_ON) { if (mode != DRM_MODE_DPMS_ON) {
...@@ -1240,7 +1241,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) ...@@ -1240,7 +1241,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
if ((temp & SDVO_ENABLE) == 0) if ((temp & SDVO_ENABLE) == 0)
intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
intel_wait_for_vblank(dev); intel_wait_for_vblank(dev, intel_crtc->pipe);
status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
/* Warn if the device reported failure to sync. /* Warn if the device reported failure to sync.
......
...@@ -1158,11 +1158,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -1158,11 +1158,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
/* Wait for vblank for the disable to take effect */ /* Wait for vblank for the disable to take effect */
if (!IS_I9XX(dev)) if (!IS_I9XX(dev))
intel_wait_for_vblank(dev); intel_wait_for_vblank(dev, intel_crtc->pipe);
I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
/* 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(dev, intel_crtc->pipe);
/* Filter ctl must be set before TV_WIN_SIZE */ /* Filter ctl must be set before TV_WIN_SIZE */
I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
...@@ -1231,6 +1231,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv) ...@@ -1231,6 +1231,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
struct drm_encoder *encoder = &intel_tv->base.enc; struct drm_encoder *encoder = &intel_tv->base.enc;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->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(encoder->crtc);
unsigned long irqflags; unsigned long irqflags;
u32 tv_ctl, save_tv_ctl; u32 tv_ctl, save_tv_ctl;
u32 tv_dac, save_tv_dac; u32 tv_dac, save_tv_dac;
...@@ -1267,11 +1268,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv) ...@@ -1267,11 +1268,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
DAC_C_0_7_V); DAC_C_0_7_V);
I915_WRITE(TV_CTL, tv_ctl); I915_WRITE(TV_CTL, tv_ctl);
I915_WRITE(TV_DAC, tv_dac); I915_WRITE(TV_DAC, tv_dac);
intel_wait_for_vblank(dev); intel_wait_for_vblank(dev, intel_crtc->pipe);
tv_dac = I915_READ(TV_DAC); tv_dac = I915_READ(TV_DAC);
I915_WRITE(TV_DAC, save_tv_dac); I915_WRITE(TV_DAC, save_tv_dac);
I915_WRITE(TV_CTL, save_tv_ctl); I915_WRITE(TV_CTL, save_tv_ctl);
intel_wait_for_vblank(dev); intel_wait_for_vblank(dev, intel_crtc->pipe);
/* /*
* A B C * A B C
* 0 1 1 Composite * 0 1 1 Composite
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册