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@xxxxxxxxx> --- 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(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d746cb4..8daa053 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -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, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index da4da2c..c2fcb82 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -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, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index bc5834b..d18da5d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -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, -- 1.8.5.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx