|
@@ -37,6 +37,89 @@
|
|
#include <drm/i915_drm.h>
|
|
#include <drm/i915_drm.h>
|
|
#include "i915_drv.h"
|
|
#include "i915_drv.h"
|
|
|
|
|
|
|
|
+static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs)
|
|
|
|
+{
|
|
|
|
+ /* paranoia */
|
|
|
|
+ if (!mode->crtc_htotal)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
|
|
|
|
+{
|
|
|
|
+ struct drm_device *dev = crtc->base.dev;
|
|
|
|
+ const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
|
|
|
|
+ enum pipe pipe = crtc->pipe;
|
|
|
|
+ long timeout = msecs_to_jiffies_timeout(1);
|
|
|
|
+ int scanline, min, max, vblank_start;
|
|
|
|
+ DEFINE_WAIT(wait);
|
|
|
|
+
|
|
|
|
+ WARN_ON(!mutex_is_locked(&crtc->base.mutex));
|
|
|
|
+
|
|
|
|
+ vblank_start = mode->crtc_vblank_start;
|
|
|
|
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
|
|
|
+ vblank_start = DIV_ROUND_UP(vblank_start, 2);
|
|
|
|
+
|
|
|
|
+ /* FIXME needs to be calibrated sensibly */
|
|
|
|
+ min = vblank_start - usecs_to_scanlines(mode, 100);
|
|
|
|
+ max = vblank_start - 1;
|
|
|
|
+
|
|
|
|
+ if (min <= 0 || max <= 0)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (WARN_ON(drm_vblank_get(dev, pipe)))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ local_irq_disable();
|
|
|
|
+
|
|
|
|
+ for (;;) {
|
|
|
|
+ /*
|
|
|
|
+ * prepare_to_wait() has a memory barrier, which guarantees
|
|
|
|
+ * other CPUs can see the task state update by the time we
|
|
|
|
+ * read the scanline.
|
|
|
|
+ */
|
|
|
|
+ prepare_to_wait(&crtc->vbl_wait, &wait, TASK_UNINTERRUPTIBLE);
|
|
|
|
+
|
|
|
|
+ scanline = intel_get_crtc_scanline(crtc);
|
|
|
|
+ if (scanline < min || scanline > max)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ if (timeout <= 0) {
|
|
|
|
+ DRM_ERROR("Potential atomic update failure on pipe %c\n",
|
|
|
|
+ pipe_name(crtc->pipe));
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ local_irq_enable();
|
|
|
|
+
|
|
|
|
+ timeout = schedule_timeout(timeout);
|
|
|
|
+
|
|
|
|
+ local_irq_disable();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ finish_wait(&crtc->vbl_wait, &wait);
|
|
|
|
+
|
|
|
|
+ drm_vblank_put(dev, pipe);
|
|
|
|
+
|
|
|
|
+ *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count)
|
|
|
|
+{
|
|
|
|
+ struct drm_device *dev = crtc->base.dev;
|
|
|
|
+ enum pipe pipe = crtc->pipe;
|
|
|
|
+ u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
|
|
|
|
+
|
|
|
|
+ local_irq_enable();
|
|
|
|
+
|
|
|
|
+ if (start_vbl_count != end_vbl_count)
|
|
|
|
+ DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n",
|
|
|
|
+ pipe_name(pipe), start_vbl_count, end_vbl_count);
|
|
|
|
+}
|
|
|
|
+
|
|
static void
|
|
static void
|
|
vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
|
|
vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
|
|
struct drm_framebuffer *fb,
|
|
struct drm_framebuffer *fb,
|
|
@@ -48,11 +131,14 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
|
|
struct drm_device *dev = dplane->dev;
|
|
struct drm_device *dev = dplane->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct intel_plane *intel_plane = to_intel_plane(dplane);
|
|
struct intel_plane *intel_plane = to_intel_plane(dplane);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
int pipe = intel_plane->pipe;
|
|
int pipe = intel_plane->pipe;
|
|
int plane = intel_plane->plane;
|
|
int plane = intel_plane->plane;
|
|
u32 sprctl;
|
|
u32 sprctl;
|
|
unsigned long sprsurf_offset, linear_offset;
|
|
unsigned long sprsurf_offset, linear_offset;
|
|
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
|
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
|
|
|
+ u32 start_vbl_count;
|
|
|
|
+ bool atomic_update;
|
|
|
|
|
|
sprctl = I915_READ(SPCNTR(pipe, plane));
|
|
sprctl = I915_READ(SPCNTR(pipe, plane));
|
|
|
|
|
|
@@ -131,6 +217,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
|
|
fb->pitches[0]);
|
|
fb->pitches[0]);
|
|
linear_offset -= sprsurf_offset;
|
|
linear_offset -= sprsurf_offset;
|
|
|
|
|
|
|
|
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
|
|
|
|
+
|
|
I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
|
|
I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
|
|
I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
|
|
I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
|
|
|
|
|
|
@@ -144,6 +232,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
|
|
I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
|
|
I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
|
|
sprsurf_offset);
|
|
sprsurf_offset);
|
|
POSTING_READ(SPSURF(pipe, plane));
|
|
POSTING_READ(SPSURF(pipe, plane));
|
|
|
|
+
|
|
|
|
+ if (atomic_update)
|
|
|
|
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
@@ -152,8 +243,13 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
|
|
struct drm_device *dev = dplane->dev;
|
|
struct drm_device *dev = dplane->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct intel_plane *intel_plane = to_intel_plane(dplane);
|
|
struct intel_plane *intel_plane = to_intel_plane(dplane);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
int pipe = intel_plane->pipe;
|
|
int pipe = intel_plane->pipe;
|
|
int plane = intel_plane->plane;
|
|
int plane = intel_plane->plane;
|
|
|
|
+ u32 start_vbl_count;
|
|
|
|
+ bool atomic_update;
|
|
|
|
+
|
|
|
|
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
|
|
|
|
|
|
I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
|
|
I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
|
|
~SP_ENABLE);
|
|
~SP_ENABLE);
|
|
@@ -161,6 +257,9 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
|
|
I915_WRITE(SPSURF(pipe, plane), 0);
|
|
I915_WRITE(SPSURF(pipe, plane), 0);
|
|
POSTING_READ(SPSURF(pipe, plane));
|
|
POSTING_READ(SPSURF(pipe, plane));
|
|
|
|
|
|
|
|
+ if (atomic_update)
|
|
|
|
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
|
|
|
|
+
|
|
intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
|
|
intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -226,10 +325,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
int pipe = intel_plane->pipe;
|
|
int pipe = intel_plane->pipe;
|
|
u32 sprctl, sprscale = 0;
|
|
u32 sprctl, sprscale = 0;
|
|
unsigned long sprsurf_offset, linear_offset;
|
|
unsigned long sprsurf_offset, linear_offset;
|
|
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
|
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
|
|
|
+ u32 start_vbl_count;
|
|
|
|
+ bool atomic_update;
|
|
|
|
|
|
sprctl = I915_READ(SPRCTL(pipe));
|
|
sprctl = I915_READ(SPRCTL(pipe));
|
|
|
|
|
|
@@ -299,6 +401,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
|
pixel_size, fb->pitches[0]);
|
|
pixel_size, fb->pitches[0]);
|
|
linear_offset -= sprsurf_offset;
|
|
linear_offset -= sprsurf_offset;
|
|
|
|
|
|
|
|
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
|
|
|
|
+
|
|
I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
|
|
I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
|
|
I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
|
|
I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
|
|
|
|
|
|
@@ -318,6 +422,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
|
I915_WRITE(SPRSURF(pipe),
|
|
I915_WRITE(SPRSURF(pipe),
|
|
i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
|
|
i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
|
|
POSTING_READ(SPRSURF(pipe));
|
|
POSTING_READ(SPRSURF(pipe));
|
|
|
|
+
|
|
|
|
+ if (atomic_update)
|
|
|
|
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
@@ -326,7 +433,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
int pipe = intel_plane->pipe;
|
|
int pipe = intel_plane->pipe;
|
|
|
|
+ u32 start_vbl_count;
|
|
|
|
+ bool atomic_update;
|
|
|
|
+
|
|
|
|
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
|
|
|
|
|
|
I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
|
|
I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
|
|
/* Can't leave the scaler enabled... */
|
|
/* Can't leave the scaler enabled... */
|
|
@@ -336,6 +448,9 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
|
|
I915_WRITE(SPRSURF(pipe), 0);
|
|
I915_WRITE(SPRSURF(pipe), 0);
|
|
POSTING_READ(SPRSURF(pipe));
|
|
POSTING_READ(SPRSURF(pipe));
|
|
|
|
|
|
|
|
+ if (atomic_update)
|
|
|
|
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Avoid underruns when disabling the sprite.
|
|
* Avoid underruns when disabling the sprite.
|
|
* FIXME remove once watermark updates are done properly.
|
|
* FIXME remove once watermark updates are done properly.
|
|
@@ -410,10 +525,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
int pipe = intel_plane->pipe;
|
|
int pipe = intel_plane->pipe;
|
|
unsigned long dvssurf_offset, linear_offset;
|
|
unsigned long dvssurf_offset, linear_offset;
|
|
u32 dvscntr, dvsscale;
|
|
u32 dvscntr, dvsscale;
|
|
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
|
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
|
|
|
+ u32 start_vbl_count;
|
|
|
|
+ bool atomic_update;
|
|
|
|
|
|
dvscntr = I915_READ(DVSCNTR(pipe));
|
|
dvscntr = I915_READ(DVSCNTR(pipe));
|
|
|
|
|
|
@@ -478,6 +596,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
|
pixel_size, fb->pitches[0]);
|
|
pixel_size, fb->pitches[0]);
|
|
linear_offset -= dvssurf_offset;
|
|
linear_offset -= dvssurf_offset;
|
|
|
|
|
|
|
|
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
|
|
|
|
+
|
|
I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
|
|
I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
|
|
I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
|
|
I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
|
|
|
|
|
|
@@ -492,6 +612,9 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
|
I915_WRITE(DVSSURF(pipe),
|
|
I915_WRITE(DVSSURF(pipe),
|
|
i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
|
|
i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
|
|
POSTING_READ(DVSSURF(pipe));
|
|
POSTING_READ(DVSSURF(pipe));
|
|
|
|
+
|
|
|
|
+ if (atomic_update)
|
|
|
|
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
@@ -500,7 +623,12 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
struct intel_plane *intel_plane = to_intel_plane(plane);
|
|
|
|
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
int pipe = intel_plane->pipe;
|
|
int pipe = intel_plane->pipe;
|
|
|
|
+ u32 start_vbl_count;
|
|
|
|
+ bool atomic_update;
|
|
|
|
+
|
|
|
|
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
|
|
|
|
|
|
I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
|
|
I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
|
|
/* Disable the scaler */
|
|
/* Disable the scaler */
|
|
@@ -509,6 +637,9 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
|
|
I915_WRITE(DVSSURF(pipe), 0);
|
|
I915_WRITE(DVSSURF(pipe), 0);
|
|
POSTING_READ(DVSSURF(pipe));
|
|
POSTING_READ(DVSSURF(pipe));
|
|
|
|
|
|
|
|
+ if (atomic_update)
|
|
|
|
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Avoid underruns when disabling the sprite.
|
|
* Avoid underruns when disabling the sprite.
|
|
* FIXME remove once watermark updates are done properly.
|
|
* FIXME remove once watermark updates are done properly.
|