struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- assert_pipe_enabled(dev_priv, intel_crtc->pipe);
+ if (WARN_ON(!intel_crtc->active))
+ return;
if (!intel_crtc->primary_enabled)
return;
intel_check_primary_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
+ struct drm_device *dev = plane->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = state->base.crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_framebuffer *fb = state->base.fb;
struct drm_rect *dest = &state->dst;
struct drm_rect *src = &state->src;
if (ret)
return ret;
- intel_crtc_wait_for_pending_flips(crtc);
- if (intel_crtc_has_pending_flip(crtc)) {
- DRM_ERROR("pipe is still busy with an old pageflip\n");
- return -EBUSY;
+ if (intel_crtc->active) {
+ intel_crtc->atomic.wait_for_flips = true;
+
+ /*
+ * FBC does not work on some platforms for rotated
+ * planes, so disable it when rotation is not 0 and
+ * update it when rotation is set back to 0.
+ *
+ * FIXME: This is redundant with the fbc update done in
+ * the primary plane enable function except that that
+ * one is done too late. We eventually need to unify
+ * this.
+ */
+ if (intel_crtc->primary_enabled &&
+ INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
+ dev_priv->fbc.plane == intel_crtc->plane &&
+ intel_plane->rotation != BIT(DRM_ROTATE_0)) {
+ intel_crtc->atomic.disable_fbc = true;
+ }
+
+ if (state->visible) {
+ /*
+ * BDW signals flip done immediately if the plane
+ * is disabled, even if the plane enable is already
+ * armed to occur at the next vblank :(
+ */
+ if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled)
+ intel_crtc->atomic.wait_vblank = true;
+ }
+
+ intel_crtc->atomic.fb_bits |=
+ INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
+
+ intel_crtc->atomic.update_fbc = true;
}
return 0;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_rect *src = &state->src;
- enum pipe pipe = intel_plane->pipe;
-
- if (!fb) {
- /*
- * 'prepare' is never called when plane is being disabled, so
- * we need to handle frontbuffer tracking here
- */
- mutex_lock(&dev->struct_mutex);
- i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
- INTEL_FRONTBUFFER_PRIMARY(pipe));
- mutex_unlock(&dev->struct_mutex);
- }
plane->fb = fb;
crtc->x = src->x1 >> 16;
intel_plane->obj = obj;
if (intel_crtc->active) {
- /*
- * FBC does not work on some platforms for rotated
- * planes, so disable it when rotation is not 0 and
- * update it when rotation is set back to 0.
- *
- * FIXME: This is redundant with the fbc update done in
- * the primary plane enable function except that that
- * one is done too late. We eventually need to unify
- * this.
- */
- if (intel_crtc->primary_enabled &&
- INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
- dev_priv->fbc.plane == intel_crtc->plane &&
- intel_plane->rotation != BIT(DRM_ROTATE_0)) {
- intel_fbc_disable(dev);
- }
-
if (state->visible) {
- bool was_enabled = intel_crtc->primary_enabled;
-
/* FIXME: kill this fastboot hack */
intel_update_pipe_size(intel_crtc);
dev_priv->display.update_primary_plane(crtc, plane->fb,
crtc->x, crtc->y);
-
- /*
- * BDW signals flip done immediately if the plane
- * is disabled, even if the plane enable is already
- * armed to occur at the next vblank :(
- */
- if (IS_BROADWELL(dev) && !was_enabled)
- intel_wait_for_vblank(dev, intel_crtc->pipe);
} else {
/*
* If clipping results in a non-visible primary plane,
*/
intel_disable_primary_hw_plane(plane, crtc);
}
+ }
+}
+
+static void intel_begin_crtc_commit(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
+ if (intel_crtc->atomic.wait_for_flips)
+ intel_crtc_wait_for_pending_flips(crtc);
+ if (intel_crtc->atomic.disable_fbc)
+ intel_fbc_disable(dev);
+
+ if (intel_crtc->atomic.pre_disable_primary)
+ intel_pre_disable_primary(crtc);
+
+ if (intel_crtc->atomic.update_wm)
+ intel_update_watermarks(crtc);
+
+ intel_runtime_pm_get(dev_priv);
+}
+
+static void intel_finish_crtc_commit(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_plane *p;
+
+ intel_runtime_pm_put(dev_priv);
+
+ if (intel_crtc->atomic.wait_vblank)
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+ intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits);
+
+ if (intel_crtc->atomic.update_fbc) {
mutex_lock(&dev->struct_mutex);
intel_fbc_update(dev);
mutex_unlock(&dev->struct_mutex);
}
+
+ if (intel_crtc->atomic.post_enable_primary)
+ intel_post_enable_primary(crtc);
+
+ drm_for_each_legacy_plane(p, &dev->mode_config.plane_list)
+ if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p))
+ intel_update_sprite_watermarks(p, crtc, 0, 0, 0,
+ false, false);
+
+ memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic));
}
int
uint32_t src_w, uint32_t src_h)
{
struct drm_device *dev = plane->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *old_fb = plane->fb;
- struct intel_plane_state state;
+ struct intel_plane_state state = {{ 0 }};
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int ret;
return ret;
}
- intel_runtime_pm_get(dev_priv);
+ if (!state.base.fb) {
+ unsigned fb_bits = 0;
+
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe);
+ break;
+ case DRM_PLANE_TYPE_CURSOR:
+ fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe);
+ break;
+ }
+
+ /*
+ * 'prepare' is never called when plane is being disabled, so
+ * we need to handle frontbuffer tracking here
+ */
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, fb_bits);
+ mutex_unlock(&dev->struct_mutex);
+ }
+
+ intel_begin_crtc_commit(crtc);
intel_plane->commit_plane(plane, &state);
- intel_runtime_pm_put(dev_priv);
+ intel_finish_crtc_commit(crtc);
if (fb != old_fb && old_fb) {
if (intel_crtc->active)
struct drm_rect *src = &state->src;
const struct drm_rect *clip = &state->clip;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int crtc_w, crtc_h;
unsigned stride;
int ret;
/* if we want to turn off the cursor ignore width and height */
if (!obj)
- return 0;
+ goto finish;
/* Check for which cursor types we support */
crtc_w = drm_rect_width(&state->orig_dst);
}
mutex_unlock(&dev->struct_mutex);
+finish:
+ if (intel_crtc->active) {
+ if (intel_crtc->cursor_width !=
+ drm_rect_width(&state->orig_dst))
+ intel_crtc->atomic.update_wm = true;
+
+ intel_crtc->atomic.fb_bits |=
+ INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe);
+ }
+
return ret;
}
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
- struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
- enum pipe pipe = intel_crtc->pipe;
- unsigned old_width;
uint32_t addr;
plane->fb = state->base.fb;
if (intel_crtc->cursor_bo == obj)
goto update;
- /*
- * 'prepare' is only called when fb != NULL; we still need to update
- * frontbuffer tracking for the 'disable' case here.
- */
- if (!obj) {
- mutex_lock(&dev->struct_mutex);
- i915_gem_track_fb(old_obj, NULL,
- INTEL_FRONTBUFFER_CURSOR(pipe));
- mutex_unlock(&dev->struct_mutex);
- }
-
if (!obj)
addr = 0;
else if (!INTEL_INFO(dev)->cursor_needs_physical)
intel_crtc->cursor_addr = addr;
intel_crtc->cursor_bo = obj;
update:
- old_width = intel_crtc->cursor_width;
-
intel_crtc->cursor_width = drm_rect_width(&state->orig_dst);
intel_crtc->cursor_height = drm_rect_height(&state->orig_dst);
- if (intel_crtc->active) {
- if (old_width != intel_crtc->cursor_width)
- intel_update_watermarks(crtc);
+ if (intel_crtc->active)
intel_crtc_update_cursor(crtc, state->visible);
-
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
- }
}
static const struct drm_plane_funcs intel_cursor_plane_funcs = {
* Avoid underruns when disabling the sprite.
* FIXME remove once watermark updates are done properly.
*/
- intel_wait_for_vblank(dev, pipe);
-
- intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false);
+ intel_crtc->atomic.wait_vblank = true;
+ intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
}
static int
* Avoid underruns when disabling the sprite.
* FIXME remove once watermark updates are done properly.
*/
- intel_wait_for_vblank(dev, pipe);
-
- intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false);
+ intel_crtc->atomic.wait_vblank = true;
+ intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
}
-static void
+/**
+ * intel_post_enable_primary - Perform operations after enabling primary plane
+ * @crtc: the CRTC whose primary plane was just enabled
+ *
+ * Performs potentially sleeping operations that must be done after the primary
+ * plane is enabled, such as updating FBC and IPS. Note that this may be
+ * called due to an explicit primary plane update, or due to an implicit
+ * re-enable that is caused when a sprite plane is updated to no longer
+ * completely hide the primary plane.
+ */
+void
intel_post_enable_primary(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
mutex_unlock(&dev->struct_mutex);
}
-static void
+/**
+ * intel_pre_disable_primary - Perform operations before disabling primary plane
+ * @crtc: the CRTC whose primary plane is to be disabled
+ *
+ * Performs potentially sleeping operations that must be done before the
+ * primary plane is enabled, such as updating FBC and IPS. Note that this may
+ * be called due to an explicit primary plane update, or due to an implicit
+ * disable that is caused when a sprite plane completely hides the primary
+ * plane.
+ */
+void
intel_pre_disable_primary(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
if (!fb) {
state->visible = false;
- return 0;
+ goto finish;
}
/* Don't modify another pipe's plane */
dst->y1 = crtc_y;
dst->y2 = crtc_y + crtc_h;
+finish:
+ /*
+ * If the sprite is completely covering the primary plane,
+ * we can disable the primary and save power.
+ */
+ state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) &&
+ !colorkey_enabled(intel_plane);
+ WARN_ON(state->hides_primary && !state->visible && intel_crtc->active);
+
+ if (intel_crtc->active) {
+ if (intel_crtc->primary_enabled == state->hides_primary)
+ intel_crtc->atomic.wait_for_flips = true;
+
+ if (intel_crtc->primary_enabled && state->hides_primary)
+ intel_crtc->atomic.pre_disable_primary = true;
+
+ intel_crtc->atomic.fb_bits |=
+ INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe);
+
+ if (!intel_crtc->primary_enabled && !state->hides_primary)
+ intel_crtc->atomic.post_enable_primary = true;
+ }
+
return 0;
}
intel_commit_sprite_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
- struct drm_device *dev = plane->dev;
struct drm_crtc *crtc = state->base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_plane *intel_plane = to_intel_plane(plane);
- enum pipe pipe = intel_crtc->pipe;
struct drm_framebuffer *fb = state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h;
uint32_t src_x, src_y, src_w, src_h;
- struct drm_rect *dst = &state->dst;
- const struct drm_rect *clip = &state->clip;
- bool primary_enabled;
-
- /*
- * 'prepare' is never called when plane is being disabled, so we need
- * to handle frontbuffer tracking here
- */
- if (!fb) {
- mutex_lock(&dev->struct_mutex);
- i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
- INTEL_FRONTBUFFER_SPRITE(pipe));
- mutex_unlock(&dev->struct_mutex);
- }
-
- /*
- * If the sprite is completely covering the primary plane,
- * we can disable the primary and save power.
- */
- primary_enabled = !drm_rect_equals(dst, clip) || colorkey_enabled(intel_plane);
- WARN_ON(!primary_enabled && !state->visible && intel_crtc->active);
intel_plane->crtc_x = state->orig_dst.x1;
intel_plane->crtc_y = state->orig_dst.y1;
intel_plane->obj = obj;
if (intel_crtc->active) {
- bool primary_was_enabled = intel_crtc->primary_enabled;
-
- intel_crtc->primary_enabled = primary_enabled;
-
- if (primary_was_enabled != primary_enabled)
- intel_crtc_wait_for_pending_flips(crtc);
-
- if (primary_was_enabled && !primary_enabled)
- intel_pre_disable_primary(crtc);
+ intel_crtc->primary_enabled = !state->hides_primary;
if (state->visible) {
crtc_x = state->dst.x1;
} else {
intel_plane->disable_plane(plane, crtc);
}
-
-
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_SPRITE(pipe));
-
- if (!primary_was_enabled && primary_enabled)
- intel_post_enable_primary(crtc);
}
}