@@ -11647,24 +11647,22 @@ intel_check_primary_plane(struct drm_plane *plane,
}
}
+ state->primary_was_enabled = to_intel_crtc(crtc)->primary_enabled;
+
return 0;
}
static void
-intel_commit_primary_plane(struct drm_plane *plane,
- struct intel_plane_state *state)
+intel_pre_commit_primary(struct drm_plane *plane,
+ struct intel_plane_state *state)
{
- struct drm_crtc *crtc = state->base.crtc;
- struct drm_framebuffer *fb = state->base.fb;
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- 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;
+ struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
+ enum pipe pipe = intel_crtc->pipe;
- if (!fb) {
+ if (!state->base.fb) {
/*
* 'prepare' is never called when plane is being disabled, so
* we need to handle frontbuffer tracking here
@@ -11675,20 +11673,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
mutex_unlock(&dev->struct_mutex);
}
- plane->fb = fb;
- crtc->x = src->x1 >> 16;
- crtc->y = src->y1 >> 16;
-
- intel_plane->crtc_x = state->orig_dst.x1;
- intel_plane->crtc_y = state->orig_dst.y1;
- intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
- intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
- intel_plane->src_x = state->orig_src.x1;
- intel_plane->src_y = state->orig_src.y1;
- intel_plane->src_w = drm_rect_width(&state->orig_src);
- intel_plane->src_h = drm_rect_height(&state->orig_src);
- intel_plane->obj = obj;
-
if (intel_crtc->active) {
/*
* FBC does not work on some platforms for rotated
@@ -11706,10 +11690,65 @@ intel_commit_primary_plane(struct drm_plane *plane,
intel_plane->rotation != BIT(DRM_ROTATE_0)) {
intel_disable_fbc(dev);
}
+ }
+}
+static void
+intel_post_commit_primary(struct drm_plane *plane,
+ struct intel_plane_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
+ enum pipe pipe = intel_crtc->pipe;
+
+ if (intel_crtc->active) {
if (state->visible) {
- bool was_enabled = intel_crtc->primary_enabled;
+ /*
+ * 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) && !state->primary_was_enabled)
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+ }
+
+ intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
+
+ mutex_lock(&dev->struct_mutex);
+ intel_update_fbc(dev);
+ mutex_unlock(&dev->struct_mutex);
+ }
+}
+
+static void
+intel_commit_primary_plane(struct drm_plane *plane,
+ struct intel_plane_state *state)
+{
+ struct drm_crtc *crtc = state->base.crtc;
+ struct drm_framebuffer *fb = state->base.fb;
+ struct drm_device *dev = plane->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ 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;
+
+ plane->fb = fb;
+ crtc->x = src->x1 >> 16;
+ crtc->y = src->y1 >> 16;
+
+ intel_plane->crtc_x = state->orig_dst.x1;
+ intel_plane->crtc_y = state->orig_dst.y1;
+ intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
+ intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
+ intel_plane->src_x = state->orig_src.x1;
+ intel_plane->src_y = state->orig_src.y1;
+ intel_plane->src_w = drm_rect_width(&state->orig_src);
+ intel_plane->src_h = drm_rect_height(&state->orig_src);
+ intel_plane->obj = obj;
+ if (intel_crtc->active) {
+ if (state->visible) {
/* FIXME: kill this fastboot hack */
intel_update_pipe_size(intel_crtc);
@@ -11717,14 +11756,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
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,
@@ -11735,12 +11766,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
*/
intel_disable_primary_hw_plane(plane, plane->crtc);
}
-
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
-
- mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
- mutex_unlock(&dev->struct_mutex);
}
}
@@ -11753,7 +11778,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
{
struct drm_device *dev = plane->dev;
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;
@@ -11791,7 +11816,11 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
return ret;
}
+ if (intel_plane->pre_commit)
+ intel_plane->pre_commit(plane, &state);
intel_plane->commit_plane(plane, &state);
+ if (intel_plane->post_commit)
+ intel_plane->post_commit(plane, &state);
if (fb != old_fb) {
if (intel_crtc->active)
@@ -11856,6 +11885,8 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
primary->rotation = BIT(DRM_ROTATE_0);
primary->check_plane = intel_check_primary_plane;
primary->commit_plane = intel_commit_primary_plane;
+ primary->pre_commit = intel_pre_commit_primary;
+ primary->post_commit = intel_post_commit_primary;
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
primary->plane = !pipe;
@@ -11944,6 +11975,46 @@ intel_check_cursor_plane(struct drm_plane *plane,
}
static void
+intel_pre_commit_cursor(struct drm_plane *plane,
+ struct intel_plane_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
+ struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
+ struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
+ enum pipe pipe = intel_crtc->pipe;
+
+ /*
+ * '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 (intel_crtc->active) {
+ if (intel_crtc->cursor_width !=
+ drm_rect_width(&state->orig_dst))
+ intel_update_watermarks(&intel_crtc->base);
+ }
+}
+
+static void
+intel_post_commit_cursor(struct drm_plane *plane,
+ struct intel_plane_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
+ enum pipe pipe = intel_crtc->pipe;
+
+ if (intel_crtc->active)
+ intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
+}
+
+static void
intel_commit_cursor_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
@@ -11952,9 +12023,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
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;
crtc->cursor_x = state->orig_dst.x1;
@@ -11973,17 +12041,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
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)
@@ -11994,18 +12051,11 @@ intel_commit_cursor_plane(struct drm_plane *plane,
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 = {
@@ -12031,6 +12081,8 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
cursor->rotation = BIT(DRM_ROTATE_0);
cursor->check_plane = intel_check_cursor_plane;
cursor->commit_plane = intel_commit_cursor_plane;
+ cursor->pre_commit = intel_pre_commit_cursor;
+ cursor->post_commit = intel_post_commit_cursor;
drm_universal_plane_init(dev, &cursor->base, 0,
&intel_cursor_plane_funcs,
@@ -251,6 +251,16 @@ struct intel_plane_state {
struct drm_rect orig_src;
struct drm_rect orig_dst;
bool visible;
+
+ /*
+ * used only for sprite planes to determine when to implicitly
+ * enable/disable the primary plane
+ */
+ bool hides_primary;
+ bool need_primary_enable;
+
+ /* used only for primary plane */
+ bool primary_was_enabled;
};
struct intel_plane_config {
@@ -513,6 +523,10 @@ struct intel_plane {
struct intel_plane_state *state);
void (*commit_plane)(struct drm_plane *plane,
struct intel_plane_state *state);
+ void (*pre_commit)(struct drm_plane *plane,
+ struct intel_plane_state *state);
+ void (*post_commit)(struct drm_plane *plane,
+ struct intel_plane_state *state);
int (*update_colorkey)(struct drm_plane *plane,
struct drm_intel_sprite_colorkey *key);
void (*get_colorkey)(struct drm_plane *plane,
@@ -1260,44 +1260,75 @@ intel_check_sprite_plane(struct drm_plane *plane,
dst->y1 = crtc_y;
dst->y2 = crtc_y + crtc_h;
+ /*
+ * Does this plane completely hide the primary plane? If so, we can
+ * disable the primary to save power.
+ */
+ if (drm_rect_equals(dst, clip) && !colorkey_enabled(intel_plane))
+ state->hides_primary = true;
+ else
+ state->hides_primary = false;
+
return 0;
}
static void
-intel_commit_sprite_plane(struct drm_plane *plane,
- struct intel_plane_state *state)
+intel_pre_commit_sprite(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
+ * 'prepare' is never called when plane is being disabled, so
+ * we need to handle frontbuffer tracking here
*/
- if (!fb) {
+ if (!state->base.fb) {
mutex_lock(&dev->struct_mutex);
i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
- INTEL_FRONTBUFFER_SPRITE(pipe));
+ INTEL_FRONTBUFFER_SPRITE(intel_crtc->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);
+ if (intel_crtc->primary_enabled && state->hides_primary) {
+ intel_crtc_wait_for_pending_flips(crtc);
+ intel_pre_disable_primary(crtc);
+ }
+
+ if (!intel_crtc->primary_enabled && !state->hides_primary)
+ state->need_primary_enable = true;
+
+ intel_crtc->primary_enabled = !state->hides_primary;
+}
+
+static void
+intel_post_commit_sprite(struct drm_plane *plane,
+ struct intel_plane_state *state)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_crtc *crtc = state->base.crtc;
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+
+ intel_frontbuffer_flip(dev,
+ INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe));
+
+ if (state->need_primary_enable)
+ intel_post_enable_primary(crtc);
+}
+
+static void
+intel_commit_sprite_plane(struct drm_plane *plane,
+ struct intel_plane_state *state)
+{
+ 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_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;
intel_plane->crtc_x = state->orig_dst.x1;
intel_plane->crtc_y = state->orig_dst.y1;
@@ -1310,16 +1341,6 @@ intel_commit_sprite_plane(struct drm_plane *plane,
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);
-
if (state->visible) {
crtc_x = state->dst.x1;
crtc_y = state->dst.y1;
@@ -1335,12 +1356,6 @@ intel_commit_sprite_plane(struct drm_plane *plane,
} 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);
}
}
@@ -1589,6 +1604,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
intel_plane->rotation = BIT(DRM_ROTATE_0);
intel_plane->check_plane = intel_check_sprite_plane;
intel_plane->commit_plane = intel_commit_sprite_plane;
+ intel_plane->pre_commit = intel_pre_commit_sprite;
+ intel_plane->post_commit = intel_post_commit_sprite;
possible_crtcs = (1 << pipe);
ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
&intel_plane_funcs,
Once we integrate our work into the atomic pipeline, plane commit operations will need to happen with interrupts disabled, due to vblank evasion. Create new 'pre_commit' and 'post_commit' handlers to cover hardware programming operations that can sleep and thus must happen outside the vblank evasion window. Signed-off-by: Matt Roper <matthew.d.roper@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 174 +++++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_drv.h | 14 +++ drivers/gpu/drm/i915/intel_sprite.c | 93 +++++++++++-------- 3 files changed, 182 insertions(+), 99 deletions(-)